npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

windgram

v0.22.1

Published

Contract, derivations, and reference renderer (scene graph + SVG) for windgram profile documents published by github.com/azohra/windgram.

Readme

windgram

TypeScript companion to the windgram dataset published from github.com/azohra/windgram: the published contract, the derivations that are pure functions of it, the transport that fetches the documents consistently, and the reference renderer (headless scene graph + SVG serializer).

npm version CI licence

Typed data in, chart out: the package validates a published profile document and serializes the reference windgram

npm install windgram

The package ships ESM with type declarations; the only dependency is zod. Nothing touches the DOM, so these APIs run identically in Node, workers, and browsers.

Sixty seconds to a chart

Discover a model from the published catalogue, load a consistent manifest/profile pair, and serialize the reference chart:

import { parseModelCatalogueJson } from "windgram/contract";
import { buildScene } from "windgram/scene";
import { renderSvg } from "windgram/svg";
import { loadProfile } from "windgram/transport";

const DATA = "https://data.meteo.azohra.com";

// Pick a model by declared capability, never by name.
const response = await fetch(`${DATA}/models.json`);
if (!response.ok) throw new Error(`models.json: HTTP ${response.status}`);
const catalogue = parseModelCatalogueJson(await response.text());
if (!catalogue) throw new Error("models.json failed contract validation");
const model = catalogue.models.find(
  (entry) => entry.kind === "deterministic" && entry.capabilities.cape,
);
if (!model) throw new Error("no deterministic model with CAPE is published");

// The manifest + profile pair goes through the reference-time skew guard.
const loaded = await loadProfile({
  fetch,
  baseUrl: DATA,
  modelSlug: model.slug,
  siteSlug: "dundee",
});
if ("miss" in loaded) {
  throw new Error(`${model.slug}/dundee ${loaded.miss}: ${loaded.url}`);
}
if (loaded.stale) console.warn("run still syncing across the CDN");

const timeZone = loaded.profile.site.timeZone ?? "America/Vancouver";
const svg = renderSvg(buildScene(loaded.profile, { timeZone }));

The parse…Json guards return the typed document or null; transport loaders return the typed pair or a discriminated DocumentMiss. The first-windgram guide walks this path step by step and shows the chart it produces.

Launches are render inputs

A profile document is launch-agnostic: its site block records where the atmosphere was sampled and what the model's own ground there is (site.modelElevationM), never a launch elevation — one document serves every launch its grid cell covers. To draw the launch marker, supply the launch yourself:

import { parseSiteContextJson } from "windgram/contract";

// The pipeline measures every catalogued site's ground truth — the
// elevation pick, terrain, and land cover — into site-context.json,
// published beside the catalogue. Pull it on your own schedule: it
// changes only when the site catalogue does, never per model run.
const contextResponse = await fetch(`${DATA}/site-context.json`);
const context = parseSiteContextJson(await contextResponse.text());
if (!context) throw new Error("site-context.json failed contract validation");

const launch = {
  name: loaded.profile.site.name,
  elevationM: context.sites["dundee"]!.elevation.elevationM,
};
const svg = renderSvg(buildScene(loaded.profile, { timeZone, launch }));

No launch option means no marker and no launch-relative statements — absence is honest, never an error — and the same seam feeds analysis: AnalyzeOptions.launch keys the launch-relative findings, and CompareOptions.launch supplies the one launch a cross-model comparison measures against.

Entry points

One import subpath per job; each links to its guide.

| Subpath | What it gives you | Guide | | --- | --- | --- | | windgram/contract | Zod schemas, inferred types, and nullable parse guards for the five published document kinds | Contract validation | | windgram/derive | Pure derivations of published state: moisture, wind, lapse, stability, shear, usable lift, day windowing, projection, alignment | Pure derivations | | windgram/analyze | Typed findings over one profile, each carrying the thresholds and evidence that produced it | Analyze a profile | | windgram/compare | Cross-run window agreement, height spread, and wind divergence over a member ledger where every non-vote has a stated reason | Compare model profiles | | windgram/transport | loadProfile and loadRuns with the torn-pair skew guard and discriminated misses | Load published documents | | windgram/history | Month-archive loaders (member-splitting gzip reader, mandatory run dedupe, the advisory sidecar index) and compareRuns — one model's runs through time. Server-side: Node, Bun, Deno; not browsers | History and run convergence | | windgram/scene | The headless scene graph: scales, strips, series, barbs, markers, hit-testing, the key spec | Build a scene graph | | windgram/svg | The deterministic reference serializer for chart and key, styled entirely by CSS custom-property tokens | Render SVG and a key |

Every option and token defaults to the reference look; Defaults and tokens lists the exported default maps.

Ensemble documents

Every numeric position is a Scalar = number | EnsembleValue: deterministic models publish numbers, ensemble models publish percentile objects in the same positions. Switch on shape, never on model name — isEnsembleValue and isEnsembleDropout narrow one position, p50(scalar) reads the median, and isDeterministicProfile narrows a whole document once so deterministic-only code never touches p50(). Semantics live in Ensemble values.

JSON Schemas for non-JS consumers

JSON Schema artifacts generated from the same zod contract ship as plain files in the npm tarball's schema/ directory (node_modules/windgram/schema/profile.schema.json and its four siblings) and in the repository at toolkit/schema/. They are not a package export specifier — read them from the filesystem or the repository, not through import. Their field semantics match the TypeScript JSDoc.

Authority boundary

The pipeline (Python) owns stored values that need provider inputs or cross-run authority: W*, boundary-layer top, cloud base, usable-lift top, and the measured site ground truth in site-context.json (the elevation pick, terrain analysis, and land cover). This package owns pure functions of the published JSON: RH, TI, shear, B/S, lapse, stability, windowing, smoothing, and consumer-parameter projections such as a different usable-lift sink rate. A projection does not replace the document's published value. The project overview maps the full boundary.

Developing

pnpm --dir toolkit test      # vitest
pnpm --dir toolkit build     # tsc -> dist/ (types + ESM)
pnpm --dir toolkit schemas   # regenerate schema/*.json

Documentation and licence

Guides, data references, and teaching material live at the documentation portal. Release history lives in the repository CHANGELOG.

The code is MIT licensed. Published profiles derive from ECCC and NOAA source data; the repository licence section records the attribution requirements.

Made with <3 by Justin Watts.