HOW TO DESIGN
3D GAMES WITH
WEB TECHNOLOGY

Book 01 of Jordi Josa's The Five Planets collection teaches Three.js, HTML5 and WebGL by building a first-person role-playing game, from a first animated scene to textures, lighting, shadows, imported models and camera controls. Get it on Amazon.

✓ FREE Book · Beginner Kindle + PaperbackThree.js + WebGLFirst-person RPG

Book by Jordi Josa · Updated November 3, 2026 · Book guide · about 6 minute read

LIVE DEMO

The book on the right of this page is a live Three.js scene with its real cover as a texture. Launch it full screen to drag to turn it and scroll to zoom. Launch asks for a free Google sign-in first. Press Esc or Exit to return.

Free Google sign-in · Orbit: drag · Zoom: scroll · Esc to exit

About This Book

How to Design 3D Games with Web Technology Book 01 cover by Jordi Josa

Web browsers grew from simple page viewers into platforms that can run full 3D games, with offline storage, native audio, speech, hardware-accelerated WebGL, motion detection and virtual reality. Jordi Josa started The Five Planets collection to explore those technologies one book at a time.

Instead of isolated snippets, the series builds a first-person role-playing game, using it as the reason to introduce each web technology. Book 01 covers Three.js, HTML5 and WebGL and ends with the game's first location.

Buy on Amazon →

As an Amazon Associate I earn from qualifying purchases, at no extra cost to you.

Who This Book Is For

Anyone with basic JavaScript and HTML who wants to add 3D animation to web pages or try game design. No advanced mathematics or WebGL knowledge is needed; everything is explained in a simple way.

What You Will Learn

  • Using Three.js to create and animate a basic scene
  • Preparing the development environment and fixing common problems
  • Geometries and materials from the core library
  • Advanced textures and transparency
  • Lighting the scene and casting shadows
  • Loading models made in other tools and animating them
  • Camera control with keyboard, mouse and even body movement
  • Building the first game location: a medieval village with a castle, cemetery, villagers and a monster-filled forest

Try Before You Buy

Want a taste of the style first? These free tutorials cover the same building blocks: creating and animating simple 3D objects, the first-person game starter and animating GLTF models.

Step-by-Step Code Breakdown

Bonus mini lesson: this is how the floating 3D book at the top of the page is built. Every excerpt is copied exactly from the full code below.

1. Scene, camera and renderer

In plain words: a dark scene, a camera a few steps in front of the book, and a renderer. Tone mapping keeps the bright cover colors from washing out under the lights.

const scene = new THREE.Scene();
scene.background = new THREE.Color(0x07090f);

const camera = new THREE.PerspectiveCamera(40, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0.3, 9);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputColorSpace = THREE.SRGBColorSpace;
document.body.appendChild(renderer.domElement);

2. Light it like a product shot

In plain words: photographers light products with a soft key light from the front side and a colored rim light from behind that outlines the edges. We do the same with two directional lights plus a little ambient fill.

scene.add(new THREE.AmbientLight(0xffffff, 0.6));
const key = new THREE.DirectionalLight(0xffffff, 2.2);
key.position.set(3, 4, 6);
scene.add(key);
const rim = new THREE.DirectionalLight(0x2ad1d6, 3);
rim.position.set(-5, 2, -4);
scene.add(rim);

3. Load the cover as a texture

In plain words: TextureLoader downloads the cover picture and turns it into a texture the graphics card can paint onto 3D shapes. setCrossOrigin('anonymous') is needed because the image lives on another website. Setting the color space to sRGB keeps the colors true to the original picture.

const loader = new THREE.TextureLoader();
loader.setCrossOrigin('anonymous');
const coverTex = loader.load('https://m.media-amazon.com/images/I/91imvv-5W7L._SY466_.jpg');
coverTex.colorSpace = THREE.SRGBColorSpace;
coverTex.anisotropy = renderer.capabilities.getMaxAnisotropy();

4. Build the book from a box with six materials

In plain words: a book is just a thin box. BoxGeometry accepts an array of six materials, one per face, in this order: right, left, top, bottom, front, back. The front gets the cover, the left side becomes the colored spine, and the other edges get a cream paper color so it reads as pages.

const paper = new THREE.MeshStandardMaterial({ color: 0xf1ead8, roughness: 0.9 });
const spineMat = new THREE.MeshStandardMaterial({ color: 0x3a2618, roughness: 0.5 });
const front = new THREE.MeshStandardMaterial({ map: coverTex, roughness: 0.45 });
const back = new THREE.MeshStandardMaterial({ color: 0x3a2618, roughness: 0.6 });
const book = new THREE.Mesh(
  new THREE.BoxGeometry(3, 4.8, 0.5),
  [paper, spineMat, paper, paper, front, back]   // right, left, top, bottom, front, back
);
scene.add(book);

5. Float the book and add drifting sparks

In plain words: a few hundred tiny points drift around the book like dust in a sunbeam. In the loop the book sways side to side with Math.sin, so you see the cover, the spine and the page edges catch the light.

const sparkPos = new Float32Array(400 * 3);
for (let i = 0; i < sparkPos.length; i++) sparkPos[i] = (Math.random() - 0.5) * 14;
const sparkGeo = new THREE.BufferGeometry();
sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPos, 3));
const sparks = new THREE.Points(sparkGeo, new THREE.PointsMaterial({ color: 0x2ad1d6, size: 0.05, transparent: true, opacity: 0.8 }));
scene.add(sparks);

const clock = new THREE.Clock();
function animate() {
  requestAnimationFrame(animate);
  const t = clock.getElapsedTime();
  book.rotation.y = Math.sin(t * 0.5) * 0.6;
  book.rotation.x = Math.sin(t * 0.3) * 0.08;
  book.position.y = Math.sin(t * 0.8) * 0.12;
  sparks.rotation.y = t * 0.03;
  controls.update();
  renderer.render(scene, camera);
}
animate();

Live Scene: The Full Code

Paste this into a file named index.html. It loads the cover image from Amazon, which allows cross-origin use, so it runs from anywhere. Launch Full Code opens this exact code as a standalone page in a new window.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Three.js 3D Book Cover Scene</title>
  <style>
    body { margin: 0; overflow: hidden; background: #000; font-family: system-ui, sans-serif; }
  </style>
  <script type="importmap">
  {
    "imports": {
      "three": "https://unpkg.com/three@0.160.0/build/three.module.js",
      "three/addons/": "https://unpkg.com/three@0.160.0/examples/jsm/"
    }
  }
  </script>
</head>
<body>
<script type="module">
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

// --- 1. Scene, camera and renderer ---
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x07090f);

const camera = new THREE.PerspectiveCamera(40, innerWidth / innerHeight, 0.1, 100);
camera.position.set(0, 0.3, 9);

const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(devicePixelRatio, 2));
renderer.setSize(innerWidth, innerHeight);
renderer.toneMapping = THREE.ACESFilmicToneMapping;
renderer.outputColorSpace = THREE.SRGBColorSpace;
document.body.appendChild(renderer.domElement);

// Orbit controls: drag (mouse or touch) to orbit. Zoom is off on the page so
// vertical swipes still scroll on phones; the full-screen demo turns zoom on.
const controls = new OrbitControls(camera, renderer.domElement);
controls.target.set(0, 0, 0);
controls.enableDamping = true;
controls.enableZoom = false;
controls.enablePan = false;
controls.autoRotate = false;
controls.autoRotateSpeed = 0;
renderer.domElement.style.touchAction = 'pan-y';

// --- 2. Light it like a product shot ---
scene.add(new THREE.AmbientLight(0xffffff, 0.6));
const key = new THREE.DirectionalLight(0xffffff, 2.2);
key.position.set(3, 4, 6);
scene.add(key);
const rim = new THREE.DirectionalLight(0x2ad1d6, 3);
rim.position.set(-5, 2, -4);
scene.add(rim);

// --- 3. Load the cover as a texture ---
const loader = new THREE.TextureLoader();
loader.setCrossOrigin('anonymous');
const coverTex = loader.load('https://m.media-amazon.com/images/I/91imvv-5W7L._SY466_.jpg');
coverTex.colorSpace = THREE.SRGBColorSpace;
coverTex.anisotropy = renderer.capabilities.getMaxAnisotropy();

// --- 4. Build the book from a box with six materials ---
const paper = new THREE.MeshStandardMaterial({ color: 0xf1ead8, roughness: 0.9 });
const spineMat = new THREE.MeshStandardMaterial({ color: 0x3a2618, roughness: 0.5 });
const front = new THREE.MeshStandardMaterial({ map: coverTex, roughness: 0.45 });
const back = new THREE.MeshStandardMaterial({ color: 0x3a2618, roughness: 0.6 });
const book = new THREE.Mesh(
  new THREE.BoxGeometry(3, 4.8, 0.5),
  [paper, spineMat, paper, paper, front, back]   // right, left, top, bottom, front, back
);
scene.add(book);

// --- 5. Float the book and add drifting sparks ---
const sparkPos = new Float32Array(400 * 3);
for (let i = 0; i < sparkPos.length; i++) sparkPos[i] = (Math.random() - 0.5) * 14;
const sparkGeo = new THREE.BufferGeometry();
sparkGeo.setAttribute('position', new THREE.BufferAttribute(sparkPos, 3));
const sparks = new THREE.Points(sparkGeo, new THREE.PointsMaterial({ color: 0x2ad1d6, size: 0.05, transparent: true, opacity: 0.8 }));
scene.add(sparks);

const clock = new THREE.Clock();
function animate() {
  requestAnimationFrame(animate);
  const t = clock.getElapsedTime();
  book.rotation.y = Math.sin(t * 0.5) * 0.6;
  book.rotation.x = Math.sin(t * 0.3) * 0.08;
  book.position.y = Math.sin(t * 0.8) * 0.12;
  sparks.rotation.y = t * 0.03;
  controls.update();
  renderer.render(scene, camera);
}
animate();

addEventListener('resize', () => {
  camera.aspect = innerWidth / innerHeight;
  camera.updateProjectionMatrix();
  renderer.setSize(innerWidth, innerHeight);
});
</script>
</body>
</html>

What To Try Next

  • Swap in your own cover: change the URL in step 3 to any image on a server that allows cross-origin loading.
  • Add a back cover: load a second texture and use it for the last material in the array instead of the plain color.
  • Make it open: split the cover into its own thin box with its pivot on the spine and rotate it on click.
  • Practice the book's first-person camera for free with the first-person game starter.

Frequently Asked Questions

What is How to Design 3D Games with Web Technology about?

It is Book 01 of Jordi Josa's The Five Planets collection. It teaches Three.js, HTML5 and WebGL by building the first location of a first-person role-playing game: a medieval village with a castle, a cemetery, villagers and a forest full of monsters.

Who wrote How to Design 3D Games with Web Technology?

Jordi Josa wrote it. It was independently published in February 2017 (ISBN 1520547455) as the first book of The Five Planets series.

What prior knowledge do I need?

Basic JavaScript and HTML. No advanced mathematics or WebGL experience is needed; the book explains everything step by step.

Is the book up to date with current Three.js?

It was written in 2017 for an older Three.js release, so some code needs updating, for example the old Geometry class is now BufferGeometry and addons load as ES modules. The concepts still apply, and the free tutorials on this site use the pinned Three.js 0.160.0.

Where can I buy How to Design 3D Games with Web Technology?

It is sold on Amazon as a Kindle ebook and a paperback. The Buy on Amazon button on this page links straight to it.

Can I read a Kindle book without a Kindle device?

Yes. The free Kindle app runs on phones, tablets and computers, and Kindle books can also be read in a web browser with Kindle Cloud Reader.

Is the 3D book scene code on this page free?

Yes. The live 3D book scene code is free to copy and Launch Full Code opens it in a new window. Only the full-screen live demo asks for a free Google sign-in.

Browse Games by Genre

Free browser games by Shane Brumback, grouped by genre: FPS, Educational, Arcade, Board game, Sport, Fantasy and Simulation. Each game keeps its release category too.

FPS Games

Educational Games

Arcade Games

Board game Games

Sport Games

Fantasy Games