import { initSkia, hasGpu } from './skiaShim'; import type { RenderAssets } from './exportEngine'; // One CanvasKit instance per page, one copy of the render assets. The wasm file // is served from /wasm/ (scripts/copy-wasm.mjs puts it there at build time); the // fonts and the wall-frame artwork are in public/assets. let assets: RenderAssets | null = null; // The faces the watermarks' FONT option offers beside DEFAULT. There is no OS // font service in a browser, so the list is exactly what the bundle carries — // and each family is ONE file, because drawText has no glyph fallback: a name // mapped to only the latin subset would print a Vietnamese place name as tofu. // The two here are the site's own self-hosted faces (styles/fonts.css, SIL OFL), // with their latin / latin-ext / vietnamese woff2 subsets decompressed, pinned // to weight 400 @ opsz 14 and merged into one TTF per family (fontTools). export const MARK_FACES: { family: string; file: string }[] = [ { family: 'Inter', file: '/assets/Inter-Regular.ttf' }, { family: 'Fraunces', file: '/assets/Fraunces-Regular.ttf' }, ]; async function buf(url: string): Promise { const res = await fetch(url); if (!res.ok) throw new Error(`fetch ${url}: ${res.status}`); return res.arrayBuffer(); } // The engine is only usable on a WebGL-backed surface (see skiaShim.ts), so the // app has to know whether it got one: reporting "no WebGL" beats silently // spending minutes per photo on the raster fallback. export function probeGpu(): boolean { return hasGpu(); } export async function loadEngine(): Promise<{ assets: RenderAssets; gpu: boolean }> { await initSkia({ locateFile: (file) => `/wasm/${file}` }); if (!assets) { const [textFont, emojiFont, wallframePng, markFonts] = await Promise.all([ buf('/assets/Cousine-Regular.ttf'), buf('/assets/NotoEmoji-GPS.ttf'), buf('/assets/wallframe.png'), Promise.all(MARK_FACES.map(async (face) => ({ family: face.family, bytes: await buf(face.file) }))), ]); assets = { textFont, emojiFont, wallframe: new Uint8Array(wallframePng), markFonts }; } return { assets, gpu: probeGpu() }; }