gradiente 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1430,6 +1430,31 @@ var RadialGradient = class RadialGradient extends GradientBase {
1430
1430
  }
1431
1431
  };
1432
1432
  //#endregion
1433
+ //#region src/gradients/DiamondGradient.ts
1434
+ var DiamondGradient = class DiamondGradient extends RadialGradient {
1435
+ type = "diamond-gradient";
1436
+ constructor(input) {
1437
+ super(input);
1438
+ }
1439
+ static fromString(input) {
1440
+ return DiamondGradient.fromAbi(parseStringToAbi(input));
1441
+ }
1442
+ static fromAbi(abi) {
1443
+ if (abi.functionName !== "diamond-gradient") throw new Error("Invalid function name for DiamondGradient");
1444
+ const config = this._parseConfig(abi.inputs);
1445
+ const inputsWithoutConfig = abi.inputs[0]?.type === "config" ? abi.inputs.slice(1) : abi.inputs;
1446
+ const stops = this._normalizeAbiInputsToStops(inputsWithoutConfig);
1447
+ return new DiamondGradient({
1448
+ isRepeating: abi.isRepeating,
1449
+ config,
1450
+ stops
1451
+ });
1452
+ }
1453
+ clone() {
1454
+ return new DiamondGradient(this.toJSON());
1455
+ }
1456
+ };
1457
+ //#endregion
1433
1458
  //#region src/gradients/ConicGradient.ts
1434
1459
  var ConicGradient = class ConicGradient extends GradientBase {
1435
1460
  type = "conic-gradient";
@@ -1612,6 +1637,421 @@ var ConicGradient = class ConicGradient extends GradientBase {
1612
1637
  }
1613
1638
  };
1614
1639
  //#endregion
1640
+ //#region src/gradients/MeshGradient.ts
1641
+ const MESH_ID_PATTERN = /^[A-Za-z_][A-Za-z0-9_-]*$/;
1642
+ const MESH_LENGTH_UNITS = [
1643
+ "px",
1644
+ "em",
1645
+ "rem",
1646
+ "vw",
1647
+ "vh",
1648
+ "vmin",
1649
+ "vmax",
1650
+ "cm",
1651
+ "mm",
1652
+ "in",
1653
+ "pt",
1654
+ "pc"
1655
+ ];
1656
+ var MeshGradient = class MeshGradient {
1657
+ type = "mesh-gradient";
1658
+ _config;
1659
+ _vertices;
1660
+ _patches;
1661
+ constructor(input) {
1662
+ const config = structuredClone(input.config);
1663
+ if (config.interpolation) config.interpolation = MeshGradient._normalizeInterpolation(config.interpolation);
1664
+ this._config = config;
1665
+ this._vertices = structuredClone(input.vertices);
1666
+ this._patches = structuredClone(input.patches);
1667
+ this._validate();
1668
+ }
1669
+ get config() {
1670
+ return structuredClone(this._config);
1671
+ }
1672
+ get vertices() {
1673
+ return structuredClone(this._vertices);
1674
+ }
1675
+ get patches() {
1676
+ return structuredClone(this._patches);
1677
+ }
1678
+ static fromString(input) {
1679
+ const { functionName, isRepeating, inputs } = MeshGradient._parseFunction(input);
1680
+ if (functionName !== "mesh-gradient") throw new Error("Invalid function name for MeshGradient");
1681
+ if (isRepeating) throw new Error("MeshGradient does not support repeating gradients");
1682
+ let config = null;
1683
+ const vertices = [];
1684
+ const patches = [];
1685
+ const handles = [];
1686
+ for (const rawInput of inputs) {
1687
+ const tokens = splitTopLevelByWhitespace(rawInput);
1688
+ const kind = tokens[0];
1689
+ if (kind === "grid") {
1690
+ if (config !== null) throw new Error("mesh-gradient can only contain one grid config");
1691
+ config = this._parseConfig(tokens);
1692
+ continue;
1693
+ }
1694
+ if (kind === "vertex") {
1695
+ vertices.push(this._parseVertex(tokens));
1696
+ continue;
1697
+ }
1698
+ if (kind === "patch") {
1699
+ patches.push(this._parsePatch(tokens));
1700
+ continue;
1701
+ }
1702
+ if (kind === "handle") {
1703
+ handles.push(this._parseHandle(tokens));
1704
+ continue;
1705
+ }
1706
+ throw new Error(`Unsupported mesh-gradient input: ${rawInput}`);
1707
+ }
1708
+ if (!config) throw new Error("mesh-gradient requires a grid config");
1709
+ const patchesWithHandles = this._attachHandles(patches, handles);
1710
+ return new MeshGradient({
1711
+ config,
1712
+ vertices,
1713
+ patches: patchesWithHandles
1714
+ });
1715
+ }
1716
+ static fromAbi(abi) {
1717
+ if (abi.functionName !== "mesh-gradient") throw new Error("Invalid function name for MeshGradient");
1718
+ if (abi.isRepeating) throw new Error("MeshGradient does not support repeating gradients");
1719
+ return MeshGradient.fromString(`${abi.functionName}(${abi.inputs.map((input) => input.value).join(", ")})`);
1720
+ }
1721
+ clone() {
1722
+ return new MeshGradient(this.toJSON());
1723
+ }
1724
+ toJSON() {
1725
+ return {
1726
+ type: this.type,
1727
+ config: this.config,
1728
+ vertices: this.vertices,
1729
+ patches: this.patches
1730
+ };
1731
+ }
1732
+ toString() {
1733
+ const parts = [
1734
+ this._serializeConfig(),
1735
+ ...this._vertices.map((vertex) => this._serializeVertex(vertex)),
1736
+ ...this._patches.map((patch) => this._serializePatch(patch)),
1737
+ ...this._patches.flatMap((patch) => this._serializeHandles(patch))
1738
+ ];
1739
+ return `${this.type}(${parts.join(", ")})`;
1740
+ }
1741
+ getVertex(id) {
1742
+ const vertex = this._vertices.find((item) => item.id === id);
1743
+ return vertex ? structuredClone(vertex) : null;
1744
+ }
1745
+ _serializeConfig() {
1746
+ const parts = [
1747
+ "grid",
1748
+ String(this._config.rows),
1749
+ String(this._config.columns),
1750
+ "method",
1751
+ this._config.method
1752
+ ];
1753
+ if (this._config.interpolation) {
1754
+ parts.push("in", this._config.interpolation.colorSpace);
1755
+ if (this._config.interpolation.hue) parts.push(this._config.interpolation.hue, "hue");
1756
+ }
1757
+ return parts.join(" ");
1758
+ }
1759
+ _serializeVertex(vertex) {
1760
+ return [
1761
+ "vertex",
1762
+ vertex.id,
1763
+ this._formatLengthPercentage(vertex.x),
1764
+ this._formatLengthPercentage(vertex.y),
1765
+ vertex.color
1766
+ ].join(" ");
1767
+ }
1768
+ _serializePatch(patch) {
1769
+ return [
1770
+ "patch",
1771
+ patch.id,
1772
+ patch.topLeft,
1773
+ patch.topRight,
1774
+ patch.bottomRight,
1775
+ patch.bottomLeft
1776
+ ].join(" ");
1777
+ }
1778
+ _serializeHandles(patch) {
1779
+ if (!patch.handles) return [];
1780
+ const result = [];
1781
+ for (const side of [
1782
+ "top",
1783
+ "right",
1784
+ "bottom",
1785
+ "left"
1786
+ ]) {
1787
+ const handle = patch.handles[side];
1788
+ if (!handle) continue;
1789
+ result.push([
1790
+ "handle",
1791
+ patch.id,
1792
+ side,
1793
+ this._formatLengthPercentage(handle.from.x),
1794
+ this._formatLengthPercentage(handle.from.y),
1795
+ this._formatLengthPercentage(handle.to.x),
1796
+ this._formatLengthPercentage(handle.to.y)
1797
+ ].join(" "));
1798
+ }
1799
+ return result;
1800
+ }
1801
+ _formatLengthPercentage(value) {
1802
+ if (value.kind === "percent") return `${value.value}%`;
1803
+ return `${value.value}${value.unit}`;
1804
+ }
1805
+ _validate() {
1806
+ if (!Number.isInteger(this._config.rows) || this._config.rows < 2) throw new Error("Mesh gradient rows must be an integer >= 2");
1807
+ if (!Number.isInteger(this._config.columns) || this._config.columns < 2) throw new Error("Mesh gradient columns must be an integer >= 2");
1808
+ if (this._config.method !== "bilinear" && this._config.method !== "bicubic") throw new Error("Invalid mesh gradient interpolation method");
1809
+ if (this._config.interpolation && !isGradientColorSpace(this._config.interpolation.colorSpace)) throw new Error(`Invalid mesh gradient color space: ${this._config.interpolation.colorSpace}`);
1810
+ const expectedVertexCount = this._config.rows * this._config.columns;
1811
+ const expectedPatchCount = (this._config.rows - 1) * (this._config.columns - 1);
1812
+ if (this._vertices.length !== expectedVertexCount) throw new Error(`Mesh gradient expected ${expectedVertexCount} vertices for ${this._config.rows}x${this._config.columns} grid, received ${this._vertices.length}`);
1813
+ if (this._patches.length !== expectedPatchCount) throw new Error(`Mesh gradient expected ${expectedPatchCount} patches for ${this._config.rows}x${this._config.columns} grid, received ${this._patches.length}`);
1814
+ const vertexIds = /* @__PURE__ */ new Set();
1815
+ for (const vertex of this._vertices) {
1816
+ this._validateId(vertex.id, "vertex");
1817
+ if (vertexIds.has(vertex.id)) throw new Error(`Duplicate mesh vertex id: ${vertex.id}`);
1818
+ vertexIds.add(vertex.id);
1819
+ this._validateLengthPercentage(vertex.x, `vertex ${vertex.id} x`);
1820
+ this._validateLengthPercentage(vertex.y, `vertex ${vertex.id} y`);
1821
+ if (!parse$1(vertex.color)) throw new Error(`Invalid mesh vertex color: ${vertex.color}`);
1822
+ }
1823
+ const patchIds = /* @__PURE__ */ new Set();
1824
+ for (const patch of this._patches) {
1825
+ this._validateId(patch.id, "patch");
1826
+ if (patchIds.has(patch.id)) throw new Error(`Duplicate mesh patch id: ${patch.id}`);
1827
+ patchIds.add(patch.id);
1828
+ const ids = [
1829
+ patch.topLeft,
1830
+ patch.topRight,
1831
+ patch.bottomRight,
1832
+ patch.bottomLeft
1833
+ ];
1834
+ if (new Set(ids).size !== 4) throw new Error(`Mesh patch must use 4 unique vertices: ${patch.id}`);
1835
+ for (const id of ids) if (!vertexIds.has(id)) throw new Error(`Mesh patch references missing vertex: ${id}`);
1836
+ if (patch.handles) this._validateHandles(patch);
1837
+ }
1838
+ if (this._patches.length === 0) throw new Error("Mesh gradient requires at least one patch");
1839
+ }
1840
+ _validateId(id, label) {
1841
+ if (!MESH_ID_PATTERN.test(id)) throw new Error(`Invalid mesh ${label} id: ${id}`);
1842
+ }
1843
+ _validateHandles(patch) {
1844
+ if (!patch.handles) return;
1845
+ for (const side of [
1846
+ "top",
1847
+ "right",
1848
+ "bottom",
1849
+ "left"
1850
+ ]) {
1851
+ const handle = patch.handles[side];
1852
+ if (!handle) continue;
1853
+ this._validateLengthPercentage(handle.from.x, `patch ${patch.id} ${side} handle from x`);
1854
+ this._validateLengthPercentage(handle.from.y, `patch ${patch.id} ${side} handle from y`);
1855
+ this._validateLengthPercentage(handle.to.x, `patch ${patch.id} ${side} handle to x`);
1856
+ this._validateLengthPercentage(handle.to.y, `patch ${patch.id} ${side} handle to y`);
1857
+ }
1858
+ }
1859
+ _validateLengthPercentage(value, label) {
1860
+ if (value.kind === "percent") {
1861
+ if (!Number.isFinite(value.value)) throw new Error(`Invalid mesh ${label}`);
1862
+ return;
1863
+ }
1864
+ if (!Number.isFinite(value.value)) throw new Error(`Invalid mesh ${label}`);
1865
+ }
1866
+ static _parseConfig(tokens) {
1867
+ if (tokens.length < 3) throw new Error("Invalid mesh grid config");
1868
+ const rows = Number(tokens[1]);
1869
+ const columns = Number(tokens[2]);
1870
+ let method = "bilinear";
1871
+ let interpolation;
1872
+ for (let index = 3; index < tokens.length; index += 1) {
1873
+ const token = tokens[index];
1874
+ if (token === "method") {
1875
+ const value = tokens[index + 1];
1876
+ if (value !== "bilinear" && value !== "bicubic") throw new Error(`Invalid mesh gradient method: ${value}`);
1877
+ method = value;
1878
+ index += 1;
1879
+ continue;
1880
+ }
1881
+ if (token === "in") {
1882
+ const colorSpace = tokens[index + 1];
1883
+ const maybeHue = tokens[index + 2];
1884
+ const maybeHueKeyword = tokens[index + 3];
1885
+ if (!isGradientColorSpace(colorSpace)) throw new Error(`Invalid mesh gradient color space: ${colorSpace}`);
1886
+ if (maybeHue !== void 0 && maybeHueKeyword === "hue" && isGradientHueInterpolation(maybeHue)) {
1887
+ interpolation = this._normalizeInterpolation({
1888
+ colorSpace,
1889
+ hue: maybeHue
1890
+ });
1891
+ index += 3;
1892
+ continue;
1893
+ }
1894
+ interpolation = { colorSpace };
1895
+ index += 1;
1896
+ continue;
1897
+ }
1898
+ throw new Error(`Unsupported mesh grid config token: ${token}`);
1899
+ }
1900
+ return {
1901
+ rows,
1902
+ columns,
1903
+ method,
1904
+ interpolation
1905
+ };
1906
+ }
1907
+ static _parseVertex(tokens) {
1908
+ if (tokens.length < 5) throw new Error("Invalid mesh vertex input");
1909
+ return {
1910
+ id: tokens[1],
1911
+ x: this._parseLengthPercentage(tokens[2]),
1912
+ y: this._parseLengthPercentage(tokens[3]),
1913
+ color: tokens.slice(4).join(" ")
1914
+ };
1915
+ }
1916
+ static _parsePatch(tokens) {
1917
+ if (tokens.length !== 6) throw new Error("Invalid mesh patch input");
1918
+ return {
1919
+ id: tokens[1],
1920
+ topLeft: tokens[2],
1921
+ topRight: tokens[3],
1922
+ bottomRight: tokens[4],
1923
+ bottomLeft: tokens[5]
1924
+ };
1925
+ }
1926
+ static _parseHandle(tokens) {
1927
+ if (tokens.length !== 7) throw new Error("Invalid mesh handle input");
1928
+ const side = tokens[2];
1929
+ if (side !== "top" && side !== "right" && side !== "bottom" && side !== "left") throw new Error(`Invalid mesh handle side: ${side}`);
1930
+ return {
1931
+ patchId: tokens[1],
1932
+ side,
1933
+ from: {
1934
+ x: this._parseLengthPercentage(tokens[3]),
1935
+ y: this._parseLengthPercentage(tokens[4])
1936
+ },
1937
+ to: {
1938
+ x: this._parseLengthPercentage(tokens[5]),
1939
+ y: this._parseLengthPercentage(tokens[6])
1940
+ }
1941
+ };
1942
+ }
1943
+ static _attachHandles(patches, handles) {
1944
+ if (handles.length === 0) return patches;
1945
+ const patchMap = new Map(patches.map((patch) => [patch.id, patch]));
1946
+ const nextPatches = patches.map((patch) => structuredClone(patch));
1947
+ const nextPatchMap = new Map(nextPatches.map((patch) => [patch.id, patch]));
1948
+ for (const handle of handles) {
1949
+ if (!patchMap.has(handle.patchId)) throw new Error(`Mesh handle references missing patch: ${handle.patchId}`);
1950
+ const patch = nextPatchMap.get(handle.patchId);
1951
+ patch.handles ??= {};
1952
+ if (patch.handles[handle.side]) throw new Error(`Duplicate mesh handle for patch ${handle.patchId} side ${handle.side}`);
1953
+ patch.handles[handle.side] = {
1954
+ from: handle.from,
1955
+ to: handle.to
1956
+ };
1957
+ }
1958
+ return nextPatches;
1959
+ }
1960
+ static _parseLengthPercentage(input) {
1961
+ if (input.endsWith("%")) {
1962
+ const value = parseFloat(input);
1963
+ if (!Number.isFinite(value)) throw new Error(`Invalid mesh length-percentage: ${input}`);
1964
+ return {
1965
+ kind: "percent",
1966
+ value
1967
+ };
1968
+ }
1969
+ const match = input.match(/^(-?\d*\.?\d+)([a-zA-Z]+)$/);
1970
+ if (!match) throw new Error(`Invalid mesh length-percentage: ${input}`);
1971
+ const unit = match[2];
1972
+ if (!MESH_LENGTH_UNITS.includes(unit)) throw new Error(`Unsupported mesh length unit: ${match[2]}`);
1973
+ return {
1974
+ kind: "length",
1975
+ value: parseFloat(match[1]),
1976
+ unit
1977
+ };
1978
+ }
1979
+ static _normalizeInterpolation(value) {
1980
+ const { colorSpace, hue } = value;
1981
+ if (hue === void 0 || !isGradientPolarColorSpace(colorSpace)) return { colorSpace };
1982
+ return {
1983
+ colorSpace,
1984
+ hue
1985
+ };
1986
+ }
1987
+ static _parseFunction(input) {
1988
+ const source = input.trim();
1989
+ const openIndex = source.indexOf("(");
1990
+ if (openIndex <= 0) throw new Error("Expected mesh-gradient function call");
1991
+ let functionName = source.slice(0, openIndex).trim();
1992
+ const isRepeating = functionName.startsWith("repeating-");
1993
+ if (isRepeating) functionName = functionName.slice(10);
1994
+ const closeIndex = this._findOuterClosingParenIndex(source, openIndex);
1995
+ if (closeIndex === -1) throw new Error("Unclosed mesh-gradient function parenthesis");
1996
+ const trailing = source.slice(closeIndex + 1).trim();
1997
+ if (trailing.length > 0 && !trailing.startsWith(`${functionName}(`) && !trailing.startsWith(`repeating-${functionName}(`)) throw new Error(`Unexpected mesh-gradient trailing input: ${trailing}`);
1998
+ const body = source.slice(openIndex + 1, closeIndex);
1999
+ return {
2000
+ functionName,
2001
+ isRepeating,
2002
+ inputs: this._splitTopLevelInputs(body)
2003
+ };
2004
+ }
2005
+ static _findOuterClosingParenIndex(value, openIndex) {
2006
+ let depth = 0;
2007
+ for (let index = openIndex; index < value.length; index += 1) {
2008
+ const char = value[index];
2009
+ if (char === "(") {
2010
+ depth += 1;
2011
+ continue;
2012
+ }
2013
+ if (char === ")") {
2014
+ depth -= 1;
2015
+ if (depth === 0) return index;
2016
+ if (depth < 0) return -1;
2017
+ }
2018
+ }
2019
+ return -1;
2020
+ }
2021
+ static _splitTopLevelInputs(value) {
2022
+ const result = [];
2023
+ let current = "";
2024
+ let parenDepth = 0;
2025
+ for (let index = 0; index < value.length; index += 1) {
2026
+ const char = value[index];
2027
+ if (char === "(") {
2028
+ parenDepth += 1;
2029
+ current += char;
2030
+ continue;
2031
+ }
2032
+ if (char === ")") {
2033
+ parenDepth -= 1;
2034
+ if (parenDepth < 0) throw new Error("Unbalanced mesh-gradient input parentheses");
2035
+ current += char;
2036
+ continue;
2037
+ }
2038
+ if (char === "," && parenDepth === 0) {
2039
+ this._pushTrimmed(result, current);
2040
+ current = "";
2041
+ continue;
2042
+ }
2043
+ current += char;
2044
+ }
2045
+ this._pushTrimmed(result, current);
2046
+ if (parenDepth !== 0) throw new Error("Unbalanced mesh-gradient input parentheses");
2047
+ return result;
2048
+ }
2049
+ static _pushTrimmed(target, value) {
2050
+ const trimmed = value.trim();
2051
+ if (trimmed.length > 0) target.push(trimmed);
2052
+ }
2053
+ };
2054
+ //#endregion
1615
2055
  //#region src/gradient-transformer/modules/css/ModuleTransformerLinearGradientToCss.ts
1616
2056
  var ModuleTransformerLinearGradientToCss = class {
1617
2057
  target = "css";
@@ -1632,21 +2072,11 @@ var ModuleTransformerRadialGradientToCss = class {
1632
2072
  }
1633
2073
  };
1634
2074
  //#endregion
1635
- //#region src/gradient-transformer/modules/css/ModuleTransformerConicGradientToCss.ts
1636
- var ModuleTransformerConicGradientToCss = class {
1637
- target = "css";
1638
- gradientType = "conic-gradient";
1639
- to(input) {
1640
- if (!(input instanceof ConicGradient)) throw new Error("Expected ConicGradient");
1641
- return input.toString();
1642
- }
1643
- };
1644
- //#endregion
1645
2075
  //#region src/gradient-transformer/modules/helpers/expand-repeating-stops.ts
1646
2076
  function positiveModulo(value, modulo) {
1647
2077
  return (value % modulo + modulo) % modulo;
1648
2078
  }
1649
- function sampleColorAtPosition(stops, position) {
2079
+ function sampleColorAtPosition$2(stops, position) {
1650
2080
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
1651
2081
  if (colorStops.length === 0) throw new Error("Cannot sample color from empty stops.");
1652
2082
  if (position <= colorStops[0].position) return colorStops[0].value;
@@ -1664,7 +2094,7 @@ function sampleColorAtPosition(stops, position) {
1664
2094
  return lastStop.value;
1665
2095
  }
1666
2096
  function sampleRepeatingColorAtPosition(stops, position, firstPosition, period) {
1667
- return sampleColorAtPosition(stops, firstPosition + positiveModulo(position - firstPosition, period));
2097
+ return sampleColorAtPosition$2(stops, firstPosition + positiveModulo(position - firstPosition, period));
1668
2098
  }
1669
2099
  function expandRepeatingStopsTo(stops, from, to) {
1670
2100
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
@@ -1783,12 +2213,12 @@ function getColorStopsWithPositions(stops) {
1783
2213
  });
1784
2214
  }
1785
2215
  function formatColorForCanvas(input) {
1786
- const color = toRgb$6(input);
2216
+ const color = toRgb$9(input);
1787
2217
  if (!color) throw new Error("Failed to convert interpolated color to rgb.");
1788
2218
  return formatRgb(color);
1789
2219
  }
1790
2220
  const DEFAULT_SAMPLE_COUNT = 64;
1791
- const toRgb$6 = converter("rgb");
2221
+ const toRgb$9 = converter("rgb");
1792
2222
  function resolveRenderableGradientStops(gradient, sampleCount = DEFAULT_SAMPLE_COUNT) {
1793
2223
  const colorStops = getColorStopsWithPositions(gradient.stops);
1794
2224
  const interpolation = gradient.config.interpolation;
@@ -1818,113 +2248,713 @@ function resolveRenderableGradientStops(gradient, sampleCount = DEFAULT_SAMPLE_C
1818
2248
  return gradient.isRepeating ? expandRepeatingStops(sampledStops) : sampledStops;
1819
2249
  }
1820
2250
  //#endregion
1821
- //#region src/gradient-transformer/modules/canvas/ModuleTransformerLinearGradientToCanvas.ts
1822
- const toRgb$5 = converter("rgb");
1823
- function toCanvasColor$1(input) {
1824
- const color = toRgb$5(input);
2251
+ //#region src/gradient-transformer/modules/helpers/mesh-rendering.ts
2252
+ const toRgb$8 = converter("rgb");
2253
+ function toColor(input) {
2254
+ const color = toRgb$8(input);
1825
2255
  if (!color) throw new Error(`Failed to convert color: ${input}`);
1826
- return formatRgb(color);
2256
+ return [
2257
+ color.r ?? 0,
2258
+ color.g ?? 0,
2259
+ color.b ?? 0,
2260
+ color.alpha ?? 1
2261
+ ];
1827
2262
  }
1828
- function getStopRange$2(stops) {
1829
- const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
1830
- if (!colorStops.length) return {
1831
- min: 0,
1832
- max: 1,
1833
- stops: []
1834
- };
2263
+ function resolveLengthPercentage$2(value, reference) {
2264
+ if (value.kind === "percent") return value.value / 100 * reference;
2265
+ if (value.unit === "px") return value.value;
2266
+ throw new Error(`Unsupported mesh-gradient length unit: ${value.unit}`);
2267
+ }
2268
+ function resolveMeshVertex(vertex, width, height) {
1835
2269
  return {
1836
- min: Math.min(...colorStops.map((stop) => stop.position)),
1837
- max: Math.max(...colorStops.map((stop) => stop.position)),
1838
- stops: colorStops
2270
+ id: vertex.id,
2271
+ x: resolveLengthPercentage$2(vertex.x, width),
2272
+ y: resolveLengthPercentage$2(vertex.y, height),
2273
+ color: toColor(vertex.color)
1839
2274
  };
1840
2275
  }
1841
- function normalizeStops$3(stops, min, max) {
1842
- const range = max - min || 1;
1843
- return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
1844
- ...stop,
1845
- position: (stop.position - min) / range
1846
- }));
2276
+ function buildMeshVertexMap(gradient, width, height) {
2277
+ return new Map(gradient.vertices.map((vertex) => [vertex.id, resolveMeshVertex(vertex, width, height)]));
1847
2278
  }
1848
- var ModuleTransformerLinearGradientToCanvas = class {
1849
- target = "canvas-2d";
1850
- gradientType = "linear-gradient";
1851
- to(input) {
1852
- const gradient = input;
1853
- return { draw: (ctx, width, height) => {
1854
- const angle = gradient.config.angle;
1855
- const dirX = Math.sin(angle);
1856
- const dirY = -Math.cos(angle);
1857
- const centerX = width / 2;
1858
- const centerY = height / 2;
1859
- const lineLength = Math.abs(width * dirX) + Math.abs(height * dirY);
1860
- let startX = centerX - dirX * lineLength / 2;
1861
- let startY = centerY - dirY * lineLength / 2;
1862
- let endX = centerX + dirX * lineLength / 2;
1863
- let endY = centerY + dirY * lineLength / 2;
1864
- const { min, max, stops } = getStopRange$2(resolveRenderableGradientStops(gradient));
1865
- let normalizedStops = stops;
1866
- if (min < 0 || max > 1) {
1867
- const vx = endX - startX;
1868
- const vy = endY - startY;
1869
- const baseStartX = startX;
1870
- const baseStartY = startY;
1871
- startX = baseStartX + vx * min;
1872
- startY = baseStartY + vy * min;
1873
- endX = baseStartX + vx * max;
1874
- endY = baseStartY + vy * max;
1875
- normalizedStops = normalizeStops$3(stops, min, max);
1876
- }
1877
- const canvasGradient = ctx.createLinearGradient(startX, startY, endX, endY);
1878
- for (const stop of normalizedStops) canvasGradient.addColorStop(stop.position, toCanvasColor$1(stop.value));
1879
- ctx.clearRect(0, 0, width, height);
1880
- ctx.fillStyle = canvasGradient;
1881
- ctx.fillRect(0, 0, width, height);
1882
- } };
2279
+ function buildRegularMeshGrid(gradient, vertexMap) {
2280
+ const idGrid = buildRegularMeshGridFromVertexIds(gradient, vertexMap);
2281
+ if (idGrid) return idGrid;
2282
+ const vertices = gradient.vertices.map((vertex) => {
2283
+ const resolved = vertexMap.get(vertex.id);
2284
+ if (!resolved) throw new Error(`Missing mesh vertex: ${vertex.id}`);
2285
+ return resolved;
2286
+ }).sort((a, b) => {
2287
+ if (Math.abs(a.y - b.y) > 1e-4) return a.y - b.y;
2288
+ return a.x - b.x;
2289
+ });
2290
+ const result = [];
2291
+ for (let row = 0; row < gradient.config.rows; row += 1) {
2292
+ const start = row * gradient.config.columns;
2293
+ const end = start + gradient.config.columns;
2294
+ result.push(vertices.slice(start, end));
1883
2295
  }
1884
- };
1885
- //#endregion
1886
- //#region src/gradient-transformer/modules/canvas/ModuleTransformerRadialGradientToCanvas.ts
1887
- const toRgb$4 = converter("rgb");
1888
- const RADIAL_GRADIENT_SAMPLE_COUNT = 128;
1889
- function toCanvasColor(input) {
1890
- const color = toRgb$4(input);
1891
- if (!color) throw new Error(`Failed to convert color: ${input}`);
1892
- return formatRgb(color);
2296
+ return result;
1893
2297
  }
1894
- function getStopRange$1(stops) {
1895
- const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
1896
- if (!colorStops.length) return {
1897
- min: 0,
1898
- max: 1,
1899
- stops: []
1900
- };
1901
- return {
1902
- min: Math.min(...colorStops.map((stop) => stop.position)),
1903
- max: Math.max(...colorStops.map((stop) => stop.position)),
1904
- stops: colorStops
2298
+ function buildRegularMeshGridFromVertexIds(gradient, vertexMap) {
2299
+ const result = Array.from({ length: gradient.config.rows }, () => []);
2300
+ for (const vertex of gradient.vertices) {
2301
+ const match = vertex.id.match(/^v(\d+)(\d+)$/);
2302
+ if (!match) return null;
2303
+ const column = Number(match[1]);
2304
+ const row = Number(match[2]);
2305
+ if (!Number.isInteger(row) || !Number.isInteger(column) || row < 0 || column < 0 || row >= gradient.config.rows || column >= gradient.config.columns) return null;
2306
+ const resolved = vertexMap.get(vertex.id);
2307
+ if (!resolved) throw new Error(`Missing mesh vertex: ${vertex.id}`);
2308
+ if (result[row][column]) return null;
2309
+ result[row][column] = resolved;
2310
+ }
2311
+ if (result.some((row) => row.length !== gradient.config.columns || row.some((vertex) => vertex === void 0))) return null;
2312
+ return result;
2313
+ }
2314
+ function findPatchCell(grid, patch) {
2315
+ for (let row = 0; row < grid.length - 1; row += 1) for (let column = 0; column < grid[row].length - 1; column += 1) if (grid[row][column].id === patch.topLeft && grid[row][column + 1].id === patch.topRight && grid[row + 1][column + 1].id === patch.bottomRight && grid[row + 1][column].id === patch.bottomLeft) return {
2316
+ row,
2317
+ column
1905
2318
  };
2319
+ throw new Error(`Mesh patch does not match adjacent regular grid vertices: ${patch.id}`);
1906
2320
  }
1907
- function normalizeStops$2(stops, min, max) {
1908
- const range = max - min || 1;
1909
- return stops.map((stop) => ({
1910
- ...stop,
1911
- position: (stop.position - min) / range
1912
- }));
2321
+ function clampIndex(index, length) {
2322
+ return Math.min(length - 1, Math.max(0, index));
1913
2323
  }
1914
- function getDistanceToSide$1(center, width, height, side) {
1915
- if (side === "left") return center.x;
1916
- if (side === "right") return width - center.x;
1917
- if (side === "top") return center.y;
1918
- return height - center.y;
2324
+ function catmullRom(p0, p1, p2, p3, t) {
2325
+ const t2 = t * t;
2326
+ const t3 = t2 * t;
2327
+ return .5 * (2 * p1 + (-p0 + p2) * t + (2 * p0 - 5 * p1 + 4 * p2 - p3) * t2 + (-p0 + 3 * p1 - 3 * p2 + p3) * t3);
1919
2328
  }
1920
- function getDistanceToCorner$1(center, corner) {
1921
- const dx = corner.x - center.x;
1922
- const dy = corner.y - center.y;
1923
- return Math.sqrt(dx * dx + dy * dy);
2329
+ function clampColor(value) {
2330
+ return Math.min(1, Math.max(0, value));
1924
2331
  }
1925
- function getCornerDeltas$1(center, width, height) {
2332
+ function mix(a, b, t) {
2333
+ return a + (b - a) * t;
2334
+ }
2335
+ function mixColor(a, b, t) {
1926
2336
  return [
1927
- {
2337
+ mix(a[0], b[0], t),
2338
+ mix(a[1], b[1], t),
2339
+ mix(a[2], b[2], t),
2340
+ mix(a[3], b[3], t)
2341
+ ];
2342
+ }
2343
+ function sampleBilinearColor(topLeft, topRight, bottomRight, bottomLeft, u, v) {
2344
+ return mixColor(mixColor(topLeft.color, topRight.color, u), mixColor(bottomLeft.color, bottomRight.color, u), v);
2345
+ }
2346
+ function sampleBicubicColor(grid, row, column, u, v) {
2347
+ const rows = grid.length;
2348
+ const columns = grid[0]?.length ?? 0;
2349
+ const color = [
2350
+ 0,
2351
+ 0,
2352
+ 0,
2353
+ 0
2354
+ ];
2355
+ for (let channel = 0; channel < 4; channel += 1) {
2356
+ const values = [];
2357
+ for (let y = -1; y <= 2; y += 1) {
2358
+ const sampleRow = grid[clampIndex(row + y, rows)];
2359
+ const p0 = sampleRow[clampIndex(column - 1, columns)].color[channel];
2360
+ const p1 = sampleRow[clampIndex(column, columns)].color[channel];
2361
+ const p2 = sampleRow[clampIndex(column + 1, columns)].color[channel];
2362
+ const p3 = sampleRow[clampIndex(column + 2, columns)].color[channel];
2363
+ values.push(catmullRom(p0, p1, p2, p3, u));
2364
+ }
2365
+ color[channel] = clampColor(catmullRom(values[0], values[1], values[2], values[3], v));
2366
+ }
2367
+ return color;
2368
+ }
2369
+ function samplePosition(topLeft, topRight, bottomRight, bottomLeft, u, v) {
2370
+ const topX = mix(topLeft.x, topRight.x, u);
2371
+ const topY = mix(topLeft.y, topRight.y, u);
2372
+ const bottomX = mix(bottomLeft.x, bottomRight.x, u);
2373
+ const bottomY = mix(bottomLeft.y, bottomRight.y, u);
2374
+ return {
2375
+ x: mix(topX, bottomX, v),
2376
+ y: mix(topY, bottomY, v)
2377
+ };
2378
+ }
2379
+ function samplePatchColor(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u, v) {
2380
+ if (gradient.config.method === "bicubic") return sampleBicubicColor(grid, row, column, u, v);
2381
+ return sampleBilinearColor(topLeft, topRight, bottomRight, bottomLeft, u, v).map(clampColor);
2382
+ }
2383
+ function buildPatchTriangles(gradient, grid, patch, vertexMap, subdivisions) {
2384
+ const topLeft = vertexMap.get(patch.topLeft);
2385
+ const topRight = vertexMap.get(patch.topRight);
2386
+ const bottomRight = vertexMap.get(patch.bottomRight);
2387
+ const bottomLeft = vertexMap.get(patch.bottomLeft);
2388
+ if (!topLeft || !topRight || !bottomRight || !bottomLeft) throw new Error(`Mesh patch references missing vertex: ${patch.id}`);
2389
+ const cell = findPatchCell(grid, patch);
2390
+ const samples = [];
2391
+ for (let y = 0; y <= subdivisions; y += 1) {
2392
+ const row = [];
2393
+ const v = y / subdivisions;
2394
+ for (let x = 0; x <= subdivisions; x += 1) {
2395
+ const u = x / subdivisions;
2396
+ const position = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u, v);
2397
+ const color = samplePatchColor(gradient, grid, cell.row, cell.column, topLeft, topRight, bottomRight, bottomLeft, u, v);
2398
+ row.push({
2399
+ id: `${patch.id}:${x}:${y}`,
2400
+ x: position.x,
2401
+ y: position.y,
2402
+ color
2403
+ });
2404
+ }
2405
+ samples.push(row);
2406
+ }
2407
+ const triangles = [];
2408
+ for (let y = 0; y < subdivisions; y += 1) for (let x = 0; x < subdivisions; x += 1) {
2409
+ const topLeftSample = samples[y][x];
2410
+ const topRightSample = samples[y][x + 1];
2411
+ const bottomRightSample = samples[y + 1][x + 1];
2412
+ const bottomLeftSample = samples[y + 1][x];
2413
+ triangles.push([
2414
+ topLeftSample,
2415
+ topRightSample,
2416
+ bottomRightSample
2417
+ ], [
2418
+ topLeftSample,
2419
+ bottomRightSample,
2420
+ bottomLeftSample
2421
+ ]);
2422
+ }
2423
+ return triangles;
2424
+ }
2425
+ function samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u, v, x, y, id) {
2426
+ return {
2427
+ id,
2428
+ x,
2429
+ y,
2430
+ color: samplePatchColor(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u, v)
2431
+ };
2432
+ }
2433
+ function buildMeshEdgeSkirtTriangles(gradient, grid, width, height, subdivisions) {
2434
+ const triangles = [];
2435
+ const rows = grid.length;
2436
+ const columns = grid[0]?.length ?? 0;
2437
+ if (rows < 2 || columns < 2) return triangles;
2438
+ for (let column = 0; column < columns - 1; column += 1) {
2439
+ const topLeft = grid[0][column];
2440
+ const topRight = grid[0][column + 1];
2441
+ const bottomRight = grid[1][column + 1];
2442
+ const bottomLeft = grid[1][column];
2443
+ for (let index = 0; index < subdivisions; index += 1) {
2444
+ const u0 = index / subdivisions;
2445
+ const u1 = (index + 1) / subdivisions;
2446
+ const top0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u0, 0);
2447
+ const top1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u1, 0);
2448
+ const bottom0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u0, 1);
2449
+ const bottom1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u1, 1);
2450
+ const v0 = Math.min(0, (0 - top0.y) / Math.max(bottom0.y - top0.y, 1e-4));
2451
+ const v1 = Math.min(0, (0 - top1.y) / Math.max(bottom1.y - top1.y, 1e-4));
2452
+ const boundary0 = samplePatchVertexAt(gradient, grid, 0, column, topLeft, topRight, bottomRight, bottomLeft, u0, 0, top0.x, top0.y, `top:${column}:${index}:b0`);
2453
+ const boundary1 = samplePatchVertexAt(gradient, grid, 0, column, topLeft, topRight, bottomRight, bottomLeft, u1, 0, top1.x, top1.y, `top:${column}:${index}:b1`);
2454
+ const projected0 = samplePatchVertexAt(gradient, grid, 0, column, topLeft, topRight, bottomRight, bottomLeft, u0, v0, top0.x, 0, `top:${column}:${index}:p0`);
2455
+ const projected1 = samplePatchVertexAt(gradient, grid, 0, column, topLeft, topRight, bottomRight, bottomLeft, u1, v1, top1.x, 0, `top:${column}:${index}:p1`);
2456
+ triangles.push([
2457
+ projected0,
2458
+ projected1,
2459
+ boundary1
2460
+ ], [
2461
+ projected0,
2462
+ boundary1,
2463
+ boundary0
2464
+ ]);
2465
+ }
2466
+ }
2467
+ for (let column = 0; column < columns - 1; column += 1) {
2468
+ const row = rows - 2;
2469
+ const topLeft = grid[row][column];
2470
+ const topRight = grid[row][column + 1];
2471
+ const bottomRight = grid[row + 1][column + 1];
2472
+ const bottomLeft = grid[row + 1][column];
2473
+ for (let index = 0; index < subdivisions; index += 1) {
2474
+ const u0 = index / subdivisions;
2475
+ const u1 = (index + 1) / subdivisions;
2476
+ const top0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u0, 0);
2477
+ const top1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u1, 0);
2478
+ const bottom0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u0, 1);
2479
+ const bottom1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, u1, 1);
2480
+ const v0 = Math.max(1, (height - top0.y) / Math.max(bottom0.y - top0.y, 1e-4));
2481
+ const v1 = Math.max(1, (height - top1.y) / Math.max(bottom1.y - top1.y, 1e-4));
2482
+ const boundary0 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u0, 1, bottom0.x, bottom0.y, `bottom:${column}:${index}:b0`);
2483
+ const boundary1 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u1, 1, bottom1.x, bottom1.y, `bottom:${column}:${index}:b1`);
2484
+ const projected0 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u0, v0, bottom0.x, height, `bottom:${column}:${index}:p0`);
2485
+ const projected1 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u1, v1, bottom1.x, height, `bottom:${column}:${index}:p1`);
2486
+ triangles.push([
2487
+ boundary0,
2488
+ boundary1,
2489
+ projected1
2490
+ ], [
2491
+ boundary0,
2492
+ projected1,
2493
+ projected0
2494
+ ]);
2495
+ }
2496
+ }
2497
+ for (let row = 0; row < rows - 1; row += 1) {
2498
+ const topLeft = grid[row][0];
2499
+ const topRight = grid[row][1];
2500
+ const bottomRight = grid[row + 1][1];
2501
+ const bottomLeft = grid[row + 1][0];
2502
+ for (let index = 0; index < subdivisions; index += 1) {
2503
+ const v0 = index / subdivisions;
2504
+ const v1 = (index + 1) / subdivisions;
2505
+ const left0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 0, v0);
2506
+ const left1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 0, v1);
2507
+ const right0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 1, v0);
2508
+ const right1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 1, v1);
2509
+ const u0 = Math.min(0, (0 - left0.x) / Math.max(right0.x - left0.x, 1e-4));
2510
+ const u1 = Math.min(0, (0 - left1.x) / Math.max(right1.x - left1.x, 1e-4));
2511
+ const boundary0 = samplePatchVertexAt(gradient, grid, row, 0, topLeft, topRight, bottomRight, bottomLeft, 0, v0, left0.x, left0.y, `left:${row}:${index}:b0`);
2512
+ const boundary1 = samplePatchVertexAt(gradient, grid, row, 0, topLeft, topRight, bottomRight, bottomLeft, 0, v1, left1.x, left1.y, `left:${row}:${index}:b1`);
2513
+ const projected0 = samplePatchVertexAt(gradient, grid, row, 0, topLeft, topRight, bottomRight, bottomLeft, u0, v0, 0, left0.y, `left:${row}:${index}:p0`);
2514
+ const projected1 = samplePatchVertexAt(gradient, grid, row, 0, topLeft, topRight, bottomRight, bottomLeft, u1, v1, 0, left1.y, `left:${row}:${index}:p1`);
2515
+ triangles.push([
2516
+ projected0,
2517
+ boundary0,
2518
+ boundary1
2519
+ ], [
2520
+ projected0,
2521
+ boundary1,
2522
+ projected1
2523
+ ]);
2524
+ }
2525
+ }
2526
+ for (let row = 0; row < rows - 1; row += 1) {
2527
+ const column = columns - 2;
2528
+ const topLeft = grid[row][column];
2529
+ const topRight = grid[row][column + 1];
2530
+ const bottomRight = grid[row + 1][column + 1];
2531
+ const bottomLeft = grid[row + 1][column];
2532
+ for (let index = 0; index < subdivisions; index += 1) {
2533
+ const v0 = index / subdivisions;
2534
+ const v1 = (index + 1) / subdivisions;
2535
+ const left0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 0, v0);
2536
+ const left1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 0, v1);
2537
+ const right0 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 1, v0);
2538
+ const right1 = samplePosition(topLeft, topRight, bottomRight, bottomLeft, 1, v1);
2539
+ const u0 = Math.max(1, (width - left0.x) / Math.max(right0.x - left0.x, 1e-4));
2540
+ const u1 = Math.max(1, (width - left1.x) / Math.max(right1.x - left1.x, 1e-4));
2541
+ const boundary0 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, 1, v0, right0.x, right0.y, `right:${row}:${index}:b0`);
2542
+ const boundary1 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, 1, v1, right1.x, right1.y, `right:${row}:${index}:b1`);
2543
+ const projected0 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u0, v0, width, right0.y, `right:${row}:${index}:p0`);
2544
+ const projected1 = samplePatchVertexAt(gradient, grid, row, column, topLeft, topRight, bottomRight, bottomLeft, u1, v1, width, right1.y, `right:${row}:${index}:p1`);
2545
+ triangles.push([
2546
+ boundary0,
2547
+ projected0,
2548
+ projected1
2549
+ ], [
2550
+ boundary0,
2551
+ projected1,
2552
+ boundary1
2553
+ ]);
2554
+ }
2555
+ }
2556
+ return triangles;
2557
+ }
2558
+ //#endregion
2559
+ //#region src/gradient-transformer/modules/css/ModuleTransformerDiamondGradientToCss.ts
2560
+ const DIAMOND_SAMPLE_COUNT = 96;
2561
+ function getColorStops$1(stops) {
2562
+ return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
2563
+ }
2564
+ function sampleColorAtPosition$1(stops, position) {
2565
+ if (stops.length === 0) throw new Error("Cannot sample color from empty diamond gradient stops.");
2566
+ if (stops.length === 1 || position <= stops[0].position) return stops[0].value;
2567
+ const lastStop = stops[stops.length - 1];
2568
+ if (position >= lastStop.position) return lastStop.value;
2569
+ for (let index = 0; index < stops.length - 1; index += 1) {
2570
+ const current = stops[index];
2571
+ const next = stops[index + 1];
2572
+ if (position >= current.position && position <= next.position) {
2573
+ const range = next.position - current.position || 1;
2574
+ const localT = (position - current.position) / range;
2575
+ return formatRgb(interpolate([current.value, next.value], "rgb")(localT));
2576
+ }
2577
+ }
2578
+ return lastStop.value;
2579
+ }
2580
+ function resolvePosition(position) {
2581
+ if (position.kind === "keywords") return {
2582
+ x: resolveKeywordX(position.x),
2583
+ y: resolveKeywordY(position.y)
2584
+ };
2585
+ return {
2586
+ x: resolveLengthPercentage$1(position.x, 100),
2587
+ y: resolveLengthPercentage$1(position.y, 100)
2588
+ };
2589
+ }
2590
+ function resolveKeywordX(value) {
2591
+ if (value === "left") return 0;
2592
+ if (value === "right") return 100;
2593
+ return 50;
2594
+ }
2595
+ function resolveKeywordY(value) {
2596
+ if (value === "top") return 0;
2597
+ if (value === "bottom") return 100;
2598
+ return 50;
2599
+ }
2600
+ function resolveLengthPercentage$1(value, reference) {
2601
+ if (value.kind === "percent") return value.value / 100 * reference;
2602
+ if (value.unit === "px") return value.value;
2603
+ throw new Error(`Unsupported diamond-gradient length unit for CSS transformer: ${value.unit}`);
2604
+ }
2605
+ function getDistanceToCorner$4(center, corner) {
2606
+ return Math.abs(corner.x - center.x) + Math.abs(corner.y - center.y);
2607
+ }
2608
+ function getCornerDeltas$4(center) {
2609
+ return [
2610
+ {
2611
+ dx: -center.x,
2612
+ dy: -center.y
2613
+ },
2614
+ {
2615
+ dx: 100 - center.x,
2616
+ dy: -center.y
2617
+ },
2618
+ {
2619
+ dx: -center.x,
2620
+ dy: 100 - center.y
2621
+ },
2622
+ {
2623
+ dx: 100 - center.x,
2624
+ dy: 100 - center.y
2625
+ }
2626
+ ];
2627
+ }
2628
+ function scaleDiamondRadiiToCorner$2(radiusX, radiusY, dx, dy) {
2629
+ const safeRadiusX = Math.max(radiusX, 1e-4);
2630
+ const safeRadiusY = Math.max(radiusY, 1e-4);
2631
+ const scale = Math.abs(dx) / safeRadiusX + Math.abs(dy) / safeRadiusY;
2632
+ return {
2633
+ x: safeRadiusX * scale,
2634
+ y: safeRadiusY * scale
2635
+ };
2636
+ }
2637
+ function getMaxVisibleDiamondT$2(center, radii) {
2638
+ return Math.max(...[
2639
+ {
2640
+ x: 0,
2641
+ y: 0
2642
+ },
2643
+ {
2644
+ x: 100,
2645
+ y: 0
2646
+ },
2647
+ {
2648
+ x: 0,
2649
+ y: 100
2650
+ },
2651
+ {
2652
+ x: 100,
2653
+ y: 100
2654
+ }
2655
+ ].map((corner) => Math.abs(corner.x - center.x) / Math.max(radii.x, 1e-4) + Math.abs(corner.y - center.y) / Math.max(radii.y, 1e-4)));
2656
+ }
2657
+ function resolveDiamondRadii$1(size, shape, center) {
2658
+ if (size.kind === "explicit") {
2659
+ const radiusX = resolveLengthPercentage$1(size.x, 100);
2660
+ const radiusY = size.y ? resolveLengthPercentage$1(size.y, 100) : radiusX;
2661
+ return {
2662
+ x: Math.max(radiusX, 1e-4),
2663
+ y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
2664
+ };
2665
+ }
2666
+ const left = center.x;
2667
+ const right = 100 - center.x;
2668
+ const top = center.y;
2669
+ const bottom = 100 - center.y;
2670
+ if (shape === "circle") {
2671
+ const cornerDistances = [
2672
+ {
2673
+ x: 0,
2674
+ y: 0
2675
+ },
2676
+ {
2677
+ x: 100,
2678
+ y: 0
2679
+ },
2680
+ {
2681
+ x: 0,
2682
+ y: 100
2683
+ },
2684
+ {
2685
+ x: 100,
2686
+ y: 100
2687
+ }
2688
+ ].map((corner) => getDistanceToCorner$4(center, corner));
2689
+ if (size.value === "closest-side") {
2690
+ const radius = Math.max(Math.min(left, right, top, bottom), 1e-4);
2691
+ return {
2692
+ x: radius,
2693
+ y: radius
2694
+ };
2695
+ }
2696
+ if (size.value === "farthest-side") {
2697
+ const radius = Math.max(Math.max(left, right, top, bottom), 1e-4);
2698
+ return {
2699
+ x: radius,
2700
+ y: radius
2701
+ };
2702
+ }
2703
+ if (size.value === "closest-corner") {
2704
+ const radius = Math.max(Math.min(...cornerDistances), 1e-4);
2705
+ return {
2706
+ x: radius,
2707
+ y: radius
2708
+ };
2709
+ }
2710
+ const radius = Math.max(Math.max(...cornerDistances), 1e-4);
2711
+ return {
2712
+ x: radius,
2713
+ y: radius
2714
+ };
2715
+ }
2716
+ const closestSideRadiusX = Math.min(left, right);
2717
+ const closestSideRadiusY = Math.min(top, bottom);
2718
+ const farthestSideRadiusX = Math.max(left, right);
2719
+ const farthestSideRadiusY = Math.max(top, bottom);
2720
+ if (size.value === "closest-side") return {
2721
+ x: Math.max(closestSideRadiusX, 1e-4),
2722
+ y: Math.max(closestSideRadiusY, 1e-4)
2723
+ };
2724
+ if (size.value === "farthest-side") return {
2725
+ x: Math.max(farthestSideRadiusX, 1e-4),
2726
+ y: Math.max(farthestSideRadiusY, 1e-4)
2727
+ };
2728
+ const corners = getCornerDeltas$4(center);
2729
+ if (size.value === "closest-corner") return corners.map((corner) => scaleDiamondRadiiToCorner$2(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => current.x * current.y < closest.x * closest.y ? current : closest);
2730
+ return corners.map((corner) => scaleDiamondRadiiToCorner$2(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => current.x * current.y > farthest.x * farthest.y ? current : farthest);
2731
+ }
2732
+ function formatPoint(value) {
2733
+ return Number(value.toFixed(3)).toString();
2734
+ }
2735
+ function buildDiamondPolygon(center, radii, position) {
2736
+ const x = radii.x * position;
2737
+ const y = radii.y * position;
2738
+ return [
2739
+ `${formatPoint(center.x)} ${formatPoint(center.y - y)}`,
2740
+ `${formatPoint(center.x + x)} ${formatPoint(center.y)}`,
2741
+ `${formatPoint(center.x)} ${formatPoint(center.y + y)}`,
2742
+ `${formatPoint(center.x - x)} ${formatPoint(center.y)}`
2743
+ ].join(" ");
2744
+ }
2745
+ function encodeSvgDataUrl$1(svg) {
2746
+ return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
2747
+ }
2748
+ var ModuleTransformerDiamondGradientToCss = class {
2749
+ target = "css";
2750
+ gradientType = "diamond-gradient";
2751
+ to(input) {
2752
+ if (!(input instanceof DiamondGradient)) throw new Error("Expected DiamondGradient");
2753
+ const center = resolvePosition(input.config.position);
2754
+ const radii = resolveDiamondRadii$1(input.config.size, input.config.shape, center);
2755
+ const maxVisibleT = getMaxVisibleDiamondT$2(center, radii);
2756
+ const maxT = input.isRepeating ? maxVisibleT : 1;
2757
+ const baseStops = resolveRenderableGradientStops(input, DIAMOND_SAMPLE_COUNT);
2758
+ const stops = getColorStops$1(input.isRepeating ? expandRepeatingStopsTo(baseStops, 0, maxVisibleT) : baseStops);
2759
+ const outerColor = sampleColorAtPosition$1(stops, maxT);
2760
+ const polygons = [];
2761
+ const sampleCount = Math.max(DIAMOND_SAMPLE_COUNT, Math.ceil(DIAMOND_SAMPLE_COUNT * maxT));
2762
+ for (let index = sampleCount; index >= 0; index -= 1) {
2763
+ const position = index / sampleCount * maxT;
2764
+ const color = sampleColorAtPosition$1(stops, position);
2765
+ const points = buildDiamondPolygon(center, radii, position);
2766
+ polygons.push(`<polygon points="${points}" fill="${color}"/>`);
2767
+ }
2768
+ return encodeSvgDataUrl$1([
2769
+ "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 100 100\" preserveAspectRatio=\"none\">",
2770
+ `<rect width="100" height="100" fill="${outerColor}"/>`,
2771
+ ...polygons,
2772
+ "</svg>"
2773
+ ].join(""));
2774
+ }
2775
+ };
2776
+ //#endregion
2777
+ //#region src/gradient-transformer/modules/css/ModuleTransformerConicGradientToCss.ts
2778
+ var ModuleTransformerConicGradientToCss = class {
2779
+ target = "css";
2780
+ gradientType = "conic-gradient";
2781
+ to(input) {
2782
+ if (!(input instanceof ConicGradient)) throw new Error("Expected ConicGradient");
2783
+ return input.toString();
2784
+ }
2785
+ };
2786
+ //#endregion
2787
+ //#region src/gradient-transformer/modules/css/ModuleTransformerMeshGradientToCss.ts
2788
+ const CSS_SAMPLE_SIZE = 96;
2789
+ const BICUBIC_SUBDIVISIONS$2 = 24;
2790
+ function formatRgba(color) {
2791
+ return `rgba(${color[0]},${color[1]},${color[2]},${Number(color[3].toFixed(3))})`;
2792
+ }
2793
+ function getBarycentric$1(x, y, a, b, c) {
2794
+ const denominator = (b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y);
2795
+ if (Math.abs(denominator) < 1e-6) return null;
2796
+ const wA = ((b.y - c.y) * (x - c.x) + (c.x - b.x) * (y - c.y)) / denominator;
2797
+ const wB = ((c.y - a.y) * (x - c.x) + (a.x - c.x) * (y - c.y)) / denominator;
2798
+ const wC = 1 - wA - wB;
2799
+ if (wA < -1e-4 || wB < -1e-4 || wC < -1e-4) return null;
2800
+ return [
2801
+ wA,
2802
+ wB,
2803
+ wC
2804
+ ];
2805
+ }
2806
+ function mixTriangleColor$1(weights, a, b, c) {
2807
+ const [wA, wB, wC] = weights;
2808
+ return [
2809
+ Math.round((a.color[0] * wA + b.color[0] * wB + c.color[0] * wC) * 255),
2810
+ Math.round((a.color[1] * wA + b.color[1] * wB + c.color[1] * wC) * 255),
2811
+ Math.round((a.color[2] * wA + b.color[2] * wB + c.color[2] * wC) * 255),
2812
+ a.color[3] * wA + b.color[3] * wB + c.color[3] * wC
2813
+ ];
2814
+ }
2815
+ function encodeSvgDataUrl(svg) {
2816
+ return `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
2817
+ }
2818
+ var ModuleTransformerMeshGradientToCss = class {
2819
+ target = "css";
2820
+ gradientType = "mesh-gradient";
2821
+ to(input) {
2822
+ if (!(input instanceof MeshGradient)) throw new Error("Expected MeshGradient");
2823
+ const vertexMap = buildMeshVertexMap(input, CSS_SAMPLE_SIZE, CSS_SAMPLE_SIZE);
2824
+ const grid = buildRegularMeshGrid(input, vertexMap);
2825
+ const subdivisions = input.config.method === "bicubic" ? BICUBIC_SUBDIVISIONS$2 : 1;
2826
+ const triangles = input.patches.flatMap((patch) => buildPatchTriangles(input, grid, patch, vertexMap, subdivisions));
2827
+ const edgeTriangles = buildMeshEdgeSkirtTriangles(input, grid, CSS_SAMPLE_SIZE, CSS_SAMPLE_SIZE, subdivisions);
2828
+ const renderTriangles = [...triangles, ...edgeTriangles];
2829
+ const rects = [];
2830
+ for (let y = 0; y < CSS_SAMPLE_SIZE; y += 1) for (let x = 0; x < CSS_SAMPLE_SIZE; x += 1) {
2831
+ const sampleX = x + .5;
2832
+ const sampleY = y + .5;
2833
+ let color = null;
2834
+ for (const [a, b, c] of renderTriangles) {
2835
+ const weights = getBarycentric$1(sampleX, sampleY, a, b, c);
2836
+ if (!weights) continue;
2837
+ color = mixTriangleColor$1(weights, a, b, c);
2838
+ break;
2839
+ }
2840
+ if (!color) continue;
2841
+ rects.push(`<rect x="${x}" y="${y}" width="1" height="1" fill="${formatRgba(color)}"/>`);
2842
+ }
2843
+ return encodeSvgDataUrl([
2844
+ `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${CSS_SAMPLE_SIZE} ${CSS_SAMPLE_SIZE}" preserveAspectRatio="none" shape-rendering="crispEdges">`,
2845
+ ...rects,
2846
+ "</svg>"
2847
+ ].join(""));
2848
+ }
2849
+ };
2850
+ //#endregion
2851
+ //#region src/gradient-transformer/modules/canvas/ModuleTransformerLinearGradientToCanvas.ts
2852
+ const toRgb$7 = converter("rgb");
2853
+ function toCanvasColor$2(input) {
2854
+ const color = toRgb$7(input);
2855
+ if (!color) throw new Error(`Failed to convert color: ${input}`);
2856
+ return formatRgb(color);
2857
+ }
2858
+ function getStopRange$2(stops) {
2859
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
2860
+ if (!colorStops.length) return {
2861
+ min: 0,
2862
+ max: 1,
2863
+ stops: []
2864
+ };
2865
+ return {
2866
+ min: Math.min(...colorStops.map((stop) => stop.position)),
2867
+ max: Math.max(...colorStops.map((stop) => stop.position)),
2868
+ stops: colorStops
2869
+ };
2870
+ }
2871
+ function normalizeStops$4(stops, min, max) {
2872
+ const range = max - min || 1;
2873
+ return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
2874
+ ...stop,
2875
+ position: (stop.position - min) / range
2876
+ }));
2877
+ }
2878
+ var ModuleTransformerLinearGradientToCanvas = class {
2879
+ target = "canvas-2d";
2880
+ gradientType = "linear-gradient";
2881
+ to(input) {
2882
+ const gradient = input;
2883
+ return { draw: (ctx, width, height) => {
2884
+ const angle = gradient.config.angle;
2885
+ const dirX = Math.sin(angle);
2886
+ const dirY = -Math.cos(angle);
2887
+ const centerX = width / 2;
2888
+ const centerY = height / 2;
2889
+ const lineLength = Math.abs(width * dirX) + Math.abs(height * dirY);
2890
+ let startX = centerX - dirX * lineLength / 2;
2891
+ let startY = centerY - dirY * lineLength / 2;
2892
+ let endX = centerX + dirX * lineLength / 2;
2893
+ let endY = centerY + dirY * lineLength / 2;
2894
+ const { min, max, stops } = getStopRange$2(resolveRenderableGradientStops(gradient));
2895
+ let normalizedStops = stops;
2896
+ if (min < 0 || max > 1) {
2897
+ const vx = endX - startX;
2898
+ const vy = endY - startY;
2899
+ const baseStartX = startX;
2900
+ const baseStartY = startY;
2901
+ startX = baseStartX + vx * min;
2902
+ startY = baseStartY + vy * min;
2903
+ endX = baseStartX + vx * max;
2904
+ endY = baseStartY + vy * max;
2905
+ normalizedStops = normalizeStops$4(stops, min, max);
2906
+ }
2907
+ const canvasGradient = ctx.createLinearGradient(startX, startY, endX, endY);
2908
+ for (const stop of normalizedStops) canvasGradient.addColorStop(stop.position, toCanvasColor$2(stop.value));
2909
+ ctx.clearRect(0, 0, width, height);
2910
+ ctx.fillStyle = canvasGradient;
2911
+ ctx.fillRect(0, 0, width, height);
2912
+ } };
2913
+ }
2914
+ };
2915
+ //#endregion
2916
+ //#region src/gradient-transformer/modules/canvas/ModuleTransformerRadialGradientToCanvas.ts
2917
+ const toRgb$6 = converter("rgb");
2918
+ const RADIAL_GRADIENT_SAMPLE_COUNT = 128;
2919
+ function toCanvasColor$1(input) {
2920
+ const color = toRgb$6(input);
2921
+ if (!color) throw new Error(`Failed to convert color: ${input}`);
2922
+ return formatRgb(color);
2923
+ }
2924
+ function getStopRange$1(stops) {
2925
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
2926
+ if (!colorStops.length) return {
2927
+ min: 0,
2928
+ max: 1,
2929
+ stops: []
2930
+ };
2931
+ return {
2932
+ min: Math.min(...colorStops.map((stop) => stop.position)),
2933
+ max: Math.max(...colorStops.map((stop) => stop.position)),
2934
+ stops: colorStops
2935
+ };
2936
+ }
2937
+ function normalizeStops$3(stops, min, max) {
2938
+ const range = max - min || 1;
2939
+ return stops.map((stop) => ({
2940
+ ...stop,
2941
+ position: (stop.position - min) / range
2942
+ }));
2943
+ }
2944
+ function getDistanceToSide$1(center, width, height, side) {
2945
+ if (side === "left") return center.x;
2946
+ if (side === "right") return width - center.x;
2947
+ if (side === "top") return center.y;
2948
+ return height - center.y;
2949
+ }
2950
+ function getDistanceToCorner$3(center, corner) {
2951
+ const dx = corner.x - center.x;
2952
+ const dy = corner.y - center.y;
2953
+ return Math.sqrt(dx * dx + dy * dy);
2954
+ }
2955
+ function getCornerDeltas$3(center, width, height) {
2956
+ return [
2957
+ {
1928
2958
  dx: -center.x,
1929
2959
  dy: -center.y
1930
2960
  },
@@ -1965,9 +2995,9 @@ var ModuleTransformerRadialGradientToCanvas = class {
1965
2995
  let normalizedStops = stops;
1966
2996
  let innerFactor = 0;
1967
2997
  let outerFactor = gradient.isRepeating ? maxVisibleT : 1;
1968
- if (gradient.isRepeating) normalizedStops = normalizeStops$2(stops, 0, maxVisibleT);
2998
+ if (gradient.isRepeating) normalizedStops = normalizeStops$3(stops, 0, maxVisibleT);
1969
2999
  else if (min < 0 || max > 1) {
1970
- normalizedStops = normalizeStops$2(stops, min, max);
3000
+ normalizedStops = normalizeStops$3(stops, min, max);
1971
3001
  innerFactor = min;
1972
3002
  outerFactor = max;
1973
3003
  }
@@ -1976,25 +3006,263 @@ var ModuleTransformerRadialGradientToCanvas = class {
1976
3006
  const innerRadius = Math.max(0, baseRadius * innerFactor);
1977
3007
  const outerRadius = Math.max(innerRadius + 1e-4, baseRadius * outerFactor);
1978
3008
  const g = ctx.createRadialGradient(center.x, center.y, innerRadius, center.x, center.y, outerRadius);
1979
- for (const stop of normalizedStops) g.addColorStop(stop.position, toCanvasColor(stop.value));
3009
+ for (const stop of normalizedStops) g.addColorStop(stop.position, toCanvasColor$1(stop.value));
1980
3010
  ctx.fillStyle = g;
1981
3011
  ctx.fillRect(0, 0, width, height);
1982
3012
  return;
1983
3013
  }
1984
- const outerRadius = Math.max(radii.x, radii.y);
1985
- const scaleX = radii.x / outerRadius;
1986
- const scaleY = radii.y / outerRadius;
1987
- const innerRadius = Math.max(0, outerRadius * innerFactor);
1988
- const scaledOuterRadius = Math.max(innerRadius + 1e-4, outerRadius * outerFactor);
1989
- ctx.save();
1990
- ctx.translate(center.x, center.y);
1991
- ctx.scale(scaleX, scaleY);
1992
- const g = ctx.createRadialGradient(0, 0, innerRadius, 0, 0, scaledOuterRadius);
1993
- for (const stop of normalizedStops) g.addColorStop(stop.position, toCanvasColor(stop.value));
1994
- ctx.fillStyle = g;
1995
- const drawRadius = scaledOuterRadius + 2;
1996
- ctx.fillRect(-drawRadius / scaleX * 2, -drawRadius / scaleY * 2, drawRadius / scaleX * 4, drawRadius / scaleY * 4);
1997
- ctx.restore();
3014
+ const outerRadius = Math.max(radii.x, radii.y);
3015
+ const scaleX = radii.x / outerRadius;
3016
+ const scaleY = radii.y / outerRadius;
3017
+ const innerRadius = Math.max(0, outerRadius * innerFactor);
3018
+ const scaledOuterRadius = Math.max(innerRadius + 1e-4, outerRadius * outerFactor);
3019
+ ctx.save();
3020
+ ctx.translate(center.x, center.y);
3021
+ ctx.scale(scaleX, scaleY);
3022
+ const g = ctx.createRadialGradient(0, 0, innerRadius, 0, 0, scaledOuterRadius);
3023
+ for (const stop of normalizedStops) g.addColorStop(stop.position, toCanvasColor$1(stop.value));
3024
+ ctx.fillStyle = g;
3025
+ const drawRadius = scaledOuterRadius + 2;
3026
+ ctx.fillRect(-drawRadius / scaleX * 2, -drawRadius / scaleY * 2, drawRadius / scaleX * 4, drawRadius / scaleY * 4);
3027
+ ctx.restore();
3028
+ } };
3029
+ }
3030
+ _resolveCenter(position, width, height) {
3031
+ if (position.kind === "keywords") return {
3032
+ x: this._resolveKeywordX(position.x, width),
3033
+ y: this._resolveKeywordY(position.y, height)
3034
+ };
3035
+ return {
3036
+ x: this._resolve(position.x, width),
3037
+ y: this._resolve(position.y, height)
3038
+ };
3039
+ }
3040
+ _resolveKeywordX(value, width) {
3041
+ if (value === "left") return 0;
3042
+ if (value === "center") return width / 2;
3043
+ return width;
3044
+ }
3045
+ _resolveKeywordY(value, height) {
3046
+ if (value === "top") return 0;
3047
+ if (value === "center") return height / 2;
3048
+ return height;
3049
+ }
3050
+ _resolveRadialRadii(size, shape, center, width, height) {
3051
+ if (size.kind === "explicit") {
3052
+ const radiusX = this._resolve(size.x, width);
3053
+ const radiusY = size.y ? this._resolve(size.y, height) : radiusX;
3054
+ return {
3055
+ x: Math.max(radiusX, 1e-4),
3056
+ y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
3057
+ };
3058
+ }
3059
+ const left = getDistanceToSide$1(center, width, height, "left");
3060
+ const right = getDistanceToSide$1(center, width, height, "right");
3061
+ const top = getDistanceToSide$1(center, width, height, "top");
3062
+ const bottom = getDistanceToSide$1(center, width, height, "bottom");
3063
+ if (shape === "circle") {
3064
+ const cornerDistances = [
3065
+ {
3066
+ x: 0,
3067
+ y: 0
3068
+ },
3069
+ {
3070
+ x: width,
3071
+ y: 0
3072
+ },
3073
+ {
3074
+ x: 0,
3075
+ y: height
3076
+ },
3077
+ {
3078
+ x: width,
3079
+ y: height
3080
+ }
3081
+ ].map((corner) => getDistanceToCorner$3(center, corner));
3082
+ if (size.value === "closest-side") {
3083
+ const radius = Math.min(left, right, top, bottom);
3084
+ return {
3085
+ x: radius,
3086
+ y: radius
3087
+ };
3088
+ }
3089
+ if (size.value === "farthest-side") {
3090
+ const radius = Math.max(left, right, top, bottom);
3091
+ return {
3092
+ x: radius,
3093
+ y: radius
3094
+ };
3095
+ }
3096
+ if (size.value === "closest-corner") {
3097
+ const radius = Math.min(...cornerDistances);
3098
+ return {
3099
+ x: radius,
3100
+ y: radius
3101
+ };
3102
+ }
3103
+ const radius = Math.max(...cornerDistances);
3104
+ return {
3105
+ x: radius,
3106
+ y: radius
3107
+ };
3108
+ }
3109
+ const closestSideRadiusX = Math.min(left, right);
3110
+ const closestSideRadiusY = Math.min(top, bottom);
3111
+ const farthestSideRadiusX = Math.max(left, right);
3112
+ const farthestSideRadiusY = Math.max(top, bottom);
3113
+ if (size.value === "closest-side") return {
3114
+ x: Math.max(closestSideRadiusX, 1e-4),
3115
+ y: Math.max(closestSideRadiusY, 1e-4)
3116
+ };
3117
+ if (size.value === "farthest-side") return {
3118
+ x: Math.max(farthestSideRadiusX, 1e-4),
3119
+ y: Math.max(farthestSideRadiusY, 1e-4)
3120
+ };
3121
+ const corners = getCornerDeltas$3(center, width, height);
3122
+ if (size.value === "closest-corner") return corners.map((corner) => scaleEllipseRadiiToCorner$1(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => {
3123
+ const closestArea = closest.x * closest.y;
3124
+ return current.x * current.y < closestArea ? current : closest;
3125
+ });
3126
+ return corners.map((corner) => scaleEllipseRadiiToCorner$1(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => {
3127
+ const farthestArea = farthest.x * farthest.y;
3128
+ return current.x * current.y > farthestArea ? current : farthest;
3129
+ });
3130
+ }
3131
+ _resolve(value, size) {
3132
+ if (value.kind === "percent") return value.value / 100 * size;
3133
+ if (value.unit === "px") return value.value;
3134
+ return value.value;
3135
+ }
3136
+ };
3137
+ //#endregion
3138
+ //#region src/gradient-transformer/modules/canvas/ModuleTransformerDiamondGradientToCanvas.ts
3139
+ const toRgb$5 = converter("rgb");
3140
+ const DIAMOND_GRADIENT_SAMPLE_COUNT = 128;
3141
+ const DIAMOND_COLOR_LOOKUP_SIZE = 1024;
3142
+ function toCanvasColor(input) {
3143
+ const color = toRgb$5(input);
3144
+ if (!color) throw new Error(`Failed to convert color: ${input}`);
3145
+ return [
3146
+ Math.round((color.r ?? 0) * 255),
3147
+ Math.round((color.g ?? 0) * 255),
3148
+ Math.round((color.b ?? 0) * 255),
3149
+ Math.round((color.alpha ?? 1) * 255)
3150
+ ];
3151
+ }
3152
+ function getColorStops(stops) {
3153
+ return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
3154
+ }
3155
+ function sampleColorAtPosition(stops, position) {
3156
+ if (stops.length === 0) throw new Error("Cannot sample color from empty diamond gradient stops.");
3157
+ if (stops.length === 1 || position <= stops[0].position) return toCanvasColor(stops[0].value);
3158
+ const lastStop = stops[stops.length - 1];
3159
+ if (position >= lastStop.position) return toCanvasColor(lastStop.value);
3160
+ for (let index = 0; index < stops.length - 1; index += 1) {
3161
+ const current = stops[index];
3162
+ const next = stops[index + 1];
3163
+ if (position >= current.position && position <= next.position) {
3164
+ const range = next.position - current.position || 1;
3165
+ const localT = (position - current.position) / range;
3166
+ const currentColor = toCanvasColor(current.value);
3167
+ const nextColor = toCanvasColor(next.value);
3168
+ return [
3169
+ Math.round(currentColor[0] + (nextColor[0] - currentColor[0]) * localT),
3170
+ Math.round(currentColor[1] + (nextColor[1] - currentColor[1]) * localT),
3171
+ Math.round(currentColor[2] + (nextColor[2] - currentColor[2]) * localT),
3172
+ Math.round(currentColor[3] + (nextColor[3] - currentColor[3]) * localT)
3173
+ ];
3174
+ }
3175
+ }
3176
+ return toCanvasColor(lastStop.value);
3177
+ }
3178
+ function buildColorLookup(stops, maxT) {
3179
+ const lookup = new Uint8ClampedArray(DIAMOND_COLOR_LOOKUP_SIZE * 4);
3180
+ for (let index = 0; index < DIAMOND_COLOR_LOOKUP_SIZE; index += 1) {
3181
+ const color = sampleColorAtPosition(stops, index / (DIAMOND_COLOR_LOOKUP_SIZE - 1) * maxT);
3182
+ const offset = index * 4;
3183
+ lookup[offset] = color[0];
3184
+ lookup[offset + 1] = color[1];
3185
+ lookup[offset + 2] = color[2];
3186
+ lookup[offset + 3] = color[3];
3187
+ }
3188
+ return lookup;
3189
+ }
3190
+ function getMaxVisibleDiamondT$1(center, radii, width, height) {
3191
+ return Math.max(...[
3192
+ {
3193
+ x: 0,
3194
+ y: 0
3195
+ },
3196
+ {
3197
+ x: width,
3198
+ y: 0
3199
+ },
3200
+ {
3201
+ x: 0,
3202
+ y: height
3203
+ },
3204
+ {
3205
+ x: width,
3206
+ y: height
3207
+ }
3208
+ ].map((corner) => Math.abs(corner.x - center.x) / Math.max(radii.x, 1e-4) + Math.abs(corner.y - center.y) / Math.max(radii.y, 1e-4)));
3209
+ }
3210
+ function getDistanceToCorner$2(center, corner) {
3211
+ return Math.abs(corner.x - center.x) + Math.abs(corner.y - center.y);
3212
+ }
3213
+ function getCornerDeltas$2(center, width, height) {
3214
+ return [
3215
+ {
3216
+ dx: -center.x,
3217
+ dy: -center.y
3218
+ },
3219
+ {
3220
+ dx: width - center.x,
3221
+ dy: -center.y
3222
+ },
3223
+ {
3224
+ dx: -center.x,
3225
+ dy: height - center.y
3226
+ },
3227
+ {
3228
+ dx: width - center.x,
3229
+ dy: height - center.y
3230
+ }
3231
+ ];
3232
+ }
3233
+ function scaleDiamondRadiiToCorner$1(radiusX, radiusY, dx, dy) {
3234
+ const safeRadiusX = Math.max(radiusX, 1e-4);
3235
+ const safeRadiusY = Math.max(radiusY, 1e-4);
3236
+ const scale = Math.abs(dx) / safeRadiusX + Math.abs(dy) / safeRadiusY;
3237
+ return {
3238
+ x: safeRadiusX * scale,
3239
+ y: safeRadiusY * scale
3240
+ };
3241
+ }
3242
+ var ModuleTransformerDiamondGradientToCanvas = class {
3243
+ target = "canvas-2d";
3244
+ gradientType = "diamond-gradient";
3245
+ to(input) {
3246
+ if (!(input instanceof DiamondGradient)) throw new Error("Expected DiamondGradient");
3247
+ const gradient = input;
3248
+ return { draw: (ctx, width, height) => {
3249
+ const center = this._resolveCenter(gradient.config.position, width, height);
3250
+ const radii = this._resolveDiamondRadii(gradient.config.size, gradient.config.shape, center, width, height);
3251
+ const maxVisibleT = getMaxVisibleDiamondT$1(center, radii, width, height);
3252
+ const baseStops = resolveRenderableGradientStops(gradient, DIAMOND_GRADIENT_SAMPLE_COUNT);
3253
+ const colorLookup = buildColorLookup(getColorStops(gradient.isRepeating ? expandRepeatingStopsTo(baseStops, 0, maxVisibleT) : baseStops), maxVisibleT);
3254
+ const imageData = ctx.createImageData(width, height);
3255
+ const data = imageData.data;
3256
+ for (let y = 0; y < height; y += 1) for (let x = 0; x < width; x += 1) {
3257
+ const t = Math.abs(x - center.x) / Math.max(radii.x, 1e-4) + Math.abs(y - center.y) / Math.max(radii.y, 1e-4);
3258
+ const lookupOffset = Math.min(DIAMOND_COLOR_LOOKUP_SIZE - 1, Math.max(0, Math.round(t / Math.max(maxVisibleT, 1e-4) * (DIAMOND_COLOR_LOOKUP_SIZE - 1)))) * 4;
3259
+ const offset = (y * width + x) * 4;
3260
+ data[offset] = colorLookup[lookupOffset];
3261
+ data[offset + 1] = colorLookup[lookupOffset + 1];
3262
+ data[offset + 2] = colorLookup[lookupOffset + 2];
3263
+ data[offset + 3] = colorLookup[lookupOffset + 3];
3264
+ }
3265
+ ctx.putImageData(imageData, 0, 0);
1998
3266
  } };
1999
3267
  }
2000
3268
  _resolveCenter(position, width, height) {
@@ -2017,7 +3285,7 @@ var ModuleTransformerRadialGradientToCanvas = class {
2017
3285
  if (value === "center") return height / 2;
2018
3286
  return height;
2019
3287
  }
2020
- _resolveRadialRadii(size, shape, center, width, height) {
3288
+ _resolveDiamondRadii(size, shape, center, width, height) {
2021
3289
  if (size.kind === "explicit") {
2022
3290
  const radiusX = this._resolve(size.x, width);
2023
3291
  const radiusY = size.y ? this._resolve(size.y, height) : radiusX;
@@ -2026,10 +3294,10 @@ var ModuleTransformerRadialGradientToCanvas = class {
2026
3294
  y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
2027
3295
  };
2028
3296
  }
2029
- const left = getDistanceToSide$1(center, width, height, "left");
2030
- const right = getDistanceToSide$1(center, width, height, "right");
2031
- const top = getDistanceToSide$1(center, width, height, "top");
2032
- const bottom = getDistanceToSide$1(center, width, height, "bottom");
3297
+ const left = center.x;
3298
+ const right = width - center.x;
3299
+ const top = center.y;
3300
+ const bottom = height - center.y;
2033
3301
  if (shape === "circle") {
2034
3302
  const cornerDistances = [
2035
3303
  {
@@ -2048,29 +3316,29 @@ var ModuleTransformerRadialGradientToCanvas = class {
2048
3316
  x: width,
2049
3317
  y: height
2050
3318
  }
2051
- ].map((corner) => getDistanceToCorner$1(center, corner));
3319
+ ].map((corner) => getDistanceToCorner$2(center, corner));
2052
3320
  if (size.value === "closest-side") {
2053
- const radius = Math.min(left, right, top, bottom);
3321
+ const radius = Math.max(Math.min(left, right, top, bottom), 1e-4);
2054
3322
  return {
2055
3323
  x: radius,
2056
3324
  y: radius
2057
3325
  };
2058
3326
  }
2059
3327
  if (size.value === "farthest-side") {
2060
- const radius = Math.max(left, right, top, bottom);
3328
+ const radius = Math.max(Math.max(left, right, top, bottom), 1e-4);
2061
3329
  return {
2062
3330
  x: radius,
2063
3331
  y: radius
2064
3332
  };
2065
3333
  }
2066
3334
  if (size.value === "closest-corner") {
2067
- const radius = Math.min(...cornerDistances);
3335
+ const radius = Math.max(Math.min(...cornerDistances), 1e-4);
2068
3336
  return {
2069
3337
  x: radius,
2070
3338
  y: radius
2071
3339
  };
2072
3340
  }
2073
- const radius = Math.max(...cornerDistances);
3341
+ const radius = Math.max(Math.max(...cornerDistances), 1e-4);
2074
3342
  return {
2075
3343
  x: radius,
2076
3344
  y: radius
@@ -2088,26 +3356,20 @@ var ModuleTransformerRadialGradientToCanvas = class {
2088
3356
  x: Math.max(farthestSideRadiusX, 1e-4),
2089
3357
  y: Math.max(farthestSideRadiusY, 1e-4)
2090
3358
  };
2091
- const corners = getCornerDeltas$1(center, width, height);
2092
- if (size.value === "closest-corner") return corners.map((corner) => scaleEllipseRadiiToCorner$1(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => {
2093
- const closestArea = closest.x * closest.y;
2094
- return current.x * current.y < closestArea ? current : closest;
2095
- });
2096
- return corners.map((corner) => scaleEllipseRadiiToCorner$1(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => {
2097
- const farthestArea = farthest.x * farthest.y;
2098
- return current.x * current.y > farthestArea ? current : farthest;
2099
- });
3359
+ const corners = getCornerDeltas$2(center, width, height);
3360
+ if (size.value === "closest-corner") return corners.map((corner) => scaleDiamondRadiiToCorner$1(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => current.x * current.y < closest.x * closest.y ? current : closest);
3361
+ return corners.map((corner) => scaleDiamondRadiiToCorner$1(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => current.x * current.y > farthest.x * farthest.y ? current : farthest);
2100
3362
  }
2101
3363
  _resolve(value, size) {
2102
3364
  if (value.kind === "percent") return value.value / 100 * size;
2103
3365
  if (value.unit === "px") return value.value;
2104
- return value.value;
3366
+ throw new Error(`Unsupported diamond-gradient length unit for Canvas transformer: ${value.unit}`);
2105
3367
  }
2106
3368
  };
2107
3369
  //#endregion
2108
3370
  //#region src/gradient-transformer/modules/canvas/ModuleTransformerConicGradientToCanvas.ts
2109
3371
  const CONIC_GRADIENT_SAMPLE_COUNT = 128;
2110
- const toRgb$3 = converter("rgb");
3372
+ const toRgb$4 = converter("rgb");
2111
3373
  var ModuleTransformerConicGradientToCanvas = class {
2112
3374
  target = "canvas-2d";
2113
3375
  gradientType = "conic-gradient";
@@ -2207,7 +3469,7 @@ var ModuleTransformerConicGradientToCanvas = class {
2207
3469
  };
2208
3470
  }
2209
3471
  _parseColor(input) {
2210
- const color = toRgb$3(input);
3472
+ const color = toRgb$4(input);
2211
3473
  if (!color) throw new Error(`Failed to convert color: ${input}`);
2212
3474
  return {
2213
3475
  r: Math.round((color.r ?? 0) * 255),
@@ -2221,9 +3483,310 @@ var ModuleTransformerConicGradientToCanvas = class {
2221
3483
  }
2222
3484
  };
2223
3485
  //#endregion
2224
- //#region src/gradient-transformer/modules/webgl/ModuleTransformerLinearGradientToWebgl.ts
3486
+ //#region src/gradient-transformer/modules/canvas/ModuleTransformerMeshGradientToCanvas.ts
3487
+ const BICUBIC_SUBDIVISIONS$1 = 24;
3488
+ function getBarycentric(x, y, a, b, c) {
3489
+ const denominator = (b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y);
3490
+ if (Math.abs(denominator) < 1e-6) return null;
3491
+ const wA = ((b.y - c.y) * (x - c.x) + (c.x - b.x) * (y - c.y)) / denominator;
3492
+ const wB = ((c.y - a.y) * (x - c.x) + (a.x - c.x) * (y - c.y)) / denominator;
3493
+ const wC = 1 - wA - wB;
3494
+ const epsilon = -1e-4;
3495
+ if (wA < epsilon || wB < epsilon || wC < epsilon) return null;
3496
+ return [
3497
+ wA,
3498
+ wB,
3499
+ wC
3500
+ ];
3501
+ }
3502
+ function mixTriangleColor(weights, a, b, c) {
3503
+ const [wA, wB, wC] = weights;
3504
+ return [
3505
+ Math.round((a.color[0] * wA + b.color[0] * wB + c.color[0] * wC) * 255),
3506
+ Math.round((a.color[1] * wA + b.color[1] * wB + c.color[1] * wC) * 255),
3507
+ Math.round((a.color[2] * wA + b.color[2] * wB + c.color[2] * wC) * 255),
3508
+ Math.round((a.color[3] * wA + b.color[3] * wB + c.color[3] * wC) * 255)
3509
+ ];
3510
+ }
3511
+ function fillTriangle(data, width, height, a, b, c) {
3512
+ const minX = Math.max(0, Math.floor(Math.min(a.x, b.x, c.x)));
3513
+ const maxX = Math.min(width - 1, Math.ceil(Math.max(a.x, b.x, c.x)));
3514
+ const minY = Math.max(0, Math.floor(Math.min(a.y, b.y, c.y)));
3515
+ const maxY = Math.min(height - 1, Math.ceil(Math.max(a.y, b.y, c.y)));
3516
+ for (let y = minY; y <= maxY; y += 1) for (let x = minX; x <= maxX; x += 1) {
3517
+ const weights = getBarycentric(x + .5, y + .5, a, b, c);
3518
+ if (!weights) continue;
3519
+ const color = mixTriangleColor(weights, a, b, c);
3520
+ const offset = (y * width + x) * 4;
3521
+ data[offset] = color[0];
3522
+ data[offset + 1] = color[1];
3523
+ data[offset + 2] = color[2];
3524
+ data[offset + 3] = color[3];
3525
+ }
3526
+ }
3527
+ var ModuleTransformerMeshGradientToCanvas = class {
3528
+ target = "canvas-2d";
3529
+ gradientType = "mesh-gradient";
3530
+ to(input) {
3531
+ if (!(input instanceof MeshGradient)) throw new Error("Expected MeshGradient");
3532
+ const gradient = input;
3533
+ return { draw: (ctx, width, height) => {
3534
+ const imageData = ctx.createImageData(width, height);
3535
+ const vertexMap = buildMeshVertexMap(gradient, width, height);
3536
+ const grid = buildRegularMeshGrid(gradient, vertexMap);
3537
+ const subdivisions = gradient.config.method === "bicubic" ? BICUBIC_SUBDIVISIONS$1 : 1;
3538
+ const edgeTriangles = buildMeshEdgeSkirtTriangles(gradient, grid, width, height, subdivisions);
3539
+ for (const patch of gradient.patches) {
3540
+ const triangles = buildPatchTriangles(gradient, grid, patch, vertexMap, subdivisions);
3541
+ for (const [a, b, c] of triangles) fillTriangle(imageData.data, width, height, a, b, c);
3542
+ }
3543
+ for (const [a, b, c] of edgeTriangles) fillTriangle(imageData.data, width, height, a, b, c);
3544
+ ctx.putImageData(imageData, 0, 0);
3545
+ } };
3546
+ }
3547
+ };
3548
+ //#endregion
3549
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerLinearGradientToWebgl.ts
3550
+ const toRgb$3 = converter("rgb");
3551
+ const MAX_STOPS$3 = 128;
3552
+ function toWebGLColor$3(input) {
3553
+ const color = toRgb$3(input);
3554
+ if (!color) throw new Error(`Failed to convert color: ${input}`);
3555
+ return [
3556
+ color.r ?? 0,
3557
+ color.g ?? 0,
3558
+ color.b ?? 0,
3559
+ color.alpha ?? 1
3560
+ ];
3561
+ }
3562
+ function getStopRange(stops) {
3563
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
3564
+ if (!colorStops.length) return {
3565
+ min: 0,
3566
+ max: 1,
3567
+ stops: []
3568
+ };
3569
+ return {
3570
+ min: Math.min(...colorStops.map((stop) => stop.position)),
3571
+ max: Math.max(...colorStops.map((stop) => stop.position)),
3572
+ stops: colorStops
3573
+ };
3574
+ }
3575
+ function normalizeStops$2(stops, min, max) {
3576
+ const range = max - min || 1;
3577
+ return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
3578
+ ...stop,
3579
+ position: (stop.position - min) / range
3580
+ }));
3581
+ }
3582
+ function createShader$4(gl, type, source) {
3583
+ const shader = gl.createShader(type);
3584
+ if (!shader) throw new Error("Failed to create WebGL shader.");
3585
+ gl.shaderSource(shader, source);
3586
+ gl.compileShader(shader);
3587
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
3588
+ const error = gl.getShaderInfoLog(shader);
3589
+ gl.deleteShader(shader);
3590
+ throw new Error(`WebGL shader compile error: ${error}`);
3591
+ }
3592
+ return shader;
3593
+ }
3594
+ function createProgram$4(gl, vertexSource, fragmentSource) {
3595
+ const vertexShader = createShader$4(gl, gl.VERTEX_SHADER, vertexSource);
3596
+ const fragmentShader = createShader$4(gl, gl.FRAGMENT_SHADER, fragmentSource);
3597
+ const program = gl.createProgram();
3598
+ if (!program) throw new Error("Failed to create WebGL program.");
3599
+ gl.attachShader(program, vertexShader);
3600
+ gl.attachShader(program, fragmentShader);
3601
+ gl.linkProgram(program);
3602
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
3603
+ const error = gl.getProgramInfoLog(program);
3604
+ gl.deleteProgram(program);
3605
+ throw new Error(`WebGL program link error: ${error}`);
3606
+ }
3607
+ return program;
3608
+ }
3609
+ function getColorStopCount$3(stops) {
3610
+ return stops.filter((stop) => stop.type === "color-stop").length;
3611
+ }
3612
+ function getWebGLSampleCount$3(gradient, maxStops) {
3613
+ const colorStopCount = getColorStopCount$3(gradient.stops);
3614
+ const segmentCount = Math.max(1, colorStopCount - 1);
3615
+ return Math.max(2, Math.floor((maxStops - 1) / segmentCount));
3616
+ }
3617
+ function getColorAtPosition$3(stops, position) {
3618
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
3619
+ if (colorStops.length === 0) throw new Error("Cannot sample color from empty gradient stops.");
3620
+ if (position <= colorStops[0].position) return colorStops[0].value;
3621
+ const lastStop = colorStops[colorStops.length - 1];
3622
+ if (position >= lastStop.position) return lastStop.value;
3623
+ for (let index = 0; index < colorStops.length - 1; index += 1) {
3624
+ const current = colorStops[index];
3625
+ const next = colorStops[index + 1];
3626
+ if (position >= current.position && position <= next.position) {
3627
+ const range = next.position - current.position || 1;
3628
+ const localT = (position - current.position) / range;
3629
+ return formatRgb(interpolate([current.value, next.value], "rgb")(localT));
3630
+ }
3631
+ }
3632
+ return lastStop.value;
3633
+ }
3634
+ function fitStopsToWebGLLimit$3(stops, maxStops) {
3635
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
3636
+ if (colorStops.length <= maxStops) return colorStops;
3637
+ const sampledStops = [];
3638
+ for (let index = 0; index < maxStops; index += 1) {
3639
+ const position = index / (maxStops - 1);
3640
+ sampledStops.push({
3641
+ type: "color-stop",
3642
+ value: getColorAtPosition$3(colorStops, position),
3643
+ position
3644
+ });
3645
+ }
3646
+ return sampledStops;
3647
+ }
3648
+ var ModuleTransformerLinearGradientToCanvasWebGL = class {
3649
+ target = "canvas-webgl";
3650
+ gradientType = "linear-gradient";
3651
+ to(input) {
3652
+ const gradient = input;
3653
+ return { draw: (canvas, width, height) => {
3654
+ const gl = canvas.getContext("webgl");
3655
+ if (!gl) throw new Error("WebGL is not supported.");
3656
+ canvas.width = width;
3657
+ canvas.height = height;
3658
+ gl.viewport(0, 0, width, height);
3659
+ const program = createProgram$4(gl, `
3660
+ attribute vec2 a_position;
3661
+ varying vec2 v_uv;
3662
+
3663
+ void main() {
3664
+ v_uv = a_position * 0.5 + 0.5;
3665
+ gl_Position = vec4(a_position, 0.0, 1.0);
3666
+ }
3667
+ `, `
3668
+ precision mediump float;
3669
+
3670
+ varying vec2 v_uv;
3671
+
3672
+ uniform vec2 u_start;
3673
+ uniform vec2 u_end;
3674
+ uniform int u_stopCount;
3675
+ uniform float u_positions[${MAX_STOPS$3}];
3676
+ uniform vec4 u_colors[${MAX_STOPS$3}];
3677
+
3678
+ vec4 getGradientColor(float t) {
3679
+ vec4 result = u_colors[0];
3680
+
3681
+ for (int i = 0; i < ${MAX_STOPS$3 - 1}; i++) {
3682
+ if (i >= u_stopCount - 1) {
3683
+ break;
3684
+ }
3685
+
3686
+ float currentPosition = u_positions[i];
3687
+ float nextPosition = u_positions[i + 1];
3688
+
3689
+ if (t <= currentPosition) {
3690
+ return u_colors[i];
3691
+ }
3692
+
3693
+ if (t >= currentPosition && t <= nextPosition) {
3694
+ float localT = (t - currentPosition) / max(nextPosition - currentPosition, 0.00001);
3695
+ return mix(u_colors[i], u_colors[i + 1], localT);
3696
+ }
3697
+
3698
+ result = u_colors[i + 1];
3699
+ }
3700
+
3701
+ return result;
3702
+ }
3703
+
3704
+ void main() {
3705
+ vec2 axis = u_end - u_start;
3706
+ vec2 point = v_uv;
3707
+
3708
+ float axisLengthSquared = dot(axis, axis);
3709
+ float t = dot(point - u_start, axis) / axisLengthSquared;
3710
+
3711
+ t = clamp(t, 0.0, 1.0);
3712
+
3713
+ gl_FragColor = getGradientColor(t);
3714
+ }
3715
+ `);
3716
+ gl.useProgram(program);
3717
+ const positionBuffer = gl.createBuffer();
3718
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
3719
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
3720
+ -1,
3721
+ -1,
3722
+ 1,
3723
+ -1,
3724
+ -1,
3725
+ 1,
3726
+ -1,
3727
+ 1,
3728
+ 1,
3729
+ -1,
3730
+ 1,
3731
+ 1
3732
+ ]), gl.STATIC_DRAW);
3733
+ const positionLocation = gl.getAttribLocation(program, "a_position");
3734
+ gl.enableVertexAttribArray(positionLocation);
3735
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
3736
+ const angle = gradient.config.angle;
3737
+ const dirX = Math.sin(angle);
3738
+ const dirY = -Math.cos(angle);
3739
+ const centerX = width / 2;
3740
+ const centerY = height / 2;
3741
+ const lineLength = Math.abs(width * dirX) + Math.abs(height * dirY);
3742
+ let startX = centerX - dirX * lineLength / 2;
3743
+ let startY = centerY - dirY * lineLength / 2;
3744
+ let endX = centerX + dirX * lineLength / 2;
3745
+ let endY = centerY + dirY * lineLength / 2;
3746
+ const { min, max, stops } = getStopRange(resolveRenderableGradientStops(gradient, getWebGLSampleCount$3(gradient, MAX_STOPS$3)));
3747
+ let normalizedStops = stops;
3748
+ if (min < 0 || max > 1) {
3749
+ const vx = endX - startX;
3750
+ const vy = endY - startY;
3751
+ const baseStartX = startX;
3752
+ const baseStartY = startY;
3753
+ startX = baseStartX + vx * min;
3754
+ startY = baseStartY + vy * min;
3755
+ endX = baseStartX + vx * max;
3756
+ endY = baseStartY + vy * max;
3757
+ normalizedStops = normalizeStops$2(stops, min, max);
3758
+ }
3759
+ const startU = startX / width;
3760
+ const startV = 1 - startY / height;
3761
+ const endU = endX / width;
3762
+ const endV = 1 - endY / height;
3763
+ const limitedStops = fitStopsToWebGLLimit$3(normalizedStops, MAX_STOPS$3);
3764
+ const positions = new Float32Array(MAX_STOPS$3);
3765
+ const colors = new Float32Array(MAX_STOPS$3 * 4);
3766
+ limitedStops.forEach((stop, index) => {
3767
+ const color = toWebGLColor$3(stop.value);
3768
+ positions[index] = stop.position;
3769
+ colors[index * 4 + 0] = color[0];
3770
+ colors[index * 4 + 1] = color[1];
3771
+ colors[index * 4 + 2] = color[2];
3772
+ colors[index * 4 + 3] = color[3];
3773
+ });
3774
+ gl.uniform2f(gl.getUniformLocation(program, "u_start"), startU, startV);
3775
+ gl.uniform2f(gl.getUniformLocation(program, "u_end"), endU, endV);
3776
+ gl.uniform1i(gl.getUniformLocation(program, "u_stopCount"), limitedStops.length);
3777
+ gl.uniform1fv(gl.getUniformLocation(program, "u_positions"), positions);
3778
+ gl.uniform4fv(gl.getUniformLocation(program, "u_colors"), colors);
3779
+ gl.clearColor(0, 0, 0, 0);
3780
+ gl.clear(gl.COLOR_BUFFER_BIT);
3781
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
3782
+ } };
3783
+ }
3784
+ };
3785
+ //#endregion
3786
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerConicGradientToWebgl.ts
2225
3787
  const toRgb$2 = converter("rgb");
2226
3788
  const MAX_STOPS$2 = 128;
3789
+ const TWO_PI = Math.PI * 2;
2227
3790
  function toWebGLColor$2(input) {
2228
3791
  const color = toRgb$2(input);
2229
3792
  if (!color) throw new Error(`Failed to convert color: ${input}`);
@@ -2234,27 +3797,7 @@ function toWebGLColor$2(input) {
2234
3797
  color.alpha ?? 1
2235
3798
  ];
2236
3799
  }
2237
- function getStopRange(stops) {
2238
- const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
2239
- if (!colorStops.length) return {
2240
- min: 0,
2241
- max: 1,
2242
- stops: []
2243
- };
2244
- return {
2245
- min: Math.min(...colorStops.map((stop) => stop.position)),
2246
- max: Math.max(...colorStops.map((stop) => stop.position)),
2247
- stops: colorStops
2248
- };
2249
- }
2250
- function normalizeStops$1(stops, min, max) {
2251
- const range = max - min || 1;
2252
- return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
2253
- ...stop,
2254
- position: (stop.position - min) / range
2255
- }));
2256
- }
2257
- function createShader$2(gl, type, source) {
3800
+ function createShader$3(gl, type, source) {
2258
3801
  const shader = gl.createShader(type);
2259
3802
  if (!shader) throw new Error("Failed to create WebGL shader.");
2260
3803
  gl.shaderSource(shader, source);
@@ -2266,9 +3809,9 @@ function createShader$2(gl, type, source) {
2266
3809
  }
2267
3810
  return shader;
2268
3811
  }
2269
- function createProgram$2(gl, vertexSource, fragmentSource) {
2270
- const vertexShader = createShader$2(gl, gl.VERTEX_SHADER, vertexSource);
2271
- const fragmentShader = createShader$2(gl, gl.FRAGMENT_SHADER, fragmentSource);
3812
+ function createProgram$3(gl, vertexSource, fragmentSource) {
3813
+ const vertexShader = createShader$3(gl, gl.VERTEX_SHADER, vertexSource);
3814
+ const fragmentShader = createShader$3(gl, gl.FRAGMENT_SHADER, fragmentSource);
2272
3815
  const program = gl.createProgram();
2273
3816
  if (!program) throw new Error("Failed to create WebGL program.");
2274
3817
  gl.attachShader(program, vertexShader);
@@ -2320,9 +3863,50 @@ function fitStopsToWebGLLimit$2(stops, maxStops) {
2320
3863
  }
2321
3864
  return sampledStops;
2322
3865
  }
2323
- var ModuleTransformerLinearGradientToCanvasWebGL = class {
3866
+ function resolveLengthPercentage(value, reference) {
3867
+ if (value.kind === "percent") return value.value / 100 * reference;
3868
+ if (value.kind === "length") {
3869
+ if (value.unit === "px") return value.value;
3870
+ throw new Error(`Unsupported gradient length unit for WebGL conic gradient: ${value.unit}`);
3871
+ }
3872
+ return value;
3873
+ }
3874
+ function resolveAngleToRadians(angle) {
3875
+ if (angle.unit === "rad") return angle.value;
3876
+ if (angle.unit === "deg") return angle.value / 360 * TWO_PI;
3877
+ if (angle.unit === "turn") return angle.value * TWO_PI;
3878
+ if (angle.unit === "grad") return angle.value / 400 * TWO_PI;
3879
+ return angle.unit;
3880
+ }
3881
+ function resolveKeywordPositionX$2(x, width) {
3882
+ if (x === "left") return 0;
3883
+ if (x === "center") return width / 2;
3884
+ if (x === "right") return width;
3885
+ return width / 2;
3886
+ }
3887
+ function resolveKeywordPositionY$2(y, height) {
3888
+ if (y === "top") return 0;
3889
+ if (y === "center") return height / 2;
3890
+ if (y === "bottom") return height;
3891
+ return height / 2;
3892
+ }
3893
+ function resolveConicCenter(position, width, height) {
3894
+ if (position.kind === "keywords") return {
3895
+ x: resolveKeywordPositionX$2(position.x, width),
3896
+ y: resolveKeywordPositionY$2(position.y, height)
3897
+ };
3898
+ if (position.kind === "values") return {
3899
+ x: resolveLengthPercentage(position.x, width),
3900
+ y: resolveLengthPercentage(position.y, height)
3901
+ };
3902
+ return {
3903
+ x: width / 2,
3904
+ y: height / 2
3905
+ };
3906
+ }
3907
+ var ModuleTransformerConicGradientToCanvasWebGL = class {
2324
3908
  target = "canvas-webgl";
2325
- gradientType = "linear-gradient";
3909
+ gradientType = "conic-gradient";
2326
3910
  to(input) {
2327
3911
  const gradient = input;
2328
3912
  return { draw: (canvas, width, height) => {
@@ -2331,7 +3915,7 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2331
3915
  canvas.width = width;
2332
3916
  canvas.height = height;
2333
3917
  gl.viewport(0, 0, width, height);
2334
- const program = createProgram$2(gl, `
3918
+ const program = createProgram$3(gl, `
2335
3919
  attribute vec2 a_position;
2336
3920
  varying vec2 v_uv;
2337
3921
 
@@ -2342,10 +3926,13 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2342
3926
  `, `
2343
3927
  precision mediump float;
2344
3928
 
3929
+ const float PI = 3.141592653589793;
3930
+ const float TWO_PI = 6.283185307179586;
3931
+
2345
3932
  varying vec2 v_uv;
2346
3933
 
2347
- uniform vec2 u_start;
2348
- uniform vec2 u_end;
3934
+ uniform vec2 u_center;
3935
+ uniform float u_startAngle;
2349
3936
  uniform int u_stopCount;
2350
3937
  uniform float u_positions[${MAX_STOPS$2}];
2351
3938
  uniform vec4 u_colors[${MAX_STOPS$2}];
@@ -2377,13 +3964,12 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2377
3964
  }
2378
3965
 
2379
3966
  void main() {
2380
- vec2 axis = u_end - u_start;
2381
- vec2 point = v_uv;
3967
+ vec2 delta = v_uv - u_center;
2382
3968
 
2383
- float axisLengthSquared = dot(axis, axis);
2384
- float t = dot(point - u_start, axis) / axisLengthSquared;
3969
+ float angle = atan(delta.y, delta.x);
3970
+ float cssAngle = mod((PI * 0.5) - angle + TWO_PI, TWO_PI);
2385
3971
 
2386
- t = clamp(t, 0.0, 1.0);
3972
+ float t = mod(cssAngle - u_startAngle + TWO_PI, TWO_PI) / TWO_PI;
2387
3973
 
2388
3974
  gl_FragColor = getGradientColor(t);
2389
3975
  }
@@ -2408,34 +3994,8 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2408
3994
  const positionLocation = gl.getAttribLocation(program, "a_position");
2409
3995
  gl.enableVertexAttribArray(positionLocation);
2410
3996
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
2411
- const angle = gradient.config.angle;
2412
- const dirX = Math.sin(angle);
2413
- const dirY = -Math.cos(angle);
2414
- const centerX = width / 2;
2415
- const centerY = height / 2;
2416
- const lineLength = Math.abs(width * dirX) + Math.abs(height * dirY);
2417
- let startX = centerX - dirX * lineLength / 2;
2418
- let startY = centerY - dirY * lineLength / 2;
2419
- let endX = centerX + dirX * lineLength / 2;
2420
- let endY = centerY + dirY * lineLength / 2;
2421
- const { min, max, stops } = getStopRange(resolveRenderableGradientStops(gradient, getWebGLSampleCount$2(gradient, MAX_STOPS$2)));
2422
- let normalizedStops = stops;
2423
- if (min < 0 || max > 1) {
2424
- const vx = endX - startX;
2425
- const vy = endY - startY;
2426
- const baseStartX = startX;
2427
- const baseStartY = startY;
2428
- startX = baseStartX + vx * min;
2429
- startY = baseStartY + vy * min;
2430
- endX = baseStartX + vx * max;
2431
- endY = baseStartY + vy * max;
2432
- normalizedStops = normalizeStops$1(stops, min, max);
2433
- }
2434
- const startU = startX / width;
2435
- const startV = 1 - startY / height;
2436
- const endU = endX / width;
2437
- const endV = 1 - endY / height;
2438
- const limitedStops = fitStopsToWebGLLimit$2(normalizedStops, MAX_STOPS$2);
3997
+ const center = resolveConicCenter(gradient.config.position, width, height);
3998
+ const limitedStops = fitStopsToWebGLLimit$2(resolveRenderableGradientStops(gradient, getWebGLSampleCount$2(gradient, MAX_STOPS$2)), MAX_STOPS$2);
2439
3999
  const positions = new Float32Array(MAX_STOPS$2);
2440
4000
  const colors = new Float32Array(MAX_STOPS$2 * 4);
2441
4001
  limitedStops.forEach((stop, index) => {
@@ -2446,8 +4006,8 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2446
4006
  colors[index * 4 + 2] = color[2];
2447
4007
  colors[index * 4 + 3] = color[3];
2448
4008
  });
2449
- gl.uniform2f(gl.getUniformLocation(program, "u_start"), startU, startV);
2450
- gl.uniform2f(gl.getUniformLocation(program, "u_end"), endU, endV);
4009
+ gl.uniform2f(gl.getUniformLocation(program, "u_center"), center.x / width, 1 - center.y / height);
4010
+ gl.uniform1f(gl.getUniformLocation(program, "u_startAngle"), resolveAngleToRadians(gradient.config.from));
2451
4011
  gl.uniform1i(gl.getUniformLocation(program, "u_stopCount"), limitedStops.length);
2452
4012
  gl.uniform1fv(gl.getUniformLocation(program, "u_positions"), positions);
2453
4013
  gl.uniform4fv(gl.getUniformLocation(program, "u_colors"), colors);
@@ -2458,10 +4018,10 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2458
4018
  }
2459
4019
  };
2460
4020
  //#endregion
2461
- //#region src/gradient-transformer/modules/webgl/ModuleTransformerConicGradientToWebgl.ts
4021
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerRadialGradientToWebgl.ts
2462
4022
  const toRgb$1 = converter("rgb");
2463
4023
  const MAX_STOPS$1 = 128;
2464
- const TWO_PI = Math.PI * 2;
4024
+ const MAX_REPEATING_RADIAL_T = 16;
2465
4025
  function toWebGLColor$1(input) {
2466
4026
  const color = toRgb$1(input);
2467
4027
  if (!color) throw new Error(`Failed to convert color: ${input}`);
@@ -2472,7 +4032,7 @@ function toWebGLColor$1(input) {
2472
4032
  color.alpha ?? 1
2473
4033
  ];
2474
4034
  }
2475
- function createShader$1(gl, type, source) {
4035
+ function createShader$2(gl, type, source) {
2476
4036
  const shader = gl.createShader(type);
2477
4037
  if (!shader) throw new Error("Failed to create WebGL shader.");
2478
4038
  gl.shaderSource(shader, source);
@@ -2484,9 +4044,9 @@ function createShader$1(gl, type, source) {
2484
4044
  }
2485
4045
  return shader;
2486
4046
  }
2487
- function createProgram$1(gl, vertexSource, fragmentSource) {
2488
- const vertexShader = createShader$1(gl, gl.VERTEX_SHADER, vertexSource);
2489
- const fragmentShader = createShader$1(gl, gl.FRAGMENT_SHADER, fragmentSource);
4047
+ function createProgram$2(gl, vertexSource, fragmentSource) {
4048
+ const vertexShader = createShader$2(gl, gl.VERTEX_SHADER, vertexSource);
4049
+ const fragmentShader = createShader$2(gl, gl.FRAGMENT_SHADER, fragmentSource);
2490
4050
  const program = gl.createProgram();
2491
4051
  if (!program) throw new Error("Failed to create WebGL program.");
2492
4052
  gl.attachShader(program, vertexShader);
@@ -2538,50 +4098,171 @@ function fitStopsToWebGLLimit$1(stops, maxStops) {
2538
4098
  }
2539
4099
  return sampledStops;
2540
4100
  }
2541
- function resolveLengthPercentage(value, reference) {
4101
+ function parseLengthPercentage$1(value, reference) {
2542
4102
  if (value.kind === "percent") return value.value / 100 * reference;
2543
4103
  if (value.kind === "length") {
2544
4104
  if (value.unit === "px") return value.value;
2545
- throw new Error(`Unsupported gradient length unit for WebGL conic gradient: ${value.unit}`);
4105
+ throw new Error(`Unsupported gradient length unit for WebGL radial gradient: ${value.unit}`);
4106
+ }
4107
+ return value;
4108
+ }
4109
+ function resolveKeywordPositionX$1(x, width) {
4110
+ if (x === "left") return 0;
4111
+ if (x === "center") return width / 2;
4112
+ if (x === "right") return width;
4113
+ return width / 2;
4114
+ }
4115
+ function resolveKeywordPositionY$1(y, height) {
4116
+ if (y === "top") return 0;
4117
+ if (y === "center") return height / 2;
4118
+ if (y === "bottom") return height;
4119
+ return height / 2;
4120
+ }
4121
+ function resolveRadialCenter(position, width, height) {
4122
+ if (position.kind === "keywords") return {
4123
+ x: resolveKeywordPositionX$1(position.x, width),
4124
+ y: resolveKeywordPositionY$1(position.y, height)
4125
+ };
4126
+ if (position.kind === "values") return {
4127
+ x: parseLengthPercentage$1(position.x, width),
4128
+ y: parseLengthPercentage$1(position.y, height)
4129
+ };
4130
+ return {
4131
+ x: width / 2,
4132
+ y: height / 2
4133
+ };
4134
+ }
4135
+ function getDistanceToSide(center, width, height, side) {
4136
+ if (side === "left") return center.x;
4137
+ if (side === "right") return width - center.x;
4138
+ if (side === "top") return center.y;
4139
+ return height - center.y;
4140
+ }
4141
+ function getDistanceToCorner$1(center, corner) {
4142
+ const dx = corner.x - center.x;
4143
+ const dy = corner.y - center.y;
4144
+ return Math.sqrt(dx * dx + dy * dy);
4145
+ }
4146
+ function normalizeStops$1(stops, min, max) {
4147
+ const range = max - min || 1;
4148
+ return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
4149
+ ...stop,
4150
+ position: (stop.position - min) / range
4151
+ }));
4152
+ }
4153
+ function getCornerDeltas$1(center, width, height) {
4154
+ return [
4155
+ {
4156
+ dx: -center.x,
4157
+ dy: -center.y
4158
+ },
4159
+ {
4160
+ dx: width - center.x,
4161
+ dy: -center.y
4162
+ },
4163
+ {
4164
+ dx: -center.x,
4165
+ dy: height - center.y
4166
+ },
4167
+ {
4168
+ dx: width - center.x,
4169
+ dy: height - center.y
4170
+ }
4171
+ ];
4172
+ }
4173
+ function scaleEllipseRadiiToCorner(radiusX, radiusY, dx, dy) {
4174
+ const safeRadiusX = Math.max(radiusX, 1e-4);
4175
+ const safeRadiusY = Math.max(radiusY, 1e-4);
4176
+ const scale = Math.sqrt(dx * dx / (safeRadiusX * safeRadiusX) + dy * dy / (safeRadiusY * safeRadiusY));
4177
+ return {
4178
+ x: safeRadiusX * scale,
4179
+ y: safeRadiusY * scale
4180
+ };
4181
+ }
4182
+ function resolveRadialRadii(size, shape, center, width, height) {
4183
+ if (size.kind === "explicit") {
4184
+ const radiusX = parseLengthPercentage$1(size.x, width);
4185
+ const radiusY = size.y ? parseLengthPercentage$1(size.y, height) : radiusX;
4186
+ return {
4187
+ x: Math.max(radiusX, 1e-4),
4188
+ y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
4189
+ };
4190
+ }
4191
+ const left = getDistanceToSide(center, width, height, "left");
4192
+ const right = getDistanceToSide(center, width, height, "right");
4193
+ const top = getDistanceToSide(center, width, height, "top");
4194
+ const bottom = getDistanceToSide(center, width, height, "bottom");
4195
+ if (shape === "circle") {
4196
+ const cornerDistances = [
4197
+ {
4198
+ x: 0,
4199
+ y: 0
4200
+ },
4201
+ {
4202
+ x: width,
4203
+ y: 0
4204
+ },
4205
+ {
4206
+ x: 0,
4207
+ y: height
4208
+ },
4209
+ {
4210
+ x: width,
4211
+ y: height
4212
+ }
4213
+ ].map((corner) => getDistanceToCorner$1(center, corner));
4214
+ if (size.value === "closest-side") {
4215
+ const radius = Math.max(Math.min(left, right, top, bottom), 1e-4);
4216
+ return {
4217
+ x: radius,
4218
+ y: radius
4219
+ };
4220
+ }
4221
+ if (size.value === "farthest-side") {
4222
+ const radius = Math.max(Math.max(left, right, top, bottom), 1e-4);
4223
+ return {
4224
+ x: radius,
4225
+ y: radius
4226
+ };
4227
+ }
4228
+ if (size.value === "closest-corner") {
4229
+ const radius = Math.max(Math.min(...cornerDistances), 1e-4);
4230
+ return {
4231
+ x: radius,
4232
+ y: radius
4233
+ };
4234
+ }
4235
+ const radius = Math.max(Math.max(...cornerDistances), 1e-4);
4236
+ return {
4237
+ x: radius,
4238
+ y: radius
4239
+ };
2546
4240
  }
2547
- return value;
2548
- }
2549
- function resolveAngleToRadians(angle) {
2550
- if (angle.unit === "rad") return angle.value;
2551
- if (angle.unit === "deg") return angle.value / 360 * TWO_PI;
2552
- if (angle.unit === "turn") return angle.value * TWO_PI;
2553
- if (angle.unit === "grad") return angle.value / 400 * TWO_PI;
2554
- return angle.unit;
2555
- }
2556
- function resolveKeywordPositionX$1(x, width) {
2557
- if (x === "left") return 0;
2558
- if (x === "center") return width / 2;
2559
- if (x === "right") return width;
2560
- return width / 2;
2561
- }
2562
- function resolveKeywordPositionY$1(y, height) {
2563
- if (y === "top") return 0;
2564
- if (y === "center") return height / 2;
2565
- if (y === "bottom") return height;
2566
- return height / 2;
2567
- }
2568
- function resolveConicCenter(position, width, height) {
2569
- if (position.kind === "keywords") return {
2570
- x: resolveKeywordPositionX$1(position.x, width),
2571
- y: resolveKeywordPositionY$1(position.y, height)
2572
- };
2573
- if (position.kind === "values") return {
2574
- x: resolveLengthPercentage(position.x, width),
2575
- y: resolveLengthPercentage(position.y, height)
4241
+ const closestSideRadiusX = Math.min(left, right);
4242
+ const closestSideRadiusY = Math.min(top, bottom);
4243
+ const farthestSideRadiusX = Math.max(left, right);
4244
+ const farthestSideRadiusY = Math.max(top, bottom);
4245
+ if (size.value === "closest-side") return {
4246
+ x: Math.max(closestSideRadiusX, 1e-4),
4247
+ y: Math.max(closestSideRadiusY, 1e-4)
2576
4248
  };
2577
- return {
2578
- x: width / 2,
2579
- y: height / 2
4249
+ if (size.value === "farthest-side") return {
4250
+ x: Math.max(farthestSideRadiusX, 1e-4),
4251
+ y: Math.max(farthestSideRadiusY, 1e-4)
2580
4252
  };
4253
+ const corners = getCornerDeltas$1(center, width, height);
4254
+ if (size.value === "closest-corner") return corners.map((corner) => scaleEllipseRadiiToCorner(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => {
4255
+ const closestArea = closest.x * closest.y;
4256
+ return current.x * current.y < closestArea ? current : closest;
4257
+ });
4258
+ return corners.map((corner) => scaleEllipseRadiiToCorner(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => {
4259
+ const farthestArea = farthest.x * farthest.y;
4260
+ return current.x * current.y > farthestArea ? current : farthest;
4261
+ });
2581
4262
  }
2582
- var ModuleTransformerConicGradientToCanvasWebGL = class {
4263
+ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2583
4264
  target = "canvas-webgl";
2584
- gradientType = "conic-gradient";
4265
+ gradientType = "radial-gradient";
2585
4266
  to(input) {
2586
4267
  const gradient = input;
2587
4268
  return { draw: (canvas, width, height) => {
@@ -2590,7 +4271,7 @@ var ModuleTransformerConicGradientToCanvasWebGL = class {
2590
4271
  canvas.width = width;
2591
4272
  canvas.height = height;
2592
4273
  gl.viewport(0, 0, width, height);
2593
- const program = createProgram$1(gl, `
4274
+ const program = createProgram$2(gl, `
2594
4275
  attribute vec2 a_position;
2595
4276
  varying vec2 v_uv;
2596
4277
 
@@ -2601,16 +4282,14 @@ var ModuleTransformerConicGradientToCanvasWebGL = class {
2601
4282
  `, `
2602
4283
  precision mediump float;
2603
4284
 
2604
- const float PI = 3.141592653589793;
2605
- const float TWO_PI = 6.283185307179586;
2606
-
2607
4285
  varying vec2 v_uv;
2608
4286
 
2609
4287
  uniform vec2 u_center;
2610
- uniform float u_startAngle;
4288
+ uniform vec2 u_radius;
2611
4289
  uniform int u_stopCount;
2612
4290
  uniform float u_positions[${MAX_STOPS$1}];
2613
4291
  uniform vec4 u_colors[${MAX_STOPS$1}];
4292
+ uniform float u_tMax;
2614
4293
 
2615
4294
  vec4 getGradientColor(float t) {
2616
4295
  vec4 result = u_colors[0];
@@ -2640,11 +4319,11 @@ var ModuleTransformerConicGradientToCanvasWebGL = class {
2640
4319
 
2641
4320
  void main() {
2642
4321
  vec2 delta = v_uv - u_center;
4322
+ vec2 normalized = delta / max(u_radius, vec2(0.00001));
4323
+ float t = length(normalized);
2643
4324
 
2644
- float angle = atan(delta.y, delta.x);
2645
- float cssAngle = mod((PI * 0.5) - angle + TWO_PI, TWO_PI);
2646
-
2647
- float t = mod(cssAngle - u_startAngle + TWO_PI, TWO_PI) / TWO_PI;
4325
+ t = clamp(t, 0.0, u_tMax);
4326
+ t = t / max(u_tMax, 0.00001);
2648
4327
 
2649
4328
  gl_FragColor = getGradientColor(t);
2650
4329
  }
@@ -2669,8 +4348,14 @@ var ModuleTransformerConicGradientToCanvasWebGL = class {
2669
4348
  const positionLocation = gl.getAttribLocation(program, "a_position");
2670
4349
  gl.enableVertexAttribArray(positionLocation);
2671
4350
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
2672
- const center = resolveConicCenter(gradient.config.position, width, height);
2673
- const limitedStops = fitStopsToWebGLLimit$1(resolveRenderableGradientStops(gradient, getWebGLSampleCount$1(gradient, MAX_STOPS$1)), MAX_STOPS$1);
4351
+ const center = resolveRadialCenter(gradient.config.position, width, height);
4352
+ const radius = resolveRadialRadii(gradient.config.size, gradient.config.shape, center, width, height);
4353
+ const maxVisibleT = getMaxVisibleRadialT(center, radius, width, height);
4354
+ const baseStops = resolveRenderableGradientStops(gradient, getWebGLSampleCount$1(gradient, MAX_STOPS$1));
4355
+ const repeatMaxT = Math.min(maxVisibleT, MAX_REPEATING_RADIAL_T);
4356
+ const maxT = gradient.isRepeating ? repeatMaxT : 1;
4357
+ const renderStops = gradient.isRepeating ? expandRepeatingStopsTo(baseStops, 0, repeatMaxT) : baseStops;
4358
+ const limitedStops = fitStopsToWebGLLimit$1(gradient.isRepeating ? normalizeStops$1(renderStops, 0, repeatMaxT) : renderStops, MAX_STOPS$1);
2674
4359
  const positions = new Float32Array(MAX_STOPS$1);
2675
4360
  const colors = new Float32Array(MAX_STOPS$1 * 4);
2676
4361
  limitedStops.forEach((stop, index) => {
@@ -2682,7 +4367,8 @@ var ModuleTransformerConicGradientToCanvasWebGL = class {
2682
4367
  colors[index * 4 + 3] = color[3];
2683
4368
  });
2684
4369
  gl.uniform2f(gl.getUniformLocation(program, "u_center"), center.x / width, 1 - center.y / height);
2685
- gl.uniform1f(gl.getUniformLocation(program, "u_startAngle"), resolveAngleToRadians(gradient.config.from));
4370
+ gl.uniform2f(gl.getUniformLocation(program, "u_radius"), radius.x / width, radius.y / height);
4371
+ gl.uniform1f(gl.getUniformLocation(program, "u_tMax"), maxT);
2686
4372
  gl.uniform1i(gl.getUniformLocation(program, "u_stopCount"), limitedStops.length);
2687
4373
  gl.uniform1fv(gl.getUniformLocation(program, "u_positions"), positions);
2688
4374
  gl.uniform4fv(gl.getUniformLocation(program, "u_colors"), colors);
@@ -2693,10 +4379,10 @@ var ModuleTransformerConicGradientToCanvasWebGL = class {
2693
4379
  }
2694
4380
  };
2695
4381
  //#endregion
2696
- //#region src/gradient-transformer/modules/webgl/ModuleTransformerRadialGradientToWebgl.ts
4382
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerDiamondGradientToWebgl.ts
2697
4383
  const toRgb = converter("rgb");
2698
4384
  const MAX_STOPS = 128;
2699
- const MAX_REPEATING_RADIAL_T = 16;
4385
+ const MAX_REPEATING_DIAMOND_T = 16;
2700
4386
  function toWebGLColor(input) {
2701
4387
  const color = toRgb(input);
2702
4388
  if (!color) throw new Error(`Failed to convert color: ${input}`);
@@ -2707,7 +4393,7 @@ function toWebGLColor(input) {
2707
4393
  color.alpha ?? 1
2708
4394
  ];
2709
4395
  }
2710
- function createShader(gl, type, source) {
4396
+ function createShader$1(gl, type, source) {
2711
4397
  const shader = gl.createShader(type);
2712
4398
  if (!shader) throw new Error("Failed to create WebGL shader.");
2713
4399
  gl.shaderSource(shader, source);
@@ -2719,9 +4405,9 @@ function createShader(gl, type, source) {
2719
4405
  }
2720
4406
  return shader;
2721
4407
  }
2722
- function createProgram(gl, vertexSource, fragmentSource) {
2723
- const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource);
2724
- const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
4408
+ function createProgram$1(gl, vertexSource, fragmentSource) {
4409
+ const vertexShader = createShader$1(gl, gl.VERTEX_SHADER, vertexSource);
4410
+ const fragmentShader = createShader$1(gl, gl.FRAGMENT_SHADER, fragmentSource);
2725
4411
  const program = gl.createProgram();
2726
4412
  if (!program) throw new Error("Failed to create WebGL program.");
2727
4413
  gl.attachShader(program, vertexShader);
@@ -2744,7 +4430,7 @@ function getWebGLSampleCount(gradient, maxStops) {
2744
4430
  }
2745
4431
  function getColorAtPosition(stops, position) {
2746
4432
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
2747
- if (colorStops.length === 0) throw new Error("Cannot sample color from empty gradient stops.");
4433
+ if (colorStops.length === 0) throw new Error("Cannot sample color from empty diamond gradient stops.");
2748
4434
  if (position <= colorStops[0].position) return colorStops[0].value;
2749
4435
  const lastStop = colorStops[colorStops.length - 1];
2750
4436
  if (position >= lastStop.position) return lastStop.value;
@@ -2773,57 +4459,40 @@ function fitStopsToWebGLLimit(stops, maxStops) {
2773
4459
  }
2774
4460
  return sampledStops;
2775
4461
  }
4462
+ function normalizeStops(stops, min, max) {
4463
+ const range = max - min || 1;
4464
+ return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
4465
+ ...stop,
4466
+ position: (stop.position - min) / range
4467
+ }));
4468
+ }
2776
4469
  function parseLengthPercentage(value, reference) {
2777
4470
  if (value.kind === "percent") return value.value / 100 * reference;
2778
- if (value.kind === "length") {
2779
- if (value.unit === "px") return value.value;
2780
- throw new Error(`Unsupported gradient length unit for WebGL radial gradient: ${value.unit}`);
2781
- }
2782
- return value;
4471
+ if (value.unit === "px") return value.value;
4472
+ throw new Error(`Unsupported diamond-gradient length unit for WebGL transformer: ${value.unit}`);
2783
4473
  }
2784
4474
  function resolveKeywordPositionX(x, width) {
2785
4475
  if (x === "left") return 0;
2786
- if (x === "center") return width / 2;
2787
4476
  if (x === "right") return width;
2788
4477
  return width / 2;
2789
4478
  }
2790
4479
  function resolveKeywordPositionY(y, height) {
2791
4480
  if (y === "top") return 0;
2792
- if (y === "center") return height / 2;
2793
4481
  if (y === "bottom") return height;
2794
4482
  return height / 2;
2795
4483
  }
2796
- function resolveRadialCenter(position, width, height) {
4484
+ function resolveDiamondCenter(position, width, height) {
2797
4485
  if (position.kind === "keywords") return {
2798
4486
  x: resolveKeywordPositionX(position.x, width),
2799
4487
  y: resolveKeywordPositionY(position.y, height)
2800
4488
  };
2801
- if (position.kind === "values") return {
4489
+ return {
2802
4490
  x: parseLengthPercentage(position.x, width),
2803
4491
  y: parseLengthPercentage(position.y, height)
2804
4492
  };
2805
- return {
2806
- x: width / 2,
2807
- y: height / 2
2808
- };
2809
- }
2810
- function getDistanceToSide(center, width, height, side) {
2811
- if (side === "left") return center.x;
2812
- if (side === "right") return width - center.x;
2813
- if (side === "top") return center.y;
2814
- return height - center.y;
2815
4493
  }
2816
4494
  function getDistanceToCorner(center, corner) {
2817
- const dx = corner.x - center.x;
2818
- const dy = corner.y - center.y;
2819
- return Math.sqrt(dx * dx + dy * dy);
2820
- }
2821
- function normalizeStops(stops, min, max) {
2822
- const range = max - min || 1;
2823
- return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
2824
- ...stop,
2825
- position: (stop.position - min) / range
2826
- }));
4495
+ return Math.abs(corner.x - center.x) + Math.abs(corner.y - center.y);
2827
4496
  }
2828
4497
  function getCornerDeltas(center, width, height) {
2829
4498
  return [
@@ -2845,16 +4514,16 @@ function getCornerDeltas(center, width, height) {
2845
4514
  }
2846
4515
  ];
2847
4516
  }
2848
- function scaleEllipseRadiiToCorner(radiusX, radiusY, dx, dy) {
4517
+ function scaleDiamondRadiiToCorner(radiusX, radiusY, dx, dy) {
2849
4518
  const safeRadiusX = Math.max(radiusX, 1e-4);
2850
4519
  const safeRadiusY = Math.max(radiusY, 1e-4);
2851
- const scale = Math.sqrt(dx * dx / (safeRadiusX * safeRadiusX) + dy * dy / (safeRadiusY * safeRadiusY));
4520
+ const scale = Math.abs(dx) / safeRadiusX + Math.abs(dy) / safeRadiusY;
2852
4521
  return {
2853
4522
  x: safeRadiusX * scale,
2854
4523
  y: safeRadiusY * scale
2855
4524
  };
2856
4525
  }
2857
- function resolveRadialRadii(size, shape, center, width, height) {
4526
+ function resolveDiamondRadii(size, shape, center, width, height) {
2858
4527
  if (size.kind === "explicit") {
2859
4528
  const radiusX = parseLengthPercentage(size.x, width);
2860
4529
  const radiusY = size.y ? parseLengthPercentage(size.y, height) : radiusX;
@@ -2863,10 +4532,10 @@ function resolveRadialRadii(size, shape, center, width, height) {
2863
4532
  y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
2864
4533
  };
2865
4534
  }
2866
- const left = getDistanceToSide(center, width, height, "left");
2867
- const right = getDistanceToSide(center, width, height, "right");
2868
- const top = getDistanceToSide(center, width, height, "top");
2869
- const bottom = getDistanceToSide(center, width, height, "bottom");
4535
+ const left = center.x;
4536
+ const right = width - center.x;
4537
+ const top = center.y;
4538
+ const bottom = height - center.y;
2870
4539
  if (shape === "circle") {
2871
4540
  const cornerDistances = [
2872
4541
  {
@@ -2926,19 +4595,34 @@ function resolveRadialRadii(size, shape, center, width, height) {
2926
4595
  y: Math.max(farthestSideRadiusY, 1e-4)
2927
4596
  };
2928
4597
  const corners = getCornerDeltas(center, width, height);
2929
- if (size.value === "closest-corner") return corners.map((corner) => scaleEllipseRadiiToCorner(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => {
2930
- const closestArea = closest.x * closest.y;
2931
- return current.x * current.y < closestArea ? current : closest;
2932
- });
2933
- return corners.map((corner) => scaleEllipseRadiiToCorner(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => {
2934
- const farthestArea = farthest.x * farthest.y;
2935
- return current.x * current.y > farthestArea ? current : farthest;
2936
- });
4598
+ if (size.value === "closest-corner") return corners.map((corner) => scaleDiamondRadiiToCorner(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => current.x * current.y < closest.x * closest.y ? current : closest);
4599
+ return corners.map((corner) => scaleDiamondRadiiToCorner(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => current.x * current.y > farthest.x * farthest.y ? current : farthest);
2937
4600
  }
2938
- var ModuleTransformerRadialGradientToCanvasWebGL = class {
4601
+ function getMaxVisibleDiamondT(center, radii, width, height) {
4602
+ return Math.max(...[
4603
+ {
4604
+ x: 0,
4605
+ y: 0
4606
+ },
4607
+ {
4608
+ x: width,
4609
+ y: 0
4610
+ },
4611
+ {
4612
+ x: 0,
4613
+ y: height
4614
+ },
4615
+ {
4616
+ x: width,
4617
+ y: height
4618
+ }
4619
+ ].map((corner) => Math.abs(corner.x - center.x) / Math.max(radii.x, 1e-4) + Math.abs(corner.y - center.y) / Math.max(radii.y, 1e-4)));
4620
+ }
4621
+ var ModuleTransformerDiamondGradientToCanvasWebGL = class {
2939
4622
  target = "canvas-webgl";
2940
- gradientType = "radial-gradient";
4623
+ gradientType = "diamond-gradient";
2941
4624
  to(input) {
4625
+ if (!(input instanceof DiamondGradient)) throw new Error("Expected DiamondGradient");
2942
4626
  const gradient = input;
2943
4627
  return { draw: (canvas, width, height) => {
2944
4628
  const gl = canvas.getContext("webgl");
@@ -2946,7 +4630,7 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2946
4630
  canvas.width = width;
2947
4631
  canvas.height = height;
2948
4632
  gl.viewport(0, 0, width, height);
2949
- const program = createProgram(gl, `
4633
+ const program = createProgram$1(gl, `
2950
4634
  attribute vec2 a_position;
2951
4635
  varying vec2 v_uv;
2952
4636
 
@@ -2994,8 +4678,8 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2994
4678
 
2995
4679
  void main() {
2996
4680
  vec2 delta = v_uv - u_center;
2997
- vec2 normalized = delta / max(u_radius, vec2(0.00001));
2998
- float t = length(normalized);
4681
+ vec2 normalized = abs(delta) / max(u_radius, vec2(0.00001));
4682
+ float t = normalized.x + normalized.y;
2999
4683
 
3000
4684
  t = clamp(t, 0.0, u_tMax);
3001
4685
  t = t / max(u_tMax, 0.00001);
@@ -3023,11 +4707,11 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
3023
4707
  const positionLocation = gl.getAttribLocation(program, "a_position");
3024
4708
  gl.enableVertexAttribArray(positionLocation);
3025
4709
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
3026
- const center = resolveRadialCenter(gradient.config.position, width, height);
3027
- const radius = resolveRadialRadii(gradient.config.size, gradient.config.shape, center, width, height);
3028
- const maxVisibleT = getMaxVisibleRadialT(center, radius, width, height);
4710
+ const center = resolveDiamondCenter(gradient.config.position, width, height);
4711
+ const radius = resolveDiamondRadii(gradient.config.size, gradient.config.shape, center, width, height);
4712
+ const maxVisibleT = getMaxVisibleDiamondT(center, radius, width, height);
3029
4713
  const baseStops = resolveRenderableGradientStops(gradient, getWebGLSampleCount(gradient, MAX_STOPS));
3030
- const repeatMaxT = Math.min(maxVisibleT, MAX_REPEATING_RADIAL_T);
4714
+ const repeatMaxT = Math.min(maxVisibleT, MAX_REPEATING_DIAMOND_T);
3031
4715
  const maxT = gradient.isRepeating ? repeatMaxT : 1;
3032
4716
  const renderStops = gradient.isRepeating ? expandRepeatingStopsTo(baseStops, 0, repeatMaxT) : baseStops;
3033
4717
  const limitedStops = fitStopsToWebGLLimit(gradient.isRepeating ? normalizeStops(renderStops, 0, repeatMaxT) : renderStops, MAX_STOPS);
@@ -3054,6 +4738,107 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
3054
4738
  }
3055
4739
  };
3056
4740
  //#endregion
4741
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerMeshGradientToWebgl.ts
4742
+ const BICUBIC_SUBDIVISIONS = 24;
4743
+ function createShader(gl, type, source) {
4744
+ const shader = gl.createShader(type);
4745
+ if (!shader) throw new Error("Failed to create WebGL shader.");
4746
+ gl.shaderSource(shader, source);
4747
+ gl.compileShader(shader);
4748
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
4749
+ const error = gl.getShaderInfoLog(shader);
4750
+ gl.deleteShader(shader);
4751
+ throw new Error(`WebGL shader compile error: ${error}`);
4752
+ }
4753
+ return shader;
4754
+ }
4755
+ function createProgram(gl, vertexSource, fragmentSource) {
4756
+ const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource);
4757
+ const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentSource);
4758
+ const program = gl.createProgram();
4759
+ if (!program) throw new Error("Failed to create WebGL program.");
4760
+ gl.attachShader(program, vertexShader);
4761
+ gl.attachShader(program, fragmentShader);
4762
+ gl.linkProgram(program);
4763
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
4764
+ const error = gl.getProgramInfoLog(program);
4765
+ gl.deleteProgram(program);
4766
+ throw new Error(`WebGL program link error: ${error}`);
4767
+ }
4768
+ return program;
4769
+ }
4770
+ function toClipX(value, width) {
4771
+ return value / width * 2 - 1;
4772
+ }
4773
+ function toClipY(value, height) {
4774
+ return 1 - value / height * 2;
4775
+ }
4776
+ var ModuleTransformerMeshGradientToCanvasWebGL = class {
4777
+ target = "canvas-webgl";
4778
+ gradientType = "mesh-gradient";
4779
+ to(input) {
4780
+ if (!(input instanceof MeshGradient)) throw new Error("Expected MeshGradient");
4781
+ const gradient = input;
4782
+ return { draw: (canvas, width, height) => {
4783
+ const gl = canvas.getContext("webgl");
4784
+ if (!gl) throw new Error("WebGL is not supported.");
4785
+ canvas.width = width;
4786
+ canvas.height = height;
4787
+ gl.viewport(0, 0, width, height);
4788
+ const program = createProgram(gl, `
4789
+ attribute vec2 a_position;
4790
+ attribute vec4 a_color;
4791
+ varying vec4 v_color;
4792
+
4793
+ void main() {
4794
+ v_color = a_color;
4795
+ gl_Position = vec4(a_position, 0.0, 1.0);
4796
+ }
4797
+ `, `
4798
+ precision mediump float;
4799
+ varying vec4 v_color;
4800
+
4801
+ void main() {
4802
+ gl_FragColor = v_color;
4803
+ }
4804
+ `);
4805
+ const vertexMap = buildMeshVertexMap(gradient, width, height);
4806
+ const grid = buildRegularMeshGrid(gradient, vertexMap);
4807
+ const subdivisions = gradient.config.method === "bicubic" ? BICUBIC_SUBDIVISIONS : 1;
4808
+ const edgeTriangles = buildMeshEdgeSkirtTriangles(gradient, grid, width, height, subdivisions);
4809
+ const positions = [];
4810
+ const colors = [];
4811
+ for (const patch of gradient.patches) {
4812
+ const triangles = buildPatchTriangles(gradient, grid, patch, vertexMap, subdivisions);
4813
+ for (const triangle of triangles) for (const vertex of triangle) {
4814
+ positions.push(toClipX(vertex.x, width), toClipY(vertex.y, height));
4815
+ colors.push(...vertex.color);
4816
+ }
4817
+ }
4818
+ for (const triangle of edgeTriangles) for (const vertex of triangle) {
4819
+ positions.push(toClipX(vertex.x, width), toClipY(vertex.y, height));
4820
+ colors.push(...vertex.color);
4821
+ }
4822
+ const positionBuffer = gl.createBuffer();
4823
+ const colorBuffer = gl.createBuffer();
4824
+ gl.useProgram(program);
4825
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
4826
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW);
4827
+ const positionLocation = gl.getAttribLocation(program, "a_position");
4828
+ gl.enableVertexAttribArray(positionLocation);
4829
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
4830
+ gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
4831
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW);
4832
+ const colorLocation = gl.getAttribLocation(program, "a_color");
4833
+ gl.enableVertexAttribArray(colorLocation);
4834
+ gl.vertexAttribPointer(colorLocation, 4, gl.FLOAT, false, 0, 0);
4835
+ gl.clearColor(0, 0, 0, 0);
4836
+ gl.clear(gl.COLOR_BUFFER_BIT);
4837
+ gl.drawArrays(gl.TRIANGLES, 0, positions.length / 2);
4838
+ } };
4839
+ }
4840
+ };
4841
+ //#endregion
3057
4842
  //#region src/gradient-transformer/GradientTransformer.ts
3058
4843
  var GradientTransformer = class {
3059
4844
  static _modules = /* @__PURE__ */ new Map();
@@ -3086,13 +4871,19 @@ var GradientTransformer = class {
3086
4871
  this._initialized = true;
3087
4872
  this.add(new ModuleTransformerLinearGradientToCss());
3088
4873
  this.add(new ModuleTransformerRadialGradientToCss());
4874
+ this.add(new ModuleTransformerDiamondGradientToCss());
3089
4875
  this.add(new ModuleTransformerConicGradientToCss());
4876
+ this.add(new ModuleTransformerMeshGradientToCss());
3090
4877
  this.add(new ModuleTransformerLinearGradientToCanvas());
3091
4878
  this.add(new ModuleTransformerRadialGradientToCanvas());
4879
+ this.add(new ModuleTransformerDiamondGradientToCanvas());
3092
4880
  this.add(new ModuleTransformerConicGradientToCanvas());
4881
+ this.add(new ModuleTransformerMeshGradientToCanvas());
3093
4882
  this.add(new ModuleTransformerLinearGradientToCanvasWebGL());
3094
4883
  this.add(new ModuleTransformerRadialGradientToCanvasWebGL());
4884
+ this.add(new ModuleTransformerDiamondGradientToCanvasWebGL());
3095
4885
  this.add(new ModuleTransformerConicGradientToCanvasWebGL());
4886
+ this.add(new ModuleTransformerMeshGradientToCanvasWebGL());
3096
4887
  }
3097
4888
  static _getKey(target, gradientType) {
3098
4889
  return `${target}:${gradientType}`;
@@ -3115,7 +4906,13 @@ var GradientFactory = class {
3115
4906
  return this._registry.delete(functionName);
3116
4907
  }
3117
4908
  static create(input) {
3118
- const abi = typeof input === "string" ? parseStringToAbi(input) : input;
4909
+ if (typeof input === "string") {
4910
+ const functionName = this._getFunctionName(input);
4911
+ const adapter = this.get(functionName);
4912
+ if (!adapter) throw new Error(`No gradient registered for: ${functionName}`);
4913
+ return adapter.fromString(input);
4914
+ }
4915
+ const abi = input;
3119
4916
  const adapter = this.get(abi.functionName);
3120
4917
  if (!adapter) throw new Error(`No gradient registered for: ${abi.functionName}`);
3121
4918
  return adapter.fromAbi(abi);
@@ -3133,7 +4930,17 @@ var GradientFactory = class {
3133
4930
  this._initialized = true;
3134
4931
  this.add("linear-gradient", LinearGradient);
3135
4932
  this.add("radial-gradient", RadialGradient);
4933
+ this.add("diamond-gradient", DiamondGradient);
3136
4934
  this.add("conic-gradient", ConicGradient);
4935
+ this.add("mesh-gradient", MeshGradient);
4936
+ }
4937
+ static _getFunctionName(input) {
4938
+ const source = input.trim();
4939
+ const openIndex = source.indexOf("(");
4940
+ if (openIndex <= 0) throw new Error("Expected function opening parenthesis");
4941
+ let functionName = source.slice(0, openIndex).trim();
4942
+ if (functionName.startsWith("repeating-")) functionName = functionName.slice(10);
4943
+ return functionName;
3137
4944
  }
3138
4945
  };
3139
4946
  function parse(input) {
@@ -3154,4 +4961,4 @@ function transformFrom(target, gradientType, input) {
3154
4961
  return GradientTransformer.from(target, gradientType, input);
3155
4962
  }
3156
4963
  //#endregion
3157
- export { ConicGradient, GRADIENT_COLOR_SPACE, GRADIENT_HUE_INTERPOLATIONS, GRADIENT_POLAR_COLOR_SPACES, GradientBase, GradientFactory, GradientTransformer, LinearGradient, ModuleTransformerConicGradientToCanvas, ModuleTransformerConicGradientToCanvasWebGL, ModuleTransformerConicGradientToCss, ModuleTransformerLinearGradientToCanvas, ModuleTransformerLinearGradientToCanvasWebGL, ModuleTransformerLinearGradientToCss, ModuleTransformerRadialGradientToCanvas, ModuleTransformerRadialGradientToCanvasWebGL, ModuleTransformerRadialGradientToCss, PatternTokenKind, RadialGradient, angleValueFromString, ceilTo, clamp, degToRad, floorTo, format, fromPercent, gradToRad, isAngle, isAngleUnit, isColorHint, isColorStop, isConfig, isGradient, isGradientColorSpace, isGradientHueInterpolation, isGradientPolarColorSpace, isPatternSyntaxValid, isPatternValid, isValid, matchExpression, normalizeAngleDeg, normalizeAngleRad, parse, parseStringToAbi, radToDeg, roundTo, splitTopLevelByWhitespace, toPercent, tokenizePattern, transformFrom, transformTo, truncTo, turnToRad, validate, validatePattern, validatePatternSemantic, validatePatternStructure, validatePatternSyntax };
4964
+ export { ConicGradient, DiamondGradient, GRADIENT_COLOR_SPACE, GRADIENT_HUE_INTERPOLATIONS, GRADIENT_POLAR_COLOR_SPACES, GradientBase, GradientFactory, GradientTransformer, LinearGradient, MeshGradient, ModuleTransformerConicGradientToCanvas, ModuleTransformerConicGradientToCanvasWebGL, ModuleTransformerConicGradientToCss, ModuleTransformerDiamondGradientToCanvas, ModuleTransformerDiamondGradientToCanvasWebGL, ModuleTransformerDiamondGradientToCss, ModuleTransformerLinearGradientToCanvas, ModuleTransformerLinearGradientToCanvasWebGL, ModuleTransformerLinearGradientToCss, ModuleTransformerMeshGradientToCanvas, ModuleTransformerMeshGradientToCanvasWebGL, ModuleTransformerMeshGradientToCss, ModuleTransformerRadialGradientToCanvas, ModuleTransformerRadialGradientToCanvasWebGL, ModuleTransformerRadialGradientToCss, PatternTokenKind, RadialGradient, angleValueFromString, ceilTo, clamp, degToRad, floorTo, format, fromPercent, gradToRad, isAngle, isAngleUnit, isColorHint, isColorStop, isConfig, isGradient, isGradientColorSpace, isGradientHueInterpolation, isGradientPolarColorSpace, isPatternSyntaxValid, isPatternValid, isValid, matchExpression, normalizeAngleDeg, normalizeAngleRad, parse, parseStringToAbi, radToDeg, roundTo, splitTopLevelByWhitespace, toPercent, tokenizePattern, transformFrom, transformTo, truncTo, turnToRad, validate, validatePattern, validatePatternSemantic, validatePatternStructure, validatePatternSyntax };