Skip to content

Hit Layer Interactivity

The glyphcss hit layer is sparse — you opt-in to interactivity by registering hotspots at specific 3D anchors. No polygon-per-DOM-node overhead.

A glyph-style “one DOM node per polygon” model gives you per-polygon events but balloons the DOM for large meshes (a 10k-triangle GLB → 10k <div>s). glyphcss takes the opposite trade: a single <pre> for visuals, and only the hotspots you explicitly register become DOM nodes.

For most real apps this is what you want. You don’t need click handlers on every roof shingle; you need them on the front door.

import { GlyphCamera, GlyphScene, GlyphMesh, GlyphHotspot } from "@glyphcss/react";
import { octahedronPolygons } from "@glyphcss/core";
const shape = octahedronPolygons({ center: [0, 0, 0], size: 1, color: "#ffcc44" });
<GlyphCamera rotX={25}>
<GlyphScene mode="solid" cols={80} rows={24}>
<GlyphMesh polygons={shape}>
<GlyphHotspot at={[0, 1, 0]} onClick={() => alert("top vertex")}>
<span className="badge">Top</span>
</GlyphHotspot>
<GlyphHotspot at={[0, -1, 0]} onClick={() => alert("bottom vertex")}>
<span className="badge">Bottom</span>
</GlyphHotspot>
</GlyphMesh>
</GlyphScene>
</GlyphCamera>

Each <GlyphHotspot> becomes:

<div class="glyph-demo__hotspot"
role="button"
style="position: absolute; transform: translate3d(...); width: ...; height: ...">
<span class="badge">Roof</span>
</div>

The transform: translate3d(...) updates every frame via @keyframes matching the strip’s steps(60, end) timing.

at accepts either an explicit Vec3 or a string anchor:

AnchorResolves to
[x, y, z]World-space coordinate
"vertex:42"Vertex index 42 of the parent mesh
"face:roof"Named face (requires mesh authoring)
"centroid"Mesh centroid

Hotspots behind the camera get opacity: 0 automatically. Use this for “show this label only when the user is looking at the front of the house”:

.glyph-demo__hotspot {
transition: opacity 200ms ease;
}

The fade is free — the renderer just writes opacity: 0 into the keyframe at any frame where the anchor is behind the camera.