{"id":48544853,"url":"https://github.com/jed1978/refactoringdungeon","last_synced_at":"2026-04-08T06:03:15.077Z","repository":{"id":345907714,"uuid":"1187796778","full_name":"jed1978/refactoringdungeon","owner":"jed1978","description":null,"archived":false,"fork":false,"pushed_at":"2026-03-21T13:56:30.000Z","size":142,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-21T23:47:25.360Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jed1978.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-03-21T07:10:14.000Z","updated_at":"2026-03-21T13:56:33.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/jed1978/refactoringdungeon","commit_stats":null,"previous_names":["jed1978/refactoringdungeon"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/jed1978/refactoringdungeon","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jed1978%2Frefactoringdungeon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jed1978%2Frefactoringdungeon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jed1978%2Frefactoringdungeon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jed1978%2Frefactoringdungeon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jed1978","download_url":"https://codeload.github.com/jed1978/refactoringdungeon/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jed1978%2Frefactoringdungeon/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31542384,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T16:28:08.000Z","status":"online","status_checked_at":"2026-04-08T02:00:06.127Z","response_time":54,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-04-08T06:03:14.985Z","updated_at":"2026-04-08T06:03:15.071Z","avatar_url":"https://github.com/jed1978.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 重構地城 Refactoring Dungeon\n\n\u003e 一款以軟體工程概念為遊戲機制的 Roguelike 瀏覽器遊戲。\n\u003e\n\u003e A browser-based roguelike where software engineering concepts ARE the game mechanics.\n\n---\n\n## 遊戲簡介 / About\n\n你是一位工程師，深入 Legacy Codebase 地城。\n用**重構技能**攻擊 Code Smell 怪物，裝備**設計模式**武裝，最終對抗終極 Boss **神類（God Class）**。\n\nYou are a Software Engineer descending into a legacy codebase dungeon.\nFight Code Smell monsters with Refactoring skills, equip Design Pattern gear, and ultimately confront the **God Class** boss.\n\n**適用場合 / Use Cases:**\n- Conference demos（DevOpsDays Taiwan、COSCUP 等）\n- Engineering team ice-breakers\n- Teaching software engineering concepts in an engaging way\n\n---\n\n## 地城結構 / Dungeon Structure\n\n| 樓層 | 主題 | Boss |\n|------|------|------|\n| 1F | 前端泥沼 — The Frontend Swamp | 義大利麵蟲（Spaghetti Code） |\n| 2F | 後端迷宮 — The Backend Labyrinth | 循環依賴蛇（Circular Dependency） |\n| 3F | 資料庫深淵 — The Database Abyss | 大泥球（Big Ball of Mud） |\n| 4F | 神類聖殿 — The God Class Sanctum | **神類（God Class）** — 4 段Phase |\n\n---\n\n## 重構技能 / Refactoring Skills\n\n| 技能 | MP | 效果 | 解鎖條件 |\n|------|----|------|---------|\n| Extract Method | 2 | 單體傷害（1.5× ATK） | 初始 |\n| Rename Variable | 1 | 揭示敵人數值與弱點 | 初始 |\n| Inline Temp | 1 | 快速攻擊（0.8× ATK），先攻 | 初始 |\n| Replace Magic Number | 4 | 眩暈 1 回合 + 1.5× 傷害（遞減抗性系統） | LV 3 |\n| Move Method | 2 | 閃避下一次攻擊 | LV 5 |\n| Parameter Object | 4 | 群體攻擊，全敵人 0.7× ATK | LV 7 |\n| Polymorphism | 5 | 削弱 Boss 當前 Phase 能力 | LV 9 |\n| Compose Method | 5 | 連鎖 3 個隨機技能（各 0.8× 威力，共 2.4×） | LV 11 |\n\n---\n\n## 平衡機制 / Balance Systems\n\n### 暈眩抗性（Stun Resistance）\n\n`Replace Magic Number` 暈眩效果採**遞減抗性系統**，模擬「同一個 patch 打兩次就不管用了」：\n\n- 每次暈眩成功後，目標 `stunResistance += 0.4`\n- 抗性在暈眩期間每回合衰減 0.15，主動回合衰減 0.1\n- Boss 有基礎暈眩抗性（`stunImmunity`）：1F Boss 30%、2F 40%、3F 50%、4F 60%\n- 神類（God Class）**Phase 4（HP \u003c 25%）完全免疫暈眩**\n\n### 臨時 Buff 系統\n\n事件獎勵的 ATK 提升改為**有期限的暫時 Buff**（不再永久修改 base stats）：\n\n- 咖啡機：ATK +3，持續 5 場戰鬥\n- Stack Overflow 圖書館：ATK +2，持續 3 場戰鬥\n- **互動格子一次性使用**（使用後變為普通地板，不可重複吃 buff）\n\n### Boss 特性說明\n\n| Boss | 特性 |\n|------|------|\n| 義大利麵蟲（1F） | 纏繞玩家，降低 SPD |\n| 循環依賴蛇（2F） | 反射 40% 受到的傷害 |\n| 大泥球（3F） | 加權隨機技能（三連擊/重擊/偷血/回血），回血回合仍會發動弱攻擊 |\n| 神類（4F） | Phase 轉換在 75/50/25% HP；Phase 3 有 40% 機率「退回 PR」使技能無效（MP 仍消耗）；Phase 4 完全免疫暈眩 |\n\n### 懶惰類別（Lazy Class）\n\n不再站著等死。有隊友時：60% 委派（跳過回合）、30% 治療隊友 15% 最大 HP、10% 罕見攻擊。\n**單獨行動時必定攻擊**（「沒人可以委派了！」）。\n\n---\n\n## 快速開始 / Quick Start\n\n```bash\nnpm install\nnpm run dev\n```\n\n開啟瀏覽器前往 `http://localhost:5173`\n\n---\n\n## DEMO MODE\n\n在 Title Screen 輸入 **↑ ↑ ↓ ↓ ← → ← →**（Konami Code）解鎖 DEMO MODE。\n\nDEMO 模式效果：\n- 角色 LV.15，全技能解鎖，全套設計模式裝備\n- **God Mode（HP 不會低於 1）** — 這是設計行為，非 Bug\n- HUD 顯示黃色 `DEMO` 標記\n\n---\n\n## 技術架構 / Technical Architecture\n\n### Hybrid Canvas + DOM Rendering\n\n```\nCanvas（低階渲染）          DOM（React 高階 UI）\n─────────────────          ──────────────────\nDungeon tile map           HUD overlays\nPlayer/monster sprites     Combat log\nBattle scene               Action menu\nParticle effects           Dialogue boxes\nLighting system            Inventory / Shop\n```\n\nCanvas 以邏輯解析度 240×176 渲染，透過 CSS `image-rendering: pixelated` 等比放大至全螢幕——保有像素風格並支援任意解析度。\n\n### Sprites-as-Code（會議 Demo 亮點）\n\n所有像素藝術以 TypeScript 2D 陣列定義，**零圖片檔案**：\n\n```typescript\n// 每個 Monster 都是一個 TypeScript data literal\nconst SLIME_FRAME: SpriteFrame = [\n  [null,   \"#4ade80\", \"#4ade80\", null  ],\n  [\"#4ade80\", \"#86efac\", \"#86efac\", \"#4ade80\"],\n  // ...\n];\n```\n\n### BSP Dungeon Generation\n\n每層地城使用 **Binary Space Partition** 演算法自動生成：\n- 遞迴分割空間 → 建立房間 → 走廊連接\n- 房間類型隨機分配（怪物、事件、寶箱、商店、練功沙盒）\n- **每層保證至少 1 個 Training Room（練功沙盒）**\n- Boss 房間永遠是最大且距出生點最遠的房間\n- Boss 房間只保留**一個入口**，其餘通道封牆 → 確保 BossDoor 不會切斷走廊\n- **雙重連通驗證**（最多重試 5 次）：\n  1. `validateMap`（BossDoor 可通行）：所有房間中心可達\n  2. `validateMapNoBossDoor`（BossDoor 視為牆）：所有非 Boss 房間不依賴 BossDoor 即可到達，防止「非 Boss 怪物被困在 BossDoor 後面」的死局\n\n### Two-Tier State Architecture\n\n```\n60fps Tier（useRef）          React Tier（useReducer）\n──────────────────            ──────────────────────\nCombatLoopState               GameState\n  animState                     player stats\n  particles                     floor layout\n  damageNumbers                 inventory\n  localPhase                    runStats\n                      dispatch()\n                    ──────────→\n```\n\n戰鬥期間，高頻狀態（動畫、粒子）住在 `useRef` 避免 re-render；\n持久結果（HP 變化、經驗、等級）透過 `dispatch` 進入 React 狀態。\n\n### Pixel Dissolve Death Effect\n\n怪物死亡時每個非透明像素獨立飛散——純 Canvas 粒子系統，無任何圖片：\n\n```\nMonster died\n  → freeze sprite pixels\n  → assign each pixel a random velocity (upward bias) + gravity\n  → animate 800ms: pixels scatter outward + fade alpha\n```\n\n### Web Audio Synthesized SFX \u0026 BGM\n\n零音訊檔案，全部使用 Web Audio API 合成：\n\n- **SFX（`AudioSystem.ts`）**：14 種一次性音效，包含攻擊音、暴擊、怪物死亡、升級琶音、勝利和弦等。\n- **BGM（`MusicSynth.ts` + `MusicSystem.ts` + `tracks/*.ts`）**：9 首合成背景音樂，依 GameMode 自動切換，300ms crossfade。\n\n#### BGM 合成管線（Chiptune 品質）\n\n```\n每個音符（Note）：\n  OscillatorNode ×1 or ×2（去諧對）\n    → GainNode（ADSR 包絡）\n    → BiquadFilterNode（lowpass，可選）\n    → StereoPannerNode（pan，可選）\n    → trackInput\n\ntrackInput（每首曲目建立一次，loop 間重用）：\n  → dryGain → masterGain → destination\n  → ConvolverNode（合成混響，可選）→ masterGain\n  → DelayNode + feedback loop（可選）→ masterGain\n```\n\n| 技術 | 效果 |\n|------|------|\n| **ADSR 包絡** | 每音符獨立振盪器，消除 gate 產生的硬切嗶嗶聲 |\n| **去諧振盪器對** | Lead/Pad 聲部用 ±N cents 雙振盪器，產生合唱厚度 |\n| **低通濾波** | BiquadFilterNode 截斷刺耳高頻，square/sawtooth 變暖 |\n| **合成混響** | 噪音 buffer × 指數衰減（1.4s），ConvolverNode 空間感 |\n| **延遲回聲** | DelayNode + feedback，探索曲飄逸、戰鬥曲緊促 |\n| **立體聲展寬** | StereoPannerNode：arp 偏右、pad 偏左 |\n| **4 聲部編排** | Lead + Bass + Pad + Arp（一般戰鬥 = 3 聲部） |\n\n| 場景 | 音樂 | 聲部 | 特性 |\n|------|------|------|------|\n| Title Screen | C minor 神秘琶音 | 4 聲部 | 100 BPM，reverb + delay，loop |\n| 1F 前端泥沼 | A minor 低調氛圍 | 4 聲部 | 80 BPM，reverb，loop |\n| 2F 後端迷宮 | D minor 機械節奏 | 4 聲部 | 80 BPM，reverb + delay，loop |\n| 3F 資料庫深淵 | G minor 深沉低音 | 4 聲部 | 70 BPM，heavy reverb，loop |\n| 4F 神類聖殿 | D minor 壓迫和弦 | 4 聲部 | 80 BPM，reverb + delay，loop |\n| 一般戰鬥 | A minor 快節奏 | 3 聲部 | 140 BPM，dry + short delay，loop |\n| Boss 戰 | D minor 高速連奏 | 4 聲部 | 160 BPM，reverb + delay，loop |\n| 勝利 | C major fanfare | 4 聲部 | 120 BPM，reverb，一次性 |\n| 遊戲結束 | A minor 下行旋律 | 3 聲部 | 60 BPM，heavy reverb，一次性 |\n\n### 樓層推進邏輯\n\n```\n清除該層所有小怪\n      ↓\nBossDoor 解鎖（按 Space 開門）\n      ↓\n進入 Boss 房間，擊敗 Boss\n      ↓\n下樓梯（StairsDown）解鎖\n      ↓\n進入下一層\n```\n\n### Training Room（練功沙盒）\n\n每層地城保證至少出現一個 **Training Room**（`TileType.TrainingRoom`，優先放在 Empty 房間中心）。\n\n- 面對 Training Room 磁磚按 **Space** 進入練習戰鬥\n- 使用該樓層怪物池隨機組成 1–3 隻怪物\n- 勝利可獲得 EXP 與 Gold，但**不移除地圖怪物**\n- 可重複挑戰，適合刷等或練習技能\n- BossDoor 邏輯不受影響（Training 戰鬥不計入 `floor.monsters`）\n\n---\n\n## 技術亮點（Conference Talk Notes）\n\n1. **Sprites-as-Code** — 開啟任何 `src/sprites/monsters/*.ts`，這就是怪物的像素藝術。TypeScript data literal = pixel art。\n2. **Pixel Dissolve** — `src/engine/PixelDissolve.ts`：每個像素都是獨立粒子，800ms 飛散效果，純數學無圖片。\n3. **BSP Generator** — `src/features/map/bspGenerator.ts`：Binary Space Partition 演算法生成無限不重複地城。\n4. **Two-Tier State** — 60fps 遊戲循環（`useRef`）與 React 狀態（`useReducer`）分離，各司其職。\n5. **Zero Dependencies** — 無後端、無外部 API、無圖片、無音效檔、無音樂檔。整個遊戲就是 TypeScript + Canvas + React。\n6. **Synthesized BGM** — `src/engine/MusicSynth.ts` + `tracks/*.ts`：9 首背景音樂用 Web Audio API 合成（ADSR 包絡、去諧振盪器對、低通濾波、混響、延遲），4 聲部編排，依遊戲模式自動切換，300ms crossfade，零音檔。\n\n---\n\n## 資料夾結構 / Folder Structure\n\n```\nsrc/\n├── app/              # React root、providers\n├── engine/           # Canvas 渲染引擎（零 React 依賴）\n│   ├── AudioSystem.ts      # Web Audio 合成音效（14 種 SFX）\n│   ├── MusicTypes.ts       # BGM 型別（Note, VoiceDef, TrackDef, AdsrEnvelope）\n│   ├── MusicSynth.ts       # BGM 合成器核心（ADSR、去諧對、濾波、混響、延遲）\n│   ├── MusicSystem.ts      # BGM 引擎（切換、淡入淡出、loop 排程）\n│   ├── MusicTracks.ts      # BGM barrel file（匯入 tracks/*.ts）\n│   └── tracks/             # 9 首曲目資料 + noteFreqs.ts 頻率常數\n│   ├── BattleAnimator.ts   # 戰鬥動畫佇列\n│   ├── BattleRenderer.ts   # 戰鬥場景繪製\n│   ├── LightingSystem.ts   # 火炬光照效果\n│   ├── ParticleSystem.ts   # 粒子系統\n│   ├── PixelDissolve.ts    # 像素飛散特效\n│   └── TileRenderer.ts     # 地城 Tile 渲染\n├── features/\n│   ├── combat/       # 戰鬥狀態機、AI、公式\n│   ├── map/          # BSP 地城生成\n│   └── events/       # 非戰鬥事件邏輯\n├── sprites/          # 所有像素藝術（純 TypeScript data）\n│   ├── player.ts\n│   ├── monsters/     # 每個怪物一個檔案\n│   └── tiles.ts\n├── state/            # GameContext + useReducer\n├── ui/               # React DOM overlay 元件\n└── data/             # 怪物、技能、裝備、字串定義\n```\n\n---\n\n## Build \u0026 Deploy\n\n```bash\nnpm run build     # 生產版本（tsc -b + vite build）\nnpm run dev       # 本地開發（http://localhost:5173）\n```\n\n\u003e **注意：** 請用 `npm run build` 驗證，不要只用 `npx tsc --noEmit`。\n\u003e `tsc -b` 才會套用 `noUnusedLocals`/`noUnusedParameters`，`tsc --noEmit` 會漏掉這些錯誤。\n\n### Vercel 部署\n\n專案已部署於 [Vercel](https://vercel.com)，連結 GitHub `main` branch 自動部署：\n\n- push to `main` → Vercel 自動觸發 `npm run build` → production deploy\n- PR → 自動產生 Preview URL\n\n---\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjed1978%2Frefactoringdungeon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjed1978%2Frefactoringdungeon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjed1978%2Frefactoringdungeon/lists"}