Skip to content

Quick Start

Let’s create a simple game that displays a moving sprite. This will introduce you to the core concepts of ESEngine.

Create a New Project

  1. Create your project directory

    Terminal window
    mkdir my-game
    cd my-game
    npm init -y
  2. Install dependencies

    Terminal window
    npm install esengine
    npm install -D esbuild typescript
  3. Create src/main.ts

    import {
    type ESEngineModule,
    createWebApp,
    defineSystem,
    Schedule,
    Commands,
    Query,
    Res,
    Time,
    LocalTransform,
    Sprite,
    Camera
    } from 'esengine';
    export async function main(Module: ESEngineModule): Promise<void> {
    const app = createWebApp(Module);
    // Startup system - runs once at the beginning
    app.addSystemToSchedule(Schedule.Startup, defineSystem(
    [Commands()],
    (cmds) => {
    // Create camera
    cmds.spawn()
    .insert(Camera, {
    projectionType: 1,
    orthoSize: 400,
    isActive: true
    })
    .insert(LocalTransform, {
    position: { x: 0, y: 0, z: 10 }
    });
    // Create a sprite
    cmds.spawn()
    .insert(Sprite, {
    color: { x: 1, y: 0.5, z: 0.2, w: 1 },
    size: { x: 100, y: 100 }
    })
    .insert(LocalTransform, {
    position: { x: 0, y: 0, z: 0 }
    });
    }
    ));
    // Update system - runs every frame
    app.addSystemToSchedule(Schedule.Update, defineSystem(
    [Res(Time), Query(LocalTransform, Sprite)],
    (time, query) => {
    for (const [entity, transform, sprite] of query) {
    // Move sprite in a circle
    transform.position.x = Math.sin(time.elapsed) * 100;
    transform.position.y = Math.cos(time.elapsed) * 100;
    }
    }
    ));
    app.run();
    }
  4. Add build script to package.json

    {
    "scripts": {
    "build": "esbuild src/main.ts --bundle --format=esm --outfile=build/main.js"
    }
    }
  5. Build your game

    Terminal window
    npm run build

Understanding the Code

App and Systems

ESEngine uses a system-based architecture. Systems are functions that run at specific points in the game loop:

// Create the app with WASM module
const app = createWebApp(Module);
// Add a system to a schedule
app.addSystemToSchedule(Schedule.Update, defineSystem(
[/* parameters */],
(/* injected params */) => {
// Game logic here
}
));
// Start the game loop
app.run();

Schedule Types

ScheduleWhen it runs
StartupOnce at the beginning
UpdateEvery frame
PostUpdateAfter Update, every frame
FixedUpdateAt fixed time intervals

System Parameters

Systems declare what data they need, and it gets injected automatically:

defineSystem(
[Commands(), Res(Time), Query(LocalTransform, Sprite)],
(cmds, time, query) => {
// cmds: spawn/despawn entities
// time: elapsed time, delta time
// query: iterate entities with components
}
)

Components

Components are data attached to entities. ESEngine provides builtin components:

ComponentDescription
LocalTransformPosition, rotation, scale
Sprite2D sprite rendering
CameraCamera settings
VelocityMovement velocity

Creating Entities

Use Commands to spawn entities and attach components:

cmds.spawn()
.insert(Sprite, { color: { x: 1, y: 0, z: 0, w: 1 } })
.insert(LocalTransform, { position: { x: 100, y: 100, z: 0 } })
.id(); // Returns the entity ID

Querying Entities

Use Query to iterate entities with specific components:

for (const [entity, transform, sprite] of query) {
transform.position.x += 1;
}

Next Steps