HTML API
glyphcss/elements is a side-effect import that registers a set of
<glyph-*> custom elements with customElements. After the import runs,
you can use them in plain HTML — no React, no Vue, no build step required.
Install
Section titled “Install”pnpm add glyphcss<script type="module" src="https://esm.sh/glyphcss/elements"></script>Or in a bundled app:
import "glyphcss/elements"; // side-effect — registers customElementsRe-imports are idempotent (the module checks customElements.get before
defining). In non-DOM environments (SSR, Node) the module silently no-ops.
Element tree
Section titled “Element tree”Camera wraps scene. Attribute names are kebab-case (rot-x, rot-y,
hidden-lines, auto-size). Boolean attributes follow standard HTML
convention — present means true.
<glyph-perspective-camera rot-x="65" rot-y="45" zoom="50" distance="3"> <glyph-scene mode="solid" cols="100" rows="30"> <glyph-orbit-controls drag wheel></glyph-orbit-controls> <glyph-mesh geometry="cube"></glyph-mesh> <glyph-hotspot hotspot-id="top" at="0,0.5,0" size="3,2"></glyph-hotspot> </glyph-scene></glyph-perspective-camera>Elements
Section titled “Elements”<glyph-scene>
Section titled “<glyph-scene>”Root container. Owns the <pre> rasterisation output and the lighting state.
| Attribute | Type | Notes |
|---|---|---|
mode | "wireframe" | "solid" | "voxel" | "ink" | Default solid |
cols | number | Grid width in character columns |
rows | number | Grid height in character rows |
cell-aspect | number | Height ÷ width of the cell (default 2.0) |
glyph-palette | string | Named palette: default, detail, ascii, lines, blocks, dots, solid, braille, runes, stars, arrows, math, binary, hex |
char-mode | "ascii" | "braille" | "halfblock" | "quadrant" | Character encoding for rasterized output (default "ascii"). "braille" (wireframe-only) packs a 2×4 subcell dot grid into Unicode Braille Patterns for smoother edges. "halfblock" (solid-only) packs two independently colored subcells (top/bottom) into ▀/▄/█ for 2× vertical color resolution. "quadrant" (solid-only) generalizes that to a full 2×2 subcell split (16 possible glyphs) for both shape AND color resolution. Each is a documented no-op outside the mode it applies to |
use-colors | bool | Emit color spans in the output |
wireframe-junctions | flag | Box-drawing junction resolve pass (wireframe + char-mode="ascii" only): corners/T-junctions/crossings render from ┌┐└┘├┤┬┴┼─│ instead of a random per-edge glyph |
hidden-lines | "show" | "hide" | Hidden-line removal for wireframe (+ braille) and ink. Default show. No-op in solid, which is already depth-buffered |
color-tolerance | number | Merge adjacent cells into one <span> while their colors stay within this redmean distance (range 0–765, not 0–255). Default 0 (off, byte-identical). NaN/negative values degrade to 0; +Infinity/-Infinity are recognized literally (as strings) and behave the same as the JS surface. No-op under glyph-output="semantic" — semantic colors are exact class identifiers, not shaded appearance |
glyph-output | "visible" | "semantic" | Default visible. semantic needs sceneManifest + dictionary, which are set as JS properties (they are data, not string attributes) |
directional-direction | "x,y,z" | Key-light source vector — the direction from the shaded surface toward the light. Comma-separated, like <glyph-mesh position>. Either this or directional-intensity configures the light; the other falls back to its default |
directional-intensity | number | Key-light intensity |
ambient-intensity | number | Ambient fill intensity |
auto-size | flag | Auto-fit cols/rows to the host’s box via ResizeObserver |
interactive-downscale | number | Render at 1/n resolution while dragging, full detail on release (e.g. 2). Keeps high-density scenes smooth. Default 1 (off) |
shadow | flag | Enable shadow-map pass. Must be present for any shadows to render |
shadow-color | string | Shadow tint hex color (default "#000000") |
shadow-opacity | number | Shadow darkness 0..1 (default 0.25) |
shadow-lift | number | Depth bias — prevents self-shadow acne (default 0.05) |
shadow-max-extend | number | Half-extent of the light-space projection volume (default 2000) |
solidWeightRamp (solid-mode-only font-weight density ramp — see the
render modes guide)
is a JS property, not an attribute — it is measurement data
({ glyph: string; weight: number }[]), the same “property, not attribute”
rule sceneManifest/dictionary use: document.querySelector("glyph-scene").solidWeightRamp = steps.
<glyph-perspective-camera> / <glyph-orthographic-camera> / <glyph-camera>
Section titled “<glyph-perspective-camera> / <glyph-orthographic-camera> / <glyph-camera>”<glyph-camera> is the ergonomic default — an alias for
<glyph-orthographic-camera>. All three accept the same orientation
attributes; perspective additionally accepts distance, perspective, and stretch.
| Attribute | Notes |
|---|---|
rot-x | Pitch in degrees |
rot-y | Yaw in degrees |
zoom | CSS pixels per world unit |
distance | Perspective only — pull-back; CSS pixels with CSS perspective, world units only in legacy perspective="0" mode |
perspective | Perspective only — CSS-perspective distance in px (default 32000; 0 = legacy orbit) |
stretch | Perspective only |
<glyph-mesh>
Section titled “<glyph-mesh>”Polygon registration. Picks one source in descending precedence: geometry
< src < explicit polygons (only available via JS property, not attribute).
| Attribute | Notes |
|---|---|
src | URL of OBJ / GLB / glTF / VOX mesh |
geometry | Built-in name from @glyphcss/core registry (cube, dodecahedron, …) |
size | Uniform size for geometry |
color | Fill color for geometry |
position | x,y,z translation |
scale | s or sx,sy,sz |
rotation | rx,ry,rz XYZ Euler degrees |
auto-center | flag — recenter the mesh’s bbox center to the origin so it pivots around its own center (center only) |
cast-shadow | flag — this mesh casts shadows onto receive-shadow surfaces |
receive-shadow | flag — this mesh displays shadows from cast-shadow meshes. Present on both = self-shadow |
density | number — render this mesh at density× the scene resolution, in its own <pre> (see the Density & Detail guide) |
font-size | explicit cell size (px or CSS length); overrides density |
line-height | explicit cell line-height; overrides density |
transparent | flag — see-through: doesn’t occlude / isn’t occluded |
mode | "wireframe" | "solid" | "voxel" | "ink" — render this mesh in its OWN mode, in its own <pre>, when it differs from the scene’s (see the Density & Detail guide). An unrecognized value is ignored |
<glyph-hotspot>
Section titled “<glyph-hotspot>”3D-anchored DOM hotspot. Child nodes are positioned at the projected screen cell every render.
| Attribute | Notes |
|---|---|
hotspot-id | Identifier for handle lookup |
at | x,y,z anchor in world space |
size | w,h in cells |
<glyph-effect-layer>
Section titled “<glyph-effect-layer>”Mounts a retained appearance program inside <glyph-scene>. The executable
definition is a JavaScript value, so use the atomic property API rather than a
JSON attribute:
import { GlyphEffects } from "@glyphcss/effects";
const effect = document.querySelector("glyph-effect-layer")!;effect.configure({ effect: GlyphEffects.matrixRain, params: { glyphs: "HOLA", speedMin: 5, speedMax: 12 },});const handle = await effect.whenReady();handle.params.time = performance.now() / 1000;Attributes target="surfaces|viewport", blend="over|replace", opacity,
order, and enabled="false" override the matching configured option. The
element emits glyphcss:effect-ready and exposes getEffectHandle(). See
Glyph Effects for the catalog, clocks, and current runtime
boundary.
<glyph-orbit-controls> / <glyph-map-controls>
Section titled “<glyph-orbit-controls> / <glyph-map-controls>”Camera controls. Orbit rotates around the target; map pans across the target plane.
| Attribute | Notes |
|---|---|
drag | flag — enable drag |
wheel | flag — enable wheel zoom |
invert | flag or number — invert axis multiplier |
clamp-pitch | flag — stop the orbit pitch from passing over the poles |
animate-speed | Orbit-only: auto-rotation speed |
animate-axis | Orbit-only: x | y |
<glyph-first-person-controls>
Section titled “<glyph-first-person-controls>”First-person camera (requires a <glyph-perspective-camera>). Pointer-lock
mouselook, WASD/arrow move, Space jump, Ctrl crouch.
| Attribute | Notes |
|---|---|
look-enabled / move-enabled / jump-enabled / crouch-enabled | flags — toggle each axis |
look-sensitivity | degrees per pixel (default 0.15) |
invert-y | flag — invert vertical look |
move-speed / jump-velocity / gravity | world-unit motion params |
eye-height / crouch-height / ground-z | world-unit placement |
min-pitch / max-pitch | pitch clamp (degrees) |
Scene-ready handshake
Section titled “Scene-ready handshake”Custom elements register asynchronously. If you need to call imperative
methods on the scene from JavaScript, listen for glyphcss:scene-ready on
the <glyph-scene> element:
const sceneEl = document.querySelector("glyph-scene")!;sceneEl.addEventListener("glyphcss:scene-ready", (ev) => { const scene = (ev.target as any).getScene(); scene.addHotspot({ id: "runtime", at: [0, 0, 1] }, () => alert("clicked"));});End-to-end example
Section titled “End-to-end example”<!DOCTYPE html><html> <head> <script type="module" src="https://esm.sh/glyphcss/elements"></script> <style> glyph-scene { display: block; width: 600px; height: 400px; } </style> </head> <body> <glyph-perspective-camera rot-x="65" rot-y="45" zoom="50" distance="3"> <glyph-scene mode="solid" cols="120" rows="36" directional-intensity="1" ambient-intensity="0.4" > <glyph-orbit-controls drag wheel></glyph-orbit-controls> <glyph-mesh geometry="dodecahedron" color="#4488ff"></glyph-mesh> <glyph-hotspot hotspot-id="top" at="0,0.5,0" size="3,2"> <span class="badge">top</span> </glyph-hotspot> </glyph-scene> </glyph-perspective-camera> </body></html>See also
Section titled “See also”- React API — same elements, JSX form
- Vue API — same elements, idiomatic Vue
- Headless API — the imperative factory the elements wrap