The port of the JavaScript versions of three-bmfont-text, layout-bmfont-text, load-bmfont, and word-wrapper to Pure Typescript, this library enables fast text rendering with Three.js and bitmap font.
The difference in rendering speed is noticeable when animations are enabled, and it runs 10x faster than canvas texture based text rendering.
v4.0 introduces WebGPU support with TSL (Three Shading Language) based node materials that work with both WebGLRenderer and WebGPURenderer.
- Three.js 0.172.0 or later
- React 19 or later
- React Three Fiber 9 or later
- Node.js 22 or later
$ npm install three-text-geometry three react @react-three/fiber
$ pnpm add three-text-geometry three react @react-three/fiber
$ yarn add three-text-geometry three react @react-three/fiber
Note:
three,react, and@react-three/fiberare peer dependencies and must be installed alongsidethree-text-geometry.
For detailed information, read the documentation and check the demo.
TextGeometry supports word wrapping, text aligning, letter spacing, kerning. See the list for all available options.
three-text-geometry provides first-class support for React Three Fiber.
TextGeometry is automatically registered with the R3F catalog when the library is imported. No manual setup is required.
import 'three-text-geometry'
// <textGeometry ... /> is now availableFactory pattern (R3F v9)
Alternatively, use R3F v9's extend to create a component directly.
import { extend } from '@react-three/fiber'
import TextGeometry from 'three-text-geometry'
const TextGeometryEl = extend(TextGeometry)
// Now you can use <TextGeometryEl ... />The useFont hook loads a BMFont file and its texture asynchronously. Combined with <textGeometry>, you can render bitmap text in just a few lines.
import * as THREE from 'three'
import { Canvas } from '@react-three/fiber'
import { TextAlign, useFont } from 'three-text-geometry'
function TextMesh() {
const { font, texture, isLoading } = useFont(
'https://example.com/font.json',
'https://example.com/font.png'
)
if (isLoading || !font || !texture) return null
return (
<mesh rotation={[Math.PI, 0, 0]}>
<textGeometry args={['Hello World', { font, align: TextAlign.Left, width: 800, flipY: texture.flipY }]} />
<meshBasicMaterial map={texture} transparent side={THREE.DoubleSide} />
</mesh>
)
}
function App() {
return (
<Canvas camera={{ fov: 45, position: [0, 0, 500] }}>
<TextMesh />
</Canvas>
)
}Importing three-text-geometry automatically augments R3F's ThreeElements interface, enabling type completions for <textGeometry> in TypeScript projects.
import 'three-text-geometry' // Adds textGeometry to ThreeElementsYou can also use TextGeometry directly without React Three Fiber.
import * as THREE from 'three'
import TextGeometry, { BMFont, BMFontJsonParser, TextAlign } from 'three-text-geometry'
// Load font and texture
const res = await fetch('https://example.com/font.json')
const font: BMFont = new BMFontJsonParser().parse(await res.json())
const texture = await new THREE.TextureLoader().loadAsync('https://example.com/font.png')
// Create geometry and mesh
const geometry = new TextGeometry('Hello World', {
font,
align: TextAlign.Left,
width: 800,
flipY: texture.flipY,
})
const material = new THREE.MeshBasicMaterial({
map: texture,
side: THREE.DoubleSide,
transparent: true,
})
const mesh = new THREE.Mesh(geometry, material)
.rotateY(Math.PI)
.rotateZ(Math.PI)
scene.add(mesh)three-text-geometry provides TSL-based node materials for text rendering. These materials work with both WebGLRenderer and WebGPURenderer.
Samples a font texture and multiplies by color and opacity. Suitable for standard bitmap fonts.
import { BasicTextNodeMaterial } from 'three-text-geometry'
const material = new BasicTextNodeMaterial({
map: texture,
color: new THREE.Color(0xffffff),
opacity: 1,
})For SDF (Signed Distance Field) fonts. Uses screen-space derivatives for anti-aliased edges.
import { SDFTextNodeMaterial } from 'three-text-geometry'
const material = new SDFTextNodeMaterial({
map: texture,
color: new THREE.Color(0xffffff),
})For MSDF (Multi-channel Signed Distance Field) fonts. Computes a median from RGB channels for high-quality rendering.
import { MSDFTextNodeMaterial } from 'three-text-geometry'
const material = new MSDFTextNodeMaterial({
map: texture,
color: new THREE.Color(0xffffff),
negate: true, // Invert RGB channels (default: true)
})For multi-texture fonts. Selects the correct texture atlas per vertex using a page attribute. Requires multipage: true in TextGeometryOption.
import { MultiPageTextNodeMaterial } from 'three-text-geometry'
const material = new MultiPageTextNodeMaterial({
textures: [texture0, texture1, texture2],
color: new THREE.Color(0xffffff),
})
const geometry = new TextGeometry('Hello', {
font,
multipage: true,
})v4 removes the legacy GLSL shader modules. If you were using MultiPageShaderMaterial or the GLSL shader sources from three-text-geometry/shaders, migrate to the new TSL-based node materials:
| v3 (Removed) | v4 (Replacement) |
|---|---|
shaders/basic |
BasicTextNodeMaterial |
shaders/sdf |
SDFTextNodeMaterial |
shaders/msdf |
MSDFTextNodeMaterial |
MultiPageShaderMaterial |
MultiPageTextNodeMaterial |
The demo is built with React Three Fiber. Clone the repository and run:
git clone https://github.com/gumob/three-text-geometry.git
cd three-text-geometry/demo
corepack enable
pnpm install
pnpm dev
TextGeometry places text based on the screen coordinate system.
Therefore, when THREE.Mesh is added to the scene, the text will be placed inverted when viewed from the positive direction of the Z axis.
To make the text visible from the positive z-axis, you need apply transformation.
Parse font data in JSON format
import { BMFontJsonParser } from 'three-text-geometry'
const font: BMFont = new BMFontJsonParser().parse(/** `string` or `object` data JSON format */)Parse font data in XML format
import { BMFontXMLParser } from 'three-text-geometry'
const font: BMFont = new BMFontXMLParser().parse(/** `string` data in XML format */)Parse font data in ASCII format
import { BMFontAsciiParser } from 'three-text-geometry'
const font: BMFont = new BMFontAsciiParser().parse(/** `string` data in ASCII format */)Parse font data in Binary format
import { BMFontBinaryParser } from 'three-text-geometry'
const font: BMFont = new BMFontBinaryParser().parse(/** `string` data in ASCII Binary */)| key | type | description | default | required |
|---|---|---|---|---|
| font | BMFont |
The BMFont definition which holds chars, kernings, etc | undefined | ✔ |
| width | number |
The desired width of the text box, causes word-wrapping and clipping in WordWrapMode mode. Leave as undefined to remove word-wrapping (default behaviour) |
undefined | |
| mode | WordWrapMode |
A mode for word-wrapper; can be WordWrapMode.Pre (maintain spacing), or WordWrapMode.NoWrap (collapse whitespace but only break on newline characters), otherwise assumes normal word-wrap behaviour (collapse whitespace, break at width or newlines) |
undefined | |
| align | TextAlign |
This can be TextAlign.left, TextAlign.center or TextAlign.right |
TextAlign.left |
|
| letterSpacing | number |
The letter spacing in pixels | 0 | |
| lineHeight | number |
The line height in pixels | font.common.lineHeight |
|
| tabSize | number |
The number of spaces to use in a single tab | 4 | |
| start | number |
The starting index into the text to layout | 0 | |
| end | number |
The ending index (exclusive) into the text to layout | text.length |
|
| flipY | boolean |
Whether the texture will be Y-flipped | true | |
| multipage | boolean |
Whether to construct this geometry with an extra buffer containing page IDs. This is necessary for multi-texture fonts | false |
The following tools can be used to convert fonts to a bitmap font:
- msdf-bmfont-web (Online Tool)
- msdf-bmfont-xml (Commandline Tool)
- Hiero (Desktop App, Windows Only)
Read the Three.js documentation about a bitmap font.
Install msdf-bmfont-xml
$ npm install msdf-bmfont-xml -g
Generate a bitmap font
$ msdf-bmfont \
--output-type json \
--filename 'OdudoMono-Regular-128' \
--font-size 128 \
--texture-size 1024,1024 \
--field-type 'sdf' \
'OdudoMono-Regular.otf'
Punycode is released under MIT license, which means you can modify it, redistribute it or use it however you like.

