#!/usr/bin/env python3 """Build four standalone liminal geometry fixtures and their capsule-walk specs.""" from __future__ import annotations import argparse import json import os from pathlib import Path ROOT = Path(__file__).resolve().parents[4] OWNER = Path(os.environ.get("VOXELFORGE_OWNER_DATA", ROOT / "Standalone/data/owner_world.json")) OUT_DEFAULT = Path(os.environ.get("VOXELFORGE_VERIFY_OUT", ROOT / "Saved/Linux/l161")) FLAT_FIELD = {"version": 1, "kind": "flatField", "minimum_arena_clearance_m": 0.0} def stamp(stamps: list[dict], stable_id: str, kind: str, x: float, y: float, z: float, half: tuple[float, float, float], *, yaw: int = 0, steps: int | None = None) -> None: row = { "stable_id": stable_id, "kind": kind, "anchor_xy_m": [x, y], "z_offset_m": z, "half_extents_m": list(half), "yaw_quarter_turns": yaw, } if steps is not None: row["step_count"] = steps stamps.append(row) def fixture(name: str, stamps: list[dict], walk_points: list[tuple[float, float, float]], doors: list[dict], *, center: tuple[float, float], wide_camera: tuple[float, float, float], eye_camera: tuple[float, float, float], eye_target_offset: tuple[float, float, float], wide_target_offset: tuple[float, float, float], eye_clip: int, wide_clip: int) -> tuple[str, dict, dict]: root = json.loads(OWNER.read_text(encoding="utf-8")) root["surface_profile_override"] = dict(FLAT_FIELD) root["liminal_stamp_fixture_override"] = { "version": 1, "strate_index": 0, "stamps": stamps, } walk = { "version": 1, "path_points_offset_m": [list(point) for point in walk_points], "door_prefixes": doors, } views = { "center_xy_m": list(center), "eye_camera_offset_m": list(eye_camera), "wide_camera_offset_m": list(wide_camera), "eye_target_offset_m": list(eye_target_offset), "wide_target_offset_m": list(wide_target_offset), "eye_clip_radius": eye_clip, "wide_clip_radius": wide_clip, } return name, root, {"walk": walk, "views": views} def pool_rooms() -> tuple[str, dict, dict]: stamps: list[dict] = [] cx, cy, cell, cells = 520.0, 440.0, 20.0, 7 half = cell * cells * 0.5 wall_height, wall_half_thickness = 9.0, 1.2 for line in range(cells + 1): offset = (line - cells * 0.5) * cell stamp(stamps, f"liminal/pool-rooms-v1/00-wall-x/{line:02d}", "fillBox", cx + offset, cy, wall_height * 0.5, (wall_half_thickness, half, wall_height * 0.5)) stamp(stamps, f"liminal/pool-rooms-v1/00-wall-y/{line:02d}", "fillBox", cx, cy + offset, wall_height * 0.5, (half, wall_half_thickness, wall_height * 0.5)) for row in range(cells): y = cy + (row - (cells - 1) * 0.5) * cell for line in range(cells + 1): x = cx + (line - cells * 0.5) * cell stamp(stamps, f"liminal/pool-rooms-v1/01-doorway-x/{row:02d}-{line:02d}", "carveArch", x, y + 7.0, 4.0, (3.6, 1.55, 4.0), yaw=1) stamp(stamps, f"liminal/pool-rooms-v1/01-doorway-y/{line:02d}-{row:02d}", "carveArch", cx + (row - (cells - 1) * 0.5) * cell, cy + (line - cells * 0.5) * cell, 4.0, (3.6, 1.55, 4.0)) for row in range(cells): y = cy + (row - (cells - 1) * 0.5) * cell for column in range(cells): x = cx + (column - (cells - 1) * 0.5) * cell stamp(stamps, f"liminal/pool-rooms-v1/02-roof/{row:02d}-{column:02d}", "fillBox", x, y, 9.4, (10.0, 10.0, 0.5)) stamp(stamps, f"liminal/pool-rooms-v1/03-skylight/{row:02d}-{column:02d}", "carveBox", x, y, 9.4, (5.5, 5.5, 1.0)) stamp(stamps, f"liminal/pool-rooms-v1/04-basin/{row:02d}-{column:02d}", "carveBox", x, y, -1.0, (5.5, 5.5, 1.5)) path_y = cy + 7.0 walk = [(-half - 2.0 + cx, path_y, 0.88), (half + 2.0 + cx, path_y, 0.88)] doors = [ {"prefix": "liminal/pool-rooms-v1/01-doorway-x/", "width_axis": 0, "minimum_width_m": 1.5}, {"prefix": "liminal/pool-rooms-v1/01-doorway-y/", "width_axis": 0, "minimum_width_m": 1.5}, ] return fixture("pool-rooms", stamps, walk, doors, center=(cx, cy), wide_camera=(-60.0, 7.0, 3.0), eye_camera=(-40.0, 7.0, 1.6), eye_target_offset=(60.0, 7.0, 0.8), wide_target_offset=(65.0, 7.0, 1.2), eye_clip=4, wide_clip=7) def backrooms(width: float = 4.0, name: str = "backrooms-grid") -> tuple[str, dict, dict]: stamps: list[dict] = [] cx, cy, cell, cells = 820.0, 420.0, 18.0, 7 half, wall_half = cell * cells * 0.5, 1.2 wall_height = 5.5 for line in range(cells + 1): offset = (line - cells * 0.5) * cell stamp(stamps, f"liminal/backrooms-grid-v1/00-wall-x/{line:02d}", "fillBox", cx + offset, cy, wall_height * 0.5, (wall_half, half, wall_height * 0.5)) stamp(stamps, f"liminal/backrooms-grid-v1/00-wall-y/{line:02d}", "fillBox", cx, cy + offset, wall_height * 0.5, (half, wall_half, wall_height * 0.5)) door_half = width * 0.5 for row in range(cells): y = cy + (row - (cells - 1) * 0.5) * cell for line in range(cells + 1): x = cx + (line - cells * 0.5) * cell stamp(stamps, f"liminal/backrooms-grid-v1/01-door-x/{row:02d}-{line:02d}", "carveBox", x, y, 1.25, (1.6, door_half, 1.25)) stamp(stamps, f"liminal/backrooms-grid-v1/01-door-y/{line:02d}-{row:02d}", "carveBox", cx + (row - (cells - 1) * 0.5) * cell, cy + (line - cells * 0.5) * cell, 1.25, (door_half, 1.6, 1.25)) stamp(stamps, "liminal/backrooms-grid-v1/02-ceiling", "fillBox", cx, cy, 5.9, (half, half, 0.5)) walk = [(cx - half - 2.0, cy, 0.88), (cx + half + 2.0, cy, 0.88)] doors = [ {"prefix": "liminal/backrooms-grid-v1/01-door-x/", "width_axis": 1, "minimum_width_m": 1.5}, {"prefix": "liminal/backrooms-grid-v1/01-door-y/", "width_axis": 0, "minimum_width_m": 1.5}, ] return fixture(name, stamps, walk, doors, center=(cx, cy), wide_camera=(-42.0, -6.0, 1.6), eye_camera=(-54.0, 0.0, 1.6), eye_target_offset=(102.0, 0.0, 1.6), wide_target_offset=(80.0, 20.0, 0.0), eye_clip=6, wide_clip=6) def nowhere_stairs() -> tuple[str, dict, dict]: stamps: list[dict] = [] cx, cy = 300.0, -760.0 stamp(stamps, "liminal/staircase-nowhere-v1/00-stair", "fillSteps", cx, cy, 6.0, (32.0, 4.0, 6.0), steps=64) stamp(stamps, "liminal/staircase-nowhere-v1/04-landing", "fillBox", cx + 40.5, cy, 11.5, (9.0, 4.5, 0.5)) stamp(stamps, "liminal/staircase-nowhere-v1/02-arch-wall", "fillBox", cx + 38.0, cy, 7.5, (1.2, 6.5, 7.5)) stamp(stamps, "liminal/staircase-nowhere-v1/03-doorway-arch", "carveArch", cx + 38.0, cy, 7.0, (5.0, 5.0, 7.0), yaw=1) # Begin high enough to clear the first riser with the audit capsule, then # walk the same ascending staircase through the arch and onto the landing. points = [(cx - 32.5, cy, 0.88 + 12.0 / 64.0 + 0.05)] tread, rise = 64.0 / 64, 12.0 / 64 for index in range(64): points.append((cx - 32.0 + (index + 0.5) * tread, cy, 0.88 + (index + 1) * rise + 0.05)) points.extend([(cx + 34.0, cy, 12.93), (cx + 38.0, cy, 12.93), (cx + 44.0, cy, 12.93)]) doors = [{"prefix": "liminal/staircase-nowhere-v1/03-doorway-arch", "width_axis": 0, "minimum_width_m": 1.5}] return fixture("staircase-to-nowhere", stamps, points, doors, center=(cx, cy), wide_camera=(-8.0, -32.0, 36.0), eye_camera=(10.0, 0.0, 9.7), eye_target_offset=(38.0, 0.0, 13.6), wide_target_offset=(42.0, 0.0, 11.0), eye_clip=4, wide_clip=6) def terraced_hills() -> tuple[str, dict, dict]: stamps: list[dict] = [] cx, cy, rows, spacing = -520.0, -500.0, 9, 96.0 half_run, half_width, half_rise, steps = 48.0, 40.0, 8.0, 80 for row in range(rows): y = cy + (row - (rows - 1) * 0.5) * spacing stamp(stamps, f"liminal/terraced-hills-v1/ridge/{row:02d}/rise-west", "fillSteps", cx - half_run, y, half_rise, (half_run, half_width, half_rise), steps=steps) stamp(stamps, f"liminal/terraced-hills-v1/ridge/{row:02d}/rise-east", "fillSteps", cx + half_run, y, half_rise, (half_run, half_width, half_rise), yaw=2, steps=steps) points = [(cx - 100.0, cy, 0.93)] tread, rise = (2.0 * half_run) / steps, (2.0 * half_rise) / steps for index in range(steps): points.append((cx - 2.0 * half_run + (index + 0.5) * tread, cy, 0.93 + (index + 1) * rise)) for index in reversed(range(steps)): points.append((cx + 2.0 * half_run - (index + 0.5) * tread, cy, 0.93 + (index + 1) * rise)) points.append((cx + 100.0, cy, 0.93)) return fixture("terraced-hills", stamps, points, [], center=(cx, cy), wide_camera=(-40.0, 0.0, 20.0), eye_camera=(-60.0, 0.0, 7.8), eye_target_offset=(0.0, 0.0, 14.5), wide_target_offset=(100.0, 0.0, -10.0), eye_clip=4, wide_clip=3) def write(path: Path, value: dict) -> None: path.parent.mkdir(parents=True, exist_ok=True) path.write_text(json.dumps(value, indent=2) + "\n", encoding="utf-8") def main() -> None: parser = argparse.ArgumentParser(description=__doc__) parser.add_argument("--out", type=Path, default=OUT_DEFAULT / "fixtures") args = parser.parse_args() args.out.mkdir(parents=True, exist_ok=True) specs = args.out / "walk-specs" fixtures = [pool_rooms(), backrooms(), nowhere_stairs(), terraced_hills()] fixtures.append(backrooms(width=1.2, name="backrooms-narrow-control")) for name, world, metadata in fixtures: write(args.out / f"liminal-{name}.json", world) write(specs / f"{name}.json", metadata["walk"]) write(args.out / "views" / f"{name}.json", metadata["views"]) print(f"[L161Fixture] name={name} stamps=" f"{len(world['liminal_stamp_fixture_override']['stamps'])} status=PASS") if __name__ == "__main__": main()