Files
osmWorkflow/.trellis/tasks/archive/2026-08/08-03-extract-building-module/prd.md

4.0 KiB

Extract building module

Goal

Move building assembly out of blender/generate_scene.py into a dedicated bpy-layer module, keeping generated .blend / .glb / metadata structure unchanged. This continues the documented P2 feature-module direction after fountain.py.

Background

  • .trellis/spec/guides/artifact-parity-guide.md records P2 as partial: water.py, grass.py, scrub.py, tree.py, and fountain.py are already split out, while building and roads still live in generate_scene.py.
  • blender/generate_scene.py:72 defines _assemble_building().
  • blender/generate_scene.py:179 defines add_building_details(), which creates office / industrial window bands with MeshBatch and add_wall_panel().
  • blender/generate_scene.py:789 dispatches OSM ways with a building tag, increments counts["building_count"] and counts["industrial_count"], and extends focus_points with the returned ring.
  • blender/generate_scene.py:710 creates building_mats from the existing catalog.MATERIALS["building_" + key] entries.
  • blender/generate_scene.py:910 persists office_override_way_ids as a scene custom property from args["office_overrides"].

Requirements

  1. Add a new bpy-layer module at blender/osmassets/building.py.
  2. Move the current building assembly behavior into the new module:
    • _assemble_building()
    • add_building_details()
  3. Expose an assemble(...) function from the new module that returns the same tuple shape currently returned by _assemble_building(): (added, industrial_added, ring_pts).
  4. Keep generate_scene.py responsible for:
    • parsing --office-overrides;
    • creating building_mats;
    • filtering OSM ways with a building tag and len(ring) >= 3;
    • updating building_count, industrial_count, and focus_points;
    • writing scene["office_override_way_ids"];
    • writing the existing SCENE_DONE JSON shape.
  5. Preserve existing building object names and mesh names:
    • Building_<way_id>
    • Building_<way_id>_Roof
    • Building_<way_id>_Windows
  6. Preserve existing building custom properties:
    • osm_height
    • render_height
    • building_kind
    • osm_building_tag
    • office_override
  7. Preserve current height rules:
    • industrial buildings use the parsed source height;
    • non-industrial buildings under 30m render at 11.4m;
    • source height has a 3.0m floor and parse_height(tag, 12.0) default.
  8. Preserve current facade behavior:
    • industrial buildings use one high horizontal band;
    • office buildings use floor-based window bands;
    • bevel modifier name, width, and segment count stay unchanged.
  9. Do not introduce a full features/ registry in this task.
  10. Do not modify roads, material definitions, MATERIALS order, ROAD_LAYERS order, stdout markers, parity ignore lists, or known unrelated defects D1-D3.

Acceptance Criteria

  • blender/osmassets/building.py contains building assembly behavior and imports only bpy-layer-safe dependencies.
  • blender/generate_scene.py imports and calls the new building module; no inline _assemble_building() or add_building_details() remains there.
  • Building counts, industrial counts, focus point behavior, scene custom properties, and SCENE_DONE JSON keys remain unchanged.
  • python3 -m py_compile blender/osmassets/building.py passes.
  • python3 -m py_compile blender/generate_scene.py passes.
  • python3 -m unittest blender/tests/test_pure.py passes.
  • A before/after parity comparison is run for the Blender/Cesium stages and any non-ignored diff is either absent or explicitly explained as expected. For this refactor, the expected result is no contract diff.

Out Of Scope

  • Full feature registry implementation.
  • Road extraction.
  • Building visual redesign.
  • Building material or Cesium export contract changes.
  • Moving CLI parsing or office_override_way_ids scene metadata out of generate_scene.py.
  • Changing geometry helper APIs in osmassets.mesh.

Open Questions

None.