# dsh-minigames [简体中文](./README.md) | **English** Floating mini-games window in the DSH Web UI: a slacking-off companion for killing time while waiting for model replies or fixing bugs. - **Collapsed state**: hiding the window leaves a round floating 🎮 button (bottom-right by default) that you can **freely drag** and whose position is remembered — releasing after a drag (> 5px travel) does NOT reopen the window; only a **click** does. - **Expanded state**: a floating mini-games window — **drag the title bar** to move it anywhere; releasing near a screen edge auto-**snaps** to that edge (left/right docking, top/bottom edge-hugging). Position, dock state, and width persist across reloads; default width is min(50vw, 640px), draggable on its left edge between 360px–80vw, and you can freely pick a game inside the panel. - **Games** (all offline, zero asset files, Canvas-rendered): 1. 🦖 **Dino Run** — the classic Chrome T-Rex (day/night/rain); 2. 🧱 **Tetris** — classic falling-block line clearing; 3. 🛡️ **Tank Battle (with AI)** — 2D tank combat, enemy tracking + line-of-sight firing, 3 waves total; 4. 💎 **Match-3** — click to clear four-connected same-color blocks; pass levels by reaching target scores that increase level by level; 5. 🔢 **Huarong Pass** — 16-tile number puzzle (15-puzzle); slide tiles into order; the faster you are, the higher the score; 6. 🐍 **Snake** — classic snake; crossing a boundary makes you emerge from the opposite side (toroidal map); 7. 🔢 **2048** — slide with arrow keys to merge numbers; merging into 2048 wins; 8. 💣 **Minesweeper** — left-click to reveal, right-click to flag, double-click a number to auto-expand its surroundings; 9. 🃏 **Memory Match** — flip two to pair them up; fewer moves mean a higher score; 10. ⚫ **Gomoku vs AI** — 15×15; the AI both attacks and blocks you; 11. 🦘 **Hop** — hold to charge, release to jump; the closer your landing, the more points; 12. 🧱 **Breakout** — move the paddle to bounce the ball; clearing a wall advances to the next level with increasing ball speed; 13. 🔨 **Whack-a-Mole** — 30-second timed clicking; hit +1, miss −1; 14. ⚫ **Othello vs AI** — 8×8 Othello; corners matter most; auto-passes when no move is available; 15. 🐦 **Flappy** — click/space to flap through pipe gaps; the farther, the higher the score; 16. 🧩 **Sudoku** — 9×9 standard sudoku; D key switches difficulty; filling with no conflicts wins; 17. 🟡 **Pac-Man** — classic maze munching; power pellets let you eat the ghosts back; 18. 🎯 **Aim Training** — FPS aim practice: locked mouse turns the view to track a 3D drifting target; left-click shoots with recoil. - **Reserved extension interface**: a game registry (`registerGame`) — adding a game only requires implementing one interface. - **Experience details**: games auto-pause when the window is hidden or the tab is switched, and resume when you come back; each game's high score is stored in localStorage; keyboard input only takes effect after clicking the game area and never hijacks the chat input box. - **Responsive sizing**: the game canvas adapts to the panel's **real available space** (toolbar + canvas + control hints always display fully with no scrollbars; browser zoom and panel drag-resizing reflow automatically), with width/height caps of 960px. ## Installation Prerequisites: a built DSH 20260808+ snapshot and `pnpm`. ```sh # Option 1: pinned-tag git dependency (public mirror, recommended; github:omdsh-dev/dsh-minigames also works) dsh plugin --profile web add '@dsh-external/dsh-minigames@github:omdsh-dev/dsh-minigames#v0.3.7' # Option 2: local install git clone https://github.com/omdsh-dev/dsh-minigames.git cd dsh-minigames pnpm install pnpm build # Install into the current web profile (writes the dependency and adds it to dsh.profile.bundles) dsh plugin --profile web add /absolute/path/to/dsh-minigames # Optional: confirm the composed config lists the plugin once dsh --profile web --dump-config | grep dsh-minigames ``` > **Install tips**: pnpm 11 may block node-pty build scripts on first install — run `pnpm approve-builds --all` under `~/.dsh/profiles/web` and re-run the install; then **hard-refresh the browser** (Ctrl/Cmd+Shift+R). ### Prompt install (let DSH install it) Paste this prompt into any DSH session and the agent installs it for you: > Install the dsh-minigames plugin (DSH floating minigames window plugin): > 1. Run `dsh plugin --profile web add '@dsh-external/dsh-minigames@github:omdsh-dev/dsh-minigames#v0.3.7'` (the first run may fail because pnpm 11 blocks node-pty build scripts) > 2. Under `~/.dsh/profiles/web`, run `pnpm approve-builds --all` (approve the build scripts) > 3. Re-run the install command from step 1 > 4. Remind me to hard-refresh the browser (Ctrl/Cmd+Shift+R) > On errors, first check the FAQ/known limitations in the README at https://github.com/omdsh-dev/dsh-minigames. Plugin-set changes take effect after **restarting `dsh web`**. To uninstall: ```sh dsh plugin --profile web remove @dsh-external/dsh-minigames ``` > This repository ships both `dsh.plugin.json` (registry-channel manifest) and `cordis.patch.yml` > (official profile bundle channel); install through one of them — never enable both at once. est includes `@dsh-external/dsh-minigames` and `/plugins/@dsh-external/dsh-minigames/client.js` returns 200 — this plugin is a pure browser bundle (a `document.body` portal) with no host-service or slot dependencies, zero change on 0.1.1-rc.1), while remaining compatible with `@deepseek-ai/dsh@0.0.1-rc.5` (dist-tag `next`, i.e. the npm release of the final snapshot snapshot0812; `npm exec -p @deepseek-ai/dsh@0.0.1-rc.5 -- dsh --profile web --port ` accesses the pinned version and starts it in lib production mode), while also staying compatible with `@deepseek-ai/dsh@0.0.1-rc.2` (the npm release of snapshot0811). Tested against the npm rc.5 baseline: after `dsh web` starts, the `window.__DSH_BOOT__` manifest includes `@dsh-external/dsh-minigames`, and `/plugins/@dsh-external/dsh-minigames/client.js` returns 200; typecheck, build, and 201 unit tests pass. Note: starting with 0811 the vendored cordis was renamed to `@deepseek-ai/cordis` (npm releases no longer publish a vendored package under the `cordis` name). This plugin's source imports cordis only as types (`src/index.ts`, `src/client/index.tsx`, `src/invariant.ts`), and the type imports plus peer/devDependencies have been migrated to `@deepseek-ai/cordis` (peer `^4.0.1-rc.1`, which is `4.0.1-rc.4` on the npm rc.5 baseline) — the build output (lib/*.js) has zero cordis runtime imports, a plain `npm install` no longer raises ERESOLVE, and `--legacy-peer-deps` is unnecessary. ### 0811 compatibility notes (snapshot0811, verified on a live instance) - **Bundle mechanism unchanged**: 0811 still supports the composite bundle-layer mechanism `dsh.bundle.patch` → `cordis.patch.yml` (this plugin's profile bundle install method stays the same); client `dsh.client` metadata discovery and the `window.__ModuleLoader__` loading protocol are both unchanged. - **cordis rename**: 0811 renamed the vendored cordis from `cordis@4.0.0-rc.7` to `@deepseek-ai/cordis@4.0.1-rc.1`. This plugin imports cordis only as types, and the build output has zero cordis runtime imports — the rename does not affect runtime loading of already-built bundles; on the npm baseline, typecheck of the bare `cordis` import resolving to the public `cordis` package still passes; see the alignment suggestion above. - **Live-instance boot verification**: after web starts on snapshot0811 (`snapshots/20260811T152241Z`), the `window.__DSH_BOOT__` manifest includes `@dsh-external/dsh-minigames`, `/plugins/@dsh-external/dsh-minigames/client.js` returns 200, and the right-side panel (🎮 mini-games) renders as verified on a live instance. typecheck and 201 unit tests pass against the 0811 baseline. ### 0812/final snapshot compatibility notes (snapshots/20260812T172954Z-final, verified on a live instance) - **cordis rename in effect**: this plugin has migrated its type-only imports (`src/index.ts`, `src/client/index.tsx`) and `peerDependencies`/`devDependencies` to `@deepseek-ai/cordis` (`^4.0.1-rc.1`; `@deepseek-ai/cordis@4.0.1-rc.4` on the npm rc.5 baseline) — the build output (lib/*.js) has zero cordis runtime imports, typecheck is fully green for npm rc.5 consumers, and `npm install` needs no `--legacy-peer-deps`. - **Bundle mechanism unchanged**: the final snapshot still supports the composite bundle-layer mechanism `dsh.bundle.patch` → `cordis.patch.yml`; client `dsh.client` metadata discovery and the `window.__ModuleLoader__` loading protocol are unchanged; the panel depends on no host services or layout slots (a pure `document.body` portal), decoupling it from the main framework's version. - **Live-instance boot verification**: after web starts on the final snapshot (`snapshots/20260812T172954Z-final`), the `window.__DSH_BOOT__` manifest includes `@dsh-external/dsh-minigames` and `/plugins/@dsh-external/dsh-minigames/client.js` returns 200; the boot manifest after starting `dsh web` as an npm rc.5 consumer also includes this plugin. typecheck, build, and 201 unit tests pass against the final-snapshot baseline. ## Changelog ### 2026-08-22 · v0.3.6 — Fix Tetris landed-row not clearing (lock delay) - **Root cause**: after reaching its final cell the piece did not merge immediately; it waited for the next gravity tick to fail before locking + clearing — up to **800ms** of hover at level 1, during which a completed row looked like it "should clear but didn't". At high levels the opposite applied (120ms), making it impossible to slide pieces into the leftmost column and leaving permanently one-cell-short rows. - **Fix**: standard **lock delay** — a landed piece stays controllable for 400ms (slide/rotate refreshes the window, max 15 refreshes per piece against infinite stalling), then auto-locks and clears immediately; Space hard drop / Down soft drop at the floor still lock instantly. Added a self-check in `lock()`: any full row surviving a clear logs an error (impossible by construction). - **Verification**: 2 new unit tests for `isLanded`/`lock` (with conservation assertion); all 203 tests pass; typecheck and build clean. ### 2026-08-20 · v0.3.5 — Declare DSH 0.1.1-rc.1 compatibility (real boot verification) - **Verification**: real boot verification passed on DSH npm `0.1.1-rc.1` — the boot manifest includes `@dsh-external/dsh-minigames` and client.js returns 200; the plugin is a pure browser bundle (a `document.body` portal) with no host-service or slot dependencies, so all 18 games behave unchanged on 0.1.1-rc.1 ### 2026-08-20 · v0.3.4 — Fix inverted Othello HUD disc symbols - **Fix**: the Othello HUD and end-of-game score used disc symbols counter-intuitively — the filled `●` was paired with the black (player) count and the hollow `○` with the white (AI) count, which read as if the score or winner was computed wrong. Now `○` (hollow) = black (player) and `●` (filled) = white (AI), matching the discs on the board; placement/flip/end-of-game logic is unchanged (verified with 300 simulated random games). ### 2026-08-16 · v0.3.3 — Floating window and draggable 🎮 launcher - **Floating window**: the collapsed rail is replaced by a round floating 🎮 button; the expanded state is a draggable, edge-snapping (left/right docking, top/bottom edge-hugging) floating window with position, dock state, and width persisted - **Draggable 🎮 button**: dragging (> 5px travel) moves the button and clamps it to the viewport; releasing remembers the position (`dsh-minigames:launcher`) without opening the window; a click without travel opens it - **Resize fix**: dragging the left edge now anchors to the window's actual right edge (the old math assumed the right edge touched the viewport) - **Accessibility**: the collapsed state is now a native `