# Heritage landmark replacement

`heritage-landmarks.js` exports `createHeritageLandmarks({THREE,xy,height,buildings,materials})`, `HERITAGE_BUILDING_IDS` and `HERITAGE_HEIGHTS`. The constructor returns `{group,stats,obstacles,anchors,surfaceSamplers,arrivals,dispose}`. Its only module dependency is the existing `./terrain-surface.js?v=4.4`; it requests no external assets. Optional `materials.plasterNormal` reuses the application's plaster surface detail. It does not mutate the supplied building records.

## Integration

Keep OSM building records, rings, holes, IDs, collision-grid membership, and geographic anchors. Before computing `b.top`, use these interpreted low-roof heights: cathedral way **255583481: 11.8 m**; Fortaleza relation **3501975: 12.6 m**. These heights are estimates for this architectural interpretation, not surveyed dimensions. The architecture agent has confirmed these two explicit exceptions.

Skip all generic wall, window, shutter, parapet, roof, and roof-prop rendering for just those two IDs. This module owns the complete mapped outer/inner wall rings and roof surfaces, including the Fortaleza courtyard opening. Geometry details such as cornices, entry steps and cylindrical tower caps project slightly beyond the wall plane, as architectural details do; the original mapped ground plans are retained.

```js
import {createHeritageLandmarks} from './heritage-landmarks.js';
const heritage=createHeritageLandmarks({
  THREE,xy,height:terrainHeight,buildings,materials:textureMaps
});
scene.add(heritage.group);
cameraObstacles.push(...heritage.obstacles);
anchors.push(...heritage.anchors);
for (const b of buildings) {
  const sample=heritage.surfaceSamplers.get(Number(b.id));
  if (sample) b.surfaceHeight=sample;
}
// Controller forward is (-sin(yaw), -cos(yaw)).
const cathedralArrival=heritage.arrivals.get(255583481);
const fortalezaArrival=heritage.arrivals.get(3501975);
```

In the current `createLandmarks()`, remove exactly these two old overlay blocks:

1. The comment `// Two small rooftop bell towers distinguish the cathedral.` and the following line beginning `const cp=vGeo(-66.11780,18.46576,18);for(const dx of[-8,8])...` through its closing `}`. It creates the two misplaced 3.5 × 7 m boxes and spherical caps.
2. The following line beginning `const fp=vGeo(-66.11925,18.46418,10);for(const dx of [-12,12])...` through its closing `}`. It creates the two generic Fortaleza cylinders with hemispherical caps.

Retain the surrounding garitas, Morro lighthouse, Capitol dome, fountain, and birds. Add the new module once, after architecture records exist. The returned obstacles cover both complete landmark groups for camera obstruction; gameplay ground/collision continues using the preserved building records. The new `surfaceSamplers` Map provides the highest intersection with each building’s original rendered triangle geometry, including the nave vault, roof cupolas, tower caps and roofline details. The parent owns integration into ground, collision, zip, and landing logic. `null` means no rendered surface at that X/Z, including the open Fortaleza courtyard. Supplied building records are not mutated by the constructor.

## Supported architecture and interpretation

The cathedral's west street facade is aligned to its two collinear mapped front edges (ring indices 6–8), a measured map width of 22.461 m. The model emphasizes three doorways with blind arched lunettes, tall pilasters, successive central tiers, concave shoulders, a saint niche, shoulder statues, a triangular pediment and cross. Small terracotta cupolas and a low nave vault sit within the mapped body. Two arbitrary large rooftop bell towers were not retained. The visual facade vocabulary and visible small cupolas come from inspected photographs; their dimensions, small sculptural figures, exact roof-cupola positions, side-window spacing and simplified roof vault are original interpretations. The ground-level door steps fit the local measured terrain.

Fortaleza's ceremonial facade is aligned to mapped east edge 25–26, a map width of 19.731 m. It has five bays, a central round-arch doorway, continuous wrought-iron balcony, white pilasters and cornices against blue-gray wall panels, white shutters and a small raised central plaque silhouette. The two cylindrical west-side towers have crenellated caps rather than the former domes. Their centers track the mapped round lobes near (−66.1194801, 18.4643282) and (−66.1193832, 18.4640675). Exact radii, heights, side-window repetitions, relief details and parapet dimensions are interpreted. The three flagstaffs carry no invented flags or insignia. The model does not reproduce a readable official plaque or coat of arms.

## Research sources

- [Cathedral official history](https://catedral.catedraldesanjuanpr.org/our-cathedral/) identifies the Calle del Cristo site and explains the Latin-cross, three-nave arrangement. Used for orientation/context rather than numerical dimensions.
- [Daderot, cathedral exterior, 21 October 2011](https://commons.wikimedia.org/wiki/File:Catedral_de_San_Juan_Bautista_de_Puerto_Rico_-_DSC06869.JPG), public domain. The actual photograph was inspected for the tiered facade, three portals/lunettes, pilasters, pediment, cross, statues, concave shoulders and small terracotta roof cupolas.
- [Fortaleza in Old San Juan, 13 February 2020](https://commons.wikimedia.org/wiki/File:Fortaleza_in_Old_San_Juan_(cropped).jpg), Steam Pipe Trunk Distribution Venue, CC BY 2.0. The actual photograph was inspected for the east-front bays, arched doorway, balcony, pilasters, white window trim, raised plaque and flagstaffs. Commons camera metadata also locates the photographer east of the palace, looking west.
- [La Fortaleza, August 2025](https://commons.wikimedia.org/wiki/File:La_Fortaleza_(August_2025).jpg), Ligocsicnarf89, CC BY 4.0. The actual photograph shows the bay-facing palace and crenellated tower silhouette. Used to distinguish the palace's military towers from a dome-topped fantasy silhouette.
- [National Park Service, La Fortaleza nomination](https://npgallery.nps.gov/NRHP/GetAsset/NHLS/66000951_text) documents the 1846 neoclassical facade, substantial entrance door, flat roofs and circular historic towers. Its description informed the architectural vocabulary; the model does not claim survey accuracy.
- Ground plans: supplied OpenStreetMap-derived `geography.json`, IDs above. Preserve existing OSM attribution.

Reference photos were downloaded for visual research only. They are not textures, bundled model assets, or part of the module's runtime. All delivered mesh geometry and schematic sculptural detail are original procedural work.

## Validation

With the recovered map footprints and filled measured DEM: **2 landmarks, 9 ordinary material draw calls, 79,034 triangles, 2 camera obstacles, 6 additional anchors**. All geometry attributes are finite; both facade frames are based on the actual mapped front edges. Roof triangulation retains the Fortaleza courtyard hole. A standalone geometry export and independent software silhouette views were inspected; app lighting/terrain integration should still receive the parent's final in-scene review.

The validation harness is `check-heritage-landmarks.mjs`; measurements are saved in `heritage-landmarks-audit.json`. No Site checkout, hosting state, or browser state was modified by this asset task.


## Roof-height and arrival correction

The module now returns `surfaceSamplers: Map<number,(x,z)=>number|null>` and `arrivals: Map<number,{x,z,yaw}>`. The samplers use `createSurfaceSampler` over the final original mesh position/index arrays with `highest=true` and 4 m grid cells. The source arrays already contain world-space coordinates.

Arrival points are 10 m along each principal facade’s outward normal. If a mapped building occupies that point, the constructor tries alternative distances along the same normal. With this dataset, both exact 10 m points are clear of every mapped building. Yaw is `atan2(nx,nz)`, matching the existing controller’s `(-sin(yaw),-cos(yaw))` forward vector and facing the facade:

- Cathedral: x −165.57733846254538, z 39.05927606086261, yaw −1.3614912674884814.
- Fortaleza: x −257.12080195857345, z 187.83158637540913, yaw 1.9095603475117173.

The numerical regression is `check-heritage-roof-samplers.mjs`; saved output is `heritage-roof-sampler-audit.json`. At the former cathedral map location (−66.1176997, 18.4657307), the sampler reports **37.319158574 m**, versus flat `b.top` **34.317364909 m**, matching a Three.js raycast against the actual rendered roof to numerical precision. The interior Fortaleza courtyard returns **null** for both the sampler and rendered-mesh raycast. Tests also assert no building-record mutation, both 10 m arrivals outside all mapped buildings, and headings aligned with their facades.
