Skip to content

Instantly share code, notes, and snippets.

@vdavid
Created March 27, 2026 12:01
Show Gist options
  • Select an option

  • Save vdavid/0f7e7ee63e382ffe55a7a59419219b7e to your computer and use it in GitHub Desktop.

Select an option

Save vdavid/0f7e7ee63e382ffe55a7a59419219b7e to your computer and use it in GitHub Desktop.
Cmdr 3D shape gallery — 30 interactive SVG shapes with hover animations
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cmdr 3D shape gallery</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #14130f;
color: #fafafa;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
min-height: 100vh;
padding: 40px 20px;
}
h1 {
text-align: center;
font-size: 28px;
font-weight: 600;
margin-bottom: 8px;
color: #ffc206;
}
.subtitle {
text-align: center;
color: #a1a1aa;
font-size: 14px;
margin-bottom: 48px;
}
/* ── Feature section ── */
.feature-group {
max-width: 1400px;
margin: 0 auto 48px;
}
.feature-header {
margin-bottom: 20px;
padding-left: 4px;
}
.feature-title {
font-size: 20px;
font-weight: 600;
color: #ffc206;
margin-bottom: 4px;
}
.feature-desc {
font-size: 14px;
color: #a1a1aa;
}
.variant-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 24px;
}
@media (max-width: 900px) {
.variant-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 600px) {
.variant-grid { grid-template-columns: 1fr; }
}
/* ── Gallery section ── */
.divider {
max-width: 1400px;
margin: 64px auto 48px;
text-align: center;
position: relative;
}
.divider::before {
content: '';
position: absolute;
top: 50%;
left: 0;
right: 0;
height: 1px;
background: #2e2d2a;
}
.divider span {
position: relative;
background: #14130f;
padding: 0 16px;
color: #7a5210;
font-size: 12px;
font-weight: 600;
letter-spacing: 0.1em;
text-transform: uppercase;
}
.gallery-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 32px;
max-width: 1400px;
margin: 0 auto;
}
/* ── Shared card styles ── */
.card {
background: #1a1917;
border: 1px solid #2e2d2a;
border-radius: 16px;
padding: 24px;
display: flex;
flex-direction: column;
align-items: center;
transition: border-color 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
border-color: #d49422;
box-shadow: 0 0 30px rgba(255, 194, 6, 0.3);
}
.card svg {
width: 100%;
max-width: 280px;
height: auto;
}
.card-info {
margin-top: 16px;
text-align: center;
}
.card-name {
font-size: 15px;
font-weight: 600;
color: #ffc206;
margin-bottom: 4px;
}
.card-desc {
font-size: 13px;
color: #a1a1aa;
line-height: 1.5;
}
.card-anim {
display: inline-block;
margin-top: 8px;
font-size: 11px;
color: #7a5210;
background: rgba(255, 194, 6, 0.08);
border: 1px solid rgba(255, 194, 6, 0.15);
border-radius: 100px;
padding: 2px 10px;
font-family: 'SF Mono', 'Fira Code', monospace;
}
</style>
</head>
<body>
<h1>Cmdr 3D shape gallery</h1>
<p class="subtitle">Hover each shape to see its animation. 30 shapes generated with scripts/3d-shapes/.</p>
<!-- Feature illustrations: 3 variants per feature -->
<div class="feature-group">
<div class="feature-header">
<h2 class="feature-title">Live full-disk index</h2>
<p class="feature-desc">Indexes your entire drive once in about 4 minutes. Then stays current forever.</p>
</div>
<div class="variant-grid">
<div class="card">
<svg id="shape-index-—-stacked-discs" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="251.86,165.26 191.99,177.39 191.99,190.56 251.86,178.42" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="191.99,177.39 140.13,158.60 140.13,171.77 191.99,190.56" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="249.26,184.50 192.39,196.03 192.39,209.19 249.26,197.67" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="192.39,196.03 143.12,178.18 143.12,191.34 192.39,209.19" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="246.67,203.75 192.79,214.67 192.79,227.83 246.67,216.91" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="192.79,214.67 146.12,197.76 146.12,210.92 192.79,227.83" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="259.87,134.33 251.86,165.26 251.86,178.42 259.87,147.50" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="244.08,222.99 193.19,233.31 193.19,246.47 244.08,236.16" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="259.87,134.33 251.86,165.26 191.99,177.39 140.13,158.60 148.14,127.68 208.01,115.54" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="193.19,233.31 149.11,217.34 149.11,230.50 193.19,246.47" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="208.01,128.71 148.14,140.84 140.13,171.77 191.99,190.56 251.86,178.42 259.87,147.50" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="256.88,155.12 249.26,184.50 249.26,197.67 256.88,168.29" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="140.13,158.60 148.14,127.68 148.14,140.84 140.13,171.77" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="256.88,155.12 249.26,184.50 192.39,196.03 143.12,178.18 150.74,148.80 207.61,137.27" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="241.48,242.24 193.59,251.95 193.59,265.11 241.48,255.40" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="193.59,251.95 152.10,236.91 152.10,250.08 193.59,265.11" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="207.61,150.44 150.74,161.97 143.12,191.34 192.39,209.19 249.26,197.67 256.88,168.29" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="253.88,175.91 246.67,203.75 246.67,216.91 253.88,189.08" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="143.12,178.18 150.74,148.80 150.74,161.97 143.12,191.34" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="253.88,175.91 246.67,203.75 192.79,214.67 146.12,197.76 153.33,169.93 207.21,159.00" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="207.21,172.17 153.33,183.09 146.12,210.92 192.79,227.83 246.67,216.91 253.88,189.08" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="146.12,197.76 153.33,169.93 153.33,183.09 146.12,210.92" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="250.89,196.71 244.08,222.99 244.08,236.16 250.89,209.87" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="250.89,196.71 244.08,222.99 193.19,233.31 149.11,217.34 155.92,191.05 206.81,180.73" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="206.81,193.90 155.92,204.21 149.11,230.50 193.19,246.47 244.08,236.16 250.89,209.87" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="149.11,217.34 155.92,191.05 155.92,204.21 149.11,230.50" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="247.90,217.50 241.48,242.24 241.48,255.40 247.90,230.66" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="208.01,115.54 259.87,134.33 259.87,147.50 208.01,128.71" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="247.90,217.50 241.48,242.24 193.59,251.95 152.10,236.91 158.52,212.17 206.41,202.47" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="148.14,127.68 208.01,115.54 208.01,128.71 148.14,140.84" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="30" points="206.41,215.63 158.52,225.34 152.10,250.08 193.59,265.11 241.48,255.40 247.90,230.66" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="31" points="207.61,137.27 256.88,155.12 256.88,168.29 207.61,150.44" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="32" points="152.10,236.91 158.52,212.17 158.52,225.34 152.10,250.08" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="33" points="150.74,148.80 207.61,137.27 207.61,150.44 150.74,161.97" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="34" points="207.21,159.00 253.88,175.91 253.88,189.08 207.21,172.17" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="35" points="153.33,169.93 207.21,159.00 207.21,172.17 153.33,183.09" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="36" points="206.81,180.73 250.89,196.71 250.89,209.87 206.81,193.90" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="37" points="155.92,191.05 206.81,180.73 206.81,193.90 155.92,204.21" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="38" points="206.41,202.47 247.90,217.50 247.90,230.66 206.41,215.63" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="39" points="158.52,212.17 206.41,202.47 206.41,215.63 158.52,225.34" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-index-—-stacked-discs');
var rd = radialData(el, 400);
var t = 0;
(function tick() {
t += 0.02;
var hovering = el.matches(':hover');
rd.forEach(function(d, i) {
var phase = d.dist * 0.02 + i * 0.1;
var wave = Math.sin(t * 0.2 + phase);
if (hovering) {
// Radial push/pull
var mag = wave * 6;
d.el.style.transition = 'transform 0.3s ease';
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
} else {
// Gentle scale breathing
d.el.style.transition = 'none';
d.el.style.transform = 'scale(' + (1 + wave * 0.02) + ')';
}
});
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Index — stacked discs</div>
<div class="card-desc">Database-like stacked discs that gently breathe, evoking layered storage.</div>
<span class="card-anim">breathe</span>
</div>
</div>
<div class="card">
<svg id="shape-index-—-hex-rings" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="275.79,214.30 188.29,232.03 188.29,258.36 275.79,240.63" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="266.46,212.37 185.03,226.62 185.03,251.30 266.46,237.05" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="257.50,210.07 182.62,221.17 182.62,244.21 257.50,233.10" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="188.29,232.03 112.50,204.57 112.50,230.90 188.29,258.36" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="248.95,207.41 181.07,215.72 181.07,237.11 248.95,228.80" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="185.03,226.62 118.57,199.94 118.57,224.62 185.03,251.30" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="182.62,221.17 125.13,195.64 125.13,218.67 182.62,244.21" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="181.07,215.72 132.12,191.69 132.12,213.08 181.07,237.11" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="267.88,175.07 248.95,207.41 248.95,228.80 267.88,196.46" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="274.87,173.43 257.50,210.07 257.50,233.10 274.87,196.46" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="281.43,171.43 266.46,212.37 266.46,237.05 281.43,196.12" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="267.88,175.07 248.95,207.41 181.07,215.72 132.12,191.69 151.05,159.35 218.93,151.04" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="287.50,169.10 275.79,214.30 275.79,240.63 287.50,195.43" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="274.87,173.43 257.50,210.07 182.62,221.17 125.13,195.64 142.50,159.00 217.38,147.89" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="281.43,171.43 266.46,212.37 185.03,226.62 118.57,199.94 133.54,159.00 214.97,144.75" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="287.50,169.10 275.79,214.30 188.29,232.03 112.50,204.57 124.21,159.37 211.71,141.64" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="218.93,172.43 151.05,180.74 132.12,213.08 181.07,237.11 248.95,228.80 267.88,196.46" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="217.38,170.93 142.50,182.03 125.13,218.67 182.62,244.21 257.50,233.10 274.87,196.46" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="214.97,169.43 133.54,183.68 118.57,224.62 185.03,251.30 266.46,237.05 281.43,196.12" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="211.71,167.97 124.21,185.70 112.50,230.90 188.29,258.36 275.79,240.63 287.50,195.43" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="112.50,204.57 124.21,159.37 124.21,185.70 112.50,230.90" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="118.57,199.94 133.54,159.00 133.54,183.68 118.57,224.62" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="125.13,195.64 142.50,159.00 142.50,182.03 125.13,218.67" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="132.12,191.69 151.05,159.35 151.05,180.74 132.12,213.08" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="218.93,151.04 267.88,175.07 267.88,196.46 218.93,172.43" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="217.38,147.89 274.87,173.43 274.87,196.46 217.38,170.93" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="151.05,159.35 218.93,151.04 218.93,172.43 151.05,180.74" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="214.97,144.75 281.43,171.43 281.43,196.12 214.97,169.43" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="142.50,159.00 217.38,147.89 217.38,170.93 142.50,182.03" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="211.71,141.64 287.50,169.10 287.50,195.43 211.71,167.97" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="30" points="133.54,159.00 214.97,144.75 214.97,169.43 133.54,183.68" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="31" points="124.21,159.37 211.71,141.64 211.71,167.97 124.21,185.70" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-index-—-hex-rings');
var rd = radialData(el, 400);
rd.forEach(function(d) {
var mag = 35 + d.dist * 0.35;
d.el.style.transition = 'transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)';
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
d.el.style.transform = 'translate(0, 0)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) {
var mag = 35 + d.dist * 0.35;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Index — hex rings</div>
<div class="card-desc">Concentric hexagonal rings that assemble inward, like an index building itself.</div>
<span class="card-anim">assemble</span>
</div>
</div>
<div class="card">
<svg id="shape-index-—-disc-tower" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="243.88,165.00 193.22,175.27 193.22,184.04 243.88,173.77" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="193.22,175.27 149.34,159.37 149.34,168.14 193.22,184.04" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="241.68,178.25 193.56,188.00 193.56,196.78 241.68,187.02" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="193.56,188.00 151.87,172.90 151.87,181.67 193.56,196.78" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="239.49,191.49 193.90,200.73 193.90,209.51 239.49,200.27" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="193.90,200.73 154.41,186.42 154.41,195.20 193.90,209.51" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="237.30,204.74 194.24,213.47 194.24,222.24 237.30,213.51" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="194.24,213.47 156.94,199.95 156.94,208.73 194.24,222.24" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="250.66,138.83 243.88,165.00 243.88,173.77 250.66,147.61" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="250.66,138.83 243.88,165.00 193.22,175.27 149.34,159.37 156.12,133.20 206.78,122.93" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="235.10,217.98 194.58,226.20 194.58,234.98 235.10,226.76" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="206.78,131.71 156.12,141.98 149.34,168.14 193.22,184.04 243.88,173.77 250.66,147.61" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="248.13,153.39 241.68,178.25 241.68,187.02 248.13,162.16" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="194.58,226.20 159.47,213.48 159.47,222.26 194.58,234.98" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="149.34,159.37 156.12,133.20 156.12,141.98 149.34,168.14" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="248.13,153.39 241.68,178.25 193.56,188.00 151.87,172.90 158.32,148.04 206.44,138.28" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="232.91,231.23 194.91,238.93 194.91,247.71 232.91,240.01" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="206.44,147.06 158.32,156.81 151.87,181.67 193.56,196.78 241.68,187.02 248.13,162.16" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="245.59,167.94 239.49,191.49 239.49,200.27 245.59,176.72" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="151.87,172.90 158.32,148.04 158.32,156.81 151.87,181.67" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="245.59,167.94 239.49,191.49 193.90,200.73 154.41,186.42 160.51,162.87 206.10,153.63" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="194.91,238.93 162.01,227.01 162.01,235.78 194.91,247.71" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="206.10,162.41 160.51,171.65 154.41,195.20 193.90,209.51 239.49,200.27 245.59,176.72" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="243.06,182.50 237.30,204.74 237.30,213.51 243.06,191.27" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="230.71,244.48 195.25,251.67 195.25,260.44 230.71,253.25" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="154.41,186.42 160.51,162.87 160.51,171.65 154.41,195.20" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="243.06,182.50 237.30,204.74 194.24,213.47 156.94,199.95 162.70,177.71 205.76,168.98" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="195.25,251.67 164.54,240.54 164.54,249.31 195.25,260.44" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="205.76,177.76 162.70,186.49 156.94,208.73 194.24,222.24 237.30,213.51 243.06,191.27" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="240.53,197.05 235.10,217.98 235.10,226.76 240.53,205.83" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="30" points="156.94,199.95 162.70,177.71 162.70,186.49 156.94,208.73" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="31" points="240.53,197.05 235.10,217.98 194.58,226.20 159.47,213.48 164.90,192.55 205.42,184.33" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="32" points="205.42,193.11 164.90,201.32 159.47,222.26 194.58,234.98 235.10,226.76 240.53,205.83" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="33" points="206.78,122.93 250.66,138.83 250.66,147.61 206.78,131.71" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="34" points="237.99,211.61 232.91,231.23 232.91,240.01 237.99,220.38" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="35" points="159.47,213.48 164.90,192.55 164.90,201.32 159.47,222.26" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="36" points="237.99,211.61 232.91,231.23 194.91,238.93 162.01,227.01 167.09,207.38 205.09,199.68" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="37" points="156.12,133.20 206.78,122.93 206.78,131.71 156.12,141.98" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="38" points="206.44,138.28 248.13,153.39 248.13,162.16 206.44,147.06" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="39" points="205.09,208.46 167.09,216.16 162.01,235.78 194.91,247.71 232.91,240.01 237.99,220.38" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="40" points="162.01,227.01 167.09,207.38 167.09,216.16 162.01,235.78" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="41" points="235.46,226.16 230.71,244.48 230.71,253.25 235.46,234.94" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="42" points="235.46,226.16 230.71,244.48 195.25,251.67 164.54,240.54 169.29,222.22 204.75,215.03" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="43" points="158.32,148.04 206.44,138.28 206.44,147.06 158.32,156.81" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="44" points="206.10,153.63 245.59,167.94 245.59,176.72 206.10,162.41" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="45" points="204.75,223.81 169.29,230.99 164.54,249.31 195.25,260.44 230.71,253.25 235.46,234.94" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="46" points="164.54,240.54 169.29,222.22 169.29,230.99 164.54,249.31" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="47" points="160.51,162.87 206.10,153.63 206.10,162.41 160.51,171.65" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="48" points="205.76,168.98 243.06,182.50 243.06,191.27 205.76,177.76" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="49" points="162.70,177.71 205.76,168.98 205.76,177.76 162.70,186.49" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="50" points="205.42,184.33 240.53,197.05 240.53,205.83 205.42,193.11" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="51" points="164.90,192.55 205.42,184.33 205.42,193.11 164.90,201.32" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="52" points="205.09,199.68 237.99,211.61 237.99,220.38 205.09,208.46" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="53" points="167.09,207.38 205.09,199.68 205.09,208.46 167.09,216.16" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="54" points="204.75,215.03 235.46,226.16 235.46,234.94 204.75,223.81" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="55" points="169.29,222.22 204.75,215.03 204.75,223.81 169.29,230.99" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-index-—-disc-tower');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
var t = 0, mouseX = 0, mouseY = 0, hovering = false;
el.addEventListener('mouseenter', function() { hovering = true; });
el.addEventListener('mouseleave', function() { hovering = false; });
el.addEventListener('mousemove', function(e) {
var rect = el.getBoundingClientRect();
mouseX = (e.clientX - rect.left) / rect.width - 0.5;
mouseY = (e.clientY - rect.top) / rect.height - 0.5;
});
(function tick() {
t += 0.03;
var floatY = Math.sin(t * 0.14285714285714285) * 6;
var floatR = Math.sin(t * 0.09999999999999999) * 2;
if (hovering) {
g.style.transition = 'transform 0.2s ease-out';
g.style.transform = 'translateY(' + floatY + 'px) perspective(400px) rotateX(' + (mouseY * -15) + 'deg) rotateY(' + (mouseX * 15) + 'deg)';
} else {
g.style.transition = 'transform 0.6s ease-out';
g.style.transform = 'translateY(' + floatY + 'px) rotate(' + floatR + 'deg)';
}
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Index — disc tower</div>
<div class="card-desc">A tall disc tower floating gently, tilting toward the cursor on hover.</div>
<span class="card-anim">float</span>
</div>
</div>
</div>
</div>
<div class="feature-group">
<div class="feature-header">
<h2 class="feature-title">Blazing fast</h2>
<p class="feature-desc">Built in Rust. Opens a 100k-file folder in 4 seconds with icons, sizes, and dates.</p>
</div>
<div class="variant-grid">
<div class="card">
<svg id="shape-speed-—-arrow-burst" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="131.37,189.04 191.24,124.25 208.76,144.12 148.89,208.91" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="170.28,194.31 131.37,189.04 148.89,208.91 187.81,214.18" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="148.89,208.91 187.81,214.18 187.81,280.00 229.72,271.51 229.72,205.69 268.63,184.64 208.76,144.12" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="191.24,124.25 251.11,164.77 268.63,184.64 208.76,144.12" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="170.28,260.13 170.28,194.31 187.81,214.18 187.81,280.00" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="251.11,164.77 212.19,185.82 229.72,205.69 268.63,184.64" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="191.24,124.25 251.11,164.77 212.19,185.82 212.19,251.64 170.28,260.13 170.28,194.31 131.37,189.04" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="212.19,185.82 212.19,251.64 229.72,271.51 229.72,205.69" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="212.19,251.64 170.28,260.13 187.81,280.00 229.72,271.51" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-speed-—-arrow-burst');
var rd = radialData(el, 400);
var g = el.querySelector('.shape-group');
var t = 0;
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
(function idleTick() {
t += 0.15;
if (!el.matches(':hover')) {
g.style.transform = 'rotate(' + (Math.sin(t * 0.02) * 2) + 'deg)';
}
requestAnimationFrame(idleTick);
})();
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
// Strictly radial: magnitude = base + proportional to distance from center
var mag = 30 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) { d.el.style.transform = 'translate(0, 0)'; });
});
})();</script>
<div class="card-info">
<div class="card-name">Speed — arrow burst</div>
<div class="card-desc">A sharp arrow prism that explodes apart, evoking bursts of speed.</div>
<span class="card-anim">explode</span>
</div>
</div>
<div class="card">
<svg id="shape-speed-—-pyramid-streak" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="200.00,134.18 263.82,288.94 190.14,303.88" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="200.00,134.18 190.14,303.88 126.32,280.75" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,134.18 273.68,250.88 263.82,288.94" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="200.00,134.18 126.32,280.75 136.18,242.69" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="209.86,227.76 136.18,242.69 126.32,280.75 190.14,303.88 263.82,288.94 273.68,250.88" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,134.18 209.86,227.76 273.68,250.88" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="200.00,134.18 136.18,242.69 209.86,227.76" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-speed-—-pyramid-streak');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 25 + d.dist * 0.5;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
// Staggered delay creates the spiral wave feel
d.el.style.transitionDelay = (i * 0.03) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0)';
d.el.style.transitionDelay = (i * 0.015) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Speed — pyramid streak</div>
<div class="card-desc">A tall pointed pyramid that spirals outward on hover — forward momentum frozen in 3D.</div>
<span class="card-anim">spiral</span>
</div>
</div>
<div class="card">
<svg id="shape-speed-—-gem-flash" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="211.68,150.06 188.72,150.14 177.44,212.61 223.37,212.45" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="200.00,129.79 211.68,150.06 188.72,150.14" fill="#ffd23f" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,129.79 188.72,150.14 172.37,142.41" fill="#f0b400" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="3" points="200.00,129.79 227.80,142.22 211.68,150.06" fill="#ffc206" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="4" points="188.72,150.14 172.37,142.41 144.74,197.16 177.44,212.61" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="227.80,142.22 211.68,150.06 223.37,212.45 255.60,196.77" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="200.00,129.79 172.37,142.41 172.20,131.41" fill="#ffc206" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="7" points="200.00,129.79 227.63,131.21 227.80,142.22" fill="#f0b400" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="8" points="223.37,212.45 177.44,212.61 200.00,270.21" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="200.00,129.79 172.20,131.41 188.32,123.57" fill="#ffd23f" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="10" points="200.00,129.79 211.28,123.49 227.63,131.21" fill="#ffc206" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="11" points="172.37,142.41 172.20,131.41 144.40,175.14 144.74,197.16" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="227.63,131.21 227.80,142.22 255.60,196.77 255.26,174.76" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="200.00,129.79 188.32,123.57 211.28,123.49" fill="#f0b400" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="14" points="177.44,212.61 144.74,197.16 200.00,270.21" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="255.60,196.77 223.37,212.45 200.00,270.21" fill="#6b480c" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="172.20,131.41 188.32,123.57 176.63,159.46 144.40,175.14" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="211.28,123.49 227.63,131.21 255.26,174.76 222.56,159.30" fill="#e4a024" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="144.74,197.16 144.40,175.14 200.00,270.21" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="255.26,174.76 255.60,196.77 200.00,270.21" fill="#6b480c" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="188.32,123.57 211.28,123.49 222.56,159.30 176.63,159.46" fill="#e4a024" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="144.40,175.14 176.63,159.46 200.00,270.21" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="222.56,159.30 255.26,174.76 200.00,270.21" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="176.63,159.46 222.56,159.30 200.00,270.21" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-speed-—-gem-flash');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
el.addEventListener('mouseenter', function() {
g.style.transition = 'transform 0.15s ease';
g.style.transform = 'rotate(8deg) scale(1.05)';
setTimeout(function() {
g.style.transition = 'transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'rotate(-5deg) scale(1.05)';
setTimeout(function() { g.style.transform = 'rotate(0deg) scale(1.05)'; }, 300);
}, 150);
});
el.addEventListener('mouseleave', function() {
g.style.transition = 'transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'rotate(0deg) scale(1)';
});
})();</script>
<div class="card-info">
<div class="card-name">Speed — gem flash</div>
<div class="card-desc">An elongated diamond that wobbles like it was hit at high speed.</div>
<span class="card-anim">wobble</span>
</div>
</div>
</div>
</div>
<div class="feature-group">
<div class="feature-header">
<h2 class="feature-title">Keyboard-first</h2>
<p class="feature-desc">Navigate, select, copy, move. All without touching your mouse.</p>
</div>
<div class="variant-grid">
<div class="card">
<svg id="shape-keys-—-cube-grid" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="176.02,218.90 167.89,220.55 167.89,228.30 176.02,226.65" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="167.89,220.55 176.02,218.90 172.58,215.00 164.45,216.65" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="167.89,220.55 164.45,216.65 164.45,224.40 167.89,228.30" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="172.58,215.00 176.02,218.90 176.02,226.65 172.58,222.75" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="164.45,224.40 172.58,222.75 176.02,226.65 167.89,228.30" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="164.45,216.65 172.58,215.00 172.58,222.75 164.45,224.40" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="206.56,211.92 194.34,214.39 194.34,226.04 206.56,223.56" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="194.34,214.39 206.56,211.92 201.40,206.05 189.17,208.53" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="194.34,214.39 189.17,208.53 189.17,220.18 194.34,226.04" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="201.40,206.05 206.56,211.92 206.56,223.56 201.40,217.70" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="237.00,204.98 220.83,208.26 220.83,223.66 237.00,220.39" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="189.17,220.18 201.40,217.70 206.56,223.56 194.34,226.04" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="189.17,208.53 201.40,206.05 201.40,217.70 189.17,220.18" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="220.83,208.26 237.00,204.98 230.16,197.23 214.00,200.51" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="220.83,208.26 214.00,200.51 214.00,215.91 220.83,223.66" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="169.35,203.27 154.17,206.35 154.17,220.81 169.35,217.73" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="154.17,206.35 169.35,203.27 162.93,195.99 147.75,199.07" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="154.17,206.35 147.75,199.07 147.75,213.53 154.17,220.81" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="230.16,197.23 237.00,204.98 237.00,220.39 230.16,212.63" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="214.00,215.91 230.16,212.63 237.00,220.39 220.83,223.66" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="261.00,201.11 249.94,203.35 249.94,213.88 261.00,211.64" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="162.93,195.99 169.35,203.27 169.35,217.73 162.93,210.46" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="214.00,200.51 230.16,197.23 230.16,212.63 214.00,215.91" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="249.94,203.35 261.00,201.11 256.32,195.81 245.26,198.05" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="147.75,213.53 162.93,210.46 169.35,217.73 154.17,220.81" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="249.94,203.35 245.26,198.05 245.26,208.58 249.94,213.88" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="192.65,199.73 183.56,201.57 183.56,210.23 192.65,208.39" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="147.75,199.07 162.93,195.99 162.93,210.46 147.75,213.53" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="183.56,201.57 192.65,199.73 188.81,195.37 179.72,197.21" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="256.32,195.81 261.00,201.11 261.00,211.64 256.32,206.34" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="30" points="183.56,201.57 179.72,197.21 179.72,205.87 183.56,210.23" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="31" points="245.26,208.58 256.32,206.34 261.00,211.64 249.94,213.88" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="32" points="245.26,198.05 256.32,195.81 256.32,206.34 245.26,208.58" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="33" points="188.81,195.37 192.65,199.73 192.65,208.39 188.81,204.03" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="34" points="179.72,205.87 188.81,204.03 192.65,208.39 183.56,210.23" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="35" points="179.72,197.21 188.81,195.37 188.81,204.03 179.72,205.87" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="36" points="220.88,193.84 210.95,195.86 210.95,205.31 220.88,203.30" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="37" points="210.95,195.86 220.88,193.84 216.68,189.09 206.75,191.10" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="38" points="210.95,195.86 206.75,191.10 206.75,200.55 210.95,205.31" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="39" points="155.52,191.04 143.36,193.51 143.36,205.09 155.52,202.63" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="40" points="143.36,193.51 155.52,191.04 150.38,185.22 138.22,187.68" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="41" points="143.36,193.51 138.22,187.68 138.22,199.26 143.36,205.09" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="42" points="216.68,189.09 220.88,193.84 220.88,203.30 216.68,198.54" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="43" points="206.75,200.55 216.68,198.54 220.88,203.30 210.95,205.31" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="44" points="252.69,186.26 236.89,189.46 236.89,204.51 252.69,201.31" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="45" points="206.75,191.10 216.68,189.09 216.68,198.54 206.75,200.55" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="46" points="150.38,185.22 155.52,191.04 155.52,202.63 150.38,196.80" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="47" points="236.89,189.46 252.69,186.26 246.01,178.68 230.21,181.89" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="48" points="186.01,184.08 169.83,187.36 169.83,202.78 186.01,199.50" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="49" points="138.22,199.26 150.38,196.80 155.52,202.63 143.36,205.09" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="50" points="236.89,189.46 230.21,181.89 230.21,196.94 236.89,204.51" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="51" points="138.22,187.68 150.38,185.22 150.38,196.80 138.22,199.26" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="52" points="169.83,187.36 186.01,184.08 179.17,176.33 162.99,179.61" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="53" points="169.83,187.36 162.99,179.61 162.99,195.02 169.83,202.78" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="54" points="246.01,178.68 252.69,186.26 252.69,201.31 246.01,193.74" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="55" points="230.21,196.94 246.01,193.74 252.69,201.31 236.89,204.51" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="56" points="179.17,176.33 186.01,184.08 186.01,199.50 179.17,191.74" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="57" points="230.21,181.89 246.01,178.68 246.01,193.74 230.21,196.94" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="58" points="162.99,195.02 179.17,191.74 186.01,199.50 169.83,202.78" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="59" points="210.05,180.19 198.92,182.45 198.92,193.04 210.05,190.79" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="60" points="162.99,179.61 179.17,176.33 179.17,191.74 162.99,195.02" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="61" points="198.92,182.45 210.05,180.19 205.34,174.86 194.22,177.11" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="62" points="198.92,182.45 194.22,177.11 194.22,187.71 198.92,193.04" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="63" points="205.34,174.86 210.05,180.19 210.05,190.79 205.34,185.46" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="64" points="194.22,187.71 205.34,185.46 210.05,190.79 198.92,193.04" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="65" points="194.22,177.11 205.34,174.86 205.34,185.46 194.22,187.71" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="66" points="235.75,175.51 227.34,177.21 227.34,185.22 235.75,183.52" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="67" points="227.34,177.21 235.75,175.51 232.19,171.48 223.79,173.18" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="68" points="227.34,177.21 223.79,173.18 223.79,181.19 227.34,185.22" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="69" points="232.19,171.48 235.75,175.51 235.75,183.52 232.19,179.49" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="70" points="223.79,181.19 232.19,179.49 235.75,183.52 227.34,185.22" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="71" points="223.79,173.18 232.19,171.48 232.19,179.49 223.79,181.19" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-keys-—-cube-grid');
var rd = radialData(el, 400);
var rand = function(seed) { var x = Math.sin(seed * 127.1 + 311.7) * 43758.5453; return x - Math.floor(x); };
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
// Radial direction, random magnitude (20–80px range)
var mag = 20 + rand(i * 7) * 60;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
d.el.style.transitionDelay = (rand(i * 5) * 0.15) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) {
d.el.style.transform = 'translate(0, 0)';
d.el.style.transitionDelay = '0s';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Keys — cube grid</div>
<div class="card-desc">A grid of small cubes like keyboard keys that scatter apart on hover.</div>
<span class="card-anim">scatter</span>
</div>
</div>
<div class="card">
<svg id="shape-keys-—-stepped-platform" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="189.37,151.13 226.21,143.67 226.21,178.77 189.37,186.24" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="1" points="173.79,133.47 210.63,126.00 226.21,143.67 189.37,151.13" fill="#6b480c" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="2" points="173.79,168.57 173.79,133.47 189.37,151.13 189.37,186.24" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="3" points="193.40,173.70 227.50,163.67 227.50,198.77 193.40,208.80" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="4" points="172.50,157.35 206.60,147.32 227.50,163.67 193.40,173.70" fill="#8a5e14" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="5" points="172.50,192.45 172.50,157.35 193.40,173.70 193.40,208.80" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="6" points="210.63,126.00 210.63,161.11 226.21,178.77 226.21,143.67" fill="#6b480c" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="7" points="210.63,161.11 173.79,168.57 189.37,186.24 226.21,178.77" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="8" points="197.59,195.96 228.18,183.60 228.18,218.71 197.59,231.06" fill="#c48a1e" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="9" points="171.82,216.40 171.82,181.29 197.59,195.96 197.59,231.06" fill="#c48a1e" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="10" points="171.82,181.29 202.41,168.94 228.18,183.60 197.59,195.96" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="11" points="173.79,168.57 210.63,161.11 210.63,126.00 173.79,133.47" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="12" points="206.60,147.32 206.60,182.43 227.50,198.77 227.50,163.67" fill="#8a5e14" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="13" points="206.60,182.43 172.50,192.45 193.40,208.80 227.50,198.77" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="14" points="171.77,240.37 171.77,205.26 201.83,217.92 201.83,253.02" fill="#e4a024" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="15" points="201.83,217.92 228.23,203.51 228.23,238.62 201.83,253.02" fill="#e4a024" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="16" points="171.77,205.26 198.17,190.86 228.23,203.51 201.83,217.92" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="17" points="172.50,192.45 206.60,182.43 206.60,147.32 172.50,157.35" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="18" points="202.41,204.04 171.82,216.40 197.59,231.06 228.18,218.71" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="19" points="202.41,168.94 202.41,204.04 228.18,218.71 228.18,183.60" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="20" points="171.82,216.40 202.41,204.04 202.41,168.94 171.82,181.29" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="21" points="198.17,225.96 171.77,240.37 201.83,253.02 228.23,238.62" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="22" points="171.77,240.37 198.17,225.96 198.17,190.86 171.77,205.26" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="23" points="198.17,190.86 198.17,225.96 228.23,238.62 228.23,203.51" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-keys-—-stepped-platform');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 20 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px) scale(0.92)';
d.el.style.transitionDelay = (i * 0.02) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0) scale(1)';
d.el.style.transitionDelay = (i * 0.01) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Keys — stepped platform</div>
<div class="card-desc">Stacked twisted cubes like keyboard tiers that bloom outward.</div>
<span class="card-anim">bloom</span>
</div>
</div>
<div class="card">
<svg id="shape-keys-—-dual-pane" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="166.57,218.88 159.18,220.38 159.18,227.42 166.57,225.92" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="159.18,220.38 166.57,218.88 163.44,215.33 156.05,216.83" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="159.18,220.38 156.05,216.83 156.05,223.87 159.18,227.42" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="163.44,215.33 166.57,218.88 166.57,225.92 163.44,222.38" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="156.05,223.87 163.44,222.38 166.57,225.92 159.18,227.42" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="156.05,216.83 163.44,215.33 163.44,222.38 156.05,223.87" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="193.16,212.76 182.05,215.02 182.05,225.61 193.16,223.35" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="182.05,215.02 193.16,212.76 188.46,207.44 177.35,209.69" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="182.05,215.02 177.35,209.69 177.35,220.28 182.05,225.61" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="188.46,207.44 193.16,212.76 193.16,223.35 188.46,218.03" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="177.35,220.28 188.46,218.03 193.16,223.35 182.05,225.61" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="177.35,209.69 188.46,207.44 188.46,218.03 177.35,220.28" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="161.00,205.23 147.20,208.03 147.20,221.18 161.00,218.38" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="147.20,208.03 161.00,205.23 155.17,198.61 141.37,201.41" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="147.20,208.03 141.37,201.41 141.37,214.56 147.20,221.18" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="155.17,198.61 161.00,205.23 161.00,218.38 155.17,211.76" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="240.25,203.94 232.86,205.44 232.86,212.48 240.25,210.98" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="141.37,214.56 155.17,211.76 161.00,218.38 147.20,221.18" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="232.86,205.44 240.25,203.94 237.13,200.40 229.74,201.90" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="232.86,205.44 229.74,201.90 229.74,208.94 232.86,212.48" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="181.01,202.25 172.75,203.92 172.75,211.80 181.01,210.12" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="141.37,201.41 155.17,198.61 155.17,211.76 141.37,214.56" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="172.75,203.92 181.01,202.25 177.52,198.28 169.25,199.96" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="172.75,203.92 169.25,199.96 169.25,207.83 172.75,211.80" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="237.13,200.40 240.25,203.94 240.25,210.98 237.13,207.44" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="229.74,208.94 237.13,207.44 240.25,210.98 232.86,212.48" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="229.74,201.90 237.13,200.40 237.13,207.44 229.74,208.94" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="266.85,197.83 255.73,200.08 255.73,210.67 266.85,208.42" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="177.52,198.28 181.01,202.25 181.01,210.12 177.52,206.16" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="169.25,207.83 177.52,206.16 181.01,210.12 172.75,211.80" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="30" points="255.73,200.08 266.85,197.83 262.15,192.50 251.03,194.75" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="31" points="169.25,199.96 177.52,198.28 177.52,206.16 169.25,207.83" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="32" points="255.73,200.08 251.03,194.75 251.03,205.34 255.73,210.67" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="33" points="148.92,194.68 137.87,196.92 137.87,207.45 148.92,205.21" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="34" points="262.15,192.50 266.85,197.83 266.85,208.42 262.15,203.09" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="35" points="251.03,205.34 262.15,203.09 266.85,208.42 255.73,210.67" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="36" points="137.87,196.92 148.92,194.68 144.25,189.38 133.20,191.62" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="37" points="137.87,196.92 133.20,191.62 133.20,202.15 137.87,207.45" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="38" points="251.03,194.75 262.15,192.50 262.15,203.09 251.03,205.34" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="39" points="234.69,190.29 220.89,193.09 220.89,206.24 234.69,203.44" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="40" points="144.25,189.38 148.92,194.68 148.92,205.21 144.25,199.91" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="41" points="175.47,188.59 160.76,191.57 160.76,205.58 175.47,202.60" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="42" points="220.89,193.09 234.69,190.29 228.85,183.68 215.05,186.48" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="43" points="133.20,202.15 144.25,199.91 148.92,205.21 137.87,207.45" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="44" points="220.89,193.09 215.05,186.48 215.05,199.62 220.89,206.24" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="45" points="133.20,191.62 144.25,189.38 144.25,199.91 133.20,202.15" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="46" points="160.76,191.57 175.47,188.59 169.25,181.54 154.54,184.52" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="47" points="160.76,191.57 154.54,184.52 154.54,198.53 160.76,205.58" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="48" points="228.85,183.68 234.69,190.29 234.69,203.44 228.85,196.83" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="49" points="215.05,199.62 228.85,196.83 234.69,203.44 220.89,206.24" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="50" points="254.70,187.31 246.43,188.99 246.43,196.86 254.70,195.19" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="51" points="169.25,181.54 175.47,188.59 175.47,202.60 169.25,195.55" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="52" points="215.05,186.48 228.85,183.68 228.85,196.83 215.05,199.62" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="53" points="154.54,198.53 169.25,195.55 175.47,202.60 160.76,205.58" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="54" points="246.43,188.99 254.70,187.31 251.20,183.35 242.94,185.02" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="55" points="246.43,188.99 242.94,185.02 242.94,192.90 246.43,196.86" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="56" points="154.54,184.52 169.25,181.54 169.25,195.55 154.54,198.53" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="57" points="251.20,183.35 254.70,187.31 254.70,195.19 251.20,191.22" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="58" points="242.94,192.90 251.20,191.22 254.70,195.19 246.43,196.86" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="59" points="242.94,185.02 251.20,183.35 251.20,191.22 242.94,192.90" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="60" points="222.61,179.74 211.55,181.98 211.55,192.51 222.61,190.27" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="61" points="211.55,181.98 222.61,179.74 217.93,174.44 206.88,176.68" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="62" points="211.55,181.98 206.88,176.68 206.88,187.21 211.55,192.51" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="63" points="217.93,174.44 222.61,179.74 222.61,190.27 217.93,184.97" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="64" points="249.15,173.65 234.45,176.63 234.45,190.65 249.15,187.66" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="65" points="206.88,187.21 217.93,184.97 222.61,190.27 211.55,192.51" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="66" points="206.88,176.68 217.93,174.44 217.93,184.97 206.88,187.21" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="67" points="234.45,176.63 249.15,173.65 242.94,166.60 228.23,169.58" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="68" points="234.45,176.63 228.23,169.58 228.23,183.60 234.45,190.65" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="69" points="242.94,166.60 249.15,173.65 249.15,187.66 242.94,180.61" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="70" points="228.23,183.60 242.94,180.61 249.15,187.66 234.45,190.65" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="71" points="228.23,169.58 242.94,166.60 242.94,180.61 228.23,183.60" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-keys-—-dual-pane');
var rd = radialData(el, 400);
var g = el.querySelector('.shape-group');
var t = 0;
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
(function idleTick() {
t += 0.15;
if (!el.matches(':hover')) {
g.style.transform = 'rotate(' + (Math.sin(t * 0.02) * 2) + 'deg)';
}
requestAnimationFrame(idleTick);
})();
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
// Strictly radial: magnitude = base + proportional to distance from center
var mag = 30 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) { d.el.style.transform = 'translate(0, 0)'; });
});
})();</script>
<div class="card-info">
<div class="card-name">Keys — dual pane</div>
<div class="card-desc">Two side-by-side cube clusters (dual pane!) that explode apart on hover.</div>
<span class="card-anim">explode</span>
</div>
</div>
</div>
</div>
<div class="feature-group">
<div class="feature-header">
<h2 class="feature-title">Smart search</h2>
<p class="feature-desc">Find files by describing them: "that PDF contract from last month."</p>
</div>
<div class="variant-grid">
<div class="card">
<svg id="shape-search-—-radar-rings" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="200.24,210.74 187.41,209.56 186.09,216.44 200.27,217.74" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="1" points="213.05,209.47 200.24,210.74 200.27,217.74 214.41,216.34" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="2" points="200.27,217.74 186.09,216.44 187.41,220.20 200.24,221.38" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="3" points="200.19,207.38 190.04,206.45 187.41,209.56 200.24,210.74" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="4" points="214.41,216.34 200.27,217.74 200.24,221.38 213.05,220.11" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="5" points="210.32,206.38 200.19,207.38 200.24,210.74 213.05,209.47" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="6" points="187.41,209.56 176.49,206.12 174.03,212.63 186.09,216.44" fill="#c48a1e" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="7" points="223.86,205.95 213.05,209.47 214.41,216.34 226.35,212.45" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="8" points="209.83,204.69 196.89,205.55 196.36,214.04 211.49,213.03" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="9" points="190.04,206.45 181.40,203.73 176.49,206.12 187.41,209.56" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="10" points="218.87,203.60 210.32,206.38 213.05,209.47 223.86,205.95" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="11" points="186.09,216.44 174.03,212.63 176.49,216.76 187.41,220.20" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="12" points="226.35,212.45 214.41,216.34 213.05,220.11 223.86,216.59" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="13" points="196.89,205.55 184.78,203.20 182.21,211.28 196.36,214.04" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="14" points="200.24,221.38 187.41,220.20 190.04,217.09 200.19,218.02" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="15" points="213.05,220.11 200.24,221.38 200.19,218.02 210.32,217.02" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="16" points="200.17,211.03 191.35,210.22 190.04,206.45 200.19,207.38" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="17" points="208.96,210.16 200.17,211.03 200.19,207.38 210.32,206.38" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="18" points="211.49,213.03 196.36,214.04 196.89,218.47 209.83,217.61" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="19" points="206.52,200.94 197.93,201.51 196.89,205.55 209.83,204.69" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="20" points="220.14,200.84 209.83,204.69 211.49,213.03 223.53,208.53" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="21" points="197.93,201.51 189.90,199.95 184.78,203.20 196.89,205.55" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="22" points="196.36,214.04 182.21,211.28 184.78,216.12 196.89,218.47" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="23" points="200.19,218.02 190.04,217.09 191.35,210.22 200.17,211.03" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="24" points="210.32,217.02 200.19,218.02 200.17,211.03 208.96,210.16" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="25" points="191.35,210.22 183.86,207.85 181.40,203.73 190.04,206.45" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="26" points="216.38,207.74 208.96,210.16 210.32,206.38 218.87,203.60" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="27" points="187.41,220.20 176.49,216.76 181.40,214.37 190.04,217.09" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="28" points="176.49,206.12 169.14,200.93 165.92,206.91 174.03,212.63" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="29" points="223.86,216.59 213.05,220.11 210.32,217.02 218.87,214.24" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="30" points="231.04,200.72 223.86,205.95 226.35,212.45 234.29,206.67" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="31" points="206.62,199.91 193.61,199.95 191.73,209.77 208.57,209.71" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="32" points="213.36,198.38 206.52,200.94 209.83,204.69 220.14,200.84" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="33" points="181.40,203.73 175.59,199.63 169.14,200.93 176.49,206.12" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="34" points="224.56,199.46 218.87,203.60 223.86,205.95 231.04,200.72" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="35" points="223.53,208.53 211.49,213.03 209.83,217.61 220.14,213.76" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="36" points="190.04,217.09 181.40,214.37 183.86,207.85 191.35,210.22" fill="#c48a1e" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="37" points="218.87,214.24 210.32,217.02 208.96,210.16 216.38,207.74" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="38" points="184.78,203.20 176.74,198.25 172.83,205.51 182.21,211.28" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="39" points="174.03,212.63 165.92,206.91 169.14,211.57 176.49,216.76" fill="#a87218" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="40" points="234.29,206.67 226.35,212.45 223.86,216.59 231.04,211.36" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="41" points="189.90,199.95 184.57,196.67 176.74,198.25 184.78,203.20" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="42" points="209.83,217.61 196.89,218.47 197.93,214.43 206.52,213.86" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="43" points="204.87,205.52 198.46,205.95 197.93,201.51 206.52,200.94" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="44" points="202.73,195.49 197.37,195.51 193.61,199.95 206.62,199.91" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="45" points="208.57,209.71 191.73,209.77 193.61,215.15 206.62,215.11" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="46" points="183.86,207.85 178.82,204.29 175.59,199.63 181.40,203.73" fill="#a87218" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="47" points="193.61,199.95 184.34,195.57 179.74,204.11 191.73,209.77" fill="#c48a1e" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="48" points="198.46,205.95 192.46,204.78 189.90,199.95 197.93,201.51" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="49" points="215.75,195.46 206.62,199.91 208.57,209.71 220.39,203.97" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="50" points="221.31,204.15 216.38,207.74 218.87,203.60 224.56,199.46" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="51" points="196.89,218.47 184.78,216.12 189.90,212.87 197.93,214.43" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="52" points="182.21,211.28 172.83,205.51 176.74,211.17 184.78,216.12" fill="#a87218" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="53" points="176.49,216.76 169.14,211.57 175.59,210.27 181.40,214.37" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="54" points="209.97,203.61 204.87,205.52 206.52,200.94 213.36,198.38" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="55" points="231.04,211.36 223.86,216.59 218.87,214.24 224.56,210.10" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="56" points="197.37,195.51 193.55,193.71 184.34,195.57 193.61,199.95" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="57" points="206.49,193.66 202.73,195.49 206.62,199.91 215.75,195.46" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="58" points="206.52,213.86 197.93,214.43 198.46,205.95 204.87,205.52" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="59" points="220.14,213.76 209.83,217.61 206.52,213.86 213.36,211.30" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="60" points="181.40,214.37 175.59,210.27 178.82,204.29 183.86,207.85" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="61" points="225.06,195.03 220.14,200.84 223.53,208.53 229.27,201.74" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="62" points="224.56,210.10 218.87,214.24 216.38,207.74 221.31,204.15" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="63" points="216.62,194.53 213.36,198.38 220.14,200.84 225.06,195.03" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="64" points="197.93,214.43 189.90,212.87 192.46,204.78 198.46,205.95" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="65" points="192.46,204.78 188.49,202.33 184.57,196.67 189.90,199.95" fill="#a87218" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="66" points="191.73,209.77 179.74,204.11 184.34,210.77 193.61,215.15" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="67" points="220.39,203.97 208.57,209.71 206.62,215.11 215.75,210.66" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="68" points="175.59,199.63 173.50,194.77 166.50,194.80 169.14,200.93" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="69" points="213.36,211.30 206.52,213.86 204.87,205.52 209.97,203.61" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="70" points="226.50,194.59 224.56,199.46 231.04,200.72 233.50,194.56" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="71" points="169.14,200.93 166.50,194.80 163.00,200.13 165.92,206.91" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="72" points="184.78,216.12 176.74,211.17 184.57,209.59 189.90,212.87" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="73" points="233.50,194.56 231.04,200.72 234.29,206.67 237.00,199.87" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="74" points="229.27,201.74 223.53,208.53 220.14,213.76 225.06,207.95" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="75" points="212.40,200.74 209.97,203.61 213.36,198.38 216.62,194.53" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="76" points="184.57,196.67 183.38,192.55 174.94,192.05 176.74,198.25" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="77" points="189.90,212.87 184.57,209.59 188.49,202.33 192.46,204.78" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="78" points="178.82,204.29 177.00,200.08 173.50,194.77 175.59,199.63" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="79" points="200.78,200.88 199.25,200.89 197.37,195.51 202.73,195.49" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="80" points="206.62,215.11 193.61,215.15 197.37,210.71 202.73,210.69" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="81" points="223.00,199.92 221.31,204.15 224.56,199.46 226.50,194.59" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="82" points="176.74,198.25 174.94,192.05 170.73,198.26 172.83,205.51" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="83" points="165.92,206.91 163.00,200.13 166.50,205.44 169.14,211.57" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="84" points="199.25,200.89 198.16,200.37 193.55,193.71 197.37,195.51" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="85" points="201.85,200.36 200.78,200.88 202.73,195.49 206.49,193.66" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="86" points="237.00,199.87 234.29,206.67 231.04,211.36 233.50,205.20" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="87" points="193.55,193.71 193.51,191.14 184.25,189.34 184.34,195.57" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="88" points="206.45,191.09 206.49,193.66 215.75,195.46 215.66,189.23" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="89" points="188.49,202.33 187.60,199.26 183.38,192.55 184.57,196.67" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="90" points="225.06,207.95 220.14,213.76 213.36,211.30 216.62,207.45" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="91" points="216.62,207.45 213.36,211.30 209.97,203.61 212.40,200.74" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="92" points="175.59,210.27 173.50,205.41 177.00,200.08 178.82,204.29" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="93" points="193.61,215.15 184.34,210.77 193.55,208.91 197.37,210.71" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="94" points="215.75,210.66 206.62,215.11 202.73,210.69 206.49,208.86" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="95" points="226.50,205.23 224.56,210.10 221.31,204.15 223.00,199.92" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="96" points="169.14,211.57 166.50,205.44 173.50,205.41 175.59,210.27" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="97" points="184.34,195.57 184.25,189.34 179.61,196.03 179.74,204.11" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="98" points="198.16,200.37 198.15,199.64 193.51,191.14 193.55,193.71" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="99" points="201.84,199.63 201.85,200.36 206.49,193.66 206.45,191.09" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="100" points="215.66,189.23 215.75,195.46 220.39,203.97 220.26,195.89" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="101" points="233.50,205.20 231.04,211.36 224.56,210.10 226.50,205.23" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="102" points="202.73,210.69 197.37,210.71 199.25,200.89 200.78,200.88" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="103" points="172.83,205.51 170.73,198.26 174.94,204.97 176.74,211.17" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="104" points="215.43,190.41 216.62,194.53 225.06,195.03 223.26,188.83" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="105" points="197.37,210.71 193.55,208.91 198.16,200.37 199.25,200.89" fill="#c48a1e" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="106" points="206.49,208.86 202.73,210.69 200.78,200.88 201.85,200.36" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="107" points="211.51,197.67 212.40,200.74 216.62,194.53 215.43,190.41" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="108" points="184.57,209.59 183.38,205.47 187.60,199.26 188.49,202.33" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="109" points="198.15,199.64 199.22,199.12 197.27,189.31 193.51,191.14" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="110" points="200.75,199.11 201.84,199.63 206.45,191.09 202.63,189.29" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="111" points="176.74,211.17 174.94,204.97 183.38,205.47 184.57,209.59" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="112" points="223.26,188.83 225.06,195.03 229.27,201.74 227.17,194.49" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="113" points="199.22,199.12 200.75,199.11 202.63,189.29 197.27,189.31" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="114" points="173.50,194.77 175.44,189.90 168.96,188.64 166.50,194.80" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="115" points="179.74,204.11 179.61,196.03 184.25,204.54 184.34,210.77" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="116" points="193.55,208.91 193.51,206.34 198.15,199.64 198.16,200.37" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="117" points="206.45,206.29 206.49,208.86 201.85,200.36 201.84,199.63" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="118" points="220.26,195.89 220.39,203.97 215.75,210.66 215.66,204.43" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="119" points="224.41,189.73 226.50,194.59 233.50,194.56 230.86,188.43" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="120" points="177.00,200.08 178.69,195.85 175.44,189.90 173.50,194.77" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="121" points="193.51,191.14 197.27,189.31 193.38,184.89 184.25,189.34" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="122" points="202.63,189.29 206.45,191.09 215.66,189.23 206.39,184.85" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="123" points="221.18,195.71 223.00,199.92 226.50,194.59 224.41,189.73" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="124" points="187.60,199.26 190.03,196.39 186.64,188.70 183.38,192.55" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="125" points="183.38,192.55 186.64,188.70 179.86,186.24 174.94,192.05" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="126" points="215.43,203.33 216.62,207.45 212.40,200.74 211.51,197.67" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="127" points="184.34,210.77 184.25,204.54 193.51,206.34 193.55,208.91" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="128" points="215.66,204.43 215.75,210.66 206.49,208.86 206.45,206.29" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="129" points="166.50,194.80 168.96,188.64 165.71,193.33 163.00,200.13" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="130" points="193.51,206.34 197.27,204.51 199.22,199.12 198.15,199.64" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="131" points="202.63,204.49 206.45,206.29 201.84,199.63 200.75,199.11" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="132" points="230.86,188.43 233.50,194.56 237.00,199.87 234.08,193.09" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="133" points="227.17,194.49 229.27,201.74 225.06,207.95 223.26,201.75" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="134" points="173.50,205.41 175.44,200.54 178.69,195.85 177.00,200.08" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="135" points="197.27,189.31 202.63,189.29 206.39,184.85 193.38,184.89" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="136" points="197.27,204.51 202.63,204.49 200.75,199.11 199.22,199.12" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="137" points="224.41,200.37 226.50,205.23 223.00,199.92 221.18,195.71" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="138" points="207.54,195.22 211.51,197.67 215.43,190.41 210.10,187.13" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="139" points="223.26,201.75 225.06,207.95 216.62,207.45 215.43,203.33" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="140" points="183.38,205.47 186.64,201.62 190.03,196.39 187.60,199.26" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="141" points="174.94,192.05 179.86,186.24 176.47,191.47 170.73,198.26" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="142" points="163.00,200.13 165.71,193.33 168.96,199.28 166.50,205.44" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="143" points="210.10,187.13 215.43,190.41 223.26,188.83 215.22,183.88" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="144" points="234.08,193.09 237.00,199.87 233.50,205.20 230.86,199.07" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="145" points="166.50,205.44 168.96,199.28 175.44,200.54 173.50,205.41" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="146" points="190.03,196.39 195.13,194.48 193.48,186.14 186.64,188.70" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="147" points="230.86,199.07 233.50,205.20 226.50,205.23 224.41,200.37" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="148" points="184.25,189.34 193.38,184.89 191.43,190.29 179.61,196.03" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="149" points="206.39,184.85 215.66,189.23 220.26,195.89 208.27,190.23" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="150" points="210.10,200.05 215.43,203.33 211.51,197.67 207.54,195.22" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="151" points="201.54,194.05 207.54,195.22 210.10,187.13 202.07,185.57" fill="#d49422" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="152" points="174.94,204.97 179.86,199.16 186.64,201.62 183.38,205.47" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="153" points="178.69,195.85 183.62,192.26 181.13,185.76 175.44,189.90" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="154" points="170.73,198.26 176.47,191.47 179.86,199.16 174.94,204.97" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="155" points="216.14,192.15 221.18,195.71 224.41,189.73 218.60,185.63" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="156" points="186.64,188.70 193.48,186.14 190.17,182.39 179.86,186.24" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="157" points="195.13,194.48 201.54,194.05 202.07,185.57 193.48,186.14" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="158" points="184.25,204.54 193.38,200.09 197.27,204.51 193.51,206.34" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="159" points="206.39,200.05 215.66,204.43 206.45,206.29 202.63,204.49" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="160" points="175.44,189.90 181.13,185.76 176.14,183.41 168.96,188.64" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="161" points="186.64,201.62 193.48,199.06 195.13,194.48 190.03,196.39" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="162" points="218.60,185.63 224.41,189.73 230.86,188.43 223.51,183.24" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="163" points="215.22,183.88 223.26,188.83 227.17,194.49 217.79,188.72" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="164" points="202.07,185.57 210.10,187.13 215.22,183.88 203.11,181.53" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="165" points="175.44,200.54 181.13,196.40 183.62,192.26 178.69,195.85" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="166" points="179.61,196.03 191.43,190.29 193.38,200.09 184.25,204.54" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="167" points="202.07,198.49 210.10,200.05 207.54,195.22 201.54,194.05" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="168" points="208.27,190.23 220.26,195.89 215.66,204.43 206.39,200.05" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="169" points="218.60,196.27 224.41,200.37 221.18,195.71 216.14,192.15" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="170" points="193.38,184.89 206.39,184.85 208.27,190.23 191.43,190.29" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="171" points="193.38,200.09 206.39,200.05 202.63,204.49 197.27,204.51" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="172" points="193.48,199.06 202.07,198.49 201.54,194.05 195.13,194.48" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="173" points="193.48,186.14 202.07,185.57 203.11,181.53 190.17,182.39" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="174" points="215.22,196.80 223.26,201.75 215.43,203.33 210.10,200.05" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="175" points="168.96,188.64 176.14,183.41 173.65,187.55 165.71,193.33" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="176" points="223.51,183.24 230.86,188.43 234.08,193.09 225.97,187.37" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="177" points="217.79,188.72 227.17,194.49 223.26,201.75 215.22,196.80" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="178" points="183.62,192.26 191.04,189.84 189.68,182.98 181.13,185.76" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="179" points="208.65,189.78 216.14,192.15 218.60,185.63 209.96,182.91" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="180" points="179.86,186.24 190.17,182.39 188.51,186.97 176.47,191.47" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="181" points="168.96,199.28 176.14,194.05 181.13,196.40 175.44,200.54" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="182" points="223.51,193.88 230.86,199.07 224.41,200.37 218.60,196.27" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="183" points="179.86,199.16 190.17,195.31 193.48,199.06 186.64,201.62" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="184" points="191.43,190.29 208.27,190.23 206.39,200.05 193.38,200.09" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="185" points="165.71,193.33 173.65,187.55 176.14,194.05 168.96,199.28" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="186" points="181.13,185.76 189.68,182.98 186.95,179.89 176.14,183.41" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="187" points="225.97,187.37 234.08,193.09 230.86,199.07 223.51,193.88" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="188" points="209.96,182.91 218.60,185.63 223.51,183.24 212.59,179.80" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="189" points="181.13,196.40 189.68,193.62 191.04,189.84 183.62,192.26" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="190" points="209.96,193.55 218.60,196.27 216.14,192.15 208.65,189.78" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="191" points="191.04,189.84 199.83,188.97 199.81,181.98 189.68,182.98" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="192" points="199.83,188.97 208.65,189.78 209.96,182.91 199.81,181.98" fill="#d49422" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="193" points="203.11,181.53 215.22,183.88 217.79,188.72 203.64,185.96" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="194" points="203.11,194.45 215.22,196.80 210.10,200.05 202.07,198.49" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="195" points="176.47,191.47 188.51,186.97 190.17,195.31 179.86,199.16" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="196" points="190.17,195.31 203.11,194.45 202.07,198.49 193.48,199.06" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="197" points="190.17,182.39 203.11,181.53 203.64,185.96 188.51,186.97" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="198" points="189.68,193.62 199.81,192.62 199.83,188.97 191.04,189.84" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="199" points="199.81,192.62 209.96,193.55 208.65,189.78 199.83,188.97" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="200" points="189.68,182.98 199.81,181.98 199.76,178.62 186.95,179.89" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="201" points="199.81,181.98 209.96,182.91 212.59,179.80 199.76,178.62" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="202" points="203.64,185.96 217.79,188.72 215.22,196.80 203.11,194.45" fill="#d49422" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="203" points="176.14,183.41 186.95,179.89 185.59,183.66 173.65,187.55" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="204" points="212.59,179.80 223.51,183.24 225.97,187.37 213.91,183.56" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="205" points="176.14,194.05 186.95,190.53 189.68,193.62 181.13,196.40" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="206" points="212.59,190.44 223.51,193.88 218.60,196.27 209.96,193.55" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="207" points="188.51,186.97 203.64,185.96 203.11,194.45 190.17,195.31" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="208" points="173.65,187.55 185.59,183.66 186.95,190.53 176.14,194.05" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="209" points="213.91,183.56 225.97,187.37 223.51,193.88 212.59,190.44" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="210" points="186.95,190.53 199.76,189.26 199.81,192.62 189.68,193.62" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="211" points="186.95,179.89 199.76,178.62 199.73,182.26 185.59,183.66" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="212" points="199.76,189.26 212.59,190.44 209.96,193.55 199.81,192.62" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="213" points="199.76,178.62 212.59,179.80 213.91,183.56 199.73,182.26" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="214" points="185.59,183.66 199.73,182.26 199.76,189.26 186.95,190.53" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="215" points="199.73,182.26 213.91,183.56 212.59,190.44 199.76,189.26" fill="#d49422" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-search-—-radar-rings');
var rd = radialData(el, 400);
var t = 0;
(function tick() {
t += 0.02;
var hovering = el.matches(':hover');
rd.forEach(function(d, i) {
var phase = d.dist * 0.02 + i * 0.1;
var wave = Math.sin(t * 0.3333333333333333 + phase);
if (hovering) {
// Radial push/pull
var mag = wave * 6;
d.el.style.transition = 'transform 0.3s ease';
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
} else {
// Gentle scale breathing
d.el.style.transition = 'none';
d.el.style.transform = 'scale(' + (1 + wave * 0.02) + ')';
}
});
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Search — radar rings</div>
<div class="card-desc">Concentric rings that pulse like search radar, breathing in and out.</div>
<span class="card-anim">breathe</span>
</div>
</div>
<div class="card">
<svg id="shape-search-—-octahedron-focus" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="200.00,125.41 233.10,237.53 121.71,215.87" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="1" points="200.00,125.41 278.29,184.13 233.10,237.53" fill="#b67e1c" stroke="#ffc206" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,274.59 121.71,215.87 233.10,237.53" fill="#8a5e14" stroke="#d49422" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="3" points="200.00,125.41 121.71,215.87 166.90,162.47" fill="#d49422" stroke="#ffe066" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="4" points="200.00,274.59 233.10,237.53 278.29,184.13" fill="#7a5210" stroke="#b67e1c" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,125.41 166.90,162.47 278.29,184.13" fill="#e4a024" stroke="#ffeb99" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="6" points="200.00,274.59 166.90,162.47 121.71,215.87" fill="#986816" stroke="#f0b400" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="7" points="200.00,274.59 278.29,184.13 166.90,162.47" fill="#a87218" stroke="#ffc206" stroke-width="1.8" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-search-—-octahedron-focus');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 20 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px) scale(0.92)';
d.el.style.transitionDelay = (i * 0.02) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0) scale(1)';
d.el.style.transitionDelay = (i * 0.01) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Search — octahedron focus</div>
<div class="card-desc">An octahedron that blooms open, revealing its inner structure — like finding a result.</div>
<span class="card-anim">bloom</span>
</div>
</div>
<div class="card">
<svg id="shape-search-—-lens-sphere" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="161.26,148.13 226.50,193.14 153.70,231.28" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="226.50,266.96 153.70,231.28 226.50,193.14" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="238.74,132.43 226.50,193.14 161.26,148.13" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="226.50,193.14 279.06,205.87 226.50,266.96" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="238.74,132.43 279.06,205.87 226.50,193.14" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="153.70,231.28 120.94,194.13 161.26,148.13" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="161.26,267.57 153.70,231.28 226.50,266.96" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="238.74,132.43 161.26,148.13 173.50,133.04" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="161.26,267.57 120.94,194.13 153.70,231.28" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="173.50,133.04 161.26,148.13 120.94,194.13" fill="#e4a024" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="238.74,251.87 226.50,266.96 279.06,205.87" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="238.74,132.43 246.30,168.72 279.06,205.87" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="161.26,267.57 226.50,266.96 238.74,251.87" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="238.74,132.43 173.50,133.04 246.30,168.72" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="279.06,205.87 246.30,168.72 238.74,251.87" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="161.26,267.57 173.50,206.86 120.94,194.13" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="120.94,194.13 173.50,206.86 173.50,133.04" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="161.26,267.57 238.74,251.87 173.50,206.86" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="246.30,168.72 173.50,133.04 173.50,206.86" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="173.50,206.86 238.74,251.87 246.30,168.72" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-search-—-lens-sphere');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
var t = 0;
el.addEventListener('mouseenter', function() {
g.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'scale(1.15)';
});
el.addEventListener('mouseleave', function() {
g.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'scale(1)';
});
(function idle() {
t += 0.02;
if (!el.matches(':hover')) {
var s = 1 + Math.sin(t * 0.25) * 0.03;
g.style.transition = 'none';
g.style.transform = 'scale(' + s + ')';
}
requestAnimationFrame(idle);
})();
})();</script>
<div class="card-info">
<div class="card-name">Search — lens sphere</div>
<div class="card-desc">Icosahedron faces that pulse gently like a scanning lens.</div>
<span class="card-anim">pulse</span>
</div>
</div>
</div>
</div>
<div class="feature-group">
<div class="feature-header">
<h2 class="feature-title">Natural language rename</h2>
<p class="feature-desc">"Make these lowercase and add date prefix" — no regex, no scripts, just words.</p>
</div>
<div class="variant-grid">
<div class="card">
<svg id="shape-rename-—-dual-arrows" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="132.84,188.95 171.52,146.71 182.43,159.07 143.74,201.31" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="157.98,192.45 132.84,188.95 143.74,201.31 168.89,204.82" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="143.74,201.31 168.89,204.82 168.89,247.82 195.96,242.33 195.96,199.33 221.11,185.63 182.43,159.07" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="171.52,146.71 210.21,173.27 221.11,185.63 182.43,159.07" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="242.02,164.54 214.94,170.03 204.04,157.67 231.11,152.18" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="157.98,235.46 157.98,192.45 168.89,204.82 168.89,247.82" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="210.21,173.27 185.06,186.97 195.96,199.33 221.11,185.63" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="214.94,170.03 214.94,213.03 204.04,200.67 204.04,157.67" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="171.52,146.71 210.21,173.27 185.06,186.97 185.06,229.97 157.98,235.46 157.98,192.45 132.84,188.95" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="228.48,253.29 267.16,211.05 242.02,207.55 242.02,164.54 214.94,170.03 214.94,213.03 189.79,226.73" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="185.06,186.97 185.06,229.97 195.96,242.33 195.96,199.33" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="214.94,213.03 189.79,226.73 178.89,214.37 204.04,200.67" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="242.02,207.55 242.02,164.54 231.11,152.18 231.11,195.18" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="185.06,229.97 157.98,235.46 168.89,247.82 195.96,242.33" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="189.79,226.73 228.48,253.29 217.57,240.93 178.89,214.37" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="178.89,214.37 204.04,200.67 204.04,157.67 231.11,152.18 231.11,195.18 256.26,198.69 217.57,240.93" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="267.16,211.05 242.02,207.55 231.11,195.18 256.26,198.69" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="228.48,253.29 267.16,211.05 256.26,198.69 217.57,240.93" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-rename-—-dual-arrows');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
var t = 0;
el.addEventListener('mouseenter', function() {
g.style.transition = 'transform 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55)';
g.style.transform = 'perspective(600px) rotateY(180deg) scale(0.9)';
});
el.addEventListener('mouseleave', function() {
g.style.transition = 'transform 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55)';
g.style.transform = 'perspective(600px) rotateY(0deg) scale(1)';
});
(function idle() {
t += 0.015;
if (!el.matches(':hover')) {
g.style.transition = 'none';
g.style.transform = 'perspective(600px) rotateY(' + (Math.sin(t) * 3) + 'deg)';
}
requestAnimationFrame(idle);
})();
})();</script>
<div class="card-info">
<div class="card-name">Rename — dual arrows</div>
<div class="card-desc">Two opposing arrows — input transforms to output. Flips on hover.</div>
<span class="card-anim">flip</span>
</div>
</div>
<div class="card">
<svg id="shape-rename-—-crystal-morph" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="186.80,165.96 201.71,201.22 185.75,202.62" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="1" points="186.80,165.96 185.75,202.62 171.67,201.45" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="2" points="185.09,172.80 202.24,205.50 181.90,211.81" fill="#f0b400" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="3" points="188.45,234.13 185.75,202.62 201.71,201.22" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="4" points="185.09,172.80 181.90,211.81 163.98,201.81" fill="#f0b400" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="5" points="188.45,234.13 171.67,201.45 185.75,202.62" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="6" points="186.80,165.96 203.58,198.64 201.71,201.22" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="7" points="202.47,166.02 219.10,202.49 198.24,208.41" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="8" points="202.47,166.02 198.24,208.41 180.04,198.03" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="9" points="185.09,172.80 204.68,189.20 202.24,205.50" fill="#f0b400" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="10" points="186.80,165.96 171.67,201.45 173.55,198.88" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="11" points="188.45,234.13 201.71,201.22 203.58,198.64" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="12" points="185.09,172.80 163.98,201.81 166.41,185.50" fill="#f0b400" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="13" points="188.45,234.13 173.55,198.88 171.67,201.45" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="14" points="200.70,174.15 215.16,195.33 197.08,194.50" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="15" points="202.47,166.02 221.75,186.18 219.10,202.49" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="16" points="200.70,174.15 197.08,194.50 180.39,190.56" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="17" points="202.47,166.02 180.04,198.03 182.69,181.72" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="18" points="186.80,165.96 189.50,197.47 203.58,198.64" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="19" points="196.23,208.63 197.08,194.50 215.16,195.33" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="20" points="196.23,208.63 180.39,190.56 197.08,194.50" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="21" points="185.09,172.80 186.76,179.19 204.68,189.20" fill="#f0b400" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="22" points="186.80,165.96 173.55,198.88 189.50,197.47" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="23" points="185.09,172.80 166.41,185.50 186.76,179.19" fill="#f0b400" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="24" points="183.57,218.20 181.90,211.81 202.24,205.50" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="25" points="183.57,218.20 163.98,201.81 181.90,211.81" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="26" points="188.45,234.13 203.58,198.64 189.50,197.47" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="27" points="188.45,234.13 189.50,197.47 173.55,198.88" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="28" points="202.47,166.02 203.55,175.80 221.75,186.18" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="29" points="202.47,166.02 182.69,181.72 203.55,175.80" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="30" points="200.70,174.15 216.55,192.22 215.16,195.33" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="31" points="200.70,174.15 180.39,190.56 181.77,187.44" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="32" points="199.32,218.19 198.24,208.41 219.10,202.49" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="33" points="183.57,218.20 202.24,205.50 204.68,189.20" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="34" points="196.23,208.63 215.16,195.33 216.55,192.22" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="35" points="199.32,218.19 180.04,198.03 198.24,208.41" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="36" points="196.23,208.63 181.77,187.44 180.39,190.56" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="37" points="183.57,218.20 166.41,185.50 163.98,201.81" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="38" points="199.32,218.19 219.10,202.49 221.75,186.18" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="39" points="183.57,218.20 204.68,189.20 186.76,179.19" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="40" points="199.32,218.19 182.69,181.72 180.04,198.03" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="41" points="183.57,218.20 186.76,179.19 166.41,185.50" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="42" points="200.70,174.15 199.85,188.28 216.55,192.22" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="43" points="200.70,174.15 181.77,187.44 199.85,188.28" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="44" points="196.23,208.63 216.55,192.22 199.85,188.28" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="45" points="196.23,208.63 199.85,188.28 181.77,187.44" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="46" points="199.32,218.19 221.75,186.18 203.55,175.80" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="47" points="199.32,218.19 203.55,175.80 182.69,181.72" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-rename-—-crystal-morph');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 0%';
var t = 0, hovering = false;
el.addEventListener('mouseenter', function() { hovering = true; });
el.addEventListener('mouseleave', function() { hovering = false; });
(function tick() {
t += 0.04;
if (hovering) {
g.style.transition = 'none';
g.style.transform = 'rotate(' + (Math.sin(t * 3) * 12 * Math.exp(-(t * 0.3) % 1)) + 'deg)';
} else {
g.style.transition = 'transform 0.5s ease';
g.style.transform = 'rotate(' + (Math.sin(t * 0.1) * 3) + 'deg)';
}
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Rename — crystal morph</div>
<div class="card-desc">A crystal cluster that swings — raw text morphing into structured names.</div>
<span class="card-anim">swing</span>
</div>
</div>
<div class="card">
<svg id="shape-rename-—-star-transform" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="233.10,222.18 195.32,202.72 195.32,233.44 233.10,252.89" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="195.32,202.72 148.75,217.15 148.75,247.87 195.32,233.44" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="230.32,195.63 233.10,222.18 233.10,252.89 230.32,226.34" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="148.75,217.15 165.00,191.74 165.00,222.45 148.75,247.87" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="284.35,189.67 230.32,195.63 230.32,226.34 284.35,220.38" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="166.90,147.11 204.68,166.56 251.25,152.13 235.00,177.55 284.35,189.67 230.32,195.63 233.10,222.18 195.32,202.72 148.75,217.15 165.00,191.74 115.65,179.62 169.68,173.66" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="165.00,191.74 115.65,179.62 115.65,210.33 165.00,222.45" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="235.00,177.55 284.35,189.67 284.35,220.38 235.00,208.26" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="169.68,204.37 115.65,210.33 165.00,222.45 148.75,247.87 195.32,233.44 233.10,252.89 230.32,226.34 284.35,220.38 235.00,208.26 251.25,182.85 204.68,197.28 166.90,177.82" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="115.65,179.62 169.68,173.66 169.68,204.37 115.65,210.33" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="251.25,152.13 235.00,177.55 235.00,208.26 251.25,182.85" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="169.68,173.66 166.90,147.11 166.90,177.82 169.68,204.37" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="204.68,166.56 251.25,152.13 251.25,182.85 204.68,197.28" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="166.90,147.11 204.68,166.56 204.68,197.28 166.90,177.82" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-rename-—-star-transform');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 25 + d.dist * 0.5;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
// Staggered delay creates the spiral wave feel
d.el.style.transitionDelay = (i * 0.03) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0)';
d.el.style.transitionDelay = (i * 0.015) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Rename — star transform</div>
<div class="card-desc">A star prism that spirals outward — transformation in motion.</div>
<span class="card-anim">spiral</span>
</div>
</div>
</div>
</div>
<div class="feature-group">
<div class="feature-header">
<h2 class="feature-title">AI batch operations</h2>
<p class="feature-desc">Organize hundreds of files with a single command: "Sort these into folders by project."</p>
</div>
<div class="variant-grid">
<div class="card">
<svg id="shape-batch-—-scattered-cubes" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="191.31,211.58 171.83,215.52 171.83,234.08 191.31,230.14" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="171.83,215.52 191.31,211.58 183.07,202.24 163.59,206.19" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="171.83,215.52 163.59,206.19 163.59,224.74 171.83,234.08" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="183.07,202.24 191.31,211.58 191.31,230.14 183.07,220.80" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="163.59,224.74 183.07,220.80 191.31,230.14 171.83,234.08" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="163.59,206.19 183.07,202.24 183.07,220.80 163.59,224.74" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="256.83,182.47 234.71,186.95 234.71,208.03 256.83,203.54" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="234.71,186.95 256.83,182.47 247.48,171.86 225.36,176.35" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="234.71,186.95 225.36,176.35 225.36,197.42 234.71,208.03" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="187.43,205.81 174.42,208.45 174.42,220.85 187.43,218.21" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="247.48,171.86 256.83,182.47 256.83,203.54 247.48,192.94" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="174.42,208.45 187.43,205.81 181.93,199.57 168.91,202.21" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="174.42,208.45 168.91,202.21 168.91,214.61 174.42,220.85" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="261.06,183.25 245.36,186.44 245.36,201.39 261.06,198.21" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="225.36,197.42 247.48,192.94 256.83,203.54 234.71,208.03" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="245.36,186.44 261.06,183.25 254.42,175.73 238.73,178.91" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="245.36,186.44 238.73,178.91 238.73,193.87 245.36,201.39" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="225.36,176.35 247.48,171.86 247.48,192.94 225.36,197.42" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="181.93,199.57 187.43,205.81 187.43,218.21 181.93,211.97" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="168.91,214.61 181.93,211.97 187.43,218.21 174.42,220.85" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="168.91,202.21 181.93,199.57 181.93,211.97 168.91,214.61" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="254.42,175.73 261.06,183.25 261.06,198.21 254.42,190.68" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="238.73,193.87 254.42,190.68 261.06,198.21 245.36,201.39" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="266.63,218.96 253.01,221.73 253.01,234.71 266.63,231.95" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="230.96,204.67 207.65,209.40 207.65,231.61 230.96,226.89" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="238.73,178.91 254.42,175.73 254.42,190.68 238.73,193.87" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="253.01,221.73 266.63,218.96 260.87,212.43 247.25,215.19" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="253.01,221.73 247.25,215.19 247.25,228.18 253.01,234.71" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="207.65,209.40 230.96,204.67 221.11,193.49 197.79,198.22" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="207.65,209.40 197.79,198.22 197.79,220.44 207.65,231.61" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="30" points="260.87,212.43 266.63,218.96 266.63,231.95 260.87,225.41" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="31" points="256.73,204.63 243.27,207.36 243.27,220.18 256.73,217.45" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="32" points="247.25,228.18 260.87,225.41 266.63,231.95 253.01,234.71" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="33" points="243.27,207.36 256.73,204.63 251.04,198.18 237.58,200.91" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="34" points="247.25,215.19 260.87,212.43 260.87,225.41 247.25,228.18" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="35" points="243.27,207.36 237.58,200.91 237.58,213.73 243.27,220.18" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="36" points="221.11,193.49 230.96,204.67 230.96,226.89 221.11,215.71" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="37" points="251.04,198.18 256.73,204.63 256.73,217.45 251.04,211.00" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="38" points="197.79,220.44 221.11,215.71 230.96,226.89 207.65,231.61" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="39" points="237.58,213.73 251.04,211.00 256.73,217.45 243.27,220.18" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="40" points="237.58,200.91 251.04,198.18 251.04,211.00 237.58,213.73" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="41" points="197.79,198.22 221.11,193.49 221.11,215.71 197.79,220.44" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="42" points="167.24,203.53 154.42,206.13 154.42,218.34 167.24,215.74" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="43" points="154.42,206.13 167.24,203.53 161.82,197.39 149.01,199.99" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="44" points="154.42,206.13 149.01,199.99 149.01,212.20 154.42,218.34" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="45" points="222.56,156.12 209.93,158.68 209.93,170.71 222.56,168.15" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="46" points="161.82,197.39 167.24,203.53 167.24,215.74 161.82,209.60" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="47" points="149.01,212.20 161.82,209.60 167.24,215.74 154.42,218.34" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="48" points="209.93,158.68 222.56,156.12 217.22,150.07 204.60,152.63" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="49" points="209.93,158.68 204.60,152.63 204.60,164.66 209.93,170.71" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="50" points="149.01,199.99 161.82,197.39 161.82,209.60 149.01,212.20" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="51" points="217.22,150.07 222.56,156.12 222.56,168.15 217.22,162.10" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="52" points="204.60,164.66 217.22,162.10 222.56,168.15 209.93,170.71" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="53" points="204.60,152.63 217.22,150.07 217.22,162.10 204.60,164.66" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-batch-—-scattered-cubes');
var rd = radialData(el, 400);
rd.forEach(function(d) {
var mag = 35 + d.dist * 0.35;
d.el.style.transition = 'transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)';
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
d.el.style.transform = 'translate(0, 0)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) {
var mag = 35 + d.dist * 0.35;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Batch — scattered cubes</div>
<div class="card-desc">Scattered cubes that snap together into formation on hover — chaos to order.</div>
<span class="card-anim">assemble</span>
</div>
</div>
<div class="card">
<svg id="shape-batch-—-radial-sort" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="206.86,225.05 158.70,219.68 158.70,246.01 206.86,251.38" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="252.40,215.82 206.86,225.05 206.86,251.38 252.40,242.15" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,186.84 206.86,225.05 158.70,219.68" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="200.00,186.84 252.40,215.82 206.86,225.05" fill="#c48a1e" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="158.70,219.68 126.32,201.77 126.32,228.10 158.70,246.01" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,186.84 158.70,219.68 126.32,201.77" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="200.00,213.16 158.70,246.01 206.86,251.38" fill="#6b480c" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="277.92,195.52 252.40,215.82 252.40,242.15 277.92,221.84" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="200.00,213.16 206.86,251.38 252.40,242.15" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="200.00,186.84 277.92,195.52 252.40,215.82" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="200.00,213.16 126.32,228.10 158.70,246.01" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="200.00,213.16 252.40,242.15 277.92,221.84" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="200.00,186.84 126.32,201.77 122.08,178.16" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="126.32,201.77 122.08,178.16 122.08,204.48 126.32,228.10" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="200.00,186.84 273.68,171.90 277.92,195.52" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="200.00,213.16 122.08,204.48 126.32,228.10" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="273.68,171.90 277.92,195.52 277.92,221.84 273.68,198.23" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="200.00,213.16 277.92,221.84 273.68,198.23" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="200.00,186.84 122.08,178.16 147.60,157.85" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="200.00,186.84 241.30,153.99 273.68,171.90" fill="#ffc206" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="200.00,213.16 147.60,184.18 122.08,204.48" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="200.00,186.84 147.60,157.85 193.14,148.62" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="122.08,178.16 147.60,157.85 147.60,184.18 122.08,204.48" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="200.00,186.84 193.14,148.62 241.30,153.99" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="24" points="200.00,213.16 273.68,198.23 241.30,180.32" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="25" points="241.30,153.99 273.68,171.90 273.68,198.23 241.30,180.32" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="26" points="200.00,213.16 193.14,174.95 147.60,184.18" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="27" points="200.00,213.16 241.30,180.32 193.14,174.95" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="28" points="147.60,157.85 193.14,148.62 193.14,174.95 147.60,184.18" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="29" points="193.14,148.62 241.30,153.99 241.30,180.32 193.14,174.95" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-batch-—-radial-sort');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 20 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px) scale(0.92)';
d.el.style.transitionDelay = (i * 0.02) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0) scale(1)';
d.el.style.transitionDelay = (i * 0.01) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Batch — radial sort</div>
<div class="card-desc">Triangular wedges blooming outward — files fanning into organized groups.</div>
<span class="card-anim">bloom</span>
</div>
</div>
<div class="card">
<svg id="shape-batch-—-hex-organize" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="271.80,210.66 188.90,227.46 188.90,258.18 271.80,241.37" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="260.09,207.81 184.96,220.28 184.96,248.43 260.09,235.96" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="188.90,227.46 117.10,201.45 117.10,232.16 188.90,258.18" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="249.03,204.34 182.47,213.05 182.47,238.65 249.03,229.93" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="184.96,220.28 124.88,195.32 124.88,223.48 184.96,248.43" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="182.47,213.05 133.44,189.78 133.44,215.37 182.47,238.65" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="266.56,172.34 249.03,204.34 249.03,229.93 266.56,197.94" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="275.12,170.38 260.09,207.81 260.09,235.96 275.12,198.54" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="266.56,172.34 249.03,204.34 182.47,213.05 133.44,189.78 150.97,157.78 217.53,149.06" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="275.12,170.38 260.09,207.81 184.96,220.28 124.88,195.32 139.91,157.89 215.04,145.42" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="282.90,167.84 271.80,210.66 271.80,241.37 282.90,198.55" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="282.90,167.84 271.80,210.66 188.90,227.46 117.10,201.45 128.20,158.63 211.10,141.82" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="217.53,174.66 150.97,183.38 133.44,215.37 182.47,238.65 249.03,229.93 266.56,197.94" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="215.04,173.58 139.91,186.05 124.88,223.48 184.96,248.43 260.09,235.96 275.12,198.54" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="211.10,172.54 128.20,189.34 117.10,232.16 188.90,258.18 271.80,241.37 282.90,198.55" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="117.10,201.45 128.20,158.63 128.20,189.34 117.10,232.16" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="124.88,195.32 139.91,157.89 139.91,186.05 124.88,223.48" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="133.44,189.78 150.97,157.78 150.97,183.38 133.44,215.37" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="217.53,149.06 266.56,172.34 266.56,197.94 217.53,174.66" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="215.04,145.42 275.12,170.38 275.12,198.54 215.04,173.58" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="150.97,157.78 217.53,149.06 217.53,174.66 150.97,183.38" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="211.10,141.82 282.90,167.84 282.90,198.55 211.10,172.54" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="139.91,157.89 215.04,145.42 215.04,173.58 139.91,186.05" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="128.20,158.63 211.10,141.82 211.10,172.54 128.20,189.34" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-batch-—-hex-organize');
var rd = radialData(el, 400);
var g = el.querySelector('.shape-group');
var t = 0;
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
(function idleTick() {
t += 0.15;
if (!el.matches(':hover')) {
g.style.transform = 'rotate(' + (Math.sin(t * 0.02) * 2) + 'deg)';
}
requestAnimationFrame(idleTick);
})();
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
// Strictly radial: magnitude = base + proportional to distance from center
var mag = 30 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) { d.el.style.transform = 'translate(0, 0)'; });
});
})();</script>
<div class="card-info">
<div class="card-name">Batch — hex organize</div>
<div class="card-desc">Nested hexagons that explode apart — visualizing batch file processing.</div>
<span class="card-anim">explode</span>
</div>
</div>
</div>
</div>
<!-- Divider -->
<div class="divider"><span>Abstract gallery</span></div>
<!-- Original gallery shapes -->
<div class="gallery-grid">
<div class="card">
<svg id="shape-nested-hexagons" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="279.78,206.97 187.67,225.64 187.67,269.52 279.78,250.85" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="266.77,203.23 183.29,217.09 183.29,257.31 266.77,243.45" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="254.47,198.80 180.52,208.49 180.52,245.06 254.47,235.37" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="187.67,225.64 107.89,196.73 107.89,240.61 187.67,269.52" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="183.29,217.09 116.53,189.36 116.53,229.58 183.29,257.31" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="180.52,208.49 126.04,182.63 126.04,219.19 180.52,245.06" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="273.96,163.26 254.47,198.80 254.47,235.37 273.96,199.82" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="283.47,161.64 266.77,203.23 266.77,243.45 283.47,201.87" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="273.96,163.26 254.47,198.80 180.52,208.49 126.04,182.63 145.53,147.08 219.48,137.39" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="283.47,161.64 266.77,203.23 183.29,217.09 116.53,189.36 133.23,147.77 216.71,133.92" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="292.11,159.39 279.78,206.97 187.67,225.64 107.89,196.73 120.22,149.15 212.33,130.48" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="292.11,159.39 279.78,206.97 279.78,250.85 292.11,203.27" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="219.48,173.96 145.53,183.64 126.04,219.19 180.52,245.06 254.47,235.37 273.96,199.82" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="216.71,174.14 133.23,187.99 116.53,229.58 183.29,257.31 266.77,243.45 283.47,201.87" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="107.89,196.73 120.22,149.15 120.22,193.03 107.89,240.61" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="126.04,182.63 145.53,147.08 145.53,183.64 126.04,219.19" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="116.53,189.36 133.23,147.77 133.23,187.99 116.53,229.58" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="212.33,174.36 120.22,193.03 107.89,240.61 187.67,269.52 279.78,250.85 292.11,203.27" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="219.48,137.39 273.96,163.26 273.96,199.82 219.48,173.96" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="216.71,133.92 283.47,161.64 283.47,201.87 216.71,174.14" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="145.53,147.08 219.48,137.39 219.48,173.96 145.53,183.64" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="212.33,130.48 292.11,159.39 292.11,203.27 212.33,174.36" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="133.23,147.77 216.71,133.92 216.71,174.14 133.23,187.99" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="120.22,149.15 212.33,130.48 212.33,174.36 120.22,193.03" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-nested-hexagons');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
var t = 0, mouseX = 0, mouseY = 0, hovering = false;
el.addEventListener('mouseenter', function() { hovering = true; });
el.addEventListener('mouseleave', function() { hovering = false; });
el.addEventListener('mousemove', function(e) {
var rect = el.getBoundingClientRect();
mouseX = (e.clientX - rect.left) / rect.width - 0.5;
mouseY = (e.clientY - rect.top) / rect.height - 0.5;
});
(function tick() {
t += 0.03;
var floatY = Math.sin(t * 0.16666666666666666) * 6;
var floatR = Math.sin(t * 0.11666666666666665) * 2;
if (hovering) {
g.style.transition = 'transform 0.2s ease-out';
g.style.transform = 'translateY(' + floatY + 'px) perspective(400px) rotateX(' + (mouseY * -15) + 'deg) rotateY(' + (mouseX * 15) + 'deg)';
} else {
g.style.transition = 'transform 0.6s ease-out';
g.style.transform = 'translateY(' + floatY + 'px) rotate(' + floatR + 'deg)';
}
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Nested hexagons</div>
<div class="card-desc">Three concentric hexagonal prisms, gently floating. Tilts toward cursor on hover.</div>
<span class="card-anim">float</span>
</div>
</div>
<div class="card">
<svg id="shape-exploding-cube" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="272.08,165.75 170.76,186.29 170.76,282.82 272.08,262.29" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="170.76,186.29 272.08,165.75 229.24,117.18 127.92,137.71" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="170.76,186.29 127.92,137.71 127.92,234.25 170.76,282.82" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="229.24,117.18 272.08,165.75 272.08,262.29 229.24,213.71" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="127.92,234.25 229.24,213.71 272.08,262.29 170.76,282.82" fill="#f0b400" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="127.92,137.71 229.24,117.18 229.24,213.71 127.92,234.25" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-exploding-cube');
var rd = radialData(el, 400);
var g = el.querySelector('.shape-group');
var t = 0;
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
(function idleTick() {
t += 0.15;
if (!el.matches(':hover')) {
g.style.transform = 'rotate(' + (Math.sin(t * 0.02) * 2) + 'deg)';
}
requestAnimationFrame(idleTick);
})();
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
// Strictly radial: magnitude = base + proportional to distance from center
var mag = 30 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) { d.el.style.transform = 'translate(0, 0)'; });
});
})();</script>
<div class="card-info">
<div class="card-name">Exploding cube</div>
<div class="card-desc">A golden cube that blows apart into its six faces when you hover, then reassembles.</div>
<span class="card-anim">explode</span>
</div>
</div>
<div class="card">
<svg id="shape-pyramid-pulse" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="200.00,147.35 258.95,285.26 153.54,289.61" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="200.00,147.35 153.54,289.61 112.34,242.89" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,147.35 282.90,235.85 258.95,285.26" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="192.28,209.67 112.34,242.89 153.54,289.61 258.95,285.26 282.90,235.85" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="200.00,147.35 112.34,242.89 192.28,209.67" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,147.35 192.28,209.67 282.90,235.85" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-pyramid-pulse');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
var t = 0;
el.addEventListener('mouseenter', function() {
g.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'scale(1.15)';
});
el.addEventListener('mouseleave', function() {
g.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'scale(1)';
});
(function idle() {
t += 0.02;
if (!el.matches(':hover')) {
var s = 1 + Math.sin(t * 0.2) * 0.03;
g.style.transition = 'none';
g.style.transform = 'scale(' + s + ')';
}
requestAnimationFrame(idle);
})();
})();</script>
<div class="card-info">
<div class="card-name">Pyramid pulse</div>
<div class="card-desc">A pentagonal pyramid with a subtle breathing pulse. Swells on hover.</div>
<span class="card-anim">pulse</span>
</div>
</div>
<div class="card">
<svg id="shape-octahedron-bloom" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="200.00,121.02 235.05,239.74 117.10,216.80" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="1" points="200.00,121.02 282.90,183.20 235.05,239.74" fill="#b67e1c" stroke="#ffc206" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,278.98 117.10,216.80 235.05,239.74" fill="#8a5e14" stroke="#d49422" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="3" points="200.00,121.02 117.10,216.80 164.95,160.26" fill="#d49422" stroke="#ffe066" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="4" points="200.00,278.98 235.05,239.74 282.90,183.20" fill="#7a5210" stroke="#b67e1c" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,121.02 164.95,160.26 282.90,183.20" fill="#e4a024" stroke="#ffeb99" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="6" points="200.00,278.98 164.95,160.26 117.10,216.80" fill="#986816" stroke="#f0b400" stroke-width="1.8" stroke-linejoin="round"/>
<polygon data-face="7" points="200.00,278.98 282.90,183.20 164.95,160.26" fill="#a87218" stroke="#ffc206" stroke-width="1.8" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-octahedron-bloom');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.8s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 20 + d.dist * 0.4;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px) scale(0.92)';
d.el.style.transitionDelay = (i * 0.02) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0) scale(1)';
d.el.style.transitionDelay = (i * 0.01) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Octahedron bloom</div>
<div class="card-desc">An octahedron whose eight faces peel open like a flower when hovered.</div>
<span class="card-anim">bloom</span>
</div>
</div>
<div class="card">
<svg id="shape-gem-wobble" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="215.58,162.38 184.96,162.48 169.93,223.25 231.15,223.04" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="184.96,162.48 163.16,152.18 126.32,202.65 169.93,223.25" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="200.00,138.57 215.58,162.38 184.96,162.48" fill="#ffd23f" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="3" points="237.07,151.92 215.58,162.38 231.15,223.04 274.13,202.13" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="200.00,138.57 184.96,162.48 163.16,152.18" fill="#f0b400" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,138.57 237.07,151.92 215.58,162.38" fill="#ffc206" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="6" points="231.15,223.04 169.93,223.25 200.00,261.43" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="200.00,138.57 163.16,152.18 162.93,137.50" fill="#ffc206" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="8" points="200.00,138.57 236.84,137.24 237.07,151.92" fill="#f0b400" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="9" points="169.93,223.25 126.32,202.65 200.00,261.43" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="274.13,202.13 231.15,223.04 200.00,261.43" fill="#6b480c" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="163.16,152.18 162.93,137.50 125.87,173.30 126.32,202.65" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="236.84,137.24 237.07,151.92 274.13,202.13 273.68,172.78" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="200.00,138.57 162.93,137.50 184.42,127.05" fill="#ffd23f" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="14" points="200.00,138.57 215.04,126.94 236.84,137.24" fill="#ffc206" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="15" points="200.00,138.57 184.42,127.05 215.04,126.94" fill="#f0b400" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="16" points="126.32,202.65 125.87,173.30 200.00,261.43" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="273.68,172.78 274.13,202.13 200.00,261.43" fill="#6b480c" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="162.93,137.50 184.42,127.05 168.85,152.39 125.87,173.30" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="215.04,126.94 236.84,137.24 273.68,172.78 230.07,152.17" fill="#e4a024" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="184.42,127.05 215.04,126.94 230.07,152.17 168.85,152.39" fill="#e4a024" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="125.87,173.30 168.85,152.39 200.00,261.43" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="230.07,152.17 273.68,172.78 200.00,261.43" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="168.85,152.39 230.07,152.17 200.00,261.43" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-gem-wobble');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
el.addEventListener('mouseenter', function() {
g.style.transition = 'transform 0.15s ease';
g.style.transform = 'rotate(8deg) scale(1.05)';
setTimeout(function() {
g.style.transition = 'transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'rotate(-5deg) scale(1.05)';
setTimeout(function() { g.style.transform = 'rotate(0deg) scale(1.05)'; }, 300);
}, 150);
});
el.addEventListener('mouseleave', function() {
g.style.transition = 'transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)';
g.style.transform = 'rotate(0deg) scale(1)';
});
})();</script>
<div class="card-info">
<div class="card-name">Gem wobble</div>
<div class="card-desc">A faceted gemstone that wobbles playfully when touched.</div>
<span class="card-anim">wobble</span>
</div>
</div>
<div class="card">
<svg id="shape-star-spiral" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="217.52,202.32 177.37,229.15 177.37,264.25 217.52,237.42" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="177.37,229.15 166.00,196.58 166.00,231.68 177.37,264.25" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="285.64,207.20 217.52,202.32 217.52,237.42 285.64,242.30" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="244.83,180.60 285.64,207.20 285.64,242.30 244.83,215.70" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="166.00,196.58 100.37,186.56 100.37,221.66 166.00,231.68" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="161.06,138.29 210.19,161.43 275.56,151.05 244.83,180.60 285.64,207.20 217.52,202.32 177.37,229.15 166.00,196.58 100.37,186.56 161.46,171.31" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="100.37,186.56 161.46,171.31 161.46,206.41 100.37,221.66" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="161.46,206.41 100.37,221.66 166.00,231.68 177.37,264.25 217.52,237.42 285.64,242.30 244.83,215.70 275.56,186.15 210.19,196.54 161.06,173.39" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="275.56,151.05 244.83,180.60 244.83,215.70 275.56,186.15" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="210.19,161.43 275.56,151.05 275.56,186.15 210.19,196.54" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="161.46,171.31 161.06,138.29 161.06,173.39 161.46,206.41" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="161.06,138.29 210.19,161.43 210.19,196.54 161.06,173.39" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-star-spiral');
var rd = radialData(el, 400);
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.6s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
var mag = 25 + d.dist * 0.5;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
// Staggered delay creates the spiral wave feel
d.el.style.transitionDelay = (i * 0.03) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d, i) {
d.el.style.transform = 'translate(0, 0)';
d.el.style.transitionDelay = (i * 0.015) + 's';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Star spiral</div>
<div class="card-desc">A five-pointed star prism whose faces spiral outward on hover with staggered timing.</div>
<span class="card-anim">spiral</span>
</div>
</div>
<div class="card">
<svg id="shape-radial-assembly" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="235.05,224.38 166.17,224.63 166.17,255.34 235.05,255.10" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="200.00,184.64 235.05,224.38 166.17,224.63" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="166.17,224.63 117.10,201.45 117.10,232.16 166.17,255.34" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="283.40,200.86 235.05,224.38 235.05,255.10 283.40,231.58" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="200.00,184.64 166.17,224.63 117.10,201.45" fill="#d49422" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="200.00,184.64 283.40,200.86 235.05,224.38" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="200.00,215.36 166.17,255.34 235.05,255.10" fill="#6b480c" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="200.00,215.36 117.10,232.16 166.17,255.34" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="200.00,215.36 235.05,255.10 283.40,231.58" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="200.00,184.64 117.10,201.45 116.60,168.42" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="200.00,184.64 282.90,167.84 283.40,200.86" fill="#b67e1c" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="117.10,201.45 116.60,168.42 116.60,199.14 117.10,232.16" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="282.90,167.84 283.40,200.86 283.40,231.58 282.90,198.55" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="200.00,215.36 116.60,199.14 117.10,232.16" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="200.00,215.36 283.40,231.58 282.90,198.55" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="200.00,184.64 116.60,168.42 164.95,144.90" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="200.00,184.64 233.83,144.66 282.90,167.84" fill="#ffc206" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="200.00,184.64 164.95,144.90 233.83,144.66" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="200.00,215.36 164.95,175.62 116.60,199.14" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="200.00,215.36 282.90,198.55 233.83,175.37" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="20" points="116.60,168.42 164.95,144.90 164.95,175.62 116.60,199.14" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="21" points="233.83,144.66 282.90,167.84 282.90,198.55 233.83,175.37" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="22" points="200.00,215.36 233.83,175.37 164.95,175.62" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="23" points="164.95,144.90 233.83,144.66 233.83,175.37 164.95,175.62" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-radial-assembly');
var rd = radialData(el, 400);
rd.forEach(function(d) {
var mag = 35 + d.dist * 0.35;
d.el.style.transition = 'transform 0.7s cubic-bezier(0.34, 1.56, 0.64, 1)';
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d) {
d.el.style.transform = 'translate(0, 0)';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) {
var mag = 35 + d.dist * 0.35;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Radial assembly</div>
<div class="card-desc">Eight triangular wedges scattered apart, snapping together into a solid ring on hover.</div>
<span class="card-anim">assemble</span>
</div>
</div>
<div class="card">
<svg id="shape-icosahedron-scatter" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="158.84,144.89 228.16,192.71 150.80,233.23" fill="#e4a024" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="228.16,271.15 150.80,233.23 228.16,192.71" fill="#986816" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="241.16,128.20 228.16,192.71 158.84,144.89" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="228.16,192.71 284.00,206.23 228.16,271.15" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="241.16,128.20 284.00,206.23 228.16,192.71" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="150.80,233.23 116.00,193.77 158.84,144.89" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="158.84,271.80 150.80,233.23 228.16,271.15" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="241.16,128.20 158.84,144.89 171.84,128.85" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="158.84,271.80 116.00,193.77 150.80,233.23" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="9" points="171.84,128.85 158.84,144.89 116.00,193.77" fill="#e4a024" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="10" points="241.16,255.11 228.16,271.15 284.00,206.23" fill="#8a5e14" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="11" points="241.16,128.20 249.20,166.77 284.00,206.23" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="12" points="158.84,271.80 228.16,271.15 241.16,255.11" fill="#6b480c" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="13" points="241.16,128.20 171.84,128.85 249.20,166.77" fill="#c48a1e" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="14" points="284.00,206.23 249.20,166.77 241.16,255.11" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="15" points="158.84,271.80 171.84,207.29 116.00,193.77" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="16" points="116.00,193.77 171.84,207.29 171.84,128.85" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="17" points="158.84,271.80 241.16,255.11 171.84,207.29" fill="#7a5210" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="18" points="249.20,166.77 171.84,128.85 171.84,207.29" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="19" points="171.84,207.29 241.16,255.11 249.20,166.77" fill="#a87218" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-icosahedron-scatter');
var rd = radialData(el, 400);
var rand = function(seed) { var x = Math.sin(seed * 127.1 + 311.7) * 43758.5453; return x - Math.floor(x); };
rd.forEach(function(d) {
d.el.style.transition = 'transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1)';
});
el.addEventListener('mouseenter', function() {
rd.forEach(function(d, i) {
// Radial direction, random magnitude (20–80px range)
var mag = 20 + rand(i * 7) * 60;
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
d.el.style.transitionDelay = (rand(i * 5) * 0.15) + 's';
});
});
el.addEventListener('mouseleave', function() {
rd.forEach(function(d) {
d.el.style.transform = 'translate(0, 0)';
d.el.style.transitionDelay = '0s';
});
});
})();</script>
<div class="card-info">
<div class="card-name">Icosahedron scatter</div>
<div class="card-desc">Twenty triangular faces that fly apart in random directions when you hover.</div>
<span class="card-anim">scatter</span>
</div>
</div>
<div class="card">
<svg id="shape-torus-breathe" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="229.60,216.84 190.63,219.44 189.27,241.39 233.88,238.42" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="1" points="190.63,219.44 154.18,212.35 147.54,233.28 189.27,241.39" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="2" points="233.88,238.42 189.27,241.39 190.63,252.88 229.60,250.28" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="3" points="221.03,207.13 193.34,208.97 190.63,219.44 229.60,216.84" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="4" points="193.34,208.97 167.44,203.93 154.18,212.35 190.63,219.44" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="5" points="189.27,241.39 147.54,233.28 154.18,245.79 190.63,252.88" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="6" points="260.63,205.25 229.60,216.84 233.88,238.42 269.41,225.15" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="7" points="243.08,198.89 221.03,207.13 229.60,216.84 260.63,205.25" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="8" points="269.41,225.15 233.88,238.42 229.60,250.28 260.63,238.69" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="9" points="154.18,212.35 130.00,197.47 119.87,216.24 147.54,233.28" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="10" points="229.60,250.28 190.63,252.88 193.34,242.41 221.03,240.57" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="11" points="216.74,218.99 194.70,220.46 193.34,208.97 221.03,207.13" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="12" points="167.44,203.93 150.26,193.36 130.00,197.47 154.18,212.35" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="13" points="194.70,220.46 174.07,216.45 167.44,203.93 193.34,208.97" fill="#986816" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="14" points="190.63,252.88 154.18,245.79 167.44,237.37 193.34,242.41" fill="#a87218" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="15" points="147.54,233.28 119.87,216.24 130.00,230.91 154.18,245.79" fill="#a87218" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="16" points="234.30,212.43 216.74,218.99 221.03,207.13 243.08,198.89" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="17" points="221.03,240.57 193.34,242.41 194.70,220.46 216.74,218.99" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="18" points="260.63,238.69 229.60,250.28 221.03,240.57 243.08,232.33" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="19" points="193.34,242.41 167.44,237.37 174.07,216.45 194.70,220.46" fill="#b67e1c" stroke="#d49422" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="20" points="275.42,187.77 260.63,205.25 269.41,225.15 286.34,205.14" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="21" points="253.59,186.47 243.08,198.89 260.63,205.25 275.42,187.77" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="22" points="174.07,216.45 160.39,208.03 150.26,193.36 167.44,203.93" fill="#a87218" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="23" points="243.08,232.33 221.03,240.57 216.74,218.99 234.30,212.43" fill="#a87218" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="24" points="154.18,245.79 130.00,230.91 150.26,226.80 167.44,237.37" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="25" points="286.34,205.14 269.41,225.15 260.63,238.69 275.42,221.21" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="26" points="167.44,237.37 150.26,226.80 160.39,208.03 174.07,216.45" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="27" points="242.67,202.54 234.30,212.43 243.08,198.89 253.59,186.47" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="28" points="150.26,193.36 146.41,180.09 124.58,178.79 130.00,197.47" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="29" points="130.00,197.47 124.58,178.79 113.66,194.86 119.87,216.24" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="30" points="275.42,221.21 260.63,238.69 243.08,232.33 253.59,219.91" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="31" points="253.59,219.91 243.08,232.33 234.30,212.43 242.67,202.54" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="32" points="160.39,208.03 157.33,197.46 146.41,180.09 150.26,193.36" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="33" points="119.87,216.24 113.66,194.86 124.58,212.23 130.00,230.91" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="34" points="249.74,173.20 253.59,186.47 275.42,187.77 270.00,169.09" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="35" points="150.26,226.80 146.41,213.53 157.33,197.46 160.39,208.03" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="36" points="239.61,191.97 242.67,202.54 253.59,186.47 249.74,173.20" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="37" points="130.00,230.91 124.58,212.23 146.41,213.53 150.26,226.80" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="38" points="270.00,169.09 275.42,187.77 286.34,205.14 280.13,183.76" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="39" points="249.74,206.64 253.59,219.91 242.67,202.54 239.61,191.97" fill="#986816" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="40" points="157.33,197.46 165.70,187.57 156.92,167.67 146.41,180.09" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="41" points="146.41,180.09 156.92,167.67 139.37,161.31 124.58,178.79" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="42" points="280.13,183.76 286.34,205.14 275.42,221.21 270.00,202.53" fill="#7a5210" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="43" points="270.00,202.53 275.42,221.21 253.59,219.91 249.74,206.64" fill="#8a5e14" stroke="#b67e1c" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="44" points="146.41,213.53 156.92,201.11 165.70,187.57 157.33,197.46" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="45" points="225.93,183.55 239.61,191.97 249.74,173.20 232.56,162.63" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="46" points="124.58,178.79 139.37,161.31 130.59,174.85 113.66,194.86" fill="#d49422" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="47" points="232.56,162.63 249.74,173.20 270.00,169.09 245.82,154.21" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="48" points="165.70,187.57 183.26,181.01 178.97,159.43 156.92,167.67" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="49" points="232.56,196.07 249.74,206.64 239.61,191.97 225.93,183.55" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="50" points="124.58,212.23 139.37,194.75 156.92,201.11 146.41,213.53" fill="#c48a1e" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="51" points="113.66,194.86 130.59,174.85 139.37,194.75 124.58,212.23" fill="#b67e1c" stroke="#f0b400" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="52" points="205.30,179.54 225.93,183.55 232.56,162.63 206.66,157.59" fill="#d49422" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="53" points="156.92,167.67 178.97,159.43 170.40,149.72 139.37,161.31" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="54" points="183.26,181.01 205.30,179.54 206.66,157.59 178.97,159.43" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="55" points="156.92,201.11 178.97,192.87 183.26,181.01 165.70,187.57" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="56" points="245.82,154.21 270.00,169.09 280.13,183.76 252.46,166.72" fill="#ffc206" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="57" points="206.66,157.59 232.56,162.63 245.82,154.21 209.37,147.12" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="58" points="206.66,191.03 232.56,196.07 225.93,183.55 205.30,179.54" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="59" points="245.82,187.65 270.00,202.53 249.74,206.64 232.56,196.07" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="60" points="178.97,192.87 206.66,191.03 205.30,179.54 183.26,181.01" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="61" points="178.97,159.43 206.66,157.59 209.37,147.12 170.40,149.72" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="62" points="252.46,166.72 280.13,183.76 270.00,202.53 245.82,187.65" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="63" points="139.37,161.31 170.40,149.72 166.12,161.58 130.59,174.85" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="64" points="139.37,194.75 170.40,183.16 178.97,192.87 156.92,201.11" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="65" points="130.59,174.85 166.12,161.58 170.40,183.16 139.37,194.75" fill="#c48a1e" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="66" points="209.37,147.12 245.82,154.21 252.46,166.72 210.73,158.61" fill="#f0b400" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="67" points="209.37,180.56 245.82,187.65 232.56,196.07 206.66,191.03" fill="#e4a024" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="68" points="170.40,183.16 209.37,180.56 206.66,191.03 178.97,192.87" fill="#e4a024" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="69" points="170.40,149.72 209.37,147.12 210.73,158.61 166.12,161.58" fill="#f0b400" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="70" points="210.73,158.61 252.46,166.72 245.82,187.65 209.37,180.56" fill="#d49422" stroke="#ffd23f" stroke-width="1" stroke-linejoin="round"/>
<polygon data-face="71" points="166.12,161.58 210.73,158.61 209.37,180.56 170.40,183.16" fill="#d49422" stroke="#ffc206" stroke-width="1" stroke-linejoin="round"/>
</g>
</svg>
<script>
function radialData(el, size) {
const faces = el.querySelectorAll('[data-face]');
const data = [];
faces.forEach(function(f) {
var pts = f.getAttribute('points').split(' ').map(function(p) { return p.split(',').map(Number); });
var cx = pts.reduce(function(s, p) { return s + p[0]; }, 0) / pts.length;
var cy = pts.reduce(function(s, p) { return s + p[1]; }, 0) / pts.length;
var rx = cx - size / 2;
var ry = cy - size / 2;
var dist = Math.sqrt(rx * rx + ry * ry) || 0.001;
var angle = Math.atan2(ry, rx);
// Unit radial direction
var ux = rx / dist;
var uy = ry / dist;
f.style.transformOrigin = cx + 'px ' + cy + 'px';
data.push({ el: f, cx: cx, cy: cy, rx: rx, ry: ry, dist: dist, angle: angle, ux: ux, uy: uy });
});
return data;
}
(function() {
var el = document.getElementById('shape-torus-breathe');
var rd = radialData(el, 400);
var t = 0;
(function tick() {
t += 0.02;
var hovering = el.matches(':hover');
rd.forEach(function(d, i) {
var phase = d.dist * 0.02 + i * 0.1;
var wave = Math.sin(t * 0.25 + phase);
if (hovering) {
// Radial push/pull
var mag = wave * 6;
d.el.style.transition = 'transform 0.3s ease';
d.el.style.transform = 'translate(' + (d.ux * mag) + 'px, ' + (d.uy * mag) + 'px)';
} else {
// Gentle scale breathing
d.el.style.transition = 'none';
d.el.style.transform = 'scale(' + (1 + wave * 0.02) + ')';
}
});
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Torus breathe</div>
<div class="card-desc">A hexagonal torus that gently breathes, with faces pulsing outward on hover.</div>
<span class="card-anim">breathe</span>
</div>
</div>
<div class="card">
<svg id="shape-spiral-tower" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="190.70,116.65 222.93,110.12 222.93,140.84 190.70,147.37" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="1" points="177.07,101.20 209.30,94.67 222.93,110.12 190.70,116.65" fill="#6b480c" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="2" points="177.07,131.91 177.07,101.20 190.70,116.65 190.70,147.37" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="3" points="196.66,143.74 224.52,133.59 224.52,164.30 196.66,174.46" fill="#986816" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="4" points="175.48,161.10 175.48,130.39 196.66,143.74 196.66,174.46" fill="#986816" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="5" points="209.30,94.67 209.30,125.38 222.93,140.84 222.93,110.12" fill="#6b480c" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="6" points="175.48,130.39 203.34,120.23 224.52,133.59 196.66,143.74" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="7" points="209.30,125.38 177.07,131.91 190.70,147.37 222.93,140.84" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="8" points="177.07,131.91 209.30,125.38 209.30,94.67 177.07,101.20" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="9" points="175.41,190.39 175.41,159.67 202.83,170.10 202.83,200.82" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="10" points="202.83,170.10 224.59,156.96 224.59,187.67 202.83,200.82" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="11" points="175.41,159.67 197.17,146.53 224.59,156.96 202.83,170.10" fill="#8a5e14" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="12" points="203.34,150.95 175.48,161.10 196.66,174.46 224.52,164.30" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="13" points="203.34,120.23 203.34,150.95 224.52,164.30 224.52,133.59" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="14" points="175.48,161.10 203.34,150.95 203.34,120.23 175.48,130.39" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="15" points="176.88,219.59 176.88,188.87 208.82,195.73 208.82,226.44" fill="#c48a1e" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="16" points="176.88,188.87 191.18,173.56 223.12,180.41 208.82,195.73" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="17" points="208.82,195.73 223.12,180.41 223.12,211.13 208.82,226.44" fill="#c48a1e" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="18" points="197.17,177.24 175.41,190.39 202.83,200.82 224.59,187.67" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="19" points="175.41,190.39 197.17,177.24 197.17,146.53 175.41,159.67" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="20" points="197.17,146.53 197.17,177.24 224.59,187.67 224.59,156.96" fill="#8a5e14" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="21" points="179.78,248.53 179.78,217.81 214.27,220.66 214.27,251.38" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="22" points="179.78,217.81 185.73,201.28 220.22,204.13 214.27,220.66" fill="#b67e1c" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="23" points="176.88,219.59 191.18,204.27 191.18,173.56 176.88,188.87" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="24" points="191.18,204.27 176.88,219.59 208.82,226.44 223.12,211.13" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="25" points="214.27,220.66 220.22,204.13 220.22,234.84 214.27,251.38" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="26" points="183.94,277.04 183.94,246.32 218.83,245.00 218.83,275.71" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="27" points="191.18,173.56 191.18,204.27 223.12,211.13 223.12,180.41" fill="#a87218" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="28" points="179.78,248.53 185.73,231.99 185.73,201.28 179.78,217.81" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="29" points="183.94,246.32 181.17,229.60 216.06,228.27 218.83,245.00" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="30" points="185.73,231.99 179.78,248.53 214.27,251.38 220.22,234.84" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="31" points="183.94,277.04 181.17,260.31 181.17,229.60 183.94,246.32" fill="#d49422" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="32" points="185.73,201.28 185.73,231.99 220.22,234.84 220.22,204.13" fill="#b67e1c" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="33" points="218.83,245.00 216.06,228.27 216.06,258.99 218.83,275.71" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="34" points="181.17,260.31 183.94,277.04 218.83,275.71 216.06,258.99" fill="#d49422" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="35" points="181.17,229.60 181.17,260.31 216.06,258.99 216.06,228.27" fill="#c48a1e" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-spiral-tower');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 50%';
var t = 0;
el.addEventListener('mouseenter', function() {
g.style.transition = 'transform 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55)';
g.style.transform = 'perspective(600px) rotateY(180deg) scale(0.9)';
});
el.addEventListener('mouseleave', function() {
g.style.transition = 'transform 0.8s cubic-bezier(0.68, -0.55, 0.27, 1.55)';
g.style.transform = 'perspective(600px) rotateY(0deg) scale(1)';
});
(function idle() {
t += 0.015;
if (!el.matches(':hover')) {
g.style.transition = 'none';
g.style.transform = 'perspective(600px) rotateY(' + (Math.sin(t) * 3) + 'deg)';
}
requestAnimationFrame(idle);
})();
})();</script>
<div class="card-info">
<div class="card-name">Spiral tower</div>
<div class="card-desc">Stacked twisted cubes forming a tower. Flips 180 degrees on hover.</div>
<span class="card-anim">flip</span>
</div>
</div>
<div class="card">
<svg id="shape-crystal-cluster" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="220.90,177.43 225.04,208.70 214.83,210.97" fill="#ffc206" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="1" points="220.90,177.43 214.83,210.97 206.16,205.21" fill="#ffc206" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="2" points="220.90,177.43 226.58,200.67 225.04,208.70" fill="#ffc206" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="3" points="220.90,177.43 206.16,205.21 207.70,197.17" fill="#ffc206" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="4" points="220.90,177.43 217.90,194.90 226.58,200.67" fill="#ffc206" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="5" points="220.90,177.43 207.70,197.17 217.90,194.90" fill="#ffc206" stroke="#ffe066" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="6" points="185.68,165.97 200.58,201.22 184.63,202.63" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="7" points="185.68,165.97 184.63,202.63 170.55,201.46" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="8" points="187.33,234.14 184.63,202.63 200.58,201.22" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="9" points="183.66,172.39 200.82,205.09 180.47,211.40" fill="#f0b400" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="10" points="187.33,234.14 170.55,201.46 184.63,202.63" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="11" points="183.66,172.39 180.47,211.40 162.55,201.40" fill="#f0b400" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="12" points="185.68,165.97 202.46,198.65 200.58,201.22" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="13" points="202.55,165.31 219.18,201.77 198.32,207.69" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="14" points="202.55,165.31 198.32,207.69 180.12,197.31" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="15" points="185.68,165.97 170.55,201.46 172.42,198.88" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="16" points="183.66,172.39 203.25,188.79 200.82,205.09" fill="#f0b400" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="17" points="211.83,228.44 214.83,210.97 225.04,208.70" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="18" points="211.83,228.44 206.16,205.21 214.83,210.97" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="19" points="187.33,234.14 200.58,201.22 202.46,198.65" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="20" points="183.66,172.39 162.55,201.40 164.99,185.09" fill="#f0b400" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="21" points="187.33,234.14 172.42,198.88 170.55,201.46" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="22" points="211.83,228.44 225.04,208.70 226.58,200.67" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="23" points="211.83,228.44 207.70,197.17 206.16,205.21" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="24" points="202.55,165.31 221.84,185.46 219.18,201.77" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="25" points="200.56,173.36 215.02,194.55 196.94,193.72" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="26" points="185.68,165.97 188.38,197.48 202.46,198.65" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="27" points="200.56,173.36 196.94,193.72 180.25,189.77" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="28" points="202.55,165.31 180.12,197.31 182.77,181.00" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="29" points="185.68,165.97 172.42,198.88 188.38,197.48" fill="#d49422" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="30" points="183.66,172.39 185.33,178.78 203.25,188.79" fill="#f0b400" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="31" points="211.83,228.44 226.58,200.67 217.90,194.90" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="32" points="211.83,228.44 217.90,194.90 207.70,197.17" fill="#b67e1c" stroke="#f0b400" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="33" points="196.09,207.85 196.94,193.72 215.02,194.55" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="34" points="196.09,207.85 180.25,189.77 196.94,193.72" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="35" points="183.66,172.39 164.99,185.09 185.33,178.78" fill="#f0b400" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="36" points="182.14,217.79 180.47,211.40 200.82,205.09" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="37" points="187.33,234.14 202.46,198.65 188.38,197.48" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="38" points="182.14,217.79 162.55,201.40 180.47,211.40" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="39" points="187.33,234.14 188.38,197.48 172.42,198.88" fill="#8a5e14" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="40" points="202.55,165.31 203.63,175.08 221.84,185.46" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="41" points="202.55,165.31 182.77,181.00 203.63,175.08" fill="#e4a024" stroke="#ffd23f" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="42" points="200.56,173.36 216.41,191.44 215.02,194.55" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="43" points="182.14,217.79 200.82,205.09 203.25,188.79" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="44" points="199.40,217.47 198.32,207.69 219.18,201.77" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="45" points="200.56,173.36 180.25,189.77 181.63,186.66" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="46" points="199.40,217.47 180.12,197.31 198.32,207.69" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="47" points="196.09,207.85 215.02,194.55 216.41,191.44" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="48" points="182.14,217.79 164.99,185.09 162.55,201.40" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="49" points="196.09,207.85 181.63,186.66 180.25,189.77" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="50" points="199.40,217.47 219.18,201.77 221.84,185.46" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="51" points="182.14,217.79 203.25,188.79 185.33,178.78" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="52" points="182.14,217.79 185.33,178.78 164.99,185.09" fill="#a87218" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="53" points="199.40,217.47 182.77,181.00 180.12,197.31" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="54" points="200.56,173.36 199.71,187.50 216.41,191.44" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="55" points="200.56,173.36 181.63,186.66 199.71,187.50" fill="#c48a1e" stroke="#ffc206" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="56" points="196.09,207.85 216.41,191.44 199.71,187.50" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="57" points="196.09,207.85 199.71,187.50 181.63,186.66" fill="#7a5210" stroke="#b67e1c" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="58" points="199.40,217.47 221.84,185.46 203.63,175.08" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
<polygon data-face="59" points="199.40,217.47 203.63,175.08 182.77,181.00" fill="#986816" stroke="#d49422" stroke-width="1.2" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-crystal-cluster');
var g = el.querySelector('.shape-group');
g.style.transformOrigin = '50% 0%';
var t = 0, hovering = false;
el.addEventListener('mouseenter', function() { hovering = true; });
el.addEventListener('mouseleave', function() { hovering = false; });
(function tick() {
t += 0.04;
if (hovering) {
g.style.transition = 'none';
g.style.transform = 'rotate(' + (Math.sin(t * 3) * 12 * Math.exp(-(t * 0.3) % 1)) + 'deg)';
} else {
g.style.transition = 'transform 0.5s ease';
g.style.transform = 'rotate(' + (Math.sin(t * 0.08333333333333333) * 3) + 'deg)';
}
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Crystal cluster</div>
<div class="card-desc">Elongated crystals growing at odd angles. Swings like a pendulum on hover.</div>
<span class="card-anim">swing</span>
</div>
</div>
<div class="card">
<svg id="shape-arrow-rotate" viewBox="0 0 400 400" width="400" height="400" class="w-full max-w-[400px] h-auto overflow-visible" style="cursor: pointer;">
<g class="shape-group" style="transform-origin: 50% 50%;">
<polygon data-face="0" points="125.79,187.99 190.26,118.75 209.74,140.83 145.26,210.07" fill="#f0b400" stroke="#ffe066" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="1" points="167.70,193.53 125.79,187.99 145.26,210.07 187.17,215.61" fill="#d49422" stroke="#ffd23f" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="2" points="145.26,210.07 187.17,215.61 187.17,285.82 232.30,276.67 232.30,206.47 274.21,183.93 209.74,140.83" fill="#5c3d0a" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="3" points="190.26,118.75 254.74,161.85 274.21,183.93 209.74,140.83" fill="#4e3608" stroke="#986816" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="4" points="167.70,263.74 167.70,193.53 187.17,215.61 187.17,285.82" fill="#b67e1c" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="5" points="254.74,161.85 212.83,184.39 232.30,206.47 274.21,183.93" fill="#5c3d0a" stroke="#b67e1c" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="6" points="190.26,118.75 254.74,161.85 212.83,184.39 212.83,254.59 167.70,263.74 167.70,193.53 125.79,187.99" fill="#f0b400" stroke="#ffc206" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="7" points="212.83,184.39 212.83,254.59 232.30,276.67 232.30,206.47" fill="#7a5210" stroke="#d49422" stroke-width="1.5" stroke-linejoin="round"/>
<polygon data-face="8" points="212.83,254.59 167.70,263.74 187.17,285.82 232.30,276.67" fill="#986816" stroke="#f0b400" stroke-width="1.5" stroke-linejoin="round"/>
</g>
</svg>
<script>
(function() {
var el = document.getElementById('shape-arrow-rotate');
var g = el.querySelector('.shape-group');
var angle = 0, hovering = false, hoverAngle = 0;
el.addEventListener('mouseenter', function() { hovering = true; });
el.addEventListener('mouseleave', function() { hovering = false; });
el.addEventListener('mousemove', function(e) {
var rect = el.getBoundingClientRect();
hoverAngle = ((e.clientX - rect.left) / rect.width - 0.5) * 25;
});
(function tick() {
angle += 0.3;
var tilt = hovering ? hoverAngle : 0;
g.style.transform = 'rotateY(' + (angle + tilt) + 'deg)';
g.style.transition = hovering ? 'none' : 'transform 0.6s ease-out';
requestAnimationFrame(tick);
})();
})();</script>
<div class="card-info">
<div class="card-name">Arrow rotate</div>
<div class="card-desc">A bold arrow/chevron prism, slowly spinning. Tracks the cursor when hovered.</div>
<span class="card-anim">rotate</span>
</div>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment