create-chimera-game
v0.2.0
Published
Scaffold a new Chimera game — a self-contained project that installs @chimera-engine/* from npm (default), or an in-monorepo app.
Maintainers
Readme
create-chimera-game
Scaffolds a new Chimera game app from a bundled template. It copies templates/<id>/ (shipped
beside this CLI) into apps/<game>, substitutes the game name into every file's contents and
its file/directory names, and then either emits a self-contained project around it (the
default) or wires it into this monorepo (--workspace).
Usage
# Standalone (default) — a self-contained project that installs @chimera-engine/* from npm.
# Published as `create-chimera-game`, so end users run:
npm create chimera-game@latest <name> # or: pnpm create chimera-game <name>
# In-monorepo (contributors adding an app like apps/tactics):
pnpm create:game <name> [--template <id>] # wraps `… --workspace`<name>— the game name in any casing (my-card-game,My Card Game,myCardGame, …). It is normalised into every casing the template needs (see the token table below). Must contain a letter, start with a letter, and use only letters, digits, and-_space separators.--template <id>— which template to scaffold from. Defaults toblank. The id resolves generically to the bundledtemplates/<id>/; any directory added there is usable with no code change here. An unknown id errors and lists the available ids.--workspace— in-monorepo mode (see below).pnpm create:gamepasses this for you.--out <dir>— standalone mode, but emit into<dir>and skippnpm install(theverify:scaffoldgate drives this).
Re-running against an existing apps/<kebab> errors instead of overwriting it.
Modes
Standalone (default). Creates a self-contained project at <cwd>/<kebab>/ whose lone
workspace member is the app under apps/<kebab>/. It emits the project root the app needs to
install + boot with no monorepo:
package.json— the toolchain (react / three / next / vitest / playwright / electron / …) at the versions the engine was built against, frozen intoolchain.generated.ts, plus a no-opbuild:packagesandpnpm.onlyBuiltDependenciesfor electron/esbuild;pnpm-workspace.yaml(apps/*), a self-containedvitest.config.mts, and atsconfig.jsoncarrying the frozen rootcompilerOptionsthe app's tsconfigsextends;- the app's
@chimera-engine/*deps rewritten fromworkspace:*onto their published^x.y.zranges, andCHIMERA_VERIFY_PACK_NODE_MODULESwired into itsbuild:app/test:e2escripts so the Electron bundler resolves the host from the installed@chimera-engine/electron.
Then pnpm install runs in the new project. Next: cd <kebab>, pnpm --filter @chimera-engine/<kebab> test,
pnpm --filter @chimera-engine/<kebab> build:app.
In-monorepo (--workspace). Writes the app under this repo's apps/<kebab>/ and registers it
(mirroring apps/tactics): adds @chimera-engine/<kebab>: "workspace:*" to the root package.json,
appends a tsconfig.build.json reference and a typecheck line, then pnpm install. Next:
pnpm typecheck, pnpm --filter @chimera-engine/<kebab> build:app.
Both modes validate the name and resolve the template before any write, copy the tree
(skipping node_modules / dist / out / .next), substitute tokens in contents + path
segments, and assert no token survives.
Emitted app layout
The blank template follows the canonical game-app structure (mirroring apps/tactics; see
docs/executive-architecture/module-boundaries-file-tree.md):
apps/<kebab>/
├── simulation/ # deterministic gameplay — actions.ts, constants.ts, visibility-rules.ts;
│ # pure (no DOM/IPC), covered by the apps/*/simulation ESLint zones
├── content/ # content-collection definitions for the Content DB
├── screens/ # game React UI (board screen + registry)
├── renderer/ # per-app Next.js app + register.ts registration seam
├── electron/ # Electron main composition root + build-main.ts bundler
├── e2e/ # Playwright boot-smoke suite
├── assets/ # game-owned binary assets (icon)
├── manifest.ts # GameManifest (registration surface, stays at the root)
├── settings-schema.ts # zod settings schema extending EngineSettings
└── package.json / tsconfig*.json / electron-builder.ymlGrow a game inside this shape: new deterministic gameplay modules go under simulation/
(subsystem subdirectories are fine), UI under screens//scene//shell/, JSON content under
data/.
Token reference
Templates embed these placeholders in file contents and in file/directory names; the scaffolder
replaces each with the corresponding casing of the game name. (The placeholder spellings double
as a worked example of each casing.) Example column uses the input my-card-game.
| Token | Casing | Example |
| ------------------- | -------------- | -------------- |
| __game_kebab__ | kebab-case | my-card-game |
| __gameCamel__ | camelCase | myCardGame |
| __GamePascal__ | PascalCase | MyCardGame |
| __Game Title__ | Title Case | My Card Game |
| __GAME_CONSTANT__ | CONSTANT_CASE | MY_CARD_GAME |
| __gamelower__ | lower (joined) | mycardgame |
Legitimate dunders such as __dirname / __filename are not tokens and are left untouched.
Implementation notes
- Pure tooling: imports only
node:*and sibling modules — the purenormalize.ts/tokens.ts/standalone.tsand the generatedtoolchain.generated.ts. It must not import any@chimera-engine/*package — boundary lint enforces this, keeping it publishable standalone. templates/<id>/is bundled beside this CLI but is not a pnpm workspace member (it holds unsubstituted tokens); only after the copy intoapps/*does the new app become a member.- The exported
scaffoldGame()performs the copy + the per-mode finish (monorepo wiring or standalone-root emission) and is fully unit-tested; thepnpm installstep lives only in the CLI entry, which is excluded under VITEST. - The standalone-root synthesizers in
standalone.tsare shared with theverify:scaffoldgate, which drives this CLI in--outmode and layers packed-tarball overrides on the emitted root — so the gate verifies the exact project the published CLI ships.
