@pix3/cli 1.6.4 → 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.
- package/LICENSE +201 -201
- package/README.md +722 -788
- package/dist/index.js +557 -421
- package/dist/runtime-types.json +1 -1
- package/dist/smoke/prebuilt/{build-7MIXIMSZ.mjs → build-7REMSA2S.mjs} +52 -52
- package/dist/smoke/prebuilt/chunk-4DGG2BKR.mjs +2 -0
- package/dist/smoke/prebuilt/chunk-YLBMUJ2H.mjs +238 -0
- package/dist/smoke/prebuilt/runtime.mjs +1 -1
- package/dist/smoke/prebuilt/smoke-worker.mjs +211 -2
- package/dist/smoke/prebuilt/tree-defaults.mjs +1 -1
- package/dist/validate/prebuilt/{build-AUGKXER3.js → build-ADF5EEE2.js} +52 -52
- package/dist/validate/prebuilt/bundle-main.js +223 -18
- package/dist/validate/prebuilt/chunk-VIHIF4G2.js +238 -0
- package/dist/validate/prebuilt/runtime.js +1 -1
- package/kit/files/.claude/skills/pix3-editor/SKILL.md +200 -0
- package/kit/files/.claude/skills/pix3-nodes/SKILL.md +13 -15
- package/kit/files/.claude/skills/pix3-nodes/reference.md +77 -71
- package/kit/files/.claude/skills/pix3-scene-format/SKILL.md +38 -41
- package/kit/files/.claude/skills/pix3-scene-format/pix3anim.md +185 -0
- package/kit/files/.claude/skills/pix3-scene-format/project-files.md +244 -0
- package/kit/files/.claude/skills/pix3-scene-format/reference.md +28 -16
- package/kit/files/.claude/skills/pix3-scripts/SKILL.md +34 -24
- package/kit/files/.claude/skills/pix3-scripts/reference.md +68 -141
- package/kit/files/.claude/skills/pix3-verify/SKILL.md +65 -326
- package/kit/files/.claude/skills/pix3-verify/reference.md +2 -14
- package/kit/files/AGENTS.md +76 -84
- package/kit/files/design/tests/bots/pix3-test-bot.d.ts +89 -0
- package/kit/kit.json +8 -5
- package/package.json +62 -54
- package/templates/2d/files/scenes/main.pix3scene +31 -0
- package/templates/2d/template.yaml +11 -0
- package/templates/3d/files/scenes/main.pix3scene +50 -0
- package/templates/3d/template.yaml +11 -0
- package/templates/base/files/README.md +39 -0
- package/templates/base/files/gitignore +11 -0
- package/templates/base/files/index.html +23 -0
- package/templates/base/files/package.json +28 -0
- package/templates/base/files/src/main.ts +3 -0
- package/templates/base/files/tsconfig.json +17 -0
- package/templates/base/files/vite.config.ts +10 -0
- package/dist/smoke/prebuilt/chunk-CBFYKDS7.mjs +0 -2
- package/dist/smoke/prebuilt/chunk-VJHJ5BCO.mjs +0 -239
- package/dist/validate/prebuilt/chunk-CFQFEI52.js +0 -239
- package/templates/empty-2d/files/README.md +0 -20
- package/templates/empty-2d/files/scenes/main.pix3scene +0 -68
- package/templates/empty-2d/files/sprites/pix3-logo.png +0 -0
- package/templates/empty-2d/template.yaml +0 -7
- package/templates/empty-3d/files/README.md +0 -20
- package/templates/empty-3d/files/scenes/main.pix3scene +0 -108
- package/templates/empty-3d/files/sprites/pix3-logo.png +0 -0
- package/templates/empty-3d/template.yaml +0 -7
- package/templates/idea-blank/files/README.md +0 -22
- package/templates/idea-blank/files/scenes/main.pix3scene +0 -37
- package/templates/idea-blank/template.yaml +0 -10
- package/templates/minigame-2d/files/README.md +0 -44
- package/templates/minigame-2d/files/design/tests/reachability.json +0 -1
- package/templates/minigame-2d/files/design/tests/routines/mute-music.json +0 -44
- package/templates/minigame-2d/files/scenes/main.pix3scene +0 -84
- package/templates/minigame-2d/files/scenes/menu.pix3scene +0 -118
- package/templates/minigame-2d/files/scenes/ui/settings-window.pix3scene +0 -138
- package/templates/minigame-2d/files/scripts/GameFlow.ts +0 -133
- package/templates/minigame-2d/files/scripts/MenuFlow.ts +0 -217
- package/templates/minigame-2d/files/scripts/SettingsWindow.ts +0 -198
- package/templates/minigame-2d/template.yaml +0 -10
- package/templates/playable-2d/files/README.md +0 -30
- package/templates/playable-2d/files/design/recipe.md +0 -83
- package/templates/playable-2d/files/design/tests/reachability.json +0 -4
- package/templates/playable-2d/files/design/tests/routines/intro-to-cta.json +0 -32
- package/templates/playable-2d/files/scenes/main.pix3scene +0 -111
- package/templates/playable-2d/files/scenes/ui/end-screen.pix3scene +0 -91
- package/templates/playable-2d/files/scenes/ui/intro.pix3scene +0 -65
- package/templates/playable-2d/files/scripts/CtaButton.ts +0 -55
- package/templates/playable-2d/files/scripts/GameFlow.ts +0 -256
- package/templates/playable-2d/files/sprites/pix3-logo.png +0 -0
- package/templates/playable-2d/template.yaml +0 -9
- package/templates/playable-3d/files/README.md +0 -32
- package/templates/playable-3d/files/design/recipe.md +0 -127
- package/templates/playable-3d/files/design/tests/reachability.json +0 -4
- package/templates/playable-3d/files/design/tests/routines/intro-to-cta.json +0 -32
- package/templates/playable-3d/files/scenes/main.pix3scene +0 -230
- package/templates/playable-3d/files/scenes/ui/end-screen.pix3scene +0 -91
- package/templates/playable-3d/files/scenes/ui/intro.pix3scene +0 -65
- package/templates/playable-3d/files/scripts/CtaButton.ts +0 -55
- package/templates/playable-3d/files/scripts/GameFlow.ts +0 -309
- package/templates/playable-3d/files/scripts/GameRules.ts +0 -290
- package/templates/playable-3d/files/scripts/ScoreHud.ts +0 -113
- package/templates/playable-3d/template.yaml +0 -9
- package/templates/recipe-arena-2d/files/README.md +0 -48
- package/templates/recipe-arena-2d/files/design/recipe.md +0 -127
- package/templates/recipe-arena-2d/files/design/tests/reachability.json +0 -4
- package/templates/recipe-arena-2d/files/design/tests/routines/terminal-retry.json +0 -23
- package/templates/recipe-arena-2d/files/scenes/main.pix3scene +0 -292
- package/templates/recipe-arena-2d/files/scenes/menu.pix3scene +0 -100
- package/templates/recipe-arena-2d/files/scenes/prefabs/hazard.pix3scene +0 -42
- package/templates/recipe-arena-2d/files/scenes/prefabs/pickup.pix3scene +0 -45
- package/templates/recipe-arena-2d/files/scenes/ui/result.pix3scene +0 -85
- package/templates/recipe-arena-2d/files/scripts/GameRules.ts +0 -368
- package/templates/recipe-arena-2d/files/scripts/MenuFlow.ts +0 -106
- package/templates/recipe-arena-2d/files/scripts/PlayerController.ts +0 -151
- package/templates/recipe-arena-2d/files/scripts/ScoreHud.ts +0 -94
- package/templates/recipe-arena-2d/files/scripts/Spawner.ts +0 -214
- package/templates/recipe-arena-2d/files/scripts/TouchRules.ts +0 -174
- package/templates/recipe-arena-2d/files/sprites/ph-avatar.png +0 -0
- package/templates/recipe-arena-2d/files/sprites/ph-hazard.png +0 -0
- package/templates/recipe-arena-2d/files/sprites/ph-pickup.png +0 -0
- package/templates/recipe-arena-2d/template.yaml +0 -10
- package/templates/recipe-blank-2d/files/README.md +0 -61
- package/templates/recipe-blank-2d/files/design/recipe.md +0 -148
- package/templates/recipe-blank-2d/files/design/tests/reachability.json +0 -4
- package/templates/recipe-blank-2d/files/design/tests/routines/restart.json +0 -27
- package/templates/recipe-blank-2d/files/design/tests/routines/terminal-retry.json +0 -23
- package/templates/recipe-blank-2d/files/scenes/main.pix3scene +0 -224
- package/templates/recipe-blank-2d/files/scenes/ui/result.pix3scene +0 -85
- package/templates/recipe-blank-2d/files/scripts/GameRules.ts +0 -350
- package/templates/recipe-blank-2d/files/scripts/ScoreHud.ts +0 -110
- package/templates/recipe-blank-2d/files/sprites/ph-bg.png +0 -0
- package/templates/recipe-blank-2d/files/sprites/ph-capsule.png +0 -0
- package/templates/recipe-blank-2d/files/sprites/ph-circle.png +0 -0
- package/templates/recipe-blank-2d/files/sprites/ph-orb.png +0 -0
- package/templates/recipe-blank-2d/files/sprites/ph-ring.png +0 -0
- package/templates/recipe-blank-2d/files/sprites/ph-star.png +0 -0
- package/templates/recipe-blank-2d/template.yaml +0 -10
- package/templates/recipe-bouncer-2d/files/README.md +0 -81
- package/templates/recipe-bouncer-2d/files/design/recipe.md +0 -146
- package/templates/recipe-bouncer-2d/files/design/tests/reachability.json +0 -4
- package/templates/recipe-bouncer-2d/files/design/tests/routines/terminal-retry.json +0 -23
- package/templates/recipe-bouncer-2d/files/scenes/main.pix3scene +0 -615
- package/templates/recipe-bouncer-2d/files/scenes/menu.pix3scene +0 -191
- package/templates/recipe-bouncer-2d/files/scenes/ui/result.pix3scene +0 -87
- package/templates/recipe-bouncer-2d/files/scripts/BallBody.ts +0 -298
- package/templates/recipe-bouncer-2d/files/scripts/GameRules.ts +0 -377
- package/templates/recipe-bouncer-2d/files/scripts/MenuFlow.ts +0 -109
- package/templates/recipe-bouncer-2d/files/scripts/PaddleController.ts +0 -112
- package/templates/recipe-bouncer-2d/files/scripts/ScoreHud.ts +0 -94
- package/templates/recipe-bouncer-2d/files/scripts/TouchRules.ts +0 -263
- package/templates/recipe-bouncer-2d/files/scripts/ball-collision.ts +0 -307
- package/templates/recipe-bouncer-2d/files/sprites/ph-ball.png +0 -0
- package/templates/recipe-bouncer-2d/files/sprites/ph-bg.png +0 -0
- package/templates/recipe-bouncer-2d/files/sprites/ph-bumper.png +0 -0
- package/templates/recipe-bouncer-2d/files/sprites/ph-paddle.png +0 -0
- package/templates/recipe-bouncer-2d/template.yaml +0 -10
- package/templates/recipe-grid-3d/files/README.md +0 -22
- package/templates/recipe-grid-3d/files/design/recipe.md +0 -110
- package/templates/recipe-grid-3d/files/scenes/main.pix3scene +0 -169
- package/templates/recipe-grid-3d/files/scenes/menu.pix3scene +0 -100
- package/templates/recipe-grid-3d/files/scenes/ui/result.pix3scene +0 -105
- package/templates/recipe-grid-3d/files/scripts/GridBoard.ts +0 -319
- package/templates/recipe-grid-3d/files/scripts/GridRules.ts +0 -278
- package/templates/recipe-grid-3d/files/scripts/MenuFlow.ts +0 -106
- package/templates/recipe-grid-3d/files/scripts/ScoreHud.ts +0 -94
- package/templates/recipe-grid-3d/template.yaml +0 -10
- package/templates/recipe-tapper-2d/files/README.md +0 -39
- package/templates/recipe-tapper-2d/files/design/recipe.md +0 -132
- package/templates/recipe-tapper-2d/files/design/tests/reachability.json +0 -4
- package/templates/recipe-tapper-2d/files/design/tests/routines/terminal-retry.json +0 -23
- package/templates/recipe-tapper-2d/files/scenes/main.pix3scene +0 -269
- package/templates/recipe-tapper-2d/files/scenes/menu.pix3scene +0 -100
- package/templates/recipe-tapper-2d/files/scenes/prefabs/hazard.pix3scene +0 -42
- package/templates/recipe-tapper-2d/files/scenes/prefabs/target.pix3scene +0 -45
- package/templates/recipe-tapper-2d/files/scenes/ui/result.pix3scene +0 -85
- package/templates/recipe-tapper-2d/files/scripts/GameRules.ts +0 -368
- package/templates/recipe-tapper-2d/files/scripts/MenuFlow.ts +0 -106
- package/templates/recipe-tapper-2d/files/scripts/ScoreHud.ts +0 -94
- package/templates/recipe-tapper-2d/files/scripts/Spawner.ts +0 -214
- package/templates/recipe-tapper-2d/files/scripts/TouchRules.ts +0 -192
- package/templates/recipe-tapper-2d/files/sprites/ph-hazard.png +0 -0
- package/templates/recipe-tapper-2d/files/sprites/ph-target.png +0 -0
- 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,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
|
-
}
|