Skip to main content

Documentation Index

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

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

SkillConstellation is the centrepiece of the /skills page. It visualises eight technology skills as floating circular nodes inside a fixed-height SVG container, connected by lines that represent relationships between tools. Hovering over any node illuminates its edges in cyan and reveals a personal tooltip — a group label and a short, flavour-text story — giving the graph both technical structure and personality.

Skill Node Data

Each node in the constellation is defined by an object in the l array:
const l = [
  { id: "js",    label: "JavaScript",  group: "Languages",      x: 20, y: 20, story: "We have a love-hate relationship, mostly love." },
  { id: "ts",    label: "TypeScript",  group: "Languages",      x: 35, y: 15, story: "The strict parent that keeps my code in line." },
  { id: "react", label: "React",       group: "Front of House", x: 25, y: 40, story: "My primary spellcasting focus." },
  { id: "css",   label: "Tailwind",    group: "Front of House", x: 10, y: 35, story: "Making things pretty without leaving the HTML." },
  { id: "node",  label: "Node.js",     group: "Back of House",  x: 60, y: 25, story: "JavaScript, but in the dark." },
  { id: "sql",   label: "PostgreSQL",  group: "Back of House",  x: 75, y: 30, story: "Organizing the chaos into neat little tables." },
  { id: "debug", label: "Debugging",   group: "Detective Work", x: 50, y: 60, story: "Staring at the screen until the bug reveals itself." },
  { id: "git",   label: "Git",         group: "Paperwork",      x: 80, y: 60, story: "Time travel, but with more merge conflicts." },
]
FieldTypeDescription
idstringUnique identifier used to match edges
labelstringDisplay name shown below the node dot
groupstringCategory shown in the tooltip header
xnumberHorizontal position as a percentage of container width
ynumberVertical position as a percentage of container height
storystringFlavour text shown in the hover tooltip body

Edge Connections

Edges are defined in the x array as [sourceId, targetId] pairs. SVG <line> elements are drawn between the percentage positions of the two referenced nodes.
const x = [
  ["js", "ts"],
  ["js", "react"],
  ["react", "css"],
  ["js", "node"],
  ["node", "sql"],
  ["debug", "js"],
  ["git", "node"],
]
Edges are directional only in the data — the rendered lines are visually identical in both directions. The graph reads as an undirected network.

Hover Interaction

The component tracks a single hoveredId string in React state (initialised to null). Hovering a node sets hoveredId to that node’s id; hover-end resets it to null. Node dot — the 16 × 16 px circle changes appearance based on whether its id matches hoveredId:
StateBackgroundBorderBox shadow
Defaultbg-voidborder-electric-purpleNone
Hoveredbg-cyanborder-cyan0 0 15px var(--cyan)
SVG lines — each line checks whether either of its endpoint IDs equals hoveredId:
StateStrokestrokeWidthstrokeOpacity
Defaultvar(--electric-purple)10.2
Activevar(--cyan)20.8
All line transitions are smoothed with className="transition-all duration-300". Framer Motion scale — each node wrapper is a motion.div with whileHover={{ scale: 1.2 }}, providing a subtle grow on cursor entry.

Tooltip

The tooltip is a motion.div positioned absolutely below the node dot. It animates between hidden and visible using initial/animate:
// Tooltip motion values
initial: { opacity: 0, y: 10 }
animate: {
  opacity: hoveredId === node.id ? 1 : 0,
  y:       hoveredId === node.id ? 0 : 10,
}
Tooltip layout (innermost to outer):
  1. Group labeltext-cyan text-[10px] uppercase mb-1
  2. Story texttext-slate-300 text-xs max-w-[200px] whitespace-normal
  3. Containerpx-3 py-2 bg-void border border-cyan/50 rounded shadow-lg

Container Classes

<div class="relative w-full h-[500px] bg-deep-void/30
            border border-electric-purple/20 rounded-xl
            overflow-hidden mb-24">
The overflow-hidden clip prevents tooltips near the edges from breaking the card boundary. The mb-24 bottom margin separates the constellation from the Cauldron section rendered below it on the skills page.

Color Tokens Used

TokenUsage
--deep-voidContainer background (30% opacity)
--electric-purpleDefault edge stroke, node border, container border
--cyanHovered edge stroke, active node fill/border/glow, tooltip border
--voidDefault node fill, tooltip background

Page Composition

On the /skills route, SkillConstellation is rendered inside ut() directly before Cauldron:
// Skills page (main.js → ut())
<motion.h1 className="font-display text-5xl md:text-7xl text-magenta ...">
  Skill Constellation
</motion.h1>
<p className="font-mono text-slate-400">Languages I Speak (to Computers)...</p>

<SkillConstellation />   {/* SVG graph */}
<Cauldron />             {/* Drag-and-drop brew below */}
Because node positions are expressed as percentages, the constellation scales gracefully to any container width. Resize the viewport and the entire graph reflows without any JavaScript resize logic.

Build docs developers (and LLMs) love