Command Palette

Search for a command to run...

Hectal
Course outline
Topic 19.1Advanced ~19 min · step 1 of 5

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.

0/5 · 0%

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. 1

    Darken it on purpose

    In the first example, set renderer.toneMapping = THREE.ACESFilmicToneMapping; after creating the renderer. The first line becomes 243, 129, 54: MeshBasicMaterial is 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. 2

    Turn the bike the other way

    In the second example, change Math.PI / 2 to -Math.PI / 2. The world position becomes 2, 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

Why is my orange wrong? Four ways, measured New tab

Exact on every GPU: one flat colour, no lighting.

idle

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.025
Where is the wheel? World = parent × local New tab
idle

Console

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 = 5
Which backend is my user getting? New tab

No `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`.

idle

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.

terminal
$ Press Run
── what you'll see ──
0
The wheel's world x reads 0: its matrices are still the identity, as if nothing had been placed.

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.info showed 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.memory after ten colour changes, then look for a missing dispose()". That is most of the job.

Remember this

  1. 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. 2

    The render loop and draw calls. renderer.render(scene, camera) updates world matrices, culls objects outside the frustum, sorts opaque objects by renderOrder, 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. 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 matrixWorld is only updated when something asks: read directly after a move, it is stale.

  4. 4

    Colour space. Materials store linear colour (#ff6b2c becomes 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 measures 255, 37, 6 (too dark) with a linear output, and 255, 173, 115 (washed out) for a colour texture whose colorSpace was never set (Topics 5.6 and 6.3).

  5. 5

    Disposal, R3F and backends. GPU memory is not garbage-collected: geometry.dispose(), material.dispose(), texture.dispose() free it, and renderer.info.memory shows if you forgot (Topic 19.2 leaks 20 textures in 20 clicks). In R3F, animate with refs in useFrame, never setState per frame (Topic 11.3: 60 renders against 1). And WebGPURenderer picks WebGPU when an adapter exists and WebGL 2 otherwise: ask renderer.backend.isWebGPUBackend, as the third example does.

Explain it without notes

01

Walk through what happens inside renderer.render(scene, camera) for one frame.

02

Why is a lit scene completely black, and how do you find out which cause it is?

03

What is the difference between WebGL 2 and WebGPU for a three.js app today?

04

How do you stop an R3F scene from re-rendering React 60 times a second?

Practice

01

Answer in two minutes, out loud: "What does dispose() free, and what doesn't it?"

02

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