Command Palette

Search for a command to run...

Hectal
Course outline
Topic 11.5Intermediate ~20 min · step 5 of 7

drei Helpers

In one line

drei is a shelf of ready-made R3F parts: controls, environments, shadows, HTML labels, loaders. Each one is plain three.js underneath. Know what each adds to the scene, because some quietly add work to every frame.

0/7 · 0%

Think of it like this

A kitchen gadget shop. A garlic press saves you time, and a food processor saves more. But the food processor takes space on the counter, needs cleaning, and uses power when it runs. A drei helper is a gadget: you should know what it puts in your scene before you buy it.

Words you'll meet

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

helper
A ready-made component from drei that wraps common three.js work.
makeDefault
An OrbitControls prop that saves the controls as state.controls, the default for the scene.
baked
Computed once and kept, instead of recomputed every frame. frames={1} bakes a contact shadow.
render pass
One complete draw of a scene or part of it. Each helper pass costs draw calls like a full render.
preset
A named setting that stands for files or values. drei's environment presets stand for HDR files on a server you do not control.

Step by step

01Ask what the helpers added

Inspect runs after 10 frames and prints what is in the scene. The crate holds a Group (from <Html>). The scene holds the crate and a Group (from <ContactShadows>).

02Look inside

The contact-shadow group holds a Mesh (the shadow plane) and an OrthographicCamera (the point of view that makes the shadow). OrbitControls is state.controls, and scene.environment is a texture.

03Count the draws

The second example puts the same crate in three Canvases and counts gl.render calls by wrapping the method. The three results are 30, 180 and 35.

04Decide

A configurator does not move its floor shadow: frames={1} is the right choice. A moving object needs the live shadow, at its price.

Try it yourself

  1. 1

    Bake the shadow

    In the second example, change frames={1} to frames={10}. The third count rises from 35 to 80: ten draws of the shadow cost 5 extra passes each, plus 30 for the scene.

  2. 2

    Take Html away

    In the first example, delete the <Html> line. The crate holds no children, and the last line says <Html> put a real div in the page: false.

Code & diagrams

What did the helpers add? New tab

Loading the HDR file takes a moment, so wait for the printout. The helpers are ordinary scene objects and DOM nodes.

idle

Console

Run the scene to see its console.

Expected console output

THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.
scene children: Mesh "crate", Group
inside the crate: Group
inside <ContactShadows>: Mesh, OrthographicCamera
<OrbitControls makeDefault>: OrbitControls | moves the default camera: true
<Environment>: scene.environment is a DataTexture | background: null
<Html> put a real div in the page: true
A helper with a second render loop New tab

Three Canvases, so three Clock warnings. Counts are over 30 animation frames.

idle

Console

Run the scene to see its console.

Expected console output

THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.
THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.
THREE.Clock: This module has been deprecated. Please use THREE.Timer instead.
plain scene: gl.render was called 30 times in 30 animation frames
with <ContactShadows>: gl.render was called 180 times in 30 animation frames
with <ContactShadows frames={1}>: gl.render was called 35 times in 30 animation frames

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

Use a preset without a network

Replace <Environment files="/data/3d/hdr/studio_small_08_1k.hdr" /> with <Environment preset="city" />.

terminal
$ Run
── what you'll see ──
Uncaught Error: Could not load potsdamer_platz_1k.hdr: Failed to fetch

Myth vs fact

Myth

A helper from drei is free.

Fact

It is code you do not read. Some add render passes, DOM nodes or downloads. Check the scene tree and renderer.info after adding one.

Myth

<Stage> is a safe shortcut.

Fact

It uses an environment preset that is downloaded from the internet. Build the same from Environment files, lights and ContactShadows when you need to work offline.

Pro corner

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

  • ▸

    <ContactShadows> default frames is Infinity, so it renders every frame. <AccumulativeShadows> and <BakeShadows> are the one-time versions for scenes that do not move.

  • ▸

    OrbitControls takes events from the events.connected element (the Canvas wrapper), not document, so two Canvases on one page do not fight for the mouse.

  • ▸

    In a frameloop="demand" Canvas, drei controls call invalidate() for you when they change something. Your own useFrame animation does not.

Remember this

  1. 1

    The problem this solves: the same scene parts are written again and again (orbit controls, an HDR environment, a soft shadow). drei has tested versions. The risk is treating them as magic: when the scene is slow or wrong, you need to know what they really are.

  2. 2

    **<OrbitControls />.** The OrbitControls from Phase 7 (drei uses the copy in three-stdlib), attached to the camera and the canvas. makeDefault stores it as state.controls, so other code can find it. It calls controls.update() inside a useFrame with priority -1, so damping works. The first example confirms: controls.constructor.name is OrbitControls and it moves the default camera.

  3. 3

    **<Environment files="..." />.** Loads an HDR image and sets scene.environment (and background if you ask). With files and a path on your own site it loads the equirectangular HDR from Phase 6 (drei uses an RGBE loader from three-stdlib and converts it to an environment map). With preset="city" it downloads the image from the internet at run time: with no internet (as in the course checker) it fails with Could not load potsdamer_platz_1k.hdr: Failed to fetch, and on your site it is a third-party dependency. Use files and ship the file.

  4. 4

    **<ContactShadows />.** A soft shadow on the floor. It adds a group with a plane and an orthographic camera, and each frame it renders the scene from below into a texture and blurs it. That is extra render passes, which the second example counts.

  5. 5

    **<Html>.** A real HTML <div> that follows a 3D point. It adds one DOM element and moves it with CSS every frame. Good for labels with real text (clickable, selectable, readable by screen readers); expensive in large numbers.

  6. 6

    **<Bounds>, <Stage>, <Center>, <Text>.** Bounds fits the camera to its children (<Bounds fit>). Stage is a ready studio (environment preset, lights, contact shadow): its preset downloads from the internet, as above. Center re-centres children on the origin. Text builds a mesh from glyphs of a font: give it your own font file.

  7. 7

    The second render loop. Some helpers draw the scene again themselves (ContactShadows, RenderTexture, View, Hud, post-processing). In the second example, a plain scene calls gl.render 30 times in 30 frames. With <ContactShadows> it is called 180 times: the scene once, plus 5 more passes (depth, then two blurs, each blur twice). With frames={1} the shadow is drawn once and baked: 35 calls. A scene that is slow only after adding a helper needs this check.

Explain it without notes

01

A scene runs at 60 fps; after adding <ContactShadows> it drops to 40. What do you check and what do you change?

02

Why might <Environment preset="sunset"> be a bad idea for production?

Practice

01

Write the JSX to orbit around a crate with a floor shadow that is drawn once, using your own HDR file.

02

Predict the gl.render count after 30 frames for a scene with <ContactShadows frames={2} />, then check.

Trade-offs

  • ↔

    Helpers save time and are tested, but each hides cost and sometimes a network call. For a product showroom keep the few you need, and replace a helper with plain three.js when it costs more than it saves.

Done when you can

  • Say what OrbitControls, Environment, ContactShadows and Html add

  • Find a helper's objects in the scene and its draws in the count

  • Bake a shadow that does not move

  • Avoid presets that download at run time