Most side projects die in the details. Mine almost did too — but fixing one janky animation taught me what "craft" actually means in product work.
Here's what happened.
I'm building SkillForge — a learning roadmap generator. You type any skill, it generates a 5-7 phase curriculum with real YouTube links and tasks baked in. Phases unlock sequentially as you complete them.
The core UI is a zig-zag timeline with a dot that tracks your progress.
Simple idea. Brutal to execute.
Problem 1: The rigid dot
The dot tracked the vertical center of each phase card. When a user expanded a card to check off tasks, the card height changed, the center point shifted, and the dot jumped. Rigidly. Visibly. It looked broken.
Fix: I stopped tracking card centers entirely. I queried the DOM coordinates of the horizontal dash connector between phases instead. The dot now targets that fixed point regardless of what the card does beneath it.
Problem 2: Choppy animation during state changes
I was using CSS transitions. When a user expanded a task card while the dot was mid-movement, the transition stuttered. It looked cheap.
Fix: I stripped out CSS transitions completely and built a custom requestAnimationFrame loop with spring physics. Stiffness and damping applied to velocity. The dot now glides to its target and dynamically adjusts mid-flight if the UI shifts beneath it.
The code looks like this:
function animateDot() {
const dx = targetX - currentX;
const dy = targetY - currentY;
velocityX += dx * stiffness;
velocityY += dy * stiffness;
velocityX *= damping;
velocityY *= damping;
currentX += velocityX;
currentY += velocityY;
dot.style.left = currentX + 'px';
dot.style.top = currentY + 'px';
requestAnimationFrame(animateDot);
}
Nobody consciously notices this detail. But they feel it. That's the whole point.
Problem 3: The AI kept hallucinating timelines
I'm using Groq (Llama 4) to generate the roadmaps. It kept outputting "Week 1-3" for every single phase, or "Ongoing" for everything. Destroys the sequential feel.
Fix: Strict prompt constraints. "If Phase 1 is Week 1-3, Phase 2 MUST start Week 4. Never repeat a timeframe. Never use Ongoing." Force JSON output. Validate the structure before rendering.
Prompt engineering is just product thinking applied to language.
Problem 4: Exposed API key
First version had the Groq key sitting in frontend JavaScript. Obvious mistake in hindsight. I spun up a lightweight Node/Express proxy on Render to inject the key server-side. Users never touch it.
What I actually learned
Shipping a product is completely different from writing code.
Getting the AI to return data was easy. Getting it to return reliable, sequential, structured data was a product problem. Making a div move was easy. Making it move in a way that feels alive was a craft problem.
The difference between a demo and a product is a hundred small decisions that nobody asked for but everybody feels.
SkillForge is live if you want to try it: skillforge-cfcn.onrender.com
No account. No setup. Just type a skill and go.
What's the most painful UI detail you've ever had to fix?
Top comments (0)