v0.21.0

Released June 12, 2026 · All releases

Registry-driven composition and sandbox integration. A minor release turning the entity registry into something you can author over and visualize — making content queryable by frontmatter, and letting sandboxes be fed registry data to drive arbitrary client-side renderings (3D sitemaps, relationship graphs). The thread that runs through it: the registry's render targets grow from HTML and SVG to bring-your-own-renderer.

Changes

  • Data-bound sandboxes (SPEC-093 core) — the registry's third render target, after collection (HTML) and aggregate (SVG): bring your own renderer. A {% sandbox data="type:page" %} binds a registry query (SPEC-070 field-match grammar); the build resolves it, projects (data-fields) and shapes it (data-shape="flat" | "tree"), caps the payload, and injects the JSON so the iframe code can read it as a frozen window.RF_DATA. The payload rides the same data-attribute rail as design tokens, so it works across every adapter. Over-cap payloads warn and truncate; a sandbox with no static fallback warns (progressive-enhancement reminder). Enables registry-fed visualizations like a 3D sitemap or relationship graph.
  • Hero cover layout + animated sandbox backgrounds (SPEC-101). hero is now a first-class media-position="cover" host: the media well fills the section interior and the headline/blurb/actions overlay it, with the cover knobs (content-place, height, aspect), a band-appropriate height authority (a viewport-relative floor instead of the 3/4 tile default), root padding rerouted to the overlay, and a centred-band overlay default with an even scrim. Any non-img/video media guest now fills a cover well; sandbox gains height="fill" (iframe pinned to 100%, auto-resize negotiation disabled), applied automatically when a sandbox is a cover backdrop — so a live three.js scene drops into a hero as a full-bleed, inert animated background. A non-eager (activation="visible"|"click") sandbox under cover warns at build time (the Run affordance is unreachable on an inert backdrop). Ships with the wireframe-waves showcase (site/examples/wireframe-waves/) — a displaced wireframe terrain whose crests pick up the niwaki palette. Also fixes nested-density title sizing: [data-section="title"] now sizes via --rf-title-size (set per density root), so a full-density rune inside a compact host (a hero in a preview) keeps its real title size. And fixes inverted stacked media labels (BUG-001): hero/feature/step have content-first DOM, so the shared media-first stacked CSS rendered top at the bottom and vice versa — their default is now a truthful bottom (zero visual change for existing content) and explicit top/bottom render where they say.
  • Deferred sandbox activation (WORK-381) — keep heavy sandboxes off the critical path. {% sandbox %} gains activation (eager default | visible | click) and a poster image URL. A non-eager sandbox shows the poster and an explicit Run control in the iframe's place and defers iframe creation and every dependency download until activated — visible mounts on scroll-in (IntersectionObserver), click mounts on user action. Under prefers-reduced-motion a non-eager sandbox never auto-activates: the poster and control stay so motion-sensitive visitors opt in. Eager sandboxes are unchanged (no markup or behaviour regression). The site's 3D star-map sitemap now loads only when scrolled into view.
  • reference list / reference dump are now site-aware (--site <name>) — they resolve a multi-site config's per-site plugins (and runes) instead of only reading the flat single-site shape, so the rune reference for a multi-site project includes its plugin runes, not just core.
  • xref no longer warns on same-destination name collisions. With SPEC-092's typed page entities, a /runes/<x> doc page is registered as both a page and a rune of the same name — an {% xref %} by that name matched both and warned, even though both resolve to the same URL. The resolver now only warns when the candidates' destinations actually diverge.
  • Pages can now register as typed registry entities (SPEC-092 Layers 2 & 3). A page that sets a frontmatter type (and optional id) is registered as that entity type in addition to its page entity, reusing the page's reserved-filtered data; id defaults to the page URL. A new routeRules entity field types a whole section by convention (e.g. { "pattern": "runes/**", "entity": "rune" }) without per-page frontmatter — a page's own type overrides the rule. Duplicate (type, id) registrations warn. This lets collection/aggregate query content by domain type (e.g. collection type="rune"), and it's the complement of entityRoutes (entity → page). Works across all adapters.
  • section rune — a generic page section: the shared eyebrow → headline → blurb (+ image) header above arbitrary body content. Unlike feature/hero/reveal, it doesn't bake in a specific body layout, so it can introduce header-less primitives like bento with a title and intro. Every header slot is optional (body-only renders just the body); align (start|center|end) positions the header while the body spans the section.
  • Page frontmatter is now indexed onto the page entity, so collection and aggregate can filter and group pages by any frontmatter field — tags, author, image, or your own custom fields (e.g. category, status). Routing/render-control keys (layout, tint, tint-mode, tint-lock, slug, redirect) are excluded so they don't pollute queries; the curated fields (title, description, date, order, icon, draft) keep their normalised values. Enables tag-driven page collections and registry-fed catalogues (SPEC-092 Layer 1).
  • data-shape="graph" for data-bound sandboxes (SPEC-093 / WORK-390) — the third payload shape, after flat and tree. A {% sandbox data="type:spec type:work" data-shape="graph" %} projects the queried entities as nodes and walks their SPEC-072 relationship edges into a node-link payload: window.RF_DATA = { shape: "graph", nodes, edges }, where each edge is { from, to, kind }. Only edges whose both endpoints are in the selection are kept, so the graph is closed — ready for a force-directed or node-link layout.
  • Fix the tree shape of a data-bound sandbox: page entity urls carry no trailing slash while parentUrls do, so the nesting never matched and the tree came out flat. Normalize trailing slashes when building the tree so parent↔child relationships resolve.