Bevy-based Blacksite game and editor workspace.
Go to file
2026-07-12 13:14:47 -04:00
.cargo Build renderer and material component foundations 2026-07-12 00:24:06 -04:00
.cursor Add material library and targeted surface drops 2026-07-12 13:14:47 -04:00
.github Improve editor workflows and thumbnail resilience 2026-07-10 00:48:25 -04:00
.vscode Build production-ready editor authoring workflows 2026-07-11 12:41:04 -04:00
assets Ship production navigation authoring workflow 2026-07-12 02:53:43 -04:00
crates Add material library and targeted surface drops 2026-07-12 13:14:47 -04:00
docs Add material library and targeted surface drops 2026-07-12 13:14:47 -04:00
source_assets Initial project import 2026-06-05 21:44:45 -04:00
third_party Build renderer and material component foundations 2026-07-12 00:24:06 -04:00
xtask Ship production navigation authoring workflow 2026-07-12 02:53:43 -04:00
.gitattributes Initial project import 2026-06-05 21:44:45 -04:00
.gitignore Build renderer and material component foundations 2026-07-12 00:24:06 -04:00
AGENTS.md Initial project import 2026-06-05 21:44:45 -04:00
Cargo.lock Ship production navigation authoring workflow 2026-07-12 02:53:43 -04:00
Cargo.toml Ship production navigation authoring workflow 2026-07-12 02:53:43 -04:00
README.md Add material library and targeted surface drops 2026-07-12 13:14:47 -04:00
rust-toolchain.toml Initial project import 2026-06-05 21:44:45 -04:00

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

Running

# 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 bake-navigation --project . --check
# 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:

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... performs a clean shutdown and opens the same browser; choosing a project starts a fresh editor process with that root.

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 (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):

# Terminal 1 — rebuild the hot dylib on save
cargo watch -w crates/game_hot -w crates/sim -x "build -p game_hot --features dylib"

# Terminal 2 — run the editor once
cargo run -p editor --features dev,hot-reload

Or use the VS Code task watch game_hot (hot reload) alongside run editor (hot reload), or choose Editor: Hot reload in Run and Debug. The watcher task requires cargo-watch (cargo install cargo-watch --locked).

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.

Target Cache Cleanup

Cargo/Bevy debug artifacts can grow quickly. Use the workspace cleanup task before reaching for a full cargo clean:

Command Effect
cargo clean-target Dry run: prints reclaimable target/ cache.
cargo clean-target --apply Safe cleanup: removes incremental and rust-analyzer flycheck cache.
cargo clean-target --include-artifacts --days 3 --apply Deeper cleanup: also removes stale hashed deps, build, .fingerprint, and example artifacts older than 3 days. Cargo will rebuild anything still needed.

Use the safe cleanup during normal iteration and the three-day deep cleanup after Bevy upgrades, feature-matrix builds, or large test runs. The cutoff preserves recent artifacts and avoids the full rebuild caused by cargo clean. The workspace test profile keeps line tables but disables full test debuginfo and incremental test caches, so routine test binaries stay materially smaller without reducing normal editor debugging fidelity. The cleanup binary deliberately excludes the scene/Bevy validation dependency; cargo clean-target therefore stays cheap even from a cold target. Use cargo validate-levels when level and prefab-graph validation is required. VS Code tasks expose dry-run, safe, and deep-stale variants.

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, the incremental target/ cache is stale. Run the VS Code task clean build editor (dev) or cargo clean -p editor -p game -p game_hot -p shared && cargo build -p editor --bin editor --features dev, then launch Editor: Debug again. Use cargo run -p editor --features dev from the terminal if you need libbevy_dylib on LD_LIBRARY_PATH automatically.

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
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)
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
Asset Browser project/file views Browse assets/, search/filter/sort models, textures, materials, audio clips, levels, and prefabs; switch grid/list; expand model subassets; inspect file details; 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
Asset Browser context/details actions Apply textures/materials, regenerate thumbnails, reimport models, place assets/submeshes, or move file assets to assets/.trash/
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 renderer slot, primitive, or brush face under the pointer; release commits one undo step, while Escape/right-click/outside restores the preview
Drag Texture onto viewport surface Set a primitive base-color texture or exact brush face; renderer slots reject loose textures and direct you to a Material Instance
Static/Skinned Mesh Renderer material slots Assign a shared Material/Material Instance per slot; Browse/Select/Locate the reference, or Clear the override to restore the imported source material
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, Open, transactional Save/Save As, recovery restore/keep-copy/discard when available, Import Assets, Export Selection, Save Selection As Prefab (including linked-root variants), Recent Scenes
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
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.
  • 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.
  • 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 and ADR 0031.
  • 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 and ADR 0032.
  • 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 and ADR 0037.
  • 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).
  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. 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.

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.

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 editor/game Debug, GPU-validation, hot-reload, SDR fallback, and Release configurations. Normal launches keep HDR enabled while quieting known Vulkan validation noise; dynamic-link launches set the required LD_LIBRARY_PATH automatically.
  • .github/workflows/ci.yml mirrors local formatting, check, clippy, test, and binary build verification.

Architecture Decisions

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

  • Workspace: game, shared, editor, protocol, sim
  • Shared authoring components + hydration
  • Protocol tick, input intent, command, and basic message/event types
  • Fixed-step deterministic sim crate for player movement/controller state
  • Runtime game refactored into GamePlugin
  • Raw game input translated into protocol intent before simulation
  • Docked egui editor scaffold
  • Editor fly camera
  • Mesh picking selection + highlights
  • Transform gizmos
  • Editor-side scene visualizers for colliders, lights, player spawns, prefab/model anchors, and runtime player/cameras
  • Selectable, screen-sized actor root icons in the 3D viewport with per-category visibility controls
  • Filtered hierarchy, inspector, viewport, toolbar, asset browser, and status panels
  • Delete, duplicate, rename, and structural/material undo-redo
  • Native Bevy scene New/Open/Save/Save As with dirty title tracking
  • Asset import, static mesh/prefab placement, texture assignment, and selection export
  • PIE player-only snapshot/restore (authored LevelObject edits persist on stop)
  • Unified viewport render-to-texture target + Play session bootstrap
  • PlayerSpawn authoring marker for editor Play start location
  • BRP enabled in the editor
  • Cursor/VSCode workspace tasks + launch configs
  • Opaque Wayland window launch defaults + SDR/HDR runtime toggle
  • CI workflow for format, check, clippy, tests, and binary builds
  • ADRs for roadmap architecture and Bevy migration policy
  • Determinism harness: same inputs over same ticks produce the same state summary/hash
  • Reusable editor operator harness for commit/cancel/block, helper cleanup, dirty state, grouped undo, and undo/redo round trips
  • Verify: cargo fmt --check / cargo check --workspace / cargo clippy --workspace / strict foundation clippy / cargo test -p sim
  • Stable asset registry with UUIDs + import settings in asset browser details
  • 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
  • Audio clip catalog/import foundation for Ogg, WAV, MP3, and FLAC with dedicated filtering, file details, and stable runtime-resolvable asset references
  • 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; production acceptance completed in Gitea #47)
  • glTF/GLB skeletal animation manifests, stable controller states, non-dirty preview, PIE/runtime hydration, and exact-signature compatibility validation (ADR 0031; production acceptance completed in Gitea #46)
  • 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; evaluation; Gitea #48)
  • 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, collaboration guide, Gitea #49)
  • Prefab instances (PrefabInstance) + save-as-prefab + unpack
  • Independent dirty-tab close confirmation and all-tab save guard when switching projects
  • Transactional scene writes + bounded user-local recovery snapshots (ADR 0023)
  • Versioned clean/crash session resume + privacy-bounded diagnostic bundle (ADR 0024)
  • Hierarchy multi-select, reparent undo, multi-entity gizmo transform
  • 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
  • Gameplay authoring markers + visualizers (WeaponSpawn, TriggerVolume, etc.)
  • Command palette execution; PIE sim step (F7); xtask validate-levels
  • ADRs 00050012 (prefab/registry, scene schema, EditorPlugin, editor structure, authoring/hydration, ActorKind, sun policy, zero-debt)
  • ActorInspectorSection registry + game demo section (game::editor_ext)
  • Command palette: reset lighting, group selection, focus selection
  • CI: cargo test -p shared, scene authoring-only check on repo level, cargo check -p editor --features dev
  • scene crate schema stamp/migrate/validate on save/load + CI validate-levels for levels and prefab graphs
  • Project Settings draft + Apply (HDR/swapchain safe)
  • Project Browser UI, strict manifest validation, --project startup activation, recent filtering, sandbox scaffolding, clean process handoff, and desktop launcher action (ADR 0025)
  • Independent scene tabs + stable subscene composition, recursive validation, ownership locks, active-world PIE consistency, and per-saved-tab recovery (ADR 0026)
  • Editor lib/bin split + EditorPluginGroup; game EditorPlugin dogfood panel
  • FBX/glTF model import + normalized static/skinned renderer routing; explicit generic scene-instance load via bevy_ufbx / ModelRef
  • Asset browser model thumbnails (unified assets/thumbnails/ pipeline; ThumbnailState cache; FBX via FbxThumbnailSource)
  • Shared Material/Material Instance assets, stable static/skinned renderer material slots, imported-source fallback, orphan preservation, and runtime-only property blocks (ADR 0035, material-system guide)
  • 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; Gitea #16, Gitea #18)
  • 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)
  • 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)
  • 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, Gitea #45)
  • 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, build guide, Gitea #44)
  • Advanced rendering: GiMode, post-process volumes, Rendering panel, requested/effective render stack, Solari integration, emissive materials, post FX assets (ADR 0013, ADR 0016, rendering guide)
  • 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, material-system guide)
  • Static mesh renderer component, generated normalized mesh artifacts, source/one-actor hierarchy placement, and inspector renderer slots (ADR 0017)
  • Dedicated SkinnedMeshRenderer/SkinnedMesh actor path, skinned-part exclusion from static slots, dedicated runtime hierarchy hydration, and v2-to-v3 animated-scene migration (ADR 0033)
  • Componentized actor inspector, unified component cards, thumbnail static mesh slots, imported asset Browse/Locate/Clear refs with inherited source defaults, collider split, shader-aware actor material data, and texture picker/drop refs (ADR 0018)
  • 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, extensibility guide)
  • Brush authoring schema MVP with ActorKind::Brush, cube BrushDesc, generated mesh hydration, scene migration, and inspector Add Component support (ADR 0021)
  • Brush draw, vertex/edge/face gizmo editing, face material/UV authoring, clip, and bounds-based CSG preview/commit workflow (brush guide)
  • 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, texture and model thumbnails (glTF albedo fast-path; offscreen render studio for FBX and untextured models), material sphere thumbnails, search/filter/sort controls, expandable model subasset shelves, and a staged details pane. File → Import Assets accepts glTF/GLB and FBX (binary; copies sibling .fbm texture folders when present). 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.
  • 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.
  • Material and direct-base Material Instance assets live under assets/materials/; shader schemas live under assets/shaders/. Window > Material Library provides cross-folder creation, editing, usage filters, and drag sources. Viewport Material drops target one exact renderer slot, primitive, or brush face and use reversible preview plus one-step history; loose Textures target primitives/brush faces and are rejected on renderer slots. Shared edits propagate through live-updated handles without reloading skinned geometry. Custom Surface evaluators share one constrained ABI between raster and Solari-eligible non-deformed geometry. Dynamic skinned/morph Solari geometry and a persisted property-block authoring workflow remain future work; see the material-system guide.
  • 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.