Run details
- Model
- thinkingmachines/inkling
- Route
- OpenRouter API, one user message
- Served by
- Together
- Effort
- high, OpenRouter's default for this model
- Limits
- 60 min · 471,859 output tokens (the model's limit)
- Date
- 27 Oct 2026
- Time
- 2 min 40 s
- Size
- 20 kB
- Tokens
- 92 in, 16,853 out (10,086 of them thinking)
- List price
- $0.068 at today's price ($1 in / $4.05 out per M)
- Paid
- $0.068
Exact prompt
Make a Breakout game I can play right now with the keyboard or the mouse. Give it several levels, a score and some juice. It must be one complete, self-contained HTML file: inline all CSS and JavaScript, and make no network requests of any kind (no CDNs, web fonts or remote images). Reply with the file in a single ```html code block.
Source
20 kB 664 lines Raw
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Neon Breakout — 5 Levels</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; user-select: none; -webkit-user-select: none; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #03030a; font-family: system-ui, -apple-system, Segoe UI, sans-serif; }
canvas { display: block; width: 100%; height: 100vh; object-fit: contain; background: #020208; box-shadow: inset 0 0 120px #000; cursor: crosshair; }
#overlay {
position: absolute; inset: 0; pointer-events: none;
display: flex; flex-direction: column; align-items: center; justify-content: center;
}
.hud {
position: absolute; top: 0; left: 0; width: 100%; padding: 14px 24px;
display: flex; justify-content: space-between; align-items: center;
font-family: system-ui, sans-serif; font-weight: 800; letter-spacing: 2px;
color: #e0f8ff; text-shadow: 0 0 8px #0ff, 0 0 20px #0ff8;
pointer-events: none; z-index: 10;
}
.hud .item { font-size: 18px; text-transform: uppercase; opacity: 0.9; }
#centerText {
text-align: center; color: #fff; text-shadow: 0 0 30px #0ff, 0 0 60px #f0f;
pointer-events: none; transition: opacity 0.2s;
}
#centerText h1 { font-size: 64px; letter-spacing: 8px; margin-bottom: 12px; }
#centerText p { font-size: 22px; opacity: 0.9; font-weight: 300; letter-spacing: 3px; }
#centerText .small { margin-top: 28px; font-size: 16px; color: #aaa; text-shadow: none; }
</style>
</head>
<body>
<canvas id="c"></canvas>
<div class="hud">
<div class="item">Score <span id="s">0</span></div>
<div class="item">Level <span id="l">1</span> / 5</div>
<div class="item">Lives <span id="live">3</span></div>
</div>
<div id="overlay"><div id="centerText"></div></div>
<script>
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
// Logical resolution (scales to window via CSS object-fit, mouse mapped below)
const W = 800;
const H = 600;
canvas.width = W;
canvas.height = H;
// Audio context (lazy init)
let audioCtx = null;
function initAudio() {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
if (audioCtx.state === 'suspended') audioCtx.resume();
}
}
function playSound(type) {
if (!audioCtx) return;
try {
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
const now = audioCtx.currentTime;
if (type === 'brick') {
osc.type = 'triangle';
osc.frequency.setValueAtTime(200 + Math.random() * 600, now);
gain.gain.setValueAtTime(0.12, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.25);
osc.start(now); osc.stop(now + 0.25);
} else if (type === 'paddle') {
osc.type = 'sine';
osc.frequency.setValueAtTime(600 + Math.random() * 400, now);
gain.gain.setValueAtTime(0.1, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.15);
osc.start(now); osc.stop(now + 0.15);
} else if (type === 'death') {
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(250, now);
osc.frequency.exponentialRampToValueAtTime(60, now + 0.35);
gain.gain.setValueAtTime(0.12, now);
gain.gain.linearRampToValueAtTime(0.01, now + 0.35);
osc.start(now); osc.stop(now + 0.35);
} else if (type === 'level') {
osc.type = 'square';
osc.frequency.setValueAtTime(500, now);
osc.frequency.linearRampToValueAtTime(1000, now + 0.15);
osc.frequency.linearRampToValueAtTime(800, now + 0.3);
gain.gain.setValueAtTime(0.12, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.4);
osc.start(now); osc.stop(now + 0.4);
} else {
osc.type = 'sine';
osc.frequency.setValueAtTime(900, now);
gain.gain.setValueAtTime(0.08, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
osc.start(now); osc.stop(now + 0.1);
}
} catch (e) {}
}
// Mapping mouse/touch to logical coords
function getMousePos(e) {
const r = canvas.getBoundingClientRect();
const x = ((e.clientX - r.left) / r.width) * W;
const y = ((e.clientY - r.top) / r.height) * H;
return { x, y };
}
// Game state
let state = 'MENU'; // MENU, READY, PLAYING, LEVEL_CLEAR, GAME_OVER, WON
let level = 1;
let score = 0;
let lives = 3;
let combo = 0;
let comboTimer = 0;
let shake = 0;
const ball = { x: W/2, y: 520, r: 9, dx: 0, dy: 0, stuck: true, trail: [] };
const paddle = { x: W/2 - 60, y: 565, w: 130, h: 14 };
let bricks = [];
const particles = [];
const floatTexts = [];
const stars = [];
for (let i = 0; i < 120; i++) {
stars.push({
x: Math.random() * W,
y: Math.random() * H,
s: 0.5 + Math.random() * 1.5,
sp: 0.2 + Math.random() * 0.6,
b: 0.3 + Math.random() * 0.7
});
}
function buildLevel(n) {
bricks = [];
const bw = 72;
const bh = 22;
const gap = 8;
const totalW = 10 * bw + 9 * gap;
const startX = (W - totalW) / 2;
const startY = 60;
if (n === 1) {
for (let r = 0; r < 6; r++) {
for (let c = 0; c < 10; c++) {
bricks.push({ x: startX + c*(bw+gap), y: startY + r*(bh+gap), w: bw, h: bh, color: `hsl(${40 + r*35}, 100%, 60%)`, active: true, hits: 1 });
}
}
} else if (n === 2) {
for (let r = 0; r < 6; r++) {
for (let c = 0; c < 10; c++) {
if ((r + c) % 2 === 0) {
bricks.push({ x: startX + c*(bw+gap), y: startY + r*(bh+gap), w: bw, h: bh, color: `hsl(${200 + (r+c)*20}, 100%, 60%)`, active: true, hits: 1 });
}
}
}
} else if (n === 3) {
// Diamond pattern
const cols = [
[4,5], [3,4,5,6], [2,3,4,5,6,7],
[1,2,3,4,5,6,7,8], [2,3,4,5,6,7],
[3,4,5,6], [4,5]
];
for (let r = 0; r < cols.length; r++) {
for (const c of cols[r]) {
bricks.push({ x: startX + c*(bw+gap), y: startY + r*(bh+gap), w: bw, h: bh, color: `hsl(${50 + r*30}, 100%, 58%)`, active: true, hits: 1 });
}
}
} else if (n === 4) {
// Fortress with center hole
for (let r = 0; r < 7; r++) {
for (let c = 0; c < 10; c++) {
let skip = false;
if (r === 2 && c >= 4 && c <= 5) skip = true;
if (r === 3 && c >= 3 && c <= 6) skip = true;
if (r === 4 && c >= 4 && c <= 5) skip = true;
if (!skip) {
bricks.push({ x: startX + c*(bw+gap), y: startY + r*(bh+gap), w: bw, h: bh, color: `hsl(${280 + r*25}, 100%, 55%)`, active: true, hits: 1 });
}
}
}
} else if (n === 5) {
for (let r = 0; r < 9; r++) {
for (let c = 0; c < 10; c++) {
const hard = (r === 4 && c === 4) || (r === 4 && c === 5);
bricks.push({ x: startX + c*(bw+gap), y: startY + r*(bh+gap), w: bw, h: bh, color: hard ? '#ff0' : `hsl(${r*25}, 100%, 58%)`, active: true, hits: hard ? 2 : 1 });
}
}
}
}
function spawnParticles(b) {
const cx = b.x + b.w/2;
const cy = b.y + b.h/2;
for (let i = 0; i < 14; i++) {
const ang = (Math.PI * 2 * i) / 14 + Math.random() * 0.5;
const speed = 2 + Math.random() * 4;
particles.push({
x: cx, y: cy,
vx: Math.cos(ang) * speed,
vy: Math.sin(ang) * speed,
life: 30 + Math.random() * 20,
color: b.color,
size: 2 + Math.random() * 3
});
}
}
function spawnText(x, y, text, big = false) {
floatTexts.push({
x, y, text, life: 70, dy: -1.2 - Math.random(), size: big ? 26 : 18
});
}
function resetGame() {
score = 0;
lives = 3;
combo = 0;
comboTimer = 0;
level = 1;
shake = 0;
particles.length = 0;
floatTexts.length = 0;
ball.stuck = true;
ball.x = W/2;
ball.y = 520;
ball.dx = 0;
ball.dy = 0;
ball.trail = [];
buildLevel(level);
document.getElementById('s').textContent = score;
document.getElementById('live').textContent = lives;
document.getElementById('l').textContent = level;
}
function update() {
// Background stars
for (const s of stars) {
s.y += s.sp;
if (s.y > H + 10) { s.y = -10; s.x = Math.random() * W; }
}
// Paddle control (keyboard continuous)
if (state === 'READY' || state === 'PLAYING') {
const spd = 9;
if (keys['ArrowLeft'] || keys['a'] || keys['A']) paddle.x -= spd;
if (keys['ArrowRight'] || keys['d'] || keys['D']) paddle.x += spd;
paddle.x = Math.max(12, Math.min(W - paddle.w - 12, paddle.x));
}
if (state === 'PLAYING') {
// Ball trail
ball.trail.push({ x: ball.x, y: ball.y });
if (ball.trail.length > 20) ball.trail.shift();
if (ball.stuck) {
ball.x = paddle.x + paddle.w/2;
ball.y = paddle.y - ball.r - 2;
} else {
ball.x += ball.dx;
ball.y += ball.dy;
// Wall bounces
if (ball.x - ball.r < 0) { ball.dx = Math.abs(ball.dx) + (Math.random()*0.5); ball.x = ball.r + 1; playSound('paddle'); shake = 3; }
if (ball.x + ball.r > W) { ball.dx = -Math.abs(ball.dx) - (Math.random()*0.5); ball.x = W - ball.r - 1; playSound('paddle'); shake = 3; }
if (ball.y - ball.r < 0) { ball.dy = Math.abs(ball.dy) + (Math.random()*0.5); ball.y = ball.r + 1; playSound('paddle'); shake = 3; }
// Bottom death
if (ball.y + ball.r > H + 20) {
lives--;
combo = 0;
comboTimer = 0;
playSound('death');
shake = 12;
spawnText(W/2, H/2 - 40, 'MISS!', true);
document.getElementById('live').textContent = lives;
if (lives <= 0) {
state = 'GAME_OVER';
} else {
ball.stuck = true;
ball.dx = 0;
ball.dy = 0;
ball.x = W/2;
ball.y = 520;
}
return;
}
// Paddle bounce
if (ball.y + ball.r > paddle.y && ball.y - ball.r < paddle.y + paddle.h &&
ball.x + ball.r > paddle.x && ball.x - ball.r < paddle.x + paddle.w) {
// Calculate angle based on hit point
const hitPoint = (ball.x - (paddle.x + paddle.w/2)) / (paddle.w/2);
let angle = hitPoint * (Math.PI/3); // up to 60° from vertical
const speed = Math.min(Math.hypot(ball.dx, ball.dy) + 0.3, 9.5);
ball.dx = speed * Math.sin(angle);
ball.dy = -speed * Math.cos(angle);
playSound('paddle');
shake = 4;
ball.stuck = false;
}
// Brick collisions
for (let i = bricks.length - 1; i >= 0; i--) {
const b = bricks[i];
if (!b.active) continue;
if (ball.x + ball.r > b.x && ball.x - ball.r < b.x + b.w &&
ball.y + ball.r > b.y && ball.y - ball.r < b.y + b.h) {
// Hit
b.hits--;
if (b.hits <= 0) {
b.active = false;
score += 10 * (combo + 1);
combo++;
comboTimer = 90; // ~1.5s at 60fps
spawnParticles(b);
spawnText(b.x + b.w/2, b.y + b.h/2, '+' + (10*(combo+1)));
if (combo > 1) spawnText(b.x + b.w/2, b.y + b.h/2 - 20, combo + 'x COMBO!', true);
playSound('brick');
shake = 6;
} else {
// Glancing hit (hard brick)
playSound('brick');
spawnText(b.x + b.w/2, b.y, 'CRACK!', false);
shake = 3;
}
// Resolve overlap side for realistic bounce
const overlapX = (ball.x + ball.r) - b.x;
const overlapY = (ball.y + ball.r) - b.y;
const overlapRight = (b.x + b.w) - (ball.x - ball.r);
const overlapBottom = (b.y + b.h) - (ball.y - ball.r);
const minOverlap = Math.min(overlapX, overlapRight, overlapY, overlapBottom);
if (minOverlap === overlapX || minOverlap === overlapRight) {
ball.dx *= -1;
} else {
ball.dy *= -1;
}
// Add slight chaos for juice
ball.dx += (Math.random() - 0.5) * 1.5;
ball.dy += (Math.random() - 0.5) * 1.5;
// Prevent near-horizontal or near-stationary
if (Math.abs(ball.dy) < 1.5) ball.dy = ball.dy > 0 ? 2 : -2;
let sp = Math.hypot(ball.dx, ball.dy);
if (sp > 10) { ball.dx = (ball.dx / sp) * 9; ball.dy = (ball.dy / sp) * 9; }
if (sp < 4) { ball.dx = (ball.dx / sp) * 4; ball.dy = (ball.dy / sp) * 4; }
document.getElementById('s').textContent = score;
break;
}
}
// Check win condition
const remaining = bricks.filter(b => b.active).length;
if (remaining === 0) {
state = 'LEVEL_CLEAR';
combo = 0;
comboTimer = 0;
playSound('level');
document.getElementById('l').textContent = level;
shake = 0;
return;
}
}
// Decay combo timer
if (comboTimer > 0) {
comboTimer--;
if (comboTimer <= 0) combo = 0;
}
}
// Particles
for (let i = particles.length - 1; i >= 0; i--) {
const p = particles[i];
p.x += p.vx;
p.y += p.vy;
p.vy += 0.12;
p.life--;
if (p.life <= 0) particles.splice(i, 1);
}
// Floating texts
for (let i = floatTexts.length - 1; i >= 0; i--) {
const t = floatTexts[i];
t.y += t.dy;
t.life--;
if (t.life <= 0) floatTexts.splice(i, 1);
}
// Shake decay
if (shake > 0) shake *= 0.88;
if (shake < 0.5) shake = 0;
}
function draw() {
// Background
const grad = ctx.createRadialGradient(W/2, H/2, 0, W/2, H/2, 800);
grad.addColorStop(0, '#0d0d22');
grad.addColorStop(0.6, '#080818');
grad.addColorStop(1, '#020208');
ctx.fillStyle = grad;
ctx.fillRect(0, 0, W, H);
// Stars
for (const s of stars) {
ctx.fillStyle = `rgba(255,255,255,${s.b * 0.6})`;
ctx.fillRect(s.x, s.y, s.s, s.s);
}
// Shake offset
let sx = 0, sy = 0;
if (shake > 0) {
sx = (Math.random() - 0.5) * shake * 2.5;
sy = (Math.random() - 0.5) * shake * 2.5;
}
ctx.save();
ctx.translate(sx, sy);
// Levels / ready message
if (state === 'READY') {
ctx.fillStyle = 'rgba(255,255,255,0.08)';
ctx.font = 'bold 22px system-ui, sans-serif';
ctx.textAlign = 'center';
ctx.fillText('CLICK OR PRESS SPACE TO LAUNCH', W/2, H/2 + 60);
}
// Bricks
for (const b of bricks) {
if (!b.active) continue;
ctx.save();
ctx.shadowColor = b.color;
ctx.shadowBlur = 12;
ctx.fillStyle = b.color;
// Rounded rect with inner highlight
roundRect(ctx, b.x, b.y, b.w, b.h, 4);
ctx.fill();
ctx.restore();
// Inner bevel
ctx.save();
ctx.strokeStyle = 'rgba(255,255,255,0.25)';
ctx.lineWidth = 1.5;
roundRect(ctx, b.x + 1, b.y + 1, b.w - 2, b.h - 2, 2);
ctx.stroke();
ctx.restore();
}
// Paddle
ctx.save();
ctx.shadowColor = '#00f0ff';
ctx.shadowBlur = 18;
ctx.fillStyle = '#00f0ff';
roundRect(ctx, paddle.x, paddle.y, paddle.w, paddle.h, 7);
ctx.fill();
// Inner shine
ctx.fillStyle = 'rgba(255,255,255,0.35)';
roundRect(ctx, paddle.x + 3, paddle.y + 3, paddle.w - 6, 5, 4);
ctx.fill();
ctx.restore();
// Ball trail
for (let i = 0; i < ball.trail.length; i++) {
const t = ball.trail[i];
const alpha = (i + 1) / ball.trail.length * 0.35;
ctx.save();
ctx.globalAlpha = alpha;
ctx.shadowColor = '#00f0ff';
ctx.shadowBlur = 8;
ctx.fillStyle = '#00f0ff';
ctx.beginPath();
ctx.arc(t.x, t.y, ball.r * 0.6, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
// Ball
ctx.save();
ctx.shadowColor = '#ffffff';
ctx.shadowBlur = 20;
ctx.fillStyle = '#ffffff';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
// Particles
for (const p of particles) {
ctx.save();
ctx.globalAlpha = Math.max(0, p.life / 40);
ctx.fillStyle = p.color;
ctx.shadowColor = p.color;
ctx.shadowBlur = 6;
ctx.beginPath();
ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
}
// Floating texts
for (const t of floatTexts) {
ctx.save();
ctx.globalAlpha = Math.max(0, t.life / 70);
ctx.font = `bold ${t.size}px system-ui, sans-serif`;
ctx.textAlign = 'center';
ctx.fillStyle = t.size > 20 ? '#ffee00' : '#ffffff';
ctx.shadowColor = t.size > 20 ? '#ffee00' : '#ffffff';
ctx.shadowBlur = 10;
ctx.fillText(t.text, t.x, t.y);
ctx.restore();
}
// HUD overlay inside canvas for consistency
ctx.save();
ctx.shadowBlur = 0;
ctx.fillStyle = '#e8f8ff';
ctx.font = 'bold 14px system-ui, sans-serif';
ctx.textAlign = 'left';
ctx.fillText('SCORE ' + score, 20, 30);
ctx.textAlign = 'center';
ctx.fillText('LEVEL ' + level + ' / 5', W/2, 30);
ctx.textAlign = 'right';
ctx.fillText('LIVES ' + lives, W - 20, 30);
ctx.restore();
// Center messages
if (state === 'MENU') {
drawMenu('NEON BREAKOUT', 'Mouse / Arrow Keys / Space • Click to Play', '5 Levels • Score • Juice');
} else if (state === 'GAME_OVER') {
drawMenu('GAME OVER', 'Score: ' + score, 'Click or Space to Restart');
} else if (state === 'WON') {
drawMenu('YOU WIN!', 'Score: ' + score, 'Thanks for playing! Click to restart');
} else if (state === 'LEVEL_CLEAR') {
drawMenu('LEVEL CLEAR!', 'Score: ' + score, 'Click or Space for Level ' + (level + 1));
}
ctx.restore();
}
function roundRect(cx, x, y, w, h, r) {
cx.beginPath();
cx.moveTo(x + r, y);
cx.lineTo(x + w - r, y);
cx.quadraticCurveTo(x + w, y, x + w, y + r);
cx.lineTo(x + w, y + h - r);
cx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
cx.lineTo(x + r, y + h);
cx.quadraticCurveTo(x, y + h, x, y + h - r);
cx.lineTo(x, y + r);
cx.quadraticCurveTo(x, y, x + r, y);
cx.closePath();
}
function drawMenu(title, sub, small) {
ctx.save();
ctx.fillStyle = 'rgba(0,0,0,0.55)';
roundRect(ctx, W/2 - 280, 140, 560, 300, 16);
ctx.fill();
ctx.textAlign = 'center';
ctx.shadowColor = '#00f0ff';
ctx.shadowBlur = 25;
ctx.fillStyle = '#00f0ff';
ctx.font = 'bold 54px system-ui, sans-serif';
ctx.fillText(title, W/2, 240);
ctx.shadowBlur = 8;
ctx.fillStyle = '#ffffff';
ctx.font = '20px system-ui, sans-serif';
ctx.fillText(sub, W/2, 290);
ctx.fillStyle = '#aaa';
ctx.font = '14px system-ui, sans-serif';
if (small) ctx.fillText(small, W/2, 330);
ctx.restore();
}
// Interaction handlers
const keys = {};
window.addEventListener('keydown', (e) => {
keys[e.key] = true;
if (e.key === ' ' || e.key === 'Enter') {
e.preventDefault();
handleAction();
}
});
window.addEventListener('keyup', (e) => keys[e.key] = false);
canvas.addEventListener('mousemove', (e) => {
const pos = getMousePos(e);
paddle.x = pos.x - paddle.w/2;
paddle.x = Math.max(12, Math.min(W - paddle.w - 12, paddle.x));
if (ball.stuck && (state === 'READY' || state === 'PLAYING')) {
ball.x = paddle.x + paddle.w/2;
ball.y = paddle.y - ball.r - 2;
}
});
canvas.addEventListener('touchmove', (e) => {
e.preventDefault();
if (e.touches.length) {
const pos = getMousePos(e.touches[0]);
paddle.x = pos.x - paddle.w/2;
paddle.x = Math.max(12, Math.min(W - paddle.w - 12, paddle.x));
if (ball.stuck && (state === 'READY' || state === 'PLAYING')) {
ball.x = paddle.x + paddle.w/2;
ball.y = paddle.y - ball.r - 2;
}
}
}, { passive: false });
canvas.addEventListener('click', () => handleAction());
function handleAction() {
initAudio();
if (state === 'MENU') {
resetGame();
state = 'READY';
} else if (state === 'READY') {
state = 'PLAYING';
ball.stuck = false;
ball.dx = 4.5 + (Math.random() * 2 - 1) * 2;
ball.dy = -7.5 - Math.random() * 1.5;
if (Math.random() > 0.5) ball.dx *= -1;
} else if (state === 'LEVEL_CLEAR') {
level++;
if (level > 5) {
state = 'WON';
} else {
buildLevel(level);
ball.stuck = true;
ball.dx = 0; ball.dy = 0;
ball.x = W/2;
ball.y = 520;
document.getElementById('l').textContent = level;
state = 'READY';
}
} else if (state === 'GAME_OVER' || state === 'WON') {
resetGame();
state = 'READY';
}
}
// Main loop
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
resetGame();
loop();
</script>
</body>
</html>

