Canyon Run
Qwen 3.6 27B MTP GGUF IQ4 NL · typescript

Reviews & generation details
Reviews
No human review yet. Unreviewed does not mean unsuccessful.
Generation context
Imported historical artifact. Its exact original instructions and lineage are not known.
Generation prompt · exact text unavailable
See the current prompt for reference. It may differ from the instructions used to generate this artifact.
Inspect original source 46,052 bytes · SHA-256 89fb384a8144
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Canyon Rush — High-Speed Procedural Racer</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/build/three.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/EffectComposer.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/RenderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/ShaderPass.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/shaders/CopyShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/shaders/LuminosityHighPassShader.js"></script>
<script src="https://cdn.jsdelivr.net/npm/three@0.128.0/examples/js/postprocessing/UnrealBloomPass.js"></script>
<style>
/* ── css: layout ── */
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body, #app { width: 100%; height: 100%; overflow: hidden; background: #0a0014; font-family: 'Segoe UI', 'Arial Black', sans-serif; }
canvas#gameCanvas { display: block; position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
/* HUD */
#hud {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
pointer-events: none;
z-index: 10;
}
#score {
position: absolute;
top: 20px; right: 30px;
font-size: 28px;
font-weight: 900;
color: #fff;
text-shadow: 0 0 20px #ff8800, 0 0 40px #ff4400;
letter-spacing: 2px;
}
#multiplier {
position: absolute;
top: 55px; right: 30px;
font-size: 36px;
font-weight: 900;
color: #ffaa00;
text-shadow: 0 0 15px #ff6600;
transition: transform 0.1s;
}
#multiplier.pulse {
transform: scale(1.4);
color: #ff4444;
text-shadow: 0 0 30px #ff0000;
}
/* Speed bar - left side */
#speedBar {
position: absolute;
left: 30px;
top: 50%;
transform: translateY(-50%);
width: 6px;
height: 200px;
background: rgba(255,255,255,0.1);
border-radius: 3px;
overflow: hidden;
}
#speedFill {
position: absolute;
bottom: 0;
width: 100%;
height: 30%;
background: linear-gradient(to top, #ff4400, #ffaa00);
border-radius: 3px;
transition: height 0.2s;
box-shadow: 0 0 10px #ff6600;
}
/* Energy bar - bottom center */
#energyBar {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
width: 200px;
height: 8px;
background: rgba(255,255,255,0.1);
border-radius: 4px;
overflow: hidden;
}
#energyFill {
position: absolute;
left: 0;
width: 100%;
height: 100%;
background: linear-gradient(to right, #00aaff, #00ffaa);
border-radius: 4px;
transition: width 0.15s;
box-shadow: 0 0 10px #00aaff;
}
/* Turbo bar */
#turboBar {
position: absolute;
bottom: 50px;
left: 50%;
transform: translateX(-50%);
width: 140px;
height: 5px;
background: rgba(255,255,255,0.08);
border-radius: 3px;
overflow: hidden;
}
#turboFill {
position: absolute;
left: 0;
width: 0%;
height: 100%;
background: linear-gradient(to right, #ff00ff, #ff8800);
border-radius: 3px;
transition: width 0.1s;
box-shadow: 0 0 8px #ff00ff;
}
/* ── css: ui ── */
/* Start screen */
#startScreen {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
background: radial-gradient(ellipse at center, rgba(26,0,48,0.9) 0%, rgba(10,0,20,0.98) 100%);
z-index: 50;
pointer-events: auto;
}
#startTitle {
font-size: 64px;
font-weight: 900;
color: #FF6600;
text-shadow: 0 0 30px #FF4400, 0 0 60px #FF2200, 0 4px 0 #882200;
letter-spacing: 8px;
margin-bottom: 10px;
}
#startSub {
font-size: 18px;
color: #AA88CC;
letter-spacing: 3px;
margin-bottom: 30px;
}
#startControls {
font-size: 13px;
color: #888;
margin-bottom: 30px;
letter-spacing: 1px;
}
#startBtn, #restartBtn {
pointer-events: auto;
padding: 15px 50px;
font-size: 20px;
font-weight: 900;
color: #fff;
background: linear-gradient(135deg, #FF4400, #CC2200);
border: none;
border-radius: 4px;
cursor: pointer;
letter-spacing: 4px;
text-shadow: 0 2px 4px rgba(0,0,0,0.5);
box-shadow: 0 4px 20px rgba(255,68,0,0.4);
transition: transform 0.1s, box-shadow 0.1s;
}
#startBtn:hover, #restartBtn:hover {
transform: scale(1.05);
box-shadow: 0 6px 30px rgba(255,68,0,0.6);
}
/* Game over screen */
#gameOver {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
display: none;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 100;
}
#goTitle {
font-size: 56px;
font-weight: 900;
color: #FF4444;
text-shadow: 0 0 30px #FF0000, 0 0 60px #CC0000;
letter-spacing: 6px;
margin-bottom: 30px;
}
#goScore, #goSpeed, #goMultiplier {
font-size: 22px;
color: #DDCCFF;
margin: 8px 0;
letter-spacing: 2px;
text-shadow: 0 0 10px rgba(200,150,255,0.5);
}
#restartBtn {
margin-top: 30px;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<div id="hud">
<div id="speedBar"><div id="speedFill"></div></div>
<div id="multiplier">x1</div>
<div id="energyBar"><div id="energyFill"></div></div>
<div id="turboBar"><div id="turboFill"></div></div>
<div id="score">0</div>
</div>
<div id="gameOver" style="display:none">
<div id="goTitle">GAME OVER</div>
<div id="goScore">Final Score: 0</div>
<div id="goSpeed">Max Speed: 0</div>
<div id="goMultiplier">Best Multiplier: x1</div>
<button id="restartBtn">RESTART</button>
</div>
<div id="startScreen">
<div id="startTitle">CANYON RUSH</div>
<div id="startSub">Navigate the procedural canyon</div>
<div id="startControls">W/S — Pitch Up/Down A/D — Turn Left/Right SPACE — Boost</div>
<button id="startBtn">LAUNCH</button>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./player":"src/player.ts","./input":"src/input.ts","./sound":"src/sound.ts","./particles":"src/particles.ts","./world":"src/world.ts","./types":"src/types.ts"},"src/input.ts":{"./types":"src/types.ts"},"src/world.ts":{"./types":"src/types.ts"},"src/player.ts":{"./types":"src/types.ts"}};
function __require(id) {
if (__cache[id]) return __cache[id].exports;
var module = __cache[id] = { exports: {} };
var factory = __mods[id];
if (!factory) throw new Error("Module not found: " + id);
factory(module.exports, function (spec) {
var target = (__map[id] && __map[id][spec]) || spec;
return __require(target);
}, module);
return module.exports;
}
// ── module: src/main.ts ──
__mods["src/main.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const player_1 = require("./player");
const input_1 = require("./input");
const sound_1 = require("./sound");
const particles_1 = require("./particles");
const world_1 = require("./world");
let renderer;
let scene;
let camera;
let composer;
let player;
let input;
let sound;
let particles;
let speedParticles;
let chunks = [];
let game;
let clock;
// HUD elements
let hudScore;
let hudMultiplier;
let hudSpeedFill;
let hudEnergyFill;
let hudTurboFill;
let gameOverScreen;
let startScreen;
let goScore;
let goSpeed;
let goMultiplier;
// Camera effects
let shakeIntensity = 0;
let cameraShakeX = 0;
let cameraShakeY = 0;
// Misc objects
let sunMesh;
let groundPlane;
let ceilingPlane;
let sunLight;
// Timers
let trailTimer = 0;
let dustTimer = 0;
const MAX_CHUNKS = 14;
const PLAYER_RADIUS = 1.5;
// Colors
const SKY_TOP = 0x0a0020;
const SKY_HORIZON = 0x4a1020;
const SUN_COLOR = 0xff8844;
function init() {
hudScore = document.getElementById('score');
hudMultiplier = document.getElementById('multiplier');
hudSpeedFill = document.getElementById('speedFill');
hudEnergyFill = document.getElementById('energyFill');
hudTurboFill = document.getElementById('turboFill');
gameOverScreen = document.getElementById('gameOver');
startScreen = document.getElementById('startScreen');
goScore = document.getElementById('goScore');
goSpeed = document.getElementById('goSpeed');
goMultiplier = document.getElementById('goMultiplier');
// Renderer
const canvas = document.getElementById('gameCanvas');
renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
// Scene
scene = new THREE.Scene();
scene.fog = new THREE.FogExp2(0x1a0a20, 0.002);
scene.background = new THREE.Color(0x0a0015);
// Camera
camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.5, 600);
camera.position.set(0, 4, -10);
// === LIGHTS ===
// Warm ambient
const ambient = new THREE.AmbientLight(0x331155, 0.5);
scene.add(ambient);
// Sunset directional (main light)
sunLight = new THREE.DirectionalLight(0xff6633, 1.0);
sunLight.position.set(40, 60, -40);
sunLight.castShadow = true;
sunLight.shadow.mapSize.width = 1024;
sunLight.shadow.mapSize.height = 1024;
sunLight.shadow.camera.near = 1;
sunLight.shadow.camera.far = 300;
sunLight.shadow.camera.left = -80;
sunLight.shadow.camera.right = 80;
sunLight.shadow.camera.top = 60;
sunLight.shadow.camera.bottom = -40;
scene.add(sunLight);
// Purple rim light from behind
const rim = new THREE.DirectionalLight(0x8844ff, 0.3);
rim.position.set(-30, 15, -15);
scene.add(rim);
// Horizon glow point light
const horizonGlow = new THREE.PointLight(0xff4400, 2, 250);
horizonGlow.position.set(0, 15, 200);
scene.add(horizonGlow);
// === SUN DISK ===
const sunGeo = new THREE.SphereGeometry(8, 16, 16);
const sunMat = new THREE.MeshBasicMaterial({ color: 0xffcc44 });
sunMesh = new THREE.Mesh(sunGeo, sunMat);
sunMesh.position.set(30, 25, 250);
scene.add(sunMesh);
// Sun glow ring
const glowGeo = new THREE.SphereGeometry(14, 16, 16);
const glowMat = new THREE.MeshBasicMaterial({
color: 0xff6633,
transparent: true,
opacity: 0.3,
});
const sunGlow = new THREE.Mesh(glowGeo, glowMat);
sunGlow.position.copy(sunMesh.position);
scene.add(sunGlow);
// === GROUND PLANE (follows camera) ===
const groundGeo = new THREE.PlaneGeometry(400, 400, 1, 1);
const groundMat = new THREE.MeshPhongMaterial({
color: 0x2a1510,
flatShading: true,
});
groundPlane = new THREE.Mesh(groundGeo, groundMat);
groundPlane.rotation.x = -Math.PI / 2;
groundPlane.position.y = -25;
groundPlane.receiveShadow = true;
scene.add(groundPlane);
// === CEILING PLANE ===
const ceilMat = new THREE.MeshPhongMaterial({
color: 0x1a0a20,
flatShading: true,
side: THREE.DoubleSide,
});
ceilingPlane = new THREE.Mesh(groundGeo, ceilMat);
ceilingPlane.rotation.x = Math.PI / 2;
ceilingPlane.position.y = 35;
scene.add(ceilingPlane);
// === POST-PROCESSING ===
try {
composer = new THREE.EffectComposer(renderer);
const renderPass = new THREE.RenderPass(scene, camera);
composer.addPass(renderPass);
const bloomPass = new THREE.UnrealBloomPass(new THREE.Vector2(window.innerWidth, window.innerHeight), 0.8, 0.4, 0.15);
composer.addPass(bloomPass);
composer.bloomPass = bloomPass;
}
catch (_e) {
composer = null;
}
// Player
player = new player_1.Player();
scene.add(player.mesh);
// Input
input = new input_1.InputManager();
// Sound
sound = new sound_1.SoundSynth();
// Particles (trails + effects)
particles = new particles_1.ParticleSystem();
scene.add(particles.getMesh());
// Speed particles (dust/debris)
speedParticles = new particles_1.ParticleSystem();
scene.add(speedParticles.getMesh());
// Clock
clock = new THREE.Clock();
// Game state
game = {
running: false,
gameOver: false,
paused: false,
score: 0,
multiplier: 1,
multiplierTimer: 0,
maxSpeed: 0,
bestMultiplier: 1,
distance: 0,
};
// Generate initial chunks
for (let i = 0; i < 6; i++) {
addChunk(i * world_1.CHUNK_LENGTH);
}
// Events
window.addEventListener('resize', onResize);
document.getElementById('startBtn').addEventListener('click', startGame);
document.getElementById('restartBtn').addEventListener('click', restartGame);
requestAnimationFrame(gameLoop);
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
if (composer)
composer.setSize(window.innerWidth, window.innerHeight);
}
function startGame() {
sound.init();
startScreen.style.display = 'none';
game.running = true;
game.gameOver = false;
}
function restartGame() {
// Clear old chunks
for (const chunk of chunks) {
for (const mesh of chunk.meshes) {
scene.remove(mesh);
try {
mesh.geometry.dispose();
}
catch (_e) { /* */ }
try {
mesh.material.dispose();
}
catch (_e) { /* */ }
}
}
chunks = [];
// Reset player
const ps = player.state;
ps.x = 0;
ps.y = 0;
ps.z = 0;
ps.vx = 0;
ps.vy = 0;
ps.vz = 0;
ps.roll = 0;
ps.pitch = 0;
ps.yaw = 0;
ps.energy = 100;
ps.turbo = 20;
ps.boosting = false;
ps.speed = 0.4;
// Reset game
game.score = 0;
game.multiplier = 1;
game.multiplierTimer = 0;
game.maxSpeed = 0;
game.bestMultiplier = 1;
game.distance = 0;
game.running = true;
game.gameOver = false;
particles.reset();
speedParticles.reset();
shakeIntensity = 0;
gameOverScreen.style.display = 'none';
gameOverScreen.style.background = '';
// Rebuild
for (let i = 0; i < 6; i++) {
addChunk(i * world_1.CHUNK_LENGTH);
}
}
function addChunk(z) {
const difficulty = Math.min(5, game.score / 5000);
const canyonCurve = game.distance * 0.001;
const chunk = (0, world_1.generateChunk)(z, difficulty, canyonCurve);
for (const mesh of chunk.meshes) {
scene.add(mesh);
}
chunks.push(chunk);
}
function removeChunk(chunk) {
for (const mesh of chunk.meshes) {
scene.remove(mesh);
try {
mesh.geometry.dispose();
}
catch (_e) { /* */ }
try {
mesh.material.dispose();
}
catch (_e) { /* */ }
}
chunks.splice(chunks.indexOf(chunk), 1);
}
function checkCollisions() {
const px = player.state.x;
const py = player.state.y;
const pz = player.state.z;
for (const chunk of chunks) {
if (Math.abs(chunk.z - pz) > world_1.CHUNK_LENGTH * 1.5)
continue;
for (const obs of chunk.obstacles) {
const halfW = obs.width / 2 + PLAYER_RADIUS * 0.5;
const halfH = obs.height / 2 + PLAYER_RADIUS * 0.5;
const halfD = obs.depth / 2 + 1.5;
const dx = Math.abs(px - obs.x);
const dy = Math.abs(py - obs.y);
const dz = Math.abs(pz - obs.z);
if (dx < halfW && dy < halfH && dz < halfD) {
triggerGameOver();
return;
}
// Near-miss: close but not colliding
const dist = Math.sqrt(dx * dx + dy * dy);
const nearMissThreshold = halfW + halfH;
if (dist < nearMissThreshold * 0.7 && dz > 0 && dz < 8 && dx < halfW * 2.5 && dy < halfH * 2.5) {
game.multiplier = Math.min(10, game.multiplier + 0.25);
game.multiplierTimer = 2;
game.score += Math.floor(25 * game.multiplier);
sound.nearMiss();
shakeIntensity = 0.4;
hudMultiplier.classList.add('pulse');
setTimeout(() => hudMultiplier.classList.remove('pulse'), 200);
}
}
// Orb collection
for (const orb of chunk.orbs) {
if (orb.collected)
continue;
const dx = px - orb.x;
const dy = py - orb.y;
const dz = pz - orb.z;
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
if (dist < 3.5) {
orb.collected = true;
scene.remove(orb.mesh);
player.state.energy = Math.min(100, player.state.energy + 18);
player.state.turbo = Math.min(100, player.state.turbo + 12);
game.score += Math.floor(30 * game.multiplier);
sound.collect();
particles.emit(orb.x, orb.y, orb.z, 12, 10, 0x00ffaa, 0.8);
}
}
}
}
function triggerGameOver() {
game.running = false;
game.gameOver = true;
sound.crash();
sound.stop();
shakeIntensity = 3;
particles.emit(player.state.x, player.state.y, player.state.z, 50, 20, 0xff4400, 1.5);
setTimeout(() => {
gameOverScreen.style.display = 'flex';
gameOverScreen.style.flexDirection = 'column';
gameOverScreen.style.alignItems = 'center';
gameOverScreen.style.justifyContent = 'center';
gameOverScreen.style.background = 'rgba(5,0,15,0.88)';
gameOverScreen.style.position = 'absolute';
gameOverScreen.style.top = '0';
gameOverScreen.style.left = '0';
gameOverScreen.style.width = '100%';
gameOverScreen.style.height = '100%';
gameOverScreen.style.zIndex = '100';
document.getElementById('goTitle').innerHTML = 'GAME OVER';
goScore.textContent = `Final Score: ${Math.floor(game.score)}`;
goSpeed.textContent = `Max Speed: ${(game.maxSpeed * 400).toFixed(0)} km/h`;
goMultiplier.textContent = `Best Multiplier: x${game.bestMultiplier.toFixed(1)}`;
}, 600);
}
function updateCamera(dt) {
const ps = player.state;
// Smooth follow with offset based on roll
const targetX = ps.x * 0.5;
const targetY = ps.y * 0.35 + 4.5;
const camDist = ps.boosting ? 14 : 10;
const targetZ = ps.z - camDist;
camera.position.x += (targetX - camera.position.x) * dt * 4;
camera.position.y += (targetY - camera.position.y) * dt * 4;
camera.position.z += (targetZ - camera.position.z) * dt * 4;
// Camera shake
if (shakeIntensity > 0.01) {
cameraShakeX = (Math.random() - 0.5) * shakeIntensity;
cameraShakeY = (Math.random() - 0.5) * shakeIntensity;
shakeIntensity *= 0.92;
}
else {
cameraShakeX = 0;
cameraShakeY = 0;
}
camera.position.x += cameraShakeX;
camera.position.y += cameraShakeY;
// Look ahead
camera.lookAt(new THREE.Vector3(ps.x * 0.25, ps.y * 0.2, ps.z + 40));
// FOV boost
const targetFov = ps.boosting ? 95 : 72;
camera.fov += (targetFov - camera.fov) * dt * 4;
camera.updateProjectionMatrix();
// Bloom intensity
try {
const bp = composer?.bloomPass;
if (bp && bp.uniforms && bp.uniforms.strength) {
const bloomTarget = 0.5 + ps.speed * 1.2 + (ps.boosting ? 0.8 : 0);
bp.uniforms.strength.value += (bloomTarget - bp.uniforms.strength.value) * dt * 3;
}
}
catch (_e) { /* skip */ }
}
function updatePlayerVisuals() {
const ps = player.state;
const pm = player.mesh;
pm.position.set(ps.x, ps.y, ps.z);
pm.rotation.z = ps.roll;
pm.rotation.x = ps.pitch;
// Engine glow
const eg = player.engineGlow;
eg.scale.x = 1;
eg.scale.y = 1;
eg.scale.z = 1 + ps.speed * 4;
eg.material.opacity = 0.5 + ps.speed * 0.5;
if (ps.boosting) {
eg.material.color.setHex(0xFF00FF);
}
else {
eg.material.color.setHex(0xFF4400);
}
// Move ground plane with player (infinite ground illusion)
groundPlane.position.set(ps.x * 0.5, -25, ps.z);
ceilingPlane.position.set(ps.x * 0.5, 35, ps.z);
// Update sun position to stay far ahead
sunMesh.position.set(30 + Math.sin(ps.z * 0.005) * 20, 25, ps.z + 250);
// Update sun light to track camera
sunLight.position.set(40 + ps.x, 60, ps.z - 40);
sunLight.target.position.set(ps.x, ps.y, ps.z);
sunLight.target.updateMatrix();
}
function updateHUD() {
const ps = player.state;
hudScore.textContent = Math.floor(game.score).toLocaleString();
hudMultiplier.textContent = `x${game.multiplier.toFixed(1)}`;
const speedPct = Math.min(100, (ps.speed / (0.4 * 1.5)) * 100);
hudSpeedFill.style.height = `${speedPct}%`;
hudEnergyFill.style.width = `${ps.energy}%`;
if (ps.energy < 20) {
hudEnergyFill.style.background = 'linear-gradient(to right, #ff0000, #ff4400)';
hudEnergyFill.style.boxShadow = '0 0 15px #ff0000';
}
else if (ps.energy < 40) {
hudEnergyFill.style.background = 'linear-gradient(to right, #ff8800, #ffaa00)';
hudEnergyFill.style.boxShadow = '0 0 10px #ff8800';
}
else {
hudEnergyFill.style.background = 'linear-gradient(to right, #00aaff, #00ffaa)';
hudEnergyFill.style.boxShadow = '0 0 10px #00aaff';
}
hudTurboFill.style.width = `${ps.turbo}%`;
if (ps.boosting) {
hudTurboFill.style.background = 'linear-gradient(to right, #ff00ff, #ffffff)';
hudTurboFill.style.boxShadow = '0 0 20px #ff00ff';
}
else {
hudTurboFill.style.background = 'linear-gradient(to right, #ff00ff, #ff8800)';
hudTurboFill.style.boxShadow = '0 0 8px #ff00ff';
}
}
function gameLoop() {
requestAnimationFrame(gameLoop);
const dt = Math.min(clock.getDelta(), 0.05);
if (game.running && !game.gameOver) {
const inputState = input.get();
player.update(dt, inputState);
updatePlayerVisuals();
// Track max speed
const speedRatio = player.getSpeedRatio();
if (speedRatio > game.maxSpeed)
game.maxSpeed = speedRatio;
// Engine sound
sound.updateEngine(speedRatio);
// Score from distance
game.distance = player.state.z;
game.score += dt * 10 * game.multiplier;
// Multiplier decay
if (game.multiplierTimer > 0) {
game.multiplierTimer -= dt;
}
else if (game.multiplier > 1) {
game.multiplier = Math.max(1, game.multiplier - dt * 0.3);
}
if (game.multiplier > game.bestMultiplier) {
game.bestMultiplier = game.multiplier;
}
// Energy death check
if (player.state.energy <= 0) {
triggerGameOver();
}
// Collisions
checkCollisions();
// Chunk management
const playerZ = player.state.z;
const visibleRange = world_1.CHUNK_LENGTH * (MAX_CHUNKS / 2);
while (chunks.length > 0 && chunks[0].z < playerZ - visibleRange) {
removeChunk(chunks[0]);
}
const lastChunk = chunks[chunks.length - 1];
if (lastChunk && lastChunk.z < playerZ + visibleRange) {
addChunk(lastChunk.z + world_1.CHUNK_LENGTH);
}
// === PARTICLES ===
// Trail behind craft
trailTimer -= dt;
if (trailTimer <= 0) {
trailTimer = 0.015;
const offset = player.state.boosting ? 3.5 : 2;
const spd = player.state.speed * 6;
particles.emit(player.state.x + (Math.random() - 0.5) * 0.8, player.state.y + (Math.random() - 0.5) * 0.8, player.state.z + offset, player.state.boosting ? 3 : 1, spd, player.state.boosting ? 0xff00ff : 0xff6600, 0.4);
}
// Dust/debris speed particles
dustTimer -= dt;
if (dustTimer <= 0) {
dustTimer = player.state.boosting ? 0.03 : 0.06;
const spread = 20;
const count = player.state.boosting ? 3 : 1;
for (let i = 0; i < count; i++) {
speedParticles.emit(player.state.x + (Math.random() - 0.5) * spread, player.state.y + (Math.random() - 0.5) * spread * 0.6, player.state.z + 25 + Math.random() * 20, 1, 0, 0xff8844, 0.4);
}
}
// Animate orbs
const time = clock.getElapsedTime();
for (const chunk of chunks) {
for (const orb of chunk.orbs) {
if (!orb.collected) {
orb.mesh.rotation.y = time * 2.5;
orb.mesh.rotation.x = Math.sin(time * 1.5) * 0.3;
orb.mesh.position.y = orb.y + Math.sin(time * 3 + orb.z * 0.1) * 0.6;
// Pulse glow
const pulse = 0.8 + Math.sin(time * 5) * 0.2;
orb.mesh.scale.set(pulse, pulse, pulse);
}
}
}
// Update camera
updateCamera(dt);
// Update particles
particles.update(dt);
speedParticles.update(dt);
// Update HUD
updateHUD();
}
// Render
if (composer) {
composer.render(dt);
}
else {
renderer.render(scene, camera);
}
}
// Start
init();
};
// ── types: globals.d.ts ──
__mods["globals.d.ts"] = function (exports) {};
// ── module: src/types.ts ──
__mods["src/types.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
};
// ── module: src/input.ts ──
__mods["src/input.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.InputManager = void 0;
class InputManager {
constructor() {
this.state = { up: false, down: false, left: false, right: false, boost: false };
window.addEventListener('keydown', this.onKey.bind(this));
window.addEventListener('keyup', this.onKey.bind(this));
window.addEventListener('blur', () => {
this.state = { up: false, down: false, left: false, right: false, boost: false };
});
}
onKey(e) {
const k = e.key.toLowerCase();
if (k === 'w' || k === 'arrowup')
this.state.up = e.type === 'keydown';
if (k === 's' || k === 'arrowdown')
this.state.down = e.type === 'keydown';
if (k === 'a' || k === 'arrowleft')
this.state.left = e.type === 'keydown';
if (k === 'd' || k === 'arrowright')
this.state.right = e.type === 'keydown';
if (k === ' ') {
this.state.boost = e.type === 'keydown';
e.preventDefault();
}
}
get() { return this.state; }
}
exports.InputManager = InputManager;
};
// ── module: src/sound.ts ──
__mods["src/sound.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SoundSynth = void 0;
class SoundSynth {
constructor() {
this.ctx = null;
this.masterGain = null;
this.engineOsc = null;
this.engineGain = null;
this.started = false;
}
init() {
if (this.started)
return;
this.ctx = new AudioContext();
this.masterGain = this.ctx.createGain();
this.masterGain.gain.value = 0.3;
this.masterGain.connect(this.ctx.destination);
// Engine hum
this.engineOsc = this.ctx.createOscillator();
this.engineGain = this.ctx.createGain();
this.engineOsc.type = 'sawtooth';
this.engineOsc.frequency.value = 60;
this.engineGain.gain.value = 0;
this.engineOsc.connect(this.engineGain);
this.engineGain.connect(this.masterGain);
this.engineOsc.start();
this.started = true;
}
updateEngine(speedRatio) {
if (!this.engineOsc || !this.engineGain)
return;
const freq = 50 + speedRatio * 150;
this.engineOsc.frequency.setTargetAtTime(freq, this.ctx.currentTime, 0.1);
this.engineGain.gain.setTargetAtTime(0.08 + speedRatio * 0.12, this.ctx.currentTime, 0.1);
}
collect() {
if (!this.ctx || !this.masterGain)
return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(800, this.ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(1600, this.ctx.currentTime + 0.1);
gain.gain.setValueAtTime(0.3, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.2);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start();
osc.stop(this.ctx.currentTime + 0.25);
}
nearMiss() {
if (!this.ctx || !this.masterGain)
return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(300, this.ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(600, this.ctx.currentTime + 0.08);
osc.frequency.exponentialRampToValueAtTime(100, this.ctx.currentTime + 0.2);
gain.gain.setValueAtTime(0.4, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.25);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start();
osc.stop(this.ctx.currentTime + 0.3);
}
crash() {
if (!this.ctx || !this.masterGain)
return;
const bufferSize = this.ctx.sampleRate * 0.5;
const buffer = this.ctx.createBuffer(1, bufferSize, this.ctx.sampleRate);
const data = buffer.getChannelData(0);
for (let i = 0; i < bufferSize; i++) {
data[i] = (Math.random() * 2 - 1) * Math.pow(1 - i / bufferSize, 2);
}
const source = this.ctx.createBufferSource();
source.buffer = buffer;
const gain = this.ctx.createGain();
gain.gain.value = 0.5;
source.connect(gain);
gain.connect(this.masterGain);
source.start();
}
boost() {
if (!this.ctx || !this.masterGain)
return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(200, this.ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(800, this.ctx.currentTime + 0.3);
gain.gain.setValueAtTime(0.15, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.5);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start();
osc.stop(this.ctx.currentTime + 0.55);
}
stop() {
if (this.engineGain) {
this.engineGain.gain.setTargetAtTime(0, this.ctx.currentTime, 0.05);
}
}
}
exports.SoundSynth = SoundSynth;
};
// ── module: src/world.ts ──
__mods["src/world.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CANYON_WIDTH = exports.CHUNK_LENGTH = void 0;
exports.generateChunk = generateChunk;
const CHUNK_LENGTH = 200;
exports.CHUNK_LENGTH = CHUNK_LENGTH;
const CANYON_WIDTH = 60;
exports.CANYON_WIDTH = CANYON_WIDTH;
const ORB_COUNT_PER_CHUNK = 5;
const WALL_COLORS = [0x8B3A0F, 0xA0522D, 0x6B2D1A, 0x7B3A1E, 0x944B2E, 0x5C2E14];
function randomColor() {
return WALL_COLORS[Math.floor(Math.random() * WALL_COLORS.length)];
}
function createMesh(geo, color, emissive, emissiveIntensity) {
const mat = new THREE.MeshPhongMaterial({
color: color,
flatShading: true,
emissive: emissive || 0x000000,
emissiveIntensity: emissiveIntensity || 0,
});
const mesh = new THREE.Mesh(geo, mat);
mesh.castShadow = true;
mesh.receiveShadow = true;
return mesh;
}
function createCanyonWall(x, y, z, w, h, d) {
// Use low-segment geometry for low-poly look
const geo = new THREE.BoxGeometry(w, h, d, 1, 1, 1);
const mesh = createMesh(geo, randomColor());
mesh.position.set(x, y, z);
// Slight random tilt for organic feel
mesh.rotation.y = (Math.random() - 0.5) * 0.05;
mesh.rotation.x = (Math.random() - 0.5) * 0.03;
return mesh;
}
function createMonolith(x, y, z, w, h, d) {
const geo = new THREE.BoxGeometry(w, h, d, 1, 1, 1);
const mesh = createMesh(geo, 0x2A1040, 0x1A0830, 0.3);
mesh.position.set(x, y, z);
mesh.rotation.y = (Math.random() - 0.5) * 0.2;
return mesh;
}
function createOrb(x, y, z) {
const geo = new THREE.IcosahedronGeometry(0.8);
const mat = new THREE.MeshBasicMaterial({
color: 0x00ffaa,
transparent: true,
opacity: 0.9,
});
const mesh = new THREE.Mesh(geo, mat);
mesh.position.set(x, y, z);
return mesh;
}
function generateChunk(z, difficulty, canyonCurve) {
const chunk = {
z: z,
meshes: [],
orbs: [],
obstacles: [],
};
// Canyon width narrows with difficulty
const currentWidth = Math.max(20, CANYON_WIDTH - difficulty * 5);
const halfWidth = currentWidth / 2;
// Generate canyon walls (left and right)
const wallSegments = 8;
for (let i = 0; i < wallSegments; i++) {
const segZ = z + i * (CHUNK_LENGTH / wallSegments);
const curve = Math.sin(segZ * 0.008 + canyonCurve) * (10 + difficulty * 3);
const noise = Math.sin(segZ * 0.02 + i) * 5;
// Left wall
const lw = 8 + Math.random() * 5;
const lh = 20 + Math.random() * 30 + difficulty * 2;
const ld = CHUNK_LENGTH / wallSegments + 5;
const lx = -halfWidth + curve + noise;
const ly = -10 + Math.random() * 5;
const leftWall = createCanyonWall(lx, ly, segZ, lw, lh, ld);
chunk.meshes.push(leftWall);
chunk.obstacles.push({
mesh: leftWall, x: lx, y: ly, z: segZ,
width: lw, height: lh, depth: ld, type: 'wall',
});
// Right wall
const rlx = halfWidth + curve + noise;
const rly = -10 + Math.random() * 5;
const rlh = 20 + Math.random() * 30 + difficulty * 2;
const rightWall = createCanyonWall(rlx, rly, segZ, lw, rlh, ld);
chunk.meshes.push(rightWall);
chunk.obstacles.push({
mesh: rightWall, x: rlx, y: rly, z: segZ,
width: lw, height: rlh, depth: ld, type: 'wall',
});
}
// Monoliths (floating obstacles)
const monolithCount = Math.floor(1 + difficulty * 1.5);
for (let i = 0; i < monolithCount; i++) {
const mz = z + 10 + Math.random() * (CHUNK_LENGTH - 20);
const mx = (Math.random() - 0.5) * (currentWidth - 10);
const my = (Math.random() - 0.5) * 18;
const mw = 2 + Math.random() * 3;
const mh = 6 + Math.random() * 10;
const md = 2 + Math.random() * 3;
const mono = createMonolith(mx, my, mz, mw, mh, md);
chunk.meshes.push(mono);
chunk.obstacles.push({
mesh: mono, x: mx, y: my, z: mz,
width: mw, height: mh, depth: md, type: 'monolith',
});
}
// Tight squeezes (narrow gaps)
if (difficulty > 0.3) {
const squeezeCount = Math.min(4, Math.floor(difficulty * 0.8));
for (let i = 0; i < squeezeCount; i++) {
const sz = z + 30 + Math.random() * (CHUNK_LENGTH - 60);
const sx = (Math.random() - 0.5) * 8;
const sy = (Math.random() - 0.5) * 8;
const gapHeight = 3.5 + Math.random() * 3;
const aboveH = 8 + Math.random() * 5;
const belowH = 8 + Math.random() * 5;
const sw = currentWidth - 4;
const sd = 2;
// Top wall segment (ceiling of squeeze)
const top = createCanyonWall(sx, sy + gapHeight / 2 + aboveH / 2, sz, sw, aboveH, sd);
chunk.meshes.push(top);
chunk.obstacles.push({
mesh: top, x: sx, y: sy + gapHeight / 2 + aboveH / 2, z: sz,
width: sw, height: aboveH, depth: sd, type: 'squeeze',
});
// Bottom wall segment (floor of squeeze)
const bottom = createCanyonWall(sx, sy - gapHeight / 2 - belowH / 2, sz, sw, belowH, sd);
chunk.meshes.push(bottom);
chunk.obstacles.push({
mesh: bottom, x: sx, y: sy - gapHeight / 2 - belowH / 2, z: sz,
width: sw, height: belowH, depth: sd, type: 'squeeze',
});
}
}
// Generate orbs - place some in tight spots for risk/reward
for (let i = 0; i < ORB_COUNT_PER_CHUNK + Math.floor(difficulty); i++) {
const ox = (Math.random() - 0.5) * (currentWidth - 12);
const oy = (Math.random() - 0.5) * 14;
const oz = z + 10 + Math.random() * (CHUNK_LENGTH - 20);
const orbMesh = createOrb(ox, oy, oz);
chunk.meshes.push(orbMesh);
chunk.orbs.push({ mesh: orbMesh, x: ox, y: oy, z: oz, collected: false });
}
return chunk;
}
};
// ── module: src/player.ts ──
__mods["src/player.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Player = void 0;
class Player {
constructor() {
this.state = {
x: 0, y: 0, z: 0,
vx: 0, vy: 0, vz: 0,
roll: 0, pitch: 0, yaw: 0,
energy: 100,
turbo: 0,
boosting: false,
speed: 0.4,
};
this.mesh = this.createCraft();
}
createCraft() {
const group = new THREE.Group();
// Main body - sleek arrow shape
const bodyGeo = new THREE.ConeGeometry(0.5, 3, 6);
const bodyMat = new THREE.MeshPhongMaterial({
color: 0xCCCCCC,
emissive: 0x333333,
emissiveIntensity: 0.2,
flatShading: true,
});
const body = new THREE.Mesh(bodyGeo, bodyMat);
body.rotation.x = Math.PI / 2;
body.castShadow = true;
group.add(body);
// Wings
const wingGeo = new THREE.BoxGeometry(4, 0.1, 1.5);
const wingMat = new THREE.MeshPhongMaterial({
color: 0xAA4400,
flatShading: true,
});
const wings = new THREE.Mesh(wingGeo, wingMat);
wings.position.z = 0.3;
wings.position.y = -0.1;
wings.castShadow = true;
group.add(wings);
// Wing tips
const tipGeo = new THREE.ConeGeometry(0.2, 0.8, 4);
const tipMat = new THREE.MeshPhongMaterial({
color: 0xFF6600,
emissive: 0xFF4400,
emissiveIntensity: 0.5,
flatShading: true,
});
const leftTip = new THREE.Mesh(tipGeo, tipMat);
leftTip.position.set(-2, -0.1, 0.3);
leftTip.rotation.z = Math.PI / 2;
group.add(leftTip);
const rightTip = new THREE.Mesh(tipGeo, tipMat);
rightTip.position.set(2, -0.1, 0.3);
rightTip.rotation.z = Math.PI / 2;
group.add(rightTip);
// Engine glow
const glowGeo = new THREE.ConeGeometry(0.3, 1.2, 6);
const glowMat = new THREE.MeshBasicMaterial({
color: 0xFF4400,
transparent: true,
opacity: 0.7,
});
this.engineGlow = new THREE.Mesh(glowGeo, glowMat);
this.engineGlow.rotation.x = -Math.PI / 2;
this.engineGlow.position.z = 1.8;
group.add(this.engineGlow);
// Engine light
const engineLight = new THREE.PointLight(0xFF4400, 1.5, 10);
engineLight.position.z = 2;
group.add(engineLight);
return group;
}
update(dt, input) {
const s = this.state;
// Speed increases with distance
const baseSpeed = 0.4;
const speedBoost = s.boosting ? 1.5 : 1;
const currentSpeed = baseSpeed * speedBoost;
s.speed += (currentSpeed - s.speed) * dt * 5;
// Movement forces
const lateralForce = 18;
const verticalForce = 12;
let targetVx = 0;
let targetVy = 0;
let targetRoll = 0;
let targetPitch = 0;
if (input.left) {
targetVx = -lateralForce;
targetRoll = -0.5;
}
if (input.right) {
targetVx = lateralForce;
targetRoll = 0.5;
}
if (input.up) {
targetVy = verticalForce;
targetPitch = -0.25;
}
if (input.down) {
targetVy = -verticalForce;
targetPitch = 0.25;
}
// Boost
if (input.boost && s.turbo > 0 && !s.boosting) {
s.boosting = true;
}
if (s.boosting && s.turbo > 0) {
s.turbo -= dt * 30;
if (s.turbo <= 0) {
s.turbo = 0;
s.boosting = false;
}
}
if (!input.boost) {
s.boosting = false;
}
// Physics integration
const damping = 0.92;
s.vx += (targetVx - s.vx) * dt * 8;
s.vy += (targetVy - s.vy) * dt * 8;
s.vx *= Math.pow(damping, dt * 60);
s.vy *= Math.pow(damping, dt * 60);
// Apply movement
s.x += s.vx * dt;
s.y += s.vy * dt;
s.z += s.speed * dt * 120;
// Banking / roll interpolation
s.roll += (targetRoll - s.roll) * dt * 10;
s.pitch += (targetPitch - s.pitch) * dt * 10;
// Energy decay
const decayRate = s.boosting ? 2.5 : 0.8 + (s.speed / 0.4) * 0.3;
s.energy -= dt * decayRate;
// Turbo charge from speed
if (!s.boosting) {
s.turbo = Math.min(100, s.turbo + dt * 5);
}
// Clamp
s.energy = Math.max(0, Math.min(100, s.energy));
s.turbo = Math.max(0, Math.min(100, s.turbo));
}
getSpeedRatio() {
return this.state.speed / (0.4 * 1.5);
}
getWorldPosition() {
return new THREE.Vector3(this.state.x, this.state.y, this.state.z);
}
}
exports.Player = Player;
};
// ── module: src/particles.ts ──
__mods["src/particles.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ParticleSystem = void 0;
class ParticleSystem {
constructor() {
this.velocities = [];
this.lifetimes = [];
this.index = 0;
this.MAX = 2000;
this.positions = new Float32Array(this.MAX * 3);
this.colors = new Float32Array(this.MAX * 3);
this.sizes = new Float32Array(this.MAX);
for (let i = 0; i < this.MAX; i++) {
this.velocities[i] = { x: 0, y: 0, z: 0 };
this.lifetimes[i] = 0;
}
this.geo = new THREE.BufferGeometry();
this.geo.setAttribute('position', new THREE.BufferAttribute(this.positions, 3));
this.geo.setAttribute('color', new THREE.BufferAttribute(this.colors, 3));
this.geo.setAttribute('size', new THREE.BufferAttribute(this.sizes, 1));
this.material = new THREE.PointsMaterial({
size: 0.3,
transparent: true,
opacity: 0.6,
blending: THREE.AdditiveBlending,
depthWrite: false,
sizeAttenuation: true,
vertexColors: true,
});
this.points = new THREE.Points(this.geo, this.material);
}
getMesh() {
return this.points;
}
emit(x, y, z, count, speed, color, life) {
const r = ((color >> 16) & 0xff) / 255;
const g = ((color >> 8) & 0xff) / 255;
const b = (color & 0xff) / 255;
for (let i = 0; i < count; i++) {
const idx = this.index % this.MAX;
this.positions[idx * 3] = x;
this.positions[idx * 3 + 1] = y;
this.positions[idx * 3 + 2] = z;
this.colors[idx * 3] = r;
this.colors[idx * 3 + 1] = g;
this.colors[idx * 3 + 2] = b;
this.sizes[idx] = 0.2 + Math.random() * 0.4;
this.velocities[idx] = {
x: (Math.random() - 0.5) * speed,
y: (Math.random() - 0.5) * speed,
z: (Math.random() - 0.5) * speed,
};
this.lifetimes[idx] = life * (0.5 + Math.random() * 0.5);
this.index++;
}
}
update(dt) {
for (let i = 0; i < this.MAX; i++) {
if (this.lifetimes[i] <= 0) {
this.sizes[i] = 0;
continue;
}
this.lifetimes[i] -= dt;
if (this.lifetimes[i] <= 0) {
this.sizes[i] = 0;
continue;
}
this.positions[i * 3] += this.velocities[i].x * dt;
this.positions[i * 3 + 1] += this.velocities[i].y * dt;
this.positions[i * 3 + 2] += this.velocities[i].z * dt;
this.sizes[i] *= 0.98;
}
this.geo.attributes.position.needsUpdate = true;
this.geo.attributes.color.needsUpdate = true;
this.geo.attributes.size.needsUpdate = true;
}
reset() {
this.index = 0;
for (let i = 0; i < this.MAX; i++) {
this.lifetimes[i] = 0;
this.sizes[i] = 0;
this.positions[i * 3 + 2] = -9999;
}
}
}
exports.ParticleSystem = ParticleSystem;
};
// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"unsloth/Qwen3.6-27B-MTP-GGUF-IQ4_NL","provider":"brigid","persona":"typescript","sessionId":"c9921633-58db-4161-b906-91a9a1801301","tokensIn":1679391,"tokensOut":36281,"tokensTotal":1715672,"cost":0,"turns":47,"toolCalls":55,"failedToolCalls":1,"timestamp":"2026-08-04T14:32:01.858Z"} -->