SKYBOUND 3D - Jetpack Cloud Escape
by ThunderPhoenix57478 lines16.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.0, maximum-scale=1.0, user-scalable=no">
<title>SKYBOUND 3D - Jetpack Cloud Escape</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; user-select: none; touch-action: none; }
body {
background: #1e3c72;
color: #ffffff;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
overflow: hidden;
width: 100vw;
height: 100vh;
}
#game-container { width: 100%; height: 100%; position: absolute; top: 0; left: 0; }
/* HUD Overlays */
.hud {
position: absolute;
top: 15px;
left: 0;
width: 100%;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0 20px;
pointer-events: none;
z-index: 10;
}
.hud-card {
background: rgba(15, 30, 60, 0.75);
border: 2px solid #64b5f6;
padding: 10px 18px;
border-radius: 12px;
backdrop-filter: blur(5px);
box-shadow: 0 4px 12px rgba(0,0,0,0.3);
}
.hud-title { font-size: 0.65rem; color: #90caf9; text-transform: uppercase; letter-spacing: 1px; }
.hud-val { font-size: 1.3rem; font-weight: 800; color: #ffffff; }
/* Jetpack Fuel Gauge */
.fuel-bar-container { width: 120px; height: 12px; background: rgba(0,0,0,0.4); border-radius: 6px; overflow: hidden; margin-top: 4px; border: 1px solid #90caf9; }
.fuel-bar-fill { width: 100%; height: 100%; background: #4caf50; transition: width 0.1s; }
/* Touch Control Buttons */
.touch-controls {
position: absolute;
bottom: 20px;
left: 0;
width: 100%;
display: none;
justify-content: space-between;
padding: 0 25px;
z-index: 15;
pointer-events: none;
}
.touch-btn {
width: 65px;
height: 65px;
background: rgba(100, 181, 246, 0.85);
border: 2px solid #ffffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.5rem;
color: #0d1b2a;
font-weight: 900;
pointer-events: auto;
}
.touch-btn:active { background: #ffffff; transform: scale(0.95); }
.touch-group { display: flex; gap: 12px; }
/* Menu / Modal Screen */
.modal {
position: absolute;
top: 0; left: 0; width: 100%; height: 100%;
background: rgba(13, 27, 42, 0.92);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 20;
padding: 20px;
text-align: center;
}
h1 { font-size: 2.8rem; color: #e3f2fd; margin-bottom: 8px; text-shadow: 2px 2px 0px #1e88e5; letter-spacing: 2px; }
p { color: #90caf9; margin-bottom: 25px; max-width: 420px; font-size: 1rem; line-height: 1.5; }
.btn {
background: #1e88e5;
color: #ffffff;
border: none;
padding: 15px 45px;
font-size: 1.2rem;
font-weight: 800;
border-radius: 30px;
cursor: pointer;
box-shadow: 0 5px 0px #1565c0;
}
.btn:active { transform: translateY(3px); box-shadow: 0 2px 0px #1565c0; }
</style>
<!-- Three.js Library -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
</head>
<body>
<div id="game-container"></div>
<div class="hud">
<div class="hud-card">
<div class="hud-title">Altitude</div>
<div class="hud-val" id="alt-txt">0m</div>
</div>
<div class="hud-card">
<div class="hud-title">Jetpack Fuel</div>
<div class="fuel-bar-container"><div class="fuel-bar-fill" id="fuel-bar"></div></div>
</div>
</div>
<div class="touch-controls" id="touchOverlay">
<div class="touch-group">
<div class="touch-btn" id="btnLeft">◀</div>
<div class="touch-btn" id="btnRight">▶</div>
</div>
<div class="touch-group">
<div class="touch-btn" id="btnThrust" style="width: 80px; border-radius: 20px;">THRUST</div>
</div>
</div>
<div class="modal" id="modal">
<h1 id="modalTitle">SKYBOUND 3D</h1>
<p id="modalDesc">Use WASD/Arrows to steer and SPACE to thrust your jetpack! Land on safe clouds to recharge fuel, dodge storm hazards, and reach the Summit Gate!</p>
<button class="btn" onclick="startGame()">LAUNCH ENGINE</button>
</div>
<script>
// --- 1. WEB AUDIO SYNTHESIS ENGINE --- //
let audioCtx = null;
function initAudio() {
if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
if (audioCtx.state === 'suspended') audioCtx.resume();
}
function playAudioTone(freq, type, duration) {
if (!audioCtx) return;
const osc = audioCtx.createOscillator();
const gain = audioCtx.createGain();
osc.type = type; osc.frequency.setValueAtTime(freq, audioCtx.currentTime);
gain.gain.setValueAtTime(0.2, audioCtx.currentTime);
gain.gain.exponentialRampToValueAtTime(0.01, audioCtx.currentTime + duration);
osc.connect(gain); gain.connect(audioCtx.destination);
osc.start(); osc.stop(audioCtx.currentTime + duration);
}
// --- 2. THREE.JS SCENE & PHYSICS ENGINE --- //
let scene, camera, renderer;
let playerGroup, playerMesh, jetpackFire;
let clouds = [], stormClouds = [], meteors = [], summitGate;
let gameRunning = false;
// Physics Constants
const gravity = -0.012;
const thrustPower = 0.028;
let velocity = new THREE.Vector3(0, 0, 0);
let fuel = 100;
let isGrounded = false;
let playerAltitude = 0;
const SUMMIT_ALTITUDE = 180;
// Inputs
const keys = { left: false, right: false, forward: false, backward: false, thrust: false };
function init3D() {
const container = document.getElementById('game-container');
// Blue Atmospheric Sky Scene
scene = new THREE.Scene();
scene.background = new THREE.Color(0x3a7bd5);
scene.fog = new THREE.FogExp2(0x3a7bd5, 0.008);
camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 300);
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
container.appendChild(renderer.domElement);
// Atmospheric Sky Lighting
const ambientLight = new THREE.AmbientLight(0xffffff, 0.85);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight(0xfffaed, 1.2);
sunLight.position.set(20, 100, 50);
scene.add(sunLight);
// Create 3D Character with Jetpack
playerGroup = new THREE.Group();
// Character Body
const bodyGeo = new THREE.CylinderGeometry(0.5, 0.5, 1.4, 8);
const bodyMat = new THREE.MeshStandardMaterial({ color: 0x1e88e5, flatShading: true });
playerMesh = new THREE.Mesh(bodyGeo, bodyMat);
playerMesh.position.y = 0.7;
playerGroup.add(playerMesh);
// Head / Helmet
const headGeo = new THREE.SphereGeometry(0.45, 8, 8);
const headMat = new THREE.MeshStandardMaterial({ color: 0xffcc80, flatShading: true });
const head = new THREE.Mesh(headGeo, headMat);
head.position.y = 1.6;
playerGroup.add(head);
// Jetpack Thrusters
const packGeo = new THREE.BoxGeometry(0.6, 0.8, 0.4);
const packMat = new THREE.MeshStandardMaterial({ color: 0x424242 });
const pack = new THREE.Mesh(packGeo, packMat);
pack.position.set(0, 0.8, -0.45);
playerGroup.add(pack);
// Thruster Flame
const fireGeo = new THREE.ConeGeometry(0.25, 0.6, 6);
const fireMat = new THREE.MeshBasicMaterial({ color: 0xff9800 });
jetpackFire = new THREE.Mesh(fireGeo, fireMat);
jetpackFire.rotation.x = Math.PI;
jetpackFire.position.set(0, 0.2, -0.45);
jetpackFire.visible = false;
playerGroup.add(jetpackFire);
scene.add(playerGroup);
// Build Level Architecture
buildLevel();
window.addEventListener('resize', onResize);
setupInputs();
}
// Procedural Low-Poly Natural Cloud Generation
function createCloudMesh(isStorm = false) {
const group = new THREE.Group();
const mat = new THREE.MeshStandardMaterial({
color: isStorm ? 0x455a64 : 0xffffff,
roughness: 0.9,
flatShading: true
});
const puffCount = 5 + Math.floor(Math.random() * 4);
for (let i = 0; i < puffCount; i++) {
const radius = 1.2 + Math.random() * 1.5;
const geo = new THREE.DodecahedronGeometry(radius, 1);
const mesh = new THREE.Mesh(geo, mat);
mesh.position.set(
(Math.random() - 0.5) * 3.5,
(Math.random() - 0.5) * 0.8,
(Math.random() - 0.5) * 3.5
);
group.add(mesh);
}
return group;
}
function buildLevel() {
// Clear existing arrays
clouds.forEach(c => scene.remove(c.mesh));
stormClouds.forEach(s => scene.remove(s.mesh));
clouds = []; stormClouds = [];
// Starting Base Cloud
const baseCloud = createCloudMesh(false);
baseCloud.position.set(0, -1, 0);
baseCloud.scale.set(2.5, 1, 2.5);
scene.add(baseCloud);
clouds.push({ mesh: baseCloud, y: -1, radius: 6.0, isMoving: false });
// Generate Staircase of Clouds to the Top
for (let y = 10; y <= SUMMIT_ALTITUDE; y += 8) {
const isStorm = Math.random() < 0.25 && y > 30;
const cloud = createCloudMesh(isStorm);
const x = (Math.random() - 0.5) * 24;
const z = (Math.random() - 0.5) * 20;
cloud.position.set(x, y, z);
scene.add(cloud);
const cloudObj = {
mesh: cloud,
y: y,
radius: 3.5,
isMoving: Math.random() < 0.3,
moveSpeed: 0.03 + Math.random() * 0.03,
moveDir: 1
};
if (isStorm) stormClouds.push(cloudObj);
else clouds.push(cloudObj);
}
// Summit Gate at the Top
const gateGeo = new THREE.TorusGeometry(5, 0.4, 8, 24);
const gateMat = new THREE.MeshBasicMaterial({ color: 0xffd54f });
summitGate = new THREE.Mesh(gateGeo, gateMat);
summitGate.rotation.x = Math.PI / 2;
summitGate.position.set(0, SUMMIT_ALTITUDE + 5, 0);
scene.add(summitGate);
}
// --- 3. PHYSICS UPDATES & COLLISION DETECTORS --- //
function updatePhysics() {
if (!gameRunning) return;
// Jetpack Horizontal Thrust Controls
if (keys.left) velocity.x -= 0.012;
if (keys.right) velocity.x += 0.012;
if (keys.forward) velocity.z -= 0.012;
if (keys.backward) velocity.z += 0.012;
// Vertical Jetpack Thrust
if (keys.thrust && fuel > 0) {
velocity.y += thrustPower;
fuel = Math.max(0, fuel - 0.65);
jetpackFire.visible = true;
if (Math.random() < 0.2) playAudioTone(220, 'sawtooth', 0.05);
} else {
jetpackFire.visible = false;
}
// Apply Gravity & Air Resistance
velocity.y += gravity;
velocity.x *= 0.92;
velocity.z *= 0.92;
// Move Player Character
playerGroup.position.add(velocity);
playerAltitude = Math.max(0, Math.floor(playerGroup.position.y));
document.getElementById('alt-txt').innerText = `${playerAltitude}m`;
// Update Fuel Bar UI
const fuelBar = document.getElementById('fuel-bar');
fuelBar.style.width = `${fuel}%`;
fuelBar.style.background = fuel < 25 ? '#f44336' : '#4caf50';
// Cloud Collision Check
isGrounded = false;
clouds.forEach(c => {
// Moving Cloud Logic
if (c.isMoving) {
c.mesh.position.x += c.moveSpeed * c.moveDir;
if (Math.abs(c.mesh.position.x) > 15) c.moveDir *= -1;
}
const dx = playerGroup.position.x - c.mesh.position.x;
const dz = playerGroup.position.z - c.mesh.position.z;
const horizontalDist = Math.sqrt(dx * dx + dz * dz);
// Landing Top Surface Collision
if (horizontalDist < c.radius &&
playerGroup.position.y >= c.mesh.position.y + 0.5 &&
playerGroup.position.y <= c.mesh.position.y + 1.6 &&
velocity.y <= 0) {
playerGroup.position.y = c.mesh.position.y + 1.2;
velocity.y = 0;
isGrounded = true;
// Fuel Recharge on Safe Clouds
if (fuel < 100) fuel = Math.min(100, fuel + 0.8);
}
});
// Storm Cloud Hazard Collision
stormClouds.forEach(s => {
const dx = playerGroup.position.x - s.mesh.position.x;
const dy = playerGroup.position.y - s.mesh.position.y;
const dz = playerGroup.position.z - s.mesh.position.z;
const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
if (dist < 3.2) {
// Zap Fuel & Knockback
fuel = Math.max(0, fuel - 2.5);
velocity.y = -0.1;
playAudioTone(120, 'sawtooth', 0.1);
}
});
// Fall Below Base Failure
if (playerGroup.position.y < -12) {
endGame(false, "Fell through the clouds! Manage your jetpack fuel carefully.");
}
// Check Summit Gate Victory
if (playerGroup.position.distanceTo(summitGate.position) < 5.0) {
endGame(true, "VICTORY! You reached the High Altitude Summit!");
}
// Smooth Camera Follow
camera.position.x = playerGroup.position.x;
camera.position.y = playerGroup.position.y + 6;
camera.position.z = playerGroup.position.z + 16;
camera.lookAt(playerGroup.position.x, playerGroup.position.y + 2, playerGroup.position.z);
}
// --- 4. GAME LOOP & INPUT BINDINGS --- //
function animate() {
requestAnimationFrame(animate);
updatePhysics();
if (summitGate) summitGate.rotation.z += 0.02;
renderer.render(scene, camera);
}
function startGame() {
initAudio();
document.getElementById('modal').style.display = 'none';
// Reset Variables
playerGroup.position.set(0, 2, 0);
velocity.set(0, 0, 0);
fuel = 100;
gameRunning = true;
buildLevel();
}
function endGame(isWin, msg) {
gameRunning = false;
document.getElementById('modal').style.display = 'flex';
document.getElementById('modalTitle').innerText = isWin ? "SUMMIT REACHED!" : "ENGINE FAILURE";
document.getElementById('modalDesc').innerText = msg;
document.querySelector('#modal .btn').innerText = "FLY AGAIN";
}
function setupInputs() {
window.addEventListener('keydown', e => {
if (e.key === 'ArrowLeft' || e.key === 'a') keys.left = true;
if (e.key === 'ArrowRight' || e.key === 'd') keys.right = true;
if (e.key === 'ArrowUp' || e.key === 'w') keys.forward = true;
if (e.key === 'ArrowDown' || e.key === 's') keys.backward = true;
if (e.key === ' ' || e.key === 'Shift') keys.thrust = true;
});
window.addEventListener('keyup', e => {
if (e.key === 'ArrowLeft' || e.key === 'a') keys.left = false;
if (e.key === 'ArrowRight' || e.key === 'd') keys.right = false;
if (e.key === 'ArrowUp' || e.key === 'w') keys.forward = false;
if (e.key === 'ArrowDown' || e.key === 's') keys.backward = false;
if (e.key === ' ' || e.key === 'Shift') keys.thrust = false;
});
// Touch Overlay Controls
if ('ontouchstart' in window) {
document.getElementById('touchOverlay').style.display = 'flex';
const bindTouch = (id, key) => {
const btn = document.getElementById(id);
btn.addEventListener('touchstart', (e) => { e.preventDefault(); keys[key] = true; });
btn.addEventListener('touchend', (e) => { e.preventDefault(); keys[key] = false; });
};
bindTouch('btnLeft', 'left');
bindTouch('btnRight', 'right');
bindTouch('btnThrust', 'thrust');
}
}
function onResize() {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
}
init3D();
animate();
</script>
</body>
</html>
Game Source: SKYBOUND 3D - Jetpack Cloud Escape
Creator: ThunderPhoenix57
Libraries: three
Complexity: complex (478 lines, 16.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: skybound-3d-jetpack-cloud-escape-thunderphoenix57" to link back to the original. Then publish at arcadelab.ai/publish.