@pix3/cli 1.6.0 → 1.6.2
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/LICENSE +201 -201
- package/README.md +788 -754
- package/dist/index.js +208 -203
- package/dist/runtime-types.json +1 -1
- package/dist/smoke/prebuilt/{chunk-J2SJVMDO.mjs → chunk-7MZGPAUK.mjs} +1 -1
- package/dist/smoke/prebuilt/chunk-7WOFGLW3.mjs +239 -0
- package/dist/smoke/prebuilt/runtime.mjs +1 -1
- package/dist/smoke/prebuilt/smoke-worker.mjs +1 -1
- package/dist/smoke/prebuilt/tree-defaults.mjs +1 -1
- package/dist/validate/prebuilt/bundle-main.js +13 -13
- package/dist/validate/prebuilt/chunk-HKG6YI6Y.js +239 -0
- package/dist/validate/prebuilt/runtime.js +1 -1
- package/kit/files/.claude/skills/pix3-nodes/SKILL.md +210 -210
- package/kit/files/.claude/skills/pix3-nodes/reference.md +32 -24
- package/kit/files/.claude/skills/pix3-scene-format/SKILL.md +238 -235
- package/kit/files/.claude/skills/pix3-scene-format/reference.md +28 -28
- package/kit/files/.claude/skills/pix3-scripts/SKILL.md +285 -281
- package/kit/files/.claude/skills/pix3-scripts/reference.md +69 -52
- package/kit/files/.claude/skills/pix3-verify/SKILL.md +298 -256
- package/kit/files/.claude/skills/pix3-verify/reference.md +21 -21
- package/kit/files/AGENTS.md +203 -203
- package/kit/files/CLAUDE.md +1 -1
- package/kit/kit.json +2 -2
- package/package.json +54 -54
- package/templates/empty-2d/files/README.md +20 -20
- package/templates/empty-2d/files/scenes/main.pix3scene +68 -68
- package/templates/empty-2d/template.yaml +7 -7
- package/templates/empty-3d/files/README.md +20 -20
- package/templates/empty-3d/files/scenes/main.pix3scene +108 -108
- package/templates/empty-3d/template.yaml +7 -7
- package/templates/idea-blank/files/README.md +22 -22
- package/templates/idea-blank/files/scenes/main.pix3scene +37 -37
- package/templates/idea-blank/template.yaml +10 -10
- package/templates/minigame-2d/files/README.md +44 -44
- package/templates/minigame-2d/files/design/tests/reachability.json +1 -1
- package/templates/minigame-2d/files/design/tests/routines/mute-music.json +44 -44
- package/templates/minigame-2d/files/scenes/main.pix3scene +84 -84
- package/templates/minigame-2d/files/scenes/menu.pix3scene +118 -118
- package/templates/minigame-2d/files/scenes/ui/settings-window.pix3scene +138 -138
- package/templates/minigame-2d/files/scripts/GameFlow.ts +133 -133
- package/templates/minigame-2d/files/scripts/MenuFlow.ts +217 -217
- package/templates/minigame-2d/files/scripts/SettingsWindow.ts +198 -198
- package/templates/minigame-2d/template.yaml +10 -10
- package/templates/playable-2d/files/README.md +30 -30
- package/templates/playable-2d/files/design/recipe.md +83 -83
- package/templates/playable-2d/files/design/tests/reachability.json +4 -4
- package/templates/playable-2d/files/design/tests/routines/intro-to-cta.json +32 -32
- package/templates/playable-2d/files/scenes/main.pix3scene +111 -111
- package/templates/playable-2d/files/scenes/ui/end-screen.pix3scene +91 -91
- package/templates/playable-2d/files/scenes/ui/intro.pix3scene +65 -65
- package/templates/playable-2d/files/scripts/GameFlow.ts +256 -256
- package/templates/playable-2d/template.yaml +9 -9
- package/templates/playable-3d/files/README.md +32 -32
- package/templates/playable-3d/files/design/recipe.md +127 -127
- package/templates/playable-3d/files/design/tests/reachability.json +4 -4
- package/templates/playable-3d/files/design/tests/routines/intro-to-cta.json +32 -32
- package/templates/playable-3d/files/scenes/main.pix3scene +230 -230
- package/templates/playable-3d/files/scenes/ui/end-screen.pix3scene +91 -91
- package/templates/playable-3d/files/scenes/ui/intro.pix3scene +65 -65
- package/templates/playable-3d/files/scripts/GameFlow.ts +309 -309
- package/templates/playable-3d/files/scripts/GameRules.ts +290 -290
- package/templates/playable-3d/files/scripts/ScoreHud.ts +113 -113
- package/templates/playable-3d/template.yaml +9 -9
- package/templates/recipe-arena-2d/files/README.md +48 -48
- package/templates/recipe-arena-2d/files/design/recipe.md +127 -127
- package/templates/recipe-arena-2d/files/scenes/main.pix3scene +292 -292
- package/templates/recipe-arena-2d/files/scenes/menu.pix3scene +100 -100
- package/templates/recipe-arena-2d/files/scenes/prefabs/hazard.pix3scene +42 -42
- package/templates/recipe-arena-2d/files/scenes/prefabs/pickup.pix3scene +45 -45
- package/templates/recipe-arena-2d/files/scenes/ui/result.pix3scene +85 -85
- package/templates/recipe-arena-2d/files/scripts/GameRules.ts +368 -368
- package/templates/recipe-arena-2d/files/scripts/MenuFlow.ts +106 -106
- package/templates/recipe-arena-2d/files/scripts/PlayerController.ts +151 -151
- package/templates/recipe-arena-2d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-arena-2d/files/scripts/Spawner.ts +214 -214
- package/templates/recipe-arena-2d/files/scripts/TouchRules.ts +174 -174
- package/templates/recipe-arena-2d/template.yaml +10 -10
- package/templates/recipe-blank-2d/files/README.md +61 -61
- package/templates/recipe-blank-2d/files/design/recipe.md +148 -148
- package/templates/recipe-blank-2d/files/design/tests/reachability.json +4 -4
- package/templates/recipe-blank-2d/files/design/tests/routines/restart.json +27 -27
- package/templates/recipe-blank-2d/files/scenes/main.pix3scene +224 -224
- package/templates/recipe-blank-2d/files/scenes/ui/result.pix3scene +85 -85
- package/templates/recipe-blank-2d/files/scripts/GameRules.ts +350 -350
- package/templates/recipe-blank-2d/files/scripts/ScoreHud.ts +110 -110
- package/templates/recipe-blank-2d/template.yaml +10 -10
- package/templates/recipe-bouncer-2d/files/README.md +81 -81
- package/templates/recipe-bouncer-2d/files/design/recipe.md +146 -146
- package/templates/recipe-bouncer-2d/files/scenes/main.pix3scene +615 -615
- package/templates/recipe-bouncer-2d/files/scenes/menu.pix3scene +191 -191
- package/templates/recipe-bouncer-2d/files/scenes/ui/result.pix3scene +87 -87
- package/templates/recipe-bouncer-2d/files/scripts/BallBody.ts +298 -298
- package/templates/recipe-bouncer-2d/files/scripts/GameRules.ts +377 -377
- package/templates/recipe-bouncer-2d/files/scripts/MenuFlow.ts +109 -109
- package/templates/recipe-bouncer-2d/files/scripts/PaddleController.ts +112 -112
- package/templates/recipe-bouncer-2d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-bouncer-2d/files/scripts/TouchRules.ts +263 -263
- package/templates/recipe-bouncer-2d/files/scripts/ball-collision.ts +307 -307
- package/templates/recipe-bouncer-2d/template.yaml +10 -10
- package/templates/recipe-grid-3d/files/README.md +22 -22
- package/templates/recipe-grid-3d/files/design/recipe.md +110 -110
- package/templates/recipe-grid-3d/files/scenes/main.pix3scene +169 -169
- package/templates/recipe-grid-3d/files/scenes/menu.pix3scene +100 -100
- package/templates/recipe-grid-3d/files/scenes/ui/result.pix3scene +105 -105
- package/templates/recipe-grid-3d/files/scripts/GridBoard.ts +319 -319
- package/templates/recipe-grid-3d/files/scripts/GridRules.ts +278 -278
- package/templates/recipe-grid-3d/files/scripts/MenuFlow.ts +106 -106
- package/templates/recipe-grid-3d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-grid-3d/template.yaml +10 -10
- package/templates/recipe-tapper-2d/files/README.md +39 -39
- package/templates/recipe-tapper-2d/files/design/recipe.md +132 -132
- package/templates/recipe-tapper-2d/files/design/tests/reachability.json +4 -4
- package/templates/recipe-tapper-2d/files/design/tests/routines/terminal-retry.json +23 -23
- package/templates/recipe-tapper-2d/files/scenes/main.pix3scene +269 -269
- package/templates/recipe-tapper-2d/files/scenes/menu.pix3scene +100 -100
- package/templates/recipe-tapper-2d/files/scenes/prefabs/hazard.pix3scene +42 -42
- package/templates/recipe-tapper-2d/files/scenes/prefabs/target.pix3scene +45 -45
- package/templates/recipe-tapper-2d/files/scenes/ui/result.pix3scene +85 -85
- package/templates/recipe-tapper-2d/files/scripts/GameRules.ts +368 -368
- package/templates/recipe-tapper-2d/files/scripts/MenuFlow.ts +106 -106
- package/templates/recipe-tapper-2d/files/scripts/ScoreHud.ts +94 -94
- package/templates/recipe-tapper-2d/files/scripts/Spawner.ts +214 -214
- package/templates/recipe-tapper-2d/files/scripts/TouchRules.ts +192 -192
- package/templates/recipe-tapper-2d/template.yaml +10 -10
- package/dist/smoke/prebuilt/chunk-OJXQXIIQ.mjs +0 -239
- package/dist/validate/prebuilt/chunk-BS2OZM7U.js +0 -239
|
@@ -1,235 +1,238 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: pix3-scene-format
|
|
3
|
-
description: The .pix3scene YAML format — file header, node shape (id/type/name/properties/children/components), component shape, 2D transform and layout blocks, res:// references, textures, prefab instances and overrides, scenes/ui overlays and the visible/initiallyVisible split, plus how to translate design/recipe.md tool names into file edits. Use BEFORE creating or editing any .pix3scene file (scene, prefab or overlay) in this project.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
<!-- Pix3 agent kit 1.6.
|
|
7
|
-
# `.pix3scene` format
|
|
8
|
-
|
|
9
|
-
Scenes, prefabs and overlays are the same file type: YAML with a `.pix3scene` extension.
|
|
10
|
-
"Prefab" only means "a scene file that other scenes instance". There is no `.pix3prefab`.
|
|
11
|
-
The engine's own statement of the format (principles, skinned UI controls, Spine nodes) is in
|
|
12
|
-
`reference.md` beside this file; where the two differ, this page describes what the loader and
|
|
13
|
-
`pix3 validate` actually do.
|
|
14
|
-
|
|
15
|
-
## Before you write
|
|
16
|
-
|
|
17
|
-
- Re-read the file you are about to change — the human may have edited it in the editor.
|
|
18
|
-
- Change only the lines you mean to change. A whole-file rewrite from memory drops what the
|
|
19
|
-
human (or the editor) wrote since you last read it.
|
|
20
|
-
- If your tools support it, write to a temporary file and rename it over the target. Not
|
|
21
|
-
required for correctness — the editor waits for the file to stop changing — but cleaner.
|
|
22
|
-
- Then `pix3 check` (see `pix3-verify`).
|
|
23
|
-
|
|
24
|
-
## File
|
|
25
|
-
|
|
26
|
-
```yaml
|
|
27
|
-
version: 1.0.0 # the only format version; copy it
|
|
28
|
-
metadata: # optional, free-form
|
|
29
|
-
author: Pix3 Recipe
|
|
30
|
-
description: Tapper gameplay — falling objects
|
|
31
|
-
root: # list of root nodes; at least one
|
|
32
|
-
- id: game-root
|
|
33
|
-
type: Group2D
|
|
34
|
-
...
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
`#` lines are comments and may appear anywhere. Top-level keys are exactly `version`,
|
|
38
|
-
`description`, `metadata`, `root`.
|
|
39
|
-
|
|
40
|
-
## Node
|
|
41
|
-
|
|
42
|
-
```yaml
|
|
43
|
-
- id: spawner-targets # REQUIRED. Unique across the scene incl. instanced prefabs.
|
|
44
|
-
type: Group2D # REQUIRED for a plain node. Exact class name (see pix3-nodes).
|
|
45
|
-
name: Spawner Targets # display name; free to change
|
|
46
|
-
groups: [spawners] # optional runtime groups
|
|
47
|
-
properties: # node properties — names from pix3-nodes
|
|
48
|
-
width: 900
|
|
49
|
-
height: 60
|
|
50
|
-
transform:
|
|
51
|
-
position: [0, 690]
|
|
52
|
-
scale: [1, 1]
|
|
53
|
-
rotation: 0
|
|
54
|
-
components: # optional; script components
|
|
55
|
-
- id: target-spawner
|
|
56
|
-
type: user:Spawner
|
|
57
|
-
enabled: true
|
|
58
|
-
config:
|
|
59
|
-
prefab: res://scenes/prefabs/target.pix3scene
|
|
60
|
-
intervalSec: 0.85
|
|
61
|
-
children: [] # optional; child nodes, same shape, recursive
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
Rules:
|
|
65
|
-
|
|
66
|
-
- **`id`**: short, readable, kebab-case, unique (`combo-label`, `spawner-bonus`). Two nodes
|
|
67
|
-
with the same id fail the load. Never rename an id the recipe lists as stable — scripts
|
|
68
|
-
find nodes by id; rename `name` instead.
|
|
69
|
-
- **`type`**: must be a real node type. An unknown or misspelled type does **not** fail the
|
|
70
|
-
load — the node becomes an inert placeholder that draws and does nothing.
|
|
71
|
-
- **`properties`**: unknown keys are kept silently and do nothing; a value of the wrong type
|
|
72
|
-
(a string where a number belongs) is silently replaced by the default. Check names and
|
|
73
|
-
types against `pix3-nodes`.
|
|
74
|
-
- **`children`**: tree order is 2D paint order — a later sibling, or a deeper node, draws on
|
|
75
|
-
top. `zIndex` overrides it.
|
|
76
|
-
|
|
77
|
-
### 2D transform
|
|
78
|
-
|
|
79
|
-
```yaml
|
|
80
|
-
transform:
|
|
81
|
-
position: [x, y] # design pixels; the node's CENTRE, relative to its parent
|
|
82
|
-
scale: [1, 1]
|
|
83
|
-
rotation: 0 # DEGREES in YAML; positive = counter-clockwise (Y is up)
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
2D space: origin at the centre of the screen/parent, **X right, Y up**. The recipes use a
|
|
87
|
-
1080 x 1920 portrait design (top edge y = 960, bottom y = -960); other projects read
|
|
88
|
-
`viewportBaseSize` / `projectType` in `pix3project.yaml` — a `3d` project may have loose
|
|
89
|
-
top-level 2D nodes (a HUD) and no 2D root at all, so position new HUD relative to the HUD
|
|
90
|
-
nodes that are already there. Scripts see the rotation in
|
|
91
|
-
radians (`node.rotation.z`). `{ x: 0, y: 690 }` is also accepted for a vector, and so is a flat
|
|
92
|
-
`position:` beside `transform` (read-compat), but write the `transform:` block the editor saves.
|
|
93
|
-
|
|
94
|
-
3D nodes (`Node3D`, meshes, cameras, lights) use
|
|
95
|
-
`transform: { position: [x, y, z], rotationEuler: [dx, dy, dz], scale: [1, 1, 1] }`,
|
|
96
|
-
rotation in degrees.
|
|
97
|
-
|
|
98
|
-
### Anchor layout (2D)
|
|
99
|
-
|
|
100
|
-
```yaml
|
|
101
|
-
layout:
|
|
102
|
-
enabled: true
|
|
103
|
-
horizontalAlign: left # left | center | right | stretch
|
|
104
|
-
verticalAlign: top # top | center | bottom | stretch
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
The node keeps its authored distance to that edge of its parent when the parent resizes
|
|
108
|
-
(a different screen aspect). `stretch` keeps both margins and resizes the node. Position is
|
|
109
|
-
still authored in `transform.position`. HUD widgets anchor to screen edges; full-screen
|
|
110
|
-
backgrounds and roots use `stretch` on both axes.
|
|
111
|
-
|
|
112
|
-
**A new HUD node must not overlap the HUD that is already there.** Before you place it, read
|
|
113
|
-
the `position`, `width`/`height` and anchoring of its siblings and pick a free spot (a combo
|
|
114
|
-
label placed "top-right" once landed under the game's Shop button). With the live channel,
|
|
115
|
-
confirm it with a `viewport_screenshot` while the game runs; without it, ask the human to look.
|
|
116
|
-
|
|
117
|
-
Flow (stack children in a row/column) is a separate block:
|
|
118
|
-
`flow: { enabled: true, direction: vertical, gap: 16, paddingX: 0, paddingY: 0, align: start, autoSize: false }`.
|
|
119
|
-
|
|
120
|
-
The flat names `layoutEnabled`, `horizontalAlign`, `flowEnabled`, `flowGap` … are the
|
|
121
|
-
inspector's names for the same values: on a plain node they belong in these blocks (flat they
|
|
122
|
-
are ignored — `pix3 validate` says so); on an **instance** node they are the only form (below).
|
|
123
|
-
|
|
124
|
-
### Values
|
|
125
|
-
|
|
126
|
-
- **Colour**: a quoted hex string, `color: "#141a2e"`. Always quote — an unquoted `#` starts
|
|
127
|
-
a YAML comment and the value becomes empty.
|
|
128
|
-
- **Asset path**: `res://` + path from the project root (the folder with `pix3project.yaml`),
|
|
129
|
-
whatever the layout: `res://sprites/ph-target.png` in a recipe, `res://src/assets/textures/x.png`
|
|
130
|
-
in a project that keeps assets under `src/`. Follow the folders the project already has; a
|
|
131
|
-
new project from `pix3 new` uses one folder per type at the root (`sprites/`, `audio/`,
|
|
132
|
-
`fonts/`, `models/`, `spine/`, `scripts/`, `scenes/`).
|
|
133
|
-
- **Texture slot**: `texture: { type: 'texture', url: 'res://sprites/x.png' }` (same shape for
|
|
134
|
-
`textureNormal`, `textureFill`, …). The saver always writes this form; a bare
|
|
135
|
-
`texturePath: 'res://…'` string is only read for compatibility.
|
|
136
|
-
- **Strings** with `:` `#` `{` or leading spaces: quote them (`label: "SCORE 0"`).
|
|
137
|
-
|
|
138
|
-
### Shader effects (`Sprite2D`, `AnimatedSprite2D`, `Button2D` only)
|
|
139
|
-
|
|
140
|
-
```yaml
|
|
141
|
-
effects:
|
|
142
|
-
- type: core:tint
|
|
143
|
-
params: { color: "#7ee787", amount: 1 }
|
|
144
|
-
```
|
|
145
|
-
|
|
146
|
-
`core:tint` multiplies a near-white placeholder PNG to the colour — this is how recipe
|
|
147
|
-
placeholders get their palette. Also `core:adjust`, `core:grayscale`, `core:flash`,
|
|
148
|
-
`core:uv-scroll`, `core:dissolve`. Other 2D nodes do not read `effects` (a `ColorRect2D` takes
|
|
149
|
-
its colour from `color`). On a `GeometryMesh` the stack lives at `material.effects`.
|
|
150
|
-
|
|
151
|
-
## Component
|
|
152
|
-
|
|
153
|
-
```yaml
|
|
154
|
-
- id: combo # readable id; keep it unique in the scene
|
|
155
|
-
type: user:Combo # user:<ExportedClassName> (scripts/*.ts) or core:<Name>
|
|
156
|
-
enabled: true
|
|
157
|
-
config: # keys = names in the component's getPropertySchema()
|
|
158
|
-
windowSec: 1.2
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
- `config` is **merged over** the defaults the script's constructor sets, so write only the
|
|
162
|
-
keys you want to differ.
|
|
163
|
-
- A `user:X` whose class does not exist (or has no `static getPropertySchema()`) is kept as
|
|
164
|
-
"pending" with a console warning and never runs.
|
|
165
|
-
- Built-ins (`core:*`) and every config key they take, with defaults, are listed in
|
|
166
|
-
`.claude/skills/pix3-scripts/reference.md` ("`core:` components").
|
|
167
|
-
|
|
168
|
-
## Prefab instance
|
|
169
|
-
|
|
170
|
-
```yaml
|
|
171
|
-
- id: result-overlay
|
|
172
|
-
name: Result Overlay
|
|
173
|
-
instance: res://scenes/ui/result.pix3scene
|
|
174
|
-
properties:
|
|
175
|
-
visible: false
|
|
176
|
-
transform: { position: [0, 0] }
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
- `instance:` **replaces** `type:`. The instanced file must contain **exactly one** root node.
|
|
180
|
-
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
|
223
|
-
|
|
|
224
|
-
| `
|
|
225
|
-
|
|
|
226
|
-
| `
|
|
227
|
-
| `
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
1
|
+
---
|
|
2
|
+
name: pix3-scene-format
|
|
3
|
+
description: The .pix3scene YAML format — file header, node shape (id/type/name/properties/children/components), component shape, 2D transform and layout blocks, res:// references, textures, prefab instances and overrides, scenes/ui overlays and the visible/initiallyVisible split, plus how to translate design/recipe.md tool names into file edits. Use BEFORE creating or editing any .pix3scene file (scene, prefab or overlay) in this project.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
<!-- Pix3 agent kit 1.6.2 -->
|
|
7
|
+
# `.pix3scene` format
|
|
8
|
+
|
|
9
|
+
Scenes, prefabs and overlays are the same file type: YAML with a `.pix3scene` extension.
|
|
10
|
+
"Prefab" only means "a scene file that other scenes instance". There is no `.pix3prefab`.
|
|
11
|
+
The engine's own statement of the format (principles, skinned UI controls, Spine nodes) is in
|
|
12
|
+
`reference.md` beside this file; where the two differ, this page describes what the loader and
|
|
13
|
+
`pix3 validate` actually do.
|
|
14
|
+
|
|
15
|
+
## Before you write
|
|
16
|
+
|
|
17
|
+
- Re-read the file you are about to change — the human may have edited it in the editor.
|
|
18
|
+
- Change only the lines you mean to change. A whole-file rewrite from memory drops what the
|
|
19
|
+
human (or the editor) wrote since you last read it.
|
|
20
|
+
- If your tools support it, write to a temporary file and rename it over the target. Not
|
|
21
|
+
required for correctness — the editor waits for the file to stop changing — but cleaner.
|
|
22
|
+
- Then `pix3 check` (see `pix3-verify`).
|
|
23
|
+
|
|
24
|
+
## File
|
|
25
|
+
|
|
26
|
+
```yaml
|
|
27
|
+
version: 1.0.0 # the only format version; copy it
|
|
28
|
+
metadata: # optional, free-form
|
|
29
|
+
author: Pix3 Recipe
|
|
30
|
+
description: Tapper gameplay — falling objects
|
|
31
|
+
root: # list of root nodes; at least one
|
|
32
|
+
- id: game-root
|
|
33
|
+
type: Group2D
|
|
34
|
+
...
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
`#` lines are comments and may appear anywhere. Top-level keys are exactly `version`,
|
|
38
|
+
`description`, `metadata`, `root`.
|
|
39
|
+
|
|
40
|
+
## Node
|
|
41
|
+
|
|
42
|
+
```yaml
|
|
43
|
+
- id: spawner-targets # REQUIRED. Unique across the scene incl. instanced prefabs.
|
|
44
|
+
type: Group2D # REQUIRED for a plain node. Exact class name (see pix3-nodes).
|
|
45
|
+
name: Spawner Targets # display name; free to change
|
|
46
|
+
groups: [spawners] # optional runtime groups
|
|
47
|
+
properties: # node properties — names from pix3-nodes
|
|
48
|
+
width: 900
|
|
49
|
+
height: 60
|
|
50
|
+
transform:
|
|
51
|
+
position: [0, 690]
|
|
52
|
+
scale: [1, 1]
|
|
53
|
+
rotation: 0
|
|
54
|
+
components: # optional; script components
|
|
55
|
+
- id: target-spawner
|
|
56
|
+
type: user:Spawner
|
|
57
|
+
enabled: true
|
|
58
|
+
config:
|
|
59
|
+
prefab: res://scenes/prefabs/target.pix3scene
|
|
60
|
+
intervalSec: 0.85
|
|
61
|
+
children: [] # optional; child nodes, same shape, recursive
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Rules:
|
|
65
|
+
|
|
66
|
+
- **`id`**: short, readable, kebab-case, unique (`combo-label`, `spawner-bonus`). Two nodes
|
|
67
|
+
with the same id fail the load. Never rename an id the recipe lists as stable — scripts
|
|
68
|
+
find nodes by id; rename `name` instead.
|
|
69
|
+
- **`type`**: must be a real node type. An unknown or misspelled type does **not** fail the
|
|
70
|
+
load — the node becomes an inert placeholder that draws and does nothing.
|
|
71
|
+
- **`properties`**: unknown keys are kept silently and do nothing; a value of the wrong type
|
|
72
|
+
(a string where a number belongs) is silently replaced by the default. Check names and
|
|
73
|
+
types against `pix3-nodes`.
|
|
74
|
+
- **`children`**: tree order is 2D paint order — a later sibling, or a deeper node, draws on
|
|
75
|
+
top. `zIndex` overrides it.
|
|
76
|
+
|
|
77
|
+
### 2D transform
|
|
78
|
+
|
|
79
|
+
```yaml
|
|
80
|
+
transform:
|
|
81
|
+
position: [x, y] # design pixels; the node's CENTRE, relative to its parent
|
|
82
|
+
scale: [1, 1]
|
|
83
|
+
rotation: 0 # DEGREES in YAML; positive = counter-clockwise (Y is up)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
2D space: origin at the centre of the screen/parent, **X right, Y up**. The recipes use a
|
|
87
|
+
1080 x 1920 portrait design (top edge y = 960, bottom y = -960); other projects read
|
|
88
|
+
`viewportBaseSize` / `projectType` in `pix3project.yaml` — a `3d` project may have loose
|
|
89
|
+
top-level 2D nodes (a HUD) and no 2D root at all, so position new HUD relative to the HUD
|
|
90
|
+
nodes that are already there. Scripts see the rotation in
|
|
91
|
+
radians (`node.rotation.z`). `{ x: 0, y: 690 }` is also accepted for a vector, and so is a flat
|
|
92
|
+
`position:` beside `transform` (read-compat), but write the `transform:` block the editor saves.
|
|
93
|
+
|
|
94
|
+
3D nodes (`Node3D`, meshes, cameras, lights) use
|
|
95
|
+
`transform: { position: [x, y, z], rotationEuler: [dx, dy, dz], scale: [1, 1, 1] }`,
|
|
96
|
+
rotation in degrees.
|
|
97
|
+
|
|
98
|
+
### Anchor layout (2D)
|
|
99
|
+
|
|
100
|
+
```yaml
|
|
101
|
+
layout:
|
|
102
|
+
enabled: true
|
|
103
|
+
horizontalAlign: left # left | center | right | stretch
|
|
104
|
+
verticalAlign: top # top | center | bottom | stretch
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
The node keeps its authored distance to that edge of its parent when the parent resizes
|
|
108
|
+
(a different screen aspect). `stretch` keeps both margins and resizes the node. Position is
|
|
109
|
+
still authored in `transform.position`. HUD widgets anchor to screen edges; full-screen
|
|
110
|
+
backgrounds and roots use `stretch` on both axes.
|
|
111
|
+
|
|
112
|
+
**A new HUD node must not overlap the HUD that is already there.** Before you place it, read
|
|
113
|
+
the `position`, `width`/`height` and anchoring of its siblings and pick a free spot (a combo
|
|
114
|
+
label placed "top-right" once landed under the game's Shop button). With the live channel,
|
|
115
|
+
confirm it with a `viewport_screenshot` while the game runs; without it, ask the human to look.
|
|
116
|
+
|
|
117
|
+
Flow (stack children in a row/column) is a separate block:
|
|
118
|
+
`flow: { enabled: true, direction: vertical, gap: 16, paddingX: 0, paddingY: 0, align: start, autoSize: false }`.
|
|
119
|
+
|
|
120
|
+
The flat names `layoutEnabled`, `horizontalAlign`, `flowEnabled`, `flowGap` … are the
|
|
121
|
+
inspector's names for the same values: on a plain node they belong in these blocks (flat they
|
|
122
|
+
are ignored — `pix3 validate` says so); on an **instance** node they are the only form (below).
|
|
123
|
+
|
|
124
|
+
### Values
|
|
125
|
+
|
|
126
|
+
- **Colour**: a quoted hex string, `color: "#141a2e"`. Always quote — an unquoted `#` starts
|
|
127
|
+
a YAML comment and the value becomes empty.
|
|
128
|
+
- **Asset path**: `res://` + path from the project root (the folder with `pix3project.yaml`),
|
|
129
|
+
whatever the layout: `res://sprites/ph-target.png` in a recipe, `res://src/assets/textures/x.png`
|
|
130
|
+
in a project that keeps assets under `src/`. Follow the folders the project already has; a
|
|
131
|
+
new project from `pix3 new` uses one folder per type at the root (`sprites/`, `audio/`,
|
|
132
|
+
`fonts/`, `models/`, `spine/`, `scripts/`, `scenes/`).
|
|
133
|
+
- **Texture slot**: `texture: { type: 'texture', url: 'res://sprites/x.png' }` (same shape for
|
|
134
|
+
`textureNormal`, `textureFill`, …). The saver always writes this form; a bare
|
|
135
|
+
`texturePath: 'res://…'` string is only read for compatibility.
|
|
136
|
+
- **Strings** with `:` `#` `{` or leading spaces: quote them (`label: "SCORE 0"`).
|
|
137
|
+
|
|
138
|
+
### Shader effects (`Sprite2D`, `AnimatedSprite2D`, `Button2D` only)
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
effects:
|
|
142
|
+
- type: core:tint
|
|
143
|
+
params: { color: "#7ee787", amount: 1 }
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
`core:tint` multiplies a near-white placeholder PNG to the colour — this is how recipe
|
|
147
|
+
placeholders get their palette. Also `core:adjust`, `core:grayscale`, `core:flash`,
|
|
148
|
+
`core:uv-scroll`, `core:dissolve`. Other 2D nodes do not read `effects` (a `ColorRect2D` takes
|
|
149
|
+
its colour from `color`). On a `GeometryMesh` the stack lives at `material.effects`.
|
|
150
|
+
|
|
151
|
+
## Component
|
|
152
|
+
|
|
153
|
+
```yaml
|
|
154
|
+
- id: combo # readable id; keep it unique in the scene
|
|
155
|
+
type: user:Combo # user:<ExportedClassName> (scripts/*.ts) or core:<Name>
|
|
156
|
+
enabled: true
|
|
157
|
+
config: # keys = names in the component's getPropertySchema()
|
|
158
|
+
windowSec: 1.2
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
- `config` is **merged over** the defaults the script's constructor sets, so write only the
|
|
162
|
+
keys you want to differ.
|
|
163
|
+
- A `user:X` whose class does not exist (or has no `static getPropertySchema()`) is kept as
|
|
164
|
+
"pending" with a console warning and never runs.
|
|
165
|
+
- Built-ins (`core:*`) and every config key they take, with defaults, are listed in
|
|
166
|
+
`.claude/skills/pix3-scripts/reference.md` ("`core:` components").
|
|
167
|
+
|
|
168
|
+
## Prefab instance
|
|
169
|
+
|
|
170
|
+
```yaml
|
|
171
|
+
- id: result-overlay
|
|
172
|
+
name: Result Overlay
|
|
173
|
+
instance: res://scenes/ui/result.pix3scene
|
|
174
|
+
properties:
|
|
175
|
+
visible: false
|
|
176
|
+
transform: { position: [0, 0] }
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
- `instance:` **replaces** `type:`. The instanced file must contain **exactly one** root node.
|
|
180
|
+
- The instance node's `name` **replaces the prefab root's name** in the loaded scene (its `id`
|
|
181
|
+
stays the instance's own id). `findByName('Result Overlay')` finds the instance above, not
|
|
182
|
+
the name written in `result.pix3scene`; omit `name` to keep the prefab's.
|
|
183
|
+
- Instance `properties` are applied to the prefab's root through its **schema names**:
|
|
184
|
+
`visible`, `opacity`, `width`, `layoutEnabled`, `horizontalAlign`, … plus a `transform` block
|
|
185
|
+
(`position`, `rotation`, `scale`). The `layout:` / `flow:` blocks of a plain node are not read
|
|
186
|
+
here — write `layoutEnabled: true` + `horizontalAlign: right` instead.
|
|
187
|
+
- Do **not** add `components` or `children` to an instance node — they are ignored (the
|
|
188
|
+
content comes from the prefab). To change what is inside, edit the prefab file itself, or
|
|
189
|
+
override one inner node's properties:
|
|
190
|
+
|
|
191
|
+
```yaml
|
|
192
|
+
overrides:
|
|
193
|
+
byLocalId:
|
|
194
|
+
retry-button: # an id below the prefab root; nested: parent-id/child-id
|
|
195
|
+
properties: { label: "AGAIN" } # schema names, as on the instance itself
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
- Nodes inside an instance keep their authored ids when those are unique, so scripts can find
|
|
199
|
+
them by id (`retry-button` inside `scenes/ui/result.pix3scene` is found as `retry-button`).
|
|
200
|
+
- A prefab carries fixed defaults only (e.g. its `core:Hitbox2D` group). Tunables live on
|
|
201
|
+
plain nodes in the host scene.
|
|
202
|
+
- Where prefabs live: `scenes/prefabs/` (the recipes) or a top-level `prefabs/` — the export
|
|
203
|
+
treats both (and `scenes/ui/`) as prefabs, never as a boot scene.
|
|
204
|
+
- Spawned at runtime with `await this.scene.instantiate('res://scenes/prefabs/x.pix3scene', { parent })`.
|
|
205
|
+
|
|
206
|
+
## Full-screen UI lives in `scenes/ui/`
|
|
207
|
+
|
|
208
|
+
A result card, pause menu or modal is its own file in `scenes/ui/`, instanced into the host
|
|
209
|
+
scene with `properties: { visible: false }`. Two different flags, both needed:
|
|
210
|
+
|
|
211
|
+
- `visible: false` on the **instance** — hides it in the **editor**, so `main.pix3scene`
|
|
212
|
+
opens on the game, not on a GAME OVER card. Never remove it.
|
|
213
|
+
- `initiallyVisible: false|true` on the **overlay file's root node** — what **play mode**
|
|
214
|
+
applies at start. A script reveals the overlay by setting `node.visible = true`.
|
|
215
|
+
|
|
216
|
+
Never put a full-screen dimmer/panel inline in `main.pix3scene`.
|
|
217
|
+
|
|
218
|
+
## Recipe tool names → file edits
|
|
219
|
+
|
|
220
|
+
`design/recipe.md` was written for the in-editor agent. Without its tools:
|
|
221
|
+
|
|
222
|
+
| recipe.md says | you do |
|
|
223
|
+
| --- | --- |
|
|
224
|
+
| tunable with `component: "user:X"` | edit `config.<property>` of the component with `type: user:X` on the node with that `id` |
|
|
225
|
+
| tunable without `component` | edit `properties.<property>` on the node with that `id` (in the `transform` / `layout` / `flow` block where it belongs) |
|
|
226
|
+
| `set_property` | edit `properties` in the YAML |
|
|
227
|
+
| `set_component_property` | edit the component's `config` |
|
|
228
|
+
| `create_node` / `add_component` | add the node / component entry to the YAML |
|
|
229
|
+
| `fs_write` (+ `overwrite: true`) | write the file |
|
|
230
|
+
| `play_start`, `game_input`, `game_observe`, `game_run` | the same tools over the live channel when it is connected (`pix3-verify`); otherwise `pix3 check`, then `pix3 smoke <the scene you changed>`, then ask the human to press Play and tell them what to look for |
|
|
231
|
+
|
|
232
|
+
Values out of a tunable's `min`/`max` load as written (`pix3 validate` warns); the script's
|
|
233
|
+
schema `setValue` may clamp them.
|
|
234
|
+
|
|
235
|
+
## Known gaps
|
|
236
|
+
|
|
237
|
+
- `metadata.description` is free text; nothing reads it but humans.
|
|
238
|
+
- Instance overrides of **components** inside a prefab are not supported from the host scene.
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
<!-- Pix3 agent kit 1.6.
|
|
2
|
-
# `.pix3scene` — the engine specification
|
|
3
|
-
|
|
4
|
-
Excerpts of the engine's specification, as shipped with this CLI. `SKILL.md` beside this file
|
|
5
|
-
is the practical version and wins where they differ — in particular node ids may be readable
|
|
6
|
-
kebab-case, and there are no scene-format migrations today (`version: 1.0.0` is the only one).
|
|
7
|
-
The "Flat Asset Layout" principle is what `pix3 new` creates; an existing project keeps its own
|
|
8
|
-
layout (`res://` is always relative to the project root). Source paths quoted here (`src/…`, `packages/…`) are files of the Pix3 engine repository, not of this project.
|
|
9
|
-
|
|
10
|
-
## Key principles
|
|
11
|
-
|
|
1
|
+
<!-- Pix3 agent kit 1.6.2 — generated from docs/pix3-specification.md ("Scene File Format"). Do not edit: pix3 kit --update regenerates it. -->
|
|
2
|
+
# `.pix3scene` — the engine specification
|
|
3
|
+
|
|
4
|
+
Excerpts of the engine's specification, as shipped with this CLI. `SKILL.md` beside this file
|
|
5
|
+
is the practical version and wins where they differ — in particular node ids may be readable
|
|
6
|
+
kebab-case, and there are no scene-format migrations today (`version: 1.0.0` is the only one).
|
|
7
|
+
The "Flat Asset Layout" principle is what `pix3 new` creates; an existing project keeps its own
|
|
8
|
+
layout (`res://` is always relative to the project root). Source paths quoted here (`src/…`, `packages/…`) are files of the Pix3 engine repository, not of this project.
|
|
9
|
+
|
|
10
|
+
## Key principles
|
|
11
|
+
|
|
12
12
|
- Declarative: The file describes the composition and structure of the scene, not the process of its creation.
|
|
13
13
|
- Asset Referencing: Assets (models, textures) are not embedded in the file but are referenced via relative paths with a res:// prefix (path from the project root).
|
|
14
14
|
- Flat Asset Layout: a game project keeps one folder per asset type **at its root** — `scenes/`, `sprites/` (images/textures), `models/`, `audio/`, `fonts/`, `spine/` (skeleton + atlas + pages together), `scripts/`, `locales/` — with free subdivision inside (`sprites/ui/…`). There is no `assets/` wrapper folder; the project templates ship this layout and `defaultAssetFolder()` (`src/core/asset-categories.ts`) is the canonical mapping used when the editor creates an asset from a bare file name.
|
|
@@ -18,10 +18,10 @@ layout (`res://` is always relative to the project root). Source paths quoted he
|
|
|
18
18
|
- Unique Identification: Every node must have an id field. The value is a short, cryptographically secure unique identifier (similar to Nano ID) to provide a balance between file readability and the absolute reliability of references.
|
|
19
19
|
- Versioned Schema: Each file includes a `version` field; migrations are maintained in the SceneManager and run automatically on load.
|
|
20
20
|
- Conflict Resolution: Instance overrides always win over parent definitions. Duplicate IDs trigger validation errors during import.
|
|
21
|
-
- Forgiving Vocabulary: a `type:` the loader does not know does **not** fail the load — the node is built as a bare `NodeBase` placeholder that does nothing, so a scene written by a newer version (or with a typo) stays openable and editable. Because such a node is otherwise indistinguishable from a working one, it is reported on three surfaces: the renderability lint (`inert-nodes` in `scene_tree` / `game_observe` / play start), the loader diagnostic (`describeUnknownNodeType`, which suggests the nearest known name), and the Scene Tree row, which carries a warn badge and states the reason in its tooltip. `isInertNode` (`packages/pix3-runtime/src/core/renderability-lint.ts`) is the one predicate behind all three.
|
|
22
|
-
|
|
23
|
-
## Skinned 2D UI controls
|
|
24
|
-
|
|
21
|
+
- Forgiving Vocabulary: a `type:` the loader does not know does **not** fail the load — the node is built as a bare `NodeBase` placeholder that does nothing, so a scene written by a newer version (or with a typo) stays openable and editable. Because such a node is otherwise indistinguishable from a working one, it is reported on three surfaces: the renderability lint (`inert-nodes` in `scene_tree` / `game_observe` / play start), the loader diagnostic (`describeUnknownNodeType`, which suggests the nearest known name), and the Scene Tree row, which carries a warn badge and states the reason in its tooltip. `isInertNode` (`packages/pix3-runtime/src/core/renderability-lint.ts`) is the one predicate behind all three.
|
|
22
|
+
|
|
23
|
+
## Skinned 2D UI controls
|
|
24
|
+
|
|
25
25
|
`Button2D`, `Checkbox2D`, `Slider2D` and `Bar2D` are colour-driven by default and
|
|
26
26
|
skinned by pointing their texture slots at `res://` sprites. A slot that is set
|
|
27
27
|
replaces the corresponding flat colour (the material tint goes white); a slot that
|
|
@@ -92,10 +92,10 @@ in **§6.23 UI Kit Assets**.
|
|
|
92
92
|
textureBox: { type: 'texture', url: 'res://sprites/ui/check_off.png' }
|
|
93
93
|
textureBoxChecked: { type: 'texture', url: 'res://sprites/ui/check_on.png' }
|
|
94
94
|
textureMark: { type: 'texture', url: 'res://sprites/ui/check_tick.png' }
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
## Spine skeleton nodes
|
|
98
|
-
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Spine skeleton nodes
|
|
98
|
+
|
|
99
99
|
A `SpineSkeleton2D` references its Spine export by two `res://` paths — the
|
|
100
100
|
skeleton (`.json` or `.skel`) and the atlas (`.atlas`). The atlas' page images are
|
|
101
101
|
NOT listed: they are named inside the atlas text and resolved relative to it (the
|
|
@@ -124,10 +124,10 @@ optional single-page override.
|
|
|
124
124
|
|
|
125
125
|
Rendering requires the optional `@esotericsoftware/spine-threejs` (`~4.3`) module,
|
|
126
126
|
registered by the host through `setSpineModuleLoader`. A scene with a Spine node
|
|
127
|
-
still loads without it — the node keeps its authored properties and warns.
|
|
128
|
-
|
|
129
|
-
## Groups
|
|
130
|
-
|
|
127
|
+
still loads without it — the node keeps its authored properties and warns.
|
|
128
|
+
|
|
129
|
+
## Groups
|
|
130
|
+
|
|
131
131
|
Groups provide runtime categorization for nodes (for example, `enemies`, `ui`, `interactables`).
|
|
132
132
|
|
|
133
133
|
#### 6.19.1 Node API
|
|
@@ -155,10 +155,10 @@ root:
|
|
|
155
155
|
type: Node3D
|
|
156
156
|
name: Player
|
|
157
157
|
groups: [actors, player]
|
|
158
|
-
```
|
|
159
|
-
|
|
160
|
-
## Prefabs — instance creation
|
|
161
|
-
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
## Prefabs — instance creation
|
|
161
|
+
|
|
162
162
|
Creating a prefab instance uses the `instance:` YAML key:
|
|
163
163
|
|
|
164
164
|
```yaml
|
|
@@ -173,4 +173,4 @@ root:
|
|
|
173
173
|
position: { x: 0, y: 0, z: 0 }
|
|
174
174
|
```
|
|
175
175
|
|
|
176
|
-
The `properties` block allows overriding base prefab values. Overrides are tracked separately from the base values.
|
|
176
|
+
The `properties` block allows overriding base prefab values. Overrides are tracked separately from the base values.
|