Skip to content

Commit 28f6c7a

Browse files
authored
dev: Swap out paid fonts for free alternatives (#3573)
1 parent e66c678 commit 28f6c7a

File tree

14 files changed

+1445
-70
lines changed

14 files changed

+1445
-70
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,4 +71,5 @@ tsconfig.tsbuildinfo
7171

7272
infra/pgdata/
7373

74-
tmp
74+
tmp
75+
details.md

README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,55 @@ pnpm dev
4949

5050
Navigate to `localhost:9876`
5151

52+
## Fonts
53+
54+
PubPub uses three main font families, plus CJK variants:
55+
56+
- **Source Sans 3** — headers, titles, UI text
57+
- **Source Serif 4** — body text in pubs
58+
- **Outfit** — landing page
59+
- **Noto Serif TC/JP/KR/SC** and **Noto Sans TC/JP/KR/SC** — CJK content
60+
61+
All fonts are variable-weight woff2 files from [Fontsource](https://fontsource.org/), hosted on S3 at `assets.pubpub.org/fonts/<hash>/`. The font files are not stored in this repo.
62+
63+
### How it works
64+
65+
A single `fonts.css` on S3 contains all the `@font-face` declarations (~940 rules) for every font family. Each rule uses `unicode-range` subsetting, so browsers only download the woff2 slices for characters actually on the page.
66+
67+
The font CSS is loaded via `<link>` tags in `server/Html.tsx` (web) and `workers/tasks/export/html.tsx` (PDF exports), so the browser can start fetching it in parallel with other resources.
68+
69+
### Cache busting
70+
71+
Files on `assets.pubpub.org` have a long TTL. To avoid cache issues, all font files live under a content-hashed directory (`/fonts/<hash>/`). The hash is derived from the sha256 of all generated files. If nothing changes, the hash stays the same and nothing gets re-uploaded. If anything changes, you get a new directory and new URLs automatically.
72+
73+
Old versions remain on S3 harmlessly — they'll just stop being referenced.
74+
75+
### Updating fonts
76+
77+
Run the upload script:
78+
79+
```
80+
# Dry run — downloads fonts, generates CSS, shows what would happen, updates source files
81+
scripts/upload-fonts-to-s3.sh --dry-run
82+
83+
# Real run — same as above, but also uploads to S3
84+
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... scripts/upload-fonts-to-s3.sh
85+
```
86+
87+
The script:
88+
89+
1. Downloads fontsource packages directly from npm (nothing gets installed in the project)
90+
2. Copies all woff2 files to a staging directory
91+
3. Generates `fonts.css` with corrected `font-family` names and relative `url()` paths
92+
4. Computes a content hash from everything in the staging directory
93+
5. Uploads to `s3://assets.pubpub.org/fonts/<hash>/`
94+
6. Updates the font URL in `server/Html.tsx` and `workers/tasks/export/html.tsx`
95+
96+
After running the script, commit the updated source files. You need AWS credentials with write access to the `assets.pubpub.org` bucket.
97+
98+
To add or remove font families, edit the `PACKAGES` and `CSS_SOURCES` arrays in the script, and update `client/styles/variables.scss` to match.
99+
100+
52101
## Storybook
53102

54103
To build and test components, we use Storybook. To run:

client/components/PubPreview/pubPreview.scss

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,9 @@
7070
text-decoration: underline;
7171
}
7272
.pub-title {
73-
font-weight: 500;
73+
font-weight: 650;
7474
font-size: 24px;
75+
letter-spacing: 0px;
7576
line-height: 1.33 !important;
7677
}
7778
}
@@ -156,6 +157,7 @@
156157
.pub-title {
157158
font-weight: 400;
158159
font-size: 22px;
160+
letter-spacing: 0px;
159161
line-height: 1.33 !important;
160162
}
161163
}
@@ -197,6 +199,7 @@
197199
.pub-title {
198200
font-weight: 400;
199201
font-size: 18px;
202+
letter-spacing: 0px;
200203
line-height: 1.33 !important;
201204
}
202205
}
@@ -213,7 +216,7 @@
213216
.title-wrapper {
214217
padding-bottom: 5px;
215218
font-family:
216-
multi-display,
219+
'Source Sans 3',
217220
-apple-system,
218221
'BlinkMacSystemFont',
219222
'Segoe UI',
@@ -228,7 +231,8 @@
228231
.pub-title {
229232
line-height: 1.25 !important;
230233
display: inline;
231-
font-weight: 500;
234+
font-weight: 650;
235+
letter-spacing: 0.2px;
232236
}
233237
.authors {
234238
font-size: 14px;

client/containers/Landing/landing.scss

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,12 @@ $leftColumnWidth: 20%;
5151

5252
#landing-container {
5353
/***** Globals *****/
54-
font-family: upgrade, sans-serif;
55-
font-weight: 300;
54+
font-family: 'Outfit', sans-serif;
55+
font-weight: 400;
5656
font-style: normal;
5757
font-size: 1em;
5858
line-height: 2em;
59-
letter-spacing: 1px;
59+
letter-spacing: 0.2px;
6060
strong {
6161
font-weight: 500;
6262
}
@@ -183,9 +183,10 @@ $leftColumnWidth: 20%;
183183
.content {
184184
h1 {
185185
margin: 1em 0 0.5em 0;
186-
font-weight: 400;
186+
font-weight: 500;
187187
font-style: normal;
188-
font-size: 4em;
188+
font-size: 3.9em;
189+
letter-spacing: 0.2px;
189190
}
190191
h2 {
191192
margin: 0.75em 0;
@@ -203,9 +204,10 @@ $leftColumnWidth: 20%;
203204
.subtitle {
204205
max-width: 500px;
205206
font-size: 1.5em;
206-
font-family: upgrade-lights, sans-serif;
207-
font-weight: 500;
207+
font-family: 'Outfit', sans-serif;
208+
font-weight: 200;
208209
font-style: normal;
210+
letter-spacing: 0px;
209211
}
210212
}
211213
}
@@ -234,13 +236,13 @@ $leftColumnWidth: 20%;
234236
.feature-number {
235237
font-size: 1em;
236238
line-height: 2em;
237-
font-weight: 200;
239+
font-weight: 300;
238240
text-transform: uppercase;
239241
}
240242
h4 {
241243
font-size: 1.25em;
242244
line-height: 2em;
243-
font-weight: 400;
245+
font-weight: 500;
244246
}
245247
> div:nth-child(odd) {
246248
text-align: right;
@@ -281,8 +283,8 @@ $leftColumnWidth: 20%;
281283
ul {
282284
margin-top: 4em;
283285
list-style-type: none;
284-
font-family: upgrade-lights;
285-
font-weight: 500;
286+
font-family: 'Outfit', sans-serif;
287+
font-weight: 250;
286288
li {
287289
margin: 2.4em 0;
288290
}
@@ -389,8 +391,8 @@ $leftColumnWidth: 20%;
389391
.description {
390392
font-size: 0.9em;
391393
line-height: 1.2em;
392-
font-family: upgrade-light;
393-
font-weight: 300;
394+
font-family: 'Outfit', sans-serif;
395+
font-weight: 300;
394396
font-style: italic;
395397
}
396398
}
@@ -425,12 +427,13 @@ $leftColumnWidth: 20%;
425427
.container {
426428
h4 {
427429
font-size: 2em;
428-
font-weight: 300;
430+
font-weight: 350;
429431
line-height: 1.2em;
432+
letter-spacing: 0px;
430433
}
431434
p.disclaimer {
432-
font-family: upgrade-lights;
433-
font-weight: 200;
435+
font-family: 'Outfit', sans-serif;
436+
font-weight: 100;
434437
font-style: italic;
435438
}
436439
}

client/containers/Pub/PubDocument/pubBody.scss

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ $bp: vendor.$bp-namespace;
55
@import 'styles/variables.scss';
66
@import '../pub.scss';
77

8-
$pub-body-font-size: if-is-export(14px, 20px);
8+
$pub-body-font-size: if-is-export(13px, 19px);
99

1010
.pub-body-component .editor.ProseMirror,
1111
.pub-body-styles {
@@ -40,40 +40,45 @@ $pub-body-font-size: if-is-export(14px, 20px);
4040
}
4141
}
4242
h1 {
43-
font-size: 1.4em;
44-
font-weight: 600;
45-
line-height: 1.3em;
43+
font-size: 1.6em;
44+
font-weight: 700;
45+
line-height: 1.1em;
4646
letter-spacing: 0px;
4747
}
4848
h2 {
49-
font-size: 1.3em;
50-
line-height: 1.3em;
51-
font-weight: 500;
49+
font-size: 1.4em;
50+
line-height: 1.1em;
51+
font-weight: 600;
5252
letter-spacing: 0px;
5353
}
5454
h3 {
55-
font-size: 1.2em;
56-
line-height: 1.3em;
55+
font-size: 1.25em;
56+
line-height: 0.8em;
5757
font-weight: 400;
58-
letter-spacing: 0.5px;
58+
letter-spacing: 0px;
5959
}
6060
h4 {
6161
font-size: 1em;
6262
line-height: 1.3em;
63-
font-weight: 500;
64-
letter-spacing: 0.5px;
63+
font-weight: 600;
64+
letter-spacing: 0px;
6565
}
6666
h5 {
6767
font-size: 1em;
6868
line-height: 1.3em;
69-
font-weight: 400;
70-
letter-spacing: 0.5px;
69+
font-weight: 500;
70+
letter-spacing: 0px;
7171
}
7272
h6 {
7373
font-size: 1em;
7474
line-height: 1.3em;
7575
font-weight: 300;
76-
letter-spacing: 0.5px;
76+
letter-spacing: 0px;
77+
}
78+
// Neutralize <strong> inside headings — headings should look
79+
// the same regardless of whether the user toggled bold.
80+
h1, h2, h3, h4, h5, h6 {
81+
strong { font-weight: inherit; }
7782
}
7883
* + h1,
7984
* + h2,
@@ -86,11 +91,10 @@ $pub-body-font-size: if-is-export(14px, 20px);
8691
p,
8792
li {
8893
font-family: $body-font;
89-
letter-spacing: 0.01rem;
9094
font-weight: 400;
9195
font-style: normal;
92-
line-height: 1.7;
93-
letter-spacing: -0.003em;
96+
line-height: if-is-export(1.7, 1.75);
97+
letter-spacing: -0.023em;
9498
word-break: break-word;
9599
}
96100

client/containers/Pub/PubHeader/pubHeader.scss

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ $mobile-bottom-buttons-spacing: 10px;
5353
margin: 0;
5454
font-size: 48px;
5555
line-height: 1.5em;
56-
font-weight: normal;
56+
font-weight: 450;
57+
letter-spacing: -1.1px;
5758
font-family: $header-font;
5859
box-decoration-break: clone;
5960
@include smaller-viewport {
@@ -101,18 +102,19 @@ $mobile-bottom-buttons-spacing: 10px;
101102
padding-top: $title-elements-spacing;
102103
margin: 0;
103104
font-size: 18px;
104-
font-weight: normal;
105+
font-weight: 400;
106+
letter-spacing: 0.3px;
105107
font-family: $header-font;
106108
}
107109

108110
.byline-component {
109111
padding-top: $title-elements-spacing;
110112
margin: 0;
111-
font-size: 18px;
113+
font-size: 19px;
112114
font-style: italic;
113-
font-weight: normal;
115+
font-weight: 400;
114116
font-family: $header-font;
115-
letter-spacing: 0.5px;
117+
letter-spacing: 0.1px;
116118
.byline-icon svg {
117119
width: 14px;
118120
height: auto;

client/styles/base.scss

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66
@import '~@blueprintjs/icons/lib/css/blueprint-icons.css';
77

88
@import './grid.scss';
9-
@import url('https://use.typekit.net/kmi0tdo.css');
109
@import './variables.scss';
1110
@import './typography.scss';
1211

client/styles/variables.scss

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,16 +6,16 @@
66
}
77

88
$cjk-body-font:
9-
source-han-serif-tc, source-han-serif-korean, source-han-serif-japanese, source-han-serif-sc;
9+
'Noto Serif TC', 'Noto Serif KR', 'Noto Serif JP', 'Noto Serif SC';
1010

1111
$cjk-header-font:
12-
source-han-sans-cjk-tc, source-han-sans-cjk-ko, source-han-sans-cjk-ja, source-han-sans-cjk-sc;
12+
'Noto Sans TC', 'Noto Sans KR', 'Noto Sans JP', 'Noto Sans SC';
1313

1414
$base-font:
1515
-apple-system, 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell',
1616
'Open Sans', 'Helvetica Neue', sans-serif;
1717
$header-font:
18-
multi-display,
18+
'Source Sans 3',
1919
-apple-system,
2020
'BlinkMacSystemFont',
2121
'Segoe UI',
@@ -28,11 +28,7 @@ $header-font:
2828
sans-serif,
2929
$cjk-header-font;
3030

31-
// We make this distinction because Adobe Acrobat hates skolar
32-
$export-body-font:
33-
Georgia, Cambria, 'Times New Roman', Times, 'DejaVu Serif', $cjk-body-font, serif;
34-
$screen-body-font: skolar-latin, Georgia, Cambria, 'Times New Roman', Times, serif;
35-
$body-font: if-is-export($export-body-font, $screen-body-font);
31+
$body-font: 'Source Serif 4', Georgia, Cambria, 'Times New Roman', Times, serif;
3632

3733
$mobile-cutoff: 750px;
3834

0 commit comments

Comments
 (0)