A 3D product on a phone: what it costs and what breaks
In September 2026 I rebuilt the shop of Smoky Candle, my own brand of soy candles, around a 3D candle. You open its box, unscrew the cap, light it and blow it out, and it stays with you down the page. Most of the work went into making it right on a phone. These are the notes.
What it costs in speed
The old static page scored 92 for performance in the Lighthouse mobile test. With the 3D, a first run over a slow connection came in at 59. After the fixes below it sits around 78 in the lab. Accessibility, best practices and SEO are at 100.
Most of that cost is the engine. three.js and the scene weigh about 250 KB compressed, and preparing the scene takes around half a second of a phone’s processor. That does not go away. What you can choose is when it happens.
- Load the 3D after the page. Text and buttons arrive first and work straight away, then the candle fades in.
- Check what your helpers bring along. A ready-made lighting component carried readers for HDR and EXR images I never used. Replacing it, and two other small helpers, with a few lines of my own took the 3D file from about 280 to about 257 KB compressed.
Why the candle shook on iPhone
The candle lived in a canvas fixed to the screen, and on every frame it read where each section of the page was and followed it. On iOS the page scrolls on one thread and the drawing happens on another, so the candle always landed one frame late. At 60 frames per second, it still shook.
The fix was to stop following. On phones the canvas now sits inside the section it belongs to, and Safari scrolls it with the page like any other element. Two details made it work:
- The canvas has the same size in every section. Resizing a WebGL canvas empties it for a frame, and you see the flash.
- It moves to the next section before that section comes on screen, and leaves a still photo of the candle in the one it leaves.
What Safari does differently
- It ignores filters on a 2D canvas. I turned the logo on the box grey with a canvas filter, and on iPhone it came out gold. Now the grey logo is an image made in advance.
- Building that image in the browser was slow anyway: a 4096-pixel texture, processed pixel by pixel. On a phone the box arrived after the candle and snapped onto it. A ready image loads far sooner, and the candle only fades in once everything is there.
Sound needs a real tap
The candle crackles, the box pops, the cap clicks. All of it is generated with the Web Audio API, with no audio files. But browsers only play sound after a real gesture: a tap, a click, a key. Scrolling does not count, with a finger or with a wheel.
- Try to unlock the audio on every gesture until it works, not only on the first one. On a phone the first touch is usually the start of a scroll, and that one does not count.
- On Safari, play a silent sound inside the gesture. That is what opens the audio.
- Keep a visible button to turn the sound on. Someone who only scrolls has no other way in.
Follow the scroll with a spring, but never the position
A mouse wheel scrolls in steps of about 100 pixels. If a rotation or a closing lid follows the scroll exactly, each step becomes a jump. I let those values chase the scroll with a spring of about a tenth of a second. The position of the candle on the page never gets a spring: that would bring the shaking back.
Tell me what you are building.
I reply within 24 hours with a realistic estimate and the next steps.