Command Palette

Search for a command to run...

Hectal
Course outline
Topic 0.5Beginner ~18 min · step 5 of 6

The Project You Will Build

In one line

Your lumen-3d folder grows into the whole showroom. Here is its final layout, one line per folder and file, which phase adds what, and how the build topics work.

0/6 · 0%

Think of it like this

A builder's plan shows every room before the first brick is laid, even though the house is built one room at a time. You always know where the kitchen will go, so you never block it with a wall. The folder tree below is the plan of your showroom.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

module
One JavaScript file that exports some functions or values for other files to import. Splitting an app into modules keeps each file small and focused.
src/
The source folder: the code you write. Vite reads it, follows the imports and builds the app from it.
public/
Files that are served exactly as they are, at the site's root (public/data/3d/models/lumen-bike.glb is fetched as /data/3d/models/lumen-bike.glb; this course keeps its assets in public/data/3d/, the same paths Hectal uses, so every example runs unchanged on your computer).
glTF / .glb
The standard file format for 3D models on the web; .glb is the single binary file version. Phase 10 explains it.

Step by step

01The plan

This is the lumen-3d folder as it will look at the end of the course. You don't make these files now; each phase adds its own.

index.html the page that holds the canvas and the panel · package.json the dependencies, pinned · vite.config.js dev server and build settings · public/data/3d/ the assets, at the same paths as on this site: showroom-poster.png (Phase 1), models/ the bike as glTF (Phase 10), textures/ and hdr/ images and environment maps (Phase 6), draco/ decoder files for compressed models (Phase 10).

src/main.js starts the app: checks support, creates the world · src/world/renderer.js, scene.js, camera.js, lights.js, loop.js the parts every 3D app has · src/objects/bike.js the bike (shapes first, a loaded model later) · src/objects/showroom.js the floor, walls and stand.

src/systems/controls.js camera and keyboard controls · picking.js what did the user click · loader.js loading with progress and errors · physics.js the test ride · budget.js the draw-call and memory checks · src/materials/paint.glsl.js and paint.tsl.js the custom paint · src/ui/panel.js the colour and part picker · src/ui/a11y.js the text alternative and announcements · src/react/App.jsx, Bike.jsx the React version · tests/scene.test.js checks on the scene.

02Why world, objects and systems

The split follows a question: would another 3D app have this too? Every app has a renderer and a loop, so those go in world/. Only Lumen has this bike, so it goes in objects/. Picking and loading are behaviour that many objects use, so they go in systems/.

This kind of split (shared engine parts, the things in the world, and the systems that act on them) is common in real 3D apps and games, and it makes the interview question "how would you structure a three.js app?" easy to answer.

03One file now, modules soon

For the first few topics everything lives in src/main.js, because one file is easier to understand. The live example below is that file already sorted into functions, and each function's comment names the module it will move to. In Phase 3 you move them, and nothing about the scene changes.

04The build topics carry you

Each phase's Build topic shows the files it touches in full, so you can always compare yours with the course's, or copy the course's and continue. Mistakes in your own project are normal and useful: the black-screen checklist and the console will find most of them.

Try it yourself

  1. 1

    Find the module for each job

    Without looking back, say which file each of these will live in: the code that turns the stand (world/loop.js), the colour picker (ui/panel.js), the code that loads the bike model (systems/loader.js), the bike's custom paint (materials/paint.glsl.js, later paint.tsl.js).

  2. 2

    Change the order

    In the example, move startLoop(...) above const stand = createStand(); (and pass stand after it is made). You can't: startLoop needs the stand to exist. This is why apps are set up in a fixed order: scene, camera, renderer, lights, objects, then the loop.

Code & diagrams

The showroom in one file, sorted into future modules New tab

Each function says where it moves to. The output lists the order things are made in, which is also the order every three.js app starts in.

idle

Console

Run the scene to see its console.

Expected console output

made, in order: scene -> camera -> renderer -> lights -> stand -> loop

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Add the stand twice

In the example, add a second scene.add(stand); just after the first one.

terminal
$ Run
── what you'll see ──
made, in order: scene -> camera -> renderer -> lights -> stand -> loop
No error, and still one stand: open the scene tree and count.

Myth vs fact

Myth

Small projects don't need folders.

Fact

Splitting early costs a few minutes. Splitting a 2,000-line file later costs days. The plan exists so that you never have to.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    The world/objects/systems split is a light version of the entity-component-system idea games use: objects are the entities, and systems run over them every frame. Phase 16's physics system is the first one that really runs per frame over many objects.

  • ▸

    Keep three.js imports inside modules that need them. Phase 18 lazy-loads the whole 3D part of the page, which only works if the page's other code doesn't import three.js at the top.

Remember this

  1. 1

    The problem this solves: a 3D app written as one long file works for a week and then becomes impossible to change: the camera code is tangled with the lights, the loader and the buttons. Knowing the final layout from the start, you put each new piece where it belongs.

  2. 2

    The idea behind the layout. src/world/ holds what every 3D app needs (renderer, scene, camera, lights, the loop). src/objects/ holds the things in the scene (the bike, the showroom). src/systems/ holds behaviour that works on objects (controls, picking, loading, physics, the performance budget). src/materials/ holds the custom shaders, src/ui/ the HTML around the canvas, and src/react/ the React version from Phase 11. public/ holds files served as they are: models, textures, decoders.

  3. 3

    How it grows. Phase 0 makes index.html and src/main.js. Phase 1 adds a support check to main.js. Phase 2 starts objects/bike.js with the first frame tubes. Phase 3 splits main.js into the world/ modules and objects/showroom.js. Phase 4 builds the rest of the bike from shapes. Phases 5–9 bring better lights and shadows, textures, camera views, picking and the turntable. Phase 10 exports the bike as a .glb file into public/data/3d/models/ and loads it with systems/loader.js. Phase 11 adds src/react/. Phases 12–13 add the paint shaders, 16 the physics, 17 the budget, 18 ui/a11y.js and the fallbacks.

  4. 4

    How a build topic works. The last topic of every phase is called *Build*. It says which files it adds or changes, shows each one in full (so if you fell behind, you can copy it and catch up), and has a live example that runs the same code on this page. The panel "Your project files" shows the whole tree as it stands after that topic.

Explain it without notes

01

Explain why the bike goes in src/objects/ but the camera controls go in src/systems/.

02

What does a Build topic give you that helps when you fall behind?

Practice

01

Where would you put a function that shows a "Loading 40%..." bar while the bike model downloads, and why?

02

Sketch (on paper) your lumen-3d folder as it is right now, after Topic 0.4.

Done when you can

  • Draw the final lumen-3d tree and say what each folder is for

  • Say which phase adds the bike, the loader, the React version and the physics

  • Explain what a Build topic shows and how to catch up with it