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.

Beyond swapping out the persona strings, v-doom’s content system is built around simple JavaScript arrays — you can add new project cards, reorder experience entries, append skill ingredients, and change the contact form behaviour without touching any component logic.

Adding a Project Card

Projects are stored in a plain array near the top of assets/main.js. Each element is an object with five fields:
// Project object shape
{
  title: "Your Project Title",
  subtitle: "Project Type / Category",
  description: "What it does and why it matters.",
  ingredients: ["React", "TypeScript", "Tailwind"],
  link: "https://github.com/you/your-project"
}
To add a new card, locate the const R = [ array (search for Grimoire.js to find it), then append your object before the closing ]:
// assets/main.js — append to the projects array
const R = [
  // ...existing entries...
  {
    title: "Phantom Router",
    subtitle: "Edge Middleware",
    description: "Zero-latency request routing at the edge. Handles geo-routing, A/B flags, and auth redirects without cold-start penalty.",
    ingredients: ["Cloudflare Workers", "TypeScript", "Hono"],
    link: "https://github.com/you/phantom-router"
  },
];
Cards are rendered as tarot-card components with a hover-to-reveal interaction. The ingredients array maps to pill badges on the card face — keep the list to 3–4 items for the best layout.
Set link to "#" to render the card without a clickable link. The card still shows the hover animation; the anchor element simply scrolls to the top of the page.

Adding a Skill Ingredient

Skills are stored in const y = [ in assets/main.js (search for React Essence to find it). Each entry drives one ingredient button on the Cauldron page and the animated potency bar beneath the cauldron:
// Skill object shape
{
  id: "vue",
  name: "Vue Essence",
  color: "#42B883",
  level: 70
}
FieldTypeDescription
idstringUnique React key — short, no spaces
namestringDisplayed on the button and the cauldron label
colorstringHex color for the bubble glow, indicator dot, and potency bar
levelnumber0100; controls the filled width of the potency bar
Append your new skill object to the array:
// assets/main.js — append to the skills array
const y = [
  { id: "react",  name: "React Essence",    color: "#61DAFB", level: 90 },
  { id: "ts",     name: "TypeScript Root",  color: "#3178C6", level: 85 },
  { id: "css",    name: "Tailwind Extract", color: "#38B2AC", level: 95 },
  { id: "node",   name: "Node.js Spores",   color: "#339933", level: 75 },
  { id: "motion", name: "Framer Dust",      color: "#FF0055", level: 80 },
  // ↓ new entry
  { id: "vue",    name: "Vue Essence",      color: "#42B883", level: 70 },
];
The ingredient grid on the Cauldron page uses a grid-cols-2 md:grid-cols-3 layout, so the grid naturally wraps at six or more items. Any number of entries is supported.

Adding an Experience Entry

Experience entries are stored in const O = [ in assets/main.js (search for Senior Spellcrafter to find it). Each entry renders as a sealed card on the Pacts page (/experience):
// Experience entry shape
{
  id: 4,
  role: "Your Title",
  company: "Company Name",
  period: "2023 - Present",
  description: "What you did and the impact you had."
}
The id field is used as the React key and as the seal-broken state identifier. When a user clicks the wax seal, the component checks t.includes(entry.id) to decide whether to show the broken or intact seal state — so id must be a unique integer.
1

Find the array

Search for Apprentice Developer in assets/main.js to locate the last entry in the array.
2

Append your entry

Add a new object after the final } inside the array, before the closing ]. Set id to the next sequential integer (e.g. 4 if there are currently three entries).
3

Reorder if needed

The timeline renders entries in array order. Place the most recent role first (at the top of the array) if you want reverse-chronological order — just keep the id values unique, they don’t need to match visual order.
The wax-seal interaction works as follows: the seal starts as a circular red badge stamped with the letter V. Clicking triggers a Framer Motion split animation — the two halves fly off — and the card expands to full height, fading in the role description with a 0.3 s delay.

Modifying the Contact Form

The Summoning page (/contact) renders a circular orb form. The form submit handler in assets/main.js works like this:
// assets/main.js — form submit handler (simplified)
const n = (s) => {
  s.preventDefault();
  if (!t.trim()) return;       // t = textarea value state

  r("casting");                // set status → "casting" (shows "Casting..." button)
  setTimeout(() => {
    r("sent");                 // after 2 s → "sent" (shows "Message Received")
    i("");                     // clear textarea
    setTimeout(() => r("idle"), 3000);  // after 3 more s → reset to "idle"
  }, 2000);
};
The contact form is purely cosmetic by default. It does not send any email or POST request — the 2-second “Casting…” state is a visual animation only. To make it functional you need to integrate a third-party form backend.
To wire up real submission, replace the setTimeout block with an async call to your chosen service:
const n = async (s) => {
  s.preventDefault();
  if (!t.trim()) return;

  r("casting");
  try {
    await fetch("https://formspree.io/f/YOUR_FORM_ID", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ message: t }),
    });
    r("sent");
    i("");
    setTimeout(() => r("idle"), 3000);
  } catch {
    r("idle"); // reset on error
  }
};
The contact orb’s “Message Received” confirmation text and the “The spirits will deliver it shortly.” subline are hard-coded strings in the JSX. Search for Message Received in assets/main.js to locate and update them.

Changing Navigation Labels

Nav labels are defined in the navLinks array inside components/Navigation.js. The array also controls the route each label links to:
// components/Navigation.js — navLinks array
const Tp = [
  { path: "/",           label: "The Circle"  },
  { path: "/about",      label: "Practitioner" },
  { path: "/projects",   label: "Spells Cast"  },
  { path: "/skills",     label: "Cauldron"     },
  { path: "/experience", label: "Pacts"        },
  { path: "/contact",    label: "Summoning"    },
];
Replace any label string to rename that nav item. The active-state amber indicator dot and the uppercase tracking-widest styling are applied automatically by the NavLink component — no further changes are needed. If you also change a path value (e.g. renaming /skills to /stack), update the corresponding React Router <Route path="..."> definition at the bottom of assets/main.js to match, otherwise the route will 404.
The logo in the top-left (V. DOOM) is rendered separately from the navLinks array — it’s a NavLink pointing to "/" hardcoded in the Navigation component. Search for V. DOOM in components/Navigation.js to update the logo text.

Build docs developers (and LLMs) love