PolyCSS: Bringing 3D Polygon Meshes to the DOM without WebGL

For years, the standard for 3D graphics on the web has been WebGL. While powerful, WebGL operates in its own canvas, creating a "black box" where the browser's DOM is unaware of the individual shapes, textures, and vertices being rendered. To interact with a specific part of a 3D model in WebGL, developers typically have to implement complex raycasting to determine which object the user clicked.

PolyCSS changes this paradigm by treating the 3D scene not as a canvas drawing, but as a collection of real HTML elements. By leveraging CSS matrix3d() transforms, PolyCSS renders polygon meshes directly into the DOM, effectively turning 3D geometry into a set of manipulatable HTML leaves. This approach opens up unique possibilities for accessibility, styling, and interaction that are traditionally difficult in GPU-accelerated canvases.

How PolyCSS Works: The DOM as a Renderer

At its core, PolyCSS is a 3D engine for the DOM. It doesn't use a canvas; instead, it emits each visible polygon as a leaf element. To maintain performance, the engine intelligently selects the most efficient CSS primitive based on the polygon's properties:

  • <b> elements: Used for solid rectangles and stable quads using background: currentColor.
  • <u> elements: Used for stable triangles and beveled-corner solids via corner-shape or border-width fallbacks.
  • <i> elements: Used for solid polygons utilizing border-shape: polygon(...) where browser support allows.
  • <s> elements: The fallback for textured polygons or unsupported shapes, which map a packed texture-atlas slice using background-image.

By using matrix3d(...) to place these primitives in 3D space, PolyCSS achieves a 3D effect while keeping the elements within the standard document flow. This allows developers to use standard CSS for styling and, more importantly, standard JavaScript event listeners for interaction.

Key Features and Capabilities

PolyCSS is designed to be a drop-in solution for developers who want 3D visuals without the overhead of a full WebGL pipeline.

Broad Format Support

PolyCSS can parse and render several industry-standard formats, making it easy to import assets from 3D modeling software:

  • OBJ + MTL: Supports materials, textures (map_Kd), and UV coordinates.
  • glTF / GLB: Supports embedded images and TEXCOORD_0.
  • MagicaVoxel (.vox): Includes optimized fast paths for voxel data.
  • Primitives: Built-in support for boxes, planes, rings, spheres, tori, cylinders, cones, and Platonic solids.

Framework Integration

To ensure ease of use, PolyCSS provides dedicated packages for different environments:

  • Vanilla JS: Custom elements and an imperative createPolyScene API.
  • React: Components like <PolyCamera>, <PolyScene>, and <PolyMesh> for a declarative 3D workflow.
  • Vue 3: Similar component-based architecture and composables.

Snapshot Export

One of the most powerful features of the library is exportPolySceneSnapshot. This function clones the rendered scene, inlines all CSS and image assets as base64 data URIs, and strips scripts. The result is a standalone HTML document that renders the 3D scene without requiring the PolyCSS runtime, making it ideal for sharing static 3D previews.

The Trade-off: DOM vs. WebGL

When introducing a tool like PolyCSS, the inevitable question is: Why not just use WebGL?

From a performance and quality standpoint, WebGL will always win. It is designed for millions of polygons and per-pixel depth testing. PolyCSS, by contrast, is limited by the number of DOM elements the browser can handle and the paint cost of texture atlases. However, the value of PolyCSS lies in developer experience and interaction.

As noted by community members on Hacker News, the primary advantage is the ability to handle per-polygon DOM events:

"The per-polygon DOM events are what make this more than a trick. Getting click handlers on individual faces in WebGL means raycasting. Here it's just onClick."

This transforms a 3D model from a visual asset into a functional UI component. Instead of calculating intersections in a 3D coordinate system, you can simply attach an onClick handler to a <Poly> element, just as you would with a button or a div.

Conclusion

PolyCSS represents a fascinating intersection of CSS transforms and 3D rendering. While it won't replace Three.js for high-fidelity gaming or complex simulations, it provides a lightweight, DOM-native alternative for developers who need interactive 3D elements, custom styling, and easy integration with the modern web stack. Whether you are building a voxel editor or a terrain generator, PolyCSS proves that the DOM is more than capable of handling 3D geometry when pushed to its limits.

Sources