Skip to main content

Documentation Index

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

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

Cosmic Developer layers three animation technologies to create a living, breathing interface: Framer Motion handles complex choreography — page transitions, scroll-linked parallax, spring physics, and continuous orbital rotation; plain CSS keyframes drive the background aurora blobs and the hero heading’s slow pulse; and Tailwind’s transition utilities provide instant, low-overhead hover feedback on every interactive element. Understanding where each layer lives makes it straightforward to tune timings or add new animated elements.

Animation Inventory

AnimationTechnologySource FileDescription
Page transitionsFramer Motion AnimatePresencePageTransition.jsOpacity + scale + blur fade on every route change
Parallax heroFramer Motion useScroll + useTransformHome pageY-translate and opacity driven by scroll progress
Orbital rotationFramer Motion animateProjects pageContinuous 360° linear rotation over 20 s
Planet springFramer Motion springAbout pageSpring-physics rotate when a sector is selected
Entrance animationsFramer Motion whileInViewWork, CaseStudiesSlide-up + fade triggered on scroll into viewport
TeletypeText revealsetInterval / setTimeoutTeletypeText.jsCharacter-by-character text reveal at 50 ms/char
Starfield twinkleCanvas requestAnimationFrameStarfieldBackground.jsStar alpha oscillation + slow drift loop
Aurora glow blobsFramer Motion animateAuroraBackground.jsFour blurred blobs floating with easeInOut loops
animate-pulse-slowCSS @keyframes pulsemain.css4 s opacity pulse on the hero heading
Hover transitionsTailwind transition-colorsButtons, nav links150 ms color transitions on interactive elements

Framer Motion Patterns

Three distinct Framer Motion patterns account for the majority of the animation work. Learning them unlocks the ability to animate any new element in the project.

Pattern 1 — Entrance Animation (whileInView)

Used on Work history cards and CaseStudy items, this pattern reveals elements as the user scrolls them into view. Setting viewport={{ once: true }} ensures each element only animates once — it doesn’t re-animate on scroll-back.
import { motion } from 'framer-motion'

<motion.div
  initial={{ opacity: 0, y: 50 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true }}
  transition={{ delay: index * 0.2 }}
>
  {/* card content */}
</motion.div>
The delay: index * 0.2 stagger means each successive card in a list enters 200 ms after the previous one — giving the grid a cascading reveal effect without a dedicated stagger container.

Pattern 2 — Continuous Rotation (Orbital)

Used for the decorative ring geometry on the Projects page. The repeat: Infinity + ease: 'linear' combination produces a perfectly smooth, uninterrupted rotation.
<motion.div
  animate={{ rotate: 360 }}
  transition={{ duration: 20, repeat: Infinity, ease: 'linear' }}
>
  {/* orbital ring or planet graphic */}
</motion.div>
Adjust duration (in seconds) to speed up or slow down the rotation. A duration of 8 feels fast and mechanical; 40 feels like a slow planetary drift.

Pattern 3 — Scroll-Linked Parallax

Used on the Home page hero. useScroll tracks how far the user has scrolled within a ref element, and useTransform maps that 0–1 progress range to pixel or opacity values.
import { useScroll, useTransform, motion } from 'framer-motion'
import { useRef } from 'react'

const ref = useRef(null)
const { scrollYProgress } = useScroll({
  target: ref,
  offset: ['start start', 'end start'],
})

// Translate 200 px downward as the section scrolls out
const y = useTransform(scrollYProgress, [0, 1], [0, 200])
// Fade out as the section leaves the viewport
const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0])

return (
  <div ref={ref}>
    <motion.div style={{ y, opacity }}>
      {/* hero content */}
    </motion.div>
  </div>
)

Page Transition Wrapper

Every page is wrapped in <PageTransition>, which renders a Framer Motion div with a shared enter/exit config. The transition uses a custom cubic-bezier ease [0.22, 1, 0.36, 1] — an “expo out” curve that feels snappy on entry and decisive on exit.
// components/cosmos/PageTransition.js (decoded from compiled output)
function PageTransition({ children }) {
  return (
    <motion.div
      initial={{ opacity: 0, scale: 0.95, filter: 'blur(10px)' }}
      animate={{ opacity: 1, scale: 1,    filter: 'blur(0px)'  }}
      exit={{    opacity: 0, scale: 1.05, filter: 'blur(10px)' }}
      transition={{ duration: 0.6, ease: [0.22, 1, 0.36, 1] }}
      className="min-h-screen w-full pt-24 pb-20 px-6 md:px-12 lg:px-24 flex flex-col"
    >
      {children}
    </motion.div>
  )
}

Aurora Background Blobs

The AuroraBackground component animates four large blurred circles — one for each aurora color — using independent Framer Motion loops. Each blob translates on X and Y while its scale pulses, creating the slow organic glow visible behind every page.
// components/cosmos/AuroraBackground.js (decoded)
<motion.div
  className="absolute top-[-10%] left-[-10%] w-[60%] h-[60%]
             rounded-full bg-aurora-teal/30 blur-[120px]"
  animate={{
    x: ['0%', '20%', '0%'],
    y: ['0%', '10%', '0%'],
    scale: [1, 1.2, 1],
  }}
  transition={{ duration: 20, repeat: Infinity, ease: 'easeInOut' }}
/>
Each blob has a different duration (18–25 s) and delay (0–5 s) so they never synchronize into a regular pattern. To change the glow color, update the bg-aurora-* class on the relevant blob element.

TeletypeText Component

The TeletypeText component uses a setInterval loop (not Framer Motion) to build up the displayed string one character at a time at 50 ms per character. An optional delay prop (in seconds) defers the start of the animation, allowing multiple TeletypeText instances to sequence one after another.
// Eyebrow label — starts immediately
<TeletypeText text="System Online // Signal Acquired" />

// Sub-label — starts 1.5 s after mount
<TeletypeText text="Loading mission parameters..." delay={1.5} />
The blinking cursor is itself a Framer Motion span that animates opacity between 1 and 0 on a 0.5 s infinite loop, and disappears once typing is complete.

CSS Keyframe Animations

Two animations are defined as CSS @keyframes rather than Framer Motion, both using Tailwind’s utility class surface:
/* Compiled from main.css — standard Tailwind pulse */
.animate-pulse {
  animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

/* Custom slow variant — same keyframe, doubled duration */
.animate-pulse-slow {
  animation: pulse 4s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}

@keyframes pulse {
  50% { opacity: 0.5; }
}
animate-pulse-slow is applied to the hero heading to give it a gentle breathing effect without distracting from readability.

Tailwind Transition Classes

Hover and focus state changes across buttons and navigation links use Tailwind’s transition utilities for zero-JavaScript micro-interactions:
ClassWhat it transitionsDuration
transition-colorscolor, background-color, border-color150 ms (Tailwind default)
transition-transformtransform (scale, translate, rotate)150 ms (Tailwind default)
transition-opacityopacity150 ms (Tailwind default)
transition-allAll animatable properties150 ms (Tailwind default)
duration-300Override to 300 ms
duration-500Override to 500 ms
Combine a transition class with a duration override when the default 150 ms feels abrupt:
<button className="transition-colors duration-300 hover:text-aurora-teal">
  Launch Mission
</button>

Adjusting Animation Speeds

Each animation has a single duration value you can tune:
AnimationFileProperty to change
Page transitioncomponents/cosmos/PageTransition.jstransition.duration (currently 0.6)
Aurora blob — tealcomponents/cosmos/AuroraBackground.jstransition.duration on first motion.div (currently 20)
Aurora blob — magentacomponents/cosmos/AuroraBackground.jstransition.duration on second motion.div (currently 25)
Aurora blob — greencomponents/cosmos/AuroraBackground.jstransition.duration on third motion.div (currently 22)
Aurora blob — violetcomponents/cosmos/AuroraBackground.jstransition.duration on fourth motion.div (currently 18)
Hero pulseassets/main.cssanimation duration in .animate-pulse-slow (currently 4s)
TeletypeText speedcomponents/cosmos/TeletypeText.jssetInterval delay argument (currently 50 ms)

Adding Entrance Animations to New Elements

To animate any new section or card into view, wrap it in a motion.div and apply the whileInView + viewport={{ once: true }} pattern used on the Work and CaseStudies pages:
import { motion } from 'framer-motion'

<motion.div
  initial={{ opacity: 0, y: 50 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true }}
  transition={{ delay: index * 0.2 }}
>
  <YourNewComponent />
</motion.div>
For a staggered list, add delay: index * 0.2 to the transition and map over the array using the item index — matching the 200 ms stagger used on the Work and CaseStudies pages.

Accessibility — Respecting prefers-reduced-motion

The current implementation does not automatically suppress animations for users who have requested reduced motion via their operating system settings. Before deploying to production, wrap Framer Motion animations in a useReducedMotion check or use a global CSS media query to disable transforms and transitions:
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}
For the Canvas-based StarfieldBackground, cancel the requestAnimationFrame loop and render a static frame when window.matchMedia('(prefers-reduced-motion: reduce)').matches returns true.

Build docs developers (and LLMs) love