← Canyon Run results

Canyon Run

Qwen 3.6 27B MTP GGUF IQ4 NL · typescript

Initial view of Canyon Run

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 46,052 bytes · SHA-256 89fb384a8144
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Canyon Rush — High-Speed Procedural Racer</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/shaders/CopyShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/shaders/LuminosityHighPassShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/UnrealBloomPass.js"></script>
<style>
/* ── css: layout ── */
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body, #app { width: 100%; height: 100%; overflow: hidden; background: #0a0014; font-family: 'Segoe UI', 'Arial Black', sans-serif; }
canvas#gameCanvas { display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; }

/* HUD */
#hud {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  pointer-events: none;
  z-index: 10;
}
#score {
  position: absolute;
  top: 20px; right: 30px;
  font-size: 28px;
  font-weight: 900;
  color: #fff;
  text-shadow: 0 0 20px #ff8800, 0 0 40px #ff4400;
  letter-spacing: 2px;
}
#multiplier {
  position: absolute;
  top: 55px; right: 30px;
  font-size: 36px;
  font-weight: 900;
  color: #ffaa00;
  text-shadow: 0 0 15px #ff6600;
  transition: transform 0.1s;
}
#multiplier.pulse {
  transform: scale(1.4);
  color: #ff4444;
  text-shadow: 0 0 30px #ff0000;
}

/* Speed bar - left side */
#speedBar {
  position: absolute;
  left: 30px;
  top: 50%;
  transform: translateY(-50%);
  width: 6px;
  height: 200px;
  background: rgba(255,255,255,0.1);
  border-radius: 3px;
  overflow: hidden;
}
#speedFill {
  position: absolute;
  bottom: 0;
  width: 100%;
  height: 30%;
  background: linear-gradient(to top, #ff4400, #ffaa00);
  border-radius: 3px;
  transition: height 0.2s;
  box-shadow: 0 0 10px #ff6600;
}

/* Energy bar - bottom center */
#energyBar {
  position: absolute;
  bottom: 30px;
  left: 50%;
  transform: translateX(-50%);
  width: 200px;
  height: 8px;
  background: rgba(255,255,255,0.1);
  border-radius: 4px;
  overflow: hidden;
}
#energyFill {
  position: absolute;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(to right, #00aaff, #00ffaa);
  border-radius: 4px;
  transition: width 0.15s;
  box-shadow: 0 0 10px #00aaff;
}

/* Turbo bar */
#turboBar {
  position: absolute;
  bottom: 50px;
  left: 50%;
  transform: translateX(-50%);
  width: 140px;
  height: 5px;
  background: rgba(255,255,255,0.08);
  border-radius: 3px;
  overflow: hidden;
}
#turboFill {
  position: absolute;
  left: 0;
  width: 0%;
  height: 100%;
  background: linear-gradient(to right, #ff00ff, #ff8800);
  border-radius: 3px;
  transition: width 0.1s;
  box-shadow: 0 0 8px #ff00ff;
}
/* ── css: ui ── */
/* Start screen */
#startScreen {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  background: radial-gradient(ellipse at center, rgba(26,0,48,0.9) 0%, rgba(10,0,20,0.98) 100%);
  z-index: 50;
  pointer-events: auto;
}
#startTitle {
  font-size: 64px;
  font-weight: 900;
  color: #FF6600;
  text-shadow: 0 0 30px #FF4400, 0 0 60px #FF2200, 0 4px 0 #882200;
  letter-spacing: 8px;
  margin-bottom: 10px;
}
#startSub {
  font-size: 18px;
  color: #AA88CC;
  letter-spacing: 3px;
  margin-bottom: 30px;
}
#startControls {
  font-size: 13px;
  color: #888;
  margin-bottom: 30px;
  letter-spacing: 1px;
}
#startBtn, #restartBtn {
  pointer-events: auto;
  padding: 15px 50px;
  font-size: 20px;
  font-weight: 900;
  color: #fff;
  background: linear-gradient(135deg, #FF4400, #CC2200);
  border: none;
  border-radius: 4px;
  cursor: pointer;
  letter-spacing: 4px;
  text-shadow: 0 2px 4px rgba(0,0,0,0.5);
  box-shadow: 0 4px 20px rgba(255,68,0,0.4);
  transition: transform 0.1s, box-shadow 0.1s;
}
#startBtn:hover, #restartBtn:hover {
  transform: scale(1.05);
  box-shadow: 0 6px 30px rgba(255,68,0,0.6);
}

/* Game over screen */
#gameOver {
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  display: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  z-index: 100;
}
#goTitle {
  font-size: 56px;
  font-weight: 900;
  color: #FF4444;
  text-shadow: 0 0 30px #FF0000, 0 0 60px #CC0000;
  letter-spacing: 6px;
  margin-bottom: 30px;
}
#goScore, #goSpeed, #goMultiplier {
  font-size: 22px;
  color: #DDCCFF;
  margin: 8px 0;
  letter-spacing: 2px;
  text-shadow: 0 0 10px rgba(200,150,255,0.5);
}
#restartBtn {
  margin-top: 30px;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="hud">
  <div id="speedBar"><div id="speedFill"></div></div>
  <div id="multiplier">x1</div>
  <div id="energyBar"><div id="energyFill"></div></div>
  <div id="turboBar"><div id="turboFill"></div></div>
  <div id="score">0</div>
</div>
<div id="gameOver" style="display:none">
  <div id="goTitle">GAME OVER</div>
  <div id="goScore">Final Score: 0</div>
  <div id="goSpeed">Max Speed: 0</div>
  <div id="goMultiplier">Best Multiplier: x1</div>
  <button id="restartBtn">RESTART</button>
</div>
<div id="startScreen">
  <div id="startTitle">CANYON RUSH</div>
  <div id="startSub">Navigate the procedural canyon</div>
  <div id="startControls">W/S — Pitch Up/Down &nbsp; A/D — Turn Left/Right &nbsp; SPACE — Boost</div>
  <button id="startBtn">LAUNCH</button>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./player":"src/player.ts","./input":"src/input.ts","./sound":"src/sound.ts","./particles":"src/particles.ts","./world":"src/world.ts","./types":"src/types.ts"},"src/input.ts":{"./types":"src/types.ts"},"src/world.ts":{"./types":"src/types.ts"},"src/player.ts":{"./types":"src/types.ts"}};
function __require(id) {
  if (__cache[id]) return __cache[id].exports;
  var module = __cache[id] = { exports: {} };
  var factory = __mods[id];
  if (!factory) throw new Error("Module not found: " + id);
  factory(module.exports, function (spec) {
    var target = (__map[id] && __map[id][spec]) || spec;
    return __require(target);
  }, module);
  return module.exports;
}

// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const player_1 = require("./player");
const input_1 = require("./input");
const sound_1 = require("./sound");
const particles_1 = require("./particles");
const world_1 = require("./world");
let renderer;
let scene;
let camera;
let composer;
let player;
let input;
let sound;
let particles;
let speedParticles;
let chunks = [];
let game;
let clock;
// HUD elements
let hudScore;
let hudMultiplier;
let hudSpeedFill;
let hudEnergyFill;
let hudTurboFill;
let gameOverScreen;
let startScreen;
let goScore;
let goSpeed;
let goMultiplier;
// Camera effects
let shakeIntensity = 0;
let cameraShakeX = 0;
let cameraShakeY = 0;
// Misc objects
let sunMesh;
let groundPlane;
let ceilingPlane;
let sunLight;
// Timers
let trailTimer = 0;
let dustTimer = 0;
const MAX_CHUNKS = 14;
const PLAYER_RADIUS = 1.5;
// Colors
const SKY_TOP = 0x0a0020;
const SKY_HORIZON = 0x4a1020;
const SUN_COLOR = 0xff8844;
function init() {
    hudScore = document.getElementById('score');
    hudMultiplier = document.getElementById('multiplier');
    hudSpeedFill = document.getElementById('speedFill');
    hudEnergyFill = document.getElementById('energyFill');
    hudTurboFill = document.getElementById('turboFill');
    gameOverScreen = document.getElementById('gameOver');
    startScreen = document.getElementById('startScreen');
    goScore = document.getElementById('goScore');
    goSpeed = document.getElementById('goSpeed');
    goMultiplier = document.getElementById('goMultiplier');
    // Renderer
    const canvas = document.getElementById('gameCanvas');
    renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    renderer.shadowMap.enabled = true;
    renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    // Scene
    scene = new THREE.Scene();
    scene.fog = new THREE.FogExp2(0x1a0a20, 0.002);
    scene.background = new THREE.Color(0x0a0015);
    // Camera
    camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.5, 600);
    camera.position.set(0, 4, -10);
    // === LIGHTS ===
    // Warm ambient
    const ambient = new THREE.AmbientLight(0x331155, 0.5);
    scene.add(ambient);
    // Sunset directional (main light)
    sunLight = new THREE.DirectionalLight(0xff6633, 1.0);
    sunLight.position.set(40, 60, -40);
    sunLight.castShadow = true;
    sunLight.shadow.mapSize.width = 1024;
    sunLight.shadow.mapSize.height = 1024;
    sunLight.shadow.camera.near = 1;
    sunLight.shadow.camera.far = 300;
    sunLight.shadow.camera.left = -80;
    sunLight.shadow.camera.right = 80;
    sunLight.shadow.camera.top = 60;
    sunLight.shadow.camera.bottom = -40;
    scene.add(sunLight);
    // Purple rim light from behind
    const rim = new THREE.DirectionalLight(0x8844ff, 0.3);
    rim.position.set(-30, 15, -15);
    scene.add(rim);
    // Horizon glow point light
    const horizonGlow = new THREE.PointLight(0xff4400, 2, 250);
    horizonGlow.position.set(0, 15, 200);
    scene.add(horizonGlow);
    // === SUN DISK ===
    const sunGeo = new THREE.SphereGeometry(8, 16, 16);
    const sunMat = new THREE.MeshBasicMaterial({ color: 0xffcc44 });
    sunMesh = new THREE.Mesh(sunGeo, sunMat);
    sunMesh.position.set(30, 25, 250);
    scene.add(sunMesh);
    // Sun glow ring
    const glowGeo = new THREE.SphereGeometry(14, 16, 16);
    const glowMat = new THREE.MeshBasicMaterial({
        color: 0xff6633,
        transparent: true,
        opacity: 0.3,
    });
    const sunGlow = new THREE.Mesh(glowGeo, glowMat);
    sunGlow.position.copy(sunMesh.position);
    scene.add(sunGlow);
    // === GROUND PLANE (follows camera) ===
    const groundGeo = new THREE.PlaneGeometry(400, 400, 1, 1);
    const groundMat = new THREE.MeshPhongMaterial({
        color: 0x2a1510,
        flatShading: true,
    });
    groundPlane = new THREE.Mesh(groundGeo, groundMat);
    groundPlane.rotation.x = -Math.PI / 2;
    groundPlane.position.y = -25;
    groundPlane.receiveShadow = true;
    scene.add(groundPlane);
    // === CEILING PLANE ===
    const ceilMat = new THREE.MeshPhongMaterial({
        color: 0x1a0a20,
        flatShading: true,
        side: THREE.DoubleSide,
    });
    ceilingPlane = new THREE.Mesh(groundGeo, ceilMat);
    ceilingPlane.rotation.x = Math.PI / 2;
    ceilingPlane.position.y = 35;
    scene.add(ceilingPlane);
    // === POST-PROCESSING ===
    try {
        composer = new THREE.EffectComposer(renderer);
        const renderPass = new THREE.RenderPass(scene, camera);
        composer.addPass(renderPass);
        const bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.8, 0.4, 0.15);
        composer.addPass(bloomPass);
        composer.bloomPass = bloomPass;
    }
    catch (_e) {
        composer = null;
    }
    // Player
    player = new player_1.Player();
    scene.add(player.mesh);
    // Input
    input = new input_1.InputManager();
    // Sound
    sound = new sound_1.SoundSynth();
    // Particles (trails + effects)
    particles = new particles_1.ParticleSystem();
    scene.add(particles.getMesh());
    // Speed particles (dust/debris)
    speedParticles = new particles_1.ParticleSystem();
    scene.add(speedParticles.getMesh());
    // Clock
    clock = new THREE.Clock();
    // Game state
    game = {
        running: false,
        gameOver: false,
        paused: false,
        score: 0,
        multiplier: 1,
        multiplierTimer: 0,
        maxSpeed: 0,
        bestMultiplier: 1,
        distance: 0,
    };
    // Generate initial chunks
    for (let i = 0; i < 6; i++) {
        addChunk(i * world_1.CHUNK_LENGTH);
    }
    // Events
    window.addEventListener('resize', onResize);
    document.getElementById('startBtn').addEventListener('click', startGame);
    document.getElementById('restartBtn').addEventListener('click', restartGame);
    requestAnimationFrame(gameLoop);
}
function onResize() {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
    if (composer)
        composer.setSize(window.innerWidth, window.innerHeight);
}
function startGame() {
    sound.init();
    startScreen.style.display = 'none';
    game.running = true;
    game.gameOver = false;
}
function restartGame() {
    // Clear old chunks
    for (const chunk of chunks) {
        for (const mesh of chunk.meshes) {
            scene.remove(mesh);
            try {
                mesh.geometry.dispose();
            }
            catch (_e) { /* */ }
            try {
                mesh.material.dispose();
            }
            catch (_e) { /* */ }
        }
    }
    chunks = [];
    // Reset player
    const ps = player.state;
    ps.x = 0;
    ps.y = 0;
    ps.z = 0;
    ps.vx = 0;
    ps.vy = 0;
    ps.vz = 0;
    ps.roll = 0;
    ps.pitch = 0;
    ps.yaw = 0;
    ps.energy = 100;
    ps.turbo = 20;
    ps.boosting = false;
    ps.speed = 0.4;
    // Reset game
    game.score = 0;
    game.multiplier = 1;
    game.multiplierTimer = 0;
    game.maxSpeed = 0;
    game.bestMultiplier = 1;
    game.distance = 0;
    game.running = true;
    game.gameOver = false;
    particles.reset();
    speedParticles.reset();
    shakeIntensity = 0;
    gameOverScreen.style.display = 'none';
    gameOverScreen.style.background = '';
    // Rebuild
    for (let i = 0; i < 6; i++) {
        addChunk(i * world_1.CHUNK_LENGTH);
    }
}
function addChunk(z) {
    const difficulty = Math.min(5, game.score / 5000);
    const canyonCurve = game.distance * 0.001;
    const chunk = (0, world_1.generateChunk)(z, difficulty, canyonCurve);
    for (const mesh of chunk.meshes) {
        scene.add(mesh);
    }
    chunks.push(chunk);
}
function removeChunk(chunk) {
    for (const mesh of chunk.meshes) {
        scene.remove(mesh);
        try {
            mesh.geometry.dispose();
        }
        catch (_e) { /* */ }
        try {
            mesh.material.dispose();
        }
        catch (_e) { /* */ }
    }
    chunks.splice(chunks.indexOf(chunk), 1);
}
function checkCollisions() {
    const px = player.state.x;
    const py = player.state.y;
    const pz = player.state.z;
    for (const chunk of chunks) {
        if (Math.abs(chunk.z - pz) > world_1.CHUNK_LENGTH * 1.5)
            continue;
        for (const obs of chunk.obstacles) {
            const halfW = obs.width / 2 + PLAYER_RADIUS * 0.5;
            const halfH = obs.height / 2 + PLAYER_RADIUS * 0.5;
            const halfD = obs.depth / 2 + 1.5;
            const dx = Math.abs(px - obs.x);
            const dy = Math.abs(py - obs.y);
            const dz = Math.abs(pz - obs.z);
            if (dx < halfW && dy < halfH && dz < halfD) {
                triggerGameOver();
                return;
            }
            // Near-miss: close but not colliding
            const dist = Math.sqrt(dx * dx + dy * dy);
            const nearMissThreshold = halfW + halfH;
            if (dist < nearMissThreshold * 0.7 && dz > 0 && dz < 8 && dx < halfW * 2.5 && dy < halfH * 2.5) {
                game.multiplier = Math.min(10, game.multiplier + 0.25);
                game.multiplierTimer = 2;
                game.score += Math.floor(25 * game.multiplier);
                sound.nearMiss();
                shakeIntensity = 0.4;
                hudMultiplier.classList.add('pulse');
                setTimeout(() => hudMultiplier.classList.remove('pulse'), 200);
            }
        }
        // Orb collection
        for (const orb of chunk.orbs) {
            if (orb.collected)
                continue;
            const dx = px - orb.x;
            const dy = py - orb.y;
            const dz = pz - orb.z;
            const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
            if (dist < 3.5) {
                orb.collected = true;
                scene.remove(orb.mesh);
                player.state.energy = Math.min(100, player.state.energy + 18);
                player.state.turbo = Math.min(100, player.state.turbo + 12);
                game.score += Math.floor(30 * game.multiplier);
                sound.collect();
                particles.emit(orb.x, orb.y, orb.z, 12, 10, 0x00ffaa, 0.8);
            }
        }
    }
}
function triggerGameOver() {
    game.running = false;
    game.gameOver = true;
    sound.crash();
    sound.stop();
    shakeIntensity = 3;
    particles.emit(player.state.x, player.state.y, player.state.z, 50, 20, 0xff4400, 1.5);
    setTimeout(() => {
        gameOverScreen.style.display = 'flex';
        gameOverScreen.style.flexDirection = 'column';
        gameOverScreen.style.alignItems = 'center';
        gameOverScreen.style.justifyContent = 'center';
        gameOverScreen.style.background = 'rgba(5,0,15,0.88)';
        gameOverScreen.style.position = 'absolute';
        gameOverScreen.style.top = '0';
        gameOverScreen.style.left = '0';
        gameOverScreen.style.width = '100%';
        gameOverScreen.style.height = '100%';
        gameOverScreen.style.zIndex = '100';
        document.getElementById('goTitle').innerHTML = 'GAME OVER';
        goScore.textContent = `Final Score: ${Math.floor(game.score)}`;
        goSpeed.textContent = `Max Speed: ${(game.maxSpeed * 400).toFixed(0)} km/h`;
        goMultiplier.textContent = `Best Multiplier: x${game.bestMultiplier.toFixed(1)}`;
    }, 600);
}
function updateCamera(dt) {
    const ps = player.state;
    // Smooth follow with offset based on roll
    const targetX = ps.x * 0.5;
    const targetY = ps.y * 0.35 + 4.5;
    const camDist = ps.boosting ? 14 : 10;
    const targetZ = ps.z - camDist;
    camera.position.x += (targetX - camera.position.x) * dt * 4;
    camera.position.y += (targetY - camera.position.y) * dt * 4;
    camera.position.z += (targetZ - camera.position.z) * dt * 4;
    // Camera shake
    if (shakeIntensity > 0.01) {
        cameraShakeX = (Math.random() - 0.5) * shakeIntensity;
        cameraShakeY = (Math.random() - 0.5) * shakeIntensity;
        shakeIntensity *= 0.92;
    }
    else {
        cameraShakeX = 0;
        cameraShakeY = 0;
    }
    camera.position.x += cameraShakeX;
    camera.position.y += cameraShakeY;
    // Look ahead
    camera.lookAt(new THREE.Vector3(ps.x * 0.25, ps.y * 0.2, ps.z + 40));
    // FOV boost
    const targetFov = ps.boosting ? 95 : 72;
    camera.fov += (targetFov - camera.fov) * dt * 4;
    camera.updateProjectionMatrix();
    // Bloom intensity
    try {
        const bp = composer?.bloomPass;
        if (bp && bp.uniforms && bp.uniforms.strength) {
            const bloomTarget = 0.5 + ps.speed * 1.2 + (ps.boosting ? 0.8 : 0);
            bp.uniforms.strength.value += (bloomTarget - bp.uniforms.strength.value) * dt * 3;
        }
    }
    catch (_e) { /* skip */ }
}
function updatePlayerVisuals() {
    const ps = player.state;
    const pm = player.mesh;
    pm.position.set(ps.x, ps.y, ps.z);
    pm.rotation.z = ps.roll;
    pm.rotation.x = ps.pitch;
    // Engine glow
    const eg = player.engineGlow;
    eg.scale.x = 1;
    eg.scale.y = 1;
    eg.scale.z = 1 + ps.speed * 4;
    eg.material.opacity = 0.5 + ps.speed * 0.5;
    if (ps.boosting) {
        eg.material.color.setHex(0xFF00FF);
    }
    else {
        eg.material.color.setHex(0xFF4400);
    }
    // Move ground plane with player (infinite ground illusion)
    groundPlane.position.set(ps.x * 0.5, -25, ps.z);
    ceilingPlane.position.set(ps.x * 0.5, 35, ps.z);
    // Update sun position to stay far ahead
    sunMesh.position.set(30 + Math.sin(ps.z * 0.005) * 20, 25, ps.z + 250);
    // Update sun light to track camera
    sunLight.position.set(40 + ps.x, 60, ps.z - 40);
    sunLight.target.position.set(ps.x, ps.y, ps.z);
    sunLight.target.updateMatrix();
}
function updateHUD() {
    const ps = player.state;
    hudScore.textContent = Math.floor(game.score).toLocaleString();
    hudMultiplier.textContent = `x${game.multiplier.toFixed(1)}`;
    const speedPct = Math.min(100, (ps.speed / (0.4 * 1.5)) * 100);
    hudSpeedFill.style.height = `${speedPct}%`;
    hudEnergyFill.style.width = `${ps.energy}%`;
    if (ps.energy < 20) {
        hudEnergyFill.style.background = 'linear-gradient(to right, #ff0000, #ff4400)';
        hudEnergyFill.style.boxShadow = '0 0 15px #ff0000';
    }
    else if (ps.energy < 40) {
        hudEnergyFill.style.background = 'linear-gradient(to right, #ff8800, #ffaa00)';
        hudEnergyFill.style.boxShadow = '0 0 10px #ff8800';
    }
    else {
        hudEnergyFill.style.background = 'linear-gradient(to right, #00aaff, #00ffaa)';
        hudEnergyFill.style.boxShadow = '0 0 10px #00aaff';
    }
    hudTurboFill.style.width = `${ps.turbo}%`;
    if (ps.boosting) {
        hudTurboFill.style.background = 'linear-gradient(to right, #ff00ff, #ffffff)';
        hudTurboFill.style.boxShadow = '0 0 20px #ff00ff';
    }
    else {
        hudTurboFill.style.background = 'linear-gradient(to right, #ff00ff, #ff8800)';
        hudTurboFill.style.boxShadow = '0 0 8px #ff00ff';
    }
}
function gameLoop() {
    requestAnimationFrame(gameLoop);
    const dt = Math.min(clock.getDelta(), 0.05);
    if (game.running && !game.gameOver) {
        const inputState = input.get();
        player.update(dt, inputState);
        updatePlayerVisuals();
        // Track max speed
        const speedRatio = player.getSpeedRatio();
        if (speedRatio > game.maxSpeed)
            game.maxSpeed = speedRatio;
        // Engine sound
        sound.updateEngine(speedRatio);
        // Score from distance
        game.distance = player.state.z;
        game.score += dt * 10 * game.multiplier;
        // Multiplier decay
        if (game.multiplierTimer > 0) {
            game.multiplierTimer -= dt;
        }
        else if (game.multiplier > 1) {
            game.multiplier = Math.max(1, game.multiplier - dt * 0.3);
        }
        if (game.multiplier > game.bestMultiplier) {
            game.bestMultiplier = game.multiplier;
        }
        // Energy death check
        if (player.state.energy <= 0) {
            triggerGameOver();
        }
        // Collisions
        checkCollisions();
        // Chunk management
        const playerZ = player.state.z;
        const visibleRange = world_1.CHUNK_LENGTH * (MAX_CHUNKS / 2);
        while (chunks.length > 0 && chunks[0].z < playerZ - visibleRange) {
            removeChunk(chunks[0]);
        }
        const lastChunk = chunks[chunks.length - 1];
        if (lastChunk && lastChunk.z < playerZ + visibleRange) {
            addChunk(lastChunk.z + world_1.CHUNK_LENGTH);
        }
        // === PARTICLES ===
        // Trail behind craft
        trailTimer -= dt;
        if (trailTimer <= 0) {
            trailTimer = 0.015;
            const offset = player.state.boosting ? 3.5 : 2;
            const spd = player.state.speed * 6;
            particles.emit(player.state.x + (Math.random() - 0.5) * 0.8, player.state.y + (Math.random() - 0.5) * 0.8, player.state.z + offset, player.state.boosting ? 3 : 1, spd, player.state.boosting ? 0xff00ff : 0xff6600, 0.4);
        }
        // Dust/debris speed particles
        dustTimer -= dt;
        if (dustTimer <= 0) {
            dustTimer = player.state.boosting ? 0.03 : 0.06;
            const spread = 20;
            const count = player.state.boosting ? 3 : 1;
            for (let i = 0; i < count; i++) {
                speedParticles.emit(player.state.x + (Math.random() - 0.5) * spread, player.state.y + (Math.random() - 0.5) * spread * 0.6, player.state.z + 25 + Math.random() * 20, 1, 0, 0xff8844, 0.4);
            }
        }
        // Animate orbs
        const time = clock.getElapsedTime();
        for (const chunk of chunks) {
            for (const orb of chunk.orbs) {
                if (!orb.collected) {
                    orb.mesh.rotation.y = time * 2.5;
                    orb.mesh.rotation.x = Math.sin(time * 1.5) * 0.3;
                    orb.mesh.position.y = orb.y + Math.sin(time * 3 + orb.z * 0.1) * 0.6;
                    // Pulse glow
                    const pulse = 0.8 + Math.sin(time * 5) * 0.2;
                    orb.mesh.scale.set(pulse, pulse, pulse);
                }
            }
        }
        // Update camera
        updateCamera(dt);
        // Update particles
        particles.update(dt);
        speedParticles.update(dt);
        // Update HUD
        updateHUD();
    }
    // Render
    if (composer) {
        composer.render(dt);
    }
    else {
        renderer.render(scene, camera);
    }
}
// Start
init();
};

// ── types: globals.d.ts ──
__mods["globals.d.ts"] = function (exports) {};

// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
};

// ── module: src/input.ts ──
__mods["src/input.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputManager = void 0;
class InputManager {
    constructor() {
        this.state = { up: false, down: false, left: false, right: false, boost: false };
        window.addEventListener('keydown', this.onKey.bind(this));
        window.addEventListener('keyup', this.onKey.bind(this));
        window.addEventListener('blur', () => {
            this.state = { up: false, down: false, left: false, right: false, boost: false };
        });
    }
    onKey(e) {
        const k = e.key.toLowerCase();
        if (k === 'w' || k === 'arrowup')
            this.state.up = e.type === 'keydown';
        if (k === 's' || k === 'arrowdown')
            this.state.down = e.type === 'keydown';
        if (k === 'a' || k === 'arrowleft')
            this.state.left = e.type === 'keydown';
        if (k === 'd' || k === 'arrowright')
            this.state.right = e.type === 'keydown';
        if (k === ' ') {
            this.state.boost = e.type === 'keydown';
            e.preventDefault();
        }
    }
    get() { return this.state; }
}
exports.InputManager = InputManager;
};

// ── module: src/sound.ts ──
__mods["src/sound.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SoundSynth = void 0;
class SoundSynth {
    constructor() {
        this.ctx = null;
        this.masterGain = null;
        this.engineOsc = null;
        this.engineGain = null;
        this.started = false;
    }
    init() {
        if (this.started)
            return;
        this.ctx = new AudioContext();
        this.masterGain = this.ctx.createGain();
        this.masterGain.gain.value = 0.3;
        this.masterGain.connect(this.ctx.destination);
        // Engine hum
        this.engineOsc = this.ctx.createOscillator();
        this.engineGain = this.ctx.createGain();
        this.engineOsc.type = 'sawtooth';
        this.engineOsc.frequency.value = 60;
        this.engineGain.gain.value = 0;
        this.engineOsc.connect(this.engineGain);
        this.engineGain.connect(this.masterGain);
        this.engineOsc.start();
        this.started = true;
    }
    updateEngine(speedRatio) {
        if (!this.engineOsc || !this.engineGain)
            return;
        const freq = 50 + speedRatio * 150;
        this.engineOsc.frequency.setTargetAtTime(freq, this.ctx.currentTime, 0.1);
        this.engineGain.gain.setTargetAtTime(0.08 + speedRatio * 0.12, this.ctx.currentTime, 0.1);
    }
    collect() {
        if (!this.ctx || !this.masterGain)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.setValueAtTime(800, this.ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(1600, this.ctx.currentTime + 0.1);
        gain.gain.setValueAtTime(0.3, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.2);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.25);
    }
    nearMiss() {
        if (!this.ctx || !this.masterGain)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.setValueAtTime(300, this.ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(600, this.ctx.currentTime + 0.08);
        osc.frequency.exponentialRampToValueAtTime(100, this.ctx.currentTime + 0.2);
        gain.gain.setValueAtTime(0.4, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.25);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.3);
    }
    crash() {
        if (!this.ctx || !this.masterGain)
            return;
        const bufferSize = this.ctx.sampleRate * 0.5;
        const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
        const data = buffer.getChannelData(0);
        for (let i = 0; i < bufferSize; i++) {
            data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / bufferSize, 2);
        }
        const source = this.ctx.createBufferSource();
        source.buffer = buffer;
        const gain = this.ctx.createGain();
        gain.gain.value = 0.5;
        source.connect(gain);
        gain.connect(this.masterGain);
        source.start();
    }
    boost() {
        if (!this.ctx || !this.masterGain)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sawtooth';
        osc.frequency.setValueAtTime(200, this.ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(800, this.ctx.currentTime + 0.3);
        gain.gain.setValueAtTime(0.15, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.5);
        osc.connect(gain);
        gain.connect(this.masterGain);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.55);
    }
    stop() {
        if (this.engineGain) {
            this.engineGain.gain.setTargetAtTime(0, this.ctx.currentTime, 0.05);
        }
    }
}
exports.SoundSynth = SoundSynth;
};

// ── module: src/world.ts ──
__mods["src/world.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CANYON_WIDTH = exports.CHUNK_LENGTH = void 0;
exports.generateChunk = generateChunk;
const CHUNK_LENGTH = 200;
exports.CHUNK_LENGTH = CHUNK_LENGTH;
const CANYON_WIDTH = 60;
exports.CANYON_WIDTH = CANYON_WIDTH;
const ORB_COUNT_PER_CHUNK = 5;
const WALL_COLORS = [0x8B3A0F, 0xA0522D, 0x6B2D1A, 0x7B3A1E, 0x944B2E, 0x5C2E14];
function randomColor() {
    return WALL_COLORS[Math.floor(Math.random() * WALL_COLORS.length)];
}
function createMesh(geo, color, emissive, emissiveIntensity) {
    const mat = new THREE.MeshPhongMaterial({
        color: color,
        flatShading: true,
        emissive: emissive || 0x000000,
        emissiveIntensity: emissiveIntensity || 0,
    });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.castShadow = true;
    mesh.receiveShadow = true;
    return mesh;
}
function createCanyonWall(x, y, z, w, h, d) {
    // Use low-segment geometry for low-poly look
    const geo = new THREE.BoxGeometry(w, h, d, 1, 1, 1);
    const mesh = createMesh(geo, randomColor());
    mesh.position.set(x, y, z);
    // Slight random tilt for organic feel
    mesh.rotation.y = (Math.random() - 0.5) * 0.05;
    mesh.rotation.x = (Math.random() - 0.5) * 0.03;
    return mesh;
}
function createMonolith(x, y, z, w, h, d) {
    const geo = new THREE.BoxGeometry(w, h, d, 1, 1, 1);
    const mesh = createMesh(geo, 0x2A1040, 0x1A0830, 0.3);
    mesh.position.set(x, y, z);
    mesh.rotation.y = (Math.random() - 0.5) * 0.2;
    return mesh;
}
function createOrb(x, y, z) {
    const geo = new THREE.IcosahedronGeometry(0.8);
    const mat = new THREE.MeshBasicMaterial({
        color: 0x00ffaa,
        transparent: true,
        opacity: 0.9,
    });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.set(x, y, z);
    return mesh;
}
function generateChunk(z, difficulty, canyonCurve) {
    const chunk = {
        z: z,
        meshes: [],
        orbs: [],
        obstacles: [],
    };
    // Canyon width narrows with difficulty
    const currentWidth = Math.max(20, CANYON_WIDTH - difficulty * 5);
    const halfWidth = currentWidth / 2;
    // Generate canyon walls (left and right)
    const wallSegments = 8;
    for (let i = 0; i < wallSegments; i++) {
        const segZ = z + i * (CHUNK_LENGTH / wallSegments);
        const curve = Math.sin(segZ * 0.008 + canyonCurve) * (10 + difficulty * 3);
        const noise = Math.sin(segZ * 0.02 + i) * 5;
        // Left wall
        const lw = 8 + Math.random() * 5;
        const lh = 20 + Math.random() * 30 + difficulty * 2;
        const ld = CHUNK_LENGTH / wallSegments + 5;
        const lx = -halfWidth + curve + noise;
        const ly = -10 + Math.random() * 5;
        const leftWall = createCanyonWall(lx, ly, segZ, lw, lh, ld);
        chunk.meshes.push(leftWall);
        chunk.obstacles.push({
            mesh: leftWall, x: lx, y: ly, z: segZ,
            width: lw, height: lh, depth: ld, type: 'wall',
        });
        // Right wall
        const rlx = halfWidth + curve + noise;
        const rly = -10 + Math.random() * 5;
        const rlh = 20 + Math.random() * 30 + difficulty * 2;
        const rightWall = createCanyonWall(rlx, rly, segZ, lw, rlh, ld);
        chunk.meshes.push(rightWall);
        chunk.obstacles.push({
            mesh: rightWall, x: rlx, y: rly, z: segZ,
            width: lw, height: rlh, depth: ld, type: 'wall',
        });
    }
    // Monoliths (floating obstacles)
    const monolithCount = Math.floor(1 + difficulty * 1.5);
    for (let i = 0; i < monolithCount; i++) {
        const mz = z + 10 + Math.random() * (CHUNK_LENGTH - 20);
        const mx = (Math.random() - 0.5) * (currentWidth - 10);
        const my = (Math.random() - 0.5) * 18;
        const mw = 2 + Math.random() * 3;
        const mh = 6 + Math.random() * 10;
        const md = 2 + Math.random() * 3;
        const mono = createMonolith(mx, my, mz, mw, mh, md);
        chunk.meshes.push(mono);
        chunk.obstacles.push({
            mesh: mono, x: mx, y: my, z: mz,
            width: mw, height: mh, depth: md, type: 'monolith',
        });
    }
    // Tight squeezes (narrow gaps)
    if (difficulty > 0.3) {
        const squeezeCount = Math.min(4, Math.floor(difficulty * 0.8));
        for (let i = 0; i < squeezeCount; i++) {
            const sz = z + 30 + Math.random() * (CHUNK_LENGTH - 60);
            const sx = (Math.random() - 0.5) * 8;
            const sy = (Math.random() - 0.5) * 8;
            const gapHeight = 3.5 + Math.random() * 3;
            const aboveH = 8 + Math.random() * 5;
            const belowH = 8 + Math.random() * 5;
            const sw = currentWidth - 4;
            const sd = 2;
            // Top wall segment (ceiling of squeeze)
            const top = createCanyonWall(sx, sy + gapHeight / 2 + aboveH / 2, sz, sw, aboveH, sd);
            chunk.meshes.push(top);
            chunk.obstacles.push({
                mesh: top, x: sx, y: sy + gapHeight / 2 + aboveH / 2, z: sz,
                width: sw, height: aboveH, depth: sd, type: 'squeeze',
            });
            // Bottom wall segment (floor of squeeze)
            const bottom = createCanyonWall(sx, sy - gapHeight / 2 - belowH / 2, sz, sw, belowH, sd);
            chunk.meshes.push(bottom);
            chunk.obstacles.push({
                mesh: bottom, x: sx, y: sy - gapHeight / 2 - belowH / 2, z: sz,
                width: sw, height: belowH, depth: sd, type: 'squeeze',
            });
        }
    }
    // Generate orbs - place some in tight spots for risk/reward
    for (let i = 0; i < ORB_COUNT_PER_CHUNK + Math.floor(difficulty); i++) {
        const ox = (Math.random() - 0.5) * (currentWidth - 12);
        const oy = (Math.random() - 0.5) * 14;
        const oz = z + 10 + Math.random() * (CHUNK_LENGTH - 20);
        const orbMesh = createOrb(ox, oy, oz);
        chunk.meshes.push(orbMesh);
        chunk.orbs.push({ mesh: orbMesh, x: ox, y: oy, z: oz, collected: false });
    }
    return chunk;
}
};

// ── module: src/player.ts ──
__mods["src/player.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Player = void 0;
class Player {
    constructor() {
        this.state = {
            x: 0, y: 0, z: 0,
            vx: 0, vy: 0, vz: 0,
            roll: 0, pitch: 0, yaw: 0,
            energy: 100,
            turbo: 0,
            boosting: false,
            speed: 0.4,
        };
        this.mesh = this.createCraft();
    }
    createCraft() {
        const group = new THREE.Group();
        // Main body - sleek arrow shape
        const bodyGeo = new THREE.ConeGeometry(0.5, 3, 6);
        const bodyMat = new THREE.MeshPhongMaterial({
            color: 0xCCCCCC,
            emissive: 0x333333,
            emissiveIntensity: 0.2,
            flatShading: true,
        });
        const body = new THREE.Mesh(bodyGeo, bodyMat);
        body.rotation.x = Math.PI / 2;
        body.castShadow = true;
        group.add(body);
        // Wings
        const wingGeo = new THREE.BoxGeometry(4, 0.1, 1.5);
        const wingMat = new THREE.MeshPhongMaterial({
            color: 0xAA4400,
            flatShading: true,
        });
        const wings = new THREE.Mesh(wingGeo, wingMat);
        wings.position.z = 0.3;
        wings.position.y = -0.1;
        wings.castShadow = true;
        group.add(wings);
        // Wing tips
        const tipGeo = new THREE.ConeGeometry(0.2, 0.8, 4);
        const tipMat = new THREE.MeshPhongMaterial({
            color: 0xFF6600,
            emissive: 0xFF4400,
            emissiveIntensity: 0.5,
            flatShading: true,
        });
        const leftTip = new THREE.Mesh(tipGeo, tipMat);
        leftTip.position.set(-2, -0.1, 0.3);
        leftTip.rotation.z = Math.PI / 2;
        group.add(leftTip);
        const rightTip = new THREE.Mesh(tipGeo, tipMat);
        rightTip.position.set(2, -0.1, 0.3);
        rightTip.rotation.z = Math.PI / 2;
        group.add(rightTip);
        // Engine glow
        const glowGeo = new THREE.ConeGeometry(0.3, 1.2, 6);
        const glowMat = new THREE.MeshBasicMaterial({
            color: 0xFF4400,
            transparent: true,
            opacity: 0.7,
        });
        this.engineGlow = new THREE.Mesh(glowGeo, glowMat);
        this.engineGlow.rotation.x = -Math.PI / 2;
        this.engineGlow.position.z = 1.8;
        group.add(this.engineGlow);
        // Engine light
        const engineLight = new THREE.PointLight(0xFF4400, 1.5, 10);
        engineLight.position.z = 2;
        group.add(engineLight);
        return group;
    }
    update(dt, input) {
        const s = this.state;
        // Speed increases with distance
        const baseSpeed = 0.4;
        const speedBoost = s.boosting ? 1.5 : 1;
        const currentSpeed = baseSpeed * speedBoost;
        s.speed += (currentSpeed - s.speed) * dt * 5;
        // Movement forces
        const lateralForce = 18;
        const verticalForce = 12;
        let targetVx = 0;
        let targetVy = 0;
        let targetRoll = 0;
        let targetPitch = 0;
        if (input.left) {
            targetVx = -lateralForce;
            targetRoll = -0.5;
        }
        if (input.right) {
            targetVx = lateralForce;
            targetRoll = 0.5;
        }
        if (input.up) {
            targetVy = verticalForce;
            targetPitch = -0.25;
        }
        if (input.down) {
            targetVy = -verticalForce;
            targetPitch = 0.25;
        }
        // Boost
        if (input.boost && s.turbo > 0 && !s.boosting) {
            s.boosting = true;
        }
        if (s.boosting && s.turbo > 0) {
            s.turbo -= dt * 30;
            if (s.turbo <= 0) {
                s.turbo = 0;
                s.boosting = false;
            }
        }
        if (!input.boost) {
            s.boosting = false;
        }
        // Physics integration
        const damping = 0.92;
        s.vx += (targetVx - s.vx) * dt * 8;
        s.vy += (targetVy - s.vy) * dt * 8;
        s.vx *= Math.pow(damping, dt * 60);
        s.vy *= Math.pow(damping, dt * 60);
        // Apply movement
        s.x += s.vx * dt;
        s.y += s.vy * dt;
        s.z += s.speed * dt * 120;
        // Banking / roll interpolation
        s.roll += (targetRoll - s.roll) * dt * 10;
        s.pitch += (targetPitch - s.pitch) * dt * 10;
        // Energy decay
        const decayRate = s.boosting ? 2.5 : 0.8 + (s.speed / 0.4) * 0.3;
        s.energy -= dt * decayRate;
        // Turbo charge from speed
        if (!s.boosting) {
            s.turbo = Math.min(100, s.turbo + dt * 5);
        }
        // Clamp
        s.energy = Math.max(0, Math.min(100, s.energy));
        s.turbo = Math.max(0, Math.min(100, s.turbo));
    }
    getSpeedRatio() {
        return this.state.speed / (0.4 * 1.5);
    }
    getWorldPosition() {
        return new THREE.Vector3(this.state.x, this.state.y, this.state.z);
    }
}
exports.Player = Player;
};

// ── module: src/particles.ts ──
__mods["src/particles.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParticleSystem = void 0;
class ParticleSystem {
    constructor() {
        this.velocities = [];
        this.lifetimes = [];
        this.index = 0;
        this.MAX = 2000;
        this.positions = new Float32Array(this.MAX * 3);
        this.colors = new Float32Array(this.MAX * 3);
        this.sizes = new Float32Array(this.MAX);
        for (let i = 0; i < this.MAX; i++) {
            this.velocities[i] = { x: 0, y: 0, z: 0 };
            this.lifetimes[i] = 0;
        }
        this.geo = new THREE.BufferGeometry();
        this.geo.setAttribute('position', new THREE.BufferAttribute(this.positions, 3));
        this.geo.setAttribute('color', new THREE.BufferAttribute(this.colors, 3));
        this.geo.setAttribute('size', new THREE.BufferAttribute(this.sizes, 1));
        this.material = new THREE.PointsMaterial({
            size: 0.3,
            transparent: true,
            opacity: 0.6,
            blending: THREE.AdditiveBlending,
            depthWrite: false,
            sizeAttenuation: true,
            vertexColors: true,
        });
        this.points = new THREE.Points(this.geo, this.material);
    }
    getMesh() {
        return this.points;
    }
    emit(x, y, z, count, speed, color, life) {
        const r = ((color >> 16) & 0xff) / 255;
        const g = ((color >> 8) & 0xff) / 255;
        const b = (color & 0xff) / 255;
        for (let i = 0; i < count; i++) {
            const idx = this.index % this.MAX;
            this.positions[idx * 3] = x;
            this.positions[idx * 3 + 1] = y;
            this.positions[idx * 3 + 2] = z;
            this.colors[idx * 3] = r;
            this.colors[idx * 3 + 1] = g;
            this.colors[idx * 3 + 2] = b;
            this.sizes[idx] = 0.2 + Math.random() * 0.4;
            this.velocities[idx] = {
                x: (Math.random() - 0.5) * speed,
                y: (Math.random() - 0.5) * speed,
                z: (Math.random() - 0.5) * speed,
            };
            this.lifetimes[idx] = life * (0.5 + Math.random() * 0.5);
            this.index++;
        }
    }
    update(dt) {
        for (let i = 0; i < this.MAX; i++) {
            if (this.lifetimes[i] <= 0) {
                this.sizes[i] = 0;
                continue;
            }
            this.lifetimes[i] -= dt;
            if (this.lifetimes[i] <= 0) {
                this.sizes[i] = 0;
                continue;
            }
            this.positions[i * 3] += this.velocities[i].x * dt;
            this.positions[i * 3 + 1] += this.velocities[i].y * dt;
            this.positions[i * 3 + 2] += this.velocities[i].z * dt;
            this.sizes[i] *= 0.98;
        }
        this.geo.attributes.position.needsUpdate = true;
        this.geo.attributes.color.needsUpdate = true;
        this.geo.attributes.size.needsUpdate = true;
    }
    reset() {
        this.index = 0;
        for (let i = 0; i < this.MAX; i++) {
            this.lifetimes[i] = 0;
            this.sizes[i] = 0;
            this.positions[i * 3 + 2] = -9999;
        }
    }
}
exports.ParticleSystem = ParticleSystem;
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"unsloth/Qwen3.6-27B-MTP-GGUF-IQ4_NL","provider":"brigid","persona":"typescript","sessionId":"c9921633-58db-4161-b906-91a9a1801301","tokensIn":1679391,"tokensOut":36281,"tokensTotal":1715672,"cost":0,"turns":47,"toolCalls":55,"failedToolCalls":1,"timestamp":"2026-08-04T14:32:01.858Z"} -->