Playground
Stars fly toward you in chunky pixels. Every knob is an attribute, so a slider (or the server) can throttle up to warp. Colours come from theme tokens, so the field follows the page's theme.
Examples
Throttle
<div data-signals="{_speed: 20, _warp: false}" style="display: grid; gap: 16px; inline-size: 100%">
<sb-starfield data-attr:speed="$_speed" data-attr:warp="$_warp" data-preserve-attr="speed warp" tint="cyan"></sb-starfield>
<div style="display: flex; gap: 24px; align-items: end; flex-wrap: wrap">
<sb-slider label="Speed" max="100" style="flex: 1; min-inline-size: 12rem" data-bind:_speed__prop.value></sb-slider>
<sb-toggle label="Warp" data-bind:_warp__prop.checked></sb-toggle>
</div>
</div>
Tints
<div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(10rem, 1fr)); gap: 12px; inline-size: 100%">
<sb-starfield tint="white" style="--sb-starfield-height: 6rem"></sb-starfield>
<sb-starfield tint="violet" style="--sb-starfield-height: 6rem"></sb-starfield>
<sb-starfield tint="cyan" style="--sb-starfield-height: 6rem"></sb-starfield>
<sb-starfield tint="green" warp speed="60" style="--sb-starfield-height: 6rem"></sb-starfield>
</div>
Performance
It renders at a third of the CSS resolution into one ImageData. It stops animating offscreen, when speed is 0, or under prefers-reduced-motion, where it shows a single still frame. Set the height with --sb-starfield-height.
Accessibility
It is decorative motion: the canvas is labelled "Animated starfield". Don't rely on it to convey information.
Installation
Add Datastar with Rocket and the Starbase autoloader once per page, then use the tag. The autoloader imports each component the first time its tag appears, including tags added later by a Datastar morph.
<!-- Once per page: Datastar with Rocket, and the Starbase autoloader.
It loads every <sb-…> component the first time its tag appears. -->
<script type="importmap">
{ "imports": { "datastar": "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js" } }
</script>
<script type="module" src="https://starbase.zweiundeins.gmbh/c/autoloader.js"></script>
<!-- Optional, no flash of undefined elements: class="sb-cloak" on <html>, and -->
<style>.sb-cloak :not(:defined) { visibility: hidden }</style>
<sb-starfield speed="35" density="260" tint="violet" warp style="--sb-starfield-height: 7.5rem"></sb-starfield>
<!-- In production, pin today's catalog instead of the latest: the browser then
refuses any file that changed. Add "integrity" to the import map above: the
hashes from https://starbase.zweiundeins.gmbh/c/@0a1ad1bf98a4/importmap.json and Datastar's, below. -->
<!--
<script type="importmap">
{ "imports": { "datastar": "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js" },
"integrity": { "https://cdn.jsdelivr.net/gh/starfederation/datastar@v1.0.4/bundles/datastar-rocket.js": "sha384-vUxZojLrF1Ar3de5h7VINqhJXBgjyZS4U49pHvGa87kum6j5Xn6JRziuARNw5ELG", "…": "…from importmap.json" } }
</script>
<script type="module" src="https://starbase.zweiundeins.gmbh/c/@0a1ad1bf98a4/autoloader.js" integrity="sha384-IvSCUjEWPS+wwXunU+48x96KmyWDx/Y4LeCwCL8cWFqJ/zHmTsTOsSMrzTOcpW3D"></script>
-->
<!-- Or load just this component, pinned to this version: -->
<!-- <script type="module" src="https://starbase.zweiundeins.gmbh/c/starfield@19849f599e6a/starfield.js" integrity="sha384-Wh4yOBUBP5tj96XHr6XmO8UBhOq5OhyBJiuO7AwWWLGwkhwqeqxdz5TpEPakJD1a"></script> -->Size
Each file compressed on its own, the way it is served (gzip -9, brotli -11). Datastar and Rocket are shared by every component and not counted.
| File | Original | gzip | brotli |
|---|---|---|---|
starfield.js | 4.9 kB | 2.1 kB | 1.9 kB |
API reference
Props
| Attribute | Type | Default | Description |
|---|---|---|---|
speed | number | 20 | Flight speed. |
density | number | 300 | Number of stars. |
tint | "white" | "violet" | "cyan" | "green" | "white" | Star colour (from theme tokens). |
warp | boolean | false | Draw streaks instead of dots. |