Course outline
3D Frontend Interview Questions
In one line
The questions 3D frontend interviews ask, with model answers built on what you measured in this course: the render loop, draw calls, matrices, normals, colour space, disposal, R3F re-renders, and WebGPU against WebGL. Each answer gives the mechanism, a number, an edge case and a trade-off.
Think of it like this
A driving test. The examiner doesn't ask you to recite the highway code; they ask what you would do at this junction, and why. 3D interviews are the same: "what happens when…", "why is it black…", "how would you make it faster…". A good answer explains the mechanism and backs it with something you measured.
Words you'll meet
New words in this topic, in plain English. Come back here whenever one feels fuzzy.
- draw call
- One request to the GPU to draw a mesh with a material; the count that most often limits frame rate.
- world matrix
- An object's full placement in the scene: its parent's world matrix times its own local matrix.
- linear colour
- Colour values proportional to light energy, used for maths; the screen expects sRGB, which is not linear.
- dispose()
- Frees the GPU memory behind a geometry, material, texture or render target; the JavaScript object stays.
- backend
- The GPU API a renderer actually uses underneath: WebGPU or WebGL 2.
Step by step
01Answer with a number
For each question below, say the mechanism in one sentence, then a number from this course: "10 WebGL calls for three meshes once compiled", "20 textures leaked in 20 clicks". Numbers show you have looked, not read.
02Measure colour
The first example draws Lumen orange four ways and reads the pixel. Two of the four are wrong in the two classic ways: too dark (linear output) and washed out (an sRGB texture read as linear).
03Place the wheel
The second example turns the bike a quarter and finds the front axle in the world three ways: getWorldPosition, the matrix by hand, and the wrong shortcut.
04Ask the renderer
The third example creates a WebGPURenderer, awaits init() and prints which backend it chose. In the checker's browser: the fallback warning and WebGL 2 (fallback); in Chrome with a GPU: WebGPU.
Try it yourself
- 1
Darken it on purpose
In the first example, set
renderer.toneMapping = THREE.ACESFilmicToneMapping;after creating the renderer. The first line becomes243, 129, 54:MeshBasicMaterialis tone-mapped too, so the orange shifts. This is the third classic colour question (Topic 5.6): "my UI colour doesn't match the 3D one". - 2
Turn the bike the other way
In the second example, change
Math.PI / 2to-Math.PI / 2. The world position becomes2, 0.35, 0.58: a quarter turn the other way round the vertical axis puts the front axle on the other side (z flips sign).
Code & diagrams
Exact on every GPU: one flat colour, no lighting.
Console
Run the scene to see its console.Expected console output
colour #ff6b2c, sRGB output (default): 255, 107, 44
same colour, linear output: 255, 37, 6
texture, colorSpace not set: 255, 173, 115
texture, colorSpace = SRGBColorSpace: 255, 107, 44
what the material stores for #ff6b2c (linear): 1.000, 0.147, 0.025Console
Run the scene to see its console.Expected console output
wheel local position: 0.58, 0.35, 0
wheel world position: 2, 0.35, -0.58
by hand (bike.matrixWorld × local): 2, 0.35, -0.58
forgetting the rotation: 2.58, 0.35, 0
after moving: wheel.matrixWorld says x = 2 | getWorldPosition says x = 5No `output` is checked: it depends on the browser. Here (no WebGPU adapter) it prints `THREE.WebGPURenderer: WebGPU is not available, running under WebGL2 backend.` and `navigator.gpu: present | backend in use: WebGL 2 (fallback)`; in Chrome with a GPU, `backend in use: WebGPU`.
Console
Run the scene to see its console.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
Read matrixWorld before anyone updates it
In the second example, delete the line bike.updateMatrixWorld(); and print wheel.matrixWorld.elements[12] before any getWorldPosition call.
Myth vs fact
Myth
A good 3D answer is a list of APIs.
Fact
Interviewers listen for mechanism and cost: what the GPU receives, how many times, and what it costs on the weakest device. An API name without that is trivia.
Pro corner
Extra depth for experienced readers. New to this? Skip it for now and come back later.
- ▸
Bring one story where a number changed your mind: "we thought textures were the problem;
renderer.infoshowed 900 draw calls". It shows you measure before you optimise. - ▸
When you don't know, say what you would measure and where: "I'd check
renderer.info.memoryafter ten colour changes, then look for a missingdispose()". That is most of the job.
Remember this
- 1
The problem this solves: most candidates who say "I know three.js" can build a scene but can't explain one. This topic turns each phase into an answer you can give in two minutes: mechanism first, then a number, then an edge case, then a trade-off.
- 2
The render loop and draw calls.
renderer.render(scene, camera)updates world matrices, culls objects outside the frustum, sorts opaque objects byrenderOrder, then by material (fewer state changes), then front to back, and transparent ones back to front, then issues one draw call per visible mesh and material. Measured in Topic 14.5: 156 WebGL calls on the first frame of a 3-mesh scene, 10 on the next. In Topic 19.4, 1,000 separate meshes cost 955 draw calls (the rest were culled) and 100,000 instances cost 1. - 3
Matrices. Each object has a local matrix (position, rotation, scale) and a world matrix = parent's world matrix × local matrix (Topic 3.5). The second example shows the classic slip: the bike's front axle at (0.58, 0.35, 0) is at (2, 0.35, −0.58) in the world after the bike turns, not (2.58, 0.35, 0). And
matrixWorldis only updated when something asks: read directly after a move, it is stale. - 4
Colour space. Materials store linear colour (
#ff6b2cbecomes 1.000, 0.147, 0.025), lighting is computed in linear, and the output is converted to sRGB. Leave out one step and colours go wrong in a recognisable way: the first example measures255, 37, 6(too dark) with a linear output, and255, 173, 115(washed out) for a colour texture whosecolorSpacewas never set (Topics 5.6 and 6.3). - 5
Disposal, R3F and backends. GPU memory is not garbage-collected:
geometry.dispose(),material.dispose(),texture.dispose()free it, andrenderer.info.memoryshows if you forgot (Topic 19.2 leaks 20 textures in 20 clicks). In R3F, animate with refs inuseFrame, neversetStateper frame (Topic 11.3: 60 renders against 1). AndWebGPURendererpicks WebGPU when an adapter exists and WebGL 2 otherwise: askrenderer.backend.isWebGPUBackend, as the third example does.
Explain it without notes
Walk through what happens inside renderer.render(scene, camera) for one frame.
Why is a lit scene completely black, and how do you find out which cause it is?
What is the difference between WebGL 2 and WebGPU for a three.js app today?
How do you stop an R3F scene from re-rendering React 60 times a second?
Practice
Answer in two minutes, out loud: "What does dispose() free, and what doesn't it?"
Answer: "Your model looks right on desktop but too bright and flat on phones. Where do you look?"
Done when you can
You can explain the render loop with measured numbers
You can diagnose a black scene by its pixel and triangle count
You can explain colour space with the two classic wrong results
You can compare WebGL 2 and WebGPU honestly