Skip to content

Instantly share code, notes, and snippets.

@EncodeTheCode
Created May 14, 2025 03:26
Show Gist options
  • Save EncodeTheCode/81a52a3653ae0d682dfb6e0d3552ea16 to your computer and use it in GitHub Desktop.
Save EncodeTheCode/81a52a3653ae0d682dfb6e0d3552ea16 to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>3D Room with Controls</title>
<style>
html, body {
margin: 0;
overflow: hidden;
height: 100%;
}
canvas {
display: block;
}
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<script src="https://cdn.jsdelivr.net/npm/three@0.160.1/build/three.min.js"></script>
<script>
const canvas = document.getElementById('gameCanvas');
const renderer = new THREE.WebGLRenderer({ canvas });
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x202020);
const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 1000);
camera.position.set(0, 2, 5);
const controls = {
forward: false,
leftClick: false
};
const velocity = 0.1;
const light = new THREE.HemisphereLight(0xffffff, 0x444444, 1);
light.position.set(0, 20, 0);
scene.add(light);
const roomSize = 10;
const wallThickness = 0.5;
const wallHeight = 4;
const materials = {
wall: new THREE.MeshLambertMaterial({ color: 0x555555 }),
floor: new THREE.MeshLambertMaterial({ color: 0x333333 }),
ceiling: new THREE.MeshLambertMaterial({ color: 0x444444 }),
box: new THREE.MeshLambertMaterial({ color: 0x888888 })
};
function createWall(x, y, z, w, h, d) {
const geo = new THREE.BoxGeometry(w, h, d);
const mesh = new THREE.Mesh(geo, materials.wall);
mesh.position.set(x, y, z);
scene.add(mesh);
}
// Floor
const floor = new THREE.Mesh(new THREE.PlaneGeometry(roomSize, roomSize), materials.floor);
floor.rotation.x = -Math.PI / 2;
floor.position.y = 0;
scene.add(floor);
// Ceiling
const ceiling = new THREE.Mesh(new THREE.PlaneGeometry(roomSize, roomSize), materials.ceiling);
ceiling.rotation.x = Math.PI / 2;
ceiling.position.y = wallHeight;
scene.add(ceiling);
// Walls
createWall(0, wallHeight / 2, -roomSize / 2, roomSize, wallHeight, wallThickness); // back
createWall(0, wallHeight / 2, roomSize / 2, roomSize, wallHeight, wallThickness); // front
createWall(-roomSize / 2, wallHeight / 2, 0, wallThickness, wallHeight, roomSize); // left
createWall(roomSize / 2, wallHeight / 2, 0, wallThickness, wallHeight, roomSize); // right
// Boxes
for (let i = 0; i < 5; i++) {
const box = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1), materials.box);
box.position.set((Math.random() - 0.5) * roomSize * 0.8, 0.5, (Math.random() - 0.5) * roomSize * 0.8);
scene.add(box);
}
// Mouse control
let pitch = 0, yaw = 0;
let isPointerLocked = false;
document.addEventListener('click', () => {
canvas.requestPointerLock();
});
document.addEventListener('pointerlockchange', () => {
isPointerLocked = document.pointerLockElement === canvas;
});
document.addEventListener('mousemove', (e) => {
if (isPointerLocked) {
yaw -= e.movementX * 0.002;
pitch -= e.movementY * 0.002;
pitch = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, pitch));
}
});
document.addEventListener('keydown', (e) => {
if (e.code === 'KeyW') controls.forward = true;
});
document.addEventListener('keyup', (e) => {
if (e.code === 'KeyW') controls.forward = false;
});
document.addEventListener('mousedown', () => controls.leftClick = true);
document.addEventListener('mouseup', () => controls.leftClick = false);
function animate() {
requestAnimationFrame(animate);
// Direction camera faces
const dir = new THREE.Vector3();
camera.getWorldDirection(dir);
dir.y = 0;
dir.normalize();
if (controls.forward && controls.leftClick) {
camera.position.add(dir.multiplyScalar(velocity));
}
camera.rotation.set(pitch, yaw, 0);
renderer.render(scene, camera);
}
animate();
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment