@pix3/cli 1.6.3 → 2.0.0-alpha.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.
Files changed (168) hide show
  1. package/LICENSE +201 -201
  2. package/README.md +722 -788
  3. package/dist/index.js +557 -421
  4. package/dist/runtime-types.json +1 -1
  5. package/dist/smoke/prebuilt/{build-7MIXIMSZ.mjs → build-7REMSA2S.mjs} +52 -52
  6. package/dist/smoke/prebuilt/chunk-4DGG2BKR.mjs +2 -0
  7. package/dist/smoke/prebuilt/chunk-YLBMUJ2H.mjs +238 -0
  8. package/dist/smoke/prebuilt/runtime.mjs +1 -1
  9. package/dist/smoke/prebuilt/smoke-worker.mjs +211 -2
  10. package/dist/smoke/prebuilt/tree-defaults.mjs +1 -1
  11. package/dist/validate/prebuilt/{build-AUGKXER3.js → build-ADF5EEE2.js} +52 -52
  12. package/dist/validate/prebuilt/bundle-main.js +223 -18
  13. package/dist/validate/prebuilt/chunk-VIHIF4G2.js +238 -0
  14. package/dist/validate/prebuilt/runtime.js +1 -1
  15. package/kit/files/.claude/skills/pix3-editor/SKILL.md +200 -0
  16. package/kit/files/.claude/skills/pix3-nodes/SKILL.md +13 -15
  17. package/kit/files/.claude/skills/pix3-nodes/reference.md +77 -71
  18. package/kit/files/.claude/skills/pix3-scene-format/SKILL.md +38 -41
  19. package/kit/files/.claude/skills/pix3-scene-format/pix3anim.md +185 -0
  20. package/kit/files/.claude/skills/pix3-scene-format/project-files.md +244 -0
  21. package/kit/files/.claude/skills/pix3-scene-format/reference.md +28 -16
  22. package/kit/files/.claude/skills/pix3-scripts/SKILL.md +34 -24
  23. package/kit/files/.claude/skills/pix3-scripts/reference.md +68 -141
  24. package/kit/files/.claude/skills/pix3-verify/SKILL.md +65 -326
  25. package/kit/files/.claude/skills/pix3-verify/reference.md +2 -14
  26. package/kit/files/AGENTS.md +76 -84
  27. package/kit/files/design/tests/bots/pix3-test-bot.d.ts +89 -0
  28. package/kit/kit.json +8 -5
  29. package/package.json +62 -54
  30. package/templates/2d/files/scenes/main.pix3scene +31 -0
  31. package/templates/2d/template.yaml +11 -0
  32. package/templates/3d/files/scenes/main.pix3scene +50 -0
  33. package/templates/3d/template.yaml +11 -0
  34. package/templates/base/files/README.md +39 -0
  35. package/templates/base/files/gitignore +11 -0
  36. package/templates/base/files/index.html +23 -0
  37. package/templates/base/files/package.json +28 -0
  38. package/templates/base/files/src/main.ts +3 -0
  39. package/templates/base/files/tsconfig.json +17 -0
  40. package/templates/base/files/vite.config.ts +10 -0
  41. package/dist/smoke/prebuilt/chunk-CBFYKDS7.mjs +0 -2
  42. package/dist/smoke/prebuilt/chunk-VJHJ5BCO.mjs +0 -239
  43. package/dist/validate/prebuilt/chunk-CFQFEI52.js +0 -239
  44. package/templates/empty-2d/files/README.md +0 -20
  45. package/templates/empty-2d/files/scenes/main.pix3scene +0 -68
  46. package/templates/empty-2d/files/sprites/pix3-logo.png +0 -0
  47. package/templates/empty-2d/template.yaml +0 -7
  48. package/templates/empty-3d/files/README.md +0 -20
  49. package/templates/empty-3d/files/scenes/main.pix3scene +0 -108
  50. package/templates/empty-3d/files/sprites/pix3-logo.png +0 -0
  51. package/templates/empty-3d/template.yaml +0 -7
  52. package/templates/idea-blank/files/README.md +0 -22
  53. package/templates/idea-blank/files/scenes/main.pix3scene +0 -37
  54. package/templates/idea-blank/template.yaml +0 -10
  55. package/templates/minigame-2d/files/README.md +0 -44
  56. package/templates/minigame-2d/files/design/tests/reachability.json +0 -1
  57. package/templates/minigame-2d/files/design/tests/routines/mute-music.json +0 -44
  58. package/templates/minigame-2d/files/scenes/main.pix3scene +0 -84
  59. package/templates/minigame-2d/files/scenes/menu.pix3scene +0 -118
  60. package/templates/minigame-2d/files/scenes/ui/settings-window.pix3scene +0 -138
  61. package/templates/minigame-2d/files/scripts/GameFlow.ts +0 -133
  62. package/templates/minigame-2d/files/scripts/MenuFlow.ts +0 -217
  63. package/templates/minigame-2d/files/scripts/SettingsWindow.ts +0 -198
  64. package/templates/minigame-2d/template.yaml +0 -10
  65. package/templates/playable-2d/files/README.md +0 -30
  66. package/templates/playable-2d/files/design/recipe.md +0 -83
  67. package/templates/playable-2d/files/design/tests/reachability.json +0 -4
  68. package/templates/playable-2d/files/design/tests/routines/intro-to-cta.json +0 -32
  69. package/templates/playable-2d/files/scenes/main.pix3scene +0 -111
  70. package/templates/playable-2d/files/scenes/ui/end-screen.pix3scene +0 -91
  71. package/templates/playable-2d/files/scenes/ui/intro.pix3scene +0 -65
  72. package/templates/playable-2d/files/scripts/CtaButton.ts +0 -55
  73. package/templates/playable-2d/files/scripts/GameFlow.ts +0 -256
  74. package/templates/playable-2d/files/sprites/pix3-logo.png +0 -0
  75. package/templates/playable-2d/template.yaml +0 -9
  76. package/templates/playable-3d/files/README.md +0 -32
  77. package/templates/playable-3d/files/design/recipe.md +0 -127
  78. package/templates/playable-3d/files/design/tests/reachability.json +0 -4
  79. package/templates/playable-3d/files/design/tests/routines/intro-to-cta.json +0 -32
  80. package/templates/playable-3d/files/scenes/main.pix3scene +0 -230
  81. package/templates/playable-3d/files/scenes/ui/end-screen.pix3scene +0 -91
  82. package/templates/playable-3d/files/scenes/ui/intro.pix3scene +0 -65
  83. package/templates/playable-3d/files/scripts/CtaButton.ts +0 -55
  84. package/templates/playable-3d/files/scripts/GameFlow.ts +0 -309
  85. package/templates/playable-3d/files/scripts/GameRules.ts +0 -290
  86. package/templates/playable-3d/files/scripts/ScoreHud.ts +0 -113
  87. package/templates/playable-3d/template.yaml +0 -9
  88. package/templates/recipe-arena-2d/files/README.md +0 -48
  89. package/templates/recipe-arena-2d/files/design/recipe.md +0 -127
  90. package/templates/recipe-arena-2d/files/design/tests/reachability.json +0 -4
  91. package/templates/recipe-arena-2d/files/design/tests/routines/terminal-retry.json +0 -23
  92. package/templates/recipe-arena-2d/files/scenes/main.pix3scene +0 -292
  93. package/templates/recipe-arena-2d/files/scenes/menu.pix3scene +0 -100
  94. package/templates/recipe-arena-2d/files/scenes/prefabs/hazard.pix3scene +0 -42
  95. package/templates/recipe-arena-2d/files/scenes/prefabs/pickup.pix3scene +0 -45
  96. package/templates/recipe-arena-2d/files/scenes/ui/result.pix3scene +0 -85
  97. package/templates/recipe-arena-2d/files/scripts/GameRules.ts +0 -368
  98. package/templates/recipe-arena-2d/files/scripts/MenuFlow.ts +0 -106
  99. package/templates/recipe-arena-2d/files/scripts/PlayerController.ts +0 -151
  100. package/templates/recipe-arena-2d/files/scripts/ScoreHud.ts +0 -94
  101. package/templates/recipe-arena-2d/files/scripts/Spawner.ts +0 -214
  102. package/templates/recipe-arena-2d/files/scripts/TouchRules.ts +0 -174
  103. package/templates/recipe-arena-2d/files/sprites/ph-avatar.png +0 -0
  104. package/templates/recipe-arena-2d/files/sprites/ph-hazard.png +0 -0
  105. package/templates/recipe-arena-2d/files/sprites/ph-pickup.png +0 -0
  106. package/templates/recipe-arena-2d/template.yaml +0 -10
  107. package/templates/recipe-blank-2d/files/README.md +0 -61
  108. package/templates/recipe-blank-2d/files/design/recipe.md +0 -148
  109. package/templates/recipe-blank-2d/files/design/tests/reachability.json +0 -4
  110. package/templates/recipe-blank-2d/files/design/tests/routines/restart.json +0 -27
  111. package/templates/recipe-blank-2d/files/design/tests/routines/terminal-retry.json +0 -23
  112. package/templates/recipe-blank-2d/files/scenes/main.pix3scene +0 -224
  113. package/templates/recipe-blank-2d/files/scenes/ui/result.pix3scene +0 -85
  114. package/templates/recipe-blank-2d/files/scripts/GameRules.ts +0 -350
  115. package/templates/recipe-blank-2d/files/scripts/ScoreHud.ts +0 -110
  116. package/templates/recipe-blank-2d/files/sprites/ph-bg.png +0 -0
  117. package/templates/recipe-blank-2d/files/sprites/ph-capsule.png +0 -0
  118. package/templates/recipe-blank-2d/files/sprites/ph-circle.png +0 -0
  119. package/templates/recipe-blank-2d/files/sprites/ph-orb.png +0 -0
  120. package/templates/recipe-blank-2d/files/sprites/ph-ring.png +0 -0
  121. package/templates/recipe-blank-2d/files/sprites/ph-star.png +0 -0
  122. package/templates/recipe-blank-2d/template.yaml +0 -10
  123. package/templates/recipe-bouncer-2d/files/README.md +0 -81
  124. package/templates/recipe-bouncer-2d/files/design/recipe.md +0 -146
  125. package/templates/recipe-bouncer-2d/files/design/tests/reachability.json +0 -4
  126. package/templates/recipe-bouncer-2d/files/design/tests/routines/terminal-retry.json +0 -23
  127. package/templates/recipe-bouncer-2d/files/scenes/main.pix3scene +0 -615
  128. package/templates/recipe-bouncer-2d/files/scenes/menu.pix3scene +0 -191
  129. package/templates/recipe-bouncer-2d/files/scenes/ui/result.pix3scene +0 -87
  130. package/templates/recipe-bouncer-2d/files/scripts/BallBody.ts +0 -298
  131. package/templates/recipe-bouncer-2d/files/scripts/GameRules.ts +0 -377
  132. package/templates/recipe-bouncer-2d/files/scripts/MenuFlow.ts +0 -109
  133. package/templates/recipe-bouncer-2d/files/scripts/PaddleController.ts +0 -112
  134. package/templates/recipe-bouncer-2d/files/scripts/ScoreHud.ts +0 -94
  135. package/templates/recipe-bouncer-2d/files/scripts/TouchRules.ts +0 -263
  136. package/templates/recipe-bouncer-2d/files/scripts/ball-collision.ts +0 -307
  137. package/templates/recipe-bouncer-2d/files/sprites/ph-ball.png +0 -0
  138. package/templates/recipe-bouncer-2d/files/sprites/ph-bg.png +0 -0
  139. package/templates/recipe-bouncer-2d/files/sprites/ph-bumper.png +0 -0
  140. package/templates/recipe-bouncer-2d/files/sprites/ph-paddle.png +0 -0
  141. package/templates/recipe-bouncer-2d/template.yaml +0 -10
  142. package/templates/recipe-grid-3d/files/README.md +0 -22
  143. package/templates/recipe-grid-3d/files/design/recipe.md +0 -110
  144. package/templates/recipe-grid-3d/files/scenes/main.pix3scene +0 -169
  145. package/templates/recipe-grid-3d/files/scenes/menu.pix3scene +0 -100
  146. package/templates/recipe-grid-3d/files/scenes/ui/result.pix3scene +0 -105
  147. package/templates/recipe-grid-3d/files/scripts/GridBoard.ts +0 -319
  148. package/templates/recipe-grid-3d/files/scripts/GridRules.ts +0 -278
  149. package/templates/recipe-grid-3d/files/scripts/MenuFlow.ts +0 -106
  150. package/templates/recipe-grid-3d/files/scripts/ScoreHud.ts +0 -94
  151. package/templates/recipe-grid-3d/template.yaml +0 -10
  152. package/templates/recipe-tapper-2d/files/README.md +0 -39
  153. package/templates/recipe-tapper-2d/files/design/recipe.md +0 -132
  154. package/templates/recipe-tapper-2d/files/design/tests/reachability.json +0 -4
  155. package/templates/recipe-tapper-2d/files/design/tests/routines/terminal-retry.json +0 -23
  156. package/templates/recipe-tapper-2d/files/scenes/main.pix3scene +0 -269
  157. package/templates/recipe-tapper-2d/files/scenes/menu.pix3scene +0 -100
  158. package/templates/recipe-tapper-2d/files/scenes/prefabs/hazard.pix3scene +0 -42
  159. package/templates/recipe-tapper-2d/files/scenes/prefabs/target.pix3scene +0 -45
  160. package/templates/recipe-tapper-2d/files/scenes/ui/result.pix3scene +0 -85
  161. package/templates/recipe-tapper-2d/files/scripts/GameRules.ts +0 -368
  162. package/templates/recipe-tapper-2d/files/scripts/MenuFlow.ts +0 -106
  163. package/templates/recipe-tapper-2d/files/scripts/ScoreHud.ts +0 -94
  164. package/templates/recipe-tapper-2d/files/scripts/Spawner.ts +0 -214
  165. package/templates/recipe-tapper-2d/files/scripts/TouchRules.ts +0 -192
  166. package/templates/recipe-tapper-2d/files/sprites/ph-hazard.png +0 -0
  167. package/templates/recipe-tapper-2d/files/sprites/ph-target.png +0 -0
  168. package/templates/recipe-tapper-2d/template.yaml +0 -10
@@ -1,25 +1,21 @@
1
- <!-- Pix3 agent kit 1.6.3 — written by `pix3 kit`. You may edit it: `pix3 kit --update` never overwrites a kit file you changed. -->
1
+ <!-- Pix3 agent kit 2.0.0-alpha.0 — written by `pix3 kit`. You may edit it: `pix3 kit --update` never overwrites a kit file you changed. -->
2
2
  # AGENTS.md — Pix3 game project
3
3
 
4
4
  This folder is a **Pix3 game**: a 2D/3D browser game. You edit it by writing files. A human
5
5
  has the same folder open in the Pix3 editor, moves things with the mouse and presses Play;
6
6
  the editor saves their edits to the same files. The files are the whole contract.
7
7
 
8
- If it started from a **recipe** (`design/recipe.md` exists), it is a game that already plays.
9
- Change it; do not rebuild it.
8
+ A project made by `npm create pix3` starts **empty**: one entry scene (`scenes/main.pix3scene`,
9
+ a 2D root and background, or a 3D camera and lights) and no scripts. The game is yours to build.
10
10
 
11
11
  ## Read first
12
12
 
13
- 1. `design/recipe.md` (if present) — the map: stable node ids, tunables with ranges, extension
14
- points, what must not be touched. It speaks in the in-editor agent's tool names; translate
15
- them with the table in `.claude/skills/pix3-scene-format/SKILL.md` ("Recipe tool names").
16
- 2. `README.md` — file layout of this project.
17
- 3. The one scene or script you are about to change. Nothing else. Do not survey the repo.
13
+ 1. `README.md` — file layout of this project.
14
+ 2. The one scene or script you are about to change. Nothing else. Do not survey the repo.
18
15
  To find it, and to find your way inside it, use `pix3 tree` (every scene and prefab with
19
16
  node counts, types and components) and `pix3 tree <scene>` (one line per node: id, type,
20
- position, size, layout, components, prefab instances; `--types Label2D,Button2D`,
21
- `--depth 2`, `--props`) — not a read of whole scene files. Read the file itself right
22
- before you edit it (rule 2).
17
+ position, size, layout, components, prefab instances) — not a read of whole scene files.
18
+ Read the file itself right before you edit it (rule 2).
23
19
 
24
20
  ## Layout
25
21
 
@@ -34,9 +30,15 @@ The layout is **whatever this project has** — do not assume folders. Three rul
34
30
  `pix3 check` scan). `export class X extends Script` → `type: user:X`.
35
31
 
36
32
  `pix3project.yaml` is the manifest (do not edit unless asked); `.pix3/` is editor + CLI
37
- bookkeeping (recovery journal, merge log, script types) — never edit it.
33
+ bookkeeping (`dev.json` of the running dev server, the version journal, script types) — read
34
+ `dev.json`, never edit anything there.
38
35
 
39
- Example — the layout a **recipe** project (`pix3 new`) ships; other projects differ:
36
+ **The editor never creates, renames, moves or deletes a file, never edits `pix3project.yaml` and
37
+ never builds — you do.** New scene, rename/move/delete with every reference, a branch turned into
38
+ a prefab, a new flipbook, a locale added or removed, project settings, build options:
39
+ `.claude/skills/pix3-scene-format/project-files.md`.
40
+
41
+ Example — the layout `npm create pix3` sets up (`pix3 new`); other projects differ:
40
42
 
41
43
  | Path | What |
42
44
  | --- | --- |
@@ -45,7 +47,8 @@ Example — the layout a **recipe** project (`pix3 new`) ships; other projects d
45
47
  | `scenes/prefabs/*.pix3scene` | Prefabs: a scene file with exactly ONE root node (a top-level `prefabs/` works too) |
46
48
  | `scripts/*.ts` | Script components |
47
49
  | `sprites/`, `audio/`, `fonts/`, `models/` … | Assets, referenced as `res://sprites/x.png` |
48
- | `design/` | Recipe contract, GDD, tests. `design/tests/` is written by the editor's harness |
50
+ | `design/` | Design notes, GDD, references |
51
+ | `src/main.ts`, `index.html`, `vite.config.ts` | The Vite entry: `startGame('#app')` boots the entry scene; `pix3()` serves the editor at `/__pix3/` |
49
52
 
50
53
  ## The five rules
51
54
 
@@ -53,35 +56,25 @@ Example — the layout a **recipe** project (`pix3 new`) ships; other projects d
53
56
  smallest form that plays, before asking anything. Choose small things yourself (a shade, a
54
57
  speed, a count) and say so in one line. At most ONE question per turn, and only about a
55
58
  fork that changes structure ("win by score or by time?"). Never open with a question.
56
- 2. **Re-read a scene before you edit it.** The human may have changed it in the editor a
57
- minute ago. Edit the lines you mean to change (search/replace), never regenerate a whole
58
- scene from memory. After writing, if `pix3 check` lists **merge-log** entries where the
59
- editor KEPT the human's value instead of yours, re-read the file with `pix3 read <file>`
60
- (that is your read confirmation); if your value is still intended, write it again — or ask
61
- the human. Without that re-read the editor keeps restoring the human's value on every
62
- write you make, even if you write the same number.
59
+ 2. **Sync, then re-read a scene before you edit it.** The human may have moved things in the
60
+ editor a minute ago; a successful `pix3_sync` puts their unsaved edits on disk. Edit the lines
61
+ you mean to change (search/replace), never regenerate a whole scene from memory. After
62
+ writing, `pix3_sync` again with `expect` = the sha256 of every file you wrote
63
+ (`.claude/skills/pix3-editor/SKILL.md`).
63
64
  3. **Leave layout, colours and fine-tuning to the human.** If asked "a bit more to the left",
64
65
  do it, then offer: "you can drag it in the editor — it saves on its own".
65
66
  4. **Run `pix3 check` after every batch of edits** and fix every error before you say "done".
66
67
  It checks YAML, node types, properties, `res://` paths, prefabs, components, and
67
- type-checks your scripts (tsc). With the live channel connected (MCP, below), then run the
68
- game with `game_run` (or `play_restart`), **passing `expect`** — the sha256 of every file you
69
- wrote, as `pix3 check --json` prints them under `files`. An answer with
70
- `disk_differs_from_agent`, or a non-empty `changedDuringRun`, is not green.
71
- **No editor connected?** `pix3 check`, then `pix3 smoke <the scene you changed>` — the
72
- game is `pix3 smoke scenes/main.pix3scene`; the menu never presses PLAY headless, so a
73
- smoke of the menu says nothing about the game. It runs that scene in Node for 2 s
74
- (`--frames N` for more) and exits 1 on any script throw, `console.error` or unhandled
75
- rejection, naming script, frame and source line. With no scene it runs several, a line
76
- each: the scenes your uncommitted changes reach (git), else every top-level scene, game
77
- first. Green means nothing threw; it does not mean it plays (nothing was tapped or drawn)
78
- — so then tell the human what to press and what they should see.
79
- 5. **Art: placeholder → SVG → `generate_asset`, never emoji.** Placeholder = `ColorRect2D`, or
68
+ type-checks your scripts. Then run the game: with the editor open, `pix3_sync` with `expect`
69
+ and `pix3_play` / `pix3_game_run` / `pix3_errors` / a screenshot (`pix3-editor`); without it,
70
+ `pix3 smoke <the scene you changed>` — the game, not the menu, which never presses PLAY
71
+ headless (`pix3-verify`). A sync that is not `ok` is not green, and a green smoke means
72
+ nothing threw, not that it plays — so tell the human what to press and what they should see.
73
+ 5. **Art: placeholder → SVG → a generated image, never emoji.** Placeholder = `ColorRect2D`, or
80
74
  a near-white PNG in `sprites/` tinted with a `core:tint` effect. Better art = an SVG you
81
- write into `sprites/` — it works on a `Sprite2D` when the root has `xmlns` plus px
82
- `width`/`height`; `pix3 validate` checks it (`E_SVG_*`); template in `pix3-nodes` — or
83
- `generate_asset` through the live channel. A label/text that is only emoji is
84
- refused — emoji are not art. List every placeholder you leave.
75
+ write into `sprites/` (`pix3-nodes` → "An SVG you write as a sprite") — or an image the
76
+ human generates. A label/text that is only emoji is refused — emoji are not art. List every
77
+ placeholder you leave.
85
78
 
86
79
  ## YAML essentials (`.pix3scene`) — details in `pix3-scene-format`
87
80
 
@@ -108,16 +101,15 @@ root:
108
101
  properties: { visible: false }
109
102
  ```
110
103
 
111
- - The sample assumes a 1080×1920 portrait 2D root; yours may not have one. Read
112
- `viewportBaseSize` and `projectType` in `pix3project.yaml` first; a `3d` project may have loose
113
- top-level 2D nodes (HUD) with no 2D root at all. Place new HUD relative to the HUD nodes that
114
- already exist (same parent, same anchoring), not to an assumed screen size.
104
+ - The sample assumes a 1080×1920 portrait 2D root; yours may not have one — read
105
+ `viewportBaseSize` and `projectType` in `pix3project.yaml`, and place new HUD relative to the
106
+ HUD that exists (`pix3-scene-format` → "2D transform").
115
107
  - 2D space: design pixels, origin at the screen centre, **X right, Y up**. `position` is the
116
108
  node's centre. Tree order is paint order: later/deeper draws on top.
117
109
  - **Quote every colour**: `color: "#141a2e"`. Unquoted, `#` starts a YAML comment.
118
110
  - Textures: `texture: { type: 'texture', url: 'res://sprites/ph-target.png' }`.
119
111
  - `visible: false` on an overlay instance hides it **in the editor only**; play mode reads
120
- `initiallyVisible` on the overlay file's root. Keep both as the recipe has them.
112
+ `initiallyVisible` on the overlay file's root. Set both.
121
113
  - The loader is forgiving — unknown types, unknown keys and wrong value types load silently
122
114
  as nothing. That is why rule 4 exists.
123
115
 
@@ -139,65 +131,65 @@ export class Combo extends Script {
139
131
  }
140
132
  ```
141
133
 
142
- - One mechanic = one new script of 70–140 lines. Extend a recipe's scripts only where
143
- `design/recipe.md` names an extension point; do not restructure them.
144
- - Talk between scripts the way the project already does. Recipes use signals on nodes:
145
- `node.emit('touch-scored', 1)` / `node.connect('touch-scored', this, fn)` — never rename the
146
- recipe's signals or node ids. An existing game may use its own event bus or store instead
147
- (next section).
134
+ - One mechanic = one new script of 70–140 lines.
135
+ - Talk between scripts the way the project already does. In a new project use signals on nodes:
136
+ `node.emit('touch-scored', 1)` / `node.connect('touch-scored', this, fn)`; once named, never
137
+ rename a signal or a node id other scripts use. An existing game may use its own event bus or
138
+ store instead (next section).
148
139
  - Transforms are mutated, never assigned: `node.position.set(x, y, 0)`, `node.rotation.z = rad`.
149
140
  - Types come from `@pix3/runtime`: `pix3 check` type-checks against the bundled declarations in
150
141
  `.pix3/types/` (or against your own `node_modules` when the project has its own `tsconfig.json`).
151
142
 
152
- ## Hosting an existing (non-recipe) game
143
+ ## Hosting an existing game
153
144
 
154
- A game that was not made from a recipe has its own architecture; plug into it, do not add a
155
- second one.
145
+ A game that was not made from `npm create pix3` has its own architecture; plug into it, do not
146
+ add a second one — its event bus or store, its own shake/sound/tween helpers, and cleanup by
147
+ hand of everything that is not a node signal (`pix3-scripts` → "Hosting an existing game").
156
148
 
157
- - **Find its event bus / state store** before writing a script:
158
- `grep -rn "CustomEvent\|dispatchEvent\|addEventListener\|subscribe(\|EventTarget\|emit(" src scripts`.
159
- Window `CustomEvent`s, an `EventTarget` singleton, or a store with `subscribe()` are all
160
- normal; node signals are only one option. Listen to what the game already emits.
161
- - **Clean up by hand.** `Script.onDetach` auto-disconnects only **node signals** whose target is
162
- the script (on its own node or any other). Window listeners, store subscriptions and timers
163
- must be removed in `onDetach` (keep the handler in a field; call the
164
- unsubscribe the store returned) — otherwise every play/stop in the editor leaves one more
165
- live listener behind.
166
149
  - **Two instruction files.** The project's own `AGENTS.md` wins on **process** (planning first,
167
150
  where config and tests go, commit rules); this kit wins on **Pix3 facts** (the YAML format,
168
151
  the runtime API, `pix3 check`).
169
152
  - The project's own `package.json` means `npm install` before `pix3 check` can type-check.
170
- - **Use the game's own feedback mechanisms.** If its camera controller writes the camera's
171
- position every frame, an engine `scene.juice.shake('camera')` / `core:Shake` on that 3D camera
172
- (or on any node the game positions itself) is overwritten every frame and never shows — call
173
- the game's own shake (grep `shake`) instead. The same holds for its own sound/tween helpers.
174
-
175
- ## The CLI and the live channel
176
-
177
- - `pix3 check [--json]` — after every batch (rule 4). `--json` prints `files` (`{ file, sha256 }`,
178
- sha256 of the raw bytes), `diagnostics`, `typecheck`, `mergeLog`, `kit`.
179
- - `pix3 read <file>` — print a file and confirm to the editor you read exactly these bytes.
180
- - `pix3 validate [paths…]` — scenes only, no type-check.
181
- - `pix3 smoke [scene] [--frames N] [--json]` — run a scene headless (no browser) and report
182
- script throws with frame and stack, `console.error`, missing `res://` files; exit 1 on errors.
183
- Name the game scene (`pix3 smoke scenes/main.pix3scene`); no scene = the scenes git changes
184
- reach, else every top-level scene (`--all` forces that).
153
+
154
+ ## The CLI and the editor bridge
155
+
156
+ A project made by `npm create pix3` has them as npm scripts: `npm run dev` (Vite: the game at
157
+ `/`, the editor at `/__pix3/`, on the port Vite got — 5173 only if it was free; read
158
+ `.pix3/dev.json`), `npm run editor` (`pix3 editor`), `npm run build` (`dist/`),
159
+ `npm run preview` (serve the build), `npm run check` (`pix3 check`), `npm run smoke`
160
+ (`pix3 smoke`; pass the scene after `--`). Elsewhere call `npx pix3 …` or read `package.json`.
161
+
162
+ - `pix3 check [--json]` — after every batch (rule 4); `--json` prints `files` (`{ file, sha256 }`)
163
+ for `pix3_sync`'s `expect`. It flushes the open editor's unsaved edits first (`--no-sync`
164
+ skips that). `pix3 validate [paths…]` — scenes only, no type-check.
165
+ - `pix3 smoke [scene] [--frames N] [--json]` — run a scene headless (no browser); exit 1 on a
166
+ script throw, `console.error` or unhandled rejection. Name the game scene.
185
167
  - `pix3 tree [scene] [--types A,B] [--depth N] [--props] [--json]` — scene outline, one line
186
168
  per node; no scene = project overview.
187
- - **Live channel (optional).** When the human runs `pix3 serve` in this folder and connects the
188
- editor to it (File → Connect to Workspace…), the MCP server in `.mcp.json`
189
- (`pix3 mcp --workspace`) gives you 14 tools: running and observing the game, screenshots,
190
- asset/sfx generation. There is no scene-editing tool — you still edit files. Details and the
191
- answer fields: `.claude/skills/pix3-verify/SKILL.md` ("Live channel").
169
+ - `pix3 editor` — find (or start) the dev server and open the editor in a Chrome reachable only
170
+ through its token proxy; `pix3 agent-setup [claude|codex] [--repair]` — write the project's
171
+ MCP config for `chrome-devtools-mcp`, once (never commit it).
172
+ - `pix3 gap "<what was missing>" --kind capability|tool|node|doc|other [--detail "…"] [--context "<file or task>"]`
173
+ — when you had to **work around** something Pix3 does not have (an engine capability, a bridge
174
+ tool, a node type, a doc that was missing or wrong), record it once, after the workaround: one
175
+ line in `.pix3/gaps.jsonl` (local, read by the Pix3 team). Sparingly — not for your own
176
+ mistakes, a question to the human, or a feature the game itself should implement.
177
+ - **The editor bridge.** With the editor tab open, the `pix3-browser` MCP server (Chrome
178
+ DevTools) reaches it: `list_pages` → `select_page` → `list_3p_developer_tools` → the
179
+ `pix3_*` tools — sync the editor with the disk, play, step the game with predicates, read the
180
+ scene and the errors, prepare a screenshot. There is no scene-editing tool — you still edit
181
+ files. No `pix3-browser` server → `npx pix3 agent-setup`, then a new thread. The loop, the
182
+ not-ok answers and the inline fallback: `.claude/skills/pix3-editor/SKILL.md`.
192
183
 
193
184
  ## Skills (read the one you need, when you need it)
194
185
 
195
- - `.claude/skills/pix3-scene-format/SKILL.md` — full YAML format, prefabs, overlays, recipe tool table
186
+ - `.claude/skills/pix3-scene-format/SKILL.md` — full YAML format, prefabs, overlays; `.pix3anim` flipbooks and `pix3 character-compile` in `pix3anim.md` beside it; file and project operations the editor does not do in `project-files.md` beside it
196
187
  - `.claude/skills/pix3-nodes/SKILL.md` — 2D node properties (Group2D, ColorRect2D, Sprite2D, Label2D, Button2D, Bar2D, CanvasLayer2D, PostProcess); every node in `reference.md` beside it
197
188
  - `.claude/skills/pix3-scripts/SKILL.md` — Script API: lifecycle, schema, scene/input/juice/tween/audio/physics, `core:` components, traps
198
- - `.claude/skills/pix3-verify/SKILL.md` — `pix3 check` / `validate` / `read`, merge-log, the live channel (`game_run` + `expect`)
189
+ - `.claude/skills/pix3-editor/SKILL.md` — the editor bridge: find the tab, `pix3_sync` with `expect`, play ownership, `pix3_game_run`, screenshots, inline fallback
190
+ - `.claude/skills/pix3-verify/SKILL.md` — `pix3 check` / `validate` / `smoke`, the diagnostic codes, how to report what was verified
199
191
 
200
192
  ## Finish every turn with
201
193
 
202
- What changed (files), what `pix3 check` said, whether you ran the game (and what `game_run`
194
+ What changed (files), what `pix3 check` said, whether you ran the game (and what `pix3_game_run`
203
195
  answered) or what the human should press and see, placeholders left, and 2–3 concrete next steps.
@@ -0,0 +1,89 @@
1
+ // Pix3 agent kit 2.0.0-alpha.0 — `pix3 kit --update` rewrites this file; do not edit.
2
+ //
3
+ // Types for the test policies in this folder (global: no import needed). A policy is
4
+ // one file exporting an object with a `tick(bot)`; the harness runs it once per logic
5
+ // tick while the game plays, through `pix3_game_run {bot: {name: '<file name without
6
+ // .ts>'}, …}`. Write it as
7
+ //
8
+ // export default {
9
+ // name: 'dodge',
10
+ // tick(bot) { … },
11
+ // } satisfies BotPolicy;
12
+ //
13
+ // so `bot` is a Pix3TestBot and `pix3 check` type-checks the policy.
14
+ //
15
+ // The timing contract, which decides whether a policy works: `tick` runs AFTER the
16
+ // game's tick, and every actuator lands on the NEXT tick. Observe frame N, act for
17
+ // frame N+1 — the same one-frame lag a human player has.
18
+
19
+ declare interface BotPoint {
20
+ x: number;
21
+ y: number;
22
+ z?: number;
23
+ }
24
+
25
+ /** What a policy sees of one live node. */
26
+ declare interface BotNodeView {
27
+ nodeId: string;
28
+ name: string;
29
+ type: string;
30
+ /** The node's own flag. `false` means it is not on screen and cannot be tapped. */
31
+ visible: boolean;
32
+ position: { x: number; y: number; z: number };
33
+ worldPosition: { x: number; y: number; z: number };
34
+ /** The text the node renders, for nodes that render one. */
35
+ text?: string;
36
+ }
37
+
38
+ declare interface BotHit {
39
+ node: BotNodeView;
40
+ distance: number;
41
+ point: { x: number; y: number; z: number };
42
+ }
43
+
44
+ declare interface Pix3TestBot {
45
+ /** Ticks this policy has been ticked for. 1 on the first tick. */
46
+ readonly frame: number;
47
+
48
+ // -- sensors ---------------------------------------------------------------
49
+
50
+ /** Live nodes answering a name, an id, or a type ('Sprite2D'). */
51
+ nodes(query: string): BotNodeView[];
52
+ /** Nearest live node of `type` to `from` (default: the world origin). */
53
+ nearest(type: string, from?: BotPoint): BotHit | null;
54
+ /** First live node struck by a ray. `dir` need not be normalised. */
55
+ raycast(from: BotPoint, dir: BotPoint): BotHit | null;
56
+ /** The game's own registerGameDebug() snapshot, or null when it registered none. */
57
+ gameState(): unknown;
58
+
59
+ // -- actuators -------------------------------------------------------------
60
+
61
+ /** Hold a key ('Key_ArrowLeft' or 'ArrowLeft') or a named button ('Action_Primary'). */
62
+ press(action: string, frames?: number): void;
63
+ /** Let go of something press() is holding. */
64
+ release(action: string): void;
65
+ /** Tap a control by node name/id: down now, up a few ticks later. */
66
+ tap(target: string): void;
67
+ /** Steer an input axis to -1..1. On physical-input this deflects the live joystick. */
68
+ axis(name: string, value: number): void;
69
+ /** Point the pointer at a world position (aim, hover, click-to-move). */
70
+ moveTo(point: BotPoint): void;
71
+
72
+ // -- protocol --------------------------------------------------------------
73
+
74
+ /** One line in the run report — how the policy explains its own reasoning. */
75
+ log(event: string): void;
76
+ /** End the run with the policy's verdict and the reason, in words. First call wins. */
77
+ done(pass: boolean, reason: string): void;
78
+ }
79
+
80
+ declare interface BotPolicy {
81
+ /** Optional label for the report; the file name is used when absent. */
82
+ name?: string;
83
+ /** Runs once before the first tick. */
84
+ start?(bot: Pix3TestBot): void;
85
+ /** Runs once per logic tick until done() or the budget ends. */
86
+ tick(bot: Pix3TestBot): void;
87
+ /** Runs once after the last tick, whatever ended the run. */
88
+ end?(bot: Pix3TestBot): void;
89
+ }
package/kit/kit.json CHANGED
@@ -1,24 +1,27 @@
1
1
  {
2
2
  "format": 1,
3
- "version": "1.6.3",
4
- "inputsStamp": "8fcca842690fa33c8ede9cb18b2ea5b950b8cceea0852c114c6431bf6bc321fd",
3
+ "version": "2.0.0-alpha.0",
4
+ "inputsStamp": "2191b8f1a8e23d36c45892f3616f747dd3f429eeb427c447163b16e4586e26dc",
5
5
  "files": [
6
+ ".claude/skills/pix3-editor/SKILL.md",
6
7
  ".claude/skills/pix3-nodes/SKILL.md",
7
8
  ".claude/skills/pix3-nodes/reference.md",
8
9
  ".claude/skills/pix3-scene-format/SKILL.md",
10
+ ".claude/skills/pix3-scene-format/pix3anim.md",
11
+ ".claude/skills/pix3-scene-format/project-files.md",
9
12
  ".claude/skills/pix3-scene-format/reference.md",
10
13
  ".claude/skills/pix3-scripts/SKILL.md",
11
14
  ".claude/skills/pix3-scripts/reference.md",
12
15
  ".claude/skills/pix3-verify/SKILL.md",
13
16
  ".claude/skills/pix3-verify/reference.md",
14
17
  "AGENTS.md",
15
- "CLAUDE.md"
18
+ "CLAUDE.md",
19
+ "design/tests/bots/pix3-test-bot.d.ts"
16
20
  ],
17
21
  "sources": [
18
22
  "docs/node-types-reference.md",
19
23
  "docs/nodes-and-systems.md",
20
24
  "docs/pix3-specification.md",
21
- "packages/pix3-cli/README.md",
22
- "src/services/agent/agent-skills/engine-api-map.md"
25
+ "packages/cli/kit-includes/engine-api-map.md"
23
26
  ]
24
27
  }
package/package.json CHANGED
@@ -1,54 +1,62 @@
1
- {
2
- "name": "@pix3/cli",
3
- "version": "1.6.3",
4
- "description": "Pix3 command line: create a project from a recipe, and link your own coding agent (Claude Code, Codex, ...) to an open Pix3 editor window over a loopback MCP channel.",
5
- "type": "module",
6
- "repository": {
7
- "type": "git",
8
- "url": "git+https://github.com/pix3dev/pix3.git",
9
- "directory": "packages/pix3-cli"
10
- },
11
- "bin": {
12
- "pix3": "dist/index.js"
13
- },
14
- "main": "dist/index.js",
15
- "files": [
16
- "dist",
17
- "templates",
18
- "kit",
19
- "README.md",
20
- "LICENSE"
21
- ],
22
- "engines": {
23
- "node": ">=24.15.0 <25"
24
- },
25
- "scripts": {
26
- "start": "node src/index.ts",
27
- "build": "tsc -p tsconfig.build.json && node scripts/build-bin.mjs && node scripts/build-validate.mjs && node scripts/build-smoke.mjs",
28
- "copy-templates": "node scripts/copy-templates.mjs",
29
- "prepack": "npm run copy-templates && npm run build && npm run build-runtime-types && npm run build-kit",
30
- "postpack": "node scripts/copy-templates.mjs --clean",
31
- "type-check": "tsc --noEmit && tsc --noEmit -p tsconfig.build.json",
32
- "build-kit": "node scripts/build-kit.mjs",
33
- "build-runtime-types": "node scripts/build-runtime-types.mjs"
34
- },
35
- "keywords": [
36
- "pix3",
37
- "cli",
38
- "mcp",
39
- "game-engine",
40
- "agent"
41
- ],
42
- "license": "Apache-2.0",
43
- "optionalDependencies": {
44
- "esbuild": "^0.27.3"
45
- },
46
- "devDependencies": {
47
- "@modelcontextprotocol/sdk": "^1.29.0",
48
- "@types/node": "^24.5.2",
49
- "@types/ws": "^8.18.1",
50
- "typescript": "~5.8.3",
51
- "ws": "^8.18.0",
52
- "yaml": "^2.6.0"
53
- }
54
- }
1
+ {
2
+ "name": "@pix3/cli",
3
+ "version": "2.0.0-alpha.0",
4
+ "description": "Pix3 command line: create a project, check and smoke-test it, open the editor in Chrome for your coding agent (Claude Code, Codex, ...) and configure chrome-devtools-mcp for it.",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/pix3dev/pix3-core.git",
9
+ "directory": "packages/cli"
10
+ },
11
+ "homepage": "https://github.com/pix3dev/pix3-core/tree/main/packages/cli#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/pix3dev/pix3-core/issues"
14
+ },
15
+ "bin": {
16
+ "pix3": "dist/index.js"
17
+ },
18
+ "main": "dist/index.js",
19
+ "files": [
20
+ "dist",
21
+ "templates",
22
+ "kit",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "engines": {
27
+ "node": ">=24.15.0 <25"
28
+ },
29
+ "scripts": {
30
+ "start": "node src/index.ts",
31
+ "build": "tsc -p tsconfig.build.json && node scripts/build-bin.mjs && node scripts/build-validate.mjs && node scripts/build-smoke.mjs",
32
+ "copy-templates": "node scripts/copy-templates.mjs",
33
+ "prepack": "npm run copy-templates && npm run build && npm run build-runtime-types && npm run build-kit",
34
+ "postpack": "node scripts/copy-templates.mjs --clean",
35
+ "type-check": "tsc --noEmit && tsc --noEmit -p tsconfig.build.json",
36
+ "build-kit": "node scripts/build-kit.mjs",
37
+ "build-runtime-types": "node scripts/build-runtime-types.mjs"
38
+ },
39
+ "keywords": [
40
+ "pix3",
41
+ "cli",
42
+ "mcp",
43
+ "game-engine",
44
+ "agent"
45
+ ],
46
+ "license": "Apache-2.0",
47
+ "optionalDependencies": {
48
+ "esbuild": "^0.27.3"
49
+ },
50
+ "devDependencies": {
51
+ "@pix3/runtime": "2.0.0-alpha.0",
52
+ "@types/node": "^24.5.2",
53
+ "@types/ws": "^8.18.1",
54
+ "typescript": "~5.8.3",
55
+ "ws": "^8.18.0",
56
+ "yaml": "^2.6.0"
57
+ },
58
+ "publishConfig": {
59
+ "access": "public",
60
+ "tag": "next"
61
+ }
62
+ }
@@ -0,0 +1,31 @@
1
+ # Pix3 Scene File (YAML). The entry scene of an empty 2D project: a root that stretches over the
2
+ # viewport (pix3project.yaml → viewportBaseSize) and a background. Add nodes under game-root.
3
+ version: 1.0.0
4
+ metadata:
5
+ description: Entry scene
6
+ root:
7
+ - id: game-root
8
+ type: Group2D
9
+ name: Game Root
10
+ properties:
11
+ width: 1920
12
+ height: 1080
13
+ layout:
14
+ enabled: true
15
+ horizontalAlign: stretch
16
+ verticalAlign: stretch
17
+ children:
18
+ - id: background
19
+ type: ColorRect2D
20
+ name: Background
21
+ properties:
22
+ color: "#1a1a2e"
23
+ layout: # stretched over the root: the margins size it, no width/height
24
+ enabled: true
25
+ horizontalAlign: stretch
26
+ verticalAlign: stretch
27
+ left: 0
28
+ right: 0
29
+ top: 0
30
+ bottom: 0
31
+ children: []
@@ -0,0 +1,11 @@
1
+ id: 2d
2
+ title: Empty 2D
3
+ description: An empty 2D project — one scene with a stretched 2D root and a background, nothing that plays.
4
+ # Shared project files (package.json, vite.config.ts, index.html, src/main.ts, tsconfig.json …)
5
+ # come from templates/base; this layer adds the 2D scene.
6
+ extends: base
7
+ projectType: 2d
8
+ targetPlatform: universal
9
+ viewport: { width: 1920, height: 1080 }
10
+ entryScene: scenes/main.pix3scene
11
+ order: 10
@@ -0,0 +1,50 @@
1
+ # Pix3 Scene File (YAML). The entry scene of an empty 3D project: a camera, a key light and an
2
+ # ambient fill. Add meshes under game-root; 2D HUD nodes go beside it as top-level 2D nodes.
3
+ version: 1.0.0
4
+ metadata:
5
+ description: Entry scene
6
+ root:
7
+ - id: game-root
8
+ type: Node3D
9
+ name: Game Root
10
+ properties:
11
+ transform:
12
+ position: [0, 0, 0]
13
+ rotationEuler: [0, 0, 0]
14
+ scale: [1, 1, 1]
15
+ children:
16
+ - id: main-camera
17
+ type: Camera3D
18
+ name: Main Camera
19
+ properties:
20
+ projection: perspective
21
+ fov: 60
22
+ near: 0.1
23
+ far: 1000
24
+ transform:
25
+ position: [0, 2, 6]
26
+ rotationEuler: [-10, 0, 0]
27
+ scale: [1, 1, 1]
28
+ children: []
29
+ - id: key-light
30
+ type: DirectionalLightNode
31
+ name: Key Light
32
+ properties:
33
+ intensity: 1.2
34
+ color: "#ffffff"
35
+ transform:
36
+ position: [5, 8, 3]
37
+ rotationEuler: [-45, 35, 0]
38
+ scale: [1, 1, 1]
39
+ children: []
40
+ - id: ambient-light
41
+ type: AmbientLightNode
42
+ name: Ambient Light
43
+ properties:
44
+ intensity: 0.5
45
+ color: "#ffffff"
46
+ transform:
47
+ position: [0, 0, 0]
48
+ rotationEuler: [0, 0, 0]
49
+ scale: [1, 1, 1]
50
+ children: []
@@ -0,0 +1,11 @@
1
+ id: 3d
2
+ title: Empty 3D
3
+ description: An empty 3D project — one scene with a camera and lights, nothing that plays.
4
+ # Shared project files (package.json, vite.config.ts, index.html, src/main.ts, tsconfig.json …)
5
+ # come from templates/base; this layer adds the 3D scene.
6
+ extends: base
7
+ projectType: 3d
8
+ targetPlatform: universal
9
+ viewport: { width: 1920, height: 1080 }
10
+ entryScene: scenes/main.pix3scene
11
+ order: 20