@codyswann/lisa 2.161.0 → 2.163.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/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/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/hooks/enforce-config-extensions.mjs +143 -0
- package/plugins/lisa-harper-fabric/hooks/enforce-config-extensions.sh +19 -0
- package/plugins/lisa-harper-fabric/rules/harper-fabric.md +1 -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/hooks/enforce-config-extensions.mjs +143 -0
- package/plugins/lisa-harper-fabric-copilot/hooks/enforce-config-extensions.sh +19 -0
- package/plugins/lisa-harper-fabric-copilot/rules/harper-fabric.md +1 -0
- package/plugins/lisa-harper-fabric-cursor/.claude-plugin/plugin.json +1 -1
- package/plugins/lisa-harper-fabric-cursor/hooks/enforce-config-extensions.mjs +143 -0
- package/plugins/lisa-harper-fabric-cursor/hooks/enforce-config-extensions.sh +19 -0
- package/plugins/lisa-harper-fabric-cursor/hooks/hooks.json +6 -0
- package/plugins/lisa-harper-fabric-cursor/rules/harper-fabric.mdc +1 -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/hooks/enforce-config-extensions.mjs +143 -0
- package/plugins/src/harper-fabric/hooks/enforce-config-extensions.sh +19 -0
- package/plugins/src/harper-fabric/rules/harper-fabric.md +1 -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/phaser.json +14 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lisa-phaser",
|
|
3
|
+
"version": "2.163.0",
|
|
4
|
+
"description": "Phaser 4 game-development rules for TypeScript projects",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Cody Swann"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": [
|
|
9
|
+
"lisa-typescript"
|
|
10
|
+
],
|
|
11
|
+
"hooks": {
|
|
12
|
+
"SessionStart": [
|
|
13
|
+
{
|
|
14
|
+
"matcher": "",
|
|
15
|
+
"hooks": [
|
|
16
|
+
{
|
|
17
|
+
"type": "command",
|
|
18
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh"
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
}
|
|
22
|
+
],
|
|
23
|
+
"SubagentStart": [
|
|
24
|
+
{
|
|
25
|
+
"matcher": "",
|
|
26
|
+
"hooks": [
|
|
27
|
+
{
|
|
28
|
+
"type": "command",
|
|
29
|
+
"command": "${CLAUDE_PLUGIN_ROOT}/hooks/inject-rules.sh"
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"hooks": {
|
|
3
|
+
"SessionStart": [
|
|
4
|
+
{
|
|
5
|
+
"matcher": "",
|
|
6
|
+
"hooks": [
|
|
7
|
+
{
|
|
8
|
+
"type": "command",
|
|
9
|
+
"command": "${PLUGIN_ROOT}/hooks/inject-rules.sh"
|
|
10
|
+
}
|
|
11
|
+
]
|
|
12
|
+
}
|
|
13
|
+
],
|
|
14
|
+
"SubagentStart": [
|
|
15
|
+
{
|
|
16
|
+
"matcher": "",
|
|
17
|
+
"hooks": [
|
|
18
|
+
{
|
|
19
|
+
"type": "command",
|
|
20
|
+
"command": "${PLUGIN_ROOT}/hooks/inject-rules.sh"
|
|
21
|
+
}
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "lisa-phaser",
|
|
3
|
+
"version": "2.163.0",
|
|
4
|
+
"description": "Phaser 4 game-development rules for TypeScript projects",
|
|
5
|
+
"author": {
|
|
6
|
+
"name": "Cody Swann"
|
|
7
|
+
},
|
|
8
|
+
"keywords": [
|
|
9
|
+
"lisa"
|
|
10
|
+
],
|
|
11
|
+
"dependencies": [
|
|
12
|
+
"lisa-typescript"
|
|
13
|
+
],
|
|
14
|
+
"skills": "./skills/",
|
|
15
|
+
"hooks": "./.codex-plugin/hooks.json",
|
|
16
|
+
"interface": {
|
|
17
|
+
"displayName": "lisa-phaser",
|
|
18
|
+
"shortDescription": "Phaser 4 game-development rules for TypeScript projects",
|
|
19
|
+
"longDescription": "Phaser 4 game-development rules for TypeScript projects",
|
|
20
|
+
"developerName": "Cody Swann",
|
|
21
|
+
"category": "Coding",
|
|
22
|
+
"capabilities": [
|
|
23
|
+
"Interactive",
|
|
24
|
+
"Write"
|
|
25
|
+
],
|
|
26
|
+
"defaultPrompt": [
|
|
27
|
+
"Use lisa-phaser"
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -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.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
display_name: "Phaser Assets"
|
|
2
|
+
short_description: "loading or organizing assets in a Phaser 4 game — the Loader (images, texture atlases, spritesheets, audio, fonts), asset-pack manifests…"
|
|
3
|
+
default_prompt:
|
|
4
|
+
- "Use $phaser-assets: loading or organizing assets in a Phaser 4 game — the Loader (images, texture atlases, spritesheets, audio, fonts), asset-pack manifests…."
|
|
@@ -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,4 @@
|
|
|
1
|
+
display_name: "Phaser Gameobjects"
|
|
2
|
+
short_description: "creating or managing Phaser 4 GameObjects — sprites, images, text, containers, groups and object pooling, animations (anims), tweens…"
|
|
3
|
+
default_prompt:
|
|
4
|
+
- "Use $phaser-gameobjects: creating or managing Phaser 4 GameObjects — sprites, images, text, containers, groups and object pooling, animations (anims), tweens…."
|
|
@@ -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,4 @@
|
|
|
1
|
+
display_name: "Phaser Physics"
|
|
2
|
+
short_description: "working with physics in a Phaser 4 game — Arcade physics bodies, velocity/acceleration, colliders and overlaps, the fixed timestep, groups…"
|
|
3
|
+
default_prompt:
|
|
4
|
+
- "Use $phaser-physics: working with physics in a Phaser 4 game — Arcade physics bodies, velocity/acceleration, colliders and overlaps, the fixed timestep, groups…."
|
|
@@ -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,4 @@
|
|
|
1
|
+
display_name: "Phaser Project Structure"
|
|
2
|
+
short_description: "creating, restructuring, or reasoning about a Phaser 4 game project — the game config, the Vite + TypeScript layout, the Boot → Preloader →…"
|
|
3
|
+
default_prompt:
|
|
4
|
+
- "Use $phaser-project-structure: creating, restructuring, or reasoning about a Phaser 4 game project — the game config, the Vite + TypeScript layout, the Boot → Preloader →…."
|
|
@@ -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,4 @@
|
|
|
1
|
+
display_name: "Phaser Rendering"
|
|
2
|
+
short_description: "working on rendering in Phaser 4 — the render node architecture that replaced v3 pipelines, the unified Filter system that replaced FX and…"
|
|
3
|
+
default_prompt:
|
|
4
|
+
- "Use $phaser-rendering: working on rendering in Phaser 4 — the render node architecture that replaced v3 pipelines, the unified Filter system that replaced FX and…."
|