I found a way. Using a @looeee’s
visibleWidthAtZDepth functions, I was able to do a binary search to find the plane perpendicular to a camera’s line of sight where the dimensions of the found plane are the same as the viewport dimensions (there’s a better way but this works for now). On this plane, one Three.js unit is equivalent to one CSS pixel.
So, for example, following is an example where the
<div> element is positioned using
top: 50%; left: 50%; transform: translate(-50%, -50%), which is using the DOM coordinate system where the point
(0, 0, 0) starts at the top left of the viewport and positive Y goes downward. When you start dragging, you’ll see the teal square that was hiding underneath the pink square. Both of them are rotating in unison, and are perfectly aligned until you begin dragging the Three.js camera. The pink
<div> has a size of 50px width/height, and the Three.js Mesh has a size of 50 width/height, so the Three.js Mesh is sized in pixels: