Appearance
Site
Read the planning context of the project's site/plot and read or update its persisted Site Analysis sheet. Accessed via snaptrude.program.site.
The site is the set of plot/parcel footprints the program is planned against: their total area, per-parcel footprints (world XZ plan coordinates in Snaptrude units — the same plan space as a space's planPoints), and — when the project is geo-located on terrain — their geographic (latitude/longitude) rings. Zoning numbers (FAR/FSI, height limits) live in the Site Analysis sheet and are available through getSiteAnalysis, not the site-context reads. One context exception is listEdges: it reads each parcel's per-edge front/side/rear classification and effective base setbacks, the same resolution the buildable-envelope setback pills show on canvas.
All methods are host API calls that return Promises. Site-context reads never throw: get returns an empty snapshot (zero totals) when there is no site, the list methods return [], and getContext returns null. updateSiteAnalysis is a guarded merge/append write and rejects when the existing sheet cannot be updated safely.
At a glance
| Method | What it does | Mutates? |
|---|---|---|
get() | Snapshot of the site: total area, parcel count, per-parcel footprints | — |
getArea() | Just the total site area and its units | — |
listPolygons() | Each parcel's footprint in world XZ coordinates (Snaptrude units) | — |
listEdges() | Each parcel's boundary edges with front/side/rear roles and setbacks | — |
listGeoPolygons() | Each parcel as a ring of geographic latitude/longitude points | — |
getContext() | Geo-referenced terrain context: map center, bounds, size, zoom, parcels | — |
getLocation() | The project's geo-location as {latitude, longitude} | — |
getNorthAngle() | True-north angle in degrees, from the terrain rotation | — |
getTimezone() | IANA timezone id of the project's geo-location | — |
getWeather() | The EPW weather file resolved for the site (project override, or null) | — |
getSiteAnalysis() | Read the active proposal's persisted Site Analysis data | — |
updateSiteAnalysis(rows, options?) | Safely merge/append rows into the Site Analysis sheet | Yes |
Geo-located projects only
listGeoPolygons, getContext, getLocation, getNorthAngle, and getTimezone return data only when the project is geo-located on terrain — otherwise listGeoPolygons returns [] and the others return null. Use listPolygons for the world-coordinate footprints that are always available.
Types
PluginSiteFootprintPoint
A 2D ground-plane point of a site parcel footprint, in world XZ plan coordinates (Snaptrude units) — the same plan space as a space's planPoints, so site parcels overlay space footprints directly.
| Property | Type | Description |
|---|---|---|
x | number | X coordinate (world, Snaptrude units) |
z | number | Z coordinate (world, Snaptrude units) |
PluginSiteGeoPoint
A geographic point of a site parcel ring (WGS84).
| Property | Type | Description |
|---|---|---|
lat | number | Latitude (degrees) |
lng | number | Longitude (degrees) |
alt | number | Altitude (metres) |
PluginSitePolygon
A single site parcel/polygon. Its area is in the enclosing result's units.
| Property | Type | Description |
|---|---|---|
id | string | Unique parcel/component id |
area | number | Footprint area, in the result's units |
label | string | Parcel label / room type (e.g. "site") |
footprint | PluginSiteFootprintPoint[] | 2D ground-plane boundary points |
PluginProgramSiteSnapshot
Result of get. Per the area-units convention, units sits on this snapshot and every area below is reported in it.
| Property | Type | Description |
|---|---|---|
units | "ft2" | "m2" | The unit all areas in this snapshot are reported in |
totalArea | number | Total area of all site parcels |
polygonCount | number | Number of site parcels |
polygons | PluginSitePolygon[] | Each site parcel with its footprint |
PluginProgramSiteEdge
One boundary edge of a site parcel, as listEdges returns it. Coordinates and lengths are world meters — unlike listPolygons footprints, which are Snaptrude units.
| Property | Type | Description |
|---|---|---|
edgeIndex | number | Index in the canonicalized (sanitized, CCW) boundary — the same index space the envelope's edge overrides use |
start, end | { x: number, z: number } | Edge endpoints, world XZ meters |
lengthMeters | number | Edge length in meters |
role | "front" | "side" | "rear" | Resolved classification. "street" never appears — it resolves to front |
roleSource | "override" | "heuristic" | "override" when the user reassigned this edge's role (setback pills); "heuristic" for the tangent classifier |
setbackMeters | number | null | Effective base setback (per-edge exception, else the role's value); null when the parcel has no zoning envelope |
PluginProgramSiteEdgesEntry
Per-parcel entry of listEdges.
| Property | Type | Description |
|---|---|---|
siteId | string | The parcel's component id — same id space as listPolygons |
buildableEnvelopeId | string | null | Linked zoning buildable envelope, when one exists |
usingLiveSiteBoundary | boolean | true when edges come from the live site boundary; false when only the envelope's persisted source polygon was resolvable |
staleOverridesDropped | boolean | true when persisted edge overrides no longer index-align with the live boundary and were ignored |
edges | PluginProgramSiteEdge[] | The classified boundary edges |
PluginSiteLatLng
A geographic latitude/longitude point (no altitude).
| Property | Type | Description |
|---|---|---|
lat | number | Latitude (degrees) |
lng | number | Longitude (degrees) |
PluginSiteBounds
Geographic bounds of the site terrain.
| Property | Type | Description |
|---|---|---|
north | number | North latitude |
south | number | South latitude |
east | number | East longitude |
west | number | West longitude |
PluginSiteContextParcel
A site parcel in the terrain context — geographic footprint and area.
| Property | Type | Description |
|---|---|---|
footprint | PluginSiteLatLng[] | Geographic boundary points |
area | number | Parcel area (project area units) |
PluginProgramSiteContext
The geo-referenced terrain context of the site.
| Property | Type | Description |
|---|---|---|
center | PluginSiteLatLng | Map center |
bounds | PluginSiteBounds | Terrain bounds |
widthInM | number | Terrain width in metres |
heightInM | number | Terrain height in metres |
zoom | number | Effective map zoom |
parcels | PluginSiteContextParcel[] | Site parcels with geographic footprints |
PluginSiteAnalysisRow
A constraint row stored in the Site Analysis sheet.
| Property | Type | Description |
|---|---|---|
category | string | Non-empty category label |
description | string | Constraint description |
quantity | string | number | Recorded value |
unit | string | Unit label, or an empty string when not applicable |
PluginProgramSiteAnalysisResult
Persisted Site Analysis data for the active proposal, or null when no parseable sheet exists.
| Property | Type | Description |
|---|---|---|
sheetName | string | Persisted sheet that supplied the data |
siteLocation | { lat: number, lng: number } | null | Recorded geographic location |
sitePolygon | string | null | JSON-encoded recorded site polygon |
rows | PluginSiteAnalysisRow[] | Constraint rows |
PluginProgramSiteAnalysisUpdateResult
Result of a Site Analysis merge/append write.
| Property | Type | Description |
|---|---|---|
sheetName | string | Sheet that was updated |
rowCount | number | Constraint rows after the write |
updatedRows | number | Existing rows whose Quantity/Unit changed |
appendedRows | number | New rows appended after the existing table |
Functions
get()
Get a snapshot of the project site: the total site area, parcel count, and each parcel's footprint.
- Returns:
PluginProgramSiteSnapshot— empty (zero totals, no parcels) when the project has no site.
ts
const site = await snaptrude.program.site.get();
console.log(`${site.totalArea} ${site.units} across ${site.polygonCount} parcels`);getArea()
Get just the total site area. A fast single-metric read — the same number as PluginProgramSiteSnapshot.totalArea, without computing the per-parcel footprints.
- Returns:
{ units: "ft2" | "m2", area: number }—areais0when there is no site.
ts
const { area, units } = await snaptrude.program.site.getArea();
console.log(`Total site area: ${area} ${units}`);listPolygons()
List the site parcels with their footprints (world XZ plan coordinates, Snaptrude units): each parcel's id, area, label, and 2D footprint (XZ ground-plane points).
- Returns:
{ units: "ft2" | "m2", polygons: PluginSitePolygon[] }—polygonsis empty when the project has no site; each parcel'sareais inunits.
ts
const { polygons, units } = await snaptrude.program.site.listPolygons();
for (const p of polygons) {
console.log(p.label, p.area, units, `${p.footprint.length} boundary points`);
}listEdges()
List each site parcel's boundary edges with their front / side / rear classification — the same per-edge roles the buildable-envelope setback pills show on canvas, so a plugin can pick up the user's edge tagging without asking them to set it up again.
Role resolution mirrors the canvas exactly: the user's per-edge overrides (set via the setback pills) win over the tangent heuristic. When a parcel has a linked zoning buildable envelope, setbackMeters is the effective base setback of the edge; parcels without one (none, or a massing envelope) classify by heuristic alone and report setbackMeters: null. staleOverridesDropped: true means the site was edited after the envelope was configured and the persisted overrides no longer align with the live boundary — the heuristic classification is reported instead.
- Returns:
{ lengthUnit: "m", sites: PluginProgramSiteEdgesEntry[] }— one entry per parcel; empty when the project has no site. Coordinates are world meters (unlikelistPolygons).
ts
const { sites } = await snaptrude.program.site.listEdges();
for (const site of sites) {
for (const e of site.edges) {
console.log(e.edgeIndex, e.role, e.roleSource, e.setbackMeters);
}
}listGeoPolygons()
List the site parcels as geographic latitude/longitude rings. Only available when the project is geo-located on terrain; returns no rings otherwise. Use listPolygons for the scene-coordinate footprints that are always available.
- Returns:
{ polygons: PluginSiteGeoPoint[][] }— one ring of{ lat, lng, alt }points per parcel;[]when the project is not geo-located.
ts
const { polygons } = await snaptrude.program.site.listGeoPolygons();
if (polygons.length > 0) {
const [firstRing] = polygons;
console.log(firstRing.map(({ lat, lng }) => `${lat}, ${lng}`));
}getContext()
Get the geo-referenced terrain context of the site: the map center and bounds, the terrain size in metres, the effective zoom, and each parcel's geographic footprint and area — the context used for site analysis.
- Returns:
PluginProgramSiteContext | null—nullwhen the project is not geo-located on terrain.
ts
const ctx = await snaptrude.program.site.getContext();
if (ctx) {
console.log(ctx.center.lat, ctx.center.lng, `${ctx.widthInM}m x ${ctx.heightInM}m`);
for (const parcel of ctx.parcels) console.log(parcel.area, parcel.footprint.length);
}getLocation()
Get the project's geographic location — the latitude/longitude the site is geo-located at, the location the analysis.* sun and daylight studies compute against. Returns null when the project is not geo-located on terrain (there is deliberately no fallback location).
- Returns:
{ latitude: number, longitude: number } | null
ts
const location = await snaptrude.program.site.getLocation();
if (location) console.log(location.latitude, location.longitude);getNorthAngle()
Get the site's true-north angle — the angle in degrees ([0, 360)) the model's north is rotated from true north, derived from the terrain's rotation — clockwise-positive viewed from above (the opposite sign convention to design.transform.rotate, where positive = counter-clockwise). 0 means the model is aligned to true north. Returns null when the project is not geo-located on terrain.
- Returns:
number | null
ts
const northAngle = await snaptrude.program.site.getNorthAngle();
if (northAngle !== null) console.log(`${northAngle}° from true north`);getTimezone()
Get the IANA timezone of the project's geographic location — the timezone identifier (e.g. "America/New_York", "Asia/Kolkata") looked up from the same geo-location getLocation returns. Returns null when the project is not geo-located on terrain.
- Returns:
string | null
ts
const timezone = await snaptrude.program.site.getTimezone();
if (timezone) console.log(`Project timezone: ${timezone}`);getWeather()
Get the EPW weather file resolved for the project site — a lightweight read of { weatherFileId, station, checksum, selectionMethod }. v1 reads only the project-level override (a station pinned for this project); returns null when no override is set. The nearest-station file a geo-located project computes against is read via analysis.weather.getSeries's source. The weatherFileId matches the id analysis.weather reads rows from and core.io.import.epw returns.
- Returns:
PluginProgramSiteWeather | null—{ weatherFileId, station, checksum, selectionMethod }, ornullwhen no project override is set. A read that never throws.
ts
const weather = await snaptrude.program.site.getWeather();
if (weather) console.log(weather.station, weather.selectionMethod);getSiteAnalysis()
Read the active proposal's persisted Site Analysis sheet without requiring Program mode to be open. When a Program tab is open, the host first makes a best-effort attempt to flush its pending edits. The active proposal's sheet is preferred, with the base "Site Analysis" sheet as fallback.
- Returns:
PluginProgramSiteAnalysisResult | null. Returnsnullwhen no parseable Site Analysis sheet is persisted. This read never throws.
ts
const analysis = await snaptrude.program.site.getSiteAnalysis();
if (analysis) {
console.log(analysis.sheetName);
for (const row of analysis.rows)
console.log(row.category, row.description, row.quantity, row.unit);
}updateSiteAnalysis(rows, options?)
Merge sourced site/zoning constraints into the active proposal's persisted Site Analysis sheet. Rows match by trimmed, case-insensitive Category + Description. Matched rows update only Quantity/Unit; unmatched rows append. Existing labels, formatting, and unrelated rows remain intact. There is no replace/reset mode.
Call getSiteAnalysis() first and reuse its exact labels. Send only rows that were actually sourced. options.siteLocation accepts { lat, lng }; options.sitePolygon accepts a JSON-encoded polygon string.
- Returns:
PluginProgramSiteAnalysisUpdateResultwith the target sheet and merge counts. - Errors: rejects when writes are disabled, no active project or unambiguous proposal sheet exists, live Program edits cannot be flushed, or an existing persisted sheet cannot be parsed safely.
ts
const result = await snaptrude.program.site.updateSiteAnalysis([
{ category: "FAR", description: "Floor Area Ratio", quantity: 3.5, unit: "ratio" },
{ category: "Set backs", description: "Front setbacks", quantity: 6, unit: "m" }
]);
console.log(result.sheetName, result.updatedRows, result.appendedRows);Errors
Failed calls reject with a typed PluginError — see Error Handling. Site-context methods and getSiteAnalysis are total reads. updateSiteAnalysis is a guarded write and rejects instead of risking loss of live or persisted sheet data; see its method-specific errors above.