File size: 5,064 Bytes
a9df2c1 b3f0c1a a9df2c1 b3f0c1a a9df2c1 b3f0c1a a9df2c1 fc2a05d | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | ---
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)**

## 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
|