Skip to content

Commit 0131229

Browse files
committed
fix: embed fonts in OG images
1 parent d765058 commit 0131229

File tree

2 files changed

+58
-11
lines changed

2 files changed

+58
-11
lines changed

server/routes/og/skill.png.ts

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ type OgQuery = {
1111
description?: string
1212
}
1313

14+
const FONT_SANS = 'Bricolage Grotesque'
15+
const FONT_MONO = 'IBM Plex Mono'
16+
1417
let markDataUrlPromise: Promise<string> | null = null
1518
let wasmInitPromise: Promise<void> | null = null
19+
let fontBuffersPromise: Promise<Uint8Array[]> | null = null
1620

1721
async function ensureWasm() {
1822
if (!wasmInitPromise) {
@@ -26,6 +30,32 @@ async function ensureWasm() {
2630
await wasmInitPromise
2731
}
2832

33+
async function getFontBuffers() {
34+
if (!fontBuffersPromise) {
35+
fontBuffersPromise = Promise.all([
36+
readFile(
37+
new URL(
38+
'../../../node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-800-normal.woff2',
39+
import.meta.url,
40+
),
41+
),
42+
readFile(
43+
new URL(
44+
'../../../node_modules/@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-500-normal.woff2',
45+
import.meta.url,
46+
),
47+
),
48+
readFile(
49+
new URL(
50+
'../../../node_modules/@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-500-normal.woff2',
51+
import.meta.url,
52+
),
53+
),
54+
]).then((buffers) => buffers.map((buffer) => new Uint8Array(buffer)))
55+
}
56+
return fontBuffersPromise
57+
}
58+
2959
function getNitroServerRootUrl() {
3060
const nitroMain = (globalThis as unknown as { __nitro_main__?: unknown }).__nitro_main__
3161
if (typeof nitroMain !== 'string') return null
@@ -197,30 +227,30 @@ function buildSvg(params: {
197227
<text x="186" y="163"
198228
fill="#F6EFE4"
199229
font-size="18"
200-
font-weight="650"
201-
font-family="ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica Neue, Helvetica, Arial, sans-serif"
230+
font-weight="600"
231+
font-family="${FONT_SANS}, sans-serif"
202232
opacity="0.92">${escapeXml(pillText)}</text>
203233
</g>
204234
205235
<text x="114" y="${titleY}"
206236
fill="#F6EFE4"
207237
font-size="${titleFontSize}"
208-
font-weight="760"
209-
font-family="ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica Neue, Helvetica, Arial, sans-serif">${titleTspans}</text>
238+
font-weight="800"
239+
font-family="${FONT_SANS}, sans-serif">${titleTspans}</text>
210240
211241
<text x="114" y="${descY}"
212242
fill="#C6B8A8"
213243
font-size="26"
214-
font-weight="520"
215-
font-family="ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica Neue, Helvetica, Arial, sans-serif">${descTspans}</text>
244+
font-weight="500"
245+
font-family="${FONT_SANS}, sans-serif">${descTspans}</text>
216246
217247
<rect x="114" y="472" width="110" height="6" rx="3" fill="#E86A47"/>
218248
<text x="114" y="530"
219249
fill="#F6EFE4"
220250
font-size="20"
221-
font-weight="650"
251+
font-weight="500"
222252
opacity="0.90"
223-
font-family="ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, Liberation Mono, Courier New, monospace">${escapeXml(params.footer)}</text>
253+
font-family="${FONT_MONO}, monospace">${escapeXml(params.footer)}</text>
224254
</svg>`
225255
}
226256

@@ -245,7 +275,10 @@ export default defineEventHandler(async (event) => {
245275
setHeader(event, 'Cache-Control', cacheKey)
246276
setHeader(event, 'Content-Type', 'image/png')
247277

248-
const [markDataUrl] = await Promise.all([getMarkDataUrl(), ensureWasm()])
278+
const [markDataUrl, fontBuffers] = await Promise.all([
279+
getMarkDataUrl(),
280+
ensureWasm().then(() => getFontBuffers()),
281+
])
249282
const svg = buildSvg({
250283
markDataUrl,
251284
title,
@@ -257,7 +290,12 @@ export default defineEventHandler(async (event) => {
257290

258291
const resvg = new Resvg(svg, {
259292
fitTo: { mode: 'width', value: 1200 },
260-
font: { loadSystemFonts: true },
293+
font: {
294+
fontBuffers,
295+
defaultFontFamily: FONT_SANS,
296+
sansSerifFamily: FONT_SANS,
297+
monospaceFamily: FONT_MONO,
298+
},
261299
})
262300
const png = resvg.render().asPng()
263301
resvg.free()

vite.config.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,23 @@ import viteTsConfigPaths from 'vite-tsconfig-paths'
99

1010
const require = createRequire(import.meta.url)
1111
const resvgWasmPath = require.resolve('@resvg/resvg-wasm/index_bg.wasm')
12+
const bricolageBoldPath = require.resolve(
13+
'@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-800-normal.woff2',
14+
)
15+
const bricolageTextPath = require.resolve(
16+
'@fontsource/bricolage-grotesque/files/bricolage-grotesque-latin-500-normal.woff2',
17+
)
18+
const plexMonoPath = require.resolve(
19+
'@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-500-normal.woff2',
20+
)
1221

1322
const config = defineConfig({
1423
plugins: [
1524
devtools(),
1625
nitro({
1726
serverDir: 'server',
1827
externals: {
19-
traceInclude: [resvgWasmPath],
28+
traceInclude: [resvgWasmPath, bricolageBoldPath, bricolageTextPath, plexMonoPath],
2029
},
2130
}),
2231
// this is the plugin that enables path aliases

0 commit comments

Comments
 (0)