← Race the Sun results

Race the Sun

Gemma 4 31b · basic

Initial view of Race the Sun

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"} -->