← Back to Treaducation
Step 00
Instructions
Read this before you start

A five-step tutorial that takes you from a blank HTML file to a working two-player 3D tank game, built entirely in the browser using Three.js.

No install required. No terminal. No prior experience needed. Just a text editor and Chrome or Firefox.

How it works

Each step is a single HTML file. Open it in your browser and you will see the finished result. Your job is to recreate it yourself from scratch - not to copy the file, but to read the code, understand what it does, and write your own version.

Use the reference files to check your work, look up syntax, or get unstuck. The hints in this page tell you what to build without giving it all away.

Before you start - colours

Throughout these steps you will see colours written as values like 0x00aa44 or 0x87ceeb. These are called hex colour codes, and they work exactly like the colour codes used in web design - the only difference is that web design writes them with a # at the front (#00aa44) while JavaScript writes them with 0x (0x00aa44). They mean the same thing.

You do not need to memorise these or work them out manually. Use a colour picker: go to g.co/color/picker, pick any colour you like, and copy the hex code shown. Just replace the # with 0x when you use it in your code.

Three.js also accepts plain colour names for common colours. Instead of 0x00aa44 you can write 'green', and instead of 0xcc2222 you can write 'red'. This works for: 'red', 'green', 'blue', 'yellow', 'white', 'black', 'orange', 'purple', and other common names. For a specific shade, use the colour picker.

Before you start - coordinates

Three.js places everything in a 3D world using three axes:

X
Left and right.
Positive X is to the right.
Y
Up and down.
Positive Y is upward.
Z
Forward and back.
Negative Z is forward (into the screen).
Positive Z is toward you.

So camera.position.z = 5 puts the camera 5 units toward you, looking at whatever is in front of it. And translateZ(-speed * dt) moves a tank forward because it moves in the negative Z direction.

Positions are always written as three numbers in order: (x, y, z). position.set(0, 40, 80) means: centred left-right, 40 units up, 80 units toward the camera.

Want a visual? See mathsisfun.com - Cartesian Coordinates and scroll to the 3D section.

Before you start - radians

Rotations in Three.js use radians rather than degrees. You don't need to understand the maths behind them - just use this table as a reference:

DegreesRadians (what to write in code)
360Math.PI * 2
180Math.PI
90Math.PI / 2
45Math.PI / 4
-90-Math.PI / 2

So terrainGeo.rotateX(-Math.PI / 2) means "rotate 90 degrees around the X axis" - which tips the plane from vertical (its default) to flat on the ground.

Visual explanation: mathsisfun.com - Radians.

Before you start - experiment

The best way to understand what any value does is to change it and reload the page. Every number in these files is adjustable. There is no magic to values like 1000 for the terrain size or 5 for the camera distance - they were just chosen because they looked good.

Try making the terrain bigger, the camera higher, the tank faster, or the fog closer. If something breaks, Ctrl+Z will undo your change, or open the reference file to find the original value.

The browser console (F12 - Console tab) shows errors in plain English. If something stops working, that is the first place to look.

The five steps

01 Hello World
Goal: get Three.js running and see something on screen.
Your job
Hint: the Camera needs camera.position.z = 5 so it's not inside the cube. The Renderer needs document.body.appendChild(renderer.domElement) to appear on screen.
Make it yours

Your cube should look different from the reference. Change the colour, the size (the numbers in BoxGeometry), the rotation speed, or the rotation axis. Try rotating on Y instead of X, or on both axes at once.

02 Flat Terrain
Goal: replace the cube with an open world you can look around.
Your job
Hint: if the fog colour and the background colour don't match, the horizon will have a visible seam. Use the same hex value for both.
Make it yours

Change the sky colour, the terrain size, the fog distance, or the grid colour. A closer fog makes the world feel small and enclosed; a further one makes it feel vast.

03 Tank and Controls
Goal: build a tank from boxes and drive it around.
Your job
Hint: translateZ moves along the object's OWN local axis, so it always goes "forward" relative to where the tank is pointing. That's what makes it useful here.
Make it yours

Change the tank colours, the hull and turret proportions, the movement speed, the turn speed, and the camera distance behind the tank.

04 Shooting
Goal: aim the turret, fire shells, and hit a target.
Your job
Hint: iterate the shells array BACKWARDS when removing items: for (let i = shells.length - 1; i >= 0; i--). Removing from a forwards loop skips the item after the removed one.
Make it yours

Change the turret rotation speed, the shell speed, the shell size, and the target colour and size. Try making the target move to a new position after each hit.

05 1v1 - The Full Game
Goal: two players, five hits wins, real game.
Your job
Hint: the camera midpoint is new THREE.Vector3().addVectors(p1.tank.position, p2.tank.position).multiplyScalar(0.5)
Make it yours

Change the player colours, the starting positions, the number of hits to win, and the health bar colours. No two students' finished games should look identical - that's how you know it worked.

What's next?

Once you have finished Step 5, here are ideas to keep going:

The full Treads of War source code is on GitHub if you want to see where all these ideas eventually lead.