Your First Game
In this guide you will create a spinning green triangle from scratch. The finished example is under 30 lines of TypeScript.
The Full Code
Section titled “The Full Code”import { Component, Engine, Scene, Transform, Vec2 } from "@yagejs/core";import { GraphicsComponent, RendererPlugin, CameraKey } from "@yagejs/renderer";import { DebugPlugin } from "@yagejs/debug";
class Spin extends Component { private readonly transform = this.sibling(Transform); private speed: number; constructor(speed = 0.002) { super(); this.speed = speed; } update(dt: number): void { this.transform.rotate(this.speed * dt); }}
class HelloWorldScene extends Scene { readonly name = "hello-world";
onEnter() { const camera = this.context.resolve(CameraKey); camera.position = new Vec2(400, 300);
const tri = this.spawn("triangle"); tri.add(new Transform({ position: new Vec2(400, 300) })); tri.add( new GraphicsComponent().draw((g) => { g.poly([0, -45, 40, 35, -40, 35]).fill({ color: 0x22c55e }); }), ); tri.add(new Spin()); }}
const engine = new Engine({ debug: true });engine.use(new RendererPlugin({ width: 800, height: 600, backgroundColor: 0x0a0a0a,}));engine.use(new DebugPlugin());await engine.start();engine.scenes.push(new HelloWorldScene());Step-by-Step Walkthrough
Section titled “Step-by-Step Walkthrough”1. Imports
Section titled “1. Imports”import { Component, Engine, Scene, Transform, Vec2 } from "@yagejs/core";import { GraphicsComponent, RendererPlugin, CameraKey } from "@yagejs/renderer";import { DebugPlugin } from "@yagejs/debug";Componentis the base class every custom behaviour extends.Engineis the entry point that orchestrates plugins and the game loop.Sceneis the base class for defining game scenes.Transformstores an entity’s position, rotation, and scale.Vec2is a 2D vector used throughout the engine.GraphicsComponentdraws shapes via the PixiJS v8 graphics API.RendererPluginsets up the PixiJS v8 rendering pipeline.CameraKeyis the DI key used to resolve the camera service.DebugPluginenables the FPS counter, entity inspector, and dev overlays.
2. A Custom Component — Spin
Section titled “2. A Custom Component — Spin”class Spin extends Component { private readonly transform = this.sibling(Transform); private speed: number; constructor(speed = 0.002) { super(); this.speed = speed; } update(dt: number): void { this.transform.rotate(this.speed * dt); }}Spin grabs its sibling Transform component and rotates it every frame.
The update(dt) method receives the delta time in milliseconds so the rotation
speed stays consistent regardless of frame rate.
3. Setting Up the Engine
Section titled “3. Setting Up the Engine”const engine = new Engine({ debug: true });engine.use(new RendererPlugin({ width: 800, height: 600, backgroundColor: 0x0a0a0a,}));engine.use(new DebugPlugin());await engine.start();engine.scenes.push(new HelloWorldScene());new Engine({ debug: true })creates the engine with debug mode enabled.engine.use()registers plugins — here the renderer and debug overlay.engine.start()initialises all plugins and starts the game loop.engine.scenes.push()pushes a scene onto the scene stack.
4. Setting Up the Scene
Section titled “4. Setting Up the Scene”class HelloWorldScene extends Scene { readonly name = "hello-world";
onEnter() { const camera = this.context.resolve(CameraKey); camera.position = new Vec2(400, 300); // ... }}HelloWorldScene extends Scene and implements onEnter(), which runs when
the scene becomes active. this.context.resolve(CameraKey) retrieves the
camera service via dependency injection.
Setting camera.position = new Vec2(400, 300) shifts the world origin to the
top-left corner of the default 800 × 600 viewport. The triangle is then spawned
at world position (400, 300) and lands in the middle of the screen. By
default the camera is at (0, 0) which puts world origin at the centre of
the viewport — see Camera → Coordinate Convention
in the Rendering guide for the full explanation.
5. Spawning an Entity
Section titled “5. Spawning an Entity”const tri = scene.spawn("triangle");scene.spawn() creates a new entity. The string argument is a human-readable
name used by the debug tools.
6. Adding Components
Section titled “6. Adding Components”tri.add(new Transform({ position: new Vec2(400, 300) }));tri.add( new GraphicsComponent().draw((g) => { g.poly([0, -45, 40, 35, -40, 35]).fill({ color: 0x22c55e }); }),);tri.add(new Spin());Three components are attached to the entity:
Transform— positions the triangle at the centre of the viewport.GraphicsComponent— draws a green triangle using three vertices defined as a flat[x, y, ...]array.Spin— the custom behaviour that rotates the triangle every frame.
Running It
Section titled “Running It”Start your dev server (e.g. npx vite) and open the page in a browser. You
should see a green triangle spinning smoothly on a dark background with the
debug overlay in the corner.
Next Steps
Section titled “Next Steps”- Add keyboard input with
@yagejs/inputto control the triangle. - Swap the shape for a sprite using
SpriteComponentfrom@yagejs/renderer. - Read Project Structure to understand the full package layout.