gameplate
v2.2.0
Published
Tiny, zero-dependency, fully-typed TypeScript framework for browser & headless games — state, loop, input, scenes. Bring any renderer.
Maintainers
Readme
gameplate
The 3 KB TypeScript game framework. Zero deps. Any renderer.
State. Loop. Input. Scenes. Selectors. Ship a game today.
👉 Docs · Live demo · API
npm install gameplateimport { createGame, defineActions } from 'gameplate';
const actions = defineActions<{ x: number }>()({
moveBy: (s, dx: number) => ({ x: s.x + dx }),
});
const game = createGame({
state: { x: 0 },
actions,
update: (state, dt, actions) => {
if (game.keyboard.isDown('ArrowRight')) actions.moveBy(200 * dt);
},
render: (state) => draw(state), // 👈 your renderer, any tech
});
game.start();That's the whole API surface. Read it, write it, ship it.
Why you'll like it
- 🪶 3 KB gzipped. Smaller than a single sprite sheet. Zero runtime deps. Forever.
- 🦺 TypeScript-first.
strict: true+ everynoUnchecked*flag. Inference does the work — noas any, ever. - 🎯 Renderer-agnostic. Canvas · WebGL · WebGPU · PIXI · Three.js · DOM · terminal. Pick one. Switch tomorrow.
- ⏱️ Deterministic loop. Variable timestep by default; opt into fixed-step + interpolation when physics need to be reproducible.
- 🎮 Input, normalized. Keyboard + pointer + gamepad (with radial-deadzoned sticks and edge detection). Headless no-ops cleanly — same API on Node.
- 🎬 Typed scene FSM.
menu → start → playingwith compile-time checks. Send a wrong event? TypeScript stops you. - 🧠 Memoized selectors. Reselect-style derived state, ~30 LOC, exact same shape.
- 🎞️ Record & replay. Capture every dispatched action; replay it deterministically. Bug repro, regression tests, server-authoritative validation — all in JSON.
- 🖥️ Browser & Node. Headless simulation, server-authoritative play, CI snapshot tests — same code, two runtimes.
- 📦 Dual ESM + CJS.
publintclean. Provenance signed. Tree-shakeable.
In 30 seconds
type State = { player: { x: number; y: number }; score: number };
const actions = defineActions<State>()({
move: (s, dx: number, dy: number) => ({
...s,
player: { x: s.player.x + dx, y: s.player.y + dy },
}),
score: (s, pts: number) => ({ ...s, score: s.score + pts }),
});
const game = createGame({ state: { player: { x: 0, y: 0 }, score: 0 }, actions });
game.actions.move(10, 0); // ✅ typed
game.actions.move('lol', 0); // ❌ TS error — caught at compile timeThat's state + actions. Add update for input handling, render for drawing, and you have a game.
What's in the box
| | |
| :--------------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- |
| createGame | One-call setup — state + loop + input wired together. |
| createStore | The underlying typed store (subscribe, getState, setState). |
| defineActions | Curried generic that gives perfect IntelliSense without retyping S. |
| createLoop | Bare loop — variable or fixed-step with interpolation alpha. |
| createKeyboard / createPointer / createGamepad | Normalized input — keys, pointer, and Standard Gamepad with edge detection. No-op stubs on the server. |
| createMachine | Compile-time-checked finite state machine for scenes/menus. |
| createSelector | Reselect-style memoization, ~30 LOC. |
| createRecorder / replay | Deterministic record + replay of every action. JSON-serialisable. |
Built for every stack
gameplate doesn't ship a renderer — it ships the glue. Drop into:
Switch renderers without changing one line of game logic. Patterns for each →
How it fits together
⌨ keyboard ─┐
🖱 pointer ─┼──▶ actions ──▶ store ──▶ selectors ──▶ render ──▶ 🎨 your renderer
🛰 network ─┘ │ ▲
▼ │
scene FSM ──────────────────┘
loop (dt, alpha) ──▶ update ──▶ actionsA handful of composable functions. Pick the ones you need. Ignore the rest.
Quality bar
- ✅ 141/141 tests, ≥ 90 % line coverage
- ✅ CI matrix: Node 20 / 22 / 24 × Ubuntu / macOS / Windows
- ✅
publint+@arethetypeswrong/cliclean on every PR - ✅ Size limit: < 4 KB gzipped ESM, enforced in CI
- ✅ CodeQL security analysis on every PR
- ✅ npm provenance on every release (OIDC trusted publishing)
Contributing
PRs welcome. See CONTRIBUTING.md. Architecture decisions are recorded in DECISIONS.md.
git clone https://github.com/yankouskia/gameplate
cd gameplate
pnpm install
pnpm test:watchLicense
MIT © Alex Yankouski · Sponsor →
If gameplate saved you a weekend, ⭐ star it — it's the easiest way to say thanks.
