Skip to content

Commit 353a937

Browse files
committed
Improve gradients
1 parent bfa2da4 commit 353a937

13 files changed

Lines changed: 3323 additions & 266 deletions

File tree

packages/backend/src/code.ts

Lines changed: 3102 additions & 16 deletions
Large diffs are not rendered by default.

packages/backend/src/common/color.ts

Lines changed: 16 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -59,42 +59,24 @@ export const rgbToCssColor = (color: RGB | RGBA, alpha: number = 1): string => {
5959

6060
// ---- Gradient Transformation ----
6161
export const gradientAngle = (fill: GradientPaint): number => {
62-
// Thanks Gleb and Liam for helping!
63-
const decomposed = decomposeRelativeTransform(
64-
fill.gradientTransform[0],
65-
fill.gradientTransform[1],
66-
);
67-
68-
return (decomposed.rotation * 180) / Math.PI;
69-
};
70-
71-
// Calculate gradient angle for CSS (different coordinate system)
72-
export const cssGradientAngle = (angle: number): number => {
73-
// Normalize angle: if negative, add 360 to make it positive.
74-
return angle < 0 ? angle + 360 : angle;
62+
const [start, end] = fill.gradientHandlePositions;
63+
return calculateAngle(start, end);
7564
};
7665

77-
// Calculate gradient coordinates for a matrix transform
78-
export const getGradientTransformCoordinates = (
79-
gradientTransform: number[][],
80-
): { centerX: string; centerY: string; radiusX: string; radiusY: string } => {
81-
const a = gradientTransform[0][0];
82-
const b = gradientTransform[0][1];
83-
const c = gradientTransform[1][0];
84-
const d = gradientTransform[1][1];
85-
const e = gradientTransform[0][2];
86-
const f = gradientTransform[1][2];
87-
88-
const scaleX = Math.sqrt(a ** 2 + b ** 2);
89-
const scaleY = Math.sqrt(c ** 2 + d ** 2);
90-
91-
const centerX = ((e * scaleX * 100) / (1 - scaleX)).toFixed(2);
92-
const centerY = (((1 - f) * scaleY * 100) / (1 - scaleY)).toFixed(2);
93-
94-
const radiusX = (scaleX * 100).toFixed(2);
95-
const radiusY = (scaleY * 100).toFixed(2);
96-
97-
return { centerX, centerY, radiusX, radiusY };
66+
/**
67+
* Calculate the angle between two points in degrees
68+
* @param start Starting point {x, y} in normalized coordinates (0-1)
69+
* @param end Ending point {x, y} in normalized coordinates (0-1)
70+
* @returns Angle in degrees (0-360)
71+
*/
72+
export const calculateAngle = (
73+
start: { x: number; y: number },
74+
end: { x: number; y: number },
75+
): number => {
76+
const dx = end.x - start.x;
77+
const dy = end.y - start.y;
78+
let angle = Math.atan2(dy, dx) * (180 / Math.PI);
79+
return (angle + 360) % 360; // Normalize to 0-360 degrees
9880
};
9981

10082
// from https://math.stackexchange.com/a/2888105

packages/backend/src/common/commonPosition.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,14 @@ export const commonIsAbsolutePosition = (node: SceneNode) => {
1919
return true;
2020
}
2121

22-
// No position when parent is inferred auto layout.
23-
// if (
24-
// optimizeLayout &&
25-
// node.parent &&
26-
// "layoutMode" in node.parent &&
27-
// node.parent.inferredAutoLayout !== null
28-
// ) {
29-
// return false;
30-
// }
31-
3222
if (!node.parent || node.parent === undefined) {
3323
return false;
3424
}
3525

36-
const parentLayoutIsNone =
37-
"layoutMode" in node.parent && node.parent.layoutMode === "NONE";
38-
const hasNoLayoutMode = !("layoutMode" in node.parent);
39-
40-
if (parentLayoutIsNone || hasNoLayoutMode) {
26+
if (
27+
("layoutMode" in node.parent && node.parent.layoutMode === "NONE") ||
28+
!("layoutMode" in node.parent)
29+
) {
4130
return true;
4231
}
4332

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,16 @@
1+
import { Paint } from "../api_types";
2+
13
/**
24
* Retrieve the first visible color that is being used by the layer, in case there are more than one.
35
*/
46
export const retrieveTopFill = (
5-
fills: ReadonlyArray<Paint> | PluginAPI["mixed"] | undefined,
7+
fills: ReadonlyArray<Paint> | undefined,
68
): Paint | undefined => {
7-
if (fills && fills !== figma.mixed && fills.length > 0) {
9+
if (fills && Array.isArray(fills) && fills.length > 0) {
810
// on Figma, the top layer is always at the last position
911
// reverse, then try to find the first layer that is visible, if any.
1012
return [...fills].reverse().find((d) => d.visible !== false);
1113
}
14+
15+
return undefined;
1216
};

0 commit comments

Comments
 (0)