# Vyin AI · Robot Lobby UI — Foundations & Components

給實作機器人端介面的前端工程師。這包是 Vyin AI 影城大廳機器人（PoC，威秀 × 迪士尼《歡迎光臨魔法秘境》活動）
kiosk 介面的**設計系統基礎層**：色彩、Grow 漸層、字級、格線、元件庫。以純 HTML / CSS 寫成，
可直接當規格書看，也可以直接把 CSS 搬進你們的環境用。

目前版本 **v3.3（2026-10-14）**：film 第二階段——11 支分支影片 + `films.html` 總覽、`prototype.html` 改用 film 引擎（▶ 是真正跑起來的對話）、DS 加 `--touch / --three-line / --notice`、規格頁 38 張、README §5.5c 規則表與 §5.5d 台詞表、Kebbi 腳本補 13 段；v3.2：新增 `film.html`（定點對話全段）與 `film-photo.html`（拍照全段）兩個一鏡到底的 Center 示範（時間軸驅動、給錄影用）；v3.1：Exit 送客畫面與 Kebbi 台詞拿掉「評分」；v3.0（2026-10-08）：Foundations、原語、元件、四種畫面版型、介面層級規則、全部 35 張畫面（`screens.html`，流程依 milo 2026-10-01 情境事件規格）、Prototype 狀態機（`data-chrome` / `data-mic` CSS 驅動）、流程模擬器（`prototype.html`）、迪士尼素材、劇照輪播（`.kv-slideshow`）、Voice Layer 動態（karaoke 逐字亮 + countdown 倒數）、Micro Moments 十二個情境（§5.7）、Kebbi 行為腳本（真表情、燈、手臂；§5.8）、四螢幕原型（Side F / B 前後 + Kebbi 表情示意 `.kv-face` 逐步同步）、去字 key art（Center 輪播、Welcome / Exit standby 底）、Side Exit 延伸邀請（動態 HTML + QR 卡，§5.6）、Micro Moments 引擎抽成 `js/moments.js`；demo 併入 prototype（說明列 + 手機那一步）、Mode 轉場動效（模糊暗黑 + 星芒 + 翻頁文字）、預告 Side 同步播放與觸控暫停、AI 文字超過兩行翻頁規則、取像告知併入 CTA。Kebbi 實際表情待實機 SDK 確認。

---

## 1. 這包是什麼

| 檔案                 | 用途                                                                     | 要帶進產品？ |
| -------------------- | ------------------------------------------------------------------------ | ------------ |
| `css/tokens.css`     | 所有設計 token（`--kiosk-*` CSS 變數）：色彩、字級、間距、格線座標、動效 | **是**       |
| `css/components.css` | 元件樣式（`kv-*` class）與格線位置 class（`kv-at-*`）                    | **是**       |
| `index.html`         | 樣式指南：把 token 與所有元件狀態渲染出來給你對照                        | 否（文件）   |
| `screens.html`       | 畫面清單：38 張畫面（四個 Mode、例外、四螢幕矩陣；2026-10-14 加 A02t 觸控版待命、E05b 預告中斷線、E10 上傳失敗），每張只用元件與版型拼成，可直接複製 markup | 否（文件）   |
| `prototype.html`     | 流程模擬器，也是**對外 demo**：四螢幕同步（Side F 前 · Kebbi · Center · Side B 後）。**v3.3 起 Center 由 film 引擎驅動**：每個 Mode 一支 film 頁載在 iframe 裡，▶ 是真正跑起來的對話，步驟鈕 = 該支的 marker；Kebbi 與 Side 靠 marker 帶的畫面編號同步。上方 Photo / Attraction / Welcome / Exit 四個主線 + 「其他」下拉（五支旅程片 + 四支補拍）；右下「觀眾說…」四句語音彩蛋疊在時間軸上。鍵盤 ← → 跳 marker、空白鍵播放 / 暫停 | 否（展示） |
| `films.html`         | **Films 總覽**（給設計師看片用）：上面一排分頁切影片、下面 iframe 直接播，數字鍵 1–9 切；新影片在 `FILMS` 陣列加一列 | 否（展示） |
| `film-welcome.html`  | **Welcome 迎賓**（給 prototype 用）：W01 待機 → W02 一組人通過（歡迎句、Grow 線）→ 回待機 → W03 被搭話固定句 → 回待機。約 15 秒。劇本在 `js/film-welcome.js` | 否（展示） |
| `film-exit.html`     | **Exit 送客**（給 prototype 用）：X01 待機 → X02 道別句 → 回待機 → X03 有人停下、QR 放大 → 回待機。約 14 秒。劇本在 `js/film-exit.js` | 否（展示） |
| `film.html`          | **一鏡到底的 Center 示範**（給錄影用）：定點對話全段——到站啟動 → 觀眾開口（逐字稿）→ 思考 → 回答 + 場次卡 + QR → 再問（特餐）→ 回答 + 特餐卡 + QR → 再問（結局）→ 純文字回答 + 開頭那三個建議問題 → 再問（預告）→ 直接進預告 → 回答 → 收尾 → 回待命，1.2× 速約 52 秒；對話畫面的底是海報紫去字 key art 壓暗加模糊（demo 連戲用，規格仍是純底）；「正在思考」不刻意出現；場次卡不顯示剩餘席次；開場就是待命畫面、不做動畫；AI 的字跟觀眾一樣逐字打出；思考時只有 AI 那一行換成狀態列，其他不動，全部在同一個 1280×800 畫面上連續發生。空白鍵開始 / 暫停、R 重頭、← → 跳場景、H 時間軸。台詞與節奏在 `js/film-attraction.js` 的 `SCRIPT` 與 `CFG` | 否（展示） |
| `film-photo.html`    | **拍照全段的一鏡到底示範**（給錄影用）：「嗨！要拍照，還是想問電影的事？」靜態開場 → 觀眾說「可以幫我拍嗎」→ 站位（鏡頭亮起、外框與取景框依序進場、框變綠）→ 倒數 3·2·1 → 白閃 → 拍好了 → 拍立得吐出顯影 → 整張相紙飛進預覽頁 + QR → 再問場次 → 回答 + 場次卡 + QR → 收尾 → 回開場畫面，1.2× 速約 37 秒。規則同 film.html | 否（展示） |
| `film-silence.html`  | **旅程片 1 · 沉默與結束**（給設計 / 工程 / PM 確認分支用）：問場次 → 回答 → 說「謝謝」→ A07 謝謝卡 → 回待命 → 第二組問特餐 → 回答後沉默（規格 30s，影片縮 6s）→ E04「還在嗎」頂列倒數 10 秒 + 底部「結束對話 / 繼續聊」→ 倒數完回待命。E04 時卡片與 QR 留著，只換頂列與底部那一格。沒有預告場景。劇本在 `js/film-silence.js`，marker 標畫面編號 | 否（展示） |
| `film-touch.html`    | **旅程片 2 · 聽不清、聽不懂、退到觸控**：辨識信心低不確認、直接用最可能的解讀回答（E01 只留給拍照倒數、播預告前）→ 說到一半被打斷糾正（E02：停嘴、沒說完的字褪色）→ 改答特餐 → 再聽 → E03 聽不懂給選單（1/3、2/3）→ 第 3 次 → A08 收音關、對話框收掉、只留 chips 加「點一下就好。」→ 觸控模式版型（對話框拿掉、三個 chips 橫排住進底部那格、AI 最多三行、卡片與 QR 撐滿變高的內容區；規則見 css/film.css「觸控模式版型」）→ 點「今天有什麼場次？」→ A05 → 再點「有特餐嗎？」→ A05c → A07 → 回待命。觸控示意只用 DS 的按下態。劇本在 `js/film-touch.js` | 否（展示） |
| `film-net.html`      | **旅程片 3 · 回答慢、思考列、網路不穩**：問場次 → 回答慢於門檻 1.5s 才出「Vyin 正在思考」→ 回答到、思考列消失 → 問特餐 → 思考列 → 超過網路門檻 8s → E05「網路有點不穩，我正在重新連線，請稍等一下。」+ 小字「重新連線中」、收音關、對話框與卡片收掉 → 恢復 → 接著回答特餐 → A07 → 回待命。兩個門檻是 `js/film-net.js` 開頭的常數 | 否（展示） |
| `film-photo-branch.html` | **旅程片 4 · 拍照分支**：第一組 P01b → 說要拍 → P02（新句、不對人數）→ 指令「不拍了」→ 回 P01b；第二組 P01b 說場次轉對話 → A05 → 「那幫我拍照」→ P02 → 指令「等一下」暫停 → 「好了」續 → 倒數 → 快門 → 拍立得 → P06 → 「再拍一次」→ 第二張 → P06「這是最後一張囉」（再拍提示收掉）→ 沒掃碼 15s 提醒句 → 20s 收尾 → 回 P01b；第三組「等一下」後一直沒說「好了」→ 30s 用說的問一次、不出倒數 → 再 10s 回 P01b。指令用規格的 `.kv-cmd` 指令框。劇本在 `js/film-photo-branch.js` | 否（展示） |
| `film-leave.html`    | **旅程片 5 · 被打斷、彩蛋、去迎賓倒數、角色切換**：問場次 → AI 講到一半被打斷「等等，有沒有下午的」（E02）→ 改答 → 說「比莉的魔法好酷」→ 火光彩蛋疊在畫面上、流程不中斷 → 班表通知 A09：頂列日期時間換成「3:00 後去影廳迎賓」環形倒數、說一次 → 再問特餐 → 回答（倒數一直在）→ role.switch E08「我要去另一邊了，QR 先給你。」QR 放大、「5 秒後出發」、收音關 → A01 移動中。劇本在 `js/film-leave.js` | 否（展示） |
| `film-a1-trailer.html` | **補拍片 A1 · 預告中的分支**：進預告（頂列「暫停收音」常駐）→ 觀眾講話不回應 → 觸控點畫面暫停、再點續播 → A09 倒數疊在預告上 → 影片斷線 E05（字幕位說明 + 重新連線中）→ 從斷點續播 → 人走掉 5s 淡出回待命。劇本在 `js/film-a1-trailer.js` | 否（展示） |
| `film-a2-photo-system.html` | **補拍片 A2 · 拍照中的系統事件**：P01 待命不主動說話、注視 3s 才說一句 → 停留沒說意圖 → P01b → 30s 沒回應回 P01；P01 直接說要拍跳過 P01b → 站位人走掉回 P01；10s 沒站好自動倒數 → 拍 → P06 才出 A09 倒數、才說那句 → 歸零換「5 秒後出發」+ 一句、QR 不另出 → A01 移動中。劇本在 `js/film-a2-photo-system.js` | 否（展示） |
| `film-a3-misc.html`  | **補拍片 A3 · 對話雜項**：中繼站說「我要拍照」→ 固定句引導去主視覺牆 → 要求扮演 → E07「我是影城的工作人員喔。」→ 太吵 E06（對話框抖、請靠近再說）→ 再說一次回答 → 300s 上限收尾句 → A07。劇本在 `js/film-a3-misc.js` | 否（展示） |
| `film-a4-standby.html` | **補拍片 A4 · 待命時的系統事件**：待命中收到 role.notice → 頂列倒數 + 待命句換「我 3 分鐘後要去影廳迎賓，想拍照要快喔。」→ 新的一組問場次、回答、說謝謝結束 → 回待命 → 歸零時沒對話 → 直接 A01、不出 E08；第二組 battery.low → E09 回充電。劇本在 `js/film-a4-standby.js` | 否（展示） |
| `js/film.js`         | 兩個一鏡到底頁共用的時間軸引擎（虛擬時鐘、at / during / marker、seek、HUD） | 否 |
| `js/film-attraction.js` · `js/film-photo.js` · `css/film.css` | 兩個頁各自的劇本（台詞、順序、停留時間、`CFG` 節奏）與共用外殼 | 否 |
| `tools/serve.mjs`   | 本機預覽用靜態伺服器（支援 Range，預告影片才播得動）：`node tools/serve.mjs` → http://localhost:8090/ | 否（內部） |
| `css/guide.css`      | 樣式指南本身的外殼                                                       | 否           |
| `js/guide.js`        | 樣式指南的縮放舞台、格線開關、時鐘、素材試裝                             | 否           |
| `assets/campaign/`   | 迪士尼素材（10 張圖片已進版控，預告影片 274MB 另外交付）                  | **是**       |
| `assets/side/`       | **Side 螢幕成品圖**：三張 1080×1920 JPG，播放端 1:1 放，不用寫縮放邏輯          | **是**       |
| `assets/README.md`   | 素材角色對照表                                                           | —            |
| `tools/export-side.mjs` | 我們這邊重出 `assets/side/` 用的腳本（Playwright），不是給產品的                | 否（內部）   |
| `js/moments.js`      | **Micro Moments 引擎**：十二個情境「什麼時候加 class / 設變數」的時序（§5.7）；`prototype.html` 用，接法見檔頭 | 參考（時序）  |
| `js/kebbi-script.js` | **Kebbi 行為腳本**：每個畫面幾段、每段的表情檔名、燈、手臂、脖子、說的話、秒數（§5.8） | **是**（資料） |
| `assets/kebbi/kebbi-script.csv` | 同上，匯成你們腳本格式的 CSV，可直接貼進 Kebbi 的腳本系統                      | **是**       |
| `assets/kebbi/*.mp4` | NUWA 115 支表情影片（512×300、7.4s 循環），只給 prototype 看，實機用 Kebbi 內建表情編號     | 否           |
| `tools/export-kebbi-script.mjs` | 把 `js/kebbi-script.js` 匯成 CSV 的腳本                                     | 否（內部）   |
| `demo-photo.html`    | 轉址到 `prototype.html`。v2.7 起兩頁合一，檔案留著是因為這個網址已經發出去 | 否           |
| `tools/deploy.sh`    | 部署整包到 Netlify（https://deft-druid-6c1405.netlify.app）的腳本，我們內部用            | 否（內部）   |

機器人有四個螢幕：**Center (Collibot) 1280×800**（橫式，主要互動）、**Side F / B 1080×1920**（前後各一片，32 吋面板 1920×1080 直立安裝，氛圍與素材）、**Kebbi 臉 1024×600**（只有表情，`.kv-face` 是示意、實際由 Kebbi SDK 控制）。這包所有數值都以 Center 的
1280×800 為基準。

## 2. 怎麼嵌入

**看規格**：在資料夾根目錄起一個靜態伺服器，開 `index.html`。

```bash
python3 -m http.server 8090
# http://localhost:8090/
```

不要用 `file://` 直接雙擊，Google Fonts 與部分樣式在 `file://` 下行為不一致。

**給別人看**：`prototype.html`（開著「說明」列），線上版 https://deft-druid-6c1405.netlify.app/prototype.html（每次改版一起部署；舊連結 `demo-photo.html` 會轉過來）。

**看流程**：開 `prototype.html`，底部切 Mode、按步驟或鍵盤 ← → 逐步走。預設是四螢幕（Side F、Kebbi、Center、Side B 同步；前後兩片攤平並排只是為了同時看），右下可切成只看 Center。

**用在產品**：只需要 `css/tokens.css` 與 `css/components.css` 兩個檔案加上字型連結。
所有資源都是相對路徑，整個資料夾放在任何子目錄都能運作。

```html
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link
  href="https://fonts.googleapis.com/css2?family=Noto+Sans+TC:wght@400;500;700;900&family=Unbounded:wght@600;800&family=IBM+Plex+Mono:wght@400;500;600&display=swap"
  rel="stylesheet"
/>
<link rel="stylesheet" href="css/tokens.css" />
<link rel="stylesheet" href="css/components.css" />

<div class="kv-screen" data-chrome="full" data-mic="full">
  <div class="kv-topbar">…</div>
  <div class="kv-transcript">…</div>
  <div class="kv-safe">
    <div class="kv-card">…</div>
    <div class="kv-qr kv-qr--active">…</div>
  </div>
  <div class="kv-pill">…</div>
</div>
```

如果你們的環境是 React / Vue / Android WebView / Unity UI，把 `tokens.css` 的變數對應成你們的
theme，再照 `components.css` 重建元件即可。每個元件的完整 markup 都在 `index.html` 裡，
直接檢視原始碼或用 DevTools 複製。

### 命名規則

- `--kiosk-*`：所有 token。
- `.kv-block` / `.kv-block__element` / `.kv-block--modifier`：BEM，只管長相。
- `.kv-at-*`：在 1280×800 格線上的位置，只在 `.kv-screen` 裡用。
- `.kv-screen--dialog / --media / --cover / --standby`：四種畫面骨架，直接子元件依 class 自動定位，
  用了版型就不需要 `.kv-at-*`。狀態修飾 `--one-line`、`--countdown`、`--camera`、`--cover-strong`。
- `.kv-grow-ring`、`.kv-dot`、`.kv-eyebrow`、`.kv-art`、`.kv-hero`：原語，多個元件共用。改 Grow 外框或光點只動這裡。
- `.kv-ph`：素材佔位，正式素材進來後移除。
- `.kv-guide` / `.kv-guides`：開發用格線疊層，正式版不輸出。

### 互動規則

**觸控**：可以按的東西分兩種——

- **Chips**（`.kv-chips` > `.kv-chip`）：發想型建議，堆在左側 safe area，例如「今天有什麼場次？」。使用者可以點，也可以直接說。
- **底部動作列**（`.kv-actions`）：決策型是/否，跟語音對話框 `.kv-pill` 同一格（bottom 44px）。主要選項在最右、用 `.kv-btn` CTA 樣式（Grow 外框 + 光暈），一屏一個。次要選項用 `.kv-actions__btn`。

Safe area 的卡片永遠不可按。按下：填色升一階 + 縮 97%、120ms。

**對話畫面的底（2026-10-14 定）**：不是純底。首頁（A02 / P01b）在輪播，觀眾一開口進對話，底就是**進對話那一刻的那張**，凍住不再換（對話中會動的東西會干擾讀卡片），壓暗 + 模糊 + 遮罩由 `--dialog` 自動套（`tokens.css` 的 `--kiosk-dialog-*`）；回首頁才繼續輪播。工程：進 dialog 時把當下 active 的 slide 複製進 dialog 的 `.kv-art` 即可。

**底部那格永遠是「你怎麼跟我說話」**（設計師 2026-10-14 定）：語音模式放對話框 `.kv-pill`，決策時放動作列 `.kv-actions`，
**純觸控模式放三個 chips 橫排**（A08 之後、連續 3 組退觸控後的待命版）。退到觸控就不留一個不會回應的對話框。

**版型規則（auto layout，2026-10-14 定；正式變體待搬進 `components.css`，目前先在 `css/film.css` 的「觸控模式版型」）**：
內容區高 = 800 − 頂列 − AI 區（行數 × 72 + 32）− 底部格（依內容：對話框 84 / chips 排 68 / 無 0，底距 44，間距 32）。
AI 1 / 2 / 3 行 × 有底部格 → 388 / 316 / 244，無 → 504 / 432 / 360；觸控模式（chips 排 68）2 行 360、3 行 288。
三行 AI + 對話框只剩 244 放不下 268 的卡片，所以三行只用在觸控模式或純文字回答。觸控模式卡片與 QR 撐滿內容區（QR 碼 = 卡高 − 132）。

### 介面層級（chrome levels）

在 `.kv-screen` 上設 `data-chrome` 和 `data-mic`，CSS 自動控制顯示/隱藏，200ms opacity transition。

| 層級    | `data-chrome` | 留                                         | 拿掉                                   | 狀態                                                   |
| ------- | ------------- | ------------------------------------------ | -------------------------------------- | ------------------------------------------------------ |
| FULL    | `full`        | logo、收音、日期時間、AI 區、safe area、對話框 | —                                      | 對話畫面、Stop Idle、Review、Touch Panel、所有例外狀態 |
| AMBIENT | `ambient`     | logo、收音、AI 字幕                        | 日期時間、對話框                       | Moving、Welcome / Exit Standby、Trailer                |
| FOCUS   | `focus`       | AI 一句指示、任務內容                       | logo、收音、時間、對話框               | Photo Position / Countdown / Capture / Success         |

收音狀態：`data-mic="full|off|cmd|dot"`，控制光點顏色和光暈。

FOCUS 時收音狀態由 Kebbi 光條顯示；光條不可用時右上角放 `.kv-mic--dot`（只有光點）。
任何例外狀態都會打斷 FOCUS 回到 FULL。細節見 `index.html` 的 00 Chrome。

### 值的分級

`tokens.css` 的註解有三種標記：

- 無標記：來自設計 README，是規格。
- `derived`：README 沒寫、從參考稿取比例對齊尺標而來。
- `proposal`：提案，定案前可能會調（目前只有 Welcome / Exit 大標與側螢幕字級）。

## 3. 外部依賴

| 依賴          | 來源                                                                   | 版本／備註                                                                         |
| ------------- | ---------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Noto Sans TC  | Google Fonts                                                           | 400 / 500 / 700 / 900。UI 與中文。                                                 |
| Unbounded     | Google Fonts                                                           | 600 / 800。Display 與數字。**暫代字體**，正式 Vyin AI wordmark 字體待定。          |
| IBM Plex Mono | Google Fonts                                                           | 400 / 500 / 600。只用在佔位圖與格線標籤，不是產品 UI，正式版可不載。               |
| 第三方 JS     | 無                                                                     | `guide.js` 只服務樣式指南，無任何函式庫。                                          |
| 建置工具      | 無                                                                     | 純 CSS，沒有 Sass / PostCSS / bundler。                                            |

kiosk 若無法連外網，請把三個字型自行下載後改用 `@font-face` 本地載入，token 裡的
`--kiosk-font-*` 不用改。

## 4. 已知限制

- **瀏覽器**：以 Chromium 110+ 為目標（Electron / Android WebView / Chrome kiosk）。用到
  `oklch()`、`mask-composite`、`conic-gradient`、CSS 巢狀變數 `calc()`。Safari 15.4+ 可，
  不支援 IE 與舊版 Edge。
- **解析度**：一切以 1280×800 絕對像素書寫，**不是 RWD**。實機以 1280×800 全螢幕呈現，
  `.kv-screen` 直接放在 body 裡即可。四個螢幕的尺寸都在 `tokens.css` 開頭的 Canvas 區，若硬體再變只改那裡。
- **Kebbi 表情**：`.kv-face` 只示意「哪個畫面對應哪個表情」（八種：idle / listen / think / speak / countdown / happy / sorry / sleep），不是要在 Kebbi 上重畫這張臉。實際能切哪些表情、速度、LED 光條，待實機 SDK 確認。
- **Side 螢幕是前後、不是左右**。Side F（前）跟 Center 同一面，配合 Center：Photo / Attraction 放素材牆（`.kv-side-wall`），Welcome / Exit 放整張有字海報 A。兩片 Side 都是整張素材，不疊任何東西。Side B（後）在機器人背面，永遠整張海報 B，不隨 Mode 變。兩片都不放要讀的文字、QR 或指令。分工表見 `screens.html` 的 M1–M4 區。面板 1920×1080 直立安裝，請以 1080×1920 直式輸出，不要用橫式解析度排版。
- **有字與去字素材怎麼分**：Side B（後）用有字海報，片名與上映日就是訊息。Center 的 cover 輪播與 Welcome / Exit standby 底用去字 key art（`keyart-*-textless.jpg`），字只在 Center 由我們的 UI 提供；Side 一律整張有字海報。不要在去字圖上用 UI 字型重打片名；沒有官方片名 logo 圖層。Welcome / Exit 的 standby 畫面（W01–W02、X01–X03）底是去字門版：放一個 `.kv-art` 進 `.kv-screen--standby`，焦點、縮放、壓暗、暗角會自動套 `tokens.css` 的 `--kiosk-keyart-*`，不要寫 inline style。

## 5. JS Integration Guide

CSS 已寫好所有狀態的視覺切換，工程師只需要在 JS 裡操作以下 hook。

### 5.1 畫面狀態（必接）

在 `.kv-screen` 元素上 `setAttribute`，CSS 自動處理 200ms opacity transition。

| Hook | 值 | 觸發時機 | 效果 |
|------|------|---------|------|
| `data-chrome` | `full` | 對話畫面、Stop Idle、所有例外狀態 | 顯示全部 UI：logo、收音、日期時間、AI 區、safe area、對話框 |
| `data-chrome` | `ambient` | Moving、Welcome/Exit Standby、Trailer | 只留 logo、收音、AI 字幕 |
| `data-chrome` | `focus` | Photo Position / Countdown / Capture / Success | 只留 AI 一句指示 + 任務內容 |
| `data-mic` | `full` | 可以說話（預設） | 綠色光點 + 光暈 + 「可以跟我說話」 |
| `data-mic` | `off` | 暫停收音（Touch Panel、網路不穩） | 灰色光點 + 「暫停收音」 |
| `data-mic` | `cmd` | 只接受指令（拍照流程中） | 綠色光點 + 「可以喊停」 |
| `data-mic` | `dot` | FOCUS 時的最小收音提示 | 只有右上角光點，無文字 |

```js
// 範例：進入 Listening 狀態
screen.setAttribute('data-chrome', 'full');
screen.setAttribute('data-mic', 'full');
```

### 5.2 AI 語音同步

| 元件 | 操作 | 說明 |
|------|------|------|
| **AI 逐字打出**（2026-10-13 起，取代 karaoke 逐字亮） | 每個字一個 span，說到才 `visibility: visible`；沒說到的留位置、行寬不跳（film.css 的 `.film-k` / `.is-said`） | 跟觀眾的逐字稿同一種節奏；被打斷時沒說完的字褪成 border 色（`.kv-transcript__interrupted` 同值）。原 karaoke（`__unspoken` 縮窄）保留在 components.css 但不再是預設 |
| **聆聽波形** | `.kv-wave__bar` 的 `height` 設為 `8px`–`36px` | 目前 CSS 有假動畫；接上真實音量後改為 JS 控制各 bar 高度，移除 `animation` |
| **聆聽逐字稿** | `.kv-pill__live` 的 `textContent` | 即時更新 STT 辨識結果，游標 `.kv-caret` 自動閃爍 |
| **Kebbi 點頭** | `.kv-face` 加 `data-gesture="nod"`，700ms 後移除 | 迎賓 / 道別觸發、掃碼完成時用；實機換成 Kebbi SDK 的點頭動作 |
| **觸發句與 Grow 線** | W02 / X02 的 `--active`、`.kv-line--wide` 加上去時自動播一次 | 亮起 200ms、線長出來 300ms；加 class 即觸發 |
| **文字翻頁（超過兩行）** | AI 回答超過兩行時，每兩行一頁，TTS 唸到第三行時直接換成下兩行（`textContent` 直接替換，不加動畫） | 每頁內逐字打出照常；翻頁時機由 TTS 進度決定 |

### 5.3 倒數計時

```js
// .kv-countdown 元素
countdown.style.setProperty('--kv-progress', pct);   // 0–100，環形 ring 進度
countdown.querySelector('.kv-countdown__num').textContent = sec;  // 秒數
```

適用畫面：E04（10s 結束對話）、E08（角色切換 5s）。

### 5.4 亮暗底適應

背景圖較亮時，日期時間需切深色。

```js
// 亮色底圖
screen.classList.add('kv-screen--bg-light');
// 暗色底圖（預設）
screen.classList.remove('kv-screen--bg-light');
```

劇照輪播時依每張圖的 `data-bg="light"` 屬性自動切換（已在 `guide.js` 示範）。

### 5.5 素材替換（一次性）

| 佔位元素 | 替換方式 |
|---------|---------|
| `.kv-qr__code` | 以 `<img>` 或 `<canvas>` 取代，放入動態產生的 QR 圖 |
| `.kv-camera` | 接上 WebRTC `getUserMedia` 的 `<video>` 即時預覽 |
| `.kv-photo` 內的 `<img>` | 拍照完成後將 canvas 截圖寫入 `src` |
| A06 Trailer `.kv-ph` | 換成 `<video src="assets/campaign/trailer-hexed-1080p.mp4">`（274MB，另外交付） |

### 5.5b 流程與事件（v2.1，照 milo 2026-10-01「情境事件規格」）

畫面編號對應規格的階段；事件名稱照規格，App 收到就切 `data-screen`：

| 規格階段 | 畫面 | 進入事件 | 離開 |
|---|---|---|---|
| 攝影師 待命 | P01 | role.ready | sense.gaze ≥ 3s 才說一句（同一組一次）；直接說「可以幫我拍嗎」→ P02（跳過 P01b，2026-10-14 裁定 3）；sense.dwell / sense.wave 沒說意圖 → P01b；P01b 30s → P01 |
| 啟動與確認意圖 | P01b | session.start | intent.photo / ui.touch「一起拍一張」→ P02（取像告知是 CTA 下方小字，法務 2026-10-14）；問電影 → A05 直接回答 |
| 取像告知 | P01c | — | consent.result 同意 → P02；拒絕 → 只給預告 QR（A05 的 QR 卡）→ P09（v3.0 併入 P01b，改為 CTA 下方小字「點擊拍照即同意」，不再是獨立畫面；法務 2026-10-14：一行小字即可、不需要同意按鈕，P06 預覽頁底部也放一行） |
| 人數與站位 → 倒數 → 快門 → 拍好 → 拍立得 | P02 → P03 → P04 → P05 → P05b | photo.framed → photo.shot | 不可中斷段 |
| 預覽與重拍 + 給 QR（合成一張） | P06 | photo.accept / qr.show | qr.scan 或 20s → P09（前 5s 說一句、不出倒數）；「再拍一次」→ P02（最多 2 次，第二張先說「最後一張」）；photo.upload.fail → E10；置底一行取像告知小字 |
| 收尾 | P09 / A07 | — | 2s → 待命 |
| 定點 啟動 → 回答（給 QR 合在回答頁） | A02 → A03 →（A04 只在 > 1.5s）→ A05 / A05c | intent.showtime / combo / trailer；asr.lowconf 不確認、直接回答最可能解讀；qr.show 跟卡片一起進場 | 單次 ≤ 300s（到了說收尾句 → A07）；說「謝謝」/ 掃碼 / 30s E04 → A07；3 次 unknown → A08（觸控版型）；細則見 §5.5c |
| 巡邏 移動播送 | A01 | nav.patrol | nav.arrived → A02 |
| 預告收單 | A09（任何畫面的頂列日期時間換成倒數「m:ss 後去影廳迎賓」，Kebbi 說一次） | role.notice | 不接新的一組；進行中的做完或 E08 收尾 → 出發 |
| 角色切換 | E08 | role.switch | 5s → A01 過場 → 新角色待命 |
| 迎賓 | W01 / W02 / W03 | nav.arrived / sense.pass / voice.heard | 只固定句，不啟動對話 |
| 送客 | X01 / X02 / X03 | sense.pass / sense.dwell | qr.show(farewell)；散場後 3 分 → 結束 |
| 劇透 / 扮演 | E07 | intent.spoiler / roleplay | 留在當下階段 |
| 回充電 | E09（Center 同 Moving 輪播 + 「去充電」膠囊，不顯示電量；Kebbi 打哈欠、說一次、疲累） | battery.low → nav.dock | 到充電點 → 充電點待命版 |

#### 5.5c 門檻、計時與分支規則（2026-10-14 用 11 支影片定下來的；數字是設計值，實機測後再調）

| 事件 / 計時 | 值 | 規則 |
|---|---|---|
| asr.lowconf（辨識信心低） | — | **查資訊的問題不確認**：直接用最可能的解讀回答、把解讀放進答句；猜錯由觀眾打斷糾正（E02）。E01 確認框只用在猜錯代價高的動作前：開始拍照倒數、播預告 |
| think.threshold | 1.5s | 聽完 1.5s 內開口不出思考列，超過才出「Vyin 正在思考」（A04） |
| net.threshold | 8s | 思考超過 8s 沒回應 → E05 網路不穩（收音關、對話框與卡片收掉）；恢復後直接接回答，不重問 |
| E02 被打斷 | — | TTS 停、沒說完的字褪成 border 色留在畫面、對話框直接進聆聽；卡片留著，新回答換卡 |
| E04 還在嗎 | 30s → 10s | AI 說完 30s 沒回應問一次、頂列倒數 10s，卡片與 QR 留著；倒數完回待命不過謝謝卡。只用在對話，P06 不用 |
| intent.unknown × 3 | 3 | E03 兩次給選單，第三次 → A08 收音關、只留觸控（E01 的低信心不算） |
| mic.restore | session.end | 退到觸控後，這一組結束回待命就恢復收音、計數歸零 |
| touch.lock | 連續 3 組 → 10 分 | 連續 3 組都退到觸控，待命直接換觸控版 10 分鐘再試語音 |
| photo.pause | 30s → 10s | 「等一下」起算 30s 沒回應，AI 用說的問一次「還要拍嗎？…」、**不出倒數**；再 10s 回去（第一張沒拍回 P01b；再拍時暫停的回 P06）。再說「等一下」重計 |
| sense.leave | 5s | 站位 / 暫停中人離開取景範圍 5s 回去；預告中人離開 5s 淡出回待命 |
| photo.stand | 10s | 站位 10s 沒站好自動倒數；口白不對人數 |
| photo.retake | 2 | 第二張拍完先說「這是最後一張囉」、再拍提示收掉；語音再說只回同一句不動作 |
| qr.timeout（P06） | 20s | 沒掃碼 20s 直接收尾，前 5s 說一句「照片我先放在 QR 裡，隨時可以掃」，不出倒數 |
| photo.upload.fail（E10） | 重試 2 次 | P06 格子換重試狀態 + CTA「我再試一次」；兩次失敗 →「這次照片沒存到，我們再拍一張好嗎」回 P02，不算進重拍次數 |
| session.limit | 300s | 到了說「我們聊了一陣子了，東西都在這個 QR 裡，先掃起來吧。」→ A07 |
| role.notice（A09） | 前 3 分 | 任何畫面頂列日期時間換倒數；FOCUS 段（P02–P05b）不出、到 P06 才出才說；待命中**接新的一組但告知**（待命句換「我 m 分鐘後要去影廳，想拍照要快喔」） |
| role.switch（E08） | 歸零 → 5s | 歸零時：對話還在 → 當下畫面倒數換「5 秒後出發」+ 一句、畫面上沒 QR 才換成 QR 卡；對話已結束 → 直接出發不出 E08；在不可中斷段 → 做完再 E08 |
| trailer（A06） | — | 預告中暫停收音、chip 常駐；觀眾講話不回應；暫停 / 停止只留觸控；斷線凍住 + 說明，恢復從斷點續播，斷超過 20s 放棄預告直接給 QR |
| 中繼站說要拍 | — | 不拍，固定句「合照在主視覺牆那邊，我等等會過去，先幫你查場次？」 |

#### 5.5d 台詞表（2026-10-14 整理；「固定」= 狀態機播的句子，設計定稿、PM / Brain 確認；「示意」= Brain 的 LLM 生成，這裡只是例句）

**生成式回答的格式規範（給 Brain）**：最多兩行、觸控模式最多三行，每行約 20 字；數字、場次、廳別這類資料進卡片，句子只講結論；固定說法統一（「QR 給你」「券在 QR 裡」）；猜測解讀時把解讀放進句子，觀眾才聽得出猜錯；不劇透、不扮演、不提別家品牌（E07 與 §5.7）。

| 畫面 · 觸發 | 句子 | 類型 | 狀態 |
|---|---|---|---|
| A02 待命 | 想看《歡迎光臨魔法秘境》嗎？／我可以幫你查場次。 | 固定 | 規格既有 |
| A02 觸控版待命（連續 3 組退觸控） | 想看《歡迎光臨魔法秘境》嗎？／點下面的，我幫你查。 | 固定 | **新句待定稿** |
| A02 待命 · role.notice 中 | 我 3 分鐘後要去影廳迎賓，想拍照要快喔。 | 固定 | **新句待定稿**（A09 原句改第一人稱語序） |
| A09 通知那一刻（任何畫面） | 3 分鐘後我要去影廳迎賓，想拍照要快喔。 | 固定 | 規格既有 |
| A05 場次 | 19:10 這場還有位子，21:30 也還有。票和特餐組合我用 QR 給你。 | 示意 | — |
| A05 信心低、直接回答解讀 | 今天晚上的場次有 19:10 和 21:30，票和特餐組合我用 QR 給你。 | 示意 | — |
| A05 被打斷後改答 | 下午有 16:40 這場，票我用 QR 給你。 | 示意 | — |
| A05c 特餐 | 今天有本檔特餐組合，券在 QR 裡。 | 示意 | — |
| A05 觸控模式第三行提示 | 還想問什麼，點下面的。 | 固定 | **新句待定稿** |
| A06 進預告 | 我放一段預告給你看。 | 固定 | 規格既有 |
| A06 播完 | 喜歡嗎？場次和特餐組合都在這個 QR 裡。 | 示意 | — |
| A07 收尾 | 祝觀影愉快！ | 固定 | 規格既有 |
| A08 退觸控 | 我可以幫你查場次、特餐，或放預告。／點一下就好。 | 固定 | 規格既有 |
| 中繼站說要拍 | 合照在主視覺牆那邊，我等等會過去，先幫你查場次？ | 固定 | **新句待定稿** |
| 彩蛋只是彩蛋（比莉 / 魔法） | 對吧！預告裡還有更厲害的，想看可以跟我說。 | 示意 | — |
| 單次 300s 到 | 我們聊了一陣子了，東西都在這個 QR 裡，先掃起來吧。 | 固定 | **新句待定稿** |
| E01 高代價動作前確認 | 你是說「…」嗎？／不是，我重說一次／是，就是這個 | 固定 | 規格既有（只在拍照倒數、播預告前） |
| E03 聽不懂 | 我可以幫你查場次、特餐，或放預告。 | 固定 | 規格既有 |
| E04 還在嗎 | 還在嗎？沒有的話，我就先回到首頁囉。 | 固定 | 規格既有 |
| E05 網路不穩 | 網路有點不穩，我正在重新連線，請稍等一下。／重新連線中 | 固定 | 規格既有 |
| E06 太吵 | 這裡有點吵，可以靠近一點，再說一次嗎？ | 固定 | 規格既有 |
| E07 劇透 / 扮演 | 結局不能講，預告裡有的我可以播。／我是影城的工作人員喔。 | 固定 | 規格既有 |
| E08 角色切換（畫面上沒 QR） | 我要去另一邊了，QR 先給你。 | 固定 | 規格既有 |
| E08 在 P06（QR 已在畫面） | 我得走了，照片在 QR 裡。 | 固定 | **新句待定稿** |
| E09 回充電 | 我去充個電／現在暫時不服務，等等回來。 | 固定 | 規格既有 |
| E10 上傳失敗 | 照片還在傳，再等我一下。／（兩次失敗）這次照片沒存到，我們再拍一張好嗎 | 固定 | **新句待定稿** |
| P01 待命 · 注視 3s | 要不要跟主視覺牆拍一張？ | 固定 | 規格既有 |
| P01b 確認意圖 | 嗨！要拍照，還是想問電影的事？ | 固定 | 規格既有 |
| P02 站位 | 請站到牆前面，靠近一點，我會等大家都進框。／提示：說「等一下」可以暫停 | 固定 | **新句待定稿**（不對人數） |
| P02 暫停 | 好，我等你。準備好跟我說「好了」。／提示：說「好了」繼續 | 固定 | **新句待定稿** |
| P02 暫停 30s 問一次 | 還要拍嗎？說「好了」我就倒數，不然我先回到首頁囉。／提示：說「好了」繼續 · 說「不拍了」結束 | 固定 | **新句待定稿** |
| P02 第二張站位 | 好，再來一張。站好我就倒數。 | 固定 | **新句待定稿** |
| P03 倒數 | 看鏡頭！ | 固定 | 規格既有 |
| P05 拍到了 | 拍好了！ | 固定 | 規格既有 |
| P06 預覽 | 拍好了！掃 QR 領取照片，裡面還有預售票和特餐組合。／提示：想重拍，說「再拍一次」 | 固定 | 規格既有 |
| P06 第二張 | 這是最後一張囉，掃 QR 領取照片。 | 固定 | **新句待定稿** |
| P06 逾時前 5s | 照片我先放在 QR 裡，隨時可以掃。 | 固定 | **新句待定稿** |
| P09 收尾 | 謝謝，祝觀影愉快！ | 固定 | 規格既有 |
| W02 迎賓 | 歡迎光臨魔法秘境 | 固定 | 規格既有 |
| W03 被搭話 | 電影快開始囉，散場後再來主視覺牆找我拍照 | 固定 | 規格既有 |
| X02 送客 | 謝謝觀賞！彩蛋 QR 在這裡。 | 固定 | 規格既有 |
| X03 有人停下 | 想合照的話，主視覺牆那邊見。 | 固定 | 規格既有 |

新句共 13 句待設計師定稿；定稿後這張表就是 `js/kebbi-script.js` 與 CSV 的來源。

### 5.6 Side 與 Kebbi 同步

**Side 大部分時候直接放圖，Exit mode 例外。** `assets/side/` 有直式 1080×1920 的 JPG，由設計系統渲染、裁好：

| 檔案 | 放哪裡 | 什麼時候 |
|------|--------|---------|
| `side-f-wall-1080x1920.jpg` | Side F（前） | Photo / Attraction / 例外狀態 |
| `side-poster-a-1080x1920.jpg` | Side F（前） | Welcome |
| `side-poster-b-1080x1920.jpg` | Side B（後） | Welcome / Photo / Attraction / 例外狀態 |
| `side-f-photo-stand-1080x1920.jpg` | Side F（前） | 拍照 P02 站位 |
| `side-f-photo-look-1080x1920.jpg` | Side F（前） | 拍照 P03 倒數（提示看鏡頭，數字在 Center / Kebbi） |
| `side-f-photo-flash-1080x1920.jpg` | Side F（前） | 拍照 P04 快門瞬間（白閃補光，約 450ms） |
| `side-f-photo-stand-filled-1080x1920.jpg` | Side F（前） | 拍照 P02 人站進框之後（人形填滿、「很好」） |

播放端請設成 1:1 或 fill，**不要再套 fit / contain**，否則會再出現黑邊（圖已經是螢幕尺寸）。
檔案是直式 1080×1920（已確認）。之後 Side 內容要換，也是我們重出圖、你們換檔，不需要改程式。

Side 不逐步變化、只跟 Mode：Photo / Attraction 時 Side F（前）是素材牆、Welcome 時是整張有字海報 A；Side B（後）除 Exit 外都是有字海報 B。
唯一例外是拍照 P02–P04：Side F 跟著 Center 的步驟切成站位 / 看鏡頭 / 白閃三張圖，P05 起回素材牆。`prototype.html` 的 ▶ 可以把拍照整段自動播一次看時序。

#### Exit mode 的 Side：延伸邀請（動態 HTML）

Exit mode 時 Side F 和 Side B 都改為**動態 HTML 畫面**（`.kv-side-exit`），用無字 key art 滿版 + 半透明遮罩 + QR 卡（Grow 外框），引導觀眾掃碼探索幕後花絮等延伸內容。

- Side F：QR 靠上（`kv-side-exit--top`），搭配門版 key art
- Side B：QR 靠下（`kv-side-exit--bottom`），搭配漂浮版 key art
- 文案：「魔法還沒結束」+ QR 卡標題「掃碼探索更多幕後花絮」
- X01 開始就切上去，一路留到離開 Exit mode

markup 見 `screens.html` 的 Exit 區段或 `prototype.html`。

**工程師備註：如果讓 Side 播放端接 HTML 的成本比較高，可以退回純 JPG 版本** — Welcome 的 `side-poster-a` / `side-poster-b` 在 Exit 也能用，只是少了 QR 導流。

#### 預告播放時的 Side（A06 Trailer）

A06 播預告時 Side F / B **同步播放預告影片**（`.kv-side-trailer`）。直式螢幕裡放橫式 16:9 影片垂直置中，下方黑邊區放片名與進度條。Side 不可觸控、沒有按鈕，暫停/停止跟著 Center 走。

Center 的暫停操作：**點擊畫面任意處 = 暫停**（出現 Grow 圓形播放鈕覆蓋 `.kv-media-pause`），再點繼續。「結束預告」按鈕（`.kv-media-btn`）在右下角。

Kebbi 跟每一步走。`prototype.html` 的 `FLOWS` 表每一步都有 `kebbi` 欄位，就是要送給 Kebbi SDK 的表情；若用 `.kv-face` 示意：

```js
face.setAttribute('data-emotion', 'listen'); // idle | listen | think | speak | countdown | happy | sorry | sleep
face.setAttribute('data-mic', 'full');       // 跟 Center 的 data-mic 同值，驅動臉下方光條
face.querySelector('.kv-face__digit').textContent = '3'; // 只有 countdown 用到
```

### 5.7 Micro Moments

十個情境的視覺都在 CSS 裡，JS 只負責「什麼時候加 class / 設變數」。Kebbi 那半是示意，實機換成 Kebbi SDK 的表情與動作；Center / Side 那半照做。時序在 `js/moments.js`（`window.createMoments(ctx)`，接法見檔頭）。`prototype.html` 按 ▶ 看流程內的，右下「🎤 觀眾說…」下拉選一句看語音觸發的（會浮出聽到的那句，再播 Center 與 Kebbi 的反應）。

| 情境 | 做什麼 | 時機 |
|------|--------|------|
| 無人互動 | `.kv-face` 與 `.kv-screen` 設 `--kv-gx / --kv-gy`（px）；cover 畫面加 `.kv-screen--gaze` 圖會反向微移；久了 Kebbi `data-emotion="sleep"` + `.kv-screen--asleep` | Idle 每 2–3 秒換一個視線；約 15 秒無人進 sleep |
| 使用者靠近 | `--kv-gx` 轉向人的方向、`data-gesture="nod"`；招呼句加 `.kv-transcript--from-left` 或 `--from-right` | 人臉偵測到方位時 |
| 站進框（P02） | Side F 換成 `side-f-photo-stand-filled` 那張圖；Kebbi `.kv-face--aperture` | 人站進取景框時 |
| 拍照完成 | P05 0.9s → P05b（`.kv-polaroid` 自動吐出、顯影，Kebbi `.kv-face--star` 1s）→ 3.6s 後 P06 加 `.kv-screen--arrive`，照片用 FLIP：量 P05b 相紙照片的 rect 與 P06 照片格的 rect，先設 `transform: translate(dx, dy) scale(k)` 再清掉，CSS 會以 600ms 飛過去 | 拍完 |
| 提到《魔法秘境》 | Kebbi `001_surprise02` 0.9s → `001_j3_happy71` 笑開變星星眼 + 右手側張介紹海報 + 點頭 2.4s → `001_j2_theads020` 星星眼腮紅撐到 10s，燈紫白慢閃（示意元件 `.kv-face--gold` 1s）；Center 加 `.kv-screen--sweep`：窄暖光帶從右邊畫面外斜掃到左邊畫面外 2.4s 慢進快中慢出（z 3，不蓋文字）、素材亮度抬一下、輪播切到海報並從 1.06 推回 1（`--enter`）、標題金光一閃（`.kv-transcript--lit`）、chips 逐顆退場換句再進場亮金邊（`--out / --in / --lit`）；Side F 換成海報 A 那張圖 10s | 語意辨識到片名：歡迎光臨魔法秘境、魔法秘境、魔法秘境那部；在對話脈絡裡的「這部片 / 那部迪士尼新片」由 NLU 判 |
| 提到比莉 / 魔法（彩蛋） | Center 丟一個 `.kv-embers`（裡面 24 顆 `.kv-ember`，各自的 `--x / --size / --dur / --delay / --drift / --op` 見 `js/moments.js` 的 `magic`），8 秒後加 `--out` 再移除；Kebbi `001_surprise` 0.7s → `001_j3_happy120` 星星眼 + 雙手側張拍兩下 2.5s → `001_j3_yell89` 興奮大叫 + 點頭兩下 2.2s → `001_j3_happy100` 2.6s，燈粉紫快閃（見 `kebbi-script.js` 的 `magic`） | 第一版（設計師 2026-10-06 定，台灣譯名）：**角色** 比莉、Billie；**她做的事** 施法、施魔法、唸咒、咒語、魔咒、法術、魔力、變魔法、變個魔法、表演魔法、你會魔法嗎、召喚、變身、飛起來；**世界觀** 女巫、巫師、巫術、秘境。「女主角」三個字本身不觸發；「火」單字、火焰、火球不觸發（跟失火、火警撞字）；一般高興詞（太棒了、好酷）不觸發 |
| 提到「復仇者聯盟」或英雄名（彩蛋） | Center 丟一個 `.kv-hud`（兩圈震波從中心擴出（14px / 8px 線）、四周 12px 粗邊框橘光呼吸兩次；光暈 40px）+ `.kv-screen--hero` 素材 punch 一下，3.2s 淡出移除；只用 Grow 5 一色，不出現任何漫威標誌、名稱、配色；Kebbi `001_tts_disgust` 鎖定 1.6s → `001_tts_angera` 戰鬥臉 + 雙手側張拍兩下 2.6s → `001_tts_contempt` 嘴角一撇 + 點頭 2.4s，燈紅白快閃；酷、不可愛，不用星星眼腮紅。不講話、不提角色名 | 第一版（設計師 2026-10-06 定，先做最常見、台灣譯名）：復仇者聯盟、漫威、鋼鐵人、美國隊長、雷神索爾、索爾、浩克、黑寡婦、蜘蛛人、奇異博士、黑豹。之後看 log 再擴 |
| 提到 Disney | Kebbi `001_j1_happy89` 大眼 → 星星眼 → 笑瞇 + 右手側邊揮 2.4s，燈七色跑 → `001_idlenod` 星星眼 + 點頭兩下 2.6s，燈粉白（示意元件 `.kv-face--star .kv-face--led-run` 1.2s）；Center 丟 70 顆 `.kv-spark` 光塵（2–10px 微粒，固定位置快閃、微微往上飄：`--size / --dur / --delay / --n / --dx`，約 5s 後移除） | 語意辨識到 Disney / 迪士尼 / 迪士尼動畫 |
| 思考中（A04） | Kebbi `.kv-face--sync`，跟 Center 思考光點同拍（`--kiosk-dur-pulse`） | 思考期間 |
| 聽不清楚（E01） | Kebbi `.kv-face--tilt` 1.4s；問句 `.kv-transcript--tilt` | 進 E01 |
| 太吵（E06） | Kebbi `.kv-face--squint` 1.2s；對話框 `.kv-pill--shake` | 進 E06 |
| Moving（A01） | Kebbi `--kv-gx` 看向前進方向；到站時路線點換 `--done / --next`、Kebbi 回正 + `nod` | 移動中 / 到站 |

不做：掃碼完成（系統不知道有沒有人掃）、萬聖節（設計師 2026-10-06 決定不做）。

#### 語音觸發的共同規則（設計師 2026-10-06 定，給 NLU / 流程端）

四個語音觸發（片名、比莉 / 魔法、復仇者聯盟、Disney）都照這組規則，個別規則寫在上表。

1. **只聽使用者，不聽自己**：觸發只來自使用者的語句。Kebbi 自己的台詞裡有「魔法」（W02「祝你有個魔法般的夜晚」）、「魔法秘境」（A02）、「迪士尼」，TTS 播放期間收音要關或把自己的語音濾掉，不然會自己觸發自己。
2. **一次只播一個，具體的優先**：同一句話命中多個（「迪士尼的魔法秘境」「比莉的魔法秘境」）只播優先序最高的一個：片名 > 比莉 / 魔法 > 復仇者聯盟 > Disney。「魔法秘境」含「魔法」，照這條只播片名、不疊火花。
3. **冷卻**：同一個觸發 30 秒內只播一次；任兩個觸發之間至少隔 5 秒。效果播放中再命中就忽略，不重播、不延長。
4. **不打斷正在講的句子**：Center / Side 的畫面效果立刻播；Kebbi 的表情與動作等這句 TTS 講完再播（燈可以先變）。打斷沒有延遲（工程師確認），但打斷句子會讓人聽不到答案。
5. **例外畫面不觸發**：拍照中 P02–P04（取景與閃光）、P05b（已有常駐火花）、A06（預告播放中）、E05（網路異常）、E09（回充電）。FOCUS 層級一律不觸發，FULL / AMBIENT 才會。
6. **流程切換優先於效果**：效果播到一半使用者切了流程（按 chip、說新指令），效果立刻清掉、Side F 的覆蓋（片名的海報 A 10s）也清掉，回到新畫面該有的狀態。`js/moments.js` 的 `clear()` 就是這個行為。
7. **收尾回原狀**：效果結束 Kebbi 的燈、手臂、脖子回到目前畫面腳本的狀態，Center 的 chips 回原句（片名 10s 後）。
8. **記錄**：每次觸發記 log（觸發詞、畫面、時間），PM 之後看哪些詞真的有人講、哪些誤觸，再調清單。
9. **回話由語意決定，效果只疊加**（設計師 2026-10-14）：句子裡有明確問題（「復仇者聯盟什麼時候可以買」）→ 回答問題、效果照跑、AI 不為彩蛋多說；句子本身只是彩蛋（「比莉的魔法好酷」）→ 那是閒聊意圖，AI 一定要接話（例：「對吧！預告裡還有更厲害的，想看可以跟我說。」）。上表「不講話」指效果本身不帶台詞。


### 5.8 Kebbi 行為腳本

Kebbi 的臉不是我們畫的，是從 NUWA 的 115 支內建表情裡**選**的。`js/kebbi-script.js` 是整份腳本（`assets/kebbi/kebbi-script.csv` 是同一份的 CSV），
欄位照你們「凱比感測情境」的格式：**畫面 → 第幾段 → 開始秒 / 秒數 → 說的話 → 表情檔名 → 講話嘴型 → 燈 → 手臂 → 脖子**。
`prototype.html` 左下「Kebbi 實機」就是照這份腳本在跑：真表情影片（`assets/kebbi/*.mp4`，NUWA 的 115 支）、燈的五區（全身、胸、臉、左右手）、雙臂與脖子示意。

規則：
- **講話一律用 `001_tts_*` 系列**（喜 A/B/C、平靜 A/B/C、悲 A/B、疲累…），情緒放在講話前後的空檔用其他表情表現。
- **待機**是循環：`001_idle` → `idlevary1` → `lookl` → `idle` → `lookr` → `idlenaughty1`，約 15 秒無人接 `yawn76` → `sleep94`，有人來 `wake130`。
- **燈**只有紅綠藍紫白青粉 + 滅，不能漸變；需要節奏的用步進組合（例如倒數「青→白→青」每秒換、思考「青→滅」每 0.9 秒、Disney 七色每 0.15 秒跑一圈）。
- **手臂只走「肩 外開」（馬達 3 / 7）**（2026-10-06 實測後改）：「肩 前後」（馬達 4 / 8）往前往上舉的弧會打到 Center 螢幕，所以你們清單上的舉左手 / 舉右手 / 雙手舉起 / 雙手平舉 / 抱胸 / 揮手（都走肩前後）**一律不用**；手肘（6 / 10）彎起來前臂也會往前，不用；肩旋轉不用。
  腳本裡的姿勢全部重定義在 `kebbi-script.js` 的 `POSES`：右手側張 -70°、雙手側張 -85°（T 字）、側邊揮（外開 -80° ↔ -50° 來回）、雙手側張拍兩下（-85° ↔ -55°）。手最高只到水平、沒有舉過頭，這是刻意的。
  **請工程端照 POSES 的角度建新姿勢，不要套用清單上同名的預設動作。**脖子照清單（點頭兩下、歪頭 35°）不受影響。
- 每個畫面開始時雙手放下、脖子回正，腳本有寫才動。

表情的播放速度用 Kebbi 的預設值，不另外調；prototype 與 demo 的影片固定 0.4× 只是示意（影片是 30fps 壓的，比實機快）。
已確認（2026-10-05）：表情播到一半可以被下一支打斷；腳本只要給表情 / 動作的編號（檔名）即可；可以自訂表情但先不用。待實機測：打斷的延遲。仍是假設：表情三格各約 0.7 秒、播完停在最後一格；燈「滅」是一個狀態。

## 6. 聯絡窗口

- 設計：Vyin AI 設計團隊（Gamania）— 透過專案 PM 聯繫。
- 這包的維護：Vyin AI 官網 repo `external/2026-vyin-robot-lobby/`，版本異動會附在交付信中。
