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.

Framer Motion powers three distinct animation systems in Aurora Cosmos: the slow, dreamy drift of the aurora background layers, the scroll-driven parallax of the starfield, and the shared-layout slide of the active navigation indicator. On top of those, a set of CSS keyframe animations defined in assets/main.css handles per-star twinkling, shooting stars, and the orbiting dot on the nav logo — keeping lightweight effects off the JavaScript thread entirely.

Aurora Background Animations

The AuroraBackground component renders three motion.div layers, each carrying a blurred radial gradient blob. All three use Framer Motion’s animate prop with keyframe arrays so the browser cycles through the values continuously via repeat: Infinity.

Layer 1 — Turquoise › Violet

Gradient: aurora-turquoiseaurora-tealcosmic-violet
  • x: ["-10%", "5%", "-10%"]
  • y: ["-5%", "5%", "-5%"]
  • rotate: [0, 2, 0]
  • duration: 25 s
  • Opacity 40%, blur-[100px]

Layer 2 — Magenta › Teal

Gradient: cosmic-magentacosmic-violetaurora-teal
  • x: ["5%", "-5%", "5%"]
  • y: ["5%", "-5%", "5%"]
  • rotate: [0, -2, 0]
  • duration: 30 s
  • Opacity 30%, blur-[120px]

Layer 3 — Green › Teal

Gradient: aurora-greenaurora-teal → transparent
  • x: ["-5%", "5%", "-5%"]
  • y: ["10%", "0%", "10%"]
  • duration: 20 s
  • Opacity 20%, blur-[90px]
Here is the exact code for Layer 1 as it appears in components/AuroraBackground.js:
<motion.div
  animate={{
    x: ["-10%", "5%", "-10%"],
    y: ["-5%", "5%", "-5%"],
    rotate: [0, 2, 0],
  }}
  transition={{
    duration: 25,
    repeat: Infinity,
    ease: "linear",
  }}
  className="absolute -top-[20%] -left-[10%] w-[120%] h-[60%]
             opacity-40 mix-blend-screen filter blur-[100px]"
>
  <div className="absolute inset-0 bg-gradient-to-r
                  from-aurora-turquoise via-aurora-teal to-cosmic-violet
                  rounded-full transform -rotate-12 scale-y-50" />
</motion.div>

Starfield Parallax

The Starfield component generates three layers of randomly positioned star dots and then moves each layer at a different speed as the user scrolls. This is achieved with Framer Motion’s useScroll() hook combined with useTransform() to map scroll progress to a y translation. Scroll input range [0, 2000] (pixels) maps to these y output ranges:
LayerStar countColorSize rangey output rangeEffect
Layer 1100 starswhite1–2 px[0, -100] pxSlowest — near stars
Layer 250 starsaurora-turquoise2–3 px[0, -250] pxMid-speed
Layer 325 starscosmic-violet3–4 px[0, -500] pxFastest — far stars
The cosmic-violet stars also carry a subtle box-shadow (0 0 10px 2px rgba(139, 92, 246, 0.4)) to simulate depth glow. The useTransform calls from components/Starfield.js:
const { scrollY } = useScroll();

const layer1Y = useTransform(scrollY, [0, 2000], [0, -100]);
const layer2Y = useTransform(scrollY, [0, 2000], [0, -250]);
const layer3Y = useTransform(scrollY, [0, 2000], [0, -500]);
Each value is then bound to a motion.div wrapper via the style prop:
<motion.div style={{ y: layer1Y }} className="absolute inset-0 w-full h-[200%]">
  {stars.layer1.map((star) => (
    <div
      key={`l1-${star.id}`}
      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`,
      }}
    />
  ))}
</motion.div>

CSS Animations

Four keyframe animations are defined directly in assets/main.css and applied via Tailwind utility classes. These run entirely on the CSS compositor thread.

.animate-twinkle

Keyframes: opacity 0.210.2Timing: 4 s, ease-in-out, infiniteApplied to every individual star dot in all three Starfield layers. Each star receives a randomised animation-delay (0–4 s) so the field shimmers naturally rather than pulsing in sync.

.animate-shooting-star

Keyframes: translate(0, 0) rotate(-45deg) at opacity 1translate(-1000px, 1000px) rotate(-45deg) at opacity 0Timing: 3 s, linear, infiniteApplied to the two shooting-star elements in the Starfield component. Each has a different animation-delay (5 s and 12 s) to stagger their crossings.

.animate-orbit

Keyframes: rotate(0deg) translate(100px) rotate(0deg)rotate(360deg) translate(100px) rotate(-360deg)Timing: 20 s, linear, infiniteApplied to the decorative dot on the navigation logo. The transform-origin is set to 0 150px so the dot orbits around the logo at a fixed radius.

.animate-pulse

Keyframes: opacity drops to 0.5 at the 50% markTiming: 2 s, cubic-bezier(0.4, 0, 0.6, 1), infiniteA secondary animation layered on the nav logo dot alongside .animate-orbit, giving it a gentle breathing effect as it orbits.

Active Nav Indicator

The navigation sidebar uses a Framer Motion shared-layout animation to slide a highlight bar between items as the active route changes. A single motion.div carries a layoutId prop — Framer Motion automatically interpolates its position whenever the active link changes, producing the smooth sliding underline effect.
{isActive && (
  <motion.div
    layoutId="activeNav"
    className="absolute left-0 top-0 h-full w-0.5
               bg-aurora-turquoise rounded-r-full"
    transition={{ type: "spring", stiffness: 380, damping: 30 }}
  />
)}
Because layoutId="activeNav" is shared across all nav items, only one instance of this motion.div exists in the DOM at any time — Framer Motion moves it rather than swapping it out.

Tuning Animations

All durations, easing curves, and keyframe values are plain JavaScript literals — change the numbers and the animation updates immediately on the next hot-reload.
// Increase duration to slow each layer
transition={{ duration: 45, repeat: Infinity, ease: "linear" }}
Framer Motion ships a useReducedMotion() hook that returns true when the visitor’s OS has Reduce Motion enabled. Wrap any long-running animation in a conditional to respect this preference:
import { useReducedMotion } from "framer-motion";

function AuroraBackground() {
  const shouldReduce = useReducedMotion();

  return (
    <motion.div
      animate={shouldReduce ? {} : {
        x: ["-10%", "5%", "-10%"],
        y: ["-5%", "5%", "-5%"],
        rotate: [0, 2, 0],
      }}
      transition={shouldReduce ? {} : {
        duration: 25,
        repeat: Infinity,
        ease: "linear",
      }}
    >
      {/* aurora blob */}
    </motion.div>
  );
}
This keeps the page fully usable and accessible for users who experience discomfort from large-scale motion effects, and it aligns with WCAG 2.1 Success Criterion 2.3.3.

Build docs developers (and LLMs) love