Canyon Run
ThinkingCap Qwen3.6 27B GGUF · 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 37,402 bytes · SHA-256 ed65169efdcf
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Canyon Racer</title>
<script src="https://cdn.jsdelivr.net/npm/three@0.157.0/build/three.min.js"></script>
<style>
/* ── css: game ── */
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; background: #0a0510; font-family: 'Segoe UI', 'Helvetica Neue', Arial, sans-serif; }
#game-container { width: 100%; height: 100%; position: relative; }
#game-canvas { width: 100%; height: 100%; display: block; }
/* HUD */
#hud { position: absolute; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; }
#speed-container { position: absolute; right: 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; width: 100%; height: 0%; background: linear-gradient(to top, #ff6a00, #ffaa00); border-radius: 3px; transition: height 0.1s; }
#multiplier { position: absolute; right: 50px; top: 50%; transform: translateY(-50%); font-size: 48px; font-weight: 900; color: #ffaa00; text-shadow: 0 0 20px rgba(255,170,0,0.5); opacity: 0; transition: opacity 0.3s, transform 0.1s; }
#multiplier.active { opacity: 1; }
#energy-container { position: absolute; bottom: 30px; left: 50%; transform: translateX(-50%); width: 300px; height: 8px; background: rgba(255,255,255,0.1); border-radius: 4px; }
#energy-bar { width: 100%; height: 100%; background: linear-gradient(to right, #ff3366, #ff6a00, #ffaa00); border-radius: 4px; transition: width 0.15s; }
#turbo-container { position: absolute; bottom: 50px; left: 50%; transform: translateX(-50%); width: 200px; height: 4px; background: rgba(255,255,255,0.08); border-radius: 2px; }
#turbo-bar { width: 0%; height: 100%; background: #00ffff; border-radius: 2px; box-shadow: 0 0 10px #00ffff; transition: width 0.2s; }
#score-display { position: absolute; top: 20px; left: 50%; transform: translateX(-50%); font-size: 24px; font-weight: 300; color: rgba(255,255,255,0.7); letter-spacing: 4px; }
/* Screens */
#start-screen, #game-over { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; flex-direction: column; align-items: center; justify-content: center; background: rgba(10,5,16,0.85); pointer-events: auto; }
#start-screen h1, #game-over h1 { font-size: 64px; font-weight: 900; color: #ffaa00; text-shadow: 0 0 40px rgba(255,170,0,0.4); letter-spacing: 8px; margin-bottom: 10px; }
#start-screen p { color: rgba(255,255,255,0.5); margin-bottom: 30px; font-size: 14px; letter-spacing: 2px; }
#game-over div { font-size: 20px; color: rgba(255,255,255,0.7); margin: 8px 0; letter-spacing: 2px; }
#final-score { font-size: 36px !important; color: #ffaa00 !important; font-weight: 700; }
#max-speed { color: #00ffff !important; }
button { background: none; border: 2px solid #ffaa00; color: #ffaa00; padding: 12px 40px; font-size: 18px; letter-spacing: 4px; cursor: pointer; pointer-events: auto; transition: all 0.2s; font-family: inherit; }
button:hover { background: #ffaa00; color: #0a0510; }
</style>
</head>
<body>
<div id="game-container">
<canvas id="game-canvas"></canvas>
<div id="hud">
<div id="speed-container">
<div id="speed-bar"></div>
</div>
<div id="multiplier"></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="game-over" style="display:none">
<h1>GAME OVER</h1>
<div id="final-score">0</div>
<div id="max-speed">0</div>
<button id="restart-btn">RESTART</button>
</div>
<div id="start-screen">
<h1>CANYON RACER</h1>
<p>WASD / Arrow Keys to fly • Space to boost</p>
<button id="start-btn">LAUNCH</button>
</div>
</div>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./state":"src/state.ts","./input":"src/input.ts","./player":"src/player.ts","./chunks":"src/chunks.ts","./particles":"src/particles.ts","./audio":"src/audio.ts"},"src/player.ts":{"./input":"src/input.ts","./state":"src/state.ts"},"src/chunks.ts":{"./state":"src/state.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 state_1 = require("./state");
const input_1 = require("./input");
const player_1 = require("./player");
const chunks_1 = require("./chunks");
const particles_1 = require("./particles");
const audio_1 = require("./audio");
// --- Globals ---
let renderer;
let scene;
let camera;
let player;
let chunkManager;
let particles;
let audio;
// Post-processing
let composerRT = null;
let composerRT2 = null;
let quadMesh;
let quadScene;
let quadCamera;
let thresholdShader;
let blurShader;
let compositeShader;
// Camera shake
let shakeAmount = 0;
// HUD elements
let speedBar;
let multiplierEl;
let energyBar;
let turboBar;
let scoreDisplay;
let gameOverScreen;
let startScreen;
let finalScoreEl;
let maxSpeedEl;
let clock;
let playerZ = 0;
function init() {
(0, input_1.initInput)();
const canvas = document.getElementById('game-canvas');
// Renderer
renderer = new THREE.WebGLRenderer({
canvas,
antialias: true,
alpha: false,
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setClearColor(0x0a0510, 1);
// Scene
scene = new THREE.Scene();
scene.fog = new THREE.Fog(0x1a0a20, 100, 350);
// Camera
camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.1, 600);
camera.position.set(0, 2, 8);
camera.lookAt(0, 0, -20);
// Lighting — cyber sunset
const sunLight = new THREE.DirectionalLight(0xff8844, 1.5);
sunLight.position.set(30, 40, -50);
scene.add(sunLight);
const ambient = new THREE.AmbientLight(0x221133, 0.6);
scene.add(ambient);
const hemiLight = new THREE.HemisphereLight(0xff6633, 0x110022, 0.5);
scene.add(hemiLight);
const backLight = new THREE.DirectionalLight(0x6633ff, 0.5);
backLight.position.set(-20, 10, 30);
scene.add(backLight);
// Player
player = new player_1.Player();
scene.add(player.mesh);
// Chunk system
chunkManager = new chunks_1.ChunkManager();
for (const chunk of chunkManager.chunks) {
scene.add(chunk.mesh);
}
// Particles
particles = new particles_1.ParticleSystem();
particles.init(scene);
// Audio
audio = new audio_1.AudioEngine();
// Clock
clock = new THREE.Clock();
// Post-processing quad
// Quad for potential post-processing (not used in this version)
// HUD refs
speedBar = document.getElementById('speed-bar');
multiplierEl = document.getElementById('multiplier');
energyBar = document.getElementById('energy-bar');
turboBar = document.getElementById('turbo-bar');
scoreDisplay = document.getElementById('score-display');
gameOverScreen = document.getElementById('game-over');
startScreen = document.getElementById('start-screen');
finalScoreEl = document.getElementById('final-score');
maxSpeedEl = document.getElementById('max-speed');
document.getElementById('start-btn').addEventListener('click', startGame);
document.getElementById('restart-btn').addEventListener('click', restartGame);
window.addEventListener('resize', onResize);
requestAnimationFrame(renderLoop);
}
function startGame() {
startScreen.style.display = 'none';
state_1.state.running = true;
audio.init();
}
function restartGame() {
Object.assign(state_1.state, (0, state_1.initialGameState)());
player.mesh.position.set(0, 0, 0);
player.mesh.rotation.set(0, 0, 0);
player.velocity.set(0, 0, 0);
playerZ = 0;
for (const chunk of chunkManager.chunks) {
scene.remove(chunk.mesh);
for (const child of chunk.mesh.children) {
child.geometry?.dispose();
child.material?.dispose();
}
}
chunkManager.chunks = [];
chunkManager.nextChunkZ = 0;
chunkManager = new chunks_1.ChunkManager();
for (const chunk of chunkManager.chunks) {
scene.add(chunk.mesh);
}
gameOverScreen.style.display = 'none';
state_1.state.running = true;
state_1.state.gameOver = false;
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function updateHUD() {
const speedPct = Math.min(100, (state_1.state.speed / 80) * 100);
speedBar.style.height = speedPct + '%';
if (state_1.state.nearMissTimer > 0 && state_1.state.multiplier > 1) {
multiplierEl.textContent = 'x' + state_1.state.multiplier.toFixed(1);
multiplierEl.classList.add('active');
}
else {
multiplierEl.classList.remove('active');
}
energyBar.style.width = state_1.state.energy + '%';
if (state_1.state.energy < 20) {
energyBar.style.background = '#ff3366';
}
else {
energyBar.style.background = '';
}
turboBar.style.width = state_1.state.turbo + '%';
scoreDisplay.textContent = Math.floor(state_1.state.score).toLocaleString();
}
function triggerShake(amount) {
shakeAmount = amount;
}
function triggerGameOver() {
state_1.state.gameOver = true;
state_1.state.running = false;
audio.playCrash();
triggerShake(1.5);
finalScoreEl.textContent = Math.floor(state_1.state.score).toLocaleString();
maxSpeedEl.textContent = 'Max Speed: ' + Math.floor(state_1.state.maxSpeed);
gameOverScreen.style.display = 'flex';
}
function renderLoop() {
requestAnimationFrame(renderLoop);
const dt = Math.min(clock.getDelta(), 0.05);
if (!state_1.state.running || state_1.state.gameOver) {
renderer.render(scene, camera);
return;
}
// Speed management
const baseSpeed = state_1.state.speed;
const currentSpeed = player.isBoosting ? baseSpeed * 1.8 : baseSpeed;
state_1.state.speed = Math.min(80, state_1.state.speed + dt * 0.5);
state_1.state.maxSpeed = Math.max(state_1.state.maxSpeed, state_1.state.speed);
state_1.state.difficulty = 1 + state_1.state.score / 5000;
// Move forward
playerZ += currentSpeed * dt;
// Player update
player.update(dt);
// Move chunks
for (const chunk of chunkManager.chunks) {
chunk.mesh.position.z = chunk.z - playerZ;
}
// Chunk management
chunkManager.update(playerZ);
// Collision
if (chunkManager.checkCollision(player.mesh.position, 1.5)) {
triggerGameOver();
return;
}
// Near-miss scoring
const closestDist = chunkManager.checkNearMiss(player.mesh.position);
if (closestDist < 7 && closestDist > 3) {
if (state_1.state.nearMissTimer <= 0)
audio.playNearMiss();
state_1.state.multiplier = Math.min(10, state_1.state.multiplier + dt * 4);
state_1.state.nearMissTimer = 2;
triggerShake(0.12);
}
else {
state_1.state.multiplier = Math.max(1, state_1.state.multiplier - dt * 1.5);
state_1.state.nearMissTimer = Math.max(0, state_1.state.nearMissTimer - dt);
}
// Orb collection
if (chunkManager.checkOrbCollection(player.mesh.position)) {
audio.playCollect();
}
// Score
state_1.state.score += currentSpeed * state_1.state.multiplier * dt;
// Energy decay
state_1.state.energy -= dt * 3;
if (state_1.state.energy <= 0) {
state_1.state.energy = 0;
triggerGameOver();
return;
}
// Turbo regen
if (Math.abs(player.yaw) < 0.3 && Math.abs(player.pitch) < 0.3) {
state_1.state.turbo = Math.min(100, state_1.state.turbo + dt * 5);
}
// Particles
particles.addTrailPoint(player.mesh.position.x, player.mesh.position.y, player.mesh.position.z);
particles.update(currentSpeed, dt);
// Camera
const targetFov = player.isBoosting ? 95 : 70;
camera.fov += (targetFov - camera.fov) * dt * 3;
camera.updateProjectionMatrix();
const camTargetX = player.mesh.position.x * 0.35;
const camTargetY = player.mesh.position.y * 0.35 + 2;
camera.position.x += (camTargetX - camera.position.x) * dt * 4;
camera.position.y += (camTargetY - camera.position.y) * dt * 4;
camera.position.z = playerZ - (player.isBoosting ? 12 : 8);
// Camera shake
if (shakeAmount > 0.01) {
camera.position.x += (Math.random() - 0.5) * shakeAmount;
camera.position.y += (Math.random() - 0.5) * shakeAmount;
shakeAmount *= 0.88;
}
camera.lookAt(player.mesh.position.x * 0.5, player.mesh.position.y * 0.3, playerZ - 40);
// Engine audio
audio.updateEngine(state_1.state.speed, player.isBoosting);
// HUD
updateHUD();
// Render
renderer.render(scene, camera);
}
init();
};
// ── types: globals.d.ts ──
__mods["globals.d.ts"] = function (exports) {};
// ── module: src/state.ts ──
__mods["src/state.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.state = exports.initialGameState = void 0;
const initialGameState = () => ({
score: 0,
multiplier: 1,
energy: 100,
turbo: 0,
speed: 30,
maxSpeed: 30,
running: false,
gameOver: false,
difficulty: 1,
nearMissTimer: 0,
});
exports.initialGameState = initialGameState;
exports.state = (0, exports.initialGameState)();
};
// ── module: src/input.ts ──
__mods["src/input.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.keys = void 0;
exports.initInput = initInput;
exports.isKey = isKey;
// Input manager — keyboard state
exports.keys = {};
function initInput() {
window.addEventListener('keydown', (e) => {
exports.keys[e.code] = true;
if (['Space', 'ArrowUp', 'ArrowDown', 'ArrowLeft', 'ArrowRight'].includes(e.code)) {
e.preventDefault();
}
});
window.addEventListener('keyup', (e) => {
exports.keys[e.code] = false;
});
}
function isKey(code) {
return !!exports.keys[code];
}
};
// ── module: src/player.ts ──
__mods["src/player.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Player = void 0;
const input_1 = require("./input");
const state_1 = require("./state");
class Player {
constructor() {
this.velocity = new THREE.Vector3(0, 0, 0);
this.pitch = 0;
this.roll = 0;
this.yaw = 0;
this.targetPitch = 0;
this.targetRoll = 0;
this.targetYaw = 0;
this.isBoosting = false;
this.mesh = new THREE.Group();
this.buildCraft();
}
buildCraft() {
// Main body — sleek wedge
const bodyMat = new THREE.MeshPhongMaterial({
color: 0xcccccc,
flatShading: true,
emissive: 0x333333,
emissiveIntensity: 0.3,
});
const bodyGeo = new THREE.ConeGeometry(0.6, 2.5, 4);
const body = new THREE.Mesh(bodyGeo, bodyMat);
body.rotation.x = Math.PI / 2;
body.position.z = 0.3;
this.mesh.add(body);
// Cockpit
const cockpitGeo = new THREE.ConeGeometry(0.3, 1.2, 4);
const cockpitMat = new THREE.MeshPhongMaterial({
color: 0x00ffff,
flatShading: true,
emissive: 0x00ffff,
emissiveIntensity: 0.8,
});
const cockpit = new THREE.Mesh(cockpitGeo, cockpitMat);
cockpit.rotation.x = -Math.PI / 2;
cockpit.position.z = 0.5;
cockpit.position.y = 0.15;
this.mesh.add(cockpit);
// Wings
const wingGeo = new THREE.BoxGeometry(4, 0.08, 1.2);
const wingMat = new THREE.MeshPhongMaterial({
color: 0xaaaaaa,
flatShading: true,
});
const wings = new THREE.Mesh(wingGeo, wingMat);
wings.position.z = 0.2;
this.mesh.add(wings);
// Wing tips (accent)
const tipGeo = new THREE.BoxGeometry(0.3, 0.15, 0.8);
const tipMat = new THREE.MeshPhongMaterial({
color: 0xff6a00,
flatShading: true,
emissive: 0xff6a00,
emissiveIntensity: 0.5,
});
const leftTip = new THREE.Mesh(tipGeo, tipMat);
leftTip.position.set(-2.1, 0, 0.2);
this.mesh.add(leftTip);
const rightTip = new THREE.Mesh(tipGeo, tipMat);
rightTip.position.set(2.1, 0, 0.2);
this.mesh.add(rightTip);
// Engine glow
const engineGeo = new THREE.CylinderGeometry(0.2, 0.4, 0.6, 8);
const engineMat = new THREE.MeshPhongMaterial({
color: 0xff4400,
flatShading: true,
emissive: 0xff4400,
emissiveIntensity: 2,
});
const engine = new THREE.Mesh(engineGeo, engineMat);
engine.rotation.x = Math.PI / 2;
engine.position.z = 1.6;
engine.userData.isEngine = true;
this.mesh.add(engine);
}
update(dt) {
const accel = 15;
const turnSpeed = 3.5;
// Pitch control (up/down)
this.targetPitch = 0;
if ((0, input_1.isKey)('ArrowUp') || (0, input_1.isKey)('KeyW'))
this.targetPitch = -turnSpeed;
if ((0, input_1.isKey)('ArrowDown') || (0, input_1.isKey)('KeyS'))
this.targetPitch = turnSpeed;
// Yaw control (left/right)
this.targetYaw = 0;
if ((0, input_1.isKey)('ArrowLeft') || (0, input_1.isKey)('KeyA'))
this.targetYaw = turnSpeed;
if ((0, input_1.isKey)('ArrowRight') || (0, input_1.isKey)('KeyD'))
this.targetYaw = -turnSpeed;
// Roll follows yaw
this.targetRoll = -this.targetYaw * 0.6;
// Boost
this.isBoosting = (0, input_1.isKey)('Space') && state_1.state.turbo > 0;
if (this.isBoosting) {
state_1.state.turbo = Math.max(0, state_1.state.turbo - 30 * dt);
}
// Smooth interpolation for banking
const lerpFactor = Math.min(dt * 8, 1);
this.pitch += (this.targetPitch - this.pitch) * lerpFactor;
this.roll += (this.targetRoll - this.roll) * lerpFactor;
this.yaw += (this.targetYaw - this.yaw) * lerpFactor;
// Apply rotation to mesh
this.mesh.rotation.x = this.pitch * 0.7;
this.mesh.rotation.z = this.roll;
this.mesh.rotation.y = this.yaw * 0.3;
// Move position based on pitch/yaw inputs
const moveSpeed = 25 * state_1.state.difficulty;
this.velocity.x += this.yaw * dt * moveSpeed;
this.velocity.y += this.pitch * dt * moveSpeed;
// Damping
this.velocity.x *= Math.pow(0.95, dt * 60);
this.velocity.y *= Math.pow(0.95, dt * 60);
this.mesh.position.x += this.velocity.x * dt;
this.mesh.position.y += this.velocity.y * dt;
// Clamp position
this.mesh.position.x = Math.max(-35, Math.min(35, this.mesh.position.x));
this.mesh.position.y = Math.max(-25, Math.min(25, this.mesh.position.y));
// Engine glow intensity based on speed
const engineMesh = this.mesh.children.find((c) => c.userData?.isEngine);
if (engineMesh) {
const intensity = this.isBoosting ? 4 : (state_1.state.speed / 50);
engineMesh.material.emissiveIntensity = intensity;
if (this.isBoosting) {
engineMesh.scale.set(1.2, 1.2, 1.5);
}
else {
engineMesh.scale.set(1, 1, 1);
}
}
}
}
exports.Player = Player;
};
// ── module: src/chunks.ts ──
__mods["src/chunks.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ChunkManager = void 0;
const state_1 = require("./state");
const CHUNK_LENGTH = 200;
const CHUNK_COUNT = 8;
const ORB_COUNT_PER_CHUNK = 5;
const WALL_COLORS = [0x6b3510, 0x7b4523, 0x5b2510, 0x8b5030, 0x704020];
const MONOLITH_COLORS = [0x4a2060, 0x3a1550, 0x5a3070, 0x2a1040, 0x552266];
const ACCENT_COLORS = [0xff4400, 0xff8800, 0xcc2200, 0xff6600];
class ChunkManager {
constructor() {
this.chunks = [];
this.nextChunkZ = 0;
for (let i = 0; i < CHUNK_COUNT; i++) {
this.addChunk(this.nextChunkZ);
this.nextChunkZ += CHUNK_LENGTH;
}
}
addChunk(z) {
const difficulty = state_1.state.difficulty;
const baseWidth = Math.max(10, 38 - difficulty * 3);
const chunk = new THREE.Group();
const variation = Math.sin(z * 0.01) * 5;
const leftWallX = -(baseWidth + 4 + variation);
const rightWallX = baseWidth + 4 - variation;
// Main canyon walls — multi-segment for visual depth
const segments = 4;
for (let s = 0; s < segments; s++) {
const segZ = (s - segments / 2) * (CHUNK_LENGTH / segments);
const segW = 6 + Math.random() * 6;
const wallH = 35 + Math.random() * 25;
// Left wall
const lGeo = new THREE.BoxGeometry(segW, wallH, CHUNK_LENGTH / segments + 1);
const lMat = new THREE.MeshPhongMaterial({
color: WALL_COLORS[Math.floor(Math.random() * WALL_COLORS.length)],
flatShading: true,
});
const lWall = new THREE.Mesh(lGeo, lMat);
lWall.position.set(leftWallX + Math.sin(s * 1.5) * 3, wallH / 2 - 8, segZ);
chunk.add(lWall);
// Right wall
const rGeo = new THREE.BoxGeometry(segW, wallH, CHUNK_LENGTH / segments + 1);
const rMat = new THREE.MeshPhongMaterial({
color: WALL_COLORS[Math.floor(Math.random() * WALL_COLORS.length)],
flatShading: true,
});
const rWall = new THREE.Mesh(rGeo, rMat);
rWall.position.set(rightWallX + Math.cos(s * 1.5) * 3, wallH / 2 - 8, segZ);
chunk.add(rWall);
// Wall accent strips (glowing edges)
const stripGeo = new THREE.BoxGeometry(0.3, wallH * 0.6, 1);
const stripMat = new THREE.MeshPhongMaterial({
color: ACCENT_COLORS[Math.floor(Math.random() * ACCENT_COLORS.length)],
flatShading: true,
emissive: 0xff4400,
emissiveIntensity: 0.4,
});
const stripL = new THREE.Mesh(stripGeo, stripMat);
stripL.position.set(leftWallX + segW / 2, wallH / 2 - 8, segZ);
chunk.add(stripL);
const stripR = new THREE.Mesh(stripGeo, stripMat);
stripR.position.set(rightWallX - segW / 2, wallH / 2 - 8, segZ);
chunk.add(stripR);
}
// Ground
const groundGeo = new THREE.PlaneGeometry(baseWidth * 2 + 30, CHUNK_LENGTH + 2);
const groundMat = new THREE.MeshPhongMaterial({
color: 0x1a0a15,
flatShading: true,
});
const ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2;
ground.position.y = -25;
chunk.add(ground);
// Ceiling
const ceilGeo = new THREE.PlaneGeometry(baseWidth * 2 + 30, CHUNK_LENGTH + 2);
const ceilMat = new THREE.MeshPhongMaterial({
color: 0x120520,
flatShading: true,
});
const ceil = new THREE.Mesh(ceilGeo, ceilMat);
ceil.rotation.x = Math.PI / 2;
ceil.position.y = 25;
chunk.add(ceil);
// Floating monoliths
const monolithCount = Math.floor(2 + difficulty * 1.5);
for (let i = 0; i < monolithCount; i++) {
const h = 5 + Math.random() * 12;
const w = 1 + Math.random() * 2.5;
const d = 1 + Math.random() * 2.5;
const mGeo = new THREE.BoxGeometry(w, h, d);
const mMat = new THREE.MeshPhongMaterial({
color: MONOLITH_COLORS[Math.floor(Math.random() * MONOLITH_COLORS.length)],
flatShading: true,
emissive: 0x220044,
emissiveIntensity: 0.3,
});
const monolith = new THREE.Mesh(mGeo, mMat);
monolith.position.set((Math.random() - 0.5) * (baseWidth * 1.2), (Math.random() - 0.5) * 16, (Math.random() - 0.5) * (CHUNK_LENGTH - 30));
monolith.rotation.y = Math.random() * Math.PI;
chunk.add(monolith);
}
// Tight squeezes
if (difficulty > 1.3 && Math.random() > 0.4) {
const squeezeZ = (Math.random() - 0.5) * (CHUNK_LENGTH - 40);
const gapX = (Math.random() - 0.5) * baseWidth * 0.5;
const gapY = (Math.random() - 0.5) * 10;
const gapSize = Math.max(3.5, 8 - difficulty * 0.5);
const sqGeo = new THREE.BoxGeometry(baseWidth + 10, 50, 2);
const sqMat = new THREE.MeshPhongMaterial({
color: 0x3a1030,
flatShading: true,
});
const topW = new THREE.Mesh(sqGeo, sqMat);
topW.position.set(gapX, gapY + gapSize / 2 + 2.5, squeezeZ);
chunk.add(topW);
const botW = new THREE.Mesh(sqGeo, sqMat);
botW.position.set(gapX, gapY - gapSize / 2 - 2.5, squeezeZ);
chunk.add(botW);
}
chunk.position.z = -z;
// Energy orbs
const orbs = [];
const orbGeo = new THREE.SphereGeometry(0.5, 6, 6);
for (let i = 0; i < ORB_COUNT_PER_CHUNK; i++) {
const orbMat = new THREE.MeshPhongMaterial({
color: 0xffcc00,
flatShading: true,
emissive: 0xffaa00,
emissiveIntensity: 2.5,
});
const orb = new THREE.Mesh(orbGeo, orbMat);
orb.position.set((Math.random() - 0.5) * baseWidth * 1.2, (Math.random() - 0.5) * 16, (Math.random() - 0.5) * (CHUNK_LENGTH - 30));
chunk.add(orb);
orbs.push({ mesh: orb, collected: false });
}
this.chunks.push({ mesh: chunk, z, orbs, width: baseWidth });
}
update(playerZ) {
while (this.chunks.length > 0 && this.chunks[0].z < playerZ - CHUNK_LENGTH * 2) {
const oldChunk = this.chunks.shift();
for (const child of oldChunk.mesh.children) {
child.geometry?.dispose();
child.material?.dispose();
}
}
const lastChunk = this.chunks[this.chunks.length - 1];
if (lastChunk && this.chunks.length < CHUNK_COUNT) {
this.addChunk(lastChunk.z + CHUNK_LENGTH);
}
}
checkOrbCollection(playerPos) {
let collected = false;
for (const chunk of this.chunks) {
for (const orb of chunk.orbs) {
if (orb.collected)
continue;
const orbWorldPos = new THREE.Vector3(orb.mesh.position.x, orb.mesh.position.y, -chunk.z + orb.mesh.position.z);
if (playerPos.distanceTo(orbWorldPos) < 3) {
orb.collected = true;
orb.mesh.visible = false;
collected = true;
state_1.state.energy = Math.min(100, state_1.state.energy + 15);
state_1.state.turbo = Math.min(100, state_1.state.turbo + 20);
}
}
}
return collected;
}
checkCollision(playerPos, playerRadius) {
for (const chunk of this.chunks) {
const chunkLocalZ = playerPos.z + chunk.z;
if (chunkLocalZ < -CHUNK_LENGTH / 2 || chunkLocalZ > CHUNK_LENGTH / 2)
continue;
const hw = chunk.width;
if (Math.abs(playerPos.x) > hw - playerRadius)
return true;
if (Math.abs(playerPos.y) > 24 - playerRadius)
return true;
for (const child of chunk.mesh.children) {
const mc = child;
if (!mc.geometry)
continue;
if (!(mc.geometry instanceof THREE.BoxGeometry))
continue;
const wpos = new THREE.Vector3(mc.position.x, mc.position.y, -chunk.z + mc.position.z);
const dx = Math.abs(playerPos.x - wpos.x);
const dy = Math.abs(playerPos.y - wpos.y);
const dz = Math.abs(playerPos.z - wpos.z);
if (dx < 2 && dy < 4 && dz < 1.5)
return true;
}
}
return false;
}
checkNearMiss(playerPos) {
let closest = 999;
for (const chunk of this.chunks) {
const chunkLocalZ = playerPos.z + chunk.z;
if (chunkLocalZ < -CHUNK_LENGTH / 2 || chunkLocalZ > CHUNK_LENGTH / 2)
continue;
const wallDist = chunk.width - Math.abs(playerPos.x);
const ceilDist = 25 - Math.abs(playerPos.y);
closest = Math.min(closest, wallDist, ceilDist);
}
return closest;
}
}
exports.ChunkManager = ChunkManager;
};
// ── 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.trailParticles = null;
this.debrisParticles = null;
this.trailHead = 0;
this.trailCapacity = 500;
this.trailPositions = new Float32Array(this.trailCapacity * 3);
this.debrisPositions = new Float32Array(200 * 3);
this.debrisVelocities = new Array(200 * 3).fill(0);
this.initDebris();
}
initDebris() {
for (let i = 0; i < 200; i++) {
this.debrisPositions[i * 3] = (Math.random() - 0.5) * 80;
this.debrisPositions[i * 3 + 1] = (Math.random() - 0.5) * 50;
this.debrisPositions[i * 3 + 2] = -Math.random() * 300;
}
}
init(scene) {
// Trail
const trailGeo = new THREE.BufferGeometry();
trailGeo.setAttribute('position', new THREE.BufferAttribute(this.trailPositions, 3));
const trailMat = new THREE.PointsMaterial({
color: 0xff6a00,
size: 0.4,
transparent: true,
opacity: 0.6,
blending: 1, // AdditiveBlending
depthWrite: false,
});
this.trailParticles = new THREE.Points(trailGeo, trailMat);
scene.add(this.trailParticles);
// Debris
const debrisGeo = new THREE.BufferGeometry();
debrisGeo.setAttribute('position', new THREE.BufferAttribute(this.debrisPositions, 3));
const debrisMat = new THREE.PointsMaterial({
color: 0xffaa44,
size: 0.2,
transparent: true,
opacity: 0.3,
depthWrite: false,
});
this.debrisParticles = new THREE.Points(debrisGeo, debrisMat);
scene.add(this.debrisParticles);
}
addTrailPoint(x, y, z) {
const idx = this.trailHead * 3;
this.trailPositions[idx] = x;
this.trailPositions[idx + 1] = y;
this.trailPositions[idx + 2] = z;
this.trailHead = (this.trailHead + 1) % this.trailCapacity;
}
update(speed, dt) {
if (this.debrisParticles) {
const pos = this.debrisParticles.geometry.attributes.position.array;
for (let i = 0; i < 200; i++) {
pos[i * 3] += this.debrisVelocities[i * 3] * dt;
pos[i * 3 + 1] += this.debrisVelocities[i * 3 + 1] * dt;
pos[i * 3 + 2] += (speed * 2 + this.debrisVelocities[i * 3 + 2]) * dt;
if (pos[i * 3 + 2] > 20) {
pos[i * 3] = (Math.random() - 0.5) * 80;
pos[i * 3 + 1] = (Math.random() - 0.5) * 50;
pos[i * 3 + 2] = -300;
}
}
this.debrisParticles.geometry.attributes.position.needsUpdate = true;
}
}
dispose() {
this.trailParticles?.geometry.dispose();
this.trailParticles?.material?.dispose();
this.debrisParticles?.geometry.dispose();
this.debrisParticles?.material?.dispose();
}
}
exports.ParticleSystem = ParticleSystem;
};
// ── module: src/audio.ts ──
__mods["src/audio.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AudioEngine = void 0;
class AudioEngine {
constructor() {
this.ctx = null;
this.masterGain = null;
this.engineOsc = null;
this.engineGain = null;
this.initialized = false;
}
init() {
this.ctx = new (window.AudioContext || window.webkitAudioContext)();
this.masterGain = this.ctx.createGain();
this.masterGain.gain.value = 0.3;
this.masterGain.connect(this.ctx.destination);
// Engine drone
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.initialized = true;
}
updateEngine(speed, boosting) {
if (!this.initialized || !this.engineOsc)
return;
const freq = 50 + speed * 2 + (boosting ? 40 : 0);
this.engineOsc.frequency.setTargetAtTime(freq, this.ctx.currentTime, 0.1);
const vol = 0.08 + (boosting ? 0.06 : 0);
this.engineGain.gain.setTargetAtTime(vol, this.ctx.currentTime, 0.1);
}
playCollect() {
if (!this.initialized || !this.ctx)
return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sine';
osc.frequency.value = 880;
osc.frequency.exponentialRampToValueAtTime(1760, this.ctx.currentTime + 0.1);
gain.gain.value = 0.15;
gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.2);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start();
osc.stop(this.ctx.currentTime + 0.2);
}
playNearMiss() {
if (!this.initialized || !this.ctx)
return;
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'triangle';
osc.frequency.value = 200;
osc.frequency.exponentialRampToValueAtTime(800, this.ctx.currentTime + 0.15);
gain.gain.value = 0.12;
gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.3);
osc.connect(gain);
gain.connect(this.masterGain);
osc.start();
osc.stop(this.ctx.currentTime + 0.3);
}
playCrash() {
if (!this.initialized || !this.ctx)
return;
// Noise burst for crash
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.exp(-i / (bufferSize * 0.1));
}
const noise = this.ctx.createBufferSource();
noise.buffer = buffer;
const gain = this.ctx.createGain();
gain.gain.value = 0.3;
gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.5);
noise.connect(gain);
gain.connect(this.masterGain);
noise.start();
// Low thud
const osc = this.ctx.createOscillator();
const g2 = this.ctx.createGain();
osc.type = 'sine';
osc.frequency.value = 80;
osc.frequency.exponentialRampToValueAtTime(20, this.ctx.currentTime + 0.5);
g2.gain.value = 0.2;
g2.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + 0.5);
osc.connect(g2);
g2.connect(this.masterGain);
osc.start();
osc.stop(this.ctx.currentTime + 0.5);
}
}
exports.AudioEngine = AudioEngine;
};
// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"ThinkingCap-Qwen3.6-27B-GGUF","provider":"brigid","persona":"typescript","sessionId":"b85c5838-0fcf-41af-8e73-9d485ed53eca","tokensIn":802252,"tokensOut":24967,"tokensTotal":827219,"cost":0,"turns":39,"toolCalls":45,"failedToolCalls":6,"timestamp":"2026-08-03T20:14:19.443Z"} -->