Documentation Index
Fetch the complete documentation index at: https://mintlify.com/apursley2012/spooky-developer/llms.txt
Use this file to discover all available pages before exploring further.
The Skills page reimagines a standard tech-stack list as a bowl of Halloween candy. Every skill is a candy-shaped pill with two side nubs — a classic wrapped-sweet silhouette — color-coded by category. Hovering a candy makes it float dramatically out of the bowl with a Framer Motion spring animation, and a tooltip above it unwraps to show the skill name. The visual metaphor extends all the way to the bowl label: “Take One”, rendered in a large faded spooky font.
Skill Categories
Three categories are defined in the SKILLS constant array in assets/main.js. Each category has a Tailwind background-color class and a list of four skill names.
const SKILLS = [
{ name: 'Languages', color: 'bg-purple-500', skills: ['JavaScript', 'TypeScript', 'Python', 'HTML/CSS'] },
{ name: 'Frameworks', color: 'bg-haunt-pumpkin', skills: ['React', 'Next.js', 'Node.js', 'Tailwind'] },
{ name: 'Tools', color: 'bg-haunt-moon', skills: ['Git', 'Docker', 'AWS', 'Figma'] },
];
| Category | Tailwind Color | Skills |
|---|
| Languages | bg-purple-500 | JavaScript, TypeScript, Python, HTML/CSS |
| Frameworks | bg-haunt-pumpkin | React, Next.js, Node.js, Tailwind |
| Tools | bg-haunt-moon | Git, Docker, AWS, Figma |
A color-coded legend appears below the bowl, mapping each dot to its category name.
Candy Shape
Each skill is rendered as a <div> with a main pill body and two absolute-positioned side nubs that mimic the twisted ends of a wrapped candy:
<div className={`w-16 h-10 ${category.color} rounded-full
flex items-center justify-center shadow-lg relative`}>
{/* Left nub */}
<div className={`absolute -left-3 w-4 h-6 ${category.color} rounded-l-full opacity-80`}
style={{ clipPath: 'polygon(100% 0, 0 20%, 0 80%, 100% 100%)' }} />
{/* Right nub */}
<div className={`absolute -right-3 w-4 h-6 ${category.color} rounded-r-full opacity-80`}
style={{ clipPath: 'polygon(0 0, 100% 20%, 100% 80%, 0 100%)' }} />
</div>
w-16 h-10 rounded-full — the main wrapped body.
- The
clipPath polygons angle the nubs inward so they taper like twisted wrapper ends.
- The
color class from the parent category object is applied to both the body and the nubs, keeping them consistent.
Hover Float Animation
Each candy is wrapped in a Framer Motion <motion.div> with whileHover configured to shoot the candy upward:
initial: { y: 0 }
whileHover: { y: -50, scale: 1.2, zIndex: 50 }
onHoverStart and onHoverEnd update a shared hoveredSkill state string, which drives the tooltip’s Framer Motion animate prop:
<motion.div
className="relative cursor-pointer group"
initial={{ y: 0 }}
whileHover={{ y: -50, scale: 1.2, zIndex: 50 }}
onHoverStart={() => setHoveredSkill(skillName)}
onHoverEnd={() => setHoveredSkill(null)}
>
{/* Tooltip */}
<motion.div
className="absolute -top-12 bg-haunt-bg border border-haunt-moon
text-haunt-moon px-3 py-1 rounded text-sm font-bold
whitespace-nowrap pointer-events-none"
initial={{ opacity: 0, y: 10 }}
animate={{
opacity: hoveredSkill === skillName ? 1 : 0,
y: hoveredSkill === skillName ? 0 : 10,
}}
>
{skillName}
</motion.div>
<CandyShape color={category.color} />
</motion.div>
The tooltip is positioned with absolute -top-12 so it appears above the candy as it floats up.
The Bowl Graphic
The bowl is built from three layered <div> elements inside a relative container:
{/* Shadow/depth layer behind the bowl */}
<div className="absolute bottom-0 left-1/2 -translate-x-1/2
w-3/4 h-48 bg-haunt-dark rounded-b-full border-b-8
border-haunt-tombstoneDark opacity-50" />
{/* Candy layout area */}
<div className="absolute bottom-10 left-1/2 -translate-x-1/2
w-2/3 h-48 flex flex-wrap justify-center
content-end gap-2 p-4 z-10">
{/* All candy elements rendered here */}
</div>
{/* Foreground bowl rim (frosted glass) */}
<div className="absolute bottom-0 left-1/2 -translate-x-1/2
w-3/4 h-48 bg-haunt-tombstone/30 backdrop-blur-md
rounded-b-full border-b-8 border-x-4
border-haunt-tombstoneDark z-20
flex items-end justify-center pb-8">
<span className="font-spooky text-3xl text-haunt-moon opacity-50">Take One</span>
</div>
The foreground bowl layer uses z-20 so it visually contains the candies, which sit on z-10. The backdrop-blur-md gives the bowl a frosted-glass look.
Adding Skills
Add a skill to an existing category
Find the matching object in the SKILLS array and append the new skill name to its skills array:{ name: 'Languages', color: 'bg-purple-500', skills: ['JavaScript', 'TypeScript', 'Python', 'HTML/CSS', 'Rust'] },
The new candy will appear in the bowl automatically with the category’s color. Add a new category
Append a new object to the SKILLS array:const SKILLS = [
// … existing categories …
{
name: 'Databases',
color: 'bg-emerald-500',
skills: ['PostgreSQL', 'MongoDB', 'Redis', 'SQLite'],
},
];
Then add a matching entry to the legend section at the bottom of the component so visitors know what the new color represents.
When choosing a color for a new category, pick any Tailwind background class (bg-sky-400, bg-rose-500, bg-emerald-600, etc.). The same class string is applied to the candy body, both nubs, and the legend dot, so a single well-chosen color keeps the whole candy visually cohesive.