Add a new mini game to the Mini Game Portal (folder, game.json manifest, pages, thumbnail, tests, docs). Use when the user wants to start a new game or add a page/tool to an existing game.
Installs into .claude/skills of the current project.
Are you the author of New Minigame?
Add the live security badge to your README. It updates with every re-scan.
[](https://www.skillsdirectory.com/skills/denispasovski-new-minigame)
---
name: new-minigame
description: Add a new mini game to the Mini Game Portal (folder, game.json manifest, pages, thumbnail, tests, docs). Use when the user wants to start a new game or add a page/tool to an existing game.
---
# Add a mini game to the portal
The portal and the Rsbuild config discover games from `src/games/<id>/game.json`.
No central registry needs editing.
## Steps
1. Pick a short id (`[a-z0-9_-]`), create `src/games/<id>/`.
2. Write `game.json` (schema: `src/portal/manifest.ts`):
```json
{
"id": "<id>",
"title": "My Game",
"version": "0.1.0",
"description": "One short sentence for the portal cover.",
"genre": "Arcade",
"inputs": "keyboard, touch",
"accent": "#4fc27a",
"onAccent": "#0b1a10",
"pages": [
{
"id": "play",
"entry": "pages/play.ts",
"title": "My Game",
"label": "Play"
},
{
"id": "level-viewer",
"entry": "pages/level-viewer.ts",
"title": "My Game · Levels",
"label": "Levels",
"dev": true
}
]
}
```
- `play` is served at `/games/<id>/`; other pages at `/games/<id>/<page-id>.html`.
- `dev: true` pages show as text links under the card's "Tools" toggle.
- `accent` / `onAccent` colour the game's cover (Play, hover outline): 6:1 against `#101216`, 4.5:1 for the text on the accent. Rules: `src/portal/STYLEGUIDE.md`.
- Links must be relative (the build may be hosted in a sub-folder): portal = `../../`, sibling page = `<page-id>.html`, main page = `./`. Never use a leading `/`.
- The game builds into its own self-contained `dist/games/<id>/` (own Rsbuild environment, picked up automatically). Load runtime files relative to the page (`new URL('models/x.glb', location.href)`) or import them, never from the portal root; a game-only file in the root `public/` needs a `gamePublicFiles` entry in `rsbuild.config.ts`.
- The play page's main menu (and pause / results screens) must offer an **All games** button when `portalUrl()` (`src/shared/portal-link.ts`) is not null - installed as a PWA there is no browser back button.
3. Entry files: the default HTML template has `<div id="root">`. Import page CSS from the entry.
Use three.js unless the user asked otherwise. Reuse `src/shared/*`:
- `tool-page.ts` (`toolPanel()`: the left tool menu in the portal look, portal `STYLEGUIDE.md` -> Tool pages), `url-state.ts` (bookmarkable state), `stats-overlay.ts` (F3)
- `rng.ts` / `noise.ts` for anything procedural (seeded!)
4. Portal screenshot: in the play page call
`installThumbnailCapture('<id>', () => { renderer.render(scene, camera); return renderer.domElement; })`,
run `npm run dev`, open the game, press **F9** -> writes `src/games/<id>/thumbnail.jpg` (1280x720) and `thumbnail-640.jpg` (the cover's srcset).
- Title face: a `wordmark.svg` next to `thumbnail.jpg` (`scripts/portal/wordmarks.py <font.woff2> "Title" src/games/<id>/wordmark.svg`); without one the cover shows the plain title.
- Audio: the game's audio class (WebAudio / `Audio`) must start silent when `isMutedByUrl()` (`src/shared/mute-param.ts`, `?mute=1`) is true. **When you open the game in the browser pane to test, always add `mute=1` to the URL** - no sound while creating / editing, unless the task is a sound fix (then no param, low volume).
5. Add the game to `GAME_LIST` in `src/portal/release.ts` (card order). Work in progress? Give it `hideInProd: true` there: the release build gives the game no portal card but still builds it, so people with the link (`games/<id>/`) can play it. The dev server and `build:test` list it. Remove the flag to release.
6. Restart `npm run dev` after adding a new game folder / page (entries are read at startup).
7. Tests in `tests/<id>/`, a `test:<id>` npm script and a CI job (`testing` skill); keep game logic DOM-free so it is testable in node.
8. Write the docs short (`AGENTS.md` "Write short"). Add `src/games/<id>/README.md` (high level: what it is, screenshot, how to play, feature list, links) and `src/games/<id>/DETAILS.md` (pages, keys, rules, architecture), and a row in the root `README.md` table.
9. Verify: `npx tsc --noEmit -p tsconfig.json`, `npm run lint`, `npm run test`, `npm run build`.
## Patterns worth copying from rally
- Fixed-step simulation + render interpolation (`src/games/rally/game/rally-game.ts`).
- `benchmark(n)` method exposed on `window.__<game>` to measure ms/frame even when the tab is hidden.
- Tool pages built on a shared shell (`src/games/rally/debug/viewer-shell.ts`).