export interface Design { /** Schema version for compatibility / migration. */ schemaVersion: number; /** Canvas width in pixels. */ width: number; /** Canvas height in pixels. */ height: number; /** Unit type for print measurements. */ unit: 'px' | 'pt' | 'mm' | 'cm' | 'in'; /** Dots per inch for print calculations. */ dpi: number; /** Arbitrary client data attached to the design. */ custom?: unknown; /** Fonts used in the design. */ fonts: Font[]; /** Pages in the design. */ pages: Page[]; /** Audio tracks in the design. */ audios: Audio[]; } export interface FontStyleVariant { /** Font source, typically in CSS `url(...)` form. */ src: string; /** CSS font style: 'normal' or 'italic'. */ fontStyle?: string; /** CSS font weight: 'normal', 'bold', or numeric string. */ fontWeight?: string; } export interface Font { /** Font family name. */ fontFamily: string; /** URL to load the font from (single-variant fonts). Defaults to ''. */ url: string; /** Per-weight/style variants (multi-variant families). */ styles?: FontStyleVariant[]; } export interface Audio { /** Unique identifier. */ id: string; /** Display name shown on the timeline. */ name: string; /** URL or data URI of the audio file. */ src: string; /** Duration in milliseconds. */ duration: number; /** Start offset (0-1). */ startTime: number; /** End offset (0-1). */ endTime: number; /** Volume (0-1). */ volume: number; /** Delay before playing, in milliseconds. */ delay: number; /** Playback speed multiplier (1 = normal). */ speed: number; /** Arbitrary client data. */ custom?: unknown; } export interface Page { /** Unique identifier. */ id: string; /** Page width in pixels or 'auto' (inherit from design). */ width: number | 'auto'; /** Page height in pixels or 'auto' (inherit from design). */ height: number | 'auto'; /** Background color or image. */ background: string; /** Bleed area in pixels for print (all sides; base value for per-side overrides). */ bleed: number; /** Per-side bleed override (top), in pixels. Inherits `bleed` when omitted. */ bleedTop?: number; /** Per-side bleed override (right), in pixels. Inherits `bleed` when omitted. */ bleedRight?: number; /** Per-side bleed override (bottom), in pixels. Inherits `bleed` when omitted. */ bleedBottom?: number; /** Per-side bleed override (left), in pixels. Inherits `bleed` when omitted. */ bleedLeft?: number; /** Arbitrary client data. */ custom?: unknown; /** Page duration in milliseconds. */ duration: number; /** Elements on this page. */ children: Element[]; } export type Element = TextElement | ImageElement | SVGElement | LineElement | VideoElement | FigureElement | GifElement | GroupElement | TableElement; export type ElementType = Element['type']; export interface Animation { /** Delay before the animation starts, in milliseconds. */ delay: number; /** Animation duration in milliseconds. */ duration: number; /** Whether the animation is enabled. */ enabled: boolean; /** Animation phase. */ type: 'enter' | 'exit' | 'loop'; /** Animation name identifier. */ name: string; /** Animation-specific data. */ data: unknown; } /** Properties shared by all non-group elements. */ export interface ShapeAttributes { /** Unique identifier. */ id: string; /** Element type identifier. */ type: string; /** Display name (defaults to ''). */ name: string; /** Arbitrary client data. */ custom?: unknown; /** X position in pixels. */ x: number; /** Y position in pixels. */ y: number; /** Width in pixels. */ width: number; /** Height in pixels. */ height: number; /** Rotation in degrees. */ rotation: number; /** Opacity (0-1). */ opacity: number; /** Animation configurations. */ animations: Animation[]; blurEnabled: boolean; blurRadius: number; brightnessEnabled: boolean; brightness: number; sepiaEnabled: boolean; grayscaleEnabled: boolean; /** Applied image filters keyed by filter name. */ filters: Record; shadowEnabled: boolean; shadowBlur: number; shadowOffsetX: number; shadowOffsetY: number; shadowColor: string; shadowOpacity: number; visible: boolean; draggable: boolean; resizable: boolean; selectable: boolean; removable: boolean; contentEditable: boolean; styleEditable: boolean; alwaysOnTop: boolean; showInExport: boolean; } export interface GroupElement { id: string; type: 'group'; /** Display name (defaults to ''). */ name: string; custom?: unknown; opacity: number; visible: boolean; selectable: boolean; removable: boolean; alwaysOnTop: boolean; showInExport: boolean; animations: Animation[]; /** Child elements in this group. */ children: Element[]; } export interface TextElement extends ShapeAttributes { type: 'text'; /** Visible text shown on canvas. */ text: string; /** Placeholder text shown when empty. */ placeholder: string; fontSize: number; fontFamily: string; /** 'normal' or 'italic'. */ fontStyle: string; /** 'normal', 'bold', or numeric string. */ fontWeight: string; textDecoration: string; textTransform: string; /** Text color. */ fill: string; /** Horizontal alignment (commonly left | center | right | justify). */ align: string; verticalAlign: string; strokeWidth: number; stroke: string; /** Stroke corner join: round, miter, bevel. */ strokeLineJoin: string; /** Line height as a number multiplier or 'auto'. */ lineHeight: number | string; /** Letter spacing as a fraction of font size. */ letterSpacing: number; backgroundEnabled: boolean; backgroundColor: string; backgroundOpacity: number; backgroundCornerRadius: number; backgroundPadding: number; curveEnabled: boolean; curvePower: number; /** Internal compatibility flag stamped by the v2→v3 migration. */ legacyBackground?: boolean; } /** Image-like crop/border properties shared by image, gif, and video. */ export interface BaseImageProps { /** URL or data URI of the source. */ src: string; /** Crop X offset (0-1). */ cropX: number; /** Crop Y offset (0-1). */ cropY: number; /** Crop width (0-1). */ cropWidth: number; /** Crop height (0-1). */ cropHeight: number; cornerRadius: number; flipX: boolean; flipY: boolean; /** URL or data URI of a clipping mask. */ clipSrc: string; borderColor: string; borderSize: number; keepRatio: boolean; stretchEnabled: boolean; } export interface ImageElement extends ShapeAttributes, BaseImageProps { type: 'image'; } export interface SVGElement extends ShapeAttributes { type: 'svg'; src: string; maskSrc: string; cropX: number; cropY: number; cropWidth: number; cropHeight: number; keepRatio: boolean; stretchEnabled: boolean; flipX: boolean; flipY: boolean; borderColor: string; borderSize: number; cornerRadius: number; /** Color replacement mappings (original → replacement). */ colorsReplace: Record; } export interface LineElement extends ShapeAttributes { type: 'line'; color: string; /** Dash pattern array. */ dash: number[]; /** Start arrow head: empty, arrow, circle, square, bar. */ startHead: string; /** End arrow head: empty, arrow, circle, square, bar. */ endHead: string; } export interface FigureElement extends ShapeAttributes { type: 'figure'; /** Figure subtype: rect, ellipse, triangle, etc. */ subType: string; fill: string; dash: number[]; strokeWidth: number; stroke: string; cornerRadius: number; } export interface GifElement extends ShapeAttributes, BaseImageProps { type: 'gif'; /** Duration in milliseconds. */ duration: number; } export interface VideoElement extends ShapeAttributes, BaseImageProps { type: 'video'; /** Duration in milliseconds. */ duration: number; /** Start offset (0-1). */ startTime: number; /** End offset (0-1). */ endTime: number; /** Volume (0-1). */ volume: number; /** Playback speed multiplier (1 = normal). */ speed: number; } export interface BorderSide { /** Border color; inherits from the table when omitted. */ color?: string; /** Border width in pixels; inherits from the table when omitted. */ width?: number; /** Border style; inherits from the table when omitted. */ style?: 'solid' | 'dashed' | 'dotted' | 'none'; } export interface CellBorders { top?: BorderSide; right?: BorderSide; bottom?: BorderSide; left?: BorderSide; } export interface TableCell { id: string; type: 'tablecell'; text: string; opacity?: number; rowSpan?: number; colSpan?: number; /** Id of the cell this one is merged into (hidden when set). */ mergedInto?: string; name?: string; custom?: unknown; /** Per-side border overrides; absent sides inherit from the table. */ borders?: CellBorders; fontSize?: number; fontFamily?: string; fontWeight?: string; fontStyle?: string; textDecoration?: string; textTransform?: string; fill?: string; align?: string; verticalAlign?: string; lineHeight?: number | string; letterSpacing?: number; strokeWidth?: number; stroke?: string; cellBackground?: string; cellPadding?: number; } /** * Table element. Shadow / blur / brightness / sepia / grayscale / filter * properties are stripped from the serialized table, so they're omitted here. */ export interface TableElement extends Omit { type: 'table'; rows: number; cols: number; /** Column width fractions (sum to 1). */ colWidths: number[]; /** Row height fractions (sum to 1). */ rowHeights: number[]; /** Flat cell array in row-major order (length = rows * cols). */ cells: TableCell[]; borderColor: string; borderWidth: number; borderStyle: 'solid' | 'dashed' | 'dotted' | 'none'; fontSize: number; fontFamily: string; fontWeight: string; fontStyle: string; textDecoration: string; textTransform: string; fill: string; align: string; verticalAlign: string; lineHeight: number | string; letterSpacing: number; strokeWidth: number; stroke: string; cellBackground: string; cellPadding: number; }