Stars Background
Three night-sky layers you stack behind hero content: `StarsBackground`, a canvas of density-seeded twinkling stars; `ShootingStars`, one SVG streak at a time; and `Meteors`, CSS-animated tails falling at a fixed 215°.
Preview
Rendered from the story the storybook (a11y) CI gate runs axe against — the preview can't show something that hasn't been verified.
Install
Two equivalent paths — the URL works in any shadcn-CLI setup; the alias works once you've registered @interlace in your components.json.
npx shadcn@latest add https://ds.interlace.tools/r/stars-background.jsonnpx shadcn@latest add @interlace/stars-backgroundHistory
This component is at v1.1.0, first shipped in @interlace/ui 1.0.0. The version is stamped as a banner into the file the install writes, so the copy in your tree says which one you have — compare it with the number above before deciding whether to re-run the install.
@interlace/ui 1.1.02 entries
- Changedpatch
Six defects found by upgrading a real consumer, plus five found by reading the components closely enough to document them. **
Meteors' glow never painted.** It readvar(--color-meteor-glow)while itscssVarsdeclare--meteor-glow;--color-*is the Tailwind@themenamespace and onlycssVars.themepopulates it, so the wholebox-shadowwas invalid at computed-value time. **This was broken only for registry consumers** — our own docs site hand-declares the--color-form. **ArticleCardcropped 28% off every cover.**h-44is 176px; at a ~302px tile that is a 1.72:1 box against a 2.381:1 image. Nowaspect-[1000/420]— the ratio the card already declared on its<img>. It also gains arenderImageslot, because every Next.js consumer was re-patching the same line to usenext/imageand the design system cannot depend on it. **BorderBeamandStarsBackgroundhad noaria-hiddenat all** — six purely decorative nodes a screen reader walked. **CloudParticlesdefaultedbodyColortocurrentColor**, painting volumetric clouds in the inherited text colour. **NumberTickergainsnotation**, because six-figure metrics overflow a tile at 320px. Also:SheetComposeandDialogComposeeach mounted a second backdrop, so a composed dialog dimmed the page twice as much as the hand-composed tree the docs show;AccordiondroppedclassNameon the animated Panel;Tooltipaccepteddelayand discarded it;PopoverAnchorwas a second trigger. **useReducedMotionwas one frame late.** The canonicaluseState(false)plus effect returnsfalseon the first render, so every gated component painted one frame of exactly the motion the user turned off.useSyncExternalStorereads during render and closes that on client renders; on hydration the server cannot know the preference, which is what the stylesheet reset is for.Badgedrops'use client'— verified with a real server-component build. - Changedpatch
The three entry animations in
styles/theme.cssnow run at 200ms with no delay, and the reduced-motion class list instyles/tokens.csscovers.animate-pulse..animate-fade-in-upwas 0.5s,.animate-slide-in-left0.5s behind a 0.3s delay, and.animate-scale-in0.4s behind a 0.2s delay — up to 800ms before the reader saw anything, against the 200ms entry ceilingMOTION_PHILOSOPHY.mdhas always set. All three are now0.2s ease-out both. The delays were the worse half: an entry animation is already laid out atopacity: 0, so a delay is time spent looking at nothing. Separately,.animate-pulse— the animationSkeletonrenders on every loading state — was missing from thetokens.cssreduced-motion list, along with.animate-meteorand.animate-meteor-effect. The universal clamp instyles/preflight.csswas already covering all three, so apps importingstyles/index.csswere never affected; apps that importtokens.cssandtheme.cssà la carte and skippreflight.csswere. All three are now listed. Both are held bypackages/ui/__tests__/motion-contract-lock.test.ts, which reads the ceiling out ofMOTION_PHILOSOPHY.mdrather than repeating it, and fails if any bareanimate-*utility inpackages/ui/srcis missing from the list.
Import
3 named exports — pull the parts you need.
import { Meteors, ShootingStars, StarsBackground } from '@/components/ui/aceternity/stars-background';Anatomy
Extracted from the primitive's JSDoc header. The source is the only documentation that can't drift.
StarsBackground (canvas — 2D context, resized by a
ResizeObserver, repainted per rAF frame)
ShootingStars (svg > rect + linearGradient#gradient)
Meteors (div > injected <style> + span ×number)API reference
Parsed from the type declarations in the source — the same file the install writes into your tree, so this table can't drift from the component you get.
StarProps
| Prop | Type | Description |
|---|---|---|
| x* | number | — |
| y* | number | — |
| radius* | number | — |
| opacity* | number | — |
| twinkleSpeed* | number | null | — |
StarBackgroundProps
| Prop | Type | Description |
|---|---|---|
| starDensity | number | — |
| allStarsTwinkle | boolean | — |
| twinkleProbability | number | — |
| minTwinkleSpeed | number | — |
| maxTwinkleSpeed | number | — |
| className | string | — |
ShootingStarProps
| Prop | Type | Description |
|---|---|---|
| minSpeed | number | — |
| maxSpeed | number | — |
| minDelay | number | — |
| maxDelay | number | — |
| starColor | string | — |
| trailColor | string | — |
| starWidth | number | — |
| starHeight | number | — |
| className | string | — |
MeteorsProps
| Prop | Type | Description |
|---|---|---|
| number | number | Number of meteors to display |
| minDuration | number | Minimum animation duration in seconds |
| maxDuration | number | Maximum animation duration in seconds |
| meteorColor | string | Meteor color — the bright head of the streak. |
| trailColor | string | Colour the tail fades OUT to, at the far end of the 120px streak. Defaults to `"transparent"`, which is the streak's natural falloff; pass a colour to have the tail land on it instead (e.g. a dim brand tint over a dark hero). |
| className | string | Additional CSS classes |
Accessibility
Every story for this component is rendered headlessly and checked with axe-core (wcag2aa, wcag22aa, best-practice, ACT) on every PR. That gate has no continue-on-error, so what ships has zero known violations.
What follows is what static analysis can see. Axe cannot press a key and never sees an overlay open, so the operable-without-a-mouse claim lives in Behavior instead, where the keyboard path is replayed step by step.
- Focus + keyboard behaviour
- Native element semantics — no interaction layer to get wrong.
- Focus ring (WCAG 2.2 SC 2.4.13)
- Not focusable — no focus indicator required.
- Reduced motion
- Animation is gated on prefers-reduced-motion.
- ARIA in the source
aria-hidden
Examples
3 more states from the same story file.
Dependencies
- Base UI primitive
- Native / no Base UI dependency
- Lucide icons
- none
- NPM dependencies
- none
- Registry dependencies
Source
The full implementation — components/ui/aceternity/stars-background.tsx once installed.
"use client";
import { cn } from "@/lib/utils";
// @interlace/stars-background v1.1.0 — Interlace design system.
// Docs, props and live preview: https://ds.interlace.tools/c/stars-background
// What changed since: https://ds.interlace.tools/c/stars-background#history
// Generated banner — keep it, the upgrade diff reads this version.
/**
* @interlace/ui — StarsBackground, ShootingStars, Meteors
*
* Three night-sky layers you stack behind hero content: `StarsBackground`, a
* canvas of density-seeded twinkling stars; `ShootingStars`, one SVG streak at
* a time; and `Meteors`, CSS-animated tails falling at a fixed 215°.
*
* All three are `absolute inset-0` overlays and are meant to be composed —
* `patterns/hero-cosmic.tsx` renders all three at once.
*
* Our reimplementation of the Aceternity UI starfield family. What is ours:
…579 more lines…Registry JSON
The raw registry record — what the shadcn CLI fetches.