Skip to content

Render SVG and a scene-derived key

renderSvg(scene, options) emits a complete SVG document with stable ordering and two-decimal geometry, styled entirely by overridable --wg-* tokens:

Same scene, same bytes — two token sets

Palette is not scene data: a downstream look is CSS custom properties on an ancestor, never a forked serializer.

The same teaching windgram rendered twice from one scene. The left panel uses the package's default tokens; the right panel sits inside an element that overrides surface, ink, temperature, and halo tokens to a dark club palette. The SVG markup of both panels is identical.

package defaults

Pressure kPa 90.3 90 Cloud % 100 0 w* m/s 3 0 900m 2953ft 1668m 5472ft 2436m 7991ft 3203m 10510ft 3971m 13029ft 4739m 15548ft 10 11 12 13 14 15 16 17 18 19 launch 1050 m 10° 20°

ancestor overrides --wg-*

Pressure kPa 90.3 90 Cloud % 100 0 w* m/s 3 0 900m 2953ft 1668m 5472ft 2436m 7991ft 3203m 10510ft 3971m 13029ft 4739m 15548ft 10 11 12 13 14 15 16 17 18 19 launch 1050 m 10° 20°
Both panels embed the same DEFAULT_STYLESHEET; only the right panel's ancestor sets --wg-surface, --wg-ink, --wg-ink-soft, --wg-ink-mute, --wg-rule, --wg-temp, --wg-halo, and --wg-halo-barb. Remove the wrapper class and the panels are byte-identical.Units altitude m and ft · time UTC
render-svg.ts
import type { SceneGraph } from "windgram/scene";
import { renderSvg } from "windgram/svg";
export function renderClubSvg(scene: SceneGraph): string {
return renderSvg(scene, { idPrefix: "club-main" });
}

Give each chart on an HTML page a unique idPrefix. The prefix namespaces definitions such as cloud hatch patterns.

buildKeySpec(scene) reports only encodings that the scene actually drew. It carries each keyed series’ real class, dash, and stroke width; describes each shaded field overlay as a ramps entry whose classes are the drawn patches’ own, in weak-to-strong reading order; includes the condensation hatch only when dense cloud is visible; includes the stability ramp only when that field is visible; and adds the p25–p75 note only when a drawn series has an ensemble band. Lines that label themselves on the plot (the 10°/20° isotherms, the Td isolines) stay out of the key by default — a consumer whose look keys them anyway opts them in with selfLabeled: ["dewPointIsoline"] and receives the real style facts instead of restating dash and width. renderKeySvg serializes that spec with the same package stylesheet:

render-key.ts
import type { SceneGraph } from "windgram/scene";
import { buildKeySpec } from "windgram/scene";
import { renderKeySvg } from "windgram/svg";
export function renderClubKey(scene: SceneGraph): string {
return renderKeySvg(buildKeySpec(scene), { idPrefix: "club-main-key" });
}

Build the key from the final scene after every option or overlay change. An all-layer key falsely labels a progressive or hidden-layer chart. Give each key its own idPrefix to separate its hatch definition from every chart and key on the page.

The default output embeds DEFAULT_STYLESHEET. Every colour fallback comes from one of the exported maps:

  • TOKEN_DEFAULTS for the renderer’s general token surface;
  • STABILITY_TOKEN_DEFAULTS for the eight-class stability ramp;
  • SERIES_TOKENS for the key-entry id → token correspondence ("wg-series-usable"usable) a legend or focus style needs — read it instead of parsing id strings; and
  • FIELD_STYLE_DEFAULTS for each field-overlay class’s fill token and opacity, the facts an HTML ramp chip needs.

Override tokens on an ancestor instead of forking the serializer:

club-overrides.css
.club-windgram {
--wg-surface: #14181c;
--wg-ink: #e8e4da;
--wg-cape-watch: #b98a2d;
--wg-temp: #d97706;
--wg-text-hour-tick: 12px;
--wg-halo-series: #14181c;
}

Pass stylesheet: null when the consumer will supply all class styling. DEFAULT_STYLESHEET remains available as a reference, but copying individual hex values into application code creates a second authority.

TOKEN_DEFAULTS defines a type-scale token for every serializer text role, including strip scales, hour ticks, the surface-temperature row, and key labels. The per-element --wg-halo-series, --wg-halo-barb, --wg-halo-marker, and --wg-halo-text slots fall back to shared --wg-halo; set one slot to transparent to remove that halo. Scalar strips print their maximum and minimum at the right edge. The cloud-layer strip keeps its H/M/L row tags.

The serializer fills sampled field bands with the SVG even-odd rule. Custom renderers of SceneGraph.fields must apply the same fill-rule="evenodd" to preserve holes between interpolated contour thresholds.

The same scene and options produce identical bytes, supporting static builds, caching, reviewable golden diffs, and reproducible teaching figures. Ensemble profile values remain percentile bands in the scene.

If an intentional renderer change alters a golden, follow the review sequence in Data and package versioning. A new snapshot is not evidence that labels, units, IDs, or accessibility stayed correct.