Widgets
Embeddable widgets. One loader. One line.
Each Hatched widget is a Shadow-DOM-isolated Preact component that hydrates from a shared store. Drop a div, pass a token, the right widget renders. Theming via CSS variables, no iframe, no rebuild.

What ships with this
14 production widgets
Buddy, marketplace, badges, streak, path, tokens, leaderboard, kudos, group quest, feed, mystery box, league, council, and the Hexad survey — every surface is a drop-in mount.
Shadow DOM isolation
No style leak in or out. The host app and the widget never fight over the cascade.
Shared workspace store
Every widget reads the same authoritative state. A coin spent in marketplace updates the buddy widget instantly.
Theme via CSS variables
Override `--hw-color-primary`, `--hw-radius`, etc. from the host. No rebuild, no SDK swap.
Smart-poll + BroadcastChannel
ETag-backed long-poll with visibility pause; cross-tab state sync via per-token channel.
A11y baked in
Every widget ships with keyboard nav, ARIA roles, prefers-reduced-motion fallbacks, and contrast-tested defaults.
Localised at the edge
i18n strings live on the widget. Tenants override per-locale from the dashboard.

One loader, one div per widget
Load the runtime once with a single token, then pick each surface with `data-hatched-mount`. The token on that one script covers every mount on the page — a server-minted `data-session-token` powers write-capable widgets (and read-only ones too). For a display-only page, swap it for a `data-embed-token`.
<!-- Load the runtime ONCE with a single token, before your mount points.
The loader reads its config from this one script; the token here powers
every mount below. Write-capable widgets need a session token. -->
<script src="https://cdn.hatched.live/widget.js" data-session-token="SESSION_TOKEN" defer></script>
<!-- One div per widget — they all share the loader token above. -->
<div data-hatched-mount="buddy"></div>
<div data-hatched-mount="leaderboard"></div>
<div data-hatched-mount="league"></div>
<div data-hatched-mount="marketplace"></div>
<!-- Display-only page? Swap the one script for a read-only embed token:
<script src="https://cdn.hatched.live/widget.js" data-embed-token="EMBED_TOKEN" defer></script> -->