# Oxide Engine — Long-Term Development Plan

Each stage must be completed and signed off (manual + automated testing) before the next begins.
Stages are designed so that each one produces a usable, standalone artifact that later stages build upon.

The **in-engine editor** (`oxide-editor`) is a first-class deliverable. It is developed in parallel with
the engine: each stage adds editor support for the systems introduced in that stage.
The editor crate lives at `editor/` and is always buildable alongside the engine.

The project must remain installable as a Linux package at all times. `install.sh` builds a release
binary and installs it to the system. Keep it current whenever new binaries or assets are added.

---

## Development Phases

Oxide is built in two phases:

- **Phase 1 — The general-purpose engine (Stages 0–16).** Everything needed to build *and ship* any
  3D game: core framework, editor + project system, input, UI, physics, scripting, animation,
  particles, shaders, audio, a content kit, and game export to Linux + Windows. Stage 16 is the
  **milestone**: a complete, general-purpose engine that can build and export real games.
- **Phase 2 — Built-in modules (Stages 17+).** Optional, self-contained capabilities — ray-traced
  audio, a developer console, a procedural toolkit, terrain, open-world streaming, pathfinding/AI,
  water — each shipped as a feature-gated **module** built entirely on Phase-1 systems. Phase 2 is
  also the proof the module API holds: adding a capability should mean *writing a module*, not
  surgery on the core.

The headline framing is simply **a general-purpose 3D engine that scales from stylized low-poly to
realistic, shipping only what each game uses.** Simulation, open world, and procedural generation are
*capabilities the engine supports through modules*, not design drivers — the goal is to **build
tools, not games**.

---

## Platform & Target Strategy

These are project-wide constraints that span every stage, not a single deliverable:

- **Primary platform is Linux**, and Linux means **both Wayland and Xorg (X11)** — the editor and
  any engine app must run on either without code changes. This is the default and must stay working
  at every stage (verified via `winit`'s `wayland` + `x11` backends, both enabled).
- **Windows support comes later** — once enough of the engine exists to be worth porting, a compiled
  Windows build of the editor/engine is added. Code should avoid Linux-only assumptions so this port
  stays cheap; `wgpu`/`winit` already abstract the platform layer.
- **Game export targets both Linux and Windows binaries.** A project built in the editor must be
  exportable to standalone runnable binaries for both platforms (see Stage 16). The editor and the
  exported game share the same engine runtime.

## Cross-Cutting Principles (apply to every stage)

- **Build tools, not games.** The engine ships composable building blocks (e.g. noise + modifiers,
  not a "make me a world" button). Genre-specific behavior belongs in game code or optional modules.
- **Ship only what's used.** Subsystems are **feature-gated modules**; an exported game compiles in
  only the modules it registers. The same engine produces a tiny stylized game and a heavy realistic
  one, differing only in which modules are present.
- **Scalable fidelity.** The renderer is a **data-driven pass pipeline** so a project can run a flat
  unlit/low-poly look (or a stylized post effect like a VCR filter) or a full realistic stack with
  shadows, SSAO, and bloom — paying only for the passes it enables.
- **Modules are the primary extension point.** A module registers engine logic (systems, components,
  asset loaders) **and** editor integration (panels, menu items, tools, inspectors) **and** its own
  settings, through one documented API. Anyone — including AI agents — can write a module. Native
  modules are Rust crates implementing the `Module` trait; lightweight modules can be `rhai` scripts.
- **Editor- and script-editable types.** Engine component types (e.g. `Transform`, `Node`, `Script`,
  materials, colliders) must be editable **both** from the editor UI **and** from scripts/code,
  through the same reflected/serializable representation. From Stage 5 this is backed by a reflection/
  type registry, so any editor — or an **AI agent in the editor terminal** — can create and edit game
  code and scene data in real time. New component types are added with this dual-editability built in.
- **Live reload by default.** Game scripts/assets are watched on disk; changes are picked up and
  applied to the running editor without a restart (watcher foundation in Stage 6, full script reload
  in Stage 10). Assets added earlier keep their loaders reload-friendly.
- **The editor grows every stage.** Each stage adds editor support for its systems through the
  Stage-6 editor framework: a top menu, dockable panels, an undo/redo command stack, a module-driven
  extension API, and a **settings/preferences framework** that every system contributes pages to
  (engine prefs, editor prefs, input bindings, per-module settings, enable/disable modules).
- **Choice of subsystems.** Where the engine offers an advanced system it also offers a standard one
  so each project can choose its trade-off — most concretely **audio**: a standard mixer/spatial
  system (Stage 14, core) *and* a ray-traced propagation module (Stage 17), sharing components.
- **Comprehensive, not minimal, gameplay systems.** Physics, input, and the UI are first-class, full
  systems (Stages 7, 8 & 9), not thin wrappers — they must cover the cases real games need.
- **Document as you build, including how to extend.** A stage is not complete until its systems are
  documented under `docs/`. Every module ships documentation for **both** how to *use* it **and** how
  to *create* one like it (an authoring guide), so the module ecosystem is approachable.

---

## Status

| Stage | Title | State |
|-------|-------|-------|
| 0 | Project Foundation | ✅ Complete |
| 1 | Math & Core Primitives | ✅ Complete |
| 2 | Window & Render Context | ✅ Complete |
| 3 | Scene Graph & Entity System | ✅ Complete |
| 4 | Basic 3D Rendering | ✅ Complete |
| **Phase 1 — General-purpose engine** | | |
| 5 | Engine Core Framework (modules, layers, assets, reflection, render graph) | ✅ Complete |
| 6 | Editor Framework & Project System | ✅ Complete |
| 7 | Input System (mapping + remappable actions) + gizmos | ✅ Complete |
| 8 | Comprehensive UI System | ✅ Complete (pieces 1–8 on `main`; the editor UI canvas — piece 9 — shipped as Stage 8.5 piece 7) |
| 8.5 | Reflection v2, Editor Redesign & Asset Database (foundation) | ✅ Complete — every component type is editor- and script-editable with no per-type code; asset database + UI canvas on `main` |
| 8.7 | Editor Play Mode (Play/Pause/Step/Stop) | ✅ Complete on `main` — snapshot/restore + play-state model, `App::step`/`tick_for`, toolbar + Ctrl+P/Ctrl+. + viewport tint, scene-swap host runner (eye-checked & approved 2026-06-16) |
| 9 | Physics Integration (comprehensive) | ✅ Complete on `main` — full sim/events/queries/joints/character controller + 2 examples + editor types/play-loop/collider gizmos + raycast debug probe (freeze-on-click; eye-checked & approved 2026-06-17) |
| 10 | Scripting, Live Reload & Editor Terminal | 🚧 Core done on `main` (eye-checked & approved 2026-06-17): `oxide-script` crate (`Script`, `.rhai` loader, sandboxed `ScriptEngine`, `ScriptModule`) + lifecycle (`init`/`update(dt)` via `ScriptHost`) + `Vec3`/transform engine API + **live reload** (`examples/script_spin`) + **editor integration** (`Script` addable; play-loop shares asset server/db → live `.rhai` edits update a *playing* scene) + **Console** (captures the `log` stream — script `print`/errors) + **command terminal** ($ → `sh -c`) + **interactive PTY terminal** (`portable-pty`+`vt100`, tabbed, auto-close on exit, Tab/arrows/Esc routed; runs shells/TUIs/`claude`). **Remaining:** richer script API (spawn/despawn + component add/edit beyond `Transform`); then the editor-UX batch (file explorer, native New/Open dialog, New-Script button, open-script-in-editor) |
| 11 | Animation System | ⬜ Planned |
| 12 | Particle System | ⬜ Planned |
| 13 | Shader System & Advanced Graphics | ⬜ Planned |
| 14 | Standard Audio System | ⬜ Planned |
| 15 | Engine Content & Prototyping Kit | ⬜ Planned |
| 16 | Windows Support & Game Export | ⬜ Planned — **Phase 1 milestone** |
| **Phase 2 — Built-in modules** | | |
| 17 | Ray-Traced Spatial Audio (module) | ⬜ Planned |
| 18 | Developer Console & Cheats (module) | ⬜ Planned |
| 19 | Procedural Toolkit (module) | ⬜ Planned |
| 20 | Terrain System (module) | ⬜ Planned |
| 21 | Open World Support (module) | ⬜ Planned |
| 22 | Pathfinding & NPC AI (module) | ⬜ Planned |
| 23 | Water System (module) | ⬜ Planned |

> Backlog (post-roadmap capabilities and additional modules) is at the end of this file.

---

## Stage 0 — Project Foundation ✅
**Goal:** A buildable, testable Rust project with core structure in place.

### Deliverables
- Cargo workspace layout (`engine/`, `editor/`, `examples/`, `tests/`)
- Basic logging and error handling infrastructure
- CI-ready: `cargo build`, `cargo test`, `cargo clippy`, `cargo fmt` all pass
- Empty integration test harness
- `README.md` with engine description, build instructions, and install instructions
- `install.sh` — builds release binaries and installs to `/usr/local` (or `$PREFIX`)
- Editor stub: `oxide-editor` binary that starts, logs, and exits cleanly

### Test Criteria
- `cargo build` succeeds from clean checkout
- `cargo test` runs (even with zero tests) without error
- Clippy reports zero warnings with `deny(warnings)`
- `install.sh` completes without errors on a clean Linux system
- `oxide-editor` binary runs after installation

---

## Stage 1 — Math & Core Primitives ✅
**Goal:** Solid math foundation every other system will depend on.

### Deliverables
- Choose and integrate math library (`glam` preferred) — done (`glam` with `serde`)
- `Transform` type: position, rotation (quaternion), scale — `engine/src/math/transform.rs`
- `AABB`, `Ray`, `Plane`, `Frustum` types — `engine/src/math/{aabb,ray,plane,frustum}.rs`
- Common utility types: `Color`, `Rect`, `Range3` — `engine/src/math/{color,rect,range3}.rs`
- Unit tests for all types (edge cases: zero scale, gimbal lock paths, etc.) — 69 unit tests
- **Editor:** no visible UI yet; math types available via `oxide_engine::math` / `prelude`

### Test Criteria
- 100% unit test coverage on all math types — ✅ every type has a `tests` module
- Fuzz transform composition (random chains should remain stable) — ✅ `tests/` `stage1::fuzz_transform_chains_stay_stable`
- Benchmark: 1M transform multiplications under 10ms — ✅ ~5.1ms (`cargo bench -p oxide-engine`)

### Notes
- `Transform` stores decomposed TRS; composition takes an exact fast path for
  uniform scale and re-decomposes from the matrix for the non-uniform case.
- `Range3` is a *value* range (clamp/lerp/remap), distinct from `Aabb` (geometry).
- Runnable example: `cargo run -p oxide-examples --bin math_demo`.

---

## Stage 2 — Window & Render Context ✅
**Goal:** A window opens, GPU context is acquired, a colored screen is displayed.

### Deliverables
- `winit` integration for window creation and event loop — `engine/src/window/` (`App` trait, `AppCtx`, `WindowConfig`, `run`)
- `wgpu` device/queue/surface setup — `engine/src/render/` (`Gpu`, `RenderContext`)
- Clear-color render loop (configurable clear color) — `render::clear_view`, `AppCtx::set_clear_color`
- Resize handling — `RenderContext::resize`, driven by the event loop; minimized windows clamp to 1×1
- Input event plumbing (keyboard, mouse — raw events only, no abstraction yet) — every `WindowEvent` forwarded to `App::event`; types re-exported via `window::event`
- **Editor:** opens its own window using this infrastructure; displays a placeholder viewport (dark clear, raw input logged, `Ctrl+Q` quits)

### Test Criteria
- Window opens on Linux without errors — ✅ manual sign-off (2026-06-11, Wayland, RADV/Vulkan)
- Resize does not crash or produce artifacts — ✅ manual sign-off
- Clear color changes are reflected immediately — ✅ manual sign-off (`hello_window` keys 1–5/Space)
- Manual: run the `hello_window` example and confirm stable 60+ FPS on minimal GPU — ✅ ~3700 FPS (RX 9070 XT, Mailbox present mode)
- Automated: headless GPU clear verified by pixel readback — ✅ `tests/` `stage2::headless_clear_fills_texture_with_clear_color`

### Notes
- Docs: `docs/windowing.md`, `docs/render-context.md`.
- `wgpu`/`winit` are re-exported (`oxide_engine::wgpu` / `::winit`) so consumers
  don't need to version-match their own copies.
- egui editor panels intentionally deferred to Stage 3 (Stage 2 editor scope is
  the placeholder viewport only).

---

## Stage 3 — Scene Graph & Entity System ✅
**Goal:** Entities with transforms exist in a hierarchy; scene can be queried and mutated.

### Deliverables
- Choose and integrate ECS — done (`hecs`, re-exported as `oxide_engine::hecs`)
- `Scene` type: add/remove/query entities — `engine/src/scene/graph.rs`
- `Transform` hierarchy (parent-child with world-space resolution) — `Scene::world_transform` / `world_transforms`
- `Node` component: name, enabled flag — `engine/src/scene/node.rs`
- Scene serialization/deserialization (RON) — `Scene::to_ron` / `from_ron`, stable index-based format
- `examples/scene_basic`: create a hierarchy, print world transforms — done
- **Editor:** scene hierarchy panel; select, rename, enable/disable, reparent nodes — done (egui Hierarchy + Inspector panels)

### Test Criteria
- Parent transform propagates correctly to children — ✅ unit + `tests/` `stage3`
- Removing a parent removes or detaches children (configurable) — ✅ `DespawnPolicy::{Recursive, DetachChildren}`
- Serialize → deserialize round-trip produces identical scene — ✅ byte-identical re-serialization
- 10,000 entity scene with 5-level deep hierarchy resolves in under 1ms — ✅ ~0.6ms (`cargo bench -p oxide-engine --bench scene`)
- Manual: editor hierarchy/inspector panel verified by maintainer (2026-06-11, Wayland, RADV/Vulkan)

### Notes
- Docs: `docs/scene.md`.
- The hierarchy is owned by `Scene` (ordered `roots`/`children`), not stored as
  components, for deterministic ordering and cheap reparenting; the ECS still
  owns all entity data, so later stages attach their own components.
- egui is an **editor-only** dependency: the engine exposes a generic post-clear
  draw hook (`App::render(&RenderCtx)`) and the editor's `EguiLayer` draws
  through it, keeping egui out of the engine's dependency tree.

---

## Stage 4 — Basic 3D Rendering ✅
**Goal:** Meshes are loaded and rendered with a simple material system.

### Deliverables
- `Mesh` type: vertex buffer (position, normal, UV), index buffer
- GLTF loader (static meshes only, no animation yet)
- Forward renderer: depth buffer, basic lit pass
- `Material` type: albedo color/texture, roughness, metallic (PBR-lite)
- Camera component with perspective projection
- `examples/hello_mesh`: load a GLTF cube/sphere and render it
- **Editor:** 3D viewport renders the active scene; camera orbit/pan/zoom controls; material inspector panel

### Test Criteria
- GLTF primitives (cube, sphere, plane) render correctly
- Depth ordering is correct (no z-fighting on simple scenes)
- Camera movement updates the view matrix correctly
- Manual: inspect rendered output for correct lighting on a sphere — ✅ maintainer sign-off (2026-06-12)

### Notes
- Docs: `docs/rendering.md`.
- The forward renderer has automatic render-backend fallback
  (Vulkan/Metal/DX12 → GL → software) so it runs on a wide range of GPUs.
- The hardcoded forward pass from this stage is generalized into a data-driven
  **render pass pipeline** in Stage 5 — later passes (shadows, post-process,
  overlay UI) compose into it rather than rewriting the renderer.

---

## Stage 5 — Engine Core Framework
**Goal:** The structural "spine" every later system plugs into: a module system, scene/object
**layers & tags**, a central **asset server**, a minimal **reflection/type registry**, and a
**data-driven render pass pipeline**. Built now, while the engine is small, so later stages add
capabilities without rewriting the core.

### Deliverables
- **Module system + app builder.** An `App`/`Engine` assembled by registering `Module`s. A
  `Module::build(&mut App)` hook registers: update systems (with an explicit ordering/schedule),
  component types, asset loaders, and (via Stage 6) editor integration. `DefaultModules` bundles the
  built-in set. Math/window/render/scene are wrapped as built-in modules; subsystems from Stage 9 on
  are built as **their own feature-gated crates** (`oxide-physics`, `oxide-audio`, …) so an exported
  game compiles in only what it registers.
- **System scheduling.** A simple, deterministic ordered schedule (e.g. `Input → PreUpdate → Update →
  PostUpdate → Render`) that modules attach systems to, with a fixed-timestep slot reserved for
  Stage 9 physics.
- **Layer & Tags.**
  - **`LayerMask`** — a 32-slot bitmask with a **project-level named-layer registry**. One shared
    definition consumed by physics collision groups + sensor filtering (Stage 9), **camera
    visibility masks** (which layers a camera renders — first-person view models, editor-only gizmo
    layers, minimap cameras), and **scene/raycast query filtering**, plus editor per-layer
    show/hide/lock.
  - **Groups/tags** — the *multi-valued* counterpart to the *single-valued* `Layer` (Unity model: an
    entity is on one layer but in any number of groups). Membership lives in the `Tags` component;
    the project's valid group names live in a `GroupRegistry` so the editor offers a fixed vocabulary
    to pick from. Separate from the hot-path `LayerMask`.
- **Asset server + handles.** A central registry returning typed, ref-counted **handles**
  (`Handle<Mesh>`, `Handle<Texture>`, …) with async loading and a pluggable loader registry. Stage 4's
  GLTF/texture loading is migrated onto it. This one system underpins live reload (Stage 10),
  streaming (Stage 21), and export packing (Stage 16), so it lands before more loaders accrue.
- **Reflection / type registry (minimal).** Register a component type once and get serialization
  (serde/RON), a generic editor inspector (Stage 6), and script access (Stage 10) — the backbone of
  the *dual-editable types* principle. Existing hand-written inspectors are migrated as the registry
  matures; every component type from Stage 7 on is dual-editable by construction.
- **Data-driven render pass pipeline.** Generalize Stage 4's forward pass into an ordered, composable
  list of passes (depth, lit, transparent, post-process, overlay) with shared render targets. A
  project/module enables only the passes it needs — this is the mechanism behind *scalable fidelity*
  (a flat low-poly look vs. a full realistic stack) and the insertion point for Stage 13's
  post-process effects and Stage 8's UI overlay.
- **Editor:** no new dedicated panel beyond wiring — the hierarchy/inspector now read the reflection
  registry, the viewport gains a layer visibility toggle, and the groundwork is laid for Stage 6's
  module/extension framework.

### Delivered (all on `main`)
- ✅ **Layers, groups & tags** (`oxide_engine::layer`) — `LayerMask`, `LayerRegistry`, single-valued
  `Layer`, multi-valued `Tags` + `GroupRegistry`.
- ✅ **Reflection/type registry** (`oxide_engine::reflect`) — generic name-keyed component access.
- ✅ **Asset server + handles** (`oxide_engine::asset`) — ref-counted `Handle<T>`, dedup, loaders,
  background load, in-place reload; glTF migrated onto it.
- ✅ **Module system + scheduling** (`oxide_engine::app`) — `App` + `Module` + `Schedule`
  (phases incl. fixed-timestep), enable/disable/remove; `CoreModule`/`RenderModule`/`DefaultModules`.
- ✅ **Data-driven render pass pipeline** (`oxide_engine::render::RenderPipeline`) — composable
  `RenderPass` list, `ClearPass`/`ForwardPass`, camera `LayerMask` visibility; editor viewport +
  `hello_mesh` retrofitted. Maintainer manual sign-off 2026-06-12 (viewport + `hello_mesh` render
  identically).

> **Known tech-debt (tracked):** there are now two `App` types — the engine container
> `oxide_engine::app::App` and the windowing `oxide_engine::window::App` trait (the per-window event
> handler). To avoid the clash the core `App` is intentionally **not** in the prelude (import it as
> `oxide_engine::app::App`); `window::App` stays in the prelude. Resolve by renaming the windowing
> trait (e.g. `WindowApp`/`AppHandler`) when the editor adopts the core `App` loop in Stage 6/7 — a
> GUI-affecting change best done with a manual-test pass, not in isolation.

### Test Criteria
- An app composed purely by registering modules runs; removing a module removes its systems,
  components, and assets with no dangling references
- A feature-gated module excluded at compile time produces a binary with none of its code
- `LayerMask` filtering is correct and shared: the same named layer drives a render visibility mask
  and (stubbed) a query filter identically
- The asset server returns ref-counted handles; loading the same asset twice yields one resource;
  dropping all handles frees it
- A component registered with the reflection registry round-trips through RON and is read/written
  generically (proving the inspector/script path) without type-specific code
- The render pipeline runs Stage 4's scene through the new pass list with identical output, and a
  pass can be added/removed without touching the renderer core
- Benchmark: module/system scheduling overhead is negligible vs. the Stage 4 hardcoded loop

---

## Stage 6 — Editor Framework & Project System ✅
**Goal:** Turn the editor from a fixed set of panels into a proper, extensible application shell with
a **project system** — so every later stage (and every third-party module) plugs UI, tools, and
settings into a consistent host, and real projects can be created, opened, and saved.

### Deliverables
- **Editor shell.** A top **menu bar** (File / Edit / View / Project / Window / Help / module menus),
  a **dockable/resizable panel system**, status bar, and a registry of panels modules can add to.
- **Command / undo-redo stack.** A central, editor-wide command stack so every tool (transform
  gizmos, inspector edits, and later sculpt/paint/scatter) is undoable/redoable through one
  mechanism — landed here so all subsequent editor tools are undoable for free.
- **Module → editor extension API.** The Stage-5 `Module` gains an editor hook to contribute: menu
  items, dockable panels, viewport tools/gizmos, component inspectors (via the reflection registry),
  and settings pages. This is *the* mechanism by which "anyone can write a module" that extends both
  engine logic and the editor.
- **Settings / preferences framework.** A unified, serialized settings system with pages contributed
  by the engine, the editor, and each module:
  - **Editor preferences** (theme, layout, viewport, shortcuts) and **engine preferences**
    (render/quality defaults) — grown incrementally as later stages add their options.
  - **Module management:** list installed modules, **enable/disable** them, and edit each module's
    own settings page.
  - Input bindings get their settings page here once Stage 7 lands.
- **Project system.** Create / open / save a **project**: a project file (RON) plus a defined asset/
  scene/script folder layout, a list of enabled modules and their settings, and per-project
  preferences. A recent-projects list and a "new project" flow. Scenes load/save within a project.
- **File-watcher foundation.** Watch the project's asset/scene folders (`notify`) and reload changed
  assets live — the groundwork for Stage 10's full script hot-reload and the "edit with any external
  editor or AI agent" workflow.
- **Editor:** the existing hierarchy/inspector/viewport are reparented into the new docking shell;
  a Project panel/asset browser; a Preferences window with the settings pages above.
- **Resolve the Stage-5 `App` naming clash.** As the editor adopts the engine's core
  `oxide_engine::app::App` loop here, rename the windowing `window::App` trait (e.g. `WindowApp`) so
  the core `App` can live in the prelude unambiguously (see the Stage-5 tech-debt note).

### Test Criteria
- Panels can be docked, undocked, resized, and restored across restarts (layout persists)
- A trivial test module adds a menu item, a panel, and a settings page purely through the extension
  API — with no edits to editor core
- Undo/redo correctly reverses and re-applies a sequence of edits (e.g. rename, reparent) through the
  single command stack
- Creating, saving, closing, and reopening a project restores its scenes, enabled modules, and
  settings unchanged (RON round-trip)
- Enabling/disabling a module in settings adds/removes its systems and editor contributions live
- Editing a watched asset file on disk updates the running editor without a restart
- Manual: maintainer creates a project, rearranges the layout, toggles a module, and reopens it

---

## Stage 7 — Input System (mapping + remappable actions) + gizmos ✅
**Goal:** A comprehensive input abstraction used by all higher-level systems, with full per-key
edge detection and a remappable named-action layer — and the editor's viewport transform gizmos,
built on the Stage-6 command stack.

**Status (2026-06-14):** ✅ Complete. Shipped in six pieces — `InputState` (1), `ActionMap` /
`Binding` (2), axis + 2D-axis actions (3), editor flythrough camera (4), input-bindings
preferences page with disk persistence (5), gizmo math + viewport tab sizing + viewport
gizmos (6a/6b/6c). Final maintainer test surfaced three issues (snap mid-drag, uniform-scale
sensitivity, sphere winding) — all fixed in the same stage. Gamepad bindings are deferred
("where available" in the deliverables); the rest is in.

### Deliverables
- `InputState`: keyboard, mouse button, mouse delta, scroll, gamepad (where available)
- **Per-key edge + state queries** for any physical key/button: `pressed` (this frame),
  `released` (this frame), and `held`/`down` (current state) — i.e. map any key to its press, up,
  and down events.
- **Named-action mapping with defaults and remapping.** Bind named actions (e.g. `"Jump"`) to one or
  more physical inputs, each action carrying a **default** binding (e.g. `Space`). Game code queries
  only the action name (`input.action_pressed("Jump")`) and never the physical key, so a project's
  settings screen can remap `"Jump"` to any other key without touching game code.
- **Bindings persistence**: action maps load/save (RON) so game settings can store user remaps,
  surfaced through the Stage-6 settings framework.
- Input consumed/propagated model (UI/editor can consume before game)
- Axis/2D-axis actions (e.g. movement) composed from keys and/or gamepad sticks
- `examples/input_debug`: print all actions and raw input each frame; `examples/input_remap`:
  rebind an action at runtime and show game code unaffected
- **Editor:** input bindings editor page (assign/clear/remap action bindings, restore defaults) in
  the settings framework; live input-state debug overlay; **viewport flythrough camera** (WASD/QE
  move, mouse-look, with Shift to accelerate) layered on top of the existing orbit/pan/zoom controls
- **Editor transform gizmos:** on-screen manipulators for the selected entity — **translate** (axis
  arrows + plane handles), **rotate** (axis circles), and **scale** (axis/uniform handles) — dragged
  directly in the viewport, every edit recorded on the Stage-6 undo stack. Includes a **snap system**
  with configurable increments (grid distance, angle step, scale step) and a modifier key to toggle
  snapping; switch active tool with hotkeys (e.g. W/E/R). With gizmos in place, the inspector's
  transform fields become **directly type-editable** (click to type an exact value), not drag-only.

### Test Criteria
- `pressed`/`released` fire exactly once on the correct frame; `held` reflects current state
- Dragging each gizmo axis moves/rotates/scales the selection on exactly that axis; snapping
  constrains the result to the configured increment; typed inspector values apply exactly; each is
  undoable/redoable through the command stack
- Action bindings can be changed at runtime and persisted/restored via RON
- Multiple keys can be bound to one action; one key can drive multiple actions
- Remapping an action changes behavior while game code (querying the action name) is unchanged
- Mouse delta is correct across frame boundaries (no jump on first frame)

---

## Stage 8 — Comprehensive UI System

**Status (2026-06-15): 🟡 In progress.** Pieces 1–7 complete and on `main`:

1. ✅ Widget tree + layout (`oxide_engine::ui::{widget, style, layout}`).
2. ✅ Styling & theming (`visual`, `theme`; cascade default → named → per-instance).
3. ✅ Text shaping + glyph atlas (`text/{font, atlas, shape}` via `ab_glyph`).
4. ✅ 2D overlay render pass — screen-space (4a) + world-space `UiPanel` (4b).
5. ✅ Input routing (`routing::Router`; hit-test + hover / press / focus state machine).
6. ✅ Events + data binding (immediate-mode `RouterFrame::clicked_left(...)` etc. + typed `WidgetValue`).
7. ✅ `examples/ui_menu` — themed main menu + draggable slider + checkbox settings.

Remaining for sign-off:

8. ✅ `examples/ui_hud` (health / ammo / minimap overlay + centre crosshair, composited over
   the Stage-4 forward pass) — signed off on `main` 2026-06-15 after maintainer eye-check. The
   atlas cache-hit claim it demonstrates is also covered by an automated GPU test
   (`render::ui_pass::atlas_caches_glyphs_and_reaches_steady_state`).
9. ⬜ Editor **UI canvas** — visual document builder.

**Goal:** A first-class, **in-game** UI system — widgets, layout, styling, text, and input routing —
that ships inside exported games. This is distinct from the editor's `egui` (which stays
editor-only): this UI is an engine system a project uses to build its menus, HUDs, and tools, and it
consumes input through the Stage 7 model and renders through the Stage 5 pass pipeline.

### Deliverables
- **Widget tree** owned by the engine and renderable in shipped games: containers/panels, label/
  text, button, image, checkbox, radio, slider, drop-down, text input, progress bar, and a
  scrollable list/view
- **Layout system**: stack (row/column), grid, and anchor/dock layouts; padding/margin, alignment,
  and sizing modes (fixed / grow / fit-content); resolution- and **DPI-aware** scaling
- **Styling & theming**: per-widget styles plus reusable themes (colors, fonts, spacing, borders),
  overridable per instance
- **Text rendering**: TTF font loading, a glyph atlas, alignment, wrapping, and multi-font support
- **Input integration**: UI consumes input *before* the game using Stage 7's consume/propagate model;
  hover/focus/press states; keyboard/gamepad focus navigation. (The Stage 7 bindings/remap settings
  screen is itself buildable with this UI system.)
- **Events & data binding**: widget callbacks/events and binding widget values to game data
- **2D overlay pass** integrated as a Stage-5 render pass (batched draws), plus optional
  **world-space UI** (a UI panel rendered on a quad in 3D)
- **Serializable, dual-editable UI documents** (RON): layouts round-trip through the engine's
  representation so they are authored in the editor *and* editable from scripts/AI agents
- `examples/ui_menu` (main menu + settings, including action remapping) and `examples/ui_hud`
  (health/ammo/minimap overlay)
- **Editor:** a visual **UI canvas** to build and arrange UI documents — widget palette, drag/resize,
  property inspector, and live preview — saving the same RON the runtime loads

### Test Criteria
- Widgets render and lay out correctly across window sizes and DPI scale factors
- Input routing is correct: UI consumes clicks/keys over its widgets, and the game receives input
  only where the UI does not consume it
- Hover/focus/press states and keyboard/gamepad focus navigation behave correctly
- Text renders crisply with correct wrapping and alignment; the atlas handles large glyph sets
- A UI document round-trips through RON unchanged (proving dual-editability)
- Manual: build a menu in the editor's UI canvas, run an example, and interact with it (including
  remapping an action from the settings screen)

---

## Stage 8.5 — Reflection v2, Editor Redesign & Asset Database (foundation)

**Status: ✅ Complete (2026-06-16).** All pieces (1–7) on `main`; piece 7c (UI canvas) eye-checked
& approved. Inserted before Stage 9 (and before Stage 8's deferred piece 9) because every later stage
adds component types (colliders, animation clips, particle emitters, audio sources, …) and each one
would otherwise need a hand-written editor inspector and hand-wired add/remove plumbing. Doing this
**now** was the cheapest it would ever be — it stops that per-type cost from accruing across Stages
9–16.

> **Known minor follow-up (UI canvas):** egui logs `Widget rect … changed id between passes` while
> interacting with the canvas — id instability from dynamically-sized property widgets across egui's
> two-pass layout. Harmless (egui recovers each frame) but noisy; quiet it by scoping the canvas's
> per-widget sections under stable `ui.push_id(...)`s. Low priority.

**Why:** Stage 5 shipped a *whole-value* reflection registry (`oxide_engine::reflect` round-trips a
whole component as RON). The editor inspector, however, is still **hand-coded per type**
(`transform_inspector`, `mesh_inspector` in `editor/src/shell.rs`), and component add/remove is
bespoke per type (`PendingAction::AddMesh/RemoveMesh`). This finishes the project's **dual-editable
types** principle: a component's public fields should surface automatically in the inspector and over
scripts (Stage 10), the Unity/Godot model — *public mutable fields appear as editable inspector
fields with no per-type code.*

### Component model — node-baked vs modular (2026-06-15 decision)

The maintainer surfaced a distinction the editor must honor explicitly:

- **Node-baked (essential):** every entity inherently carries them — they're
  part of *being a node*, not a feature the user adds. Today: `Node`,
  `Transform`, `Layer` (auto-attached on `Scene::spawn`). Always present,
  single-instance, rendered in a fixed canonical order, **no** enable
  checkbox, **no** remove button, **no** drag-reorder handle, **not** offered
  by the Add Component menu.
- **Modular:** the user's choice — `MeshRenderer`, `Camera`, `DirectionalLight`,
  future `RigidBody`, particle emitters, audio sources, custom scripts. Addable
  from the registry, removable, disable-able, reorderable.

The editor enforces this with `ESSENTIAL_COMPONENTS = ["Node", "Transform",
"Layer"]` (see `editor/src/shell.rs::is_essential_component`). Future
node-baked additions extend that list; modular ones just register through
`register_addable`.

**Layers & groups in the inspector (2026-06-16 decision — Unity model "A").**
The single-valued `Layer` renders as a single-select dropdown (with a Layer
Names editor); gameplay **Groups** (multi-valued, backed by `Tags` + a
`GroupRegistry`) render as a multi-select dropdown (with a Groups editor). Both
sit in the node-baked section above the modular list. An archetypal ECS allows
only **one component of a given type per entity**, so a second mesh/collider/etc.
lives on a **child** entity (the Add Component menu's "as child" path); several
*distinct* addable types (`MeshRenderer`, `Camera`, `DirectionalLight`) is what
makes multi-component nodes and drag-reorder exercisable.

**Multi-component-of-same-type** (e.g. two colliders, two meshes) is not
supported by archetypal ECS (`hecs` allows one per type per entity) and
**won't be lifted in Oxide**. The two principled patterns the engine offers:

- **Child entities** (Bevy-style): each "additional" piece is its own
  entity, parented to the owner. Composes with the existing hierarchy +
  drag-drop reparent + per-child enable/disable.
- **Submeshes / multi-slot components** (Unity-style): a single component
  wraps a list internally (e.g. a `Mesh` asset can have multiple submeshes
  with their own material slots).

Stage 9 (Physics) picks for colliders; Stage 13 (Shaders) may revisit for
meshes. The Add Component menu surfaces this clearly when a user tries to
add a duplicate ("Add Child with …" affordance — TODO in piece 4 polish).

### Deliverables

- **Reflection v2 — per-field reflection + a `#[derive(Reflect)]` macro.** A new
  `oxide-engine-derive` proc-macro crate generates, for a struct's public fields, a field table
  (name + type + typed get/set) re-exported from `oxide_engine`. `reflect.rs` grows from whole-value
  to field-level access while keeping the existing name-keyed registry API. Pure logic, fully
  unit-testable.
- **Generic reflection-driven inspector.** One inspector that walks a selected entity's registered
  components and renders a widget per field by type (`f32`→drag, `bool`→checkbox, `Color`→picker,
  `Vec3`→vec3 drag, enum→combo, `Handle<T>`→asset picker), falling back to a RON text field for
  unknown types. The hand-written `transform_inspector` / `mesh_inspector` are **deleted** and proven
  equivalent. All edits route through the existing undo/redo command stack.
- **Editor redesign items.** Hierarchy **right-click context menu** (Add Child / Add prefab / Rename
  / Duplicate / Delete); inspector **"Add Component ▾"** menu enumerated from the type registry;
  remove-component control per component. (The deferred Stage-8 piece 9 — the visual UI canvas — lands
  on top of this redesign so its property inspector is reflection-driven, not bespoke.)
- **Prefabs / archetypes (lightweight).** A named "spawn a thing that already carries these
  components" entry so the hierarchy add-menu is data-driven (an entity is its component set; this is
  not a parallel "object type" system).
- **Asset database + typed project folders.** `assets/` gains typed subfolders
  (`fonts/`, `textures/`, `models/`, `audio/`, `ui/`); an asset database maps **project-relative
  paths ↔ stable ids ↔ `Handle<T>`** so scenes and UI documents reference `"fonts/Inter-Regular.ttf"`
  rather than absolute system paths (a prerequisite for clean game export at Stage 16). The Project
  panel becomes an asset browser; "import" = drop a file into the right folder and let the watcher
  register it. A bundled default UI font lands here (resolves the Stage-8 follow-up).
- **`Handle<T>` as a reflected field type** so the generic inspector renders an asset-picker filtered
  by type — selecting a UI element then choosing its font is exactly this.
- **Docs:** `docs/reflection.md` (per-field model + derive), `docs/assets.md` (database + folders +
  picker), and an editor-redesign note; update `architecture.md`.

### Piece breakdown (each = one green commit)

1. ✅ `oxide-engine-derive` crate + `Reflect` trait (per-field name/type/get/set) + derive — pure
   logic, unit-tested, on `main`. Public-only fields + `#[reflect(skip)]`; per-field RON get/set.
2. ✅ `reflect.rs` per-field get/set through the registry via `register_reflected::<T: Reflect>`
   (`field_infos` / `get_field` / `set_field`); Transform + Node derive `Reflect`. Whole-value API
   unchanged. Pure logic, on `main`.
3. ✅ Generic reflection-driven inspector (signed off on `main` 2026-06-15 after eye-check). Split:
   - **3a**: `EditorState.registry` (Transform + Node reflected) + generic
     `SetFieldCmd{entity,type,field,before,after}` with merge-coalescing. Pure logic.
   - **3b**: the inspector UI — walks the registry, one heading per component, one typed widget per
     field (f32→drag, bool→checkbox, Vec3→3 drags, String→text, `Quat`→Euler degrees, unknown→RON
     fallback). Deletes the hand-written `transform_inspector`; `mesh_inspector` stays until piece 4.
     `Node` skipped (name/enabled shown by the header). Enum→combo deferred (needs variant reflection).
4. Hierarchy redesign + component lifecycle (GUI) — → `dev`, eye-check:
   - Hierarchy **right-click** context menu (Add Child / Add prefab / Rename / Duplicate / Delete).
   - **Drag-and-drop reparenting in the hierarchy**, and **remove the inspector's Parent dropdown**
     (maintainer request 2026-06-15: the dropdown lists every entity, so it doesn't scale to large
     scenes — reparenting belongs in the tree via drag-and-drop).
   - Inspector **"Add Component ▾"** (enumerated from the registry) + per-component remove control;
     make `MeshRenderer` reflected and retire the bespoke `mesh_inspector`.
   - Enum→combo widget (add variant reflection to `#[derive(Reflect)]` so enum fields like
     `PrimitiveShape` get a dropdown instead of the RON fallback).
5. Prefab/archetype spawn entries (logic + a little GUI) — split:
   - ✅ **5a** (engine logic, on `main`): `oxide_engine::prefab` — `ComponentSpec`/`Prefab`/
     `PrefabRegistry`, data-driven (component name + RON applied via the `TypeRegistry`), `spawn`/
     `spawn_child`/`unknown_specs`. Pure logic, unit-tested; `docs/prefabs.md`.
   - 🟡 **5b** (editor GUI, on `dev` — awaiting eye-check): `EditorState.prefab_registry` seeded
     with built-in prefabs (Empty/Cube/Sphere/Plane/Camera/Directional Light); hierarchy add-menus
     (toolbar Root/Child, row right-click Add Child, empty-area Add Root) are submenus listing them.
     Plain `AddRoot`/`AddChild` retired (the `Empty` prefab covers a bare node).
6. Asset database + typed folders + `Handle<T>` reflected + asset-picker widget (logic → `main`;
   picker GUI → `dev`) — split:
   - ✅ **6a** (engine logic, on `main`): `oxide_engine::asset::AssetDatabase` — typed `assets/`
     subfolders (`AssetKind`: fonts/textures/models/audio/ui), stable `AssetUid` ↔ relative-path
     manifest (`assets.manifest`), `scan`/`register`/`open`/`save`, and uid→`Handle<T>` resolution
     through the `AssetServer`. Unit-tested round-trip + moved-project case; `docs/assets.md`.
   - ✅ **6b** (engine logic, on `main`): `asset_ref_target` parses an `AssetRef<T>`/`Handle<T>`
     field's syntactic `type_name` to its target type, and `AssetKind::for_handle_target` maps that
     to the picker's filter kind. Added the serializable `AssetRef<T>` reference type (the form a
     component stores — `Option<AssetUid>` that `resolve`s to a `Handle<T>`). Pure logic, unit-tested.
   - 🟡 **6c** (editor GUI, on `dev` — awaiting eye-check): `EditorState.asset_db` (opened + scanned
     on project open/create, rescanned on watcher events); Project panel is an asset browser
     (typed-folder sections from the database + Rescan); `field_widget` asset-picker for
     `AssetRef<T>`/`Handle<T>` fields (lists assets of the matching kind, stores the `AssetUid`);
     bundles **Inter** (SIL OFL) as the default UI font, seeded into new projects' `fonts/`. The
     first component *using* an `AssetRef` field arrives with piece 7 (UI canvas).
7. Migrate Stage-8 piece 9 (UI canvas) onto the reflection-driven inspector — split:
   - ✅ **7a** (engine logic, on `main`): widget-tree authoring primitives in `oxide_engine::ui` —
     `WidgetPath` (positional addressing) + `Widget::{get_path,insert_child,remove_path,move_subtree}`
     (the basis for the canvas's undoable add/remove/move). Unit-tested.
   - ✅ **7b** (engine logic, on `main`): `FontLoader` (default-registered, makes `.ttf`/`.otf`
     loadable via `AssetServer`) + `VisualStyle.font_asset: Option<AssetRef<Font>>` (the engine's
     first `AssetRef<T>` field; overrides the `FontRef` descriptor when set). Unit-tested.
   - ✅ **7c** (editor GUI, on `main` — eye-checked & approved 2026-06-16): the UI canvas (`PanelKind::UiCanvas`,
     **centre tab beside the Viewport** — it needs the large central area), in a scroll area —
     open/new a `UiPanel` document; widget-tree panel (selectable, using 7a), Add ▾ palette
     (Leaf/Row/Column/Grid/Anchor), Remove, scaled canvas preview (egui painter), and a **type-aware
     property panel**: id/text, kind-specific (Leaf intrinsic; Stack direction/gap/main-align; Grid
     cols/rows/gap), visual (background/foreground/font size/**font asset picker**), and a Layout
     section (sizing, align x/y, padding, margin, **anchor preset**) so widgets are sized and
     positioned. Save to a `ui/` asset; edits route through `SetUiPanelCmd` (undoable). Follow-ups:
     engine-font-accurate preview via the real `UiOverlayPass`; change-kind; widget drag-reorder
     (the 7a `move_subtree` primitive is ready); anchor offset/handles for free drag-positioning.

### Test Criteria

- A brand-new component (e.g. a `Timer { repeating: bool, duration: f32 }`) becomes fully editable in
  the inspector **and** over RON/scripts with only `#[derive(Reflect, Serialize, Deserialize)]` + one
  registration line — **no per-type editor code**.
- The generic inspector reproduces the old Transform/Mesh inspectors' behavior (positions, rotation
  in degrees, scale, mesh shape) — verified by an automated round-trip plus a manual eye-check.
- An asset referenced by project-relative path resolves to the same `Handle<T>` across save/load and
  survives moving the project directory.
- Selecting a UI element in the editor and picking a font from the asset browser updates the rendered
  text.
- Manual: right-click the hierarchy to add/duplicate/delete; add a component from the inspector; pick
  an asset for a `Handle<T>` field.

### Editor-UX follow-ups (deferred from piece 6c — maintainer feedback 2026-06-16)

Piece 6c shipped a *functional* asset browser, but the maintainer flagged UX
improvements to do **properly later** (not blockers; kept out of their stages to
avoid feature creep mid-stage). **Reconfirmed + expanded 2026-06-17** (during
Stage 10): do this batch **after Stage 10 pieces 4 (terminal panel) & 5 (error
console)**. Each is GUI → `dev` + eye-check.

- **Unity-style asset/file explorer in the Project panel.** Today the typed
  folders (`fonts/ textures/ …`) are fixed, so importing means creating/using a
  folder with that exact name. Wanted: a real file explorer — create/rename/move
  folders, rename/delete assets, **drag files in from the OS** to import, context
  menus, breadcrumb navigation. The `AssetDatabase` already tracks arbitrary
  relative paths, so this is a UI/interaction layer over it (re-classify by
  folder still applies; loose files fall back to extension).
- **Proper file/path opener for New/Open Project.** Today both take a raw typed
  path, which the maintainer confirms "is very hard to use". Wanted: a native
  file/folder picker (a `rfd`-style dialog, working on Wayland + X11) and/or a
  better-designed in-editor chooser, instead of a free-typed path field.
- **"New Script" button on the `Script` component inspector** (Stage 10
  follow-up). Create a new `.rhai` from a template into `assets/scripts/` and
  auto-assign it to the component, without leaving the editor — today scripts
  must be authored as files outside the editor. The `.rhai` loader +
  `AssetKind::Script` already exist; this writes a template file + registers it.
- **Open a script in an editor** (Stage 10 follow-up). Double-click / button to
  open a `.rhai` in an in-editor text view or launch `$EDITOR` / a configured
  external editor; edits flow back through the existing live reload.

---

## Stage 8.7 — Editor Play Mode

**Status: ✅ Complete on `main`** (all three pieces; piece 3 GUI eye-checked & approved 2026-06-16).
Inserted before Stage 9 because Stage 9 already assumes the editor can **play/pause/step** the
simulation to test physics, yet no piece defined that loop. Decided with the maintainer 2026-06-16:
a **hybrid** model — in-editor play as the primary loop now, a standalone launch later.
Docs: [`docs/play-mode.md`](docs/play-mode.md).

### Piece breakdown
1. **Play-state model + snapshot/restore** — ✅ `main`. `PlayState {Editing,Playing,Paused}` +
   `play_snapshot` on `EditorState` (`enter_play`/`toggle_pause`/`stop`); registry-aware
   `oxide_engine::scene::SceneSnapshot` (captures reflected components + intrinsic `Tags`/
   `DisabledComponents`, not just `to_ron`'s hierarchy), restoring the scene bit-for-bit.
2. **Schedule driver primitives** — ✅ `main`. `App::step()` (one fixed tick, accumulator bypassed)
   and `oxide_editor::play::tick_for` (the testable Playing→Frame / Paused+Step→FixedStep / else Idle
   decision).
3. **Toolbar + viewport tint + runner** — ✅ `main`. Play/Pause/Step/Stop toolbar (gated by state,
   badge; Resume routes through `play_or_resume`), Ctrl+P / Ctrl+. shortcuts, green/amber viewport
   border; host runner owns the play `App`, swaps the editor scene in/out per tick (`state.scene`
   stays the source of truth), undo cleared on Play/Stop.

**Goal:** Drive the engine's update [`Schedule`](#stage-5--engine-core-framework) from the editor so
the open scene can be run, paused, single-stepped, and stopped **in the viewport**, with edits made
during play safely reverted on stop. The same fixed-timestep tick a shipped game uses is what the
editor drives, so play behaves like the real runtime.

### Deliverables
- **Play-mode toolbar** (Play / Pause / Step / Stop) in the editor's top bar, with matching
  shortcuts; a clear **"PLAYING" viewport tint / indicator** so edit vs play state is never ambiguous.
- **Play-state model** on `EditorState` (`Editing` / `Playing` / `Paused`); the host runner ticks the
  `Schedule` (incl. the fixed-timestep slot) only while `Playing`, and advances exactly one fixed tick
  per **Step** while `Paused`.
- **Snapshot / restore.** On **Play**, snapshot the scene (reuse the RON scene serialization); on
  **Stop**, restore it, so play-mode mutations (physics moving bodies, scripts spawning entities)
  never corrupt the authored scene — avoiding Unity's classic "edited in play mode, lost it" footgun.
- **Live inspect during play.** The reflection inspector and gizmos keep working while `Paused` (and
  `Playing`), so a field can be tweaked and the result observed live — the payoff of the Stage-8.5
  reflection work. (rhai scripts hot-reload with no compile step, so iteration is instant.)
- **Deferred to Stage 16 (export):** a **"Launch standalone"** button that runs the *real* exported
  runtime in a separate window/process via the export builder — the truest-to-ship check, reusing the
  Stage-16 packer rather than the in-editor loop.

### Test Criteria
- Press Play → the scene's update systems run and the viewport animates; Pause halts ticking; Step
  advances exactly one fixed tick; Stop returns the scene **bit-for-bit** to its pre-play state
  (automated: snapshot, mutate via a tick, stop, assert the scene RON matches the snapshot).
- Entering/leaving play mode does not leak entities, handles, or undo-stack entries into edit mode.
- Manual: play a scene, pause, edit a reflected field, observe the change; stop and confirm the scene
  reverts.

---

## Stage 9 — Physics Integration (comprehensive)
**Goal:** A comprehensive rigid-body physics system — collision, queries, constraints, and a
character controller — built as a **module** (`oxide-physics`) on `rapier3d`, not a minimal wrapper.

### Deliverables
- Integrate `rapier3d` as a feature-gated module registered through the Stage-5 app builder
- `RigidBody` component: static, kinematic, dynamic (mass, damping, gravity scale, CCD)
- `Collider` component: box, sphere, capsule, cylinder, convex hull, trimesh; friction/restitution,
  **collision groups/masks driven by the Stage-5 `LayerMask`**, and **sensor (trigger) colliders**
  that report overlap without resolving (filtered by layer — e.g. a trigger that only fires for the
  Player or NPC layer)
- Forces & control: apply force/impulse/torque, set velocities, sleep/wake
- **Joints/constraints**: fixed, revolute, prismatic, spherical
- **Scene queries**: raycast, shape-cast, point/overlap queries against the physics world, with
  `LayerMask` filtering
- **Kinematic character controller** (capsule): move-and-slide, step offset, slope limit, grounded
  state — reused later by the Stage-15 prototyping kit's character controller
- Collision/trigger **events** surfaced to game code (enter/stay/exit)
- Physics step synchronized with game loop (**fixed timestep** with interpolation to render, using
  the Stage-5 fixed-timestep schedule slot)
- `examples/physics_stack` (boxes fall and collide) and `examples/character_capsule`
  (walk/jump a capsule over terrain)
- **Editor:** collider shape gizmos in viewport; RigidBody/Collider inspector panels; play/pause/step
  physics simulation; raycast debug visualization — all contributed via the Stage-6 extension API

### Test Criteria
- A dropped sphere lands on a static plane and comes to rest
- Stacked boxes maintain stable contact without jitter
- Kinematic bodies move without being affected by forces
- Raycast/shape-cast return correct hits; sensor colliders fire enter/exit without resolving contact;
  layer masks correctly include/exclude bodies from collisions, triggers, and queries
- A joint (e.g. revolute) constrains motion to its expected degrees of freedom
- Character controller climbs steps below the offset, is blocked by walls, and reports grounded
- Physics and render transforms stay in sync (no visual lag/offset) under fixed-timestep interpolation

### Piece breakdown (status)
The `oxide-physics` crate is a new workspace member; the ECS is the source of truth and the rapier
world is a transient resource rebuilt from components (so play-mode snapshot/restore works for free).
Pure-logic/headless pieces go to `main`; editor gizmos/visual behaviour stop at `dev` for eye-check.

| # | Piece | Where | Status |
|---|-------|-------|--------|
| 1 | Component data model + module wiring: `RigidBody`/`RigidBodyKind`, `Collider`/`ColliderShape`, `PhysicsModule`, `PhysicsSettings` (gravity) | `oxide-physics` (new crate) | ✅ on `main` |
| 2 | Rapier-backed simulation: build the world from components, step on `FixedUpdate`, write transforms back; by-entity forces/velocities/sleep | `oxide-physics` | ✅ on `main` |
| 3 | Collision groups/masks via `LayerMask`, sensors, collision/trigger events (enter/stay/exit) | `oxide-physics` | ✅ on `main` |
| 4 | Scene queries: raycast, shape-cast, point/overlap with `LayerMask` filtering | `oxide-physics` | ✅ on `main` |
| 5 | Joints/constraints: fixed, revolute, prismatic, spherical (programmatic API; component authoring needs serializable entity refs — backlog) | `oxide-physics` | ✅ on `main` |
| 6 | Kinematic character controller (capsule): move-and-slide, step offset, slope limit, grounded | `oxide-physics` | ✅ on `main` |
| 7 | `examples/physics_stack` + `examples/character_capsule` (headless console demos) | `examples` | ✅ on `main` |
| 8a | Editor integration: register RigidBody/Collider/CharacterController (addable, reflected) + enums; wire `PhysicsModule` into the play `App` (physics = first real consumer of Play; Stop reverts via snapshot) | `oxide-editor` | ✅ on `main` |
| 8b | Editor viewport: collider shape wireframe gizmos (box/sphere/capsule/cylinder), green=solid / amber=sensor, View ▸ Show Colliders toggle; matches the sim (ignores `Transform::scale`) | `oxide-editor` | ✅ on `main` |
| 8c | Editor viewport: raycast debug viz — `PhysicsWorld::sync_to_scene` (pure-logic) + a View ▸ Raycast Probe toggle: click freezes a camera→cursor ray into the world (orbit to view it as a 3D line) + hit point/normal | `oxide-physics` + `oxide-editor` | ✅ on `main` |

Standalone "Launch" stays deferred to Stage 16. Convex-hull/trimesh colliders (need mesh data) land
within piece 2/3 or as a follow-up.

---

## Stage 10 — Scripting, Live Reload & Editor Terminal
**Goal:** Game logic lives in watched scripts that hot-reload while the editor runs, an integrated
terminal hosts tools and AI agents, and every component type is editable from both the editor and
scripts/code through the Stage-5 reflection registry.

### Deliverables
- **Scripting layer** (`rhai` preferred — embeddable, sandboxed, Rust-friendly): a `Script`
  component attaching a script file to an entity; lifecycle hooks (`init`, `update(dt)`, events).
  Scripts can also register lightweight **script modules** through the Stage-5 module API.
- **Component reflection / dual-editability**: scripts read/write engine component types through the
  Stage-5 reflection registry, so the **same** fields are editable from the editor inspector, from
  scripts, and from external tools/AI agents — backed by the serde/RON representation. Scripts can
  spawn entities and add/edit components.
- **File watching + live reload**: extend the Stage-6 watcher to recompile/reload changed scripts
  into the running editor with no restart, preserving scene state where possible. This is what lets
  *any* external editor or AI agent edit game code and have it take effect live.
- **Integrated editor terminal panel**: a real shell/terminal inside the editor able to run commands
  and host long-running processes — including **AI agents** that edit the watched scripts, whose
  edits flow back through live reload.
- Safe error surfacing: a script error pauses that script and reports to the editor console/terminal
  without crashing the editor.
- `examples/script_spin`: a script rotates an entity each frame; editing the script live changes the
  spin without restarting
- **Editor:** terminal panel; script console (errors/logs/`print`); per-entity script attach/detach;
  generic reflection-driven inspector for component fields

### Test Criteria
- Editing a watched script changes running behavior without an editor restart
- A script reads and writes a component (e.g. `Transform`) and the editor inspector reflects the
  same value (and vice-versa) — proving dual-editability over one representation
- A scripted entity spawn/despawn and component add/edit round-trips through RON serialization
- A script runtime error is reported and isolated; the editor stays alive
- A command run in the editor terminal executes and streams output back to the panel
- Manual: run an AI agent / external editor against the watched script dir and confirm live updates

---

## Stage 11 — Animation System
**Goal:** Skeletal animation plays on a skinned mesh.

### Deliverables
- `Skeleton` type: joint hierarchy with bind pose
- GLTF skinned mesh and animation clip loading (via the Stage-5 asset server)
- `AnimationPlayer` component: play, pause, seek, loop
- Animation blending (linear blend between two clips)
- `examples/anim_character`: load a character GLTF and play walk/idle clips
- **Editor:** animation timeline panel; clip browser; playback controls; blend weight sliders

### Test Criteria
- Idle and walk clips play without visual artifacts
- Blend between clips produces smooth interpolation
- Seeking to frame 0 and frame N is deterministic
- Manual: visually verify no mesh distortion at extreme joint angles

---

## Stage 12 — Particle System
**Goal:** GPU-driven particle emitters with configurable behavior.

### Deliverables
- `ParticleEmitter` component: spawn rate, lifetime, velocity, gravity, color-over-lifetime
- GPU-side simulation (compute shader)
- Billboard rendering pass (registered into the Stage-5 render pipeline)
- Emitter types: point, cone, sphere surface
- `examples/particles_fire`: a fire-like particle effect
- **Editor:** particle emitter inspector with live preview; curve editor for color/size over lifetime

### Test Criteria
- 100,000 particles maintain 60 FPS on mid-tier GPU
- Lifetime and color curves produce correct visual output
- Emitter enable/disable works without particle artifacts
- Manual: fire effect looks plausible

---

## Stage 13 — Shader System & Advanced Graphics
**Goal:** Custom shaders, post-processing, and advanced rendering effects — the realistic end of the
*scalable fidelity* spectrum, all composed as passes in the Stage-5 render pipeline.

### Deliverables
- Hot-reloadable WGSL shader pipeline (shaders watched via the Stage-6 file watcher)
- **Post-process stack** built as composable render passes: bloom, SSAO, tone mapping, FXAA, plus a
  stylization slot (e.g. a **VCR/CRT-style filter**) — each pass opt-in, so a project ships only the
  effects it enables
- Shadow mapping (directional light, single cascade)
- Skybox rendering (HDR cubemap)
- `examples/advanced_scene`: showcase scene with shadows, SSAO, bloom; `examples/stylized_scene`:
  the same scene with a flat/low-poly look and a VCR post filter (demonstrating fidelity scaling)
- **Editor:** shader asset editor with hot-reload button; post-process stack configuration panel
  (enable/reorder passes)

### Test Criteria
- Shader hot-reload works without GPU crash or validation errors
- Shadows appear on correct geometry, no peter-panning
- SSAO adds visible depth cues on curved surfaces
- Enabling/disabling individual post passes changes only that effect; a project with no post passes
  pays no post-process cost
- Manual: realistic scene looks polished; stylized scene shows the low-poly + VCR look

---

## Stage 14 — Standard Audio System
**Goal:** A conventional, low-overhead audio system every project can use by default — the simple
audio model, with the ray-traced model available later as an opt-in module (Stage 17).

### Deliverables
- Audio backend/device + mixer (`kira` or `rodio`): load/decode clips (WAV/OGG via the asset server),
  play/stop/pause, volume, pitch, looping, per-bus mixing (master/music/sfx)
- `AudioSource` / `AudioListener` components designed to be shared with Stage 17 (same component
  types, swappable backend) — **standard spatialization**: distance attenuation (inverse-square) +
  stereo panning from listener-relative position, optional low-pass with distance
- One-shot and streaming playback; music crossfade
- Per-source **audio-model selector** (standard now; "ray-traced" becomes selectable once the
  Stage-17 module is enabled) — both share components and the listener
- `examples/audio_basic`: positional sound that pans and attenuates as the listener moves
- **Editor:** audio source inspector (clip, volume, range, loop, bus); per-source model selector;
  range-sphere gizmo

### Test Criteria
- Clips play/stop/loop with correct volume and pitch; buses mix independently
- Panning and attenuation track listener-relative position (inverse-square within 5% error)
- Selecting a non-standard audio model on a source requires no component-type change (forward-compat
  with Stage 17)
- Manual: positional audio feels correct moving around a source

---

## Stage 15 — Engine Content & Prototyping Kit
**Goal:** Ship the batteries — built-in primitives, controllers, shaders, and example scenes — so
projects start building immediately instead of from an empty scene. The general-purpose capstone
before export.

### Deliverables
- **Prototyping primitives**: ready-to-use cube/sphere/capsule/plane/cylinder meshes and a grid/
  checker "prototype" material, placeable from the editor (greybox blockout workflow)
- **Built-in character controller** asset: a drop-in first/third-person controller built on the
  Stage-9 capsule controller + Stage-7 named actions (move/look/jump/crouch/sprint), remappable
- **Built-in shader library**: curated, documented WGSL shaders/materials (unlit, PBR, prototype
  grid, simple sky) usable as-is or as templates for Stage-13's shader editor
- **Example games/scenes**: a small set of runnable example projects exercising the engine end to
  end (e.g. a walk-around prototype level, a physics playground)
- **Editor:** an "Add ▸" content menu/asset browser exposing the primitives, controller, materials,
  and example scenes
- Everything here is built only from already-shipped engine systems (no new core subsystems)

### Test Criteria
- Each prototyping primitive spawns and renders correctly from the editor
- The built-in character controller walks/looks/jumps on a prototype level with remappable actions
- Built-in shaders compile and render without validation errors
- Example projects build and run via `cargo run` and from the editor
- Manual: blockout a small level using only built-in content and play it with the controller

---

## Stage 16 — Windows Support & Game Export
**Goal:** A Windows build of the editor/engine, and one-click export of a project to standalone
Linux **and** Windows game binaries. **This completes Phase 1: a general-purpose engine that builds
and ships real games.**

### Deliverables
- **Windows build** of `oxide-engine` and `oxide-editor` (verified on Windows; `wgpu` DX12/Vulkan,
  `winit` Win32) alongside the existing Linux Wayland/Xorg build
- **Game runtime/export pipeline**: package a project's scenes, scripts, and assets into a
  standalone runnable game that links the engine runtime (without the editor), compiling in **only
  the modules the project enables** (validating the Stage-5 feature-gating)
- **Cross-target export**: from the editor (on Linux) export to both a Linux binary and a Windows
  binary (cross-compile, e.g. `x86_64-pc-windows-gnu`), bundling assets next to the executable
- Export presets (target platform, asset packing, build profile) and a CLI equivalent for CI
- Packaging: keep `install.sh` for the editor; add export output layout docs for both platforms
- `examples/`: export one of the Stage-15 example projects to Linux and Windows binaries
- **Editor:** "Export Project" dialog (choose Linux/Windows targets, output dir, profile)

### Test Criteria
- The editor builds and runs on Windows (Wayland/Xorg Linux build remains unaffected)
- A project exports to a Linux binary that runs standalone (no editor, no toolchain) with its assets
- The same project cross-exports to a Windows binary that runs on Windows
- Exported binaries contain no editor-only code paths and none of the modules the project didn't use
- Manual: run an exported Linux build and an exported Windows build of an example project

---

# Phase 2 — Built-in Modules

Each Phase-2 stage is a **self-contained, feature-gated module** built on Phase-1 systems and wired in
through the Stage-5 module API and Stage-6 editor extension API. Every module ships documentation for
both *using* it and *authoring* one like it, and each automatically works with export (Stage 16) and
the settings framework (Stage 6). The order below is a default; modules are largely independent and
can be reprioritized to match the needs of the first real game built in Oxide.

## Stage 17 — Ray-Traced Spatial Audio (module)
**Goal:** Sound propagation that simulates real wave behavior from scene geometry — the advanced
audio model, built on the Stage-14 components so projects opt in per source.

### Deliverables
- Reuses `AudioSource` / `AudioListener` from Stage 14 (ray-traced model selected per source)
- Sound ray casting: shoot rays from source, accumulate energy at listener (built on the engine's
  own ray casts / `LayerMask` filtering)
- Occlusion: blocked rays reduce volume
- Reflection: rays bounce off surfaces and arrive with delay (reverb model)
- Distance attenuation using inverse square law
- `examples/sound_cave`: walk around a cave with echoing footstep sounds
- **Editor:** audio source visualizer (range sphere, ray debug lines); reverb parameter inspector;
  the module's settings page

### Test Criteria
- Sound behind a wall is measurably quieter than line-of-sight
- Moving away from source follows inverse square law within 5% error
- Reverb tail length correlates with room size
- Switching a source between standard and ray-traced models requires no component-type change
- Manual: walk through the cave example and confirm intuitive sound behavior

---

## Stage 18 — Developer Console & Cheats (module)
**Goal:** A drop-in developer console any game can enable for commands, cheats, and debugging help —
trivially added to a project and removed from release builds.

### Deliverables
- In-game console overlay (built on the Stage-8 UI) with command input, history, autocomplete, and
  log output; toggled by a Stage-7 action (default backtick)
- **Command registry**: register named commands with typed arguments from engine, game code, scripts,
  or other modules; built-in commands (spawn, teleport, set var, toggle layer, time scale, etc.)
- **Cheats / dev variables (cvars)**: registerable toggles and values (godmode, noclip, give, fly)
  with a guard so they can be compiled out or locked in release/export builds
- Bind console commands to keys via the Stage-7 input system for quick dev shortcuts
- `examples/console_demo`: a scene with registered cheats and commands
- **Editor:** command browser/inspector; console mirrored in the editor; the module's settings page
  (enable in build, default key, release lockout)

### Test Criteria
- Registered commands execute with correct typed-argument parsing; unknown commands report cleanly
- Cheats/cvars change game state live and can be disabled/compiled out for release
- The console consumes input over the game via the Stage-8 routing model
- Console state and command registry are unaffected by hot-reload of game scripts
- Manual: enable the module in a game, open the console, run commands and toggle a cheat

---

## Stage 19 — Procedural Toolkit (module)
**Goal:** Composable procedural *building blocks* — noise and a modifier/operation stack the user
combines — not a fixed world generator. Consumed by the terrain module (Stage 20) and usable
standalone. **Build tools, not the game.**

### Deliverables
- Noise library: Perlin, Simplex, Worley, fractal octaves, domain warping (deterministic, seeded)
- **Modifier/operation stack**: chainable operations over heightfields/value grids (add, multiply,
  terrace, erode, mask, remap, blend) authored as a data-driven, serializable graph/stack
- Seeded RNG utilities and distribution helpers for scatter/placement
- Simple L-system helper for vegetation/structure layout
- Region/`Biome` helper: blend by temperature/humidity/height maps (a tool, not a built-in world)
- `examples/procgen_playground`: build a noise + modifier stack and preview the result
- **Editor:** noise preview panel (2D heatmap); modifier-stack editor with live re-evaluation; seed
  controls; the module's settings page

### Test Criteria
- Same seed + same stack always produces identical output (determinism)
- Each modifier transforms its input correctly and composes in a chain
- A modifier stack round-trips through RON unchanged (dual-editable)
- Benchmark: evaluating a representative stack over a 1024² grid completes within target time
- Manual: build and preview a multi-stage noise stack in the editor

---

## Stage 20 — Terrain System (module)
**Goal:** A comprehensive terrain module: generate terrain (via the Stage-19 toolkit), sculpt and
paint it with editor brushes, and scatter vegetation/objects onto it. Designed to stream later under
Stage 21.

### Deliverables
- **Terrain representation**: chunked heightmap terrain with a meshing pass (normals, UVs) and
  collider generation (heightfield collider via Stage 9); LOD-ready chunk layout
- **Generators**: drive terrain from the Stage-19 noise + modifier stack, from basic Perlin/Simplex
  up to layered erosion/domain-warp stacks and biome-driven generation
- **Sculpt brush tools** (editor): raise/lower, smooth, flatten, noise — adjustable radius, strength,
  falloff; live edits, undoable through the Stage-6 command stack
- **Texture/splat painting** (editor): paint multiple terrain material layers (e.g. grass/rock/sand)
  with a splat map and per-layer tiling; brush-based painting with falloff
- **Foliage & object scatter** (editor): paint/spray grass, trees, rocks, or arbitrary prefabs with
  density/scale/rotation jitter and slope/height masks; instanced rendering for dense foliage,
  entity placement for larger objects
- **Dual-editable & serializable**: terrain data (heightmap, splat layers, scatter sets) round-trips
  through RON so it is editable from editor and scripts/AI agents
- `examples/terrain_playground`: generate a terrain, sculpt/paint it, scatter grass and trees
- **Editor:** terrain tool panel (generate, sculpt, paint, scatter sub-tools); brush settings;
  layer/material list; foliage/prefab palette; the module's settings page

### Test Criteria
- A generated terrain produces correct mesh normals and a matching heightfield collider
- The same seed/generator stack produces identical terrain (determinism)
- Sculpt and paint brush edits modify the heightmap/splat map correctly and are undoable
- Scatter respects density and slope/height masks; instanced foliage renders without per-instance
  entity overhead
- Terrain + splat + scatter data round-trips through serialization unchanged
- Manual: sculpt, paint layers, and scatter grass/trees on a terrain and confirm it collides correctly

---

## Stage 21 — Open World Support (module)
**Goal:** Streaming, chunked worlds that can exceed memory limits.

### Deliverables
- World chunk system: load/unload chunks based on camera position (built on the Stage-5 asset server)
- Async asset streaming (chunks load on background threads)
- Level of Detail (LOD) system for meshes and terrain
- Entity streaming: entities activate/deactivate with their chunk
- `examples/open_world`: a large world that streams seamlessly as you move
- **Editor:** world chunk map overlay; streaming debug view (loaded/unloaded chunks); LOD visualizer;
  the module's settings page

### Test Criteria
- No frame drops during chunk load/unload transitions
- Memory usage stays bounded regardless of world size
- Entities in unloaded chunks do not tick (verified via counters)
- Manual: drive across chunk boundaries and confirm invisible seams

---

## Stage 22 — Pathfinding & NPC AI (module)
**Goal:** Built-in navigation and reusable NPC behavior building blocks, so games get agents that
move and decide without writing it all from scratch.

### Deliverables
- **NavMesh**: bake a navigation mesh from scene/terrain geometry (with `LayerMask`-driven
  walkable/obstacle filtering); runtime queries (path find, nearest point, path smoothing)
- **Agent component**: follow a path with steering, avoidance, speed/acceleration, and grounded
  movement via the Stage-9 character controller
- **NPC AI building blocks**: a behavior-tree and/or state-machine system, perception helpers
  (vision cones / hearing using scene queries and layers), and steering behaviors (seek/flee/wander/
  patrol) — composable, not a fixed AI
- Dual-editable, serializable behavior/agent definitions
- `examples/npc_patrol`: agents navigate, patrol waypoints, chase the player, and avoid obstacles
- **Editor:** navmesh bake/visualize panel; agent inspector; behavior-tree/state-machine editor; the
  module's settings page

### Test Criteria
- A baked navmesh produces correct paths around obstacles; queries return valid points
- Agents follow paths, avoid each other, and stop at goals without jitter
- A behavior tree/state machine transitions correctly and is serializable (dual-editable)
- Perception correctly gates on layers and line-of-sight
- Manual: watch NPCs patrol, detect, chase, and give up

---

## Stage 23 — Water System (module)
**Goal:** Built-in water — rendering and gameplay mechanics — that a project can drop in.

### Deliverables
- **Water rendering**: animated water surface (waves/normals), reflection/refraction, depth-based
  color/fog, shoreline blending — composed as Stage-5 render passes and a Stage-13 shader material
- **Water bodies**: planar/ocean and bounded volumes (lakes/pools) with configurable height/level
- **Gameplay mechanics**: buoyancy/floating on Stage-9 rigid bodies, water-volume triggers
  (enter/exit, submerged state), simple flow/current forces, and a swim mode for the Stage-15
  character controller
- Optional underwater post-process (tint, distortion, muffled audio hook for Stages 14/17)
- Dual-editable, serializable water-body definitions
- `examples/water_scene`: a floating object, a swimmable lake, and an ocean horizon
- **Editor:** water body inspector and placement gizmos; surface/material settings; the module's
  settings page

### Test Criteria
- Water renders with plausible reflection/refraction and correct depth blending at shorelines
- Rigid bodies float and settle at the correct waterline; flow forces push bodies as configured
- Water-volume triggers fire enter/exit and report submerged state correctly
- The character controller enters swim mode in water and exits on leaving
- Manual: drop objects in water, swim the character, and confirm it looks and behaves correctly

---

## Backlog (additional modules & post-roadmap capabilities)

### Editor UX / inspector (raised 2026-06-16, maintainer GUI review)
- **Editor visual overhaul** — overall styling, spacing, and panel layout need a
  dedicated polish pass (egui theme, inspector/panel density). Tracked as a
  standalone editor-styling piece, not folded into feature work.
- **Component gizmos / viewport handles** — components with spatial meaning need
  editor-only viewport visualization: `DirectionalLight` direction arrow (+ cone
  for future spot lights), camera frustum, collider/audio shapes. Pairs with the
  multiple-light-types work below.
- **Multiple light types** — `DirectionalLight` is the only light today; add
  point + spot (and the renderer support to gather light *entities*, which the
  reflected `DirectionalLight`/`Camera` components are scaffolding toward).
- **Component multiplicity model (DECIDED 2026-06-16 — hybrid).** Archetypal ECS
  (`hecs`) allows one component of a given type per entity. Chosen approach,
  applied as each component type lands:
  - **Local-offset field** for things that are naturally *single per node but
    positioned* — a collider's `center`, a light/audio emitter offset — stored as
    a `Vec3`/`Transform` field on the component (one node, no extra hierarchy).
    This mirrors Unity (`BoxCollider.center`).
  - **Child entities** for *genuine multiples* (several meshes on one logical
    object): each is a real node with its own `Transform`, gizmo-movable and
    shown in the viewport — what Unity/Bevy do for multi-mesh. The "Add … (as
    child)" path stays; editor UX is polished so it doesn't feel like clutter.
  - Explicitly **not** doing internal multi-instance lists + sub-object gizmos
    (rejected as the biggest lift / least ECS-native).
  Concretely: colliders (Stage 9) and audio sources (later) get offset fields;
  multi-mesh stays child-based.

- Networking (deterministic lockstep or rollback for simulation use)
- Multi-threading and job system (rayon or custom)
- **Dynamically loadable native plugins** (C-ABI/dylib) — currently modules are compile-time crates
  or `rhai` scripts; revisit once the static module API is proven
- Save-format/asset versioning and migration (backward compatibility for shipped projects)
- VR/XR support
- Volumetric fog and clouds
- GPU-driven rendering (indirect draw, bindless resources)
- Terrain deformation at runtime
- Fluid simulation (beyond the Stage-23 water surface model)
- Vehicle physics module
- Destruction / fracture module
- **SDF (signed-distance-field) text rendering** for the Stage-8 UI — each
  glyph rasterized once at one canonical size as an SDF, then scaled
  arbitrarily in the shader. Decouples atlas memory from font-size
  combinatorics (HiDPI, animated scale, many sizes) and is how Unity
  TextMeshPro / Unreal Slate / Godot 4's font system all ship. Slots in
  next to the piece-3 `ab_glyph` rasterizer without rewriting the shaper.

---

## Testing Protocol (All Stages)

1. **Unit tests** — every module has tests for core behavior and edge cases
2. **Integration tests** — the `tests/` crate runs end-to-end scenarios
3. **Example review** — each stage ships at least one runnable example; both user and Claude review it
4. **Benchmarks** — performance-sensitive systems have `criterion` benchmarks; regressions block stage completion
5. **Clippy + fmt** — zero warnings, consistent formatting required before stage sign-off
6. **Module authoring docs** — every module (Stage 9 on) ships both a usage guide and an authoring
   guide under `docs/`; a stage is not done until its docs land
