Components
A component is a small, plain data struct attached to an entity. Declare one
with defineComponent, giving it a name and its default values:
import { defineComponent } from 'esengine';
const Speed = defineComponent('Speed', { value: 200 });const Health = defineComponent('Health', { current: 100, max: 100 });The defaults define both the shape (fields and types) and the initial values a new instance gets. Components are pure data — no methods, no behavior. Behavior lives in systems.
Field types
Section titled “Field types”A field’s type is inferred from its default. Numbers, booleans, and strings work as you’d expect, and structured shapes get matching editor controls:
const Missile = defineComponent('Missile', { speed: 400, // number homing: true, // boolean targetTag: '', // string velocity: { x: 0, y: 0 }, // vector — edited as an X/Y pair tint: { r: 1, g: 1, b: 1, a: 1 }, // {r,g,b,a} fields render a color picker});Tags — components with no data
Section titled “Tags — components with no data”A tag is a zero-field marker used purely for filtering — Player, Enemy,
Frozen. Declare it with defineTag and use it in queries with .with() /
.without():
import { defineTag, defineSystem, Query, Mut, Transform } from 'esengine';
const Player = defineTag('Player');const Frozen = defineTag('Frozen');
defineSystem([Query(Mut(Transform)).with(Player).without(Frozen)], (q) => { /* … */ });Editor metadata
Section titled “Editor metadata”A third argument controls how fields present in the editor’s Details panel — ranges, sliders, units, enums, and asset pickers:
const Turret = defineComponent('Turret', { range: 300, mode: 0,}, { fields: { range: { min: 0, max: 1000, slider: true, unit: 'px' }, mode: { enum: [{ label: 'Idle', value: 0 }, { label: 'Attack', value: 1 }] }, },});Useful fields options: min / max / step, slider, unit, enum
(dropdown storing the option’s int), flags (bitmask multi-select), tooltip.
Other component-level metadata: assetFields (marks a field as an asset
reference, so Details renders a picker and the cook ships the dependency),
animatableFields (which fields the Sequencer can
key — defaults to all numeric fields), transient (never saved into the scene —
for per-frame runtime state), replicatedFields (synced by
networking’s state replication), and
renderableField.
renderableField names the boolean field that gates your component’s drawing —
declare it if the component draws something of its own (say through a custom
draw callback), and hiding the entity reaches it: the Outliner’s eye,
setEntityVisible, and a sleeping scene all switch that field off and restore it
afterwards. Leave it out for a component that only carries data or behaviour;
plenty of those have an enabled field that has nothing to do with drawing, and
switching it off would stop the wrong thing.
Built-in components
Section titled “Built-in components”The engine registers 77 components you query alongside your own — Transform,
Sprite, ShapeRenderer, Camera, Light, ParticleEmitter,
SpineAnimation, TilemapLayer, the UI set, the physics colliders, and more.
Each subsystem guide teaches the ones it owns; the
component reference lists every one of them
with its fields, types and authoring defaults, derived from the same registry the
editor’s Details panel reads.
The ones the engine reads about your entities
Section titled “The ones the engine reads about your entities”Four of them carry no subsystem of their own — they are how the engine and the editor describe an entity to themselves, and you will meet them in the Outliner and in scene files before you ever query them.
| Component | What it is |
|---|---|
Name |
The entity’s display name — what the World Outliner shows and what name lookups resolve against. |
Parent / Children |
The hierarchy. The engine keeps the pair in step; see Transforms. |
Disabled |
A tag. setEntityActive(entity, false) adds it and isEntityActive is simply its absence, so “active” is a question about one component rather than a flag to keep in sync. |
RuntimeOnly |
A tag for an entity a system derives rather than one you authored — the layer entities a Tilemap projects, runtime tile colliders. Scene saving skips them, because persisting a derived entity would duplicate it against the next derivation. |
Both tags are ordinary components: query them with .with(Disabled) /
.without(Disabled) like any other, and add or remove them directly if you
prefer that to setEntityActive. Note that the Outliner’s eye is a different
thing — an edit-time visibility fold that never touches Disabled, so hiding an
entity while you work does not change what the running game does with it.
Reading and writing
Section titled “Reading and writing”Systems receive component data through a query. Wrap a component in Mut(...)
when a system writes to it, so change detection and the renderer know the data
was touched:
Query(Mut(Transform), Speed)// Transform is written; Speed is read-onlyBecause writes are tracked, systems can also react to lifecycle:
Added(Comp) / Changed(Comp) narrow a query to entities whose component just
appeared / just changed — see Systems for the
full query vocabulary.
Under the hood a component is a C++ struct annotated with ES_COMPONENT /
ES_PROPERTY; the cross-boundary layout is generated, so the TypeScript
component and the C++ struct are always in sync.