Telemetry is animated end-to-end with Framer Motion. Every moving element — page transitions, the aurora background, the custom cursor, the nav indicator, orbital rings, and scroll reveals — has explicit, tunable configuration values you can modify directly in the source files. This page documents each animation system and explains how to adjust it.Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/telemetry/llms.txt
Use this file to discover all available pages before exploring further.
Page Transitions
All route changes are managed by Framer Motion’sAnimatePresence component with mode="wait". This setting ensures the outgoing page completes its exit animation before the incoming page starts entering, preventing both pages from being visible simultaneously.
The transition wrapper is applied at the router level in main.js:
opacity— Fades the page in from transparent on enter, out to transparent on exit.y— Slides the page up 20px on enter (starts below, moves to position) and up 20px further on exit (continues moving up and away).filter: 'blur(10px)'— Adds a soft defocus on enter and exit, reinforcing the “tuning in” space-signal metaphor.duration: 0.5— The transition takes 500ms.ease: 'easeOut'— The motion decelerates at the end, giving a settling feel.
duration. To use a slide-only transition without the blur effect, remove the filter property entirely:
Aurora Background Animations
The three aurora blobs inAuroraBackground.js each have an independent Framer Motion keyframe animation. They move in continuous loops on different timings to create an organic, non-repeating flow. All three share a parent <div> with opacity-30 mix-blend-screen filter blur-[100px] — it is these CSS properties, not the Framer Motion values, that produce the luminous glow effect.
Teal blob — positioned top-left (top-[-20%] left-[-10%] w-[70%] h-[60%]):
top-[20%] right-[-20%] w-[60%] h-[80%]):
bottom-[-20%] left-[20%] w-[80%] h-[50%]):
delay values stagger the blobs so they never reach their peak positions at the same time. The keyframe arrays ([start, peak, end]) define the motion path — the animation interpolates from the first value to the second, then back to the third (which matches the first, creating a seamless loop).
To speed up or slow down: Change the duration values. Lower numbers make blobs move faster.
To make blobs travel further: Increase the displacement numbers in the animate arrays — for example, changing x: [0, 100, 0] to x: [0, 200, 0] doubles the horizontal travel distance.
To add a fourth blob: Copy an existing blob element, give it a new position class and color (bg-aurora-magenta, bg-sunset-orange, etc.), and set a unique duration and delay.
The two starfield SVG layers also animate using a CSS keyframe applied as a Tailwind arbitrary value:
- Layer 1:
animate-[aurora-flow_100s_linear_infinite]— slow clockwise scroll - Layer 2:
animate-[aurora-flow_70s_linear_infinite_reverse]— slightly faster, reversed scroll
AuroraBackground.js.
Custom Cursor Animations
The custom cursor inCustomCursor.js replaces the native OS cursor with two layered elements driven by Framer Motion spring physics. The two layers have different spring configs intentionally — the inner dot is tight and responsive while the outer ring lags behind, creating a trailing feel.
Inner dot — w-3 h-3 bg-aurora-cyan rounded-full (tight, snappy):
w-8 h-8 rounded-full border border-aurora-teal/30 (loose, laggy):
stiffness— How quickly the element snaps toward the target. Higher = snappier. Lower = floatier.damping— How much the oscillation is suppressed. Higher = less bounce, faster settle. Lower = more bounce.mass— Simulated weight. Higher = more lag and heavier feel. Lower = quicker response.
isHovering is true when the cursor is over an <a>, <button>, or any element with the interactive class).
To make the cursor feel tighter overall, increase stiffness on both layers and decrease mass. To make it floatier, do the opposite.
Navigation Active Pill
The sliding active-state indicator behind the current nav item inNavigation.js uses Framer Motion’s shared layout animation. The layoutId="nav-pill" prop means Framer Motion automatically animates the element’s position whenever it moves to a different nav item — you only need to render it under the active item and Framer Motion handles the interpolation.
stiffness (e.g., 500).
To make it bouncier: Decrease damping (e.g., 15). Be aware that very low damping causes the pill to overshoot and oscillate noticeably before settling.
To replace the spring with a tween: Change type to 'tween' and add duration: 0.2.
Hero Orbital Rings
The home page hero section displays two concentric orbital rings animated with continuous rotation. Both rings are driven by a simple Framer Motionanimate with repeat: Infinity. The values below are representative examples drawn from the compiled output — consult your source file for the exact numbers:
Outer ring — border-aurora-teal/20 border-t-aurora-cyan/60 (clockwise):
border-aurora-violet/20 border-b-aurora-magenta/60 (counter-clockwise):
ease: 'linear' is critical here — any other easing function would cause the ring to visibly speed up and slow down during each revolution, breaking the illusion of constant orbital motion.
To change orbit speed: Lower the duration value for a faster orbit, raise it for slower. The inner ring is intentionally faster than the outer ring — maintaining this speed difference preserves the visual depth of a real orbital system.
Counter-clockwise rotation: The negative rotate: -360 is what drives the inner ring in the opposite direction. To make both rings rotate the same direction, change the inner ring to rotate: 360.
The Projects page also uses continuous rotation for individual project orbiters, with duration values driven by project data and orbit radius — each project orbits at a different speed to suggest varying distances from a center point.
Scroll Animations
Sections throughout the site use Framer Motion’swhileInView prop to trigger entry animations when elements scroll into the viewport. The viewport={{ once: true }} option means each element only animates on its first scroll-into-view and stays in its final state permanently:
margin: '-100px' triggers the animation when the element is 100px above the viewport edge, giving a slightly early reveal that feels natural when scrolling at normal speed.
To make elements re-animate on every scroll: Remove once: true from the viewport object:
delay, as the About page timeline does (delay: index * 0.1). This creates a cascade where each card enters 100ms after the previous one.