Race the Sun
Gemma 4 31b · basic

Browser check: Artifact runtime error. This is a technical check, not a quality review.
Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 17,897 bytes · SHA-256 7d60842aa2a8
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SOLAR DRIFT</title>
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
overflow: hidden;
background-color: #0a0a12;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: #fff;
user-select: none;
}
canvas {
display: block;
width: 100vw;
height: 100vh;
cursor: none;
}
#ui {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
box-sizing: border-box;
}
.hud-top {
display: flex;
justify-content: space-between;
align-items: flex-start;
}
.stat-group {
display: flex;
flex-direction: column;
gap: 5px;
}
.label {
font-size: 12px;
text-transform: uppercase;
letter-spacing: 2px;
opacity: 0.7;
}
.value {
font-size: 24px;
font-weight: bold;
font-variant-numeric: tabular-nums;
}
#energy-container {
width: 200px;
height: 10px;
background: rgba(255,255,255,0.1);
border: 1px solid rgba(255,255,255,0.3);
margin-top: 5px;
position: relative;
}
#energy-bar {
width: 100%;
height: 100%;
background: #ffcc00;
box-shadow: 0 0 10px #ffcc00;
transition: width 0.1s linear;
}
#screen-msg {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
text-align: center;
pointer-events: auto;
background: rgba(0,0,0,0.8);
padding: 40px;
border: 2px solid #ffcc00;
box-shadow: 0 0 30px rgba(255, 204, 0, 0.3);
display: block;
}
h1 {
font-size: 48px;
margin: 0 0 20px 0;
letter-spacing: 10px;
color: #ffcc00;
text-shadow: 0 0 20px #ffcc00;
}
.btn {
background: transparent;
border: 1px solid #fff;
color: #fff;
padding: 10px 30px;
font-size: 18px;
cursor: pointer;
text-transform: uppercase;
letter-spacing: 2px;
transition: 0.2s;
}
.btn:hover {
background: #fff;
color: #000;
}
.hint {
margin-top: 20px;
font-size: 14px;
opacity: 0.6;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="ui">
<div class="hud-top">
<div class="stat-group">
<div class="label">Distance</div>
<div id="dist-val" class="value">0m</div>
<div class="label">Score</div>
<div id="score-val" class="value">0</div>
</div>
<div class="stat-group" style="align-items: flex-end;">
<div class="label">Energy</div>
<div id="energy-container"><div id="energy-bar"></div></div>
<div class="label" style="margin-top:10px">Speed</div>
<div id="speed-val" class="value">0 km/h</div>
</div>
</div>
<div id="screen-msg">
<h1 id="msg-title">SOLAR DRIFT</h1>
<p id="msg-body">Stay in the light. Avoid the dark.</p>
<button class="btn" id="start-btn">Launch Craft</button>
<div class="hint">WASD / ARROWS to Move | SPACE to Boost | R to Restart</div>
</div>
</div>
<script>
// === CONSTANTS & TUNING ===
const CONFIG = {
BASE_SPEED: 40,
MAX_SPEED: 180,
ACCELERATION: 0.02,
STRAFE_SPEED: 0.15,
PITCH_SPEED: 0.12,
FRICTION: 0.92,
ENERGY_DRAIN: 0.05,
SHADOW_DRAIN_MULT: 4.0,
BOOST_COST: 15,
BOOST_POWER: 1.5,
SUNK_SUN_Y: 0.8, // 0 to 1 (y coord on screen)
WORLD_WIDTH: 1200,
WORLD_DEPTH: 5000,
OBSTACLE_MIN_DIST: 300,
OBSTACLE_MAX_DIST: 800,
COLOR_SUN: '#ffcc00',
COLOR_SKY_TOP: '#1a1a2e',
COLOR_SKY_BOT: '#e94560',
COLOR_OBSTACLE: '#16213e',
}
// === GAME STATE ===
const state = {
running: false,
distance: 0,
score: 0,
multiplier: 1,
energy: 100,
speed: CONFIG.BASE_SPEED,
time: 0,
seed: Math.random(),
highScore: localStorage.getItem('solarDriftScore') || 0,
shake: 0,
flash: 0,
keys: {},
player: {
x: 0,
y: 0,
vx: 0,
vy: 0,
roll: 0,
pitch: 0,
width: 30,
height: 10
},
obstacles: [],
particles: [],
pickups: [],
sunPos: { x: 0, y: 0.5 },
camera: { x: 0, y: 0 }
}
// === AUDIO ENGINE (WebAudio) ===
const AudioCtx = window.AudioContext || window.webkitAudioContext;
let audioCtx = null;
function playSound(type) {
if (!audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.connect(gain);
gain.connect(audioCtx.destination);
const now = audioCtx.currentTime;
if (type === 'pickup') {
osc.type = 'sine';
osc.frequency.setValueAtTime(440, now);
osc.frequency.exponentialRampToValueAtTime(880, now + 0.1);
gain.gain.setValueAtTime(0.2, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.1);
osc.start();
osc.stop(now + 0.1);
} else if (type === 'crash') {
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(100, now);
osc.frequency.exponentialRampToValueAtTime(20, now + 0.3);
gain.gain.setValueAtTime(0.3, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.3);
osc.start();
osc.stop(now + 0.3);
} else if (type === 'boost') {
osc.type = 'square';
osc.frequency.setValueAtTime(60, now);
osc.frequency.linearRampToValueAtTime(120, now + 0.2);
gain.gain.setValueAtTime(0.1, now);
gain.gain.exponentialRampToValueAtTime(0.01, now + 0.2);
osc.start();
osc.stop(now + 0.2);
}
}
// === UTILS ===
const lerp = (a, b, t) => a + (b - a) * t;
const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
function seededRandom() {
const x = Math.sin(state.seed++) * 10000;
return x - Math.floor(x);
}
// === INITIALIZATION ===
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const distEl = document.getElementById('dist-val');
const scoreEl = document.getElementById('score-val');
const speedEl = document.getElementById('speed-val');
const energyBar = document.getElementById('energy-bar');
const screenMsg = document.getElementById('screen-msg');
const msgTitle = document.getElementById('msg-title');
const msgBody = document.getElementById('msg-body');
const startBtn = document.getElementById('start-btn');
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
}
window.addEventListener('resize', resize);
resize();
window.addEventListener('keydown', e => {
state.keys[e.code] = true;
if (e.code === 'KeyR' && !state.running) initGame();
});
window.addEventListener('keyup', e => state.keys[e.code] = false);
startBtn.addEventListener('click', () => {
if (!audioCtx) audioCtx = new AudioCtx();
initGame();
});
function initGame() {
state.running = true;
state.distance = 0;
state.score = 0;
state.multiplier = 1;
state.energy = 100;
state.speed = CONFIG.BASE_SPEED;
state.time = 0;
state.seed = Math.random() * 1000;
state.player.x = 0;
state.player.y = 0;
state.player.vx = 0;
state.player.vy = 0;
state.obstacles = [];
state.pickups = [];
state.particles = [];
state.sunPos.y = 0.4;
screenMsg.style.display = 'none';
}
function gameOver() {
state.running = false;
if (state.score > state.highScore) {
state.highScore = state.score;
localStorage.setItem('solarDriftScore', state.highScore);
}
playSound('crash');
msgTitle.innerText = "SYSTEM CRITICAL";
msgBody.innerHTML = `Distance: ${Math.floor(state.distance)}m<br>Score: ${Math.floor(state.score)}<br>High Score: ${Math.floor(state.highScore)}`;
startBtn.innerText = "Re-Launch";
screenMsg.style.display = 'block';
}
// === GAME ENGINE ===
function spawnObstacles() {
// Spawn at the horizon
if (state.obstacles.length < 20) {
const x = (seededRandom() - 0.5) * CONFIG.WORLD_WIDTH * 2;
const w = 50 + seededRandom() * 150;
const h = 50 + seededRandom() * 300;
const z = CONFIG.WORLD_DEPTH;
state.obstacles.push({ x, y: 0, z, w, h });
// Spawn energy or score near it
if (seededRandom() > 0.6) {
state.pickups.push({
x: x + w/2 + (seededRandom()-0.5)*100,
y: h/2,
z: z,
type: seededRandom() > 0.3 ? 'energy' : 'token',
size: 10
});
}
}
}
function updatePlayer() {
const p = state.player;
// Movement
if (state.keys['ArrowLeft'] || state.keys['KeyA']) p.vx -= CONFIG.STRAFE_SPEED;
if (state.keys['ArrowRight'] || state.keys['KeyD']) p.vx += CONFIG.STRAFE_SPEED;
if (state.keys['ArrowUp'] || state.keys['KeyW']) p.vy -= CONFIG.PITCH_SPEED;
if (state.keys['ArrowDown'] || state.keys['KeyS']) p.vy += CONFIG.PITCH_SPEED;
// Boost
if (state.keys['Space'] && state.energy > CONFIG.BOOST_COST) {
state.speed *= CONFIG.BOOST_POWER;
state.energy -= CONFIG.BOOST_COST / 60;
playSound('boost');
// Particle burst
for(let i=0; i<5; i++) spawnParticle(p.x, p.y, '#fff');
}
p.vx *= CONFIG.FRICTION;
p.vy *= CONFIG.FRICTION;
p.x += p.vx;
p.y += p.vy;
// Visual Tilts
p.roll = lerp(p.roll, p.vx * 2, 0.1);
p.pitch = lerp(p.pitch, p.vy, 0.1);
// Bounds
p.x = clamp(p.x, -CONFIG.WORLD_WIDTH/2, CONFIG.WORLD_WIDTH/2);
p.y = clamp(p.y, -200, 400);
}
function spawnParticle(x, y, color) {
state.particles.push({
x, y, z: 0,
vx: (Math.random()-0.5)*10,
vy: (Math.random()-0.5)*10,
vz: (Math.random()-0.5)*10,
life: 1.0,
color
});
}
function updateWorld() {
state.time += 0.016;
state.distance += state.speed / 100;
state.speed = lerp(state.speed, CONFIG.MAX_SPEED, CONFIG.ACCELERATION * 0.1);
// Sun sinks
state.sunPos.y = lerp(state.sunPos.y, CONFIG.SUNK_SUN_Y, 0.0001 * state.distance);
if (state.sunPos.y >= CONFIG.SUNK_SUN_Y) gameOver();
// Energy Drain
let inShadow = false;
state.obstacles.forEach(o => {
// Simple AABB check for shadow (if obstacle is between player and sun)
if (Math.abs(state.player.x - o.x) < o.w && o.z < 500) {
inShadow = true;
}
});
const drain = inShadow ? CONFIG.ENERGY_DRAIN * CONFIG.SHADOW_DRAIN_MULT : CONFIG.ENERGY_DRAIN;
state.energy -= drain;
if (state.energy <= 0) gameOver();
// Update Obstacles
for (let i = state.obstacles.length - 1; i >= 0; i--) {
const o = state.obstacles[i];
o.z -= state.speed;
// Collision
if (o.z < 50 && o.z > -50) {
const dx = Math.abs(state.player.x - o.x);
const dy = Math.abs(state.player.y - o.y);
if (dx < o.w/2 + 15 && dy < o.h/2 + 15) {
gameOver();
} else if (dx < o.w/2 + 50) {
// Near miss
state.score += 10 * state.multiplier;
state.shake = 5;
}
}
if (o.z < -1000) state.obstacles.splice(i, 1);
}
// Update Pickups
for (let i = state.pickups.length - 1; i >= 0; i--) {
const p = state.pickups[i];
p.z -= state.speed;
const dist = Math.sqrt((p.x - state.player.x)**2 + (p.y - state.player.y)**2 + (p.z)**2);
if (dist < 50) {
if (p.type === 'energy') {
state.energy = Math.min(100, state.energy + 20);
playSound('pickup');
} else {
state.score += 100 * state.multiplier;
state.multiplier += 0.1;
playSound('pickup');
}
state.pickups.splice(i, 1);
for(let j=0; j<10; j++) spawnParticle(p.x, p.y, '#fff');
} else if (p.z < -1000) {
state.pickups.splice(i, 1);
}
}
// Update Particles
for (let i = state.particles.length - 1; i >= 0; i--) {
const p = state.particles[i];
p.x += p.vx; p.y += p.vy; p.z += p.vz;
p.life -= 0.02;
if (p.life <= 0) state.particles.splice(i, 1);
}
spawnObstacles();
}
function project(x, y, z) {
const focalLength = 600;
const scale = focalLength / (focalLength + z);
return {
x: (canvas.width / 2) + x * scale,
y: (canvas.height / 2) + (y + 200) * scale, // Adjusted for horizon
scale: scale
};
}
function draw() {
// BG Gradient
const grad = ctx.createLinearGradient(0, 0, 0, canvas.height);
grad.addColorStop(0, CONFIG.COLOR_SKY_TOP);
grad.addColorStop(1, CONFIG.COLOR_SKY_BOT);
ctx.fillStyle = grad;
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Sun
const sunX = canvas.width * 0.5;
const sunY = canvas.height * state.sunPos.y;
const sunRad = 60;
const sunGrad = ctx.createRadialGradient(sunX, sunY, 0, sunX, sunY, sunRad * 2);
sunGrad.addColorStop(0, '#fff');
sunGrad.addColorStop(0.2, CONFIG.COLOR_SUN);
sunGrad.addColorStop(1, 'transparent');
ctx.fillStyle = sunGrad;
ctx.beginPath();
ctx.arc(sunX, sunY, sunRad * 2, 0, Math.PI * 2);
ctx.fill();
// Camera Shake
ctx.save();
if (state.shake > 0) {
ctx.translate((Math.random()-0.5)*state.shake, (Math.random()-0.5)*state.shake);
state.shake *= 0.9;
}
// Draw Obstacles
ctx.fillStyle = CONFIG.COLOR_OBSTACLE;
state.obstacles.forEach(o => {
const p1 = project(o.x - o.w/2, o.y - o.h/2, o.z);
const p2 = project(o.x + o.w/2, o.y + o.h/2, o.z);
const w = p2.x - p1.x;
const h = p2.y - p1.y;
ctx.globalAlpha = clamp(1 - o.z/CONFIG.WORLD_DEPTH, 0, 1);
ctx.fillRect(p1.x, p1.y, w, h);
// Highlight edge
ctx.strokeStyle = '#fff';
ctx.globalAlpha = clamp(1 - o.z/CONFIG.WORLD_DEPTH, 0, 1) * 0.3;
ctx.strokeRect(p1.x, p1.y, w, h);
});
ctx.globalAlpha = 1;
// Draw Pickups
state.pickups.forEach(p => {
const proj = project(p.x, p.y, p.z);
ctx.fillStyle = p.type === 'energy' ? '#ffcc00' : '#00ffff';
ctx.beginPath();
ctx.arc(proj.x, proj.y, p.size * proj.scale, 0, Math.PI * 2);
ctx.fill();
});
// Draw Particles
state.particles.forEach(p => {
const proj = project(p.x - state.player.x, p.y - state.player.y, p.z);
ctx.fillStyle = p.color;
ctx.globalAlpha = p.life;
ctx.fillRect(proj.x, proj.y, 3 * proj.scale, 3 * proj.scale);
});
ctx.globalAlpha = 1;
// Draw Player
const p = state.player;
ctx.save();
ctx.translate(canvas.width/2, canvas.height/2 + 200);
ctx.rotate(p.roll * 0.05);
// Craft Shape
ctx.fillStyle = '#fff';
ctx.beginPath();
ctx.moveTo(-20, 0);
ctx.lineTo(0, -10);
ctx.lineTo(20, 0);
ctx.lineTo(0, 10);
ctx.closePath();
ctx.fill();
// Cockpit
ctx.fillStyle = '#00ffff';
ctx.fillRect(-5, -2, 10, 4);
// Engine Glow
const glow = Math.sin(state.time * 20) * 5;
ctx.fillStyle = '#ff4400';
ctx.beginPath();
ctx.arc(0, 10, 5 + glow, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
// High Speed FX
if (state.speed > 120) {
ctx.strokeStyle = 'rgba(255,255,255,0.2)';
ctx.lineWidth = 2;
for(let i=0; i<10; i++) {
const x = Math.random() * canvas.width;
const y = Math.random() * canvas.height;
const len = Math.random() * 100;
ctx.beginPath();
ctx.moveTo(x, y);
ctx.lineTo(x, y + len);
ctx.stroke();
}
}
ctx.restore();
// Flash Effect
if (state.flash > 0) {
ctx.fillStyle = `rgba(255,255,255,${state.flash})`;
ctx.fillRect(0,0,canvas.width, canvas.height);
state.flash -= 0.1;
}
}
function loop() {
if (state.running) {
updatePlayer();
updateWorld();
// HUD update
distEl.innerText = `${Math.floor(state.distance)}m`;
scoreEl.innerText = Math.floor(state.score);
speedEl.innerText = `${Math.floor(state.speed * 10)} km/h`;
energyBar.style.width = `${state.energy}%`;
energyBar.style.backgroundColor = state.energy < 30 ? '#ff0000' : '#ffcc00';
}
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>
<!-- agent-meta {"model":"gemma-4-31b","provider":"cerebras","persona":"basic","sessionId":"3e7eef63-ac15-4802-8e34-1b3f8069297e","tokensIn":945,"tokensOut":6133,"tokensTotal":7078,"turns":1,"toolCalls":0,"failedToolCalls":0,"timestamp":"2026-07-14T21:56:21.091Z"} -->