Game Engine Choice
Decided 2026-04-14: PixiJS + @pixi/react, TypeScript, embedded in the existing Guild Next.js app.
Stack
| Layer | Choice | Role |
|---|---|---|
| Rendering | PixiJS (v8.x, MIT) | 2D WebGL rendering — sprites, graphics, filters/shaders |
| React integration | @pixi/react (v8, MIT, official) | Express Pixi scenes as JSX; hooks for render loop; mix with DOM at any level |
| Language | TypeScript | Same as Guild portal, kiosk, Medusa storefront |
| Framework | Next.js + React | Already in Guild; game is composed within it |
| Data | Medusa JS client | Product / inventory / cart — the same one the Solace storefront uses |
| State bridge | React state + Zustand | @pixi/react components consume the same stores as the rest of the app |
| Tile authoring | In-code (2D arrays → sprite components) | No Tiled editor, no external tools — user constraint: live in code |
| Audio (if added later) | Howler.js or @pixi/sound | Not needed v1 |
| Shaders | PixiJS Filter API | CRT and other post-process experimentation; first-class in Pixi |
Architecture
Unified codebase. The game is not a separate deployment, not a separate URL, not an iframe. It’s React components living in the Guild Next.js app alongside the dashboards, product grids, and admin surfaces.
Why this works: @pixi/react is a React reconciler. Pixi-rendered elements compose with React DOM at any level of the tree. A Pixi canvas can span the viewport as an ambient layer, or sit as a component inside a page, or fill a route. Same codebase, same build, same deploy, same auth, same state.
Data flow: standard React patterns. Medusa SDK is called from React hooks (React Query / SWR). Relevant data is passed into @pixi/react components as props or read from Zustand stores. When a sprite is clicked, it emits a React event; a DOM overlay renders the product detail using normal React.
No bridge layer required. This is the core reason PixiJS + @pixi/react beat Phaser in the final analysis — Phaser’s Scene/Game lifecycle would have required a bespoke state bridge between React and Phaser. With @pixi/react, pixi is just more React.
Scope (v1)
In scope:
- Pixel rendering embedded inside the existing Next.js app
- Ambient fantasy-pixel layer across the whole Guild UI (see guild-1bit-aesthetic “wizard shopping on eBay” section)
- Top-down shop interior scene as one instance of the treatment
- Shader/filter experimentation (CRT etc.) via PixiJS Filter API
- Integration with real Medusa inventory — click a shelf sprite, see real product detail
Deferred:
- Cross-platform native (mobile/desktop/console). Not chasing this yet.
- Roguelike game loop (combat, dungeons, procgen). The product v1 is a spatial commerce interface, not a game.
- Audio / music / SFX. Add when the interaction design actually calls for it.
- Physics engine. Shop interface doesn’t need it.
- Scene-management framework. React Router / Next.js routing handles “scenes.”
Explicitly not adding:
- Tiled editor — user wants code-first authoring
- Phaser — its Scene/Game lifecycle is a seam we don’t need for a React-native product
- Any roguelike toolkit — rot.js, malwoden, bracket-lib all dormant and not needed for an authored shop scene anyway
Why not the alternatives
Brief notes for future readers. Fuller analysis is in the git history of this file.
- Phaser 3 — strong contender; lost to PixiJS + @pixi/react because the product is a React-native interactive UI. Phaser would have required a state-bridge layer. Still a valid pick if the game grows into something with physics, complex scene switching, and less DOM interop.
- Excalibur.js — TS-native, batteries-included. Pre-1.0 (breaking changes expected) and smaller community ruled it out for a first-game project.
- Defold (Lua) — mature, cross-platform native including Switch. Owns its own canvas/lifecycle; doesn’t mix with React at a component level. Worth reconsidering if we ever need native mobile/console distribution.
- Godot 4 — best first-game editor experience + excellent shader tooling, but heavy web export (~50MB runtime) and painful React embed. Right tool for a standalone Steam game, wrong for a React-embedded commerce UI.
- Bevy (Rust) — powerful, cross-platform, but fat WASM bundles and awkward React embed. User flagged as “feels too new.” Revisit only if product ships to native platforms.
- Haxe / Heaps.io — niche-language tax; Bevy would replace it before this came back on the table.
- bracket-lib (Rust) — mostly dormant (last release Oct 2022) and optimized for ASCII/CP437 register, not 16-bit pixel. Wrong on both counts.
- rot.js, malwoden — dormant JS roguelike toolkits. Don’t need one anyway for scope v1.
- melonJS, HaxeFlixel — no advantage over the above.
When to revisit
- If performance at scale becomes a bottleneck (thousands of live sprites at once) — PixiJS directly handles far more than any likely scale, so unlikely.
- If the roguelike game layer becomes a real product (combat, procgen, dungeons) — Phaser becomes worth reconsidering. Or add scene/physics libraries (matter.js, etc.) to the existing PixiJS codebase.
- If the product needs to ship as a native mobile or desktop app — evaluate Capacitor (wraps the web build) before switching engines. Capacitor keeps the PixiJS+React codebase intact.
- If PixiJS v9 or v10 ships breaking changes that hurt — revisit via normal dep-management, not engine choice.
Creative direction this serves
- guild-1bit-aesthetic — visual direction (top-down pixel, “wizard shopping on eBay” ambient layer)
- rpg-loyalty-system-creative-direction — brand voice + fantasy-internet infrastructure metaphors
- outsiderpg-platform-vision — product vision this renders
Open decisions (specific to the stack)
- First prototype surface: pick ONE ambient pixel element to ship end-to-end (header sprite? cursor trail? loading sigil?) before scoping the full shop scene
- Set perf budget + wire dev-only FPS/draw-call overlay before the first sprite ships
- Decide
prefers-reduced-motionfallback pattern — required before any ambient animation - Pick sprite asset pack for v1 ambient layer (Urizen CC0 is the default; see guild-1bit-aesthetic for the full evaluation)
- @pixi/react v8
extendAPI pattern: document the project’s conventions for which Pixi components are registered where
Related
- guild-kiosk — kiosk is one of the surfaces this renders on
- guild-portal-ui-implementation — portal integration surface
- solana-frontier-hackathon — separate decision; not driving this one