Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/aurora-cosmos/llms.txt

Use this file to discover all available pages before exploring further.

Starfield places 175 procedurally-generated stars across three independent parallax layers that respond to page scroll, creating a sense of deep three-dimensional space. Stars in the foreground move faster than those far away, reinforcing the cosmic depth illusion established by AuroraBackground. Two hardcoded shooting stars cross the viewport on independent timers to add life without adding scroll weight.

Star Layers

Stars are generated once on mount and divided into three layers. Each layer moves at a different speed as the user scrolls, simulating parallax depth. All stars carry the animate-twinkle class and a random animationDelay between 0 and 4 seconds so they never all pulse together.
LayerCountColourSizeRendered opacityParallax (scrollY 0 → 2000)
1100White (#ffffff)1 – 2 pxstar.opacity (0.20 – 1.00)y: 0 → -100px
250Aurora Turquoise (#5eead4)2 – 3 pxstar.opacity × 0.8 (0.16 – 0.80)y: 0 → -250px
325Cosmic Violet (#8b5cf6)3 – 4 pxstar.opacity × 0.6 (0.12 – 0.60)y: 0 → -500px
Every star is a rounded-full div whose left, top, width, height, and opacity are computed at runtime from Math.random(). Layer 3 stars additionally carry a box-shadow glow (0 0 10px 2px rgba(139, 92, 246, 0.4)) that gives them a soft violet halo.

Twinkling

Each star receives the Tailwind utility animate-twinkle, which cycles opacity between 0.2 → 1 → 0.2 over a 4-second ease-in-out infinite loop. An inline animationDelay ranging from 0 to 4 seconds is applied to each star individually so the field sparkles asynchronously rather than pulsing in unison.
// Star generation helper (runs once inside useEffect)
const generateStars = (count, minSize, maxSize) =>
  Array.from({ length: count }).map((_, id) => ({
    id,
    x:       Math.random() * 100,            // % across viewport width
    y:       Math.random() * 100,            // % across double-height container
    size:    Math.random() * (maxSize - minSize) + minSize,
    opacity: Math.random() * 0.8 + 0.2,     // base: 0.20 – 1.00
    // Layer 2 renders at opacity × 0.8; Layer 3 renders at opacity × 0.6
  }));
// Rendered star (Layer 1 example)
<div
  className="absolute bg-white rounded-full animate-twinkle"
  style={{
    left:           `${star.x}%`,
    top:            `${star.y}%`,
    width:          `${star.size}px`,
    height:         `${star.size}px`,
    opacity:         star.opacity,
    animationDelay: `${Math.random() * 4}s`,
  }}
/>

Shooting Stars

Two shooting stars are hard-coded inside the component. They use the .animate-shooting-star utility (3-second linear infinite loop, travelling diagonally at −45°) with long delays so they appear infrequently.
StarColourPositionDelay
1Whitetop: 20%, left: 80%5 s
2Aurora Turquoise (#5eead4)top: 40%, left: 60%12 s
Each shooting star is a 1 × 1 px rounded-full head with an absolutely-positioned gradient tail extending to its right:
{/* White shooting star */}
<div
  className="absolute top-[20%] left-[80%] w-1 h-1 bg-white rounded-full
             shadow-[0_0_10px_2px_white] animate-shooting-star"
  style={{ animationDelay: "5s" }}
>
  <div className="absolute top-1/2 right-0 w-20 h-[1px]
                  bg-gradient-to-r from-transparent to-white
                  transform -translate-y-1/2" />
</div>

{/* Aurora turquoise shooting star */}
<div
  className="absolute top-[40%] left-[60%] w-1 h-1 bg-aurora-turquoise rounded-full
             shadow-[0_0_10px_2px_#5eead4] animate-shooting-star"
  style={{ animationDelay: "12s" }}
>
  <div className="absolute top-1/2 right-0 w-32 h-[1px]
                  bg-gradient-to-r from-transparent to-aurora-turquoise
                  transform -translate-y-1/2" />
</div>

Parallax Implementation

Starfield uses Framer Motion’s useScroll to track scrollY, then useTransform to map that value to three independent Y offsets — one per star layer. Each layer’s motion.div wrapper receives the derived MotionValue directly via its style prop.
import { useScroll, useTransform } from "framer-motion";

// Track document scroll position
const { scrollY } = useScroll();

// Map scrollY 0→2000 to layer Y translations
const layer1Y = useTransform(scrollY, [0, 2000], [0, -100]);
const layer2Y = useTransform(scrollY, [0, 2000], [0, -250]);
const layer3Y = useTransform(scrollY, [0, 2000], [0, -500]);

// Apply to each layer wrapper
<motion.div style={{ y: layer1Y }} className="absolute inset-0 w-full h-[200%]">
  {stars.layer1.map(star => <div key={`l1-${star.id}`} ... />)}
</motion.div>

<motion.div style={{ y: layer2Y }} className="absolute inset-0 w-full h-[200%]">
  {stars.layer2.map(star => <div key={`l2-${star.id}`} ... />)}
</motion.div>

<motion.div style={{ y: layer3Y }} className="absolute inset-0 w-full h-[200%]">
  {stars.layer3.map(star => <div key={`l3-${star.id}`} ... />)}
</motion.div>
Each layer container is h-[200%] so there are always stars above the initial viewport — the parallax shift simply reveals them rather than creating empty space.
Stars are generated exactly once: inside a useEffect with an empty dependency array []. The result is stored in useState and never recalculated during scrolling. Framer Motion’s MotionValue system updates the CSS transform of each layer wrapper directly in the browser’s compositor thread — React never re-renders the star divs on scroll. This keeps the scroll path completely off the React render cycle and ensures smooth 60 fps parallax even with 175 star elements in the DOM.

No props

Starfield accepts no props. All layer counts, colour assignments, size ranges, parallax distances, and shooting-star positions are defined internally. Like AuroraBackground, it is a self-contained global layout element that renders itself autonomously when mounted.

Build docs developers (and LLMs) love