← back to Model Arena
data/artifacts/176d578251e3/kimi.html
312 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Radial Spring Menu</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
width: 100vw;
height: 100vh;
background: radial-gradient(circle at center, #1e293b 0%, #0f172a 100%);
overflow: hidden;
font-family: system-ui, -apple-system, sans-serif;
display: flex;
justify-content: center;
align-items: center;
}
.menu-container {
position: relative;
width: 400px;
height: 400px;
display: flex;
justify-content: center;
align-items: center;
}
.center-btn {
position: relative;
width: 72px;
height: 72px;
border-radius: 50%;
background: linear-gradient(135deg, #ffffff 0%, #e2e8f0 100%);
border: none;
cursor: pointer;
z-index: 10;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 10px 40px -10px rgba(0,0,0,0.5),
0 0 0 1px rgba(255,255,255,0.1) inset;
transition: transform 0.2s cubic-bezier(0.175, 0.885, 0.32, 1.275),
box-shadow 0.2s ease;
}
.center-btn:active {
transform: scale(0.92);
box-shadow: 0 5px 20px -5px rgba(0,0,0,0.4),
0 0 0 1px rgba(255,255,255,0.1) inset;
}
.center-btn svg {
width: 32px;
height: 32px;
fill: none;
stroke: #0f172a;
stroke-width: 2.5;
stroke-linecap: round;
stroke-linejoin: round;
transition: transform 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
}
.center-btn.open svg {
transform: rotate(135deg);
}
.satellite {
position: absolute;
width: 56px;
height: 56px;
border-radius: 50%;
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(12px);
border: 1px solid rgba(255, 255, 255, 0.15);
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
transform: translate(var(--x, 0px), var(--y, 0px));
will-change: transform;
z-index: 5;
}
.satellite-inner {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50%;
transition: transform 0.3s cubic-bezier(0.175, 0.885, 0.32, 1.275),
background 0.3s ease;
}
.satellite:hover .satellite-inner {
transform: scale(1.15);
background: rgba(255,255,255,0.15);
}
.satellite:active .satellite-inner {
transform: scale(0.95);
}
.satellite svg {
width: 24px;
height: 24px;
fill: none;
stroke: currentColor;
stroke-width: 2;
stroke-linecap: round;
stroke-linejoin: round;
pointer-events: none;
}
.satellite:nth-child(1) { color: #f472b6; }
.satellite:nth-child(2) { color: #60a5fa; }
.satellite:nth-child(3) { color: #34d399; }
.satellite:nth-child(4) { color: #fbbf24; }
.satellite:nth-child(5) { color: #a78bfa; }
.satellite:nth-child(6) { color: #f87171; }
.glow {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
opacity: 0;
transition: opacity 0.3s ease;
pointer-events: none;
}
.satellite:hover .glow {
opacity: 0.4;
}
.satellite:nth-child(1) .glow { background: radial-gradient(circle, rgba(244,114,182,0.6) 0%, transparent 70%); }
.satellite:nth-child(2) .glow { background: radial-gradient(circle, rgba(96,165,250,0.6) 0%, transparent 70%); }
.satellite:nth-child(3) .glow { background: radial-gradient(circle, rgba(52,211,153,0.6) 0%, transparent 70%); }
.satellite:nth-child(4) .glow { background: radial-gradient(circle, rgba(251,191,36,0.6) 0%, transparent 70%); }
.satellite:nth-child(5) .glow { background: radial-gradient(circle, rgba(167,139,250,0.6) 0%, transparent 70%); }
.satellite:nth-child(6) .glow { background: radial-gradient(circle, rgba(248,113,113,0.6) 0%, transparent 70%); }
</style>
</head>
<body>
<div class="menu-container">
<button class="center-btn" id="centerBtn" aria-label="Toggle menu">
<svg viewBox="0 0 24 24">
<line x1="12" y1="5" x2="12" y2="19"></line>
<line x1="5" y1="12" x2="19" y2="12"></line>
</svg>
</button>
<div class="satellites" id="satellites">
<button class="satellite" aria-label="Home">
<div class="glow"></div>
<div class="satellite-inner">
<svg viewBox="0 0 24 24"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"></path><polyline points="9 22 9 12 15 12 15 22"></polyline></svg>
</div>
</button>
<button class="satellite" aria-label="Search">
<div class="glow"></div>
<div class="satellite-inner">
<svg viewBox="0 0 24 24"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>
</div>
</button>
<button class="satellite" aria-label="Profile">
<div class="glow"></div>
<div class="satellite-inner">
<svg viewBox="0 0 24 24"><path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path><circle cx="12" cy="7" r="4"></circle></svg>
</div>
</button>
<button class="satellite" aria-label="Favorites">
<div class="glow"></div>
<div class="satellite-inner">
<svg viewBox="0 0 24 24"><path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"></path></svg>
</div>
</button>
<button class="satellite" aria-label="Notifications">
<div class="glow"></div>
<div class="satellite-inner">
<svg viewBox="0 0 24 24"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"></path><path d="M13.73 21a2 2 0 0 1-3.46 0"></path></svg>
</div>
</button>
<button class="satellite" aria-label="Settings">
<div class="glow"></div>
<div class="satellite-inner">
<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>
</div>
</button>
</div>
</div>
<script>
class Spring {
constructor() {
this.x = 0;
this.y = 0;
this.vx = 0;
this.vy = 0;
this.targetX = 0;
this.targetY = 0;
this.stiffness = 0.12;
this.damping = 0.75;
this.mass = 1;
}
update() {
const forceX = (this.targetX - this.x) * this.stiffness;
const forceY = (this.targetY - this.y) * this.stiffness;
const ax = forceX / this.mass;
const ay = forceY / this.mass;
this.vx += ax;
this.vy += ay;
this.vx *= this.damping;
this.vy *= this.damping;
this.x += this.vx;
this.y += this.vy;
}
setTarget(x, y) {
this.targetX = x;
this.targetY = y;
}
}
const centerBtn = document.getElementById('centerBtn');
const satellites = document.querySelectorAll('.satellite');
const springs = [];
const count = 6;
const radius = 140;
const startAngle = -Math.PI * 5/6;
const endAngle = -Math.PI / 6;
const step = (endAngle - startAngle) / (count - 1);
const targets = [];
for (let i = 0; i < count; i++) {
const angle = startAngle + step * i;
targets.push({
x: Math.cos(angle) * radius,
y: Math.sin(angle) * radius
});
springs.push(new Spring());
}
let isOpen = false;
let animationId = null;
function animate() {
let active = false;
satellites.forEach((sat, i) => {
const spring = springs[i];
spring.update();
const dx = Math.abs(spring.targetX - spring.x);
const dy = Math.abs(spring.targetY - spring.y);
const velocity = Math.abs(spring.vx) + Math.abs(spring.vy);
if (dx > 0.01 || dy > 0.01 || velocity > 0.01) {
active = true;
}
sat.style.setProperty('--x', spring.x + 'px');
sat.style.setProperty('--y', spring.y + 'px');
});
if (active) {
animationId = requestAnimationFrame(animate);
} else {
animationId = null;
}
}
function toggleMenu() {
isOpen = !isOpen;
centerBtn.classList.toggle('open', isOpen);
springs.forEach((spring, i) => {
if (isOpen) {
spring.setTarget(targets[i].x, targets[i].y);
} else {
spring.setTarget(0, 0);
}
});
if (!animationId) {
animate();
}
}
centerBtn.addEventListener('click', toggleMenu);
// Initialize
animate();
</script>
</body>
</html>