Skip to content

Commit 7b6c3ce

Browse files
[og images] Resize long og image text (#8543)
* Resize long og image text * address feedback
1 parent 6be2b02 commit 7b6c3ce

2 files changed

Lines changed: 30 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
"@babel/preset-react": "^7.18.6",
5353
"@mdx-js/mdx": "^2.1.3",
5454
"@resvg/resvg-js": "^2.6.2",
55+
"@shuding/opentype.js": "1.4.0-beta.0",
5556
"@types/body-scroll-lock": "^2.6.1",
5657
"@types/classnames": "^2.2.10",
5758
"@types/debounce": "^1.2.1",

scripts/generateOgImages.mjs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import path from 'path';
1414
import satori from 'satori';
1515
import {Resvg} from '@resvg/resvg-js';
1616
import matter from 'gray-matter';
17+
import opentype from '@shuding/opentype.js';
1718

1819
const ROOT = process.cwd();
1920
const CONTENT_DIR = path.join(ROOT, 'src', 'content');
@@ -34,6 +35,33 @@ const medium = fs.readFileSync(
3435
path.join(ROOT, 'public', 'fonts', 'Optimistic_Display_W_Md.ttf')
3536
);
3637

38+
// Title area width: card width minus the horizontal padding (80px per side).
39+
const TITLE_MAX_WIDTH = 1200 - 80 * 2;
40+
const TITLE_MAX_FONT = 96;
41+
const TITLE_MIN_FONT = 56;
42+
// Small margin so borderline titles don't wrap and orphan a single trailing
43+
// character (e.g. the "p" in "renderToStaticMarkup", which is 1px too wide
44+
// to fit on one line at 96px).
45+
const TITLE_SAFETY = 8;
46+
47+
const boldFont = opentype.parse(
48+
bold.buffer.slice(bold.byteOffset, bold.byteOffset + bold.byteLength)
49+
);
50+
51+
// Multi-word titles wrap cleanly at spaces, so a length bucket is fine for
52+
// them. Single-word titles (most API names) can only break mid-word, which
53+
// leaves an orphaned letter on its own line, so instead shrink them just
54+
// enough to fit on a single line.
55+
function titleFontSize(title) {
56+
const trimmed = title.trim();
57+
if (/\s/.test(trimmed)) {
58+
return trimmed.length > 24 ? 72 : 96;
59+
}
60+
const widthPerPx = boldFont.getAdvanceWidth(trimmed, 1);
61+
const fit = Math.floor((TITLE_MAX_WIDTH - TITLE_SAFETY) / widthPerPx);
62+
return Math.max(TITLE_MIN_FONT, Math.min(TITLE_MAX_FONT, fit));
63+
}
64+
3765
function el(type, style, children) {
3866
return {type, props: {style, children}};
3967
}
@@ -103,7 +131,7 @@ function card(title, pagePath) {
103131
flexGrow: 1,
104132
display: 'flex',
105133
alignItems: 'center',
106-
fontSize: title.length > 24 ? 72 : 96,
134+
fontSize: titleFontSize(title),
107135
fontFamily: 'Optimistic Display Bold',
108136
color: '#f6f7f9',
109137
lineHeight: 1.1,

0 commit comments

Comments
 (0)