fontmap / README.md
tfrere's picture
tfrere HF Staff
chore: clean up repo for open source release
fc2a05d
---
title: FontMap
short_description: Visual font explorer powered by FontCLIP
emoji: πŸ—ΊοΈ
colorFrom: indigo
colorTo: blue
sdk: static
pinned: false
app_build_command: "CI=false npm run build"
app_file: "build/index.html"
---
# FontMap
An interactive map of 1,100+ Google Fonts organized by visual similarity, using [FontCLIP](https://github.com/kinit-sk/FontCLIP) embeddings and UMAP dimensionality reduction.
Inspired by [IDEO's Font Map](https://medium.com/ideo-stories/organizing-the-world-of-fonts-with-ai-7d9e49ff2b25) (2017, Kevin Ho) β€” rebuilt from scratch with modern ML, fully open source, and documented.
**[Live demo](https://huggingface.co/spaces/tfrere/fontmap)**
![FontMap screenshot](https://huggingface.co/spaces/tfrere/fontmap/resolve/main/public/screenshot.png)
## Features
- **Visual similarity map** β€” fonts that look alike are physically close together
- **1,192 Google Fonts** β€” full catalog, family variants merged
- **Click any font** β€” see details + 5 nearest visual neighbors
- **Filter by category** β€” serif, sans-serif, display, handwriting, monospace
- **Category colors** β€” toggle color coding to see how clusters map to official categories
- **Search** β€” find any font by name
- **Zoom & pan** β€” explore the full map with smooth D3.js navigation
## How it works
```
Font images ──→ FontCLIP (512D) ──→ PCA (50D) ──→ UMAP (2D) ──→ Interactive map
↓
k-NN (similar fonts)
```
1. **Render** β€” each font is rendered as a 224Γ—224 composite glyph image
2. **Embed** β€” [FontCLIP](https://github.com/kinit-sk/FontCLIP) (CLIP ViT-B/32 fine-tuned for typography) encodes each image into a 512-dimensional vector
3. **Reduce** β€” PCA compresses to 50D, then UMAP with spectral initialization projects to 2D (n_neighbors=12, min_dist=1.0)
4. **Merge** β€” font family variants (Regular, Bold, Italic…) are fused into a single representative point
5. **Neighbors** β€” k-NN is computed in the original 512D space for "similar fonts" recommendations
6. **Visualize** β€” React + D3.js renders all glyphs from a single SVG sprite (zero individual network requests)
## Getting started
### Run locally
```bash
git clone https://github.com/tfrere/fontmap.git
cd fontmap
npm install
npm start
```
Open [http://localhost:3000](http://localhost:3000).
### Build for production
```bash
npm run build
```
### Deploy to Hugging Face Spaces
The project is configured for [HF Spaces static SDK](https://huggingface.co/docs/hub/spaces-sdks-static) with a build step:
```yaml
sdk: static
app_build_command: "CI=false npm run build"
app_file: "build/index.html"
```
## Regenerating the map
The embedding pipeline lives in `src/typography/new-pipe/`. See its [README](src/typography/new-pipe/README.md) for full instructions.
**Quick summary:**
```bash
# 1. Generate FontCLIP embeddings (requires Python + GPU, ~1h one-time)
cd src/typography/new-pipe/python-pipeline
python run_fontclip.py
# 2. Test different UMAP configurations
cd ..
npm run batch-umap
npm run copy-to-debug
# Compare visually at http://localhost:3000/#/debug-umap
# 3. Deploy chosen config to production
npm run deploy fontclip-spectral
```
## Project structure
```
fontmap/
β”œβ”€β”€ public/
β”‚ β”œβ”€β”€ data/
β”‚ β”‚ β”œβ”€β”€ char/ # Individual glyph SVGs (~1,200 files)
β”‚ β”‚ β”œβ”€β”€ sentences/ # Sentence preview SVGs
β”‚ β”‚ β”œβ”€β”€ font-sprite.svg # All glyphs in a single sprite (3 MB)
β”‚ β”‚ └── typography_data.json # Font positions + metadata
β”‚ └── debug-umap/ # Pre-computed UMAP configs for comparison
β”œβ”€β”€ src/
β”‚ β”œβ”€β”€ components/
β”‚ β”‚ β”œβ”€β”€ FontMap/ # Main map component (production)
β”‚ β”‚ β”œβ”€β”€ DebugUMAP/ # UMAP comparison tool (development)
β”‚ β”‚ └── FontMapV2/ # Experimental canvas renderer
β”‚ β”œβ”€β”€ hooks/ # Shared hooks (data loading, dark mode)
β”‚ β”œβ”€β”€ store/ # Zustand state management
β”‚ └── typography/new-pipe/ # Embedding + UMAP generation pipeline
β”‚ └── python-pipeline/ # FontCLIP + PCA + UMAP (Python)
└── package.json
```
## Tech stack
| Layer | Tech |
|-------|------|
| Frontend | React 19, D3.js v7, Zustand |
| Rendering | SVG sprite + D3 zoom/pan |
| Embeddings | FontCLIP (CLIP ViT-B/32 fine-tuned for typography) |
| Dim. reduction | PCA + UMAP (spectral init) via `umap-learn` |
| Hosting | Hugging Face Spaces (static SDK) |
## Credits
- **[FontCLIP](https://github.com/kinit-sk/FontCLIP)** β€” Typography-aware CLIP model by KInIT
- **[IDEO Font Map](https://medium.com/ideo-stories/organizing-the-world-of-fonts-with-ai-7d9e49ff2b25)** β€” Original inspiration by Kevin Ho (2017)
- **[Google Fonts](https://fonts.google.com)** β€” Font catalog
- **[UMAP](https://umap-learn.readthedocs.io/)** β€” Dimensionality reduction by Leland McInnes
## License
MIT