@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,30 +0,0 @@
1
- # {{PROJECT_NAME}}
2
-
3
- A Pix3 project created from the **Playable 2D** template — a portrait playable-ad blank.
4
-
5
- ## What's included
6
-
7
- - **Tap-to-start intro** (`intro-overlay`, `scenes/ui/intro.pix3scene`) — the first tap unlocks browser audio and starts the game (`scripts/GameFlow.ts`).
8
- - **Gameplay placeholder** — replace the animated logo sprite in `main.pix3scene` with your game.
9
- - **End screen with CTA** (`end-screen`, `scenes/ui/end-screen.pix3scene`) — the PLAY NOW button reports game end (`playable.gameEnd()`) and logs the click. It opens nothing: the ad network decides the store target at delivery time (`mraid.open` / `dapi.openStoreUrl`), so wire its SDK in `CtaButton.ctaClick()` when you package the ad.
10
- - `GameFlow` shows the end screen automatically after `autoWinAfterSec` seconds — replace that with your real win/lose condition.
11
- - **Readable state** — `GameFlow` publishes a `registerGameDebug` snapshot (phase, timer, overlay visibility, session end), so tooling reads the run's state instead of judging it from a screenshot. Add your own fields as you add state.
12
- - **Intent-first handlers** — every reaction to the player is a named method (`GameFlow.start/finish/restart`, `CtaButton.ctaClick`) that the event handler merely calls; keep that shape and the game stays drivable by intent.
13
-
14
- ## Project structure
15
-
16
- - `design/` — game design document and reference images
17
- - `design/tests/` — agent-testing material: `routines/*.json` (named step +
18
- assertion scripts, written on the highest channel the game offers) and
19
- `reachability.json` (controls proven reachable on a live run). The harness
20
- that runs them is still in development; format and location are fixed now.
21
- - `scenes/` — scene files; `main.pix3scene` is the startup scene
22
- - `scenes/ui/` — the full-screen overlays (`intro.pix3scene`, `end-screen.pix3scene`),
23
- instanced into `main.pix3scene` with `visible: false` so the editor opens on the
24
- game. That flag is editor-only; `initiallyVisible` on each overlay's root is what
25
- play mode reads. Edit an overlay in its own tab, or tick the eye on its instance
26
- node to preview it composited — just don't save that tick.
27
- - `sprites/` — images and textures
28
- - `scripts/` — game scripts (`export class X extends Script`, used as `user:X`)
29
- - `audio/` — music and sound effects
30
- - `AGENTS.md` — rules and pointers for AI agents working on this project
@@ -1,83 +0,0 @@
1
- # Recipe: recipe-playable-ad
2
-
3
- ## What this is
4
-
5
- The playable-ad shape: a portrait scene with a tap-to-start gate, a short piece
6
- of gameplay, and an end screen whose CTA button reports game end through the
7
- engine Playable SDK and logs the click. It opens no store page — the ad network
8
- picks that target at delivery time, so hook its SDK into `CtaButton.ctaClick()`
9
- when you package the ad. One scene, no menu — an ad has no menu.
10
-
11
- The gameplay itself is deliberately a placeholder (`hero-sprite` bobbing on a
12
- `core:Sine`) plus an auto-win timer. Replace both: keep the gate and the CTA,
13
- build the middle. If the brief needs real mechanics, start from `recipe-arena-2d`,
14
- `recipe-bouncer-2d` or `recipe-tapper-2d` and port this gate/CTA structure over.
15
-
16
- ## Node map
17
-
18
- | id | what |
19
- | --- | --- |
20
- | `game-root` | scene root; hosts `GameFlow` (the phase driver: intro → playing → ended) |
21
- | `background` | full-screen `ColorRect2D` (palette background) |
22
- | `hero-sprite` | placeholder gameplay object, bobbing on a `core:Sine` |
23
- | `hud-label` | in-game text line |
24
- | `intro-overlay` → `intro-dim`, `intro-label` | the tap gate (`scenes/ui/intro.pix3scene`, instanced into main); the first tap hides it, starts the game, and unlocks browser audio |
25
- | `end-screen` → `end-dim`, `end-label`, `cta-button` | end screen (`scenes/ui/end-screen.pix3scene`, instanced into main), `initiallyVisible: false` |
26
- | `cta-button` | hosts `CtaButton` — `playable.gameEnd()` + a `[CtaButton] CTA clicked` log; the store call belongs to the ad network SDK, not to the template |
27
-
28
- `GameFlow.finish()` reveals the end screen; call it from your gameplay code for
29
- a real win/lose instead of the placeholder timer.
30
-
31
- ## Placeholders
32
-
33
- | role | file | node |
34
- | --- | --- | --- |
35
- | hero | `sprites/pix3-logo.png` | `hero-sprite` |
36
-
37
- ## Tunables
38
-
39
- ```yaml
40
- tunables:
41
- autoWinAfterSec: { node: game-root, component: "user:GameFlow", property: autoWinAfterSec, min: 0, max: 120, default: 15 }
42
- introNode: { node: game-root, component: "user:GameFlow", property: introNode, default: intro-overlay }
43
- endNode: { node: game-root, component: "user:GameFlow", property: endNode, default: end-screen }
44
- skipIntro: { node: game-root, component: "user:GameFlow", property: skipIntro, default: false }
45
- bgColor: { node: background, property: color, default: "#16213e" }
46
- ```
47
-
48
- `component` present → `set_component_property`; absent → `set_property`.
49
-
50
- `skipIntro: true` starts the run already playing, with the tap gate hidden — a
51
- prototyping vent so iterating does not cost a tap per reload. Turn it back off
52
- before shipping: in an ad container that first tap is what unlocks browser audio.
53
-
54
- ## Extension points
55
-
56
- - **Real gameplay.** Replace `hero-sprite` and set `autoWinAfterSec: 0`, then
57
- call `finish()` on the `GameFlow` component from your own script when the
58
- player wins or loses. Everything else (gate, end screen, CTA) stays.
59
- - **Fail state.** Add a `lose-label` inside `end-screen` and pick the text in
60
- your `finish()` caller — a playable that can only be won reads as a demo.
61
- - **Second CTA.** Any `Button2D` with a `user:CtaButton` component works, so an
62
- early "install now" banner is one node.
63
- - **Network requirements.** Keep everything self-contained: an ad bundle is a
64
- single HTML file, so no external fetches, and prefer few, small textures.
65
-
66
- ## Do not touch
67
-
68
- - The node ids above (rename `name`, never `id`).
69
- - `intro-overlay` must exist and be visible at start (`initiallyVisible: true` in
70
- `scenes/ui/intro.pix3scene`): the first tap is what unlocks browser audio, so a
71
- playable without a gate ships silent.
72
- - `end-screen` must keep `initiallyVisible: false` (in `scenes/ui/end-screen.pix3scene`).
73
- - The `visible: false` on both `instance:` nodes in `main.pix3scene` is an
74
- editor-only hide so the scene opens on the game — keep it, and author
75
- `initiallyVisible` in the overlay file, never as an instance override.
76
- - Do not import rapier — it would put a ~2 MB wasm payload in an ad bundle.
77
-
78
- ## Verify
79
-
80
- 1. `play_start` on `scenes/main.pix3scene`; `intro-overlay` is visible.
81
- 2. `game_input` a tap → `intro-overlay` hides and `hero-sprite` starts bobbing.
82
- 3. Wait `autoWinAfterSec` → `end-screen` becomes visible with `cta-button`.
83
- 4. Press `cta-button` → the SDK reports game end and `[CtaButton] CTA clicked` appears in the console (nothing navigates away).
@@ -1,4 +0,0 @@
1
- {
2
- "version": 1,
3
- "proven": []
4
- }
@@ -1,32 +0,0 @@
1
- {
2
- "name": "intro-to-cta",
3
- "description": "Tap through the intro gate, end the run by intent, and press the CTA on the end screen.",
4
- "note": "Run it with game_run {routine:'intro-to-cta'}. Steps are the game_input vocabulary (tap/key/keys/drag/hover/wait/invoke) plus {type:'command', name} for an intent the scene registered; `expect` holds the ordinary game_run predicates, ANDed and judged once after the last step. A step's `why` and this `note` are documentation — the runner ignores both — but they are why the routine also reads as a checklist. Note what is NOT here: no step calls a component method directly. Ending the run goes through the `finish` command, because a routine that called the handler would prove the handler works while skipping every wire between the player and it.",
5
- "scope": "scenes/main.pix3scene",
6
- "params": {},
7
- "uses": ["game-root", "intro-overlay", "end-screen", "cta-button"],
8
- "steps": [
9
- {
10
- "type": "tap",
11
- "target": "intro-overlay",
12
- "why": "The tap gate is the gesture under test: it hides the overlay and unlocks browser audio, so it is driven as a real tap rather than by dispatching start-game."
13
- },
14
- {
15
- "type": "command",
16
- "name": "finish",
17
- "why": "Reveal the end screen by intent instead of waiting out autoWinAfterSec — the timer is a placeholder every real playable replaces, and 15 s of wall clock in every run is a budget nobody gets back."
18
- },
19
- {
20
- "type": "tap",
21
- "target": "cta-button",
22
- "holdMs": 700,
23
- "why": "Button2D needs a real press; this proves the button is on screen and hittable, not just present in the tree."
24
- }
25
- ],
26
- "expect": [
27
- { "kind": "gameState", "path": "phase", "op": "eq", "value": "ended" },
28
- { "kind": "gameState", "path": "introVisible", "op": "eq", "value": false },
29
- { "kind": "gameState", "path": "endVisible", "op": "eq", "value": true },
30
- { "kind": "gameState", "path": "gameEnded", "op": "eq", "value": true }
31
- ]
32
- }
@@ -1,111 +0,0 @@
1
- # Pix3 Scene File (YAML)
2
- # Playable 2D blank (portrait 1080x1920): 2D gameplay placeholder plus a
3
- # tap-to-start intro overlay and an end screen with a CTA button.
4
- #
5
- # Full-screen UI lives in its own file under scenes/ui/ and is instanced here
6
- # hidden (`visible: false` = editor only; `initiallyVisible` in the overlay file
7
- # is what play mode reads), so opening this scene shows the game rather than a
8
- # dim or a CTA card:
9
- # intro-overlay (intro-dim, intro-label) scenes/ui/intro.pix3scene
10
- # end-screen (end-dim, end-label, cta-button) scenes/ui/end-screen.pix3scene
11
- # Instance children keep their ids, so `GameFlow`'s introNode/endNode and every
12
- # `findNode` still resolve. Node order in the tree is paint order.
13
- version: 1.0.0
14
- metadata:
15
- author: Pix3 Template
16
- description: Playable 2D blank with intro overlay and CTA end screen
17
- root:
18
- - id: game-root
19
- type: Group2D
20
- name: Game Root
21
- properties:
22
- width: 1080
23
- height: 1920
24
- layout:
25
- enabled: true
26
- horizontalAlign: stretch
27
- verticalAlign: stretch
28
- components:
29
- - id: game-flow
30
- type: user:GameFlow
31
- enabled: true
32
- config:
33
- introNode: intro-overlay
34
- endNode: end-screen
35
- autoWinAfterSec: 15
36
- children:
37
- - id: background
38
- type: ColorRect2D
39
- name: Background
40
- properties:
41
- width: 1080
42
- height: 1920
43
- color: "#16213e"
44
- transform:
45
- position: [0, 0]
46
- scale: [1, 1]
47
- rotation: 0
48
- layout:
49
- enabled: true
50
- horizontalAlign: stretch
51
- verticalAlign: stretch
52
- children: []
53
- - id: hero-sprite
54
- type: Sprite2D
55
- name: Hero Sprite
56
- properties:
57
- texture: { type: 'texture', url: 'res://sprites/pix3-logo.png' }
58
- width: 242
59
- height: 96
60
- transform:
61
- position: [0, 0]
62
- scale: [1, 1]
63
- rotation: 0
64
- layout:
65
- enabled: true
66
- horizontalAlign: center
67
- verticalAlign: center
68
- components:
69
- - id: hero-bob
70
- type: core:Sine
71
- enabled: true
72
- config:
73
- amplitude: 40
74
- frequency: 0.6
75
- axis: y
76
- children: []
77
- - id: hud-label
78
- type: Label2D
79
- name: HUD Label
80
- properties:
81
- label: "PROTOTYPE"
82
- labelFontSize: 40
83
- labelColor: "#ffffff"
84
- labelAlign: center
85
- transform:
86
- position: [0, 860]
87
- scale: [1, 1]
88
- rotation: 0
89
- layout:
90
- enabled: true
91
- horizontalAlign: center
92
- verticalAlign: top
93
- children: []
94
- # Tap gate — authored in scenes/ui/intro.pix3scene so this scene opens on
95
- # the GAME. `visible: false` hides it in the EDITOR only; `initiallyVisible`
96
- # (in the overlay file) is what play mode reads. Tick the eye to preview it
97
- # composited over the game.
98
- - id: intro-overlay
99
- name: Intro Overlay
100
- instance: res://scenes/ui/intro.pix3scene
101
- properties:
102
- visible: false
103
- # End screen — authored in scenes/ui/end-screen.pix3scene so this scene opens
104
- # on the GAME. `visible: false` hides it in the EDITOR only; `initiallyVisible`
105
- # (in the overlay file) is what play mode reads. Tick the eye to preview it
106
- # composited over the game.
107
- - id: end-screen
108
- name: End Screen
109
- instance: res://scenes/ui/end-screen.pix3scene
110
- properties:
111
- visible: false
@@ -1,91 +0,0 @@
1
- # Pix3 Scene File (YAML)
2
- # Playable 2D — the END screen (result + CTA), in its own file so the game
3
- # scene opens clean. `main.pix3scene` carries it as a one-line `instance:`
4
- # reference marked `visible: false`, which hides it in the EDITOR only;
5
- # `initiallyVisible: false` below is what play mode reads, and `user:GameFlow`
6
- # reveals it on `finish()`.
7
- #
8
- # Edit it here, full-screen, in its own tab. To preview it composited over the
9
- # game, tick the eye on `end-screen` in main.pix3scene — just do not commit
10
- # that tick, or every iteration starts behind a CTA card again.
11
- #
12
- # Stable node ids (design/recipe.md is the contract — do not rename these):
13
- # end-screen, end-dim, end-label, cta-button
14
- version: 1.0.0
15
- metadata:
16
- author: Pix3 Template
17
- description: End screen — dim, result headline and a PLAY NOW CTA button
18
- root:
19
- - id: end-screen
20
- type: Group2D
21
- name: End Screen
22
- properties:
23
- width: 1080
24
- height: 1920
25
- initiallyVisible: false
26
- layout:
27
- enabled: true
28
- horizontalAlign: stretch
29
- verticalAlign: stretch
30
- children:
31
- - id: end-dim
32
- type: ColorRect2D
33
- name: End Dim
34
- properties:
35
- width: 1080
36
- height: 1920
37
- color: "#000000"
38
- opacity: 0.75
39
- transform:
40
- position: [0, 0]
41
- scale: [1, 1]
42
- rotation: 0
43
- layout:
44
- enabled: true
45
- horizontalAlign: stretch
46
- verticalAlign: stretch
47
- children: []
48
- - id: end-label
49
- type: Label2D
50
- name: End Label
51
- properties:
52
- label: "GREAT RUN!"
53
- labelFontSize: 84
54
- labelColor: "#ffcf33"
55
- labelAlign: center
56
- transform:
57
- position: [0, 220]
58
- scale: [1, 1]
59
- rotation: 0
60
- layout:
61
- enabled: true
62
- horizontalAlign: center
63
- verticalAlign: center
64
- children: []
65
- - id: cta-button
66
- type: Button2D
67
- name: CTA Button
68
- properties:
69
- width: 480
70
- height: 140
71
- label: "PLAY NOW"
72
- labelFontSize: 56
73
- labelColor: "#1a1a2e"
74
- backgroundColor: "#ffcf33"
75
- hoverColor: "#ffe066"
76
- pressedColor: "#e6b800"
77
- buttonAction: cta
78
- transform:
79
- position: [0, -120]
80
- scale: [1, 1]
81
- rotation: 0
82
- layout:
83
- enabled: true
84
- horizontalAlign: center
85
- verticalAlign: center
86
- components:
87
- - id: cta-action
88
- type: user:CtaButton
89
- enabled: true
90
- config: {}
91
- children: []
@@ -1,65 +0,0 @@
1
- # Pix3 Scene File (YAML)
2
- # Playable 2D — the tap-to-start INTRO overlay, in its own file so the
3
- # game scene opens clean. `main.pix3scene` carries it as a one-line `instance:`
4
- # reference marked `visible: false`, which hides it in the EDITOR only.
5
- # `initiallyVisible: true` below is what play mode reads, so the gate is UP at
6
- # t=0 — in an ad container that first tap is what unlocks browser audio.
7
- # `user:GameFlow` hides it on the first tap.
8
- #
9
- # Edit it here, full-screen, in its own tab. To preview it composited over the
10
- # game, tick the eye on `intro-overlay` in main.pix3scene — just do not commit
11
- # that tick, or every iteration starts behind the dim again.
12
- #
13
- # Stable node ids (design/recipe.md is the contract — do not rename these):
14
- # intro-overlay, intro-dim, intro-label
15
- version: 1.0.0
16
- metadata:
17
- author: Pix3 Template
18
- description: Intro overlay — dim plus a TAP TO START label
19
- root:
20
- - id: intro-overlay
21
- type: Group2D
22
- name: Intro Overlay
23
- properties:
24
- width: 1080
25
- height: 1920
26
- initiallyVisible: true
27
- layout:
28
- enabled: true
29
- horizontalAlign: stretch
30
- verticalAlign: stretch
31
- children:
32
- - id: intro-dim
33
- type: ColorRect2D
34
- name: Intro Dim
35
- properties:
36
- width: 1080
37
- height: 1920
38
- color: "#000000"
39
- opacity: 0.65
40
- transform:
41
- position: [0, 0]
42
- scale: [1, 1]
43
- rotation: 0
44
- layout:
45
- enabled: true
46
- horizontalAlign: stretch
47
- verticalAlign: stretch
48
- children: []
49
- - id: intro-label
50
- type: Label2D
51
- name: Tap To Start
52
- properties:
53
- label: "TAP TO START"
54
- labelFontSize: 72
55
- labelColor: "#ffffff"
56
- labelAlign: center
57
- transform:
58
- position: [0, 0]
59
- scale: [1, 1]
60
- rotation: 0
61
- layout:
62
- enabled: true
63
- horizontalAlign: center
64
- verticalAlign: center
65
- children: []
@@ -1,55 +0,0 @@
1
- /**
2
- * CtaButton — the playable's call-to-action. Attach to a Button2D; on press it
3
- * reports game end and logs the click. It deliberately does NOT open a store
4
- * page: which URL a playable opens (and whether it opens one at all) is decided
5
- * by the ad network at delivery time via `mraid.open` / `dapi.openStoreUrl`, so
6
- * a hardcoded store URL in a template is a wrong default that ships a real
7
- * navigation out of the game on every tap. Wire the network SDK here when you
8
- * package the ad; until then the log is the whole contract.
9
- *
10
- * The press handler does nothing itself: it dispatches the named command
11
- * `cta-click`, whose handler is the intent method `ctaClick()`. Keep that shape
12
- * as you add buttons — a game whose reactions are named intents can be driven
13
- * and tested by `scene.commands.dispatch(...)` rather than by simulated taps,
14
- * the wiring survives any relayout of the UI, and one real tap is enough to
15
- * prove the button still raises the intent it claims.
16
- */
17
- import { Script, playable } from '@pix3/runtime';
18
- import type { NodeBase } from '@pix3/runtime';
19
-
20
- export class CtaButton extends Script {
21
- private disposeCommands: (() => void)[] = [];
22
-
23
- onAttach(node: NodeBase): void {
24
- node.connect('pressed', this, this.handlePressed);
25
- }
26
-
27
- onStart(): void {
28
- // Registered here rather than in onAttach: `scene` is injected once the
29
- // graph is built, which is after components are attached during load.
30
- const commands = this.scene?.commands;
31
- this.disposeCommands = [
32
- commands?.register('cta-click', () => this.ctaClick(), {
33
- description: 'Accept the call to action: end the session and report the CTA click.',
34
- }),
35
- ].filter((dispose): dispose is () => void => dispose !== undefined);
36
- }
37
-
38
- onDetach(): void {
39
- for (const dispose of this.disposeCommands) {
40
- dispose();
41
- }
42
- this.disposeCommands = [];
43
- super.onDetach();
44
- }
45
-
46
- /** Intent: the player accepted the call to action — end the session and report the click. */
47
- ctaClick(): void {
48
- playable.gameEnd();
49
- console.info(`[CtaButton] CTA clicked (${this.node?.name ?? this.node?.id ?? 'unknown node'})`);
50
- }
51
-
52
- private handlePressed = (): void => {
53
- this.scene?.commands.dispatch('cta-click');
54
- };
55
- }