Add lower-corner layouts, custom blur backgrounds, and classic blur fill.

Ship composition families, optional background images for lower-corner templates, and an optional blurred cover fill for classic letterbox.
This commit is contained in:
Atakan Doğan Özban
2026-08-07 00:51:37 +02:00
parent 03634d5100
commit 848607f9e0
25 changed files with 1081 additions and 122 deletions
+17 -4
View File
@@ -2,19 +2,32 @@
import fs from "fs/promises";
import path from "path";
import { CURATED_FONTS, type CuratedFontKey } from "./fonts";
import { CURATED_FONTS, SYSTEM_FONT, type CuratedFontKey } from "./fonts";
export function getFontsDir(): string {
return path.join(process.cwd(), "assets", "fonts");
}
/** Resolve the bundled system (Arimo) font for FFmpeg + preview. */
export function resolveSystemFontPath(weight: "regular" | "bold" = "regular"): string {
const file = weight === "bold" ? SYSTEM_FONT.boldFile : SYSTEM_FONT.file;
const safe = file.replace(/[^a-zA-Z0-9._-]/g, "");
if (safe !== file) throw new Error("Invalid font asset name");
return path.join(getFontsDir(), safe);
}
/** Resolve a curated font file on disk (must exist under assets/fonts). */
export function resolveCuratedFontPath(key: CuratedFontKey): string {
export function resolveCuratedFontPath(
key: CuratedFontKey,
weight: "regular" | "bold" = "regular",
): string {
const meta = CURATED_FONTS.find((f) => f.key === key);
if (!meta) throw new Error("Unknown font");
const file =
weight === "bold" && meta.boldFile ? meta.boldFile : meta.file;
// Whitelist filename only never accept user-controlled path segments
const safe = meta.file.replace(/[^a-zA-Z0-9._-]/g, "");
if (safe !== meta.file) throw new Error("Invalid font asset name");
const safe = file.replace(/[^a-zA-Z0-9._-]/g, "");
if (safe !== file) throw new Error("Invalid font asset name");
return path.join(getFontsDir(), safe);
}