← Canyon Run results

Canyon Run

GLM 4.7 Flash GGUF · typescript

Initial view of Canyon Run

Browser check: Artifact runtime error. This is a technical check, not a quality review.

Reviews & generation details

Reviews

No human review yet. Unreviewed does not mean unsuccessful.

Generation context

Imported historical artifact. Its exact original instructions and lineage are not known.

Generation prompt · exact text unavailable

See the current prompt for reference. It may differ from the instructions used to generate this artifact.

Inspect original source 34,862 bytes · SHA-256 ab4b495aa95b
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Canyon Racer - Procedural Flight</title>
<script src="https://unpkg.com/three@0.160.0/build/three.module.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/jsm/postprocessing/EffectComposer.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/jsm/postprocessing/RenderPass.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/jsm/postprocessing/UnrealBloomPass.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/jsm/postprocessing/ShaderPass.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/jsm/shaders/CopyShader.js"></script>
<script src="https://unpkg.com/three@0.160.0/examples/jsm/shaders/LuminosityHighPassShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.0/examples/jsm/postprocessing/OutputPass.js"></script>
<style>
/* ── css: hud ── */
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  background: #0a0a0a;
  overflow: hidden;
  font-family: 'Courier New', monospace;
  color: #fff;
}

#game-container {
  position: relative;
  width: 100vw;
  height: 100vh;
}

#game-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

/* HUD */
#hud {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  padding: 20px;
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  pointer-events: none;
  z-index: 10;
}

.hud-panel {
  background: rgba(0, 0, 0, 0.5);
  border: 1px solid rgba(255, 100, 50, 0.3);
  border-radius: 4px;
  padding: 10px 15px;
  backdrop-filter: blur(5px);
}

.hud-speed {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 100px;
}

.speed-label {
  font-size: 10px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 2px;
}

.speed-bar {
  width: 100%;
  height: 4px;
  background: rgba(255, 255, 255, 0.1);
  border-radius: 2px;
  overflow: hidden;
}

.fill {
  height: 100%;
  background: linear-gradient(90deg, #ff6b35, #ffcc00);
  width: 0%;
  transition: width 0.1s linear;
}

.speed-num {
  font-size: 18px;
  font-weight: bold;
  text-align: right;
  color: #ffcc00;
  text-shadow: 0 0 10px rgba(255, 200, 0, 0.5);
}

.hud-multiplier {
  text-align: center;
}

.multiplier-label {
  font-size: 10px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 2px;
  display: block;
}

.multiplier-num {
  font-size: 32px;
  font-weight: bold;
  color: #ff6b35;
  text-shadow: 0 0 20px rgba(255, 107, 53, 0.6);
  transition: transform 0.1s ease, color 0.2s ease;
}

.multiplier-num.pulse {
  transform: scale(1.2);
  color: #ffcc00;
}

.hud-energy {
  display: flex;
  flex-direction: column;
  gap: 5px;
  min-width: 100px;
  text-align: right;
}

.energy-label {
  font-size: 10px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 2px;
}

/* Overlays */
.overlay {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  background: rgba(0, 0, 0, 0.8);
  backdrop-filter: blur(10px);
  z-index: 20;
  opacity: 1;
  transition: opacity 0.5s ease;
}

.overlay.hidden {
  opacity: 0;
  pointer-events: none;
}

#start-screen h1 {
  font-size: 48px;
  color: #ffcc00;
  text-shadow: 0 0 30px rgba(255, 200, 0, 0.4);
  letter-spacing: 8px;
  margin-bottom: 10px;
}

.subtitle {
  font-size: 14px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 4px;
  margin-bottom: 40px;
}

#start-btn, #restart-btn {
  background: linear-gradient(135deg, #ff6b35, #ff4444);
  border: none;
  color: white;
  padding: 15px 40px;
  font-size: 16px;
  font-family: 'Courier New', monospace;
  letter-spacing: 3px;
  cursor: pointer;
  clip-path: polygon(10% 0, 100% 0, 100% 70%, 90% 100%, 0 100%, 0 30%);
  transition: all 0.2s ease;
  text-transform: uppercase;
}

#start-btn:hover, #restart-btn:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 30px rgba(255, 107, 53, 0.4);
}

.stats {
  display: flex;
  gap: 40px;
  margin-bottom: 30px;
}

.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
}

.stat-label {
  font-size: 10px;
  color: rgba(255, 255, 255, 0.5);
  letter-spacing: 2px;
  margin-bottom: 5px;
}

.stat-value {
  font-size: 36px;
  color: #ffcc00;
  text-shadow: 0 0 20px rgba(255, 200, 0, 0.4);
}

.hidden {
  display: none !important;
}
</style>
</head>
<body>
<div id="app"><div id="game-container">
  <canvas id="game-canvas"></canvas>
  <div id="hud">
    <div class="hud-speed">
      <div class="speed-label">SPEED</div>
      <div class="speed-bar"><div id="speed-fill" class="fill"></div></div>
      <div id="speed-value" class="speed-num">0</div>
    </div>
    <div class="hud-multiplier" id="multiplier-display">
      <span class="multiplier-label">MULTIPLIER</span>
      <span id="multiplier-value" class="multiplier-num">x1</span>
    </div>
    <div class="hud-energy">
      <div class="energy-label">ENERGY</div>
      <div class="energy-bar"><div id="energy-fill" class="fill"></div></div>
    </div>
  </div>
  <div id="start-screen" class="overlay">
    <h1>CANYON RACER</h1>
    <p class="subtitle">Procedural Flight</p>
    <button id="start-btn" class="btn">START ENGINE</button>
  </div>
  <div id="game-over-screen" class="overlay hidden">
    <h2>CRITICAL FAILURE</h2>
    <div class="stats">
      <div class="stat">
        <span class="stat-label">SCORE</span>
        <span id="final-score" class="stat-value">0</span>
      </div>
      <div class="stat">
        <span class="stat-label">MAX SPEED</span>
        <span id="final-speed" class="stat-value">0</span>
      </div>
      <div class="stat">
        <span class="stat-label">NEAR MISSES</span>
        <span id="final-misses" class="stat-value">0</span>
      </div>
    </div>
    <button id="restart-btn" class="btn">RESTART</button>
  </div>
</div></div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./game":"src/game.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 game_1 = require("./game");
// Expose to window for debugging
window.gameState = game_1.STATE;
window.game = {
    init: game_1.init,
    startGame: game_1.startGame,
    gameOver: game_1.gameOver,
    updatePlayer: game_1.updatePlayer,
    updateEnvironment: game_1.updateEnvironment,
    checkCollisions: game_1.checkCollisions,
    updateHUD: game_1.updateHUD,
};
// Start when DOM is ready
if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', () => {
        (0, game_1.init)();
    });
}
else {
    (0, game_1.init)();
}
};

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

// ── module: src/game.ts ──
__mods["src/game.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.trailIndex = exports.trailCapacity = exports.trailCount = exports.trailPositions = exports.trailGeometry = exports.trailSystem = exports.audioManager = exports.composer = exports.renderer = exports.camera = exports.scene = exports.INPUT = exports.orbs = exports.obstacles = exports.CHUNKS = exports.GAME_STATE = exports.STATE = exports.CONSTANTS = exports.AudioManager = void 0;
exports.generateChunk = generateChunk;
exports.createPlayerCraft = createPlayerCraft;
exports.initTrailSystem = initTrailSystem;
exports.updateTrail = updateTrail;
exports.addTrailPoint = addTrailPoint;
exports.updateCameraShake = updateCameraShake;
exports.checkCollisions = checkCollisions;
exports.initEnvironment = initEnvironment;
exports.updateEnvironmentArrays = updateEnvironmentArrays;
exports.generateAhead = generateAhead;
exports.cleanupBehind = cleanupBehind;
exports.updateEnvironment = updateEnvironment;
exports.updatePlayer = updatePlayer;
exports.updateHUD = updateHUD;
exports.gameOver = gameOver;
exports.startGame = startGame;
exports.gameLoop = gameLoop;
exports.setupInputs = setupInputs;
exports.handleResize = handleResize;
exports.init = init;
// Audio Context
const AudioContext = window.AudioContext || window.webkitAudioContext;
class AudioManager {
    constructor() {
        this.ctx = null;
        this.engineOsc = null;
        this.engineGain = null;
        this.gainNode = null;
    }
    init() {
        this.ctx = new AudioContext();
        this.gainNode = this.ctx.createGain();
        this.gainNode.connect(this.ctx.destination);
        this.gainNode.gain.value = 0.3;
        this.engineOsc = this.ctx.createOscillator();
        this.engineOsc.type = 'sawtooth';
        this.engineOsc.frequency.value = 60;
        this.engineGain = this.ctx.createGain();
        this.engineGain.gain.value = 0;
        this.engineOsc.connect(this.engineGain);
        this.engineGain.connect(this.gainNode);
        this.engineOsc.start();
    }
    updateEngineSpeed(speed, maxSpeed) {
        if (!this.ctx || !this.engineGain)
            return;
        const normalizedSpeed = Math.min(speed / maxSpeed, 1);
        this.engineOsc.frequency.setTargetAtTime(60 + normalizedSpeed * 80, this.ctx.currentTime, 0.1);
        this.engineGain.gain.setTargetAtTime(normalizedSpeed * 0.15, this.ctx.currentTime, 0.1);
    }
    playCollect() {
        if (!this.ctx)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sine';
        osc.frequency.setValueAtTime(880, this.ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(1760, 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.gainNode);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.2);
    }
    playNearMiss() {
        if (!this.ctx)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'triangle';
        osc.frequency.setValueAtTime(440, this.ctx.currentTime);
        osc.frequency.linearRampToValueAtTime(660, this.ctx.currentTime + 0.3);
        gain.gain.setValueAtTime(0.1, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.4);
        osc.connect(gain);
        gain.connect(this.gainNode);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.4);
    }
    playCrash() {
        if (!this.ctx)
            return;
        const osc = this.ctx.createOscillator();
        const gain = this.ctx.createGain();
        osc.type = 'sawtooth';
        osc.frequency.setValueAtTime(200, this.ctx.currentTime);
        osc.frequency.exponentialRampToValueAtTime(50, this.ctx.currentTime + 0.5);
        gain.gain.setValueAtTime(0.4, this.ctx.currentTime);
        gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.5);
        osc.connect(gain);
        gain.connect(this.gainNode);
        osc.start();
        osc.stop(this.ctx.currentTime + 0.5);
    }
    resume() {
        if (this.ctx && this.ctx.state === 'suspended') {
            this.ctx.resume();
        }
    }
}
exports.AudioManager = AudioManager;
// Constants
exports.CONSTANTS = {
    PLAYER_SPEED: 80,
    MAX_SPEED: 300,
    ACCELERATION: 15,
    FRICTION: 0.98,
    ENERGY_DECAY: 8,
    ENERGY_RECHARGE: 30,
    BOOST_MULTIPLIER: 2,
    NEAR_MISS_THRESHOLD: 3,
    NEAR_MISS_BONUS: 100,
    CHUNK_SIZE: 400,
    CHUNK_GENERATION_DISTANCE: 2,
    WALL_COLOR: 0x1a1a2e,
    MONOLITH_COLOR: 0x4a4a6e,
    SQUEEZE_COLOR: 0x3a3a5e,
    ORB_COLOR: 0xffcc00,
    PLAYER_COLOR: 0xff6b35,
    TRAIL_COLOR: 0xff4444,
    AMBIENT_LIGHT: 0x404060,
    DIRECTIONAL_LIGHT: 0xffcc88,
};
exports.STATE = {
    position: new THREE.Vector3(0, 0, 0),
    velocity: new THREE.Vector3(0, 0, exports.CONSTANTS.PLAYER_SPEED),
    rotation: new THREE.Euler(0, 0, 0),
    energy: 100,
    maxEnergy: 100,
    multiplier: 1,
    score: 0,
    maxSpeed: exports.CONSTANTS.MAX_SPEED,
    boost: 0,
    boostAvailable: false,
    nearMisses: 0,
    isBoosting: false,
    turboMeter: 0,
    isPlaying: false,
};
exports.GAME_STATE = {
    isPlaying: false,
    speed: exports.CONSTANTS.PLAYER_SPEED,
    distance: 0,
    difficultyMultiplier: 1,
    cameraShake: 0,
    turboMeter: 0,
};
exports.CHUNKS = [];
exports.obstacles = [];
exports.orbs = [];
// Input State
exports.INPUT = {
    left: false,
    right: false,
    up: false,
    down: false,
    boost: false,
};
exports.trailCount = 0;
exports.trailCapacity = 200;
exports.trailIndex = 0;
// Procedural Generation
function generateChunk(zPosition, difficulty) {
    const chunk = {
        obstacles: [],
        orbs: [],
        position: zPosition,
    };
    const width = 100 + difficulty * 20;
    const center = 0;
    const numObstacles = 3 + Math.floor(difficulty);
    for (let i = 0; i < numObstacles; i++) {
        const type = Math.random() < 0.5 ? 'wall' : 'monolith';
        const x = center + (Math.random() - 0.5) * width;
        const z = zPosition - 150 + Math.random() * 200;
        if (type === 'wall') {
            const size = 20 + Math.random() * 30 + difficulty * 5;
            const geometry = new THREE.BoxGeometry(size, 80, 40);
            const material = new THREE.MeshLambertMaterial({
                color: Math.random() > 0.5 ? exports.CONSTANTS.WALL_COLOR : exports.CONSTANTS.MONOLITH_COLOR,
            });
            const mesh = new THREE.Mesh(geometry, material);
            mesh.position.set(x, 0, z);
            mesh.castShadow = true;
            mesh.receiveShadow = true;
            const collider = new THREE.Box3().setFromObject(mesh);
            chunk.obstacles.push({
                type,
                mesh,
                collider,
                scoreValue: 10,
            });
        }
        else {
            const size = 15 + Math.random() * 15 + difficulty * 3;
            const geometry = new THREE.ConeGeometry(size * 0.7, size * 2, 8);
            const material = new THREE.MeshLambertMaterial({
                color: exports.CONSTANTS.MONOLITH_COLOR,
            });
            const mesh = new THREE.Mesh(geometry, material);
            mesh.position.set(x, -size * 0.5, z);
            mesh.rotation.z = Math.PI / 2;
            mesh.castShadow = true;
            mesh.receiveShadow = true;
            const collider = new THREE.Box3().setFromObject(mesh);
            chunk.obstacles.push({
                type,
                mesh,
                collider,
                scoreValue: 15,
            });
        }
    }
    // Generate orbs
    const numOrbs = 3 + Math.floor(difficulty * 0.5);
    for (let i = 0; i < numOrbs; i++) {
        const x = center + (Math.random() - 0.5) * width;
        const z = zPosition - 150 + Math.random() * 200;
        const geometry = new THREE.OctahedronGeometry(3);
        const material = new THREE.MeshBasicMaterial({
            color: exports.CONSTANTS.ORB_COLOR,
            emissive: exports.CONSTANTS.ORB_COLOR,
            emissiveIntensity: 2,
        });
        const mesh = new THREE.Mesh(geometry, material);
        mesh.position.set(x, 0, z);
        const collider = new THREE.Sphere();
        chunk.orbs.push({
            mesh,
            collider,
            active: true,
        });
    }
    return chunk;
}
// Player Craft
function createPlayerCraft() {
    const group = new THREE.Group();
    // Main body
    const bodyGeometry = new THREE.ConeGeometry(1.5, 6, 6);
    const bodyMaterial = new THREE.MeshPhongMaterial({
        color: exports.CONSTANTS.PLAYER_COLOR,
        flatShading: true,
        shininess: 100,
    });
    const body = new THREE.Mesh(bodyGeometry, bodyMaterial);
    body.rotation.x = Math.PI / 2;
    group.add(body);
    // Wings
    const wingGeometry = new THREE.BoxGeometry(8, 0.2, 3);
    const wingMaterial = new THREE.MeshPhongMaterial({
        color: 0xcc4400,
        flatShading: true,
    });
    const wings = new THREE.Mesh(wingGeometry, wingMaterial);
    wings.position.set(0, 0, 1);
    group.add(wings);
    // Engine glow
    const engineGeometry = new THREE.SphereGeometry(0.5, 8, 8);
    const engineMaterial = new THREE.MeshBasicMaterial({
        color: 0xffaa00,
        emissive: 0xff6600,
        emissiveIntensity: 3,
    });
    const engine = new THREE.Mesh(engineGeometry, engineMaterial);
    engine.position.set(0, 0, 2.5);
    group.add(engine);
    // Engine particle emitter point
    engine.particleOrigin = new THREE.Vector3(0, 0, 3);
    group.position.copy(exports.STATE.position);
    return group;
}
// Trail System
function initTrailSystem() {
    exports.trailGeometry = new THREE.BufferGeometry();
    exports.trailPositions = new Float32Array(exports.trailCapacity * 3);
    exports.trailGeometry.setAttribute('position', new THREE.BufferAttribute(exports.trailPositions, 3));
    const trailMaterial = new THREE.PointsMaterial({
        color: exports.CONSTANTS.TRAIL_COLOR,
        size: 0.3,
        transparent: true,
        opacity: 0.8,
        blending: THREE.AdditiveBlending,
    });
    exports.trailSystem = new THREE.Points(exports.trailGeometry, trailMaterial);
    exports.trailSystem.frustumCulled = false;
    exports.scene.add(exports.trailSystem);
}
function updateTrail() {
    if (exports.trailCount === 0)
        return;
    const positions = exports.trailGeometry.attributes.position.array;
    const fade = 0.95;
    for (let i = 0; i < exports.trailCount; i++) {
        const srcIdx = (exports.trailIndex + i) % exports.trailCapacity;
        positions[srcIdx * 3] = exports.trailPositions[i * 3] * fade;
        positions[srcIdx * 3 + 1] = exports.trailPositions[i * 3 + 1] * fade;
        positions[srcIdx * 3 + 2] = exports.trailPositions[i * 3 + 2] * fade;
    }
    exports.trailGeometry.attributes.position.needsUpdate = true;
}
function addTrailPoint(position) {
    const positions = exports.trailGeometry.attributes.position.array;
    positions[exports.trailIndex * 3] = position.x;
    positions[exports.trailIndex * 3 + 1] = position.y;
    positions[exports.trailIndex * 3 + 2] = position.z;
    exports.trailIndex = (exports.trailIndex + 1) % exports.trailCapacity;
    exports.trailCount = Math.min(exports.trailCount + 1, exports.trailCapacity);
}
// Camera Shake
function updateCameraShake() {
    if (exports.GAME_STATE.cameraShake <= 0)
        return;
    exports.GAME_STATE.cameraShake *= 0.9;
    if (exports.GAME_STATE.cameraShake < 0.1) {
        exports.GAME_STATE.cameraShake = 0;
        return;
    }
    const offsetX = (Math.random() - 0.5) * exports.GAME_STATE.cameraShake;
    const offsetY = (Math.random() - 0.5) * exports.GAME_STATE.cameraShake;
    const offsetZ = (Math.random() - 0.5) * exports.GAME_STATE.cameraShake;
    exports.camera.position.add(new THREE.Vector3(offsetX, offsetY, offsetZ));
}
// Collision Detection
function checkCollisions() {
    const playerBox = new THREE.Box3();
    const playerRadius = 2;
    playerBox.min.set(exports.STATE.position.x - playerRadius, exports.STATE.position.y - playerRadius, exports.STATE.position.z - playerRadius);
    playerBox.max.set(exports.STATE.position.x + playerRadius, exports.STATE.position.y + playerRadius, exports.STATE.position.z + playerRadius);
    // Check obstacles
    for (let i = exports.obstacles.length - 1; i >= 0; i--) {
        const obstacle = exports.obstacles[i];
        if (playerBox.intersectsBox(obstacle.collider)) {
            gameOver();
            return;
        }
        // Check near misses
        const distance = obstacle.collider.center.distanceTo(exports.STATE.position);
        if (distance < exports.CONSTANTS.NEAR_MISS_THRESHOLD && distance > 1) {
            exports.STATE.multiplier = Math.min(exports.STATE.multiplier + 1, 5);
            exports.STATE.score += exports.CONSTANTS.NEAR_MISS_BONUS * exports.STATE.multiplier;
            exports.STATE.nearMisses++;
            exports.GAME_STATE.cameraShake = Math.min(exports.GAME_STATE.cameraShake + 0.2, 1);
            exports.obstacles.splice(i, 1);
        }
    }
    // Check orbs
    for (let i = exports.orbs.length - 1; i >= 0; i--) {
        const orb = exports.orbs[i];
        if (orb.active) {
            const distance = orb.collider.center.distanceTo(exports.STATE.position);
            if (exports.STATE.position.distanceTo(orb.mesh.position) < distance) {
                orb.active = false;
                orb.mesh.visible = false;
                exports.STATE.energy = Math.min(exports.STATE.energy + exports.CONSTANTS.ENERGY_RECHARGE, exports.STATE.maxEnergy);
                exports.STATE.score += 50;
                exports.STATE.multiplier = Math.max(exports.STATE.multiplier - 1, 1);
                exports.STATE.turboMeter = Math.min(exports.STATE.turboMeter + 20, 100);
                exports.audioManager.playCollect();
            }
        }
    }
}
// Procedural Environment
function initEnvironment() {
    exports.scene = new THREE.Scene();
    exports.scene.background = new THREE.Color(0x0a0a15);
    exports.scene.fog = new THREE.Fog(0x0a0a15, 200, 600);
    exports.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 2000);
    exports.camera.position.set(0, 10, 30);
    exports.camera.lookAt(exports.STATE.position.clone().add(new THREE.Vector3(0, 0, 100)));
    exports.renderer = new THREE.WebGLRenderer({
        canvas: document.getElementById('game-canvas'),
        antialias: true,
        alpha: false,
    });
    exports.renderer.setSize(window.innerWidth, window.innerHeight);
    exports.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    exports.renderer.shadowMap.enabled = true;
    exports.renderer.shadowMap.type = THREE.PCFSoftShadowMap;
    // Post-processing
    const renderScene = new THREE.RenderPass(exports.scene, exports.camera);
    const bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 1.5, 0.4, 0.85);
    bloomPass.threshold = 0.2;
    bloomPass.strength = 1.2;
    bloomPass.radius = 0.5;
    const outputPass = new THREE.OutputPass();
    exports.composer = new THREE.EffectComposer(exports.renderer);
    exports.composer.addPass(renderScene);
    exports.composer.addPass(bloomPass);
    exports.composer.addPass(outputPass);
    // Lighting
    const ambientLight = new THREE.AmbientLight(exports.CONSTANTS.AMBIENT_LIGHT, 0.5);
    exports.scene.add(ambientLight);
    const directionalLight = new THREE.DirectionalLight(exports.CONSTANTS.DIRECTIONAL_LIGHT, 1);
    directionalLight.position.set(50, 100, 50);
    directionalLight.castShadow = true;
    directionalLight.shadow.mapSize.width = 2048;
    directionalLight.shadow.mapSize.height = 2048;
    directionalLight.shadow.camera.near = 0.5;
    directionalLight.shadow.camera.far = 500;
    directionalLight.shadow.camera.left = -100;
    directionalLight.shadow.camera.right = 100;
    directionalLight.shadow.camera.top = 100;
    directionalLight.shadow.camera.bottom = -100;
    exports.scene.add(directionalLight);
    // Hemisphere light for sky
    const hemisphereLight = new THREE.HemisphereLight(0xff6644, 0x080820, 0.6);
    exports.scene.add(hemisphereLight);
    // Generate initial chunks
    for (let i = 0; i < 5; i++) {
        const chunk = generateChunk(-i * exports.CONSTANTS.CHUNK_SIZE, 1);
        exports.CHUNKS.push(chunk);
    }
    // Collect all obstacles and orbs
    updateEnvironmentArrays();
}
function updateEnvironmentArrays() {
    exports.obstacles = [];
    exports.orbs = [];
    for (const chunk of exports.CHUNKS) {
        exports.obstacles.push(...chunk.obstacles);
        exports.orbs.push(...chunk.orbs);
    }
    // Remove old chunks
    const minZ = exports.STATE.position.z - 400;
    for (let i = exports.CHUNKS.length - 1; i >= 0; i--) {
        if (exports.CHUNKS[i].position < minZ) {
            // Remove meshes from scene
            for (const obstacle of exports.CHUNKS[i].obstacles) {
                exports.scene.remove(obstacle.mesh);
                obstacle.mesh.geometry.dispose();
                obstacle.mesh.material.dispose();
            }
            for (const orb of exports.CHUNKS[i].orbs) {
                exports.scene.remove(orb.mesh);
                orb.mesh.geometry.dispose();
                orb.mesh.material.dispose();
            }
            exports.CHUNKS.splice(i, 1);
        }
    }
}
function generateAhead() {
    const lastChunk = exports.CHUNKS[exports.CHUNKS.length - 1];
    const nextPosition = lastChunk.position - exports.CONSTANTS.CHUNK_SIZE;
    if (nextPosition > exports.STATE.position.z - exports.CONSTANTS.CHUNK_GENERATION_DISTANCE * exports.CONSTANTS.CHUNK_SIZE) {
        const difficulty = 1 + exports.STATE.score / 1000;
        const chunk = generateChunk(nextPosition, difficulty);
        exports.CHUNKS.push(chunk);
    }
}
function cleanupBehind() {
    const minZ = exports.STATE.position.z - exports.CONSTANTS.CHUNK_SIZE * 2;
    const chunksToRemove = [];
    for (let i = exports.CHUNKS.length - 1; i >= 0; i--) {
        if (exports.CHUNKS[i].position < minZ) {
            chunksToRemove.push(exports.CHUNKS[i]);
        }
    }
    for (const chunk of chunksToRemove) {
        for (const obstacle of chunk.obstacles) {
            exports.scene.remove(obstacle.mesh);
        }
        for (const orb of chunk.orbs) {
            exports.scene.remove(orb.mesh);
        }
    }
    exports.CHUNKS = exports.CHUNKS.filter((chunk) => chunk.position >= minZ);
}
function updateEnvironment() {
    generateAhead();
    cleanupBehind();
    updateEnvironmentArrays();
}
// Player Movement
function updatePlayer(dt) {
    const speed = exports.STATE.isBoosting ? exports.GAME_STATE.speed * exports.CONSTANTS.BOOST_MULTIPLIER : exports.GAME_STATE.speed;
    // Input handling
    const moveX = (exports.INPUT.left ? 1 : 0) - (exports.INPUT.right ? 1 : 0);
    const moveY = (exports.INPUT.down ? 1 : 0) - (exports.INPUT.up ? 1 : 0);
    // Acceleration
    exports.STATE.velocity.x += moveX * exports.CONSTANTS.ACCELERATION * dt;
    exports.STATE.velocity.y += moveY * exports.CONSTANTS.ACCELERATION * dt;
    // Limit speed
    exports.STATE.velocity.clampLength(0, speed);
    // Apply velocity
    exports.STATE.position.add(exports.STATE.velocity.clone().multiplyScalar(dt));
    // Banking based on horizontal velocity
    const bankAngle = THREE.MathUtils.degToRad(30);
    const targetBank = -exports.STATE.velocity.x * 0.3;
    exports.STATE.rotation.z = THREE.MathUtils.lerp(exports.STATE.rotation.z, targetBank, dt * 5);
    // Pitch based on vertical velocity
    const pitchAngle = THREE.MathUtils.degToRad(20);
    const targetPitch = -exports.STATE.velocity.y * 0.2;
    exports.STATE.rotation.x = THREE.MathUtils.lerp(exports.STATE.rotation.x, targetPitch, dt * 5);
    // Energy decay
    exports.STATE.energy -= exports.CONSTANTS.ENERGY_DECAY * dt;
    if (exports.STATE.energy <= 0) {
        gameOver();
        return;
    }
    // Boost management
    if (exports.STATE.turboMeter >= 100) {
        exports.STATE.turboMeter = 0;
        exports.STATE.isBoosting = true;
        setTimeout(() => {
            exports.STATE.isBoosting = false;
        }, 3000);
    }
    // Trail
    addTrailPoint(exports.STATE.position.clone());
    updateTrail();
    // Update game state
    exports.GAME_STATE.speed = Math.max(speed, exports.CONSTANTS.PLAYER_SPEED);
    exports.GAME_STATE.distance += speed * dt;
    exports.GAME_STATE.difficultyMultiplier = 1 + exports.STATE.score / 1000;
    // Camera follow
    exports.camera.position.x = THREE.MathUtils.lerp(exports.camera.position.x, exports.STATE.position.x * 0.3, dt * 2);
    exports.camera.position.y = THREE.MathUtils.lerp(exports.camera.position.y, exports.STATE.position.y + 15, dt * 2);
    exports.camera.position.z = exports.STATE.position.z + 30;
    // FOV change on boost
    const targetFOV = exports.STATE.isBoosting ? 90 : 75;
    exports.camera.fov = THREE.MathUtils.lerp(exports.camera.fov, targetFOV, dt * 2);
    exports.camera.updateProjectionMatrix();
    // Camera shake
    updateCameraShake();
    // Audio update
    exports.audioManager.updateEngineSpeed(speed, exports.CONSTANTS.MAX_SPEED);
}
// HUD Updates
function updateHUD() {
    // Speed
    const speedPercent = (exports.STATE.velocity.length() / exports.STATE.maxSpeed) * 100;
    document.getElementById('speed-fill').style.width = `${speedPercent}%`;
    document.getElementById('speed-value').textContent = Math.round(exports.STATE.velocity.length()).toString();
    // Multiplier
    const multiplierEl = document.getElementById('multiplier-value');
    multiplierEl.textContent = `x${exports.STATE.multiplier}`;
    if (exports.STATE.multiplier > 1) {
        multiplierEl.classList.add('pulse');
    }
    else {
        multiplierEl.classList.remove('pulse');
    }
    // Energy
    const energyPercent = (exports.STATE.energy / exports.STATE.maxEnergy) * 100;
    document.getElementById('energy-fill').style.width = `${energyPercent}%`;
    // Turbo
    if (exports.STATE.turboMeter >= 100) {
        document.getElementById('energy-fill').style.background = 'linear-gradient(90deg, #00ff88, #00cc66)';
        document.getElementById('energy-fill').style.boxShadow = '0 0 10px #00ff88';
    }
    else {
        document.getElementById('energy-fill').style.background = 'linear-gradient(90deg, #ff6b35, #ffcc00)';
        document.getElementById('energy-fill').style.boxShadow = 'none';
    }
}
// Game Over
function gameOver() {
    exports.STATE.isPlaying = false;
    exports.audioManager.playCrash();
    document.getElementById('game-over-screen').classList.remove('hidden');
    document.getElementById('final-score').textContent = Math.round(exports.STATE.score).toString();
    document.getElementById('final-speed').textContent = Math.round(exports.STATE.velocity.length()).toString();
    document.getElementById('final-misses').textContent = exports.STATE.nearMisses.toString();
}
// Start Game
function startGame() {
    exports.audioManager.resume();
    exports.STATE.isPlaying = true;
    exports.STATE.score = 0;
    exports.STATE.energy = 100;
    exports.STATE.multiplier = 1;
    exports.STATE.nearMisses = 0;
    exports.STATE.turboMeter = 0;
    exports.STATE.position.set(0, 0, 0);
    exports.STATE.velocity.set(0, 0, exports.CONSTANTS.PLAYER_SPEED);
    exports.STATE.rotation.set(0, 0, 0);
    exports.GAME_STATE.difficultyMultiplier = 1;
    // Clear obstacles
    for (const chunk of exports.CHUNKS) {
        for (const obstacle of chunk.obstacles) {
            exports.scene.remove(obstacle.mesh);
        }
        for (const orb of chunk.orbs) {
            exports.scene.remove(orb.mesh);
        }
    }
    // Clear orbs array
    exports.orbs.forEach((orb) => {
        exports.scene.remove(orb.mesh);
    });
    exports.orbs = [];
    // Generate initial chunks again
    exports.CHUNKS.length = 0;
    for (let i = 0; i < 5; i++) {
        const chunk = generateChunk(-i * exports.CONSTANTS.CHUNK_SIZE, 1);
        exports.CHUNKS.push(chunk);
    }
    updateEnvironmentArrays();
    // Hide screens
    document.getElementById('start-screen').classList.add('hidden');
    document.getElementById('game-over-screen').classList.add('hidden');
}
// Main Game Loop
function gameLoop() {
    if (!exports.STATE.isPlaying)
        return;
    const dt = Math.min(1 / 60, 0.016);
    updatePlayer(dt);
    updateEnvironment();
    checkCollisions();
    updateHUD();
    exports.composer.render();
    requestAnimationFrame(gameLoop);
}
// Input Handling
function setupInputs() {
    document.addEventListener('keydown', (e) => {
        switch (e.key) {
            case 'ArrowLeft':
            case 'a':
            case 'A':
                exports.INPUT.left = true;
                break;
            case 'ArrowRight':
            case 'd':
            case 'D':
                exports.INPUT.right = true;
                break;
            case 'ArrowUp':
            case 'w':
            case 'W':
                exports.INPUT.up = true;
                break;
            case 'ArrowDown':
            case 's':
            case 'S':
                exports.INPUT.down = true;
                break;
            case 'Shift':
                if (exports.STATE.turboMeter >= 100) {
                    exports.STATE.isBoosting = true;
                    setTimeout(() => {
                        exports.STATE.isBoosting = false;
                    }, 3000);
                }
                break;
        }
    });
    document.addEventListener('keyup', (e) => {
        switch (e.key) {
            case 'ArrowLeft':
            case 'a':
            case 'A':
                exports.INPUT.left = false;
                break;
            case 'ArrowRight':
            case 'd':
            case 'D':
                exports.INPUT.right = false;
                break;
            case 'ArrowUp':
            case 'w':
            case 'W':
                exports.INPUT.up = false;
                break;
            case 'ArrowDown':
            case 's':
            case 'S':
                exports.INPUT.down = false;
                break;
            case 'Shift':
                exports.STATE.isBoosting = false;
                break;
        }
    });
    document.getElementById('start-btn').addEventListener('click', startGame);
    document.getElementById('restart-btn').addEventListener('click', startGame);
}
// Window Resize
function handleResize() {
    exports.camera.aspect = window.innerWidth / window.innerHeight;
    exports.camera.updateProjectionMatrix();
    exports.renderer.setSize(window.innerWidth, window.innerHeight);
    exports.composer.setSize(window.innerWidth, window.innerHeight);
}
// Initialize
async function init() {
    exports.audioManager = new AudioContext();
    initEnvironment();
    initTrailSystem();
    const playerCraft = createPlayerCraft();
    exports.scene.add(playerCraft);
    setupInputs();
    window.addEventListener('resize', handleResize);
    requestAnimationFrame(gameLoop);
}
};

// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>