/** * Generates device frame PNG assets + meta.json files from SVG templates. * * Run: cd apps/api && npx tsx scripts/generate-frames.ts */ import { existsSync, mkdirSync, writeFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import sharp from "sharp"; const __dirname = dirname(fileURLToPath(import.meta.url)); const FRAMES_DIR = join(__dirname, "../src/assets/frames"); interface FrameDef { id: string; svg: string; meta: { screenX: number; screenY: number; screenW: number; screenH: number }; } // --------------------------------------------------------------------------- // iPhone frames // --------------------------------------------------------------------------- function iphoneSvg(variant: "light" | "dark"): string { const body = variant === "light" ? "#c0c0c0" : "#2a2a2a"; const border = variant === "light" ? "#333333" : "#111111"; return ` `; } const IPHONE_META = { screenX: 20, screenY: 80, screenW: 390, screenH: 720 }; // --------------------------------------------------------------------------- // MacBook frames // --------------------------------------------------------------------------- function macbookSvg(variant: "light" | "dark"): string { const bezel = variant === "light" ? "#d4d4d8" : "#3f3f46"; const base = variant === "light" ? "#e4e4e7" : "#27272a"; const cameraDot = variant === "light" ? "#a1a1aa" : "#52525b"; return ` `; } const MACBOOK_META = { screenX: 100, screenY: 30, screenW: 1000, screenH: 625 }; // --------------------------------------------------------------------------- // iPad frames // --------------------------------------------------------------------------- function ipadSvg(variant: "light" | "dark"): string { const body = variant === "light" ? "#d4d4d8" : "#3f3f46"; const cameraDot = variant === "light" ? "#a1a1aa" : "#52525b"; return ` `; } const IPAD_META = { screenX: 25, screenY: 25, screenW: 490, screenH: 670 }; // --------------------------------------------------------------------------- // Generate all frames // --------------------------------------------------------------------------- const frames: FrameDef[] = [ { id: "iphone", svg: iphoneSvg("light"), meta: IPHONE_META }, { id: "iphone-dark", svg: iphoneSvg("dark"), meta: IPHONE_META }, { id: "macbook", svg: macbookSvg("light"), meta: MACBOOK_META }, { id: "macbook-dark", svg: macbookSvg("dark"), meta: MACBOOK_META }, { id: "ipad", svg: ipadSvg("light"), meta: IPAD_META }, { id: "ipad-dark", svg: ipadSvg("dark"), meta: IPAD_META }, ]; async function main() { if (!existsSync(FRAMES_DIR)) { mkdirSync(FRAMES_DIR, { recursive: true }); } for (const frame of frames) { const pngPath = join(FRAMES_DIR, `${frame.id}.png`); const metaPath = join(FRAMES_DIR, `${frame.id}.meta.json`); const pngBuf = await sharp(Buffer.from(frame.svg)).png().toBuffer(); writeFileSync(pngPath, pngBuf); writeFileSync(metaPath, JSON.stringify(frame.meta, null, 2) + "\n"); console.log(`Generated ${frame.id}.png + ${frame.id}.meta.json`); } console.log(`\nAll frames written to ${FRAMES_DIR}`); } main().catch((err) => { console.error(err); process.exit(1); });