Supercar X3D
by WildOwl74257 lines9.0 KB🛠️ Three.js (3D graphics)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Supercar X3D</title>
<style>
*{box-sizing:border-box}
body{margin:0;overflow:hidden;background:#07111e;color:white;font-family:Arial,sans-serif}
#ui{position:fixed;inset:0;pointer-events:none}
.panel{pointer-events:auto;background:#071522df;border:1px solid #48d9ff66;
border-radius:14px;padding:12px;backdrop-filter:blur(8px)}
#top{position:absolute;top:10px;left:10px;right:10px;display:flex;
justify-content:space-between;align-items:flex-start;gap:8px}
h2{margin:0 0 6px;color:#52e1ff;font-size:19px}
small{color:#b4d8e8}
select,button,input{accent-color:#36dfff}
select,button{padding:9px;border-radius:8px;border:1px solid #3b8fa9;
background:#10293a;color:white}
button{cursor:pointer}
#tune{position:absolute;right:10px;top:120px;width:190px}
#tune label{display:block;font-size:12px;margin-top:12px}
#tune input{width:100%}
#bottom{position:absolute;bottom:15px;left:0;right:0;display:flex;
justify-content:space-between;align-items:end;padding:0 15px}
.controls{display:flex;gap:9px;align-items:end}
.drive{width:65px;height:65px;font-size:23px;background:#102b40dd}
#gas{height:76px;width:76px;background:#087b91;font-weight:bold}
#stats{font-size:14px;line-height:1.7}
@media(max-width:500px){
#tune{top:126px;width:150px;padding:9px}
#top .panel{padding:9px}
h2{font-size:16px}
.drive{width:54px;height:58px}
#gas{width:66px;height:68px}
#stats{font-size:12px}
}
</style>
</head>
<body>
<div id="ui">
<div id="top">
<div class="panel">
<h2>🏎️ SUPERCAR X3D</h2>
<select id="car">
<option value="0">V12 Hypercar</option>
<option value="1">Red Supercar</option>
<option value="2">Electric GT</option>
<option value="3">Track Racer</option>
</select>
<button id="start">START ENGINE</button>
</div>
<div class="panel" id="stats">
SPEED: <b id="speed">0</b> km/h<br>
DISTANCE: <b id="dist">0</b> m<br>
GEAR: <b id="gear">N</b>
</div>
</div>
<div id="tune" class="panel">
<b>🔧 ENGINE TUNING</b>
<label>Engine RPM <span id="rpmv">45%</span></label>
<input id="rpm" type="range" min="10" max="100" value="45">
<label>Sound Volume <span id="volv">40%</span></label>
<input id="vol" type="range" min="0" max="100" value="40">
<label>Engine Power <span id="powv">60%</span></label>
<input id="power" type="range" min="20" max="100" value="60">
<button id="sound">🔊 Enable Sound</button>
<button id="reset">↻ Reset</button>
<small>RPM, volume aur power badlo ya ghatao.</small>
</div>
<div id="bottom">
<div class="controls">
<button class="drive" id="left">◀</button>
<button class="drive" id="right">▶</button>
</div>
<div class="controls">
<button class="drive" id="brake">▼</button>
<button class="drive" id="gas">GAS ▲</button>
</div>
</div>
</div>
<script>
let scene,camera,renderer,carBody,wheels=[];
let speed=0,distance=0,steer=0,started=false;
let audio,osc,filter,gain;
let held={};
const $=id=>document.getElementById(id);
const colors=[0x00bfff,0xff2525,0x27efb1,0xffa322];
function mat(color,roughness=.35,metalness=.25){
return new THREE.MeshStandardMaterial({color,roughness,metalness});
}
function cube(parent,x,y,z,sx,sy,sz,material){
let m=new THREE.Mesh(new THREE.BoxGeometry(sx,sy,sz),material);
m.position.set(x,y,z);parent.add(m);return m;
}
function makeCar(){
if(carBody)scene.remove(carBody);
carBody=new THREE.Group();wheels=[];
let color=mat(colors[+$('car').value],.24,.65);
let black=mat(0x11151b,.35,.35),glass=mat(0x183c50,.15,.55);
cube(carBody,0,.72,0,1.8,.48,3.65,color);
cube(carBody,0,1.05,-.35,1.5,.55,1.8,color);
cube(carBody,0,1.36,-.42,1.15,.43,1.0,glass);
cube(carBody,0,.98,1.02,1.52,.24,.68,color);
cube(carBody,-.56,.74,-1.52,.35,.13,.08,mat(0xff2020));
cube(carBody,.56,.74,-1.52,.35,.13,.08,mat(0xff2020));
cube(carBody,0,.9,-1.9,1.75,.13,.22,black);
for(let x of [-.96,.96])for(let z of [-1.15,1.15]){
let w=new THREE.Mesh(new THREE.CylinderGeometry(.34,.34,.22,20),
black);
w.rotation.z=Math.PI/2;w.position.set(x,.42,z);
carBody.add(w);wheels.push(w);
let hub=new THREE.Mesh(new THREE.CylinderGeometry(.15,.15,.23,12),
mat(0x9daab5,.25,.8));
hub.rotation.z=Math.PI/2;hub.position.set(x,.42,z);
carBody.add(hub);
}
scene.add(carBody);carBody.position.set(0,0,2);
}
function init(){
scene=new THREE.Scene();
scene.background=new THREE.Color(0x80c8ed);
scene.fog=new THREE.Fog(0x80c8ed,35,180);
camera=new THREE.PerspectiveCamera(62,innerWidth/innerHeight,.1,400);
camera.position.set(0,5,10);
renderer=new THREE.WebGLRenderer({antialias:true});
renderer.setSize(innerWidth,innerHeight);
renderer.setPixelRatio(Math.min(devicePixelRatio,1.7));
renderer.shadowMap.enabled=true;
renderer.shadowMap.type=THREE.PCFSoftShadowMap;
document.body.appendChild(renderer.domElement);
scene.add(new THREE.HemisphereLight(0xc5eaff,0x38452b,2));
let sun=new THREE.DirectionalLight(0xffffff,3);
sun.position.set(-8,15,7);sun.castShadow=true;scene.add(sun);
let ground=new THREE.Mesh(new THREE.PlaneGeometry(300,400),
mat(0x43804b,1));
ground.rotation.x=-Math.PI/2;ground.position.z=-120;
ground.receiveShadow=true;scene.add(ground);
cube(scene,-6,.02,-120,.25,.04,400,mat(0xffffff));
cube(scene,6,.02,-120,.25,.04,400,mat(0xffffff));
for(let z=15;z>-240;z-=8){
cube(scene,0,.025,z, .12,.04,3.5,mat(0xffe88a));
}
// Trees and roadside scenery
for(let z=10;z>-230;z-=13){
for(let side of [-1,1]){
let x=side*(9+Math.random()*7);
let trunk=new THREE.Mesh(new THREE.CylinderGeometry(.15,.22,1.8,7),
mat(0x67452d));
trunk.position.set(x,.9,z);scene.add(trunk);
let leaves=new THREE.Mesh(new THREE.ConeGeometry(1.25,3.6,7),
mat(0x12613c));
leaves.position.set(x,3,z);scene.add(leaves);
}
}
makeCar();
}
function initSound(){
if(audio)return;
audio=new (window.AudioContext||window.webkitAudioContext)();
osc=audio.createOscillator();filter=audio.createBiquadFilter();
gain=audio.createGain();
osc.type='sawtooth';filter.type='lowpass';
osc.connect(filter);filter.connect(gain);gain.connect(audio.destination);
osc.start();updateSound();
}
function updateSound(){
if(!audio)return;
if(audio.state==='suspended')audio.resume();
let rpm=+$('rpm').value/100;
let throttle=held.gas?1:0;
osc.frequency.setTargetAtTime(
45+rpm*150+speed*1.8+throttle*35,audio.currentTime,.06);
filter.frequency.setTargetAtTime(180+rpm*1800,audio.currentTime,.08);
gain.gain.setTargetAtTime(+$('vol').value/100*.11,
audio.currentTime,.05);
$('rpmv').textContent=$('rpm').value+'%';
$('volv').textContent=$('vol').value+'%';
$('powv').textContent=$('power').value+'%';
}
function bindHold(id,key){
let el=$(id);
el.addEventListener('pointerdown',e=>{
e.preventDefault();held[key]=true;
if(el.setPointerCapture)el.setPointerCapture(e.pointerId);
});
for(let ev of ['pointerup','pointercancel','lostpointercapture'])
el.addEventListener(ev,()=>held[key]=false);
}
bindHold('gas','gas');bindHold('brake','brake');
bindHold('left','left');bindHold('right','right');
addEventListener('keydown',e=>{
held[({ArrowUp:'gas',w:'gas',ArrowDown:'brake',s:'brake',
ArrowLeft:'left',a:'left',ArrowRight:'right',d:'right'})[e.key]||e.key]=true;
if(['ArrowUp','ArrowDown','ArrowLeft','ArrowRight',' '].includes(e.key))
e.preventDefault();
});
addEventListener('keyup',e=>{
let k=({ArrowUp:'gas',w:'gas',ArrowDown:'brake',s:'brake',
ArrowLeft:'left',a:'left',ArrowRight:'right',d:'right'})[e.key]||e.key;
held[k]=false;
});
$('start').onclick=()=>{
started=true;initSound();$('start').textContent='ENGINE ON';
};
$('sound').onclick=()=>{
initSound();$('sound').textContent='🔊 Sound Enabled';
};
$('car').onchange=makeCar;
['rpm','vol','power'].forEach(id=>$(id).oninput=updateSound);
$('reset').onclick=()=>{
speed=0;distance=0;steer=0;
carBody.position.x=0;
};
addEventListener('resize',()=>{
camera.aspect=innerWidth/innerHeight;
camera.updateProjectionMatrix();renderer.setSize(innerWidth,innerHeight);
});
init();
let last=performance.now();
function loop(now){
requestAnimationFrame(loop);
let dt=Math.min((now-last)/1000,.04);last=now;
if(started){
let power=+$('power').value/100;
if(held.gas)speed+=42*power*dt;
else speed-=8*dt;
if(held.brake)speed-=65*dt;
speed=Math.max(0,Math.min(260,speed));
if(held.left)steer+=2.0*dt;
if(held.right)steer-=2.0*dt;
if(!held.left&&!held.right)steer*=Math.max(0,1-3*dt);
steer=Math.max(-1,Math.min(1,steer));
carBody.position.x=Math.max(-4,Math.min(4,
carBody.position.x+steer*speed*.012*dt));
carBody.rotation.y=-steer*.12;
wheels.forEach(w=>w.rotation.x+=speed*dt*.08);
distance+=speed*dt/3.6;
$('speed').textContent=Math.round(speed);
$('dist').textContent=Math.floor(distance);
$('gear').textContent=speed<1?'N':Math.min(7,Math.ceil(speed/35));
updateSound();
}
// Follow camera
let target=new THREE.Vector3(carBody.position.x*.55,3.6,8.7);
camera.position.lerp(target,.07);
camera.lookAt(carBody.position.x*.35,0,-3);
// Move road scenery illusion using the ground markings
renderer.render(scene,camera);
}
requestAnimationFrame(loop);
</script>
</body>
</html>
Game Source: Supercar X3D
Creator: WildOwl74
Libraries: three
Complexity: complex (257 lines, 9.0 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: supercar-x3d-wildowl74" to link back to the original. Then publish at arcadelab.ai/publish.