Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/apursley2012/dev.void/llms.txt

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

The AsteroidQuotes component renders a section of three testimonial cards whose irregular, asteroid-like silhouettes and perpetual floating animation reinforce the space theme running through dev.void. Each card drifts gently up and down while rocking back and forth, entering the viewport with a smooth fade-in on first scroll into view.

Testimonial Data Shape

Testimonials are stored in a plain array called o inside AsteroidQuotes.js. Every entry follows this shape:
{
  id: number,       // Unique React key
  text: string,     // The testimonial body (no surrounding quotes needed — added by JSX)
  author: string,   // Attributed name / title
  role: string,     // Job title and company, displayed in aurora-pink mono text
  delay: number,    // Animation delay in seconds (staggers cards across the grid)
  yOffset: number   // Starting vertical offset in pixels for the float cycle
}
The three built-in entries are:
idauthorroledelayyOffset
1Cmdr. Sarah JenkinsVP of Engineering, Stellar Dynamics0 s20 px
2Dr. Marcus VanceLead Designer, Nebula Corp2 s−30 px
3Elena RostovaProduct Manager, Void Tech4 s10 px
Staggering delay values by ~2 s per card (0, 2, 4) prevents all three cards from moving in sync, creating a naturalistic, independent drift effect across the row.

Asteroid / Blob Border Radius

Each card’s container <div> receives an inline style property that overrides the default rectangular border radius with a CSS organic blob shape:
style={{ borderRadius: "30% 70% 70% 30% / 30% 30% 70% 70%" }}
This CSS border-radius shorthand uses the horizontal / vertical slash syntax. The eight values (four horizontal radii, then four vertical radii at each corner) produce the asymmetric, asteroid-like silhouette. The base container also carries bg-space-900/80 backdrop-blur-sm border border-slate-700 p-8 shadow-xl for its dark, frosted-glass appearance.
The blob shape is applied to the inner content div, not the outer Framer Motion div. This keeps the Framer Motion wrapper a plain transparent element so its whileInView and animate props are unaffected by the unusual border geometry.

Continuous Float + Rotate Animation

Each card runs two independent continuous animations simultaneously via Framer Motion’s animate prop, both looping infinitely:

Vertical Float

animate: {
  y: [yOffset, yOffset - 15, yOffset]  // e.g. [20, 5, 20] for card 1
},
transition: {
  y: { duration: 6, repeat: Infinity, ease: "easeInOut", delay: delay }
}
The card oscillates over a 15 px range anchored to its yOffset baseline. A six-second cycle keeps the motion perceptible but unhurried.

Subtle Rotation

animate: {
  rotate: [-1, 1, -1]   // ±1 degree rock
},
transition: {
  rotate: { duration: 8, repeat: Infinity, ease: "easeInOut", delay: delay }
}
The slower eight-second rotation cycle is intentionally out of phase with the float, so the combined result feels organic rather than mechanical.

Viewport Entry

On first scroll into view each card fades up from below:
initial: { opacity: 0, y: 50 },
whileInView: { opacity: 1, y: 0 },
viewport: { once: true }
once: true means the entry animation fires exactly once and is not replayed on subsequent scrolls. After entry, the continuous animate float takes over.

Card Anatomy

Quote Icon

A Lucide Quote icon (w-8 h-8 text-aurora-teal/40) sits at the top of each card, visually anchoring the testimonial before the body text.

Body Text

Rendered in font-serif italic text-lg text-slate-300 leading-relaxed. Surrounding double-quote characters are injected by JSX — do not include them in the text field.

Author Name

Displayed in font-sans font-bold text-slate-200 below a border-t border-slate-800 divider.

Role / Company

Rendered in font-mono text-[10px] text-aurora-pink uppercase tracking-widest — the tiny all-caps mono style matches the terminal aesthetic of the rest of the portfolio.

Layout

The section uses a CSS grid that stacks to a single column on small screens and expands to three equal columns on md and above:
<div className="max-w-6xl mx-auto w-full grid grid-cols-1 md:grid-cols-3 gap-8 relative z-10">
The wrapping <section> is min-h-[70vh] with overflow-hidden to contain the floating cards without causing scroll artifacts.

Adding or Editing Testimonials

1

Open the source file

Navigate to components/AsteroidQuotes.js and locate the o array near the top of the file.
2

Append a new object

Add a new entry to the array following the data shape above. Choose a delay that keeps the stagger pattern — increment by ~2 s per new card. Pick a yOffset between −40 and 40 to vary the float baseline.
{
  id: 4,
  text: "The deployment pipeline they built cut our release time in half.",
  author: "J. Torres",
  role: "DevOps Lead, Orbit Systems",
  delay: 6,
  yOffset: -15
}
3

Update the grid columns

If you add a fourth card, change md:grid-cols-3 to md:grid-cols-2 lg:grid-cols-4 (or any layout that suits the new count) so cards do not stretch awkwardly.
4

Verify the animation

Run the dev server and scroll to the testimonials section. Confirm the new card floats independently and does not move in lockstep with its neighbours. Adjust delay if the motion feels too synchronised.
Avoid setting two cards to the same delay value. Identical delays cause cards to float and rotate in perfect sync, which looks unnatural and undermines the asteroid-field illusion.

Build docs developers (and LLMs) love