Snake, with juice, built by Clover 35B A3B Preview
Hostedvia DaBenchCustom endpoint
422tok/s
First token included
6.3Ktokens
14.9s
Show the code the model wroteHide the code
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
background: #0a0a0f;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
overflow: hidden;
user-select: none;
-webkit-user-select: none;
}
#wrapper {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
gap: 12px;
}
#hud {
display: flex;
justify-content: space-between;
width: 480px;
padding: 0 4px;
color: #8888aa;
font-size: 14px;
letter-spacing: 1px;
text-transform: uppercase;
}
#hud span { font-weight: 600; }
#scoreVal { color: #7fdbca; }
#speedVal { color: #e8a838; }
canvas {
display: block;
border-radius: 6px;
box-shadow: 0 0 60px rgba(127, 219, 202, 0.06), inset 0 0 1px rgba(255,255,255,0.05);
}
</style>
</head>
<body>
<div id="wrapper">
<div id="hud">
<div>Score <span id="scoreVal">0</span></div>
<div>Speed <span id="speedVal">1</span></div>
</div>
<canvas id="c"></canvas>
</div>
<script>
const COLS = 24, ROWS = 24;
const CELL = 20;
const W = COLS * CELL, H = ROWS * CELL;
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
canvas.width = W;
canvas.height = H;
// --- Audio ---
let audioCtx = null;
function ensureAudio() {
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
function playTick() {
ensureAudio();
const t = audioCtx.currentTime;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'square';
osc.frequency.setValueAtTime(600, t);
osc.frequency.exponentialRampToValueAtTime(300, t + 0.04);
gain.gain.setValueAtTime(0.06, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.06);
osc.connect(gain).connect(audioCtx.destination);
osc.start(t); osc.stop(t + 0.06);
}
function playEat() {
ensureAudio();
const t = audioCtx.currentTime;
[800, 1100].forEach((freq, i) => {
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(freq, t + i * 0.05);
gain.gain.setValueAtTime(0.08, t + i * 0.05);
gain.gain.exponentialRampToValueAtTime(0.001, t + i * 0.05 + 0.12);
osc.connect(gain).connect(audioCtx.destination);
osc.start(t + i * 0.05); osc.stop(t + i * 0.05 + 0.12);
});
}
function playDeath() {
ensureAudio();
const t = audioCtx.currentTime;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(200, t);
osc.frequency.exponentialRampToValueAtTime(40, t + 0.4);
gain.gain.setValueAtTime(0.12, t);
gain.gain.exponentialRampToValueAtTime(0.001, t + 0.4);
osc.connect(gain).connect(audioCtx.destination);
osc.start(t); osc.stop(t + 0.4);
}
// --- Game State ---
let snake, direction, nextDirection, food, score, bestScore, speedLevel, tickRate;
let gameState; // 'ready' | 'playing' | 'dying' | 'dead'
let moveTimer, lastMoveTime;
let particles, scorePops, shakeAmount, flashAlpha, speedFlash;
let prevSpeedLevel;
function initGame() {
const startX = Math.floor(COLS / 2);
const startY = Math.floor(ROWS / 2);
snake = [
{ x: startX, y: startY },
{ x: startX, y: startY + 1 },
{ x: startX, y: startY + 2 },
];
direction = { x: 0, y: -1 };
nextDirection = { x: 0, y: -1 };
score = 0;
speedLevel = 1;
tickRate = 130;
prevSpeedLevel = 1;
particles = [];
scorePops = [];
shakeAmount = 0;
flashAlpha = 0;
speedFlash = 0;
spawnFood();
}
function spawnFood() {
let attempts = 0;
while (attempts < 1000) {
const x = Math.floor(Math.random() * COLS);
const y = Math.floor(Math.random() * ROWS);
if (!snake.some(s => s.x === x && s.y === y)) {
food = { x, y };
return;
}
attempts++;
}
}
// --- Particles ---
function spawnParticles(x, y, color, count) {
for (let i = 0; i < count; i++) {
const angle = Math.random() * Math.PI * 2;
const speed = 40 + Math.random() * 120;
particles.push({
x: x * CELL + CELL / 2,
y: y * CELL + CELL / 2,
vx: Math.cos(angle) * speed,
vy: Math.sin(angle) * speed,
life: 0.6 + Math.random() * 0.4,
maxLife: 0.6 + Math.random() * 0.4,
size: 2 + Math.random() * 3,
color,
});
}
}
function spawnScorePop(x, y, text) {
scorePops.push({
x: x * CELL + CELL / 2,
y: y * CELL + CELL / 2,
text,
life: 0.8,
vy: -60,
});
}
// --- Input ---
document.addEventListener('keydown', e => {
if (gameState === 'dead') {
if (e.code === 'Space') {
e.preventDefault();
initGame();
gameState = 'playing';
lastMoveTime = performance.now();
tickRate = 130;
speedLevel = 1;
prevSpeedLevel = 1;
return;
}
}
if (e.code === 'KeyP') {
if (gameState === 'playing') gameState = 'paused';
else if (gameState === 'paused') { gameState = 'playing'; lastMoveTime = performance.now(); }
return;
}
if (gameState !== 'playing') return;
switch (e.code) {
case 'ArrowUp': case 'KeyW':
if (direction.y !== -1) nextDirection = { x: 0, y: -1 };
break;
case 'ArrowDown': case 'KeyS':
if (direction.y !== 1) nextDirection = { x: 0, y: 1 };
break;
case 'ArrowLeft': case 'KeyA':
if (direction.x !== -1) nextDirection = { x: -1, y: 0 };
break;
case 'ArrowRight': case 'KeyD':
if (direction.x !== 1) nextDirection = { x: 1, y: 0 };
break;
}
e.preventDefault();
});
// --- Update ---
function update(dt) {
if (gameState === 'playing') {
// Speed up
const newSpeedLevel = Math.min(10, 1 + Math.floor(score / 5));
if (newSpeedLevel > speedLevel) {
speedLevel = newSpeedLevel;
tickRate = Math.max(55, 130 - (speedLevel - 1) * 8);
playTick();
speedFlash = 1.0;
prevSpeedLevel = speedLevel;
}
// Movement timer
lastMoveTime += dt * 1000;
while (lastMoveTime >= tickRate) {
lastMoveTime -= tickRate;
direction = { ...nextDirection };
const head = snake[0];
const nx = head.x + direction.x;
const ny = head.y + direction.y;
// Wall collision
if (nx < 0 || nx >= COLS || ny < 0 || ny >= ROWS) {
die();
return;
}
// Self collision
if (snake.some(s => s.x === nx && s.y === ny)) {
die();
return;
}
snake.unshift({ x: nx, y: ny });
// Eat food
if (nx === food.x && ny === food.y) {
score++;
playEat();
spawnParticles(nx, ny, '#ff6b6b', 18);
spawnParticles(nx, ny, '#ffd93d', 10);
spawnScorePop(nx, ny, '+1');
food = null;
spawnFood();
} else {
snake.pop();
}
}
}
// Dying animation
if (gameState === 'dying') {
flashAlpha += dt * 3;
shakeAmount = Math.max(0, shakeAmount - dt * 600);
if (flashAlpha > 1) {
gameState = 'dead';
flashAlpha = 1;
if (score > bestScore) bestScore = score;
}
}
// Decay effects
if (speedFlash > 0) speedFlash -= dt * 2.5;
if (shakeAmount < 0.5) shakeAmount = 0;
// Particles
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.life -= dt;
p.x += p.vx * dt;
p.y += p.vy * dt;
p.vy += 150 * dt; // gravity
p.vx *= 0.98;
if (p.life <= 0) particles.splice(i, 1);
}
// Score pops
for (let i = scorePops.length - 1; i >= 0; i--) {
const sp = scorePops[i];
sp.life -= dt;
sp.y += sp.vy * dt;
if (sp.life <= 0) scorePops.splice(i, 1);
}
}
function die() {
gameState = 'dying';
playDeath();
shakeAmount = 12;
flashAlpha = 0;
// Death particles along the snake
for (let i = 0; i < snake.length; i++) {
setTimeout(() => {
spawnParticles(snake[i].x, snake[i].y, '#ff4444', 6);
spawnParticles(snake[i].x, snake[i].y, '#ff8800', 4);
}, i * 30);
}
}
// --- Render ---
function render() {
ctx.save();
// Screen shake
if (shakeAmount > 0) {
const sx = (Math.random() - 0.5) * shakeAmount;
const sy = (Math.random() - 0.5) * shakeAmount;
ctx.translate(sx, sy);
}
// Background
ctx.fillStyle = '#0d0d18';
ctx.fillRect(0, 0, W, H);
// Grid lines (subtle)
ctx.strokeStyle = 'rgba(255,255,255,0.018)';
ctx.lineWidth = 0.5;
for (let x = 0; x <= COLS; x++) {
ctx.beginPath();
ctx.moveTo(x * CELL, 0);
ctx.lineTo(x * CELL, H);
ctx.stroke();
}
for (let y = 0; y <= ROWS; y++) {
ctx.beginPath();
ctx.moveTo(0, y * CELL);
ctx.lineTo(W, y * CELL);
ctx.stroke();
}
// Food glow
if (food) {
const pulse = 0.7 + 0.3 * Math.sin(performance.now() / 300);
const fx = food.x * CELL + CELL / 2;
const fy = food.y * CELL + CELL / 2;
const glowR = CELL * 1.2 * pulse;
const grad = ctx.createRadialGradient(fx, fy, 0, fx, fy, glowR);
grad.addColorStop(0, `rgba(255, 100, 100, ${0.3 * pulse})`);
grad.addColorStop(1, 'rgba(255, 100, 100, 0)');
ctx.fillStyle = grad;
ctx.fillRect(fx - glowR, fy - glowR, glowR * 2, glowR * 2);
// Food body
const fr = CELL * 0.32 * pulse;
ctx.fillStyle = '#ff6b6b';
ctx.beginPath();
ctx.arc(fx, fy, fr, 0, Math.PI * 2);
ctx.fill();
// Food shine
ctx.fillStyle = 'rgba(255,255,255,0.35)';
ctx.beginPath();
ctx.arc(fx - fr * 0.25, fy - fr * 0.25, fr * 0.35, 0, Math.PI * 2);
ctx.fill();
}
// Snake body
if (snake.length > 0) {
const len = snake.length;
for (let i = len - 1; i >= 0; i--) {
const seg = snake[i];
const sx = seg.x * CELL;
const sy = seg.y * CELL;
const isHead = i === 0;
const t = isHead ? 0 : i / Math.max(1, len - 1);
// Gradient from bright head to darker tail
const r = Math.round(127 - t * 60);
const g = Math.round(219 - t * 90);
const b = Math.round(202 - t * 80);
const color = `rgb(${r},${g},${b})`;
// Shadow
ctx.fillStyle = 'rgba(0,0,0,0.3)';
roundRect(ctx, sx + 1.5, sy + 1.5, CELL - 3, CELL - 3, isHead ? 7 : 5);
ctx.fill();
// Body segment
ctx.fillStyle = color;
roundRect(ctx, sx + 1.5, sy + 1.5, CELL - 3, CELL - 3, isHead ? 7 : 5);
ctx.fill();
// Highlight on top
ctx.fillStyle = 'rgba(255,255,255,0.12)';
roundRect(ctx, sx + 2, sy + 2, CELL - 4, CELL * 0.45, isHead ? 6 : 4);
ctx.fill();
// Joints between segments
if (i > 0) {
const prev = snake[i - 1];
const dx = seg.x - prev.x;
const dy = seg.y - prev.y;
// Draw a rounded connector
ctx.fillStyle = color;
const jointW = CELL - 5;
const jointH = CELL - 5;
let jx, jy;
if (dx === 1) { jx = sx + CELL - 2; jy = sy + 2; }
else if (dx === -1) { jx = sx - 2; jy = sy + 2; }
else if (dy === 1) { jx = sx + 2; jy = sy + CELL - 2; }
else if (dy === -1) { jx = sx + 2; jy = sy - 2; }
else { continue; }
roundRect(ctx, jx, jy, jointW, jointH, 4);
ctx.fill();
}
// Head details
if (isHead) {
// Eyes
const eyeSize = 3;
const pupilSize = 1.5;
let ex1, ey1, ex2, ey2;
const cx = sx + CELL / 2;
const cy = sy + CELL / 2;
if (direction.x === 1) {
ex1 = cx + 3; ey1 = cy - 4;
ex2 = cx + 3; ey2 = cy + 4;
} else if (direction.x === -1) {
ex1 = cx - 3; ey1 = cy - 4;
ex2 = cx - 3; ey2 = cy + 4;
} else if (direction.y === -1) {
ex1 = cx - 4; ey1 = cy - 3;
ex2 = cx + 4; ey2 = cy - 3;
} else {
ex1 = cx - 4; ey1 = cy + 3;
ex2 = cx + 4; ey2 = cy + 3;
}
// Eye whites
ctx.fillStyle = '#fff';
ctx.beginPath(); ctx.arc(ex1, ey1, eyeSize, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(ex2, ey2, eyeSize, 0, Math.PI * 2); ctx.fill();
// Pupils looking in movement direction
ctx.fillStyle = '#111';
ctx.beginPath(); ctx.arc(ex1 + direction.x * 1.2, ey1 + direction.y * 1.2, pupilSize, 0, Math.PI * 2); ctx.fill();
ctx.beginPath(); ctx.arc(ex2 + direction.x * 1.2, ey2 + direction.y * 1.2, pupilSize, 0, Math.PI * 2); ctx.fill();
}
}
}
// Particles
for (const p of particles) {
const alpha = p.life / p.maxLife;
ctx.globalAlpha = alpha;
ctx.fillStyle = p.color;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size * alpha, 0, Math.PI * 2);
ctx.fill();
}
ctx.globalAlpha = 1;
// Score pops
for (const sp of scorePops) {
const alpha = Math.min(1, sp.life / 0.3);
ctx.globalAlpha = alpha;
ctx.fillStyle = '#ffd93d';
ctx.font = 'bold 16px "Segoe UI", system-ui, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(sp.text, sp.x, sp.y);
}
ctx.globalAlpha = 1;
// Speed flash overlay
if (speedFlash > 0) {
ctx.fillStyle = `rgba(232, 168, 56, ${speedFlash * 0.08})`;
ctx.fillRect(0, 0, W, H);
}
// Death flash
if (flashAlpha > 0) {
const fa = Math.min(1, flashAlpha);
ctx.fillStyle = `rgba(255, 40, 40, ${fa * 0.35})`;
ctx.fillRect(0, 0, W, H);
}
// Overlay screens
if (gameState === 'ready') {
ctx.fillStyle = 'rgba(0,0,0,0.5)';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#7fdbca';
ctx.font = 'bold 32px "Segoe UI", system-ui, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('SNAKE', W / 2, H / 2 - 20);
ctx.fillStyle = '#8888aa';
ctx.font = '14px "Segoe UI", system-ui, sans-serif';
ctx.fillText('Arrow keys or WASD to move', W / 2, H / 2 + 20);
ctx.fillText('Press any arrow key to start', W / 2, H / 2 + 42);
}
if (gameState === 'paused') {
ctx.fillStyle = 'rgba(0,0,0,0.45)';
ctx.fillRect(0, 0, W, H);
ctx.fillStyle = '#e8a838';
ctx.font = 'bold 28px "Segoe UI", system-ui, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('PAUSED', W / 2, H / 2);
ctx.fillStyle = '#8888aa';
ctx.font = '13px "Segoe UI", system-ui, sans-serif';
ctx.fillText('Press P to resume', W / 2, H / 2 + 28);
}
if (gameState === 'dead') {
ctx.fillStyle = 'rgba(0,0,0,0.55)';
ctx.fillRect(0, 0, W, H);
// Flash fade
if (flashAlpha > 0) {
const fa = Math.min(1, flashAlpha);
ctx.fillStyle = `rgba(255, 40, 40, ${fa * 0.25})`;
ctx.fillRect(0, 0, W, H);
}
ctx.fillStyle = '#ff6b6b';
ctx.font = 'bold 30px "Segoe UI", system-ui, sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('GAME OVER', W / 2, H / 2 - 30);
ctx.fillStyle = '#7fdbca';
ctx.font = 'bold 20px "Segoe UI", system-ui, sans-serif';
ctx.fillText(`Score: ${score}`, W / 2, H / 2 + 5);
ctx.fillStyle = '#e8a838';
ctx.font = '14px "Segoe UI", system-ui, sans-serif';
ctx.fillText(`Best: ${bestScore}`, W / 2, H / 2 + 28);
const blink = Math.sin(performance.now() / 300) > 0;
if (blink) {
ctx.fillStyle = '#ffffff';
ctx.font = '14px "Segoe UI", system-ui, sans-serif';
ctx.fillText('Press SPACE to restart', W / 2, H / 2 + 60);
}
}
ctx.restore();
}
// Rounded rect helper
function roundRect(ctx, x, y, w, h, r) {
ctx.beginPath();
ctx.moveTo(x + r, y);
ctx.lineTo(x + w - r, y);
ctx.quadraticCurveTo(x + w, y, x + w, y + r);
ctx.lineTo(x + w, y + h - r);
ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
ctx.lineTo(x + r, y + h);
ctx.quadraticCurveTo(x, y + h, x, y + h - r);
ctx.lineTo(x, y + r);
ctx.quadraticCurveTo(x, y, x + r, y);
ctx.closePath();
}
// --- Start ---
initGame();
gameState = 'ready';
lastMoveTime = performance.now();
// Listen for first key to start
document.addEventListener('keydown', function startHandler(e) {
if (gameState === 'ready' && ['ArrowUp','ArrowDown','ArrowLeft','ArrowRight','KeyW','KeyS','KeyA','KeyD'].includes(e.code)) {
gameState = 'playing';
lastMoveTime = performance.now();
tickRate = 130;
speedLevel = 1;
prevSpeedLevel = 1;
document.removeEventListener('keydown', startHandler);
}
}, { once: false });
let prevTime = performance.now();
function loop(now) {
let dt = (now - prevTime) / 1000;
prevTime = now;
// Clamp dt to avoid huge jumps
if (dt > 0.1) dt = 0.016;
update(dt);
render();
// Update HUD
document.getElementById('scoreVal').textContent = score;
document.getElementById('speedVal').textContent = speedLevel;
requestAnimationFrame(loop);
}
requestAnimationFrame(loop);
</script>
</body>
</html>Same prompt, other models
One email when a new model lands on the board or in the showcase. Unsubscribe anytime.