Skip to main content

Documentation Index

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

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

The About page is one of the most technically expressive pages in v-doom. A split layout pairs a 3D-perspective portrait that physically responds to your cursor with a character-by-character typewriter bio that feels as if the text is being inscribed in real time. Once the bio finishes typing, an affinities and bane grid fades into view.

What’s on This Page

The page is divided into two columns (stacked on mobile, side-by-side on lg+): Left Column — 3D Portrait Card A card with perspective-1000 and preserve-3d applied (w-64 h-80 md:w-80 md:h-96). It listens to mousemove events on the window and translates the cursor’s position into a normalized -1 to 1 range:
// Mouse tracking normalization
state.x = (clientX / window.innerWidth)  * 2 - 1;  // -1 (left)  → 1 (right)
state.y = (clientY / window.innerHeight) * 2 - 1;  // -1 (top)   → 1 (bottom)
These values are multiplied by 10 to produce rotateY and rotateX values in degrees, so the card tilts up to ±10° in any direction as the mouse moves. The spring physics use stiffness: 75, damping: 15. Inside the card is an inline SVG portrait made up of:
ElementDescription
Animated violet pathBody outline that morphs between two d path values on a looping spring
Head outlineStatic bone-colored path forming the head/shoulders silhouette
Amber pulsing dotSmall r-5 amber circle at (100, 110) with a CSS animate-pulse glow
Dashed orbit ringr-40 amber dashed circle that rotates continuously at constant speed (20s per revolution)
Right Column — Typewriter Bio The bio text is revealed one character at a time. A random delay of 20–70 ms is applied between each character to simulate natural, uneven typing rhythm (Math.random() * 50 + 20). While typing is in progress:
  • An amber block cursor blinks at the end of the revealed text using a Framer Motion animate: { opacity: [1, 0] } loop (not CSS keyframes).
  • A feather-pen icon (lucide-react) floats near the active typing position — it is visible during typing and disappears once the bio is complete.
The full bio string:
I am a digital practitioner specializing in the arcane arts of frontend
engineering. I bind chaotic data into structured, beautiful forms. My rituals
involve strict typing, component isolation, and obsessive performance tuning.
I do not write code; I cast intentions into the machine.
Affinities & Bane Grid Once the bio is fully revealed, a grid fades in (opacity: 0 → 1, duration: 1s) displaying two columns:
Affinities                 Bane
─────────────────────────────────────────────
React & Next.js            Internet Explorer
TypeScript                 Un-typed JavaScript
WebGL / Three.js           Scope Creep
Framer Motion

Key Interactions

  • Mouse-tracked 3D tilt — Every mousemove event updates the card’s rotateX and rotateY transform. The card smoothly interpolates using Framer Motion spring (stiffness: 75, damping: 15) so fast mouse movements don’t snap.
  • Typewriter reveal — Each character schedules the next with setTimeout, using Math.random() * 50 + 20 ms. There is no way to skip ahead — the reveal always runs at its natural pace.
  • Blinking cursor — A motion.span styled as a solid amber block (w-2 h-5 bg-amber) blinks via a Framer Motion animate={{ opacity: [1, 0] }} loop while the bio is not yet complete. The cursor is always rendered but becomes invisible once typing finishes (the bio is done when charCount === bio.length).
  • Floating pen — A motion.div wrapping the feather-pen icon is rendered while typing is in progress (charCount < bio.length). It loops a jittery x/y/rotate oscillation to simulate the pen inscribing the text.
  • Fade-in grid — The affinities/bane section uses initial={{ opacity: 0 }}animate={{ opacity: charCount === bio.length ? 1 : 0 }} with a 1 s ease transition.

Customizing

Updating the bio text: Locate the bio string in the About page component and replace it in full. Do not split it into an array — the typewriter effect iterates over bio.split('').
// src/pages/About.jsx
const bio = `I am a digital practitioner specializing in the arcane arts of
frontend engineering. I bind chaotic data into structured, beautiful
forms. My rituals involve strict typing, component isolation, and
obsessive performance tuning. I do not write code; I cast intentions
into the machine.`;
Updating affinities and bane:
// src/pages/About.jsx
const affinities = [
  'React & Next.js',
  'TypeScript',
  'WebGL / Three.js',
  'Framer Motion',
];

const bane = [
  'Internet Explorer',
  'Un-typed JavaScript',
  'Scope Creep',
];
Adjusting the typing speed:
// Faster: reduce the random range
const delay = Math.random() * 20 + 10;  // 10–30 ms

// Slower / more dramatic:
const delay = Math.random() * 100 + 40; // 40–140 ms
The mouse-tracking effect only runs on devices with a pointer (desktop/laptop). On touch devices the card renders in its neutral position without tilt. No fallback animation is needed — the SVG portrait is visually complete without the 3D effect.
To replace the SVG portrait with a real photo, swap the <svg> element inside the portrait card with an <img> tag and add object-fit: cover with the same border and glow classes. The 3D tilt logic on the parent div will still work without any changes.

Build docs developers (and LLMs) love