Game to
Website.
g2w is a TypeScript-first framework for building and shipping HTML5 games — 2D first with 3D planned — for desktop and mobile web browsers. A renderer-agnostic core, an Effect-native lifecycle, and browser adapters you compose yourself.
// the @g2w/* packages are not yet published to npm — resolved from packed tarballs until the release lands
A shared core to build games on
Small packages with one strict rule, enforced by architecture tests:@g2w/core never depends on a rendering technology.
Renderer Agnostic
Game code targets the renderer contract in @g2w/core, never PixiJS. WebGL today; Canvas and WebGPU backends browser-verified; a Three.js adapter planned — the core never knows.
Effect-Native Lifecycle
G2WGame orchestrates init, ownership, and idempotent shutdown through one managed Effect runtime. LIFO finalizers release every resource — the frame loop stays synchronous.
Input, Everywhere
Keyboard, pointer, and multi-touch ride one DOM-free InputState; gamepads sample through the Gamepad API adapter. Edge states reset at exactly one boundary per frame.
Scenes & Sprites
A renderer-agnostic SceneManager with explicit transition semantics, plus Transform2D/Sprite2D models with anchors and z-order — mutate the model, call sync().
Ownership-Explicit Audio
AudioManager in core, Web Audio backend in the adapter. Tracked playbacks, autoplay-aware resume(), and sounds that stay caller-owned so they can be shared freely.
AI-Agent Ready
A deterministic, DOM-free core designed to be driven by agents: injected schedulers and fakes everywhere, honest docs, and a read-only devtools overlay for live inspection.
One framework, small packages
Compose only what your game needs. Adapters depend on core — never the reverse.
| Package | Responsibility | Status |
|---|---|---|
| @g2w/core | Renderer-agnostic engine contracts, Game runtime, SceneManager, InputState, GamepadState, AssetManager, sprites, audio contract — zero runtime dependencies. | Done |
| @g2w/runtime | Effect-based application lifecycle: G2WGame, one managed runtime, LIFO finalizers, idempotent shutdown. | Done |
| @g2w/renderer-pixi | PixiJS 8 adapter: WebGL / Canvas / WebGPU backends, sprite views, texture asset loading. | Done |
| @g2w/input-dom | DOM adapter: keyboard, pointer, and multi-touch through Pointer Events onto InputState. | Done |
| @g2w/input-gamepad | Gamepad API adapter with an injectable polling source; the host drives poll() once per frame. | Done |
| @g2w/audio-web | Web Audio backend: decode, playback, AudioContext ownership, autoplay resume(). | Done |
| @g2w/devtools | Read-only dev overlay: scene explorer, transforms, FPS, watched input, runtime logs. Dev-only. | Done |
| create-g2w | Zero-dependency CLI that scaffolds a TypeScript + Vite game project from a template. | Done |
| @g2w/renderer-three | Planned 3D rendering adapter proving the renderer contract generalizes. | Planned · R8 |
A game is a composition of small packages
Build a G2WGame from @g2w/runtime with a renderer, a SceneManager, input, audio, and assets — then register your resources as finalizers and let the Effect runtime own the lifecycle.
import { SceneManager, InputState, Sprite2D, Transform2D } from "@g2w/core";
import { DomInput } from "@g2w/input-dom";
import { PixiRenderer, createSpriteView } from "@g2w/renderer-pixi";
import { G2WGame } from "@g2w/runtime";
// a renderer-agnostic sprite: game code mutates the model only
const logo = new Sprite2D({ texture, transform: new Transform2D({ x: 16, y: 32) });
const logoView = createSpriteView({ sprite: logo, renderer });
const game = new G2WGame({
renderer,
canvas: document.querySelector("#game")!,
width: 640, height: 360,
onUpdate: (deltaTime) => {
scenes.update(deltaTime);
input.endFrame(); // one boundary per frame, after every consumer
},
});
await game.init();
game.addFinalizer(() => scenes.dispose()); // LIFO disposal
game.start();Start building with g2w
Scaffold a working TypeScript + Vite 2D game that boots through the public g2w API.