/** * Narrow Figma REST types — we only model the fields we actually consume. * The full Figma schema is enormous; typing it wholesale is a liability. * * Reference: https://www.figma.com/developers/api (spot-check before wide changes). */ // -------------------------------------------------------------------------- // // REST response shapes (partial, on-demand) // -------------------------------------------------------------------------- // export interface FigmaColor { r: number; g: number; b: number; a: number; } export interface FigmaBoundingBox { x: number; y: number; width: number; height: number; } export interface FigmaPaint { type: string; // SOLID, GRADIENT_LINEAR, IMAGE, ... visible?: boolean; opacity?: number; color?: FigmaColor; gradientStops?: Array<{ position: number; color: FigmaColor }>; imageRef?: string; } export interface FigmaTypeStyle { fontFamily?: string; fontWeight?: number; fontSize?: number; lineHeightPx?: number; lineHeightPercent?: number; letterSpacing?: number; textCase?: string; textAlignHorizontal?: string; textAlignVertical?: string; } export interface FigmaNode { id: string; name: string; type: string; // DOCUMENT, CANVAS, FRAME, GROUP, TEXT, RECTANGLE, ... visible?: boolean; children?: FigmaNode[]; absoluteBoundingBox?: FigmaBoundingBox; constraints?: { vertical: string; horizontal: string }; // Auto-layout layoutMode?: "NONE" | "HORIZONTAL" | "VERTICAL"; primaryAxisAlignItems?: string; counterAxisAlignItems?: string; itemSpacing?: number; paddingTop?: number; paddingRight?: number; paddingBottom?: number; paddingLeft?: number; // Visuals fills?: FigmaPaint[]; strokes?: FigmaPaint[]; strokeWeight?: number; cornerRadius?: number; rectangleCornerRadii?: [number, number, number, number]; opacity?: number; // Text characters?: string; style?: FigmaTypeStyle; // Components componentId?: string; componentPropertyReferences?: Record; // eslint-disable-next-line @typescript-eslint/no-explicit-any componentProperties?: Record; } export interface FigmaComponent { key: string; name: string; description?: string; componentSetId?: string; } export interface FigmaStyle { key: string; name: string; description?: string; styleType: "FILL" | "TEXT" | "EFFECT" | "GRID"; } export interface FigmaFileResponse { name: string; lastModified: string; version: string; role?: string; editorType?: string; document: FigmaNode; components?: Record; componentSets?: Record; styles?: Record; thumbnailUrl?: string; } export interface FigmaNodesResponse { name: string; lastModified: string; version: string; nodes: Record; styles?: Record } | null>; } // -------------------------------------------------------------------------- // // Compact shapes we emit to the LLM. Hex colors, array bboxes, no noise. // -------------------------------------------------------------------------- // export interface CompactNode { id: string; name: string; type: string; /** [x, y, w, h], rounded to ints. Omitted if absent. */ bbox?: [number, number, number, number]; /** Auto-layout direction when set. */ layout?: "H" | "V"; /** [top, right, bottom, left] only if any > 0. */ padding?: [number, number, number, number]; /** itemSpacing only if > 0. */ gap?: number; /** corner radius or [tl,tr,br,bl]. */ radius?: number | [number, number, number, number]; /** First visible solid fill as hex/rgba. */ fill?: string; /** First stroke as hex/rgba + weight. */ stroke?: { color: string; width: number }; /** Opacity if < 1. */ opacity?: number; /** Text content (TEXT nodes only). */ text?: string; /** Compact text style for TEXT nodes. */ textStyle?: { font?: string; size?: number; weight?: number; lineHeight?: number }; /** Component reference on INSTANCE nodes. */ component?: string; /** Children — only present if caller asked for them. */ children?: CompactNode[]; /** Count of descendants dropped because we hit the depth limit. */ truncatedChildren?: number; } export interface TokenBundle { colors: Array<{ name: string; value: string; description?: string }>; text: Array<{ name: string; description?: string; font?: string; size?: number; weight?: number; lineHeight?: number; }>; effects: Array<{ name: string; description?: string }>; grids: Array<{ name: string; description?: string }>; }