← Canyon Run results

Canyon Run

Qwen 3.6 27b MTP · 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 69,353 bytes · SHA-256 3d5f43518c5f
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Canyon Racer — High-Speed Procedural Arcade</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
/* ── css: layout ── */
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0612; font-family: 'Segoe UI', system-ui, sans-serif; }
#game-container { position: relative; width: 100vw; height: 100vh; }
#game-canvas { display: block; width: 100%; height: 100%; }

.hidden { display: none !important; }

/* Vignette overlay */
#game-container::after {
  content: '';
  position: absolute;
  top: 0; left: 0; right: 0; bottom: 0;
  background: radial-gradient(ellipse at center, transparent 50%, rgba(10,6,18,0.6) 100%);
  pointer-events: none;
  z-index: 4;
}

/* Start Screen */
#start-screen {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: radial-gradient(ellipse at center, rgba(255,100,30,0.08) 0%, rgba(10,6,18,0.97) 70%);
  z-index: 10; color: #fff; text-align: center;
}
#start-screen h1 {
  font-size: clamp(2rem, 6vw, 5rem); font-weight: 900; letter-spacing: 0.3em;
  background: linear-gradient(180deg, #ffaa44 0%, #ff4422 50%, #cc2266 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent;
  margin-bottom: 0.2em;
}
#start-screen .subtitle {
  font-size: clamp(0.7rem, 1.5vw, 1rem); letter-spacing: 0.5em; color: #8866aa;
  text-transform: uppercase; margin-bottom: 3em;
}
#controls-info { margin-bottom: 2em; }
#controls-info p { font-size: 0.9rem; color: #aaa; margin: 0.4em 0; letter-spacing: 0.1em; }
#controls-info strong { color: #ffaa44; }

/* Buttons */
button {
  padding: 0.8em 3em; font-size: 1.1rem; font-weight: 700; letter-spacing: 0.2em;
  border: 2px solid #ff6633; background: transparent; color: #ffaa44;
  cursor: pointer; text-transform: uppercase; transition: all 0.2s;
}
button:hover { background: #ff6633; color: #fff; }

/* HUD */
#hud { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 5; }

#score-display {
  position: absolute; top: 20px; right: 30px; font-size: 2rem; font-weight: 900;
  color: #ffcc44; text-shadow: 0 0 20px rgba(255,170,68,0.5); letter-spacing: 0.05em;
}

#multiplier-display {
  position: absolute; top: 55px; right: 30px; font-size: 1.4rem; font-weight: 700;
  color: #ff6644; text-shadow: 0 0 15px rgba(255,102,68,0.4); letter-spacing: 0.1em;
  transition: transform 0.1s;
}

/* Speed Bar - Left side */
#speed-bar-container {
  position: absolute; left: 30px; top: 50%; transform: translateY(-50%);
  width: 6px; height: 200px; background: rgba(255,255,255,0.1); border-radius: 3px;
}
#speed-bar {
  position: absolute; bottom: 0; left: 0; width: 100%; height: 50%;
  background: linear-gradient(0deg, #ff4422, #ffaa44); border-radius: 3px;
  transition: height 0.1s; box-shadow: 0 0 10px rgba(255,68,34,0.5);
}

/* Energy Bar - Bottom center */
#energy-container {
  position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%);
  width: 200px; height: 8px; background: rgba(255,255,255,0.1); border-radius: 4px;
}
#energy-bar {
  position: absolute; left: 0; top: 0; width: 100%; height: 100%;
  background: linear-gradient(90deg, #ff2266, #ffaa44); border-radius: 4px;
  transition: width 0.1s; box-shadow: 0 0 15px rgba(255,34,102,0.5);
}

/* Turbo Bar - Bottom right */
#turbo-container {
  position: absolute; bottom: 30px; right: 30px;
  width: 120px; height: 6px; background: rgba(255,255,255,0.1); border-radius: 3px;
}
#turbo-bar {
  position: absolute; left: 0; top: 0; width: 0%; height: 100%;
  background: linear-gradient(90deg, #44aaff, #88ffcc); border-radius: 3px;
  transition: width 0.1s; box-shadow: 0 0 10px rgba(68,170,255,0.5);
}

/* Game Over Screen */
#game-over-screen {
  position: absolute; top: 0; left: 0; width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  background: rgba(10,6,18,0.92); z-index: 10; color: #fff; text-align: center;
}
#game-over-screen h1 {
  font-size: clamp(2rem, 5vw, 4rem); font-weight: 900; letter-spacing: 0.3em;
  color: #ff4466; margin-bottom: 2em; text-shadow: 0 0 30px rgba(255,68,102,0.5);
}
#final-stats { display: flex; gap: 3em; margin-bottom: 2em; }
#final-stats > div { display: flex; flex-direction: column; align-items: center; }
.stat-label { font-size: 0.7rem; letter-spacing: 0.3em; color: #8866aa; text-transform: uppercase; margin-bottom: 0.3em; }
.stat-value { font-size: 2rem; font-weight: 900; color: #ffcc44; text-shadow: 0 0 15px rgba(255,204,68,0.4); }

/* Near-miss flash */
@keyframes nearMissFlash {
  0% { transform: scale(1); opacity: 1; }
  50% { transform: scale(1.3); opacity: 0.8; }
  100% { transform: scale(1); opacity: 1; }
}
.near-miss-pulse { animation: nearMissFlash 0.2s ease-out; }

/* Energy warning pulse */
@keyframes energyWarning {
  0%, 100% { box-shadow: 0 0 15px rgba(255,34,102,0.5); }
  50% { box-shadow: 0 0 25px rgba(255,0,68,0.9); }
}

/* Turbo ready glow */
@keyframes turboReady {
  0%, 100% { box-shadow: 0 0 10px rgba(68,170,255,0.5); }
  50% { box-shadow: 0 0 20px rgba(68,170,255,0.9), 0 0 30px rgba(136,255,204,0.3); }
}
</style>
</head>
<body>
<div id="game-container">
  <canvas id="game-canvas"></canvas>
  <div id="hud" class="hidden">
    <div id="speed-bar-container"><div id="speed-bar"></div></div>
    <div id="multiplier-display">x1.0</div>
    <div id="energy-container"><div id="energy-bar"></div></div>
    <div id="turbo-container"><div id="turbo-bar"></div></div>
    <div id="score-display">0</div>
  </div>
  <div id="start-screen">
    <h1>CANYON RACER</h1>
    <p class="subtitle">HIGH-SPEED PROCEDURAL ARCADE</p>
    <div id="controls-info">
      <p><strong>W/S</strong> — Pitch Up/Down</p>
      <p><strong>A/D</strong> — Roll Left/Right</p>
      <p><strong>SPACE</strong> — Boost</p>
    </div>
    <button id="start-btn">LAUNCH</button>
  </div>
  <div id="game-over-screen" class="hidden">
    <h1>RUN ENDED</h1>
    <div id="final-stats">
      <div><span class="stat-label">FINAL SCORE</span><span id="final-score" class="stat-value">0</span></div>
      <div><span class="stat-label">MAX SPEED</span><span id="max-speed" class="stat-value">0</span></div>
      <div><span class="stat-label">DISTANCE</span><span id="distance" class="stat-value">0</span></div>
    </div>
    <button id="restart-btn">RESTART</button>
  </div>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./types":"src/types.ts","./state":"src/state.ts","./audio":"src/audio.ts","./player":"src/player.ts","./world":"src/world.ts","./particles":"src/particles.ts","./hud":"src/hud.ts","./postprocessing":"src/postprocessing.ts"},"src/state.ts":{"./types":"src/types.ts"},"src/player.ts":{"./types":"src/types.ts"},"src/world.ts":{"./types":"src/types.ts"},"src/hud.ts":{"./types":"src/types.ts"},"src/postprocessing.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";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
const types_1 = require("./types");
const state_1 = require("./state");
const audio = __importStar(require("./audio"));
const playerModule = __importStar(require("./player"));
const world = __importStar(require("./world"));
const particles = __importStar(require("./particles"));
const hud = __importStar(require("./hud"));
const postprocessing = __importStar(require("./postprocessing"));
// Three.js globals
let scene;
let camera;
let renderer;
let playerCraft;
// Game state
let playerState;
let gameState;
// Track which chunk meshes are in the scene for proper cleanup
const activeChunkKeys = new Set();
// Add distant sky particles for depth perception
function addSkyParticles(scene) {
    const starCount = 200;
    const starGeo = new THREE.BoxGeometry(0.1, 0.1, 0.1);
    const starMat = new THREE.MeshBasicMaterial({
        color: 0xffaacc, transparent: true, opacity: 0.4
    });
    for (let i = 0; i < starCount; i++) {
        const star = new THREE.Mesh(starGeo, starMat);
        star.position.set((Math.random() - 0.5) * 200, Math.random() * 80 + 10, -Math.random() * 400 - 50);
        const s = 0.5 + Math.random();
        star.scale.set(s, s, s);
        scene.add(star);
    }
}
// Timing
let lastTime = 0;
let frameCount = 0;
let debrisTimer = 0;
let trailTimer = 0;
// Camera target for smooth following
let cameraTargetPos;
let cameraCurrentOffset;
// Near-miss tracking
let lastNearMissTime = 0;
function init() {
    // Setup Three.js scene with sunset gradient feel
    scene = new THREE.Scene();
    scene.background = new THREE.Color(0x1a0830);
    scene.fog = new THREE.Fog(0x1a0830, 50, 200);
    // Camera
    camera = new THREE.PerspectiveCamera(types_1.CONFIG.FOV_BASE, window.innerWidth / window.innerHeight, 0.1, 500);
    cameraTargetPos = new THREE.Vector3(0, types_1.CONFIG.CAMERA_HEIGHT, types_1.CONFIG.CAMERA_DISTANCE);
    cameraCurrentOffset = new THREE.Vector3();
    // Renderer
    renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById('game-canvas'),
        antialias: true,
    });
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.setClearColor(0x1a0a2e);
    // Post-processing (bloom)
    postprocessing.initPostProcessing(renderer, scene, camera);
    // Lighting - Golden hour / cyber sunset palette
    const ambientLight = new THREE.AmbientLight(0x332244, 0.5);
    scene.add(ambientLight);
    const sunLight = new THREE.DirectionalLight(0xff8844, 1.0);
    sunLight.position.set(-20, 30, -50);
    scene.add(sunLight);
    // Secondary fill light from behind
    const fillLight = new THREE.DirectionalLight(0x6644aa, 0.3);
    fillLight.position.set(10, 10, 20);
    scene.add(fillLight);
    // Hemisphere for sky/ground color variation
    const hemiLight = new THREE.HemisphereLight(0xff8855, 0x332244, 0.2);
    scene.add(hemiLight);
    // Sun disc - glowing sphere in the distance
    const sunGeo = new THREE.SphereGeometry(15, 16, 16);
    const sunMat = new THREE.MeshBasicMaterial({ color: 0xff8844 });
    const sunMesh = new THREE.Mesh(sunGeo, sunMat);
    sunMesh.position.set(-30, 25, -300);
    scene.add(sunMesh);
    // Sun glow ring
    const sunGlowGeo = new THREE.SphereGeometry(22, 16, 16);
    const sunGlowMat = new THREE.MeshBasicMaterial({
        color: 0xff4422, transparent: true, opacity: 0.15
    });
    const sunGlowMesh = new THREE.Mesh(sunGlowGeo, sunGlowMat);
    sunGlowMesh.position.copy(sunMesh.position);
    scene.add(sunGlowMesh);
    // Distant stars / particles in the sky
    addSkyParticles(scene);
    // Horizon glow - a large flat plane at the horizon with gradient-like appearance
    const horizonGeo = new THREE.PlaneGeometry(400, 30);
    const horizonMat = new THREE.MeshBasicMaterial({
        color: 0xff6622, transparent: true, opacity: 0.15, side: THREE.DoubleSide
    });
    const horizonMesh = new THREE.Mesh(horizonGeo, horizonMat);
    horizonMesh.position.set(0, 8, -300);
    scene.add(horizonMesh);
    // Second layer of horizon glow (wider, more transparent)
    const horizon2Geo = new THREE.PlaneGeometry(500, 40);
    const horizon2Mat = new THREE.MeshBasicMaterial({
        color: 0xcc3366, transparent: true, opacity: 0.08, side: THREE.DoubleSide
    });
    const horizon2Mesh = new THREE.Mesh(horizon2Geo, horizon2Mat);
    horizon2Mesh.position.set(0, 10, -350);
    scene.add(horizon2Mesh);
    // Create player craft
    playerCraft = playerModule.createPlayerCraft();
    playerModule.setPlayerMesh(playerCraft);
    scene.add(playerCraft);
    // Initialize game systems
    playerState = (0, state_1.createPlayer)();
    gameState = (0, state_1.createGameState)();
    world.initWorld();
    particles.initParticles(scene);
    hud.initHUD();
    hud.showStartScreen();
    // Input handling
    setupInput();
    // Resize handler
    window.addEventListener('resize', onResize);
    // Register game callbacks for HUD buttons
    window.onStartGame = startGame;
    window.onRestartGame = restartGame;
    // Start render loop
    requestAnimationFrame(gameLoop);
}
function setupInput() {
    document.addEventListener('keydown', (e) => {
        switch (e.code) {
            case 'KeyW':
            case 'ArrowUp':
                state_1.input.up = true;
                break;
            case 'KeyS':
            case 'ArrowDown':
                state_1.input.down = true;
                break;
            case 'KeyA':
            case 'ArrowLeft':
                state_1.input.left = true;
                break;
            case 'KeyD':
            case 'ArrowRight':
                state_1.input.right = true;
                break;
            case 'Space':
                state_1.input.boost = true;
                e.preventDefault();
                break;
        }
    });
    document.addEventListener('keyup', (e) => {
        switch (e.code) {
            case 'KeyW':
            case 'ArrowUp':
                state_1.input.up = false;
                break;
            case 'KeyS':
            case 'ArrowDown':
                state_1.input.down = false;
                break;
            case 'KeyA':
            case 'ArrowLeft':
                state_1.input.left = false;
                break;
            case 'KeyD':
            case 'ArrowRight':
                state_1.input.right = false;
                break;
            case 'Space':
                state_1.input.boost = false;
                break;
        }
    });
}
// Sync chunk meshes with Three.js scene - add new, remove old
function syncChunkMeshes() {
    const currentKeys = world.getChunks();
    // Add new chunks to scene
    for (const [key] of currentKeys) {
        if (!activeChunkKeys.has(key)) {
            activeChunkKeys.add(key);
            const chunkData = currentKeys.get(key);
            for (const mesh of chunkData.meshes) {
                scene.add(mesh);
            }
            // Add orb meshes too
            for (const orb of chunkData.orbs) {
                if (!orb.collected && orb.mesh) {
                    scene.add(orb.mesh);
                }
            }
        }
    }
    // Remove old chunks from scene
    for (const key of activeChunkKeys) {
        if (!currentKeys.has(key)) {
            activeChunkKeys.delete(key);
            // Meshes are cleaned up by world.cleanupChunk
        }
    }
}
function startGame() {
    audio.initAudio();
    (0, state_1.resetGame)(playerState, gameState);
    particles.resetParticles();
    postprocessing.resetCameraShake();
    // Add initial chunk meshes to scene
    activeChunkKeys.clear();
    for (const [key] of world.getChunks()) {
        activeChunkKeys.add(key);
        const chunkData = world.getChunks().get(key);
        for (const mesh of chunkData.meshes) {
            scene.add(mesh);
        }
        for (const orb of chunkData.orbs) {
            if (!orb.collected && orb.mesh) {
                scene.add(orb.mesh);
            }
        }
    }
    hud.showHUD();
}
function restartGame() {
    // Remove all existing meshes from scene
    for (const key of activeChunkKeys) {
        const chunkData = world.getChunks().get(key);
        if (chunkData) {
            for (const mesh of chunkData.meshes) {
                scene.remove(mesh);
            }
            for (const orb of chunkData.orbs) {
                if (orb.mesh)
                    scene.remove(orb.mesh);
            }
        }
    }
    // Clean up old world chunks
    for (const [, chunk] of world.getChunks()) {
        world.cleanupChunk(chunk);
    }
    (0, state_1.resetGame)(playerState, gameState);
    particles.resetParticles();
    postprocessing.resetCameraShake();
    activeChunkKeys.clear();
    world.initWorld();
    // Add new initial chunks to scene
    for (const [key] of world.getChunks()) {
        activeChunkKeys.add(key);
        const chunkData = world.getChunks().get(key);
        for (const mesh of chunkData.meshes) {
            scene.add(mesh);
        }
        for (const orb of chunkData.orbs) {
            if (!orb.collected && orb.mesh) {
                scene.add(orb.mesh);
            }
        }
    }
    hud.showHUD();
}
function gameLoop(timestamp) {
    const dt = Math.min((timestamp - lastTime) / 1000, 0.05); // Cap delta time
    lastTime = timestamp;
    frameCount++;
    if (gameState.running && !gameState.gameOver) {
        update(dt);
    }
    render();
    requestAnimationFrame(gameLoop);
}
function update(dt) {
    // Update player physics
    playerModule.updatePlayerPhysics(playerState, state_1.input, dt);
    // Handle boost/turbo
    handleBoost(dt);
    // Update world generation and sync meshes with scene
    world.updateWorld(playerState.position.z);
    syncChunkMeshes();
    // Collision detection & near-miss scoring
    checkCollisions();
    // Collect orbs
    collectOrbs();
    // Energy decay
    playerState.energy -= types_1.CONFIG.ENERGY_DECAY * dt * 60;
    if (playerState.energy <= 0) {
        playerState.energy = 0;
        triggerGameOver();
        return;
    }
    // Score accumulation
    gameState.score += types_1.CONFIG.BASE_SCORE_RATE * gameState.multiplier * dt;
    gameState.distance -= playerState.position.z;
    // Track max speed
    const displaySpeed = playerState.speed * 100;
    if (displaySpeed > gameState.maxSpeed) {
        gameState.maxSpeed = displaySpeed;
    }
    // Difficulty scaling
    gameState.difficulty = 1.0 + Math.floor(gameState.score / 500) * 0.1;
    // Multiplier decay
    if (frameCount % 3 === 0) {
        gameState.multiplier = Math.max(1.0, gameState.multiplier - types_1.CONFIG.MULTIPLIER_DECAY);
    }
    // Update particles
    particles.updateParticles(dt);
    // Emit trail particles
    trailTimer += dt;
    if (trailTimer > 0.02) {
        particles.emitTrail(playerState.position, playerState.speed);
        trailTimer = 0;
    }
    // Emit debris particles based on speed
    debrisTimer += dt;
    const debrisInterval = Math.max(0.03, 0.1 - playerState.speed * 0.02);
    if (debrisTimer > debrisInterval) {
        particles.emitDebris(playerState.position, playerState.speed);
        debrisTimer = 0;
    }
    // Emit speed lines at higher speeds for velocity feel
    if (playerState.speed > types_1.CONFIG.BASE_SPEED * 1.2) {
        const speedLineChance = (playerState.speed - types_1.CONFIG.BASE_SPEED) / (types_1.CONFIG.BOOST_SPEED - types_1.CONFIG.BASE_SPEED);
        if (Math.random() < speedLineChance * 0.5) {
            particles.emitSpeedLines(playerState.position, playerState.speed);
        }
    }
    // Update audio
    audio.updateEngineSound(playerState.speed, types_1.CONFIG.BOOST_SPEED);
    // Update HUD
    hud.updateHUD(playerState, gameState);
    // Update bloom based on speed/boost
    postprocessing.updateBloom(playerState.speed, playerState.isBoosting);
}
function handleBoost(dt) {
    if (state_1.input.boost && playerState.turbo >= types_1.CONFIG.TURBO_MAX && !playerState.isBoosting) {
        // Activate boost
        playerState.isBoosting = true;
        audio.playBoost();
        postprocessing.triggerCameraShake(0.3);
        // FOV widening effect
        camera.fov = THREE.MathUtils.lerp(camera.fov, types_1.CONFIG.FOV_BOOST, 0.1);
        camera.updateProjectionMatrix();
    }
    else if (playerState.isBoosting) {
        playerState.turbo -= types_1.CONFIG.TURBO_DRAIN_RATE * dt * 60;
        if (playerState.turbo <= 0) {
            playerState.turbo = 0;
            playerState.isBoosting = false;
            // Return FOV to normal
            camera.fov = THREE.MathUtils.lerp(camera.fov, types_1.CONFIG.FOV_BASE, 0.1);
            camera.updateProjectionMatrix();
        }
    }
    else {
        // Build turbo during normal play
        playerState.turbo += types_1.CONFIG.TURBO_BUILD_RATE * dt * 60;
        playerState.turbo = Math.min(types_1.CONFIG.TURBO_MAX, playerState.turbo);
        // Smooth FOV return
        camera.fov = THREE.MathUtils.lerp(camera.fov, types_1.CONFIG.FOV_BASE, 0.05);
        camera.updateProjectionMatrix();
    }
}
function checkCollisions() {
    const obstacles = world.getAllObstacles();
    const playerPos = playerState.position;
    const playerRadius = types_1.CONFIG.PLAYER_RADIUS;
    for (const obstacle of obstacles) {
        // Skip if too far away in Z
        const dz = Math.abs(obstacle.position.z - playerPos.z);
        if (dz > 20)
            continue;
        const dx = Math.abs(obstacle.position.x - playerPos.x);
        const dy = Math.abs(obstacle.position.y - playerPos.y);
        // Simple box-based collision check
        const distX = obstacle.radius + playerRadius;
        const distY = obstacle.radius * 0.8 + playerRadius;
        if (dx < distX && dy < distY) {
            // Collision!
            triggerGameOver();
            return;
        }
        // Near-miss detection
        const totalDist = Math.sqrt(dx * dx + dy * dy);
        const nearMissThreshold = types_1.CONFIG.NEAR_MISS_DISTANCE + obstacle.radius * 0.5;
        if (totalDist < nearMissThreshold && dz < 8) {
            const now = performance.now();
            if (now - lastNearMissTime > 300) { // Debounce near-misses
                gameState.multiplier += types_1.CONFIG.NEAR_MISS_MULTIPLIER_BOOST;
                lastNearMissTime = now;
                audio.playNearMiss();
                postprocessing.triggerCameraShake(0.15);
                particles.emitSparks(playerPos);
            }
        }
    }
}
function collectOrbs() {
    const orbs = world.getAllOrbs();
    const playerPos = playerState.position;
    for (const orb of orbs) {
        if (orb.collected)
            continue;
        const dx = orb.position.x - playerPos.x;
        const dy = orb.position.y - playerPos.y;
        const dz = orb.position.z - playerPos.z;
        const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
        if (dist < 3.0) {
            // Collect!
            orb.collected = true;
            if (orb.mesh) {
                scene.remove(orb.mesh);
                // Remove children too
                while (orb.mesh.children.length > 0) {
                    const child = orb.mesh.children[0];
                    orb.mesh.remove(child);
                }
            }
            playerState.energy = Math.min(types_1.CONFIG.ENERGY_MAX, playerState.energy + types_1.CONFIG.ENERGY_RECHARGE);
            audio.playCollect();
            // Bonus turbo on collect
            playerState.turbo = Math.min(types_1.CONFIG.TURBO_MAX, playerState.turbo + 10);
        }
    }
}
function triggerGameOver() {
    gameState.gameOver = true;
    gameState.running = false;
    audio.playCrash();
    postprocessing.triggerCameraShake(0.8);
    hud.showGameOver(gameState);
}
function render() {
    // Apply player transform to craft mesh
    playerModule.applyPlayerTransform(playerState, playerCraft);
    // Update engine glow
    playerModule.updateEngineGlow(playerState.speed, playerState.isBoosting);
    // Camera follow with smooth interpolation
    const targetCamPos = new THREE.Vector3(playerState.position.x * 0.5 + cameraTargetPos.x, playerState.position.y * 0.4 + cameraTargetPos.y, playerState.position.z + types_1.CONFIG.CAMERA_DISTANCE);
    // Add camera shake
    const shake = postprocessing.getCameraShake();
    targetCamPos.add(shake);
    camera.position.lerp(targetCamPos, 0.08);
    camera.lookAt(playerState.position.x * 0.3, playerState.position.y * 0.5 + 2, playerState.position.z - 30);
    // Animate orbs (rotation and pulsing)
    const time = performance.now() / 1000;
    for (const orb of world.getAllOrbs()) {
        if (!orb.collected && orb.mesh) {
            orb.mesh.rotation.y += 0.03;
            orb.mesh.rotation.x += 0.02;
            const pulse = 1 + Math.sin(time * 4) * 0.15;
            orb.mesh.scale.set(pulse, pulse, pulse);
            // Update glow child
            if (orb.mesh.children.length > 0) {
                const glow = orb.mesh.children[0];
                glow.rotation.y -= 0.02;
                const glowPulse = 1 + Math.sin(time * 3 + 1) * 0.2;
                glow.scale.set(glowPulse, glowPulse, glowPulse);
            }
        }
    }
    // Render particles
    particles.renderParticles();
    // Render scene directly (bloom achieved via emissive materials)
    renderer.render(scene, camera);
}
function onResize() {
    const w = window.innerWidth;
    const h = window.innerHeight;
    camera.aspect = w / h;
    camera.updateProjectionMatrix();
    renderer.setSize(w, h);
    postprocessing.resizePostProcessing(w, h);
}
// Start the game
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 });
exports.CONFIG = void 0;
// Game configuration constants
exports.CONFIG = {
    // Player physics
    BASE_SPEED: 0.8,
    MAX_SPEED: 2.5,
    BOOST_SPEED: 4.0,
    ACCELERATION: 0.015,
    DECELERATION: 0.008,
    TURN_RATE: 0.035,
    BANK_ANGLE: 0.6,
    PITCH_LIMIT: 0.7,
    // Energy system
    ENERGY_MAX: 100,
    ENERGY_DECAY: 0.04,
    ENERGY_RECHARGE: 25,
    // Turbo system
    TURBO_MAX: 100,
    TURBO_BUILD_RATE: 0.15,
    TURBO_DRAIN_RATE: 0.6,
    TURBO_DURATION: 3000,
    // Scoring
    NEAR_MISS_DISTANCE: 4.0,
    NEAR_MISS_MULTIPLIER_BOOST: 0.5,
    MULTIPLIER_DECAY: 0.01,
    BASE_SCORE_RATE: 10,
    // World generation
    CHUNK_LENGTH: 80,
    CHUNKS_AHEAD: 6,
    CHUNKS_BEHIND: 2,
    CANYON_WIDTH_BASE: 30,
    CANYON_HEIGHT_BASE: 40,
    // Camera
    CAMERA_DISTANCE: 12,
    CAMERA_HEIGHT: 5,
    FOV_BASE: 70,
    FOV_BOOST: 95,
    // Collision
    PLAYER_RADIUS: 1.2,
};
};

// ── module: src/state.ts ──
__mods["src/state.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.input = void 0;
exports.createPlayer = createPlayer;
exports.createGameState = createGameState;
exports.resetGame = resetGame;
const types_1 = require("./types");
exports.input = { up: false, down: false, left: false, right: false, boost: false };
function createPlayer() {
    return {
        position: new THREE.Vector3(0, 5, 0),
        velocity: new THREE.Vector3(0, 0, types_1.CONFIG.BASE_SPEED),
        rotation: new THREE.Euler(0, Math.PI, 0), // facing forward (negative Z)
        speed: types_1.CONFIG.BASE_SPEED,
        energy: types_1.CONFIG.ENERGY_MAX,
        turbo: 0,
        isBoosting: false,
    };
}
function createGameState() {
    return {
        score: 0,
        multiplier: 1.0,
        maxSpeed: 0,
        distance: 0,
        difficulty: 1.0,
        running: false,
        gameOver: false,
    };
}
function resetGame(player, state) {
    player.position.set(0, 5, 0);
    player.velocity.set(0, 0, types_1.CONFIG.BASE_SPEED);
    player.rotation.set(0, Math.PI, 0);
    player.speed = types_1.CONFIG.BASE_SPEED;
    player.energy = types_1.CONFIG.ENERGY_MAX;
    player.turbo = 0;
    player.isBoosting = false;
    state.score = 0;
    state.multiplier = 1.0;
    state.maxSpeed = 0;
    state.distance = 0;
    state.difficulty = 1.0;
    state.running = true;
    state.gameOver = false;
}
};

// ── module: src/audio.ts ──
__mods["src/audio.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initAudio = initAudio;
exports.updateEngineSound = updateEngineSound;
exports.playCollect = playCollect;
exports.playNearMiss = playNearMiss;
exports.playBoost = playBoost;
exports.playCrash = playCrash;
exports.stopEngine = stopEngine;
// Procedural audio system using Web Audio API
let audioCtx = null;
let engineOsc = null;
let engineGain = null;
let masterGain = null;
function initAudio() {
    if (audioCtx)
        return;
    audioCtx = new AudioContext();
    masterGain = audioCtx.createGain();
    masterGain.gain.value = 0.3;
    masterGain.connect(audioCtx.destination);
    // Engine hum - low frequency oscillator
    engineOsc = audioCtx.createOscillator();
    engineGain = audioCtx.createGain();
    engineOsc.type = 'sawtooth';
    engineOsc.frequency.value = 60;
    engineGain.gain.value = 0.08;
    // Low-pass filter for engine sound
    const filter = audioCtx.createBiquadFilter();
    filter.type = 'lowpass';
    filter.frequency.value = 200;
    filter.Q.value = 5;
    engineOsc.connect(filter);
    filter.connect(engineGain);
    engineGain.connect(masterGain);
    engineOsc.start();
}
function updateEngineSound(speed, maxSpeed) {
    if (!engineOsc || !engineGain)
        return;
    const ratio = speed / maxSpeed;
    engineOsc.frequency.value = 50 + ratio * 120;
    engineGain.gain.value = 0.04 + ratio * 0.1;
}
function playCollect() {
    if (!audioCtx || !masterGain)
        return;
    const osc = audioCtx.createOscillator();
    const gain = audioCtx.createGain();
    osc.type = 'sine';
    osc.frequency.setValueAtTime(800, audioCtx.currentTime);
    osc.frequency.exponentialRampToValueAtTime(1200, audioCtx.currentTime + 0.1);
    gain.gain.setValueAtTime(0.15, audioCtx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.2);
    osc.connect(gain);
    gain.connect(masterGain);
    osc.start();
    osc.stop(audioCtx.currentTime + 0.25);
}
function playNearMiss() {
    if (!audioCtx || !masterGain)
        return;
    const osc = audioCtx.createOscillator();
    const gain = audioCtx.createGain();
    osc.type = 'triangle';
    osc.frequency.setValueAtTime(300, audioCtx.currentTime);
    osc.frequency.exponentialRampToValueAtTime(600, audioCtx.currentTime + 0.15);
    gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.3);
    osc.connect(gain);
    gain.connect(masterGain);
    osc.start();
    osc.stop(audioCtx.currentTime + 0.35);
    // Whoosh noise
    const bufferSize = audioCtx.sampleRate * 0.2;
    const buffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate);
    const data = buffer.getChannelData(0);
    for (let i = 0; i < bufferSize; i++) {
        data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (bufferSize * 0.3));
    }
    const noise = audioCtx.createBufferSource();
    noise.buffer = buffer;
    const noiseGain = audioCtx.createGain();
    noiseGain.gain.setValueAtTime(0.1, audioCtx.currentTime);
    noiseGain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.2);
    const filter = audioCtx.createBiquadFilter();
    filter.type = 'bandpass';
    filter.frequency.value = 800;
    filter.Q.value = 2;
    noise.connect(filter);
    filter.connect(noiseGain);
    noiseGain.connect(masterGain);
    noise.start();
}
function playBoost() {
    if (!audioCtx || !masterGain)
        return;
    const osc = audioCtx.createOscillator();
    const gain = audioCtx.createGain();
    osc.type = 'sawtooth';
    osc.frequency.setValueAtTime(100, audioCtx.currentTime);
    osc.frequency.exponentialRampToValueAtTime(400, audioCtx.currentTime + 0.3);
    gain.gain.setValueAtTime(0.12, audioCtx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.5);
    osc.connect(gain);
    gain.connect(masterGain);
    osc.start();
    osc.stop(audioCtx.currentTime + 0.55);
}
function playCrash() {
    if (!audioCtx || !masterGain)
        return;
    // Noise burst for crash
    const bufferSize = audioCtx.sampleRate * 0.5;
    const buffer = audioCtx.createBuffer(1, bufferSize, audioCtx.sampleRate);
    const data = buffer.getChannelData(0);
    for (let i = 0; i < bufferSize; i++) {
        data[i] = (Math.random() * 2 - 1) * Math.exp(-i / (bufferSize * 0.4));
    }
    const noise = audioCtx.createBufferSource();
    noise.buffer = buffer;
    const gain = audioCtx.createGain();
    gain.gain.setValueAtTime(0.3, audioCtx.currentTime);
    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.5);
    noise.connect(gain);
    gain.connect(masterGain);
    noise.start();
    // Low thud
    const osc = audioCtx.createOscillator();
    const oscGain = audioCtx.createGain();
    osc.type = 'sine';
    osc.frequency.setValueAtTime(80, audioCtx.currentTime);
    osc.frequency.exponentialRampToValueAtTime(20, audioCtx.currentTime + 0.3);
    oscGain.gain.setValueAtTime(0.3, audioCtx.currentTime);
    oscGain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.4);
    osc.connect(oscGain);
    oscGain.connect(masterGain);
    osc.start();
    osc.stop(audioCtx.currentTime + 0.5);
}
function stopEngine() {
    if (engineOsc) {
        engineOsc.stop();
        engineOsc = null;
    }
}
};

// ── module: src/player.ts ──
__mods["src/player.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createPlayerCraft = createPlayerCraft;
exports.getPlayerMesh = getPlayerMesh;
exports.setPlayerMesh = setPlayerMesh;
exports.updateEngineGlow = updateEngineGlow;
exports.updatePlayerPhysics = updatePlayerPhysics;
exports.applyPlayerTransform = applyPlayerTransform;
const types_1 = require("./types");
let mesh = null;
let engineGlowMesh = null;
let engineCoreMesh = null;
function createPlayerCraft() {
    const group = new THREE.Group();
    // Main body - sleek arrow/dart shape
    const bodyGeo = new THREE.ConeGeometry(0.5, 3.2, 6);
    bodyGeo.rotateX(Math.PI / 2);
    const bodyMat = new THREE.MeshPhongMaterial({
        color: 0xccccdd, flatShading: true, shininess: 100,
        emissive: 0x111133, emissiveIntensity: 0.2
    });
    const body = new THREE.Mesh(bodyGeo, bodyMat);
    group.add(body);
    // Nose cone accent
    const noseGeo = new THREE.ConeGeometry(0.25, 1.0, 6);
    noseGeo.rotateX(Math.PI / 2);
    const noseMat = new THREE.MeshPhongMaterial({
        color: 0xffaa44, flatShading: true, emissive: 0xff6622, emissiveIntensity: 0.5
    });
    const nose = new THREE.Mesh(noseGeo, noseMat);
    nose.position.z = -1.8;
    group.add(nose);
    // Wings - swept back triangles using custom geometry
    const wingShape = createWingGeometry();
    const wingMat = new THREE.MeshPhongMaterial({
        color: 0x445566, flatShading: true, side: THREE.DoubleSide,
        emissive: 0x112233, emissiveIntensity: 0.3
    });
    const leftWing = new THREE.Mesh(wingShape, wingMat);
    leftWing.position.set(-1.4, -0.2, 0.5);
    leftWing.rotation.z = 0.15;
    group.add(leftWing);
    const rightWing = new THREE.Mesh(wingShape.clone(), wingMat);
    rightWing.position.set(1.4, -0.2, 0.5);
    rightWing.rotation.z = -0.15;
    group.add(rightWing);
    // Wing tips with accent color
    const tipGeo = new THREE.BoxGeometry(0.3, 0.1, 0.8);
    const tipMat = new THREE.MeshPhongMaterial({
        color: 0xff4422, flatShading: true, emissive: 0xff2200, emissiveIntensity: 0.5
    });
    const leftTip = new THREE.Mesh(tipGeo, tipMat);
    leftTip.position.set(-2.3, -0.3, 1.0);
    group.add(leftTip);
    const rightTip = new THREE.Mesh(tipGeo.clone(), tipMat);
    rightTip.position.set(2.3, -0.3, 1.0);
    group.add(rightTip);
    // Engine glow - outer shell
    const engineGeo = new THREE.ConeGeometry(0.4, 1.5, 6);
    engineGeo.rotateX(-Math.PI / 2);
    const engineMat = new THREE.MeshBasicMaterial({
        color: 0xff4422, transparent: true, opacity: 0.7
    });
    engineGlowMesh = new THREE.Mesh(engineGeo, engineMat);
    engineGlowMesh.position.z = 1.8;
    group.add(engineGlowMesh);
    // Engine core - bright white center
    const coreGeo = new THREE.ConeGeometry(0.2, 0.8, 6);
    coreGeo.rotateX(-Math.PI / 2);
    const coreMat = new THREE.MeshBasicMaterial({
        color: 0xffffff, transparent: true, opacity: 0.9
    });
    engineCoreMesh = new THREE.Mesh(coreGeo, coreMat);
    engineCoreMesh.position.z = 1.6;
    group.add(engineCoreMesh);
    // Cockpit - small diamond shape on top
    const cockpitGeo = new THREE.OctahedronGeometry(0.25, 0);
    const cockpitMat = new THREE.MeshPhongMaterial({
        color: 0xffaa44, flatShading: true, emissive: 0xff6622, emissiveIntensity: 0.8
    });
    const cockpit = new THREE.Mesh(cockpitGeo, cockpitMat);
    cockpit.position.set(0, 0.35, -0.6);
    group.add(cockpit);
    return group;
}
function createWingGeometry() {
    // Create a swept wing shape using PlaneGeometry with modified vertices
    const geo = new THREE.PlaneGeometry(2.8, 1.4);
    const pos = geo.attributes.position.array;
    // Sweep back the outer edges for aerodynamic look
    // Vertices are: bottom-left, top-left, bottom-right, top-right
    pos[0] = -1.3;
    pos[1] = 0;
    pos[2] = 0.6; // bottom-left swept back
    pos[3] = -1.3;
    pos[4] = 0;
    pos[5] = 0.6; // top-left swept back
    return geo;
}
function getPlayerMesh() {
    return mesh;
}
function setPlayerMesh(m) {
    mesh = m;
}
function updateEngineGlow(speed, boosting) {
    if (!engineGlowMesh || !engineCoreMesh)
        return;
    const ratio = speed / types_1.CONFIG.BOOST_SPEED;
    // Scale engine based on speed
    const scaleX = 1 + ratio * 0.3;
    const scaleY = 1 + ratio * 2.5;
    engineGlowMesh.scale.set(scaleX, scaleY, 1);
    engineCoreMesh.scale.set(scaleX * 0.8, scaleY * 0.7, 1);
    if (boosting) {
        // Blue-white boost flame
        engineGlowMesh.material.color.setHex(0x44ccff);
        engineGlowMesh.material.opacity = 0.9;
        engineCoreMesh.material.color.setHex(0xaaddff);
        engineGlowMesh.scale.y *= 1.5;
    }
    else {
        // Orange-red normal flame, shifts with speed
        const r = Math.floor(255 * ratio + 180 * (1 - ratio));
        const g = Math.floor(68 * ratio + 34 * (1 - ratio));
        const b = Math.floor(34);
        engineGlowMesh.material.color.setHex((r << 16) | (g << 8) | b);
        engineGlowMesh.material.opacity = 0.5 + ratio * 0.4;
        engineCoreMesh.material.color.setHex(0xffddaa);
    }
    // Flicker effect
    const flicker = 1 + Math.sin(performance.now() * 0.02) * 0.1 * ratio;
    engineGlowMesh.scale.y *= flicker;
}
function updatePlayerPhysics(player, inputState, dt) {
    // Speed management
    const targetSpeed = player.isBoosting ? types_1.CONFIG.BOOST_SPEED : types_1.CONFIG.MAX_SPEED;
    if (player.speed < targetSpeed) {
        player.speed += types_1.CONFIG.ACCELERATION * dt * 60;
    }
    else if (!player.isBoosting && player.speed > types_1.CONFIG.BASE_SPEED) {
        player.speed -= types_1.CONFIG.DECELERATION * dt * 30;
    }
    // Clamp speed
    player.speed = Math.max(types_1.CONFIG.BASE_SPEED, Math.min(player.speed, types_1.CONFIG.BOOST_SPEED));
    const moveSpeed = player.speed * dt * 60;
    // Lateral movement with momentum feel
    if (inputState.left) {
        player.velocity.x -= types_1.CONFIG.TURN_RATE * dt * 60;
    }
    else if (inputState.right) {
        player.velocity.x += types_1.CONFIG.TURN_RATE * dt * 60;
    }
    // Vertical movement with momentum feel
    if (inputState.up) {
        player.velocity.y += types_1.CONFIG.TURN_RATE * dt * 45;
    }
    else if (inputState.down) {
        player.velocity.y -= types_1.CONFIG.TURN_RATE * dt * 45;
    }
    // Dampen lateral/vertical velocity for weighty feel
    const dampFactor = Math.pow(0.92, dt * 60);
    player.velocity.x *= dampFactor;
    player.velocity.y *= dampFactor;
    // Apply movement
    player.position.x += player.velocity.x * moveSpeed * 0.15;
    player.position.y += player.velocity.y * moveSpeed * 0.12;
    player.position.z -= moveSpeed;
    // Clamp position to reasonable bounds
    player.position.x = Math.max(-35, Math.min(35, player.position.x));
    player.position.y = Math.max(2, Math.min(45, player.position.y));
    // Banking (roll) based on lateral input/velocity
    const targetRoll = -player.velocity.x * types_1.CONFIG.BANK_ANGLE;
    const currentRoll = player.rotation.z;
    player.rotation.z += (targetRoll - currentRoll) * 0.1 * dt * 60;
    // Pitch based on vertical velocity
    const targetPitch = -player.velocity.y * 0.3;
    const clampedPitch = Math.max(-types_1.CONFIG.PITCH_LIMIT, Math.min(types_1.CONFIG.PITCH_LIMIT, targetPitch));
    player.rotation.x += (clampedPitch - player.rotation.x) * 0.1 * dt * 60;
    // Yaw stays at PI (facing forward in negative Z)
    player.rotation.y = Math.PI;
}
function applyPlayerTransform(player, group) {
    group.position.copy(player.position);
    group.rotation.copy(player.rotation);
}
};

// ── module: src/world.ts ──
__mods["src/world.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initWorld = initWorld;
exports.getChunks = getChunks;
exports.updateWorld = updateWorld;
exports.cleanupChunk = cleanupChunk;
exports.getObstaclesInRange = getObstaclesInRange;
exports.getOrbsInRange = getOrbsInRange;
exports.getAllMeshes = getAllMeshes;
exports.getAllObstacles = getAllObstacles;
exports.getAllOrbs = getAllOrbs;
const types_1 = require("./types");
const chunks = new Map();
let nextChunkZ;
// Seeded random for reproducible generation
function seededRandom(seed) {
    let s = seed;
    return () => {
        s = (s * 16807 + 0) % 2147483647;
        return (s - 1) / 2147483646;
    };
}
// Color palette for canyon walls - golden hour / cyber sunset
const WALL_COLORS = [
    0x994422, // deep orange-red
    0xaa5533, // warm terracotta  
    0x884466, // purple-brown
    0x773355, // dark plum
    0x6644aa, // violet
    0xbb6644, // burnt orange
    0x995577, // mauve
];
function initWorld() {
    nextChunkZ = types_1.CONFIG.CHUNK_LENGTH * types_1.CONFIG.CHUNKS_AHEAD;
    for (let i = 0; i < types_1.CONFIG.CHUNKS_AHEAD + types_1.CONFIG.CHUNKS_BEHIND; i++) {
        generateChunk(-i * types_1.CONFIG.CHUNK_LENGTH);
    }
}
function getChunks() {
    return chunks;
}
function updateWorld(playerZ) {
    while (nextChunkZ > playerZ - types_1.CONFIG.CHUNK_LENGTH * types_1.CONFIG.CHUNKS_AHEAD) {
        generateChunk(nextChunkZ);
        nextChunkZ -= types_1.CONFIG.CHUNK_LENGTH;
    }
    const removeThreshold = playerZ + types_1.CONFIG.CHUNK_LENGTH * types_1.CONFIG.CHUNKS_BEHIND;
    for (const [key, chunk] of chunks) {
        if (chunk.zStart > -removeThreshold)
            continue;
        cleanupChunk(chunk);
        chunks.delete(key);
    }
}
function generateChunk(zPos) {
    const rng = seededRandom(Math.abs(zPos * 7919 + 104729));
    const chunkLength = types_1.CONFIG.CHUNK_LENGTH;
    const zStart = -zPos;
    const zEnd = zStart - chunkLength;
    const obstacles = [];
    const orbs = [];
    const meshes = [];
    const canyonWidth = types_1.CONFIG.CANYON_WIDTH_BASE * (1 + Math.sin(zStart * 0.02) * 0.3);
    const canyonHeight = types_1.CONFIG.CANYON_HEIGHT_BASE;
    // Ground plane for this chunk
    addGroundPlane(meshes, zStart, zEnd, canyonWidth, rng);
    // Canyon walls
    generateCanyonWalls(meshes, obstacles, zStart, zEnd, canyonWidth, canyonHeight, rng);
    // Floating monoliths
    const monolithCount = Math.floor(2 + rng() * 3);
    for (let i = 0; i < monolithCount; i++) {
        generateMonolith(meshes, obstacles, zStart, zEnd, canyonWidth, canyonHeight, rng);
    }
    // Tight squeezes
    if (rng() > 0.4) {
        generateSqueeze(meshes, obstacles, zStart, zEnd, canyonWidth, canyonHeight, rng);
    }
    // Energy orbs - place in interesting positions
    const orbCount = Math.floor(3 + rng() * 4);
    for (let i = 0; i < orbCount; i++) {
        generateOrb(orbs, zStart, zEnd, canyonWidth, canyonHeight, rng);
    }
    chunks.set(zPos, { zStart, zEnd, meshes, obstacles, orbs });
}
function addGroundPlane(meshes, zStart, zEnd, width, rng) {
    // Create a ground plane with grid-like appearance using multiple segments
    const segCount = Math.floor((zStart - zEnd) / 20);
    for (let i = 0; i < segCount; i++) {
        const segZ = zStart - (i / segCount) * (zStart - zEnd);
        // Main ground strip
        const geo = new THREE.PlaneGeometry(width + 20, 20);
        geo.rotateX(-Math.PI / 2);
        const mat = new THREE.MeshPhongMaterial({
            color: 0x2a1530, flatShading: true, shininess: 5
        });
        const mesh = new THREE.Mesh(geo, mat);
        mesh.position.set(0, -5, segZ);
        meshes.push(mesh);
        // Occasional raised platform/rock on ground
        if (rng() > 0.6) {
            const rockGeo = new THREE.BoxGeometry(2 + rng() * 4, 1 + rng() * 3, 2 + rng() * 4);
            const rockMat = new THREE.MeshPhongMaterial({
                color: WALL_COLORS[Math.floor(rng() * WALL_COLORS.length)], flatShading: true
            });
            const rock = new THREE.Mesh(rockGeo, rockMat);
            rock.position.set((rng() - 0.5) * width * 0.6, -3 + rng(), segZ);
            meshes.push(rock);
        }
    }
}
function generateCanyonWalls(meshes, obstacles, zStart, zEnd, width, height, rng) {
    const segmentCount = Math.floor((zStart - zEnd) / 12);
    for (let i = 0; i < segmentCount; i++) {
        const t = i / segmentCount;
        const segZ = zStart - t * (zStart - zEnd);
        // Varying wall positions for organic feel
        const leftOffset = Math.sin(zStart * 0.05 + i) * 3;
        const rightOffset = Math.cos(zStart * 0.07 + i) * 3;
        // Left wall - multiple stacked segments for jagged look
        const leftX = -(width / 2 + rng() * 6 + leftOffset);
        const leftH = height * (0.4 + rng() * 0.6);
        const leftW = 2 + rng() * 5;
        addWallSegment(meshes, obstacles, leftX, leftH, leftW, segZ, 'wall', rng);
        // Right wall
        const rightX = width / 2 + rng() * 6 + rightOffset;
        const rightH = height * (0.4 + rng() * 0.6);
        const rightW = 2 + rng() * 5;
        addWallSegment(meshes, obstacles, rightX, rightH, rightW, segZ, 'wall', rng);
        // Occasional wall overhangs
        if (rng() > 0.7) {
            const overhangSide = rng() > 0.5 ? -1 : 1;
            const ohX = overhangSide * (width / 2 + rng() * 3);
            addWallSegment(meshes, obstacles, ohX, height * 0.3, 4 + rng() * 3, segZ, 'wall', rng);
        }
    }
    // Ceiling segments (sparse)
    for (let i = 0; i < segmentCount / 2; i++) {
        const segZ = zStart - (i / (segmentCount / 2)) * (zStart - zEnd);
        if (rng() > 0.5)
            continue;
        const ceilW = width * (0.3 + rng() * 0.4);
        addCeilingSegment(meshes, obstacles, ceilW, height * 1.1, segZ);
    }
}
function addWallSegment(meshes, obstacles, x, h, w, z, type, rng) {
    const geo = new THREE.BoxGeometry(w, h, 14);
    // Pick color from palette with some variation
    let colorIdx;
    if (rng) {
        colorIdx = Math.floor(rng() * WALL_COLORS.length);
    }
    else {
        colorIdx = Math.floor(Math.random() * WALL_COLORS.length);
    }
    const baseColor = WALL_COLORS[colorIdx];
    // Add slight emissive glow for atmosphere
    const mat = new THREE.MeshPhongMaterial({
        color: baseColor, flatShading: true,
        emissive: 0x110822, emissiveIntensity: 0.2
    });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.set(x, h / 2 - 5, z);
    meshes.push(mesh);
    obstacles.push({
        position: new THREE.Vector3(x, h / 2 - 5, z),
        radius: Math.max(w, h) * 0.4,
        mesh,
        type: 'wall',
    });
}
function addCeilingSegment(meshes, obstacles, w, y, z) {
    const geo = new THREE.BoxGeometry(w, 4, 10);
    const mat = new THREE.MeshPhongMaterial({ color: 0x663355, flatShading: true });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.set((Math.random() - 0.5) * w * 0.3, y, z);
    meshes.push(mesh);
    obstacles.push({
        position: new THREE.Vector3(mesh.position.x, mesh.position.y, mesh.position.z),
        radius: Math.max(w, 4) * 0.35,
        mesh,
        type: 'wall',
    });
}
function generateMonolith(meshes, obstacles, zStart, zEnd, width, height, rng) {
    const x = (rng() - 0.5) * width * 0.7;
    const y = 3 + rng() * (height * 0.6);
    const z = zStart - rng() * (zStart - zEnd);
    const h = 4 + rng() * 8;
    const w = 1.5 + rng() * 2;
    let geo;
    if (rng() > 0.5) {
        geo = new THREE.BoxGeometry(w, h, w);
    }
    else {
        geo = new THREE.OctahedronGeometry(Math.max(w, h * 0.3), 0);
    }
    const mat = new THREE.MeshPhongMaterial({
        color: 0x8844aa, flatShading: true, emissive: 0x221133, emissiveIntensity: 0.5
    });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.set(x, y, z);
    meshes.push(mesh);
    obstacles.push({
        position: new THREE.Vector3(x, y, z),
        radius: Math.max(w, h) * 0.45,
        mesh,
        type: 'monolith',
    });
}
function generateSqueeze(meshes, obstacles, zStart, zEnd, width, height, rng) {
    const squeezeZ = zStart - (zStart - zEnd) * (0.3 + rng() * 0.4);
    const gapWidth = 6 + rng() * 4;
    const centerX = (rng() - 0.5) * width * 0.2;
    addWallSegment(meshes, obstacles, centerX - gapWidth / 2 - 1, height * 0.8, 3, squeezeZ, 'squeeze', rng);
    addWallSegment(meshes, obstacles, centerX + gapWidth / 2 + 1, height * 0.8, 3, squeezeZ, 'squeeze', rng);
    // Overhead bar for tight squeezes
    if (rng() > 0.5) {
        const geo = new THREE.BoxGeometry(gapWidth + 4, 2, 6);
        const mat = new THREE.MeshPhongMaterial({ color: 0x773355, flatShading: true });
        const mesh = new THREE.Mesh(geo, mat);
        mesh.position.set(centerX, height * 0.7, squeezeZ);
        meshes.push(mesh);
        obstacles.push({
            position: new THREE.Vector3(centerX, height * 0.7, squeezeZ),
            radius: (gapWidth + 4) * 0.5,
            mesh,
            type: 'squeeze',
        });
    }
}
function generateOrb(orbs, zStart, zEnd, width, height, rng) {
    const x = (rng() - 0.5) * width * 0.6;
    const y = 3 + rng() * (height * 0.5);
    const z = zStart - rng() * (zStart - zEnd);
    // Core orb - bright emissive for glow effect
    const geo = new THREE.IcosahedronGeometry(0.7, 1);
    const mat = new THREE.MeshBasicMaterial({
        color: 0xffcc44, transparent: true, opacity: 0.95
    });
    const mesh = new THREE.Mesh(geo, mat);
    mesh.position.set(x, y, z);
    // Outer glow shell - larger and more transparent
    const glowGeo = new THREE.IcosahedronGeometry(1.3, 1);
    const glowMat = new THREE.MeshBasicMaterial({
        color: 0xff6622, transparent: true, opacity: 0.25
    });
    const glowMesh = new THREE.Mesh(glowGeo, glowMat);
    mesh.add(glowMesh);
    // Inner bright core
    const coreGeo = new THREE.IcosahedronGeometry(0.3, 0);
    const coreMat = new THREE.MeshBasicMaterial({ color: 0xffffff });
    const coreMesh = new THREE.Mesh(coreGeo, coreMat);
    mesh.add(coreMesh);
    orbs.push({ position: new THREE.Vector3(x, y, z), collected: false, mesh });
}
function cleanupChunk(chunk) {
    // Remove meshes from scene handled by main loop
    chunk.meshes.length = 0;
    chunk.obstacles.length = 0;
    chunk.orbs.length = 0;
}
function getObstaclesInRange(playerZ, range) {
    const result = [];
    for (const [, chunk] of chunks) {
        if (chunk.zEnd > playerZ + range || chunk.zStart < playerZ - range)
            continue;
        result.push(...chunk.obstacles);
    }
    return result;
}
function getOrbsInRange(playerZ, range) {
    const result = [];
    for (const [, chunk] of chunks) {
        if (chunk.zEnd > playerZ + range || chunk.zStart < playerZ - range)
            continue;
        result.push(...chunk.orbs);
    }
    return result;
}
function getAllMeshes() {
    const all = [];
    for (const [, chunk] of chunks) {
        all.push(...chunk.meshes);
    }
    for (const [, chunk] of chunks) {
        for (const orb of chunk.orbs) {
            if (!orb.collected && orb.mesh) {
                all.push(orb.mesh);
            }
        }
    }
    return all;
}
function getAllObstacles() {
    const all = [];
    for (const [, chunk] of chunks) {
        all.push(...chunk.obstacles);
    }
    return all;
}
function getAllOrbs() {
    const all = [];
    for (const [, chunk] of chunks) {
        all.push(...chunk.orbs);
    }
    return all;
}
};

// ── module: src/particles.ts ──
__mods["src/particles.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initParticles = initParticles;
exports.emitTrail = emitTrail;
exports.emitDebris = emitDebris;
exports.emitSparks = emitSparks;
exports.emitSpeedLines = emitSpeedLines;
exports.updateParticles = updateParticles;
exports.renderParticles = renderParticles;
exports.resetParticles = resetParticles;
let trailParticles = [];
let debrisParticles = [];
let sparkParticles = [];
let speedLineParticles = [];
const MAX_TRAIL_PARTICLES = 150;
const MAX_DEBRIS_PARTICLES = 120;
const MAX_SPARKS = 80;
const MAX_SPEED_LINES = 60;
// Particle meshes (reused)
let trailMeshes = [];
let debrisMeshes = [];
let sparkMeshes = [];
let speedLineMeshes = [];
function initParticles(scene) {
    // Trail particles (engine exhaust)
    const trailGeo = new THREE.BoxGeometry(0.12, 0.12, 0.12);
    for (let i = 0; i < MAX_TRAIL_PARTICLES; i++) {
        const mat = new THREE.MeshBasicMaterial({ color: 0xff4422, transparent: true });
        const mesh = new THREE.Mesh(trailGeo.clone(), mat);
        mesh.visible = false;
        scene.add(mesh);
        trailMeshes.push(mesh);
    }
    // Debris particles (small rocks flying past)
    const debrisGeo = new THREE.BoxGeometry(0.1, 0.1, 0.3);
    for (let i = 0; i < MAX_DEBRIS_PARTICLES; i++) {
        const mat = new THREE.MeshBasicMaterial({ color: 0x886644, transparent: true });
        const mesh = new THREE.Mesh(debrisGeo.clone(), mat);
        mesh.visible = false;
        scene.add(mesh);
        debrisMeshes.push(mesh);
    }
    // Spark particles (near-miss sparks)
    const sparkGeo = new THREE.BoxGeometry(0.2, 0.2, 0.2);
    for (let i = 0; i < MAX_SPARKS; i++) {
        const mat = new THREE.MeshBasicMaterial({ color: 0xffaa44, transparent: true });
        const mesh = new THREE.Mesh(sparkGeo.clone(), mat);
        mesh.visible = false;
        scene.add(mesh);
        sparkMeshes.push(mesh);
    }
    // Speed lines (streaks emphasizing velocity)
    const speedLineGeo = new THREE.BoxGeometry(0.05, 0.05, 3);
    for (let i = 0; i < MAX_SPEED_LINES; i++) {
        const mat = new THREE.MeshBasicMaterial({ color: 0xffccaa, transparent: true });
        const mesh = new THREE.Mesh(speedLineGeo.clone(), mat);
        mesh.visible = false;
        scene.add(mesh);
        speedLineMeshes.push(mesh);
    }
}
function emitTrail(position, speed) {
    if (trailParticles.length >= MAX_TRAIL_PARTICLES)
        return;
    trailParticles.push({
        position: new THREE.Vector3(position.x + (Math.random() - 0.5) * 0.4, position.y + (Math.random() - 0.5) * 0.4, position.z + 1.8),
        velocity: new THREE.Vector3((Math.random() - 0.5) * 0.03, (Math.random() - 0.5) * 0.03, speed * 0.4),
        life: 1.0,
        maxLife: 0.5 + Math.random() * 0.4,
        size: 0.12 + Math.random() * 0.12,
    });
}
function emitDebris(playerPos, speed) {
    if (debrisParticles.length >= MAX_DEBRIS_PARTICLES)
        return;
    debrisParticles.push({
        position: new THREE.Vector3(playerPos.x + (Math.random() - 0.5) * 25, playerPos.y + (Math.random() - 0.5) * 18, playerPos.z - speed * 40 - Math.random() * 25),
        velocity: new THREE.Vector3((Math.random() - 0.5) * 0.15, (Math.random() - 0.5) * 0.15, speed * 2.5 + Math.random() * speed),
        life: 1.0,
        maxLife: 0.3 + Math.random() * 0.4,
        size: 0.06 + Math.random() * 0.12,
        color: Math.random() > 0.5 ? 0x775544 : 0x998877,
    });
}
function emitSparks(position) {
    if (sparkParticles.length >= MAX_SPARKS)
        return;
    for (let i = 0; i < 6; i++) {
        sparkParticles.push({
            position: new THREE.Vector3(position.x + (Math.random() - 0.5) * 2, position.y + (Math.random() - 0.5) * 2, position.z + (Math.random() - 0.5) * 2),
            velocity: new THREE.Vector3((Math.random() - 0.5) * 0.4, (Math.random() - 0.5) * 0.4, (Math.random() - 0.5) * 0.4),
            life: 1.0,
            maxLife: 0.2 + Math.random() * 0.3,
            size: 0.08 + Math.random() * 0.15,
            color: 0xffaa44,
        });
    }
}
function emitSpeedLines(playerPos, speed) {
    if (speedLineParticles.length >= MAX_SPEED_LINES)
        return;
    // Speed lines appear at the edges of vision, flying past quickly
    const angle = Math.random() * Math.PI * 2;
    const radius = 8 + Math.random() * 15;
    speedLineParticles.push({
        position: new THREE.Vector3(playerPos.x + Math.cos(angle) * radius, playerPos.y + (Math.random() - 0.5) * 20, playerPos.z - speed * 30 - Math.random() * 15),
        velocity: new THREE.Vector3(Math.cos(angle) * 0.1, (Math.random() - 0.5) * 0.1, speed * 4 + Math.random() * speed * 2),
        life: 1.0,
        maxLife: 0.15 + Math.random() * 0.2,
        size: 0.03 + Math.random() * 0.05,
        color: 0xffccaa,
    });
}
function updateParticles(dt) {
    // Update all particle arrays
    const updateArray = (arr) => {
        for (let i = arr.length - 1; i >= 0; i--) {
            const p = arr[i];
            p.life -= dt / p.maxLife;
            if (p.life <= 0) {
                arr.splice(i, 1);
                continue;
            }
            p.position.x += p.velocity.x * dt * 60;
            p.position.y += p.velocity.y * dt * 60;
            p.position.z += p.velocity.z * dt * 60;
        }
    };
    updateArray(trailParticles);
    updateArray(debrisParticles);
    updateArray(sparkParticles);
    updateArray(speedLineParticles);
}
function renderParticles() {
    // Render trail particles
    for (let i = 0; i < MAX_TRAIL_PARTICLES; i++) {
        const mesh = trailMeshes[i];
        if (i < trailParticles.length) {
            const p = trailParticles[i];
            mesh.visible = true;
            mesh.position.copy(p.position);
            const s = p.size * p.life;
            mesh.scale.set(s, s, s);
            mesh.material.opacity = p.life * 0.5;
        }
        else {
            mesh.visible = false;
        }
    }
    // Render debris particles
    for (let i = 0; i < MAX_DEBRIS_PARTICLES; i++) {
        const mesh = debrisMeshes[i];
        if (i < debrisParticles.length) {
            const p = debrisParticles[i];
            mesh.visible = true;
            mesh.position.copy(p.position);
            const s = p.size * p.life;
            mesh.scale.set(s, s, s * 2);
            mesh.material.opacity = p.life * 0.35;
        }
        else {
            mesh.visible = false;
        }
    }
    // Render spark particles
    for (let i = 0; i < MAX_SPARKS; i++) {
        const mesh = sparkMeshes[i];
        if (i < sparkParticles.length) {
            const p = sparkParticles[i];
            mesh.visible = true;
            mesh.position.copy(p.position);
            const s = p.size * p.life;
            mesh.scale.set(s, s, s);
            mesh.material.opacity = p.life * 0.7;
        }
        else {
            mesh.visible = false;
        }
    }
    // Render speed lines
    for (let i = 0; i < MAX_SPEED_LINES; i++) {
        const mesh = speedLineMeshes[i];
        if (i < speedLineParticles.length) {
            const p = speedLineParticles[i];
            mesh.visible = true;
            mesh.position.copy(p.position);
            // Orient the line along its velocity direction
            const velLen = Math.sqrt(p.velocity.x * p.velocity.x +
                p.velocity.y * p.velocity.y +
                p.velocity.z * p.velocity.z);
            if (velLen > 0) {
                mesh.lookAt(p.position.x + p.velocity.x, p.position.y + p.velocity.y, p.position.z + p.velocity.z);
            }
            const s = p.size * p.life;
            mesh.scale.set(s, s, 1);
            mesh.material.opacity = p.life * 0.3;
        }
        else {
            mesh.visible = false;
        }
    }
}
function resetParticles() {
    trailParticles.length = 0;
    debrisParticles.length = 0;
    sparkParticles.length = 0;
    speedLineParticles.length = 0;
}
};

// ── module: src/hud.ts ──
__mods["src/hud.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initHUD = initHUD;
exports.showHUD = showHUD;
exports.hideHUD = hideHUD;
exports.showStartScreen = showStartScreen;
exports.showGameOver = showGameOver;
exports.updateHUD = updateHUD;
const types_1 = require("./types");
let scoreEl;
let multiplierEl;
let speedBarEl;
let energyBarEl;
let turboBarEl;
let hudContainer;
let startScreen;
let gameOverScreen;
function initHUD() {
    scoreEl = document.getElementById('score-display');
    multiplierEl = document.getElementById('multiplier-display');
    speedBarEl = document.getElementById('speed-bar');
    energyBarEl = document.getElementById('energy-bar');
    turboBarEl = document.getElementById('turbo-bar');
    hudContainer = document.getElementById('hud');
    startScreen = document.getElementById('start-screen');
    gameOverScreen = document.getElementById('game-over-screen');
    // Start button handler
    const startBtn = document.getElementById('start-btn');
    if (startBtn) {
        startBtn.addEventListener('click', () => {
            if (typeof window !== 'undefined' && window.onStartGame) {
                window.onStartGame();
            }
        });
    }
    // Restart button handler
    const restartBtn = document.getElementById('restart-btn');
    if (restartBtn) {
        restartBtn.addEventListener('click', () => {
            if (typeof window !== 'undefined' && window.onRestartGame) {
                window.onRestartGame();
            }
        });
    }
}
function showHUD() {
    if (hudContainer)
        hudContainer.classList.remove('hidden');
    if (startScreen)
        startScreen.classList.add('hidden');
    if (gameOverScreen)
        gameOverScreen.classList.add('hidden');
}
function hideHUD() {
    if (hudContainer)
        hudContainer.classList.add('hidden');
}
function showStartScreen() {
    if (startScreen)
        startScreen.classList.remove('hidden');
    if (gameOverScreen)
        gameOverScreen.classList.add('hidden');
    if (hudContainer)
        hudContainer.classList.add('hidden');
}
function showGameOver(state) {
    if (gameOverScreen)
        gameOverScreen.classList.remove('hidden');
    if (hudContainer)
        hudContainer.classList.add('hidden');
    const finalScore = document.getElementById('final-score');
    const maxSpeedEl = document.getElementById('max-speed');
    const distanceEl = document.getElementById('distance');
    if (finalScore)
        finalScore.textContent = Math.floor(state.score).toLocaleString();
    if (maxSpeedEl)
        maxSpeedEl.textContent = Math.floor(state.maxSpeed * 100) + ' km/h';
    if (distanceEl)
        distanceEl.textContent = Math.floor(state.distance / 100) + ' km';
}
function updateHUD(player, state) {
    // Score
    if (scoreEl)
        scoreEl.textContent = Math.floor(state.score).toLocaleString();
    // Multiplier - pulse effect on near miss
    if (multiplierEl) {
        multiplierEl.textContent = 'x' + state.multiplier.toFixed(1);
        if (state.multiplier > 2.0) {
            multiplierEl.classList.add('near-miss-pulse');
            setTimeout(() => multiplierEl?.classList.remove('near-miss-pulse'), 200);
        }
    }
    // Speed bar
    if (speedBarEl) {
        const speedRatio = Math.min(1, player.speed / types_1.CONFIG.BOOST_SPEED);
        speedBarEl.style.height = (speedRatio * 100) + '%';
    }
    // Energy bar
    if (energyBarEl) {
        const energyRatio = Math.max(0, player.energy / types_1.CONFIG.ENERGY_MAX);
        energyBarEl.style.width = (energyRatio * 100) + '%';
        // Color change when low
        if (energyRatio < 0.25) {
            energyBarEl.style.background = 'linear-gradient(90deg, #ff0044, #ff2266)';
            energyBarEl.style.animation = 'energyWarning 0.5s infinite';
        }
        else {
            energyBarEl.style.background = 'linear-gradient(90deg, #ff2266, #ffaa44)';
            energyBarEl.style.animation = '';
        }
    }
    // Turbo bar
    if (turboBarEl) {
        const turboRatio = Math.max(0, player.turbo / types_1.CONFIG.TURBO_MAX);
        turboBarEl.style.width = (turboRatio * 100) + '%';
        // Glow when full
        if (turboRatio >= 1.0) {
            turboBarEl.style.animation = 'turboReady 0.8s infinite';
        }
        else {
            turboBarEl.style.animation = '';
        }
    }
}
};

// ── module: src/postprocessing.ts ──
__mods["src/postprocessing.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.initPostProcessing = initPostProcessing;
exports.renderWithEffects = renderWithEffects;
exports.updateBloom = updateBloom;
exports.triggerCameraShake = triggerCameraShake;
exports.getCameraShake = getCameraShake;
exports.resetCameraShake = resetCameraShake;
exports.getComposer = getComposer;
exports.resizePostProcessing = resizePostProcessing;
const types_1 = require("./types");
let cameraShakeAmount = 0;
const cameraShakeDecay = 0.9;
// Simple glow sprites for bloom-like effect on orbs and engine
let glowSprites = [];
function initPostProcessing(_renderer, _scene, _camera) {
    // Post-processing via CDN doesn't chain properly.
    // We'll use emissive materials for glow instead.
}
function renderWithEffects() {
    // No-op - rendering handled in main loop
}
function updateBloom(speed, _boosting) {
    // Adjust glow sprite intensity based on speed
    const intensity = 0.5 + (speed / types_1.CONFIG.BOOST_SPEED) * 0.5;
    for (const sprite of glowSprites) {
        if (sprite.material.opacity !== undefined) {
            sprite.material.opacity = Math.min(1, intensity);
        }
    }
}
function triggerCameraShake(amount) {
    cameraShakeAmount = Math.min(cameraShakeAmount + amount, 1.0);
}
function getCameraShake() {
    if (cameraShakeAmount < 0.01)
        return new THREE.Vector3(0, 0, 0);
    const shake = new THREE.Vector3((Math.random() - 0.5) * cameraShakeAmount * 2, (Math.random() - 0.5) * cameraShakeAmount * 1.5, (Math.random() - 0.5) * cameraShakeAmount * 0.5);
    cameraShakeAmount *= cameraShakeDecay;
    if (cameraShakeAmount < 0.01)
        cameraShakeAmount = 0;
    return shake;
}
function resetCameraShake() {
    cameraShakeAmount = 0;
}
function getComposer() {
    return null; // No composer - we render directly
}
function resizePostProcessing(_width, _height) {
    // No-op
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"qwen3.6-27b-mtp","provider":"lmstudio","persona":"typescript","sessionId":"a1f1db67-b77d-4748-9e3a-67aee02eb577","tokensIn":2909774,"tokensOut":46150,"tokensTotal":2955924,"turns":78,"toolCalls":77,"failedToolCalls":4,"timestamp":"2026-07-30T16:38:34.942Z"} -->