mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-07 10:06:21 +00:00
Compositions are now self-contained: the compiler captures font files and embeds them as woff2 data URIs, eliminating silent render-time fallback when the render environment lacks the author's fonts. Resolution order (each tier falls through to the next): 1. Existing @font-face → use as-is 2. Bundled alias (38 cross-platform mappings) → embed data URI 3. Google Fonts → fetch, cache, embed 4. Local system font → locate on OS, compress to woff2, embed 5. Local @font-face paths → read file, compress, inline as data URI 6. External CDN stylesheets → fetch CSS, extract @font-face, inline 7. Alias map fallback → closest bundled equivalent 8. Actionable error with guidance Key changes: - System font locator (macOS/Windows/Linux) with path-bounding and symlink defense (realpathSync + O_NOFOLLOW) - woff2 compression via wawoff2 (WASM, cross-platform) - Multi-weight/style variant capture with length-sorted token matching - External stylesheet inlining with SSRF defense (assertPublicHttpsUrl, HTTPS-only, private-host blocking, 2MB cap, 4-concurrent limit) - Studio auto-import via GET /fonts/file API + renderAliasFor() derived from shared FONT_ALIAS_MAP (no more hand-curated drift) - failClosedFontFetch throws on unresolved fonts in distributed renders - Single source of truth: @hyperframes/core/fonts/aliases - system_font_will_alias lint rule (escalates to warning for distributed) - Default to Inter + JetBrains Mono in templates and CSS reset
134 lines
2.5 KiB
TypeScript
134 lines
2.5 KiB
TypeScript
export const POPULAR_GOOGLE_FONT_FAMILIES = [
|
|
"ABeeZee",
|
|
"Abel",
|
|
"Abril Fatface",
|
|
"Alegreya",
|
|
"Alegreya Sans",
|
|
"Anton",
|
|
"Archivo",
|
|
"Archivo Black",
|
|
"Arimo",
|
|
"Assistant",
|
|
"Barlow",
|
|
"Barlow Condensed",
|
|
"Bebas Neue",
|
|
"Bitter",
|
|
"Bricolage Grotesque",
|
|
"Cabin",
|
|
"Cardo",
|
|
"Catamaran",
|
|
"Caveat",
|
|
"Chivo",
|
|
"Cormorant Garamond",
|
|
"Crimson Text",
|
|
"Dancing Script",
|
|
"DM Sans",
|
|
"DM Serif Display",
|
|
"Domine",
|
|
"EB Garamond",
|
|
"Exo 2",
|
|
"Figtree",
|
|
"Fira Code",
|
|
"Fira Sans",
|
|
"Fraunces",
|
|
"Fredoka",
|
|
"IBM Plex Mono",
|
|
"IBM Plex Sans",
|
|
"IBM Plex Serif",
|
|
"Inconsolata",
|
|
"Instrument Sans",
|
|
"Instrument Serif",
|
|
"Inter",
|
|
"JetBrains Mono",
|
|
"Josefin Sans",
|
|
"Jost",
|
|
"Kanit",
|
|
"Karla",
|
|
"Lato",
|
|
"League Gothic",
|
|
"Lexend",
|
|
"Libre Baskerville",
|
|
"Libre Franklin",
|
|
"Lora",
|
|
"Manrope",
|
|
"Merriweather",
|
|
"Montserrat",
|
|
"Mukta",
|
|
"Mulish",
|
|
"Newsreader",
|
|
"Noto Sans",
|
|
"Noto Sans JP",
|
|
"Noto Serif",
|
|
"Nunito",
|
|
"Nunito Sans",
|
|
"Open Sans",
|
|
"Oswald",
|
|
"Outfit",
|
|
"Overpass",
|
|
"Pacifico",
|
|
"Pathway Extreme",
|
|
"Permanent Marker",
|
|
"Playfair Display",
|
|
"Plus Jakarta Sans",
|
|
"Poppins",
|
|
"Prata",
|
|
"PT Sans",
|
|
"PT Serif",
|
|
"Public Sans",
|
|
"Quicksand",
|
|
"Raleway",
|
|
"Red Hat Display",
|
|
"Roboto",
|
|
"Roboto Condensed",
|
|
"Roboto Mono",
|
|
"Roboto Serif",
|
|
"Rubik",
|
|
"Schibsted Grotesk",
|
|
"Signika",
|
|
"Source Code Pro",
|
|
"Source Sans 3",
|
|
"Source Serif 4",
|
|
"Space Grotesk",
|
|
"Space Mono",
|
|
"Spectral",
|
|
"Sora",
|
|
"Syne",
|
|
"Teko",
|
|
"Titillium Web",
|
|
"Ubuntu",
|
|
"Ubuntu Mono",
|
|
"Unbounded",
|
|
"Urbanist",
|
|
"Varela Round",
|
|
"Work Sans",
|
|
"Young Serif",
|
|
"Zilla Slab",
|
|
] as const;
|
|
|
|
export const COMMON_LOCAL_FONT_FAMILIES = [
|
|
"TT Norms Pro",
|
|
"SF Pro Display",
|
|
"SF Pro Text",
|
|
"Avenir",
|
|
"Avenir Next",
|
|
"Menlo",
|
|
"Monaco",
|
|
] as const;
|
|
|
|
import { resolveAliasDisplayName } from "@hyperframes/core/fonts/aliases";
|
|
|
|
/**
|
|
* Resolves the render-time canonical font for a local font family name.
|
|
* Derived from the shared FONT_ALIAS_MAP — no hand-curation needed.
|
|
*/
|
|
export function renderAliasFor(family: string): string | undefined {
|
|
const display = resolveAliasDisplayName(family);
|
|
if (!display || display.toLowerCase() === family.toLowerCase()) return undefined;
|
|
return display;
|
|
}
|
|
|
|
export function googleFontStylesheetUrl(family: string): string {
|
|
const encodedFamily = encodeURIComponent(family.trim()).replace(/%20/g, "+");
|
|
return `https://fonts.googleapis.com/css2?family=${encodedFamily}:wght@300;400;500;600;700;800;900&display=swap`;
|
|
}
|