Skip to content

Heatmaps

Render plugin-computed scalar data as a heatmap overlay. Accessed via snaptrude.analysis.heatmaps.

Unlike the built-in studies (Sunlight Hours, Illuminance) where the host computes the values, here the plugin brings its own numbers — occupancy, energy use, a CFD field, anything — and the host maps them through a colour ramp and paints them into the scene. Two render modes:

  • renderSpaces — one flat colour per space, painted on the space's top face (per-room metrics).
  • renderGrid — a coloured grid mesh from point samples in world coordinates (fields sampled over an area: wind, noise, microclimate).

Shared semantics:

  • Single active heatmap — a render call replaces whatever heatmap is currently showing (from either mode).
  • Colour rampoptions.colors is an ordered list of hex colour stops, low → high (e.g. ["#0000ff", "#ff0000"]); the host default is a blue → cyan → green → yellow → red ramp. Values outside [min, max] clamp to the end colours. min/max are auto-derived from the data when omitted.
  • Legend — a client-drawn card (title, unit, discrete colour segments, min/max) with < / > markers when the data ran past the range.
  • Ephemeral — never persisted, never saved with views, and auto-cleared when a scene-mutating edit invalidates it. Re-render after changing the model.

At a glance

MethodWhat it doesMutates?
renderSpaces(entries, options?)Flat colour per space, on each space's top face
renderGrid(cells, cellSize, options?)Coloured grid mesh from world-coordinate samples
reset()Clear the plugin heatmap and its legend
isActive()Whether a plugin heatmap is currently showing

Types

PluginAnalysisHeatmapSpaceEntry

PropertyTypeDescription
spaceComponentHandleHandle of the space to colour
valuenumberThe scalar value mapped to a colour

PluginAnalysisHeatmapGridCell

PropertyTypeDescription
position{ x, y, z }Cell centre in world coordinates
valuenumberThe scalar value mapped to a colour

PluginAnalysisHeatmapOptions

PropertyTypeDescription
titlestring | undefinedLegend title
unitstring | undefinedUnit label shown on the legend (e.g. "m/s")
minnumber | undefinedValue mapped to the first colour stop; data minimum when omitted
maxnumber | undefinedValue mapped to the last colour stop; data maximum when omitted
colorsstring[] | undefinedOrdered hex colour stops, low → high; host blue → cyan → green → yellow → red default

PluginAnalysisHeatmapsRenderResult

PropertyTypeDescription
successtrueThe heatmap is rendered on the scene

Render failures throw, so a returned value always carries success: true.

Functions

renderSpaces(entries, options?)

Render a per-space heatmap — one flat colour per space's top face. Each entry maps a space to a scalar value; the value is mapped through the colour ramp and the space's top face is painted that single flat colour. Replaces any heatmap currently showing. Spaces whose top face is not flat (pitched/sloped tops) are skipped with a console warning — the rest of the heatmap still renders.

  • Parameters:
    • entries: PluginAnalysisHeatmapSpaceEntry[] — one per space.
    • options: PluginAnalysisHeatmapOptions | undefined
  • Returns: PluginAnalysisHeatmapsRenderResult{ success: true }.
  • Throws: When entries is empty, a handle does not resolve to a space, no space had a flat top face to paint, options.colors has a malformed hex, options.min is greater than options.max, or plugin writes are disabled.
ts
const { groups } = await snaptrude.program.areas.list("storeys");
const { members } = await snaptrude.program.areas.listMembers("storeys", groups[0].groupId);
await snaptrude.analysis.heatmaps.renderSpaces(
  members.map((m) => ({ space: m.id, value: occupancy[m.id] ?? 0 })),
  { title: "Occupancy", unit: "people", min: 0, max: 50 }
);

renderGrid(cells, cellSize, options?)

Render a grid heatmap — a coloured mesh from point samples. Each cell is a scalar sample at a world-coordinate position (y is up — a ground-level field sits at y = 0); the host builds one square cell of edge cellSize per sample — in the same Snaptrude internal units as position (convert real-world lengths via core.units.convert) — coloured through the ramp. This is the mode for field data — wind, noise, microclimate. Replaces any heatmap currently showing.

  • Parameters:
    • cells: PluginAnalysisHeatmapGridCell[] — one per sample.
    • cellSize: number — edge length of each square cell, in the same Snaptrude internal units as position (convert via core.units.convert). Must be a positive, finite number.
    • options: PluginAnalysisHeatmapOptions | undefined
  • Returns: PluginAnalysisHeatmapsRenderResult{ success: true }.
  • Throws: When cells is empty, cellSize is not a positive, finite number, options.colors has a malformed hex, options.min is greater than options.max, or plugin writes are disabled.
ts
// World coordinates are y-up: a ground-level field varies in x/z at y = 0.
await snaptrude.analysis.heatmaps.renderGrid(
  samples.map((s) => ({ position: { x: s.x, y: 0, z: s.z }, value: s.windSpeed })),
  2, // 2-unit square cells
  { title: "Wind speed", unit: "m/s", colors: ["#0000ff", "#00ff00", "#ff0000"] }
);

reset()

Clear the plugin heatmap from the scene and remove its legend. A no-op (returns false) when no plugin heatmap is showing. Does not touch the built-in study heatmaps (sunlightHours / illuminance) — they have their own reset.

  • Returns: booleantrue when a heatmap was cleared, false when none was showing.
  • Throws: When plugin writes are disabled.
ts
await snaptrude.analysis.heatmaps.reset();

isActive()

Whether a plugin heatmap is currently showing — true between a successful render and the next reset (or the scene-mutating edit that auto-clears it). A pure read.

  • Returns: booleantrue when a plugin heatmap is rendered on the scene.
ts
if (!(await snaptrude.analysis.heatmaps.isActive())) {
  await snaptrude.analysis.heatmaps.renderGrid(cells, 2);
}