Rally
Gemma 4 12b · 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 18,467 bytes · SHA-256 438cdf511991
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Rally Pro 3D</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/0.160.0/three.min.js"></script>
<style>
/* ── css: layout ── */
#game-canvas {
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
z-index: -1;
}
#ui-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
color: white;
user-select: none;
}
#hud {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.6);
padding: 15px 30px;
border-radius: 50px;
display: flex;
gap: 40px;
align-items: center;
border: 2px solid rgba(255, 255, 255, 0.3);
}
#hud .speedometer {
font-size: 2rem;
font-weight: bold;
}
#hud .stats {
display: flex;
gap: 15px;
font-size: 1.2rem;
}
#minimap-container {
position: absolute;
top: 20px;
right: 20px;
background: rgba(0, 0, 0, 0.5);
padding: 10px;
border-radius: 10px;
border: 2px solid white;
}
#minimap {
width: 150px;
height: 150px;
background: #333;
}
#overlay, #pause-menu, #finish-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0, 0, 0, 0.7);
}
#overlay.hidden { display: none; }
#pause-menu.hidden { display: none; }
#finish-screen.hidden { display: none; }
button {
padding: 15px 40px;
font-size: 1.5rem;
background: #e74c3c;
color: white;
border: none;
border-radius: 10px;
cursor: pointer;
}
button:hover { background: #c0392b; }
#overlay h1 { font-size: 5rem; }
</style>
</head>
<body>
<div id="ui-layer">
<div id="hud">
<div class="speedometer">
<span id="speed-val">0</span> <span class="unit">KM/H</span>
</div>
<div class="stats">
<div>LAP <span id="lap-current">1</span> / 3</div>
<div>TIME <span id="timer">0.00</span></div>
<div>BEST <span id="best-lap">-</span></div>
</div>
</div>
<div id="minimap-container">
<canvas id="minimap"></canvas>
</div>
<div id="overlay" class="hidden">
<h1 id="overlay-text">READY?</h1>
</div>
<div id="pause-menu" class="hidden">
<h2>PAUSED</h2>
<button id="btn-resume">RESUME</button>
<button id="btn-restart">RESTART</button>
</div>
<div id="finish-screen" class="hidden">
<h1>RACE FINISHED!</h1>
<p>Final Time: <span id="final-time">-</span></p>
<p>Best Lap: <span id="best-lap-final">-</span></p>
<button id="btn-next-race">NEXT RACE</button>
</div>
</div>
<canvas id="game-canvas"></canvas>
<script>
(function () {
'use strict';
var __mods = {};
var __cache = {};
var __map = {"src/main.ts":{"./physics":"src/physics.ts","./audio":"src/audio.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 physics_1 = require("./physics");
const audio_1 = require("./audio");
class Game {
constructor() {
this.trackPoints = [];
this.checkpoints = [];
this.currentLap = 1;
this.totalLaps = 3;
this.lastCheckpointIndex = -1;
this.bestLap = Infinity;
this.timer = 0;
this.isPaused = false;
this.isStarted = false;
this.countdown = 3;
this.inputState = {};
this.cameraMode = 'chase';
const THREE = window.THREE;
this.scene = new THREE.Scene();
const skyColor = new THREE.Color(0x87ceeb);
this.scene.background = skyColor;
this.scene.fog = new THREE.Fog(skyColor, 20, 150);
this.camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
const canvas = document.getElementById('game-canvas');
this.renderer = new THREE.WebGLRenderer({ canvas: canvas });
this.renderer.setSize(window.innerWidth, window.innerHeight);
this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
this.audio = new audio_1.AudioEngine();
// Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
this.scene.add(ambientLight);
const sun = new THREE.PointLight(0xffffff, 1.5);
sun.position.set(50, 50, 50);
this.scene.add(sun);
// Ground & Environment
this.createEnvironment();
this.createTrack();
// Car
this.physics = new physics_1.CarPhysics(new THREE.Vector3(0, 0, 0), new THREE.Vector3(0, 0, 1));
this.carModel = this.createCarModel();
this.scene.add(this.carModel);
// Controls
this.initInputs();
// UI
this.updateUI();
this.setupGameLoop();
}
createEnvironment() {
const THREE = window.THREE;
const groundGeo = new THREE.PlaneGeometry(2000, 2000);
const groundMat = new THREE.MeshStandardMaterial({ color: 0x3a5f0b });
const ground = new THREE.Mesh(groundGeo, groundMat);
ground.rotation.x = -Math.PI / 2;
this.scene.add(ground);
for (let i = 0; i < 100; i++) {
const tree = new THREE.Group();
const trunk = new THREE.Mesh(new THREE.CylinderGeometry(0.5, 0.7, 4), new THREE.MeshStandardMaterial({ color: 0x4b3621 }));
trunk.position.y = 2;
const leaves = new THREE.Mesh(new THREE.SphereGeometry(2, 8, 8), new THREE.MeshStandardMaterial({ color: 0x0a5d00 }));
leaves.position.y = 4;
tree.add(trunk);
tree.add(leaves);
tree.position.set(Math.random() * 400 - 200, 0, Math.random() * 400 - 200);
if (Math.abs(tree.position.x) > 50 || Math.abs(tree.position.z) > 50) {
this.scene.add(tree);
}
}
}
createTrack() {
const THREE = window.THREE;
const pts = [
new THREE.Vector3(0, 0, 0),
new THREE.Vector3(100, 20, 50),
new THREE.Vector3(150, 40, 150),
new THREE.Vector3(50, 30, 200),
new THREE.Vector3(-50, 20, 150),
new THREE.Vector3(-100, 10, 50),
new THREE.Vector3(-50, 0, -50),
new THREE.Vector3(0, 0, 0)
];
this.trackPoints = pts;
const curve = new THREE.CatmullRomCurve3(pts);
const geometry = new THREE.TubeGeometry(curve, 64, 8, 8, false);
const material = new THREE.MeshStandardMaterial({ color: 0x333333 });
const road = new THREE.Mesh(geometry, material);
road.position.y = 2;
this.scene.add(road);
for (let i = 0; i < pts.length - 1; i++) {
const cp = new THREE.Vector3().lerpVectors(pts[i], pts[i + 1], 0.5);
this.checkpoints.push({ pos: cp, id: i });
}
}
createCarModel() {
const THREE = window.THREE;
const car = new THREE.Group();
const body = new THREE.Mesh(new THREE.BoxGeometry(2, 1, 4), new THREE.MeshStandardMaterial({ color: 0xff0000 }));
body.position.y = 0.6;
car.add(body);
const cabin = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.8, 2), new THREE.MeshStandardMaterial({ color: 0x333333 }));
cabin.position.y = 1.4;
cabin.position.z = -0.2;
car.add(cabin);
const spoiler = new THREE.Mesh(new THREE.BoxGeometry(2, 0.2, 0.5), new THREE.MeshStandardMaterial({ color: 0x111111 }));
spoiler.position.set(0, 1.4, 1.8);
car.add(spoiler);
const wheelGeo = new THREE.CylinderGeometry(0.5, 0.5, 0.4, 8);
const wheelMat = new THREE.MeshStandardMaterial({ color: 0x111111 });
const wheels = [];
const positions = [
[1, 0.5, 1.2], [-1, 0.5, 1.2],
[1, 0.5, -1.2], [-1, 0.5, -1.2]
];
positions.forEach(p => {
const w = new THREE.Mesh(wheelGeo, wheelMat);
w.rotation.z = Math.PI / 2;
w.position.set(p[0], p[1], p[2]);
car.add(w);
wheels.push(w);
});
return car;
}
initInputs() {
window.addEventListener('keydown', (e) => {
this.inputState[e.code] = true;
if (e.code === 'KeyR')
this.restart();
if (e.code === 'KeyP')
this.togglePause();
if (e.code === 'KeyC')
this.toggleCamera();
});
window.addEventListener('keyup', (e) => {
this.inputState[e.code] = false;
});
}
togglePause() {
this.isPaused = !this.isPaused;
const pm = document.getElementById('pause-menu');
if (pm)
pm.classList.toggle('hidden', !this.isPaused);
}
toggleCamera() {
this.cameraMode = this.cameraMode === 'chase' ? 'cinematic' : 'chase';
}
setupGameLoop() {
const loop = () => {
if (!this.isPaused) {
this.update();
}
this.renderer.render(this.scene, this.camera);
requestAnimationFrame(loop);
};
requestAnimationFrame(loop);
}
update() {
const THREE = window.THREE;
if (!this.isStarted) {
this.countdown--;
const overlayText = document.getElementById('overlay-text');
if (overlayText) {
overlayText.innerText = this.countdown > 0 ? this.countdown.toString() : "GO!";
}
if (this.countdown <= 0) {
this.isStarted = true;
const overlay = document.getElementById('overlay');
if (overlay)
overlay.classList.add('hidden');
this.audio.playBeep();
}
return;
}
const input = {
gas: this.inputState['ArrowUp'] || this.inputState['KeyW'] ? 1 : 0,
brake: this.inputState['ArrowDown'] || this.inputState['KeyS'] ? 1 : 0,
steer: this.inputState['ArrowLeft'] ? -1 : (this.inputState['ArrowRight'] || this.inputState['KeyD'] ? 1 : 0)
};
const grip = 1.0;
this.physics.update(input, grip);
this.carModel.position.copy(this.physics.position);
this.carModel.rotation.y = this.physics.rotation;
this.carModel.rotation.z = -input.steer * (Math.min(this.physics.speed, 100) / 100) * 0.5;
const camOffset = new THREE.Vector3(0, 5, -12);
camOffset.applyAxisAngle(new THREE.Vector3(0, 1, 0), this.physics.rotation);
const targetCamPos = new THREE.Vector3();
targetCamPos.copy(this.carModel.position);
targetCamPos.add(camOffset);
const currentPos = this.camera.position;
this.camera.position.x = currentPos.x + (targetCamPos.x - currentPos.x) * 0.1;
this.camera.position.y = currentPos.y + (targetCamPos.y - currentPos.y) * 0.1;
this.camera.position.z = currentPos.z + (targetCamPos.z - currentPos.z) * 0.1;
this.camera.lookAt(this.carModel.position);
this.timer += 1 / 60;
this.checkpoints.forEach((cp, idx) => {
if (this.physics.position.distanceTo(cp.pos) < 25) {
if (idx === this.lastCheckpointIndex + 1) {
this.lastCheckpointIndex = idx;
if (idx === this.checkpoints.length - 1) {
this.completeLap();
}
}
}
});
this.audio.playEngine(this.physics.speed);
this.updateUI();
}
completeLap() {
if (this.currentLap < this.totalLaps) {
this.currentLap++;
this.lastCheckpointIndex = -1;
if (this.timer < this.bestLap)
this.bestLap = this.timer;
}
else {
this.endRace();
}
}
endRace() {
const fs = document.getElementById('finish-screen');
if (fs)
fs.classList.remove('hidden');
const ft = document.getElementById('final-time');
if (ft)
ft.innerText = this.timer.toFixed(2);
const blf = document.getElementById('best-lap-final');
if (blf)
blf.innerText = this.bestLap === Infinity ? "-" : this.bestLap.toFixed(2);
}
updateUI() {
const speedEl = document.getElementById('speed-val');
if (speedEl)
speedEl.innerText = Math.floor(this.physics.speed * 2.5).toString();
const lapEl = document.getElementById('lap-current');
if (lapEl)
lapEl.innerText = this.currentLap.toString();
const timerEl = document.getElementById('timer');
if (timerEl)
timerEl.innerText = this.timer.toFixed(2);
const bestEl = document.getElementById('best-lap');
if (bestEl)
bestEl.innerText = this.bestLap === Infinity ? "-" : this.bestLap.toFixed(2);
}
restart() {
location.reload();
}
}
new Game();
};
// ── types: src/globals.d.ts ──
__mods["src/globals.d.ts"] = function (exports) {};
// ── 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.engineObj = null;
this.ctx = new window.AudioContext || new window.webkitAudioContext();
}
// Simple synth for engine sound
createOscillator(freq, volume) {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sawtooth';
osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
gain.gain.setValueAtTime(volume, this.ctx.currentTime);
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.start();
return { osc, gain };
}
playEngine(speed) {
if (!this.engineObj) {
this.engineObj = this.createOscillator(100, 0.1);
}
const freq = 100 + speed * 2;
this.engineObj.osc.frequency.setTargetAtTime(freq, this.ctx.currentTime, 0.1);
}
playBeep() {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'sine';
osc.frequency.setValueAtTime(880, this.ctx.currentTime);
gain.gain.setValueAtTime(0.1, this.ctx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, this.ctx.currentTime + 0.5);
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.start();
osc.stop(this.ctx.currentTime + 0.5);
}
playCrash() {
const osc = this.ctx.createOscillator();
const gain = this.ctx.createGain();
osc.type = 'square';
osc.frequency.setValueAtTime(150, this.ctx.currentTime);
osc.frequency.exponentialRampToValueAtTime(40, this.ctx.currentTime + 0.3);
gain.gain.setValueAtTime(0.2, this.ctx.currentTime);
gain.gain.linearRampToValueAtTime(0, this.ctx.currentTime + 0.3);
osc.connect(gain);
gain.connect(this.ctx.destination);
osc.start();
osc.stop(this.ctx.currentTime + 0.3);
}
}
exports.AudioEngine = AudioEngine;
};
// ── module: src/physics.ts ──
__mods["src/physics.ts"] = function (exports, require, module) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.CarPhysics = void 0;
class CarPhysics {
constructor(position, direction) {
this.position = position;
this.direction = direction;
this.speed = 0;
this.acceleration = 0;
this.steering = 0;
this.drift = 0;
this.rotation = 0;
this.maxSpeed = 150;
this.accelRate = 0.4;
this.friction = 0.98;
this.turnSensitivity = 2.5;
}
update(input, surfaceGrip) {
// Acceleration/Braking
const targetAccel = input.gas * 0.8 - input.brake * 0.5;
this.acceleration += targetAccel;
this.acceleration *= 0.9;
const force = (this.acceleration * surfaceGrip);
this.speed += force;
this.speed *= this.friction;
if (Math.abs(this.speed) < 1 && Math.abs(this.acceleration) < 0.1) {
this.speed *= 0.9;
}
if (this.speed > this.maxSpeed * surfaceGrip) {
this.speed = this.maxSpeed * surfaceGrip;
}
// Steering
const steerAmount = input.steer * this.turnSensitivity * (Math.min(Math.abs(this.speed), 100) / 50);
this.rotation += steerAmount * (this.speed / 50);
// Drifting calculation
const driftFactor = (Math.abs(input.steer) > 0.7 && this.speed > 60) ? 0.9 : 1;
this.drift = (1 - driftFactor) * surfaceGrip;
// Update direction vector based on rotation
const forwardX = Math.sin(this.rotation);
const forwardZ = Math.cos(this.rotation);
// Apply drift (sideways velocity component)
const sidewaysX = -Math.cos(this.rotation);
const sidewaysZ = Math.sin(this.rotation);
this.position.x += forwardX * this.speed * 0.01;
this.position.z += forwardZ * this.speed * 0.01;
this.position.x += sidewaysX * (this.drift * 5);
this.position.z += sidewaysZ * (this.drift * 5);
}
}
exports.CarPhysics = CarPhysics;
};
// ── entry ──
__require("src/main.ts");
})();
</script>
</body>
</html>
<!-- agent-meta {"model":"google/gemma-4-12b","provider":"lmstudio","persona":"typescript","sessionId":"12dd928b-3bff-4464-9a81-121738201870","tokensIn":1527210,"tokensOut":51219,"tokensTotal":1578429,"turns":42,"toolCalls":41,"failedToolCalls":3,"timestamp":"2026-07-31T04:00:48.402Z"} -->