Skip to content

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:

  1. Schema: Add the engine name to the layout.engine enum in schemas/world/v1/spec.json. Define its inputs shape within the if/then/else conditional logic block in the schema layout object.
  2. Rust Traits: Create the struct inside world/src/layout.rs and implement LayoutEngine.
  3. Rust Wiring: Update the LayoutEngineKind enum, deserialization logic for LayoutInputs, and the WorldInstantiator in /world-runner/backend/spec_instantiation.rs to route the new engine.
  4. Testing: Write unit tests for layout behaviors and an integration test verifying region POST instantiations end-to-end. Provide a new example spec (e.g., examples/new_engine.yml).
  5. 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