91 lines
6.9 KiB
Markdown
91 lines
6.9 KiB
Markdown
# ADR 0045: Content Workspace and Material Fallback Contract
|
|
|
|
## Status
|
|
|
|
Accepted
|
|
|
|
## Context
|
|
|
|
Blacksite's Content Browser scans the project `assets/` tree, but authored RON type detection and
|
|
import destinations still depend on conventional folders. The asset registry is editor-owned and
|
|
serialized as an unversioned record list, so validation, packaging, runtime hydration, and future
|
|
headless processing duplicate parts of its contract. Imported model materials are either read-only
|
|
source defaults or scene-level assignments; a model asset cannot own editable project defaults.
|
|
|
|
Missing renderer materials currently create separate magenta `StandardMaterial` values, while
|
|
skinned, primitive, brush, terrain, thumbnail, raster, and Solari paths use different fallback
|
|
rules. A missing or broken material therefore does not have one predictable, production-safe
|
|
result.
|
|
|
|
## Decision
|
|
|
|
- User-authored content may live in any normal nested folder beneath the project `assets/` root.
|
|
Folder names are organizational only. External absolute linked assets are not supported.
|
|
- `AssetId` is authoritative identity. Project-relative paths and labels are repairable cached
|
|
metadata. Moves and reimports reconcile by stable IDs and never by display name.
|
|
- Registry contracts move to `shared::content`: typed asset kinds, versioned registry documents,
|
|
project content defaults, import settings, model material policies, and runtime catalog records.
|
|
UI-independent filesystem scanning, classification, transaction planning, import/reimport, and
|
|
processing live in a `content_pipeline` crate used by the editor, validator, watcher, and xtask.
|
|
- Registry schema v3 is `AssetRegistryDocument { schema_version, defaults, records }` with typed
|
|
Model/Texture import settings as extended by [ADR 0046](0046-schema-driven-material-inputs-and-processed-textures.md). The source
|
|
registry remains editor-managed under `assets/.index/`; packages receive a stripped runtime
|
|
catalog without editor import provenance or source-only dependencies.
|
|
- Project content roots normalize to `assets/`. `.index`, `.trash`, thumbnails, recovery data, and
|
|
implementation-owned derived artifacts are hidden and protected from normal file operations.
|
|
- Fixed-folder consumers are retired or explicitly constrained as follows:
|
|
|
|
| Consumer | Current contract / migration |
|
|
|----------|------------------------------|
|
|
| Project settings and templates | `asset_roots` upgrades to exactly `["assets"]`; the explicit project upgrader performs the write. |
|
|
| Content Browser and registry scanner | Walk all user-managed descendants and classify by extension plus document schema, never by parent folder. |
|
|
| Material, shader, model, audio, level, and prefab lookup | Resolve the registry's stable ID to its current path; a cached path is a repair hint only. |
|
|
| Scene/prefab validation and hydration | Consume registry/runtime-catalog resolution rather than conventional authoring directories. |
|
|
| Packaging and headless processing | Scan the same content root and publish the same stripped catalog and normalized model manifests. |
|
|
| Material creation UX | The current browser folder is authoritative; `assets/materials/` remains only a Material Library convenience default. |
|
|
| Generated mesh, animation, navigation, thumbnail, trash, and index data | Their fixed implementation-owned locations remain hidden managed storage, excluded from user classification and ordinary file operations. |
|
|
|
|
- Model material selections are per stable slot: Source, Project Material/Instance, or Default.
|
|
Extracting a source material creates an ordinary project Material and then stores a Project
|
|
selection. Re-extraction may replace a provenance-matched Material only after an explicit diff
|
|
and fingerprint-guarded Apply decision; Create New remains available and unrelated provenance is
|
|
never overwritten. Reimport retains removed project assignments as explicit orphans.
|
|
- Effective material precedence, strongest first, is: runtime MaterialPropertyBlock, scene/prefab
|
|
assignment, model-asset default, imported source, project default, built-in DefaultGrid. Missing
|
|
layers inherit downward. A configured but broken authored reference renders the fallback and
|
|
reports the broken layer rather than silently revealing a different authored layer.
|
|
- Primitive surfaces participate in that same chain through their saved
|
|
`slot:primitive:surface`; they no longer hydrate from a separate actor-local descriptor. Static
|
|
and skinned draws bind their exact saved slot IDs through the same runtime binding contract.
|
|
- DefaultGrid is immutable engine content compiled into the renderer. It is a shared,
|
|
UV-independent world-space checker with raster/Solari parity and a neutral StandardMaterial
|
|
emergency path. A project may choose a Material/Instance fallback; clearing or breaking it
|
|
returns to DefaultGrid. Terrain retains its specialized layer fallback.
|
|
- Built-in DefaultGrid is not editable, instanceable, or a valid MaterialPropertyBlock promotion
|
|
base. Promotion requires a resolved project or imported Material base.
|
|
- Ordinary editor/runtime loading is read-only. Registry, project-settings, and scene migrations
|
|
run only through the explicit transactional project upgrader.
|
|
|
|
## Consequences
|
|
|
|
- Editor, runtime, validation, packaging, watcher, and headless processing share one content model
|
|
and one stable-ID resolver.
|
|
- Arbitrary organization no longer changes asset type, runtime behavior, or package inclusion.
|
|
- The content pipeline becomes a reusable crate boundary instead of an editor implementation
|
|
detail; this adds one workspace crate and moves registry types out of `editor`.
|
|
- Older registries, conventional asset roots, global model material policy, and legacy mesh material
|
|
overrides require the explicit transactional upgrader; normal loading accepts current schemas.
|
|
- Broken assignments stay visible and diagnosable, but may look different from their previous
|
|
imported source because failure uses the project/engine fallback deliberately.
|
|
- One cached DefaultGrid/emergency handle covers repeated primitive and mesh hydration, so missing
|
|
assignments do not grow the material asset stores.
|
|
- Thumbnail cache ownership includes the backing Egui image registration. Replacement, retry, and
|
|
catalog invalidation explicitly release the last registration before a new studio render owns
|
|
the key, preventing refresh-driven GPU resource growth.
|
|
- File operations and imports must be staged transactions that update authored references,
|
|
registry state, derived manifests, and runtime catalogs together.
|
|
- Ordinary asset-property edits use the explicit dirty-document and two-phase publication boundary
|
|
defined by [ADR 0047](0047-editor-authored-asset-documents.md); topology transactions remain immediate.
|
|
- Scene schema v6 carries actor/model/imported/inherit origin explicitly at hydration time, so a
|
|
broken authored layer uses DefaultGrid instead of accidentally revealing a weaker layer.
|