Skip to content

Quick Start

Let’s create a simple game that animates a sprite. This will introduce you to the core concepts of Estella.

Create a Project

  1. Open the editor and click New Project

  2. Choose a template — select Empty Project for a blank canvas, or pick a built-in template like Space Shooter to start with a working example

  3. Name your project (e.g. “my-first-game”) and click Create

    The editor creates a project with a default scene containing a Camera entity.

  4. Add a Sprite entity in the editor

    In the Hierarchy panel, create a new entity and add Transform and Sprite components to it. Set the Sprite size to 100 x 100 and pick a color.

  5. Create src/main.ts with the following code:

    import {
    defineSystem,
    addSystem,
    Query,
    Mut,
    Res,
    Time,
    Transform,
    Sprite,
    } from 'esengine';
    addSystem(defineSystem(
    [Res(Time), Query(Mut(Transform), Sprite)],
    (time, query) => {
    for (const [entity, transform, sprite] of query) {
    transform.position.x = Math.sin(time.elapsed) * 100;
    transform.position.y = Math.cos(time.elapsed) * 100;
    }
    }
    ));
  6. Press F5 in the editor to preview — the sprite moves in a circle

Understanding the Code

Components Live in the Scene

In Estella, entities and their components are created in the scene editor. Your code doesn’t create them — it defines systems that query and operate on scene entities.

The sprite you placed in step 3 already has Transform and Sprite components. The system in step 4 finds it via Query(Mut(Transform), Sprite) and animates it.

Custom Components

You can define custom components in code, then attach them to entities in the editor:

src/components/Speed.ts
import { defineComponent } from 'esengine';
export const Speed = defineComponent('Speed', { value: 200 });

After saving, the Speed component appears in the editor’s “Add Component” menu. Attach it to an entity, then write a system that queries it:

src/systems/movement.ts
import { defineSystem, addSystem, Res, Time, Query, Mut, Transform } from 'esengine';
import { Speed } from '../components/Speed';
addSystem(defineSystem(
[Res(Time), Query(Mut(Transform), Speed)],
(time, query) => {
for (const [entity, transform, speed] of query) {
transform.position.x += speed.value * time.delta;
}
}
));

Registering Systems

import { addSystem, addStartupSystem, addSystemToSchedule, Schedule } from 'esengine';
addStartupSystem(system); // runs once at start
addSystem(system); // runs every frame (Update)
addSystemToSchedule(Schedule.FixedUpdate, system); // runs at fixed intervals

Schedule Types

ScheduleWhen it runs
StartupOnce at the beginning
FirstBefore PreUpdate, every frame
PreUpdateBefore Update, every frame
UpdateEvery frame (default)
PostUpdateAfter Update, every frame
LastAfter PostUpdate, every frame
FixedPreUpdateBefore FixedUpdate, at fixed intervals
FixedUpdateAt fixed time intervals
FixedPostUpdateAfter FixedUpdate, at fixed intervals

Runtime Spawning

Use Commands when you need to create entities at runtime (e.g. bullets, particles):

import { addStartupSystem, defineSystem, Commands, Sprite, Transform } from 'esengine';
addStartupSystem(defineSystem(
[Commands()],
(cmds) => {
cmds.spawn()
.insert(Sprite, { size: { x: 10, y: 10 } })
.insert(Transform, { position: { x: 0, y: 0, z: 0 } });
}
));

Next Steps