# Prefab Authoring

Blacksite prefabs are schema-versioned `.scn.ron` documents under `assets/`. A placed prefab stays
linked through its authored `PrefabInstance`; entities loaded from the source are runtime-owned
members and are never flattened into the scene that contains the instance.

## Create and place a prefab

1. Select one or more authored actor roots.
2. Choose **File > Save Selection As Prefab...** and save under `assets/prefabs/`.
3. Place the resulting prefab from the Asset Browser. The placed root exposes a **Prefab Instance**
   component with its stable asset ID and source path.

Saving expands the selected authored hierarchy. Hydrated prefab members and composed-scene members
are excluded from the prefab file. Missing or duplicate authored `ActorId` values are repaired before
a direct prefab save; a failed save restores the original in-memory IDs.

## Stable identity and layering

An override target is not a runtime `Entity` or display name. `PrefabActorPath` stores the target
actor's stable `ActorId` plus the `ActorId` chain of every nested prefab anchor needed to reach it.
Two nested copies may therefore contain the same source actor IDs without sharing override identity.

The hydrated result is resolved from least to most specific:

1. the source prefab document;
2. each nested link's own overrides;
3. the containing variant document and its authored local structure;
4. the overrides on the placed instance.

The override schema and runtime application live in `crates/shared`, so standalone and packaged game
builds apply the same data without loading the editor plugin.

## Instance overrides

Select a generated prefab member to edit its override layer. The current inspector exposes:

- **Property overrides** for Transform position, rotation, and scale, plus Material base color,
  metallic, and roughness.
- **Component overrides** for adding, replacing, or removing `MaterialDesc`, plus visibility on
  direct or nested generated actors.
- **Structural overrides** for removing a source actor or reparenting generated actors within the
  same instance layer. Hierarchy **Unparent override** writes the same stable structural operation.

These edits update `PrefabInstance.overrides_ron`; they do not immediately edit the source asset.
Use **Revert** at field scope, **Revert component overrides**, **Revert actor overrides**, or
**Revert all** at instance scope. Each edit/revert is one undoable prefab-state command.

Legacy root transform/material data and name-keyed visibility data still load. Current operations
use the full stable `PrefabActorPath`, so repeated leaf `ActorId` values in sibling nested instances
remain distinct.

## Apply to source

**Apply to source** is an explicit source-asset write, not another name for storing an instance
override. It is available for a field, component, generated actor, or all operations on the placed
instance.

For a direct target, Blacksite patches the linked source document. For a target reached through a
nested `instance_chain`, it moves the operation into the immediate nested link recorded by that
source layer. This preserves the base/variant boundary instead of unexpectedly mutating the deepest
leaf prefab.

Before writing, Blacksite compares the recorded base with the current source value, serializes the
patched document, validates the complete dependency graph, and performs an atomic same-directory
write. The history entry stores exact before/after source bytes and the old/new instance state.
Undo or redo is blocked if another process changed the source after the command; Blacksite reports
the block instead of overwriting that external work.

## Source status and conflict recovery

The **Prefab Instance** card combines hydration state, transitive graph validation, recorded source
revision, stable target resolution, and base-value checks:

- **Loading source** - wait for hydration before unpacking or editing generated targets.
- **Ready** - the graph is valid, the recorded revision matches, and overrides resolve cleanly.
- **Base not tracked** - a legacy instance has no revision. **Accept current base** records it without
  changing override values.
- **Base changed** - the source graph changed but no semantic conflict was found. Inspect the result,
  then **Accept current base** or relink.
- **Override conflict** - a target disappeared or a source property/component/parent changed from the
  base captured by an override. **Keep overrides** rebases the stored bases, while **Take source**
  removes only semantically conflicting operations. **Remove stale overrides** cleans unresolved
  legacy visibility keys; **Relink...** selects another valid source.
- **Broken source** - a source is missing or its graph/path/identity validation failed. Hydrated
  generated state is removed, the authored anchor remains repairable, and **Retry source** or
  **Relink source...** starts one clean hydration attempt.
- **Invalid overrides** - the serialized override payload is malformed. **Discard invalid data**
  resets that payload explicitly.

Accept, keep/take, stale cleanup, relink, and source Apply participate in undo/redo according to
their scope. Reload and Retry refresh hydration without creating an authoring history entry.

## Local children and hierarchy overrides

Authored local actors may be created or reparented below a linked instance root or another authored
local actor. Nested linked prefabs may be placed there as well. Those entries remain normal
scene-owned content: they can be selected, transformed, reordered, saved, and undone.

Rows carrying `HydratedPrefabMember` are generated context. Their Transform/Material fields are
edited through overrides rather than direct source mutation. Generated actors may be removed or
reparented only within the same owning instance and nested layer. Cross-instance, cross-layer, and
composition-boundary drops are rejected. Between-row ordering of generated siblings is not modeled,
and authored local children cannot yet attach directly to a generated source member.

## Save a variant

Variants use normal linked-prefab composition rather than a separate asset type:

1. Start with a linked prefab instance and author its instance override layer.
2. Add local children or nested prefab instances below its root/local structure.
3. Select the linked root and choose **Create Variant...** in the Prefab Instance inspector, or use
   **File > Save Selection As Prefab...**.

The saved prefab contains the base `PrefabInstance` link, its stable overrides, and local authored
structure. Hydrated base members are excluded. Placing the variant therefore evaluates base, nested
layers, variant, and placed-instance overrides in order without duplicating generated actors.

Applying an override on a nested source actor writes it to the immediate link in the variant/source
document; open the leaf prefab itself when the intended change should affect every use of that leaf.

## Unpack and convert

**Unpack Layer** removes only the selected outer `PrefabInstance`/`PrefabRef` ownership link and
turns its hydrated members into authored local actors. Nested prefab instances remain linked, and
outer overrides targeting them are folded into those retained links transactionally. Undo restores
the outer link and removes the local copy; redo restores the captured authored result.

**Convert to Local** recursively removes the selected outer link and every generated or authored
local nested prefab link below it. Every converted hydrated source actor receives a fresh local
`ActorId`, including actors from different nested documents that originally reused an ID. The
operation is one undo step and redo uses captured snapshots, so it does not depend on the source
files still being present.

## Validation and remaining acceptance

Prefab save, editor load, project inspection, and `cargo validate-levels` recursively inspect linked
`PrefabInstance` components. Validation rejects missing sources, unsafe paths (including symlink
escapes), non-`.scn.ron` sources, cycles (including path aliases), empty asset IDs, incomplete link
anchors, malformed outer or inner override payloads, missing authored `ActorId` values, and
duplicate IDs within a document. The committed `assets/prefabs/example_base.scn.ron` ->
`example_nested.scn.ron` -> `example_variant.scn.ron` chain is the healthy production-format
fixture for this gate.

The shared format can apply registered reflected property/component operations, but the current
authoring UI exposes the Transform and Material fields/components listed above. Generated sibling
ordering and direct local-child attachment to a generated member are not yet override operations.
Variants remain ordinary composed prefab documents rather than a separately named asset type.

Production acceptance closed in Gitea issue
[#43](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/43) after the
complete workspace suite, recursive headless validation, packaged release startup, and live editor
placement/inspection regression passed against the committed fixture chain.

See [ADR 0027](../adr/0027-stable-prefab-ownership-and-variants.md) for the ownership, stable identity,
layering, and source-write contract.
