<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Cosmic Rider - Stylized Edition</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
<style>
body {
overflow: hidden;
margin: 0;
background-color: #020205;
font-family: 'Segoe UI', system-ui, sans-serif;
}
#webgl-canvas {
display: block;
position: fixed;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
}
#ui-layer {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;
pointer-events: none;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 2.5rem;
}
.glass-panel {
background: rgba(10, 10, 25, 0.4);
backdrop-filter: blur(15px);
border: 1px solid rgba(255, 255, 255, 0.1);
box-shadow: 0 8px 32px 0 rgba(0, 0, 0, 0.8);
pointer-events: auto;
}
.pulse {
animation: pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: .5; }
}
</style>
</head>
<body>
<canvas id="webgl-canvas"></canvas>
<div id="ui-layer">
<div class="flex flex-col items-start gap-4">
<div class="glass-panel p-8 rounded-3xl text-white">
<h1 class="text-5xl font-black tracking-tighter text-transparent bg-clip-text bg-gradient-to-r from-yellow-300 via-orange-400 to-red-500">
STELLAR RIDE
</h1>
<p class="text-blue-200 text-lg font-light tracking-widest uppercase mt-2">Beyond the Horizon</p>
</div>
</div>
<div class="flex justify-center mb-4">
<div class="glass-panel px-8 py-4 rounded-2xl text-white text-sm flex items-center gap-3">
<span class="w-2 h-2 rounded-full bg-green-400 pulse"></span>
<span class="opacity-80 tracking-widest font-medium uppercase">Active Exploration Mode</span>
</div>
</div>
</div>
<script>
let scene, camera, renderer, rocketGroup, character, thrusterLight, engineFire;
let isDragging = false, previousMouseX = 0, previousMouseY = 0;
let targetRotationX = 0.3, targetRotationY = 0;
let zoomLevel = 18;
// Function to create a capsule-like shape manually (r128 fix)
function createCapsule(radius, height, material) {
const group = new THREE.Group();
const cylinderGeom = new THREE.CylinderGeometry(radius, radius, height, 32);
const cylinder = new THREE.Mesh(cylinderGeom, material);
const sphereGeom = new THREE.SphereGeometry(radius, 32, 32);
const topSphere = new THREE.Mesh(sphereGeom, material);
topSphere.position.y = height / 2;
const bottomSphere = new THREE.Mesh(sphereGeom, material);
bottomSphere.position.y = -height / 2;
group.add(cylinder, topSphere, bottomSphere);
return group;
}
function init() {
scene = new THREE.Scene();
scene.background = new THREE.Color(0x020206);
scene.fog = new THREE.Fog(0x020206, 10, 100);
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 5, zoomLevel);
renderer = new THREE.WebGLRenderer({
canvas: document.getElementById('webgl-canvas'),
antialias: true,
alpha: true
});
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(window.devicePixelRatio);
// --- Advanced Lighting ---
const ambientLight = new THREE.AmbientLight(0x223366, 1.5);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight(0xffffff, 2.5);
sunLight.position.set(20, 40, 20);
scene.add(sunLight);
const rimLight = new THREE.PointLight(0x6699ff, 3, 50);
rimLight.position.set(-20, 10, -20);
scene.add(rimLight);
// --- Rocket Construction ---
rocketGroup = new THREE.Group();
const bodyGeom = new THREE.CylinderGeometry(0.8, 1.1, 4.5, 32);
const rocketMat = new THREE.MeshStandardMaterial({
color: 0xd63031,
metalness: 0.6,
roughness: 0.3
});
const rocketBody = new THREE.Mesh(bodyGeom, rocketMat);
rocketGroup.add(rocketBody);
const noseGeom = new THREE.ConeGeometry(0.8, 1.8, 32);
const noseMat = new THREE.MeshStandardMaterial({ color: 0xfdcb6e, metalness: 0.4, roughness: 0.2 });
const nose = new THREE.Mesh(noseGeom, noseMat);
nose.position.y = 3.15;
rocketGroup.add(nose);
// Fins
const finShape = new THREE.Shape();
finShape.moveTo(0, 0);
finShape.lineTo(1.2, -1);
finShape.lineTo(1.2, -2.5);
finShape.lineTo(0, -1.8);
const extrudeSettings = { depth: 0.1, bevelEnabled: true, bevelThickness: 0.05, bevelSize: 0.05 };
const finGeom = new THREE.ExtrudeGeometry(finShape, extrudeSettings);
const finMat = new THREE.MeshStandardMaterial({ color: 0x0984e3, metalness: 0.5, roughness: 0.4 });
for(let i=0; i<3; i++) {
const fin = new THREE.Mesh(finGeom, finMat);
fin.rotation.y = (Math.PI * 2 / 3) * i;
fin.position.y = -0.5;
rocketGroup.add(fin);
}
// Engine
const engineGeom = new THREE.CylinderGeometry(0.6, 0.8, 0.5, 32);
const engineMat = new THREE.MeshStandardMaterial({ color: 0x2d3436, metalness: 0.9 });
const engine = new THREE.Mesh(engineGeom, engineMat);
engine.position.y = -2.5;
rocketGroup.add(engine);
const fireGeom = new THREE.ConeGeometry(0.5, 2, 16);
const fireMat = new THREE.MeshBasicMaterial({ color: 0xffaa00, transparent: true, opacity: 0.8 });
engineFire = new THREE.Mesh(fireGeom, fireMat);
engineFire.position.y = -3.5;
engineFire.rotation.x = Math.PI;
rocketGroup.add(engineFire);
thrusterLight = new THREE.PointLight(0xff6600, 5, 10);
thrusterLight.position.y = -3.5;
rocketGroup.add(thrusterLight);
// --- Stylized Character (Fixed r128 compatible) ---
character = new THREE.Group();
const charBodyMat = new THREE.MeshStandardMaterial({ color: 0xe84393, roughness: 0.8 });
const charBody = createCapsule(0.4, 0.6, charBodyMat);
character.add(charBody);
const headGeom = new THREE.SphereGeometry(0.45, 32, 32);
const skinMat = new THREE.MeshStandardMaterial({ color: 0xffdbac, roughness: 0.5 });
const head = new THREE.Mesh(headGeom, skinMat);
head.position.y = 0.9;
character.add(head);
const hairMat = new THREE.MeshStandardMaterial({ color: 0x2d3436, roughness: 0.9 });
const pigtailGeom = new THREE.SphereGeometry(0.28, 16, 16);
const lp = new THREE.Mesh(pigtailGeom, hairMat);
lp.position.set(-0.4, 1.15, 0);
lp.scale.y = 1.3;
character.add(lp);
const rp = new THREE.Mesh(pigtailGeom, hairMat);
rp.position.set(0.4, 1.15, 0);
rp.scale.y = 1.3;
character.add(rp);
const legMat = new THREE.MeshStandardMaterial({ color: 0x6c5ce7 });
const lLeg = createCapsule(0.12, 0.6, legMat);
lLeg.position.set(-0.25, -0.4, 0.4);
lLeg.rotation.x = Math.PI / 1.8;
character.add(lLeg);
const rLeg = createCapsule(0.12, 0.6, legMat);
rLeg.position.set(0.25, -0.4, 0.4);
rLeg.rotation.x = Math.PI / 1.8;
character.add(rLeg);
character.position.set(0, 0.5, 1);
character.rotation.y = Math.PI;
rocketGroup.add(character);
rocketGroup.rotation.z = -Math.PI / 4;
scene.add(rocketGroup);
// --- Environment ---
const starCount = 4000;
const starPos = new Float32Array(starCount * 3);
const starColors = new Float32Array(starCount * 3);
for(let i=0; i < starCount; i++) {
const ix = i * 3;
starPos[ix] = (Math.random() - 0.5) * 250;
starPos[ix+1] = (Math.random() - 0.5) * 250;
starPos[ix+2] = (Math.random() - 0.5) * 250;
const c = new THREE.Color().setHSL(Math.random(), 0.2, 0.8);
starColors[ix] = c.r; starColors[ix+1] = c.g; starColors[ix+2] = c.b;
}
const starGeom = new THREE.BufferGeometry();
starGeom.setAttribute('position', new THREE.BufferAttribute(starPos, 3));
starGeom.setAttribute('color', new THREE.BufferAttribute(starColors, 3));
const starMat = new THREE.PointsMaterial({ size: 0.25, vertexColors: true, transparent: true, opacity: 0.8 });
scene.add(new THREE.Points(starGeom, starMat));
createPlanet(5, 0xff7f50, {x: 35, y: 15, z: -60}, true);
createPlanet(3, 0x00cec9, {x: -40, y: -20, z: -40}, false);
createPlanet(1.2, 0xa29bfe, {x: 15, y: -15, z: -25}, false);
window.addEventListener('resize', onWindowResize);
window.addEventListener('mousedown', (e) => { isDragging = true; previousMouseX = e.clientX; previousMouseY = e.clientY; });
window.addEventListener('mouseup', () => isDragging = false);
window.addEventListener('mousemove', onMouseMove);
window.addEventListener('wheel', (e) => {
zoomLevel += e.deltaY * 0.01;
zoomLevel = Math.max(8, Math.min(60, zoomLevel));
});
animate();
}
function createPlanet(radius, color, pos, ring) {
const group = new THREE.Group();
const geom = new THREE.SphereGeometry(radius, 64, 64);
const mat = new THREE.MeshStandardMaterial({ color: color, roughness: 0.7, metalness: 0.1 });
const planet = new THREE.Mesh(geom, mat);
group.add(planet);
if(ring) {
const ringGeom = new THREE.TorusGeometry(radius + 2, 0.1, 2, 100);
const ringMat = new THREE.MeshStandardMaterial({ color: 0xffffff, transparent: true, opacity: 0.3 });
const planetRing = new THREE.Mesh(ringGeom, ringMat);
planetRing.rotation.x = Math.PI / 2.1;
group.add(planetRing);
}
group.position.set(pos.x, pos.y, pos.z);
scene.add(group);
group.userData.rotSpeed = (Math.random() - 0.5) * 0.005;
return group;
}
function onMouseMove(e) {
if (!isDragging) return;
targetRotationY += (e.clientX - previousMouseX) * 0.005;
targetRotationX += (e.clientY - previousMouseY) * 0.005;
previousMouseX = e.clientX;
previousMouseY = e.clientY;
}
function onWindowResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
function animate() {
requestAnimationFrame(animate);
const time = Date.now() * 0.001;
rocketGroup.position.x = Math.sin(time * 0.4) * 12;
rocketGroup.position.y = Math.cos(time * 0.6) * 6;
rocketGroup.position.z = Math.sin(time * 0.2) * 8;
rocketGroup.rotation.x = Math.sin(time * 0.8) * 0.15;
rocketGroup.rotation.y += 0.01;
rocketGroup.rotation.z = -Math.PI / 4 + Math.cos(time * 0.5) * 0.2;
const fireScale = 1 + Math.sin(time * 20) * 0.2;
engineFire.scale.set(fireScale, fireScale, fireScale);
thrusterLight.intensity = 4 + Math.sin(time * 20) * 2;
character.rotation.x = Math.sin(time * 3) * 0.03;
const camTargetX = Math.sin(targetRotationY) * zoomLevel;
const camTargetZ = Math.cos(targetRotationY) * zoomLevel;
const camTargetY = targetRotationX * 10;
camera.position.lerp(new THREE.Vector3(camTargetX, camTargetY, camTargetZ), 0.05);
camera.lookAt(0, 0, 0);
scene.children.forEach(obj => {
if(obj.userData.rotSpeed) obj.rotation.y += obj.userData.rotSpeed;
});
renderer.render(scene, camera);
}
window.onload = init;
</script>
</body>
</html>
Leave a Reply