Skip to main content

Documentation Index

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

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

The Skills page abandons the conventional progress-bar or tag-cloud approach in favour of an interactive constellation map. Every skill is a glowing star dot positioned inside a glass-morphism panel; three animated SVG path lines connect related skills the way constellation lines connect stars in a star chart. Hovering any dot reveals the skill name and its magnitude — a scaled score that reflects proficiency — making capability immediately readable at a glance without a single percentage label.

Visual Overview

The entire skills display lives inside a single full-width glass-panel div. Three layers render inside it, back to front:
LayerElementPurpose
Constellation lines<svg> with three <path> strokesConnect related skills with animated dim lines
Star dotsFramer Motion <motion.div> elementsRepresent individual skills; size scales with magnitude
Hover labels<motion.div> tooltipsAppear below the hovered dot with name + magnitude score
A TeletypeText line — “Calibrating instruments… Array optimal.” — leads the section above the panel.

Skills Data

All skill positions and scores are defined in the ht array in the ft component:
const skills = [
  { name: 'React',         x: 20, y: 30, magnitude: 0.9,  category: 'frontend' },
  { name: 'TypeScript',    x: 40, y: 20, magnitude: 0.85, category: 'frontend' },
  { name: 'Tailwind',      x: 30, y: 50, magnitude: 0.8,  category: 'frontend' },
  { name: 'Framer Motion', x: 50, y: 45, magnitude: 0.75, category: 'frontend' },
  { name: 'Node.js',       x: 70, y: 30, magnitude: 0.7,  category: 'backend'  },
  { name: 'PostgreSQL',    x: 80, y: 50, magnitude: 0.65, category: 'backend'  },
  { name: 'Figma',         x: 25, y: 70, magnitude: 0.8,  category: 'design'   },
  { name: 'UI/UX',         x: 45, y: 75, magnitude: 0.85, category: 'design'   },
  { name: 'WebGL',         x: 65, y: 65, magnitude: 0.5,  category: 'creative' },
]

Skill Properties Reference

PropertyTypeDescription
namestringDisplayed in the hover tooltip
xnumber (%)Horizontal position as a percentage of the panel width
ynumber (%)Vertical position as a percentage of the panel height
magnitudenumber (0–1)Proficiency score; drives dot scale and tooltip display
categorystringGroups skills by color; one of frontend, backend, design, creative

Skills by Category

CategorySkillsAccent Color
frontendReact, TypeScript, Tailwind, Framer Motionaurora-teal
backendNode.js, PostgreSQLaurora-magenta
designFigma, UI/UXaurora-violet
creativeWebGLaurora-green

Dot Size Formula

Each skill dot is a <div> with base classes w-4 h-4 (16 px square, border-radius: 50%). Its rendered size is further scaled by an inline CSS transform:
// For each skill dot:
<div
  className={`relative -ml-2 -mt-2 rounded-full bg-star-white
              shadow-[0_0_15px_#7af0a8] transition-all duration-300
              ${hoveredSkill === skill.name ? 'w-6 h-6 bg-aurora-green' : 'w-4 h-4'}`}
  style={{ transform: `scale(${skill.magnitude * 1.5})` }}
/>
The magnitude * 1.5 scale multiplier means a skill at 0.9 renders at 1.35× the base size, while WebGL at 0.5 renders at 0.75×. On hover the dot switches from w-4 h-4 to w-6 h-6 and changes color to bg-aurora-green for a clear active state.

Constellation Line Paths

Three SVG <path> elements are rendered in an <svg> positioned to fill the panel. All paths use stroke="#7af0a8", strokeWidth="1", and fill="none", and each animates its pathLength from 0 to 1 on mount using Framer Motion:
<svg className="absolute inset-0 w-full h-full pointer-events-none opacity-20">
  {/* Frontend cluster */}
  <motion.path
    d="M 20% 30% L 40% 20% L 50% 45% L 30% 50% Z"
    stroke="#7af0a8" strokeWidth="1" fill="none"
    initial={{ pathLength: 0 }}
    animate={{ pathLength: 1 }}
    transition={{ duration: 2, ease: 'easeInOut' }}
  />
  {/* Backend + creative cluster */}
  <motion.path
    d="M 50% 45% L 70% 30% L 80% 50% L 65% 65%"
    stroke="#7af0a8" strokeWidth="1" fill="none"
    initial={{ pathLength: 0 }}
    animate={{ pathLength: 1 }}
    transition={{ duration: 2, delay: 0.5, ease: 'easeInOut' }}
  />
  {/* Design + creative cluster */}
  <motion.path
    d="M 30% 50% L 25% 70% L 45% 75% L 65% 65%"
    stroke="#7af0a8" strokeWidth="1" fill="none"
    initial={{ pathLength: 0 }}
    animate={{ pathLength: 1 }}
    transition={{ duration: 2, delay: 1, ease: 'easeInOut' }}
  />
</svg>
The three paths draw in sequence (delays of 0 s, 0.5 s, and 1 s) so the constellation “wires up” progressively as the page loads. The SVG is rendered at low opacity (opacity-20) so the dots remain the primary visual element.

Hover Interaction

Each skill dot is wrapped in a <motion.div> with onHoverStart / onHoverEnd handlers that set the hoveredSkill state. When a skill is hovered:
  1. The dot switches from w-4 h-4 to w-6 h-6 and changes to bg-aurora-green.
  2. A tooltip <motion.div> fades in (opacity: 0 → 1) positioned below the dot.
  3. The tooltip shows the skill name and the magnitude formatted as Mag: (value * 10).toFixed(1) (so 0.9 displays as Mag: 9.0).
<motion.div
  className="absolute interactive"
  style={{ left: `${skill.x}%`, top: `${skill.y}%` }}
  onHoverStart={() => setHoveredSkill(skill.name)}
  onHoverEnd={() => setHoveredSkill(null)}
>
  {/* Dot */}
  <div
    className={`relative -ml-2 -mt-2 rounded-full bg-star-white
                shadow-[0_0_15px_#7af0a8] transition-all duration-300
                ${hoveredSkill === skill.name ? 'w-6 h-6 bg-aurora-green' : 'w-4 h-4'}`}
    style={{ transform: `scale(${skill.magnitude * 1.5})` }}
  />

  {/* Tooltip */}
  <AnimatePresence>
    {hoveredSkill === skill.name && (
      <motion.div
        initial={{ opacity: 0, y: 10 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0 }}
        className="absolute top-6 left-1/2 -translate-x-1/2 whitespace-nowrap pointer-events-none"
      >
        <div className="glass-panel px-3 py-1 text-sm font-mono flex flex-col items-center">
          <span className="text-aurora-green font-bold">{skill.name}</span>
          <span className="text-xs text-star-dim mt-1">
            Mag: {(skill.magnitude * 10).toFixed(1)}
          </span>
        </div>
      </motion.div>
    )}
  </AnimatePresence>
</motion.div>

TeletypeText Configuration

<TeletypeText
  text="Calibrating instruments... Array optimal."
  className="text-aurora-green font-mono text-sm"
/>

Customization

  1. Add a skill — Append a new object to the skills array. Choose x/y values (percentages) that place it near related skills without overlapping existing dots, set magnitude (0–1), and assign a category.
  2. Remove a skill — Delete the entry from skills. Also update any SVG <path> d attributes that connected to that skill’s position to avoid orphaned line segments.
  3. Change skill positions — Update x and y values to rearrange the constellation. Since values are percentages, the layout adapts to any panel size automatically.
  4. Adjust magnitude scores — Update the magnitude value for any skill. Dot size and tooltip readout update automatically.
  5. Add a new category — Add a new category string to a skill and extend the category-to-color lookup in the component with a matching Tailwind color token.
  6. Edit constellation lines — Update the d attribute on one of the three <path> elements to change which skill coordinates are connected. Use the x% / y% values from the skills array as your coordinate source.
  7. Change dot scale factor — To make all dots larger across the board, increase the 1.5 multiplier in skill.magnitude * 1.5. To create a wider visual spread between high- and low-proficiency skills, increase it further (e.g., 2.5).
When placing new skills, aim to keep related skills within roughly 20–30 percentage-point proximity on both axes. Constellation lines longer than ~40% of the panel width become visually disconnected and can confuse the grouping hierarchy.
All coordinates are expressed as percentages of the glass panel’s bounding box, so the constellation map is fully responsive — it reflows correctly when the panel resizes between breakpoints. Avoid using fixed-pixel x/y values if you extend this component, as they would break the responsive layout.

Build docs developers (and LLMs) love