@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,146 +0,0 @@
1
- # Recipe: recipe-bouncer-2d
2
-
3
- ## What this is
4
-
5
- A ball under gravity bounces off walls, bumpers and a paddle you steer; hits score, the
6
- bottom drain costs a life. Playable, neon-lit and audible before any edit.
7
-
8
- Ball physics lives in the project: `BallBody` runs the swept solver (`ball-collision.ts`)
9
- over colliders rebuilt each frame from the marker nodes' **live world transforms**, so
10
- a rotated flipper works for free. No `core:Hitbox2D` on the ball, no rapier. (The
11
- engine's own `scene.physics2d` / `core:PhysicsBody2D` solver exists for games that grow
12
- many interacting bodies — do not put both on the same ball.)
13
-
14
- The paddle is optional: for an idle pinball, hide it and make the drain relaunch
15
- instead of costing a life — the bumpers and the `ball-hit` juice carry the game.
16
-
17
- The look: `PostProcess` (bloom + vignette) over bright accents, a tinted gradient
18
- sprite behind the board, `Label2D` glow on the HUD (drawn after post — it glows on
19
- canvas, never blooms).
20
-
21
- ## Node map
22
-
23
- | id | what |
24
- | --- | --- |
25
- | `post-fx` | `PostProcess` (`affect2D`): bloom + vignette |
26
- | `game-root` | root; hosts `GameRules` + `TouchRules`; emits the HUD signals |
27
- | `game-background` | full-screen `ColorRect2D`, the darkest colour |
28
- | `bg-glow` | full-screen `Sprite2D`, the tinted gradient over it |
29
- | `board` | playfield `Group2D`; clamps the paddle |
30
- | `board-floor` | the plate, translucent so the glow shows through |
31
- | `board-trim` | `trim-left`/`-right`/`-top` + `trim-drain`: DECOR, not colliders |
32
- | `walls` → `wall-left`/`-right`/`-top` | box colliders, kind `wall` |
33
- | `bumpers` → `bumper-a`/`-b`/`-c` | circle colliders, kind `bumper`; each a `Group2D` of `*-halo` + `*-core` rings |
34
- | `paddles` → `paddle` | box collider, kind `paddle`; `PaddleController` |
35
- | `drain` | trigger box, kind `drain` — entering it loses a ball |
36
- | `ball` | hosts `BallBody` |
37
- | `hud` | `CanvasLayer2D` + `ScoreHud`: `score-label`, `time-label`, `lives-bar`, `menu-button` |
38
- | `result-overlay` / `result-label` / `retry-button` | end screen in `scenes/ui/result.pix3scene`, instanced into main hidden (`visible: false` is editor-only) |
39
-
40
- `menu.pix3scene`: `menu-post-fx`, `menu-root`, `menu-background`, `menu-bg-glow`,
41
- `title-label` (title patched in), `title-rule`, `subtitle-label`, `play-button`.
42
-
43
- Signals: `ball` emits `ball-hit` (kind, nodeId, speed, x, y — world) and `ball-drained`;
44
- `TouchRules` re-emits `touch-scored` / `touch-damaged` on `game-root`, where `GameRules`
45
- answers `score-changed`, `lives-changed`, `time-changed`, `game-won` / `game-lost`.
46
-
47
- ## Placeholders
48
-
49
- Near-white PNGs carrying a `core:tint`: set `effects[0].params.color`.
50
-
51
- | role | file | node |
52
- | --- | --- | --- |
53
- | background | `sprites/ph-bg.png` | `bg-glow`, `menu-bg-glow` (radial gradient) |
54
- | avatar | `sprites/ph-ball.png` | `ball` |
55
- | player | `sprites/ph-paddle.png` | `paddle` |
56
- | collectible | `sprites/ph-bumper.png` | `bumper-*-core` / `*-halo` (a ring) |
57
-
58
- ## Tunables
59
-
60
- ```yaml
61
- tunables:
62
- gravity: { node: ball, component: "user:BallBody", property: gravity }
63
- maxSpeed: { node: ball, component: "user:BallBody", property: maxSpeed }
64
- minSpeed: { node: ball, component: "user:BallBody", property: minSpeed }
65
- ballRadius: { node: ball, component: "user:BallBody", property: radius }
66
- launchSpeed: { node: ball, component: "user:BallBody", property: launchSpeed }
67
- launchAngleDeg: { node: ball, component: "user:BallBody", property: launchAngleDeg }
68
- wallBounce: { node: ball, component: "user:BallBody", property: wallRestitution }
69
- paddleBounce: { node: ball, component: "user:BallBody", property: paddleRestitution }
70
- bumperBounce: { node: ball, component: "user:BallBody", property: bumperRestitution }
71
- paddleMode: { node: paddle, component: "user:PaddleController", property: mode, default: pointer }
72
- paddleSpeed: { node: paddle, component: "user:PaddleController", property: speed }
73
- paddleHalfWidth: { node: paddle, component: "user:PaddleController", property: halfWidth }
74
- targetScore: { node: game-root, component: "user:GameRules", property: targetScore }
75
- startingLives: { node: game-root, component: "user:GameRules", property: startingLives }
76
- touchRules: { node: game-root, component: "user:TouchRules", property: rules, default: "bumper:score:100;paddle:score:10;drain:damage:1" }
77
- punchAmount: { node: game-root, component: "user:TouchRules", property: punchAmount }
78
- hitstopMs: { node: game-root, component: "user:TouchRules", property: hitstopMs }
79
- burstCount: { node: game-root, component: "user:TouchRules", property: burstCount }
80
- sfxEnabled: { node: game-root, component: "user:TouchRules", property: sfxEnabled }
81
- bgColor: { node: game-background, property: color, default: "#05030f" }
82
- boardColor: { node: board-floor, property: color, default: "#120a33" }
83
- bloomIntensity: { node: post-fx, property: bloomIntensity, min: 0, max: 3, default: 0.9 }
84
- menuBloomIntensity: { node: menu-post-fx, property: bloomIntensity, min: 0, max: 3, default: 0.7 }
85
- ```
86
-
87
- `component` present → `set_component_property`, absent → `set_property`. Current values
88
- live in the scene; each script's schema clamps on write. Bloom lifts only what is
89
- *already* bright — brighten the colour or lower `bloomThreshold` (0.58), don't raise
90
- intensity. A pastel / light ground is the reverse: **raise** it (~0.9) or everything blooms.
91
-
92
- ## Extension points
93
-
94
- - **Pinball flippers.** Two boxes **directly** under `paddles` (`flipper-left`,
95
- `flipper-right`); swap `PaddleController` for a flipper script. `BallBody` reads each
96
- direct child as a box centred on the node (a pivot `Group2D` there would itself be
97
- the collider), so pivot in code: fix each flipper's **outer** end near its wall, tip
98
- toward the centre, and every frame put the centre at `pivot ± (width/2)(cos θ, sin θ)`.
99
- Holding `Key_ArrowLeft`/`Key_ArrowRight` lerps `rotation.z` −25° → +35° in ~0.06 s
100
- (the right flipper mirrored: +25° → −35°); release lerps back. Add inlane guides
101
- (boxes under `walls` from each side wall to a flipper's outer end), or the ball
102
- drains around the flippers.
103
- - **Juice is one-liners — add it WITH the mechanic, never as a later pass.**
104
- `scene.audio.sfx('score')`, `scene.juice.burst({x, y})`,
105
- `floatText('+100', { at: node })`, `punchScale`/`shake`/`flash`,
106
- `scene.time.hitstop(50)` (on contact START, not every frame),
107
- `core:BurstOnSignal`/`core:SfxOnSignal`. `TouchRules` already calls them on
108
- contact — copy the line next to your mechanic, in board space.
109
- - **More bumpers.** Duplicate a `bumpers` child (radius = width/2 × world scale) —
110
- punch, particles and score already ride `ball-hit`.
111
- - **Brick field (arkanoid).** Bricks under `walls` with ids `brick-*`; in `TouchRules`
112
- `queueFree` the hit node when `kind === 'wall'` and the id matches.
113
-
114
- Replacing a script named above is expected — `fs_write` with `overwrite: true` + `reason`.
115
-
116
- ## Do not touch
117
-
118
- - **Ending a run is `GameRules`' job**: `finish(won)` shows `result-overlay`, plays the
119
- jingle, enables the initially-disabled `retry-button` and freezes gameplay. Call it
120
- for custom endings — showing the overlay yourself leaves RETRY unpressable.
121
- - The node ids above (rename `name`, never `id`), and the signal names.
122
- - The collider grouping: `walls`/`paddles` children are boxes, `bumpers` children
123
- circles, `drain` a trigger. Moving a node between them changes its physics, and a
124
- decoration dropped into one becomes a collider.
125
- - `post-fx` / `menu-post-fx`: keep the ids and `affect2D: true` — without it a 2D-only
126
- scene gets no effects. Tune the values, don't delete the nodes.
127
- - No `core:Hitbox2D` on the ball or walls (axis-aligned overlap would disagree with the
128
- swept solver), and no rapier.
129
-
130
- ## Playtest contract
131
-
132
- terminalVisual: static
133
- terminalRestartRoutine: terminal-retry
134
-
135
- ## Verify
136
-
137
- 1. `play_start` on `scenes/main.pix3scene`.
138
- 2. `game_observe` twice ~0.5 s apart: `ball` moves and stays inside the board
139
- (|x| < 470, y > −800 board space).
140
- 3. **The core promise: the defender keeps the ball in play.** Whatever guards the
141
- drain (paddle, flippers, …) must cover or funnel every downward path, never let the
142
- ball round its open sides. Prove a save with `game_input`: a driven run outlives an
143
- unattended one, and an unattended one survives several seconds (the stage idles
144
- between turns, so a board that loses itself instantly reads as broken).
145
- 4. Let the ball drain: `lives-bar` drops one and it relaunches after `resetDelaySec`;
146
- three drains → `result-overlay` with `GAME OVER`.
@@ -1,4 +0,0 @@
1
- {
2
- "version": 1,
3
- "proven": []
4
- }
@@ -1,23 +0,0 @@
1
- {
2
- "name": "terminal-retry",
3
- "description": "From the result screen, physically tap RETRY and check that play resumes.",
4
- "scope": "scenes/main.pix3scene",
5
- "params": {},
6
- "uses": ["result-overlay", "retry-button"],
7
- "steps": [
8
- {
9
- "type": "tap",
10
- "target": "retry-button",
11
- "holdMs": 200,
12
- "why": "A real pointer press proves the button is visible, enabled and reachable."
13
- },
14
- {
15
- "type": "wait",
16
- "frames": 30,
17
- "why": "Let the scene transition finish before reading the new game's phase."
18
- }
19
- ],
20
- "expect": [
21
- { "kind": "gameState", "path": "phase", "op": "eq", "value": "playing" }
22
- ]
23
- }