505 lines
47 KiB
Markdown
505 lines
47 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
|
||
|
||
## 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 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:
|
||
|
||
```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...** 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`](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
|
||
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) |
|
||
| 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 |
|
||
| 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, non-blocking native Open/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 |
|
||
| 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. 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 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
|
||
|
||
- [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)
|
||
|
||
## 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] 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] 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] 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] Asset browser model thumbnails (unified `assets/thumbnails/` pipeline; `ThumbnailState` cache; FBX via `FbxThumbnailSource`)
|
||
- [x] Shared Material/Material Instance assets, stable static/skinned renderer material slots, imported-source fallback, orphan preservation, and a persistence-excluded property-block schema; runtime block application/promotion remains tracked in [Gitea #53](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/53) ([ADR 0035](docs/adr/0035-shared-material-assets-and-renderer-slots.md), [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, 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](docs/adr/0018-componentized-actor-inspector-and-materials.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,
|
||
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](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 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. Runtime property-block application/promotion is tracked in [#53](https://git.spacetrainclubhouse.com/Falling-Metal-Interactive/Blacksite/issues/53); dynamic skinned/morph Solari geometry is 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`.
|