@codyswann/lisa 2.161.0 → 2.162.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 (160) hide show
  1. package/.agents/plugins/marketplace.json +12 -0
  2. package/.claude-plugin/marketplace.json +24 -0
  3. package/dist/codex/plugin-marketplace-installer.d.ts.map +1 -1
  4. package/dist/codex/plugin-marketplace-installer.js +2 -0
  5. package/dist/codex/plugin-marketplace-installer.js.map +1 -1
  6. package/dist/configs/eslint/index.d.ts +2 -0
  7. package/dist/configs/eslint/index.d.ts.map +1 -1
  8. package/dist/configs/eslint/index.js +2 -0
  9. package/dist/configs/eslint/index.js.map +1 -1
  10. package/dist/configs/eslint/phaser.d.ts +29 -0
  11. package/dist/configs/eslint/phaser.d.ts.map +1 -0
  12. package/dist/configs/eslint/phaser.js +87 -0
  13. package/dist/configs/eslint/phaser.js.map +1 -0
  14. package/dist/configs/vitest/index.d.ts +3 -2
  15. package/dist/configs/vitest/index.d.ts.map +1 -1
  16. package/dist/configs/vitest/index.js +3 -2
  17. package/dist/configs/vitest/index.js.map +1 -1
  18. package/dist/configs/vitest/phaser.d.ts +29 -0
  19. package/dist/configs/vitest/phaser.d.ts.map +1 -0
  20. package/dist/configs/vitest/phaser.js +36 -0
  21. package/dist/configs/vitest/phaser.js.map +1 -0
  22. package/dist/core/config.d.ts +1 -1
  23. package/dist/core/config.d.ts.map +1 -1
  24. package/dist/core/config.js +2 -0
  25. package/dist/core/config.js.map +1 -1
  26. package/dist/detection/detectors/phaser.d.ts +15 -0
  27. package/dist/detection/detectors/phaser.d.ts.map +1 -0
  28. package/dist/detection/detectors/phaser.js +24 -0
  29. package/dist/detection/detectors/phaser.js.map +1 -0
  30. package/dist/detection/index.d.ts.map +1 -1
  31. package/dist/detection/index.js +2 -0
  32. package/dist/detection/index.js.map +1 -1
  33. package/dist/migrations/reconcile-claude-stack-plugins.d.ts.map +1 -1
  34. package/dist/migrations/reconcile-claude-stack-plugins.js +1 -0
  35. package/dist/migrations/reconcile-claude-stack-plugins.js.map +1 -1
  36. package/dist/strategies/package-lisa.d.ts.map +1 -1
  37. package/dist/strategies/package-lisa.js +4 -0
  38. package/dist/strategies/package-lisa.js.map +1 -1
  39. package/oxlint/phaser.json +11 -0
  40. package/package.json +7 -2
  41. package/phaser/copy-contents/.prettierignore +7 -0
  42. package/phaser/copy-overwrite/.github/workflows/ci.yml +23 -0
  43. package/phaser/copy-overwrite/eslint.config.ts +38 -0
  44. package/phaser/copy-overwrite/knip.json +17 -0
  45. package/phaser/copy-overwrite/tsconfig.eslint.json +20 -0
  46. package/phaser/copy-overwrite/tsconfig.json +7 -0
  47. package/phaser/copy-overwrite/vitest.config.ts +30 -0
  48. package/phaser/deletions.json +3 -0
  49. package/phaser/merge/.claude/settings.json +34 -0
  50. package/phaser/merge/.oxlintrc.json +16 -0
  51. package/phaser/package-lisa/package.lisa.json +73 -0
  52. package/plugins/lisa/.claude-plugin/plugin.json +1 -1
  53. package/plugins/lisa/.codex-plugin/plugin.json +1 -1
  54. package/plugins/lisa-agy/plugin.json +1 -1
  55. package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
  56. package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
  57. package/plugins/lisa-cdk-agy/plugin.json +1 -1
  58. package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
  59. package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
  60. package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
  61. package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
  62. package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
  63. package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
  64. package/plugins/lisa-expo-agy/plugin.json +1 -1
  65. package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
  66. package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
  67. package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +1 -1
  68. package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
  69. package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
  70. package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +1 -1
  71. package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
  72. package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
  73. package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
  74. package/plugins/lisa-nestjs-agy/plugin.json +1 -1
  75. package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
  76. package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
  77. package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
  78. package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
  79. package/plugins/lisa-openclaw-agy/plugin.json +1 -1
  80. package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
  81. package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
  82. package/plugins/lisa-phaser/.claude-plugin/plugin.json +35 -0
  83. package/plugins/lisa-phaser/.codex-plugin/hooks.json +26 -0
  84. package/plugins/lisa-phaser/.codex-plugin/plugin.json +30 -0
  85. package/plugins/lisa-phaser/hooks/inject-rules.sh +16 -0
  86. package/plugins/lisa-phaser/rules/phaser.md +59 -0
  87. package/plugins/lisa-phaser/skills/phaser-assets/SKILL.md +96 -0
  88. package/plugins/lisa-phaser/skills/phaser-assets/agents/openai.yaml +4 -0
  89. package/plugins/lisa-phaser/skills/phaser-gameobjects/SKILL.md +94 -0
  90. package/plugins/lisa-phaser/skills/phaser-gameobjects/agents/openai.yaml +4 -0
  91. package/plugins/lisa-phaser/skills/phaser-physics/SKILL.md +86 -0
  92. package/plugins/lisa-phaser/skills/phaser-physics/agents/openai.yaml +4 -0
  93. package/plugins/lisa-phaser/skills/phaser-project-structure/SKILL.md +89 -0
  94. package/plugins/lisa-phaser/skills/phaser-project-structure/agents/openai.yaml +4 -0
  95. package/plugins/lisa-phaser/skills/phaser-rendering/SKILL.md +89 -0
  96. package/plugins/lisa-phaser/skills/phaser-rendering/agents/openai.yaml +4 -0
  97. package/plugins/lisa-phaser/skills/phaser-scenes/SKILL.md +86 -0
  98. package/plugins/lisa-phaser/skills/phaser-scenes/agents/openai.yaml +4 -0
  99. package/plugins/lisa-phaser/skills/phaser-testing/SKILL.md +99 -0
  100. package/plugins/lisa-phaser/skills/phaser-testing/agents/openai.yaml +4 -0
  101. package/plugins/lisa-phaser/skills/phaser-v3-migration/SKILL.md +81 -0
  102. package/plugins/lisa-phaser/skills/phaser-v3-migration/agents/openai.yaml +4 -0
  103. package/plugins/lisa-phaser-agy/plugin.json +11 -0
  104. package/plugins/lisa-phaser-agy/skills/phaser-assets/SKILL.md +96 -0
  105. package/plugins/lisa-phaser-agy/skills/phaser-gameobjects/SKILL.md +94 -0
  106. package/plugins/lisa-phaser-agy/skills/phaser-physics/SKILL.md +86 -0
  107. package/plugins/lisa-phaser-agy/skills/phaser-project-structure/SKILL.md +89 -0
  108. package/plugins/lisa-phaser-agy/skills/phaser-rendering/SKILL.md +89 -0
  109. package/plugins/lisa-phaser-agy/skills/phaser-scenes/SKILL.md +86 -0
  110. package/plugins/lisa-phaser-agy/skills/phaser-testing/SKILL.md +99 -0
  111. package/plugins/lisa-phaser-agy/skills/phaser-v3-migration/SKILL.md +81 -0
  112. package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +24 -0
  113. package/plugins/lisa-phaser-copilot/hooks/inject-rules.sh +16 -0
  114. package/plugins/lisa-phaser-copilot/rules/phaser.md +59 -0
  115. package/plugins/lisa-phaser-copilot/skills/phaser-assets/SKILL.md +96 -0
  116. package/plugins/lisa-phaser-copilot/skills/phaser-gameobjects/SKILL.md +94 -0
  117. package/plugins/lisa-phaser-copilot/skills/phaser-physics/SKILL.md +86 -0
  118. package/plugins/lisa-phaser-copilot/skills/phaser-project-structure/SKILL.md +89 -0
  119. package/plugins/lisa-phaser-copilot/skills/phaser-rendering/SKILL.md +89 -0
  120. package/plugins/lisa-phaser-copilot/skills/phaser-scenes/SKILL.md +86 -0
  121. package/plugins/lisa-phaser-copilot/skills/phaser-testing/SKILL.md +99 -0
  122. package/plugins/lisa-phaser-copilot/skills/phaser-v3-migration/SKILL.md +81 -0
  123. package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +11 -0
  124. package/plugins/lisa-phaser-cursor/rules/phaser.mdc +64 -0
  125. package/plugins/lisa-phaser-cursor/skills/phaser-assets/SKILL.md +96 -0
  126. package/plugins/lisa-phaser-cursor/skills/phaser-gameobjects/SKILL.md +94 -0
  127. package/plugins/lisa-phaser-cursor/skills/phaser-physics/SKILL.md +86 -0
  128. package/plugins/lisa-phaser-cursor/skills/phaser-project-structure/SKILL.md +89 -0
  129. package/plugins/lisa-phaser-cursor/skills/phaser-rendering/SKILL.md +89 -0
  130. package/plugins/lisa-phaser-cursor/skills/phaser-scenes/SKILL.md +86 -0
  131. package/plugins/lisa-phaser-cursor/skills/phaser-testing/SKILL.md +99 -0
  132. package/plugins/lisa-phaser-cursor/skills/phaser-v3-migration/SKILL.md +81 -0
  133. package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
  134. package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
  135. package/plugins/lisa-rails-agy/plugin.json +1 -1
  136. package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
  137. package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
  138. package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
  139. package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
  140. package/plugins/lisa-typescript-agy/plugin.json +1 -1
  141. package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
  142. package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
  143. package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
  144. package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
  145. package/plugins/lisa-wiki-agy/plugin.json +1 -1
  146. package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
  147. package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
  148. package/plugins/src/phaser/.claude-plugin/plugin.json +15 -0
  149. package/plugins/src/phaser/hooks/inject-rules.sh +16 -0
  150. package/plugins/src/phaser/rules/phaser.md +59 -0
  151. package/plugins/src/phaser/skills/phaser-assets/SKILL.md +96 -0
  152. package/plugins/src/phaser/skills/phaser-gameobjects/SKILL.md +94 -0
  153. package/plugins/src/phaser/skills/phaser-physics/SKILL.md +86 -0
  154. package/plugins/src/phaser/skills/phaser-project-structure/SKILL.md +89 -0
  155. package/plugins/src/phaser/skills/phaser-rendering/SKILL.md +89 -0
  156. package/plugins/src/phaser/skills/phaser-scenes/SKILL.md +86 -0
  157. package/plugins/src/phaser/skills/phaser-testing/SKILL.md +99 -0
  158. package/plugins/src/phaser/skills/phaser-v3-migration/SKILL.md +81 -0
  159. package/scripts/build-plugins.sh +1 -1
  160. package/tsconfig/phaser.json +14 -0
@@ -0,0 +1,96 @@
1
+ ---
2
+ name: phaser-assets
3
+ description: This skill should be used when loading or organizing assets in a Phaser 4 game — the Loader (images, texture atlases, spritesheets, audio, fonts), asset-pack manifests via this.load.pack, the new PCT compact atlas format (load.atlasPCT), typed asset keys, and where files live in the Vite project. Use it when adding any asset, restructuring loading, fixing a missing-texture/green-square bug, or optimizing load size. Pairs with phaser-project-structure, phaser-scenes, and phaser-gameobjects.
4
+ ---
5
+
6
+ # Phaser 4 Assets and Loading
7
+
8
+ ## Overview
9
+
10
+ All runtime assets live under `public/assets/` (served verbatim by Vite — never
11
+ `import` game assets through the bundler) and are loaded by Phaser's Loader in a
12
+ scene's `preload()`. The opinionated pattern: **one asset-pack manifest, loaded
13
+ by the Preloader, with every key defined as a typed constant.**
14
+
15
+ ## Asset packs (the default loading strategy)
16
+
17
+ A pack is a JSON manifest the Loader consumes wholesale:
18
+
19
+ ```json
20
+ {
21
+ "main": {
22
+ "files": [
23
+ { "type": "atlasPCT", "key": "game-atlas", "url": "atlases/game.pct" },
24
+ { "type": "image", "key": "background", "url": "images/background.png" },
25
+ { "type": "audio", "key": "sfx-jump", "url": ["audio/jump.ogg", "audio/jump.m4a"] },
26
+ { "type": "spritesheet", "key": "explosion", "url": "sheets/explosion.png",
27
+ "frameConfig": { "frameWidth": 64, "frameHeight": 64 } }
28
+ ]
29
+ }
30
+ }
31
+ ```
32
+
33
+ ```ts
34
+ // Preloader.preload()
35
+ this.load.pack("game-pack", "assets/pack.json");
36
+ ```
37
+
38
+ Why packs: loading is declared in one reviewable file instead of scattered
39
+ `load.*` calls; adding an asset never touches scene code beyond using the key.
40
+
41
+ ## Texture atlases — the rule, not the suggestion
42
+
43
+ Individual images break sprite batching. Everything that renders together ships
44
+ in an atlas:
45
+
46
+ - **PCT (Phaser Compact Texture)** is the preferred v4 atlas format —
47
+ `this.load.atlasPCT(key, url)` — its manifests are 90–95% smaller than the
48
+ JSON-hash equivalent. JSON/XML/Unity/multi-atlas loaders still exist for
49
+ third-party toolchains.
50
+ - Spritesheets (`load.spritesheet`) are acceptable only for uniform-grid
51
+ animation strips; anything else is an atlas.
52
+
53
+ ## Audio
54
+
55
+ - Provide at least two encodings (`.ogg` + `.m4a`) in the url array; Phaser
56
+ picks the first the browser can play.
57
+ - Web Audio is the default manager; it unlocks on first user gesture — never
58
+ autoplay sound before input (it will silently fail and "work on my machine").
59
+ - Use audio sprites (`load.audioSprite`) for large sets of short SFX.
60
+
61
+ ## Typed keys
62
+
63
+ Every key lives in `src/assets.ts`:
64
+
65
+ ```ts
66
+ export const Tex = { GameAtlas: "game-atlas", Background: "background" } as const;
67
+ export const Sfx = { Jump: "sfx-jump" } as const;
68
+ export const SceneKeys = { Boot: "Boot", Preloader: "Preloader", Game: "Game" } as const;
69
+ ```
70
+
71
+ Scenes use `Tex.GameAtlas`, never `"game-atlas"` inline. A bad inline key fails
72
+ at runtime as a green square or silent missing audio; a bad constant fails in
73
+ review and in tests that assert the pack manifest covers every constant.
74
+
75
+ ## Loading UX and failure handling
76
+
77
+ - The Preloader binds `this.load.on("progress", …)` to a progress bar built from
78
+ Boot-loaded art ([[phaser-project-structure]]).
79
+ - Handle `loaderror`: `this.load.on(Phaser.Loader.Events.FILE_LOAD_ERROR, …)` —
80
+ log the key and URL; a missing asset must fail loudly in dev, not render as a
81
+ placeholder in production.
82
+
83
+ ## Project conventions
84
+
85
+ - `public/assets/` subdirs: `atlases/`, `images/`, `audio/`, `sheets/`, `fonts/`,
86
+ plus `pack.json` at the root of `assets/`.
87
+ - Generated atlas files (PCT/JSON + PNG pages) are build inputs, committed to the
88
+ repo; their source art lives wherever the art pipeline keeps it.
89
+ - A test should assert that every key constant in `src/assets.ts` appears in
90
+ `pack.json` (cheap manifest-coverage check; see [[phaser-testing]]).
91
+
92
+ ## Verification
93
+
94
+ Asset changes are verified by booting the game and watching the network panel /
95
+ console: every file 200s, no `FILE_LOAD_ERROR`, and the new asset visibly renders
96
+ or audibly plays in the scene that uses it.
@@ -0,0 +1,94 @@
1
+ ---
2
+ name: phaser-gameobjects
3
+ description: This skill should be used when creating or managing Phaser 4 GameObjects — sprites, images, text, containers, groups and object pooling, animations (anims), tweens, particles, and the v4 GPU layers (SpriteGPULayer, TilemapGPULayer) for massive object counts. Use it when adding entities, fixing per-frame allocation/GC issues, pooling projectiles, or choosing between a Container and a Group. Pairs with phaser-scenes, phaser-physics, phaser-rendering, and phaser-assets.
4
+ ---
5
+
6
+ # Phaser 4 GameObjects
7
+
8
+ ## Overview
9
+
10
+ GameObjects carry over from Phaser 3 largely unchanged: `Sprite`, `Image`,
11
+ `Text`, `BitmapText`, `Container`, `Group`, `Graphics`, the Shape objects, and
12
+ the particle system. v4 adds `Gradient`, `Stamp`, `CaptureFrame`, the Noise
13
+ objects, NineSlice tiling (`tileX`/`tileY`), and — the headline — the GPU
14
+ layers. Removed: `Mesh`, `Plane`, the OBJ loader, `Camera3D`/`Layer3D`
15
+ ([[phaser-v3-migration]]).
16
+
17
+ ## Choosing the right object
18
+
19
+ - **Image** for static visuals (cheaper than Sprite — no animation component).
20
+ - **Sprite** only when it animates.
21
+ - **Container** for transform-grouping a small, fixed set of children (a unit +
22
+ its health bar). Containers are not free — don't nest deeply or use them as
23
+ ad-hoc layers. In v4.1+, `Layer` is a true GameObject and is the right tool
24
+ for z-grouping with filters.
25
+ - **Group** for managing many homogeneous objects — and for pooling (below).
26
+ - **Text** uses Canvas rasterization per change; for score counters and other
27
+ hot text use `BitmapText`.
28
+
29
+ ## Object pooling (mandatory for spawn-heavy entities)
30
+
31
+ Bullets, enemies, particles, pickups: never `new`/`destroy` per spawn — pool
32
+ through a Group:
33
+
34
+ ```ts
35
+ this.bullets = this.add.group({ classType: Bullet, maxSize: 64, runChildUpdate: true });
36
+ // spawn
37
+ const b = this.bullets.get(x, y, Tex.GameAtlas, "bullet") as Bullet | null;
38
+ if (b) { b.setActive(true).setVisible(true); b.fire(dir); }
39
+ // despawn (inside Bullet when off-screen/expired)
40
+ this.bullets.killAndHide(this); this.body.enable = false;
41
+ ```
42
+
43
+ `maxSize` caps the pool; `get()` returns `null` when exhausted — handle it
44
+ (drop the spawn) rather than growing unbounded.
45
+
46
+ ## Per-frame discipline
47
+
48
+ In `update()` paths: no object literals, no array spreads, no `.map/.filter`
49
+ chains, no closures. Hoist scratch `Vector2`s and reuse them. The GC pause from
50
+ per-frame garbage is the most common cause of stutter that profilers get blamed
51
+ for.
52
+
53
+ ## Animations and tweens
54
+
55
+ - Define animations once (Preloader `create` or a dedicated module) on the
56
+ global `this.anims`; play by key constant: `sprite.play(Anim.Run)`.
57
+ - Tweens (`this.tweens.add`) and Timelines carry over from v3 unchanged. Kill
58
+ tweens that target objects you pool/despawn — a tween holding a pooled object
59
+ alive is a classic leak.
60
+
61
+ ## Massive counts: the GPU layers
62
+
63
+ New in v4 — reach for these instead of "thousands of sprites":
64
+
65
+ - **SpriteGPULayer** — on the order of a million static-ish sprites in a single
66
+ draw call, with per-member GPU-driven animation, easing, and parallax. Use for
67
+ starfields, crowds, debris, background fauna.
68
+ - **TilemapGPULayer** — renders a whole tile layer as one quad with per-pixel
69
+ cost, up to 4096×4096 tiles. Use for large maps, especially on mobile.
70
+
71
+ Regular Sprites + Groups remain correct for interactive entities (things with
72
+ bodies, input, per-entity logic).
73
+
74
+ ## Particles
75
+
76
+ The particle API is the v3.60-style `this.add.particles(x, y, texture, config)`
77
+ emitter manager. v4 additions: particles respect the lighting system. Pool
78
+ explosion-style one-shot emitters or use `emitter.explode()` rather than
79
+ creating emitters per event.
80
+
81
+ ## Project conventions
82
+
83
+ - Entity classes (`Bullet extends Phaser.Physics.Arcade.Sprite`) live in
84
+ `src/entities/`, take their tunables from `src/logic/` config objects, and use
85
+ asset-key constants ([[phaser-assets]]).
86
+ - Depth management: named depth constants (`Depth.World`, `Depth.FX`,
87
+ `Depth.UI`), not scattered magic numbers.
88
+
89
+ ## Verification
90
+
91
+ Object-lifecycle changes are verified in the running game: spawn/despawn the
92
+ entity repeatedly and watch the object count (`this.children.length`,
93
+ `group.getLength()`) stay bounded, and the FPS meter stay flat — an unbounded
94
+ count or sawtooth memory profile means the pool or tween cleanup is wrong.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: phaser-physics
3
+ description: This skill should be used when working with physics in a Phaser 4 game — Arcade physics bodies, velocity/acceleration, colliders and overlaps, the fixed timestep, groups and static groups, and when (rarely) to reach for Matter.js instead. Use it when adding movement, collision, platforming behavior, or debugging tunneling/jitter. Pairs with phaser-gameobjects and phaser-scenes.
4
+ ---
5
+
6
+ # Phaser 4 Physics
7
+
8
+ ## Overview
9
+
10
+ Phaser 4 bundles the same two engines as v3: **Arcade** (AABB, fast, the
11
+ default) and **Matter.js** (full rigid-body). The opinionated default is
12
+ Arcade; Matter is opt-in for genuinely physical mechanics (stacking, joints,
13
+ torque). Bundled Spine left v4, Matter did not.
14
+
15
+ Key v4 fact: Arcade's **`fixedStep` defaults to `true`** — the world steps at a
16
+ fixed rate decoupled from render FPS. Keep it. Fixed-step physics is what makes
17
+ movement deterministic across 60 Hz/144 Hz displays and what makes
18
+ logic-level tests reproducible. Do not switch to variable step to mask a bug.
19
+
20
+ ## Setup
21
+
22
+ ```ts
23
+ // game config
24
+ physics: { default: "arcade", arcade: { gravity: { x: 0, y: 0 }, debug: false } }
25
+
26
+ // scene
27
+ const player = this.physics.add.sprite(x, y, Tex.GameAtlas, "player");
28
+ player.setCollideWorldBounds(true);
29
+ const platforms = this.physics.add.staticGroup();
30
+ this.physics.add.collider(player, platforms);
31
+ this.physics.add.overlap(player, pickups, (p, item) => this.collect(item), undefined, this);
32
+ ```
33
+
34
+ ## Movement rules
35
+
36
+ - Move bodies with **velocity/acceleration** (`setVelocity`, `setAccelerationX`),
37
+ never by writing `x`/`y` per frame — direct position writes teleport the body
38
+ past colliders and create tunneling.
39
+ - For teleports (respawn, screen wrap) set position once and reset the body
40
+ (`body.reset(x, y)`).
41
+ - Drag, bounce, and max velocity are body config, not per-frame math:
42
+ `setDrag`, `setBounce`, `setMaxVelocity`.
43
+ - Platformer jump checks use `body.blocked.down` (world/static contact) rather
44
+ than `touching.down` alone.
45
+
46
+ ## Colliders, overlaps, groups
47
+
48
+ - `collider` separates bodies; `overlap` only reports. Pickups/triggers are
49
+ overlaps; walls/floors are colliders.
50
+ - Register colliders **once in `create`** between groups — never inside
51
+ `update` (a per-frame `add.collider` leaks collider objects and tanks the
52
+ frame rate).
53
+ - Pooled entities ([[phaser-gameobjects]]) must disable their body on despawn
54
+ (`body.enable = false`) or dead objects keep colliding invisibly.
55
+
56
+ ## Tunneling and jitter checklist
57
+
58
+ 1. Fast small bodies passing through thin walls → keep `fixedStep: true`, give
59
+ walls thickness, cap speed with `setMaxVelocity`.
60
+ 2. Jitter against walls → bodies overlap due to direct position writes; use
61
+ velocities.
62
+ 3. "Collider stopped working" after pooling → the body wasn't re-enabled on
63
+ `get()` or wasn't disabled on despawn.
64
+ 4. Different behavior on different monitors → someone turned off fixed step or
65
+ moved physics math into `update` scaled by render delta.
66
+
67
+ ## When Matter is justified
68
+
69
+ Choose Matter for: realistic stacking/toppling, constraints/joints, compound
70
+ bodies, polygon collision shapes. Run it in a dedicated scene; don't mix Arcade
71
+ and Matter for the same entities. If the mechanic is "platformer/top-down/
72
+ shmup", the answer is Arcade.
73
+
74
+ ## Determinism
75
+
76
+ Physics-adjacent randomness (spawn jitter, knockback variance) uses the seeded
77
+ `Phaser.Math.RND` — never `Math.random()` — so a recorded seed reproduces a run
78
+ exactly. Combined with fixed-step Arcade, gameplay bugs become replayable; see
79
+ [[phaser-testing]].
80
+
81
+ ## Verification
82
+
83
+ Physics changes are verified by playing the affected interaction in the running
84
+ game with `arcade.debug: true` toggled on (body outlines visible), confirming
85
+ contacts/velocities behave as specified, then toggling debug back off before
86
+ committing.
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: phaser-project-structure
3
+ description: This skill should be used when creating, restructuring, or reasoning about a Phaser 4 game project — the game config, the Vite + TypeScript layout, the Boot → Preloader → MainMenu → Game scene flow, scale/resolution setup for desktop and mobile, and where code and assets belong. Use it before scaffolding a project, adding a major subsystem, or deciding where a file should live. Pairs with phaser-scenes, phaser-assets, phaser-rendering, and phaser-testing.
4
+ ---
5
+
6
+ # Phaser 4 Project Structure
7
+
8
+ ## Overview
9
+
10
+ This stack targets **Phaser 4** (v4.1+ "Salusa", npm package `phaser`), built
11
+ with **Vite + TypeScript** — the layout the official `phaserjs/template-vite-ts`
12
+ template and `npm create @phaserjs/game@latest` scaffold. Phaser 4 ships its own
13
+ type definitions (`types/phaser.d.ts`); do not add `@types/phaser`.
14
+
15
+ ## Canonical layout
16
+
17
+ | Path | Role |
18
+ | --- | --- |
19
+ | `index.html` | Single page that loads `src/main.ts`; owns the game container div |
20
+ | `src/main.ts` | Game config + `new Phaser.Game(config)` — the only bootstrap file |
21
+ | `src/scenes/` | One scene class per file (`Boot.ts`, `Preloader.ts`, `MainMenu.ts`, `Game.ts`, …) |
22
+ | `src/logic/` | Pure TypeScript game logic — **no `phaser` imports** (testable) |
23
+ | `src/assets.ts` | Typed asset-key constants (texture, audio, anim, scene keys) |
24
+ | `public/assets/` | Static assets served by Vite (atlases, audio, packs) — never imported |
25
+ | `tests/` | Vitest unit tests for `src/logic/**` and pure helpers |
26
+ | `dist/` | Vite build output — generated, never edited or committed |
27
+
28
+ ## The game config
29
+
30
+ One config object in `src/main.ts`. The opinionated baseline:
31
+
32
+ ```ts
33
+ const config: Phaser.Types.Core.GameConfig = {
34
+ type: Phaser.AUTO, // WebGL; Canvas renderer is deprecated in v4
35
+ width: 1280,
36
+ height: 720,
37
+ parent: "game-container",
38
+ backgroundColor: "#028af8",
39
+ scale: {
40
+ mode: Phaser.Scale.FIT,
41
+ autoCenter: Phaser.Scale.CENTER_BOTH,
42
+ },
43
+ physics: {
44
+ default: "arcade",
45
+ arcade: { gravity: { x: 0, y: 0 }, debug: false }, // fixedStep defaults to true in v4 — keep it
46
+ },
47
+ scene: [Boot, Preloader, MainMenu, Game],
48
+ };
49
+ ```
50
+
51
+ v4-specific config facts:
52
+
53
+ - `roundPixels` now defaults to **`false`** (v3 defaulted true). Leave it — the
54
+ new default prevents flicker on rotated/scaled objects.
55
+ - Pixel-art games: `pixelArt: true` (nearest-neighbor + roundPixels), or the new
56
+ **`render.smoothPixelArt: true`** (WebGL-only) for pixel art that rotates or
57
+ scales smoothly. Pick one per project and record the choice.
58
+ - Custom render nodes register under `render.renderNodes` — see [[phaser-rendering]].
59
+ - `Phaser.HEADLESS` exists for logic-only boots (tests) — see [[phaser-testing]].
60
+
61
+ ## Scene flow
62
+
63
+ Four-stage boot, in order (see [[phaser-scenes]] for lifecycle detail):
64
+
65
+ 1. **Boot** — loads only the handful of assets the Preloader's loading screen
66
+ needs (logo, progress-bar art). No game assets here.
67
+ 2. **Preloader** — renders the loading UI and loads everything else, preferably
68
+ via a single asset-pack manifest (see [[phaser-assets]]), then starts MainMenu.
69
+ 3. **MainMenu** — entry UI; starts Game.
70
+ 4. **Game** (+ overlay scenes like `HUD`, `Pause` run in parallel) — gameplay.
71
+
72
+ ## Project conventions
73
+
74
+ - All game code is TypeScript under `src/`; `bun run dev` (vite), `bun run build`
75
+ (vite build), `bun run preview` serve and package it.
76
+ - Scenes orchestrate; they do not contain algorithmic game logic. Rules
77
+ evaluation, procedural generation, scoring, pathfinding, and state machines
78
+ live in `src/logic/` as pure functions/classes so Vitest can run them without
79
+ a browser.
80
+ - Asset keys come from `src/assets.ts` constants — a typo in an inline string
81
+ key fails at runtime only; a typo in a constant fails at compile time.
82
+ - Determinism: seed `Phaser.Math.RND` (or a local `RandomDataGenerator`) from a
83
+ single place; never `Math.random()` in game code.
84
+
85
+ ## Verification
86
+
87
+ A structural change is verified when `bun run typecheck`, `bun run test`, and
88
+ `bun run build` pass AND the game boots: `bun run dev`, open the page, confirm
89
+ the canvas renders past the Preloader with no console errors.
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: phaser-rendering
3
+ description: This skill should be used when working on rendering in Phaser 4 — the render node architecture that replaced v3 pipelines, the unified Filter system that replaced FX and masks, tint modes, pixel-rounding options (roundPixels, smoothPixelArt, vertexRoundMode), DynamicTexture's buffered drawing, the Extern object for external WebGL, and lighting. Use it for any visual-effect, shader, mask, or custom-rendering task, and whenever v3 rendering idioms (setPipeline, preFX/postFX, BitmapMask, tintFill) appear. Pairs with phaser-gameobjects and phaser-v3-migration.
4
+ ---
5
+
6
+ # Phaser 4 Rendering
7
+
8
+ ## Overview
9
+
10
+ Phaser 4 replaced the entire v3 WebGL pipeline system with a **render node
11
+ architecture**: small single-purpose nodes (each with a `run` method, batchable
12
+ where it matters) that the renderer composes per object. WebGL state is fully
13
+ managed, context loss restores automatically, and rendering is just-in-time —
14
+ GPU work is deferred until actually needed. WebGL2 is fully supported; WebGL1
15
+ still works; **there is no WebGPU backend**; the Canvas renderer is deprecated.
16
+
17
+ Practical consequences, in order of how often they bite:
18
+
19
+ ## Filters replaced FX and masks
20
+
21
+ The v3 `preFX`/`postFX` controllers and `BitmapMask` are gone. Phaser 4 has one
22
+ unified **Filter** system that works on any GameObject **and on cameras**:
23
+
24
+ - Geometry/bitmap masks → the `Mask` filter.
25
+ - Bloom / Shine / Circle FX → `Phaser.Actions.AddEffectBloom()`,
26
+ `AddEffectShine()`, `AddMaskShape()` helpers.
27
+ - Gradient FX → the new `Gradient` GameObject.
28
+ - Filters split into **internal** and **external** lists (replacing the
29
+ pre/post distinction); filter setters are chainable.
30
+ - A filtered or masked `Container` can itself be used as a mask source — new
31
+ capability, not possible in v3.
32
+
33
+ ## Tinting
34
+
35
+ `tintFill` and `setTintFill()` were removed. Use `setTint(color)` plus
36
+ `setTintMode(mode)` with `Phaser.TintModes`: `MULTIPLY` (default), `FILL`,
37
+ `ADD`, `SCREEN`, `OVERLAY`, `HARD_LIGHT`.
38
+
39
+ ## Custom shaders and pipelines
40
+
41
+ - A v3 custom pipeline must be rewritten as a **RenderNode**, registered at boot
42
+ via the game config's `render.renderNodes` map.
43
+ - The `Shader` GameObject was rewritten: config-based constructor
44
+ (`ShaderQuadConfig`), explicit `setUniform()`, `renderImmediate`, GLSL
45
+ `#pragma` directives. Shadertoy-style automatic uniforms are gone.
46
+ - **Never make raw WebGL calls** — wrap external GL renderers in the `Extern`
47
+ GameObject, which fences GL state around your code.
48
+ - Texture coordinates now follow GL orientation (**Y=0 at bottom**). Phaser
49
+ translates standard usage automatically, but custom shaders and pre-compressed
50
+ textures must account for the flip (re-encode compressed textures).
51
+
52
+ ## Pixel rounding and pixel art
53
+
54
+ - `roundPixels` defaults to **`false`** in v4 (v3: true). The old default caused
55
+ flicker on rotated/scaled objects; leave the new default alone.
56
+ - Pixel-art projects choose ONE strategy: `pixelArt: true` (crisp,
57
+ nearest-neighbor) or `render.smoothPixelArt: true` (WebGL-only, anti-aliased
58
+ scaling/rotation of pixel art).
59
+ - Per-object fine-tuning: `gameObject.vertexRoundMode` —
60
+ `"off" | "safe" | "safeAuto" | "full" | "fullAuto"`.
61
+
62
+ ## DynamicTexture / RenderTexture are buffered
63
+
64
+ Draw commands no longer execute immediately — they queue until you call
65
+ **`render()`**. Forgetting `render()` is the #1 "my RenderTexture is blank" bug
66
+ in v4. Related: `preserve()` keeps a command buffer for reuse, `callback()`
67
+ injects custom steps, and `RenderTexture#renderMode` selects
68
+ `"render" | "redraw" | "all"`.
69
+
70
+ ## Lighting
71
+
72
+ `setPipeline('Light2D')` is gone. Enable per object with
73
+ `gameObject.setLighting(true)`; lights have an explicit `z`; self-shadowing is
74
+ supported; lighting now works on many more object types (including particles).
75
+
76
+ ## Performance notes specific to the v4 renderer
77
+
78
+ - Quads render from index buffers (4 vertices, not 6) and batching survives
79
+ multi-texture switches better, especially on mobile — but atlases are still
80
+ the foundation of batching ([[phaser-assets]]).
81
+ - For massive draw counts use `SpriteGPULayer` / `TilemapGPULayer`
82
+ ([[phaser-gameobjects]]) instead of thousands of individual sprites.
83
+
84
+ ## Verification
85
+
86
+ Rendering changes are verified visually in a real browser: `bun run dev`, then a
87
+ Playwright screenshot assertion or manual confirmation that the effect renders
88
+ and the console shows no WebGL errors. For filter/shader work, verify on both a
89
+ WebGL2 and (if supported) WebGL1 context before calling it done.
@@ -0,0 +1,86 @@
1
+ ---
2
+ name: phaser-scenes
3
+ description: This skill should be used when creating or editing Phaser 4 scenes — the init/preload/create/update lifecycle, starting/stopping/sleeping scenes, running scenes in parallel (HUD/pause overlays), passing data between scenes, the registry, and event-based communication. Use it when adding a scene, wiring scene transitions, or debugging lifecycle/ordering issues. Pairs with phaser-project-structure, phaser-assets, and phaser-gameobjects.
4
+ ---
5
+
6
+ # Phaser 4 Scenes
7
+
8
+ ## Overview
9
+
10
+ Scenes are Phaser's unit of game-flow composition. The lifecycle is unchanged
11
+ from Phaser 3 — `init(data)` → `preload()` → `create(data)` → `update(time, delta)`
12
+ — and each scene owns its display list, input, camera, time events, and (if
13
+ enabled) physics world.
14
+
15
+ One scene class per file under `src/scenes/`, exported as a class whose key
16
+ matches the file name:
17
+
18
+ ```ts
19
+ export class Game extends Phaser.Scene {
20
+ constructor() {
21
+ super("Game"); // the scene key — also a constant in src/assets.ts
22
+ }
23
+ init(data: GameStartData) { /* receive data, reset state */ }
24
+ preload() { /* per-scene late loads only — bulk loading is the Preloader's job */ }
25
+ create() { /* build GameObjects, wire input + events */ }
26
+ update(_time: number, delta: number) { /* per-frame; delta in ms */ }
27
+ }
28
+ ```
29
+
30
+ ## Lifecycle rules
31
+
32
+ - `init` receives the data passed by `scene.start(key, data)` — type that payload
33
+ (an interface per scene) instead of `any`.
34
+ - `preload` in gameplay scenes should be rare; the Preloader scene loads the game
35
+ pack up front ([[phaser-assets]]). Use per-scene `preload` only for genuinely
36
+ scene-local or late-bound assets.
37
+ - `create` is where GameObjects are built. Everything constructed here must be
38
+ cleaned up on shutdown if it lives outside the scene's display list (timers on
39
+ other scenes, global event listeners, DOM elements).
40
+ - `update(time, delta)` runs per render frame. Frame-rate-independent movement
41
+ multiplies by `delta`; physics movement belongs in Arcade bodies, not manual
42
+ position math ([[phaser-physics]]).
43
+
44
+ ## Scene control
45
+
46
+ Via `this.scene` (the ScenePlugin):
47
+
48
+ - `start(key, data)` — stop the current scene, start another.
49
+ - `launch(key, data)` — start another scene **in parallel** (HUD, pause overlay).
50
+ - `pause` / `resume`, `sleep` / `wake` — suspend update/render without rebuild.
51
+ - `stop(key)` — shuts a scene down (fires `Phaser.Scenes.Events.SHUTDOWN`).
52
+ - `bringToTop` / `sendToBack` — z-order between parallel scenes.
53
+
54
+ Overlay pattern: `Game` launches `HUD`; `HUD` renders score/health and listens to
55
+ events from `Game`. Pause: launch `Pause`, `this.scene.pause("Game")`.
56
+
57
+ ## Communicating between scenes
58
+
59
+ In preference order:
60
+
61
+ 1. **Events** — emit on the scene's own emitter and have the other scene listen:
62
+ `gameScene.events.emit("score-changed", score)`. Always remove listeners on
63
+ `SHUTDOWN`: `this.events.once(Phaser.Scenes.Events.SHUTDOWN, () => …)`.
64
+ 2. **`scene.start`/`launch` data** — for handoff at transition time.
65
+ 3. **The registry** (`this.registry`) — game-wide key/value store with change
66
+ events; for cross-cutting state like settings or the run seed.
67
+
68
+ Never reach into another scene's GameObjects directly
69
+ (`this.scene.get("Game").player.x = …`) — that couples scenes to each other's
70
+ display-list internals and breaks when the other scene rebuilds.
71
+
72
+ ## Project conventions
73
+
74
+ - Scene keys are constants in `src/assets.ts` (e.g. `SceneKeys.Game`) — `super(SceneKeys.Game)`.
75
+ - A scene is an orchestrator: input wiring, GameObject lifecycles, and event
76
+ plumbing. Game rules live in `src/logic/**` and are called from the scene.
77
+ - Per-scene state is reset in `init`, not in field initializers — scene classes
78
+ are instantiated once but started many times; stale fields from a previous run
79
+ are a classic restart bug.
80
+
81
+ ## Verification
82
+
83
+ A scene change is verified by booting the game (`bun run dev`) and exercising the
84
+ actual transition: start → play → (pause/resume or restart) → confirm no
85
+ duplicated listeners (events firing twice after a restart is the canonical
86
+ symptom of a missed `SHUTDOWN` cleanup).
@@ -0,0 +1,99 @@
1
+ ---
2
+ name: phaser-testing
3
+ description: This skill should be used when writing or designing tests for a Phaser 4 game — unit-testing pure game logic with Vitest, keeping logic Phaser-free so it tests without a browser, the Phaser.HEADLESS renderer for logic-only boots, asset-manifest coverage tests, and Playwright smoke tests that prove the game actually boots and renders. Use it when adding tests, setting up CI verification, or deciding what is testable at which level. Pairs with phaser-project-structure, phaser-assets, and phaser-physics.
4
+ ---
5
+
6
+ # Phaser 4 Testing
7
+
8
+ ## Overview
9
+
10
+ Games are testable when the game is not welded to the engine. The stack's test
11
+ pyramid, bottom-up:
12
+
13
+ 1. **Vitest unit tests** over `src/logic/**` — the bulk of coverage.
14
+ 2. **Manifest/contract tests** — cheap structural checks (asset packs, scene
15
+ keys, anim definitions).
16
+ 3. **Playwright smoke test** — the game boots in a real browser, renders past
17
+ the Preloader, no console errors.
18
+
19
+ There is no official Phaser testing harness — this layering IS the strategy.
20
+
21
+ ## Layer 1: pure logic under Vitest (the rule that makes it possible)
22
+
23
+ `src/logic/**` contains game rules as plain TypeScript with **no `phaser`
24
+ imports**: damage calculation, wave spawning schedules, inventory, scoring,
25
+ state machines, procedural generation. Scenes call logic; logic never touches
26
+ GameObjects.
27
+
28
+ ```ts
29
+ // src/logic/score.ts
30
+ export function comboMultiplier(streak: number): number { … }
31
+
32
+ // tests/logic/score.test.ts — plain vitest, node environment, no browser
33
+ import { comboMultiplier } from "../../src/logic/score";
34
+ it("caps the combo multiplier at 8x", () => {
35
+ expect(comboMultiplier(999)).toBe(8);
36
+ });
37
+ ```
38
+
39
+ Determinism makes this work for anything random: logic takes a
40
+ `Phaser.Math.RandomDataGenerator`-compatible interface (or just a `() => number`)
41
+ as a parameter, production passes the seeded RND, tests pass a fixed sequence.
42
+
43
+ If a piece of "logic" can't be tested without constructing a Scene, that is a
44
+ design smell — extract the rule from the scene first, then test it.
45
+
46
+ ## Layer 2: contract tests
47
+
48
+ Cheap tests that catch the silent runtime failures Phaser is famous for:
49
+
50
+ - **Asset coverage**: every key constant in `src/assets.ts` appears in
51
+ `public/assets/pack.json` (and optionally vice versa). A missing pack entry
52
+ otherwise ships as a green-square texture ([[phaser-assets]]).
53
+ - **Scene registry**: every `SceneKeys` constant has a scene class registered in
54
+ the game config's `scene` array.
55
+ - These are plain Vitest tests reading JSON/TS — no Phaser instance needed.
56
+
57
+ ## Layer 3: booting Phaser in tests (use sparingly)
58
+
59
+ `Phaser.HEADLESS` (renderer type 3) boots a Game without creating a canvas or
60
+ WebGL context — but Phaser still expects DOM-ish globals, so it needs a
61
+ browser-like environment (jsdom/happy-dom) and careful teardown
62
+ (`game.destroy(true)`). Reserve headless boots for integration tests of things
63
+ that genuinely need the engine loop (scene transitions, timer events). Most of
64
+ what people reach for headless to test belongs in Layer 1 instead.
65
+
66
+ ## Layer 4: Playwright smoke
67
+
68
+ The non-negotiable end of the pyramid — proof the game runs:
69
+
70
+ ```ts
71
+ test("game boots and renders", async ({ page }) => {
72
+ const errors: string[] = [];
73
+ page.on("pageerror", e => errors.push(e.message));
74
+ await page.goto("/");
75
+ const canvas = page.locator("canvas");
76
+ await expect(canvas).toBeVisible();
77
+ // Past the Preloader: poll a window hook the game sets, e.g. in MainMenu.create()
78
+ await page.waitForFunction(() => (window as never as { __sceneReady?: string }).__sceneReady === "MainMenu");
79
+ expect(errors).toEqual([]);
80
+ await expect(page).toHaveScreenshot("boot.png", { maxDiffPixelRatio: 0.02 });
81
+ });
82
+ ```
83
+
84
+ Convention: scenes set `window.__sceneReady = key` in `create()` (dev/test
85
+ builds) so tests await real readiness instead of sleeping. Run against
86
+ `bun run dev` (or `vite preview` in CI).
87
+
88
+ ## Project conventions
89
+
90
+ - `bun run test` = Vitest (layers 1–2, coverage-gated). Playwright smoke runs as
91
+ its own script/CI job against a built preview.
92
+ - Tests never assert on private scene fields; they assert on logic outputs
93
+ (layer 1) or observable behavior (layer 4).
94
+
95
+ ## Verification
96
+
97
+ The testing setup itself is verified when `bun run test` passes with coverage
98
+ over `src/logic/**`, and the Playwright smoke fails when you deliberately break
99
+ boot (rename a pack file) — a smoke test that can't fail is decoration.