Bundle
@dsh-external/dsh-minigames
DSH Web UI 浮动小游戏窗口:18 款离线小游戏,可扩展游戏注册表。等待模型回复或修 bug 时的摸鱼神器。
- Source
- lhh010
- stars
- 27 stars
- License
- BSD-3-Clause
- Updated
- Updated 14 days ago
Readme
# dsh-minigames
**简体中文** | [English](./README.en.md)
DSH Web UI 浮动小游戏窗口:等待模型回复或修 bug 时的摸鱼神器。
- **折叠态**:窗口隐藏后留下一个圆形浮动 🎮 按钮(默认右下角),**可自由拖动**并记住位置,
按住拖动(位移超过 5px)松手不会打开窗口;**单击**才重新打开面板。
- **展开态**:浮动小游戏窗口,**拖动标题栏**可随意移动,松手靠近屏幕边缘自动**吸附**
(左右停靠/上下贴边),位置、停靠状态与宽度均持久化,刷新后自动恢复;默认宽度
min(50vw, 640px),可拖左缘调整 360px–80vw,面板内自由选择游戏。
- **游戏**(全部离线、零资源文件、Canvas 绘制):
1. 🦖 **恐龙跳一跳** —— Chrome 经典小恐龙(昼夜/雨天);
2. 🧱 **俄罗斯方块** —— 经典下落消除;
3. 🛡️ **坦克大战(带 AI)** —— 2D 坦克对战,敌军追踪 + 视线开火,共 3 波;
4. 💎 **消消乐** —— 点击消除四连通同色块,目标分过关、逐关递增;
5. 🔢 **华容道** —— 16 格数字华容道(15-puzzle),滑动方块按序排列,用时越短分越高;
6. 🐍 **贪吃蛇** —— 经典贪吃蛇,穿越边界会从对侧出现(环面地图);
7. 🔢 **2048** —— 方向键滑动合并数字,合成 2048 即达成;
8. 💣 **扫雷** —— 左键翻开、右键标旗、双击数字自动展开周围;
9. 🃏 **记忆翻牌** —— 翻开两张配对,步数越少分越高;
10. ⚫ **五子棋 vs AI** —— 15×15,AI 会进攻也会堵你;
11. 🦘 **跳一跳** —— 按住蓄力、松开起跳,落点越准加分越多;
12. 🧱 **打砖块** —— 移动挡板反弹小球,清完进入下一关、球速递增;
13. 🔨 **打地鼠** —— 30 秒限时点击打地鼠,命中 +1、打空 -1;
14. ⚫ **黑白棋 vs AI** —— 8×8 奥赛罗,角最重要,无棋可下自动让位;
15. 🐦 **Flappy** —— 点击/空格振翅穿过柱子缝隙,越远分越高;
16. 🧩 **数独** —— 9×9 标准数独,D 键切换难度,填满无冲突即胜;
17. 🟡 **吃豆人** —— 经典迷宫吃豆,力量豆可反吃幽灵;
18. 🎯 **跟枪练习** —— FPS 跟枪:锁定鼠标转视角压住三维漂移靶子,左键射击有后坐力。
- **预留扩展接口**:游戏注册表(`registerGame`),新增游戏只需实现一个接口。
- **体验细节**:隐藏窗口/切换标签页时自动暂停游戏、恢复时继续;每局最高分存
localStorage;键盘输入只在点击游戏区域后生效,不会劫持聊天输入框。
- **尺寸自适应**:游戏画布按面板**真实可用空间**自适应(工具条+画布+按键提示整体
始终完整展示,不出现滚动条;浏览器缩放/面板拖宽缩窄都会自动重排),宽高上限
960px。
## 版本兼容 / Version compatibility
兼容 DSH snapshot0810(`snapshots/20260810T155924Z`)、snapshot0811(`snapshots/20260811T152241Z`)与最终快照 snapshot0812(`snapshots/20260812T172954Z-final`):纯浏览器端 bundle(node half 仅 loader 占位),客户端元数据声明为嵌套 `dsh.client`——0810 的 ClientModuleHostService 只读该字段,顶层 `dshClient` 会被静默忽略(无日志无报错,插件不进 boot 图)。0810 实机验证通过;0811 与 0812 最终快照实机 boot 验证通过(见下)。
**npm 发版兼容**:兼容 DSH npm 发版 `@deepseek-ai/dsh@0.1.1-rc.1`(v0.3.5 实机 boot 验证:`dsh --profile web` 启动后 boot 清单包含 `@dsh-external/dsh-minigames`、`/plugins/@dsh-external/dsh-minigames/client.js` 返回 200——本插件是纯浏览器端 bundle(`document.body` portal),不依赖任何宿主服务/槽位,0.1.1-rc.1 上零改动),同时兼容 `@deepseek-ai/dsh@0.0.1-rc.5`(dist-tag `next`,即最终快照 snapshot0812 的 npm 发版;`npm exec -p @deepseek-ai/dsh@0.0.1-rc.5 -- dsh --profile web --port <port>` 可访问指定版本并启动,lib 生产模式),同时保持兼容 `@deepseek-ai/dsh@0.0.1-rc.2`(snapshot0811 的 npm 发版)。实测(npm rc.5 基线):`dsh web` 启动后 `window.__DSH_BOOT__` 清单包含 `@dsh-external/dsh-minigames`,`/plugins/@dsh-external/dsh-minigames/client.js` 返回 200;typecheck、build 与 201 个单测通过。注意:0811 起 vendored cordis 更名为 `@deepseek-ai/cordis`(npm 发版不再发布 `cordis` 名义的 vendored 包)。本插件源码对 cordis 只有 type-only 导入(`src/index.ts`、`src/client/index.tsx`、`src/invariant.ts`),已把类型导入与 peer/devDependencies 迁移至 `@deepseek-ai/cordis`(peer `^4.0.1-rc.1`,npm rc.5 基线上为 `4.0.1-rc.4`)——构建产物(lib/*.js)零 cordis 运行时导入,纯 `npm install` 不再报 ERESOLVE,无需 `--legacy-peer-deps`。
### 0811 兼容要点(snapshot0811,实机验证)
- **bundle 机制不变**:0811 仍支持 `dsh.bundle.patch` → `cordis.patch.yml` 的组合包层机制(本插件的 profile bundles 安装方式照旧),客户端 `dsh.client` 元数据发现与 `window.__ModuleLoader__` 加载协议均未变。
- **cordis 更名**:0811 将 vendored cordis 由 `cordis@4.0.0-rc.7` 更名为 `@deepseek-ai/cordis@4.0.1-rc.1`。本插件对 cordis 只有 type-only 导入,构建产物零 cordis 运行时导入——更名不影响已构建 bundle 的运行时加载;npm 基线 typecheck 时 `cordis` 裸导入解析到公开 `cordis` 包仍可通过,对齐建议见上。
- **实机 boot 验证**:snapshot0811(`snapshots/20260811T152241Z`)web 启动后 `window.__DSH_BOOT__` 清单包含 `@dsh-external/dsh-minigames`,`/plugins/@dsh-external/dsh-minigames/client.js` 返回 200,右侧面板(🎮 小游戏)实测渲染。typecheck 与 201 个单测对 0811 基线通过。
### 0812/最终快照 兼容要点(snapshots/20260812T172954Z-final,实机验证)
- **cordis 更名落地**:本插件已把 type-only 导入(`src/index.ts`、`src/client/index.tsx`)与 `peerDependencies`/`devDependencies` 迁移至 `@deepseek-ai/cordis`(`^4.0.1-rc.1`;npm rc.5 基线上为 `@deepseek-ai/cordis@4.0.1-rc.4`)——构建产物(lib/*.js)零 cordis 运行时导入,npm rc.5 消费者 typecheck 全绿,`npm install` 无需 `--legacy-peer-deps`。
- **bundle 机制不变**:最终快照仍支持 `dsh.bundle.patch` → `cordis.patch.yml` 的组合包层机制,客户端 `dsh.client` 元数据发现与 `window.__ModuleLoader__` 加载协议未变;面板不依赖任何宿主服务与布局槽(纯 `document.body` portal),与主框架版本解耦。
- **实机 boot 验证**:最终快照(`snapshots/20260812T172954Z-final`)web 启动后 `window.__DSH_BOOT__` 清单包含 `@dsh-external/dsh-minigames`,`/plugins/@dsh-external/dsh-minigames/client.js` 返回 200;npm rc.5 consumer `dsh web` 启动后 boot 清单同样包含本插件。typecheck、build 与 201 个单测对最终快照基线通过。
## 更新记录 / Changelog
### 2026-08-22 · v0.3.6 — 修复俄罗斯方块落地不消除(锁定延迟)
- **根因**:方块落到最终位置后并不立即合并,要等下一次重力 tick 失败才锁定+消除——1 级时最长悬停 **800ms**,期间拼满的行看起来「该消除却没消除」;而高级别(120ms)又快到无法把方块滑进最左列,留下永远差一格的死列
- **修复**:引入标准**锁定延迟(lock delay)**——落地后保留 400ms 可控窗口(可滑动/旋转微调,滑动与旋转会刷新窗口,每块最多刷新 15 次防无限拖延),到期自动锁定并立即执行消除;空格硬降/↓ 软降到底仍是即时锁定。同时在 `lock()` 内加入自检:满行若在消除后仍残留会输出错误日志(正常情况下不可能发生)
- **验证**:新增 `isLanded`/`lock` 单测 2 例(含消除后守恒断言),203 例全部通过;typecheck、build 通过
### 2026-08-20 · v0.3.5 — 声明 DSH 0.1.1-rc.1 兼容性(实机 boot 验证)
- **验证**:DSH npm `0.1.1-rc.1` 实机 boot 验证通过——boot 清单包含 `@dsh-external/dsh-minigames`、client.js 返回 200;本插件为纯浏览器端 bundle(`document.body` portal),不依赖任何宿主服务或布局槽位,0.1.1-rc.1 上零改动,全部 18 款游戏行为不变
### 2026-08-20 · v0.3.4 — 修复黑白棋 HUD 棋子符号反向
- **修复**:黑白棋 HUD 与终局比分的棋子符号与直觉相反——此前实心 `●` 配的是黑棋(玩家)计数、空心 `○` 配的是白棋(AI)计数,读起来像比分/胜负算错了。现改为 `○`(空心)= 黑棋(玩家)、`●`(实心)= 白棋(AI),与棋盘实际棋子一致;落子/翻转/终局判定逻辑不变(已用 300 局随机模拟验证)。
### 2026-08-16 · v0.3.3 — 浮动窗口与可拖动 🎮 启动按钮
- **面板浮动窗口化**:折叠态由右侧 rail 改为圆形浮动 🎮 按钮;展开态为可拖动、
边缘吸附(左右停靠/上下贴边)的浮动窗口,位置、停靠状态与宽度持久化
- **🎮 按钮可拖动**:按住拖动(位移超过 5px)移动按钮并限制在视口内,松手记住
位置(`dsh-minigames:launcher`)且不触发打开面板;未位移的单击才打开窗口
- **调宽修复**:拖左缘调宽改为锚定窗口实际右缘(原实现隐含右缘贴边的假设)
- **可访问性**:折叠态由 `<div role="button">` 改为原生 `<button>`
- **验证**:typecheck 与 201 个单测通过;实机加载验证通过
### 2026-08-11 · v0.3.2 — 恐龙跳一跳角色美化
- **🦖 小恐龙**:按经典像素矩阵重绘——大头朝右、上翘尾巴、流线身体、
两条跑步腿(跳跃收起)、白色像素眼;白天近黑、夜晚反白
- **🐦 鸟**:圆润身体 + 前伸头 + 尖嘴 + 扑动翅膀 + 尾巴,双调色板
- **🌵 仙人掌**:圆角圆顶 + 弯折手臂 + 竖纹肋线 + 顶部高光,双株同理
- **验证**:typecheck 与 201 个单测通过;实机加载验证通过
### 2026-08-11 · v0.3.1 — 跟枪练习 FPS 化与多游戏打磨
- **🎯 跟枪练习 FPS 化**:Pointer Lock 鼠标锁定(光标隐藏)、准星固定屏幕中央、
鼠标增量转视角(含俯仰,修复上下方向)、目标三维漂移(横向 + 高度浮动)、
**左键射击**(后坐力视角上跳回落 + 随机横向晃动衰减 + 可见子弹弹道与命中火花)、
右下角第一人称步枪 viewmodel、开枪枪口火光、暂停/开始覆盖层提示
- **🔨 打地鼠**:3×3 → **5×5**(25 洞),同时冒头最多 **5 只**
- **🟡 吃豆人**:嘴巴补集动画(张嘴闭嘴)、幽灵走路与眼睛转向、
格子对齐移动(不再中心/墙体晃动)、撞墙回中不卡死、开局幽灵缓冲、
幽灵出生点移到上部通道两端
- **移除**:🏓 乒乓
- **验证**:typecheck 与 201 个单测通过;实机加载验证通过
### 2026-08-11 · v0.3.0 — 新增 6 款小游戏(共 18 款,后移除乒乓)
- **新增游戏**:🔨 打地鼠(最多 3 只同现)、⚫ 黑白棋 vs AI、🐦 Flappy、
🧩 数独(三档难度 + 计时)、🟡 吃豆人(双幽灵 AI + 力量豆)
- **移除**:🏓 乒乓(对局体验不佳)
- **验证**:typecheck 与 189 个单测通过;实机加载验证通过
### 2026-08-11 · v0.2.0 — 新增 7 款小游戏与细节打磨
- **新增游戏**(共 12 款):🐍 贪吃蛇(环面穿越)、🔢 2048、💣 扫雷(双击展开)、
🃏 记忆翻牌、⚫ 五子棋 vs AI、🦘 跳一跳、🧱 打砖块
- **贪吃蛇**:穿越边界从对侧镜像位置继续,不再撞墙死亡
- **扫雷**:双击已翻开的数字,若周围标记雷数 == 数字则自动翻开剩余未开启位置
- **验证**:typecheck 与 128 个单测通过;实机加载验证通过
### 2026-08-11 · v0.1.1 — snapshot0810 适配与面板自适应修复
- **迁移**:package.json 客户端元数据从顶层 `dshClient` 迁移为嵌套 `dsh.client`(inject 原样保留)
- **修复**:面板可用高度不足时不再出现纵向滚动条——`.dmg-body` 改为 flex 列布局,游戏区拿到真实可用高度,画布按"工具条+画布+按键提示"整体自适应(此前画布高度由自身内容决定、形成循环测量,窄窗口下画布溢出并触发滚动条)
- **变大**:画布显示宽度上限 640 → 960,游戏在大面板下显示更大
- **验证**:typecheck 与 70 个单测通过;DSH snapshot0810 实机 + 多视口(1600×900 / 1536×864 / 1366×640 / 1280×600 / 1024×600 / 960×540 / 1600×500)实测均无滚动条
## 游戏玩法与细节
### 🦖 恐龙跳一跳
- 空格 / ↑ / 点击跳跃,↓ 蹲下;速度会**随分数提升**(`320 + 分数×0.15`)直到
760 px/s 上限,越跑越快。
- **分数 = 移动距离 ÷ 10**,持续增长(约 50–150 分/秒)。
- 障碍:单柱仙人掌 / 双柱仙人掌 / **三种鸟**——
- 高空鸟:从站姿头顶飞过,惩罚乱跳;
- 低空鸟:**蹲下可躲**,或**跳到最高点**越过;
- 贴地鸟:紧贴地面,**只能跳跃**躲(蹲下无效)。
- **后期障碍更密**:生成间隔随分数缩短(1.1–2.4s → 0.5–1.2s)。
- **每 800 分切换昼夜**:白天(米色)↔ 黑夜(反白)。
- **雨天机制**:每 1000 分起有 300 分(1000–1300、2000–2300 …)——
斜落雨点 + 迷雾遮挡视线,并**随机闪电全屏白闪**。
- 计分上报节流为每 10 分一次,避免面板频繁刷新。
### 🧱 俄罗斯方块
- ←→ 移动,↑/X 旋转(Z 逆时针),空格硬降,C 暂存,P 暂停。
- 标准 10×20 棋盘、7 种方块(T/S/Z/J/L 采用 3×3 方阵旋转,不截断)、
幽灵落点、下一个/暂存预览、等级加速(每 10 行一级)。
- 画布随面板自适应缩放(devicePixelRatio 高清),高度不足时收缩保比例,顶部不会被截断。
### 🛡️ 坦克大战(带 AI)
- WASD/方向键移动(**自由转向**,车身可贴墙转弯),空格开火,P 暂停,R 重开。
- 碰撞体积略小于一格(32×32 → 26×26),能过略窄通道;撞墙自动回吸网格线,
直行时吸附网格边界,不会卡半格。
- 场景叠加半透明网格线,车道走向一目了然。
- 敌军 AI:贪心追踪 + 视线直射,出生口 2 格宽不卡墙;共 3 波(每波 5 辆)。
- 爆炸特效、出生闪烁无敌、履带动画、波次/生命 HUD。
### 💎 消消乐
- **点击任意格子,消除与它上下左右四连通的同色块**(对角线不算);
- 一次消得越多分越高(平方级:`得分 = 10 × 消除数²`);
- 消除后上方宝石**自由落体**补位(带下落动画、消除闪光、得分飘字),本关内不补新宝石;
- 达到**目标分过关**,目标逐关 **+400**(800 → 1200 → 1600 → …);
- 无 ≥2 的同色块且未达标 → 游戏结束(R 重开);支持鼠标点击与方向键+空格。
- 支持鼠标点击/拖动与键盘(方向键 + 空格)。
### 🔢 华容道
- 16 格数字华容道(15-puzzle):4×4 棋盘,15 个编号方块 + 1 个空位;
- 从已解状态做随机有效滑动来打乱,**保证每次都可解**;
- **点击**空位同行/同列的方块(支持一次推多个);或**方向键**滑动(方块朝箭头方向滑入空位);
- 方块滑动带**插值动画**,在正确位置的方块自动变绿;
- **按最短用时计分**(`max(0, 1000 − 用时×2)`):用时越短分数越高;
- HUD 显示步数 + 计时;完成显示步数/用时,R 或点击重新打乱。
### 🐍 贪吃蛇
- 方向键 / WASD 移动,R 重开,P 暂停。
- 16×12 网格,吃食物变长、+1 分。
- **环面地图**:穿越任意边界会从**对侧镜像位置**继续出现,不会撞墙死亡;
唯一死亡方式是撞到自己身体(即将移出的尾格不算)。
- 棋盘填满即胜利(`over` 同时置为胜态)。
### 🔢 2048
- 方向键 / WASD 滑动合并,R 重开,P 暂停;也支持点击方向按钮。
- 4×4 棋盘,相同数字相邻滑动时合并为两倍并加分(合并分累加进总分);
- 每次有效移动后随机生成新块(90% 为 2、10% 为 4);
- 合成 **2048 达成**(`won`),无任何可移动/合并方向时游戏结束;
- 计分:合并产生的数值累加(合成 2048 的合并即 +2048)。
### 💣 扫雷
- **左键**翻开、**右键**标旗/取消、**双击已翻开的数字**自动展开,R 重开,P 暂停。
- 9×9 棋盘、10 颗雷;**首次点击必定安全**(避开 3×3 安全区布雷);
- 数字 0 自动**洪水展开**周围;全部安全格翻开即胜(`won`);
- **双击展开(chord)**:当周围已标旗数 == 该数字时,自动翻开剩余未开启的
位置——若旗子标错,翻到雷则游戏结束并亮出全部雷;
- **计时与最短用时**:首次点击开始计时(HUD 右上角实时显示),排雷完成
停止;**按用时计分**(`max(0, 1000 − 用时×2)`)上报,面板保留最高分 =
最短通关用时,越快分越高。
### 🃏 记忆翻牌
- 点击翻牌,R 重开,P 暂停。
- 4×4 共 8 对符号,两张成对即消除,全部消除即胜(`finished`);
- 翻到不匹配自动翻回;**步数越少分越高**
(`max(0, 500 − 步数×5)`)。
### ⚫ 五子棋 vs AI
- 点击落子(黑子先行),R 重新开始,P 暂停。
- 15×15 棋盘,**五子连珠(横/竖/斜)即胜**;棋盘满为平局;
- AI 策略:优先**自己连五** → 其次**堵你的连五** → 再按
「进攻 ×1.1 + 防守」启发式打分选点(只考虑已有棋子附近);
- AI 有约 0.5s 的思考停顿,模拟对弈节奏。
### 🦘 跳一跳
- **按住蓄力**(力度条上升)、**松开起跳**,R 重开,P 暂停。
- **高抛物线**:跳起高度显著,空中带地面阴影与方块前倾,跳跃感强。
- 蓄力决定跳距与滞空时间;落到**下一个平台**前进 +1 分,
落点越靠近平台中心额外 +2/+1 分;
- 落回当前平台不扣分继续;**落空(掉下)游戏结束**(带下坠动画);
- **间距与宽度混合分布**:间距近(55–105)约 40%、中(105–140)约 35%、
远(140–160)约 25%;平台宽度**有的宽有的窄**——窄(42–52)约 30%、
普通(56–64)约 40%、宽(72–88)约 30%,窄平台更难精准落中;
- **满蓄力可跨越最远平台**(跳距约 202),但满蓄力会**飞过**近/中平台,
需要按实际间距与宽度调节蓄力,不能无脑满蓄力。
### 🧱 打砖块
- 鼠标 / ←→ 移动挡板,R 重开,P 暂停。
- 480×320 视口:5 行 × 8 列砖墙,小球碰砖即碎、+10×关数 分;
- 挡板反弹角度随**击点位置**变化(打两侧球更斜);
- 清空一墙进入**下一关**:砖墙重建、球速提升(`250 + 关数×20`);
- 3 条命,球落地扣除,扣完游戏结束。
- **颜色机制**:每行砖固定一种颜色(删砖不变色);小球会变成所消除
方块的颜色,**消除同色方块得分 ×3**,连续同色可连锁高分。
### 🔨 打地鼠
- **30 秒限时**:点击冒头的地鼠,R 重开,P 暂停。
- **5×5 草地**(25 洞),**最多 5 只地鼠同时冒头**,每只 0.9–1.6s 后缩回;
- **命中 +1、打空 -1**(最低 0 分);时间耗尽游戏结束。
### ⚫ 黑白棋 vs AI
- 点击落子(黑子先行),R 重开,P 暂停。
- 8×8 奥赛罗:落子**翻转被夹住的对方棋子**;无棋可下自动让位,
双方都无棋可下时**子多者胜**;
- 合法位置有提示点;AI 启发式:**优先占角**、避让角邻位、偏爱边缘,
也考虑当前翻转数与中心机动性。
### 🐦 Flappy
- **点击 / 空格 / ↑ / W** 振翅,R 重开,P 暂停。
- 重力下落、每穿过一对柱子 +1 分、球速随分数略增;
- 撞柱、触地或触顶即结束;小鸟带俯仰与振翅动画。
### 🧩 数独
- 点击选中格子,**1–9 填入 / 0 或退格清除**,方向键移动光标;
- **D 键切换难度**(简单 45 线索 / 普通 35 / 困难 30),R 开新题;
- 题面深色不可改,玩家填入蓝色、**冲突标红**;
- 填满且无冲突即胜;**按用时计分**(`max(0, 1000 − 用时×2)`),
越快分越高,面板保留最短用时。
### 🟡 吃豆人
- **方向键 / WASD** 移动(只在路口转向),R 重开,P 暂停。
- 15×19 迷宫:吃豆 +10、**力量豆 +50 并让幽灵变蓝可反吃**(吃幽灵 +200);
- 幽灵追逐玩家(力量期间反向逃跑);**开局与复活后幽灵有 1.5s 缓冲**
不参与碰撞,不会开局即死;撞到正常幽灵**损失一条命**,
3 条命扣完结束;吃完所有豆子**过关**。
### 🎯 跟枪练习
- **鼠标**转动视角(准星固定在屏幕中央),**左键射击**,R 重开,P 暂停。
- **第一人称场景**:天空 + 透视地面网格,地平线随俯仰移动,右下角手持步枪
viewmodel;
- 靶子在大型世界里**三维漂移**(横向随机变向、**上下高度浮动**、碰壁反弹),
投影到视野中,越远越小;
- 锁定(准星压住靶子)持续得分(10 分/秒);**射击**命中 +20 分,
**开火带后坐力**(视角上跳、随恢复回落)与**随机横向晃动**(快速衰减),
**子弹可见**:发光弹道从枪口飞向目标(命中)或飞向远处(脱靶),
命中目标处有爆炸火花,枪口有火光;
- **30 秒限时**,结束显示总分与**射击命中率**。
## 安装
前置:已构建的 DSH 20260808+ 快照、`pnpm`。
```sh
git clone https://github.com/lhh010/dsh-minigames.git # 或直接使用本目录
cd dsh-minigames
pnpm install
pnpm build
# 装入当前 web profile(自动写入依赖并加入 dsh.profile.bundles)
dsh plugin --profile web add /绝对路径/to/dsh-minigames
# 可选:确认组合配置只出现一个插件行
dsh --profile web --dump-config | grep dsh-minigames
```
插件集合变更在**重启 `dsh web`** 后生效。卸载:
```sh
dsh plugin --profile web remove @dsh-external/dsh-minigames
```
> 本仓库同时携带 `dsh.plugin.json`(registry 通道清单)与 `cordis.patch.yml`
> (官方 profile bundle 通道);二选一安装,不要同时启用。
## 使用
1. 打开 DSH Web UI(`dsh web`),页面右缘出现 🎮 小竖条。
2. 点击竖条 → 面板展开为窗口右半部分。
3. 点击游戏卡片开始;`P` 暂停、`R`(结算后)重开、点「选游戏」返回选择列表。
4. 再次点击「收起」折叠为竖条(游戏自动暂停,进度保留)。
## 开发
```sh
pnpm install
pnpm run typecheck # tsc --noEmit
pnpm run test # vitest 纯逻辑单测(189 个:引擎/棋盘/世界模型/三消/华容道/贪吃蛇/2048/扫雷/翻牌/五子棋/跳一跳/打砖块/打地鼠/黑白棋/Flappy/数独/吃豆人/跟枪/注册表)
pnpm run build # tsc 声明 + tsdown:lib/index.js(node half)+ lib/client.js(浏览器 bundle)
```
产物结构(随源码提交,与 dsh-web-panel 一致):
- `lib/index.js` —— node half(loader 行实现,仅日志;客户端插件扫描依赖该行存在)。
- `lib/client.js` —— 浏览器 bundle,`window.__ModuleLoader__.load({ id:
'@dsh-external/dsh-minigames', factory })`,id 必须与 `package.json` 的
`name` 一致(client-modules 以包名作为 compose 键)。
- `lib/types/` —— 声明文件。
### 架构
```
src/
index.ts node half(loader 行实现)
invariant.ts 不变式伴生文件
client/
index.tsx 客户端插件:DOM portal 挂载面板(ctx.effect 管理生命周期)
app.css 面板样式(全部 dmg- 前缀,随 bundle 注入 <style>)
panel/Panel.tsx 折叠条 / 展开面板 / 游戏选择器 / GameArea 生命周期
games/
types.ts 游戏扩展接口(MiniGameDefinition / MiniGameInstance)
registry.ts 注册表(registerGame / getGames / getGame)
focus.ts 键盘焦点门控(避免劫持聊天输入)
canvas-fit.ts 画布按宿主自适应缩放(devicePixelRatio,防截断)
index.ts 内置游戏注册点
dino/ 纯逻辑(引擎:物理/计分/昼夜/雨天/生成密度)+ 渲染 + 游戏定义
tetris/ 纯逻辑(棋盘:旋转/消行/暂存/等级)+ 渲染 + 游戏定义
tanks/ 纯逻辑(世界:网格/转向吸附/AI/波次/特效)+ 渲染 + 游戏定义
match3/ 纯逻辑(三消:四连通/落体/目标分/关卡)+ 渲染 + 游戏定义
huarong/ 纯逻辑(华容道:滑动/打乱/解状态)+ 渲染 + 游戏定义
snake/ 纯逻辑(贪吃蛇:环面穿越/自撞/成长)+ 渲染 + 游戏定义
game2048/ 纯逻辑(2048:滑动合并/生成/胜负判定)+ 渲染 + 游戏定义
minesweeper/ 纯逻辑(扫雷:布雷/洪水展开/标旗/双击展开)+ 渲染 + 游戏定义
memory/ 纯逻辑(翻牌:配对/步数)+ 渲染 + 游戏定义
gomoku/ 纯逻辑(五子棋:落子/胜负/启发式 AI)+ 渲染 + 游戏定义
hop/ 纯逻辑(跳一跳:蓄力/落地判定/计分)+ 渲染 + 游戏定义
breakout/ 纯逻辑(打砖块:挡板/碰撞/关卡/球速)+ 渲染 + 游戏定义
whack/ 纯逻辑(打地鼠:计时/冒头/得分)+ 渲染 + 游戏定义
othello/ 纯逻辑(黑白棋:翻转/让位/终局/启发式 AI)+ 渲染 + 游戏定义
flappy/ 纯逻辑(Flappy:重力/柱子/碰撞/计分)+ 渲染 + 游戏定义
sudoku/ 纯逻辑(数独:生成/挖洞/冲突/计时)+ 渲染 + 游戏定义
pacman/ 纯逻辑(吃豆人:迷宫/移动/幽灵 AI/力量豆)+ 渲染 + 游戏定义
aimtrack/ 纯逻辑(跟枪:视角转向/三维漂移/射击后坐/晃动/命中率)+ 渲染 + 游戏定义
tests/ 纯逻辑单元测试
```
面板不依赖任何宿主服务与布局槽(纯 `document.body` portal),因此:
- 与主框架版本解耦,`dsh.client.inject` 为空,客户端零 `@deepseek-ai` 依赖;
- 无论 DSH 布局如何变化(左栏/右栏/折叠)都不会冲突。
## 添加新游戏(预留接口)
实现 `MiniGameDefinition`(`src/client/games/types.ts`):
```ts
import { registerGame, type MiniGameDefinition } from './index.ts'
const myGame: MiniGameDefinition = {
id: 'my-game', // 唯一 id(作为选中记忆与最高分 key)
title: '我的游戏',
icon: '🎯',
description: '一句话介绍',
controls: ['空格:跳跃', 'P:暂停'], // 画布下方的按键图例
create(host, options) {
// 在 host 内创建 <canvas>;返回实例:
return {
start() {}, // 启动/恢复主循环
pause() {}, // 暂停(面板折叠/切标签页/用户暂停时调用)
resume() {}, // 恢复
destroy() {}, // 释放 rAF/键盘监听等
}
},
}
registerGame(myGame)
```
`create` 返回的实例由面板驱动生命周期:切换游戏时先 `destroy()` 旧实例再
`create()` 新实例;面板折叠、标签页隐藏或用户点暂停时调用 `pause()`。
分数通过 `options.onScore?.(score)` 上报(仅在变化时调用),面板负责显示与
最高分持久化。建议把游戏逻辑拆成纯函数模块(不碰 DOM/定时器),与现有游戏
一样用单元测试覆盖。
## 已知限制与后续计划
- 键盘控制依赖游戏区域焦点;点击聊天输入框后需点回游戏区域才能继续操作(有意为之)。
- 坦克大战 AI 为贪心追踪 + 视线开火,无寻路;后续可加障碍绕行与不同装甲类型。
- 消消乐与方块/坦克的关卡进度不跨会话保存(仅最高分持久化)。
- 恐龙雨天/昼夜为纯视觉氛围,不影响判定。
Install
dsh plugin --profile web add github:lhh010/dsh-minigames#1bb6d8664281ea8d03cdf82050a398a69222a3ff
Profile: web
With the hub plugin installed, ask your agent to install it by name — it resolves the same plan shown here.
dsh plugin --profile web add github:stvlynn/dsh.fish#path:packages/dsh-plugin-hub
install dsh-external-dsh-minigames from the hub
- This package builds from source on install. pnpm will ask you to allow its build script — that is permission to run the package’s code on your machine, outside the agent sandbox. Only allow sources you trust.