Skip to content

Prefabs

A prefab is a saved entity tree — a template you author once in the editor and spawn many times (enemies, pickups, bullets). Instantiate one at runtime through the Prefabs resource. The prefab asset stays the single source of truth; instances can layer their own values on top.

You build a prefab visually, then spawn it from code. Everything in this section happens in the editor; the runtime API follows below.

Right-click an entity in the World Outliner → Create Prefab. The editor extracts that entity and its whole subtree into assets/prefabs/<Name>.esprefab (named after the entity) and leaves your scene untouched — the originals stay put; they aren’t swapped for an instance. To place instances, drag the .esprefab from the Content Browser into the scene, or spawn it from the Create → Prefabs category.

Double-click a .esprefab (or, from an instance, Edit Prefab) to enter Prefab Mode: the prefab opens as its own editable entity tree in the same viewport / Outliner / Details, framed in a warm accent under an Editing Prefab banner. Add, remove, rename, reparent, and tune components exactly as in a scene, then Save Prefab — every instance in every scene picks up the change. Back to Scene returns you where you were.

Not yet supported in Prefab Mode: editing a nested prefab in place, or a variant whose base isn’t flat. Play and Save As are disabled while you’re editing a prefab.

The editor in Prefab Mode, editing a Coin prefab in isolation

Prefab Mode: the Editing Prefab banner with Save Prefab / Back to scene, the prefab opened as its own entity tree — every instance updates when you save.

Drop an instance into a scene and it stays linked to its source. Change a field on the instance and it becomes an override — a per-instance value layered on top of the prefab. The editor marks overrides so you always know what’s local:

  • the instance’s root name is tinted warm in the Outliner;
  • an overridden field shows a reset arrow (↺ Reset to default) and its component gets an amber dot;
  • an Inspector filter narrows the Details panel to only overridden fields.

Reset a single field with its ↺ button and the value falls back to the prefab’s.

Right-click an instance in the Outliner (or use the Inspector’s prefab bar) for the identity actions:

Action What it does
Edit Prefab Open the source in Prefab Mode.
Select Prefab Source Reveal the .esprefab in the Content Browser.
Apply to Prefab Push this instance’s overrides back to the source — updating the base for every instance.
Revert to Prefab Discard this instance’s overrides and re-sync it to the source.
Create Variant Save a new .esprefab that inherits the base and bakes in this instance’s overrides (a prefab of a prefab).
Unpack Prefab Detach the subtree — its entities become ordinary scene entities and lose every prefab link. Undoable.

Apply is the one action that rewrites the shared asset, so it always previews an itemized diff first (“Apply changes to prefab?”) — edits in amber, additions in green, removals in red, with structural changes flagged as destructive.

instantiate loads the prefab and spawns it. It’s async and returns the spawned tree — root is the new root entity:

import { defineSystem, Res, Prefabs } from 'esengine';
const spawnEnemy = defineSystem([Res(Prefabs)], async (prefabs) => {
const { root } = await prefabs.instantiate('prefabs/enemy.esprefab');
// `root` is the new entity — move it, tag it, give it a Transform position…
});

Nest the instance under another entity, and use the returned entities map to reach children by their prefab-local id:

const { root, entities } = await prefabs.instantiate('prefabs/turret.esprefab', {
parent: mountPointEntity,
});
// root → the instance root
// entities → Map<prefab-local id, spawned Entity>, for reaching children

Pass overrides to change a value for this instance only without editing the prefab asset — spawn the same enemy with different health or tint. Each override targets a prefab entity by its string prefabEntityId (a UUID for editor-authored prefabs) and names the component + property:

const { root } = await prefabs.instantiate('prefabs/enemy.esprefab', {
overrides: [
{ prefabEntityId: '0', type: 'property', componentType: 'Health', propertyName: 'value', value: 250 },
],
});

Besides 'property', type can be 'name', 'visibility', 'component_added', 'component_replaced', 'component_removed', 'metadata_set', or 'metadata_removed' (the metadata forms use metadataKey in place of componentType/propertyName).

Option Type Description
parent Entity Nest the instance under this entity.
overrides override[] Per-instance component-value changes.
baseUrl string Base URL for resolving the prefab’s assets.
Result field Description
root The instance’s root Entity.
entities Map<prefab-local id, Entity> for reaching children.
  • One prefab, many instances — keep shared data in the prefab and vary instances with overrides, so a design change updates every instance.
  • Reach children via the entities map, not by walking the hierarchy by index.
  • Parent at spawn (parent) rather than re-parenting after, so transforms resolve correctly on the first frame.
  • Apply-to-prefab in the editor to push an instance’s tweaks back to the source when a change should be global.
  • Scenes — scenes are where prefab instances live.
  • Assets — prefabs are assets, loaded on first instantiate.