dsh-minigames
简体中文 | 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.
Version compatibility
Compatible with DSH snapshot0810 (snapshots/20260810T155924Z), snapshot0811 (snapshots/20260811T152241Z), and the final snapshot snapshot0812 (snapshots/20260812T172954Z-final): it is a pure browser-side bundle (the node half is only a loader placeholder), with client metadata declared as nested dsh.client — snapshot0810's ClientModuleHostService reads only that field, and a top-level dshClient is silently ignored (no logs, no errors, and the plugin never enters the boot graph). Verified against 0810 on a live instance; boot verification passed on live instances of 0811 and the final 0812 snapshot (see below).
npm release compatibility: compatible with the DSH npm release @deepseek-ai/dsh@0.1.1-rc.1 (v0.3.5 real boot verification: after dsh --profile web starts, the boot manifest 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 <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); clientdsh.clientmetadata discovery and thewindow.__ModuleLoader__loading protocol are both unchanged. - cordis rename: 0811 renamed the vendored cordis from
cordis@4.0.0-rc.7to@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 barecordisimport resolving to the publiccordispackage still passes; see the alignment suggestion above. - Live-instance boot verification: after web starts on snapshot0811 (
snapshots/20260811T152241Z), thewindow.__DSH_BOOT__manifest includes@dsh-external/dsh-minigames,/plugins/@dsh-external/dsh-minigames/client.jsreturns 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) andpeerDependencies/devDependenciesto@deepseek-ai/cordis(^4.0.1-rc.1;@deepseek-ai/cordis@4.0.1-rc.4on the npm rc.5 baseline) — the build output (lib/*.js) has zero cordis runtime imports, typecheck is fully green for npm rc.5 consumers, andnpm installneeds no--legacy-peer-deps. - Bundle mechanism unchanged: the final snapshot still supports the composite bundle-layer mechanism
dsh.bundle.patch→cordis.patch.yml; clientdsh.clientmetadata discovery and thewindow.__ModuleLoader__loading protocol are unchanged; the panel depends on no host services or layout slots (a puredocument.bodyportal), decoupling it from the main framework's version. - Live-instance boot verification: after web starts on the final snapshot (
snapshots/20260812T172954Z-final), thewindow.__DSH_BOOT__manifest includes@dsh-external/dsh-minigamesand/plugins/@dsh-external/dsh-minigames/client.jsreturns 200; the boot manifest after startingdsh webas 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-minigamesand client.js returns 200; the plugin is a pure browser bundle (adocument.bodyportal) 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
<button>instead of<div role="button"> - Verification: typecheck and 201 unit tests pass; live-loading verification passes
2026-08-11 · v0.3.2 — Dino Run character polish
- 🦖 Dino: redrawn from the classic pixel matrix — big head facing right, upturned tail, streamlined body,
two running legs (tucked while jumping), white pixel eye; near-black in day, inverted to white at night
- 🐦 Bird: rounded body + forward-reaching head + pointed beak + flapping wings + tail, dual color palettes
- 🌵 Cactus: rounded dome + bent arms + vertical rib lines + top highlight; same for the two-cactus variant
- Verification: typecheck and 201 unit tests pass; live-loading verification passes
2026-08-11 · v0.3.1 — Aim Training becomes FPS-style, plus polish across games
- 🎯 Aim Training FPS-ified: Pointer Lock mouse capture (cursor hidden), crosshair fixed at screen center,
mouse-delta view rotation (with pitch; vertical direction fixed), 3D drifting target (lateral movement + height floating), left-click shooting (recoil kicks the view up then it recovers + random lateral sway that decays + visible bullet tracers and hit sparks), first-person rifle viewmodel in the bottom-right, muzzle flash on firing, pause/start overlay hints
- 🔨 Whack-a-Mole: 3×3 → 5×5 (25 holes), up to 5 moles up at once
- 🟡 Pac-Man: mouth complement animation (open/close), ghost walking and eye-turning,
grid-aligned movement (no more center/wall jitter), snapping back to center on wall hits without getting stuck, opening ghost grace period, ghost spawn points moved to both ends of the upper corridor
- Removed: 🏓 Pong
- Verification: typecheck and 201 unit tests pass; live-loading verification passes
2026-08-11 · v0.3.0 — 6 new mini-games (18 total, Pong removed afterwards)
- New games: 🔨 Whack-a-Mole (up to 3 up at once), ⚫ Othello vs AI, 🐦 Flappy,
🧩 Sudoku (three difficulties + timer), 🟡 Pac-Man (dual-ghost AI + power pellets)
- Removed: 🏓 Pong (poor gameplay experience)
- Verification: typecheck and 189 unit tests pass; live-loading verification passes
2026-08-11 · v0.2.0 — 7 new mini-games and detail polish
- New games (12 total): 🐍 Snake (toroidal crossing), 🔢 2048, 💣 Minesweeper (double-click expand),
🃏 Memory Match, ⚫ Gomoku vs AI, 🦘 Hop, 🧱 Breakout
- Snake: crossing a boundary continues from the mirrored position on the opposite side instead of dying against a wall
- Minesweeper: double-click an already-revealed number; when the flagged count around it equals the number, the remaining unrevealed cells auto-open
- Verification: typecheck and 128 unit tests pass; live-loading verification passes
2026-08-11 · v0.1.1 — snapshot0810 adaptation and panel responsive-sizing fix
- Migration: package.json client metadata migrated from top-level
dshClientto nesteddsh.client(inject kept as-is) - Fix: no more vertical scrollbar when the panel's available height is insufficient —
.dmg-bodyswitched to a flex column layout, the game area gets the real available height, and the canvas adapts as a whole ("toolbar + canvas + control hints") (previously the canvas height was determined by its own content, creating circular measurement; on narrow windows the canvas overflowed and triggered a scrollbar) - Bigger: canvas display width cap 640 → 960, games render larger on big panels
- Verification: typecheck and 70 unit tests pass; verified on a live DSH snapshot0810 instance plus multiple viewports (1600×900 / 1536×864 / 1366×640 / 1280×600 / 1024×600 / 960×540 / 1600×500) with no scrollbars
Gameplay and details
🦖 Dino Run
- Space / ↑ / click to jump, ↓ to duck; speed increases with score (
320 + score×0.15) up to a
760 px/s cap — the longer you run, the faster you go.
- Score = distance moved ÷ 10, growing continuously (roughly 50–150 points/second).
- Obstacles: single cacti / double cacti / three bird types —
- High-flying bird: passes over the standing dino's head — punishes random jumping; - Low-flying bird: duck to dodge, or jump to the apex to clear it; - Ground-hugging bird: hugs the ground, only jumping dodges it (ducking is useless).
- Denser obstacles later on: spawn intervals shrink with score (1.1–2.4s → 0.5–1.2s).
- Day/night switches every 800 points: day (beige) ↔ night (inverted white).
- Rain mechanic: from every 1000 points, a 300-point window (1000–1300, 2000–2300, …) —
slanting rain + mist that obscures the view, plus random lightning with full-screen white flashes.
- Score reporting is throttled to once per 10 points to avoid frequent panel refreshes.
🧱 Tetris
- ←→ move, ↑/X rotate (Z counterclockwise), space hard drop, C hold, P pause.
- Standard 10×20 board, 7 tetrominoes (T/S/Z/J/L rotate within a 3×3 matrix without truncation),
ghost piece, next/hold previews, level acceleration (one level per 10 lines).
- The canvas scales with the panel (devicePixelRatio hi-DPI); when height is insufficient it shrinks to preserve aspect ratio without truncating the top.
🛡️ Tank Battle (with AI)
- WASD/arrow keys to move (free steering — the hull can turn while hugging walls), space to fire, P pause, R restart.
- The collision box is slightly smaller than one cell (32×32 → 26×26), letting you pass through slightly narrow lanes; hitting a wall snaps
you back onto the grid lines, and driving straight snaps you to grid boundaries — no getting stuck half-way.
- The scene overlays translucent grid lines so lane directions are obvious at a glance.
- Enemy AI: greedy tracking + line-of-sight shooting; the 2-cell-wide spawn opening doesn't block them; 3 waves total (5 tanks each).
- Explosion effects, spawn-invincibility flashing, track animations, wave/lives HUD.
💎 Match-3
- Click any tile to clear all same-color tiles connected to it in four directions (diagonals don't count);
- The more you clear at once, the higher the score (quadratic:
score = 10 × cleared²); - After clearing, gems above fall freely to fill gaps (with fall animations, clear flashes, and floating score text); no new gems are added within a level;
- Reaching the target score passes the level, and the target increases by +400 per level (800 → 1200 → 1600 → …);
- No same-color group ≥2 and target unmet → game over (R restarts); mouse click and arrow keys + space are supported.
- Supports mouse click/drag and keyboard (arrow keys + space).
🔢 Huarong Pass
- 16-tile number puzzle (15-puzzle): a 4×4 board with 15 numbered tiles + 1 empty slot;
- Shuffling is done via random valid slides from the solved state, guaranteeing every puzzle is solvable;
- Click a tile in the same row/column as the empty slot (multiple tiles can be pushed at once); or slide with arrow keys (tiles slide into the empty slot in the arrow's direction);
- Tiles slide with interpolation animation, and tiles in their correct positions turn green automatically;
- Scored by fastest time (
max(0, 1000 − time×2)): the shorter the time, the higher the score; - The HUD shows moves + elapsed time; on completion it shows moves/time; R or a click reshuffles.
🐍 Snake
- Arrow keys / WASD to move, R restart, P pause.
- 16×12 grid; eating food grows the snake and scores +1.
- Toroidal map: crossing any boundary makes you emerge at the mirrored position on the opposite side instead of dying against a wall;
the only way to die is hitting your own body (the tail cell about to move out doesn't count).
- Filling the entire board wins (
overis then flagged as a win state).
🔢 2048
- Arrow keys / WASD to slide and merge, R restart, P pause; on-screen direction buttons are also supported.
- 4×4 board; when equal numbers slide into each other they merge into double and score points (merge points accumulate into the total);
- After every valid move a new tile spawns at random (90% are 2s, 10% are 4s);
- Merging into 2048 wins (
won); when no move or merge direction remains, the game is over; - Scoring: the values produced by merges accumulate (the merge that creates 2048 alone is +2048).
💣 Minesweeper
- Left-click to reveal, right-click to flag/unflag, double-click an already-revealed number to auto-expand, R restart, P pause.
- 9×9 board with 10 mines; the first click is always safe (mines are placed outside a 3×3 safe zone);
- A revealed 0 auto-flood-expands its surroundings; revealing every safe cell wins (
won); - Double-click expand (chord): when the number of flags around a cell equals that number, the remaining unrevealed cells auto-open —
if a flag was wrong, hitting a mine ends the game and reveals all mines;
- Timer and fastest time: timing starts at the first click (shown live in the HUD's top-right) and stops when sweeping finishes;
scored by time (max(0, 1000 − time×2)) and reported, with the panel keeping the best score = fastest clear time; the faster, the higher the score.
🃏 Memory Match
- Click to flip cards, R rest
…