HOW TO BUILD AN
EDUCATIONAL SPACE GAME
By Shane Brumback · Published · Advanced Three.js tutorial · about 45 minutes
Part 2 of the series: learn how educational 3D games are built — a world worth exploring, interactions that reward discovery, a learning UI that teaches at the right moment, and progress that keeps students going. We take the Beginner solar system and turn it into a full learning game: students travel to each planet, and when they are close and looking at it, a learning panel shows its picture and facts. It is the worked example from my article on creating 3D virtual educational worlds.
LIVE DEMO
The solar system behind this page is the demo. Sign in free to launch it full screen and see every educational-game system working together: explore the world, discover a planet by flying close and pointing at it, read its learning panel, and track your progress to all 10 goals: the Sun, 8 planets and a comet. In the full game, reaching every goal unlocks a 25-question Mission Quiz. The ship is just how learners move. Spot the comet for a bonus — it is ported from my Three.js comet particle system tutorial. Every signed-in visitor gets a 3-minute free trial of the full-screen classroom; members get unlimited time.
Advanced (default): the full educational game — discovery by proximity and aim, learning panels with planet images, progress and a bonus comet. Beginner: the simpler first-version classroom scene — fly with WASD and hover planets.
Throttle: W / S · Turn: A / D · Pitch: arrow keys · Climb: E / Q · Boost: Shift · Phones: landscape, left stick pitch + yaw, right stick throttle · Learn: fly close to a planet or hover it · Esc to exit
The Solar System Series
- Article: Creating 3D Virtual Educational Worlds — the design ideas.
- Beginner tutorial — orbits, WASD fly-through, hover-to-learn and a classroom login.
- Advanced tutorial — build a full educational 3D game: discovery, learning panels, progress, VFX and mobile controls.
- Play Planet Quest: Solar System Explorer — the finished game.
How to Build a Solar System in Three.js (Quick Answer)
Make a sphere for the Sun with a PointLight at its center, then put each planet mesh inside an empty Object3D pivot and rotate the pivots at different speeds to animate the orbits. Store each planet's facts in mesh.userData, use a Raycaster from the mouse to detect which planet is hovered, and show those facts in an HTML card. Move the camera with keys to fly through it, and start the loop only after a login form is submitted.
Introduction
A diagram of the solar system tells students the planet order. A 3D solar system lets them feel it: how small Mercury is next to Jupiter, how slowly Neptune crawls while Mercury races around the Sun, and how much empty space there is between worlds. That is the difference between a render and an educational world.
In plain words: we build a little space classroom. A student signs in, the planets start orbiting, they fly around like a spaceship and point at any planet to read about it. A counter tracks how many worlds they have explored until the mission is complete.
This tutorial is the hands-on companion to Creating 3D Virtual Educational Worlds with Three.js, which explains the five systems every learning world needs. Here we build all five. The tutorial and full code are free.
Frequently Asked Questions
How do I add a comet to a Three.js solar system?
Use the approach from the comet particle system tutorial: one THREE.Points cloud with a dust population and an ion population, both pushed away from the Sun, plus a glowing coma sprite. Move the whole comet group along an eccentric orbit and update the sun direction every frame so the tails always point away from the Sun.
How do I make planets orbit the Sun in Three.js?
Put each planet mesh inside an empty Object3D pivot at the center of the scene, offset the mesh by its orbit distance, and rotate the pivot a little every frame. The pivot carries the planet around the Sun. Give each pivot its own speed so inner planets move faster.
How do I show information when the mouse hovers over a planet?
Store the facts on each mesh in userData, convert the mouse position to normalized device coordinates, call raycaster.setFromCamera(pointer, camera) and intersectObjects on your planets every frame. When the first hit changes, fill an HTML info card with that object's userData and move the card next to the cursor.
How do I make a third-person spaceship in Three.js?
Build the ship as a Group, turn it with rotateY and rotateX from the keys, and move it along its forward vector (0,0,-1) rotated by its quaternion. Each frame, place the camera at an offset behind and above the ship in the ship frame and lerp toward it, then slerp the camera to look a little ahead of the ship. That gives a smooth chase camera.
How do I add a login to a Three.js educational game?
Show a login form over the canvas and only start the animation loop after it is submitted. The free code uses a simple classroom name and class code saved in localStorage, which is fine for prototypes. For real student accounts use a proper auth provider and store progress on a server.
How do I add a quiz that unlocks after exploring?
Count goals in a Set and fire a custom event (solar-mission-complete) when every goal is reached. A separate quiz module listens for that event, pauses the game, and runs questions stored as plain arrays. Add ?quiz=1 to the game URL to open the quiz right away while testing.
How do I make asteroids solid in Three.js?
Save each instanced rock position and radius when you build the belt. Each frame, rotate the ship position into the belt's local space and do a sphere distance check against the rocks; on a hit push the ship out, reverse part of its speed and shake the camera.
Is the solar system to scale?
No. Sizes and distances are scaled so every planet is visible and reachable in a few seconds of flight. True scale would put Neptune thousands of Earth widths away, which makes a great classroom discussion.
Is this tutorial free?
Yes. The tutorial and the full code are free. The full-screen live demo needs a free Google sign-in and includes a 3-minute free trial; members get unlimited demo time.
What Students Learn
- The order and relative sizes of the eight planets.
- That inner planets orbit faster than outer ones — seen, not memorized.
- Key facts per planet: type, day length, year length, moons and one memorable fact.
- How vast and empty space is, something a flat diagram cannot show.
The scene teaches through discovery. Nothing lectures the student: they choose where to fly and curiosity unlocks the content. Tell students sizes and distances are scaled for readability, then ask how far away Neptune would really be. Moon counts change as new moons are confirmed, so have students check NASA's current planet pages too.
The Five Systems in This Scene
| System | Solar system implementation |
|---|---|
| World | Sun, planet spheres, orbit lines, starfield |
| Player | Third-person spaceship with a chase camera; dual joysticks on phones |
| Interactive objects | 10 goals (Sun, 8 planets, a comet) found by flying close and aiming, plus a solid asteroid belt bonus zone |
| Learning UI | Learning panel, WORLD DISCOVERED popup and a 25-question Mission Quiz |
| Identity and progress | Explored X / 10 HUD, quiz unlocks after every goal, saved high score, classroom login |
How It Works
- Set up the renderer, scene and camera — In plain words: We make the 3D window and a camera far enough back to see the whole solar system. ACES tone mapping keeps the bright Sun from clipping, and the pixel ratio is capped so it stays smooth on school laptops and phones.
- Keep the learning content in data — In plain words: Every planet is one plain object: size, distance, orbit speed and the facts students will discover. Teachers can edit facts here without touching any 3D code.
- Make VFX textures in code — In plain words: Small canvas drawings become glow sprites, banded gas-giant textures and cratered rocky planets, so the whole demo loads with zero image files.
- Build a glowing Sun — In plain words: A shader animates a boiling plasma surface with darker edges (limb darkening). Two additive sprites make the corona and halo, and a PointLight at the center lights every planet.
- Twinkling stars and nebula clouds — In plain words: Thousands of tinted stars twinkle in a tiny shader, and big soft colored sprites far away add nebula clouds so space never looks flat.
- Planets, atmospheres, Saturn rings and orbit trails — In plain words: Each planet rides an orbit pivot with a soft atmosphere: a thin glowing rim shader that hugs the limb plus a camera-facing gradient haze sprite behind it (no glass shell), and a fading trail. Saturn gets a procedural multi-band ring shader with a Cassini division, crisp anti-aliased edges and the planet shadow cast across the rings. An asteroid belt sits between Mars and Jupiter.
- Add the comet — In plain words: The comet is adapted from my comet particle system tutorial (linked in the live demo card): a rocky nucleus, a glowing coma, a curved dust tail and a straight blue ion tail that always point away from the Sun, on an eccentric orbit that speeds up near the Sun. Students get a bonus when they spot it.
- Add bloom — In plain words: An UnrealBloomPass makes the Sun, engine and comet glow. The threshold is high so only bright things bloom.
- Fly a spaceship in third person — In plain words: The ship is built from simple shapes. W and S set the throttle, A and D turn, the arrow keys pitch, E and Q climb, Shift boosts. The chase camera sits behind and above the ship and smoothly follows it, the ship banks into turns, and the engine leaves a glowing exhaust trail. On phones the same flight reads a touch input object filled by two on-screen joysticks (see the mobile step). While a popup or the quiz is open, the global __solarPaused flag stops the ship.
- Fly close to a planet to learn about it — In plain words: When the ship is near a planet, the Sun or the comet AND its nose points at it, a soft glowing square frames it and an education panel pops up with a picture of that world and its facts. Nearby worlds you are not pointing at are ignored, so panels never pop up too fast. Fly closer to arrive and count it as explored.
- Animate everything in one loop — In plain words: Every frame the orbits turn, the Sun and stars animate, the comet moves, the ship flies and the HUD updates. Delta time is capped so a slow frame never makes planets jump.
- Turn the scene into a game page with options — In plain words: Planet Quest is not a separate engine. The game page loads the same shared module as this tutorial and passes game-only options: a world 8x bigger, a richer solid asteroid belt, and the Mission Quiz module. Options become window flags that the scene reads, so the demo and the tutorials stay simple.
- Define the goals and count progress — In plain words: A goal is any body the learner must reach. The game has 10: the Sun, the 8 planets and a comet (comets are a general class of icy body, so this one has no name). A Set remembers what was reached and the HUD shows Explored X / 10 plus the nearest goal still to find, so learners always know what to do next.
- Announce each discovery with events — In plain words: When the ship is close to a goal and pointing at it, the scene does not draw any game UI itself. It fires a solar-body-arrived event with the name, facts, a picture and the progress count. When the last goal is reached it fires solar-mission-complete. Any game module can listen, which keeps 3D code and learning UI separate. In the game, the small proximity info panel is switched off (COMET_GOAL is true), so this celebration popup is the only learning card.
- Show a WORLD DISCOVERED popup — In plain words: The quiz module listens for solar-body-arrived and shows a game-style card: the world name, its picture, its Type, Day, Year and Moons, a fun fact, progress and a KEEP EXPLORING button (Enter, Space or Esc also work). Flight is paused while it is open. If the final discovery also completes the mission, the quiz waits until the card is closed.
- Build a solid asteroid belt — In plain words: The game adds hundreds of 3D rocks in three size classes to the belt between Mars and Jupiter. Each vertex is pushed in or out by a hash of its position, so shared corners move together and every rock stays a closed, solid shape. One InstancedMesh draws them all in a single call, and each rock's position and radius are saved for collisions.
- Bounce off asteroids — In plain words: Every frame the ship position is rotated into the belt's own (spinning) space. Only if it is inside the belt ring do we test the rocks: a simple sphere-sphere distance check. On a hit the ship is pushed out, bounced backwards at a third of its speed and the camera shakes. A short cooldown makes one impact count once. Entering the belt the first time also fires solar-belt-entered.
- Belt bonus card and hit feedback — In plain words: The belt is a bonus zone, not a goal, so it never blocks the quiz. Flying in shows a BONUS ZONE DISCOVERED card with belt facts (these appear in the quiz too), and every collision flashes ASTEROID HIT! with a running count.
- Write the Mission Quiz as data — In plain words: Questions are plain arrays: question, correct answer, three wrong answers. Every answer comes from a fact the learner already saw in a popup, including comet and asteroid questions. Ranks map the number correct to stars and a title.
- Unlock and run the quiz after every goal — In plain words: The quiz opens only when solar-mission-complete fires, so a learner must reach all 10 goals first. It shuffles the questions and answers, scores 100 points plus a streak bonus, shows instant feedback, then a final score with stars, rank, accuracy and a saved high score. Keys A to D or 1 to 4 answer.
- Test the quiz with ?quiz=1 — In plain words: Flying to 10 goals every time you change a question is slow. Adding ?quiz=1 (or ?testQuiz=1) to the game URL launches the game and opens the quiz about 2 seconds later. Try it: https://www.shanebrumback.com/planet-quest-solar-system-explorer.html?quiz=1
- Mobile: dual joysticks, no BOOST, HUD top-left — In plain words: Phones get two sticks: left for pitch and yaw, right for throttle. They write into one shared input object that the flight code adds to the keyboard values. There is no BOOST button on phones, and the Explored HUD moves to the top-left corner so the sticks have room.
- Keep planets and the ship easy to see — In plain words: Learners cannot discover what they cannot see. Planets use their own texture as an emissive map, brighter in the game, and the ship has a bright emissive hull plus a small light that travels with it, so both stay readable far from the Sun.
- Gate the game behind a classroom login — In plain words: In the free full code, students type a name and class code before the game starts. Their explored planets are saved in localStorage so progress survives a refresh. This is prototype auth for classrooms, not real security; for graded work use a real auth provider and save progress on a server.
- Audio: procedural sound with the Web Audio API — In plain words: js/solar-audio.js builds every sound in code with no audio files: an engine hum that follows the throttle, a happy discovery chime (fresh nodes each time, and it resumes the audio context so it plays even while the popup pauses the game), an asteroid thud, and a mute button saved in localStorage. Sound starts only after a click or tap and only while the demo is live, so the homepage autopilot stays silent.
Taking It Further
- Teacher question packs: load the quiz array from a JSON file per class so teachers can write their own questions.
- Time slider: bind the orbit time scale to a range input so students control time.
- Real textures: swap the colors for planet maps with TextureLoader, like in the transparent PNG textures tutorial.
- Moons: nest a moon pivot inside Earth's mesh — the same pivot trick one level deeper.
- Teacher dashboard: with real auth, send explored planets to a backend to see class progress.
- Read the design side in Creating 3D Virtual Educational Worlds with Three.js.