Skip to content
Back to skills

New Minigame

ASecurity

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.

  • 2 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added November 7, 2026
developmentshellnodetesting

Security analysis

A100/100

Scanned November 7, 2026

npx -y skills add DeniSpasovski/mini-games --skill new-minigame --agent claude-code

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.

Security grade badge for New Minigame
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/denispasovski-new-minigame/badge)](https://www.skillsdirectory.com/skills/denispasovski-new-minigame)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
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`).

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.