@codyswann/lisa 2.160.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.
- package/.agents/plugins/marketplace.json +12 -0
- package/.claude-plugin/marketplace.json +24 -0
- package/dist/codex/plugin-marketplace-installer.d.ts.map +1 -1
- package/dist/codex/plugin-marketplace-installer.js +2 -0
- package/dist/codex/plugin-marketplace-installer.js.map +1 -1
- package/dist/configs/eslint/harper-fabric.js +2 -2
- package/dist/configs/eslint/harper-fabric.js.map +1 -1
- package/dist/configs/eslint/index.d.ts +2 -0
- package/dist/configs/eslint/index.d.ts.map +1 -1
- package/dist/configs/eslint/index.js +2 -0
- package/dist/configs/eslint/index.js.map +1 -1
- package/dist/configs/eslint/phaser.d.ts +29 -0
- package/dist/configs/eslint/phaser.d.ts.map +1 -0
- package/dist/configs/eslint/phaser.js +87 -0
- package/dist/configs/eslint/phaser.js.map +1 -0
- package/dist/configs/vitest/index.d.ts +3 -2
- package/dist/configs/vitest/index.d.ts.map +1 -1
- package/dist/configs/vitest/index.js +3 -2
- package/dist/configs/vitest/index.js.map +1 -1
- package/dist/configs/vitest/phaser.d.ts +29 -0
- package/dist/configs/vitest/phaser.d.ts.map +1 -0
- package/dist/configs/vitest/phaser.js +36 -0
- package/dist/configs/vitest/phaser.js.map +1 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +2 -0
- package/dist/core/config.js.map +1 -1
- package/dist/detection/detectors/phaser.d.ts +15 -0
- package/dist/detection/detectors/phaser.d.ts.map +1 -0
- package/dist/detection/detectors/phaser.js +24 -0
- package/dist/detection/detectors/phaser.js.map +1 -0
- package/dist/detection/index.d.ts.map +1 -1
- package/dist/detection/index.js +2 -0
- package/dist/detection/index.js.map +1 -1
- package/dist/migrations/reconcile-claude-stack-plugins.d.ts.map +1 -1
- package/dist/migrations/reconcile-claude-stack-plugins.js +1 -0
- package/dist/migrations/reconcile-claude-stack-plugins.js.map +1 -1
- package/dist/strategies/package-lisa.d.ts.map +1 -1
- package/dist/strategies/package-lisa.js +4 -0
- package/dist/strategies/package-lisa.js.map +1 -1
- package/harper-fabric/copy-contents/.prettierignore +4 -1
- package/harper-fabric/copy-overwrite/knip.json +2 -1
- package/harper-fabric/copy-overwrite/tsconfig.eslint.json +2 -1
- package/harper-fabric/merge/.oxlintrc.json +2 -1
- package/oxlint/harper-fabric.json +2 -1
- package/oxlint/phaser.json +11 -0
- package/package.json +7 -2
- package/phaser/copy-contents/.prettierignore +7 -0
- package/phaser/copy-overwrite/.github/workflows/ci.yml +23 -0
- package/phaser/copy-overwrite/eslint.config.ts +38 -0
- package/phaser/copy-overwrite/knip.json +17 -0
- package/phaser/copy-overwrite/tsconfig.eslint.json +20 -0
- package/phaser/copy-overwrite/tsconfig.json +7 -0
- package/phaser/copy-overwrite/vitest.config.ts +30 -0
- package/phaser/deletions.json +3 -0
- package/phaser/merge/.claude/settings.json +34 -0
- package/phaser/merge/.oxlintrc.json +16 -0
- package/phaser/package-lisa/package.lisa.json +73 -0
- package/plugins/lisa/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-agy/plugin.json +1 -1
- package/plugins/lisa-cdk/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-agy/plugin.json +1 -1
- package/plugins/lisa-cdk-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cdk-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-agy/plugin.json +1 -1
- package/plugins/lisa-expo-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-expo-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/.claude-plugin/plugin.json +12 -1
- package/plugins/lisa-harper-fabric/.codex-plugin/hooks.json +11 -0
- package/plugins/lisa-harper-fabric/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric/generated-artifact-globs.txt +4 -0
- package/plugins/lisa-harper-fabric/hooks/block-generated-artifact-edits.sh +72 -0
- package/plugins/lisa-harper-fabric-agy/generated-artifact-globs.txt +4 -0
- package/plugins/lisa-harper-fabric-agy/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-copilot/.claude-plugin/plugin.json +12 -1
- package/plugins/lisa-harper-fabric-copilot/generated-artifact-globs.txt +4 -0
- package/plugins/lisa-harper-fabric-copilot/hooks/block-generated-artifact-edits.sh +72 -0
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/generated-artifact-globs.txt +4 -0
- package/plugins/lisa-harper-fabric-cursor/hooks/block-generated-artifact-edits.sh +72 -0
- package/plugins/lisa-harper-fabric-cursor/hooks/hooks.json +11 -0
- package/plugins/lisa-nestjs/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-agy/plugin.json +1 -1
- package/plugins/lisa-nestjs-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-nestjs-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-agy/plugin.json +1 -1
- package/plugins/lisa-openclaw-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-openclaw-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-phaser/.claude-plugin/plugin.json +35 -0
- package/plugins/lisa-phaser/.codex-plugin/hooks.json +26 -0
- package/plugins/lisa-phaser/.codex-plugin/plugin.json +30 -0
- package/plugins/lisa-phaser/hooks/inject-rules.sh +16 -0
- package/plugins/lisa-phaser/rules/phaser.md +59 -0
- package/plugins/lisa-phaser/skills/phaser-assets/SKILL.md +96 -0
- package/plugins/lisa-phaser/skills/phaser-assets/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-gameobjects/SKILL.md +94 -0
- package/plugins/lisa-phaser/skills/phaser-gameobjects/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-physics/SKILL.md +86 -0
- package/plugins/lisa-phaser/skills/phaser-physics/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-project-structure/SKILL.md +89 -0
- package/plugins/lisa-phaser/skills/phaser-project-structure/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-rendering/SKILL.md +89 -0
- package/plugins/lisa-phaser/skills/phaser-rendering/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-scenes/SKILL.md +86 -0
- package/plugins/lisa-phaser/skills/phaser-scenes/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-testing/SKILL.md +99 -0
- package/plugins/lisa-phaser/skills/phaser-testing/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser/skills/phaser-v3-migration/SKILL.md +81 -0
- package/plugins/lisa-phaser/skills/phaser-v3-migration/agents/openai.yaml +4 -0
- package/plugins/lisa-phaser-agy/plugin.json +11 -0
- package/plugins/lisa-phaser-agy/skills/phaser-assets/SKILL.md +96 -0
- package/plugins/lisa-phaser-agy/skills/phaser-gameobjects/SKILL.md +94 -0
- package/plugins/lisa-phaser-agy/skills/phaser-physics/SKILL.md +86 -0
- package/plugins/lisa-phaser-agy/skills/phaser-project-structure/SKILL.md +89 -0
- package/plugins/lisa-phaser-agy/skills/phaser-rendering/SKILL.md +89 -0
- package/plugins/lisa-phaser-agy/skills/phaser-scenes/SKILL.md +86 -0
- package/plugins/lisa-phaser-agy/skills/phaser-testing/SKILL.md +99 -0
- package/plugins/lisa-phaser-agy/skills/phaser-v3-migration/SKILL.md +81 -0
- package/plugins/lisa-phaser-copilot/.claude-plugin/plugin.json +24 -0
- package/plugins/lisa-phaser-copilot/hooks/inject-rules.sh +16 -0
- package/plugins/lisa-phaser-copilot/rules/phaser.md +59 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-assets/SKILL.md +96 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-gameobjects/SKILL.md +94 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-physics/SKILL.md +86 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-project-structure/SKILL.md +89 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-rendering/SKILL.md +89 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-scenes/SKILL.md +86 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-testing/SKILL.md +99 -0
- package/plugins/lisa-phaser-copilot/skills/phaser-v3-migration/SKILL.md +81 -0
- package/plugins/lisa-phaser-cursor/.claude-plugin/plugin.json +11 -0
- package/plugins/lisa-phaser-cursor/rules/phaser.mdc +64 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-assets/SKILL.md +96 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-gameobjects/SKILL.md +94 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-physics/SKILL.md +86 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-project-structure/SKILL.md +89 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-rendering/SKILL.md +89 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-scenes/SKILL.md +86 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-testing/SKILL.md +99 -0
- package/plugins/lisa-phaser-cursor/skills/phaser-v3-migration/SKILL.md +81 -0
- package/plugins/lisa-rails/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-agy/plugin.json +1 -1
- package/plugins/lisa-rails-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-rails-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-agy/plugin.json +1 -1
- package/plugins/lisa-typescript-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-typescript-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki/.codex-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-agy/plugin.json +1 -1
- package/plugins/lisa-wiki-copilot/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-wiki-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/src/harper-fabric/.claude-plugin/plugin.json +8 -0
- package/plugins/src/harper-fabric/generated-artifact-globs.txt +4 -0
- package/plugins/src/harper-fabric/hooks/block-generated-artifact-edits.sh +72 -0
- package/plugins/src/phaser/.claude-plugin/plugin.json +15 -0
- package/plugins/src/phaser/hooks/inject-rules.sh +16 -0
- package/plugins/src/phaser/rules/phaser.md +59 -0
- package/plugins/src/phaser/skills/phaser-assets/SKILL.md +96 -0
- package/plugins/src/phaser/skills/phaser-gameobjects/SKILL.md +94 -0
- package/plugins/src/phaser/skills/phaser-physics/SKILL.md +86 -0
- package/plugins/src/phaser/skills/phaser-project-structure/SKILL.md +89 -0
- package/plugins/src/phaser/skills/phaser-rendering/SKILL.md +89 -0
- package/plugins/src/phaser/skills/phaser-scenes/SKILL.md +86 -0
- package/plugins/src/phaser/skills/phaser-testing/SKILL.md +99 -0
- package/plugins/src/phaser/skills/phaser-v3-migration/SKILL.md +81 -0
- package/scripts/build-plugins.sh +1 -1
- package/tsconfig/harper-fabric.json +3 -1
- 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.
|
package/scripts/build-plugins.sh
CHANGED
|
@@ -63,7 +63,7 @@ build_per_agent_variant() {
|
|
|
63
63
|
build_plugin base lisa
|
|
64
64
|
|
|
65
65
|
# Stack-specific plugins (NO base copy)
|
|
66
|
-
STACKS=(typescript expo nestjs cdk harper-fabric rails)
|
|
66
|
+
STACKS=(typescript expo nestjs cdk harper-fabric phaser rails)
|
|
67
67
|
for stack in "${STACKS[@]}"; do
|
|
68
68
|
build_plugin "$stack" "lisa-$stack"
|
|
69
69
|
done
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./typescript.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["ES2022", "DOM", "DOM.Iterable"],
|
|
5
|
+
"rootDir": ".",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"resolveJsonModule": true,
|
|
8
|
+
"allowJs": false,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"types": ["node", "vitest"]
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts", "tests/**/*.ts"],
|
|
13
|
+
"exclude": ["dist", "coverage", "node_modules", "public/assets"]
|
|
14
|
+
}
|