Overview
A two-player 3D tank battle game, running entirely in a browser. No downloads, no accounts, no install. By the end of Step 5 each student has a working game they built themselves - and can take home, share, and modify.
Curious beginners aged roughly 12-16. No prior coding experience required. Students who have done a little HTML or JavaScript before will move faster, but the material assumes nothing.
- A laptop or desktop with Chrome or Firefox
- A text editor - Notepad or TextEdit work fine; VS Code is better if available
- The tutorial files work fully offline - Three.js is bundled in the download alongside the step files. No internet connection is needed to run the games.
- The reference files open in a second browser tab to check work against
starter.htmlfrom the download - each student saves their own copy and renames it before starting each step
- Each step is roughly 45-60 minutes for a beginner working independently
- Steps 3 and 5 tend to run longer - budget extra time or split them across sessions
- Steps 1 and 2 work well together as a first session - short and satisfying
- Five sessions of one hour each is a realistic schedule for most groups
- Fast finishers: point them at the "What's next?" ideas in the README, or ask them to explain their code to a classmate
- Download the zip from the Treaducation page and extract it to a folder
- Put the extracted folder somewhere students can access it - a shared drive, USB stick, or send it via your school's file sharing tool
- Each student needs their own copy of the folder. They will be saving files into it as they work.
- Tell each student: open
starter.html, then use File > Save As to save it with a new name (e.g.step1.html) before writing any code. This is their working copy for each step. - Open one of the reference files in a browser yourself before the session so you know what a working version looks like
- Test that the files work on a classroom machine - open
step1-hello-world.htmlin a browser. You should see a rotating green cube. Three.js loads from the local files in the folder, so no internet connection is required for this.
Your role as facilitator
You don't need to know JavaScript to run these sessions. The step files are the answer key. If a student is stuck, the first step is always: "Open the reference file and compare your code to it line by line." The reference files can be opened directly in the browser - to read the code, right-click anywhere on the page and choose View Page Source or Inspect. That skill - reading and comparing code - is itself something worth learning.
Each step ends with a "Make it yours" section. Treat this as mandatory, not optional. Students should change colours, sizes, speeds, and spacing so their version looks different from the reference and from each other. If every student finishes with an identical green cube, the learning did not happen - they copied rather than understood. A quick check: ask a student to explain why they chose a particular value. If they can't, ask them to change it and see what happens.
At the start of each step, remind students: open starter.html, save a copy with a new name, then open it in the browser side by side with their text editor. They should be making changes and refreshing the browser constantly - not writing the whole step before checking anything.
Useful things to say when a student is stuck:
- "Open the reference file. Find the part that does this. What's different in yours?"
- "Open the browser console (F12, then Console tab). What does it say?"
- "Read it out loud to me." (Students often spot their own errors while explaining.)
- "Did you save the file before refreshing the browser?"
The browser console (F12) is your most powerful tool. Almost every error appears there in plain English. You don't need to understand JavaScript to read "Uncaught ReferenceError: camera is not defined" and help a student find where they forgot to declare a variable.
Step by step
Students create a blank HTML file and get a rotating green cube on screen. This is the hardest step emotionally - starting from nothing is daunting. Once the cube appears, confidence jumps sharply.
- Scene - the container that holds everything in the 3D world
- Camera - the viewpoint we look through
- Renderer - the engine that draws the scene onto the screen
- Animation loop - a function that runs ~60 times per second and redraws the scene
- Forgetting to append the renderer to the page body - the canvas exists but is invisible
- Missing or broken importmap - Three.js won't load, everything fails silently
- Not calling requestAnimationFrame inside animate - the cube appears but doesn't move
- Camera still at 0,0,0 (inside the cube) - screen appears solid green
- "What would happen if we removed the animate() call at the bottom?"
- "Why do we need all three things - scene, camera, and renderer? What does each one do?"
- "What would you change to make the cube red instead of green?"
The cube is replaced with an open landscape - a flat plane, a grid overlay, a sky colour, and fog that hides the edge. OrbitControls let students fly around. This step is short and satisfying.
- PlaneGeometry - a flat surface that acts as the ground
- Fog - fades objects to the background colour with distance, hiding the world edge
- OrbitControls - an add-on that lets the mouse rotate, pan, and zoom the camera
- Forgetting to rotate the plane - PlaneGeometry starts vertical like a wall, not flat like a floor
- Fog colour different from background - leaves a visible hard edge at the horizon
- OrbitControls import path wrong - Three.js add-ons need a slightly different path than the core library
- "Comment out the fog line. What changes? Why might we want fog in a game?"
- "What does OrbitControls actually do? What controls it - the library or your code?"
- "How would you change the sky to sunset orange?"
The longest step. Students build a tank from three grouped boxes, add keyboard controls, and get the camera to follow behind. The key concept - delta time - is introduced here and is worth spending time on.
- THREE.Group - a container that holds multiple objects so they move together
- Keyboard events - listening for keydown and keyup to track which keys are held
- translateZ - moves an object along its own forward axis, regardless of which way it's pointing
- Delta time - the time since the last frame; makes movement speed consistent across different hardware
Without delta time, a game runs faster on a fast computer and slower on a slow one. Delta time fixes this: instead of moving 1 unit per frame, the tank moves 10 units per second, and each frame it moves 10 * dt. A fast machine takes many small steps; a slow one takes fewer but larger ones. The result is the same.
- Not calling clock.getDelta() every frame - movement stutters or stops
- Camera position updated once at setup but not each frame - camera stays still while tank moves
- Barrel position inside the group wrong - pokes through the hull or floats above it
- Keys object declared in the wrong scope - keydown event can't find it
- "Why does translateZ always move forward, even when the tank is pointing sideways?"
- "How would you make the tank move faster? Slower? Turn faster?"
- "What would happen if you forgot to update the camera position every frame?"
Students add turret rotation, a firing mechanic, and a target that reacts to being hit. This step introduces arrays of moving objects and collision detection - two patterns that appear in almost every game ever made.
- Projectile array - an array that holds all active shells, updated every frame
- localToWorld - converts a position inside a group (the gun barrel tip) to a world position
- Box3 collision - a bounding box used to test whether a point is inside an object
- scene.remove and geometry.dispose - cleaning up objects that are no longer needed
When removing items from an array while looping through it, looping forwards causes bugs: removing item 3 shifts item 4 into position 3, and the loop skips it. Looping backwards avoids this - removing an item only affects indices below the current position, which have already been processed.
- Iterating the shells array forwards when removing - causes every other hit to be missed
- Shell spawned at the tank body position rather than the barrel tip - shells appear inside the tank
- Shell rotation not set to match the tank - shells fly sideways
- Target bounding box not updated after moving - collision still uses the old position
- "What happens if we never remove shells from the array? Try it and watch the console."
- "How is this collision detection different from a real physics engine? What can't it do?"
- "What would you change to make the turret rotate faster?"
A second player is added, health bars appear, and the game now has a win condition and a reset. This step introduces factory functions - one of the most important ideas in programming - and a dynamic camera that watches both players.
- Factory function - a function that creates and returns a new object each time it's called; call it twice to get two tanks
- Player data objects - grouping everything about a player (tank, health, keys) into one object that gets passed around
- Game state flags - a simple variable like gameOver = true that changes what the update loop does
- Reset function - a function that puts everything back to its starting state
- Dynamic camera - finds the midpoint between both players and pulls back as they separate
Tell both players the controls before they start - it is easy to miss that P2 uses the arrow keys and Enter, not WASD and Space.
- Player 1: W/S drive, A/D turn, Q/E aim turret, Space fire
- Player 2: Up/Down drive, Left/Right turn, Comma/Period aim turret, Enter fire
- Shells hitting their own owner - need to store which player fired each shell and skip that player on collision check
- Reset function incomplete - some state resets but others don't, causing strange behaviour on the second game
- Both players using the same keys object - one player controls both tanks
- Health bar width not clamped - can go below 0% on edge cases
- "What is a factory function? Why is it better than writing createTank() code twice?"
- "How would you add a third player? What would you need to change?"
- "What would a reload timer look like? Where would you add it?"
After step 5 - keeping momentum
Students who finish early or want to keep going have several natural directions. The README.md in the download lists these - here is how to frame them as challenges:
- Add a reload timer - "Right now you can fire as fast as you can press Space. How would you add a 1-second wait between shots?"
- Add a boundary - "Tanks can drive off the edge forever. How would you stop that?"
- Add terrain height - "The ground is perfectly flat. Look up SimplexNoise and see if you can make hills."
- Add a third player - "The updatePlayer function takes a player object. What would it take to call it three times?"
- Look at the full game - the full Treads of War source is on GitHub. Much larger, but built on all the same ideas.
Common problems and fixes
- Open the browser console (F12, Console tab) and read the error
- Check the importmap block at the top is present and unmodified
- Make sure the file was saved before refreshing
- Try a hard refresh: Ctrl+Shift+R (Windows) or Cmd+Shift+R (Mac)
- Three.js loads from the local files bundled in the download - no internet connection is needed. If it fails, the most likely cause is that the student's HTML file is not in the same folder as
three.module.js. - Check the importmap block at the top of the file is present and unmodified - if a student accidentally deleted or edited it, Three.js will not load.
- Make sure the student opened their file from inside the extracted folder, not from a different location. The file must sit next to
three.module.jsand thejsm/folder for the imports to resolve.
- Delta time is almost certainly wrong - check that clock.getDelta() is called inside the animate loop, not outside it
- Speed constants can be adjusted freely if they feel off
- Open the reference file and the student's file side by side
- Ask them to find one difference and fix it, then look for the next
- It's fine to copy a section from the reference to get unstuck - ask them to explain what each copied line does
Reference resources
These links are useful to have open during a session - either for yourself or to share with students who want a clearer explanation of a concept.
g.co/color/picker - Google's built-in colour picker.
Pick any colour visually and copy the hex code shown. Replace the # with
0x when using it in Three.js code.
mathsisfun.com - Cartesian Coordinates - a visual, beginner-friendly explanation of how 3D coordinate systems work, with diagrams and an interactive component. Scroll to the 3D section.
mathsisfun.com - Radians - visual diagrams showing how radians relate to degrees. Best for ages 14 and up.
Khan Academy - Introduction to Radians - short video explanation, better suited to younger or less confident students.
Where to go next?
Once your students have finished Step 5 and want to keep going, here are the most useful places to send them.
github.com/filecore/treads-of-war - the full source code for the game that inspired this tutorial. It uses all the same ideas from Steps 1-5 but taken much further: procedural terrain, AI enemies, online multiplayer, weather, and more. Ambitious students can read through it and identify patterns they recognise from the tutorial.
threejs.org/docs - the official reference for every class and method used in this tutorial. It is written for developers rather than beginners, but students can look up anything they encounter (BoxGeometry, MeshBasicMaterial, etc.) and find a clear description of what it does and what parameters it accepts.
threejs.org/examples - a large gallery of live demos with source code. A good source of inspiration and a useful way to see what is possible with the same library.
MDN Web Docs - JavaScript First Steps - Mozilla's beginner guide to JavaScript. Well-written, free, and thorough. Good for students who want to understand the language itself rather than just the Three.js layer.
Khan Academy - Computer Programming - interactive lessons covering JavaScript and general programming concepts, pitched at a younger audience. A good starting point for students who feel they need to go back to basics before tackling the tutorial steps.
code.org - free resources for teachers including lesson plans, Hour of Code activities, and structured courses. Useful as a companion curriculum alongside Treaducation, or as preparation before starting the tutorial.
STEM Learning - Game Design resources - curated teaching resources on game design for UK schools, covering both the creative and technical sides of making games.