# Design ## Architecture `fountain.py` will join the existing bpy-layer feature modules under `blender/osmassets/`. It may import `bpy`, `math`, and the collection helper needed to preserve current object linking behavior. The module will expose one function: ```python def assemble(name, x, y, collection, materials): ... ``` The signature mirrors the existing inline `add_fountain(name, x, y, collection, materials)` call site to keep the migration mechanical and parity-friendly. ## Boundaries - `generate_scene.py` keeps OSM feature filtering, projection, material creation, and count ownership. - `fountain.py` owns only Blender object creation for one fountain at already projected `(x, y)` coordinates. - No pure-Python module may import `bpy`; this module is explicitly in the bpy layer, like `water.py`, `grass.py`, `scrub.py`, and `tree.py`. ## Data Flow 1. `generate_scene.py` creates `fountain_mats` from `catalog.MATERIALS`. 2. `generate_scene.py` finds point features where `tags.amenity == "fountain"`. 3. `Projector.xy()` converts the OSM coordinate to local meters. 4. `fountain.assemble("Fountain_" + id, fx, fy, props_c, fountain_mats)` creates the existing basin, water disk, pedestal, crown, and droplets. 5. `generate_scene.py` increments `counts["fountain_count"]`. ## Compatibility The refactor must preserve all generated object names, primitive dimensions, materials, smoothing flags, and custom properties. Cesium export reads the resulting `.blend`; it should see an equivalent scene graph. ## Trade-Offs A full feature registry is intentionally deferred. Starting with a one-module extraction keeps the diff small and lets parity isolate any regression to the fountain move before higher-risk building or road work. ## Rollback Rollback is straightforward: remove `fountain.py`, restore the inline `add_fountain()` function, remove the module import, and restore the original call site.