/** * Pure, synchronous math helpers for Figma gradient geometry and blend-mode * normalisation. No DOM, no CSS, no network. * * Supports two gradient-transform sources: * - REST API `gradientHandlePositions` (3-element Vec2 array, already in * normalized 0..1 node-space). * - 2×3 affine transform in **either** the Kiwi/fig-file object form * `{m00..m12}` or the REST/Plugin API array form `[[a,b,tx],[c,d,ty]]`. * Both encode the **node-to-gradient** mapping (same convention as Figma's * own `gradientTransform` field); invert to obtain handle positions. */ export interface Vec2 { x: number; y: number; } export interface GradientHandles { start: Vec2; end: Vec2; width: Vec2; } /** * 2×3 affine transform in the row-major object form used by Kiwi/fig-file * decoded paint nodes: * [m00, m01, m02] * [m10, m11, m12] */ export interface Mat2x3Object { m00: number; m01: number; m02: number; m10: number; m11: number; m12: number; } /** * 2×3 affine transform in the nested-array form used by the Figma REST API * and Plugin API `gradientTransform` field: * [[a, b, tx], [c, d, ty]] */ export type Mat2x3Array = [[number, number, number], [number, number, number]]; export type BlendVerdict = "exact" | "approximated"; export interface BlendModeResult { cssMode: string; verdict: BlendVerdict; } export type GradientKind = "LINEAR" | "RADIAL" | "ANGULAR" | "DIAMOND"; export interface GradientGeometry { kind: GradientKind; handles: GradientHandles; start: Vec2; end: Vec2; center: Vec2; rx: number; ry: number; rotationDeg: number; fromDeg: number; } /** Convert the REST/Plugin nested-array form to the object form. */ export declare function mat2x3FromArray(m: Mat2x3Array): Mat2x3Object; /** * Invert a 2×3 affine transform. Returns null when the matrix is singular * (determinant near zero, i.e. the gradient has collapsed to a line or point). * * The 2×2 rotation/scale sub-matrix is [[m00,m01],[m10,m11]]; the * standard 2×2 inverse is applied and the translation is back-solved: * inv_tx = (-m11*m02 + m01*m12) / det * inv_ty = ( m10*m02 - m00*m12) / det */ export declare function invert2x3(m: Mat2x3Object): Mat2x3Object | null; /** * Derive REST-style `GradientHandles` from a 2×3 **node-to-gradient** * transform in Kiwi/fig-file object form. * * Figma's gradient transform encodes where the gradient's natural coordinate * system sits inside the node's normalized [0,1]² box. The three canonical * gradient-space points (start, end, width) map back to node-space by * inverting the transform: * handles = inv(M) * {(0,0), (1,0), (0,1)} */ export declare function handlePositionsFromObjectTransform(t: Mat2x3Object): GradientHandles | null; export declare function gradientGeometryFromTransform(kind: GradientKind, transform: Mat2x3Object, box: { width: number; height: number; }): GradientGeometry | null; /** * Derive REST-style `GradientHandles` from a 2×3 **node-to-gradient** * transform in REST/Plugin API nested-array form. */ export declare function handlePositionsFromArrayTransform(t: Mat2x3Array): GradientHandles | null; /** * Resolve `GradientHandles` from a raw `gradientHandlePositions` array as * returned by the Figma REST API. Returns null when the array is too short. */ export declare function resolveGradientHandles(gradientHandlePositions: Array | undefined): GradientHandles | null; /** * Derive a CSS `linear-gradient()` angle (degrees) from Figma's normalized * `gradientHandlePositions`. Handle positions are normalized independently in * x and y (0..1 relative to the node's bounding box), so the angle must be * computed in actual pixel space using the node's real width/height — * otherwise a non-square box silently distorts the angle. * * Identity: left-to-right handles (start=(0,0.5), end=(1,0.5)) → 90 deg. * Top-to-bottom handles (start=(0.5,0), end=(0.5,1)) → 180 deg. * * This is the same function previously inlined in figma-node-to-html.ts and * is preserved here verbatim for public API compatibility. */ export declare function gradientAngleDegrees(paint: { gradientHandlePositions?: Array; }, box: { width: number; height: number; }): number | null; /** * Same calculation as `gradientAngleDegrees` but accepts already-resolved * `GradientHandles` — useful when handles come from a transform inversion. */ export declare function gradientAngleDegreesFromHandles(handles: GradientHandles, box: { width: number; height: number; }): number; /** * CSS `linear-gradient(angle, ...)` always stretches its 0%/100% stops across * the box's full diagonal at that angle (the CSS "gradient line" always spans * corner-to-corner). Figma's stop positions are fractions of the literal * handle-to-handle distance, which only coincides with the CSS span when the * handles are dragged exactly corner-to-corner. * * This function returns a remap closure that projects each Figma stop's real * pixel position onto the CSS gradient line and re-expresses it as a * percentage of the CSS line's length, so a partial/offset gradient renders at * the same pixel positions Figma draws it at. */ export declare function remapLinearStopPosition(handles: GradientHandles, box: { width: number; height: number; }, angleDeg: number): (position: number) => number; /** * Euclidean distance between two normalized-coordinate points after scaling * into actual pixel space. */ export declare function vectorLength(from: Vec2, to: Vec2, box: { width: number; height: number; }): number; /** * Map a Figma blend mode string to a CSS `mix-blend-mode` value with an * explicit fidelity verdict: * - `"exact"` — CSS supports the mode natively. * - `"approximated"` — mapped to the closest CSS equivalent. * * Returns `null` for `PASS_THROUGH`, `NORMAL`, and unrecognised modes (caller * should omit the CSS property entirely in those cases). */ export declare function cssBlendMode(figmaBlendMode: string): BlendModeResult | null; //# sourceMappingURL=figma-paint-math.d.ts.map