import fs from "node:fs"; import path from "node:path"; // Screen-tracking marker images for on-set use (served at /set). // Files live in public/set/markers and are discovered at build time, so adding // a device is just dropping in a PNG named like: // markers_phone_iPhone-Pro_1179x2556.png // edge-markers_phone_iPhone-Pro_2556x1179_landscape.png // markers_laptop_1920x1080.png (no device name) // plain_grey_128.png (anything else = "extra") export type Kind = "phone" | "tablet" | "laptop" | "monitor"; export type MarkerScreen = { id: string; // stable key, e.g. "phone-iphone-pro-1179x2556" kind: Kind; name: string; // "iPhone Pro" width: number; height: number; landscape: boolean; full?: string; // /set/markers/markers_….png edge?: string; // /set/markers/edge-markers_….png }; export type MarkerExtra = { id: string; name: string; src: string }; const DIR = path.join(process.cwd(), "public", "set", "markers"); const URL_BASE = "/set/markers/"; const ORDER: Kind[] = ["phone", "tablet", "laptop", "monitor"]; const PATTERN = /^(edge-markers|markers)_(phone|tablet|laptop|monitor)_(?:(.+?)_)?(\d+)x(\d+)(_landscape)?\.png$/i; function prettyName(raw: string | undefined, kind: Kind, w: number, h: number) { if (!raw) { if (kind === "laptop" && Math.max(w, h) === 1920) return "Laptop Full HD"; return `${kind[0].toUpperCase()}${kind.slice(1)} ${w}×${h}`; } return raw .replace(/-/g, " ") .replace(/ProMax/g, "Pro Max") .replace(/(\d+(\.\d+)?)$/, "$1″") .replace(/^4K$/, "4K Monitor"); } export function loadMarkers(): { screens: MarkerScreen[]; extras: MarkerExtra[] } { const files = fs.existsSync(DIR) ? fs.readdirSync(DIR).filter((f) => f.toLowerCase().endsWith(".png")) : []; const screens = new Map(); const extras: MarkerExtra[] = []; for (const file of files.sort()) { const m = file.match(PATTERN); if (!m) { const name = file .replace(/\.png$/i, "") .replace(/[_-]+/g, " ") .replace(/\b\w/g, (c) => c.toUpperCase()); extras.push({ id: file.replace(/\.png$/i, "").toLowerCase(), name, src: URL_BASE + file }); continue; } const [, variant, kindRaw, rawName, w, h, land] = m; const kind = kindRaw.toLowerCase() as Kind; const width = Number(w); const height = Number(h); const id = `${kind}-${(rawName ?? "generic").toLowerCase()}-${width}x${height}`; const screen = screens.get(id) ?? { id, kind, name: prettyName(rawName, kind, width, height), width, height, landscape: Boolean(land) || width > height, }; if (variant.toLowerCase() === "edge-markers") screen.edge = URL_BASE + file; else screen.full = URL_BASE + file; screens.set(id, screen); } const sorted = [...screens.values()].sort( (a, b) => ORDER.indexOf(a.kind) - ORDER.indexOf(b.kind) || a.name.localeCompare(b.name) || Number(a.landscape) - Number(b.landscape), ); return { screens: sorted, extras }; }