Render Modes
glyphcss has three render modes. Each maps the same projected mesh to a different glyph layout.
| Mode | Best for | Cost |
|---|---|---|
wireframe | Geometric meshes, lattices, line art | Scales with edge count |
solid | Smooth-shaded surfaces from real mesh files | Scales with triangle count × grid cells |
voxel | MagicaVoxel .vox files, chunky low-poly | Scales with visible voxel faces |
wireframe
Section titled “wireframe”Bresenham-rasterizes each edge into a Uint8Array stamp with three weight tiers,
then maps the stamp to glyphs:
| Weight | Glyph palette | Used for |
|---|---|---|
| 1 (thin) | ·⋅∙˙·⋅∙ | Spokes, inner lattice, decorative scaffolding |
| 2 (normal) | ╋╬┼╳◆◇◊▲△▼▽◈⬡⬢∴∵⊥⊕⊗⊙⊚⊛ | Main cage edges |
| 3 (core) | ✦✧✩◉⊙◎ | Focal accents, “sun” centre |
import { GlyphCamera, GlyphScene, GlyphMesh, GlyphOrbitControls } from "@glyphcss/react";import { icosahedronPolygons } from "@glyphcss/core";
const icosa = icosahedronPolygons({ center: [0, 0, 0], size: 1, color: "#44ffcc" });
export function WireframeDemo() { return ( <GlyphCamera rotX={25}> <GlyphScene mode="wireframe" cols={80} rows={24}> <GlyphOrbitControls /> <GlyphMesh polygons={icosa} /> </GlyphScene> </GlyphCamera> );}import { createGlyphCamera, createGlyphScene } from "glyphcss";
const camera = createGlyphCamera({ rotX: 25 });const scene = createGlyphScene(document.querySelector("#scene")!, { camera, mode: "wireframe", cols: 80, rows: 24,});
// Custom wireframe edges with explicit weights:import { buildSceneContext } from "glyph-core";
const ctx = buildSceneContext({ camera, grid, wireframe: [ { from: [1, 0, 0], to: [-1, 0, 0], weight: 2 }, // bold edge { from: [0, 1, 0], to: [0, -1, 0], weight: 1 }, // thin spoke ], mode: "wireframe",});Best for: geometric meshes, lattices, iconic visuals.
Triangle scan-fill, with Lambert shading per cell mapped to a ramp:
" .:-=+*#%@"Darker glyphs for cells facing away from the directional light, brighter glyphs for cells facing it. Per-cell normal is interpolated from the triangle’s vertex normals.
import { GlyphCamera, GlyphScene, GlyphMesh, GlyphOrbitControls } from "@glyphcss/react";import { dodecahedronPolygons } from "@glyphcss/core";
const dodeca = dodecahedronPolygons({ center: [0, 0, 0], size: 1, color: "#cc44ff" });
export function SolidDemo() { return ( <GlyphCamera rotX={25}> <GlyphScene mode="solid" cols={100} rows={30} directionalLight={{ direction: [0.5, 0.7, 0.5], intensity: 1 }} ambientLight={{ intensity: 0.4 }} > <GlyphOrbitControls /> <GlyphMesh polygons={dodeca} /> </GlyphScene> </GlyphCamera> );}import { createGlyphCamera, createGlyphScene } from "glyphcss";import { dodecahedronPolygons } from "@glyphcss/core";
const camera = createGlyphCamera({ rotX: 25 });const scene = createGlyphScene(document.querySelector("#scene")!, { camera, mode: "solid", cols: 100, rows: 30, directionalLight: { direction: [0.5, 0.7, 0.5], intensity: 1 }, ambientLight: { intensity: 0.4 },});scene.add(dodecahedronPolygons({ center: [0, 0, 0], size: 1, color: "#cc44ff" }));Best for: smooth-shaded surfaces from real mesh files.
One glyph per voxel face, depth-sorted. Natural fit for MagicaVoxel .vox files
where the source data is already cell-aligned.
import { GlyphCamera, GlyphScene, GlyphMesh, GlyphOrbitControls } from "@glyphcss/react";import type { Polygon } from "@glyphcss/core";
// `polygons` comes from parseVox() — load the file outside the component.// Replace "/tree.vox" with your own MagicaVoxel file path.export function VoxelDemo({ polygons }: { polygons: Polygon[] }) { return ( <GlyphCamera rotX={25}> <GlyphScene mode="voxel" cols={80} rows={24}> <GlyphOrbitControls /> <GlyphMesh polygons={polygons} /> </GlyphScene> </GlyphCamera> );}import { createGlyphCamera, createGlyphScene } from "glyphcss";import { parseVox } from "@glyphcss/core";
// Replace "/tree.vox" with the path to your own MagicaVoxel file.const voxBuffer = await fetch("/tree.vox").then((r) => r.arrayBuffer());const { polygons } = parseVox(voxBuffer);
const camera = createGlyphCamera({ rotX: 25 });const scene = createGlyphScene(document.querySelector("#scene")!, { camera, mode: "voxel", cols: 80, rows: 24,});scene.add(polygons);Each face’s color (from the VOX palette) maps to a glyph density — bright colors
become # / @, dim colors become . / :. Back faces are culled.
Best for: voxel art, chunky low-poly aesthetics.
Shadows
Section titled “Shadows”Shadows use a shadow-map technique: the rasterizer renders a depth pass from the
light’s perspective, then compares each cell’s depth against it. Set shadow on
<GlyphScene> to enable, then opt individual meshes in with castShadow and
receiveShadow. A mesh with both flags self-shadows. <GlyphGround> defaults to
receiveShadow=true.
import { GlyphPerspectiveCamera, GlyphScene, GlyphMesh, GlyphGround,} from "@glyphcss/react";
const shadow = { color: "#000000", opacity: 0.25, lift: 0.05 };const directionalLight = { direction: [0.5, 0.7, 0.5], intensity: 1 };const ambientLight = { intensity: 0.35 };
export function ShadowDemo() { return ( <GlyphPerspectiveCamera rotX={45} rotY={30} zoom={50} distance={5}> <GlyphScene mode="solid" cols={100} rows={30} directionalLight={directionalLight} ambientLight={ambientLight} shadow={shadow} > <GlyphMesh geometry="dodecahedron" color="#4488ff" castShadow receiveShadow /> <GlyphGround /> </GlyphScene> </GlyphPerspectiveCamera> );}import { createGlyphPerspectiveCamera, createGlyphScene } from "glyphcss";import { dodecahedronPolygons, planePolygons } from "@glyphcss/core";
const camera = createGlyphPerspectiveCamera({ rotX: 45, rotY: 30, zoom: 50, distance: 5 });const scene = createGlyphScene(document.querySelector("#scene")!, { camera, mode: "solid", cols: 100, rows: 30, directionalLight: { direction: [0.5, 0.7, 0.5], intensity: 1 }, ambientLight: { intensity: 0.35 }, shadow: { color: "#000000", opacity: 0.25, lift: 0.05 },});
const caster = scene.add( dodecahedronPolygons({ center: [0, 0, 0], size: 1, color: "#4488ff" }), { castShadow: true, receiveShadow: true },);
const ground = scene.add( planePolygons({ axis: 1, size: 5, offset: 0, color: "#444444" }), { position: [0, -0.5, 0], receiveShadow: true },);Shadow fields (GlyphShadowOptions):
| Field | Default | Description |
|---|---|---|
color | "#000000" | Shadow tint color |
opacity | 0.25 | Darkness 0..1 |
lift | 0.05 | Depth bias — prevents self-shadow acne on flat lit surfaces |
maxExtend | 2000 | Half-extent of the light-space projection volume |
Built-in geometry attribute
Section titled “Built-in geometry attribute”The <glyph-mesh> custom element and the GlyphMesh component accept a
geometry string shortcut for three built-in shapes. These are runtime-internal
presets, not public core helpers — for procedural code use the @glyphcss/core
generators instead.
| Value | Shape | Notes |
|---|---|---|
"cuboctahedron" | Cuboctahedron with inner lattice | Default demo shape |
"icosahedron" | Icosahedron, edge-only wireframe | 20 faces |
"cube" | Plain cube wireframe | 6 faces |
// Built-in preset (no import needed):<GlyphMesh geometry="cuboctahedron" />
// Equivalent procedural form (more control):import { icosahedronPolygons } from "@glyphcss/core";<GlyphMesh polygons={icosahedronPolygons({ center: [0,0,0], size:1 })} />