Browse Google Fonts as full-size specimens and discover display + text pairings — both hand-curated and algorithmically suggested. A calmer way to choose type than scrolling a wall of font names.
Live: type-explorer-pi.vercel.app
Status: a personal project, shared publicly as a work sample. Not accepting contributions — issues and pull requests may be closed without response. You're welcome to fork it and make it your own (see Licensing).
- Home — a gallery of ready-made display + text pairings: a less-common "Suggested" set up top and the familiar "Popular" combinations grouped below. Favorite any card.
- Explorer — browse the full Google Fonts catalog as real specimens (title, subtitle, and paragraph set in the actual font), with search, category filters, and popularity / trending / recently-updated sort. Set a custom "typographic voice" to judge every font against the same words. Hit Get Pairings on any font to see curated and algorithmic partners in a modal.
- Favorites — everything you've collected, fonts and pairings, in one place.
- Changelog — a running, newest-first log of changes at
/changelog.
Pairing suggestions are precomputed offline (see Data & scripts) from Google Fonts' own semantic tags plus a curated set — so the app ships with a rich pairing library and needs no AI or API keys at runtime.
The Explorer — the full catalog as real specimens, with search, filters, and sort:
The typographic voice — one pop-up sets the title, subtitle, and paragraph applied to every card, so fonts and pairings are judged against the same words:
The changelog at /changelog — one card per dated entry:
pnpm install
pnpm dev # http://localhost:3000That's it — no API keys or environment variables are required to run or host
the app. It reads static data committed to the repo (data/fonts.json,
content/pairing-library.json, content/suggested-pairings.json).
Zero-config on any Next.js host. On Vercel, import the repo and deploy — no environment variables to set. The font catalog and pairing library are static files bundled into the build, so there are no runtime secrets or external API calls (fonts themselves load from the Google Fonts CDN in the browser).
The app reads three committed data files. Two are regenerated by offline scripts that talk to the Google Fonts API; you only run these to refresh the data, and they never run as part of the app or the deploy.
| File | What it is | Refresh with |
|---|---|---|
data/fonts.json |
The font catalog (families, variable axes, popularity/trending order) | pnpm catalog:refresh |
content/pairing-library.json |
Per-font curated + algorithmic pairings (the "Get Pairings" data) | pnpm pairings:build |
content/suggested-pairings.json |
The home-page pairing gallery | hand-maintained |
The two refresh scripts need a free Google Fonts Developer API key:
cp .env.example .env.local # add GOOGLE_FONTS_API_KEY
pnpm catalog:refresh # rewrites data/fonts.json
pnpm pairings:build # rewrites content/pairing-library.jsonGet a key by enabling the Web Fonts Developer API in a Google Cloud project and creating an API key. Commit the regenerated JSON when you're happy with it.
- Next.js (App Router) with React 19 and Tailwind v4.
lib/catalog.tsreads the staticdata/fonts.json;app/api/fontsfilters, sorts, and paginates it for the Explorer.lib/pairing-library.tslazy-loads the pairing JSON so it stays out of the main bundle.lib/css2-url.tsbuilds the fiddly Google Fontscss2URLs (axis ordering rules) and is unit-tested;lib/font-loader.tsinjects the stylesheet on demand.- Favorites and the typographic-voice overrides persist in
localStorage— no backend, no accounts.
pnpm dev # local dev server
pnpm build # production build
pnpm start # serve the production build
pnpm test # unit tests (css2 URL construction)
pnpm lint # eslint
pnpm catalog:refresh # regenerate data/fonts.json (needs GOOGLE_FONTS_API_KEY)
pnpm pairings:build # regenerate content/pairing-library.jsonThe /changelog page renders content/changelog.json — a plain, newest-first
JSON array of { date, title, changes[] } entries. To record a change, add or
edit an entry:
[
{
"date": "2026-06-16",
"title": "Short headline",
"changes": ["What's different, from a user's point of view."],
"files": ["app/path/to/file.tsx — what lives here"]
}
]files is optional and lists the key files the entry touched — it surfaces as a
small reference on the card and doubles as orientation for anyone (or any agent)
returning to the repo. Editing the file by hand is all it takes — no build step
or dependency. If you work on this repo with Claude Code, the /changes slash
command (.claude/commands/changes.md) drafts an entry from the current diff and
recent commits and prepends it for you.
This project's code is released under the MIT License — fork it, modify it, build on it freely; just keep the copyright notice.
Google Fonts are under the SIL Open Font License or Apache License. The app embeds no font files — it references the Google Fonts CDN — so the project and anything you build from it stays licensing-clean.



