Skip to content

Commit c14c94a

Browse files
Kjubikstronkclaude
andcommitted
Serve the fonts ourselves instead of from Google
Loading Google Fonts sends every visitor's IP address to Google before they have agreed to anything, which EU courts have ruled a GDPR breach. The three faces now ship in the bundle via @fontsource and are precached by the service worker, so the pixel type also renders offline, which it never did before. Rendering is unchanged (compared before and after). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 62adcf8 commit c14c94a

7 files changed

Lines changed: 76 additions & 31 deletions

File tree

‎CLAUDE.md‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,11 @@ Seed on open, not on mount.
6363
and compare correctly and can't drift by timezone. A date happening *today* is
6464
not past — use `<`, not `<=`.
6565

66+
**Fonts are self-hosted (`@fontsource`, imported in `main.tsx`).** Never
67+
re-add the Google Fonts `<link>`: it sends every visitor's IP to Google
68+
before any consent, which German courts have ruled a GDPR breach. Bundled,
69+
they are also precached, so the pixel type works offline.
70+
6671
**One service worker only.** `vite-plugin-pwa` owns it. Adding Firebase
6772
messaging later needs `injectManifest` and a single combined worker, not a
6873
second file at the same scope.

‎index.html‎

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,10 @@
1919
anyone find it in the first place. -->
2020
<meta name="robots" content="noindex, nofollow" />
2121

22-
<link rel="preconnect" href="https://fonts.googleapis.com" />
23-
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
24-
<link
25-
href="https://fonts.googleapis.com/css2?family=Pixelify+Sans:wght@400..700&family=Silkscreen:wght@400;700&family=Space+Grotesk:wght@400;500;700&display=swap"
26-
rel="stylesheet"
27-
/>
22+
<!-- No Google Fonts. The faces ship inside the bundle (see src/main.tsx):
23+
loading them from Google hands every visitor's IP address to Google
24+
before they've agreed to anything, which EU courts have ruled a GDPR
25+
breach. It also means the pixel type works offline. -->
2826

2927
<!-- Before first paint, or a phone that chose another theme shows the
3028
default palette for a frame. Deliberately inline and dependency-free:

‎package-lock.json‎

Lines changed: 54 additions & 22 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎package.json‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@
1515
"check": "npm run lint && npm run contrast && npm test && npm run build"
1616
},
1717
"dependencies": {
18+
"@fontsource-variable/pixelify-sans": "^5.3.0",
19+
"@fontsource-variable/space-grotesk": "^5.3.0",
20+
"@fontsource/silkscreen": "^5.3.0",
1821
"@vis.gl/react-google-maps": "^1.9.0",
1922
"date-fns": "^4.4.0",
2023
"firebase": "^12.16.0",

‎src/main.tsx‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import { StrictMode } from 'react'
22
import { createRoot } from 'react-dom/client'
3+
// Self-hosted, never fetched from Google — see the note in index.html.
4+
import '@fontsource-variable/pixelify-sans/wght.css'
5+
import '@fontsource-variable/space-grotesk/wght.css'
6+
import '@fontsource/silkscreen/400.css'
7+
import '@fontsource/silkscreen/700.css'
38
import './index.css'
49
import App from './App.tsx'
510

‎src/theme.css‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,8 @@
5252
/* Type -----------------------------------------------------
5353
Pixel faces are unreadable in paragraphs, so the bitmap face is
5454
rationed: headings, day numbers, buttons. Prose gets a real face. */
55-
--font-display: 'Pixelify Sans', ui-monospace, monospace;
56-
--font-body: 'Space Grotesk', ui-sans-serif, system-ui, sans-serif;
55+
--font-display: 'Pixelify Sans Variable', ui-monospace, monospace;
56+
--font-body: 'Space Grotesk Variable', ui-sans-serif, system-ui, sans-serif;
5757
--font-util: 'Silkscreen', ui-monospace, monospace;
5858

5959
/* Motion ---------------------------------------------------

‎vite.config.ts‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,9 @@ export default defineConfig({
2929
'manifest.webmanifest',
3030
],
3131
workbox: {
32-
globPatterns: ['**/*.{js,css,html,svg,png,webmanifest}'],
32+
// woff2: the fonts are bundled now, and precaching them is what lets
33+
// the pixel type render offline.
34+
globPatterns: ['**/*.{js,css,html,svg,png,webmanifest,woff2}'],
3335
navigateFallback: 'index.html',
3436
cleanupOutdatedCaches: true,
3537
// Deliberately no runtimeCaching. Firestore keeps its own offline

0 commit comments

Comments
 (0)