# Scene Graph & Entity System

The `oxide_engine::scene` module is the world model every later system plugs
into. It pairs a lightweight ECS ([`hecs`](https://docs.rs/hecs)) with a
parent/child [`Transform`](math.md) hierarchy, so entities can hold arbitrary
components *and* live in a spatial tree.

This document is the usage reference for the module as delivered in **Stage 3**.
For the math types it builds on, see [math.md](math.md); for coordinate and
units conventions, see [conventions.md](conventions.md).

## Importing

```rust
use oxide_engine::scene::{Scene, Node, Entity, DespawnPolicy, SceneError};
// or, for the common types, via the prelude:
use oxide_engine::prelude::*; // Scene, Node, Entity, DespawnPolicy, SceneError, Transform, …
```

The full ECS is re-exported as `oxide_engine::hecs` so you share one copy of
`Entity` and the query API with the engine.

## Mental model

- An **entity** is a `hecs::Entity` handle — a small `Copy` id.
- Every entity created through the scene carries a [`Node`](#node) (name +
  enabled flag) and a **local** [`Transform`](math.md).
- The **hierarchy** (which entity parents which) is owned by the `Scene`, not
  stored as components. This keeps child ordering deterministic and makes
  reparenting cheap.
- A **local** transform is what you author. A **world** transform is the local
  composed with every ancestor: `world = parent_world * local`. The scene
  resolves these on demand; it does not cache them.

| Type | Role |
|------|------|
| [`Scene`](#scene) | Owns entities + hierarchy; spawn, despawn, reparent, query, resolve transforms |
| [`Node`](#node) | Per-entity metadata: `name`, `enabled` |
| [`DespawnPolicy`](#despawning) | Whether despawn takes the subtree or detaches children |
| [`SceneError`](#errors) | Reparent / (de)serialization failures |

---

## `Scene`

### Building a hierarchy

```rust
use oxide_engine::prelude::*;

let mut scene = Scene::new();

// A root entity (no parent).
let sun = scene.spawn("sun", Transform::IDENTITY);

// Children. `spawn_child` panics if the parent is not a live entity.
let planet = scene.spawn_child(
    sun,
    "planet",
    Transform::from_translation(Vec3::new(10.0, 0.0, 0.0)),
);
let moon = scene.spawn_child(
    planet,
    "moon",
    Transform::from_translation(Vec3::new(0.0, 0.0, 2.0)),
);
```

`spawn`/`spawn_child` take anything that converts into a `Node`, so a bare
`&str` works as a name (`"planet"` ≡ `Node::new("planet")`); pass a `Node`
directly when you need to set `enabled`.

### Resolving world transforms

```rust
// One entity (walks up the parent chain):
let moon_world = scene.world_transform(moon).unwrap();

// Every entity at once (single top-down pass — prefer this in bulk):
let worlds = scene.world_transforms(); // HashMap<Entity, Transform>
```

`world_transforms()` is the path the renderer will use; it resolves a
10,000-entity, 5-level scene in well under a millisecond (see the
`world_transforms_10k_depth5` benchmark).

### Reparenting

```rust
scene.set_parent(moon, Some(sun))?; // moon now orbits the sun directly
scene.set_parent(moon, None)?;      // moon becomes a root
```

Reparenting preserves the **local** transform (it does not compensate to keep
the world transform fixed). Cycles are rejected: parenting an entity to itself
or to one of its descendants returns [`SceneError::WouldCycle`], leaving the
hierarchy untouched.

### Despawning

```rust
use oxide_engine::scene::DespawnPolicy;

// Remove the entity and its entire subtree:
scene.despawn(planet, DespawnPolicy::Recursive);

// Remove only the entity; its children move up to its parent (or become roots
// if it was a root):
scene.despawn(planet, DespawnPolicy::DetachChildren);
```

### Editing nodes

```rust
scene.set_name(planet, "earth");
scene.set_enabled(moon, false);          // later systems skip disabled subtrees
scene.set_local_transform(moon, Transform::IDENTITY);

let name = scene.name(planet);           // Option<String>
let on   = scene.is_enabled(moon);       // Option<bool>
let local = scene.local_transform(moon); // Option<Transform>
```

### Querying

```rust
for &root in scene.roots() { /* … */ }
for &child in scene.children(planet) { /* … */ }
let parent = scene.parent(moon);         // Option<Entity>
let n = scene.len();
```

### Extra components (it's a real ECS)

Entities are full `hecs` entities, so later stages attach their own components
(meshes, rigid bodies, …) alongside the `Node`/`Transform`:

```rust
scene.world_mut().insert_one(planet, /* e.g. */ 0u32).unwrap();
let value = scene.get::<u32>(planet); // Option<hecs::Ref<u32>>
```

Use `world()` for read-only queries and `world_mut()` for adding/removing
*non-hierarchy* components. Drive lifecycle and parenting through the `Scene`
methods so the hierarchy bookkeeping stays consistent — spawning or despawning
directly on the world bypasses it.

---

## `Node`

```rust
pub struct Node {
    pub name: String,   // display name; not required to be unique
    pub enabled: bool,  // honored by later systems, not by transform resolution
}
```

`Node::new(name)` builds an enabled node. `enabled` is a declaration of intent:
Stage 3 only stores and toggles it; rendering/physics/audio will skip disabled
subtrees in later stages. It deliberately does **not** affect
`world_transform`, which is purely geometric.

---

## Serialization

A scene round-trips through RON. Because `hecs::Entity` handles are not stable
across a save/load, the scene is flattened to an indexed node list in a
deterministic pre-order walk, so serialize → deserialize → serialize is
byte-for-byte stable.

```rust
let ron: String = scene.to_ron()?;
let restored = Scene::from_ron(&ron)?;
assert_eq!(ron, restored.to_ron()?); // identical
```

Corrupt input (out-of-range child indices, a node listed as both root and
child) is rejected with [`SceneError::Deserialize`].

---

## Errors

```rust
pub enum SceneError {
    NoSuchEntity,         // operation referenced a dead entity
    WouldCycle,           // reparent would make an entity its own ancestor
    Serialize(String),    // encoding to RON failed
    Deserialize(String),  // decoding failed or data was inconsistent
}
```

---

## Example

A complete, runnable tour lives in
[`examples/src/bin/scene_basic.rs`](../examples/src/bin/scene_basic.rs):

```sh
cargo run -p oxide-examples --bin scene_basic
```

It builds a sun/planet/moon hierarchy, prints local vs. world transforms,
reparents a node, round-trips through RON, and despawns with a detach policy.

## In the editor

`oxide-editor` renders a **Scene Hierarchy** panel (left) and an **Inspector**
(right) over the viewport, driving this same API: select a node, rename it,
toggle its `enabled` flag, reparent it via the Inspector's parent dropdown, and
add/delete nodes from the toolbar. The egui integration is editor-only — the
engine exposes a generic post-clear draw hook ([`App::render`]) and keeps egui
out of its own dependency tree.

[`App::render`]: ../engine/src/window/app.rs

## Design notes

- **Why hierarchy outside the ECS?** Storing `Parent`/`Children` as components
  is idiomatic but makes ordered iteration and reparenting awkward (archetype
  moves, borrow juggling) and gives no ordering guarantee. Keeping the tree in
  the `Scene` yields deterministic child order — which serialization and the
  editor both rely on — and O(1) link edits. The ECS still owns all entity
  *data*.
- **World transforms are resolved, not stored.** There is no dirty-flag cache
  yet; `world_transforms()` recomputes in one pass. A cache can be added later
  behind the same API without changing callers.
- **Despawn policies** map onto the two things callers actually want: delete a
  whole subtree, or remove one node and keep its children.
