Skip to content

Publish static output

A windgram publisher produces files ahead of page view time. A website can host those files directly or render them during its own build.

Static publishing path
Static artifacts cross explicit boundaries.Generation owns model-dependent quantities; the package validates and renders the published profile document.
  1. Generate model-dependent values in Python. Quantities that require inputs beyond the published document stay in the pipeline.
  2. Validate the document boundary. Consumers accept only profile documents that satisfy the exported contract.
  3. Publish static artifacts. Put versioned JSON and generated assets on infrastructure the publisher controls.
  4. Render from the artifact. Build a scene and serialize SVG in Node, a worker, or another non-DOM runtime.

The CLI writes one directory per selected model beneath --output:

public/data/
<model-slug>/
manifest.json
sites/
<site-slug>.json
history/
<site-slug>/
<YYYY-MM>.jsonl.gz

runs.json at the published dataset’s root is a cross-model index rebuilt by the publish workflow from every published manifest; a single-model external output does not gain that file automatically. Treat the manifest and each profile as one publication pair. Their referenceTime values must agree before rendering; the windgram/transport loader performs that check for TypeScript consumers.

Copy or sync the output directory only after a successful builder exit. Keep paths stable, preserve JSON content types and gzip encoding, and let caches expire independently without assuming an atomic multi-file deployment. That last condition is why consumers validate the manifest/profile pair.

Possible destinations include a club’s existing static site, object storage, or a private member-gated application. They are deployment choices, not Windgram features. Do not add credentials, launch membership, or access policy to the profile contract.

render-profile.ts
import { readFile } from "node:fs/promises";
import { parseWindgramProfileJson } from "windgram/contract";
import { buildScene } from "windgram/scene";
import { renderSvg } from "windgram/svg";
const source = await readFile("./public/data/hrrr-conus/sites/test-hill.json", "utf8");
const profile = parseWindgramProfileJson(source);
if (!profile) throw new Error("profile failed contract validation");
const scene = buildScene(profile, { timeZone: "America/Vancouver" });
const svg = renderSvg(scene, { idPrefix: "club-profile" });

The package contract, scene, and SVG tests exercise this validation → scene → serialization chain. The input path, timezone, rendering options, palette, hosting destination, and audience remain downstream configuration. A publisher can change them without copying formulas or renderer internals.