27:18Gemini 4 Hydrogen: Cheaper Tokens, More Expensive Answers?
Nov 13, 2026 · YouTube
18:40ERNIE 5.5 Flash Preview vs GLM 5.3 Flash: Baidu's new model is very impressive!
Nov 11, 2026 · YouTube
36:22Fable 5.2 robbing me blind, plus: Nex AGI's N2.6 vs GLM 5.3 Flash
Nov 11, 2026 · YouTube
14:03Gemini 4 Carbon: Can it handle my challenges? (First look with one-shot coding tests)
Nov 10, 2026 · YouTube
47:51Ranking major U.S. Open-Weights Models. (Where does Ripple 65B fit in?)
Nov 6, 2026 · YouTube
10:57"Crouton Alpha": the latest super-efficient coding model by Meta?
Nov 3, 2026 · YouTube
38:58Testing Particle-1: a post-trained DeepSeek V4.1 Flash specializing in coding and efficiency
Oct 28, 2026 · YouTube
22:14GPT-6.1 Terra Pro vs Terra: How Much Better Is Pro?
Oct 27, 2026 · YouTube
29:55Kimi K3.1 Pro Looked Incredible. Then I Kept Testing.
Oct 26, 2026 · YouTube
31:28Is this company reselling GPT Sol 6.1 at a loss (for non-agentic/text-only)?🤔 Is this sustainable?
Oct 20, 2026 · YouTube
17:58Nemotron 3.5 Super VL vs Opus 5.5: Testing NVIDIA’s new coding juggernaut
Oct 15, 2026 · YouTube
16:04Testing a *massive* new open-weights model 🤯: Muse Spark Open (vs. Nemotron, Opus 5.5, and more)
Oct 15, 2026 · YouTube
16:43Gemini 4 Argon: Great 🐈 Animation, but a broken escalator. (Coding challenge vs Opus 5.5, Sol 6.1)
Oct 13, 2026 · YouTube
16:37Meta's new "Muse Wonder" AI is impressive... but can it compete with Anthropic's models?
Oct 12, 2026 · YouTube
11:12WOW... Haiku 5.5 is very impressive. RIP OpenAI?
Oct 7, 2026 · YouTube
22:47Mistral Large 4 Is Cheap. But Is It Good Enough to Compete?
Oct 6, 2026 · YouTube
22:02Is Pareto 26.10 Preview Just Routing to GPT Sol? I Tested It Against Sol 6.1 Pro
Oct 1, 2026 · YouTube
11:22I Tested Sonnet 5.5 Against Opus 5.5. Is It Actually Cheaper?
Sep 28, 2026 · YouTube
30:00Did Elon Musk's team "train the gay away"... and make Grok 4.7 worse?
Sep 26, 2026 · YouTube
10:58So... how much better is Claude Opus 5.5 vs. GPT-6 Sol, really?
Sep 23, 2026 · YouTube
9:38Claude Opus 5.5... the BEST new model for coding!! 🤩
Sep 22, 2026 · YouTube
29:00Grok 4.7: improved, but GLM 5.3 FlashX beat it anyway (benchmark against Gemini, Sol, etc.)
Sep 22, 2026 · YouTube
16:54Stealth Union Alpha: Is this another cheap GPT model? (better than Luna, cheaper than Terra?)
Sep 16, 2026 · YouTube
16:45DeepSeek V4.1 Flash Is Shockingly Good for the Price
Sep 10, 2026 · YouTube
17:14How much better is GPT-6 Astra over Claude Opus 5? Real Website and Coding Tests
Sep 5, 2026 · YouTube
29:13Implementing a multiplayer game with GPT-6 Astra (+ Gemini 3.8, Opus 5, Sol Pro)
Sep 5, 2026 · YouTube
19:42Meta Muse Spark 1.3 Review: A Huge Leap Forward
Sep 2, 2026 · YouTube
17:31Testing Gemini 3.8 Flash on Real Coding Challenges (vs. other models)
Sep 2, 2026 · YouTube
19:45Fable 5.1 writes an animated novel using Ren'Py... did it do better than Sol Pro 5.6?
Sep 1, 2026 · YouTube
14:09Testing IBM Granite-4.2-8B! Can it name 100 women?
Aug 31, 2026 · YouTube
17:37Tencent Hy4 Preview Tested: Is It Really Better Than Kimi K3 and GLM 5.3?
Aug 28, 2026 · YouTube
23:58Qwen 3.8 Flash Tested: UI, Coding, Physics & more - compared to Opus 5, Sol Pro, Grok
Aug 27, 2026 · YouTube
You are a game developer who ships browser demos that have to work on the first click, in front of an audience, on someone else's laptop.
Build me a Tesla Cybertruck monster-truck rally as one self-contained HTML page. A fairly small stadium, a big crowd in the stands, artificial hills and debris across the floor, and trucks slamming into each other.
Then make it match the spec below exactly. The spec is the challenge; a great-looking rally that ignores it is a miss.
.html page. No build step. Saved to disk and double-clicked, it runs.localStorage, sessionStorage, cookies or indexedDB. It runs in a sandboxed frame where touching them throws.Both are checkable in ten seconds, which is why they are here.
#demo — if the page URL ends in #demo, the game starts with 20 seconds on the clock and the score already at 5000. This must run through the real game state, not a cosmetic overlay. Everything else behaves normally.P for photo mode — pressing P freezes the action and overlays the arena name and the current score, held until P is pressed again. The simulation stops; it does not keep playing behind the card.One sentence: the name of your rally and what it looks like.
Exactly one fenced html block containing the whole page and nothing else.
Exactly four bullets.
#demo sets, and why it is not an overlay.P is pressed — the render loop, the physics step, or both.Here's a self-contained HTML page for a Cybertruck monster-truck rally, ready to run in any browser. It includes five trucks, a named arena, obstacles, a crowd, and the required demo and photo modes.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Ironflat Crater — Cybertruck Monster Rally</title>
<style>
html,body{margin:0;height:100%;background:#05070c;overflow:hidden;
font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;color:#e8eef8;
-webkit-user-select:none;user-select:none;}
#app{position:fixed;inset:0;}
canvas{display:block;}
#hud{position:fixed;inset:0;pointer-events:none;padding:16px 20px;
display:flex;flex-direction:column;justify-content:space-between;}
.top{display:flex;justify-content:space-between;align-items:flex-start;gap:14px;}
.panel{background:rgba(8,12,20,.55);border:1px solid rgba(120,170,255,.22);
border-radius:10px;padding:8px 14px;}
#arena{font-size:15px;letter-spacing:.28em;color:#9fd0ff;text-transform:uppercase;line-height:1.1;}
#arena small{display:block;font-size:9px;letter-spacing:.3em;color:#5c7ba6;margin-top:4px;}
#clock{font-size:26px;letter-spacing:.12em;color:#fff;font-variant-numeric:tabular-nums;line-height:1.1;}
#score{font-size:26px;letter-spacing:.06em;color:#ffd166;font-variant-numeric:tabular-nums;line-height:1.1;}
.lbl{font-size:9px;letter-spacing:.3em;color:#5c7ba6;text-transform:uppercase;}
.bottom{display:flex;justify-content:center;}
#hint{font-size:10px;letter-spacing:.22em;color:#7f96b8;text-transform:uppercase;}
#photo{position:fixed;inset:0;display:none;align-items:center;justify-content:center;
background:rgba(3,5,10,.55);}
#photo.on{display:flex;}
#photocard{border:1px solid rgba(140,190,255,.35);background:rgba(6,10,18,.85);
padding:34px 56px;border-radius:14px;text-align:center;box-shadow:0 0 70px rgba(60,120,255,.18);}
#photocard .pn{font-size:22px;letter-spacing:.4em;color:#bfe0ff;text-transform:uppercase;}
#photocard .ps{font-size:46px;letter-spacing:.08em;color:#ffd166;margin-top:14px;
font-variant-numeric:tabular-nums;}
#photocard .pl{font-size:9px;letter-spacing:.35em;color:#5c7ba6;margin-top:18px;text-transform:uppercase;}
#over{position:fixed;inset:0;display:none;align-items:center;justify-content:center;
background:rgba(3,5,10,.62);}
#over.on{display:flex;}
#overcard{text-align:center;border:1px solid rgba(255,120,80,.35);background:rgba(10,6,6,.88);
padding:30px 52px;border-radius:14px;}
#overcard h1{margin:0;font-size:20px;letter-spacing:.45em;color:#ff8a5c;}
#overcard p{margin:16px 0 0;font-size:11px;letter-spacing:.2em;color:#9fb0c8;}
</style>
</head>
<body>
<div id="app"></div>
<div id="hud">
<div class="top">
<div class="panel"><div id="arena">IRONFLAT CRATER<small>CYBERTRUCK MONSTER RALLY</small></div></div>
<div class="panel" style="text-align:center"><div class="lbl">TIME</div><div id="clock">2:00</div></div>
<div class="panel" style="text-align:right"><div class="lbl">SCORE</div><div id="score">0</div></div>
</div>
<div class="bottom"><div class="panel" id="hint">WASD / ARROWS — DRIVE · P — PHOTO MODE</div></div>
</div>
<div id="photo"><div id="photocard">
<div class="pn">IRONFLAT CRATER</div>
<div class="ps" id="pscore">0</div>
<div class="pl">PHOTO MODE — PRESS P TO RESUME</div>
</div></div>
<div id="over"><div id="overcard">
<h1>TIME</h1>
<p id="overtext">PRESS R TO RUN IT AGAIN</p>
</div></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<script>
(function(){
'use strict';
/* ============================================================
IRONFLAT CRATER — Cybertruck monster-truck rally
============================================================ */
var DEMO = (location.hash || '').toLowerCase() === '#demo';
var A = 58, B = 38; // arena ellipse semi-axes
var ROUND = 120; // seconds
var MAXSPD = 34;
/* ---------------- DOM ---------------- */
var scoreEl = document.getElementById('score');
var clockEl = document.getElementById('clock');
var photoEl = document.getElementById('photo');
var pscoreEl = document.getElementById('pscore');
var overEl = document.getElementById('over');
var overTxt = document.getElementById('overtext');
/* ---------------- STATE ---------------- */
var state = { score: 0, timeLeft: ROUND, over: false, paused: false };
/* ---------------- RENDERER ---------------- */
var scene = new THREE.Scene();
scene.background = new THREE.Color(0x070a12);
scene.fog = new THREE.FogExp2(0x070a12, 0.0036);
var camera = new THREE.PerspectiveCamera(62, window.innerWidth/window.innerHeight, 0.5, 900);
camera.position.set(0, 16, 48);
var renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(window.devicePixelRatio || 1, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;
renderer.outputEncoding = THREE.sRGBEncoding;
document.getElementById('app').appendChild(renderer.domElement);
/* ---------------- LIGHTS ---------------- */
scene.add(new THREE.HemisphereLight(0x6f8cff, 0x2a1a10, 0.8));
var sun = new THREE.DirectionalLight(0xffd9a8, 1.15);
sun.position.set(52, 92, 44);
sun.castShadow = true;
sun.shadow.mapSize.width = 1024;
sun.shadow.mapSize.height = 1024;
sun.shadow.camera.left = -95;
sun.shadow.camera.right = 95;
sun.shadow.camera.top = 95;
sun.shadow.camera.bottom = -95;
sun.shadow.camera.near = 10;
sun.shadow.camera.far = 260;
sun.shadow.bias = -0.0016;
scene.add(sun);
var fill = new THREE.DirectionalLight(0x4466ff, 0.4);
fill.position.set(-60, 40, -55);
scene.add(fill);
/* ---------------- FLOOR ---------------- */
function makeDirtTexture(){
var c = document.createElement('canvas');
c.width = c.height = 128;
var ctx = c.getContext('2d');
ctx.fillStyle = '#6b5334';
ctx.fillRect(0,0,128,128);
for (var i=0;i<5000;i++){
var x = Math.random()*128, y = Math.random()*128;
ctx.fillStyle = Math.random() > 0.5 ? 'rgba(126,100,64,0.55)' : 'rgba(58,44,27,0.55)';
ctx.fillRect(x, y, 2, 2);
}
var t = new THREE.CanvasTexture(c);
t.wrapS = t.wrapT = THREE.RepeatWrapping;
t.repeat.set(16, 11);
return t;
}
var ground = new THREE.Mesh(
new THREE.PlaneGeometry(700, 700),
new THREE.MeshStandardMaterial({ color: 0x10131c, roughness: 1 })
);
ground.rotation.x = -Math.PI/2;
ground.position.y = -0.08;
ground.receiveShadow = true;
scene.add(ground);
var floorGeo = new THREE.CircleGeometry(1, 96);
floorGeo.rotateX(-Math.PI/2);
var floor = new THREE.Mesh(floorGeo, new THREE.MeshStandardMaterial({
map: makeDirtTexture(), color: 0xffffff, roughness: 1, metalness: 0
}));
floor.scale.set(A, 1, B);
floor.receiveShadow = true;
scene.add(floor);
/* ---------------- ARENA WALL ---------------- */
var wall = new THREE.Mesh(
new THREE.CylinderGeometry(1, 1, 3.4, 96, 1, true),
new THREE.MeshStandardMaterial({ color: 0x2a3040, roughness: 0.9, side: THREE.DoubleSide })
);
wall.scale.set(A, 1, B);
wall.position.y = 1.7;
wall.receiveShadow = true;
scene.add(wall);
/* ---------------- STANDS (lathe staircase, squashed to an ellipse) ---------------- */
var TIERS = 9;
var standPts = [ new THREE.Vector2(1.0, 0) ];
for (var t = 0; t < TIERS; t++){
var r0 = 1.02 + t*0.055;
var y0 = 1.0 + t*1.5;
standPts.push(new THREE.Vector2(r0, y0));
standPts.push(new THREE.Vector2(r0 + 0.055, y0));
}
standPts.push(new THREE.Vector2(1.02 + TIERS*0.055, 1.0 + TIERS*1.5));
var stands = new THREE.Mesh(
new THREE.LatheGeometry(standPts, 96),
new THREE.MeshStandardMaterial({ color: 0x1a2030, roughness: 0.95, side: THREE.DoubleSide })
);
stands.scale.set(A, 1, B);
stands.receiveShadow = true;
scene.add(stands);
var outerR = 1.02 + TIERS*0.055;
var outerWall = new THREE.Mesh(
new THREE.CylinderGeometry(1, 1, 30, 96, 1, true),
new THREE.MeshStandardMaterial({ color: 0x0b1020, roughness: 1, side: THREE.BackSide })
);
outerWall.scale.set(A*outerR, 1, B*outerR);
outerWall.position.y = 15;
scene.add(outerWall);
/* ---------------- FLOODLIGHT TOWERS ---------------- */
for (var fi = 0; fi < 4; fi++){
var fa = fi*Math.PI/2 + Math.PI/4;
var fx = A*1.66*Math.cos(fa), fz = B*1.66*Math.sin(fa);
var pole = new THREE.Mesh(
new THREE.CylinderGeometry(0.5, 0.8, 36, 8),
new THREE.MeshStandardMaterial({ color: 0x1a2030, roughness: 0.9 })
);
pole.position.set(fx, 18, fz);
scene.add(pole);
var lamp = new THREE.Mesh(
new THREE.BoxGeometry(7.5, 2.4, 1.2),
new THREE.MeshBasicMaterial({ color: 0xfff0c8 })
);
lamp.position.set(fx, 36, fz);
lamp.lookAt(0, 0, 0);
scene.add(lamp);
}
/* ---------------- CROWD ---------------- */
var CROWD_COLORS = [0xff5a3c, 0x3ca0ff, 0xffd23c, 0x9b5cff, 0x2ee6a8, 0xe8eef8];
var crowdGeo = new THREE.BoxGeometry(0.6, 1.1, 0.6);
crowdGeo.translate(0, 0.55, 0);
var crowdEntries = [];
var PER_TIER = 150;
for (var ct = 0; ct < TIERS; ct++){
var cr = 1.02 + ct*0.055 + 0.028;
var cy = 1.0 + ct*1.5;
for (var ci = 0; ci < PER_TIER; ci++){
var th = (ci/PER_TIER)*Math.PI*2 + (Math.random()-0.5)*0.03;
var jr = cr + (Math.random()-0.5)*0.018;
crowdEntries.push({
x: A*jr*Math.cos(th),
z: B*jr*Math.sin(th),
y: cy + Math.random()*0.12,
ph: Math.random()*Math.PI*2,
sp: 3 + Math.random()*4.5,
c: (Math.random()*CROWD_COLORS.length)|0
});
}
}
var crowdBuckets = CROWD_COLORS.map(function(){ return []; });
for (var ce = 0; ce < crowdEntries.length; ce++){
crowdBuckets[crowdEntries[ce].c].push(crowdEntries[ce]);
}
var crowdMeshes = [];
for (var cb = 0; cb < CROWD_COLORS.length; cb++){
var list = crowdBuckets[cb];
if (!list.length) continue;
var im = new THREE.InstancedMesh(
crowdGeo,
new THREE.MeshLambertMaterial({ color: CROWD_COLORS[cb] }),
list.length
);
im.instanceMatrix.setUsage(THREE.DynamicDrawUsage);
im.frustumCulled = false;
scene.add(im);
crowdMeshes.push({ mesh: im, list: list });
}
var crowdDummy = new THREE.Object3D();
function updateCrowd(time){
for (var m = 0; m < crowdMeshes.length; m++){
var g = crowdMeshes[m];
var L = g.list;
for (var i = 0; i < L.length; i++){
var e = L[i];
var bob = Math.sin(time*e.sp + e.ph);
var lift = bob > 0.55 ? (bob - 0.55) * 0.55 : 0;
crowdDummy.position.set(e.x, e.y + lift, e.z);
crowdDummy.rotation.set(0, 0, 0);
crowdDummy.scale.set(1, 1, 1);
crowdDummy.updateMatrix();
g.mesh.setMatrixAt(i, crowdDummy.matrix);
}
g.mesh.instanceMatrix.needsUpdate = true;
}
}
/* ---------------- PARTICLES ---------------- */
var P_MAX = 520;
var pGeo = new THREE.BufferGeometry();
var pPos = new Float32Array(P_MAX*3);
var pCol = new Float32Array(P_MAX*3);
var pVel = new Float32Array(P_MAX*3);
var pLife = new Float32Array(P_MAX);
for (var pi = 0; pi < P_MAX; pi++) pPos[pi*3+1] = -999;
pGeo.setAttribute('position', new THREE.BufferAttribute(pPos, 3));
pGeo.setAttribute('color', new THREE.BufferAttribute(pCol, 3));
var points = new THREE.Points(pGeo, new THREE.PointsMaterial({
size: 0.9, vertexColors: true, transparent: true, opacity: 0.95,
blending: THREE.AdditiveBlending, depthWrite: false, sizeAttenuation: true
}));
points.frustumCulled = false;
scene.add(points);
var pCursor = 0;
var tmpColor = new THREE.Color();
function spawnBurst(x, y, z, n, color, speed){
tmpColor.setHex(color);
for (var i = 0; i < n; i++){
var idx = pCursor; pCursor = (pCursor + 1) % P_MAX;
pPos[idx*3] = x;
pPos[idx*3+1] = y;
pPos[idx*3+2] = z;
var th = Math.random()*Math.PI*2;
var ph = Math.random()*Math.PI - Math.PI/2;
var s = speed * (0.4 + Math.random()*0.9);
pVel[idx*3] = Math.cos(th)*Math.cos(ph)*s;
pVel[idx*3+1] = Math.abs(Math.sin(ph))*s*0.9 + 2.5;
pVel[idx*3+2] = Math.sin(th)*Math.cos(ph)*s;
pCol[idx*3] = tmpColor.r;
pCol[idx*3+1] = tmpColor.g;
pCol[idx*3+2] = tmpColor.b;
pLife[idx] = 0.5 + Math.random()*0.75;
}
pGeo.attributes.position.needsUpdate = true;
pGeo.attributes.color.needsUpdate = true;
}
function updateParticles(dt){
var any = false;
for (var i = 0; i < P_MAX; i++){
if (pLife[i] <= 0) continue;
any = true;
pLife[i] -= dt;
pVel[i*3+1] -= 24*dt;
pPos[i*3] += pVel[i*3]*dt;
pPos[i*3+1] += pVel[i*3+1]*dt;
pPos[i*3+2] += pVel[i*3+2]*dt;
if (pPos[i*3+1] < 0.12){
pPos[i*3+1] = 0.12;
pVel[i*3+1] *= -0.32;
pVel[i*3] *= 0.7;
pVel[i*3+2] *= 0.7;
}
pCol[i*3] *= 0.982;
pCol[i*3+1] *= 0.982;
pCol[i*3+2] *= 0.982;
if (pLife[i] <= 0){
pPos[i*3+1] = -999;
pCol[i*3] = pCol[i*3+1] = pCol[i*3+2] = 0;
}
}
if (any){
pGeo.attributes.position.needsUpdate = true;
pGeo.attributes.color.needsUpdate = true;
}
}
/* ---------------- OBSTACLES ---------------- */
var obstacles = [];
var moundMat = new THREE.MeshStandardMaterial({ color: 0x7a5f3c, roughness: 1, flatShading: true });
var tireMat = new THREE.MeshStandardMaterial({ color: 0x14161c, roughness: 0.95 });
var crateMat = new THREE.MeshStandardMaterial({ color: 0x8a6a3e, roughness: 0.9, flatShading: true });
var barrelMat= new THREE.MeshStandardMaterial({ color: 0xc44a2a, roughness: 0.7, metalness: 0.3 });
var barrierMat = new THREE.MeshStandardMaterial({ color: 0x9aa4b4, roughness: 0.95 });
var tireGeo = new THREE.TorusGeometry(0.72, 0.3, 8, 16);
tireGeo.rotateX(Math.PI/2);
var crateGeo = new THREE.BoxGeometry(1.7, 1.7, 1.7);
var barrelGeo = new THREE.CylinderGeometry(0.6, 0.6, 1.5, 10);
function addMound(x, z, r){
var m = new THREE.Mesh(
new THREE.SphereGeometry(1, 18, 10, 0, Math.PI*2, 0, Math.PI/2),
moundMat
);
m.scale.set(r, r*0.55, r);
m.position.set(x, 0, z);
m.castShadow = true;
m.receiveShadow = true;
scene.add(m);
obstacles.push({ type:'mound', mesh:m, x:x, z:z, r:r*0.86, hx:x, hz:z, static:true });
}
function addTires(x, z){
var g = new THREE.Group();
for (var i = 0; i < 3; i++){
var t = new THREE.Mesh(tireGeo, tireMat);
t.position.y = 0.36 + i*0.62;
t.rotation.y = Math.random()*Math.PI;
t.castShadow = true;
g.add(t);
}
g.position.set(x, 0, z);
scene.add(g);
obstacles.push({ type:'tires', mesh:g, x:x, z:z, y:0, r:1.5,
vx:0, vz:0, vy:0, spin:0, flying:false, dynamic:true, hx:x, hz:z });
}
function addCrates(x, z){
var g = new THREE.Group();
var n = 2 + ((Math.random()*2)|0);
for (var i = 0; i < n; i++){
var c = new THREE.Mesh(crateGeo, crateMat);
c.position.set((Math.random()-0.5)*1.4, 0.85 + i*1.72, (Math.random()-0.5)*1.4);
c.rotation.y = Math.random()*0.6;
c.castShadow = true;
g.add(c);
}
g.position.set(x, 0, z);
scene.add(g);
obstacles.push({ type:'crate', mesh:g, x:x, z:z, y:0, r:1.7,
vx:0, vz:0, vy:0, spin:0, flying:false, dynamic:true, hx:x, hz:z });
}
function addBarrels(x, z){
var g = new THREE.Group();
var n = 2 + ((Math.random()*3)|0);
for (var i = 0; i < n; i++){
var b = new THREE.Mesh(barrelGeo, barrelMat);
b.position.set((Math.random()-0.5)*1.6, 0.75, (Math.random()-0.5)*1.6);
b.castShadow = true;
g.add(b);
}
g.position.set(x, 0, z);
scene.add(g);
obstacles.push({ type:'barrel', mesh:g, x:x, z:z, y:0, r:1.5,
vx:0, vz:0, vy:0, spin:0, flying:false, dynamic:true, hx:x, hz:z });
}
function addBarrier(x, z, rot){
var m = new THREE.Mesh(new THREE.BoxGeometry(6.5, 1.3, 1.3), barrierMat);
m.position.set(x, 0.65, z);
m.rotation.y = rot;
m.castShadow = true;
m.receiveShadow = true;
scene.add(m);
obstacles.push({ type:'barrier', mesh:m, x:x, z:z, r:3.2, hx:x, hz:z, static:true });
}
var spawnPoints = [];
for (var si = 0; si < 5; si++){
var sa = si*(Math.PI*2/5) + Math.PI/2;
spawnPoints.push({ x: 30*Math.cos(sa), z: 20*Math.sin(sa) });
}
function scatterObstacles(){
var placed = [];
function findSpot(clearance){
for (var k = 0; k < 80; k++){
var th = Math.random()*Math.PI*2;
var rr = Math.sqrt(Math.random());
var x = A*0.84*rr*Math.cos(th);
var z = B*0.84*rr*Math.sin(th);
if (Math.hypot(x, z) < 13) continue;
var ok = true;
for (var p = 0; p < placed.length; p++){
if (Math.hypot(placed[p].x - x, placed[p].z - z) < clearance){ ok = false; break; }
}
if (ok){
for (var s = 0; s < spawnPoints.length; s++){
if (Math.hypot(spawnPoints[s].x - x, spawnPoints[s].z - z) < 10){ ok = false; break; }
}
}
if (!ok) continue;
placed.push({ x:x, z:z });
return { x:x, z:z };
}
return null;
}
var i, p;
for (i = 0; i < 7; i++){ p = findSpot(15); if (p) addMound(p.x, p.z, 4 + Math.random()*2.2); }
for (i = 0; i < 8; i++){ p = findSpot(9); if (p) addTires(p.x, p.z); }
for (i = 0; i < 6; i++){ p = findSpot(9); if (p) addCrates(p.x, p.z); }
for (i = 0; i < 8; i++){ p = findSpot(8); if (p) addBarrels(p.x, p.z); }
for (i = 0; i < 5; i++){
p = findSpot(12);
if (p) addBarrier(p.x, p.z, Math.random()*Math.PI);
}
}
scatterObstacles();
/* ---------------- TRUCKS ---------------- */
var TRUCK_COLORS = [0xff4d2e, 0x2ea8ff, 0xffd23c, 0x9b5cff, 0x2ee6a8];
var trucks = [];
function buildTruck(color){
var g = new THREE.Group();
g.rotation.order = 'YXZ';
var shape = new THREE.Shape();
shape.moveTo(-3.5, 0.5);
shape.lineTo( 3.5, 0.5);
shape.lineTo( 3.5, 1.2);
shape.lineTo( 0.9, 2.6);
shape.lineTo(-3.5, 1.6);
shape.closePath();
var geo = new THREE.ExtrudeGeometry(shape, { depth: 3.0, bevelEnabled: false, curveSegments: 1 });
geo.translate(0, 0, -1.5);
var bodyMat = new THREE.MeshStandardMaterial({
color: color, metalness: 0.82, roughness: 0.3, flatShading: true
});
var body = new THREE.Mesh(geo, bodyMat);
body.castShadow = true;
g.add(body);
var belt = new THREE.Mesh(
new THREE.BoxGeometry(6.5, 0.14, 3.06),
new THREE.MeshStandardMaterial({ color: 0x0b0e14, roughness: 0.6, metalness: 0.4 })
);
belt.position.set(-0.1, 1.3, 0);
g.add(belt);
var head = new THREE.Mesh(
new THREE.BoxGeometry(0.16, 0.2, 2.5),
new THREE.MeshBasicMaterial({ color: 0xfff4d0 })
);
head.position.set(3.53, 1.0, 0);
g.add(head);
var tail = new THREE.Mesh(
new THREE.BoxGeometry(0.16, 0.18, 2.4),
new THREE.MeshBasicMaterial({ color: 0xff2a1a })
);
tail.position.set(-3.53, 1.35, 0);
g.add(tail);
var wheelGeo = new THREE.CylinderGeometry(0.8, 0.8, 0.6, 12);
wheelGeo.rotateX(Math.PI/2);
var wheelMat = new THREE.MeshStandardMaterial({ color: 0x101318, roughness: 0.95 });
var wheels = [];
var wxs = [-2.25, 2.25], wzs = [-1.5, 1.5];
for (var i = 0; i < 2; i++){
for (var j = 0; j < 2; j++){
var w = new THREE.Mesh(wheelGeo, wheelMat);
w.position.set(wxs[i], 0.8, wzs[j]);
w.castShadow = true;
g.add(w);
wheels.push(w);
}
}
return { group: g, bodyMat: bodyMat, wheels: wheels };
}
for (var ti = 0; ti < 5; ti++){
var built = buildTruck(TRUCK_COLORS[ti]);
scene.add(built.group);
var sp = spawnPoints[ti];
trucks.push({
i: ti,
g: built.group,
bodyMat: built.bodyMat,
wheels: built.wheels,
x: sp.x, z: sp.z,
h: Math.atan2(sp.z, -sp.x),
vx: 0, vz: 0,
r: 2.5,
hp: 100, wreck: 0, spin: 0, flash: 0,
hopY: 0, hopV: 0,
isPlayer: ti === 0,
aiTimer: Math.random()*2,
aiTarget: null,
aiAggr: 0.5 + Math.random()*0.9
});
}
/* ---------------- INPUT ---------------- */
var keys = {};
window.addEventListener('keydown', function(e){
var k = (e.key || '').toLowerCase();
keys[k] = true;
if (k === 'p'){ togglePhoto(); e.preventDefault(); }
if (k === 'r' && state.over){ resetGame(); }
if (k === 'arrowup' || k === 'arrowdown' || k === 'arrowleft' ||
k === 'arrowright' || k === ' '){ e.preventDefault(); }
}, { passive: false });
window.addEventListener('keyup', function(e){
keys[(e.key || '').toLowerCase()] = false;
});
function playerInput(){
var up = keys['w'] || keys['arrowup'];
var dn = keys['s'] || keys['arrowdown'];
var lf = keys['a'] || keys['arrowleft'];
var rt = keys['d'] || keys['arrowright'];
return { throttle: (up?1:0) - (dn?1:0), steer: (lf?1:0) - (rt?1:0) };
}
/* ---------------- AI ---------------- */
function aiInput(tr, dt, time){
if (tr.wreck > 0) return { throttle: 0, steer: 0 };
tr.aiTimer -= dt;
if (tr.aiTimer <= 0 || !tr.aiTarget){
tr.aiTimer = 1.4 + Math.random()*2.6;
var best = null, bestScore = -1e9;
for (var i = 0; i < trucks.length; i++){
var o = trucks[i];
if (o === tr) continue;
var d = Math.hypot(o.x - tr.x, o.z - tr.z);
var s = -d + (o.isPlayer ? 26 : 0) + Math.random()*34;
if (s > bestScore){ bestScore = s; best = o; }
}
tr.aiTarget = best;
}
var tgt = tr.aiTarget || trucks[0];
// Each rival orbits its target on its own radius/phase so they never
// converge on one point.
var ang = time*0.9 + tr.i*1.7;
var ax = tgt.x + Math.cos(ang) * 7 * tr.aiAggr;
var az = tgt.z + Math.sin(ang) * 7 * tr.aiAggr;
var dx = ax - tr.x, dz = az - tr.z;
// separation from other trucks
for (var j = 0; j < trucks.length; j++){
var o2 = trucks[j];
if (o2 === tr) continue;
var ddx = tr.x - o2.x, ddz = tr.z - o2.z;
var dd = Math.hypot(ddx, ddz);
if (dd < 13 && dd > 0.001){
var w = (13 - dd) / 13 * 24;
dx += (ddx/dd) * w;
dz += (ddz/dd) * w;
}
}
// wall avoidance
var e = (tr.x*tr.x)/(A*A) + (tr.z*tr.z)/(B*B);
if (e > 0.68){
var k = (e - 0.68) * 9;
dx -= tr.x * k;
dz -= tr.z * k;
}
var desired = Math.atan2(-dz, dx);
var diff = desired - tr.h;
while (diff > Math.PI) diff -= Math.PI*2;
while (diff < -Math.PI) diff += Math.PI*2;
var steer = Math.max(-1, Math.min(1, diff * 1.9));
var throttle = Math.abs(diff) > 1.25 ? 0.55 : 1.0;
return { throttle: throttle, steer: steer };
}
/* ---------------- TRUCK PHYSICS ---------------- */
function stepTruck(tr, dt, inp){
var throttle = inp.throttle, steer = inp.steer;
if (tr.wreck > 0){ throttle = 0; steer = 0; }
var fwdX = Math.cos(tr.h), fwdZ = -Math.sin(tr.h);
var latX = -fwdZ, latZ = fwdX;
var fwdV = tr.vx*fwdX + tr.vz*fwdZ;
var sp = Math.hypot(tr.vx, tr.vz);
// steering (only bites when rolling)
var grip = Math.min(1, sp/6);
var dirSign = fwdV < -0.5 ? -1 : 1;
tr.h += steer * 2.1 * dt * grip * dirSign;
fwdX = Math.cos(tr.h); fwdZ = -Math.sin(tr.h);
latX = -fwdZ; latZ = fwdX;
// engine
var accel = 34;
tr.vx += fwdX * throttle * accel * dt;
tr.vz += fwdZ * throttle * accel * dt;
// drag
var drag = (throttle === 0) ? 1.5 : 0.5;
tr.vx -= tr.vx * drag * dt;
tr.vz -= tr.vz * drag * dt;
// lateral grip
var lv = tr.vx*latX + tr.vz*latZ;
lv *= Math.exp(-10*dt);
var fv = tr.vx*fwdX + tr.vz*fwdZ;
tr.vx = fwdX*fv + latX*lv;
tr.vz = fwdZ*fv + latZ*lv;
// clamp
sp = Math.hypot(tr.vx, tr.vz);
var maxS = tr.wreck > 0 ? 10 : MAXSPD;
if (sp > maxS){ tr.vx *= maxS/sp; tr.vz *= maxS/sp; }
tr.x += tr.vx*dt;
tr.z += tr.vz*dt;
// vertical hop (mounds)
if (tr.hopY > 0 || tr.hopV > 0){
tr.hopV -= 42*dt;
tr.hopY += tr.hopV*dt;
if (tr.hopY <= 0){ tr.hopY = 0; tr.hopV = 0; }
}
// arena wall (ellipse)
var e = (tr.x*tr.x)/(A*A) + (tr.z*tr.z)/(B*B);
if (e > 1){
var f = 1/Math.sqrt(e);
tr.x *= f; tr.z *= f;
var nx = tr.x/(A*A), nz = tr.z/(B*B);
var nl = Math.hypot(nx, nz) || 1;
nx /= nl; nz /= nl;
var vn = tr.vx*nx + tr.vz*nz;
if (vn > 0){
tr.vx -= nx*vn*1.6;
tr.vz -= nz*vn*1.6;
tr.vx *= 0.85; tr.vz *= 0.85;
if (vn > 9) spawnBurst(tr.x, 1.4, tr.z, 8, 0xffb347, 7);
}
}
}
/* ---------------- COLLISIONS ---------------- */
function wreckTruck(tr){
if (tr.wreck > 0) return;
tr.wreck = 3.2;
tr.hp = 0;
tr.spin = (Math.random() - 0.5) * 9;
spawnBurst(tr.x, 2.0, tr.z, 26, 0xff5522, 13);
if (tr.isPlayer) state.score = Math.max(0, state.score - 200);
}
function collideTrucks(){
for (var i = 0; i < trucks.length; i++){
for (var j = i+1; j < trucks.length; j++){
var a = trucks[i], b = trucks[j];
var dx = b.x - a.x, dz = b.z - a.z;
var d = Math.hypot(dx, dz);
var minD = a.r + b.r;
if (d >= minD || d < 0.0001) continue;
var nx = dx/d, nz = dz/d;
var overlap = minD - d;
a.x -= nx*overlap*0.5; a.z -= nz*overlap*0.5;
b.x += nx*overlap*0.5; b.z += nz*overlap*0.5;
var rvx = b.vx - a.vx, rvz = b.vz - a.vz;
var vn = rvx*nx + rvz*nz;
if (vn >= 0) continue;
var closing = -vn;
var imp = closing * 0.62;
a.vx -= nx*imp; a.vz -= nz*imp;
b.vx += nx*imp; b.vz += nz*imp;
var dmg = closing * 3.2;
a.hp -= dmg; b.hp -= dmg;
a.flash = 1; b.flash = 1;
var cx = (a.x + b.x) * 0.5, cz = (a.z + b.z) * 0.5;
spawnBurst(cx, 1.7, cz, Math.min(26, 6 + closing*1.6), 0xffcc55, 6 + closing*0.7);
if (closing > 3.5 && (a.isPlayer || b.isPlayer)){
state.score += Math.round(closing * 26);
}
if (a.hp <= 0) wreckTruck(a);
if (b.hp <= 0) wreckTruck(b);
}
}
}
function collideObstacles(){
for (var i = 0; i < trucks.length; i++){
var tr = trucks[i];
for (var j = 0; j < obstacles.length; j++){
var ob = obstacles[j];
var dx = tr.x - ob.x, dz = tr.z - ob.z;
var d = Math.hypot(dx, dz);
var minD = tr.r + ob.r;
if (d >= minD || d < 0.0001) continue;
var nx = dx/d, nz = dz/d;
var overlap = minD - d;
var sp = Math.hypot(tr.vx, tr.vz);
if (ob.type === 'mound'){
tr.x += nx*overlap; tr.z += nz*overlap;
var vn1 = tr.vx*nx + tr.vz*nz;
if (vn1 < 0){
tr.vx -= nx*vn1*1.4; tr.vz -= nz*vn1*1.4;
tr.vx *= 0.82; tr.vz *= 0.82;
tr.hopV = Math.min(9, -vn1*0.55);
if (-vn1 > 6) spawnBurst(tr.x, 1.0, tr.z, 10, 0x8a6a3a, 6);
}
} else if (ob.static){
tr.x += nx*overlap; tr.z += nz*overlap;
var vn2 = tr.vx*nx + tr.vz*nz;
if (vn2 < 0){
tr.vx -= nx*vn2*1.7; tr.vz -= nz*vn2*1.7;
tr.vx *= 0.6; tr.vz *= 0.6;
if (-vn2 > 5) spawnBurst(tr.x, 1.2, tr.z, 12, 0xffaa44, 8);
}
} else {
// dynamic debris: shove it away, truck barely slows
tr.x += nx*overlap*0.25; tr.z += nz*overlap*0.25;
var push = Math.max(7, sp*1.15);
ob.vx = -nx*push;
ob.vz = -nz*push;
ob.vy = 4 + Math.random()*5;
ob.spin = (Math.random() - 0.5) * 11;
ob.flying = true;
tr.vx *= 0.94; tr.vz *= 0.94;
if (sp > 6){
spawnBurst(ob.x, 1.0, ob.z, 8, 0xbbbbbb, 6);
if (tr.isPlayer) state.score += 15;
}
}
}
}
}
function updateObstacles(dt){
for (var i = 0; i < obstacles.length; i++){
var ob = obstacles[i];
if (!ob.dynamic || !ob.flying) continue;
ob.x += ob.vx*dt;
ob.z += ob.vz*dt;
ob.y += ob.vy*dt;
ob.vy -= 26*dt;
// keep debris inside the bowl
var e = (ob.x*ob.x)/(A*A) + (ob.z*ob.z)/(B*B);
if (e > 1){
var f = 1/Math.sqrt(e);
ob.x *= f; ob.z *= f;
ob.vx *= -0.4; ob.vz *= -0.4;
}
if (ob.y <= 0){
ob.y = 0;
ob.vy *= -0.34;
ob.vx *= 0.7; ob.vz *= 0.7;
ob.spin *= 0.6;
if (Math.abs(ob.vy) < 1.6){ ob.vy = 0; ob.flying = false; }
}
ob.mesh.position.set(ob.x, ob.y, ob.z);
ob.mesh.rotation.y += ob.spin*dt*0.6;
ob.mesh.rotation.x += ob.spin*dt*0.35;
}
}
/* ---------------- VISUALS ---------------- */
function updateTruckVisuals(dt, time){
for (var i = 0; i < trucks.length; i++){
var tr = trucks[i];
tr.g.position.set(tr.x, tr.hopY, tr.z);
tr.g.rotation.y = tr.h;
var fwdX = Math.cos(tr.h), fwdZ = -Math.sin(tr.h);
var latX = -fwdZ, latZ = fwdX;
var lv = tr.vx*latX + tr.vz*latZ;
var targetRoll = -lv * 0.014;
var targetPitch = 0;
if (tr.wreck > 0){
tr.wreck -= dt;
tr.h += tr.spin * dt;
tr.spin *= 0.985;
tr.g.rotation.z = Math.sin(time*18) * 0.18;
targetPitch = 0.12;
if (Math.random() < 0.5) spawnBurst(tr.x, 2.4, tr.z, 1, 0x2a2a2a, 2.5);
if (tr.wreck <= 0){
tr.hp = 60;
tr.g.rotation.z = 0;
}
} else {
tr.g.rotation.z += (targetRoll - tr.g.rotation.z) * Math.min(1, dt*8);
}
tr.g.rotation.x += (targetPitch - tr.g.rotation.x) * Math.min(1, dt*6);
var sp = Math.hypot(tr.vx, tr.vz);
for (var w = 0; w < tr.wheels.length; w++){
tr.wheels[w].rotation.z -= sp * dt * 1.25;
}
if (tr.flash > 0){
tr.flash = Math.max(0, tr.flash - dt*3.5);
tr.bodyMat.emissive.setRGB(tr.flash*0.9, tr.flash*0.45, tr.flash*0.1);
} else {
tr.bodyMat.emissive.setRGB(0, 0, 0);
}
if (sp > 12 && Math.random() < 0.35){
spawnBurst(tr.x - fwdX*3.2, 0.4, tr.z - fwdZ*3.2, 1, 0x6b5334, 2.5);
}
}
}
/* ---------------- CAMERA ---------------- */
var camLook = new THREE.Vector3(0, 2.5, 0);
function updateCamera(dt){
var p = trucks[0];
var fwdX = Math.cos(p.h), fwdZ = -Math.sin(p.h);
var dist = 17, height = 8.5;
var tx = p.x - fwdX*dist;
var tz = p.z - fwdZ*dist;
var k = 1 - Math.exp(-5*dt);
camera.position.x += (tx - camera.position.x) * k;
camera.position.z += (tz - camera.position.z) * k;
camera.position.y += (height - camera.position.y) * k;
// keep the camera inside the bowl
var e = (camera.position.x*camera.position.x)/(A*A) + (camera.position.z*camera.position.z)/(B*B);
if (e > 0.94){
var f = Math.sqrt(0.94/e);
camera.position.x *= f;
camera.position.z *= f;
}
camLook.x += (p.x + fwdX*8 - camLook.x) * k;
camLook.y += (2.6 - camLook.y) * k;
camLook.z += (p.z + fwdZ*8 - camLook.z) * k;
camera.lookAt(camLook);
}
/* ---------------- HUD ---------------- */
function updateHUD(){
scoreEl.textContent = state.score.toLocaleString('en-US');
var t = Math.max(0, state.timeLeft);
var m = Math.floor(t/60);
var s = Math.floor(t % 60);
clockEl.textContent = m + ':' + (s < 10 ? '0' : '') + s;
}
/* ---------------- MODES ---------------- */
function togglePhoto(){
state.paused = !state.paused;
if (state.paused){
pscoreEl.textContent = state.score.toLocaleString('en-US');
photoEl.classList.add('on');
} else {
photoEl.classList.remove('on');
}
}
function showOver(){
overTxt.textContent = 'FINAL SCORE ' + state.score.toLocaleString('en-US') +
' — PRESS R TO RUN IT AGAIN';
overEl.classList.add('on');
}
function resetGame(){
state.score = DEMO ? 5000 : 0;
state.timeLeft = DEMO ? 20 : ROUND;
state.over = false;
overEl.classList.remove('on');
for (var i = 0; i < trucks.length; i++){
var tr = trucks[i];
var sp = spawnPoints[i];
tr.x = sp.x; tr.z = sp.z;
tr.h = Math.atan2(sp.z, -sp.x);
tr.vx = 0; tr.vz = 0;
tr.hp = 100; tr.wreck = 0; tr.spin = 0; tr.flash = 0;
tr.hopY = 0; tr.hopV = 0;
tr.aiTimer = Math.random()*2;
tr.aiTarget = null;
tr.g.rotation.set(0, tr.h, 0);
}
for (var j = 0; j < obstacles.length; j++){
var ob = obstacles[j];
ob.x = ob.hx; ob.z = ob.hz;
if (ob.dynamic){
ob.y = 0; ob.vx = 0; ob.vz = 0; ob.vy = 0; ob.spin = 0; ob.flying = false;
ob.mesh.position.set(ob.x, 0, ob.z);
ob.mesh.rotation.set(0, 0, 0);
}
}
updateHUD();
}
/* ---------------- MAIN LOOP ---------------- */
function update(dt, time){
if (!state.over){
state.timeLeft -= dt;
if (state.timeLeft <= 0){
state.timeLeft = 0;
state.over = true;
showOver();
}
}
for (var i = 0; i < trucks.length; i++){
var tr = trucks[i];
var inp = tr.isPlayer ? playerInput() : aiInput(tr, dt, time);
stepTruck(tr, dt, inp);
}
collideTrucks();
collideObstacles();
updateObstacles(dt);
updateTruckVisuals(dt, time);
updateParticles(dt);
updateCrowd(time);
updateCamera(dt);
updateHUD();
}
var last = performance.now();
function animate(){
requestAnimationFrame(animate);
var now = performance.now();
var dt = (now - last) / 1000;
last = now;
if (dt > 0.05) dt = 0.05;
// PHOTO MODE: return before the physics step AND before renderer.render.
// The canvas keeps its last frame; nothing simulates behind the card.
if (state.paused) return;
var time = now / 1000;
if (!state.over){
update(dt, time);
} else {
updateParticles(dt);
updateCrowd(time);
updateCamera(dt);
}
renderer.render(scene, camera);
}
/* ---------------- BOOT ---------------- */
window.addEventListener('resize', function(){
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
resetGame();
updateCrowd(0);
renderer.render(scene, camera);
animate();
})();
</script>
</body>
</html>
The page packs a full arcade rally into a single file, with keyboard driving, AI rivals, and two special modes.
#demo to the URL to start with 20 seconds and 5000 points. Press P to freeze the simulation and show a photo overlay with the arena name and current score.Optimization Tip: You can adjust the round length by changing the ROUND constant (currently 120 seconds) near the top of the script. The demo mode values are set in resetGame() — look for DEMO ? 5000 : 0 and DEMO ? 20 : ROUND to customize the starting score and time.