Font Generator is a browser-first font design app built with Next.js. It turns a plain English prompt into a usable typeface by combining model-assisted design choices with real variable font technology.
The app lets a user:
- Describe a typeface in natural language.
- Generate a font direction from that prompt.
- Adjust the selected base font and its variable axes.
- Edit individual glyph outlines in the browser.
- Export a downloadable
.ttfor.otffile.
The core design choice is conservative: the project uses real bundled variable fonts as source material instead of asking a model to invent every glyph. That means exported fonts start from professional outlines and complete character sets.
prompt
-> /api/generate
-> model-backed JSON or deterministic fallback
-> FontParams
-> live CSS preview
-> HarfBuzz/opentype export
FontParams is the shared contract between the API route and the UI:
{
familyName: string;
base: string;
axes: Record<string, number>;
tracking: number;
shape: ShapeParams;
}The UI sanitizes generated parameters before rendering or exporting, so invalid model output cannot select unknown fonts or out-of-range axis values.
app/api/generate/route.ts receives a prompt and returns sanitized font
parameters. When NVIDIA_API_KEY is configured, the route calls an
OpenAI-compatible NVIDIA endpoint. When no valid key exists, it uses a
deterministic keyword fallback.
The fallback is intentional. It lets contributors develop, test, and review the project without paid credentials.
The route also includes:
- prompt and body size limits
- basic in-memory rate limiting
- upstream timeout configuration
- safe provider fallback behavior
- server-only API key usage
lib/fontCatalog.ts is the source of truth for bundled fonts. Each font entry
defines:
- stable id
- display label
- CSS family
- served file path
- variable axis ranges
- default axis values
- keyword hints for fallback generation
The catalog powers the model prompt, fallback generation, UI controls, live preview, and export code.
Most previews render through normal CSS:
@font-face + font-variation-settings + letter-spacing
This keeps the studio fast. Character maps, specimens, weight ladders, and the hero preview all render the same selected base font and axis values.
lib/genShape.ts applies prompt-seeded geometric changes to glyph outlines.
components/GlyphEditor.tsx lets users move glyph nodes directly.
When a user edits a glyph, that glyph is frozen as edited outline data. Unedited glyphs can still receive the global shape transform during export.
There are two export paths:
- No glyph edits or shape changes:
lib/instanceFont.tsuses HarfBuzz (public/hb-subset.wasm) to pin variable axes and export a static.ttf. Nonzero tracking is baked into the advance widths by patchinghmtx(lib/sfnt.ts) so the download matches the CSS preview. - Edited or shaped glyphs:
lib/glyphOutline.tsrebuilds an.otfwith the modified outlines baked in. Kerning pairs are recovered from the instanced source font (GPOS orkern) and re-emitted as a legacykerntable, and tracking is baked into advances at export time only.
The .ttf path preserves more of the original font behavior. The edited .otf
path prioritizes baking user geometry into a valid font file.
lib/sfnt.ts holds the binary table surgery shared by both paths: table
directory rebuild, per-table checksums, and head.checkSumAdjustment.
app/
api/generate/route.ts server-side prompt generation route
page.tsx landing page
studio/page.tsx main editor workspace
globals.css application styles and bundled @font-face rules
components/
DesignPanel.tsx base font, axis, tracking, and shape controls
DesignPrompt.tsx prompt input inside the studio
FontSpecimen.tsx preview, type scale, body text, weights, metadata
GlyphEditor.tsx SVG node editor for one glyph
GlyphInspector.tsx character map and glyph edit panel
lib/
fontCatalog.ts bundled font metadata and CSS helpers
genShape.ts prompt-seeded outline shaping
glyphOutline.ts glyph extraction and edited font assembly
instanceFont.ts HarfBuzz-backed static font instancing
presets.ts preset examples
sfnt.ts binary font table patching (kern injection, hmtx tracking)
specimenContent.ts preview text data
types.ts shared generated font parameter contract
public/
fonts/ bundled variable fonts
hb-subset.wasm HarfBuzz subset WebAssembly module
This is a bring-your-own-key project. The repository should never contain real
provider keys. .env.example contains placeholders and documented defaults only.
For public deployments, configure:
- provider-side spending limits
- hosting-platform secret storage
- platform-level rate limiting if available
- the route limits from
.env.example
To add a bundled font:
- Confirm the license allows redistribution and derivative exports.
- Add the font file to
public/fonts. - Add an
@font-facerule inapp/globals.css. - Add the font metadata and real variable axis ranges in
lib/fontCatalog.ts. - Update
THIRD_PARTY_NOTICES.md. - Run
npm run check.
Use the font's actual fvar axis ranges. Incorrect ranges can break preview or
export behavior.
- The built-in rate limiter is in-memory. It is useful for local and simple deployments, but not enough for multi-region or high-traffic production.
- Edited
.otfexports rebuild the font from outlines. Pair kerning is preserved via a legacykerntable, but substitutions (ligatures, alternates) and other advanced OpenType features are not. - The model route chooses parameters; it does not create a fully original font family from scratch.