@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,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.
@@ -0,0 +1,81 @@
1
+ ---
2
+ name: phaser-v3-migration
3
+ description: This skill should be used when migrating a Phaser 3 game to Phaser 4, reviewing code that contains Phaser 3 idioms, or answering "does this v3 API still exist" questions — pipelines→render nodes, preFX/postFX/BitmapMask→Filters, tintFill→TintModes, removed namespaces (Geom.Point, Struct, Mesh/Plane, Camera3D, bundled Spine), config default changes, and texture-orientation changes. Pairs with phaser-rendering and phaser-project-structure.
4
+ ---
5
+
6
+ # Phaser 3 → Phaser 4 Migration
7
+
8
+ ## Overview
9
+
10
+ Phaser 4.0.0 "Caladan" (April 2026; current line v4.1 "Salusa") keeps the core
11
+ game-facing API stable — scenes, input, Arcade/Matter physics, tweens,
12
+ animations, audio, and the scale manager are **unchanged** — and replaces the
13
+ rendering internals. The official estimate for a standard-API game is hours,
14
+ not weeks. The npm package is still `phaser`; v4 ships its own
15
+ `types/phaser.d.ts`.
16
+
17
+ Upstream references for deeper detail: the official migration guide in the
18
+ phaser repo (`changelog/v4/4.0/MIGRATION-GUIDE.md`) and the shader-specific
19
+ guide. This skill is original Lisa content written against those primary
20
+ sources — it is not a port of any upstream plugin or skill package.
21
+
22
+ ## What did NOT change (don't "migrate" these)
23
+
24
+ Scene lifecycle (`init/preload/create/update`), `this.scene` control, Loader
25
+ API (plus new `atlasPCT`), Input, Arcade & Matter physics, Tweens/Timelines,
26
+ `anims`, Scale Manager, Sound managers, Groups, Containers, particle emitter
27
+ API (v3.60 style).
28
+
29
+ ## The breaking changes, by frequency of impact
30
+
31
+ | Phaser 3 | Phaser 4 |
32
+ | --- | --- |
33
+ | `setPipeline(...)` / `setPostPipeline(...)` / `resetPipeline()` | RenderNodes (`render.renderNodes` config) — rewrite required |
34
+ | `preFX` / `postFX` controllers | Unified **Filter** system (internal/external lists) |
35
+ | `BitmapMask` / `GeometryMask` | `Mask` filter; `Phaser.Actions.AddMaskShape()` |
36
+ | Bloom/Shine/Circle FX | `Actions.AddEffectBloom()` / `AddEffectShine()` |
37
+ | Gradient FX | `Gradient` GameObject |
38
+ | `setTintFill(c)` / `tintFill` | `setTint(c)` + `setTintMode(Phaser.TintModes.FILL)` |
39
+ | `setPipeline('Light2D')` | `gameObject.setLighting(true)`; lights gained `z` |
40
+ | `Phaser.Geom.Point` | Removed — `Phaser.Math.Vector2` (geometry returns Vector2) |
41
+ | `Phaser.Struct.Set` / `Struct.Map` | Native `Set` / `Map` |
42
+ | Shadertoy-style `Shader` uniforms | Rewritten Shader: `ShaderQuadConfig`, `setUniform()`, `#pragma` |
43
+ | RenderTexture/DynamicTexture draw-executes-immediately | **Buffered** — call `render()`; `preserve()`, `renderMode` |
44
+ | Bundled Spine 3/4 plugins | Removed — Esoteric's official Phaser Spine runtime |
45
+ | `Mesh`, `Plane`, OBJ loader, `Camera3D`, `Layer3D` | Removed, no replacement |
46
+ | `Math.TAU` = π/2 (wrong) | `Math.TAU` = 2π (correct); `PI_OVER_2` added; `PI2` removed |
47
+ | `Create.GenerateTexture`, polyfills, IE9 entry | Removed |
48
+
49
+ ## Behavior/default changes that silently alter a port
50
+
51
+ - `roundPixels` default flipped **true → false**. If a pixel-art game looks
52
+ blurry after porting, set `pixelArt: true` (or `render.smoothPixelArt`) —
53
+ don't blanket-restore roundPixels.
54
+ - **Texture Y-flip**: UVs are GL-oriented (Y=0 bottom). Standard usage is
55
+ translated automatically, but custom shaders and **compressed textures** must
56
+ be updated/re-encoded.
57
+ - `Camera#matrix` no longer includes position (`matrixExternal` does;
58
+ `matrixCombined` removed) — affects code doing manual camera-space math.
59
+ - `Grid` "outline" properties renamed to "stroke". TileSprite was rebuilt
60
+ (atlas frames, `tileRotation`; cropping removed). `DOMElement` without a
61
+ container parent now throws.
62
+
63
+ ## Migration procedure
64
+
65
+ 1. Bump `phaser` to `^4.1.0`; remove any `@types/phaser`.
66
+ 2. Typecheck — removed APIs surface as compile errors; fix using the table.
67
+ 3. Grep for the silent ones types won't catch: `Light2D`, `tintFill`,
68
+ `Math.TAU`, custom shader GLSL, compressed-texture loads.
69
+ 4. Rewrite pipelines/FX as RenderNodes/Filters ([[phaser-rendering]]); re-add
70
+ `render()` calls after DynamicTexture drawing.
71
+ 5. Swap Spine to the Esoteric runtime; check third-party plugins (`rex` users:
72
+ the v4 line is the separate `phaser4-rex-plugins` package, which also ships
73
+ `p3-fx` ports of the dropped v3 FX).
74
+ 6. Verify visually per [[phaser-rendering]] — renderer migrations produce
75
+ wrong-pixels bugs, not exceptions.
76
+
77
+ ## Project conventions
78
+
79
+ This stack's lint config hard-bans the left column of the table in `src/**` —
80
+ a migration is not complete until lint passes with those rules on, with zero
81
+ disables.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "Ruby on Rails-specific skills and hooks for RuboCop and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-rails",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "Ruby on Rails-specific hooks — RuboCop linting/formatting and ast-grep scanning on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "TypeScript-specific hooks for formatting, linting, and ast-grep scanning on edit.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-typescript",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "TypeScript-specific hooks — Prettier formatting, ESLint linting, ast-grep scanning, and error-suppression blocking on edit",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "Distributable LLM Wiki kernel — ingest, query, lint, and maintain a git-native markdown knowledge base across Claude and Codex.",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lisa-wiki",
3
- "version": "2.161.0",
3
+ "version": "2.162.0",
4
4
  "description": "LLM Wiki — a distributable, git-native markdown knowledge base for Claude Code and Codex",
5
5
  "author": {
6
6
  "name": "Cody Swann"
@@ -0,0 +1,15 @@
1
+ {
2
+ "name": "lisa-phaser",
3
+ "version": "1.0.0",
4
+ "description": "Phaser 4 game-development rules for TypeScript projects",
5
+ "author": { "name": "Cody Swann" },
6
+ "dependencies": ["lisa-typescript"],
7
+ "hooks": {
8
+ "SessionStart": [
9
+ { "matcher": "", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh" }] }
10
+ ],
11
+ "SubagentStart": [
12
+ { "matcher": "", "hooks": [{ "type": "command", "command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh" }] }
13
+ ]
14
+ }
15
+ }
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env bash
2
+ # Reads all .md files from the plugin's rules/ directory and injects them
3
+ # into Claude context at session/subagent start.
4
+ set -euo pipefail
5
+
6
+ ROOT="${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)}}"
7
+ RULES_DIR="$ROOT/rules"
8
+
9
+ [ -d "$RULES_DIR" ] || exit 0
10
+
11
+ for rule in "$RULES_DIR"/*.md; do
12
+ [ -f "$rule" ] || continue
13
+ printf '\n<lisa-phaser-rule path="%s">\n' "$rule"
14
+ cat "$rule"
15
+ printf '\n</lisa-phaser-rule>\n'
16
+ done
@@ -0,0 +1,59 @@
1
+ # Phaser 4 Project Rules
2
+
3
+ This is a **Phaser 4** (v4.1+ "Salusa") TypeScript game project. Phaser 4 is the
4
+ only supported target — never introduce Phaser 3 idioms. The lint config enforces
5
+ the bans below; do not disable those rules, fix the code.
6
+
7
+ ## Phaser 4 Only — Banned v3 Idioms
8
+
9
+ - **No pipelines.** `setPipeline` / `setPostPipeline` / `resetPipeline` are gone.
10
+ Custom rendering is a **RenderNode** (registered via `render.renderNodes` in the
11
+ game config); post-processing is a **Filter** (`gameObject.filters` /
12
+ `camera.filters`). See the `phaser-rendering` skill.
13
+ - **No preFX/postFX.** The v3 FX controllers were replaced by the unified Filter
14
+ system. `BitmapMask` → `Mask` filter.
15
+ - **No `setTintFill`/`tintFill`.** Use `setTint()` + `setTintMode(Phaser.TintModes.FILL)`.
16
+ - **No `Phaser.Geom.Point`** (removed — use `Phaser.Math.Vector2`) and **no
17
+ `Phaser.Struct.Set/Map`** (removed — use native `Set`/`Map`).
18
+ - **No raw WebGL calls.** External GL work goes through the `Extern` game object.
19
+ - **No `setPipeline('Light2D')`.** Lighting is `gameObject.setLighting(true)`.
20
+
21
+ ## Architecture
22
+
23
+ - **One scene class per file** under `src/scenes/`, named after the scene key.
24
+ The scene flow is `Boot → Preloader → MainMenu → Game` (plus overlays). Boot
25
+ loads only what the Preloader needs; the Preloader loads everything else.
26
+ - **Pure game logic lives outside scenes** in `src/logic/` (or `src/core/`) with
27
+ **no `phaser` imports** — plain TypeScript functions and classes that take and
28
+ return data. Scenes are thin orchestrators that wire logic to GameObjects.
29
+ This is what makes the game unit-testable; see the `phaser-testing` skill.
30
+ - **Asset keys are typed constants** in `src/assets.ts` — never inline magic
31
+ strings for texture/audio/animation keys. Load via asset-pack manifests
32
+ (`this.load.pack`), not ad-hoc `load.image` lists scattered across scenes.
33
+
34
+ ## Determinism
35
+
36
+ - **No `Math.random()` in game code.** Use the scene-seeded
37
+ `Phaser.Math.RandomDataGenerator` (`Phaser.Math.RND` or a local instance with
38
+ an explicit seed) so replays and tests are reproducible.
39
+ - Arcade physics keeps its v4 default `fixedStep: true`. Do not switch physics to
40
+ variable step to "fix" a tunneling bug — fix the body/velocity configuration.
41
+
42
+ ## Performance
43
+
44
+ - **No allocations in `update()`.** No `new`, array literals, closures, or
45
+ `.filter/.map` chains in per-frame paths — hoist scratch objects, reuse vectors.
46
+ - **Pool, don't churn.** Bullets, enemies, particles, and pickups come from
47
+ `Group` pools (`get`/`killAndHide`), never `new`/`destroy` per spawn.
48
+ - **Mass rendering uses the GPU layers.** Large static/animated sprite fields →
49
+ `SpriteGPULayer`; large tile maps → `TilemapGPULayer`. Texture atlases (PCT
50
+ where possible) over loose images — see the `phaser-assets` skill.
51
+ - Target WebGL; the Canvas renderer is deprecated in v4 and only acceptable as an
52
+ explicit, documented fallback decision.
53
+
54
+ ## Verification
55
+
56
+ Before reporting any change complete: run `bun run typecheck`, `bun run test`,
57
+ and `bun run build`. For changes that affect rendering or input, verify in the
58
+ real browser — `bun run dev` plus a Playwright check (the game boots, the canvas
59
+ renders, no console errors). A green typecheck alone is not proof a game works.
@@ -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.