Skip to content

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

MethodWhat it doesMutates?
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 sheetYes

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.

PropertyTypeDescription
xnumberX coordinate (world, Snaptrude units)
znumberZ coordinate (world, Snaptrude units)

PluginSiteGeoPoint

A geographic point of a site parcel ring (WGS84).

PropertyTypeDescription
latnumberLatitude (degrees)
lngnumberLongitude (degrees)
altnumberAltitude (metres)

PluginSitePolygon

A single site parcel/polygon. Its area is in the enclosing result's units.

PropertyTypeDescription
idstringUnique parcel/component id
areanumberFootprint area, in the result's units
labelstringParcel label / room type (e.g. "site")
footprintPluginSiteFootprintPoint[]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.

PropertyTypeDescription
units"ft2" | "m2"The unit all areas in this snapshot are reported in
totalAreanumberTotal area of all site parcels
polygonCountnumberNumber of site parcels
polygonsPluginSitePolygon[]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.

PropertyTypeDescription
edgeIndexnumberIndex 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
lengthMetersnumberEdge 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
setbackMetersnumber | nullEffective base setback (per-edge exception, else the role's value); null when the parcel has no zoning envelope

PluginProgramSiteEdgesEntry

Per-parcel entry of listEdges.

PropertyTypeDescription
siteIdstringThe parcel's component id — same id space as listPolygons
buildableEnvelopeIdstring | nullLinked zoning buildable envelope, when one exists
usingLiveSiteBoundarybooleantrue when edges come from the live site boundary; false when only the envelope's persisted source polygon was resolvable
staleOverridesDroppedbooleantrue when persisted edge overrides no longer index-align with the live boundary and were ignored
edgesPluginProgramSiteEdge[]The classified boundary edges

PluginSiteLatLng

A geographic latitude/longitude point (no altitude).

PropertyTypeDescription
latnumberLatitude (degrees)
lngnumberLongitude (degrees)

PluginSiteBounds

Geographic bounds of the site terrain.

PropertyTypeDescription
northnumberNorth latitude
southnumberSouth latitude
eastnumberEast longitude
westnumberWest longitude

PluginSiteContextParcel

A site parcel in the terrain context — geographic footprint and area.

PropertyTypeDescription
footprintPluginSiteLatLng[]Geographic boundary points
areanumberParcel area (project area units)

PluginProgramSiteContext

The geo-referenced terrain context of the site.

PropertyTypeDescription
centerPluginSiteLatLngMap center
boundsPluginSiteBoundsTerrain bounds
widthInMnumberTerrain width in metres
heightInMnumberTerrain height in metres
zoomnumberEffective map zoom
parcelsPluginSiteContextParcel[]Site parcels with geographic footprints

PluginSiteAnalysisRow

A constraint row stored in the Site Analysis sheet.

PropertyTypeDescription
categorystringNon-empty category label
descriptionstringConstraint description
quantitystring | numberRecorded value
unitstringUnit label, or an empty string when not applicable

PluginProgramSiteAnalysisResult

Persisted Site Analysis data for the active proposal, or null when no parseable sheet exists.

PropertyTypeDescription
sheetNamestringPersisted sheet that supplied the data
siteLocation{ lat: number, lng: number } | nullRecorded geographic location
sitePolygonstring | nullJSON-encoded recorded site polygon
rowsPluginSiteAnalysisRow[]Constraint rows

PluginProgramSiteAnalysisUpdateResult

Result of a Site Analysis merge/append write.

PropertyTypeDescription
sheetNamestringSheet that was updated
rowCountnumberConstraint rows after the write
updatedRowsnumberExisting rows whose Quantity/Unit changed
appendedRowsnumberNew 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 }area is 0 when 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[] }polygons is empty when the project has no site; each parcel's area is in units.
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 (unlike listPolygons).
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 | nullnull when 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 }, or null when 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. Returns null when 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: PluginProgramSiteAnalysisUpdateResult with 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.