Skip to content

Prefabs ​

A Prefab is a saved object subtree you can stamp into a scene over and over - a reusable template for anything from a single crate to a fully-scripted first-person player. This page explains how prefabs are saved, instanced, and how their dependencies are resolved.

What a prefab is ​

A prefab is a serialized subtree: an object, all of its descendants, and all of their components, captured as a small SceneJSON blob and stored in the project's prefab library under a name. The instances you place stay linked to it: Apply an instance's changes and every instance follows. It is the same on-disk shape as a scene - just a fragment of one rather than the whole world.

Prefabs are part of the Project Bundle, so they travel with your project, and a single prefab can also be exported as a self-contained .awakenpkg package - right-click it and choose Export as package… - that bundles the prefab plus every asset it references, for sharing between projects or publishing to the Asset Store.

Save as Prefab ​

Select an object in the Hierarchy, right-click it, and choose Save as Prefab. The whole subtree under that object is snapshotted into the prefab library, named after the object (or Prefab, Prefab 2 and so on if it has no name), and rebased so its root sits at the origin. The prefab now appears under Prefabs in the Asset Browser. The objects you saved it from become its first instance: every one of them is linked to the prefab (see Linked instances). The save is one undo step.

When a prefab with that name already exists, Awaken asks before it writes anything (prefabSaveIntent in apps/editor/src/state/commands.ts):

The object is...What you are askedWhat happens
The root of an instance of that very prefabApply this object's changes to it?The same as the Inspector's Apply: part ids are kept and every instance follows.
Anything elseA name for the new prefab, prefilled with a free one (Crate 2)A new name saves a new prefab. Keeping the old name replaces that prefab: its placed instances, in the open scene, the library scenes and other prefabs, are unlinked and keep their objects exactly as they are. The prompt says how many there are.

Typing the name of a different existing prefab asks once more, with a Replace confirm. Undo of a replace puts the old prefab and every link back.

The Hierarchy right-click context menu with Save as Prefab highlighted on the Ramp.

Instancing a prefab ​

There are several ways to drop a prefab into the current scene, all of which produce one undoable step:

  • Drag the prefab from the Asset Browser into the Viewport - it lands at the cursor, snapped to the surface (or ground plane) under the drop point.
  • Drag it onto the Hierarchy, or double-click it in the Asset Browser - it lands at the camera focus point (where you're looking).
  • Select the prefab and press Add to Scene in its Inspector preview.

Each instance is its own deep copy of the prefab's objects. Object-valued fields are cloned on instantiate, so a script mutating one instance's transform (a rotator, a mover) never corrupts the prefab or its siblings. What ties an instance back to its prefab is a link on each of its objects, not shared data.

The prefab Inspector for the Physics playground's Ball: a rotatable 3D preview of its sphere, the object, vertex and triangle counts, its components and mesh as chips, and Add to Scene.

Linked instances ​

Every object of an instance carries a PrefabLink component (packages/core/src/prefabLink.ts): prefab (the prefab's name) and part (which of the prefab's objects this is, by its id in the prefab JSON). The link is how an edit to a prefab finds every instance of it in every scene.

Overrides are not stored. Any field of an instance that differs from the prefab's value is an override, worked out by comparing the two (instanceOverrides in apps/editor/src/state/prefabs.ts). The instance root's position and rotation are always the instance's own and never count.

A Script component's scripts are compared setting by setting: each script's on/off and each of its fields is an override of its own. Three cars from one prefab can each set their own skill on their driver script and still all take a new grip you apply to the car script. An instance that adds, removes or reorders scripts has a script list of its own, and keeps it when the prefab changes.

A reference to an object outside the instance, such as a speedometer's car or an AI driver's path, is also the instance's own. A prefab cannot hold one (it saves as none), so it is not an override, and Apply, Revert and prefab changes leave it in place.

Select any object of an instance and the Inspector shows a prefab bar above its components: the prefab's name, N overrides or matches prefab, and five buttons. Overridden fields are marked in blue.

ButtonWhat it does
SelectOpens the prefab in the Inspector.
ApplyWrites this instance's overrides into the prefab. Every instance of it, in the open scene, in every library scene and inside other prefabs, takes the new values wherever it still had the old ones, and keeps its own overrides elsewhere. New objects you added under the instance become parts of the prefab.
RevertTakes the prefab's values back (the root keeps its position and rotation).
UnpackRemoves the links: the objects stay as they are and no longer follow the prefab.
Variant...Saves this instance as a new prefab that derives from this one (see below).

Apply and Revert are enabled only when the instance has field overrides. A change that is only structural (an object added or removed, a component removed) leaves them disabled, and moving an object to another parent inside an instance is not carried to the other instances.

Apply is one undo step, and undo reaches everything it touched: the prefab, every prefab and library scene it changed, and the instances of nested and variant prefabs in the open scene.

Variants and nesting ​

A prefab's JSON can itself hold objects linked to another prefab:

  • Nesting. Place an instance of prefab A inside an instance of prefab B and Apply B: B now holds a linked copy of A. An edit to A reaches B, and from there B's instances.
  • Variant. Variant... names a new prefab whose objects all stay linked to the base. The base's changes reach the variant except where the variant differs, and the instance you made it from becomes an instance of the variant.

An edit travels up to two prefabs along a nesting or variant chain (propagatePrefab).

Part ids are never reused ​

A prefab keeps a nextPart counter in its JSON (SceneJSON.nextPart): a part added on Apply takes the next id, never the id of a part that was deleted. Without that, an instance that still held the deleted part would mistake the new part for it and take its name and components. A prefab saved before the counter existed counts as one past its largest id, so its links keep working. The counter is editor bookkeeping and is stripped from shipped scenes.

Old scenes ​

Scenes are SCENE_VERSION = 5. Instances placed in a scene saved at version 4 or earlier load as plain objects with no link: they keep everything they had and do not follow later prefab edits.

Spawning from scripts ​

api.spawn(prefab, opts?) instantiates a prefab while the game runs and returns its root entity, or null for an unknown name. The options are all optional:

OptionEffect
position, rotationThe root's pose. Local to parent when one is given.
parentPut the new root under this entity. A UI prefab spawned into a UI screen is shown, hidden and scaled with that screen. A dead or missing parent leaves the root at the scene root.
nameRename the new root, so several spawned copies answer to different names.
ts
const grid = api.find("Level Grid")!;
for (let i = 0; i < 8; i++) {
  const tile = api.spawn("Level Tile", { parent: grid, name: `Tile ${i}` });
}

Spawned colliders join the running physics simulation. A spawned instance carries no editor link. api.destroy(entity) (or api.world.destroyEntity) removes the entity and everything under it, so destroying a spawned tile takes its labels and icons with it. With no argument, api.destroy() destroys the script's own object, its children included.

Prefabs you made ship in an export, so a script can spawn them. The prefab palette an imported Unity, Godot or Unreal pack brings in stays in the project and is left out of the game.

Auto-binding entity-ref parameters ​

Scripts often need to point at another object - a first-person controller needs the camera, for example. When those references are exposed as component-filtered entity parameters, instancing auto-binds them: for each unset entity-ref parameter, if the scene contains exactly one matching object, that object is bound automatically.

So dropping a "First Person Player" prefab into a scene that has a single Camera wires the player's camera slot to it with no manual step. When there are zero or more than one candidates the binding is left unset - the choice is ambiguous, so it's yours to make in the Inspector. The same auto-bind runs when you assign a script directly to an object.

Prefab dependencies ​

A prefab does not embed the assets it uses - it references them by id. That keeps prefabs small and lets several prefabs share one script, material, graph, or effect. The trade-off is that a prefab is only fully functional if those assets exist in the project.

A prefab's dependencies are collected from the components in its subtree (deduplicated, order-stable). This one walk drives two things: what a self-contained .awakenpkg package bundles, and what the importer must resolve when you bring in a references-only .awakenprefab (the older portable form that points at its dependencies by id):

DependencyRead fromFile to locate
Scriptsevery entry in a Script component's script list (and the legacy single-script field on pre-v4 prefabs).awakenscript
Materialsa MeshMaterial component's material id.awakenmat
Anim graphsan AnimStateMachine component's graph id - builtin: graphs are always available and are skipped.awakenanimgraph
Particle effectsa ParticleEmitter component's effect id.awakenfx

The .awakenfx case is easy to miss because nothing looks broken without it: an emitter whose effect id isn't in the project imports "successfully" and then simply emits nothing, silently. The starter Fire prefab is exactly this shape - one object with a ParticleEmitter pointing at the fire effect and no geometry of its own - so importing Fire.awakenprefab without Fire.awakenfx gives you an invisible, inert object.

The Locate Dependency flow ​

When you import a .awakenprefab whose dependencies aren't already in the project, Awaken walks the missing list - scripts, then materials, then anim graphs, then particle effects - and opens a Missing script / Missing material / Missing animation graph / Missing particle effect dialog for each:

  • Locate… lets you pick the matching file; it is imported through the normal import path (so a located .awakenscript compiles, a .awakenmat validates), and Awaken checks that the file actually provides the requested id - a wrong file is reported rather than silently failing at Play.
  • Skip imports the prefab anyway - it loads and can be placed, but stays inert for that dependency until you add the asset later.
  • Whatever is still missing at the end is listed in the Console as Imported prefab "Name" - unresolved: <ids>. That line is the record of what to go and find; check it after every prefab import.

Multiple missing-dependency requests are queued and shown one at a time, so importing several prefabs at once never drops a prompt.

Avoiding the prompts ​

Two shapes of import resolve everything by themselves:

  • Drop the prefab together with its dependency files (or the whole starter-content folder) in one go. Dependencies in the same drop are imported before the prefab, so there is nothing left to locate. A prefab dropped on its own still prompts.
  • A self-contained package - a .awakenpkg (from Export as package… or the Asset Store) carries the prefab plus every asset it references. It merges straight in, skipping any id the project already has, with no prompts at all. Older binary .awakenprefab packs import the same way (both are content-sniffed, so a plain JSON .awakenprefab still takes the Locate flow above).

See also ​

Awaken: browser-native WebGPU game engine.