@appmockup/core 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +38 -0
- package/dist/index.cjs +1138 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1160 -0
- package/dist/index.d.ts +1160 -0
- package/dist/index.js +1079 -0
- package/dist/index.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/schema.ts","../src/color.ts","../src/fonts.ts","../src/starter.ts","../src/render/decorations.ts","../src/render/background.ts","../src/render/device-frame.ts","../src/render/text.ts","../src/render/index.ts","../src/templates.ts","../src/themes.ts"],"sourcesContent":["// Schema + types (single source of truth)\nexport {\n fontWeightSchema,\n outputSizeSchema,\n shadowSchema,\n decorationSchema,\n backgroundSchema,\n headlineSchema,\n subtitleSchema,\n deviceFrameSchema,\n screenshotEntrySchema,\n mockupConfigSchema,\n parseConfig,\n validateHeadlines,\n} from \"./schema.js\";\nexport type {\n FontWeightName,\n OutputSize,\n ShadowConfig,\n DecorationConfig,\n BackgroundConfig,\n GradientDirection,\n HeadlineConfig,\n SubtitleConfig,\n DeviceFrameConfig,\n ScreenshotEntry,\n MockupConfig,\n} from \"./schema.js\";\n\n// Canvas2D structural types\nexport type { Ctx2D, Gradient2D, TextMetricsLike, ScreenshotImage } from \"./types.js\";\n\n// Color + fonts helpers\nexport { parseHexColor, parseHexColorWithAlpha } from \"./color.js\";\nexport {\n DEFAULT_FONT_FAMILY,\n FALLBACK_FONT_STACK,\n cssFont,\n cssFontWeight,\n} from \"./fonts.js\";\n\n// Starter config + standard sizes\nexport { createStarterConfig, STANDARD_OUTPUT_SIZES } from \"./starter.js\";\n\n// Renderer\nexport { renderMockup, resolveScene } from \"./render/index.js\";\nexport type { RenderScene } from \"./render/index.js\";\nexport { drawBackground, drawDecorations, drawDeviceFrame, drawHeadline, drawSubtitle } from \"./render/index.js\";\nexport { deviceFrameRect } from \"./render/index.js\";\nexport type { TextResult, DeviceRect } from \"./render/index.js\";\n\n// Demo templates\nexport { TEMPLATES, getTemplate } from \"./templates.js\";\nexport type { Template } from \"./templates.js\";\n\n// Accent color themes\nexport { THEMES, getTheme, applyTheme } from \"./themes.js\";\nexport type { AccentTheme } from \"./themes.js\";\n","import { z } from \"zod\";\n\n/**\n * Mockup config schema — a faithful port of the Swift `MockupConfig` Codable\n * structs. This zod schema is the single source of truth for both validation and\n * the TypeScript types (inferred below).\n */\n\nexport const fontWeightSchema = z.enum([\n \"regular\",\n \"medium\",\n \"semibold\",\n \"bold\",\n \"heavy\",\n \"black\",\n]);\nexport type FontWeightName = z.infer<typeof fontWeightSchema>;\n\nexport const outputSizeSchema = z.object({\n name: z.string(),\n width: z.number().int().positive(),\n height: z.number().int().positive(),\n});\nexport type OutputSize = z.infer<typeof outputSizeSchema>;\n\n/**\n * A soft shadow. All fields optional — renderers apply sensible defaults, so a\n * bare `{}` means \"shadow on, default look\". blur/offsetX/offsetY are fractions\n * of the canvas width (resolution-independent); color is hex (#RRGGBBAA for alpha).\n */\nexport const shadowSchema = z.object({\n color: z.string().optional(),\n blur: z.number().min(0).optional(),\n offsetX: z.number().optional(),\n offsetY: z.number().optional(),\n});\nexport type ShadowConfig = z.infer<typeof shadowSchema>;\n\n/**\n * A decorative background element drawn between the background fill and the\n * content. Geometry is in canvas fractions: x/y of width/height, size of width.\n * All fields except `type` optional — per-type defaults apply at render time.\n */\nexport const decorationSchema = z.object({\n type: z.enum([\"glow\", \"circle\", \"dots\"]),\n /** Center x as a fraction of canvas width (glow/circle; ignored by dots). */\n x: z.number().optional(),\n /** Center y as a fraction of canvas height (glow/circle; ignored by dots). */\n y: z.number().optional(),\n /** glow/circle: radius as a fraction of canvas width; dots: dot radius. */\n size: z.number().positive().optional(),\n /** dots only: grid pitch as a fraction of canvas width. */\n spacing: z.number().positive().optional(),\n color: z.string().optional(),\n opacity: z.number().min(0).max(1).optional(),\n});\nexport type DecorationConfig = z.infer<typeof decorationSchema>;\n\nexport const backgroundSchema = z.object({\n type: z.enum([\"solid\", \"gradient\", \"radial\"]),\n colors: z.array(z.string()).min(1),\n direction: z\n .enum([\n \"topToBottom\",\n \"leftToRight\",\n \"topLeftToBottomRight\",\n \"bottomToTop\",\n \"rightToLeft\",\n \"bottomLeftToTopRight\",\n ])\n .optional(),\n /** Decorative shapes drawn on top of the fill, behind text and device. */\n decorations: z.array(decorationSchema).optional(),\n});\nexport type BackgroundConfig = z.infer<typeof backgroundSchema>;\nexport type GradientDirection = NonNullable<BackgroundConfig[\"direction\"]>;\n\nexport const headlineSchema = z.object({\n fontFamily: z.string().optional(),\n fontWeight: fontWeightSchema.optional(),\n color: z.string(),\n relativeSize: z.number().positive(),\n /** Optional text shadow; a bright color at zero offsets reads as a glow. */\n shadow: shadowSchema.optional(),\n});\nexport type HeadlineConfig = z.infer<typeof headlineSchema>;\n\nexport const subtitleSchema = z.object({\n text: z.string(),\n fontFamily: z.string().optional(),\n fontWeight: fontWeightSchema.optional(),\n color: z.string(),\n relativeSize: z.number().positive(),\n /** Optional text shadow; a bright color at zero offsets reads as a glow. */\n shadow: shadowSchema.optional(),\n});\nexport type SubtitleConfig = z.infer<typeof subtitleSchema>;\n\nexport const deviceFrameSchema = z.object({\n style: z.enum([\"iPhone\", \"iPad\"]),\n bezelColor: z.string(),\n cornerRadius: z.number(),\n bezelWidth: z.number(),\n screenRelativeWidth: z.number(),\n verticalOffset: z.number(),\n /** Device left edge as a fraction of canvas width. Omit/undefined = horizontally centered. */\n horizontalOffset: z.number().optional(),\n /** Clockwise rotation about the device center, in degrees. Omit/undefined = 0. */\n rotation: z.number().optional(),\n /**\n * How the screenshot fills the device screen. \"cover\" (default) scales to fill and crops\n * the overflow; \"contain\" scales to fit entirely, letterboxing with the bezel color.\n */\n fit: z.enum([\"cover\", \"contain\"]).optional(),\n /** Drop shadow under the device. A bare `{}` uses the default soft look. */\n shadow: shadowSchema.optional(),\n /** Horizontal shear in degrees about the device center — a pseudo-3D lean. */\n tilt: z.number().optional(),\n});\nexport type DeviceFrameConfig = z.infer<typeof deviceFrameSchema>;\n\nexport const screenshotEntrySchema = z.object({\n id: z.string(),\n file: z.string(),\n headlines: z.record(z.string(), z.string()),\n /** Overrides the global background for this screenshot (incl. its decorations). */\n background: backgroundSchema.optional(),\n});\nexport type ScreenshotEntry = z.infer<typeof screenshotEntrySchema>;\n\nexport const mockupConfigSchema = z.object({\n appName: z.string(),\n outputPrefix: z.string(),\n languages: z.array(z.string()).min(1),\n outputSizes: z.array(outputSizeSchema).min(1),\n background: backgroundSchema,\n headline: headlineSchema,\n subtitle: subtitleSchema.optional(),\n deviceFrame: deviceFrameSchema,\n screenshots: z.array(screenshotEntrySchema).min(1),\n});\nexport type MockupConfig = z.infer<typeof mockupConfigSchema>;\n\n/**\n * Parse + validate an unknown value into a MockupConfig, throwing a readable\n * error on failure. (Equivalent to Swift's `MockupConfig.load`.)\n */\nexport function parseConfig(input: unknown): MockupConfig {\n return mockupConfigSchema.parse(input);\n}\n\n/**\n * Cross-field validation: every screenshot must have a headline for every\n * declared language. Mirrors the headline check in Swift `MockupConfig.validate`.\n * (The screenshot-file-exists check is environment-specific and lives in node-render.)\n * Returns a list of human-readable problems; empty means valid.\n */\nexport function validateHeadlines(config: MockupConfig): string[] {\n const errors: string[] = [];\n for (const entry of config.screenshots) {\n for (const lang of config.languages) {\n if (entry.headlines[lang] === undefined) {\n errors.push(\n `Missing headline for screenshot '${entry.id}' in language '${lang}'`,\n );\n }\n }\n }\n return errors;\n}\n","/**\n * Hex color parsing, ported from the Swift `ColorParsing.cgColor(from:)`.\n *\n * Returns a CSS `rgba(...)` string (canvas-ready). Supports #RGB, #RRGGBB and\n * #RRGGBBAA. Matches the Swift behaviour of falling back to opaque black for\n * anything it can't parse, so output stays identical to the original tool.\n */\n\nfunction parseHexParts(hex: string): { r: number; g: number; b: number; a: number } {\n let h = hex.trim();\n if (h.startsWith(\"#\")) h = h.slice(1);\n\n let r = 0;\n let g = 0;\n let b = 0;\n let a = 1;\n\n if (h.length === 3 && /^[0-9a-fA-F]{3}$/.test(h)) {\n r = parseInt(h[0]! + h[0]!, 16);\n g = parseInt(h[1]! + h[1]!, 16);\n b = parseInt(h[2]! + h[2]!, 16);\n } else if (h.length === 6 && /^[0-9a-fA-F]{6}$/.test(h)) {\n r = parseInt(h.slice(0, 2), 16);\n g = parseInt(h.slice(2, 4), 16);\n b = parseInt(h.slice(4, 6), 16);\n } else if (h.length === 8 && /^[0-9a-fA-F]{8}$/.test(h)) {\n r = parseInt(h.slice(0, 2), 16);\n g = parseInt(h.slice(2, 4), 16);\n b = parseInt(h.slice(4, 6), 16);\n a = parseInt(h.slice(6, 8), 16) / 255;\n }\n // else: leave as opaque black, matching Swift's default branch.\n\n return { r, g, b, a };\n}\n\nexport function parseHexColor(hex: string): string {\n const { r, g, b, a } = parseHexParts(hex);\n return `rgba(${r}, ${g}, ${b}, ${a})`;\n}\n\n/**\n * Like parseHexColor, but multiplies the parsed alpha by `alphaScale` (0..1).\n * Used for gradient fade-outs (e.g. a glow's outer stop at alphaScale 0).\n */\nexport function parseHexColorWithAlpha(hex: string, alphaScale: number): string {\n const { r, g, b, a } = parseHexParts(hex);\n return `rgba(${r}, ${g}, ${b}, ${a * alphaScale})`;\n}\n","import type { FontWeightName } from \"./schema.js\";\n\n/**\n * Default font family. The Swift tool used the macOS system font (San Francisco);\n * for deterministic, cross-platform output we standardize on Inter and register\n * the same file in Node (see @appmockup/node-render) and load it via @font-face in\n * the web studio, so preview == export.\n */\nexport const DEFAULT_FONT_FAMILY = \"Inter\";\n\n/** Broad-coverage fallback (Latin/Cyrillic/Arabic/CJK) appended after the primary family. */\nexport const FALLBACK_FONT_STACK = '\"Noto Sans\", \"Noto Sans Arabic\", \"Noto Sans KR\", sans-serif';\n\n/** Map the Swift Core Text weight names to CSS numeric weights. */\nexport function cssFontWeight(weight: FontWeightName): number {\n switch (weight) {\n case \"regular\":\n return 400;\n case \"medium\":\n return 500;\n case \"semibold\":\n return 600;\n case \"bold\":\n return 700;\n case \"heavy\":\n return 800;\n case \"black\":\n return 900;\n }\n}\n\n/** Build a CSS `font` shorthand string for `ctx.font`. */\nexport function cssFont(\n family: string | undefined,\n weight: FontWeightName,\n sizePx: number,\n): string {\n // Swift ignored families starting with \".\" (private system font names).\n const fam = family && !family.startsWith(\".\") ? family : DEFAULT_FONT_FAMILY;\n return `${cssFontWeight(weight)} ${sizePx}px \"${fam}\", ${FALLBACK_FONT_STACK}`;\n}\n","import type { MockupConfig } from \"./schema.js\";\n\n/** A sensible starter config for a new app — used by `appmockup init`, the MCP\n * `init_config` tool, and the web studio's \"new project\" action. */\nexport function createStarterConfig(appName: string): MockupConfig {\n return {\n appName,\n outputPrefix: appName.toLowerCase().replace(/\\s+/g, \"-\") || \"app\",\n languages: [\"en\"],\n outputSizes: [\n { name: \"iPhone_6.7\", width: 1290, height: 2796 },\n { name: \"iPhone_6.5\", width: 1242, height: 2688 },\n { name: \"iPad_12.9\", width: 2048, height: 2732 },\n ],\n background: {\n type: \"gradient\",\n colors: [\"#FBF8F2\", \"#F0E4CF\"],\n direction: \"topToBottom\",\n },\n headline: { fontWeight: \"bold\", color: \"#1D2939\", relativeSize: 0.05 },\n subtitle: { text: appName, fontWeight: \"medium\", color: \"#C9975B\", relativeSize: 0.025 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#1D2939\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.75,\n verticalOffset: 0.25,\n },\n screenshots: [\n {\n id: \"01\",\n file: \"screenshots/01.png\",\n headlines: { en: \"Your headline\\ngoes here\" },\n },\n ],\n };\n}\n\n/** Standard App Store / Play Store output sizes (marketing asset dimensions). */\nexport const STANDARD_OUTPUT_SIZES: { name: string; width: number; height: number; note: string }[] =\n [\n { name: \"iPhone_6.9\", width: 1320, height: 2868, note: \"iPhone 16 Pro Max etc.\" },\n { name: \"iPhone_6.7\", width: 1290, height: 2796, note: \"iPhone 15/16 Pro Max, 14 Plus\" },\n { name: \"iPhone_6.5\", width: 1242, height: 2688, note: \"iPhone 11 Pro Max, XS Max\" },\n { name: \"iPad_13\", width: 2064, height: 2752, note: \"iPad Pro 13-inch (M4)\" },\n { name: \"iPad_12.9\", width: 2048, height: 2732, note: \"iPad Pro 12.9-inch\" },\n { name: \"Android_Phone\", width: 1080, height: 1920, note: \"Google Play phone (portrait)\" },\n ];\n","import type { DecorationConfig } from \"../schema.js\";\nimport type { Ctx2D } from \"../types.js\";\nimport { parseHexColor, parseHexColorWithAlpha } from \"../color.js\";\n\n/**\n * Decorative background elements, drawn on top of the background fill and\n * behind text and the device: soft radial \"glow\"s, plain circles, and a dots\n * grid. Geometry is in canvas fractions (x/y of width/height, size of width),\n * so decorations scale across output sizes. Every field except `type` is\n * optional — these per-type defaults apply.\n */\nconst DEFAULTS = {\n glow: { x: 0.5, y: 0.3, size: 0.35, color: \"#FFFFFF\", opacity: 0.5 },\n circle: { x: 0.5, y: 0.3, size: 0.18, color: \"#FFFFFF\", opacity: 0.25 },\n dots: { size: 0.006, spacing: 0.06, color: \"#FFFFFF\", opacity: 0.18 },\n} as const;\n\nexport function drawDecorations(\n ctx: Ctx2D,\n width: number,\n height: number,\n decorations: DecorationConfig[] | undefined,\n): void {\n if (!decorations || decorations.length === 0) return;\n\n for (const deco of decorations) {\n ctx.save();\n if (deco.type === \"glow\") {\n const d = DEFAULTS.glow;\n const cx = (deco.x ?? d.x) * width;\n const cy = (deco.y ?? d.y) * height;\n const r = (deco.size ?? d.size) * width;\n const color = deco.color ?? d.color;\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, r);\n gradient.addColorStop(0, parseHexColor(color));\n gradient.addColorStop(1, parseHexColorWithAlpha(color, 0));\n ctx.globalAlpha = deco.opacity ?? d.opacity;\n ctx.fillStyle = gradient;\n ctx.fillRect(cx - r, cy - r, r * 2, r * 2);\n } else if (deco.type === \"circle\") {\n const d = DEFAULTS.circle;\n const cx = (deco.x ?? d.x) * width;\n const cy = (deco.y ?? d.y) * height;\n const r = (deco.size ?? d.size) * width;\n ctx.globalAlpha = deco.opacity ?? d.opacity;\n ctx.fillStyle = parseHexColor(deco.color ?? d.color);\n ctx.beginPath();\n ctx.arc(cx, cy, r, 0, Math.PI * 2);\n ctx.fill();\n } else {\n // dots — a regular grid across the whole canvas.\n const d = DEFAULTS.dots;\n const r = (deco.size ?? d.size) * width;\n const pitch = (deco.spacing ?? d.spacing) * width;\n ctx.globalAlpha = deco.opacity ?? d.opacity;\n ctx.fillStyle = parseHexColor(deco.color ?? d.color);\n for (let py = pitch / 2; py < height; py += pitch) {\n for (let px = pitch / 2; px < width; px += pitch) {\n ctx.beginPath();\n ctx.arc(px, py, r, 0, Math.PI * 2);\n ctx.fill();\n }\n }\n }\n ctx.restore();\n }\n}\n","import type { BackgroundConfig } from \"../schema.js\";\nimport type { Ctx2D, Gradient2D } from \"../types.js\";\nimport { parseHexColor } from \"../color.js\";\nimport { drawDecorations } from \"./decorations.js\";\n\n/**\n * Port of Swift `BackgroundRenderer`, extended with radial gradients, more\n * linear directions, and decorative shapes.\n *\n * Note on gradient directions: in Swift/CoreGraphics the y-axis points up, so its\n * start/end points read \"inverted\" vs canvas. Working it through, the direction\n * names map cleanly onto canvas top-left coordinates: topToBottom goes y=0→h, etc.\n * colors[0] sits at the start point; remaining colors are evenly distributed\n * (matching CGGradient with `locations: nil`).\n */\nexport function drawBackground(\n ctx: Ctx2D,\n width: number,\n height: number,\n config: BackgroundConfig,\n): void {\n if (config.type === \"solid\") {\n ctx.fillStyle = parseHexColor(config.colors[0] ?? \"#FFFFFF\");\n ctx.fillRect(0, 0, width, height);\n } else if (config.type === \"radial\") {\n // Centered, with the outer stop reaching the canvas corners.\n const cx = width / 2;\n const cy = height / 2;\n const radius = Math.hypot(cx, cy);\n const gradient = ctx.createRadialGradient(cx, cy, 0, cx, cy, radius);\n addStops(gradient, config.colors);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, width, height);\n } else {\n const direction = config.direction ?? \"topToBottom\";\n let x0 = 0;\n let y0 = 0;\n let x1 = 0;\n let y1 = 0;\n switch (direction) {\n case \"topToBottom\":\n x0 = width / 2;\n y0 = 0;\n x1 = width / 2;\n y1 = height;\n break;\n case \"bottomToTop\":\n x0 = width / 2;\n y0 = height;\n x1 = width / 2;\n y1 = 0;\n break;\n case \"leftToRight\":\n x0 = 0;\n y0 = height / 2;\n x1 = width;\n y1 = height / 2;\n break;\n case \"rightToLeft\":\n x0 = width;\n y0 = height / 2;\n x1 = 0;\n y1 = height / 2;\n break;\n case \"topLeftToBottomRight\":\n x0 = 0;\n y0 = 0;\n x1 = width;\n y1 = height;\n break;\n case \"bottomLeftToTopRight\":\n x0 = 0;\n y0 = height;\n x1 = width;\n y1 = 0;\n break;\n }\n\n const gradient = ctx.createLinearGradient(x0, y0, x1, y1);\n addStops(gradient, config.colors);\n ctx.fillStyle = gradient;\n ctx.fillRect(0, 0, width, height);\n }\n\n drawDecorations(ctx, width, height, config.decorations);\n}\n\n/** Distribute colors evenly along a gradient (a single color fills solid). */\nfunction addStops(gradient: Gradient2D, colors: string[]): void {\n if (colors.length === 1) {\n const only = parseHexColor(colors[0]!);\n gradient.addColorStop(0, only);\n gradient.addColorStop(1, only);\n } else {\n colors.forEach((c, i) => {\n gradient.addColorStop(i / (colors.length - 1), parseHexColor(c));\n });\n }\n}\n","import type { DeviceFrameConfig } from \"../schema.js\";\nimport type { Ctx2D, ScreenshotImage } from \"../types.js\";\nimport { parseHexColor } from \"../color.js\";\n\n/** Default look for `deviceFrame.shadow` when fields are omitted (units: canvas-width fractions). */\nconst DEVICE_SHADOW_DEFAULTS = {\n color: \"#00000055\",\n blur: 0.035,\n offsetX: 0,\n offsetY: 0.015,\n} as const;\n\n/** Axis-aligned device bounding box (before rotation) plus its center + rotation. */\nexport interface DeviceRect {\n x: number;\n y: number;\n width: number;\n height: number;\n centerX: number;\n centerY: number;\n rotationDeg: number;\n}\n\n/**\n * Compute the device frame's geometry on a canvas. Single source of truth shared by\n * the renderer and the studio's interactive overlay (hit-testing / handles).\n *\n * - Size: `screenRelativeWidth` × canvas width, with iPhone AR 2.167 / iPad 1.4.\n * - X: `horizontalOffset` × canvas width (left edge); undefined ⇒ horizontally centered.\n * - Y: `verticalOffset` × canvas height (top edge).\n * - Rotation: `rotation` degrees about the device center; undefined ⇒ 0.\n */\nexport function deviceFrameRect(\n canvasWidth: number,\n canvasHeight: number,\n config: DeviceFrameConfig,\n): DeviceRect {\n const cw = canvasWidth;\n const ch = canvasHeight;\n const width = config.screenRelativeWidth * cw;\n const aspectRatio = config.style === \"iPhone\" ? 2.167 : 1.4;\n const height = width * aspectRatio;\n const x = config.horizontalOffset != null ? config.horizontalOffset * cw : (cw - width) / 2;\n const y = config.verticalOffset * ch;\n return {\n x,\n y,\n width,\n height,\n centerX: x + width / 2,\n centerY: y + height / 2,\n rotationDeg: config.rotation ?? 0,\n };\n}\n\n/**\n * Port of Swift `DeviceFrameRenderer`, extended with horizontal offset + rotation.\n *\n * Works in canvas top-left space. The device top is `verticalOffset * canvasHeight`,\n * the left is centered unless `horizontalOffset` is set. When `rotation` is set, the\n * whole device (bezel, screen, Dynamic Island, home indicator) is rotated about its\n * center. Corner radius and bezel width scale relative to a 400pt baseline width.\n */\nexport function drawDeviceFrame(\n ctx: Ctx2D,\n screenshot: ScreenshotImage | null | undefined,\n canvasWidth: number,\n canvasHeight: number,\n config: DeviceFrameConfig,\n): void {\n const rect = deviceFrameRect(canvasWidth, canvasHeight, config);\n const deviceX = rect.x;\n const deviceTop = rect.y;\n const deviceWidth = rect.width;\n const deviceHeight = rect.height;\n\n const scaledCornerRadius = config.cornerRadius * (deviceWidth / 400);\n const scaledBezelWidth = config.bezelWidth * (deviceWidth / 400);\n\n const rotationRad = (rect.rotationDeg * Math.PI) / 180;\n const tiltRad = ((config.tilt ?? 0) * Math.PI) / 180;\n const rotated = rotationRad !== 0;\n const tilted = tiltRad !== 0;\n\n // Outer group: rotation and/or a horizontal shear (pseudo-3D tilt), both\n // about the device center.\n ctx.save();\n if (rotated || tilted) {\n ctx.translate(rect.centerX, rect.centerY);\n if (rotated) ctx.rotate(rotationRad);\n if (tilted) ctx.transform(1, 0, Math.tan(tiltRad), 1, 0, 0);\n ctx.translate(-rect.centerX, -rect.centerY);\n }\n\n // 1. Bezel (outer rounded rect), optionally with a drop shadow underneath.\n // (Canvas shadow offsets ignore the transform, so the light direction stays\n // constant under rotation/tilt — exactly what a real shadow would do.)\n ctx.save();\n if (config.shadow) {\n ctx.shadowColor = parseHexColor(config.shadow.color ?? DEVICE_SHADOW_DEFAULTS.color);\n ctx.shadowBlur = (config.shadow.blur ?? DEVICE_SHADOW_DEFAULTS.blur) * canvasWidth;\n ctx.shadowOffsetX =\n (config.shadow.offsetX ?? DEVICE_SHADOW_DEFAULTS.offsetX) * canvasWidth;\n ctx.shadowOffsetY =\n (config.shadow.offsetY ?? DEVICE_SHADOW_DEFAULTS.offsetY) * canvasWidth;\n }\n ctx.fillStyle = parseHexColor(config.bezelColor);\n ctx.beginPath();\n ctx.roundRect(deviceX, deviceTop, deviceWidth, deviceHeight, scaledCornerRadius);\n ctx.fill();\n ctx.restore();\n\n // 2. Inner screen — clip to a rounded rect, then draw the screenshot (cover or contain fit).\n const innerX = deviceX + scaledBezelWidth;\n const innerY = deviceTop + scaledBezelWidth;\n const innerW = deviceWidth - scaledBezelWidth * 2;\n const innerH = deviceHeight - scaledBezelWidth * 2;\n const innerCornerRadius = Math.max(scaledCornerRadius - scaledBezelWidth, 0);\n\n ctx.save();\n ctx.beginPath();\n ctx.roundRect(innerX, innerY, innerW, innerH, innerCornerRadius);\n ctx.clip();\n\n if (screenshot) {\n const imgW = screenshot.width;\n const imgH = screenshot.height;\n // \"cover\" (default) fills the screen and crops overflow; \"contain\" fits entirely,\n // leaving letterbox gutters that reveal the bezel color drawn behind the clip.\n const scale =\n config.fit === \"contain\"\n ? Math.min(innerW / imgW, innerH / imgH)\n : Math.max(innerW / imgW, innerH / imgH);\n const drawW = imgW * scale;\n const drawH = imgH * scale;\n const drawX = innerX + (innerW - drawW) / 2;\n const drawY = innerY + (innerH - drawH) / 2;\n ctx.drawImage(screenshot.source, drawX, drawY, drawW, drawH);\n }\n ctx.restore();\n\n // 3. Dynamic Island (iPhone only) — near the top of the screen.\n if (config.style === \"iPhone\") {\n const pillWidth = deviceWidth * 0.27;\n const pillHeight = deviceWidth * 0.075;\n const pillX = innerX + innerW / 2 - pillWidth / 2;\n const pillY = innerY + innerH * 0.015;\n ctx.save();\n ctx.fillStyle = \"rgba(0, 0, 0, 1)\";\n ctx.beginPath();\n ctx.roundRect(pillX, pillY, pillWidth, pillHeight, pillHeight / 2);\n ctx.fill();\n ctx.restore();\n }\n\n // 4. Home indicator — near the bottom of the screen.\n const barWidth = deviceWidth * 0.33;\n const barHeight = deviceWidth * 0.012;\n const barX = innerX + innerW / 2 - barWidth / 2;\n const barY = innerY + innerH - innerH * 0.01 - barHeight;\n ctx.save();\n ctx.fillStyle = \"rgba(0, 0, 0, 0.3)\";\n ctx.beginPath();\n ctx.roundRect(barX, barY, barWidth, barHeight, barHeight / 2);\n ctx.fill();\n ctx.restore();\n\n ctx.restore();\n}\n","import type { HeadlineConfig, SubtitleConfig, FontWeightName, ShadowConfig } from \"../schema.js\";\nimport type { Ctx2D } from \"../types.js\";\nimport { parseHexColor } from \"../color.js\";\nimport { cssFont } from \"../fonts.js\";\n\nconst LINE_HEIGHT_MULTIPLE = 1.1; // matches Swift's CTParagraphStyle lineHeightMultiple\n\n/** Default look for headline/subtitle `shadow` (units: canvas-width fractions). */\nconst TEXT_SHADOW_DEFAULTS = {\n color: \"#00000066\",\n blur: 0.012,\n offsetX: 0,\n offsetY: 0,\n} as const;\n\nexport interface TextResult {\n /** Canvas y-coordinate of the bottom of the rendered text block. */\n bottomY: number;\n}\n\n/** Port of Swift `TextRenderer.drawHeadline`. */\nexport function drawHeadline(\n ctx: Ctx2D,\n text: string,\n canvasWidth: number,\n canvasHeight: number,\n config: HeadlineConfig,\n topMarginFraction = 0.035,\n): TextResult {\n const fontSize = config.relativeSize * canvasHeight;\n const topY = topMarginFraction * canvasHeight;\n const maxWidth = canvasWidth * 0.88;\n return drawText(ctx, {\n text,\n fontFamily: config.fontFamily,\n fontWeight: config.fontWeight ?? \"bold\",\n color: config.color,\n fontSize,\n x: (canvasWidth - maxWidth) / 2,\n y: topY,\n maxWidth,\n shadow: config.shadow,\n canvasWidth,\n });\n}\n\n/** Port of Swift `TextRenderer.drawSubtitle`. */\nexport function drawSubtitle(\n ctx: Ctx2D,\n text: string,\n canvasWidth: number,\n canvasHeight: number,\n config: SubtitleConfig,\n belowY: number,\n): TextResult {\n const fontSize = config.relativeSize * canvasHeight;\n const gap = canvasHeight * 0.008;\n const maxWidth = canvasWidth * 0.88;\n return drawText(ctx, {\n text,\n fontFamily: config.fontFamily,\n fontWeight: config.fontWeight ?? \"medium\",\n color: config.color,\n fontSize,\n x: (canvasWidth - maxWidth) / 2,\n y: belowY + gap,\n maxWidth,\n shadow: config.shadow,\n canvasWidth,\n });\n}\n\ninterface DrawTextOptions {\n text: string;\n fontFamily: string | undefined;\n fontWeight: FontWeightName;\n color: string;\n fontSize: number;\n x: number;\n y: number;\n maxWidth: number;\n /** Optional shadow/glow; blur+offsets scale by canvasWidth. */\n shadow?: ShadowConfig;\n canvasWidth: number;\n}\n\n/**\n * Break text into visual lines: respect explicit `\\n` paragraph breaks, then\n * greedily word-wrap each paragraph to `maxWidth`. This mirrors Core Text's\n * framesetter, which wraps on word boundaries to the width constraint. Assumes\n * `ctx.font` is already set.\n */\nfunction layoutLines(ctx: Ctx2D, text: string, maxWidth: number): string[] {\n const out: string[] = [];\n for (const paragraph of text.split(\"\\n\")) {\n const words = paragraph.split(/\\s+/).filter((w) => w.length > 0);\n if (words.length === 0) {\n out.push(\"\");\n continue;\n }\n let line = \"\";\n for (const word of words) {\n const candidate = line ? `${line} ${word}` : word;\n if (line === \"\" || ctx.measureText(candidate).width <= maxWidth) {\n line = candidate;\n } else {\n out.push(line);\n line = word;\n }\n }\n out.push(line);\n }\n return out;\n}\n\n/**\n * Lay out centered, word-wrapped, multi-line text starting at (x, y) (the\n * top-left of the text block) with the same 1.1× line-height as the Swift renderer.\n */\nfunction drawText(ctx: Ctx2D, opts: DrawTextOptions): TextResult {\n const fontSize = opts.fontSize;\n ctx.font = cssFont(opts.fontFamily, opts.fontWeight, fontSize);\n const lines = layoutLines(ctx, opts.text, opts.maxWidth);\n\n const metrics = ctx.measureText(\"Mg\");\n const ascent =\n metrics.fontBoundingBoxAscent ?? metrics.actualBoundingBoxAscent ?? fontSize * 0.8;\n const descent =\n metrics.fontBoundingBoxDescent ?? metrics.actualBoundingBoxDescent ?? fontSize * 0.2;\n const naturalLineHeight = ascent + descent;\n const lineHeight = naturalLineHeight * LINE_HEIGHT_MULTIPLE;\n\n ctx.save();\n if (opts.shadow) {\n ctx.shadowColor = parseHexColor(opts.shadow.color ?? TEXT_SHADOW_DEFAULTS.color);\n ctx.shadowBlur = (opts.shadow.blur ?? TEXT_SHADOW_DEFAULTS.blur) * opts.canvasWidth;\n ctx.shadowOffsetX =\n (opts.shadow.offsetX ?? TEXT_SHADOW_DEFAULTS.offsetX) * opts.canvasWidth;\n ctx.shadowOffsetY =\n (opts.shadow.offsetY ?? TEXT_SHADOW_DEFAULTS.offsetY) * opts.canvasWidth;\n }\n ctx.fillStyle = parseHexColor(opts.color);\n ctx.textAlign = \"center\";\n ctx.textBaseline = \"alphabetic\";\n const centerX = opts.x + opts.maxWidth / 2;\n lines.forEach((line, i) => {\n const baseline = opts.y + ascent + i * lineHeight;\n ctx.fillText(line, centerX, baseline);\n });\n ctx.restore();\n\n return { bottomY: opts.y + lines.length * lineHeight };\n}\n","import type {\n MockupConfig,\n ScreenshotEntry,\n OutputSize,\n BackgroundConfig,\n HeadlineConfig,\n SubtitleConfig,\n DeviceFrameConfig,\n} from \"../schema.js\";\nimport type { Ctx2D, ScreenshotImage } from \"../types.js\";\nimport { drawBackground } from \"./background.js\";\nimport { drawDeviceFrame } from \"./device-frame.js\";\nimport { drawHeadline, drawSubtitle } from \"./text.js\";\n\n/** A fully-resolved, environment-agnostic description of one mockup to render. */\nexport interface RenderScene {\n width: number;\n height: number;\n background: BackgroundConfig;\n headlineText: string;\n headline: HeadlineConfig;\n subtitle?: SubtitleConfig;\n deviceFrame: DeviceFrameConfig;\n screenshot?: ScreenshotImage | null;\n}\n\n/**\n * Render a single mockup into the given context. Layer order matches Swift\n * `MockupRenderer.render`: background → headline → subtitle → device/screenshot\n * (the framed device is drawn last, on top).\n */\nexport function renderMockup(ctx: Ctx2D, scene: RenderScene): void {\n drawBackground(ctx, scene.width, scene.height, scene.background);\n\n const headlineResult = drawHeadline(\n ctx,\n scene.headlineText,\n scene.width,\n scene.height,\n scene.headline,\n );\n\n if (scene.subtitle) {\n drawSubtitle(\n ctx,\n scene.subtitle.text,\n scene.width,\n scene.height,\n scene.subtitle,\n headlineResult.bottomY,\n );\n }\n\n if (scene.screenshot) {\n drawDeviceFrame(ctx, scene.screenshot, scene.width, scene.height, scene.deviceFrame);\n }\n}\n\n/**\n * Resolve a config + screenshot entry + language + size + decoded image into a\n * RenderScene. Shared by the CLI, MCP and web studio so they stay in lock-step.\n */\nexport function resolveScene(\n config: MockupConfig,\n entry: ScreenshotEntry,\n language: string,\n size: OutputSize,\n screenshot: ScreenshotImage | null | undefined,\n): RenderScene {\n return {\n width: size.width,\n height: size.height,\n // A screenshot may carry its own background (incl. decorations), so a set\n // can alternate looks across the store listing.\n background: entry.background ?? config.background,\n headlineText: entry.headlines[language] ?? \"\",\n headline: config.headline,\n subtitle: config.subtitle,\n deviceFrame: config.deviceFrame,\n screenshot,\n };\n}\n\nexport { drawBackground } from \"./background.js\";\nexport { drawDecorations } from \"./decorations.js\";\nexport { drawDeviceFrame, deviceFrameRect } from \"./device-frame.js\";\nexport type { DeviceRect } from \"./device-frame.js\";\nexport { drawHeadline, drawSubtitle } from \"./text.js\";\nexport type { TextResult } from \"./text.js\";\n","import type { MockupConfig } from \"./schema.js\";\n\n/**\n * A demo template = a complete sample project (styled background + frame, a\n * positioned/rotated device, and example screenshots + captions). Surface-agnostic:\n * the studio overlays its own bundled images per template id; MCP/CLI hand back the\n * config for the user to point at their own screenshots.\n */\nexport interface Template {\n id: string;\n name: string;\n description: string;\n /** CSS background used for the picker swatch in the studio. */\n swatch: string;\n config: MockupConfig;\n}\n\nconst STANDARD_SIZES: MockupConfig[\"outputSizes\"] = [\n { name: \"iPhone_6.7\", width: 1290, height: 2796 },\n { name: \"iPhone_6.5\", width: 1242, height: 2688 },\n { name: \"iPad_12.9\", width: 2048, height: 2732 },\n];\n\nexport const TEMPLATES: Template[] = [\n {\n id: \"sunrise\",\n name: \"Sunrise\",\n description: \"Warm cream gradient, navy headline, centered device.\",\n swatch: \"linear-gradient(180deg, #FBF8F2, #F0E4CF)\",\n config: {\n appName: \"Sunrise\",\n outputPrefix: \"sunrise\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"gradient\", colors: [\"#FBF8F2\", \"#F0E4CF\"], direction: \"topToBottom\" },\n headline: { fontWeight: \"bold\", color: \"#1D2939\", relativeSize: 0.05 },\n subtitle: { text: \"Sunrise\", fontWeight: \"medium\", color: \"#C9975B\", relativeSize: 0.025 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#1D2939\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.75,\n verticalOffset: 0.25,\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Start every day\\nwith intention\", de: \"Beginne jeden Tag\\nmit Absicht\", tr: \"Her güne\\nbir niyetle başla\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Build habits\\nthat stick\", de: \"Gewohnheiten,\\ndie bleiben\", tr: \"Kalıcı\\nalışkanlıklar kur\" } },\n { id: \"03\", file: \"screenshots/03.png\", headlines: { en: \"Watch your\\nprogress grow\", de: \"Sieh deinen\\nFortschritt wachsen\", tr: \"İlerlemeni\\nbüyürken gör\" } },\n ],\n },\n },\n {\n id: \"aurora\",\n name: \"Aurora\",\n description: \"Dark gradient, white headline, slight tilt.\",\n swatch: \"linear-gradient(180deg, #0B1220, #1E293B)\",\n config: {\n appName: \"Aurora\",\n outputPrefix: \"aurora\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"gradient\", colors: [\"#0B1220\", \"#1E293B\"], direction: \"topToBottom\" },\n headline: { fontWeight: \"heavy\", color: \"#F8FAFC\", relativeSize: 0.052 },\n subtitle: { text: \"Aurora\", fontWeight: \"medium\", color: \"#7DD3FC\", relativeSize: 0.025 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#0F172A\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.72,\n verticalOffset: 0.27,\n rotation: -4,\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Your night,\\nbeautifully tracked\", de: \"Deine Nacht,\\nschön erfasst\", tr: \"Gecen,\\nzarifçe takip edilir\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Insights that\\nactually help\", de: \"Einblicke, die\\nwirklich helfen\", tr: \"Gerçekten yardımcı\\nolan içgörüler\" } },\n ],\n },\n },\n {\n id: \"ocean\",\n name: \"Ocean\",\n description: \"Blue diagonal gradient, device shifted right and rotated.\",\n swatch: \"linear-gradient(135deg, #0EA5E9, #2563EB)\",\n config: {\n appName: \"Wavelength\",\n outputPrefix: \"wavelength\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"gradient\", colors: [\"#0EA5E9\", \"#2563EB\"], direction: \"topLeftToBottomRight\" },\n headline: { fontWeight: \"bold\", color: \"#FFFFFF\", relativeSize: 0.05 },\n subtitle: { text: \"Wavelength\", fontWeight: \"medium\", color: \"#E0F2FE\", relativeSize: 0.024 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#0C4A6E\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.66,\n verticalOffset: 0.3,\n horizontalOffset: 0.3,\n rotation: 6,\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Ride your\\nfocus flow\", de: \"Reite deinen\\nFokus-Flow\", tr: \"Odak akışına\\nbin\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Deep work,\\nmade simple\", de: \"Tiefe Arbeit,\\neinfach gemacht\", tr: \"Derin çalışma,\\nbasitleştirildi\" } },\n ],\n },\n },\n {\n id: \"minimal\",\n name: \"Minimal\",\n description: \"Clean white, large centered device, no subtitle.\",\n swatch: \"#FFFFFF\",\n config: {\n appName: \"Focus\",\n outputPrefix: \"focus\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"solid\", colors: [\"#FFFFFF\"] },\n headline: { fontWeight: \"bold\", color: \"#111827\", relativeSize: 0.052 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#111827\",\n cornerRadius: 55,\n bezelWidth: 11,\n screenRelativeWidth: 0.82,\n verticalOffset: 0.22,\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Less noise.\\nMore done.\", de: \"Weniger Lärm.\\nMehr geschafft.\", tr: \"Daha az gürültü.\\nDaha çok iş.\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Everything\\nin one place\", de: \"Alles an\\neinem Ort\", tr: \"Her şey\\ntek yerde\" } },\n ],\n },\n },\n {\n id: \"sunset\",\n name: \"Sunset\",\n description: \"Pink-to-amber diagonal, device shifted left and tilted.\",\n swatch: \"linear-gradient(135deg, #FB7185, #F59E0B)\",\n config: {\n appName: \"Ember\",\n outputPrefix: \"ember\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"gradient\", colors: [\"#FB7185\", \"#F59E0B\"], direction: \"topLeftToBottomRight\" },\n headline: { fontWeight: \"heavy\", color: \"#FFFFFF\", relativeSize: 0.05 },\n subtitle: { text: \"Ember\", fontWeight: \"semibold\", color: \"#FFE4E6\", relativeSize: 0.024 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#7F1D1D\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.64,\n verticalOffset: 0.3,\n horizontalOffset: 0.05,\n rotation: -8,\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Make every\\nmoment count\", de: \"Lass jeden\\nMoment zählen\", tr: \"Her anı\\ndeğerli kıl\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Glow up\\nyour routine\", de: \"Bring Glanz in\\ndeine Routine\", tr: \"Rutinine\\nparlaklık kat\" } },\n ],\n },\n },\n {\n id: \"neon\",\n name: \"Neon Glow\",\n description: \"Dark radial background, neon glows, glowing text and device.\",\n swatch: \"radial-gradient(circle, #2E1065, #0F0A1F)\",\n config: {\n appName: \"Neon\",\n outputPrefix: \"neon\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: {\n type: \"radial\",\n colors: [\"#2E1065\", \"#0F0A1F\"],\n decorations: [\n { type: \"glow\", x: 0.22, y: 0.18, size: 0.4, color: \"#8B5CF6\", opacity: 0.55 },\n { type: \"glow\", x: 0.85, y: 0.65, size: 0.45, color: \"#06B6D4\", opacity: 0.4 },\n ],\n },\n headline: {\n fontWeight: \"heavy\",\n color: \"#F5F3FF\",\n relativeSize: 0.052,\n shadow: { color: \"#A78BFAAA\", blur: 0.02 },\n },\n subtitle: {\n text: \"Neon\",\n fontWeight: \"medium\",\n color: \"#C4B5FD\",\n relativeSize: 0.025,\n shadow: { color: \"#A78BFA88\", blur: 0.015 },\n },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#1E1145\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.7,\n verticalOffset: 0.27,\n shadow: { color: \"#8B5CF680\", blur: 0.05, offsetY: 0.01 },\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Turn the lights\\nup on your data\", de: \"Bring Licht\\nin deine Daten\", tr: \"Verilerinin\\nışığını aç\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"After dark,\\nstill in control\", de: \"Nach Einbruch der Nacht\\nweiter im Griff\", tr: \"Gece bile\\nkontrol sende\" } },\n ],\n },\n },\n {\n id: \"glass\",\n name: \"Soft Glass\",\n description: \"Airy light gradient, soft circles, hero drop shadow.\",\n swatch: \"linear-gradient(0deg, #EEF2F7, #DDE5F0)\",\n config: {\n appName: \"Glass\",\n outputPrefix: \"glass\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: {\n type: \"gradient\",\n colors: [\"#EEF2F7\", \"#DDE5F0\"],\n direction: \"bottomToTop\",\n decorations: [\n { type: \"circle\", x: 0.15, y: 0.12, size: 0.22, color: \"#FFFFFF\", opacity: 0.5 },\n { type: \"circle\", x: 0.9, y: 0.5, size: 0.3, color: \"#BFD3EE\", opacity: 0.35 },\n ],\n },\n headline: { fontWeight: \"bold\", color: \"#1E293B\", relativeSize: 0.05 },\n subtitle: { text: \"Glass\", fontWeight: \"medium\", color: \"#3B82F6\", relativeSize: 0.024 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#334155\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.74,\n verticalOffset: 0.25,\n shadow: { color: \"#33415566\", blur: 0.045, offsetY: 0.02 },\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Light as air,\\nclear as glass\", de: \"Leicht wie Luft,\\nklar wie Glas\", tr: \"Hava kadar hafif,\\ncam kadar net\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Calm design,\\nsharp results\", de: \"Ruhiges Design,\\nklare Ergebnisse\", tr: \"Sakin tasarım,\\nkeskin sonuçlar\" } },\n ],\n },\n },\n {\n id: \"pulse\",\n name: \"Bold Pulse\",\n description: \"Three-stop radial burst, black-weight headline, default shadow.\",\n swatch: \"radial-gradient(circle, #F59E0B, #DC2626, #7F1D1D)\",\n config: {\n appName: \"Pulse\",\n outputPrefix: \"pulse\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"radial\", colors: [\"#F59E0B\", \"#DC2626\", \"#7F1D1D\"] },\n headline: {\n fontWeight: \"black\",\n color: \"#FFFFFF\",\n relativeSize: 0.055,\n shadow: { color: \"#00000066\", blur: 0.015, offsetY: 0.004 },\n },\n subtitle: { text: \"Pulse\", fontWeight: \"semibold\", color: \"#FDE68A\", relativeSize: 0.024 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#450A0A\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.7,\n verticalOffset: 0.28,\n shadow: {},\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Feel the beat\\nof your goals\", de: \"Spür den Takt\\ndeiner Ziele\", tr: \"Hedeflerinin\\nritmini hisset\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Push harder.\\nGo further.\", de: \"Gib mehr.\\nKomm weiter.\", tr: \"Daha sıkı çalış.\\nDaha ileri git.\" } },\n ],\n },\n },\n {\n id: \"dotgrid\",\n name: \"Dot Grid\",\n description: \"Minimal paper white with a dot pattern and subtle shadow.\",\n swatch: \"radial-gradient(circle at 30% 30%, #E7E5E4 8%, #FAFAF9 9%)\",\n config: {\n appName: \"Grid\",\n outputPrefix: \"grid\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: {\n type: \"solid\",\n colors: [\"#FAFAF9\"],\n decorations: [\n { type: \"dots\", color: \"#1C1917\", opacity: 0.12, size: 0.005, spacing: 0.05 },\n ],\n },\n headline: { fontWeight: \"bold\", color: \"#1C1917\", relativeSize: 0.052 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#1C1917\",\n cornerRadius: 55,\n bezelWidth: 11,\n screenRelativeWidth: 0.8,\n verticalOffset: 0.22,\n shadow: { color: \"#1C191740\", blur: 0.03, offsetY: 0.012 },\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Ideas on\\na clean grid\", de: \"Ideen auf\\nklarem Raster\", tr: \"Temiz bir ızgarada\\nfikirler\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Structure\\nwithout clutter\", de: \"Struktur\\nohne Ballast\", tr: \"Dağınıklık olmadan\\ndüzen\" } },\n ],\n },\n },\n {\n id: \"momentum\",\n name: \"Momentum\",\n description: \"Diagonal gradient with a tilted, rotated hero device.\",\n swatch: \"linear-gradient(45deg, #0EA5E9, #6366F1)\",\n config: {\n appName: \"Momentum\",\n outputPrefix: \"momentum\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: {\n type: \"gradient\",\n colors: [\"#0EA5E9\", \"#6366F1\"],\n direction: \"bottomLeftToTopRight\",\n decorations: [\n { type: \"glow\", x: 0.8, y: 0.15, size: 0.35, color: \"#38BDF8\", opacity: 0.45 },\n ],\n },\n headline: { fontWeight: \"heavy\", color: \"#FFFFFF\", relativeSize: 0.05 },\n subtitle: { text: \"Momentum\", fontWeight: \"medium\", color: \"#BAE6FD\", relativeSize: 0.024 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#1E1B4B\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.62,\n verticalOffset: 0.3,\n horizontalOffset: 0.22,\n rotation: -6,\n tilt: 10,\n shadow: { color: \"#00000059\", blur: 0.05, offsetX: 0.02, offsetY: 0.02 },\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"Momentum you\\ncan actually see\", de: \"Schwung, den man\\nwirklich sieht\", tr: \"Gerçekten görebileceğin\\nbir ivme\" } },\n { id: \"02\", file: \"screenshots/02.png\", headlines: { en: \"Built for\\nforward motion\", de: \"Gebaut für\\nVorwärtsdrang\", tr: \"İleri hareket için\\ntasarlandı\" } },\n ],\n },\n },\n {\n id: \"spectrum\",\n name: \"Spectrum\",\n description: \"Each screenshot gets its own background color story.\",\n swatch: \"linear-gradient(90deg, #7C3AED, #DB2777, #0891B2)\",\n config: {\n appName: \"Spectrum\",\n outputPrefix: \"spectrum\",\n languages: [\"en\", \"de\", \"tr\"],\n outputSizes: STANDARD_SIZES,\n background: { type: \"gradient\", colors: [\"#7C3AED\", \"#DB2777\"], direction: \"topToBottom\" },\n headline: { fontWeight: \"bold\", color: \"#FFFFFF\", relativeSize: 0.05 },\n subtitle: { text: \"Spectrum\", fontWeight: \"medium\", color: \"#FBCFE8\", relativeSize: 0.024 },\n deviceFrame: {\n style: \"iPhone\",\n bezelColor: \"#3B0764\",\n cornerRadius: 55,\n bezelWidth: 12,\n screenRelativeWidth: 0.72,\n verticalOffset: 0.26,\n shadow: {},\n },\n screenshots: [\n { id: \"01\", file: \"screenshots/01.png\", headlines: { en: \"A color for\\nevery mood\", de: \"Eine Farbe für\\njede Stimmung\", tr: \"Her ruh haline\\nbir renk\" } },\n {\n id: \"02\",\n file: \"screenshots/02.png\",\n headlines: { en: \"Switch scenes,\\nkeep the flow\", de: \"Szenen wechseln,\\nim Fluss bleiben\", tr: \"Sahne değiştir,\\nakışı koru\" },\n background: {\n type: \"gradient\",\n colors: [\"#0891B2\", \"#2563EB\"],\n direction: \"topToBottom\",\n decorations: [\n { type: \"glow\", x: 0.5, y: 0.2, size: 0.35, color: \"#67E8F9\", opacity: 0.4 },\n ],\n },\n },\n ],\n },\n },\n];\n\n/** Look up a template by id. */\nexport function getTemplate(id: string): Template | undefined {\n return TEMPLATES.find((t) => t.id === id);\n}\n","import type { MockupConfig, BackgroundConfig } from \"./schema.js\";\n\n/**\n * An accent color theme: a harmonious palette applied over an existing config.\n * Themes recolor (background colors, text colors, bezel, decoration accents)\n * but never touch layout — device position/size/rotation, text sizes, gradient\n * type/direction, decoration geometry and shadows all stay as they are.\n */\nexport interface AccentTheme {\n id: string;\n name: string;\n /** CSS background used for the picker chip in the studio. */\n swatch: string;\n /** Gradient stops; a solid background uses only the first entry. */\n backgroundColors: string[];\n headlineColor: string;\n subtitleColor: string;\n bezelColor: string;\n /** Applied to background decoration colors. */\n accent: string;\n}\n\nexport const THEMES: AccentTheme[] = [\n {\n id: \"indigo\",\n name: \"Indigo Night\",\n swatch: \"linear-gradient(135deg, #1E1B4B, #312E81)\",\n backgroundColors: [\"#1E1B4B\", \"#312E81\"],\n headlineColor: \"#EEF2FF\",\n subtitleColor: \"#A5B4FC\",\n bezelColor: \"#171532\",\n accent: \"#818CF8\",\n },\n {\n id: \"emerald\",\n name: \"Emerald\",\n swatch: \"linear-gradient(135deg, #064E3B, #059669)\",\n backgroundColors: [\"#064E3B\", \"#059669\"],\n headlineColor: \"#ECFDF5\",\n subtitleColor: \"#6EE7B7\",\n bezelColor: \"#022C22\",\n accent: \"#34D399\",\n },\n {\n id: \"coral\",\n name: \"Coral Pop\",\n swatch: \"linear-gradient(135deg, #9F1239, #FB7185)\",\n backgroundColors: [\"#9F1239\", \"#FB7185\"],\n headlineColor: \"#FFF1F2\",\n subtitleColor: \"#FECDD3\",\n bezelColor: \"#4C0519\",\n accent: \"#FDA4AF\",\n },\n {\n id: \"violet\",\n name: \"Neon Violet\",\n swatch: \"linear-gradient(135deg, #0F0A1F, #2E1065)\",\n backgroundColors: [\"#0F0A1F\", \"#2E1065\"],\n headlineColor: \"#F5F3FF\",\n subtitleColor: \"#C4B5FD\",\n bezelColor: \"#1E1145\",\n accent: \"#A78BFA\",\n },\n {\n id: \"sand\",\n name: \"Warm Sand\",\n swatch: \"linear-gradient(135deg, #FAF5EF, #EAD9C2)\",\n backgroundColors: [\"#FAF5EF\", \"#EAD9C2\"],\n headlineColor: \"#292524\",\n subtitleColor: \"#B45309\",\n bezelColor: \"#292524\",\n accent: \"#D6A662\",\n },\n {\n id: \"slate\",\n name: \"Slate Mono\",\n swatch: \"linear-gradient(135deg, #F8FAFC, #E2E8F0)\",\n backgroundColors: [\"#F8FAFC\", \"#E2E8F0\"],\n headlineColor: \"#0F172A\",\n subtitleColor: \"#64748B\",\n bezelColor: \"#0F172A\",\n accent: \"#94A3B8\",\n },\n];\n\n/** Look up a theme by id. */\nexport function getTheme(id: string): AccentTheme | undefined {\n return THEMES.find((t) => t.id === id);\n}\n\n/** Recolor one background config (fill colors + decoration accents). */\nfunction themeBackground(bg: BackgroundConfig, theme: AccentTheme): BackgroundConfig {\n return {\n ...bg,\n colors: bg.type === \"solid\" ? [theme.backgroundColors[0]!] : [...theme.backgroundColors],\n decorations: bg.decorations?.map((d) => ({ ...d, color: theme.accent })),\n };\n}\n\n/**\n * Apply a theme to a config: pure — returns a new config, never mutates the\n * input. Only colors change (background stops, decoration accents, headline,\n * subtitle if present, bezel, and any per-screenshot background overrides);\n * layout, sizes, gradient type/direction and shadows are untouched.\n */\nexport function applyTheme(config: MockupConfig, theme: AccentTheme): MockupConfig {\n return {\n ...config,\n background: themeBackground(config.background, theme),\n headline: { ...config.headline, color: theme.headlineColor },\n subtitle: config.subtitle\n ? { ...config.subtitle, color: theme.subtitleColor }\n : undefined,\n deviceFrame: { ...config.deviceFrame, bezelColor: theme.bezelColor },\n screenshots: config.screenshots.map((s) =>\n s.background ? { ...s, background: themeBackground(s.background, theme) } : s,\n ),\n };\n}\n"],"mappings":"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","names":[]}
|