Joshua Opolko

Driftlights: Depth of Field & Object Permanence in WebXR

Most "WebXR demos" are a clever shader painted on the inside of a sphere. They look great until you move, and then you notice the whole universe is glued to your face — there's no there there. Driftlights is the opposite. It's a real volume of hundreds of glowing orbs hanging at fixed points in space, rendered with genuine optical depth of field, so the near ones melt into soft bokeh and the far ones haze into fog. Orbit around and they stay put. Click, and you leave a light behind that's still there when you come back. Put on a headset and you can walk among them.

The point of the demo: two things the shader demos can't do — depth of field (a real focal plane with bokeh, not a flat filter) and object permanence (objects anchored in world space that persist as you move and as you place new ones).
Three.js · WebXR · Depth of Field Drag to orbit · Click to leave a light
Enter VR to walk among them
Your browser blocked WebGL, so the live scene can't render here. Try a current desktop or mobile browser.

What you're actually looking at

The blur is the whole trick. Real cameras have a focal plane: things at one distance are sharp, and everything nearer or farther falls out of focus into round highlights — bokeh. Driftlights renders that honestly using the scene's depth buffer, not a fake vignette. Slide Focus and watch the sharp band travel through the field; slide Aperture to open the lens wider and drown the edges in creamy circles.

The orbs are not a backdrop. Each one is a real mesh at a fixed coordinate, which is what makes object permanence obvious: as the camera drifts, near and far orbs slide past each other with true parallax, the way real objects do. Click anywhere and you drop a new light into the world at that point. Orbit away, come back — it's still glowing exactly where you left it, casting light on its neighbours.

How it works

It's Three.js with a small post-processing stack. A normal render pass draws the orbs, then a BokehPass reads the depth buffer and blurs by distance from the focal plane, an UnrealBloomPass adds the glow, and an OutputPass tone-maps it. The lights are MeshStandardMaterial orbs with emissive color; the ones you place carry a real PointLight so they illuminate the field around them.

WebXR needs to render straight to the headset's framebuffer per eye, which screen-space post-processing fights with. So the loop branches: on desktop it runs the full bokeh-and-bloom composer; the moment you Enter VR it switches to a direct stereo render. You lose the artificial bokeh in the headset — but you gain the real thing, because now your own two eyes are doing the depth. It's the same idea behind my Three.js fractal and Babylon.js grid demos, just pointed at optics instead of noise.

Things to try

Frequently asked questions

What is depth of field in WebGL?

Depth of field is the optical effect where only objects at a chosen distance (the focal plane) are sharp while nearer and farther objects blur into bokeh. In WebGL it's done as a post-processing pass that samples the scene's depth buffer and blurs each pixel by how far it sits from the focal distance.

What does "object permanence" mean in a 3D demo?

It means the objects live at fixed world coordinates rather than being painted onto your view. They persist as you move, show true parallax, and stay where you place them. It's the difference between a real 3D scene and a screen-space shader that follows the camera.

Do I need a VR headset to use it?

No. On desktop or mobile you orbit by dragging and place lights by clicking, with full bokeh depth of field. A WebXR headset is optional — it just lets you step inside the field and place lights with a controller. No app install, no downloads.


Resources

Last updated: June 13, 2026.

Josh builds WebXR and self-hosted tooling, and runs nowservingto.com, a daily-fresh directory of Toronto's newest restaurants.