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 rowThis 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:
- Figma starts with a base horizontal gradient (left to right)
- The transformation matrix rotates, scales, and translates this base gradient
- 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/helpersPractical 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
- MDN - Transform Matrix - CSS perspective on matrices
- SVG gradientTransform - Similar concept in SVG
- 3Blue1Brown - Essence of Linear Algebra - Visual intuition for transformations
- Khan Academy - Linear Algebra - Formal mathematical foundation
Interactive Tools
- Desmos Graphing Calculator - Visualize matrix transformations
Key Takeaways
- Figma gradient transforms are 3x2 affine matrices - Not simple coordinate pairs
- Use the official helpers - Don't try to parse matrices manually
- Think in normalized space - Everything is 0 to 1, relative to bounding box
- Gradients are transformed lines - Not just start/end points
- 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.
.png)


![What if you swam in a nuclear storage pool? [video]](https://www.youtube.com/img/desktop/supported_browsers/chrome.png)