If you've ever tried to load a standard .ttf or .otf file directly into THREE.TextGeometry, you probably ran into errors. That's because WebGL doesn't natively understand vector font curves.
Three.js relies on a format called Typeface JSON. This is essentially a JSON file that pre-calculates the paths of every glyph, allowing the 3D engine to triangulate and extrude them into 3D meshes efficiently.
Step 1: Uploading Your Font
Head over to the Vextrude Font Converter. Since the tool runs entirely in your browser using opentype.js, your font files are never uploaded to a server. This makes it safe for proprietary or licensed fonts.
- Click the drop zone or drag your file onto it.
- Supported formats: TTF (TrueType) and OTF (OpenType).
- The tool will immediately parse the file and show a 3D preview.
Step 2: Optimizing Settings
Before downloading, you have two critical settings to check in the "Conversion Settings" panel:
Reverse Winding
If your 3D text looks "inside out" or has holes where it shouldn't, enable Reverse Winding. This flips the direction of the path definitions. It's a common issue with certain font editors, and this toggle fixes it instantly.
Restrict Characters
Font files can be huge, especially if they contain CJK characters or extensive symbol sets.
- Unchecked: Converts every glyph in the font. Good for complete support, but large file size.
- Checked: Converts only English letters, numbers, and basic punctuation. Drastically reduces JSON size (often from 1MB+ down to 50KB).
Step 3: Using the File
Once you click Download JSON, you'll get a file that works with any Three.js project.
In Vextrude Text Tool
You can upload this JSON file directly into the Text to 3D Tool to use your custom font with all our material and lighting effects.
In Your Own Code
If you're a developer, load the file using FontLoader:
import { FontLoader } from 'three/examples/jsm/loaders/FontLoader.js';
import { TextGeometry } from 'three/examples/jsm/geometries/TextGeometry.js';
const loader = new FontLoader();
loader.load('path/to/your-font.json', function (font) {
const geometry = new TextGeometry('Hello World', {
font: font,
size: 80,
height: 5,
});
// ... create mesh
}); What Is Actually Inside typeface.json
The output is not a repackaged font. It is a JSON document containing the outline of each glyph rewritten as drawing commands.
Each glyph entry holds an o string — a sequence of move, line, quadratic and bézier instructions with their coordinates — plus ha, the horizontal advance that determines how far the cursor moves before the next character. Alongside the glyphs sit family name, weight, resolution (the units-per-em the coordinates are expressed in, typically 1000), and ascender and descender values used for vertical alignment.
Because coordinates are stored in font units rather than pixels, the same file renders at any size without loss. The renderer scales the outline, then triangulates it into a mesh.
Everything else a font contains — hinting, kerning tables, OpenType features, colour layers — is discarded. Only outlines and advances survive, which explains several of the limitations in the sections below.
Why Convert At All
Three.js has no built-in TrueType parser. Its text geometry expects glyph outlines already expressed as paths, so a .ttf cannot be handed to it directly.
You can parse fonts at runtime with a library such as opentype.js, and for some applications that is the better answer — it keeps the original font file and supports dynamic loading. The cost is a parsing library in your bundle and per-load parsing work.
Pre-converting moves that cost to build time. The browser downloads plain JSON and starts rendering immediately, with no parser involved. For a site showing a fixed set of typefaces, that is the faster path; for one where users upload arbitrary fonts, runtime parsing is the more flexible one.
File Size Is Driven by Glyph Count
A converted Latin font typically lands somewhere in the low hundreds of kilobytes — larger than the original binary, because JSON stores coordinates as text.
CJK fonts are a different proposition entirely. A typeface covering common Chinese characters holds thousands of glyphs, each with its own outline, and the converted JSON can reach tens of megabytes. Loading that to render four characters is not viable.
The answer is subsetting: convert only the glyphs you need. If your 3D text is a fixed word or a known character set, a subset of twenty glyphs produces a file a browser loads instantly. Tools such as fonttools' pyftsubset do this on the original font before conversion.
Practical check:
Convert the full font once and look at the resulting size. Anything over roughly 1 MB is worth subsetting before it reaches production, particularly if the text is decorative rather than user-supplied.
Converting Does Not Change the Licence
This deserves stating plainly, because format conversion feels like it creates something new. It does not. A converted typeface.json is a derivative of the original font and remains bound by that font's licence.
Two clauses matter in practice. Many commercial font EULAs distinguish desktop licences from webfont licences, and publishing a converted font to a website is web distribution regardless of format. Some also prohibit modification or conversion outright.
Open-licensed families avoid the question. SIL Open Font License fonts — the whole Google Fonts catalogue among them — explicitly permit modification and redistribution, with the condition that derivatives stay under the same licence and are not sold on their own.
If a font came bundled with software you bought, check before publishing. Bundled fonts are frequently licensed for use with that application only.
When Conversion Fails or Looks Wrong
A handful of causes account for most problems:
- Variable fonts. A single file containing an axis of weights has no one outline per glyph. Export a static instance at the weight you want, then convert that.
- Colour and bitmap fonts. Emoji fonts store layered colour or embedded bitmaps rather than plain outlines. There is nothing to extrude.
- Overlapping contours. Some fonts draw a glyph as several overlapping shapes, correct for a rasteriser but ambiguous for triangulation. The result is a filled counter or an inverted region.
- Wrong glyphs entirely. Usually a subsetted or encoding-remapped file where codepoints no longer map where you expect.
When a conversion produces mangled output, try a different weight of the same family before concluding the font is unsupported — static, single-master files convert far more reliably than anything variable.
