Desktop-shaped web platform for games built across analytics teams. Consensus Radar remains the multiplayer engine reference; three isolated browser-local classics demonstrate lightweight games without server state. Independently hosted HTTPS games integrate through bridge v1.
Original prototype made one game equal whole application: room persistence, client polling, rules, private data, scoring, translations, and 1,400+ lines of visuals lived together. Database had no game identity. Adding another game meant copying app.
Platform now separates two layers:
- Millennium Desktop owns discovery, windows, entry/exit, plugin slots, and external bridge.
- Optional engine owns room codes, capabilities, polling, locked actions, private projections, and leaderboards.
- Game owns deployment, rules, content, and visuals. It may live here or at any registered HTTPS URL.
cp .env.example .env.local
npm install
npm run devPip's optional repository-aware chat requires OPENROUTER_API_KEY as a server-side deployment secret. Without it, the desktop and games continue to work and Pip reports that chat is not configured. The key is never exposed to the browser.
Production and preview workflows run the idempotent scripts/migrate.mjs before deployment.
Local development also initializes missing tables on first API use. Canonical engine DDL:
db/migrations/0001_game_platform.sql.
npm run check runs ESLint (Next.js, TypeScript, React, and security rules), tests,
workspace type checks, and a production build. npm run scan:security additionally
runs npm audit, Gitleaks, Trivy, actionlint, and zizmor locally. CI also runs CodeQL
while Dependabot opens weekly npm and Actions updates. Scanner versions, container
images, and GitHub Actions are pinned.
npm test
npm run buildExternal game (recommended):
- Host anywhere over HTTPS.
- Implement
game.ready/host.init/game.exitbridge v1. - Register strict manifest through
POST /api/platform/games. - Desktop handles launch and return; no platform source contribution needed.
Internal engine game:
- Create
games/<game-id>/manifest.ts,model.ts,server.ts, and client component. - Implement
createState,reduce,project, andleaderboardEntryin server module. - Register manifest in
games/catalog.ts, server rules inlib/engine/server/registry.ts, client ingames/client-registry.tsx. - Use
useGameRoom()in client; send semantic actions, never replacement room state.
Browser-local game:
- Create
games/<game-id>/manifest.tsand a client component. - Keep gameplay/state/assets inside that workspace.
- Register manifest in
games/catalog.tsand client ingames/client-registry.tsx. - No room API or database code required.
See docs/ADDING_A_GAME.md, docs/EXTERNAL_GAMES.md, and in-app /develop page.
app/ desktop entry, dynamic game route, APIs
components/desktop/ window manager and bridge host
games/ isolated internal game workspaces
packages/ bridge and plugin SDK workspaces
plugins/ desktop plugin workspaces
lib/engine/client/ reusable browser room client
lib/engine/server/ registry, room store, leaderboards
db/migrations/ PostgreSQL schema
docs/ architecture + author guide
Built-ins: Chess, Consensus Radar, Minefield, upstream Classic Pinball, and Paintbox. Desktop plugins: Pip Assistant, Sticky Note, Game Shuffle, and Game Counter.