Liveloop

Uma timeline interativa para redes sociais. Cada post é um app minúsculo que você pode jogar, salvar e remixar.

Produto

  • Feed
  • Jogos
  • Criar
  • Plugin do Claude Code
  • Blog

Jurídico

  • Política de Privacidade
  • Termos de Serviço
  • Política de Cookies
  • DMCA

Projeto

  • Templates
© 2026 Liveloop. Todos os direitos reservados.
LiveloopHistórico de versões

v2Atual

@joaobarrosfranca · 8/12/2026, 3:59:20 PM

Diferença em relação à v1.

-<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Apex Rush 3D</title>
-<style>
-*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#7db9e5;font-family:system-ui,-apple-system,sans-serif;touch-action:none}canvas{display:block}#hud{position:fixed;z-index:5;top:0;left:0;right:0;padding:18px 20px;display:flex;justify-content:space-between;color:#fff;text-shadow:0 2px 7px #17233d;pointer-events:none}.label{font-size:10px;font-weight:950;letter-spacing:1.7px}.value{font-size:30px;font-weight:1000;line-height:1}.right{text-align:right}.controls{position:fixed;z-index:6;left:0;right:0;bottom:18px;padding:0 18px;display:flex;justify-content:space-between}.controls button{width:61px;height:61px;border-radius:50%;border:3px solid #fff;color:#fff;font-size:26px;font-weight:1000;background:#113b74bd;box-shadow:0 5px 12px #12264988}.controls button:active{background:#f22f39;transform:scale(.93)}#cover{position:fixed;z-index:10;inset:0;display:grid;place-items:center;text-align:center;padding:27px;background:linear-gradient(150deg,#091d46e8,#174e8bde 48%,#e3323aa8);color:#fff}#card{max-width:325px}.tag{font-size:11px;font-weight:950;letter-spacing:4px;color:#ffde61}.title{font-size:56px;line-height:.78;font-weight:1000;letter-spacing:-4px;margin:18px 0 21px;text-shadow:4px 4px 0 #111e43}.title span{color:#ff494c}.copy{font-size:16px;line-height:1.5;color:#edf7ff;margin-bottom:27px}#start{border:3px solid #ffeb9a;border-radius:4px;background:#f23742;color:#fff;padding:15px 28px;font-size:14px;font-weight:1000;letter-spacing:1px;box-shadow:0 5px 0 #751e3c;cursor:pointer}#start:active{transform:translateY(3px);box-shadow:0 2px 0 #751e3c}.hint{font-size:12px;color:#fff2bf;margin-top:18px}
-</style></head><body>
-<div id="hud"><div><div class="label">DISTANCE</div><div id="score" class="value">0</div></div><div class="right"><div class="label">LAP</div><div id="lap" class="value">1</div></div></div>
-<div class="controls"><button id="left" aria-label="Steer left">←</button><button id="right" aria-label="Steer right">→</button></div>
-<div id="cover"><div id="card"><div class="tag">OPEN WHEEL ARCADE RACING</div><div class="title">APEX<br><span>RUSH</span></div><div id="copy" class="copy">Thread the traffic, hold the racing line, and make every second count.</div><button id="start" type="button">START ENGINE</button><div class="hint">Hold ← / → to steer · Arrow keys also work</div></div></div>
+<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><style>
+*{box-sizing:border-box}html,body{margin:0;overflow:hidden;background:#77bde7;font-family:system-ui,sans-serif;touch-action:none}canvas{position:fixed;inset:0;z-index:0}.hud{position:fixed;z-index:3;top:0;left:0;right:0;padding:17px;display:flex;justify-content:space-between;color:white;text-shadow:0 2px 6px #173358;pointer-events:none}.lab{font-size:10px;font-weight:1000;letter-spacing:1.7px}.num{font-size:29px;font-weight:1000}.r{text-align:right}#speedometer{position:fixed;z-index:3;left:50%;bottom:18px;transform:translateX(-50%);width:126px;height:68px;border:3px solid #fff;border-bottom:0;border-radius:130px 130px 0 0;background:#102b56cc;color:#fff;text-align:center;padding-top:13px;box-shadow:0 4px 13px #132a4d99;pointer-events:none}.speed{font-size:28px;font-weight:1000;line-height:.8}.unit{font-size:9px;font-weight:900;letter-spacing:2px;color:#aee6ff}.controls{position:fixed;z-index:4;left:0;right:0;bottom:17px;display:flex;justify-content:space-between;padding:0 16px}.cluster{display:flex;gap:8px}.controls button{border:2px solid #fff;color:white;font-weight:1000;box-shadow:0 4px 10px #10233e99;cursor:pointer}.turn{width:52px;height:52px;border-radius:15px;background:#24477f;font-size:22px}.pedal{width:65px;height:65px;border-radius:50%;font-size:10px}.gas{background:#e43d43}.brake{background:#3b4369}.controls button:active{transform:scale(.94)}#overlay{position:fixed;z-index:8;inset:0;display:grid;place-items:center;text-align:center;padding:25px;background:linear-gradient(150deg,#071d47e8,#174d89dd 48%,#e3333ba8);color:#fff}#card{max-width:320px}.tag{font-size:11px;letter-spacing:4px;font-weight:1000;color:#ffe16c}.title{font-size:55px;line-height:.78;letter-spacing:-4px;font-weight:1000;margin:18px;text-shadow:4px 4px #101f44}.title span{color:#ff5353}.copy{font-size:16px;line-height:1.5}.start{border:3px solid #ffed9d;border-radius:4px;background:#e93842;color:#fff;padding:15px 27px;font-weight:1000;box-shadow:0 5px #741d37;cursor:pointer}.tip{font-size:12px;color:#fff4c5;margin-top:17px}
+</style></head><body><div class="hud"><div><div class="lab">DISTANCE</div><div id="dist" class="num">0 m</div></div><div class="r"><div class="lab">LAP</div><div id="lap" class="num">1</div></div></div><div id="speedometer"><div id="speed" class="speed">0</div><div class="unit">KM/H</div></div><div class="controls"><div class="cluster"><button id="left" class="turn">←</button><button id="right" class="turn">→</button></div><div class="cluster"><button id="brake" class="pedal brake">BRAKE</button><button id="gas" class="pedal gas">GAS</button></div></div><div id="overlay"><div id="card"><div class="tag">OPEN-WHEEL ARCADE RACING</div><div class="title">APEX<br><span>RUSH</span></div><p id="copy" class="copy">You are in control: hold GAS to accelerate, brake for the corners, and steer around traffic.</p><button id="start" class="start">START ENGINE</button><div class="tip">W / ↑ accelerate · S / ↓ brake · A/D or arrows steer</div></div></div>
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js";
-const scene=new THREE.Scene();scene.background=new THREE.Color(0x83bce7);scene.fog=new THREE.Fog(0x83bce7,18,65);
-const camera=new THREE.PerspectiveCamera(60,innerWidth/innerHeight,.1,100);camera.position.set(0,4.2,9.5);camera.lookAt(0,.4,-9);
-const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);renderer.outputColorSpace=THREE.SRGBColorSpace;renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);
-scene.add(new THREE.HemisphereLight(0xf5fcff,0x35404b,2.6));const sun=new THREE.DirectionalLight(0xfff0bd,2.5);sun.position.set(-8,15,6);sun.castShadow=true;scene.add(sun);
-const grass=new THREE.Mesh(new THREE.PlaneGeometry(50,140),new THREE.MeshStandardMaterial({color:0x4ba657,roughness:.92}));grass.rotation.x=-Math.PI/2;grass.position.z=-48;scene.add(grass);
-const track=new THREE.Mesh(new THREE.PlaneGeometry(9,140),new THREE.MeshStandardMaterial({color:0x273341,roughness:.85}));track.rotation.x=-Math.PI/2;track.position.y=.01;track.position.z=-48;scene.add(track);
-const curbMat=new THREE.MeshStandardMaterial({color:0xf4f1e4,roughness:.8}),redMat=new THREE.MeshStandardMaterial({color:0xe3393f,roughness:.8});
-for(let z=-110;z<18;z+=1.4){[-4.65,4.65].forEach(x=>{const curb=new THREE.Mesh(new THREE.BoxGeometry(.35,.08,.7),Math.floor((z+110)/1.4)%2?curbMat:redMat);curb.position.set(x,.05,z);scene.add(curb)});if(Math.floor(z)%5===0){const stripe=new THREE.Mesh(new THREE.BoxGeometry(.12,.02,1.5),new THREE.MeshBasicMaterial({color:0xe0eaf3}));stripe.position.set(0,.03,z);scene.add(stripe)}}
-const stands=new THREE.Group();scene.add(stands);for(let i=0;i<30;i++){const h=1+Math.random()*3,side=Math.random()<.5?-1:1;const box=new THREE.Mesh(new THREE.BoxGeometry(1.7,h,1),new THREE.MeshStandardMaterial({color:Math.random()<.5?0x255c9d:0xe24c4d,roughness:.72}));box.position.set(side*(6.6+Math.random()*3),h/2,-Math.random()*80);stands.add(box)}
+const s=new THREE.Scene(),c=new THREE.PerspectiveCamera(60,innerWidth/innerHeight,.1,100),r=new THREE.WebGLRenderer({antialias:true});r.setSize(innerWidth,innerHeight);r.setPixelRatio(Math.min(devicePixelRatio,2));r.outputColorSpace=THREE.SRGBColorSpace;document.body.appendChild(r.domElement);s.background=new THREE.Color(0x7dbfe7);s.fog=new THREE.Fog(0x7dbfe7,17,70);c.position.set(0,3.6,8.8);c.lookAt(0,.4,-9);s.add(new THREE.HemisphereLight(0xffffff,0x384554,2.8));let sun=new THREE.DirectionalLight(0xffefc2,2.4);sun.position.set(-8,16,5);s.add(sun);
+let ground=new THREE.Mesh(new THREE.PlaneGeometry(50,160),new THREE.MeshStandardMaterial({color:0x4da35c,roughness:1}));ground.rotation.x=-Math.PI/2;ground.position.z=-55;s.add(ground);let road=new THREE.Mesh(new THREE.PlaneGeometry(9,160),new THREE.MeshStandardMaterial({color:0x27313d,roughness:.88}));road.rotation.x=-Math.PI/2;road.position.y=.02;road.position.z=-55;s.add(road);let roadBits=[];for(let z=-118;z<10;z+=2){let g=new THREE.Group();[-4.6,4.6].forEach((x,ix)=>{let q=new THREE.Mesh(new THREE.BoxGeometry(.36,.07,.95),new THREE.MeshStandardMaterial({color:((z/2+ix)%2)?0xe53c42:0xf4eee1}));q.position.set(x,.06,0);g.add(q)});if(z%8===0){let m=new THREE.Mesh(new THREE.BoxGeometry(.13,.025,2),new THREE.MeshBasicMaterial({color:0xffffff}));m.position.y=.04;g.add(m)}g.position.z=z;s.add(g);roadBits.push(g)}
+function formula(col){let g=new THREE.Group(),m=new THREE.MeshStandardMaterial({color:col,metalness:.25,roughness:.32}),d=new THREE.MeshStandardMaterial({color:0x0e1119});let b=new THREE.Mesh(new THREE.BoxGeometry(.76,.25,1.7),m);b.position.y=.34;g.add(b);let nose=new THREE.Mesh(new THREE.ConeGeometry(.29,1.2,4),m);nose.rotation.x=-Math.PI/2;nose.position.set(0,.32,-1.23);g.add(nose);let cockpit=new THREE.Mesh(new THREE.SphereGeometry(.27,12,8),d);cockpit.scale.set(1,.5,1.35);cockpit.position.set(0,.59,.12);g.add(cockpit);let wing=new THREE.Mesh(new THREE.BoxGeometry(1.32,.08,.32),m);wing.position.set(0,.26,-1.58);g.add(wing);[-1,1].forEach(a=>[-.75,.55].forEach(z=>{let wh=new THREE.Mesh(new THREE.CylinderGeometry(.24,.24,.17,10),d);wh.rotation.z=Math.PI/2;wh.position.set(a*.48,.23,z);g.add(wh)}));return g}
+let car=formula(0xf3313d);car.position.set(0,.02,2);s.add(car);let traffic=[];
+function addTraffic(){let x=[-2.55,0,2.55][Math.floor(Math.random()*3)],g=formula([0x3a75e5,0xffbf32,0x58c68c,0xa65ad9][Math.floor(Math.random()*4)]);g.position.set(x,.02,-44);s.add(g);traffic.push(g)}
</script></body></html>

v2Atual

@joaobarrosfranca · 8/12/2026, 3:59:20 PM

Diferença em relação à v1.

-<!doctype html>
-<html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><title>Apex Rush 3D</title>
-<style>
-*{box-sizing:border-box}html,body{margin:0;height:100%;overflow:hidden;background:#7db9e5;font-family:system-ui,-apple-system,sans-serif;touch-action:none}canvas{display:block}#hud{position:fixed;z-index:5;top:0;left:0;right:0;padding:18px 20px;display:flex;justify-content:space-between;color:#fff;text-shadow:0 2px 7px #17233d;pointer-events:none}.label{font-size:10px;font-weight:950;letter-spacing:1.7px}.value{font-size:30px;font-weight:1000;line-height:1}.right{text-align:right}.controls{position:fixed;z-index:6;left:0;right:0;bottom:18px;padding:0 18px;display:flex;justify-content:space-between}.controls button{width:61px;height:61px;border-radius:50%;border:3px solid #fff;color:#fff;font-size:26px;font-weight:1000;background:#113b74bd;box-shadow:0 5px 12px #12264988}.controls button:active{background:#f22f39;transform:scale(.93)}#cover{position:fixed;z-index:10;inset:0;display:grid;place-items:center;text-align:center;padding:27px;background:linear-gradient(150deg,#091d46e8,#174e8bde 48%,#e3323aa8);color:#fff}#card{max-width:325px}.tag{font-size:11px;font-weight:950;letter-spacing:4px;color:#ffde61}.title{font-size:56px;line-height:.78;font-weight:1000;letter-spacing:-4px;margin:18px 0 21px;text-shadow:4px 4px 0 #111e43}.title span{color:#ff494c}.copy{font-size:16px;line-height:1.5;color:#edf7ff;margin-bottom:27px}#start{border:3px solid #ffeb9a;border-radius:4px;background:#f23742;color:#fff;padding:15px 28px;font-size:14px;font-weight:1000;letter-spacing:1px;box-shadow:0 5px 0 #751e3c;cursor:pointer}#start:active{transform:translateY(3px);box-shadow:0 2px 0 #751e3c}.hint{font-size:12px;color:#fff2bf;margin-top:18px}
-</style></head><body>
-<div id="hud"><div><div class="label">DISTANCE</div><div id="score" class="value">0</div></div><div class="right"><div class="label">LAP</div><div id="lap" class="value">1</div></div></div>
-<div class="controls"><button id="left" aria-label="Steer left">←</button><button id="right" aria-label="Steer right">→</button></div>
-<div id="cover"><div id="card"><div class="tag">OPEN WHEEL ARCADE RACING</div><div class="title">APEX<br><span>RUSH</span></div><div id="copy" class="copy">Thread the traffic, hold the racing line, and make every second count.</div><button id="start" type="button">START ENGINE</button><div class="hint">Hold ← / → to steer · Arrow keys also work</div></div></div>
+<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><style>
+*{box-sizing:border-box}html,body{margin:0;overflow:hidden;background:#77bde7;font-family:system-ui,sans-serif;touch-action:none}canvas{position:fixed;inset:0;z-index:0}.hud{position:fixed;z-index:3;top:0;left:0;right:0;padding:17px;display:flex;justify-content:space-between;color:white;text-shadow:0 2px 6px #173358;pointer-events:none}.lab{font-size:10px;font-weight:1000;letter-spacing:1.7px}.num{font-size:29px;font-weight:1000}.r{text-align:right}#speedometer{position:fixed;z-index:3;left:50%;bottom:18px;transform:translateX(-50%);width:126px;height:68px;border:3px solid #fff;border-bottom:0;border-radius:130px 130px 0 0;background:#102b56cc;color:#fff;text-align:center;padding-top:13px;box-shadow:0 4px 13px #132a4d99;pointer-events:none}.speed{font-size:28px;font-weight:1000;line-height:.8}.unit{font-size:9px;font-weight:900;letter-spacing:2px;color:#aee6ff}.controls{position:fixed;z-index:4;left:0;right:0;bottom:17px;display:flex;justify-content:space-between;padding:0 16px}.cluster{display:flex;gap:8px}.controls button{border:2px solid #fff;color:white;font-weight:1000;box-shadow:0 4px 10px #10233e99;cursor:pointer}.turn{width:52px;height:52px;border-radius:15px;background:#24477f;font-size:22px}.pedal{width:65px;height:65px;border-radius:50%;font-size:10px}.gas{background:#e43d43}.brake{background:#3b4369}.controls button:active{transform:scale(.94)}#overlay{position:fixed;z-index:8;inset:0;display:grid;place-items:center;text-align:center;padding:25px;background:linear-gradient(150deg,#071d47e8,#174d89dd 48%,#e3333ba8);color:#fff}#card{max-width:320px}.tag{font-size:11px;letter-spacing:4px;font-weight:1000;color:#ffe16c}.title{font-size:55px;line-height:.78;letter-spacing:-4px;font-weight:1000;margin:18px;text-shadow:4px 4px #101f44}.title span{color:#ff5353}.copy{font-size:16px;line-height:1.5}.start{border:3px solid #ffed9d;border-radius:4px;background:#e93842;color:#fff;padding:15px 27px;font-weight:1000;box-shadow:0 5px #741d37;cursor:pointer}.tip{font-size:12px;color:#fff4c5;margin-top:17px}
+</style></head><body><div class="hud"><div><div class="lab">DISTANCE</div><div id="dist" class="num">0 m</div></div><div class="r"><div class="lab">LAP</div><div id="lap" class="num">1</div></div></div><div id="speedometer"><div id="speed" class="speed">0</div><div class="unit">KM/H</div></div><div class="controls"><div class="cluster"><button id="left" class="turn">←</button><button id="right" class="turn">→</button></div><div class="cluster"><button id="brake" class="pedal brake">BRAKE</button><button id="gas" class="pedal gas">GAS</button></div></div><div id="overlay"><div id="card"><div class="tag">OPEN-WHEEL ARCADE RACING</div><div class="title">APEX<br><span>RUSH</span></div><p id="copy" class="copy">You are in control: hold GAS to accelerate, brake for the corners, and steer around traffic.</p><button id="start" class="start">START ENGINE</button><div class="tip">W / ↑ accelerate · S / ↓ brake · A/D or arrows steer</div></div></div>
<script type="module">
import * as THREE from "https://cdn.jsdelivr.net/npm/three@0.160.0/build/three.module.js";
-const scene=new THREE.Scene();scene.background=new THREE.Color(0x83bce7);scene.fog=new THREE.Fog(0x83bce7,18,65);
-const camera=new THREE.PerspectiveCamera(60,innerWidth/innerHeight,.1,100);camera.position.set(0,4.2,9.5);camera.lookAt(0,.4,-9);
-const renderer=new THREE.WebGLRenderer({antialias:true});renderer.setPixelRatio(Math.min(devicePixelRatio,2));renderer.setSize(innerWidth,innerHeight);renderer.outputColorSpace=THREE.SRGBColorSpace;renderer.shadowMap.enabled=true;document.body.appendChild(renderer.domElement);
-scene.add(new THREE.HemisphereLight(0xf5fcff,0x35404b,2.6));const sun=new THREE.DirectionalLight(0xfff0bd,2.5);sun.position.set(-8,15,6);sun.castShadow=true;scene.add(sun);
-const grass=new THREE.Mesh(new THREE.PlaneGeometry(50,140),new THREE.MeshStandardMaterial({color:0x4ba657,roughness:.92}));grass.rotation.x=-Math.PI/2;grass.position.z=-48;scene.add(grass);
-const track=new THREE.Mesh(new THREE.PlaneGeometry(9,140),new THREE.MeshStandardMaterial({color:0x273341,roughness:.85}));track.rotation.x=-Math.PI/2;track.position.y=.01;track.position.z=-48;scene.add(track);
-const curbMat=new THREE.MeshStandardMaterial({color:0xf4f1e4,roughness:.8}),redMat=new THREE.MeshStandardMaterial({color:0xe3393f,roughness:.8});
-for(let z=-110;z<18;z+=1.4){[-4.65,4.65].forEach(x=>{const curb=new THREE.Mesh(new THREE.BoxGeometry(.35,.08,.7),Math.floor((z+110)/1.4)%2?curbMat:redMat);curb.position.set(x,.05,z);scene.add(curb)});if(Math.floor(z)%5===0){const stripe=new THREE.Mesh(new THREE.BoxGeometry(.12,.02,1.5),new THREE.MeshBasicMaterial({color:0xe0eaf3}));stripe.position.set(0,.03,z);scene.add(stripe)}}
-const stands=new THREE.Group();scene.add(stands);for(let i=0;i<30;i++){const h=1+Math.random()*3,side=Math.random()<.5?-1:1;const box=new THREE.Mesh(new THREE.BoxGeometry(1.7,h,1),new THREE.MeshStandardMaterial({color:Math.random()<.5?0x255c9d:0xe24c4d,roughness:.72}));box.position.set(side*(6.6+Math.random()*3),h/2,-Math.random()*80);stands.add(box)}
+const s=new THREE.Scene(),c=new THREE.PerspectiveCamera(60,innerWidth/innerHeight,.1,100),r=new THREE.WebGLRenderer({antialias:true});r.setSize(innerWidth,innerHeight);r.setPixelRatio(Math.min(devicePixelRatio,2));r.outputColorSpace=THREE.SRGBColorSpace;document.body.appendChild(r.domElement);s.background=new THREE.Color(0x7dbfe7);s.fog=new THREE.Fog(0x7dbfe7,17,70);c.position.set(0,3.6,8.8);c.lookAt(0,.4,-9);s.add(new THREE.HemisphereLight(0xffffff,0x384554,2.8));let sun=new THREE.DirectionalLight(0xffefc2,2.4);sun.position.set(-8,16,5);s.add(sun);
+let ground=new THREE.Mesh(new THREE.PlaneGeometry(50,160),new THREE.MeshStandardMaterial({color:0x4da35c,roughness:1}));ground.rotation.x=-Math.PI/2;ground.position.z=-55;s.add(ground);let road=new THREE.Mesh(new THREE.PlaneGeometry(9,160),new THREE.MeshStandardMaterial({color:0x27313d,roughness:.88}));road.rotation.x=-Math.PI/2;road.position.y=.02;road.position.z=-55;s.add(road);let roadBits=[];for(let z=-118;z<10;z+=2){let g=new THREE.Group();[-4.6,4.6].forEach((x,ix)=>{let q=new THREE.Mesh(new THREE.BoxGeometry(.36,.07,.95),new THREE.MeshStandardMaterial({color:((z/2+ix)%2)?0xe53c42:0xf4eee1}));q.position.set(x,.06,0);g.add(q)});if(z%8===0){let m=new THREE.Mesh(new THREE.BoxGeometry(.13,.025,2),new THREE.MeshBasicMaterial({color:0xffffff}));m.position.y=.04;g.add(m)}g.position.z=z;s.add(g);roadBits.push(g)}
+function formula(col){let g=new THREE.Group(),m=new THREE.MeshStandardMaterial({color:col,metalness:.25,roughness:.32}),d=new THREE.MeshStandardMaterial({color:0x0e1119});let b=new THREE.Mesh(new THREE.BoxGeometry(.76,.25,1.7),m);b.position.y=.34;g.add(b);let nose=new THREE.Mesh(new THREE.ConeGeometry(.29,1.2,4),m);nose.rotation.x=-Math.PI/2;nose.position.set(0,.32,-1.23);g.add(nose);let cockpit=new THREE.Mesh(new THREE.SphereGeometry(.27,12,8),d);cockpit.scale.set(1,.5,1.35);cockpit.position.set(0,.59,.12);g.add(cockpit);let wing=new THREE.Mesh(new THREE.BoxGeometry(1.32,.08,.32),m);wing.position.set(0,.26,-1.58);g.add(wing);[-1,1].forEach(a=>[-.75,.55].forEach(z=>{let wh=new THREE.Mesh(new THREE.CylinderGeometry(.24,.24,.17,10),d);wh.rotation.z=Math.PI/2;wh.position.set(a*.48,.23,z);g.add(wh)}));return g}
+let car=formula(0xf3313d);car.position.set(0,.02,2);s.add(car);let traffic=[];
+function addTraffic(){let x=[-2.55,0,2.55][Math.floor(Math.random()*3)],g=formula([0x3a75e5,0xffbf32,0x58c68c,0xa65ad9][Math.floor(Math.random()*4)]);g.position.set(x,.02,-44);s.add(g);traffic.push(g)}
</script></body></html>
-function car(color){const g=new THREE.Group(),bodyMat=new THREE.MeshStandardMaterial({color,metalness:.28,roughness:.35}),dark=new THREE.MeshStandardMaterial({color:0x10131d,roughness:.5});const body=new THREE.Mesh(new THREE.BoxGeometry(.72,.26,1.7),bodyMat);body.position.y=.4;g.add(body);const nose=new THREE.Mesh(new THREE.ConeGeometry(.32,1.25,4),bodyMat);nose.rotation.x=-Math.PI/2;nose.position.set(0,.36,-1.25);g.add(nose);const cockpit=new THREE.Mesh(new THREE.SphereGeometry(.32,14,10),dark);cockpit.scale.set(1,.48,1.25);cockpit.position.set(0,.64,.18);g.add(cockpit);const wing=new THREE.Mesh(new THREE.BoxGeometry(1.32,.08,.35),bodyMat);wing.position.set(0,.28,-1.66);g.add(wing);const rear=new THREE.Mesh(new THREE.BoxGeometry(1.15,.1,.23),dark);rear.position.set(0,.76,.86);g.add(rear);[-1,1].forEach(s=>[-.78,.55].forEach(z=>{const wheel=new THREE.Mesh(new THREE.CylinderGeometry(.27,.27,.18,12),dark);wheel.rotation.z=Math.PI/2;wheel.position.set(s*.48,.27,z);g.add(wheel)}));return g}
-function car(color){const g=new THREE.Group(),bodyMat=new THREE.MeshStandardMaterial({color,metalness:.28,roughness:.35}),dark=new THREE.MeshStandardMaterial({color:0x10131d,roughness:.5});const body=new THREE.Mesh(new THREE.BoxGeometry(.72,.26,1.7),bodyMat);body.position.y=.4;g.add(body);const nose=new THREE.Mesh(new THREE.ConeGeometry(.32,1.25,4),bodyMat);nose.rotation.x=-Math.PI/2;nose.position.set(0,.36,-1.25);g.add(nose);const cockpit=new THREE.Mesh(new THREE.SphereGeometry(.32,14,10),dark);cockpit.scale.set(1,.48,1.25);cockpit.position.set(0,.64,.18);g.add(cockpit);const wing=new THREE.Mesh(new THREE.BoxGeometry(1.32,.08,.35),bodyMat);wing.position.set(0,.28,-1.66);g.add(wing);const rear=new THREE.Mesh(new THREE.BoxGeometry(1.15,.1,.23),dark);rear.position.set(0,.76,.86);g.add(rear);[-1,1].forEach(s=>[-.78,.55].forEach(z=>{const wheel=new THREE.Mesh(new THREE.CylinderGeometry(.27,.27,.18,12),dark);wheel.rotation.z=Math.PI/2;wheel.position.set(s*.48,.27,z);g.add(wheel)}));return g}
-const player=car(0xf12d3c);player.position.set(0,.04,2);scene.add(player);
-const player=car(0xf12d3c);player.position.set(0,.04,2);scene.add(player);
-const racers=[];function spawn(){const c=car([0x3b75e5,0xffbd2e,0x47c98c,0xa058d4][Math.floor(Math.random()*4)]);c.position.set([-2.5,0,2.5][Math.floor(Math.random()*3)],.04,-42);scene.add(c);racers.push(c)}
-const racers=[];function spawn(){const c=car([0x3b75e5,0xffbd2e,0x47c98c,0xa058d4][Math.floor(Math.random()*4)]);c.position.set([-2.5,0,2.5][Math.floor(Math.random()*3)],.04,-42);scene.add(c);racers.push(c)}
-let steer=0,running=false,score=0,lap=1,last=0,next=0,playerX=0;
-let steer=0,running=false,score=0,lap=1,last=0,next=0,playerX=0;
-const scoreEl=document.querySelector("#score"),lapEl=document.querySelector("#lap"),cover=document.querySelector("#cover"),copy=document.querySelector("#copy"),start=document.querySelector("#start");
-const scoreEl=document.querySelector("#score"),lapEl=document.querySelector("#lap"),cover=document.querySelector("#cover"),copy=document.querySelector("#copy"),start=document.querySelector("#start");
-function hold(el,v){el.addEventListener("pointerdown",e=>{e.preventDefault();steer=v});["pointerup","pointerleave","pointercancel"].forEach(t=>el.addEventListener(t,()=>steer=0))}
-function hold(el,v){el.addEventListener("pointerdown",e=>{e.preventDefault();steer=v});["pointerup","pointerleave","pointercancel"].forEach(t=>el.addEventListener(t,()=>steer=0))}
-hold(document.querySelector("#left"),-1);hold(document.querySelector("#right"),1);
-hold(document.querySelector("#left"),-1);hold(document.querySelector("#right"),1);
-function clean(){racers.forEach(c=>scene.remove(c));racers.length=0}
-function clean(){racers.forEach(c=>scene.remove(c));racers.length=0}
-function begin(){clean();score=0;lap=1;playerX=0;player.position.x=0;scoreEl.textContent=0;lapEl.textContent=1;running=true;cover.style.display="none";last=0;next=0}
-function begin(){clean();score=0;lap=1;playerX=0;player.position.x=0;scoreEl.textContent=0;lapEl.textContent=1;running=true;cover.style.display="none";last=0;next=0}
-function crash(){running=false;copy.innerHTML="You covered <b>"+score+"</b> metres.<br>Brake later, turn sharper, and chase the next lap.";start.textContent="RACE AGAIN";cover.style.display="grid";clean()}
-function crash(){running=false;copy.innerHTML="You covered <b>"+score+"</b> metres.<br>Brake later, turn sharper, and chase the next lap.";start.textContent="RACE AGAIN";cover.style.display="grid";clean()}
-start.addEventListener("click",begin);
-start.addEventListener("click",begin);
-addEventListener("keydown",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"){e.preventDefault();steer=-1}if(k==="arrowright"||k==="d"){e.preventDefault();steer=1}if((k===" "||k==="enter")&&!running)begin()});addEventListener("keyup",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"||k==="arrowright"||k==="d")steer=0});
-addEventListener("keydown",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"){e.preventDefault();steer=-1}if(k==="arrowright"||k==="d"){e.preventDefault();steer=1}if((k===" "||k==="enter")&&!running)begin()});addEventListener("keyup",e=>{const k=e.key.toLowerCase();if(k==="arrowleft"||k==="a"||k==="arrowright"||k==="d")steer=0});
-function animate(t){requestAnimationFrame(animate);const dt=Math.min(35,last?t-last:16);last=t;if(running){const pace=.041+Math.min(score,400)/14000;playerX=Math.max(-3.85,Math.min(3.85,playerX+steer*dt*.0055));player.position.x+=(playerX-player.position.x)*.18;player.rotation.z=-steer*.14;player.rotation.y=-steer*.05;if(t>next){spawn();next=t+Math.max(430,820-score*1.3)}for(let i=racers.length-1;i>=0;i--){const c=racers[i];c.position.z+=pace*dt;c.rotation.z=Math.sin(t*.004+i)*.035;if(c.position.z>1&&c.position.z<3.2&&Math.abs(c.position.x-player.position.x)<.82){crash();break}if(c.position.z>11){scene.remove(c);racers.splice(i,1);score++;scoreEl.textContent=score;if(score%70===0){lap++;lapEl.textContent=lap}}}camera.position.x+=(player.position.x*.22-camera.position.x)*.035;camera.lookAt(player.position.x*.14,.4,-10)}renderer.render(scene,camera)}
-function animate(t){requestAnimationFrame(animate);const dt=Math.min(35,last?t-last:16);last=t;if(running){const pace=.041+Math.min(score,400)/14000;playerX=Math.max(-3.85,Math.min(3.85,playerX+steer*dt*.0055));player.position.x+=(playerX-player.position.x)*.18;player.rotation.z=-steer*.14;player.rotation.y=-steer*.05;if(t>next){spawn();next=t+Math.max(430,820-score*1.3)}for(let i=racers.length-1;i>=0;i--){const c=racers[i];c.position.z+=pace*dt;c.rotation.z=Math.sin(t*.004+i)*.035;if(c.position.z>1&&c.position.z<3.2&&Math.abs(c.position.x-player.position.x)<.82){crash();break}if(c.position.z>11){scene.remove(c);racers.splice(i,1);score++;scoreEl.textContent=score;if(score%70===0){lap++;lapEl.textContent=lap}}}camera.position.x+=(player.position.x*.22-camera.position.x)*.035;camera.lookAt(player.position.x*.14,.4,-10)}renderer.render(scene,camera)}
-addEventListener("resize",()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight)});animate(0);
-addEventListener("resize",()=>{camera.aspect=innerWidth/innerHeight;camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight)});animate(0);
+const ui={dist:document.getElementById("dist"),lap:document.getElementById("lap"),speed:document.getElementById("speed"),overlay:document.getElementById("overlay"),copy:document.getElementById("copy"),start:document.getElementById("start")};let run=false,speed=0,x=0,steer=0,gas=false,brake=false,distance=0,lap=1,last=0,nextCar=0;
+const ui={dist:document.getElementById("dist"),lap:document.getElementById("lap"),speed:document.getElementById("speed"),overlay:document.getElementById("overlay"),copy:document.getElementById("copy"),start:document.getElementById("start")};let run=false,speed=0,x=0,steer=0,gas=false,brake=false,distance=0,lap=1,last=0,nextCar=0;
+function btn(id,fn){let b=document.getElementById(id);b.addEventListener("pointerdown",e=>{e.preventDefault();fn(true)});["pointerup","pointerleave","pointercancel"].forEach(t=>b.addEventListener(t,()=>fn(false)))}btn("left",v=>steer=v?-1:0);btn("right",v=>steer=v?1:0);btn("gas",v=>gas=v);btn("brake",v=>brake=v);
+function btn(id,fn){let b=document.getElementById(id);b.addEventListener("pointerdown",e=>{e.preventDefault();fn(true)});["pointerup","pointerleave","pointercancel"].forEach(t=>b.addEventListener(t,()=>fn(false)))}btn("left",v=>steer=v?-1:0);btn("right",v=>steer=v?1:0);btn("gas",v=>gas=v);btn("brake",v=>brake=v);
+function lose(){run=false;speed=0;ui.copy.innerHTML="Traffic got you at <b>"+Math.floor(distance)+" m</b>.<br>Use BRAKE and choose a safer line.";ui.start.textContent="RACE AGAIN";ui.overlay.style.display="grid"}function begin(){traffic.forEach(a=>s.remove(a));traffic=[];run=true;speed=0;x=0;distance=0;lap=1;ui.dist.textContent="0 m";ui.lap.textContent="1";ui.overlay.style.display="none";last=0}ui.start.addEventListener("click",begin);
+function lose(){run=false;speed=0;ui.copy.innerHTML="Traffic got you at <b>"+Math.floor(distance)+" m</b>.<br>Use BRAKE and choose a safer line.";ui.start.textContent="RACE AGAIN";ui.overlay.style.display="grid"}function begin(){traffic.forEach(a=>s.remove(a));traffic=[];run=true;speed=0;x=0;distance=0;lap=1;ui.dist.textContent="0 m";ui.lap.textContent="1";ui.overlay.style.display="none";last=0}ui.start.addEventListener("click",begin);
+addEventListener("keydown",e=>{let k=e.key.toLowerCase();if(k==="a"||k==="arrowleft")steer=-1;if(k==="d"||k==="arrowright")steer=1;if(k==="w"||k==="arrowup")gas=true;if(k==="s"||k==="arrowdown")brake=true;if(k==="enter"&&!run)begin()});addEventListener("keyup",e=>{let k=e.key.toLowerCase();if(["a","d","arrowleft","arrowright"].includes(k))steer=0;if(k==="w"||k==="arrowup")gas=false;if(k==="s"||k==="arrowdown")brake=false});
+addEventListener("keydown",e=>{let k=e.key.toLowerCase();if(k==="a"||k==="arrowleft")steer=-1;if(k==="d"||k==="arrowright")steer=1;if(k==="w"||k==="arrowup")gas=true;if(k==="s"||k==="arrowdown")brake=true;if(k==="enter"&&!run)begin()});addEventListener("keyup",e=>{let k=e.key.toLowerCase();if(["a","d","arrowleft","arrowright"].includes(k))steer=0;if(k==="w"||k==="arrowup")gas=false;if(k==="s"||k==="arrowdown")brake=false});
+function loop(t){requestAnimationFrame(loop);let dt=Math.min(35,last?t-last:16);last=t;if(run){speed+=gas?dt*.0007: -dt*.00014;if(brake)speed-=dt*.0011;speed=Math.max(0,Math.min(.055,speed));x=Math.max(-3.9,Math.min(3.9,x+steer*dt*(.0015+speed*.06)));car.position.x+=(x-car.position.x)*.16;car.rotation.z=-steer*.14;car.rotation.y=-steer*.05;let motion=speed*dt;distance+=motion*2.4;ui.dist.textContent=Math.floor(distance)+" m";let newLap=1+Math.floor(distance/650);if(newLap!==lap){lap=newLap;ui.lap.textContent=lap}ui.speed.textContent=Math.round(speed/.055*320);roadBits.forEach(b=>{b.position.z+=motion;if(b.position.z>11)b.position.z-=128});if(speed>.008&&t>nextCar){addTraffic();nextCar=t+Math.max(470,1150-speed*8500)}for(let i=traffic.length-1;i>=0;i--){let a=traffic[i];a.position.z+=motion*(.8+Math.random()*.13);if(a.position.z>1&&a.position.z<3.3&&Math.abs(a.position.x-car.position.x)<.82){lose();break}if(a.position.z>12){s.remove(a);traffic.splice(i,1)}}c.position.x+=(car.position.x*.22-c.position.x)*.04;c.lookAt(car.position.x*.1,.4,-9)}r.render(s,c)}
+function loop(t){requestAnimationFrame(loop);let dt=Math.min(35,last?t-last:16);last=t;if(run){speed+=gas?dt*.0007: -dt*.00014;if(brake)speed-=dt*.0011;speed=Math.max(0,Math.min(.055,speed));x=Math.max(-3.9,Math.min(3.9,x+steer*dt*(.0015+speed*.06)));car.position.x+=(x-car.position.x)*.16;car.rotation.z=-steer*.14;car.rotation.y=-steer*.05;let motion=speed*dt;distance+=motion*2.4;ui.dist.textContent=Math.floor(distance)+" m";let newLap=1+Math.floor(distance/650);if(newLap!==lap){lap=newLap;ui.lap.textContent=lap}ui.speed.textContent=Math.round(speed/.055*320);roadBits.forEach(b=>{b.position.z+=motion;if(b.position.z>11)b.position.z-=128});if(speed>.008&&t>nextCar){addTraffic();nextCar=t+Math.max(470,1150-speed*8500)}for(let i=traffic.length-1;i>=0;i--){let a=traffic[i];a.position.z+=motion*(.8+Math.random()*.13);if(a.position.z>1&&a.position.z<3.3&&Math.abs(a.position.x-car.position.x)<.82){lose();break}if(a.position.z>12){s.remove(a);traffic.splice(i,1)}}c.position.x+=(car.position.x*.22-c.position.x)*.04;c.lookAt(car.position.x*.1,.4,-9)}r.render(s,c)}
+addEventListener("resize",()=>{c.aspect=innerWidth/innerHeight;c.updateProjectionMatrix();r.setSize(innerWidth,innerHeight)});loop(0);
+addEventListener("resize",()=>{c.aspect=innerWidth/innerHeight;c.updateProjectionMatrix();r.setSize(innerWidth,innerHeight)});loop(0);
← Histórico de versões