agentic game-dev stack · open-source · 2026

What is the most up-to-date open-source agentic game-dev stack in 2026 —
and how do we improve on PlayCanvas-for-3D + PixiJS-for-2D?

This page consolidates the research notes in research/ into one answer for a build-time agent pipeline: the agent writes files, runs a headless build, verifies, ships. Runtime/in-game LLM NPCs are out of scope. The baseline it is judged against is NEON PURGE (this repo): a browser 2D neon arena roguelite on PixiJS 8.22.0, plain ES modules + import map, no build step, zero external assets, seeded RNG, headless Node autotests.

Every claim carries a note filename chip. Filenames are shown as plain text on purpose — source notes are not published with this page, so only the external URLs are real links.

decay warning All observations are a single snapshot taken 2026-10-09 (~08:18–08:35 GMT for the metadata; the 2D and 3D harnesses ran the same day). Version numbers, star counts, download counts, licences and "last push" dates move fast — the notes themselves record star counts drifting within the same hour. Treat this page as a verified starting point to re-check, not as a permanent fact sheet. The asset-model field replaced its own leader twice in the twelve months before the snapshot. 04-asset-pipeline.md §Confidence & gaps

01Executive answer — the improved stack in one screen

One pick per layer. Where a layer legitimately has two answers (a zero-dependency default plus an optional dev-only add-on), both are named and the cost of the add-on is stated.

Harness
OpenCode (MIT, opencode-ai 1.18.35, 2026-10-06) as the interactive harness, OpenAI Codex CLI (Apache-2.0, @openai/codex 0.162.0, 2026-10-08) for non-interactive CI runs. Spec layer: AGENTS.md + GitHub spec-kit (MIT, pushed 2026-10-08).
Engine runtime
2D — keep PixiJS 8.22.0 (MIT, 2026-10-01) as the renderer and close its battery gaps with planck 1.5.0 (MIT) + bitecs 0.4.0 (MPL-2.0). 3D — replace PlayCanvas with Babylon.js 9.30.0 (Apache-2.0, @babylonjs/core, 2026-10-08) + Havok 1.3.14 (MIT).
Tool interop
Chrome DevTools MCP (Apache-2.0, 1.10.1, 2026-09-23) + Playwright MCP (Apache-2.0, 0.0.83, 2026-09-28) + the official filesystem / memory / sequential-thinking servers (npm 2026.8.31, not deprecated). Pin the SDK: @modelcontextprotocol/sdk 1.32.1; spec revision 2026-07-28.
Assets
Keep it procedural (PixiJS generateTexture + Web Audio). If polish is wanted, only the permissive offline tier: Z-Image-Turbo / FLUX.2-klein-4B (Apache-2.0 weights), ACE-Step 1.5 (MIT), TRELLIS.2-4B (MIT, needs ≥24 GB VRAM), glued with gltf-transform 4.5.1 (MIT) + sharp 0.35.5 (Apache-2.0).
Verification
node --test (0 deps, Node v24.21.0 verified in this workspace) + the existing tools/check.mjs → smoke.mjs → shots.mjs chain + pixelmatch 8.0.0 (ISC, ESM) + Playwright 1.64.0 (Apache-2.0, dev-only, for input injection). Node-side pixels need no browser at all: PixiJS's own CanvasRenderer on jsdom + @napi-rs/canvas 1.0.10. Biggest flake risk: blank-canvas PNGs that still pass a file-size check.
Layer-by-layer pick, with the reason and the evidence note. All versions/dates/licences fetched 2026-10-09.
LayerRecommended pickVersion & dateLicenceWhy this oneEvidence
Harness / orchestration OpenCode (opencode-ai) 1.18.35 · 2026-10-06
pushed 2026-10-09
MIT Largest, fastest-moving OSS terminal harness (212,273★), LSP-aware, runs a no-build-step repo out of the box. Tradeoff: huge surface area, re-pin versions. 01-agent-harness.md
Harness (CI) OpenAI Codex CLI 0.162.0 · 2026-10-08 Apache-2.0 Best-documented non-interactive mode for CI, reads AGENTS.md, 93.1 M npm downloads/month. 01-agent-harness.md
Spec / convention AGENTS.md + GitHub spec-kit spec-kit pushed 2026-10-08
AGENTS.md 2026-09-10
MIT / MIT Cheapest way to make any harness obey docs/SPEC.md and the deterministic tools/*.mjs evidence loop. 01-agent-harness.md 03-mcp-interop.md
Engine runtime — 2D PixiJS 8.22.0 (keep) + the named add-on stack in §05 8.22.0 · 2026-10-01 MIT The pin is npm latest; no editor exists to fight; and it is the only candidate empirically proven to render headless both in a GPU-free browser (WebGL2 via SwANGLE) and in pure Node (its own CanvasRenderer, no compiler, no GPU). Ranked #4/21 on the agent-target rubric (84.0%). 07-improve-2d.md 02-engines.md
Engine runtime — 3D Babylon.js (@babylonjs/core) + @babylonjs/havok 9.30.0 · 2026-10-08
Havok 1.3.14 · 2026-07-29
Apache-2.0
MIT
The only web 3D engine whose whole loop survives headless Node: NullEngine scene + Havok physics + glTF import all verified with no GPU. Batteries first-party. 08-improve-3d.md 02-engines.md
Tool interop Chrome DevTools MCP + Playwright MCP + official filesystem/memory/sequential-thinking 1.10.1 · 2026-09-23
0.0.83 · 2026-09-28
2026.8.31
Apache-2.0 / Apache-2.0 / MIT–Apache-2.0 The only MCP category that actually targets a no-build browser game, and the healthiest part of the ecosystem. Engine-editor MCP bridges are irrelevant here. 03-mcp-interop.md
Assets Keep procedural; permissive offline tier only Z-Image-Turbo 2025-11-25
FLUX.2-klein-4B 2026-01-14
ACE-Step 1.5 2026-01-23
Apache-2.0 / Apache-2.0 / MIT Shipped payload 2.52 MB and 0 assets vs +1.8 MB and a 10–33 GB dev toolchain. The procedural route wins every axis this project measures except photographic fidelity. 04-asset-pipeline.md
Verification node --test + existing tools/ + pixelmatch + Playwright (dev-only) + jsdom/@napi-rs/canvas Node v24.21.0 (this box)
pixelmatch 8.0.0 · 2026-10-06
Playwright 1.64.0 · 2026-10-07
@napi-rs/canvas 1.0.10 · 2026-10-01
built-in / ISC / Apache-2.0 / MIT The unit layer costs zero dependencies, and the Node pixel path costs no compiler. The current suite is red (15 findings) so a green run carries no signal until that is fixed. 05-qa-harness.md 07-improve-2d.md
Isolation (optional) git worktrees; microsandbox only if untrusted code appears microsandbox 2026-10-09 Apache-2.0 Worktrees work natively on Windows and are proportionate for a zero-dependency, no-build-step JS repo. E2B/Daytona are cloud/Linux-oriented and awkward locally. 01-agent-harness.md

What changed versus the proposal being reviewed

3D: PlayCanvas → Babylon.js

PlayCanvas' engine is MIT and strong, but the Editor/cloud that owns projects, asset import and publishing is proprietary, and its terms expressly prohibit accounts created by "non-humans, 'bots' or other automated methods". Engine-only use is legal but has no headless render path. Babylon 9.30.0 replaces it.

08-improve-3d.md

2D: keep PixiJS, add the stack

Verdict of the dedicated 2D note: "Keep PixiJS 8.22.0 as the 2D renderer, and close every battery gap with a named MIT stack… plus a real verification layer." It is the only candidate empirically proven to render headless in a GPU-free browser and in pure Node, and a swap would touch 32/32 files and ~12,061 LOC for zero capability the stack does not already supply.

07-improve-2d.md

02Improving on your proposal

Both halves of the original proposal are judged on fetched evidence, not on taste. One is replaced; one is kept and reinforced.

PlayCanvas-for-3D — replaced by Babylon.js 9.30.0

Why the 3D layer changes. All cells fetched 2026-10-09.
QuestionWhat the evidence saysVerdictEvidence
Is the engine open source? Yes — [email protected] (2026-10-07) is MIT, 2 deps, 90.1 MB unpacked / 5,089 files, 88,194 downloads last week. The editor frontend repo is also MIT. fine 08-improve-3d.md §1
Is the platform an agent may use? No. playcanvas.com/terms (§4, "Your Account"): "You will not register any accounts by non-humans, 'bots' or other automated methods as such methods are expressly prohibited." §2 grants only a "revocable" personal licence to the Services; §3 takes a broad IP licence over content made publicly available. blocking 08-improve-3d.md §1
Is the agent-facing part the proprietary part? Yes — "A project lives in the Editor"; asset import pipeline, prefabs, version control, publishing/hosting and the REST API are all Editor-only. The engine-standalone path is first-party documented but you supply glTF loading, bundling and hosting yourself. inverted 08-improve-3d.md §1
Can an agent verify what it built headlessly? NullGraphicsDevice + app.update(dt) works (verified: 30 ticks, ESM script ran), but its own agent docs say "Rendering, input and physics can only be confirmed in a browser"; asset loading needs jsdom, physics needs an externally supplied ammo.js, and readPixels is a no-op by design. partial 08-improve-3d.md §2
What replaces it? Babylon.js 9.30.0 (Apache-2.0, 2026-10-08): the only one of the three web candidates whose scene graph, physics and asset loading were all booted in Node with no GPU, first-party batteries, own TypeScript types, and official graph-authoring MCP servers runnable as plain npx binaries. pick 08-improve-3d.md §0, §5
Where is PlayCanvas still the best answer? Browser 3D experiences/apps: product configurators, splat scenes, embeddable viewers. @playcanvas/react 0.11.7 and @playcanvas/web-components 0.28.0 need no build step, and its docs are the best-written of the three for agents. The ToS issue rarely bites when a human ships the app. keep, narrowed 08-improve-3d.md §5, §7

PixiJS-for-2D — kept, with the battery gaps named and priced

The dedicated 2D note answers this directly. Its verdict (§0): "Keep PixiJS 8.22.0 as the 2D renderer, and close every battery gap with a named MIT stack (planck/@dimforge/rapier2d, bitecs, @pixi/tilemap, @pixi/ui, @pixi/sound, pixi-filters) plus a real verification layer (pixelmatch + playwright + jsdom+@napi-rs/canvas)." 07-improve-2d.md §0

The decisive new finding

The usual claim "PixiJS v8 is WebGL2-only, so you need a browser (or a compiled gl) for headless pixels" is false. PixiJS v8 ships a real CanvasRenderer (type: RendererType.CANVAS) and its autoDetectRenderer order is webgpu | webgl | canvas; driving it with jsdom + @napi-rs/canvas produces engine-drawn pixels in plain Node with zero native build. Verified, not inferred.

07-improve-2d.md §1

The honest limits of that path

The Canvas2D renderer is a reduced pipeline: it silently skips filters and masks (the repo's glowLayer BlurFilter would not render there), and WebGL-in-Node via @pixi/node + gl is compiler-gated — it failed here at node-gyp with "Could not find any Visual Studio installation to use".

07-improve-2d.md §1.2, §7

Why not swap to Phaser

Phaser 4.2.1 has the batteries, but adopting it is a framework rewrite to its Scene/GameObject model; its LLM corpus is still overwhelmingly Phaser 3 (so an agent emits v3 API that no longer exists); Phaser.HEADLESS gives logic only, no pixels (verified); the package is 112.5 MB; and cadence is the slowest of the active web engines (last push 2026-08-21).

07-improve-2d.md §4

The runner-up, honestly priced

melonJS 20.8.0 is the only serious candidate that is both batteries-included and verified to render headlessly in pure Node — plus ~250 KB minzip, 0 deps, 22 stable releases/6 mo, agent skills and an llms.txt. The blocker is 1,652 downloads/week: effectively no LLM training corpus, so an agent guesses its API and is wrong. Its docs are best only if you accept "the agent reads the shipped types, not memory".

07-improve-2d.md §3, §4

The honest summary of the whole review: the proposal's 2D half was directionally right but under-priced — it named a renderer and stopped. The 3D half was wrong, and wrong for a reason a feature matrix cannot show: a service contract, not a licence. 07-improve-2d.md 08-improve-3d.md §7

03Engine comparison table — live versions, dates, licences

Transcribed from 02-engines.md §2; every cell was fetched on 2026-10-09 (the note pins its live date from the Date: header of api.github.com/rate_limit). Licences were re-read from raw LICENSE files, not taken from GitHub's SPDX detection, which the note found wrong or ambiguous in five cases.

(works without JavaScript — the filter is progressive enhancement)
Legend: W Windows, M macOS, L Linux, A Android, i iOS, Web browser/WASM, Cons consoles (vendor-gated, never publicly redistributable). "Rel. 6mo" = releases in the six months before 2026-10-09.
EngineLicence (exact)Latest stable + date StarsRel. 6moLast push Text-only authoring?Headless CI verificationWeb exportPlatforms
GodotMIT4.7.2-stable · 2026-08-22 (3.6.3 same day; master 4.8.0-dev)118,11462026-10-08yes .tscn/.tres/.gd plain textyes --headless --script, --import, --export-releaseWebGL2 only; no WebGPU; C# cannot export to webW M L A i Web Cons
BevyMIT OR Apache-2.0 (dual; both files present)0.20.0 · 2026-10-0848,7493 stable (+2 rc)2026-10-09yes pure Rust, no editoryes headless.rs, headless_renderer.rs; cargo testWASM: WebGL2 + WebGPUW M L Web
DefoldDefold License v1.0, May 2020 — custom, not OSI-approved1.13.2-stable · 2026-10-046,356102026-10-09partial bob CLI exists; .go/.collection text format UNVERIFIEDyes java -jar bob.jar + dmengine_headless (OpenJDK 25)Yes (HTML5)W M L A i Web Cons
O3DEApache-2.0 default, MIT at your option2605.0 · 2026-05-279,73412026-10-09partial heavy editor/project structurepartial / UNVERIFIEDnoneW L
FlaxFlax Engine EULA — source-available, not OSI-libreUpdate 1.12.6912 · 2026-05-187,04512026-10-08partial editor-centricUNVERIFIEDnone officialW M L
StrideMIT4.3.0.2507 (NuGet 2025-11-16); 4.4.0-beta9 2026-10-04; Launcher 6.0.4 2026-10-067,85010 (incl. betas)2026-10-09partial C#, editor + .slnUNVERIFIEDnone officialW M L A i
FyroxMIT1.0.1 · 2026-03-289,57702026-10-08partialUNVERIFIEDnoneW M L
Unreal EngineProprietary Epic EULA; source-available on request; not OSI-libre5.8 (Epic docs page HTTP 200 on 2026-10-09; exact date UNVERIFIED)n/a — repo 404n/an/apartial binary .uassetcommandlet UNVERIFIEDrare/communityW M L Cons
Panda3DNOASSERTION — UNVERIFIEDSDK 1.10.16 · 2025-12-255,24402026-07-28yes (Python)UNVERIFIEDnoneW M L
libGDXApache-2.01.14.2 · 2026-06-0525,43732026-10-06yes (Java/Kotlin)UNVERIFIEDYes (GWT/TeaVM)W M L A i Web
Cocos CreatorMIT3.8.8 · 2025-12-169,85102026-10-08partialUNVERIFIEDYesW M L A i Web
Redot (Godot fork)MIT26.3-rc.3 · 2026-10-08; Redot LTS 26.2 2026-07-016,12652026-10-09yes Godot-compatibleyes (Godot flags)YesW M L A i Web
raylibZlib6.0 · 2026-04-2335,06912026-10-09yes (C)no first-party flag foundYes (WASM)W M L A i Web
LÖVEzlib (own code; third-party components bundled)11.5 · 2024-04-258,80802026-09-20yes (Lua)no first-party flag foundvia love.js (3rd-party)W M L A i
MonoGameMS-PL3.8.6 · 2026-10-0814,50082026-10-07yes MGCB CLI content pipelineUNVERIFIEDno official browser target foundW M L A i Cons
FNAMS-PL (stated in README; no root LICENSE on master)26.10 · 2026-10-013,05162026-10-07yes (C#)UNVERIFIEDno (web dropped)W M L Cons
MacroquadMIT OR Apache-2.00.4.16 · 2026-07-304,65422026-08-18yes (Rust)UNVERIFIEDWASM (miniquad)W M L Web
EbitenApache-2.0v2.10.4 · 2026-09-2513,54752026-10-08yes (Go)CI test workflow exists; mechanism UNVERIFIEDWASM/Web (official)W M L A i Web Cons
PyxelMIT2.9.9 · 2026-08-1218,418112026-10-08yes (Python ≥3.11)UNVERIFIEDWASM/WebW M L Web
LittleJSMIT1.27.0 · 2026-10-094,19952026-10-09yes (JS)browser/jsdom; headlessMode confirmed in source, logic onlyWebWeb
SFMLZlib3.1.0 · 2026-04-2312,06012026-10-06yes (C++)UNVERIFIEDnoneW M L A i
HeapsMIT2.1.1 · 2025-06-073,50602026-10-09yes (Haxe)UNVERIFIEDYesW M L Web Cons
HaxeFlixelMIT6.2.0 · 2026-07-202,21312026-08-23yes (Haxe)UNVERIFIEDYesW M L Web
OpenFLMIT9.5.2 · 2026-05-132,16312026-10-01yes (Haxe)UNVERIFIEDYesW M L Web
PixiJS (baseline)MIT8.22.0 · 2026-10-01 ← pin is current48,3167 stable / 101 tags2026-10-09yes no editor existspixels in Node via its own CanvasRenderer (verified in §05); no first-party headless tool thoughWeb (native)Web
Three.jsMIT0.186.1 · 2026-09-24 (tag r186)116,16352026-10-09yesWebGPU/WebGL in Node — UNVERIFIED here, resolved empirically in §04Web (native)Web
Babylon.jsApache-2.09.30.0 · 2026-10-0826,14457 npm stable2026-10-09yesUNVERIFIED here, verified PASS in §04Web (native)Web
PlayCanvasMIT (engine); Editor cloud is proprietary SaaSengine 2.23.1 · 2026-10-07; react 0.11.7 2026-09-25; web-components 0.28.0 2026-10-0416,99732 stable2026-10-09yes editor optionalUNVERIFIED here, resolved in §04Web (native)Web
PhaserMIT4.2.1 · 2026-07-0940,43542026-08-21yeslogic only Phaser.HEADLESS verified → renderer = null, no pixels (§05)Web (native)Web
melonJSMIT20.8.0 · 2026-10-066,40522 stable2026-10-07yespixels in Node verified via its CanvasRenderer (§05)WebGPU, WebGL2 or Canvas2D with auto-fallback; ~250 KB minzipped; 0 depsWeb
ExcaliburBSD-2-Clause0.32.0 · 2025-12-232,3510 stable / 57 prereleases2026-10-05yesUNVERIFIEDWeb (native)Web
KaplayMIT3001.0.19 · 2025-06-151,8100 stable / 1 tag2026-10-04yes "game library"UNVERIFIEDWeb (native)Web
RapierApache-2.0Rust 0.36.0 · 2026-09-25; @dimforge/rapier2d 0.21.0 · 2026-09-255,83110 feed / 7 crates2026-10-06yes (library)n/aWASMall
Box2DMIT3.1.1 · 2025-08-0710,40502026-10-09yes (library)n/abox2d-wasm 7.0.0 @ 2021-11-28 → dead; use planck.jsall
planck.js (Box2D port)MIT1.5.0 · 2026-04-075,29312026-09-22yes (library)browser; explicit world.step(dt)WebWeb
matter-jsMIT0.20.0 · 2024-06-23 (stable line stale; tags are alphas)18,4460 stable2026-09-30yes (library)browser/jsdomWebWeb
JoltMIT5.6.0 · 2026-07-1111,68212026-10-08yes (C++)n/avia bindingsall

Adoption signals (last-month totals, fetched 2026-10-09)

three 78,674,917 · pixi.js 5,061,531 · phaser 1,754,552 · @babylonjs/core 1,623,073 · matter-js 1,343,879 · planck 722,224 · playcanvas 373,587 · @dimforge/rapier2d 88,746 · excalibur 39,522 · kaplay 33,800 · melonjs 7,071  // crates: bevy 7,878,259 total / 1,648,461 recent · fyrox 73,732 / 5,453 (tiny ecosystem)

The same packages on a last-week window (the basis 07-improve-2d.md used, so the numbers are not comparable to the month totals above): pixi.js 1,348,473 · phaser 479,112 · melonjs 1,652 · littlejs 3,299 · excalibur 11,558 · kaplay 9,312 · planck 204,123 · @dimforge/rapier2d 22,754 · matter-js 298,169 · bitecs 13,953 · pixi-filters 100,917 · @pixi/ui 21,143 · @pixi/sound 28,946 · @pixi/tilemap 5,468 · @napi-rs/canvas 28,876,913 · playwright 109,567,471. 07-improve-2d.md §2, §3

Install weight (npm dist.unpackedSize — a proxy for install weight and tree-shaking surface, not the runtime payload): phaser 107.3 MiB/3,593 files (112.5 MB on the 07 probe) · playcanvas 85.9 MiB/5,089 · pixi.js 72.7 MiB/3,745/10 deps (76.3 MB on the 07 probe) · @babylonjs/core 68.4 MiB/10,037 · three 19.5 MiB/1,263/0 deps · melonjs 9.0 MiB/650/0 deps (9.46 MB on the 07 probe). 02-engines.md §2 07-improve-2d.md §3

Ranked for an agent-driven build pipeline

Rubric from 02-engines.md §3: Text-only authoring [3] · Headless determinism [3] · Iteration latency [2] · 2D-action richness [2] · Performance [1] · Export breadth [1] · Maintenance evidence [2] · Docs for LLMs [1] → % of 75. Ties broken by text-only, then headless. The scores are the note author's judgement, each paired with the fetched evidence that moved it — the weights are stated so they can be re-weighted.

Top 10 of 21 scored. Unreal is deliberately unscored in the source note (licence, source access and headless commandlet behaviour were all unfetchable from the sandbox).
#EngineScoreWhat earned the score, and what docked it
1Godot 4.7.288.0.tscn verified plain text; --headless verified; 6 releases/6mo; 118k★; MIT. Docked: headless creates no rendering device; .import needs a pass; editor-centric ecosystem.
2Bevy 0.20.085.3Zero GUI ever; first-party headless.rs and headless_renderer.rs; asset hot-reload. Docked: compile-latency tax per agent cycle; API churn hurts LLM accuracy.
3Phaser 4.2.185.3Node-native, MIT, 1.75 M dl/mo, huge LLM corpus, complete 2D action set. Docked: headless unverified for v4 — later resolved by 07-improve-2d.md, which verified Phaser.HEADLESS boots logic only, no pixels; slowest push of the active web engines; Canvas/WebGL only.
4PixiJS 8.22.0 (baseline)84.0No editor exists at all; 7 stable releases in 6 months; README: "WebGL & WebGPU Renderers"; the repo already proves text-only + headless-Node. Docked: it is a renderer — physics/UI/scene plumbing is the agent's job, a gap 07-improve-2d.md prices at 3 load-bearing packages.
5melonJS 20.8.084.0WebGPU/WebGL2/Canvas2D auto-fallback, ~250 KB, zero deps, 22 stable releases/6mo; Node pixels verified in §05. Docked: 1,652 dl/week → thin corpus.
6Ebiten v2.10.484.0Go: fast builds, single static binary, 5 releases/6mo, official WASM/desktop/mobile. Headless capped at 4 pending verification of the exact mechanism.
7Babylon.js 9.30.082.7Apache-2.0, 57 stable npm releases in 6 months, webgpuEngine.ts present, batteries included, excellent docs — the most engine-like web 3D option, confirmed empirically in §04.
8Three.js 0.186.181.378.7 M dl/mo, 0 runtime deps, 20 MiB package, R3F 9.8.1 + drei 10.7.9. Docked: renderer-not-engine; 2D action work is all custom; WebGL path dead in Node (§04).
9MonoGame 3.8.677.3C#/MS-PL, 8 releases/6mo, CLI content pipeline (MGCB). Docked: MS-PL is OSI-approved but non-standard; no official browser target found.
10Excalibur 0.32.076.0BSD-2-Clause, TS-first, pleasant API. Docked hard on cadence: 0 stable releases in 6 months, 57 prerelease tags.

Per-scenario picks (verbatim from the source note)

dead / licence traps
  • Archived: Amethyst (2021-12-06), Urho3D (2023-01-25), Atomic Game Engine (2024-03-17).
  • Dead releases: Torque3D (2018-04-05), cannon.js (2023-08-04) and successor cannon-es (0.20.0 @ 2022-08-12), box2d-wasm (7.0.0 @ 2021-11-28), matter-js stable line (0.20.0 @ 2024-06-23), miniplex (2.0.0 @ 2023-07-16, no publish in ~3 years), @pixi/spine-pixi (2.1.1 @ 2024-09-24, 573 dl/wk — not recommended).
  • Licence traps: Unreal (proprietary EULA, public API 404 for EpicGames/UnrealEngine), Flax (LICENSE.md is an EULA at flaxengine.com/licensing), Defold (custom, non-OSI), MonoGame/FNA (MS-PL; FNA also inherits an LGPL-dual LzxDecoder.cs), olcPixelGameEngine ("OLC-3", GitHub reports "Other"), GDevelop (MIT core but GUI/event-sheet-centric), OpenRA/Descent3/OpenJK (GPL copyleft), and bitecs (MPL-2.0 — file-level copyleft, fine to consume, note it if you vendor it).
  • Version-line traps: Stride publishes engine, launcher (6.0.4) and samples (4.4.3) as separate releases, so the Atom feed's "latest" is often not the engine; Excalibur and Kaplay publish dozens of prereleases while the stable channel stalls, and npm latest disagrees with GitHub's "latest release" in both cases.
02-engines.md §5 07-improve-2d.md §2

04The 3D verdict in detail

This is the one layer where the proposal is wrong, and it is wrong for a reason that never appears in a feature matrix. The note's verdict (§0): "PlayCanvas is not the 3D layer for an agent-driven game-building pipeline… Choose Babylon.js 9.30.0 as the 3D engine (Apache-2.0, batteries included, NullEngine + Havok + glTF all verified working in Node with no GPU, official MCP authoring servers, ships its own TypeScript types) with Three.js 0.186.1 as the renderer-first alternative." 08-improve-3d.md

The PlayCanvas Editor licensing / ToS finding

the blocking finding

playcanvas.com/terms (last updated 2024-05-15), §4 "Your Account": "You will not register any accounts by non-humans, 'bots' or other automated methods as such methods are expressly prohibited." §2 grants only "a personal, worldwide, non-assignable, non-exclusive, non-sublicenseable, and revocable license to access and use the Services", and §3 grants PlayCanvas a broad IP licence over content you make publicly available on the Services. Text extracted live from the page.

Why this bites: the engine is MIT, the editor frontend repo is MIT, but the parts a build agent most needs — project storage, asset import/transcode, scene/prefab authoring, version control, publishing/hosting and the REST API — exist only on the proprietary cloud ("A project lives in the Editor"). The engine-standalone path is first-party documented and legal; it just means the agent must rebuild the asset pipeline, scene authoring and hosting itself.

08-improve-3d.md §1 · playcanvas.com/terms · engine/standalone docs

Agent tooling exists but is editor- or session-bound: @playcanvas/[email protected] (2026-09-09) needs "an open Editor session"; third-party [email protected] (2026-10-01) drives the REST API and needs PLAYCANVAS_ACCESS_TOKEN, i.e. a real account. MIT-editor optics are the trap here: nothing is a licence trap for the code; the trap is a service contract. 08-improve-3d.md §1, §7

Empirical headless results (all three engines booted in Node, no GPU)

The note author installed all three engines in a scratch directory (%TEMP%\gg3d, Node v24.21.0) and ran them. Raw run outputs: research/tavily/3d-harness-results.json.

Ranking for "how completely an agent can TEST what it built without a GPU". Nothing below is from memory.
EngineInstallable headless deviceVerified resultWhat it does not verify
Babylon.js 9.30.0 NullEngine (present at @babylonjs/core/Engines/nullEngine.d.ts; docs since v3.1: "does not require a WebGL-capable device"; Node needs global.XMLHttpRequest = require("xhr2").XMLHttpRequest) PASS NullEngine scene, 60 × scene.render() at fps 60, no GPU.
PASS Havok physics headless: HavokPhysics({wasmBinary}) + PhysicsAggregate → box fell y 0.000 → −0.159.
PASS glTF headless: ImportMeshAsync(DamagedHelmet.gltf) with xhr2 → 2 meshes, 14,359 verts, 6 textures.
Pixels — docs: "does not produce any rendering". Pixels come from a headless browser pass.
Three.js 0.186.1 No scene harness at all; WebGLRenderer needs WebGL2, so headless-gl cannot help (source throws THREE.WebGLRenderer: WebGL 1 is not supported since r163 and only ever requests webgl2). gl latest stable 8.1.6 (2024-10-29); 9.0.0-rc.10 (2026-04-10) is still WebGL1-only. Installing gl here failed (node-gyp: no Visual Studio). DEAD in Node new WebGLRenderer() → Error creating WebGL context.
PASS when shimmed WebGPURenderer with [email protected] (Dawn: requestAdapter()→ADAPTER OK, requestDevice()→DEVICE OK on this machine), navigator.gpu, globalThis.self = {requestAnimationFrame,…} (three's Animation.js reads typeof self) and a canvas stub that fabricates its texture from three's own device → init()+render()+submit completed (backend=WebGPUBackend). Loaders additionally need DOM shims (ProgressEvent is not defined).
Anything you don't shim yourself; there is no NullEngine-style facilities/logic harness.
PlayCanvas 2.23.1 NullGraphicsDevice + DEVICETYPE_NULL + NullPhysicsWorld ship in the engine; the null-device source comment reads "nothing is rendered, so headless environments such as Node.js can omit the canvas". Docs: "The PlayCanvas Engine fully supports running in Node.js… runs its own unit tests using Node.js." PASS (logic) NullGraphicsDevice app, 30 × app.update(1/60), ESM Script.update ran.
PASS (GPU) only with scaffolding createGraphicsDevice(canvas,{deviceTypes:['webgpu:bare']}) without DOM → window is not defined; with jsdom + [email protected] → deviceType=webgpu and app.update() ran with Render/Camera/Light systems.
Physics and asset-registry loading: register Ammo yourself via WasmModule.setConfig('Ammo',…) and use jsdom for XHR-based asset loading. The company's own rule for agents: "Run the app to verify. Rendering, input and physics can only be confirmed in a browser."

Headless ranking: 1) Babylon (scene graph + animation + physics + glTF asset validation, one documented xhr2 polyfill, no DOM) → 2) Three (no logic harness; real offscreen WebGPU rendering is now achievable but only with hand-written self/canvas/device shims; the WebGL path is dead in Node) → 3) PlayCanvas (good logic harness, but asset loading needs jsdom and physics needs a wasm you supply, and its own docs disclaim browser-free rendering). For pixels, all three converge on the same answer: a headless browser pass (Playwright/Chrome) — identical work for all three. 08-improve-3d.md §2

Babylon.js vs Three.js vs PlayCanvas on the rest

Fetch date 2026-10-09 for every cell. "First-party" = shipped by the engine, not assembled by the agent.
PlayCanvas 2.23.1Babylon.js 9.30.0 (+ Lite 1.33.0)Three.js 0.186.1
LicenceMIT engine + MIT editor frontend; cloud/Editor SaaS proprietary, bot accounts prohibited (playcanvas.com/terms §4)Apache-2.0 (@babylonjs/core); @babylonjs/havok MIT; Babylon Lite Apache-2.0MIT, 0 runtime deps
Latest + dateengine 2.23.1 @ 2026-10-07; React 0.11.7 @ 2026-09-25; web-components 0.28.0 @ 2026-10-04core 9.30.0 @ 2026-10-08 (58 npm releases in 6 months); Lite 1.33.0 @ 2026-10-050.186.1 @ 2026-09-24
Adoption (last week npm)playcanvas 88,194 · react 6,684 · web-components 1,294core 350,575 · loaders 205,664 · gui 67,449 · havok 23,882 · Lite 2,305three 20,100,280 · R3F 5,915,275 · drei 4,180,583 · @types/three 12,885,346
Package weight (unpacked)90.1 MB / 5,089 files / 2 depscore 71.7 MB / 10,037 files / 0 deps; Lite 45.3 MB / 0 deps20.4 MB / 0 deps
TypeScript typesships own (build/playcanvas.d.ts)ships own (index.d.ts)not bundled → @types/[email protected] (DefinitelyTyped)
Headless logic testsNullGraphicsDevice, app.update(dt) — verifiedNullEngine — verified, incl. physics + glTFnone built-in
Physicsbring ammo.jsHavok (@babylonjs/havok 1.3.14, MIT) + cannon/ammo plugins; verified headlessbring @dimforge/rapier3d-compat 0.21.0 (10.4 M/week) or cannon-es (stale, 2022-08-12)
Animation / retargetstate-graph assets; no retarget/IK symbols in the engine d.tskeyframe + skeletal + morph + Bones/boneIKController; official Animation Retargeting page/toolSkeletonUtils.retargetClip() in official addons
GUI / UIElementComponent/ScreenComponent in engine; PCUI 6.1.4 for tools@babylonjs/gui 9.30.0 + GUI-editor MCP servernone official (three-mesh-ui 6.5.4 last published 2023-03-24)
Navigation / AInone in engine; third-party @recast-navigation/playcanvas 0.43.1Navigation/* + RecastJS plugin in corethird-party @recast-navigation/three 0.43.1
WebGPUWebGL2 default, WebGPU opt-in + auto-fallbackfull WebGPU engine; cannot switch WebGPU⇆WebGL after scene creation; Lite is WebGPU-exclusiveWebGPURenderer falls back to WebGL2; TSL
Agent-facing docs / MCPllms.txt "entry point for AI agents", llms-full.txt 3.03 MB, Skills, Editor MCP server (needs an open editor session)llms.txt 4.3 KB index, sitemap 4,747 doc pages, official @babylonjs/[email protected]: 7 headless graph-authoring MCP servers runnable via npxllms.txt + docs/llms-full.txt 363 KB; community [email protected]
API stability evidence32 stable releases/6mo plus Engine 1→2 API breaks ("Code written for Engine 1 often breaks in Engine 2")58 npm releases in 6 months on the 9.x line, backward-compatible5 r-releases/6mo, a documented migration guide each time

Start-from-here package set (Babylon)

All fetched 2026-10-09. Keep the headless scene harness as the first commit, mirroring this repo's tools/ habit.
PackageVersionDateLicenceWhy
@babylonjs/core9.30.02026-10-08Apache-2.0engine + NullEngine
@babylonjs/loaders9.30.02026-10-08Apache-2.0glTF/OBJ/STL — headless asset validation
@babylonjs/materials9.30.02026-10-08Apache-2.0sky, grid, decals
@babylonjs/gui9.30.02026-10-08Apache-2.0HUD/UI without DOM
@babylonjs/havok1.3.142026-07-29MITphysics, verified working under NullEngine
@babylonjs/addons9.30.02026-10-08Apache-2.0navigation/RecastJS plumbing
xhr2latest—MITthe documented Node shim for glTF loading
@babylonjs/inspector9.30.02026-10-08Apache-2.0dev-only debug in the browser
@babylonjs/mcp-servers9.30.02026-10-08Apache-2.0optional: graph-authoring MCP servers for the agent
vite + vitestcurrent—MITbrowser build + unit harness
playwrightcurrent—Apache-2.0the only way to verify pixels headlessly
// tools/scene.mjs - prove the loop before any graphics work (from 08-improve-3d.md §6)
// npm i @babylonjs/[email protected] @babylonjs/[email protected] @babylonjs/[email protected] xhr2
import * as B from '@babylonjs/core';
import '@babylonjs/loaders';
import HavokPhysics from '@babylonjs/havok';
import xhr2 from 'xhr2';
import fs from 'node:fs';
import assert from 'node:assert';
globalThis.XMLHttpRequest = xhr2.XMLHttpRequest;      // documented Node requirement

export async function boot({ glb } = {}) {
  const engine = new B.NullEngine();                   // no GPU, no DOM
  const scene = new B.Scene(engine);
  const ground = B.MeshBuilder.CreateGround('ground', { width: 20, height: 20 }, scene);
  const box = B.MeshBuilder.CreateBox('box', { size: 1 }, scene);
  box.position.y = 4;

  const havok = await HavokPhysics({                                            // pass the wasm,
    wasmBinary: fs.readFileSync('node_modules/@babylonjs/havok/lib/esm/HavokPhysics.wasm') // not fetch()
  });
  scene.enablePhysics(new B.Vector3(0, -9.81, 0), new B.HavokPlugin(true, havok));
  new B.PhysicsAggregate(box, B.PhysicsShapeType.BOX, { mass: 1 }, scene);
  new B.PhysicsAggregate(ground, B.PhysicsShapeType.BOX, { mass: 0 }, scene);

  if (glb) await B.ImportMeshAsync(glb, scene);                                 // asset smoke test
  return { engine, scene, box };
}

export async function step(scene, frames = 120, dt = 1 / 60) {
  const zero = scene.getEngine().getDeltaTime();
  for (let i = 0; i < frames; i++) scene.render();                              // deterministic ticks
  return zero;
}

if (import.meta.url === `file://${process.argv[1].replace(/\\/g, '/')}`) {
  const { scene, box } = await boot();
  const y0 = box.position.y;
  await step(scene);
  assert.ok(box.position.y < y0, 'gravity did not apply');                     // logic assertion
  console.log('OK headless: y', y0.toFixed(2), '->', box.position.y.toFixed(2));
}

Then, in order: (1) this harness + npm test; (2) a Playwright spec that boots the same scene in Chromium and screenshots it (the pixel gate); (3) one glTF from the Khronos sample set as the asset smoke test; (4) only after that, gameplay. Keep assets out of git or use LFS — the zero-external-asset discipline of the 2D project does not survive 3D. 08-improve-3d.md §6

biggest remaining risk in 3D Every web candidate still needs a browser pass for pixels. If CI has no GPU and no headless browser, no web 3D engine can be pixel-verified, and Babylon's webgpu-in-Node trick depends on the runner exposing a Dawn adapter (it worked on this machine, unproven elsewhere). Desktop-first 3D should leave the browser entirely: Godot 4.7.2 (MIT) then Bevy 0.20.0. 08-improve-3d.md §8, §9

05The 2D verdict in detail, with the add-on stack

verdict (fetched, not synthesised) "Keep PixiJS 8.22.0 as the 2D renderer, and close every battery gap with a named MIT stack (planck/@dimforge/rapier2d, bitecs, @pixi/tilemap, @pixi/ui, @pixi/sound, pixi-filters) plus a real verification layer (pixelmatch + playwright + jsdom+@napi-rs/canvas)." The deciding evidence: PixiJS is the only candidate empirically proved to render headlessly both in a GPU-free browser (WebGL2 via ANGLE/SwiftShader) and in pure Node (its built-in Canvas2D CanvasRenderer on @napi-rs/canvas, no compiler). A swap to Phaser or melonJS is only better greenfield; here it rewrites essentially 100 % of src/ for no capability this stack does not already supply. 07-improve-2d.md §0

1. The decisive new finding: PixiJS v8 renders pixels in pure Node

The common assumption — "PixiJS v8 is WebGL2-only, so headless pixels need a browser or a compiled gl" — is false. PixiJS v8 ships a real CanvasRenderer (type: RendererType.CANVAS), its autoDetectRenderer order is webgpu | webgl | canvas and it will drop to Canvas2D; GlContextSystem tries getContext("webgl2") then falls back to getContext("webgl") (v8 supports WebGL1). Driving the canvas path with jsdom + @napi-rs/canvas produces engine-drawn pixels in plain Node with zero native build. 07-improve-2d.md §1.1 (row I), §1.2

2. What was actually executed (verbatim results in research/tavily/2d-harness-results.json)

Every row is something the note author ran on this machine, Node v24.21.0, on 2026-10-09.
#PathHowResult
D PixiJS 8.22.0 in headless Chrome + SwANGLE --headless=new --disable-gpu --enable-unsafe-swiftshader --use-gl=angle --use-angle=swiftshader --virtual-time-budget=15000 --dump-dom PASS In-page pixel probe returned {"rendererName":"webgl","isWebGL2":true,"glVersion":"WebGL 2.0 (OpenGL ES 3.0 Chromium)","pixelsTotal":173900,"nonBg":59644,"distinctColors":3,"ok":true}; --screenshot PNG written (7,314 bytes).
E PixiJS 8.22.0 in pure Node built-in CanvasRenderer + jsdom + @napi-rs/canvas PASS PIXI node renderer = canvas | type = 4 | ctor = CanvasRenderer → {"nonBg":9600,"distinctColors":2} (exactly the 120×80 rect). No GPU, no compiler, no gl.
A @pixi/node WebGL-in-Node npm i @pixi/[email protected] FAIL Pulls native gl, which has no Node-24/win32 prebuild and fell back to node-gyp → Could not find any Visual Studio installation to use.
B/C @napi-rs/canvas as a WebGL substitute / bare pixi.js in Node node test-node.mjs getContext("webgl2") THREW: webgl2 is not supported; getContext("webgl") THREW: webgl is not supported; importing pixi.js without a DOM → ReferenceError: document is not defined.
F melonJS 20.8.0 in pure Node CanvasRenderer + jsdom + @napi-rs/canvas PASS (Canvas2D) engine-drawn ColorLayer filled the buffer → {"renderer":"CanvasRenderer","nonBg":480000,"distinctColors":1} (all 800×600 px). Caveat: a Text renderable then threw a node-canvas drawImage type error (UNVERIFIED fix).
G Phaser 4.2.1 in pure Node new Phaser.Game({type: Phaser.HEADLESS}) PARTIAL import needs Element/screen globals shimmed; the game boots (HEADLESS=3 | CANVAS=1 | WEBGL=2 | AUTO=0) but renderer = null → no pixels, logic only.
H LittleJS 1.27.0 grep of littlejs.esm.js Ships a headlessMode that returns before setup and drawFrame() → logic harness, no pixels.
I PixiJS v8 renderer inventory grep of vendor/pixi.mjs autoDetectRenderer order webgpu | webgl | canvas; webgl2 → webgl fallback; the Canvas2D renderer prints CanvasRenderer: filter "X" is not supported in Canvas2D and will be skipped.

3. Per-candidate headless verdict

The differentiator is the Node column: it decides whether an agent gets pixel readback in CI with no GPU and no browser.
CandidatePixels in browser (software GPU)Pixels in Node (no browser, no compiler)Logic in Node
PixiJS 8.22.0yes — verified (D)yes — verified (E) via its own CanvasRenderer; WebGL-in-Node needs gl and failed here (A)trivial (it is a library; the ticker is yours)
Phaser 4.2.1yes (same Chrome recipe)no first-party path; canvas renderer exists but Node boot is brittle (needs Element/screen)yes — Phaser.HEADLESS verified (G)
melonJS 20.8.0yes (same Chrome recipe)yes — verified (F) CanvasRenderer (engine's own AUTO falls to Canvas when no WebGL)yes
LittleJS 1.27.0yes (4 K-line engine, Canvas2D/WebGL)likely (it has a Canvas2D path) — UNVERIFIEDyes (headlessMode, H)
Excalibur 0.32.0 / Kaplay 3001.0.19yes (Canvas2D/WebGL)UNVERIFIEDUNVERIFIED
Godot 4.7.2 (web) / Bevy 0.20.0 (WASM) / Defold 1.13.2 (HTML5)WebGL2-only export / WebGL2+WebGPU / HTML5 exportn/a — native toolchains--headless --script / headless.rs+headless_renderer.rs / dmengine_headless

4. The add-on stack: package + version + licence + what it closes

PixiJS is a renderer: everything below is code the agent must otherwise write and verify. Three packages are load-bearing — planck (or rapier2d), bitecs, and the verification pair around pixelmatch. 07-improve-2d.md §2, §6

Versions, licences, unpacked sizes and last-week downloads all fetched 2026-10-09.
Gap the agent must hand-writePackage that closes itVersion (published)LicenceUnpacked / deps / dl last-wkMaintenance reality
Physics + collisionsplanck (Box2D 2.3 port, pure JS)1.5.0 (2026-04-07)MIT9.09 MB / 0 / 204,123active; engines.node ≥24; explicit world.step(dt) — a fixed-timestep-friendly engine
″ performance alternative@dimforge/rapier2d (Rust→WASM)0.21.0 (2026-09-25)Apache-2.04.10 MB / 0 / 22,754active; async WASM init; float determinism across platforms is not guaranteed — pin it
″ avoidmatter-js0.20.0 (2024-06-23)MIT0.93 MB / 0 / 298,169stable line stale; repo tags are alphas
ECS / scene lifecyclebitecs (data-oriented, typed arrays)0.4.0 (2025-12-06)MPL-2.01.75 MB / 0 / 13,953active; file-level copyleft — fine to consume, note it if you vendor it
″ alternativeminiplex2.0.0 (2023-07-16)MIT0.11 MB / 3 / 7,946stale — no publish in ~3 years
Tilemaps / Tiled@pixi/tilemap (renders; parser is yours)5.0.2 (2025-07-14)MIT0.52 MB / 0 / 5,468active; peer pixi.js ≥8.5
UI (in-canvas)@pixi/ui2.4.1 (2026-10-01)MIT2.75 MB / 1 / 21,143active; peer pixi.js ^8.6.2
″ DOM UI — already chosen herenone needed — #ui-root + overlay.css——0DOM UI is more accessible, keyboard-reachable and directly assertable via --dump-dom
Audio plumbing@pixi/sound (WebAudio + filters)6.0.1 (2024-07-27)MIT1.04 MB / 0 / 28,946maintained but quiet; this repo synthesises audio, so mostly redundant
Filters / post-FXpixi-filters (bloom, glow, CRT, shockwave…)6.1.5 (2025-11-29)MIT2.69 MB / 1 / 100,917active; BlurFilter is already built into pixi.js
Input mapping / save-loadno package — Pixi events + localStorage——0src/core/input.js (417 lines) and src/core/save.js (318 lines) already exist
Sprite / skeletal helpers@pixi/spine-pixi2.1.1 (2024-09-24)MIT1.47 MB / 1 / 573stale & near-unused — not recommended; procedural Graphics + generateTexture needs no package
Node-side headless pixelsjsdom + @napi-rs/canvas1.0.10 (2026-10-01)MIT / MITprebuilt / — / 28,876,913prebuilt, no compiler — verified working here
Visual regression + input injectionpixelmatch + playwright8.0.0 (2026-10-06) / 1.64.0 (2026-10-07)ISC / Apache-2.0tiny / 5.03 MB / 109,567,471from 05-qa-harness.md; pixelmatch is pure ESM and drops straight into the existing tools

What the agent still owns after this stack (and why that is acceptable): the game simulation (steering AI, wave budget, upgrade rarity/clash rules, projectile pooling, XP curve) — that is the actual depth of a roguelite and no engine hands it over; Tiled/TMX parsing (@pixi/tilemap renders, it does not parse); determinism discipline; and netcode (out of scope, single-player). 07-improve-2d.md §6

5. The alternatives, priced as decisions

6. Migration cost from this repo, with real counts

Measured over src/** on 2026-10-09: 07-improve-2d.md §5

LOC by group, and the swap-vs-stay decision.
GroupFilesLOCSwap → PhaserSwap → melonJSStay on PixiJS + stack
src/main.js1631/11/10
src/core/**134,21313/1313/130
src/game/**125,05112/1212/120
src/ui/**52,1415/55/50
src/dev/fxlab.js15931/11/10
Total3212,06132/32 files, ~12,061 LOC32/32 files, ~12,061 LOC~6–10 files touched, 0 rewritten; ~600–1,200 new lines for physics/ECS adapters

Pure-renderer-bound code that must be re-authored in any other framework's drawing model — core/textures.js 181 + core/textures/shapes.js 410 + core/particles.js 660 + core/postfx.js 331 + core/camera.js 311 + ui/rendering.js 492 + ui/hud.js 512 + ui/dom-ui.js 437 + ui/dom-panels.js 266 + ui/overlay.css 434 + dev/fxlab.js 593 = ~4,627 LOC (38 %) — and that is a lower bound, because every entity's view/layer wiring inside src/game/** is written against Pixi Container/Sprite/Graphics. A swap would also invalidate tools/check.mjs's import-map and "no PixiJS-v7 API" checks, rewrite docs/SPEC.md §(b)(e)(f), and replace the index.html import map. 07-improve-2d.md §5

7. Determinism fit, and what this stack does not solve

Does the recommendation preserve seeded-RNG headless reproducibility? Yes — and that is the strongest structural argument for the verdict.
Not solvedFatal?Honest position
No first-party Tiled/TMX parserNo@pixi/tilemap renders; parsing is ~200 lines or Tiled's JSON export. This repo bakes its own grid and needs none.
No first-party physics / ECS / netcodeNoplanck + bitecs close physics/ECS; netcode is out of scope.
The Canvas2D Node path skips filters & masksNo for CI; yes if you expect bloom in a Node screenshotKeep the browser SwANGLE pass as the polished-look gate (verified, D); use the Node path for fast layout/HUD assertions.
WebGL-in-Node needs a compiled glNoUse the browser for the WebGL path; the Node path uses Canvas2D. Do not adopt @pixi/node in CI.
No GPU frame-time gateNot solvable by any web engine headlessAlready proven in 05-qa-harness.md; claim only JS/heap via Performance.getMetrics.
Ambient RNG draws in render codeNo (already guarded)tools/check.mjs bans Math.random(); extend the ban to src/core/** per 05-qa-harness.md.

Why determinism survives: PixiJS is only the renderer; the simulation stays the repo's own 60 Hz fixed-step loop over world.rng. Adding planck (explicit world.step(dt), no hidden clock) or bitecs (entity ids and iteration order are explicit arrays, not hash-map order) strengthens reproducibility rather than endangering it — provided RNG draws stay inside the sim and out of render. Costs: a physics engine adds a float path (planck is deterministic per build for the same step sequence; rapier2d's WASM floats are not guaranteed bit-identical across platforms, so pin it and keep gameplay RNG out of it); and the Node-canvas pixel path validates layout/geometry/HUD placement, not the bloom look. The recommended stack adds no build step and every package is either 0-dep or prebuilt, so the repo's "no bundler, no transpiler, import map" identity survives — with a vendor/-style copy per package, exactly as it already does for pixi.js. 07-improve-2d.md §7, §8

06Verification harness — the layered recommendation

Keep the three existing tools as the default npm test path and add layers around them, adding at most two dev-only dependencies. Layer order matters: each layer is cheap and fast, and a failure in an earlier layer invalidates the later ones. Layers 1–3 take seconds; 5–7 take minutes and belong on a schedule, not on every edit. 05-qa-harness.md §3

npm test
├─ 1  node --test tools/unit/            → pure logic: math, RNG, pool, waves, upgrades   [0 deps]
├─ 2  node tools/check.mjs               → static/policy/DOM/import contract              [0 deps]
├─ 3  node tools/smoke.mjs               → boot, schema, stateHash + rngDraws determinism [0 deps]
├─ 4  node tools/input.mjs               → real keyboard/mouse paths (NEW, dev-only dep)
├─ 5  node tools/shots.mjs               → content assertion + stability gate + diff     [+pixelmatch]
├─ 6  node tools/perf.mjs                → wall-clock frame pacing, heap, long tasks     [0 deps]
└─ 7  node tools/soak.mjs                → peak caps, pool return, heap growth           [0 deps]

engine-side pixel path (no browser, from 07-improve-2d.md)
└─    node tools/pixels.mjs              → PixiJS CanvasRenderer + jsdom + @napi-rs/canvas  [prebuilt]
single biggest flake risk Blank-canvas PNGs that still pass a file-size check. tools/shots.mjs asserts only that the PNG exists with non-zero size, that #fatal is still hidden and that data-game-state is not boot/shell. A fully black canvas, a blank white page, a wrong palette, a missing glow layer or an unrendered HUD all pass as long as Chrome wrote some bytes. shots.mjs is currently a capture tool, not a visual-regression tool. 05-qa-harness.md §1.3

The fix needs no baseline, no decoder and no new dependency: add a ?shotcheck=1 mode that draws the live canvas into a small 2D context, quantizes to a 16×16 grid, and writes {nonBackgroundRatio, distinctBuckets, gridHash} into #autotest-report. --dump-dom then yields a machine-readable assertion that the canvas is not blank, not one flat colour and not the wrong palette — exactly the bug class that passes today. Note that the 2D note's Node path uses the same idea natively: its probes returned {"nonBg":59644,"distinctColors":3,"ok":true} in the browser and {"nonBg":9600,"distinctColors":2} in Node, i.e. a content assertion with no baseline at all. 05-qa-harness.md §3 Layer 4 07-improve-2d.md §1.1

What the current suite catches today, from a full read of all three tools.
LayerExists?Catches todayMissing
Static / policyyes, strongsyntax, imports, determinism lint, DOM contractcurrently red (15 findings); the layer check is a substring heuristic
Unit / property (logic)no—everything: math, RNG, pool, waves, economy
Simulation determinismpartly4-field fingerprint (kills, wavesReached, playerLevel, upgradesTaken)full state hash, RNG draw count, replay artifact. A stray Math.random() in src/core/** — which check 5 does not scan — would not move any of the four fields
Input injectionno—keyboard/mouse paths, upgrade selection, pause/restart. Chrome is driven with --dump-dom only
Visual regressionnofile exists + DOM statebaseline diff, content assertion, masking, thresholds
Performanceno— (avgFrameMs/fps are virtual-clock deltas, correctly printed and never asserted)wall-clock pacing gate, heap, long tasks
Soak / leakno—peak-cap and heap-growth gates over minutes; the three peak counters are reported but never asserted

Anti-flake rules for canvas screenshots

  1. Pin the rasterizer, not just "headless". --use-gl=angle --use-angle=swiftshader + --disable-gpu + --enable-unsafe-swiftshader (Chromium's documented SwANGLE recipe). The repo already passes the last two — it is on the right side of this. SwiftShader's automatic fallback is deprecated; the opt-in flag is required. The 2D harness confirmed the full recipe works here (row D).
  2. Never compare across renderers. Baselines must carry the renderer + Chrome version in the name.
  3. Multi-pass capture. Capture twice back-to-back and require zero changed pixels (includeAA: false) before accepting either capture — the manual equivalent of Playwright's "wait until two consecutive screenshots yield the same result".
  4. Double-rAF before capture so the compositor has promoted the WebGL back buffer into the surface a screenshot reads; this replaces setTimeout(200) with a wait exactly as long as needed. In headless Chromium the timer-query/fence path is degenerate: SwiftShader's synchronous pipeline makes clientWaitSync report signalled immediately.
  5. Lock the frame state. Fixed window size, deviceScaleFactor: 1, scale: "css", --force-color-profile=srgb, fixed seed. Do not copy --disable-lcd-text/--font-render-hinting=none from the text-site case study — they are font-antialiasing flags and are irrelevant to a canvas.
  6. Mask or clip. Mask the HUD for arena shots and clip to regions, so one HUD change does not invalidate every baseline.
  7. Assert content before diffing (see the ?shotcheck=1 mode above, and the Node pixel probe).
  8. Thresholds are a sensitivity trade, not a fix. A threshold loose enough to absorb SwiftShader/ANGLE variance is also loose enough to hide a missing glow layer. Prefer deterministic rasterization + a tight threshold: start at threshold: 0.1 and a low-single-digit-percent maxDiffPixelRatio.
  9. Quarantine by renderer, not by retry. If a shot flakes, capture it on the renderer CI uses — retries hide the mutation.
  10. Do not add a WebKit project for the visual layer. There is an open Windows-WebKit bug (#42885, opened 2026-09-23) where page.screenshot() renders the page background where a WebGL canvas should be after setViewportSize() resizes the drawing buffer — Windows fails 5/5, macOS passes 5/5, with the GL context healthy and gl.readPixels() returning the correct colour. Chromium is the only browser where canvas capture is defensible today.

What is honestly not automatable headless

Real GPU frame time

EXT_disjoint_timer_query_webgl2 support is 65.52% overall, 81.21% Chrome, 0.01% Firefox, 0.23% Safari. In headless SwiftShader the fence query degenerates, and SwiftShader is a CPU rasterizer, so its frame times are not GPU frame times at all. A SwiftShader perf gate can prove "the JS didn't get slower"; it cannot prove "the game hits 60 fps on a real GPU".

"MCP browser agents can playtest your game"

Mostly no, for a canvas game. Playwright MCP's README states it "Uses Playwright's accessibility tree, not pixel-based input… operates purely on structured data". A <canvas> contributes essentially nothing to the a11y tree, so the tool most often pitched as "an agent that can use a browser" is structurally blind to the game. Chrome DevTools MCP can drive and screenshot, but no fetched doc makes a canvas/WebGL claim for it.

"Traces show you the canvas frames"

No — by Playwright's own admission: v1.50 — "Display of canvas content in traces is error-prone. Display is now disabled by default." v1.47 — "We've seen reports of WebGL in Webkit misbehaving on GitHub Actions macos-13."

"Autonomous playtesting agents are a solved OSS layer"

They are not, for browser games. LMGame Bench / GamingAgent (ICLR 2026, MIT, 987★) standardises on Gymnasium + emulators and its "UI-only Interface" is literally "Coming Soon!" in the README, last pushed 2025-11-16. Voyager last pushed 2024-04-03. mineflayer and poke-env are genuinely active — but for Minecraft and Pokémon Showdown, i.e. games with a programmatic API, not a WebGL canvas. TITAN (arXiv:2509.22170) reports 95% task completion on two commercial MMORPGs but no public code repository was found: treat it as a paper, not a tool.

Machine-readable artifacts — the self-correction affordance

05-qa-harness.md §3

state of the suite at the QA survey node tools/check.mjs returned FAIL, exit 1, 15 findings: four files over the 650-line cap (src/core/audio.js 732, src/core/particles.js 713, src/dev/fxlab.js 681, src/game/world.js 806) and eleven main.js "layer never referenced" findings; the producers src/dev/autotest.js and src/dev/autopilot.js are specified in docs/SPEC.md §(e) but absent, so smoke.mjs cannot pass yet. Get the suite green first — until then a green run carries no signal. The single highest signal-per-byte change is widening the Math.random() ban from src/game/** + src/ui/** to src/core/**. 05-qa-harness.md §1.1
Change since that observation: src/dev/fxlab.js was being split into src/dev/fxlab/{layout,selftests,sim}.js during the session that produced this page, which is consistent with the 650-line-cap findings being actively worked — so re-run check.mjs rather than quoting this count.

07MCP / tool-interop picks for this repo

finding 1 — "official MCP" now signals risk The 2025-era claim "no engine vendor ships an official MCP server" is false, and the official ones are the compromised ones: Unity's in-editor server (inside com.unity.ai.assistant) is deprecated in favour of its own CLI; Unreal's Unreal MCP plugin (UE 5.8) is Experimental with "many features incomplete or missing" and binds 127.0.0.1:8000/mcp with no authentication layer; Blender's Blender Lab server ships with the vendor's own warning that it "will execute LLM generated code in Blender without any guards" and the recommended mitigation is "use a virtual machine". The engine with the best agent story — Defold — deliberately declines to ship an MCP server at all, arguing it "would mostly duplicate the existing API surface". 03-mcp-interop.md §2, §Hype vs. reality
finding 2 — high-star servers are often dead Stars measure age, not health: Coding-Solo/godot-mcp 5,984★ is the most-starred Godot server and has been stale since 2026-04-16, while hi-godot/godot-ai at 2,871★ was pushed 2026-10-08. chongdashu/unreal-mcp 2,109★ has been dead since 2025-04-22. executeautomation/mcp-playwright ~5.7k★ is still the #1 tutorial hit and has been stale since 2025-12-13. And the canonical discovery list, punkpeye/awesome-mcp-servers (~96k★, updated daily), is spam-saturated: greps returned blocks of 0–30-star repos with identical badge boilerplate and off-topic domains. Use it to discover names, then verify each repo individually. 03-mcp-interop.md §4, §Hype vs. reality
finding 3 — the spec broke backwards compatibility in 2026-07-28 Revision 2026-07-28 (previous 2025-11-25) makes MCP stateless: the initialize/notifications/initialized handshake is removed (version and capabilities travel in _meta on every request), Mcp-Session-Id is deleted, server/discover is mandatory, ping/logging/setLevel/notifications/roots/list_changed are gone, every result must carry a resultType, and SSE resumability is removed. Consequence: "an MCP server" has not been a stable interface across the last 12 months, and any config written before ~Aug 2026 targets a superseded handshake — including Epic's own official Unreal MCP documentation, which still describes the removed initialize handshake. Pin versions and expect a migration. SDKs at the snapshot: TS @modelcontextprotocol/sdk 1.32.1 (2026-10-05), Python mcp 2.3.0 (2026-10-02). MCP is an AAIF (Linux Foundation) project, founded 2025-12-09. 03-mcp-interop.md §1

The picks for this repo

For NEON PURGE's constraints (no build step, no external assets, deterministic, headless tests), engine-editor MCP servers are irrelevant. The useful set is small.
#ServerVersion · dateLicence / starsWhy, and the caveat
1Chrome DevTools MCP1.10.1 · 2026-09-23
pushed 2026-10-08
Apache-2.0 · ~53k★Highest-value single install: console/network visibility plus performance traces over the real PixiJS render loop; --headless supported. Caveat: usage statistics are enabled by default — opt out with --no-usage-statistics or CI. Only officially supports Chrome/Chrome for Testing.
2Playwright MCP0.0.83 · 2026-09-28
pushed 2026-10-08
Apache-2.0 · ~38k★Scripted interaction and gameplay regression driving. Caveat: accessibility-tree-based, not pixel-based — it sees the DOM HUD, not the arena.
3filesystem + memory + sequential-thinkingnpm 2026.8.31MIT–Apache-2.0 · 91k★ (repo)Cheap local context; all three verified current and not deprecated. Install: npx -y @modelcontextprotocol/server-filesystem <dir>, …-server-memory, …-server-sequential-thinking.
4Official git serverPyPI 2026.8.18MITRepo history/blame without shelling out: uvx mcp-server-git --repository <path>.
5GitHub MCP serverpushed 2026-10-08MIT · ~33k★Only if the project is on GitHub (issues/PRs/Actions): docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server.
6basic-memory (optional)PyPI 0.23.2AGPL-3.0 · ~4.1k★Cross-session project memory — note the copyleft licence. uvx --prerelease=allow basic-memory mcp.
7Only if a native engine is added laterAsset Library 5050MIT · 2,871★hi-godot/godot-ai over every other Godot option (one-click config for 22 clients). For Unity, prefer the official Unity CLI over any MCP.
8skip all Unreal servers, mem0-mcp, executeautomation/mcp-playwright, the three deprecated @modelcontextprotocol/server-* packages, and every ComfyUI/image-gen serverdeprecated flags: 2025-04-08 (github), 2024-12-04 (postgres), 2025-05-12 (puppeteer)—The official README still shows the deprecated servers; they now live in servers-archived. NEON PURGE is procedurally drawn with zero external assets by design, so image-gen servers have nothing to do here.

Windows note (from the official servers README): wrap npx entries as "command": "cmd", "args": ["/c", "npx", …]; uvx entries need no wrapper.

the pattern to copy Agent-friendliness tracks text-format projects + a real headless CLI, not engine popularity and not whether a vendor shipped an MCP server. Defold's position is the most thought-through: expose general-purpose HTTP/CLI surfaces with an explicit privilege taxonomy (read-only → verification → modification → privileged /eval), keep policy in the adapter, and skip the MCP layer entirely. Unity is the trap case — it shipped an MCP server first and has now deprecated it in favour of a CLI. Note also that engine MCP bridges are arbitrary code execution in your project; several circulating entries are 0–40-star repos. 03-mcp-interop.md §Table B, §Hype vs. reality

Adjacent standards

08Asset pipeline — keep procedural, and the traps to avoid

The verdict is unambiguous: keep the procedural, zero-asset approach as the default. Adopt generated assets only as an optional, build-time-baked, permissively-licensed polish layer — never as a runtime or build dependency. 04-asset-pipeline.md §Recommendation

Measured on 2026-10-09. The baseline numbers are this repo's own: vendor/pixi.mjs is 2,200,191 bytes and src/ is 32 files / 442,487 bytes.
PropertyNEON PURGE todayGenerated-asset route
Shipped payload≈2.52 MB (2.10 MB PixiJS + 0.42 MB src), 0 assets+ a 2048² WebP atlas (~300 KB at q85) + ~24 OGG SFX (~1.5 MB) ≈ +1.8 MB → ~4.3 MB (+72%)
Runtime dependenciesnone (no CDN, no fonts, no images)none if assets are committed as static files
Build-machine toolchain0 MB~10–33 GB of model weights + PyTorch/CUDA (dev-only)
Determinismexact — seeded RNG, fixed-timestep autotest; docs/SPEC.md requires identical kills/wavesReached/upgradesTaken per seedgenerated assets must be frozen as committed artefacts; the generation step itself is not reproducible without pinning model + LoRA + sampler + seed + library versions
Licence exposurezeronon-zero the moment any weight file with an other/NC/community licence is used
VRAM / latency on the build box02D ~13 GB (FLUX.2-klein-4B); 3D ≥24 GB (TRELLIS.2-4B); audio <4 GB (ACE-Step 1.5)

The permissive tier (the only one to use, offline)

Code licence and weight licence are different things, which is why the survey tracks both. Every row here is permissive on both columns.
CategoryPickWeight licenceCode licenceLatest · dateRequirements / signal
2D imageZ-Image-TurboApache-2.0Apache-2.02025-11-25620,806 downloads, 5,424 likes; bf16 weights ≈33 GB download; 8 NFEs; CPU-offload supported
2D image + editFLUX.2-klein-4BApache-2.0Apache-2.0 (flux repo, 26,009★)2026-01-14406,006 downloads; card: "Open weights available for commercial use under the Apache 2.0 license", ~13 GB VRAM on an RTX 3090/4070
2D imageHiDream-O1-ImageMITMIT2026-05-084,719 downloads; CUDA GPU required; the undistilled variant is the heaviest
Sprite/pixel LoRAstarn59/pixel_art_style_lora_z_image_turbo, svntax-dev/pixel_spritesheet_4walk_*Apache-2.0Apache-2.02025-11-30 / 2026-02-01 / 2026-03-18Applied on top of Z-Image-Turbo. There is no dominant purpose-built sprite-sheet foundation model — the whole category is LoRA-shaped bolt-ons
3D generationTRELLIS.2-4BMITMIT (microsoft/TRELLIS, 13,779★)2025-12-011,894,990 downloads, 1,300 likes; designed for arbitrary topology; ≥24 GB GPU verified on A100/H100
3D (lighter)TripoSR / InstantMeshMIT / Apache-2.0MIT / Apache-2.02024-02-29 / 2024-04-10~6–8 GB and ~16 GB respectively — the fully-permissive fallbacks
Audio (music)ACE-Step 1.5MITApache-2.02026-01-2368,462 downloads; card: <4 GB VRAM, "Commercial-Ready", royalty-free/public-domain training data (vendor claim, third parties cannot audit provenance from the fetch)
Animation / riggingUniRig + SkinTokens, or Wan2.2-Animate-14BMIT / MIT / Apache-2.0MIT / MIT / Apache-2.02025-04-09 / 2026-04-20 / 2025-09-11UniRig needs a CUDA GPU >8 GB. Wan-Animate-2 ComfyUI repack: 537,092 downloads
Optimiser / gluebpy → gltf-transform → gltfpack → toktx/Basis → sharp+oxipng → maxrects-packern/a (tools)GPL-3.0 (output unencumbered) / MIT / MIT / Apache-2.0 / Apache-2.0+MIT / MITbpy 5.2.2 · gltf-transform 4.5.1 · gltfpack 1.3.0 · sharp 0.35.5 · maxrects-packer 2.7.3The whole chain is MIT/Apache-2.0 and CLI-only (except bpy, whose GPL covers the tool, not your output). Headless throughout.

Licence traps, ordered by how likely an agent is to walk into them

  1. Qwen-Image 2.1 — the biggest trap. The most-downloaded current image model (7,472,445 downloads on the ComfyUI repack, 2026-09-15) and its weights are under the "Qwen RESEARCH LICENSE AGREEMENT" (Release Date: September 20, 2026): "Non-Commercial shall mean for research or evaluation purposes only… You shall not use the Materials for any commercial purpose without obtaining a separate commercial license." An agent that picks "the top model" ships an asset it has no right to. Qwen-Image v1 is Apache-2.0; 2.1 is not.
  2. FLUX dev lines. FLUX.2-dev / FLUX.1-dev / FLUX.2-klein-9B have HF cardData.license_name literally flux-non-commercial-license. Only FLUX.1-schnell, FLUX.2-klein-4B, FLUX.2-klein-base-4B and FLUX.2-small-decoder are Apache-2.0 in the family.
  3. MusicGen and MMAudio weights are CC-BY-NC-4.0 while the AudioCraft/MMAudio code is MIT. The whole facebook/musicgen-* family (1,911,195 downloads on medium alone) is non-commercial for the weights.
  4. The Stability AI Community Licence is revenue-gated, not free. Free only for "individuals or organizations that generate under $1M of annual revenue"; above that an Enterprise Licence is required. It is also revocable on violation. Covers SD3.5, SDXL Turbo, Stable Audio 3.0 and Stable Fast 3D.
  5. Hunyuan3D is territory-limited. The Tencent Hunyuan 3D 2.1 Community Licence states in its second line: "THIS LICENSE AGREEMENT DOES NOT APPLY IN THE EUROPEAN UNION, UNITED KINGDOM AND SOUTH KOREA." Covers Hunyuan3D-2, 2.1, 2mini, Omni and HunyuanWorld.
  6. Non-OSI tool licences. Aseprite is not open source — its EULA.txt is an End-User Licence Agreement from Igara Studio S.A. ("licensed, not sold"), and GitHub reports no SPDX licence. Use LibreSprite (GPL-2.0) instead. pngquant is GPL-3.0-or-later (dual-licensed commercially): fine as a build tool, don't link it into a proprietary binary. ComfyUI is GPL-3.0 — Copyleft applies to ComfyUI, not to the images it produces, so never ship ComfyUI itself as a component.
  7. Gated downloads are an automation blocker, not just a legal one. FLUX.2-dev, all stabilityai/* weight repos and Lightricks/LTX-Video return HTTP 401 without an authenticated HF account and often require accepting a licence plus name/email/country. An unattended agent pipeline will fail on these unless the token and gate acceptance are handled explicitly.
  8. "Open weights" ≠ "open licence". Every family above is code-permissive (flux Apache-2.0, generative-models MIT, audiocraft MIT, LTX-Video repo Apache-2.0) while the weights are restricted. That is why the source note carries two licence columns.
where generated assets are still not game-ready 3D output needs mesh surgery (TRELLIS.2 concedes its raw meshes "may occasionally contain small holes"; Hunyuan3D-2.1 needs 10 GB for shape / 21 GB for texture / 29 GB for both). Rigging is a separate research step, not a button: UniRig has 94 likes on its weights repo and Isabellaliu/RigAnything has no declared licence at all — unusable commercially. There is no sprite-sheet model; character consistency across frames is still a human-in-the-loop job, and no published consistency metric exists (that claim is explicitly qualitative). And "Commercial-Ready" is a marketing phrase — the ACE-Step licence is verifiable, its training-data provenance is not. 04-asset-pipeline.md §Hype vs. reality

09Sources & evidence — every claim linkable, with honesty about gaps

Each claim above is traceable to one of seven research notes. The notes are not published alongside this page, so they are shown as filenames in text; the external URLs below are the real links (all fetched/observed 2026-10-09).

Note inventory. Each note pins its own live date from an HTTP Date: response header, which is why the "evidence as of" date on this page can be asserted rather than assumed.
Note (plain text, not a link)Live date proof used by the noteCovers
research/01-agent-harness.mdapi.github.com Date header → Fri, 09 Oct 2026 08:19:03 GMTharnesses, tiers, dead projects, licence traps, Windows sandboxing, AGENTS.md / MCP / A2A adoption
research/02-engines.mdapi.github.com/rate_limit → Fri, 09 Oct 2026 08:18:45 GMTmaster engine table, rubric ranking, per-scenario picks, dead/licence traps
research/03-mcp-interop.mdapi.github.com → 08:18:37 GMT + local clockMCP spec state, server table, engine integration surface, registries, hype-vs-reality
research/04-asset-pipeline.mdapi.github.com → 08:18:52 GMT (re-checked 08:25:52)asset generation, code vs weight licences, optimiser chain, traps, the recommendation
research/05-qa-harness.mdapi.github.com → 08:18:50 GMTtool inventory, the 7-layer harness, anti-flake rules, what is not automatable
research/07-improve-2d.mdregistry.npmjs.org / api.npmjs.org / jsDelivr, plus a harness the author ran in %TEMP%\gg2d-harnessthe 2D verdict, the Node-canvas pixel finding, the add-on stack, migration cost, determinism fit
research/08-improve-3d.mdregistry.npmjs.org/-/ping → 08:31:56 GMTPlayCanvas ToS finding, empirical headless harness for all three engines, package set
research/tavily/2d-harness-results.jsonraw run output, 2026-10-09rows D/E/A/B-C/F/G/H/I in §05
research/tavily/3d-harness-results.jsonraw Node run output, 2026-10-09the empirical headless results in §04
research/tavily/improve-stack-pro.jsonstatus completed, 45 sources, 14,540-char reportcross-check only (see below), not a primary source

External evidence index (the real links)

registry.npmjs.org/pixi.js · registry.npmjs.org/planck · registry.npmjs.org/@dimforge/rapier2d · registry.npmjs.org/bitecs · registry.npmjs.org/@napi-rs/canvas · registry.npmjs.org/@pixi/ui · registry.npmjs.org/pixi-filters · registry.npmjs.org/melonjs · registry.npmjs.org/@babylonjs/core · registry.npmjs.org/playcanvas · registry.npmjs.org/three · api.npmjs.org/downloads (playcanvas) · api.npmjs.org/downloads (@babylonjs/core) · api.npmjs.org/downloads (pixi.js, month)
playcanvas.com/terms · PlayCanvas: engine standalone · developer.playcanvas.com/llms.txt · playcanvas/editor README · playcanvas null-graphics-device source
doc.babylonjs.com — server-side / NullEngine · Babylon WebGPU · Babylon MCP servers · @babylonjs/core 9.30.0 NullEngine d.ts
three 0.186.1 WebGLRenderer source · gl 8.1.6 README (WebGL 1.0.3 only) · threejs.org/docs/llms.txt
Godot releases.atom · Godot command-line tutorial · Godot web export (WebGL2 only) · crates.io bevy · Defold bob manual · Defold AI-agents position
registry.npmjs.org/pixelmatch · registry.npmjs.org/vitest · Spector.js · fast-check model-based testing · registry.npmjs.org/@modelcontextprotocol/sdk · pypi.org/pypi/mcp · official MCP registry · registry about (preview)
chrome-devtools-mcp · playwright-mcp README (a11y-tree, not pixels) · Playwright release notes · Playwright snapshots · Playwright issue #42885 (Windows WebKit blank canvas)
Chromium SwiftShader doc · Chrome headless CLI (virtual time) · Web3D Survey: timer query support · Spector.js README
Z-Image-Turbo · FLUX.2-klein-4B · Qwen-Image 2.1 licence (non-commercial) · Hunyuan3D-2.1 licence (EU/UK/KR excluded) · Stability AI Community Licence ($1M gate) · ACE-Step 1.5 · TRELLIS.2-4B · UniRig · ComfyUI (GPL-3.0) · Aseprite EULA
AAIF formation (2025-12-09) · Unity CLI replaces its MCP server · Unreal MCP plugin (Experimental) · Blender Lab MCP server · AGENTS.md · A2A · anthropics/skills

Confidence and gaps — nothing UNVERIFIED is presented as fact

High confidence (fetched live, URL + date recorded)

Every version, date, licence, star count and download count in the engine table; the Godot web-export limits; PlayCanvas engine MIT + editor-frontend MIT + the playcanvas.com/terms bot prohibition and revocable personal licence; Babylon's NullEngine docs, xhr2 requirement and the nullEngine.d.ts path in 9.30.0; three's "WebGL 1 is not supported since r163"; gl's WebGL 1.0.3 README; every harness result in §04 and §05 (the note authors ran these themselves); MCP spec 2026-07-28 and its breaking changes; the three official engine MCP servers and their statuses; npm deprecated flags for the archived official servers; Playwright's canvas-in-trace and WebKit notes; toHaveScreenshot semantics and defaults; Chromium's SwiftShader deprecation and SwANGLE recipe; --virtual-time-budget semantics; the timer-query support percentages; the licence text for every asset model named in §08; and the repo inventory itself (all three tools read in full, node tools/check.mjs run → FAIL/15 findings).

Medium confidence

"No retarget symbols in the PlayCanvas d.ts" and "no retarget file in the Babylon core listing" mean absent rather than named differently. Babylon Lite's 19×/3.6× medians are vendor figures. The claim that shots.mjs currently passes a blank canvas is a strong inference from reading its assertions, not an observation (neither smoke.mjs nor shots.mjs was executed). --force-color-profile=srgb / --force-device-scale-factor=1 come from a capture-sync guide plus Playwright's same-environment warning. The ~4,627-LOC figure is a lower bound on renderer-bound rewrite effort, and "no HEADLESS symbol in the Excalibur/Kaplay dist" means absent rather than named differently (shipped JS was grepped, not the whole source tree). Star counts marked "~" are shields.io-rounded; "maintained?" verdicts and all rubric scores are judgement.

UNVERIFIED — do not treat as fact

  • Unreal Engine — licence terms, exact 5.8 release date, royalties and headless commandlet behaviour: EpicGames/UnrealEngine returns 404, www.unrealengine.com returns 403, and the 5.9 release-notes URL returned HTTP 200 with empty content. Only "Epic's docs host a UE 5.8 release-notes page" is verified.
  • Godot --write-movie headless frame capture — whether the movie writer can render without a display is an inference; test it first or use a virtual display.
  • Defold .go/.collection text format — raw path probes 404'd (wrong paths, not proof of absence). The CLI build path is verified.
  • Per-engine headless determinism — only Godot, Bevy and Defold were verified directly in 02-engines.md; every JS engine, Ebiten, raylib, LÖVE, FNA, MonoGame, Stride, Fyrox, macroquad and Panda3D are marked UNVERIFIED there, not "no". 07-improve-2d.md additionally leaves Excalibur/Kaplay/LittleJS headless pixel paths UNVERIFIED (only LittleJS's headlessMode flag is confirmed), and the melonJS-Text node-canvas drawImage error (row F) is unresolved.
  • Babylon WebGPUEngine in Node — untested; the docs recommend starting from NullEngine. Whether [email protected] yields a working adapter on GPU-less CI runners is unproven — it produced a real adapter on one machine.
  • planck bit-identical across OS/arch on CI runners — unverified; rapier2d's WASM float maths is explicitly not guaranteed bit-identical across platforms.
  • gl/headless-gl on a machine that has MSVC — the install failure here is friction evidence, not proof of impossibility (and the WebGL1 verdict means it would not help WebGLRenderer anyway).
  • Pixel capture for PlayCanvas / Godot — whether any pixel readback works with NullGraphicsDevice (readPixels is a no-op by design) and Godot's --write-movie path.
  • Hypothesis's licence (GitHub reports NOASSERTION); Spector.js MCP availability on npm (npm latest 0.9.33 vs README 0.9.35); Puppeteer / chrome-devtools-mcp canvas behaviour (no fetched doc makes a WebGL claim); reg-cli's stable line (npm latest is an RC); odiff's "SIMD-first" claim (repo description only).
  • microsandbox's Windows microVM path — README claim only, not executed. Daytona's current home after daytonaio/daytona was archived (2026-07-24) could not be located.
  • Canonical repo URLs that have moved — badlogic/pi-mono and Hmbown/CodeWhale returned no match.
  • Screenshot/visual-diff MCP — no credible dedicated server was found; a negative result from search, not an exhaustive registry query.
  • Isabellaliu/RigAnything — no licence declared in HF metadata; commercial status unknown. No published sprite-sheet-consistency metric exists, and generated-3D topology was not benchmarked locally.
  • Numbers drift — GitHub core/search rate limits were shared across agents on one IP and were exhausted more than once, so some rows were recovered via alternate paths; counts may have drifted between 08:19Z and 08:35Z on the snapshot date.
cross-check: the pro deep-research report research/tavily/improve-stack-pro.json (status completed, 45 sources) was used as a cross-check, not a primary source. Where it overlaps, it agrees on the shape of the answer: a text-format, headless-CI-able engine plus an external tool bridge, and it independently singles out Defold's "OpenAPI-described HTTP API, Bob CLI and Automation Bridge with an explicit privilege taxonomy" as unusually agent-friendly — the same finding as 03-mcp-interop.md §Table B. Where it differs and was not followed: its executive recommendation is Godot-first, then Defold, then Bevy, and it does not evaluate the browser renderer layer at all (no PixiJS / Babylon / PlayCanvas headless comparison), so it cannot adjudicate the 2D or 3D browser question this page answers. The repo's own notes also carry a provenance warning: the sibling Tavily-based QA survey (research/tavily/06-qa-playtesting.log) is empty — it contains only {"error": "This request exceeds your plan's set usage limit…"} — so §06 of this page stands on 05-qa-harness.md alone, with no independent second source.
how to keep this honest Before acting on any row: re-fetch the version/date, re-read the weight licence (not the code licence), and check the repo's last push. The 2026 record shows why — Qwen-Image 2.1 became the most-downloaded image model while being non-commercial, PlayCanvas' editor ToS forbids the very agent its own docs are written for, Unity shipped an MCP server and then deprecated it, and the MCP spec itself removed the handshake that nearly every 2025-era server still documents.