Prefab system — configurable, AI-modifiable units of content
This doc names and unifies a pattern that already runs through several other docs (recipes, generators, compositions, directors, theme system). It is the noun for “the unit of reusable content in our dev experience” and the spec for the dev-tooling that lets us build, test, view, and AI-modify them.
No new architecture is introduced here. Recipe → Generator → Composition → Renderer (from
scene-construction.md) is still the pipeline; director surfaces (fromdirector-pattern.md) are still the AI loop. Prefab is the package that bundles a recipe schema + a generator + a director surface + an AI brief + a preview, presented as a single first-class concept to authors.
What a prefab is in this project
Section titled “What a prefab is in this project”In Unity, a prefab is a saved object you drag into a scene; variants override prop values. Familiar mental model — adopt it, then extend.
In our system, a prefab is the full bundle that lets a human or an AI agent produce a concrete instance of a content type:
Prefab├── Recipe schema ── Zod schema declaring the prefab's parameters├── Generator ── pure (recipe, seed) → Composition function├── Director surface ── recipe editor + intervention pipeline (per-type)├── AI brief ── prompt context for the type-specific director agent├── Preview ── thumbnail / variant grid / live render└── Metadata ── name, tags, theme affinity, provenance, versionA prefab is always configurable (its recipe parameters), always generatable (its generator produces instances), and always AI-modifiable (its director surface accepts feedback that maps to recipe patches). These aren’t optional features layered on — they’re the definition.
A prefab instance is the Composition output: a concrete arrangement of entities, rendered to the scene, with provenance back to the source prefab + seed + intervention history.
Why “prefab” is the right name
Section titled “Why “prefab” is the right name”- Unity-familiar mental model. Most contributors will read “prefab” and have a 90% accurate intuition immediately.
- First-class dev surface. “Prefab” is a noun authors can talk about. “Recipe / generator / composition” is internal vocabulary; prefab is the externally-visible thing.
- Unifies otherwise-scattered concepts. Buildings, NPCs, settlements, threads, voice cards, items, world objects — they’re all prefabs in our system. Same anatomy, same tooling, different schemas.
- Maps to the director loop directly. “Modify this prefab via prompt” is the user’s mental model; the system translates that into director-mode interventions.
Key difference from Unity prefabs: ours are recipe-driven, not instance-driven. A Unity prefab is a saved instance you spawn copies of; ours is a parametric description that generators turn into instances. Variation lives in the recipe, not in per-instance overrides.
Prefab anatomy (the six artifacts)
Section titled “Prefab anatomy (the six artifacts)”For a hypothetical Building prefab in packages/content/prefabs/cottage/:
packages/content/prefabs/cottage/├── schema.ts ── Recipe schema (Zod): footprint, roof, materials, …├── generator.ts ── (recipe, seed) → Composition function├── director.md ── AI brief for `cottage-director` subagent├── preview.ts ── How to render a thumbnail / variant grid├── meta.json ── name, tags, theme affinities, version, status└── examples/ ── canonical seed instances for regression testing ├── camelot.json ├── midgard.json └── hinterlands.jsonEvery prefab type lives in a folder like this. The structure is
enforced by a prefab-critic subagent (when it lands) — a folder under
prefabs/ without one of the six artifacts fails its PR check.
Recipe schema
Section titled “Recipe schema”The parameters the prefab accepts. Zod-validated. Defines the configuration surface.
import { z } from 'zod';
export const CottageRecipe = z.object({ id: z.string(), kind: z.literal('cottage'), seed: z.number().int(), footprint: z.object({ width: z.number().min(3).max(8), depth: z.number().min(3).max(8), }), roof: z.enum(['gable', 'hip', 'shed']), materials: z.object({ walls: z.string(), // asset key roof: z.string(), door: z.string(), }), hasChimney: z.boolean().default(true), windowCount: z.number().int().min(0).max(6).default(2), theme: z.string().optional(),});export type CottageRecipe = z.infer<typeof CottageRecipe>;Generator
Section titled “Generator”Pure function. Recipe + seed → Composition. Deterministic.
export function generateCottage( recipe: CottageRecipe, ctx: GenContext,): Composition { // … procedural composition using ctx.procgen + ctx.assets}Director surface
Section titled “Director surface”Per-prefab-type director: selection modes, intervention levels, AI brief.
export const cottageDirector: DirectorSurface<CottageRecipe> = { type: 'cottage', interventions: [ 'composition-patch', // move/delete an entity 'recipe-patch', // change footprint/roof/materials 'seed-reroll', // same recipe, new seed 'generator-suggestion', // propose code change ], agentBrief: './director.md', fieldEditors: { /* leva spec per recipe field */ },};AI brief
Section titled “AI brief”Markdown file consumed by the type-specific director agent. Defines the prompt context for AI modifications:
# cottage-director brief
Recipes describe a single residential cottage in a the chosen asset pack-aesthetic world…
## Constraints- Footprint: 3-8m on each axis (small/medium scale only — manors and taverns are separate prefabs)- Roof types: gable / hip / shed; pitched, never flat- Materials must be drawn from the asset manifest's `cottage-eligible` tag
## Tonal anchors- the project's tonal register: a cottage is a small home for a small life- Theme-specific material palettes (Theme-A ≠ Theme-B ≠ Theme-C)
## Common intervention shapes- "make it bigger" → footprint +1-2m, possibly chimney removal- "less generic" → vary window placement, add asymmetry to roof- "doesn't fit this theme" → swap materials per theme paletteThe director agent reads this brief plus the current recipe + composition when processing user feedback.
Preview
Section titled “Preview”How to produce a thumbnail or live render of the prefab:
export const cottagePreview: PrefabPreview<CottageRecipe> = { defaultRecipe: () => ({ /* a canonical "neutral" recipe */ }), cameraFraming: 'building-3q', // standard framing preset variantGridSeeds: [1, 7, 42, 137, 1024], // for "show me variations"};Metadata
Section titled “Metadata”{ "name": "Building", "tags": ["residential", "small", "low-poly"], "realmAffinities": ["camelot", "hinterlands"], "status": "stable", "version": "1.0.0", "author": "system", "supersedes": null}Prefab types — initial catalogue
Section titled “Prefab types — initial catalogue”What we’ll have prefabs for, roughly in build order:
| Type | Parameters drive | First instance | Director agent |
|---|---|---|---|
| Building | Footprint, roof, materials, windows | camelot.json | cottage-director |
| Building | Footprint, anchor role, signage | hinterlands-tavern.json | inherits scene-director |
| Building | Multi-storey footprint, courtyard | tbd | inherits scene-director |
| Building | Footprint, steeple, denomination flavour | tbd | inherits scene-director |
| NPC | Voice card ref, archetype, equipment, behaviour | hella.json | npc-director |
| Settlement | Patches, anchors, population, threads | example-village.json | scene-director (already exists) |
| Region | Terrain, settlements, POIs, scatter | tbd | scene-director |
| Thread | Anchors, beats, branches, completion | welcoming.json | thread-director |
| Voice card | Register, vocabulary, quirks | hella.json | voice-card-director |
| Dialogue corpus | Slot variants, theme verdicts | hella-corpus.json | dialogue-corpus-director |
| Item | Stats, art, flavour, rarity | tbd | item-director |
| World object | Mesh, interaction, lifecycle | tbd | inherits scene-director |
| Ambient marker | Position, audio, particle, fade | tbd | scene-director |
Many directors are shared (the scene-director handles anything spatial); specialists exist where the content type has its own grammar (threads, voice cards, dialogue).
Prefab composition (hierarchical embedding)
Section titled “Prefab composition (hierarchical embedding)”A prefab’s recipe can reference other prefabs. The Settlement prefab’s recipe lists NPCs, Buildings, Landmarks — each a reference to another prefab + a specific recipe variant + a placement.
// example-village recipe (simplified){ kind: 'settlement', patches: { /* … */ }, anchors: [ { role: 'tavern', prefabRef: { type: 'tavern', recipe: 'hinterlands-tavern' }, placement: 'center', }, { role: 'cottage', prefabRef: { type: 'cottage', recipe: 'cottage-modest' }, placement: 'ring', count: 5, }, ], population: [ { prefabRef: { type: 'npc', recipe: 'hella' }, placement: 'tavern-doorstep', }, ],}When the settlement generator runs, it ctx.subGenerate('cottage', recipe.anchors[1]) for each cottage, which produces a Composition; the
settlement composition flattens those into its entity list with
provenance attribution.
This is how Unity’s prefab-of-prefabs nesting works, but in our system it’s just a recipe field referencing another recipe. No special serialisation, no nested-prefab override system.
Prefab inheritance / variants
Section titled “Prefab inheritance / variants”Recipes can extend other recipes via a parent field:
{ "parent": "cottage-base", "materials": { "walls": "synty/camelot/wattle-daub", "roof": "synty/camelot/thatch", "door": "synty/camelot/oak-plank" }, "windowCount": 3}The recipe loader resolves inheritance at load time — apply parent fields, then override with child fields. Validate the merged result against the schema.
Inheritance is one level deep by default; deeper hierarchies need explicit opt-in (avoid the Unity prefab-variant labyrinth).
The AI-assisted loop (concrete user flow)
Section titled “The AI-assisted loop (concrete user flow)”- User opens the prefab editor for
Building. Sees current recipe on the right, live preview on the left, variant grid below. - User adjusts a slider (window count: 2 → 4). Preview re-renders in <100ms (deterministic generator on a stable seed).
- User clicks a building in the preview and types: “this side of the cottage feels too plain — break it up with a small lean-to.”
cottage-directoragent receives: selection (the entity clicked), feedback text, current recipe, current composition slice, the AI brief, available asset tags. Emits an intervention.- Intervention applied + validated: recipe patches
leanToSide: 'east'(or composition patch if simpler). Tier 0 checks pass. Theme Critic approves. - Diff preview shows before/after side by side. User clicks Accept.
- Recipe saved to disk. New variant
cottage-with-lean-to.jsonis either an in-place edit or a new variant depending on user intent (the editor asks). - Provenance log appended — recording the feedback that produced the change, for replay / audit / training-data-future.
This is the same loop the director-pattern doc describes. The prefab system is its packaging — every prefab type has its own slice of this loop, with its own director agent and editor surface.
Dev tooling: the Prefab Browser
Section titled “Dev tooling: the Prefab Browser”The most-used dev surface in this whole system. Looks like Unity’s Project panel cross-bred with a 3D asset browser.
┌──────────────┬──────────────────────────────┬─────────────┐│ Prefab types │ Browser grid │ Inspector ││ │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │ (selected ││ ▾ Buildings │ │ │ │ │ │ │ │ │ │ prefab's ││ Building │ └──┘ └──┘ └──┘ └──┘ │ recipe + ││ Building │ ┌──┐ ┌──┐ ┌──┐ ┌──┐ │ metadata) ││ Building │ │ │ │ │ │ │ │ │ │ ││ ▾ NPCs │ └──┘ └──┘ └──┘ └──┘ │ ││ an example NPC │ │ ││ ▾ Settlements│ ↑ thumbnails per variant │ ││ Settlement A │ │ ││ ▸ Threads │ │ ││ ▸ Voices │ │ │├──────────────┴──────────────────────────────┴─────────────┤│ Search · Filter (theme, tag, status, author) · Sort │└────────────────────────────────────────────────────────────┘Standard dev-tooling-ui.md conventions apply (three-panel layout, Cmd-P palette, scrubbable numeric inputs, etc.).
Per-prefab actions (right-click or button row):
- Open editor (full-screen director surface)
- Generate variant (open editor with a forked recipe)
- Variant grid (5×5 seed shuffles for visual variance check)
- Add to scene (drop the prefab into the current scene at cursor)
- Find references (which scenes / parent prefabs use this)
- History / provenance (every intervention this prefab has been through)
- AI: regenerate from prompt (open a quick-action prompt, send to the type-specific director, preview result)
Prefab testing
Section titled “Prefab testing”A prefab passes when:
- Schema validates for every example recipe in
examples/ - Generator is deterministic — same
(recipe, seed)produces identical Composition across runs (Tier 0 probe) - Generator output passes per-type Tier 0 assertions (no overlapping entities, walkable gaps, expected anchor count, tonal- flags clean, etc.)
- Variant grid renders cleanly at the canonical seeds (smoke test that no seed crashes)
- Theme Critic approves the canonical examples
Failing any of these blocks merging the prefab. The prefab-critic
subagent enforces.
What this isn’t
Section titled “What this isn’t”- Not Unity prefab variants with override stacks. We use recipe inheritance (one level by default); overrides are recipe field changes, not per-instance.
- Not a runtime concept. Players never see “prefab”; they see the generated world. Prefabs are an author-time abstraction.
- Not a way to bypass the director discipline. Every prefab edit still goes through the apply pipeline (validate → Tier 0 → Theme Critic → diff preview → accept).
- Not coupled to Three.js or Colyseus. Prefab data is JSON; rendering
- sync are downstream concerns. (Per
abstraction-discipline.md.)
- sync are downstream concerns. (Per
- Not a place for game balance. Stats, costs, drop rates — those live in the item / skill / economy systems, not generic prefab fields.
Build order
Section titled “Build order”- Prefab folder convention + critic (
prefab-criticsubagent that validates folder structure on PR) — week one - Building prefab as the first concrete instance (schema + generator + AI brief + 1 example). Validates the pattern.
- Prefab Browser dev surface — lists prefab types, shows the cottage, opens its editor
- Scene-director extension — handles “drop a cottage into the scene” via the prefab system, not as a one-off
- Settlement prefab — first composing prefab; tests prefab-of- prefabs flow
- NPC + Voice card prefabs — port from MyProject canon
- Thread prefab + Dialogue corpus prefab — port and adapt
- Variant grid + AI quick-action prompt in the browser
- Inheritance support for recipe extension
- Asset director becomes a prefab director for raw source assets (same UI, different content type)
Cross-references
Section titled “Cross-references”scene-construction.md— the underlying Recipe → Generator → Composition → Renderer pipeline that prefabs usedirector-pattern.md— the AI loop every prefab’s editor surface builds ondev-tooling-ui.md— UI conventions every prefab editor followsin-game-ui.md— separate concern; prefabs are dev-time, in-game UI is player-timeabstraction-discipline.md— prefab data is JSON, decoupled from any specific enginesubagent-roster.md— per-prefab-type director agentsmaterial-system.md— material roles named in prefab recipes; framework resolves to tier-appropriate concrete materials