---
name: edu_3d_game_workflow
description: 當使用者說「製作 3D 教學遊戲」、「課文 3D 遊戲」、「第一人稱闖關遊戲」、「沉浸式閱讀遊戲」、「Three.js 教學遊戲」、「用 Blender 建模」、「做像〈鳥〉那樣的遊戲」，或要把一篇課文／教材做成遊戲時觸發。涵蓋：教材拆解→關卡與題目設計→場景與 UI→Blender 建模匯出 glb→音效與配樂→Three.js 實作與無頭測試。（發布、教學頁、貼文由其他 skill 負責。）以梁實秋〈鳥〉遊戲（2026-10）的完整做法為範本。
---

# 教學 3D 遊戲：遊戲開發流程

範本專案：`I:\我的雲端硬碟\粉專\002國文教材\1151011鳥\`（梁實秋〈鳥〉第一人稱 3D 沉浸式閱讀遊戲，線上 https://ijun-ai.com/chinese/bird-liang/ ）。
新專案先看範本的 `game.html`、`tools\`、`關卡.txt`、`3D模型提示詞.md`、`背景音樂提示詞.md`，沿用同樣的結構與工具。

## 本 skill 附帶資料（要做到品質一致，開工前必讀）
- `references/data-schema.md`：`ST` 關卡欄位、九種題型欄位表、數量基準、存檔鍵、除錯鉤子、模型載入與骨架命名細節。**寫關卡與題目前先讀。**
- `references/visual-audio-presets.md`：渲染／後製參數、八組 ENV 光影數值、配樂與音效規則。**調場景與音樂前先讀，從這些數值微調，不要重猜。**
- `scripts/quality_check.py`（資料與載入）、`scripts/cert_check.py`（證書與解鎖）、`scripts/touch_check.py`（觸控搖桿與行動版版面）、`scripts/text_check.py`（課文逐字對照）：自動檢查，見第 6、7 節；`scripts/_common.py` 為共用模組。需要 `pip install playwright && playwright install chromium`。
- `scripts/export_glb.py`：Blender 批次匯出 glb。

## 0. 作業原則
- **每個階段做完才說完成**，用精準狀態詞：Created locally／Integrated／Deployed／Verified live，不要把「寫好了」說成「上線了」。
- 單一 HTML 遊戲（`game.html`，three@0.160.0 從 CDN 載入 import map），所有素材要能在 **雙擊 file://** 與 **線上網址** 兩種情況下運作。
- 避開傷人的設計：不要拿外表、身材、性別開玩笑（〈鳥〉曾因「仙女圖有嘲笑女性身材嫌疑」而整組換成鳥類圖）。
- 使用者途中的修改指示（題目、答案、順序、UI）一律以最新一句為準，改完回頭檢查是否影響題號、答案位置與測試。

## 1. 教材拆解（先做、先問）
1. 讀課文／備課檔，**依文意切分段落**，每段決定是「闖關關卡（有題目）」或「劇情站（沒題目的課文也要讓學生讀到）」。
2. 列出關卡表（`關卡.txt`）：幕 → 關 → 場景 → 課文原句 → 互動 → 題型。〈鳥〉結果：四幕、17 關、5 個劇情站（含序章）、45 題。
3. 與老師確認：幕數、每關要聽什麼／看什麼／做什麼、哪些題目維持現狀。**課文原文不得改字**；與課文不符的畫面（如某種鳥的叫聲）要如實處理。

## 2. 題目設計
- 每題標 **PIRLS 層次**（提取訊息／直接推論／詮釋整合／評鑑），題幹需要依據課文時寫「根據文本」。
- 題型混合：choice（正解位置要平均分布，用 `q.pos`）、tf、multi、fill、match（含聲音卡）、order、slider、imgchoice、imgmatch。
- 答錯：扣體力＋提示；體力歸零重玩該關。答對：羽毛（或同類收集物）。題號 `q.no` 連續編號，刪題後要重排。
- 結局：稱號依羽毛比例，輸入名字產生證書圖（canvas），證書紀錄存 localStorage，**通關過的瀏覽器自動解鎖全部關卡**；教師密碼 `ijun`（公開寫在教學頁，忘記請看網址前 4 個字母）。

## 3. 場景與 UI 風格
- UI 要像「遊戲」不是「網頁」：血條、任務框、提示菱形、右側選單（說明／關卡／存檔／音效）、金色邊框。入口畫面明亮。
- 主角活動範圍限制在關卡附近（`P.area`、`block`），走出去給提示 toast。
- 場景用程式化材質（`surface()` shader）＋ENV 預設（天空、霧、光、色調）＋bloom/ACES；不同幕換天氣與時間（清晨、黃昏、夜、雪）。
- 觸控裝置：左下**圓形類比搖桿**（拖越遠越快）＋拖畫面轉視角；畫面尺寸用 visualViewport／`--appH` 自動適應（iPad Safari 工具列會變）。電腦用 WASD／方向鍵。
- 存檔隨時可存（localStorage），含 `cleared`、`unlocked`、站別。

## 4. 3D 模型：改用 Blender（2026-10-12 起的標準流程）
過去做法（AI 生成：混元／Tripo／Mixamo）已改為 **Blender 為主**。

### 4.1 建模與整理
1. 在 Blender 建模或匯入參考模型後整理：單位公尺、**+Y 朝上、面向 -Z**（匯出時勾「+Y Up」）、原點在腳底中心、套用縮放與旋轉（Ctrl+A）。
2. 減面：單一模型必須 < 1 MB（鷹 852 KB 為目前最大，`quality_check.py` 會擋）；用 Decimate 或手動重拓撲。
3. UV 展開、貼圖**內嵌**進 glb（Shader 用 Principled BSDF，貼圖 2048 以下，必要時轉 JPEG 壓縮）。
4. 人形角色需要動作時：在 Blender 綁骨架與做動畫（或把 Mixamo 的 FBX 匯入 Blender 再整理）。**骨架／動畫名稱要和 `game.html` 約定一致**（例如 `Walk`、`Idle`），改名前先到 `game.html` 搜尋用到的名稱。
5. 注意：FBX 的 UV 常需翻轉 V；若走 FBX 路線先在 Blender 檢查貼圖方向。

### 4.2 匯出 glb
- 檔案 → 匯出 → glTF 2.0，格式 **glb**；勾「Apply Modifiers」「+Y Up」，有動畫則勾 Animation；貼圖內嵌。
- 可用 Blender 命令列批次匯出（先確認 Blender 路徑，本機 PATH 內沒有 blender，需向使用者確認安裝位置）：
  `"<blender.exe>" -b 檔案.blend -P <skill>\scripts\export_glb.py -- <專案>\models [--anim]`（每個頂層物件輸出一個小寫檔名 glb；範本複製到專案 `tools\` 也可）。
- 檔名使用英文小寫（`hawk.glb`、`keeper.glb`…），與遊戲載入名稱一致。

### 4.3 進遊戲
1. 把 `.glb` 放到專案 `models\`。
2. 用 `model-check.html` 先目視檢查（比例、朝向、貼圖、動畫）。
3. `python tools/pack_models.py` → 產生 `models\models.js`（base64，供 file:// 載入；〈鳥〉約 3 MB，是首次載入的主要成本，所以模型越小越好）。遊戲讀 `window.BIRD_MODELS`，缺檔時退回程式化模型。載入器用 `GLTFLoader`＋`MeshoptDecoder`、以 `fitModel` 縮放貼地、以 `swapIn` 換掉程式化模型；骨架名稱、動畫取用方式見 `references/data-schema.md` 第 6 節。改了 glb 一定要重打包（`quality_check.py` 會檢查 models.js 是否比 glb 舊）。
4. 若模型為人形，檢查骨架對位、腳底接地、動畫速度與走路腳步是否打滑。

## 5. 音效與配樂
- 配樂用 AI 生成（提示詞寫在 `背景音樂提示詞.md`），每幕一軌，以 `BGM_OF` 對應關卡編號；標題與結局另有曲目。預設音量 0.2。
- 課文有關的實錄音（鳥鳴等）放 `audio\*.mp3`，用 HTMLAudio 播放；短音效（點擊、答對）用 `audio\sfx.js`（`tools/pack_sfx.py` 打包）。
- **播放重點音效時要暫停背景音樂**（`MUSIC.duck(true/false)`，結束後恢復）。
- 聲音題（如找杜鵑）若老師說維持現狀就不要動。

## 6. 實作與自我測試
- 實作順序：骨架（world/ST 站別陣列）→ 一幕做到能玩 → 其餘幕 → 結局與證書 → UI 微調。新關卡沿用 `ST` 陣列的 `pre/mid/steps`，欄位照 `references/data-schema.md`。
- **必跑的自動檢查**：`python <skill>\scripts\quality_check.py <專案資料夾>`（需 playwright；用 `--use-angle=d3d11` 實體 GPU）。它檢查：載入無 pageerror／console error、`window.__bird` 存在、題號連續、各題型欄位與答案合法、choice 正解位置 A–D 各占 15%～35%、同關不連續 3 題同題型、引用圖片／音檔存在、glb < 1 MB、models.js 不比 glb 舊、localStorage 可用。失敗（exit 1）就不可說完成；警告要在回報中交代。
- **證書與解鎖**：`python <skill>\scripts\cert_check.py <專案> [--save-key … --cert-key …]`。預先寫入存檔與證書紀錄，按「繼續遊戲」進結局，檢查證書為 1200×840 的 PNG 且非空白、截圖存 `QA/cert.png`、「下載證書」會下載「名字.png」、重新整理後 `G.unlocked` 仍為 true、清除證書紀錄後解鎖會消失、偵測教師密碼欄。新專案的 `--save-key`／`--cert-key` 要與遊戲的 `SAVE_KEY`／`CERT_KEY` 一致。證書版面（名字、稱號、日期、朱印、字體）要**目視** `QA/cert.png`。
- **觸控搖桿**：`python <skill>\scripts\touch_check.py <專案> [--station N]`。以手機模擬（375×812，再轉 812×375）與 CDP 真實 touch 事件，檢查 `(pointer:coarse)` 成立、`#pad` 完整在視窗內、推到底 1 秒移動 ≥ 1.5 m、推一半明顯較慢（類比）、放開後鈕回正且不再移動、在畫面拖曳會轉視角、`--appH` 與視窗高度相符且頁面不可垂直捲動（無下方黑區）。截圖存 `QA/touch-portrait.png`、`QA/touch-landscape.png`，要目視搖桿位置與 HUD 是否遮擋。〈鳥〉實測：推到底 2.70 m、推一半 1.65 m。
- **課文逐字對照**：`python <skill>\scripts\text_check.py <專案> --source <老師確認的課文.txt> [--skip 0] [--map "遊戲字=來源字,…"]`。去除標籤與標點後，每站 `text` 必須在來源中連續一致；不一致會列出「來源 ↔ 遊戲」的差異字。規則：
  - **不可自行判斷哪個字對**。有差異就列給老師確認（教育部標準字、課本版本、來源檔 OCR 錯字都可能），確認後才用 `--map` 記錄已確認的異體，報告會再列出該清單。
  - 來源檔沒有的段落（如〈鳥〉序章「我愛鳥」只在課本）用 `--skip` 略過，並另行對照課本。
  - 〈鳥〉實測（來源 `鳥 課文.txt`，該檔本身有 OCR 痕跡）：蹓躂／遛達、鷹／鹰、哪／那、昂／昻、籠子裡／籠裡、等差異，**尚待老師確認用字**，不得直接改。
- 自動檢查**仍不涵蓋**：實際玩到結局時的「輸入名字」畫面（需整場自動作答）、iPad Safari 工具列收放（須真機）、視覺美感、聲音。這些列在回報的「未驗證項目」。

## 7. 驗收標準（全部達成才能說 Created locally 完成）
1. `quality_check.py` 結果為「通過」，警告已逐項處理或說明。
2. 題數基準：每關 2～3 題；題型 ≥ 5 種；PIRLS 五層次都出現；題號 1～N 連續。
3. `text_check.py` 無未解釋的差異：每個差異都已由老師確認用字（寫入 `--map` 或修正遊戲），結果附在回報中。
4. 檔案：glb 單檔 < 1 MB；`game.html` 雙擊（file://）與本機伺服器兩種方式都能載入。
5. `cert_check.py` 通過，且 `QA/cert.png` 目視無誤；另任選 3 關實際作答，答錯扣血與提示、體力歸零重玩、答對得羽毛。
6. `touch_check.py` 通過，且直／橫向截圖目視無黑邊、搖桿不遮擋；真機 iPad 另行確認或列為未驗證。
7. 素材授權與來源（AI 生成模型的授權、配樂提示詞）記錄在專案文件。
8. 回報使用精準狀態詞（Created locally／Integrated／Deployed／Verified live），並附未驗證項目。
