Guide
arcade2d games are assembled in a fixed order: a Game
owns the canvas and loop, a World holds your objects,
prefabs are reusable blueprints, and
components are the behaviour you compose onto
objects. This guide walks that scaffolding top to bottom — terse on purpose. Each step links
into the API reference for the full detail.
1. Setting up Game
Everything hangs off a single Game. Game.bootstrap
is async — it spins up the renderer, sizes the canvas, and starts the frame loop —
so await it before doing anything else. The returned instance
also owns game.assets and game.audio.
import { Game } from '@arcade2d/engine';
const game = await Game.bootstrap({
backgroundColour: 0x1099bb,
canvas: { fill: 'window' }, // or { width: 960, height: 640 }
debug: true, // exposes the instance as window.game in the console
}); 2. Creating a World
A World holds your objects and runs the per-frame update loop the
Game drives. createWorld builds one and makes it active.
const world = game.createWorld();
World-level systems — things that act on the whole world rather than one object, like physics —
are registered up front through the components factory. The keys
you give them are how you look them up later.
import { PhysicsWorld } from '@arcade2d/engine';
const world = game.createWorld({
components: (world) => ({
physics: () => new PhysicsWorld(world, { gravity: { x: 0, y: 980 } }),
}),
});3. Setting up prefabs
A Prefab is a reusable blueprint for a world object: a name, optional
tags, and a map of component factories. Define it once, spawn it many times. Each factory is
handed a context — { object, world, assets } — so a component
can wire itself to its host object and pull from the asset library.
import { Prefab, PolygonGraphics } from '@arcade2d/engine';
import { PlayerController } from './player.controller';
export const PlayerPrefab = new Prefab({
name: 'player',
tags: ['player'],
components: {
controller: ({ object }) => new PlayerController(object),
graphics: ({ object }) =>
PolygonGraphics.asRectangle(object, 50, 50, 0xffffff),
},
});
Hand a PrefabRegistry to createWorld
if you want to spawn prefabs by name instead of by import.
4. Understanding components
Components are where behaviour lives. There are two tiers:
- AbstractWorldObjectComponent — attached to a single object: a controller, a rigid body, a sprite.
- AbstractWorldComponent — attached to the world itself: physics, a spawner, score-keeping.
Override only the lifecycle hooks you need; the world calls them each frame.
this.host is the owning object, and
this.world / this.game reach up the
tree. Release anything you allocate in onDestroy.
import { AbstractWorldObjectComponent, WorldTimer } from '@arcade2d/engine';
import type { WorldUpdate } from '@arcade2d/engine';
export class PlayerController extends AbstractWorldObjectComponent {
public override onUpdate(update: WorldUpdate): void {
const keyboard = this.game.getKeyboardState();
const mouse = this.world.getMouseState();
const angle = this.host.position.angleTo(mouse.position);
if (keyboard.isDown('KeyW')) {
this.host.position.moveInDirection(angle, 0.08 * update.deltaMilliseconds);
}
this.host.rotation = angle;
}
}5. Spawning world objects
With a prefab defined, createFromPrefab instantiates its
components onto a fresh WorldObject and adds it to the world
(it joins on the next tick). Pass a position, or omit it to spawn at the origin.
world.createFromPrefab(PlayerPrefab);
world.createFromPrefab(ZombiePrefab, { x: 200, y: -120 });
Need an object without a prefab? createEmpty gives you a bare
object (with optional tags) you can attach component factories to directly.
import { Circle, CircleGraphics, RigidBody } from '@arcade2d/engine';
const ball = world.createEmpty({ x: 0, y: -200 }, ['ball']);
ball.addComponentsFromFactories({
graphics: (host) => new CircleGraphics(host, new Circle(16), 0xff9f1c),
body: (host) =>
new RigidBody(host, {
type: 'dynamic',
collider: { shape: new Circle(16), restitution: 0.6 },
}),
});6. Graphics, audio & physics
The engine ships components for the three things every game needs. Attach them like any other
component — in a prefab factory or via addComponent.
Graphics
Render an object as a shape or a texture. Graphics components auto-sync to their host's transform every frame, so you never position them by hand. Reach for PolygonGraphics, CircleGraphics, Sprite, AnimatedSprite, TilingSprite, or Text.
import { ImageAsset, Sprite, Texture } from '@arcade2d/engine';
// In a prefab component factory — resolve a preloaded, typed texture:
graphics: ({ assets, object }) => {
const asset = assets.use(characters).getAs('player', ImageAsset);
return new Sprite(object, new Texture(asset));
},Audio
AudioSource plays a clip from an object; the game-level
game.audio engine is the master bus with per-category volume.
import { AudioAsset, AudioSource } from '@arcade2d/engine';
const gunshot = assets.use(sfx).getAs('gunshot', AudioAsset);
object.addComponentFromFactory(
'sfx',
(host) => new AudioSource(host, gunshot, { volume: 0.6 }),
);
object.getComponent<AudioSource>('sfx').play();Physics
Physics is opt-in and backed by Rapier. Call initPhysics once (it bootstraps the WebAssembly module) before building a world that uses it, register a PhysicsWorld (step 2), then give objects a RigidBody (step 5).
import { initPhysics } from '@arcade2d/engine';
await initPhysics(); // one-time WASM bootstrap, before createWorld