Future Web
A 3D hero without a 3D library
The obvious way to build an interactive 3D homepage is to reach for Three.js. We wrote roughly eight kilobytes of maths instead, saved about six hundred, and got sharper text out of it.
by Patrick Albert
The brief for this site called for an interactive scene on the homepage: a central core with projects orbiting it, rotatable, clickable, and quick enough that it never gets in the way of reading the page.
The default answer is Three.js. It is excellent and we use it elsewhere. Here we did not, and the reasoning is worth writing down because it applies to a lot of decisions that get made on autopilot.
What the scene actually needed
Points positioned in three dimensions, projected onto a flat screen with perspective, sorted so near ones draw over far ones, plus text labels and hit detection for clicks.
What it did not need was lighting, materials, shadows, textures, model loading, or the several dozen other things a 3D engine exists to provide. Once the list is written out like that, the ratio is uncomfortable. That is a lot of library for four operations.
The numbers
- Minified 3D library: roughly six hundred kilobytes
- Hand written projection: roughly eight kilobytes
- Everything else about the page: unchanged
Perspective projection is one line. Take a point's distance from the camera, divide a focal length by it, and multiply the coordinates by the result. Things further away get smaller. That is the entire trick, and it has been the entire trick since the fifteenth century.
The unexpected win
Text. Rendering readable labels in WebGL means building a texture atlas of glyphs and mapping them onto geometry, and at small sizes the result is always a little soft. Drawing text on a plain 2D canvas uses the same font rendering the rest of the page uses, at the device's real resolution.
The labels on our scene are crisper than the library version would have been, which was not the reason for the decision and turned out to be the most visible benefit.
Six hundred kilobytes lighter and the text got better. That is not a trade, that is just a better answer.
The rule this came from
A framework earns its size when you use a meaningful fraction of what it does. Pulling in a full engine for four operations is not building on the shoulders of giants. It is asking a giant to hold a teaspoon.
The inverse is also true and worth saying, because this argument gets abused. If the scene needed real lighting, imported models or physics, writing it by hand would be a slow reimplementation of something better than we would build. We would use the library and not think twice.
The part we would not skip
None of this matters if the scene makes the site worse for anyone. So it loads after the content, never blocks navigation, pauses when the tab is hidden, limits its resolution on phones, and stops entirely when the operating system asks for reduced motion.
Most importantly, every project the scene shows also exists as ordinary text and links further down the page. The scene is a second view of the same information, not the only way to reach it. If it never loads at all, nothing is lost except the animation.