606 lines
61 KiB
Markdown
606 lines
61 KiB
Markdown
# Bevy FPS Foundation
|
||
|
||
A modular first-person game foundation and in-process editor built on **Bevy 0.19** and
|
||
**Avian 0.7** physics.
|
||
|
||
The runtime game provides a high-fidelity PBR stack (HDR, procedural atmosphere + image-based
|
||
lighting, cascaded shadows, SSAO, TAA, bloom, fog, ACES tonemapping) plus Hybrid Auto Solari
|
||
raytraced indirect lighting where supported, and local input/presentation glue for a fixed-step
|
||
kinematic FPS simulation. The editor provides dockable egui panels, a
|
||
filtered scene hierarchy, click selection, transform gizmos, undo/redo, asset import/placement,
|
||
native Bevy scene save/load, and BRP support for external tooling.
|
||
|
||
## Requirements
|
||
|
||
- Rust (stable; pinned via `rust-toolchain.toml`)
|
||
- Git LFS for binary game/source assets: run `git lfs install` once, then `git lfs pull` after clone.
|
||
- A Vulkan-capable GPU + drivers (developed against an NVIDIA RTX 3080 Ti)
|
||
- Linux build deps for `winit`/`wgpu` (ALSA, udev, etc.) if not already present
|
||
|
||
## Repository Workflow
|
||
|
||
[`docs/authority.toml`](docs/authority.toml) classifies current documentation, active plans,
|
||
evidence, historical records, and superseded material. The complete workflow and policy index is
|
||
[`docs/workflow/codex-workflow.md`](docs/workflow/codex-workflow.md). Validate documentation changes
|
||
with `python scripts/codex/docs_audit.py`.
|
||
|
||
Codex compile/test work uses `scripts/codex/verify.py` and `scripts/codex/cargo_lane.py` so focused
|
||
checks reuse one stable development lane and broad candidate gates run only when explicitly
|
||
nominated. The direct Cargo examples below remain contributor commands, not an instruction to rerun
|
||
the full set after every edit.
|
||
|
||
| Workflow action | Command |
|
||
|-----------------|---------|
|
||
| Start a resumable task | `python scripts/codex/state.py init --goal "..." --accept "..." --slice "..." --next "..."` |
|
||
| Resume | `python scripts/codex/state.py resume` |
|
||
| Preview / run focused verification | `python scripts/codex/verify.py plan` / `python scripts/codex/verify.py fast` |
|
||
| Run a stable slice gate | `python scripts/codex/verify.py slice` |
|
||
| Inspect build storage | `python scripts/codex/build_storage.py status` |
|
||
| Run storage preflight / postflight | `python scripts/codex/build_storage.py enforce --phase pre` / `python scripts/codex/build_storage.py enforce --phase post` |
|
||
| Preview / apply safe pruning | `python scripts/codex/build_storage.py prune --dry-run` / `python scripts/codex/build_storage.py prune --apply` |
|
||
| Preserve a candidate before expiry | `python scripts/codex/build_storage.py mark-candidate-preserved --evidence <manifest> --artifact <binary-or-package>` |
|
||
| Audit documentation | `python scripts/codex/docs_audit.py` |
|
||
| Preview a named native scenario without launching | `bash scripts/codex/native_qa.sh plan material-slot-live-edit` |
|
||
| Sync tracker state | Ask Codex to use `blacksite-gitea-sync` in `read`, `plan`, or authorized `status` mode for exact issue IDs |
|
||
| Nominate / verify a candidate | `python scripts/codex/state.py nominate --commit <sha>` then `python scripts/codex/verify.py candidate` |
|
||
|
||
## Running
|
||
|
||
```bash
|
||
# Check everything
|
||
cargo fmt --all --check
|
||
cargo check --workspace --all-targets
|
||
cargo clippy --workspace --all-targets -- -D warnings
|
||
cargo clippy -p editor -p game --bins --features dev,hot-reload -- -D warnings
|
||
cargo test --workspace
|
||
cargo validate-levels
|
||
cargo validate-samples
|
||
cargo bake-navigation --project . --check
|
||
cargo process-assets --project . --check
|
||
# Refresh registry v3 and the stripped runtime content catalog after external content changes
|
||
cargo process-assets --project .
|
||
# Validate one artifact without opening a game window
|
||
cargo run -p game -- --validate-navigation assets/navigation/generated/navigation_showcase_humanoid.nav.ron
|
||
# Machine-readable project dependency and finding report
|
||
cargo validate-levels --json
|
||
cargo package-project --profile development
|
||
|
||
# Runtime game
|
||
cargo run -p game
|
||
cargo run -p game --features dev
|
||
|
||
# In-engine editor
|
||
cargo run -p editor
|
||
cargo run -p editor --features dev
|
||
```
|
||
|
||
The standalone `game` binary loads `default_level` from `assets/project.ron` as the initial authored
|
||
scene. That entrypoint must be a regular `.scn.ron` file under `assets/levels/` so validation audits
|
||
its complete runtime dependency graph. The in-process editor defers that bootstrap to its scene tabs
|
||
and `SceneIo`, so opening the editor never creates a competing runtime scene root.
|
||
|
||
Open a different validated Blacksite project before engine startup:
|
||
|
||
```bash
|
||
cargo run -p editor --features dev -- --project /path/to/project
|
||
cargo run -p editor --bin project_launcher --features dev
|
||
```
|
||
|
||
The installed **Blacksite Editor** desktop entry also exposes **Open Project Browser** from its
|
||
desktop action menu. In the editor, **File > Switch Project...** uses the guarded Save All / Discard /
|
||
Cancel shutdown path before opening the same browser; choosing a project starts a fresh editor
|
||
process with that root. A normal desktop click incrementally builds the editor and project browser
|
||
through Blacksite's persistent managed development lane before launching, so saved Rust changes are
|
||
always represented by the opened binary. The splash reports exact resolved-crate progress while
|
||
Cargo reuses warm artifacts; a build or storage-preflight failure leaves the splash open with an
|
||
actionable log. Run `~/.local/bin/blacksite-editor --build-only` to perform the same managed update
|
||
without opening the editor. Clicking the shortcut while an editor is open still performs the update
|
||
check. If the executable changed, Blacksite protects unsaved work by focusing the running process
|
||
and showing an explicit close-and-reopen notification instead of terminating it or pretending that
|
||
it has hot-swapped to the new binary.
|
||
|
||
### Hot reload (gameplay iteration)
|
||
|
||
`--features dev` turns on Bevy **dynamic linking** for faster rebuilds (recommended day-to-day).
|
||
|
||
Add `--features hot-reload` for **in-process hot reload** of [`game_hot`](crates/game_hot) (sim movement, player input/camera, world bootstrap). The editor process stays open; only gameplay system bodies swap when the dylib rebuilds.
|
||
|
||
**Two-terminal workflow (hot reload):**
|
||
|
||
```bash
|
||
# Terminal 1 — rebuild the hot dylib on save in the managed hot-reload lane
|
||
python scripts/codex/cargo_lane.py exec hot-reload -- cargo watch -w crates/game_hot -w crates/sim -x "build -p game_hot --features dylib"
|
||
|
||
# Terminal 2 — run the editor once in the same lane
|
||
python scripts/codex/cargo_lane.py exec hot-reload -- cargo run -p editor --features dev,hot-reload
|
||
```
|
||
|
||
Or use the VS Code task **watch game_hot (hot reload)** alongside **run editor (hot reload)**. The
|
||
managed tasks intentionally replace the former CodeLLDB hot-reload launch so lane-specific runtime
|
||
paths are never guessed. The watcher task requires an existing `cargo-watch` installation; this
|
||
workflow never installs it implicitly.
|
||
|
||
| Input | Action |
|
||
|-------|--------|
|
||
| Save `game_hot` / `sim` gameplay code | Dylib rebuilds; status bar shows **building…** then **reloaded** |
|
||
| **Ctrl+Shift+R** | Manual refresh (`on_hot_reload` bootstrap: camera FX, ambient light) |
|
||
|
||
**Safe to hot reload:** system logic, movement tuning in code, input mapping.
|
||
|
||
**Requires full editor restart:** new/changed component fields, new components, plugin schedule changes, editor UI code.
|
||
|
||
> Note: the workspace uses the `mold` linker via `clang` (see `.cargo/config.toml`) for fast link times.
|
||
|
||
### Focused editor UI iteration
|
||
|
||
Use the lightweight gallery when changing shared Inspector/design-system components instead of
|
||
restarting the project editor for every visual edit:
|
||
|
||
```bash
|
||
python scripts/editor/ui_gallery.py watch
|
||
```
|
||
|
||
The gallery renders the production `editor_ui` components without loading a project, scene,
|
||
renderer, or gameplay runtime. It includes exact Materials 620/420 and Renderer 760/480 presets,
|
||
direct Penpot side-by-side/overlay/difference views, representative material states, and live
|
||
theme/material fixture reload. Rust edits rebuild the focused dependency closure with a bounded
|
||
`resolved/rebuilt` counter; the last-good gallery stays open unless its replacement launches
|
||
successfully. See the [Editor Design System](docs/editor/design-system.md#focused-ui-gallery-workflow)
|
||
for shortcuts, fixtures, and acceptance rules.
|
||
|
||
### Target Cache Cleanup
|
||
|
||
Cargo/Bevy artifacts are managed as whole, sentinel-marked build lanes. Inspect and plan cleanup
|
||
before applying it:
|
||
|
||
| Command | Effect |
|
||
|---------|--------|
|
||
| `python scripts/codex/build_storage.py status` | Measure repository output, managed lanes, package caches, and free space. |
|
||
| `python scripts/codex/build_storage.py plan` | Explain policy actions without deleting anything. |
|
||
| `python scripts/codex/build_storage.py enforce --phase pre` | Enforce budgets before a heavy command; under pressure, prune only expired verified disposable lanes after printing their checked plan. |
|
||
| `python scripts/codex/build_storage.py enforce --phase post` | Recheck after the command and apply the same bounded expired-lane policy. |
|
||
| `python scripts/codex/build_storage.py prune --dry-run` | Byte-count expired disposable lanes after path/sentinel safety checks. |
|
||
| `python scripts/codex/build_storage.py prune --apply` | Remove only the verified complete lanes shown by the dry run. |
|
||
| `python scripts/codex/build_storage.py reset-lane <lane> --dry-run` | Preview an explicit whole-lane reset. |
|
||
| `python scripts/codex/build_storage.py reset-lane <lane> --apply` | Apply that explicit whole-lane reset only after reviewing its printed dry run. |
|
||
| `python scripts/codex/build_storage.py mark-candidate-preserved --evidence <manifest> --artifact <binary-or-package>` | Hash evidence and at least one preserved artifact outside the candidate lane before that lane can expire. |
|
||
|
||
Do not use an unscoped `cargo clean` as a troubleshooting reflex. Never delete individual Cargo
|
||
`deps`, `.fingerprint`, `build`, or `incremental` files by age; preserve nominated binaries/evidence
|
||
and remove only an entire verified disposable lane. See the
|
||
[build-storage policy](docs/workflow/build-storage-policy.md).
|
||
|
||
### Launch Troubleshooting
|
||
|
||
- The native game/editor windows force an opaque Wayland surface and opaque camera clears to avoid compositor alpha issues on mixed HDR/SDR desktops.
|
||
- If the window maps but appears transparent on Hyprland or another Wayland compositor, launch with `BEVY_FPS_HDR=0` to force the SDR camera path while debugging monitor/compositor behavior.
|
||
- Bevy 0.19 removed the prior local `bevy_render` swapchain-timeout patch; launch troubleshooting should start from current wgpu/driver/compositor logs.
|
||
- Normal Debug and run configurations preserve project HDR and set `WGPU_VALIDATION=0` to suppress known Bevy/Solari Vulkan memory-model VUID noise on this stack. Use **GPU validation** when actively debugging renderer work; it forces `WGPU_VALIDATION=1` and may report those known upstream/driver messages. Use **SDR fallback** for compositor/HDR mapping failures; it additionally sets `BEVY_FPS_HDR=0`.
|
||
- If **CodeLLDB / mold** fails with hundreds of `undefined symbol` linker errors, inspect the active
|
||
lane signature first. Preview a development-lane reset with
|
||
`python scripts/codex/build_storage.py reset-lane hot-reload --dry-run`, apply it only at a safe
|
||
slice boundary, then rebuild through `python scripts/codex/cargo_lane.py exec hot-reload -- cargo build -p editor --bin editor --features dev`.
|
||
|
||
## Editor Controls
|
||
|
||
| Input | Action |
|
||
|-------|--------|
|
||
| `F5` | Toggle Edit / Play in the same viewport |
|
||
| `F6` | While playing: pause / resume simulation (stay in Play mode) |
|
||
| `F8` | While playing: possess player / eject to editor camera |
|
||
| `G` | Toggle clean game-view overlay (hide editor widgets/proxies/gizmos) |
|
||
| `Ctrl+G` | Toggle viewport grid |
|
||
| `F` | Focus editor camera on selection |
|
||
| `Ctrl+Shift+1` / `Ctrl+Shift+2` | Save / recall viewport camera bookmark |
|
||
| RMB + mouse | Editor camera look; cursor hides while held |
|
||
| RMB + `W` `A` `S` `D` | Editor camera fly |
|
||
| RMB + `Q` / `E` | Editor camera down / up |
|
||
| Mouse wheel | Dolly editor camera |
|
||
| MMB + mouse | Pan editor camera |
|
||
| Click authored object, actor root icon, or visualizer in viewport | Select source entity |
|
||
| Click empty viewport / `Esc` | Deselect |
|
||
| `Delete` / `Backspace` | Delete selection |
|
||
| `Ctrl+D` | Duplicate selection |
|
||
| `Ctrl+Z` / `Ctrl+Shift+Z` / `Ctrl+Y` | Undo / redo; returning exactly to the last loaded or saved authored state clears that scene tab's dirty marker |
|
||
| `F2` in Hierarchy | Rename selection |
|
||
| `W` / `E` / `R` | Translate / rotate / scale gizmo; multi-selection uses one grouped gizmo and undo step |
|
||
| `X` | Toggle world/local gizmo orientation |
|
||
| `B` | Enter Draw Brush mode |
|
||
| Draw Brush: LMB / `Enter` / mouse up-down / `Esc` / `Backspace` | Place floor points / enter height phase or create / set height / cancel / remove point or return to outline |
|
||
| Brush selected: `1` / `2` / `3` / `4` | Vertex / edge / face / clip edit modes |
|
||
| Brush edit mode: LMB / `Shift+LMB` / `W` / `E` / `R` / `Esc` | Select element / toggle element selection / move / rotate / scale selected brush elements / return to object mode |
|
||
| Viewport toolbar (sun / brush / box icons) | Shading: Lit, Unlit (albedo), Colliders (mesh off) |
|
||
| Collider viewport mode | Inspect world-scale box/sphere/capsule overlays and cooked mesh bounds; green/cyan/gray/amber/red identify ready/trigger/disabled/warning/invalid state, with selected health in the lower-left HUD |
|
||
| Viewport eye/options | Toggle actor root icon categories, adjust icon/gizmo size, and control colliders, lights, spawns, gameplay markers, volumes, prefab/model anchors, and runtime player/camera visualizers |
|
||
| `Tab` in viewport | Cycle selection through overlapping objects at last click |
|
||
| Viewport selection/orientation HUD | Identify the primary selection, multi-selection count, overlapping-pick position, camera axes, shading mode, and active render path |
|
||
| Click Player visualizer in Edit mode | Select or create the authored `PlayerSpawn` (`Player Start`) |
|
||
| Select Project Sun | Inspect project default lighting; create a scene sun override |
|
||
| Content Browser project/file views | Browse `assets/` through a dense file-manager workspace: wide layouts keep navigation, breadcrumbs, import/new, search/filter, and view controls in one 55 px row; expanded widths also expose sort and thumbnail scale directly, while compact layouts use an 88 px two-row toolbar with Sources/Details drawers; folders and assets share one continuous card flow; search/filter/sort models, textures, materials, audio clips, levels, and prefabs; switch grid/list; expand model subassets; inspect file details; resize the wide Details pane by dragging its divider (double-click resets it); use click/Ctrl/Shift multi-selection and item/empty-space context menus; audition audio; drag supported assets/submeshes into the viewport |
|
||
| Drag audio clip into viewport | Create an authored audio source; when an audio source is selected, assign the clip instead |
|
||
| Content Browser context/details actions | Preview affected IDs/reference rewrites, then create folders or Materials in the current folder; rename, duplicate, cut/copy/paste or drag-to-folder; undo an unchanged content move; use **Import Here** or **Import To...** and review every source dependency/final target before committing; review/group loose PBR textures into editable Materials; assign/locate/clear per-slot model materials and resolve preserved reimport orphans; extract editable glTF/GLB/FBX PBR materials, explicitly diff/apply or create-new on re-extraction, and atomically map their source slots; regenerate thumbnails; reimport; place assets/submeshes; or trash and collision-guarded restore complete deletion batches |
|
||
| Texture Details | Set semantic and sRGB/Linear intent, mip policy, Basis UASTC or uncompressed KTX2 output, size limit, filtering, wrapping, anisotropy, and OpenGL/DirectX normal convention; **Apply & Reprocess** publishes derived runtime data without altering the source image |
|
||
| Window → Material Library | Search/filter project Materials and Material Instances, inspect scene usage and dependency health, create/edit shared assets, and drag them into the viewport |
|
||
| Drag Material/Instance onto viewport surface | Preview and assign the exact primitive/static/skinned slot or brush face under the pointer; release commits one undo step, while Escape/right-click/outside restores the preview |
|
||
| Drag Texture onto viewport surface | Primitive/static/skinned slots reject loose textures and explain that a Material/Instance is required; brush faces retain their specialized direct-texture path |
|
||
| Primitive/Static/Skinned material slots | Use the same Penpot-led material panel: Drop or Browse a shared Material/Instance; Clear returns to model source, project default, or DefaultGrid; expand the panel for immediate shared-handle updates that mark the asset **UNSAVED** without writing on release, then use contextual Save/Save All; use **Create Instance and Assign** for actor variation or **Extract Editable…** for one imported source slot; runtime property-block promotion remains exact-slot and transactional |
|
||
| `Ctrl+P` | Centered command palette; search human labels or stable command IDs, use arrow keys to select, Enter to run |
|
||
| `F7` | While paused in Play: advance one sim tick |
|
||
| Shift/Ctrl + click (Hierarchy) | Additive selection |
|
||
| Drag actor row onto another actor (Hierarchy) | Attach/reparent while preserving world placement; multi-selection keeps existing subtrees and commits one undo step |
|
||
| Drag actor between rows / onto Scene Root (Hierarchy, Manual sort) | Reorder siblings / unparent to the root |
|
||
| Hierarchy lock | Excludes the actor from selection, gizmos, multi-drag, structural drops, and mutating context actions |
|
||
| Hierarchy context | Group selection, create authored local children below linked prefab roots, remove/reparent generated members through same-layer structural overrides, or unparent |
|
||
| File menu | New, non-blocking native Open/Save As, **Open Sample** for the five-area regression pack, recovery restore/keep-copy/discard when available, Import Assets, Export Selection, Save Selection As Prefab (including linked-root variants), Recent Scenes, Switch Project, and Quit |
|
||
| Window close / **File > Quit** | Clean sessions exit immediately; dirty scene tabs use one non-blocking **Save All / Discard / Cancel** decision, and cancel or failed saves keep the editor open |
|
||
| Status strip / Asset Details source-state chip | Inspect compact clean, modified, untracked, conflicted, read-only, and optional ownership status; hover for the source path and provider details |
|
||
| Authored File Not Saved dialog | Resolve an external edit, read-only target, or ownership lock with Reload, Compare Metadata, Save As, or Cancel; the editor never offers force overwrite |
|
||
| Main toolbar, right side | Switch or close independent scene tabs, create an untitled tab, and manage loaded/locked composed subscenes |
|
||
| Prefab Instance inspector | Inspect/recover source health, Apply/Revert overrides by scope, Apply overrides to source, create a variant, **Unpack Layer**, or recursively **Convert to Local** |
|
||
| Inspector component card | Collapse with caret, toggle active with status dot, or use triple-dot menu for reset/copy/paste/move/remove actions |
|
||
| Inspector footer → Add Component | Expands an inline search shelf for registered authoring, rendering, physics, gameplay, and volume components with descriptions, availability hints, and undo |
|
||
| Inspector footer → Add Component → Terrain | Add a height-grid terrain actor; configure grid scale/chunking/collision in its component card and use Resize Flat only for deliberate grid replacement |
|
||
| Selected Terrain → viewport mountains tool | Sculpt Raise/Lower/Flatten/Smooth/Noise strokes with a terrain-following footprint; release commits one undo step, while Escape/right-click restores the pre-stroke grid |
|
||
| Terrain card → Material Layers; selected Terrain → viewport paint tool | Assign up to four shared materials, then Paint/Erase normalized layer weights with live blended preview; release commits one undo step and Escape/right-click restores the pre-stroke map |
|
||
| Selected physics props → viewport hand/down-arrow tool | Release the selection into real gravity/colliders; check commits one grouped transform edit, while Escape/X restores the exact starting state |
|
||
| Audio Source / Listener inspector | Assign and audition clips; edit gain, pitch, loop/autoplay, spatial blend, attenuation, bus, listener priority, and ear gap |
|
||
| Edit → Project Settings… | Edit `assets/project.ron` rendering, audio buses, physics, and input |
|
||
|
||
Viewport shortcut keys require the pointer to be in the viewport and are suspended while typing in egui text fields or actively using camera navigation. `Delete`, `Backspace`, duplicate, and undo/redo also defer to text-field focus.
|
||
|
||
### Play Mode
|
||
|
||
- Press **F5** (or Play menu) to run the **real game** in-process: same `GamePlugin`, player,
|
||
fixed-step `sim`, and rendering stack as the standalone `game` binary.
|
||
- The unified **Viewport** stays in place on play enter. The editor fly camera and player camera
|
||
render to the same offscreen HDR texture depending on Edit/Play possession state.
|
||
- While editing, gameplay simulation and input are disabled (`SimEnabled` / `GameInputEnabled`).
|
||
Entering Play enables simulation; **F6** pauses/resumes the sim without leaving Play; **F8** toggles **possess** (player input + camera) vs **eject**
|
||
(editor fly camera while sim keeps running).
|
||
- Transport controls (Play, Pause, Stop, Eject) live on the **main toolbar** below the menu bar.
|
||
- The viewport uses the full project rendering stack from **`assets/project.ron`**
|
||
(Edit → Project Settings…). Only one 3D camera carries that stack at a
|
||
time (editor fly cam while editing/ejected, player cam while possessed) so GPU bind limits are
|
||
respected.
|
||
- Add a `PlayerSpawn` marker component (via Inspector) on a level object to choose where Play
|
||
starts; otherwise the default game spawn `(0, 1.5, 10)` is used.
|
||
- Actor root icons draw over scene meshes, stay screen-sized while zooming, and are prioritized when clicked.
|
||
- Clean game-view overlay (`G`) hides editor widgets, actor root icons, visualizers, selectable proxies, gizmos,
|
||
selection outlines, and grid without changing the active camera.
|
||
- **F5** stops Play and restores **player sim state** only; authored scene edits made during PIE
|
||
are kept. **Esc** frees the cursor mid-play.
|
||
|
||
## Game Controls
|
||
|
||
| Input | Action |
|
||
|-------|--------|
|
||
| `W` `A` `S` `D` | Move |
|
||
| Mouse | Look |
|
||
| `Space` | Jump (coyote-time + buffered) |
|
||
| `Left Shift` | Sprint |
|
||
| `Left Ctrl` | Crouch |
|
||
| `Esc` | Release / re-grab mouse cursor |
|
||
|
||
## Scene Workflow
|
||
|
||
- Levels are saved as native Bevy dynamic scenes under `assets/levels/`.
|
||
- Scene tabs live at the right end of the existing main toolbar. Open creates another tab; each tab
|
||
retains its own path and dirty state, and close prompts only for that document.
|
||
- The adjacent **Composition** menu adds validated project-relative subscenes, loads/unloads them,
|
||
applies read-only hierarchy locks, and focuses their actors. Recursive validation rejects missing
|
||
or cyclic references before replacing the active world. See
|
||
[multi-scene-composition.md](docs/editor/multi-scene-composition.md).
|
||
- Editable entities use reflectable authoring components from `crates/shared`.
|
||
- Linked prefabs keep source-generated actors out of owner-scene serialization through runtime
|
||
`HydratedPrefabMember` ownership. Generated actor properties/components and same-layer structural
|
||
changes use stable nested override paths; authored local children and nested linked instances can
|
||
live below an instance root. Saving that linked root and its local hierarchy as a prefab creates
|
||
the current variant representation. See [prefab-authoring.md](docs/editor/prefab-authoring.md).
|
||
- The editable player start is an authored `PlayerSpawn`; moving it with the transform gizmo changes
|
||
where Play mode boots the runtime player.
|
||
- Project settings provide default ambient/sun lighting. A scene-authored directional `LightDesc`
|
||
acts as a per-scene sun override and disables the project sun contribution.
|
||
- Hydration systems turn authoring data into runtime meshes, GLTF scenes, materials, lights, and
|
||
Avian colliders. Persisted `ActorId` / `ComponentInstanceId` values are stable; raw Bevy `Entity`
|
||
IDs are runtime-only.
|
||
- Inspector component active toggles are saved in `InspectorOrder`. Inactive authoring components
|
||
keep their data but do not hydrate runtime meshes, lights, physics, or post-process effects.
|
||
- Dragging glTF/GLB/FBX assets creates `StaticMeshRenderer` actors by default from normalized
|
||
artifacts in `assets/meshes/generated/`. Renderer slots reference imported content-browser mesh
|
||
and material assets, while generated collision is stored separately in `ColliderDesc` plus
|
||
`RigidBodyDesc`. Switch a model asset's placement mode to **Scene Instance** in Asset Browser
|
||
details when you need full `WorldAssetRoot` scene data instead of normalized static slots.
|
||
Expanding a model in the Asset Browser exposes normalized mesh/material/texture plus generated
|
||
skeleton/animation-clip subassets. Dragging a mesh places that part through the static mesh path;
|
||
dragging a clip creates a dedicated skinned renderer or assigns an exact-rig-compatible state to
|
||
the selected skinned actor. **Default animation** in Model Import Settings optionally selects the
|
||
exact clip sampled and paused as the edit-rest pose; **Imported rest pose** never guesses a clip.
|
||
Preview stop and PIE exit restore imported transforms and morph weights before resampling that
|
||
explicit default. The Animation Controller inspector edits state IDs, clips,
|
||
range/loop/speed/default/crossfade and provides non-dirty play/pause/stop/scrub preview. See the
|
||
[animation authoring guide](docs/editor/animation-authoring.md) and [ADR 0031](docs/adr/0031-animation-authoring-runtime-contract.md).
|
||
- Navigation bounds, obstacles, areas, and links are created from **Scene > Navigation** or the path
|
||
icon in the existing horizontal toolbar. Bounds bake versioned Rerecast artifacts under
|
||
`assets/navigation/generated/`; overlapping primitive and additive-brush triangles participate
|
||
in the bake fingerprint while distant authoring is excluded. Visible composed subscenes and linked
|
||
prefab sources resolve through the same deterministic bake path used by CI. The Inspector reports
|
||
stale/current state, pins named validation paths, and provides a Polyanya-backed path test whose
|
||
mesh, links, and route render in the viewport. Use
|
||
`cargo bake-navigation --project . --check` in CI. See the
|
||
[navigation authoring guide](docs/editor/navigation-authoring.md) and [ADR 0032](docs/adr/0032-versioned-navigation-bake-and-runtime-query.md).
|
||
- Brush actors are persisted as `ActorKind::Brush + BrushDesc`; valid convex faces hydrate into
|
||
generated preview meshes. Vertex, edge, and face selections use the standard transform gizmo,
|
||
face material/UV fields are undoable, and clip/intersect/merge/subtract provide conservative
|
||
bounds-based blockout operations with preview-before-commit.
|
||
- Draw Brush mode (`B` or toolbar pencil) places snapped floor points; `Enter` locks the outline,
|
||
mouse up/down adjusts height, and `Enter` or left-click commits additive prism brushes. Simple
|
||
concave outlines decompose into convex brush parts, while self-intersections are blocked with
|
||
status text. The viewport shows quick brush key hints while drawing. `Esc` or right-click cancels
|
||
without changing the scene.
|
||
- Runtime-only handles/colliders are not serialized directly, keeping scenes stable and portable.
|
||
- Editor-only cameras and helper roots are filtered from selection, hierarchy, and scene save.
|
||
- Loaded scenes, prefab source Apply/history, Materials, Material Instances, and Project Settings
|
||
retain exact BLAKE3 disk revisions. Save verifies the revision again immediately before atomic
|
||
replacement; an external edit, create race, read-only target, or provider lock leaves the
|
||
existing file untouched and opens the collaborative recovery dialog. Git status is observational
|
||
and optional. See the
|
||
[collaborative file-safety guide](docs/editor/collaborative-file-safety.md) and
|
||
[ADR 0037](docs/adr/0037-collaborative-authored-file-safety.md).
|
||
- **PIE restores player sim only** (transform, velocity, jump state) when you stop Play; authored
|
||
`LevelObject` edits made during PIE **remain** in the scene (the level may show as dirty).
|
||
- Play mode swaps the unified viewport between the player camera (possessed) and editor fly camera
|
||
(ejected).
|
||
- Gameplay movement runs in a fixed timestep in `crates/sim`. Raw keyboard/mouse input is translated
|
||
by `crates/game` into `protocol::PlayerInputIntent` before it mutates simulation state.
|
||
|
||
## Troubleshooting
|
||
|
||
### Viewport is black or wireframe-only
|
||
|
||
1. Check the **mode badge** (bottom-right of the viewport). **Collider** hides meshes — click the **sun** toolbar icon for **Lit** shading.
|
||
2. **Window → Rendering → Active Camera**: check **Runtime lights** (directional/point/spot counts), scene vs project sun status, and contributing post-process volumes. Scene directionals override the project sun; use **Scene → Lighting → Use project sun** to restore project defaults.
|
||
3. **Solari requested but not visually changing**: check **Window → Rendering → Active Camera** for requested/effective GI, fallback reason, tagged meshes, Solari-compatible mesh assets, render instances, bind-group readiness, and compatible lights. Effective Solari forces an HDR camera target because Bevy Solari writes through a storage texture; imported/custom meshes need TriangleList geometry, POSITION/NORMAL/UV_0/TANGENT attributes, and U32 indices for Bevy 0.19 Solari.
|
||
4. **Lighting changes do nothing in Solari**: Bevy 0.19 Solari samples directional lights and emissive meshes, not point/spot lights. Use Directional lights or emissive materials in Solari; switch to Forward PBR for point/spot light authoring.
|
||
5. **GiMode Auto shows Forward**: Solari RT wgpu features are unavailable on this GPU. Dev RT override: `BEVY_FPS_FORCE_SOLARI=1`.
|
||
6. **Volume overrides ignored**: confirm camera is inside volume AABB; check priority in Rendering → Volumes tab.
|
||
7. **Custom post FX**: RON under `assets/post_fx/`; assign path in volume inspector (see [docs/editor/rendering.md](docs/editor/rendering.md)).
|
||
8. Scene **Open** / **Recent** runs hydration immediately; **zero runtime lights** after load usually means missing `LightDesc` on light actors (see Rendering panel).
|
||
|
||
### Hierarchy sort jumps when clicking
|
||
|
||
**Sort: Name** / **Type** now use stable tie-breakers (duplicate names like several `Pillar` rows stay put). Use **Sort: Manual** and drag-and-drop for explicit sibling order.
|
||
|
||
### Hierarchy scrolls during drag
|
||
|
||
Scroll-to-drag is disabled while dragging actors. The pointer card reports the pending action:
|
||
drop on a full actor row to attach, on the **Scene Root** zone to unparent, or between rows in
|
||
**Manual** sort to reorder. Amber means attach, cyan means reorder/root, and red blocks a hierarchy
|
||
cycle. Release away from a valid target to cancel.
|
||
|
||
### Scene recovery
|
||
|
||
Dirty saved scenes create a recovery snapshot every 120 seconds and retain the newest five
|
||
generations under `$XDG_STATE_HOME/blacksite-editor/recovery` or
|
||
`~/.local/state/blacksite-editor/recovery`. If a snapshot is newer than the authored scene, the
|
||
status strip shows `[recovery]` and recovery actions become available in **File**. **Restore
|
||
Recovery Snapshot** loads it into dirty editor state for inspection, **Save Recovery Copy As...**
|
||
writes a separate transactional scene copy without changing the active scene, and **Discard
|
||
Recovery Snapshot** retires all generations. Restore keeps the generation available until **Save**
|
||
commits the active scene or discard explicitly retires it. The **Diagnostics** window retains the
|
||
latest 32 scene I/O results, including exact recovery paths and failures, for the current session.
|
||
Unsaved new scenes are not yet covered by automatic recovery.
|
||
For recovery testing only, `BLACKSITE_RECOVERY_INTERVAL_SECS=<seconds>` overrides the interval for
|
||
the current process without changing preferences.
|
||
|
||
### Session recovery
|
||
|
||
Clean editor exits restore the last authored scene, panel visibility, and viewport bookmarks from
|
||
the versioned machine-local session document. After an abnormal exit, Blacksite opens the safe
|
||
startup scene and asks whether to **Resume Last Scene** or **Continue Safe**; modal tools and dirty
|
||
preview state are never restored. The recovery prompt is modal and blocks interaction with the
|
||
safe scene until one of those choices is made. Session metadata lives under
|
||
`$XDG_STATE_HOME/blacksite-editor/session.ron` or `~/.local/state/blacksite-editor/session.ron` and
|
||
contains no scene contents or credentials. See [ADR 0024](docs/adr/0024-versioned-editor-session-state.md).
|
||
|
||
Open **Window → Diagnostics** and choose **Export Diagnostic Bundle** to write a transactional
|
||
support report under `$XDG_STATE_HOME/blacksite-editor/diagnostics` or
|
||
`~/.local/state/blacksite-editor/diagnostics`. The report includes build/platform and renderer
|
||
identity, project and active-scene paths, dirty flags, aggregate validation counts, prior-crash
|
||
state, and the bounded Scene I/O log. It excludes scene and asset contents, environment values,
|
||
host/user identity, credentials, access tokens, and modal tool state.
|
||
|
||
### External file changes and read-only assets
|
||
|
||
The active scene status strip and selected asset header show compact Git/read-only/ownership state
|
||
when available. If Save or Apply detects a different disk revision, Blacksite leaves that revision
|
||
untouched and opens **Authored File Not Saved**. Use **Compare Metadata** to inspect both revisions,
|
||
**Save As** to preserve the editor copy elsewhere, **Reload** to take the disk version, or **Cancel**
|
||
to keep the local draft unsaved. Git and ownership providers are optional; the status scanner never
|
||
stages, commits, resets, checks out, restores, or discards files. See
|
||
[collaborative-file-safety.md](docs/editor/collaborative-file-safety.md).
|
||
|
||
## Cursor / VSCode Setup
|
||
|
||
The `.vscode/` folder is preconfigured:
|
||
|
||
- `extensions.json` recommends rust-analyzer, Even Better TOML, CodeLLDB, crates, and Error Lens.
|
||
- `settings.json` runs `clippy` on save, enables proc-macro/build-script support, formats on save,
|
||
and excludes `target/` from search/watch.
|
||
- `tasks.json` mirrors the full workspace formatting, all-target check, strict Clippy, test, level-validation, build/run, hot-reload, and target-cleanup workflows. **build editor (dev fast-link)** is the default build task.
|
||
- `launch.json` uses CodeLLDB Cargo artifact filtering for ordinary editor/game Debug,
|
||
GPU-validation, SDR fallback, and Release configurations. Managed hot reload uses the lane-aware
|
||
tasks above so exceptional artifacts cannot overwrite or borrow the ordinary editor's runtime
|
||
dependency path.
|
||
- `.github/workflows/ci.yml` mirrors local formatting, check, clippy, test, and binary build verification.
|
||
|
||
## Architecture Decisions
|
||
|
||
- [Documentation index](docs/README.md)
|
||
- [Mission — editor framework & principles](docs/mission.md)
|
||
- [Editor framework docs](docs/editor/README.md)
|
||
- [ADR 0001: Roadmap Architecture](docs/adr/0001-roadmap-architecture.md)
|
||
- [ADR 0002: Bevy Version And Migration Policy](docs/adr/0002-bevy-version-and-migration-policy.md)
|
||
- [ADR 0003: Editor Framework Mission](docs/adr/0003-editor-framework-mission.md)
|
||
- [ADR 0014: Unified Viewport Model](docs/adr/0014-unified-viewport-model.md)
|
||
- [ADR 0016: Unified Rendering Contract](docs/adr/0016-unified-rendering-contract.md)
|
||
- [ADR 0017: Normalized Static Mesh Assets](docs/adr/0017-normalized-static-mesh-assets.md)
|
||
- [ADR 0034: Registry-driven Authoring Components](docs/adr/0034-registry-driven-authoring-components.md)
|
||
- [ADR 0037: Collaborative Authored-File Safety](docs/adr/0037-collaborative-authored-file-safety.md)
|
||
- [ADR 0047: Editor Authored-Asset Documents](docs/adr/0047-editor-authored-asset-documents.md)
|
||
- [ADR 0048: Modular Editor Composition and Debt Ratchet](docs/adr/0048-modular-editor-composition-and-debt-ratchet.md)
|
||
- [ADR 0049: Penpot-Led Editor Visual System](docs/adr/0049-penpot-led-editor-visual-system.md)
|
||
- [ADR 0043: Content-Addressed Import Fingerprints](docs/adr/0043-content-addressed-import-fingerprints.md)
|
||
- [ADR 0044: Sandboxed FBX External Texture Dependencies](docs/adr/0044-sandboxed-fbx-external-texture-dependencies.md)
|
||
|
||
## Project Layout
|
||
|
||
```
|
||
crates/
|
||
protocol/ Shared tick, input intent, command, and message/event protocol types
|
||
sim/ Fixed-step gameplay simulation and determinism test scaffolding
|
||
shared/ Reflectable authoring components + hydration systems
|
||
game/ Runtime FPS game library + standalone game binary
|
||
editor/ In-process egui editor binary
|
||
```
|
||
|
||
## Implementation Checklist
|
||
|
||
- [x] Workspace: `game`, `shared`, `editor`, `protocol`, `sim`
|
||
- [x] Shared authoring components + hydration
|
||
- [x] Protocol tick, input intent, command, and basic message/event types
|
||
- [x] Fixed-step deterministic sim crate for player movement/controller state
|
||
- [x] Runtime game refactored into `GamePlugin`
|
||
- [x] Raw game input translated into protocol intent before simulation
|
||
- [x] Docked egui editor scaffold
|
||
- [x] Editor fly camera
|
||
- [x] Mesh picking selection + highlights
|
||
- [x] Transform gizmos
|
||
- [x] Editor-side scene visualizers for colliders, lights, player spawns, prefab/model anchors, and runtime player/cameras
|
||
- [x] Selectable, screen-sized actor root icons in the 3D viewport with per-category visibility controls
|
||
- [x] Filtered hierarchy, inspector, viewport, toolbar, asset browser, and status panels
|
||
- [x] Delete, duplicate, rename, and structural/material undo-redo
|
||
- [x] Native Bevy scene New/Open/Save/Save As with dirty title tracking
|
||
- [x] First-class height-grid Terrain actor with deterministic generated render/collider chunks, reflected history, validation, and a committed showcase fixture ([ADR 0039](docs/adr/0039-inline-height-grid-terrain-foundation.md), [terrain guide](docs/editor/terrain.md), [Gitea #22](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/22))
|
||
- [x] Modal terrain Raise/Lower/Flatten/Smooth/Noise sculpting with a terrain-following footprint, deterministic noise, safe cancel restore, and one undo transaction per stroke ([terrain guide](docs/editor/terrain.md), [Gitea #23](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/23))
|
||
- [x] Four shared terrain Material/Material Instance layers with compact normalized sample weights, blended raster hydration, drag/browse assignment, Paint/Erase preview, exact cancel, and one undo transaction per stroke ([ADR 0040](docs/adr/0040-terrain-material-layer-weights.md), [terrain guide](docs/editor/terrain.md), [Gitea #24](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/24))
|
||
- [x] Transactional physics placement with real Avian gravity/colliders, paused Edit-mode physics, prerequisite diagnostics, isolated non-selected bodies, exact cancel, and grouped transform undo ([ADR 0041](docs/adr/0041-transactional-editor-physics-placement.md), [workflow guide](docs/editor/physics-placement.md), [Gitea #25](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/25))
|
||
- [x] Collider authoring health shared by the inspector, Collider viewport, Diagnostics panel, and physics placement, with scaled shape overlays, cooked mesh bounds, missing/stale/invalid/oversized findings, and undoable dimension-preserving shape switching ([collider guide](docs/editor/collider-authoring.md), [Gitea #26](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/26))
|
||
- [x] Non-blocking native file/folder/confirmation broker across scene, asset, prefab, composition, collaboration, and Project Browser workflows ([ADR 0038](docs/adr/0038-non-blocking-native-dialog-broker.md), [workflow guide](docs/editor/native-dialogs.md), [Gitea #52](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/52))
|
||
- [x] Guarded native/menu/programmatic editor shutdown with asynchronous multi-tab Save All / Discard / Cancel and canonical per-tab clean checkpoints for exact undo/redo dirtiness ([ADR 0042](docs/adr/0042-guarded-editor-shutdown-and-document-savepoints.md), [Gitea #55](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/55))
|
||
- [x] Scoped egui action safety for toolbar/navigation spawns, Inspector state, cross-panel selection/tab requests, diagnostics selection, and full-slice selection precedence ([evaluation](docs/editor/evaluations/scoped-ui-actions/), [Gitea #57](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/57))
|
||
- [x] Asset import, static mesh/prefab placement, texture assignment, and selection export
|
||
- [x] PIE player-only snapshot/restore (authored `LevelObject` edits persist on stop)
|
||
- [x] Unified viewport render-to-texture target + Play session bootstrap
|
||
- [x] `PlayerSpawn` authoring marker for editor Play start location
|
||
- [x] BRP enabled in the editor
|
||
- [x] Cursor/VSCode workspace tasks + launch configs
|
||
- [x] Opaque Wayland window launch defaults + SDR/HDR runtime toggle
|
||
- [x] CI workflow for format, check, clippy, tests, and binary builds
|
||
- [x] Deterministic five-area editor sample regression pack with stable actor IDs, **File > Open Sample**, typed scene checks, headless validation, and committed brush/material/terrain/physics/rendering fixtures ([sample guide](docs/editor/sample-regression-pack.md), [Gitea #32](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/32))
|
||
- [x] ADRs for roadmap architecture and Bevy migration policy
|
||
- [x] Determinism harness: same inputs over same ticks produce the same state summary/hash
|
||
- [x] Production operator invariants across palette dispatch, assets/material drops, brush/terrain/physics modal tools, grouping/lighting, and the transform finalizer: stable terminal status, exact cancel/failure rollback, helper cleanup, grouped history, and repeated undo/redo projections ([testing contract](docs/editor/operator-regression-testing.md), [evaluation](docs/editor/evaluations/operator-invariants/), [Gitea #33](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/33))
|
||
- [x] Verify: `cargo fmt --check` / `cargo check --workspace` / `cargo clippy --workspace` / strict foundation clippy / `cargo test -p sim`
|
||
- [x] Stable asset registry with UUIDs + import settings in asset browser details
|
||
- [x] Deterministic imported-source fingerprints for models, textures, and audio; BLAKE3-backed
|
||
static/animation manifests; byte-preserving equivalent refresh; and read-only validator checkout
|
||
assertions ([ADR 0043](docs/adr/0043-content-addressed-import-fingerprints.md), [evaluation](docs/editor/evaluations/deterministic-asset-fingerprints/), [Gitea #56](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/56))
|
||
- [x] Sandboxed FBX external-texture discovery for sibling and `.fbm/` layouts, transactional
|
||
referenced-bundle import, manifest-first consolidated validation, deduplicated loader reads, and
|
||
stable Asset Browser dependency status ([ADR 0044](docs/adr/0044-sandboxed-fbx-external-texture-dependencies.md), [Gitea #58](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/58))
|
||
- [x] Asset Browser expandable model subasset shelves, independent mesh/material/texture thumbnails, staged import/material details with shader-schema parameters, context actions, and trash-first file removal
|
||
- [x] Audio clip catalog/import foundation for Ogg, WAV, MP3, and FLAC with dedicated filtering, file details, and stable runtime-resolvable asset references
|
||
- [x] Audio source/listener authoring, non-dirty spatial audition, viewport icons/range gizmos, stable buses, PIE/runtime parity, device diagnostics, and shared release validation ([ADR 0030](docs/adr/0030-audio-authoring-and-bus-schema.md); production acceptance completed in [Gitea #47](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/47))
|
||
- [x] glTF/GLB skeletal animation manifests, stable controller states, non-dirty preview, PIE/runtime hydration, and exact-signature compatibility validation ([ADR 0031](docs/adr/0031-animation-authoring-runtime-contract.md); production acceptance completed in [Gitea #46](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/46))
|
||
- [x] Navigation bounds/obstacles/areas/links, persisted validation samples, composed-source resolution, deterministic stale-checked bake artifacts, viewport path preview, headless bake, and shared game/runtime query API ([ADR 0032](docs/adr/0032-versioned-navigation-bake-and-runtime-query.md); [evaluation](docs/editor/evaluations/navigation-authoring/); [Gitea #48](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/48))
|
||
- [x] Exact authored-file revision guards for scenes, prefab source Apply/history, Materials, Material Instances, and Project Settings; compact observational Git/read-only/ownership state; and explicit Reload/Compare Metadata/Save As/Cancel recovery without force overwrite ([ADR 0037](docs/adr/0037-collaborative-authored-file-safety.md), [collaboration guide](docs/editor/collaborative-file-safety.md), [Gitea #49](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/49))
|
||
- [x] Prefab instances (`PrefabInstance`) + save-as-prefab + unpack
|
||
- [x] Independent dirty-tab close confirmation and all-tab save guard when switching projects
|
||
- [x] Transactional scene writes + bounded user-local recovery snapshots ([ADR 0023](docs/adr/0023-transactional-scene-persistence-and-recovery.md))
|
||
- [x] Versioned clean/crash session resume + privacy-bounded diagnostic bundle ([ADR 0024](docs/adr/0024-versioned-editor-session-state.md))
|
||
- [x] Hierarchy multi-select, reparent undo, multi-entity gizmo transform
|
||
- [x] Typed inspector undo (light, rigid body, collider, primitive, material, static mesh renderer) + registry-driven Add Component footer; skinned renderer sources are asset-owned and inspectable
|
||
- [x] Gameplay authoring markers + visualizers (`WeaponSpawn`, `TriggerVolume`, etc.)
|
||
- [x] Command palette execution; PIE sim step (F7); `xtask validate-levels`
|
||
- [x] ADRs 0005–0012 (prefab/registry, scene schema, EditorPlugin, editor structure, authoring/hydration, ActorKind, sun policy, zero-debt)
|
||
- [x] `ActorInspectorSection` registry + game demo section (`game::editor_ext`)
|
||
- [x] Command palette: reset lighting, group selection, focus selection
|
||
- [x] CI: `cargo test -p shared`, scene authoring-only check on repo level, `cargo check -p editor --features dev`
|
||
- [x] `scene` crate schema stamp/migrate/validate on save/load + CI `validate-levels` for levels and prefab graphs
|
||
- [x] Project Settings draft + Apply (HDR/swapchain safe)
|
||
- [x] Project Browser UI, strict manifest validation, `--project` startup activation, recent filtering, sandbox scaffolding, clean process handoff, and desktop launcher action ([ADR 0025](docs/adr/0025-project-root-is-a-startup-boundary.md))
|
||
- [x] Independent scene tabs + stable subscene composition, recursive validation, ownership locks, active-world PIE consistency, and per-saved-tab recovery ([ADR 0026](docs/adr/0026-stable-scene-composition-and-active-document.md))
|
||
- [x] Editor lib/bin split + `EditorPluginGroup`; game EditorPlugin dogfood panel
|
||
- [x] FBX/glTF model import + normalized static/skinned renderer routing; explicit generic scene-instance load via `bevy_ufbx` / `ModelRef`
|
||
- [x] Typed texture/model/mesh-subasset/source-material thumbnail cache keys; model and mesh cards always render geometry in the offscreen studio instead of substituting an albedo texture (`ThumbnailState`; FBX via `FbxThumbnailSource`)
|
||
- [x] Shared Material/Material Instance assets, generalized primitive/static/skinned slots, expandable guarded shared parameters, stable model defaults, six-layer fallback through immutable DefaultGrid, exact-actor source extraction, orphan preservation, cached Standard/Surface runtime property-block application, and exact-slot transactional instance creation/promotion ([ADR 0035](docs/adr/0035-shared-material-assets-and-renderer-slots.md), [ADR 0045](docs/adr/0045-content-workspace-and-material-fallback-contract.md), [material-system guide](docs/editor/material-system.md))
|
||
- [x] Path-agnostic content classification, reference-safe file operations, destination-first dependency-bundle import, deterministic runtime catalog/model manifests, shared debounced watcher core, and atomic GPU-free `cargo process-assets` write/check validation ([content workspace guide](docs/editor/content-workspace.md))
|
||
- [x] Registry v3 Texture properties, schema-v2 Material inputs, paired multiplier/texture controls, channel-selectable ARM/ORM repacking, and content-addressed UASTC/KTX2 runtime artifacts shared by editor refresh and `cargo process-assets` ([ADR 0046](docs/adr/0046-schema-driven-material-inputs-and-processed-textures.md), [material guide](docs/editor/material-system.md))
|
||
- [x] Asset-keyed dirty documents use one overlay-first live Material authority and conditional derived processing without pointer-release writes; contextual Save/Save All, recovery, background processing, and live-handle persistence passed native acceptance ([ADR 0047](docs/adr/0047-editor-authored-asset-documents.md))
|
||
- [x] Registry-only Inspector dispatch, shared material/asset-card UI, and the architecture debt ratchet are implemented; both Inspector and Content Browser shells are <=500 nonblank lines and pass the selective architecture gate plus native resize/deep-scroll acceptance ([ADR 0048](docs/adr/0048-modular-editor-composition-and-debt-ratchet.md))
|
||
- [ ] Penpot-led tokens, Source Sans Pro typography, responsive Inspector/material components, asset/color pickers, and exact current 620/420 px geometry are undergoing final M2 native acceptance ([ADR 0049](docs/adr/0049-penpot-led-editor-visual-system.md))
|
||
- [ ] Penpot-led Content Browser wide/compact composition, dock-header ownership, responsive Sources/Details access, and catalog-processing status pass current Page 03 native comparison and resize stress; exact candidate publication remains pending ([content workspace guide](docs/editor/content-workspace.md), [ADR 0049](docs/adr/0049-penpot-led-editor-visual-system.md))
|
||
- [x] File-manager Content Browser selection for assets and folders, Ctrl/Cmd toggle and Shift ranges, batch clipboard/duplicate/drag/trash operations, stable-ID moves, fresh-ID copies with internal-only reference remapping, concrete destructive-reference previews, exact cancel-state restoration, restart-safe explicit ambiguous external-move identity repair, fingerprint-guarded move/create/copy/trash undo, modal-safe content-scoped keyboard shortcuts, exact-name Cut/Paste collision review, safe navigation/filter selection clearing, consistent right-click targeting for files/folders/subassets, current-folder Material creation, and right-click menus on items and empty workspace space ([content workspace guide](docs/editor/content-workspace.md))
|
||
- [x] Transactional Content Trash with versioned batch manifests, stable-ID restore, generated model-manifest preservation, collision guards, legacy-batch discovery, and registry/runtime-catalog rollback ([content workspace guide](docs/editor/content-workspace.md))
|
||
- [x] Transactional loose-texture PBR grouping with suffix/confidence detection, manual role correction and target merge/split, packed ORM/ARM mapping, and no-overwrite Material publication ([material-system guide](docs/editor/material-system.md))
|
||
- [x] Docked Material Library with cross-folder type/usage filters, resolved Material Instance thumbnails, shared guarded editors, and exact reversible viewport Material/Texture drops for renderer slots, primitives, and brush faces ([material-system guide](docs/editor/material-system.md); [Gitea #16](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/16), [Gitea #18](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/18))
|
||
- [x] Prefab v2 core: shared stable nested override paths, property/component/structural scopes, recursive graph validation, linked-root variants, conflict recovery, transactional source Apply, and undoable unpack/convert ([ADR 0027](docs/adr/0027-stable-prefab-ownership-and-variants.md))
|
||
- [x] Prefab v2 production acceptance: committed base/nested/variant fixtures pass workspace tests, recursive headless validation, packaged release startup, and live editor placement/inspection regression coverage ([Gitea #43](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/43))
|
||
- [x] Shared project validation: editor Diagnostics and `cargo validate-levels --json` use one owner-attributed dependency/finding report across project settings, registry/import artifacts, materials, shaders, scenes, prefabs, brushes, and colliders; valid/missing/cyclic/incompatible fixtures fail on blocking content errors ([ADR 0028](docs/adr/0028-authoritative-project-content-validation.md), [Gitea #45](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/45))
|
||
- [x] Validation-gated package foundation: versioned development/QA/release profiles, deterministic runtime exclusions, stable input snapshots, transactional staged publication, Cargo-reported artifacts, BLAKE3 metadata, authored default-scene startup, and a non-blocking editor Build panel with live logs/cancel/run/reveal ([ADR 0029](docs/adr/0029-validation-gated-build-profiles-and-packaging.md), [build guide](docs/editor/build-and-package.md), [Gitea #44](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/44))
|
||
- [x] Advanced rendering: `GiMode`, post-process volumes, Rendering panel, requested/effective render stack, Solari integration, emissive materials, post FX assets ([ADR 0013](docs/adr/0013-rendering-tiers-and-post-process-volumes.md), [ADR 0016](docs/adr/0016-unified-rendering-contract.md), [rendering guide](docs/editor/rendering.md))
|
||
- [x] Surface ABI v1 with shared raster/Solari evaluator dispatch, packed typed parameters/textures, exact cutout ray-candidate evaluation, last-good shader fallback, and explicit exclusion of skinned/morph-deformed Solari geometry ([ADR 0036](docs/adr/0036-surface-abi-and-solari-parity.md), [material-system guide](docs/editor/material-system.md))
|
||
- [x] Static mesh renderer component, generated normalized mesh artifacts, source/one-actor hierarchy placement, and inspector renderer slots ([ADR 0017](docs/adr/0017-normalized-static-mesh-assets.md))
|
||
- [x] Dedicated `SkinnedMeshRenderer`/`SkinnedMesh` actor path, skinned-part exclusion from static slots, dedicated runtime hierarchy hydration, and v2-to-v3 animated-scene migration ([ADR 0033](docs/adr/0033-dedicated-skinned-mesh-renderer.md))
|
||
- [x] Componentized actor inspector with one primitive/static/skinned Material-slot widget, full-width valid/invalid drop feedback, material sphere and exact mesh-subasset previews, inherited status, Browse/Locate/Clear, guarded shared parameter foldouts, and no synthetic primitive Authoring Material card ([ADR 0018](docs/adr/0018-componentized-actor-inspector-and-materials.md), [ADR 0035](docs/adr/0035-shared-material-assets-and-renderer-slots.md))
|
||
- [x] Stable authoring component IDs, registry-built save filtering, reflected atomic add/remove/reset/copy/paste history, independent active state, static extension registration, and derived composable `ActorKind` hints ([ADR 0034](docs/adr/0034-registry-driven-authoring-components.md), [extensibility guide](docs/editor/extensibility.md))
|
||
- [x] Brush authoring schema MVP with `ActorKind::Brush`, cube `BrushDesc`, generated mesh hydration, scene migration, and inspector Add Component support ([ADR 0021](docs/adr/0021-brush-authoring-schema.md))
|
||
- [x] Brush draw, vertex/edge/face gizmo editing, face material/UV authoring, clip, and bounds-based CSG preview/commit workflow ([brush guide](docs/editor/brushes.md))
|
||
- [x] Searchable command palette with human labels/stable IDs and a status bar that exposes scene I/O, tool, history, mode, and selection feedback
|
||
|
||
## Notes / Future Work
|
||
|
||
- Crouch lowers the camera and movement speed; the collider stays full-height for stability.
|
||
- The editor asset browser is filesystem-backed with folder/tree navigation, grid/list views,
|
||
direct texture thumbnails, offscreen geometry renders for all models and mesh subassets,
|
||
material sphere thumbnails, and a managed content-addressed 256 px disk cache that reuses valid
|
||
previews across editor sessions while restoring the last-good image after a restart during
|
||
dependency-driven regeneration or source failure. It also provides search/filter/sort controls, expandable model
|
||
subasset shelves, and a staged details pane. **File -> Import Assets**
|
||
accepts glTF/GLB and binary **FBX**. FBX import parses and transactionally preserves every safe
|
||
referenced sibling `textures/` or `.fbm/` file while rejecting traversal and external absolute
|
||
paths before project content changes. Missing source textures appear once in validation and Asset
|
||
Browser dependency status; choosing **Project** or **Default** for every stable model slot
|
||
deliberately permits an untextured model, while any **Source** slot keeps the bundle required.
|
||
Model assets generate normalized model manifests under `assets/meshes/generated/`; drag/drop uses
|
||
**Renderable Asset (Auto)**. Unrigged sources use `StaticMeshRenderer` with imported asset refs
|
||
and optional separate static mesh colliders. Skin-bound or animated sources and their subasset placement use
|
||
`SkinnedMeshRenderer`, preserve the source joint hierarchy, and never create static slots or
|
||
automatic triangle colliders. Expanded mesh subassets generate independent thumbnails. Asset details can switch
|
||
placement to **Scene Instance** for generic `ModelRef`/`WorldAssetRoot` scenes, shared material assets can be
|
||
edited from the browser, and delete actions move files to `assets/.trash/`. Animation authoring
|
||
supports glTF/GLB rig and clip manifests, stable controller refs, clip drag assignment/placement,
|
||
inspector preview, PIE/runtime playback, and headless compatibility diagnostics. Animated or
|
||
skinned FBX remains blocked until the loader can build hierarchy, Bevy skinned meshes, and clips.
|
||
See the [animation authoring guide](docs/editor/animation-authoring.md).
|
||
- Prefab instances use stable asset IDs and shared versioned override data keyed by nested
|
||
`PrefabActorPath` identity. Generated source members are excluded from owner save/export, while
|
||
property/component edits and same-layer remove/reparent operations persist as overrides. Revert
|
||
stays instance-local; explicit **Apply to source** validates and atomically patches the appropriate
|
||
source layer, with exact-file undo/redo guards against external edits. Source health exposes
|
||
changed, semantic-conflict, broken, and malformed states with keep/take/retry/relink recovery.
|
||
**Unpack Layer** preserves nested links; **Convert to Local** recursively removes them. Current
|
||
authoring UI coverage and production-acceptance gaps are tracked in
|
||
[prefab-authoring.md](docs/editor/prefab-authoring.md).
|
||
- Material and direct-base Material Instance assets may live anywhere under `assets/`; shader schemas are also folder-independent. **Window > Material Library** provides cross-folder creation, editing, usage filters, and drag sources. Material parameters update one live shared handle and mark the asset **UNSAVED**; releasing a control does not write or process. **Ctrl+S** saves the last edited context and **Ctrl+Shift+S** / **File > Save All** saves every dirty scene, asset, and project setting. Scalar/color/render-state Material saves finish without a processing job; ARM/ORM binding changes continue through affected-only background processing. Viewport Material drops target one exact primitive/static/skinned slot or brush face and use reversible preview plus one-step history; loose Textures are rejected by primitive/mesh slots while brushes retain their specialized face texture path. Runtime property blocks apply after resolved bases without mutating shared assets. Custom Surface evaluators share one constrained ABI between raster and Solari-eligible non-deformed geometry. Dynamic skinned/morph Solari geometry remains tracked in [#54](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/54). See the [material-system guide](docs/editor/material-system.md).
|
||
- Per-field reflect undo for all components remains future work; typed `shared` inspectors cover the common authoring path.
|
||
- The authoring/hydration layer is intentionally small so richer asset workflows (terrain,
|
||
material graphs, lighting profiles) can be added without changing the scene format foundation.
|
||
- The M2 sim split keeps camera pitch as local presentation state; body yaw and movement are
|
||
fixed-step intent consumers. M3 should map the existing protocol envelopes onto Lightyear and add
|
||
server-authoritative snapshots/prediction rather than broadening the local input path ad hoc.
|
||
- The editor renders egui on a dedicated full-window `Camera2d` (`PrimaryEguiContext`,
|
||
`RenderLayers::none()`, `auto_create_primary_context = false`) so the 3D viewport camera can be
|
||
cropped to the viewport panel without cropping egui itself. Attaching egui to a viewport-cropped
|
||
3D camera makes `egui_dock` lay out into a NaN rect and panics in `advance_cursor_after_rect`.
|