Why gameplate?
You probably don't need yet another game engine. You probably do need:
- A typed state container that doesn't pull in 30 KB of Redux ceremony.
- A game loop that handles the spiral-of-death and fixed-timestep math for you.
- A renderer hook so your existing Canvas / WebGL / PIXI code drops straight in.
- A headless mode so the same code runs in CI, on a server, or in a Web Worker.
gameplate is exactly that, and nothing more.
Comparison
vs. PIXI / Three / Phaser
Those are renderers (or full engines, in Phaser's case). They tell you how to draw things.
gameplate is the glue between your game logic and any of them. You bring whichever
renderer you love — gameplate keeps your state, loop, input, and scenes in shape.
You can absolutely use them together:
import { createGame } from 'gameplate';
import * as PIXI from 'pixi.js';
const app = new PIXI.Application();
await app.init({ width: 640, height: 360 });
const game = createGame({
state,
actions,
render: (state) => {
// update PIXI sprites from state, then let PIXI's own ticker draw.
sprite.x = state.x;
sprite.y = state.y;
},
});
game.start();
vs. XState
XState is great for arbitrary statecharts: hierarchical states, parallel regions, history, guards, the works. It is also ~30 KB minified and has its own steep learning curve.
gameplate's createMachine is ~150 LOC, ships with the framework, and is purpose-built for
the "menu → playing → paused → gameover" shape that 95 % of games use. If you need true
statecharts, reach for XState — they compose just fine.
vs. rolling your own
Everyone does it. Everyone hits the same gotchas:
requestAnimationFramecallbacks lose theirdtparameter the first time the tab pauses.- Mutating state in-place breaks React-style renderers but compiles fine.
- Headless tests need a fake
window… unless you abstract over the global. - Memoization of derived state is more annoying than it has any right to be.
gameplate is what your fifth from-scratch loop wants to become — already typed, already
tested, already headless-ready.
When gameplate is not the right tool
Be honest with yourself:
- You're writing a 3D game. You probably want Three.js + Cannon-es directly.
gameplatecan still help with scenes and input, but the meat of the work is the renderer. - You're writing a multi-developer commercial game. Look at Phaser, Defold, Godot, Unity.
- You want a level editor / asset pipeline / particle GUI. That's not what this is.
gameplate is a library, not an engine. It assumes you write code.
Design tenets
The "no" list is more informative than the "yes" list:
- ❌ No runtime dependencies. Forever. Anything we'd inline (an emitter, a memoizer) is short enough to live in this package.
- ❌ No DOM in core. Browser globals are optional. The Node build runs the same code.
- ❌ No magic. No proxies, no decorators, no
Object.definePropertytraps. Read any file top-to-bottom and you'll understand it. - ❌ No "framework lock-in" for rendering. You can swap PIXI for Three between commits.
- ❌ No
any. Every public signature is fully typed.
Roadmap
gameplate is feature-complete for v2. Future-considered:
@gameplate/network— deterministic state-sync helpers for multiplayer.@gameplate/audio— a tiny WebAudio wrapper with the same "headless no-ops" pattern.@gameplate/devtools— a Chrome extension to inspect state, action history, FSM state.
Want one of these? Open an issue — your votes help us prioritize.