World Layout Engines
The LayoutEngine trait decouples the spatial placement contract of world regions from hard-coded geometry, allowing procedurally generated or dynamically packed worlds based on the plant_world spec schema.
LayoutEngine Trait Contract
The LayoutEngine trait provides an abstraction for parsing a world's layout inputs and geometry, producing ClaimRect coordinates for each region.
pub trait LayoutEngine {
type Placement;
fn place(
&self,
inputs: &LayoutInputs,
config: &LayoutConfig,
bounds: (u32, u32), // (width, height) in spatial cells
) -> Result<Self::Placement, LayoutError>;
}
Config/Inputs Envelope Conventions
The layout schema uses an if/then/else structure to isolate engine-specific parameters into an inputs block while keeping global configuration in the config envelope.
layout:
engine: grid-auto-pack
config:
gap_min: 5
overlap: false
inputs:
# Engine-specific data goes here
regions:
samanga: { width: 50, height: 50 }
Current vs Reserved Engines
| Engine | Status | Inputs Shape | Description |
|---|---|---|---|
grid-claims |
Current | claims: { origin_x, origin_y, width, height } |
Explicit rectangle placements. |
grid-auto-pack |
Current | regions: { width, height } |
Deterministic scanline packing. |
radial-pack |
Reserved | TBD | Places items radially from an origin point. |
spherical-tiles |
Reserved | TBD | Packs regions onto a non-Euclidean spherical surface. |
force-graph |
Reserved | TBD | Node repulsion & edge constraints. |
constraint |
Reserved | TBD | Formal constraint solver based layout. |
Geometry x Engine Compatibility Matrix
| Engine | flat_grid | cylindrical | spherical |
|---|---|---|---|
grid-claims |
yes | yes | no |
grid-auto-pack |
yes | conditional: wrap-aware packing | no |
radial-pack |
yes | conditional: axis of revolution | yes (future) |
spherical-tiles |
no | no | yes (future) |
force-graph |
yes | yes | yes (future) |
constraint |
yes | yes | yes (future) |
Extension Guide
To add a new layout engine:
- Schema: Add the engine name to the
layout.engineenum inschemas/world/v1/spec.json. Define its inputs shape within theif/then/elseconditional logic block in the schema layout object. - Rust Traits: Create the struct inside
world/src/layout.rsand implementLayoutEngine. - Rust Wiring: Update the
LayoutEngineKindenum, deserialization logic forLayoutInputs, and theWorldInstantiatorin/world-runner/backend/spec_instantiation.rsto route the new engine. - Testing: Write unit tests for layout behaviors and an integration test verifying region
POSTinstantiations end-to-end. Provide a new example spec (e.g.,examples/new_engine.yml). - Documentation: Update the "Current vs Reserved Engines" table in this document.
LayoutError Mapping Rule
New engines must strictly map failures to existing LayoutError categories. The canonical variants and their HTTP mappings must not be duplicated or shadowed by engine-specific error types.
| Variant | Meaning | HTTP Status |
|---|---|---|
Conflict |
Two items claim overlapping space | 409 |
OutOfBounds |
Item placement exceeds stage bounds on at least one axis | 422 |
InsufficientSpace |
No valid slot found for an item (packing engines) | 409 |
IncompatibleEngine |
Engine is not valid for the given geometry/stage type | 422 |
UnresolvableRef |
Item named in inputs is not declared in items block | 422 |
MalformedInputs |
Inputs block is structurally invalid for this engine | 400 |