ultra‑text documentation

Mini3 & Vanilla WebGPU integration

ultra-text
for Mini3 & Vanilla JS

Your HTML. Zero Three.js dependency. Text in Mini3 or any engine.

const text = await UltraText.create(renderer, source)
Copy the starter once, or use ultra-text/vanilla directly

Import from ultra-text/vanilla to run the full DOM capture, Pretext layout, WebGPU JFA / CPU EDT SDF atlas generator, and typed-array instance buffer packer without installing or bundling Three.js.

Checked 19 October 2026
Mini3 0.1.0-alpha.0 · ultra-text/vanilla (Three.js-free)

01 — Install & copy

Add it to your Mini3 or Vanilla app

Install ultra-text alongside mini3 (Three.js is an optional peer dependency and is not required when importing ultra-text/vanilla):

npm install ultra-text mini3
Install — no Three.js dependency required for ultra-text/vanilla

Save this file in src/components/:

This is an ordinary source file you can adapt, covered by the MIT License. It is ready for you or your coding agent to copy into your project.

02 — Render in Mini3

Mark your text. Add the node to your Mini3 scene.

import { Camera, Renderer, Scene } from 'mini3'
import { UltraText } from './components/UltraText.js'

const renderer = await Renderer.create({ autoResize: true, appendTo: document.body })
const scene = new Scene(renderer)
const camera = new Camera(40, renderer.aspect, 0.1, 100)
camera.position.set(0, 0, 6)

const source = document.querySelector<HTMLElement>('#card')!
const text = await UltraText.create(renderer, source)
scene.add(text)

renderer.setAnimationLoop(() => {
  renderer.render(scene, camera)
})
main.ts — complete Mini3 usage example

data-sdf-block marks the text to capture inside #card. Keep the source connected and visible with a real layout box. Update DOM text or styles as usual; UltraText observes those changes and updates its Mini3 meshes automatically.

03 — Vanilla JS & custom engines

Use ultra-text/vanilla directly

Building your own WebGPU or Canvas renderer? Import DomText, Text, or the lower-level stages from ultra-text/vanilla:

import { DomText } from 'ultra-text/vanilla'

const domText = await DomText.create(source, gpuDevice, {
  quality: 'high',
  reflowable: true,
  onChange(instance, reason) {
    // Upload instance.glyphs, instance.plainRects, instance.decorations
    // and bind instance.atlas.gpuTexture (or instance.atlas.data on CPU)
  },
})
Engine-agnostic retained controller & typed-array buffers
What ultra-text/vanilla exports

DomText (aliased as DomSdf and VanillaDomText) and Text (VanillaText) manage font readiness, DOM capture, WebGPU JFA or CPU EDT SDF atlas generation, typed-array instance buffer packing (glyphs, plainRects, litRects, decorations), in-place reflow(width), observers and dispose().

Lower-level stages are also exported: collectDomSnapshot, reflowSnapshot, rasterizeGlyphAtlas, buildVanillaSdfAtlas (buildSdfAtlas), buildVanillaGpuSdfAtlas, buildVanillaCpuSdfAtlas, packGlyphInstances, packRectInstances, packDecorationInstances, and resolveDomTextTone.

What the copied Mini3 component takes care of

It waits for fonts, captures the source once, builds the R8 SDF atlas directly on renderer.device, adopts the GPUTexture into a Mini3 Texture, observes DOM changes, cancels superseded work and disposes its resources on unmount. Capture and rebuild stay outside the frame loop.

Working with a coding agent? Give it the integration instructions. They include permission to copy and adapt these MIT examples, plus the setup and lifecycle rules.