← ALL NOTES
METHOD·2026.09·4 MIN READ
Occlusion for 2D Overlays in a 3D Scene
3d-visualization3d-design
The Problem

SVG and HTML overlays are useful for outlines, labels, and interaction feedback in a 3D interface. They are often easier to style than equivalent geometry inside Three.js, especially for thin lines and text.

The limitation is that a 2D overlay has no 3D depth information. Anything drawn there sits above the rendered scene and is not automatically occluded by objects in front of it.

I ran into this in a cube-manipulation prototype. Unselected cubes used thin SVG outlines to separate them from the background. With only a few cubes, the result looked fine. Once several cubes were placed close together, outlines from cubes in the back became visible through cubes in front.

The screen coordinates were not wrong. The problem was the rendering layer: SVG knew where the projected edges were, but not which 3D object was closer to the camera.

The root-cause diagnosis and implementation approach mainly came from Claude Code. My part was validating whether the revised behavior produced the correct occlusion in dense scenes.

Choosing the Layer by Occlusion Semantics

The final solution did not add more occlusion logic to SVG. Instead, different outline states were assigned to different rendering layers.

Normal outlines for unselected objects moved into the 3D scene. Each cube uses its own EdgesGeometry. Because the lines are real 3D objects, they participate in depth testing and inherit the scene's occlusion behavior automatically.

Selection and hover outlines remain in the SVG overlay. Those states have a different purpose. Even if part of the object is hidden behind something else, the user still needs a clear indication of what is selected or currently under the pointer. Keeping those outlines above the scene is therefore intentional.

The rule became straightforward: if the visual should respect real spatial occlusion, render it in 3D. If it needs to remain visible regardless of depth, render it as a 2D overlay.

Why Not Rebuild Occlusion in SVG

It would be possible to keep all outlines in SVG and calculate which projected edges are hidden by other objects.

But that would recreate a problem the 3D renderer already solves through its depth buffer. As object count, camera angle, and scene complexity increase, the custom visibility logic would also become more complicated.

For ordinary object outlines, there is little value in moving depth responsibility into the 2D layer. Once the effect is placed back in the 3D scene, the renderer can handle the relationship naturally.

The issue was not that SVG could never be made to work. It was that a 2D layer was being asked to manage spatial behavior that belonged to the 3D layer.

Visual Trade-off

Moving from SVG to WebGL lines reduced some visual precision.

SVG can specify sub-pixel widths such as 0.5px. Basic WebGL line width is much less controllable across platforms and is often effectively limited to around 1px.

The trade-off was acceptable because the two problems were not equally important:

  • incorrect occlusion visibly breaks the spatial model;
  • a small difference in line width is much less noticeable in this interface.

Opacity was adjusted to compensate for the heavier 3D line. The normal and hover states still needed enough contrast to separate adjacent cubes clearly in dense arrangements.

Testing in Dense Scenes

This issue was easy to miss with only a few objects.

A rear outline becomes visibly wrong only when its screen projection overlaps an object in front. Dense layouts therefore create the test condition that exposes the missing depth relationship.

For 3D outlines, labels, and overlays, it is useful to test more than isolated objects:

  • multiple objects overlapping in depth;
  • dense arrangements;
  • camera rotations that change which object is in front.

The question is not only whether an individual component renders correctly, but whether it still behaves correctly once it becomes part of the full spatial composition.

Takeaways
  1. Decide whether a visual effect should participate in depth testing before choosing the rendering technology.
  2. Normal object states should usually respect real spatial relationships. If an outline belongs to the object itself, it should usually be occluded with it.
  3. Emphasis states can intentionally ignore depth. Selection and hover feedback often benefit from staying visible above the scene.
  4. Changing rendering layers introduces new visual constraints. Moving from SVG to WebGL may require re-tuning width, opacity, or contrast.
  5. Test occlusion in dense scenes. Sparse layouts are often not enough to reveal the limitations of a 2D overlay.
About the Technical Choice

The specific diagnosis and the EdgesGeometry implementation mainly came from Claude Code. My responsibility was deciding which outline states should follow real occlusion and validating whether the result matched the intended interaction.

The more reusable question is not "should this outline use SVG or Three.js?" It is: should this visual still be visible when another object is physically in front of it?

Normal and selected outlines can have different answers, even though they look similar. Once that semantic decision is clear, the rendering layer becomes much easier to choose.

CONTINUE READING
Translating Figma Component Properties into Code Props2026.09Engineering a Figma Design System into Production Assets2026.09