TIL: Figma provides a helper function for gradient transforms

3 hours ago 1

If you've ever tried to extract gradient data from Figma's API, you've probably encountered cryptic transformation matrices like [[-0.5, 0.5, 0.5], [-0.5, -0.5, 1]] and wondered what on earth these numbers mean. After diving deep into this rabbit hole, I'm here to save you the hours of confusion I went through.

The Problem

When you fetch a gradient from Figma's API, you get something like this:

{ type: 'GRADIENT_LINEAR', gradientTransform: [ [-0.08691141754388809, 0.09161579608917236, 0.5163052678108215], [-0.09161579608917236, -0.08691141754388809, 0.5846190452575684] ], gradientStops: [ { color: { r: 0, g: 0, b: 0, a: 1 }, position: 0 }, { color: { r: 1, g: 1, b: 1, a: 1 }, position: 1 } ] }

Those gradientTransform values? They're not pixel coordinates. They're not percentages. They're not even directly related to where you placed the gradient handles in Figma. They're a 3x2 affine transformation matrix.

Understanding the Matrix

Each gradient transform consists of two rows with three values each:

[a, b, tx] // First row [c, d, ty] // Second row

This matrix transforms gradient coordinates through:

  • a, d: Scaling factors
  • b, c: Rotation and skew
  • tx, ty: Translation (position offset)

The gradient operates in a normalized coordinate space where:

  • (0, 0) = top-left of the bounding box
  • (1, 1) = bottom-right of the bounding box

The Gotcha: It's Not What You Think

Here's what tripped me up: the gradient handles you see in Figma don't directly map to these transform values. Instead:

  1. Figma starts with a base horizontal gradient (left to right)
  2. The transformation matrix rotates, scales, and translates this base gradient
  3. The final position is where your gradient ends up

For example, a diagonal gradient that looks centered might have ty = 0.96 because the transformation needs to compensate for the rotation to keep the gradient visually centered.

The Solution: Figma's Helper Functions

Thankfully, Figma provides an official helper that makes this manageable:

import { extractLinearGradientParamsFromTransform } from "@figma-plugin/helpers"; // Convert matrix to readable handle positions const params = extractLinearGradientParamsFromTransform(gradientTransform); // Returns: { start: {x, y}, end: {x, y}, width } // Now you have intuitive values! console.log(`Gradient from ${params.start.x},${params.start.y} to ${params.end.x},${params.end.y}`);

Install it with:

npm install @figma-plugin/helpers

Practical Examples

Converting to CSS

Here's a complete function to convert Figma gradients to CSS:

function figmaGradientToCSS(paint, elementWidth = 100, elementHeight = 100) { const { extractLinearGradientParamsFromTransform } = require('@figma-plugin/helpers'); const params = extractLinearGradientParamsFromTransform(paint.gradientTransform); // Calculate angle from start/end points const dx = params.end.x - params.start.x; const dy = params.end.y - params.start.y; const angle = Math.atan2(dy * elementHeight, dx * elementWidth) * 180 / Math.PI; // Convert color stops to CSS format const stops = paint.gradientStops.map(stop => { const r = Math.round(stop.color.r * 255); const g = Math.round(stop.color.g * 255); const b = Math.round(stop.color.b * 255); const a = stop.color.a; return `rgba(${r}, ${g}, ${b}, ${a}) ${stop.position * 100}%`; }); return `linear-gradient(${angle}deg, ${stops.join(', ')})`; }

Understanding Different Gradient Types

Through experimentation, here's what different gradient configurations look like:

// Horizontal gradient (left to right) // Transform: [[1, 0, 0], [0, 1, 0]] // Extracted: { start: {x: 0, y: 0.5}, end: {x: 1, y: 0.5} } // Vertical gradient (top to bottom) // Transform: [[0, 1, 0], [-1, 0, 1]] // Extracted: { start: {x: 0.5, y: 0}, end: {x: 0.5, y: 1} } // Diagonal gradient // Transform: [[-0.5, 0.5, 0.5], [-0.5, -0.5, 1]] // Extracted: { start: {x: 0, y: 1}, end: {x: 1, y: 0} }

Working with "Out of Bounds" Gradients

Sometimes you'll see gradients that extend beyond the shape boundaries. These have smaller scale values in the transform matrix:

// Gradient extends beyond bounds // Transform has small scale factors like 0.09 // This creates softer, more subtle transitions function isGradientOutOfBounds(transform) { const params = extractLinearGradientParamsFromTransform(transform); return params.width > 1.5; // Arbitrary threshold }

Creating Gradients Programmatically

If you need to create gradient transforms:

// Hypothetical function (check if Figma provides this) import { createLinearGradientTransform } from "@figma-plugin/helpers"; const transform = createLinearGradientTransform( { x: 0, y: 0 }, // start point { x: 1, y: 1 }, // end point 1.0 // width/scale );

Resources for Going Deeper

Figma-Specific

Understanding Transformation Matrices

Interactive Tools

Key Takeaways

  1. Figma gradient transforms are 3x2 affine matrices - Not simple coordinate pairs
  2. Use the official helpers - Don't try to parse matrices manually
  3. Think in normalized space - Everything is 0 to 1, relative to bounding box
  4. Gradients are transformed lines - Not just start/end points
  5. Out-of-bounds is normal - Smaller scale factors = gradient extends beyond shape

Troubleshooting Checklist

  • ✅ Installed @figma-plugin/helpers?
  • ✅ Using extractLinearGradientParamsFromTransform()?
  • ✅ Converting colors from 0-1 to 0-255 for CSS?
  • ✅ Calculating angles correctly for CSS gradients?
  • ✅ Handling gradient stops positions (0-1 to percentages)?

Final Thoughts

Working with Figma gradients programmatically can be frustrating at first, but once you understand that these transforms are standard affine matrices and use the right helper functions, it becomes manageable. The key is not trying to manually interpret the matrix values - let Figma's helpers do the heavy lifting.

Read Entire Article