diff --git a/src/features/editScene/demos/demo-taxi/PLAN.md b/src/features/editScene/demos/demo-taxi/PLAN.md index 0a8a880..b9ac844 100644 --- a/src/features/editScene/demos/demo-taxi/PLAN.md +++ b/src/features/editScene/demos/demo-taxi/PLAN.md @@ -5786,33 +5786,167 @@ boarding-standoff snap on NPC 1099511627776 and no rotation. stats and persistence layers exist; architecture can be designed earlier). -### Phase 7 — CellGrid stair generation - before interiors +### Phase 7 — CellGrid stair generation — before interiors -Multi-storey CellGrid buildings (`height` > 1) generate stacked floors -with no connection between them — interiors above ground level are -unreachable. Add stairs to the CellGrid generator (engine-level, not -taxi-specific): +**Goal.** Multi-storey CellGrid buildings (`height` > 1) currently +generate stacked floors with no connection between them, so interiors +above ground level are unreachable. Add stairs to the CellGrid +generator — **engine-level, not taxi-specific** — so that both the +player (Jolt character) and NPCs (Recast navmesh) can travel between +every floor. Phase 8's interior generator consumes the result. -- Stair cell: a cell flag (like the existing door/window flags) marking - a stairwell; the generator cuts the matching opening in the - floor/ceiling above and emits a stair mesh (steps sized within the - Jolt character's and Recast's climb limits) plus walkable colliders. -- Placement rules: stairwell position comes from the room layout - (RoomLayoutSystem integration) or an explicit cell flag in - hand-authored grids; a stairwell column stacks through all floors. -- Navmesh: stairs rasterize as walkable (Recast step/slope limits), so - NPCs can path between floors; verify doorway-area costs and door - obstacles still behave. -- should support stairwells and explicit floor connections between rooms where a room has stair in it which connects to above location. Like single-floor stairwell. Floors and ceilings are removed for the stair to pass. The space between floors should be hidden by geometry to avoid gaps. -- should support exterior stairs outside walls (like in many motels) -- should support procedural material the same as walls/floors, using squares for walls and floors by default, depending on surface. -- Editor + serialization + Lua binding, per the component rules - (serialized flag, Cell Grid editor toggle, `cellgrid_door_test`-style - headless coverage). -- Headless: multi-floor grid with a stairwell — character walks from - ground floor to the top floor (physics), navmesh query finds a - ground->top path; grids without stair flags are unchanged. -- from DSL and scene components point of view, the easiest way to create stairwell would be to create a room with type of stairwell. However sometimes for lobby rooms we want a large stair which leads to next floor, like in some hotels, theatres, administrative buildings... Needs research. +**Status:** planned (decomposed 2026-10-30); nothing implemented yet. + +**How to read this phase.** 7.1 is the vertical slice: one hand- +authored grid, one stairwell, real geometry. 7.2 proves traversal. +7.3 adds the authoring paths (rooms, DSL, editor, Lua). 7.4 and 7.5 +are independent extensions. Every slice ends buildable with headless +verification, and every slice keeps the global invariant: + +> **Invariant:** grids without stair flags produce bit-identical +> geometry to what they produce today. + +**What the code already gives us (verified 2026-10-30):** + +- `CellFlags` bits 0-25 are used (`components/CellGrid.hpp`); bits + 26-63 are free. Cell flags serialize as a raw `uint64` per cell, so + a new flag needs **no JSON schema change** and old scenes keep + loading. `LayoutLib::PlanFlags` is bit-identical to `CellFlags` + (static_asserted in `TownGenSystem.cpp`) — a new bit must be + mirrored there with a new assert. +- Openings are free: `buildFloorsAndCeilings` only emits a floor/ + ceiling plane for cells carrying the `Floor`/`Ceiling` flag, so + clearing those flags on stair cells cuts the hole with no special + mesh surgery. Roofs are separate (`RoofComponent` children). +- Colliders follow the mesh lists in `buildPhysicsColliders` — a new + stair mesh added there gets its static collider automatically. +- Recast limits (`NavMeshComponent` defaults): `agentMaxClimb` 1.0 m + (5 voxels at `cellHeight` 0.2), `agentMaxSlope` 20 deg, + `agentRadius` 0.5 m. Stepped treads rasterize walkable; a smooth + ramp does **not** help (4 m of rise at 20 deg needs an 11 m run). +- Jolt character: no explicit step-height knob (supporting-volume + plane at -0.2 m). The proven climbing envelope is the existing + entrance stairs (`TownGenSystem::createStairs`: rise 0.18 / tread + 0.30 / width 1.4 m boxes with box colliders). Step size for + interior stairs starts from those numbers and is tuned empirically + in 7.2 — do not assume Recast's 1.0 m climb means the character can + climb 1.0 m steps. +- Navmesh geometry collection drops mesh names containing + "ceiling"/"frame"/"furniture" (`isNavMeshGeometry`) — stair meshes + must avoid those substrings. +- Default cell is 4 x 4 m with `cellHeight` 4 m; the floor surface + sits at `floorSurfaceY()` = 0.2 m above the cell base, so a + floor-to-floor connection rises exactly `cellHeight`. + +**Shared geometry contract (all slices):** + +- A **stair connection** between level y and y+1 occupies one or more + cells at the same (x, z) on both levels: the generator clears + `Ceiling` at level y and `Floor` at level y+1 on those cells and + fills the opening with a stepped stair mesh plus walkable + colliders. A **stairwell column** chains connections upward through + consecutive floors at the same (x, z). +- Steps: tread 0.30 m, rise 0.18-0.25 m (exact value settled in 7.2), + flight width >= 1.2 m (twice the Recast agent radius plus margin). +- One 4 x 4 m cell fits a **dogleg** (two flights + mid-landing); + a **straight flight** needs two or more cells in a row. The + generator picks the layout from the stair cell run's shape. +- The space between floors around the opening is closed by geometry + (shaft sides and top cap): no visible void, no gaps at slab edges. + How the top cap interacts with the per-row-run roofs of cut + footprints is settled in 7.1. +- Stairs use the grid's procedural material like walls/floors: + treads default to the floor rect, shaft sides to the wall rect + (square UV mapping per surface), with a serialized `stairRectName` + override. + +#### Phase 7.1 — Core stairwell cells (vertical slice) + +Hand-authored grids only; no DSL, no RoomLayoutSystem yet. + +- New `CellFlags::StairWell` bit (mirrored `PlanFlags` bit + static + assert). A stair cell marks "a stair passes through here"; the + column/run shape comes from the flagged cells themselves. +- `buildCellGrid` pass: cut the openings per the geometry contract, + emit straight-flight and dogleg stair meshes + shaft closure, add + them to the collider lists, apply the procedural-material UV + mapping. Serialized `stairRectName` field (empty = floor/wall + rect defaults). +- Serialization: flags ride the existing raw-uint64 cell format; + `stairRectName` round-trips like the other rect names. + +Verify: +- `cellgrid_door_test`-style case: flag + `stairRectName` round trip, + old scenes load with defaults. +- New terrain-tests step (`TERRAIN_TEST_FILTER=cellGridStairs`): + multi-floor grid with a stairwell builds openings, stair mesh and + colliders; a grid without stair flags is unchanged. + +#### Phase 7.2 — Traversal acceptance (physics + navmesh) + +- Character physics: tune rise/tread inside the proven envelope so + the Jolt character climbs without snagging; verify headroom under + landings and at the top opening. +- Navmesh: stairs rasterize walkable (per the Recast limits above); + doorway-area costs and locked-door obstacles keep behaving (the + `navMeshDoors` step stays green). + +Verify: +- Headless: a character walks from the ground floor to the top floor + over the stairs (physics), and a navmesh query finds a + ground-to-top path. No-stair grids: no path between floors, as + today. + +#### Phase 7.3 — Authoring paths (rooms, DSL, editor, Lua) + +- **RoomLayoutSystem:** a room of type `stairwell` marks its cells; + single-floor stairwells connect a room to the level directly above + it (floors/ceilings removed for the stair to pass, per the shared + contract). A stairwell room column stacks through all floors it + spans. `processRoom` must not re-stamp `Floor`/`Ceiling` over the + openings it just cut. +- **Layout DSL:** `(room ... :type stairwell)` records the same + cells in `BuildingPlan` (rooms-first claims skip the opening + flags; filled-shell mode stays metadata + flags). `fillBuildingCells` + needs no change — flags flow through verbatim. +- **Editor:** Cell Grid editor per-cell stair toggle (next to the + door/window toggles) plus the `stairRectName` widget. +- **Lua:** stair flag/rect exposed per the component rules. +- Docs (`editScene/AGENTS.md`, this file) updated with the slice. + +Verify: +- DSL grammar probes in `road_geometry_overlap_test`; Lua round trip + in `component_lua_test`; a DSL-authored two-storey stairwell + building passes the 7.1/7.2 checks. + +#### Phase 7.4 — Exterior stairs (motel-style) + +- Stairs outside the shell walls: exterior corridors/galleries on + upper floors reached by an external flight (as in many motels). + Reuses the 7.1 step geometry and materials; placement is driven by + authored cells/DSL, not by a town-wide rule. + +Verify: +- Headless: character climbs from terrain level to the upper + gallery and enters through its exterior door; navmesh connects + terrain to the gallery. + +#### Phase 7.5 — Grand / lobby stairs (research, then implement) + +Open design question carried over from the original phase notes: +typing a room `stairwell` is the easiest DSL/component authoring +path, but lobbies of hotels, theatres and administrative buildings +want a **large stair inside an ordinary room** — wide flights, +possibly curved or branching, not a utilitarian shaft. Research +first: how a wide multi-cell flight is authored (room option vs. +dedicated cells), whether the 7.1 straight/dogleg layouts suffice +when scaled up, and what railing/balustrade geometry is needed. +Only then implement. + +**Explicitly out of scope for Phase 7:** interior scene generation +and door wiring (Phase 8), spiral stairs, elevators, and town-wide +rules for where stairwells go (layouts decide; default layouts get +stairwells when Phase 8 makes upper floors enterable). ### Phase 8 — Enterable buildings (on-the-fly interiors)