Skip to content

Font Families & Google Fonts Picker

Follow-up to font-optimization branch. Separate branch/PR.

Problem

Today, each block uploads its own font file independently. There is no concept of a font family -- uploading Regular, SemiBold, and Bold for the same typeface means three separate uploads with no grouping. HTML blocks have no way to discover which fonts are available. Google Fonts are limited to a hardcoded list of 10.

Design

Data Model

New top-level field creativeFonts in creative JSON (requires backend schema PR):

ts
type CreativeFonts = Record<string, FontFamily>

type FontFamily = {
  name: string                    // "Ford F-1", "Poppins"
  source: 'custom' | 'google'
  variants: FontVariant[]
}

type FontVariant = {
  label: string                   // "Regular", "SemiBold", "Bold Italic"
  style: 'normal' | 'italic'
  url?: string                    // CDN URL (custom uploads only)
  fontName?: string               // original filename (custom uploads only)
}

Block reference (replaces current customFont: { url, fontName }):

ts
customFont: {
  family: string                  // key in creativeFonts
  variant: string                 // matches variant label
}

Backward compatible: old customFont: { url, fontName } treated as a single-variant family.

Backend PR

One-liner in start/validators/creative_validation.ts:

ts
creativeFonts: schema.object.optional().anyMembers()

No database migration needed (longtext JSON blob).

TypefaceSection (Upload UX)

Inline compact approach -- extends current dropdown:

  • Drop zone accepts multiple files (.woff2, .woff, .ttf, .otf)
  • Auto-groups by font family name from metadata (name table)
  • Variant chips below drop zone show uploaded variants
  • Can add individual variants to existing family
  • Can remove individual variants from family
  • Uploads go to creativeFonts, shared across all blocks

FontWeight Section

  • Custom fonts: variant chips (Regular, SemiBold, Bold) based on what is in the family
  • Google Fonts: keeps weight slider as today (supports arbitrary weights)
  • Removed variant: block falls back to nearest available variant

Google Fonts Picker

  • Searchable picker with full Google Fonts catalog via API
  • Shows font preview in search results
  • Selecting a family auto-fetches all available variants
  • Favorites stored in localStorage (personal preference)
  • Selected Google Font added to creativeFonts with source: 'google'

HTML Block Font Hints

Info section in HTML block config showing available fonts:

Available fonts:
  Ford F-1  ->  font-family: 'Ford-F1';    (Regular, SemiBold, Bold)
  Poppins   ->  font-family: 'Poppins';    (Google Font)

Click to copy font-family name to clipboard. Upload button in HTML config adds to creativeFonts (shared with all blocks).

Creative Engine Changes

  • FontHelper reads creativeFonts and registers one @font-face per variant
  • Each variant gets a unique font-family name (e.g. Ford-F1-SemiBold)
  • Backward compatible with old customFont format
  • parseCustomStyling resolves family+variant to correct font-family name

Creative Composer Changes

  • Font optimizer reads creativeFonts for subsetting
  • Only variants actually referenced by blocks are included in build
  • Subsetting works per-variant (each variant gets its own charset)

Out of Scope

  • Asset library integration (future -- replaces localStorage favorites with server-side per brand/group)
  • Font preview in builder block list
  • Variable fonts (single file with continuous weight axis)

Dependencies

  • font-optimization branch merged first (subsetting, DevTools improvements)
  • Backend schema PR for creativeFonts field

Internal documentation