Skip to content

Commit 117ae0f

Browse files
mldangeloclaude
andcommitted
feat(landing): add interactive delights to website
Adds three new interactive features to the landing page: 1. **Animated Metric Counters** - Numbers count up from 0 when scrolled into view - Smooth easing animation over 1.5 seconds - Uses Intersection Observer for performance 2. **Bubble Pop Game** - Floating bubbles are now clickable - Each pop shows "+1 🦀" score popup - Achievement unlocks at 10 pops: "Bubble Popper Unlocked!" - Adds a subtle gamification layer 3. **Section Transition Crabs** - 3-5 crabs scurry across screen when entering new sections - Creates delightful micro-moments between content - Random speeds and positions for organic feel These features reward exploration and create memorable, shareable moments while maintaining the playful-yet-professional tone. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent c9277a9 commit 117ae0f

1 file changed

Lines changed: 150 additions & 8 deletions

File tree

docs/index.html

Lines changed: 150 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,37 +1247,37 @@ <h3>Persistent Configuration Layer</h3>
12471247
<div class="container">
12481248
<div class="metrics-grid">
12491249
<div class="metric-item">
1250-
<div class="metric-value">94%</div>
1250+
<div class="metric-value" data-target="94" data-suffix="%">0%</div>
12511251
<div class="metric-label">Reduction in Setup Overhead</div>
12521252
</div>
12531253
<div class="metric-item">
1254-
<div class="metric-value">73%</div>
1254+
<div class="metric-value" data-target="73" data-suffix="%">0%</div>
12551255
<div class="metric-label">Less Context Switching</div>
12561256
</div>
12571257
<div class="metric-item">
1258-
<div class="metric-value">2.4x</div>
1258+
<div class="metric-value" data-target="2.4" data-suffix="x" data-decimals="1">0x</div>
12591259
<div class="metric-label">Sprint Velocity Multiplier</div>
12601260
</div>
12611261
<div class="metric-item">
1262-
<div class="metric-value">37%</div>
1262+
<div class="metric-value" data-target="37" data-suffix="%">0%</div>
12631263
<div class="metric-label">Faster Headcount Scaling</div>
12641264
</div>
12651265
</div>
12661266
<div class="metrics-grid" style="margin-top: 2rem; padding-top: 2rem; border-top: 1px solid var(--border-subtle);">
12671267
<div class="metric-item">
1268-
<div class="metric-value">147</div>
1268+
<div class="metric-value" data-target="147" data-suffix="">0</div>
12691269
<div class="metric-label">Eng Hours Saved/Quarter</div>
12701270
</div>
12711271
<div class="metric-item">
1272-
<div class="metric-value">89%</div>
1272+
<div class="metric-value" data-target="89" data-suffix="%">0%</div>
12731273
<div class="metric-label">Fewer Config Incidents</div>
12741274
</div>
12751275
<div class="metric-item">
1276-
<div class="metric-value">$2.3M</div>
1276+
<div class="metric-value" data-target="2.3" data-prefix="$" data-suffix="M" data-decimals="1">$0M</div>
12771277
<div class="metric-label">Annual Productivity Gains*</div>
12781278
</div>
12791279
<div class="metric-item">
1280-
<div class="metric-value">4.9</div>
1280+
<div class="metric-value" data-target="4.9" data-suffix="" data-decimals="1">0</div>
12811281
<div class="metric-label">Engineer Satisfaction (NPS)</div>
12821282
</div>
12831283
</div>
@@ -1641,6 +1641,148 @@ <h3>Stakeholder Communications</h3>
16411641
};
16421642
document.addEventListener('mousemove', window.__crabMouseMoveHandler);
16431643
}
1644+
1645+
// ANIMATED METRIC COUNTERS - count up when scrolled into view
1646+
const metricObserver = new IntersectionObserver((entries) => {
1647+
entries.forEach(entry => {
1648+
if (entry.isIntersecting && !entry.target.dataset.animated) {
1649+
entry.target.dataset.animated = 'true';
1650+
const target = parseFloat(entry.target.dataset.target);
1651+
const decimals = parseInt(entry.target.dataset.decimals) || 0;
1652+
const prefix = entry.target.dataset.prefix || '';
1653+
const suffix = entry.target.dataset.suffix || '';
1654+
const duration = 1500;
1655+
const startTime = performance.now();
1656+
1657+
const animate = (currentTime) => {
1658+
const elapsed = currentTime - startTime;
1659+
const progress = Math.min(elapsed / duration, 1);
1660+
// Ease out cubic
1661+
const eased = 1 - Math.pow(1 - progress, 3);
1662+
const current = target * eased;
1663+
entry.target.textContent = prefix + current.toFixed(decimals) + suffix;
1664+
if (progress < 1) {
1665+
requestAnimationFrame(animate);
1666+
}
1667+
};
1668+
requestAnimationFrame(animate);
1669+
}
1670+
});
1671+
}, { threshold: 0.5 });
1672+
1673+
document.querySelectorAll('.metric-value[data-target]').forEach(el => {
1674+
metricObserver.observe(el);
1675+
});
1676+
1677+
// BUBBLE POP - click floating bubbles to pop them
1678+
let bubbleScore = 0;
1679+
document.addEventListener('click', (e) => {
1680+
if (e.target.classList.contains('bubble')) {
1681+
e.target.style.animation = 'none';
1682+
e.target.style.transform = 'scale(1.5)';
1683+
e.target.style.opacity = '0';
1684+
e.target.style.transition = 'all 0.2s ease-out';
1685+
bubbleScore++;
1686+
1687+
// Show score popup
1688+
const popup = document.createElement('div');
1689+
popup.textContent = '+1 🦀';
1690+
popup.style.cssText = `
1691+
position: fixed;
1692+
left: ${e.clientX}px;
1693+
top: ${e.clientY}px;
1694+
color: var(--crab-coral);
1695+
font-size: 1rem;
1696+
font-weight: bold;
1697+
pointer-events: none;
1698+
z-index: 9999;
1699+
animation: pop-score 0.8s ease-out forwards;
1700+
`;
1701+
document.body.appendChild(popup);
1702+
setTimeout(() => popup.remove(), 800);
1703+
1704+
// Achievement at 10
1705+
if (bubbleScore === 10) {
1706+
const achievement = document.createElement('div');
1707+
achievement.innerHTML = '🦀 Bubble Popper Unlocked! 🦀';
1708+
achievement.style.cssText = `
1709+
position: fixed;
1710+
top: 20%;
1711+
left: 50%;
1712+
transform: translateX(-50%);
1713+
background: var(--crab-shell);
1714+
color: white;
1715+
padding: 1rem 2rem;
1716+
border-radius: 8px;
1717+
font-weight: bold;
1718+
z-index: 10000;
1719+
animation: achievement-pop 2s ease-out forwards;
1720+
`;
1721+
document.body.appendChild(achievement);
1722+
setTimeout(() => achievement.remove(), 2000);
1723+
}
1724+
1725+
setTimeout(() => e.target.remove(), 200);
1726+
}
1727+
});
1728+
1729+
// Make bubbles clickable
1730+
const style = document.createElement('style');
1731+
style.textContent = `
1732+
.bubble { pointer-events: auto !important; cursor: pointer; }
1733+
.bubble:hover { transform: scale(1.2); }
1734+
@keyframes pop-score {
1735+
0% { transform: translateY(0) scale(1); opacity: 1; }
1736+
100% { transform: translateY(-50px) scale(1.5); opacity: 0; }
1737+
}
1738+
@keyframes achievement-pop {
1739+
0% { transform: translateX(-50%) scale(0); opacity: 0; }
1740+
20% { transform: translateX(-50%) scale(1.1); opacity: 1; }
1741+
30% { transform: translateX(-50%) scale(1); }
1742+
80% { transform: translateX(-50%) scale(1); opacity: 1; }
1743+
100% { transform: translateX(-50%) scale(0.8); opacity: 0; }
1744+
}
1745+
@keyframes scurry {
1746+
0% { left: -30px; transform: scaleX(1); }
1747+
100% { left: calc(100vw + 30px); transform: scaleX(1); }
1748+
}
1749+
.scurry-crab {
1750+
position: fixed;
1751+
font-size: 1rem;
1752+
z-index: 999;
1753+
pointer-events: none;
1754+
animation: scurry 1.5s linear forwards;
1755+
}
1756+
`;
1757+
document.head.appendChild(style);
1758+
1759+
// SECTION TRANSITION CRABS - crabs scurry across when entering new sections
1760+
let lastSection = null;
1761+
const sectionObserver = new IntersectionObserver((entries) => {
1762+
entries.forEach(entry => {
1763+
if (entry.isIntersecting && entry.target !== lastSection) {
1764+
lastSection = entry.target;
1765+
// Spawn 3-5 scurrying crabs
1766+
const numCrabs = Math.floor(Math.random() * 3) + 3;
1767+
for (let i = 0; i < numCrabs; i++) {
1768+
setTimeout(() => {
1769+
const crab = document.createElement('div');
1770+
crab.className = 'scurry-crab';
1771+
crab.textContent = '🦀';
1772+
crab.style.top = (entry.target.offsetTop - 20 + Math.random() * 40) + 'px';
1773+
crab.style.animationDuration = (1 + Math.random() * 0.5) + 's';
1774+
document.body.appendChild(crab);
1775+
setTimeout(() => crab.remove(), 2000);
1776+
}, i * 150);
1777+
}
1778+
}
1779+
});
1780+
}, { threshold: 0.3 });
1781+
1782+
// Observe major sections
1783+
document.querySelectorAll('.bento-section, .metrics-section, .layout-section, .manifesto, .commands-section').forEach(section => {
1784+
sectionObserver.observe(section);
1785+
});
16441786
</script>
16451787
</body>
16461788
</html>

0 commit comments

Comments
 (0)