A hyper-lightweight local font previewer for desktop — rebuilt in Tauri 2 + SvelteKit 5.
Recursively scan folders of .ttf and .otf files, preview custom text across all fonts in real time. No installation required.
This is a from-scratch port of the original foundryglance Flutter app to the Tauri desktop framework with a SvelteKit 5 frontend. Same purpose, same lightweight philosophy — rewritten for a native desktop experience with a fraction of the binary size.
- Recursive scanning — Point it at a directory and it finds every
.ttfand.otffile, no matter how deeply nested. - SFNT metadata parser — Reads font family name, subfamily/style, weight, and italic flag directly from font binary tables (
name,OS/2,head) — zero external dependencies. Implemented in both Rust (backend) and TypeScript (browser dev fallback). - On-the-fly font loading — Fonts are loaded via the
FontFaceJavaScript API with Blob URLs. No system-wide installation needed. - Web font importing — Enter a Google Fonts family, paste a Google Fonts specimen/share URL, or use a CORS-enabled CSS font stylesheet. Remote variants appear in the same preview cards without being installed.
- Bulk import — Paste a whole Google Fonts
<link>or@importembed snippet (thepreconnectlines are ignored) to import every selected family at once, or list several families/URLs one per line. Sources that fail are reported without blocking the rest. - Family grouping with merged view — All variants of the same family are automatically grouped. Toggle between merged cards and individual variant tiles.
- Grid & list views — Switch between a responsive card grid or a compact list layout. Adjustable columns (2–5).
- Live font size control — Smooth slider (8–96) to instantly scale preview text.
- Bold / Italic / Weight sliders — Per-family interactive controls to test different variants dynamically.
- RTL & complex script support — Full bidirectional text support. Choose from 18 language presets (Arabic, Pashto, Hebrew, CJK, etc.) or type your own text.
- Per-card language — Override the preview language on an individual font card from its globe button, so an Arabic face can be tested in Arabic while the rest of the grid stays in English. Overrides show the language code on the card, survive merged/separate view switches, and reset to the toolbar language from the same menu.
- Text alignment — Start, center, end alignment controls.
- Custom per-language preview text — Set persistent custom preview strings per language in settings.
- Drag & drop — Drop a font folder directly onto the window to start scanning. Uses native Tauri drag-drop events.
- Native iOS-themed UI — Konsta UI iOS theme with frosted glass cards, native-feeling controls, and automatic light/dark mode.
- Light / dark theme — Toggle with a button. Your choice is saved and wins over the OS preference on the next launch; until you pick one it follows
prefers-color-schemelive. - Configurable accent color — Pick from 8 iOS-style accent colors in settings; buttons, badges, sliders, and segmented controls recolor live.
- Web import history — Every web font import is recorded with a timestamp, its source URLs, families, and font count. Browse it in the Add Web Fonts popup, click any entry to re-import it, or clear the list.
- Settings persistence — Custom preview texts, default font size, accent color, and theme choice saved to
~/.config/foundryglance/settings.json; import history tohistory.jsonalongside it. Outside the Tauri runtime (bun run dev) both fall back to localStorage so a reload still keeps them. - Session restore — The last folder or web import is remembered and reloaded on launch, so a refresh does not empty the grid. Only the source is stored, never font data.
- Cross-platform — Runs on macOS, Windows, and Linux.
| Layer | Technology |
|---|---|
| Desktop framework | Tauri 2 (Rust) |
| Frontend framework | SvelteKit 5 with Svelte 5 runes ($state, $derived, $effect) |
| State management | Runes-based store singletons in src/lib/stores/*.svelte.ts |
| Language | TypeScript |
| UI components | Konsta UI 5 (iOS theme) |
| Styling | Tailwind CSS v4 |
| Font parsing (Rust) | Custom SFNT binary table parser |
| Font parsing (TS) | Custom SFNT binary table parser (browser dev fallback) |
| Font loading | FontFace API with Blob URLs |
| File picking | @tauri-apps/plugin-dialog (native) / hidden <input webkitdirectory> (browser) |
| Drag & drop | @tauri-apps/api onDragDropEvent (native) / HTML5 DnD (browser) |
| Language data | src/lib/assets/languages.json (18 languages) |
| Settings & history storage | JSON files via dirs-next config directory (localStorage fallback in browser) |
| Session restore | SessionSource pointer in localStorage, replayed on boot |
| Build tool | Vite 6 |
| Package manager | Bun |
| Platforms | macOS, Windows, Linux |
foundryglance/
├── src/ # SvelteKit frontend
│ ├── app.css # Tailwind + Konsta theme
│ ├── app.html # HTML shell
│ ├── lib/
│ │ ├── assets/
│ │ │ └── languages.json # 18 language preview samples
│ │ ├── components/
│ │ │ ├── AppToolbar.svelte # Main toolbar with all controls
│ │ │ ├── DropZone.svelte # Drag-and-drop overlay
│ │ │ ├── FontCard.svelte # Merged family card with B/I/weight controls
│ │ │ ├── FontTile.svelte # Individual variant tile
│ │ │ ├── ExternalFontDialog.svelte # Web font importer + import history
│ │ │ ├── LanguageMenu.svelte # Shared language search/select popover
│ │ │ └── SettingsDialog.svelte # Settings popup
│ │ ├── types/
│ │ │ └── index.ts # TypeScript interfaces
│ │ ├── stores/ # App state (Svelte 5 runes singletons)
│ │ │ ├── settings.svelte.ts # AppSettings + persistence + accent class
│ │ │ ├── theme.svelte.ts # Dark mode
│ │ │ ├── preview.svelte.ts # Preview text, language, size, layout, overrides
│ │ │ ├── library.svelte.ts # Loaded font set + scan/import actions
│ │ │ └── history.svelte.ts # Web import history
│ │ └── utils/
│ │ ├── accent.ts # Accent palette -> Konsta brand class
│ │ ├── browser-fonts.ts # Browser-based SFNT parser
│ │ ├── external-fonts.ts # Remote CSS fetch, sanitization, metadata
│ │ ├── family-utils.ts # Weight/italic helpers
│ │ ├── font-loader.ts # FontFace loading & Blob URL management
│ │ ├── languages.ts # Language data loader
│ │ └── time.ts # Intl relative/absolute timestamps
│ └── routes/
│ ├── +layout.svelte # Root layout (Konsta App, dark mode)
│ ├── +layout.ts # SSR disabled (SPA mode)
│ └── +page.svelte # Main single-page app
│
├── src-tauri/ # Tauri (Rust) backend
│ ├── src/
│ │ ├── main.rs # Entry point
│ │ ├── lib.rs # Tauri builder, command registration
│ │ ├── commands/
│ │ │ ├── mod.rs
│ │ │ ├── history.rs # load_history, save_history, clear_history
│ │ │ ├── scan.rs # scan_directory, read_font_bytes
│ │ │ └── settings.rs # load_settings, save_settings, reset_settings
│ │ └── parser/
│ │ ├── mod.rs
│ │ └── sfnt.rs # Raw TTF/OTF SFNT metadata parser
│ ├── tauri.conf.json # App configuration
│ ├── capabilities/
│ │ └── default.json # Permissions
│ └── Cargo.toml
│
├── package.json
├── svelte.config.js
├── vite.config.js
└── tsconfig.json
- Scan: User picks a folder → Tauri native dialog → Rust
scan_directoryrecursively walks the directory, reads first 128 KB of each.ttf/.otffile, parses SFNT binary metadata, groups by family → returnsScanResultto frontend. - Import web fonts (alternative): The input is parsed into a list of stylesheet URLs (embed snippets, family names, specimen/share links, raw URLs) → each is fetched in the frontend, in parallel → only sanitized
@font-facedescriptors are retained → families and variants are derived from the combined CSS, merging families that appear in more than one stylesheet. - Render: SvelteKit renders
FontCard(merged) orFontTile(separate) components in a responsive grid or list. - Load: Local cards call
read_font_bytes, create Blob URLs, and registerFontFaceobjects. Web cards install the sanitized font-face rules and let the browser fetch selected variants from the provider. - Preview: User types text, adjusts size/alignment, toggles bold/italic — all live, re-rendered by Svelte 5 reactivity.
- Settings: Edits in the settings popup are saved via Tauri commands to
~/.config/foundryglance/settings.json. The accent color is applied by swapping a Konsta.k-color-brand-*class on the App root — Konsta bakes its color tokens at build time, so a runtime CSS variable would have no effect. - History: Each successful web import is stamped and appended to
~/.config/foundryglance/history.json(localStorage outside Tauri), replayable from the Add Web Fonts popup.
The frontend works in two modes:
- Tauri mode (desktop): Uses
@tauri-apps/apifor native dialogs, file system access, and drag-drop events. - Browser mode (dev): Falls back to hidden
<input webkitdirectory>for folder selection and HTML5 drag-drop, with a TypeScript reimplementation of the SFNT parser. Runbun run devfor rapid frontend development without Tauri.
# Frontend-only (browser dev mode, no Tauri)
bun install
bun run dev
# → http://localhost:5173
# Full Tauri desktop mode (hot-reloads frontend + Rust)
bun run tauri devbun run tauri buildThe production binary will be in src-tauri/target/release/ (or .dmg/.msi/.AppImage depending on platform).
| Command | Description |
|---|---|
bun run dev |
Vite dev server (frontend only) |
bun run build |
Production SvelteKit build |
bun run check |
TypeScript type checking |
cargo check (in src-tauri/) |
Rust compilation check |
bun run tauri dev |
Tauri desktop dev mode |
bun run tauri build |
Production Tauri bundle |
- Launch the app.
- Click Open (or drag a folder onto the window) and select a directory containing font files. Alternatively, click Web and enter a Google Fonts family, or paste a full Google Fonts
<link>/@importembed snippet to bulk-import every selected family at once. - The app scans local
.ttf/.otffiles or derives remote family metadata from the imported stylesheet, then groups variants by family. - Type custom preview text in the search field, or pick a language preset from the popover.
- Adjust font size with the slider, toggle between grid/list and merged/separate views, and switch text alignment as needed.
- Click the settings gear to customize the accent color, default font size, and per-language preview text.
- Use the B (bold) and I (italic) toggles and weight slider on merged family cards to explore variants.
| Setting | Description |
|---|---|
| Default font size | Base preview font size (12–64) |
| Accent color | Primary UI accent (8 iOS-style colors) |
| Per-language text | Custom default preview string for each of the 18 languages |
Settings are persisted to ~/.config/foundryglance/settings.json.
This is a complete rewrite from the original Flutter app. Key differences:
| Aspect | Flutter (original) | Tauri + SvelteKit (this port) |
|---|---|---|
| Framework | Flutter 3 / Dart | Tauri 2 / Rust + SvelteKit 5 / TypeScript |
| UI | Custom glassmorphism widgets | Konsta UI (native iOS theme) |
| Font parser | Pure Dart SFNT parser | Rust SFNT parser (backend) + TypeScript SFNT parser (browser fallback) |
| Font loading | FontLoader (Flutter engine) |
FontFace API with Blob URLs |
| Background | Animated mesh gradient (mesh_gradient package) |
Native iOS light/dark surfaces via Konsta <Page> |
| Settings | In-app shared preferences | JSON file via dirs-next |
| Web support | GitHub Pages deployment | Not a target (desktop-only) |
| Binary size | ~20 MB+ (Flutter runtime) | ~5–8 MB (native binary) |
MIT