Appearance
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 ramp —
options.colorsis 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/maxare 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
| Method | What it does | Mutates? |
|---|---|---|
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
| Property | Type | Description |
|---|---|---|
space | ComponentHandle | Handle of the space to colour |
value | number | The scalar value mapped to a colour |
PluginAnalysisHeatmapGridCell
| Property | Type | Description |
|---|---|---|
position | { x, y, z } | Cell centre in world coordinates |
value | number | The scalar value mapped to a colour |
PluginAnalysisHeatmapOptions
| Property | Type | Description |
|---|---|---|
title | string | undefined | Legend title |
unit | string | undefined | Unit label shown on the legend (e.g. "m/s") |
min | number | undefined | Value mapped to the first colour stop; data minimum when omitted |
max | number | undefined | Value mapped to the last colour stop; data maximum when omitted |
colors | string[] | undefined | Ordered hex colour stops, low → high; host blue → cyan → green → yellow → red default |
PluginAnalysisHeatmapsRenderResult
| Property | Type | Description |
|---|---|---|
success | true | The 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
entriesis empty, a handle does not resolve to a space, no space had a flat top face to paint,options.colorshas a malformed hex,options.minis greater thanoptions.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 asposition(convert viacore.units.convert). Must be a positive, finite number.options:PluginAnalysisHeatmapOptions | undefined
- Returns:
PluginAnalysisHeatmapsRenderResult—{ success: true }. - Throws: When
cellsis empty,cellSizeis not a positive, finite number,options.colorshas a malformed hex,options.minis greater thanoptions.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:
boolean—truewhen a heatmap was cleared,falsewhen 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:
boolean—truewhen a plugin heatmap is rendered on the scene.
ts
if (!(await snaptrude.analysis.heatmaps.isActive())) {
await snaptrude.analysis.heatmaps.renderGrid(cells, 2);
}