← back to Model Arena
data/artifacts/2ca024f41f3c/claude-code.html
305 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Solar System Orrery</title>
<style>
html, body {
margin: 0;
padding: 0;
height: 100%;
background: #05060f;
overflow: hidden;
font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
color: #dfe6ff;
}
#wrap { position: relative; width: 100vw; height: 100vh; }
canvas { display: block; width: 100%; height: 100%; cursor: default; }
#controls {
position: absolute;
left: 50%;
bottom: 18px;
transform: translateX(-50%);
display: flex;
align-items: center;
gap: 14px;
background: rgba(10, 14, 30, 0.72);
border: 1px solid rgba(120, 150, 255, 0.25);
border-radius: 999px;
padding: 10px 18px;
backdrop-filter: blur(6px);
user-select: none;
}
#controls label { font-size: 13px; letter-spacing: 0.04em; opacity: 0.85; white-space: nowrap; }
#speed { width: 160px; accent-color: #6ea8ff; cursor: pointer; }
#speedVal { font-size: 12px; min-width: 42px; text-align: right; font-variant-numeric: tabular-nums; opacity: 0.8; }
#pauseBtn {
background: #1d2b55;
color: #dfe6ff;
border: 1px solid rgba(120, 150, 255, 0.4);
border-radius: 999px;
padding: 6px 16px;
font-size: 13px;
cursor: pointer;
min-width: 84px;
transition: background 0.15s;
}
#pauseBtn:hover { background: #2a3c74; }
#tooltip {
position: absolute;
pointer-events: none;
background: rgba(8, 12, 28, 0.9);
border: 1px solid rgba(140, 170, 255, 0.45);
border-radius: 6px;
padding: 4px 10px;
font-size: 13px;
letter-spacing: 0.03em;
white-space: nowrap;
transform: translate(-50%, -140%);
opacity: 0;
transition: opacity 0.12s;
}
#title {
position: absolute;
top: 16px;
left: 50%;
transform: translateX(-50%);
font-size: 13px;
letter-spacing: 0.35em;
text-transform: uppercase;
opacity: 0.55;
user-select: none;
}
</style>
</head>
<body>
<div id="wrap">
<canvas id="cv"></canvas>
<div id="title">Solar System Orrery</div>
<div id="tooltip"></div>
<div id="controls">
<button id="pauseBtn">Pause</button>
<label for="speed">Speed</label>
<input type="range" id="speed" min="0" max="300" value="100">
<span id="speedVal">1.0×</span>
</div>
</div>
<script>
(function () {
"use strict";
var canvas = document.getElementById("cv");
var ctx = canvas.getContext("2d");
var tooltip = document.getElementById("tooltip");
var pauseBtn = document.getElementById("pauseBtn");
var speedSlider = document.getElementById("speed");
var speedVal = document.getElementById("speedVal");
var W = 0, H = 0, DPR = 1, cx = 0, cy = 0, scale = 1;
// Orbital periods in Earth years (proportional speeds), display radii/sizes stylized.
var planets = [
{ name: "Mercury", period: 0.241, dist: 0.10, size: 3.2, color: "#b8a89a" },
{ name: "Venus", period: 0.615, dist: 0.155, size: 5.2, color: "#e8c47a" },
{ name: "Earth", period: 1.000, dist: 0.215, size: 5.6, color: "#5f9ce0" },
{ name: "Mars", period: 1.881, dist: 0.275, size: 4.2, color: "#d1663d" },
{ name: "Jupiter", period: 11.86, dist: 0.40, size: 12, color: "#d9a878" },
{ name: "Saturn", period: 29.46, dist: 0.53, size: 10, color: "#e3cf9a", ring: true },
{ name: "Uranus", period: 84.01, dist: 0.65, size: 7, color: "#9fd8de" },
{ name: "Neptune", period: 164.8, dist: 0.76, size: 6.8, color: "#5a7fe0" }
];
planets.forEach(function (p, i) {
p.angle = (i * 2.399963) % (Math.PI * 2); // spread starting positions
p.x = 0; p.y = 0;
});
// Static starfield (regenerated on resize)
var stars = [];
function makeStars() {
stars = [];
var n = Math.floor((W * H) / 3800);
for (var i = 0; i < n; i++) {
stars.push({
x: Math.random() * W,
y: Math.random() * H,
r: Math.random() * 1.1 + 0.2,
a: Math.random() * 0.6 + 0.15
});
}
}
function resize() {
DPR = window.devicePixelRatio || 1;
W = window.innerWidth;
H = window.innerHeight;
canvas.width = Math.round(W * DPR);
canvas.height = Math.round(H * DPR);
ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
cx = W / 2;
cy = H / 2;
scale = Math.min(W, H) * 0.60; // max orbit dist 0.76 of half-min stays inside
makeStars();
}
window.addEventListener("resize", resize);
resize();
var paused = false;
var speedFactor = 1.0;
var hovered = null;
var mouseX = -1, mouseY = -1;
pauseBtn.addEventListener("click", function () {
paused = !paused;
pauseBtn.textContent = paused ? "Resume" : "Pause";
});
speedSlider.addEventListener("input", function () {
// 0..300 -> 0x..3x, quadratic-ish feel around 1x at 100
speedFactor = speedSlider.value / 100;
speedVal.innerHTML = speedFactor.toFixed(1) + "×";
});
canvas.addEventListener("mousemove", function (e) {
var rect = canvas.getBoundingClientRect();
mouseX = e.clientX - rect.left;
mouseY = e.clientY - rect.top;
});
canvas.addEventListener("mouseleave", function () {
mouseX = -1; mouseY = -1;
});
function pickHover() {
hovered = null;
if (mouseX < 0) return;
var best = 1e9;
for (var i = 0; i < planets.length; i++) {
var p = planets[i];
var dx = mouseX - p.x, dy = mouseY - p.y;
var d = Math.sqrt(dx * dx + dy * dy);
var hitR = Math.max(p.size + 6, 12);
if (d < hitR && d < best) { best = d; hovered = p; }
}
canvas.style.cursor = hovered ? "pointer" : "default";
}
function draw(dt) {
// background
ctx.fillStyle = "#05060f";
ctx.fillRect(0, 0, W, H);
// stars
for (var i = 0; i < stars.length; i++) {
var s = stars[i];
ctx.globalAlpha = s.a;
ctx.fillStyle = "#ffffff";
ctx.beginPath();
ctx.arc(s.x, s.y, s.r, 0, 6.2832);
ctx.fill();
}
ctx.globalAlpha = 1;
// orbit rings
ctx.lineWidth = 1;
for (i = 0; i < planets.length; i++) {
var p = planets[i];
ctx.strokeStyle = (p === hovered) ? "rgba(150,180,255,0.55)" : "rgba(120,140,200,0.18)";
ctx.beginPath();
ctx.arc(cx, cy, p.dist * scale, 0, 6.2832);
ctx.stroke();
}
// sun with glow
var sunR = Math.max(14, scale * 0.045);
var g = ctx.createRadialGradient(cx, cy, 0, cx, cy, sunR * 3);
g.addColorStop(0, "rgba(255,220,130,0.9)");
g.addColorStop(0.25, "rgba(255,180,70,0.35)");
g.addColorStop(1, "rgba(255,150,40,0)");
ctx.fillStyle = g;
ctx.beginPath();
ctx.arc(cx, cy, sunR * 3, 0, 6.2832);
ctx.fill();
var sg = ctx.createRadialGradient(cx - sunR * 0.3, cy - sunR * 0.3, sunR * 0.1, cx, cy, sunR);
sg.addColorStop(0, "#fff6d8");
sg.addColorStop(0.6, "#ffd257");
sg.addColorStop(1, "#f39b1d");
ctx.fillStyle = sg;
ctx.beginPath();
ctx.arc(cx, cy, sunR, 0, 6.2832);
ctx.fill();
// planets
for (i = 0; i < planets.length; i++) {
p = planets[i];
if (!paused) {
// Earth completes one orbit in 12s at 1x speed; others proportional to real periods
p.angle += (dt * speedFactor * (2 * Math.PI / 12)) / p.period;
}
var r = p.dist * scale;
p.x = cx + Math.cos(p.angle) * r;
p.y = cy + Math.sin(p.angle) * r;
// saturn ring
if (p.ring) {
ctx.save();
ctx.translate(p.x, p.y);
ctx.rotate(-0.45);
ctx.strokeStyle = "rgba(220,200,150,0.75)";
ctx.lineWidth = 2.4;
ctx.beginPath();
ctx.ellipse(0, 0, p.size * 1.9, p.size * 0.72, 0, 0, 6.2832);
ctx.stroke();
ctx.restore();
}
var pg = ctx.createRadialGradient(p.x - p.size * 0.35, p.y - p.size * 0.35, p.size * 0.15, p.x, p.y, p.size);
pg.addColorStop(0, "#ffffff");
pg.addColorStop(0.25, p.color);
pg.addColorStop(1, shade(p.color, -55));
ctx.fillStyle = pg;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, 6.2832);
ctx.fill();
if (p === hovered) {
ctx.strokeStyle = "rgba(255,255,255,0.85)";
ctx.lineWidth = 1.5;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size + 4, 0, 6.2832);
ctx.stroke();
}
}
}
function shade(hex, amt) {
var n = parseInt(hex.slice(1), 16);
var r = Math.max(0, Math.min(255, (n >> 16) + amt));
var gr = Math.max(0, Math.min(255, ((n >> 8) & 255) + amt));
var b = Math.max(0, Math.min(255, (n & 255) + amt));
return "rgb(" + r + "," + gr + "," + b + ")";
}
function updateTooltip() {
if (hovered) {
tooltip.textContent = hovered.name;
tooltip.style.left = hovered.x + "px";
tooltip.style.top = hovered.y + "px";
tooltip.style.opacity = "1";
} else {
tooltip.style.opacity = "0";
}
}
var last = performance.now();
function frame(now) {
var dt = Math.min((now - last) / 1000, 0.1);
last = now;
pickHover();
draw(dt);
updateTooltip();
requestAnimationFrame(frame);
}
requestAnimationFrame(frame);
})();
</script>
</body>
</html>