npm i phaser has installed Phaser 4 since April 2026, but nearly every Phaser example an agent learnt from is Phaser 3. Phaser 4 replaced the WebGL renderer, so the commonest Phaser 3 calls are gone: pipelines (setPipeline('Light2D')), preFX and postFX, BitmapMask, setTintFill, Geom.Point and Structs.Set. Other changes compile and still break the game: Math.TAU is now PI * 2 rather than PI / 2, RenderTexture drawing waits for render(), and roundPixels is off by default.
This loadout pairs a short Cursor rule and AGENTS.md (check the version, then a never/always table) with a skill that checks the work. A standard-library Python scanner reports removed Phaser 3 APIs as errors and the silent changes as warnings, then tsc checks the code against Phaser 4's own types. It also points the agent at the migration skills Phaser now ships inside the npm package. The verifier runs it on a Phaser 4 scene and a Phaser 3.90 sample with the pinned phaser 4.2.1 and TypeScript 7.0.2.
What's in it
- Checks package.json first, and stays on Phaser 3 if the game is still 3.x
- Scanner flags pipelines, preFX/postFX, BitmapMask and setTintFill as errors
- Warns on Math.TAU, now PI * 2, and RenderTexture draws without render()
- tsc against Phaser 4.2.1's types rejects every removed call in the sample
- Points agents at the migration skills shipped in node_modules/phaser/skills
You'll need
- Tools:
node,python3
Verification
| Check | Result | What we found |
|---|---|---|
| Listinglisting.yaml matches the schema and declares every file in the folder. | Pass | Schema valid; 8 files declared, none missing or extra
|
| Files parseJSON parses; SKILL.md and .mdc front matter is valid YAML with the fields each agent needs; code fences are closed. | Pass | All 8 files parse; front matter valid |
| AdaptersCLAUDE.md imports @AGENTS.md, GEMINI.md imports @./AGENTS.md, and both match the generator. | Pass | CLAUDE.md and GEMINI.md import AGENTS.md and are up to date
|
| Install pathsEvery file lands where each agent documents it, with no collisions, and the laid-out project is re-discovered correctly. | Pass | Correct paths for all 6 agents; layouts re-discovered
|
| MCP configmcp.json is structurally valid, converts to each agent's format, declares no literal secrets, and referenced packages exist on npm/PyPI. | Not applicable | No MCP servers in this loadout |
| Safety scanThe intake scanner finds no credentials, risky shell, hidden Unicode, instructions hidden in HTML comments or after long blank padding, or prompt-injection and covert wording (such as telling the agent to keep something from you), and the listing's network flag is honest. | Pass | Clean: no credentials, risky shell, hidden text or covert instructions
|
| ReferencesLinks and file paths between the loadout's files resolve, including for each agent's installed layout. | Pass | 3 references between files resolve for every agent |
| Size limitsFile count and sizes are within the submission limits; SKILL.md bodies stay under 500 lines. | Pass | 8 files, 16.8 KB total; largest skills/phaser-4-guard/scripts/phaser4_guard.py 7.1 KB
|
| LicenceA recognised SPDX licence, with the licence text available. | Pass | MIT, by SetupBay; text in the repository LICENSE |
| Starter buildA minimal fixture project with the loadout applied installs and builds or type-checks, and the loadout's own code examples compile. | Pass | phaser4_guard.py passes a Phaser 4 scene and flags every Phaser 3 line in the skill's sample: 13 removed APIs as errors, and the changed Math.TAU and an unrendered RenderTexture draw as warnings. With the pinned phaser 4.2.1, tsc passes the Phaser 4 scene and rejects the sample's removed calls, and
|
What this means: a script checked the files themselves: they parse, they install where each agent looks, any MCP config is sound, the safety scan is clean, references between files resolve, and, where a free and repeatable fixture exists, a small starter project builds with the loadout applied. No AI agent was run. Per-agent results from agent runs are separate and stay untested until an agent actually runs.
Install
Choose your agent. Run the commands from your project root, or download a zip already laid out in the right folders.
Claude Code reads CLAUDE.md (imports AGENTS.md with @AGENTS.md) and skills from .claude/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/AGENTS.md curl -fsSL --create-dirs -o CLAUDE.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/CLAUDE.md curl -fsSL --create-dirs -o .claude/skills/phaser-4-guard/SKILL.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/SKILL.md curl -fsSL --create-dirs -o .claude/skills/phaser-4-guard/scripts/phaser4_guard.py https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/scripts/phaser4_guard.py curl -fsSL --create-dirs -o .claude/skills/phaser-4-guard/references/v3-to-v4.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/v3-to-v4.md curl -fsSL --create-dirs -o .claude/skills/phaser-4-guard/references/phaser3-sample.ts.txt https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/phaser3-sample.ts.txt
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
CLAUDE.md | CLAUDE.md |
skills/phaser-4-guard/SKILL.md | .claude/skills/phaser-4-guard/SKILL.md |
skills/phaser-4-guard/scripts/phaser4_guard.py | .claude/skills/phaser-4-guard/scripts/phaser4_guard.py |
skills/phaser-4-guard/references/v3-to-v4.md | .claude/skills/phaser-4-guard/references/v3-to-v4.md |
skills/phaser-4-guard/references/phaser3-sample.ts.txt | .claude/skills/phaser-4-guard/references/phaser3-sample.ts.txt |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what Claude Code reads.
Codex CLI reads AGENTS.md and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/SKILL.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/SKILL.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/scripts/phaser4_guard.py https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/scripts/phaser4_guard.py curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/v3-to-v4.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/v3-to-v4.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/phaser3-sample.ts.txt
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/phaser-4-guard/SKILL.md | .agents/skills/phaser-4-guard/SKILL.md |
skills/phaser-4-guard/scripts/phaser4_guard.py | .agents/skills/phaser-4-guard/scripts/phaser4_guard.py |
skills/phaser-4-guard/references/v3-to-v4.md | .agents/skills/phaser-4-guard/references/v3-to-v4.md |
skills/phaser-4-guard/references/phaser3-sample.ts.txt | .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what Codex CLI reads.
Cursor reads AGENTS.md + .cursor/rules/*.mdc and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .cursor/rules/phaser-4-only.mdc https://setupbay.com/raw/phaser-4-api-guard/1.0.0/.cursor/rules/phaser-4-only.mdc curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/SKILL.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/SKILL.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/scripts/phaser4_guard.py https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/scripts/phaser4_guard.py curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/v3-to-v4.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/v3-to-v4.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/phaser3-sample.ts.txt
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
.cursor/rules/phaser-4-only.mdc | .cursor/rules/phaser-4-only.mdc |
skills/phaser-4-guard/SKILL.md | .agents/skills/phaser-4-guard/SKILL.md |
skills/phaser-4-guard/scripts/phaser4_guard.py | .agents/skills/phaser-4-guard/scripts/phaser4_guard.py |
skills/phaser-4-guard/references/v3-to-v4.md | .agents/skills/phaser-4-guard/references/v3-to-v4.md |
skills/phaser-4-guard/references/phaser3-sample.ts.txt | .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what Cursor reads.
Gemini CLI reads GEMINI.md (imports AGENTS.md with @./AGENTS.md) and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/AGENTS.md curl -fsSL --create-dirs -o GEMINI.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/GEMINI.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/SKILL.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/SKILL.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/scripts/phaser4_guard.py https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/scripts/phaser4_guard.py curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/v3-to-v4.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/v3-to-v4.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/phaser3-sample.ts.txt
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
GEMINI.md | GEMINI.md |
skills/phaser-4-guard/SKILL.md | .agents/skills/phaser-4-guard/SKILL.md |
skills/phaser-4-guard/scripts/phaser4_guard.py | .agents/skills/phaser-4-guard/scripts/phaser4_guard.py |
skills/phaser-4-guard/references/v3-to-v4.md | .agents/skills/phaser-4-guard/references/v3-to-v4.md |
skills/phaser-4-guard/references/phaser3-sample.ts.txt | .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what Gemini CLI reads.
Antigravity CLI reads AGENTS.md (read natively; GEMINI.md is also read) and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/SKILL.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/SKILL.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/scripts/phaser4_guard.py https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/scripts/phaser4_guard.py curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/v3-to-v4.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/v3-to-v4.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/phaser3-sample.ts.txt
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/phaser-4-guard/SKILL.md | .agents/skills/phaser-4-guard/SKILL.md |
skills/phaser-4-guard/scripts/phaser4_guard.py | .agents/skills/phaser-4-guard/scripts/phaser4_guard.py |
skills/phaser-4-guard/references/v3-to-v4.md | .agents/skills/phaser-4-guard/references/v3-to-v4.md |
skills/phaser-4-guard/references/phaser3-sample.ts.txt | .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what Antigravity CLI reads.
GitHub Copilot reads AGENTS.md and skills from .agents/skills/.
curl -fsSL --create-dirs -o AGENTS.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/AGENTS.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/SKILL.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/SKILL.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/scripts/phaser4_guard.py https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/scripts/phaser4_guard.py curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/v3-to-v4.md https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/v3-to-v4.md curl -fsSL --create-dirs -o .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt https://setupbay.com/raw/phaser-4-api-guard/1.0.0/skills/phaser-4-guard/references/phaser3-sample.ts.txt
| File | Goes to |
|---|---|
AGENTS.md | AGENTS.md |
skills/phaser-4-guard/SKILL.md | .agents/skills/phaser-4-guard/SKILL.md |
skills/phaser-4-guard/scripts/phaser4_guard.py | .agents/skills/phaser-4-guard/scripts/phaser4_guard.py |
skills/phaser-4-guard/references/v3-to-v4.md | .agents/skills/phaser-4-guard/references/v3-to-v4.md |
skills/phaser-4-guard/references/phaser3-sample.ts.txt | .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt |
Already have an AGENTS.md or CLAUDE.md? The commands above overwrite it — download the file instead and merge the sections you want. Which file wins when several are present: what GitHub Copilot reads.
Or as a Claude Code plugin
Adds the skill to Claude Code for all your projects, without copying files. Plugins can't carry project rules, so add AGENTS.md and CLAUDE.md with the commands above. About the plugin marketplace.
/plugin marketplace add https://setupbay.com/marketplace.json /plugin install phaser-4-api-guard@setupbay
Files
Rules AGENTS.md Version check, Phaser 4 rules and the done checklist. 34 lines
# AGENTS.md: Phaser 4 game (Phaser 3 API guard)
This game runs **Phaser 4** (`phaser` 4.2.x), with TypeScript. `npm i phaser` has installed Phaser 4 since
April 2026, and 3.90.0 was the last Phaser 3 release. Nearly every Phaser tutorial and answer you learnt from is
Phaser 3, and Phaser 4 replaced the renderer: pipelines, preFX/postFX and BitmapMask are gone.
## Check the version first
- Read `package.json`. If `phaser` is `3.x`, this file doesn't apply: write Phaser 3 code and don't use any
Phaser 4 API. If it's `4.x`, follow the rules below. If you're not sure, stop and ask.
- Phaser 4 ships its own agent skills in the package: `node_modules/phaser/skills/`. Read
`node_modules/phaser/skills/v3-to-v4-migration/SKILL.md` before porting Phaser 3 code, and the topic skill
(for example `filters-and-postfx`, `render-textures`) before using an API you're unsure of.
- The types are the truth: `node_modules/phaser/types/phaser.d.ts`. If `tsc` says a property doesn't exist, it's
gone. Don't cast to `any` to get round it.
## Rules
- Write Phaser 4 code only. The `phaser-4-guard` skill has the table. The common ones are:
- `setPipeline('Light2D')` → `setLighting(true)` (and `this.lights.enable()`)
- `preFX` / `postFX` → `obj.enableFilters()`, then `obj.filters.internal` / `obj.filters.external`, or `camera.filters`
- `BitmapMask` → `obj.filters.internal.addMask(maskObject)`
- `setTintFill(c)` → `setTint(c).setTintMode(Phaser.TintModes.FILL)`
- `Geom.Point` → `Phaser.Math.Vector2`. `Structs.Set` / `Map` → native `Set` / `Map`
- `Math.PI2` → `Math.TAU`. **`Math.TAU` is now `PI * 2`**; in Phaser 3 it was `PI / 2`. Use `Math.PI_OVER_2` for a quarter turn.
- `colorMatrix.sepia()` → `colorMatrix.colorMatrix.sepia()`
- `RenderTexture` / `DynamicTexture` drawing is buffered: call `.render()` after `draw()`, `stamp()` and so on.
- `roundPixels` now defaults to `false`. For pixel art set `pixelArt: true` or choose a `vertexRoundMode`.
- Don't make raw WebGL calls. Use an `Extern` game object if you need to.
- Don't upgrade or downgrade Phaser without asking.
## Before you say "done"
1. Run the `phaser-4-guard` scanner on `src` and `package.json`. It must report `0 error(s)`. Any warning you leave needs a reason.
2. Run `npx tsc --noEmit`. It must pass, with no new `any` or `@ts-ignore` around Phaser calls.
3. If you changed rendering, filters or lighting, run the game and look at it. Adapter CLAUDE.md Imports AGENTS.md for Claude Code. 11 lines
# CLAUDE.md
@AGENTS.md
## Claude Code notes
- Skills from this loadout live in `.claude/skills/`: `phaser-4-guard`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.
<!-- From SetupBay "Phaser 4 guard for Phaser 3 pipelines, FX and masks" v1.0.0 — https://setupbay.com/loadouts/phaser-4-api-guard/ --> Adapter GEMINI.md Imports AGENTS.md for Gemini CLI. 11 lines
# GEMINI.md
@./AGENTS.md
## Gemini CLI notes
- Skills from this loadout live in `.agents/skills/`: `phaser-4-guard`. Use them when their description matches the task.
- Follow AGENTS.md above; where this file and AGENTS.md disagree, AGENTS.md wins.
<!-- From SetupBay "Phaser 4 guard for Phaser 3 pipelines, FX and masks" v1.0.0 — https://setupbay.com/loadouts/phaser-4-api-guard/ --> Cursor rule .cursor/rules/phaser-4-only.mdc Never/always table for game source and package.json. 24 lines
---
description: Phaser 4 only; never Phaser 3 pipelines, FX or masks
globs: "src/**/*.ts,src/**/*.js,package.json"
alwaysApply: false
---
This game uses Phaser 4 (check `package.json`; if it says 3.x, ignore this rule and stay on Phaser 3).
| Never (Phaser 3) | Always (Phaser 4) |
|---|---|
| `sprite.setPipeline("Light2D")` | `sprite.setLighting(true)` and `this.lights.enable()` |
| `sprite.preFX.addGlow()`, `postFX` | `sprite.enableFilters()` then `sprite.filters.internal.addGlow()` |
| `new Display.Masks.BitmapMask(...)`, `setMask` | `sprite.filters.internal.addMask(maskObject)` |
| `setTintFill(0xff0000)` | `setTint(0xff0000).setTintMode(Phaser.TintModes.FILL)` |
| `new Geom.Point(x, y)` | `new Phaser.Math.Vector2(x, y)` |
| `Math.PI2`; `Math.TAU` meaning a quarter turn | `Math.TAU` (= PI * 2); `Math.PI_OVER_2` |
| `new Structs.Set()` / `Structs.Map` | native `Set` / `Map` |
| `cm.sepia()` | `cm.colorMatrix.sepia()` |
| `rt.draw(obj)` and nothing else | `rt.draw(obj).render()` |
| `this.add.mesh()`, `textures.generate()` | removed; ask |
- Official guide: `node_modules/phaser/skills/v3-to-v4-migration/SKILL.md`.
- After editing, run the `phaser-4-guard` skill's scanner and `npx tsc --noEmit`. Skill skills/phaser-4-guard/SKILL.md Scan for Phaser 3 APIs and silent changes, then type-check against Phaser 4's types. 43 lines
---
name: phaser-4-guard
description: Check a Phaser 4 game for Phaser 3 APIs (pipelines, preFX/postFX, BitmapMask, setTintFill, Geom.Point, Math.PI2) and silent changes such as Math.TAU and buffered RenderTexture drawing, then type-check against Phaser 4's own types. Use after writing or editing Phaser scenes, when tsc says a Phaser property doesn't exist, or when porting a Phaser 3 tutorial.
---
# Phaser 4 guard
`npm i phaser` gives you Phaser 4, but most Phaser examples online are Phaser 3. Phaser 4 replaced the renderer,
so the commonest Phaser 3 calls (`setPipeline`, `preFX`, `postFX`, `BitmapMask`) no longer exist. Some changes don't
fail at all: `Math.TAU` changed value, and RenderTexture drawing does nothing until `render()`.
## 1. Confirm the version
- `node -p "require('phaser/package.json').version"` should print `4.x`. If it's `3.x`, stop: this skill is for Phaser 4.
## 2. Scan
```bash
python3 .agents/skills/phaser-4-guard/scripts/phaser4_guard.py src package.json
```
(Use the path the skill was installed to: `.claude/skills/...` for Claude Code, `.agents/skills/...` for the others.)
- Each `error` line is a Phaser 3 API that Phaser 4 removed. Fix it with the replacement on the line, or look it up
in `references/v3-to-v4.md`.
- Each `warn` line is a change that compiles but may behave differently: `Math.TAU`, a texture `draw()` that may need
`.render()`, `roundPixels`, `GeometryMask` (Canvas only), Grid `outline*` names, raw WebGL. Check each one. When it's
right, add `// guard: ok <reason>` to the line.
## 3. Type-check against Phaser 4
```bash
npx tsc --noEmit
```
- Phaser 4's types are generated from its source, so `Property 'postFX' does not exist` means the API is gone, not
that the types are wrong. Never cast to `any` or add `@ts-ignore` to keep a Phaser 3 call.
- For JavaScript projects, add `// @ts-check` to the file or `"checkJs": true` to get the same errors.
## 4. Read the official guide when porting
Phaser ships agent skills in the package. For anything not in the table, read
`node_modules/phaser/skills/v3-to-v4-migration/SKILL.md`, then the topic skill such as
`node_modules/phaser/skills/filters-and-postfx/SKILL.md`.
## 5. Report
Say which Phaser 3 calls you replaced, which warnings you kept and why, and that the scanner and `tsc` were clean.
If you changed rendering, filters or lighting, say whether you ran the game and looked at it. Skill file skills/phaser-4-guard/scripts/phaser4_guard.py Read-only scanner for removed Phaser 3 APIs and Phaser 4 behaviour changes. 152 lines
#!/usr/bin/env python3
"""Find Phaser 3 APIs that Phaser 4 removed or changed, in a Phaser 4 game's .ts/.js files.
Usage: python3 phaser4_guard.py [PATH ...] (default: the current folder)
python3 phaser4_guard.py --list (print every rule)
A "guard: ok" comment on a line silences its warnings (never its errors).
Prints one line per finding: path:line: level [rule] what is wrong -> what to use
Exit 0 when nothing at "error" level is found, 1 when something is, 2 on bad usage.
Standard library only. Read-only: it never edits a file and makes no network calls.
"""
import fnmatch
import os
import re
import sys
# (rule id, level, regex, message, file patterns). Patterns run against each line with comments removed.
RULES = [
('set-pipeline', 'error', '\\.setPipeline\\(|\\.setPostPipeline\\(|\\.resetPipeline\\(|pipelines\\.(add|get)\\(',
'pipelines were removed in Phaser 4 -> render nodes (RenderConfig#renderNodes); for lights use setLighting(true)', []),
('prefx-postfx', 'error', '\\.(preFX|postFX)\\b',
'preFX/postFX were replaced by filters -> obj.filters.internal / obj.filters.external (enable with obj.enableFilters())', []),
('bitmap-mask', 'error', '\\bBitmapMask\\b|\\.createBitmapMask\\(',
'BitmapMask was removed -> obj.filters.internal.addMask(maskObject)', []),
('geometry-mask-webgl', 'warn', '\\bcreateGeometryMask\\(|\\bGeometryMask\\b',
'GeometryMask only works in the Canvas renderer in Phaser 4 -> the Mask filter for WebGL', []),
('set-tint-fill', 'error', '\\.setTintFill\\(|\\.tintFill\\b',
'setTintFill()/tintFill were removed -> setTint(c).setTintMode(Phaser.TintModes.FILL)', []),
('geom-point', 'error', '\\bGeom\\.Point\\b',
'Geom.Point was removed -> Phaser.Math.Vector2', []),
('math-pi2', 'error', '\\bMath\\.PI2\\b',
'Phaser.Math.PI2 was removed -> Phaser.Math.TAU (now PI * 2)', []),
('struct-set-map', 'error', '\\bStructs\\.(Set|Map)\\b',
'Phaser.Structs.Set/Map were removed -> native Set / Map', []),
('mesh-plane', 'error', '\\.add\\.(mesh|plane)\\(|\\bGameObjects\\.(Mesh|Plane)\\b',
'Mesh and Plane were removed in Phaser 4', []),
('textures-generate', 'error', '\\btextures\\.generate\\(|\\bCreate\\.GenerateTexture\\b',
'TextureManager.generate / Create.GenerateTexture were removed -> draw to a Graphics and generateTexture(), or load an image', []),
('bloom-shine-fx', 'error', '\\.add(Bloom|Shine|Circle|Gradient)\\(',
'the Bloom/Shine/Circle/Gradient FX were removed -> Phaser.Actions.AddEffectBloom/AddEffectShine/AddMaskShape, or the Gradient game object', []),
('color-matrix-direct', 'error', '(?<![.\\w])(cm|colorMatrix|matrixFX|cmFX|grade|fx)\\.(sepia|grayscale|blackWhite|brown|vintagePinhole|kodachrome|technicolor|polaroid|shiftToBGR|desaturate|saturate|hue|brightness|contrast|night|lsd|negative)\\(',
'ColorMatrix methods moved onto .colorMatrix -> filter.colorMatrix.sepia()', []),
('spine-bundled', 'error', 'SpinePlugin|phaser/plugins/spine',
'the bundled Spine plugins are no longer updated -> the official Spine plugin from Esoteric Software', []),
('camera3d', 'error', 'Camera3D|Layer3D|phaser-ie9',
'Camera3D/Layer3D plugins and phaser-ie9 were removed', []),
('math-tau', 'warn', '\\bMath\\.TAU\\b',
'Phaser.Math.TAU is now PI * 2 (in Phaser 3 it was PI / 2) -> check intent; use Math.PI_OVER_2 for a quarter turn', []),
('render-texture-draw', 'warn', '\\b(rt|dt|\\w*Texture|\\w*RT)\\.(draw|drawFrame|stamp|erase|fill|repeat)\\(',
'DynamicTexture/RenderTexture commands are buffered in Phaser 4 -> call .render() after drawing (mark the line guard: ok once it does)', []),
('round-pixels', 'warn', '\\broundPixels\\b',
'roundPixels now defaults to false and only applies to unscaled, axis-aligned objects -> see GameObject#vertexRoundMode', []),
('grid-outline', 'warn', '\\b(outlineFillColor|outlineFillAlpha|setOutlineStyle)\\b',
'Grid shape outline* properties were renamed to stroke* in Phaser 4', []),
('raw-gl', 'warn', '\\b(renderer\\.gl|getContext\\(\\s*[\\"\']webgl)',
"direct WebGL calls desync Phaser 4's WebGL state -> use an Extern game object", []),
('phaser3-pin', 'error', '[\\"\']phaser[\\"\']\\s*:\\s*[\\"\'][~^]?3\\.',
'package.json pins Phaser 3 -> phaser 4.x', ['package.json']),
]
FILES = ['*.ts', '*.tsx', '*.js', '*.mjs', '*.jsx', 'package.json']
COMMENT = '//'
SKIP_DIRS = {".git", ".venv", "venv", "node_modules", "__pycache__", ".agents", ".claude", ".cursor", "dist", "build", "target", ".godot"}
COMPILED = [(rid, lvl, re.compile(rx), msg, globs) for rid, lvl, rx, msg, globs in RULES]
def strip_comment(line):
"""Drop a trailing comment, leaving string literals alone."""
q = None
i = 0
while i < len(line):
c = line[i]
if q:
if c == "\\":
i += 2
continue
if c == q:
q = None
elif c in "\"'`":
q = c
elif line.startswith(COMMENT, i):
return line[:i]
i += 1
return line
def wanted(name):
return any(fnmatch.fnmatch(name, g) for g in FILES)
def walk(paths):
for p in paths:
if os.path.isfile(p):
yield p
continue
for root, dirs, files in os.walk(p):
dirs[:] = sorted(d for d in dirs if d not in SKIP_DIRS)
for f in sorted(files):
if wanted(f):
yield os.path.join(root, f)
def scan(path):
out = []
name = os.path.basename(path)
try:
with open(path, encoding="utf-8", errors="replace") as fh:
lines = fh.read().splitlines()
except OSError as e:
return [(path, 0, "error", "unreadable", str(e))]
for n, raw in enumerate(lines, 1):
code = strip_comment(raw)
if not code.strip():
continue
accepted = "guard: ok" in raw # a person accepted the warnings on this line
for rid, lvl, rx, msg, globs in COMPILED:
if accepted and lvl == "warn":
continue
if globs and not any(fnmatch.fnmatch(name, g) for g in globs):
continue
if rx.search(code):
out.append((path, n, lvl, rid, msg))
return out
def main(argv):
if "--list" in argv:
for rid, lvl, _, msg, globs in RULES:
print(f"{lvl:5} [{rid}] {msg}" + (f" (only {', '.join(globs)})" if globs else ""))
return 0
if any(a.startswith("-") for a in argv):
print(__doc__)
return 2
paths = argv or ["."]
for p in paths:
if not os.path.exists(p):
print(f"no such path: {p}", file=sys.stderr)
return 2
files = list(walk(paths))
findings = []
for f in files:
findings.extend(scan(f))
for path, n, lvl, rid, msg in findings:
print(f"{os.path.relpath(path)}:{n}: {lvl} [{rid}] {msg}")
errors = sum(1 for x in findings if x[2] == "error")
warns = sum(1 for x in findings if x[2] == "warn")
print(f"phaser4_guard: {len(files)} file(s), {errors} error(s), {warns} warning(s)")
return 1 if errors else 0
if __name__ == "__main__":
sys.exit(main(sys.argv[1:])) Skill file skills/phaser-4-guard/references/v3-to-v4.md Phaser 3 to Phaser 4 table for the calls agents get wrong. 29 lines
# Phaser 3 to Phaser 4, the calls agents get wrong
From the official migration guide shipped in `phaser` 4.2.1 (`node_modules/phaser/changelog/v4/4.0/MIGRATION-GUIDE.md`,
also in the package's v3-to-v4-migration skill). The replacements used in the verifier's Phaser 4 scene type-check against Phaser 4.2.1.
| Phaser 3 | Phaser 4 |
|---|---|
| `sprite.setPipeline("Light2D")` | `sprite.setLighting(true)`; `this.lights.enable()` |
| custom `WebGLPipeline` / `PostFXPipeline` | a render node registered with `RenderConfig#renderNodes` |
| `sprite.preFX.addGlow()` / `sprite.postFX.addBlur()` | `sprite.enableFilters()`; `sprite.filters.internal.addGlow()` / `sprite.filters.external.addBlur()` |
| `camera.postFX.addColorMatrix()` | `camera.filters.external.addColorMatrix()` |
| `cm.sepia()` | `cm.colorMatrix.sepia()` |
| `postFX.addBloom()` / `addShine()` / `addCircle()` | `Phaser.Actions.AddEffectBloom(obj)` / `AddEffectShine(obj)` / `AddMaskShape(obj)` |
| `addGradient()` FX | the `Gradient` game object |
| `new Display.Masks.BitmapMask(scene, obj)` + `setMask` | `sprite.filters.internal.addMask(obj)` |
| `GeometryMask` in WebGL | the `Mask` filter (GeometryMask is Canvas only) |
| `sprite.setTintFill(c)`, `tintFill` | `sprite.setTint(c).setTintMode(Phaser.TintModes.FILL)` |
| `new Geom.Point(x, y)` | `new Phaser.Math.Vector2(x, y)` |
| `Point.GetMagnitude(p)` | `v.length()` |
| `Phaser.Math.PI2` | `Phaser.Math.TAU` |
| `Phaser.Math.TAU` (was PI / 2) | `Phaser.Math.PI_OVER_2` (TAU is now PI * 2) |
| `Phaser.Structs.Set` / `Map` | native `Set` / `Map` |
| `rt.draw(obj)` drawing at once | `rt.draw(obj).render()` (commands are buffered) |
| `this.add.mesh()`, `this.add.plane()` | removed |
| `this.textures.generate(key, { data })` | draw to a `Graphics` and call `generateTexture(key, w, h)` |
| bundled `SpinePlugin` | the official Spine plugin from Esoteric Software |
| `roundPixels` true by default | false by default; `pixelArt: true` or `GameObject#vertexRoundMode` |
| Grid `outlineFillColor`, `setOutlineStyle` | the `stroke*` equivalents | Skill file skills/phaser-4-guard/references/phaser3-sample.ts.txt A Phaser 3.90 scene for checking the guard. 26 lines
// A Phaser 3.90 scene, used to check the guard. Phaser 4 removed or changed every marked call.
import Phaser from "phaser";
export class GameScene extends Phaser.Scene {
create() {
const hero = this.add.sprite(100, 100, "hero");
hero.setTintFill(0xff0000);
hero.setPipeline("Light2D");
hero.preFX?.addGlow(0xffffff);
const glow = hero.postFX.addBloom();
const mask = new Phaser.Display.Masks.BitmapMask(this, this.add.image(0, 0, "mask"));
hero.setMask(mask);
const p = new Phaser.Geom.Point(1, 2);
const quarter = Phaser.Math.TAU;
const full = Phaser.Math.PI2;
const seen = new Phaser.Structs.Set<string>();
const rt = this.add.renderTexture(0, 0, 64, 64);
rt.draw(hero);
const mesh = this.add.mesh(0, 0, "hero");
const cm = this.cameras.main.postFX.addColorMatrix();
cm.sepia();
this.textures.generate("dot", { data: ["1"] });
console.log(p, quarter, full, seen, glow, mesh);
}
} All files: source zip · Licence MIT · By SetupBay · First listed
Credits
Public work that inspired this loadout. The wording here is our own; follow the links for the originals.
Installing and checks
How do I install Phaser 4 guard for Phaser 3 pipelines, FX and masks in Claude Code?
From your project root, put AGENTS.md, CLAUDE.md, skills/phaser-4-guard/SKILL.md at .claude/skills/phaser-4-guard/SKILL.md, skills/phaser-4-guard/scripts/phaser4_guard.py at .claude/skills/phaser-4-guard/scripts/phaser4_guard.py, skills/phaser-4-guard/references/v3-to-v4.md at .claude/skills/phaser-4-guard/references/v3-to-v4.md, skills/phaser-4-guard/references/phaser3-sample.ts.txt at .claude/skills/phaser-4-guard/references/phaser3-sample.ts.txt. The "Claude Code" tab on this page has the curl commands, or download https://setupbay.com/download/phaser-4-api-guard/claude-code.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Phaser 4 guard for Phaser 3 pipelines, FX and masks in Codex CLI?
From your project root, put AGENTS.md, skills/phaser-4-guard/SKILL.md at .agents/skills/phaser-4-guard/SKILL.md, skills/phaser-4-guard/scripts/phaser4_guard.py at .agents/skills/phaser-4-guard/scripts/phaser4_guard.py, skills/phaser-4-guard/references/v3-to-v4.md at .agents/skills/phaser-4-guard/references/v3-to-v4.md, skills/phaser-4-guard/references/phaser3-sample.ts.txt at .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt. The "Codex CLI" tab on this page has the curl commands, or download https://setupbay.com/download/phaser-4-api-guard/codex.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Phaser 4 guard for Phaser 3 pipelines, FX and masks in Cursor?
From your project root, put AGENTS.md, .cursor/rules/phaser-4-only.mdc, skills/phaser-4-guard/SKILL.md at .agents/skills/phaser-4-guard/SKILL.md, skills/phaser-4-guard/scripts/phaser4_guard.py at .agents/skills/phaser-4-guard/scripts/phaser4_guard.py, skills/phaser-4-guard/references/v3-to-v4.md at .agents/skills/phaser-4-guard/references/v3-to-v4.md, skills/phaser-4-guard/references/phaser3-sample.ts.txt at .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt. The "Cursor" tab on this page has the curl commands, or download https://setupbay.com/download/phaser-4-api-guard/cursor.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Phaser 4 guard for Phaser 3 pipelines, FX and masks in Gemini CLI?
From your project root, put AGENTS.md, GEMINI.md, skills/phaser-4-guard/SKILL.md at .agents/skills/phaser-4-guard/SKILL.md, skills/phaser-4-guard/scripts/phaser4_guard.py at .agents/skills/phaser-4-guard/scripts/phaser4_guard.py, skills/phaser-4-guard/references/v3-to-v4.md at .agents/skills/phaser-4-guard/references/v3-to-v4.md, skills/phaser-4-guard/references/phaser3-sample.ts.txt at .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt. The "Gemini CLI" tab on this page has the curl commands, or download https://setupbay.com/download/phaser-4-api-guard/gemini-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Phaser 4 guard for Phaser 3 pipelines, FX and masks in Antigravity CLI?
From your project root, put AGENTS.md, skills/phaser-4-guard/SKILL.md at .agents/skills/phaser-4-guard/SKILL.md, skills/phaser-4-guard/scripts/phaser4_guard.py at .agents/skills/phaser-4-guard/scripts/phaser4_guard.py, skills/phaser-4-guard/references/v3-to-v4.md at .agents/skills/phaser-4-guard/references/v3-to-v4.md, skills/phaser-4-guard/references/phaser3-sample.ts.txt at .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt. The "Antigravity CLI" tab on this page has the curl commands, or download https://setupbay.com/download/phaser-4-api-guard/antigravity-cli.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
How do I install Phaser 4 guard for Phaser 3 pipelines, FX and masks in GitHub Copilot?
From your project root, put AGENTS.md, skills/phaser-4-guard/SKILL.md at .agents/skills/phaser-4-guard/SKILL.md, skills/phaser-4-guard/scripts/phaser4_guard.py at .agents/skills/phaser-4-guard/scripts/phaser4_guard.py, skills/phaser-4-guard/references/v3-to-v4.md at .agents/skills/phaser-4-guard/references/v3-to-v4.md, skills/phaser-4-guard/references/phaser3-sample.ts.txt at .agents/skills/phaser-4-guard/references/phaser3-sample.ts.txt. The "GitHub Copilot" tab on this page has the curl commands, or download https://setupbay.com/download/phaser-4-api-guard/copilot.zip, which is already laid out. Do not overwrite an existing AGENTS.md or CLAUDE.md; merge it.
What has been checked in Phaser 4 guard for Phaser 3 pipelines, FX and masks?
It passed the Level 1 automated install checks on 2026-10-29: the files parse, install to each agent's documented paths, and pass the safety scan. No AI agent has run it yet, so no agent pass or fail is claimed.
More for Claude Code, Codex, Cursor, Gemini CLI, Antigravity CLI and GitHub Copilot.