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
| Animation | Technology | Source File | Description |
|---|
| Page transitions | Framer Motion AnimatePresence | PageTransition.js | Opacity + scale + blur fade on every route change |
| Parallax hero | Framer Motion useScroll + useTransform | Home page | Y-translate and opacity driven by scroll progress |
| Orbital rotation | Framer Motion animate | Projects page | Continuous 360° linear rotation over 20 s |
| Planet spring | Framer Motion spring | About page | Spring-physics rotate when a sector is selected |
| Entrance animations | Framer Motion whileInView | Work, CaseStudies | Slide-up + fade triggered on scroll into viewport |
| TeletypeText reveal | setInterval / setTimeout | TeletypeText.js | Character-by-character text reveal at 50 ms/char |
| Starfield twinkle | Canvas requestAnimationFrame | StarfieldBackground.js | Star alpha oscillation + slow drift loop |
| Aurora glow blobs | Framer Motion animate | AuroraBackground.js | Four blurred blobs floating with easeInOut loops |
animate-pulse-slow | CSS @keyframes pulse | main.css | 4 s opacity pulse on the hero heading |
| Hover transitions | Tailwind transition-colors | Buttons, nav links | 150 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:
| Class | What it transitions | Duration |
|---|
transition-colors | color, background-color, border-color | 150 ms (Tailwind default) |
transition-transform | transform (scale, translate, rotate) | 150 ms (Tailwind default) |
transition-opacity | opacity | 150 ms (Tailwind default) |
transition-all | All animatable properties | 150 ms (Tailwind default) |
duration-300 | Override to 300 ms | — |
duration-500 | Override 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:
| Animation | File | Property to change |
|---|
| Page transition | components/cosmos/PageTransition.js | transition.duration (currently 0.6) |
| Aurora blob — teal | components/cosmos/AuroraBackground.js | transition.duration on first motion.div (currently 20) |
| Aurora blob — magenta | components/cosmos/AuroraBackground.js | transition.duration on second motion.div (currently 25) |
| Aurora blob — green | components/cosmos/AuroraBackground.js | transition.duration on third motion.div (currently 22) |
| Aurora blob — violet | components/cosmos/AuroraBackground.js | transition.duration on fourth motion.div (currently 18) |
| Hero pulse | assets/main.css | animation duration in .animate-pulse-slow (currently 4s) |
| TeletypeText speed | components/cosmos/TeletypeText.js | setInterval 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.