Demo app that showcases scalable GPU text rendering with MTSDF (Multi-channel True Signed Distance Field) and HarfBuzz shaping. Built with Next.js (App Router), React Three Fiber, and TypeScript in strict mode.
- MTSDF rendering for crisp, scalable text
- HarfBuzz shaping (ligatures/kerning, multilingual)
- Two visualization modes: Plane and Cube (all six faces)
- 10 bundled fonts; on-demand atlas generation with caching
- Font size range 4pt–50pt; MSDF + SDF fallback for tiny sizes
- Minimal UI with loading overlay while atlas is generated
- Next.js 16 (App Router), React, TypeScript (strict)
- React Three Fiber + Three.js for 3D
- harfbuzz-modern-wrapper (WASM) for shaping
- msdf-atlas-gen for atlas generation (CLI)
- Tailwind CSS (shadcn-style components)
- Vercel Blob (serverless cache for atlases, public-read objects)
- Node.js 18+
msdf-atlas-genCLI available (built viascripts/setup-msdf-atlas-gen.shor installed system-wide)- Fonts present in
public/fonts/(scripts/setup-fonts.sh can download them) - For Vercel serverless:
BLOB_READ_WRITE_TOKENmust be set (used to store atlases in Vercel Blob instead of local disk; objects are uploaded with public access for direct serving)
npm install
# postinstall runs setup-all:
# - downloads fonts (setup-fonts.sh)
# - copies HarfBuzz WASM (setup-harfbuzz.sh)
# - clones/builds msdf-atlas-gen v1.3 (setup-msdf-atlas-gen.sh)If you skip postinstall, run manually:
npm run setup-harfbuzz
npm run setup-fonts
npm run setup-msdf-atlas-genOn Vercel serverless, atlases are stored in Vercel Blob automatically; set BLOB_READ_WRITE_TOKEN in project settings. Objects are uploaded as public-read for simplicity. Local/Node runtimes keep using public/generated (or ATLAS_CACHE_DIR if provided).
npm run dev
# open http://localhost:3000npm run build
npm startnpm run lint # biome
npx tsc --noEmit # TypeScript strict check- Atlas generation:
/api/atlas?font=idchecks/public/generated/<font>/; if missing, runsmsdf-atlas-gen(2048×2048 PNG + JSON metrics, glyph size 48px, pxRange 4). Results are cached on disk. - Shaping: HarfBuzz (WASM) shapes the static text using the selected font file in
/public/fonts/. - Geometry: Quads are generated from shaping data + atlas metrics; UVs map to glyph regions.
- Rendering: Custom MTSDF shader samples RGB (MSDF) with A-channel fallback for tiny sizes; smoothstep for AA. Plane scene and cube faces share the same gradient/text content.
- UI: Sidebar controls (font selector, size slider, mode toggle), splitter to resize sidebar; modal loading overlay during atlas generation.
- Sans: Roboto, Open Sans, Lato, Montserrat
- Serif: Merriweather, PT Serif, Playfair Display
- Mono: JetBrains Mono, Fira Code, Roboto Mono
npm run setup-fonts— downloads required TTFs intopublic/fonts/.npm run setup-harfbuzz— copieshb.wasmandhbjs.jsintopublic/wasm.npm run setup-msdf-atlas-gen— clonesexternal/msdf-atlas-gen, checks out tagv1.3, appliesmisc/msdf-atlas-gen.patchon macOS, builds with CMake (no vcpkg/skia).npm run setup-all— runs all setup scripts (hooked topostinstall, so it also runs on Vercel).
GET /api/fonts→ list of fonts{ id, name, category, file }GET /api/atlas?font=<id>→ triggers/checks atlas generation, returns{ atlasUrl, metadata }
- Atlas generation on Vercel: the filesystem is read-only; atlases are generated in
/tmpand uploaded to Vercel Blob (public-read). EnsureBLOB_READ_WRITE_TOKENis configured;ATLAS_CACHE_DIRoverrides the local path for non-serverless runs. - msdf-atlas-gen not found: ensure the binary exists at
external/msdf-atlas-gen/build/bin/msdf-atlas-genor on PATH; rerunsetup-msdf-atlas-gen.sh. - Fonts missing: check
public/fonts/filenames matchlib/server/fonts-config.ts. - Slow first load: first atlas build per font may take several seconds; cached afterward.
MIT