From dfa1f90a1689395c633be2a1b3829cad9da850e4 Mon Sep 17 00:00:00 2001 From: "khalid@traclabs.com" Date: Tue, 1 Sep 2026 23:29:04 -0500 Subject: [PATCH] v0.8: self-hosted fonts replace the Google Fonts CDN link MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit index.html now loads /api/fonts/fonts.css, synthesized at request time by goods-editor's mountEditorApi from the host's fonts/ directory (populated via fetch-fonts in goods-editor-module — the host-local fetch script shrinks to a pointer). Shipped synchronously in on purpose: the module's runtime injector races first paint and the editor's text measurement gives wrong answers against fallback metrics until real fonts load. Co-Authored-By: Claude Fable 5 --- index.html | 22 +++++- scripts/fetch-fonts.mjs | 159 ++++++---------------------------------- 2 files changed, 40 insertions(+), 141 deletions(-) diff --git a/index.html b/index.html index 6899ff8..9614f4b 100644 --- a/index.html +++ b/index.html @@ -6,9 +6,25 @@ Pawfectly Yours — Customize Your Shirt - - - + +
diff --git a/scripts/fetch-fonts.mjs b/scripts/fetch-fonts.mjs index 1deda7f..16a6ef4 100644 --- a/scripts/fetch-fonts.mjs +++ b/scripts/fetch-fonts.mjs @@ -1,145 +1,28 @@ #!/usr/bin/env node /** - * Downloads TTF font files for the Google Fonts used in the editor and saves - * them under ./fonts/. server.js scans that directory at startup and calls - * registerFont() for each file. + * DEPRECATED — fonts now live with goods-editor-module. * - * Why we do this: - * node-canvas does not pick up Google Fonts automatically. It only knows - * about fonts that are either (a) registered explicitly via registerFont() - * or (b) installed system-wide and discoverable via fontconfig. Without - * this script, the server falls back to whatever Cairo can find for - * "Roboto", "Bebas Neue", etc., which is usually nothing — exports get - * substituted to a generic sans-serif and look nothing like the preview. + * The host used to fetch TTFs into its own fonts/ directory and + * register them at server boot. After the v0.8 module reorg, font + * ownership moved into goods-editor-module: * - * Source: - * We pull TTFs from the Fontsource jsDelivr CDN. URLs look like - * https://cdn.jsdelivr.net/fontsource/fonts/@latest/latin-400-normal.ttf - * Slugs are the lowercase, hyphenated family name. The script asks for two - * weights per family (regular + bold) and falls through gracefully if a - * weight isn't published. + * • The TTF files live under goods-editor-module/fonts/. + * • Fetch them with `npm run fetch-fonts` inside goods-editor-module. + * • mountEditorApi (called from the host's server.js) registers them + * with node-canvas at boot and serves them to the browser via + * /api/fonts/fonts.css. + * • The host's index.html loads that stylesheet directly — no more + * Google Fonts CDN, no more host-side TTFs. * - * Usage: - * npm run fetch-fonts - * - * Re-running is cheap: existing files are skipped unless --force is passed. + * This file is kept as a tombstone so anyone who looks for it + * understands what happened. Safe to `rm scripts/fetch-fonts.mjs` + * in the next housekeeping commit; nothing references it anymore + * (package.json's scripts block was already trimmed during the + * module-split work in May 2026). */ -import { mkdir, writeFile, access } from 'node:fs/promises'; -import { constants as fsConstants } from 'node:fs'; -import { join, dirname } from 'node:path'; -import { fileURLToPath } from 'node:url'; - -const __dirname = dirname(fileURLToPath(import.meta.url)); -const ROOT = join(__dirname, '..'); -const FONTS_DIR = join(ROOT, 'fonts'); - -const FORCE = process.argv.includes('--force'); - -// Families used by the editor (FONTS in src/constants/fonts.js + the two -// CSS-level defaults). Keep this list in sync with that file. -const FAMILIES = [ - 'Roboto', - 'Open Sans', - 'Lato', - 'Montserrat', - 'Oswald', - 'Raleway', - 'Poppins', - 'Roboto Condensed', - 'Source Sans 3', - 'Roboto Slab', - 'Merriweather', - 'Ubuntu', - 'Playfair Display', - 'Nunito', - 'Rubik', - 'Work Sans', - 'Lora', - 'Fira Sans', - 'Barlow', - 'Bebas Neue', - 'DM Sans', - 'Space Mono', - // Display + handwritten faces used by the Pawfectly Yours theme. Pacifico is - // the brand logo face; Caveat is a friendly script fallback exposed in the - // text-tab font picker so users can match the brand voice in their designs. - 'Pacifico', - 'Caveat', -]; - -const WEIGHTS = [ - { weight: 400, suffix: 'Regular' }, - { weight: 700, suffix: 'Bold' }, -]; - -const familyToSlug = (family) => family.toLowerCase().replace(/\s+/g, '-'); - -// Filename convention used by server.js's registration scanner: -// "Family_Name-Variant.ttf" → family = "Family Name", variant = "Variant". -// Underscore-vs-space is so the file system stays portable. -const familyToFileBase = (family) => family.replace(/\s+/g, '_'); - -async function fileExists(path) { - try { - await access(path, fsConstants.R_OK); - return true; - } catch { - return false; - } -} - -async function fetchOne(family, weight, suffix) { - const slug = familyToSlug(family); - const url = `https://cdn.jsdelivr.net/fontsource/fonts/${slug}@latest/latin-${weight}-normal.ttf`; - const dest = join(FONTS_DIR, `${familyToFileBase(family)}-${suffix}.ttf`); - - if (!FORCE && await fileExists(dest)) { - return { family, weight, status: 'skipped', dest }; - } - - const res = await fetch(url); - if (!res.ok) { - return { family, weight, status: 'missing', dest, code: res.status }; - } - const buf = Buffer.from(await res.arrayBuffer()); - await writeFile(dest, buf); - return { family, weight, status: 'fetched', dest, bytes: buf.length }; -} - -async function main() { - await mkdir(FONTS_DIR, { recursive: true }); - - let fetched = 0, skipped = 0, missing = 0; - - for (const family of FAMILIES) { - for (const { weight, suffix } of WEIGHTS) { - try { - const r = await fetchOne(family, weight, suffix); - if (r.status === 'fetched') { - fetched++; - console.log(`✓ ${family} ${weight} → ${r.dest} (${(r.bytes / 1024).toFixed(0)} KB)`); - } else if (r.status === 'skipped') { - skipped++; - console.log(`· ${family} ${weight} (already present)`); - } else { - missing++; - console.log(`! ${family} ${weight} HTTP ${r.code} — variant not published`); - } - } catch (err) { - missing++; - console.log(`! ${family} ${weight} ${err.message}`); - } - } - } - - console.log(`\nDone. Fetched ${fetched}, skipped ${skipped}, missing ${missing}.`); - if (missing > 0) { - console.log('Missing variants are not fatal — the server will fall back to other registered weights.'); - } -} - -main().catch((err) => { - console.error('Font fetch failed:', err); - process.exit(1); -}); +console.error( + '[fetch-fonts] This script has moved to goods-editor-module.\n' + + ' Run: (cd ../goods-editor-module && npm run fetch-fonts)' +); +process.exit(1);