/** Shared font catalog safe for client and server bundles (no Node APIs). */ /** Max custom font upload size (10 MB). */ export const FONT_UPLOAD_MAX_BYTES = 10 * 1024 * 1024; /** Bundled default font for preview + FFmpeg parity (Apache 2.0, Google Arimo). */ export const SYSTEM_FONT = { key: "system", label: "Arimo", file: "Arimo-Regular.ttf", boldFile: "Arimo-Bold.ttf", previewFamily: "S2VIDPreview-system", } as const; export const CURATED_FONTS = [ { key: "inter", label: "Inter", cssFamily: "Inter", googleCss: "Inter:wght@400;600", file: "Inter-Regular.ttf", boldFile: null as string | null, }, { key: "montserrat", label: "Montserrat", cssFamily: "Montserrat", googleCss: "Montserrat:wght@400;600", file: "Montserrat-Regular.ttf", boldFile: null as string | null, }, { key: "roboto", label: "Roboto", cssFamily: "Roboto", googleCss: "Roboto:wght@400;500", file: "Roboto-Regular.ttf", boldFile: null as string | null, }, { key: "oswald", label: "Oswald", cssFamily: "Oswald", googleCss: "Oswald:wght@400;500", file: "Oswald-Regular.ttf", boldFile: null as string | null, }, { key: "playfair", label: "Playfair Display", cssFamily: "Playfair Display", googleCss: "Playfair+Display:wght@400;600", file: "PlayfairDisplay-Regular.ttf", boldFile: null as string | null, }, ] as const; export type CuratedFontKey = (typeof CURATED_FONTS)[number]["key"]; export type WatermarkFontKey = CuratedFontKey | "custom" | "system"; const CURATED_KEYS = new Set(CURATED_FONTS.map((f) => f.key)); export function isCuratedFontKey(v: unknown): v is CuratedFontKey { return typeof v === "string" && CURATED_KEYS.has(v); } export function isWatermarkFontKey(v: unknown): v is WatermarkFontKey { return v === "custom" || v === "system" || isCuratedFontKey(v); } /** * Escape an absolute font path for use inside an FFmpeg filtergraph `fontfile=` value. * Paths are never passed through a shell; this only escapes filter special chars. */ export function sanitizeFontfileForFilter(absPath: string): string { return absPath .replace(/\\/g, "/") .replace(/:/g, "\\:") .replace(/'/g, "\\'") .replace(/\[/g, "\\[") .replace(/\]/g, "\\]"); } export function googleFontsStylesheetUrl(keys: CuratedFontKey[]): string { const families = CURATED_FONTS.filter((f) => keys.includes(f.key)) .map((f) => `family=${f.googleCss}`) .join("&"); return `https://fonts.googleapis.com/css2?${families}&display=swap`; }