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
-
Open the editor and click New Project
-
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
-
Name your project (e.g. “my-first-game”) and click Create
The editor creates a project with a default scene containing a Camera entity.
-
Add a Sprite entity in the editor
In the Hierarchy panel, create a new entity and add
TransformandSpritecomponents to it. Set the Sprite size to100 x 100and pick a color. -
Create
src/main.tswith 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;}})); -
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:
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:
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 startaddSystem(system); // runs every frame (Update)addSystemToSchedule(Schedule.FixedUpdate, system); // runs at fixed intervalsSchedule Types
| Schedule | When it runs |
|---|---|
Startup | Once at the beginning |
First | Before PreUpdate, every frame |
PreUpdate | Before Update, every frame |
Update | Every frame (default) |
PostUpdate | After Update, every frame |
Last | After PostUpdate, every frame |
FixedPreUpdate | Before FixedUpdate, at fixed intervals |
FixedUpdate | At fixed time intervals |
FixedPostUpdate | After 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 } }); }));