@moku-labs/game 0.5.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/llms.txt CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > 2D puzzle game engine on TypeScript, built as a Layer-2 framework on @moku-labs/core. The game is a deterministic graph of business logic. State commits only on edges. Position is data. Player input and world events are answers a node waits for. The screen is a projection of committed state. V1 is the logic plugins `time`, `lifecycle`, `model`, `clock`, `flow` and a headless testing entry; V2 adds the screen plugins `world`, `renderer`, `input`, `assets`, `scenes`, a Pixi v8 renderer loaded lazily, and the `@moku-labs/game/assets` entry that generates typed asset keys. V3 adds the interface plugins `anim`, `i18n`, `text`, `ui` (`screen` lists all nine) and the opt-in `audio`: choreographies as data, strings as data, text from MSDF fonts, screens in JSX laid out by Yoga, sound as an effect a node awaits. V4 adds two doors for the editor: `@moku-labs/game/inspect` reads a running game, `@moku-labs/game/control` drives a dev build. V5 adds the opt-in plugin `effects`: particles and WGSL/GLSL filters as components. V6 adds the opt-in plugin `platform`: the Back button, haptics and keep-awake through a provider the game passes. The package is published on npm as `@moku-labs/game`, and this file ships inside it.
4
4
 
5
- Facts: Bun only. ESM only. `"sideEffects": false`. `pixi.js` `^8.0.0` is a peer dependency, no V1 code imports it. `playwright-core` (visual tests) and `sharp` (the asset pack) are optional peers. Node >= 24, Bun >= 1.3.14. TypeScript strict with `exactOptionalPropertyTypes` and `noUncheckedIndexedAccess`. The engine ships no genre rules: no merge, no match-3, no physics. A game brings its own pure rule functions.
5
+ Facts: Bun only. ESM only. `"sideEffects": false`. `pixi.js` `^8.0.0` is a peer dependency, no V1 code imports it. `playwright-core` (visual tests), `sharp` (the asset pack) and `typescript` (the project index) are optional peers. Node >= 24, Bun >= 1.3.14. TypeScript strict with `exactOptionalPropertyTypes` and `noUncheckedIndexedAccess`. The engine ships no genre rules: no merge, no match-3, no physics. A game brings its own pure rule functions.
6
6
 
7
7
  ## Entry points
8
8
 
@@ -13,6 +13,7 @@ Facts: Bun only. ESM only. `"sideEffects": false`. `pixi.js` `^8.0.0` is a peer
13
13
  - `@moku-labs/game/control`: the write door of the editor, dev builds only. See "Doors for the editor".
14
14
  - `@moku-labs/game/hot` (the Bun dev server only): the `bunfig.toml` plugin that hot swaps views in a running page. See "Hot swap".
15
15
  - `@moku-labs/game/lint`: the oxlint JS plugin `moku-game` with the game lint rules. See "Lint for games".
16
+ - `@moku-labs/game/project` (node and bun only): the project index, where every engine id of a game is defined, line read fresh at the call. The package bin `moku-game-index` runs it. See "Project index".
16
17
  - `@moku-labs/game/fonts/*`: the shipped MSDF body font and its licence. See "Fonts".
17
18
  - `@moku-labs/game/jsx-runtime` and `@moku-labs/game/jsx-dev-runtime`: what `"jsxImportSource": "@moku-labs/game"` resolves to. A game never imports them by hand.
18
19
 
@@ -503,6 +504,26 @@ Two subpaths, neither on the root (V4). An editor, MCP tools and e2e scripts rea
503
504
  - A command's effect is `read`, `route`, `cosmetic`, `cheat` or `raw`. A `cheat` or `raw` command taints the session and is journaled; read it with `sources.tainted` and `sources.cheats`. Of the base commands only `restore` is `raw`. `bookmark` answers `flow.bookmark()` plus `scene`, the mounted scene; `restore` calls `scenes.expect(scene)` before `flow.restore`, so a bookmark at a popup restores the scene under it.
504
505
  - A game's own: `defineSource({ id, title, input, changes, read })` with `changes` `"frame"`, `"commit"` or `"edge"`, and `defineCommand({ id, title, input, effect, run })`. The id is camelCase words joined by dots, at least two: `dice.rolls`. An input schema maps field names to `"string"`, `"number"`, `"boolean"` or `"json"`; a trailing `?` makes one optional. A command body starts with `if (typeof __MOKU_GAME_DEV__ === "undefined" || !__MOKU_GAME_DEV__) throw controlRefused();`. Keep them in `.dev` modules that only the dev entry and the tests import.
505
506
 
507
+ ## Project index
508
+
509
+ `@moku-labs/game/project` maps every engine id of a game to anchors (a path plus a binding, a key or a component), never to line numbers; `find` reads the line from the file on disk at the call. `typescript` (`>=5.5`) is an optional peer: a game that uses the index adds it as a dev dependency. Nothing is persisted. The contract is in `docs/project-index.md`.
510
+
511
+ ```ts
512
+ import { openProject } from "@moku-labs/game/project";
513
+
514
+ const project = await openProject({ root: "tests/integration/merge-game" });
515
+ (await project.find("node:board/merge"))[0]?.line; // 17, in "nodes/merge.ts"
516
+ const stop = project.watch((index, change) => refresh(index.revision, change.moved));
517
+ stop();
518
+ project.close();
519
+ ```
520
+
521
+ - `openProject({ root, manifest?, debounceMs? })` resolves `ProjectApi`: `index` (frozen, replaced per batch), `find(key)` (a `Found[]`: the anchor plus `line`, `range` `[startLine, startCol, endLine, endCol]` 1-based with an exclusive end column, `hash`, and `broken: true` when the file does not parse now), `watch(onIndex)` (one call per batch that changed bytes, with `(index, change)`; returns the stop function), `changed(path)` (re-index one root-relative path now, no watch call), `close()`. Without `typescript` it rejects with `[game] The project index needs the "typescript" package.`
522
+ - Keys: `flow:<id>`, `node:<flow>/<node>` (every entry of a `nodes` table: node, sub-flow, slot), `feature:<id>`, `scene:<id>`, `projection:<name>`, `emitter:<id>`, `textStyle:<key>`, `style:<path>#<binding>` (a module-level `const` of `defineStyle`), `jsx:<key>`. Definers are recognised by binding from the kit's `defineGame()` destructure, renamed imports too. A non-literal id goes to `index.unresolved` with the reason, never guessed.
523
+ - JSX keys are patterns: literal text stays, same-file consts and functions are followed, `props.id` becomes `{id}`, any other hole `*`. `` key={`${id}Picture`} `` reads `jsx:card*Picture` (stem `card`); `id="settingsBoard"` on `<Signboard>` reads `jsx:settingsBoard` (kind `idProp`, component `Signboard`). `find("jsx:settingsBoardClose")`, a key `game.locate` reports, answers the `{id}Close` pattern of the kit and the `id=` prop that fills it.
524
+ - `ProjectChange` is `{ revision, files, moved: [{ key, from, to }], removed }`. A broken file keeps its last good keys and gets `files[path].state === "broken"`. Paths are root-relative POSIX; a path that leaves the root is refused.
525
+ - CLI: `moku-game-index --root <dir> where <key>` prints `<path>:<line>` per place (exit 1 for an unknown key); `--json` prints the index; `--check` exits 1 on a broken file or a key in conflict and lists the unresolved items as info. `--root` is required, `--manifest <path>` is root-relative.
526
+
506
527
  ## Hot swap
507
528
 
508
529
  Dev only. A save of a view file swaps the module in the running page: same state, same node, no reload. The game's `bunfig.toml` lists the plugin; the dev server runs in the game root, and a production `Bun.build` never loads it:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@moku-labs/game",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "2D puzzle game engine on TypeScript and PixiJS, built on @moku-labs/core.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -35,6 +35,10 @@
35
35
  "types": "./dist/lint.d.mts",
36
36
  "default": "./dist/lint.mjs"
37
37
  },
38
+ "./project": {
39
+ "types": "./dist/project.d.mts",
40
+ "default": "./dist/project.mjs"
41
+ },
38
42
  "./jsx-runtime": {
39
43
  "types": "./dist/jsx-runtime.d.mts",
40
44
  "default": "./dist/jsx-runtime.mjs"
@@ -46,7 +50,8 @@
46
50
  "./fonts/*": "./fonts/*"
47
51
  },
48
52
  "bin": {
49
- "moku-game-assets": "./bin/moku-game-assets.mjs"
53
+ "moku-game-assets": "./bin/moku-game-assets.mjs",
54
+ "moku-game-index": "./bin/moku-game-index.mjs"
50
55
  },
51
56
  "license": "MIT",
52
57
  "files": [
@@ -97,7 +102,8 @@
97
102
  "@moku-labs/core": "^1.7.1",
98
103
  "pixi.js": "^8.0.0",
99
104
  "playwright-core": ">=1.50.0",
100
- "sharp": "^0.34.0"
105
+ "sharp": "^0.34.0",
106
+ "typescript": ">=5.5"
101
107
  },
102
108
  "publishConfig": {
103
109
  "access": "public"
@@ -108,6 +114,9 @@
108
114
  },
109
115
  "sharp": {
110
116
  "optional": true
117
+ },
118
+ "typescript": {
119
+ "optional": true
111
120
  }
112
121
  },
113
122
  "devDependencies": {