gradiente 2.2.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";
@@ -1460,18 +1485,12 @@ var ConicGradient = class ConicGradient extends GradientBase {
1460
1485
  _validateConfig(config) {}
1461
1486
  _serializeConfig() {
1462
1487
  const parts = [];
1463
- const angle = this.config.from;
1464
- parts.push(`from ${angle.value}${angle.unit}`);
1465
- parts.push(`at ${this._serializePosition(this.config.position)}`);
1466
- if (this.config.interpolation) {
1467
- const i = this.config.interpolation;
1468
- if (i.kind === "rectangular") parts.push(`in ${i.space}`);
1469
- else {
1470
- let str = `in ${i.space}`;
1471
- if (i.hueMethod) str += ` ${i.hueMethod} hue`;
1472
- parts.push(str);
1473
- }
1488
+ if (!this._isDefaultFrom(this.config.from)) {
1489
+ const angle = this.config.from;
1490
+ parts.push(`from ${angle.value}${angle.unit}`);
1474
1491
  }
1492
+ if (!this._isDefaultPosition(this.config.position)) parts.push(`at ${this._serializePosition(this.config.position)}`);
1493
+ if (this.config.interpolation !== void 0) parts.push(this._serializeInterpolation(this.config.interpolation));
1475
1494
  return parts.join(" ");
1476
1495
  }
1477
1496
  _serializePosition(position) {
@@ -1484,6 +1503,17 @@ var ConicGradient = class ConicGradient extends GradientBase {
1484
1503
  if (value.kind === "percent") return `${value.value}%`;
1485
1504
  return `${value.value}${value.unit}`;
1486
1505
  }
1506
+ _serializeInterpolation(interpolation) {
1507
+ const { colorSpace, hue } = interpolation;
1508
+ if (hue === void 0) return `in ${colorSpace}`;
1509
+ return `in ${colorSpace} ${hue} hue`;
1510
+ }
1511
+ _isDefaultFrom(from) {
1512
+ return from.value === 0 && from.unit === "deg";
1513
+ }
1514
+ _isDefaultPosition(position) {
1515
+ return position.kind === "keywords" && position.x === "center" && position.y === "center";
1516
+ }
1487
1517
  static _parseConfig(input) {
1488
1518
  const config = {
1489
1519
  from: {
@@ -1499,46 +1529,86 @@ var ConicGradient = class ConicGradient extends GradientBase {
1499
1529
  };
1500
1530
  if (!input) return config;
1501
1531
  const tokens = splitTopLevelByWhitespace(input);
1532
+ const isLengthPercentage = (value) => {
1533
+ if (value === void 0) return false;
1534
+ return value.endsWith("%") || /^-?\d*\.?\d+[a-zA-Z]+$/.test(value);
1535
+ };
1502
1536
  for (let i = 0; i < tokens.length; i++) {
1503
1537
  const token = tokens[i];
1504
1538
  if (token === "from") {
1505
- config.from = this._parseAngle(tokens[i + 1]);
1539
+ const angleToken = tokens[i + 1];
1540
+ if (angleToken === void 0) throw new Error("Invalid conic-gradient config: missing angle after from");
1541
+ config.from = this._parseAngle(angleToken);
1506
1542
  i += 1;
1507
1543
  continue;
1508
1544
  }
1509
1545
  if (token === "at") {
1510
1546
  const xToken = tokens[i + 1];
1511
1547
  const yToken = tokens[i + 2];
1512
- if ((xToken === "left" || xToken === "center" || xToken === "right") && (yToken === "top" || yToken === "center" || yToken === "bottom")) config.position = {
1513
- kind: "keywords",
1514
- x: xToken,
1515
- y: yToken
1516
- };
1517
- else config.position = {
1518
- kind: "values",
1519
- x: this._parseLengthPercentage(xToken),
1520
- y: this._parseLengthPercentage(yToken)
1521
- };
1522
- i += 2;
1523
- continue;
1548
+ if (xToken === void 0) throw new Error("Invalid conic-gradient config: missing position after at");
1549
+ if (xToken === "center" && (yToken === void 0 || yToken === "in")) {
1550
+ config.position = {
1551
+ kind: "keywords",
1552
+ x: "center",
1553
+ y: "center"
1554
+ };
1555
+ i += 1;
1556
+ continue;
1557
+ }
1558
+ if ((xToken === "left" || xToken === "right") && (yToken === void 0 || yToken === "in")) {
1559
+ config.position = {
1560
+ kind: "keywords",
1561
+ x: xToken,
1562
+ y: "center"
1563
+ };
1564
+ i += 1;
1565
+ continue;
1566
+ }
1567
+ if ((xToken === "top" || xToken === "bottom") && (yToken === void 0 || yToken === "in")) {
1568
+ config.position = {
1569
+ kind: "keywords",
1570
+ x: "center",
1571
+ y: xToken
1572
+ };
1573
+ i += 1;
1574
+ continue;
1575
+ }
1576
+ if ((xToken === "left" || xToken === "center" || xToken === "right") && (yToken === "top" || yToken === "center" || yToken === "bottom")) {
1577
+ config.position = {
1578
+ kind: "keywords",
1579
+ x: xToken,
1580
+ y: yToken
1581
+ };
1582
+ i += 2;
1583
+ continue;
1584
+ }
1585
+ if (isLengthPercentage(xToken) && isLengthPercentage(yToken)) {
1586
+ config.position = {
1587
+ kind: "values",
1588
+ x: this._parseLengthPercentage(xToken),
1589
+ y: this._parseLengthPercentage(yToken)
1590
+ };
1591
+ i += 2;
1592
+ continue;
1593
+ }
1594
+ throw new Error(`Invalid conic-gradient position: ${xToken} ${yToken ?? ""}`);
1524
1595
  }
1525
1596
  if (token === "in") {
1526
- const space = tokens[i + 1];
1527
- const hueMethod = tokens[i + 2];
1528
- if (tokens[i + 3] === "hue" && (hueMethod === "shorter" || hueMethod === "longer" || hueMethod === "increasing" || hueMethod === "decreasing")) {
1597
+ const colorSpace = tokens[i + 1];
1598
+ const maybeHue = tokens[i + 2];
1599
+ const maybeHueKeyword = tokens[i + 3];
1600
+ if (colorSpace === void 0) throw new Error("Invalid conic-gradient interpolation: missing color space");
1601
+ if (maybeHueKeyword === "hue" && (maybeHue === "shorter" || maybeHue === "longer" || maybeHue === "increasing" || maybeHue === "decreasing")) {
1529
1602
  config.interpolation = {
1530
- kind: "polar",
1531
- space,
1532
- hueMethod
1603
+ colorSpace,
1604
+ hue: maybeHue
1533
1605
  };
1534
1606
  i += 3;
1535
1607
  continue;
1536
1608
  }
1537
- config.interpolation = {
1538
- kind: "rectangular",
1539
- space
1540
- };
1609
+ config.interpolation = { colorSpace };
1541
1610
  i += 1;
1611
+ continue;
1542
1612
  }
1543
1613
  }
1544
1614
  return config;
@@ -1567,6 +1637,421 @@ var ConicGradient = class ConicGradient extends GradientBase {
1567
1637
  }
1568
1638
  };
1569
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
1570
2055
  //#region src/gradient-transformer/modules/css/ModuleTransformerLinearGradientToCss.ts
1571
2056
  var ModuleTransformerLinearGradientToCss = class {
1572
2057
  target = "css";
@@ -1587,21 +2072,11 @@ var ModuleTransformerRadialGradientToCss = class {
1587
2072
  }
1588
2073
  };
1589
2074
  //#endregion
1590
- //#region src/gradient-transformer/modules/css/ModuleTransformerConicGradientToCss.ts
1591
- var ModuleTransformerConicGradientToCss = class {
1592
- target = "css";
1593
- gradientType = "conic-gradient";
1594
- to(input) {
1595
- if (!(input instanceof ConicGradient)) throw new Error("Expected ConicGradient");
1596
- return input.toString();
1597
- }
1598
- };
1599
- //#endregion
1600
2075
  //#region src/gradient-transformer/modules/helpers/expand-repeating-stops.ts
1601
2076
  function positiveModulo(value, modulo) {
1602
2077
  return (value % modulo + modulo) % modulo;
1603
2078
  }
1604
- function sampleColorAtPosition(stops, position) {
2079
+ function sampleColorAtPosition$2(stops, position) {
1605
2080
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
1606
2081
  if (colorStops.length === 0) throw new Error("Cannot sample color from empty stops.");
1607
2082
  if (position <= colorStops[0].position) return colorStops[0].value;
@@ -1619,7 +2094,7 @@ function sampleColorAtPosition(stops, position) {
1619
2094
  return lastStop.value;
1620
2095
  }
1621
2096
  function sampleRepeatingColorAtPosition(stops, position, firstPosition, period) {
1622
- return sampleColorAtPosition(stops, firstPosition + positiveModulo(position - firstPosition, period));
2097
+ return sampleColorAtPosition$2(stops, firstPosition + positiveModulo(position - firstPosition, period));
1623
2098
  }
1624
2099
  function expandRepeatingStopsTo(stops, from, to) {
1625
2100
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
@@ -1738,12 +2213,12 @@ function getColorStopsWithPositions(stops) {
1738
2213
  });
1739
2214
  }
1740
2215
  function formatColorForCanvas(input) {
1741
- const color = toRgb$5(input);
2216
+ const color = toRgb$9(input);
1742
2217
  if (!color) throw new Error("Failed to convert interpolated color to rgb.");
1743
2218
  return formatRgb(color);
1744
2219
  }
1745
2220
  const DEFAULT_SAMPLE_COUNT = 64;
1746
- const toRgb$5 = converter("rgb");
2221
+ const toRgb$9 = converter("rgb");
1747
2222
  function resolveRenderableGradientStops(gradient, sampleCount = DEFAULT_SAMPLE_COUNT) {
1748
2223
  const colorStops = getColorStopsWithPositions(gradient.stops);
1749
2224
  const interpolation = gradient.config.interpolation;
@@ -1773,77 +2248,677 @@ function resolveRenderableGradientStops(gradient, sampleCount = DEFAULT_SAMPLE_C
1773
2248
  return gradient.isRepeating ? expandRepeatingStops(sampledStops) : sampledStops;
1774
2249
  }
1775
2250
  //#endregion
1776
- //#region src/gradient-transformer/modules/canvas/ModuleTransformerLinearGradientToCanvas.ts
1777
- const toRgb$4 = converter("rgb");
1778
- function toCanvasColor$1(input) {
1779
- const color = toRgb$4(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);
1780
2255
  if (!color) throw new Error(`Failed to convert color: ${input}`);
1781
- return formatRgb(color);
2256
+ return [
2257
+ color.r ?? 0,
2258
+ color.g ?? 0,
2259
+ color.b ?? 0,
2260
+ color.alpha ?? 1
2261
+ ];
1782
2262
  }
1783
- function getStopRange$2(stops) {
1784
- const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null);
1785
- if (!colorStops.length) return {
1786
- min: 0,
1787
- max: 1,
1788
- stops: []
1789
- };
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) {
1790
2269
  return {
1791
- min: Math.min(...colorStops.map((stop) => stop.position)),
1792
- max: Math.max(...colorStops.map((stop) => stop.position)),
1793
- 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)
1794
2274
  };
1795
2275
  }
1796
- function normalizeStops$3(stops, min, max) {
1797
- const range = max - min || 1;
1798
- return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
1799
- ...stop,
1800
- position: (stop.position - min) / range
1801
- }));
2276
+ function buildMeshVertexMap(gradient, width, height) {
2277
+ return new Map(gradient.vertices.map((vertex) => [vertex.id, resolveMeshVertex(vertex, width, height)]));
1802
2278
  }
1803
- var ModuleTransformerLinearGradientToCanvas = class {
1804
- target = "canvas-2d";
1805
- gradientType = "linear-gradient";
1806
- to(input) {
1807
- const gradient = input;
1808
- return { draw: (ctx, width, height) => {
1809
- const angle = gradient.config.angle;
1810
- const dirX = Math.sin(angle);
1811
- const dirY = -Math.cos(angle);
1812
- const centerX = width / 2;
1813
- const centerY = height / 2;
1814
- const lineLength = Math.abs(width * dirX) + Math.abs(height * dirY);
1815
- let startX = centerX - dirX * lineLength / 2;
1816
- let startY = centerY - dirY * lineLength / 2;
1817
- let endX = centerX + dirX * lineLength / 2;
1818
- let endY = centerY + dirY * lineLength / 2;
1819
- const { min, max, stops } = getStopRange$2(resolveRenderableGradientStops(gradient));
1820
- let normalizedStops = stops;
1821
- if (min < 0 || max > 1) {
1822
- const vx = endX - startX;
1823
- const vy = endY - startY;
1824
- const baseStartX = startX;
1825
- const baseStartY = startY;
1826
- startX = baseStartX + vx * min;
1827
- startY = baseStartY + vy * min;
1828
- endX = baseStartX + vx * max;
1829
- endY = baseStartY + vy * max;
1830
- normalizedStops = normalizeStops$3(stops, min, max);
1831
- }
1832
- const canvasGradient = ctx.createLinearGradient(startX, startY, endX, endY);
1833
- for (const stop of normalizedStops) canvasGradient.addColorStop(stop.position, toCanvasColor$1(stop.value));
1834
- ctx.clearRect(0, 0, width, height);
1835
- ctx.fillStyle = canvasGradient;
1836
- ctx.fillRect(0, 0, width, height);
1837
- } };
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));
1838
2295
  }
1839
- };
1840
- //#endregion
1841
- //#region src/gradient-transformer/modules/canvas/ModuleTransformerRadialGradientToCanvas.ts
1842
- const toRgb$3 = converter("rgb");
1843
- const RADIAL_GRADIENT_SAMPLE_COUNT = 128;
1844
- function toCanvasColor(input) {
1845
- const color = toRgb$3(input);
1846
- if (!color) throw new Error(`Failed to convert color: ${input}`);
2296
+ return result;
2297
+ }
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
2318
+ };
2319
+ throw new Error(`Mesh patch does not match adjacent regular grid vertices: ${patch.id}`);
2320
+ }
2321
+ function clampIndex(index, length) {
2322
+ return Math.min(length - 1, Math.max(0, index));
2323
+ }
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);
2328
+ }
2329
+ function clampColor(value) {
2330
+ return Math.min(1, Math.max(0, value));
2331
+ }
2332
+ function mix(a, b, t) {
2333
+ return a + (b - a) * t;
2334
+ }
2335
+ function mixColor(a, b, t) {
2336
+ return [
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}`);
1847
2922
  return formatRgb(color);
1848
2923
  }
1849
2924
  function getStopRange$1(stops) {
@@ -1859,7 +2934,7 @@ function getStopRange$1(stops) {
1859
2934
  stops: colorStops
1860
2935
  };
1861
2936
  }
1862
- function normalizeStops$2(stops, min, max) {
2937
+ function normalizeStops$3(stops, min, max) {
1863
2938
  const range = max - min || 1;
1864
2939
  return stops.map((stop) => ({
1865
2940
  ...stop,
@@ -1872,12 +2947,12 @@ function getDistanceToSide$1(center, width, height, side) {
1872
2947
  if (side === "top") return center.y;
1873
2948
  return height - center.y;
1874
2949
  }
1875
- function getDistanceToCorner$1(center, corner) {
2950
+ function getDistanceToCorner$3(center, corner) {
1876
2951
  const dx = corner.x - center.x;
1877
2952
  const dy = corner.y - center.y;
1878
2953
  return Math.sqrt(dx * dx + dy * dy);
1879
2954
  }
1880
- function getCornerDeltas$1(center, width, height) {
2955
+ function getCornerDeltas$3(center, width, height) {
1881
2956
  return [
1882
2957
  {
1883
2958
  dx: -center.x,
@@ -1920,9 +2995,9 @@ var ModuleTransformerRadialGradientToCanvas = class {
1920
2995
  let normalizedStops = stops;
1921
2996
  let innerFactor = 0;
1922
2997
  let outerFactor = gradient.isRepeating ? maxVisibleT : 1;
1923
- if (gradient.isRepeating) normalizedStops = normalizeStops$2(stops, 0, maxVisibleT);
2998
+ if (gradient.isRepeating) normalizedStops = normalizeStops$3(stops, 0, maxVisibleT);
1924
2999
  else if (min < 0 || max > 1) {
1925
- normalizedStops = normalizeStops$2(stops, min, max);
3000
+ normalizedStops = normalizeStops$3(stops, min, max);
1926
3001
  innerFactor = min;
1927
3002
  outerFactor = max;
1928
3003
  }
@@ -1931,7 +3006,7 @@ var ModuleTransformerRadialGradientToCanvas = class {
1931
3006
  const innerRadius = Math.max(0, baseRadius * innerFactor);
1932
3007
  const outerRadius = Math.max(innerRadius + 1e-4, baseRadius * outerFactor);
1933
3008
  const g = ctx.createRadialGradient(center.x, center.y, innerRadius, center.x, center.y, outerRadius);
1934
- 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));
1935
3010
  ctx.fillStyle = g;
1936
3011
  ctx.fillRect(0, 0, width, height);
1937
3012
  return;
@@ -1945,7 +3020,7 @@ var ModuleTransformerRadialGradientToCanvas = class {
1945
3020
  ctx.translate(center.x, center.y);
1946
3021
  ctx.scale(scaleX, scaleY);
1947
3022
  const g = ctx.createRadialGradient(0, 0, innerRadius, 0, 0, scaledOuterRadius);
1948
- for (const stop of normalizedStops) g.addColorStop(stop.position, toCanvasColor(stop.value));
3023
+ for (const stop of normalizedStops) g.addColorStop(stop.position, toCanvasColor$1(stop.value));
1949
3024
  ctx.fillStyle = g;
1950
3025
  const drawRadius = scaledOuterRadius + 2;
1951
3026
  ctx.fillRect(-drawRadius / scaleX * 2, -drawRadius / scaleY * 2, drawRadius / scaleX * 4, drawRadius / scaleY * 4);
@@ -2003,7 +3078,7 @@ var ModuleTransformerRadialGradientToCanvas = class {
2003
3078
  x: width,
2004
3079
  y: height
2005
3080
  }
2006
- ].map((corner) => getDistanceToCorner$1(center, corner));
3081
+ ].map((corner) => getDistanceToCorner$3(center, corner));
2007
3082
  if (size.value === "closest-side") {
2008
3083
  const radius = Math.min(left, right, top, bottom);
2009
3084
  return {
@@ -2043,7 +3118,7 @@ var ModuleTransformerRadialGradientToCanvas = class {
2043
3118
  x: Math.max(farthestSideRadiusX, 1e-4),
2044
3119
  y: Math.max(farthestSideRadiusY, 1e-4)
2045
3120
  };
2046
- const corners = getCornerDeltas$1(center, width, height);
3121
+ const corners = getCornerDeltas$3(center, width, height);
2047
3122
  if (size.value === "closest-corner") return corners.map((corner) => scaleEllipseRadiiToCorner$1(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => {
2048
3123
  const closestArea = closest.x * closest.y;
2049
3124
  return current.x * current.y < closestArea ? current : closest;
@@ -2060,8 +3135,241 @@ var ModuleTransformerRadialGradientToCanvas = class {
2060
3135
  }
2061
3136
  };
2062
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);
3266
+ } };
3267
+ }
3268
+ _resolveCenter(position, width, height) {
3269
+ if (position.kind === "keywords") return {
3270
+ x: this._resolveKeywordX(position.x, width),
3271
+ y: this._resolveKeywordY(position.y, height)
3272
+ };
3273
+ return {
3274
+ x: this._resolve(position.x, width),
3275
+ y: this._resolve(position.y, height)
3276
+ };
3277
+ }
3278
+ _resolveKeywordX(value, width) {
3279
+ if (value === "left") return 0;
3280
+ if (value === "center") return width / 2;
3281
+ return width;
3282
+ }
3283
+ _resolveKeywordY(value, height) {
3284
+ if (value === "top") return 0;
3285
+ if (value === "center") return height / 2;
3286
+ return height;
3287
+ }
3288
+ _resolveDiamondRadii(size, shape, center, width, height) {
3289
+ if (size.kind === "explicit") {
3290
+ const radiusX = this._resolve(size.x, width);
3291
+ const radiusY = size.y ? this._resolve(size.y, height) : radiusX;
3292
+ return {
3293
+ x: Math.max(radiusX, 1e-4),
3294
+ y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
3295
+ };
3296
+ }
3297
+ const left = center.x;
3298
+ const right = width - center.x;
3299
+ const top = center.y;
3300
+ const bottom = height - center.y;
3301
+ if (shape === "circle") {
3302
+ const cornerDistances = [
3303
+ {
3304
+ x: 0,
3305
+ y: 0
3306
+ },
3307
+ {
3308
+ x: width,
3309
+ y: 0
3310
+ },
3311
+ {
3312
+ x: 0,
3313
+ y: height
3314
+ },
3315
+ {
3316
+ x: width,
3317
+ y: height
3318
+ }
3319
+ ].map((corner) => getDistanceToCorner$2(center, corner));
3320
+ if (size.value === "closest-side") {
3321
+ const radius = Math.max(Math.min(left, right, top, bottom), 1e-4);
3322
+ return {
3323
+ x: radius,
3324
+ y: radius
3325
+ };
3326
+ }
3327
+ if (size.value === "farthest-side") {
3328
+ const radius = Math.max(Math.max(left, right, top, bottom), 1e-4);
3329
+ return {
3330
+ x: radius,
3331
+ y: radius
3332
+ };
3333
+ }
3334
+ if (size.value === "closest-corner") {
3335
+ const radius = Math.max(Math.min(...cornerDistances), 1e-4);
3336
+ return {
3337
+ x: radius,
3338
+ y: radius
3339
+ };
3340
+ }
3341
+ const radius = Math.max(Math.max(...cornerDistances), 1e-4);
3342
+ return {
3343
+ x: radius,
3344
+ y: radius
3345
+ };
3346
+ }
3347
+ const closestSideRadiusX = Math.min(left, right);
3348
+ const closestSideRadiusY = Math.min(top, bottom);
3349
+ const farthestSideRadiusX = Math.max(left, right);
3350
+ const farthestSideRadiusY = Math.max(top, bottom);
3351
+ if (size.value === "closest-side") return {
3352
+ x: Math.max(closestSideRadiusX, 1e-4),
3353
+ y: Math.max(closestSideRadiusY, 1e-4)
3354
+ };
3355
+ if (size.value === "farthest-side") return {
3356
+ x: Math.max(farthestSideRadiusX, 1e-4),
3357
+ y: Math.max(farthestSideRadiusY, 1e-4)
3358
+ };
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);
3362
+ }
3363
+ _resolve(value, size) {
3364
+ if (value.kind === "percent") return value.value / 100 * size;
3365
+ if (value.unit === "px") return value.value;
3366
+ throw new Error(`Unsupported diamond-gradient length unit for Canvas transformer: ${value.unit}`);
3367
+ }
3368
+ };
3369
+ //#endregion
2063
3370
  //#region src/gradient-transformer/modules/canvas/ModuleTransformerConicGradientToCanvas.ts
2064
- const toRgb$2 = converter("rgb");
3371
+ const CONIC_GRADIENT_SAMPLE_COUNT = 128;
3372
+ const toRgb$4 = converter("rgb");
2065
3373
  var ModuleTransformerConicGradientToCanvas = class {
2066
3374
  target = "canvas-2d";
2067
3375
  gradientType = "conic-gradient";
@@ -2072,7 +3380,8 @@ var ModuleTransformerConicGradientToCanvas = class {
2072
3380
  const data = imageData.data;
2073
3381
  const { x: cx, y: cy } = this._resolvePosition(gradient.config.position, width, height);
2074
3382
  const from = this._toRad(gradient.config.from);
2075
- const stops = this._normalizeStops(gradient.stops);
3383
+ const renderStops = resolveRenderableGradientStops(gradient, CONIC_GRADIENT_SAMPLE_COUNT);
3384
+ const stops = this._normalizeStops(renderStops);
2076
3385
  if (stops.length === 0) {
2077
3386
  ctx.putImageData(imageData, 0, 0);
2078
3387
  return;
@@ -2160,7 +3469,7 @@ var ModuleTransformerConicGradientToCanvas = class {
2160
3469
  };
2161
3470
  }
2162
3471
  _parseColor(input) {
2163
- const color = toRgb$2(input);
3472
+ const color = toRgb$4(input);
2164
3473
  if (!color) throw new Error(`Failed to convert color: ${input}`);
2165
3474
  return {
2166
3475
  r: Math.round((color.r ?? 0) * 255),
@@ -2174,11 +3483,74 @@ var ModuleTransformerConicGradientToCanvas = class {
2174
3483
  }
2175
3484
  };
2176
3485
  //#endregion
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
2177
3549
  //#region src/gradient-transformer/modules/webgl/ModuleTransformerLinearGradientToWebgl.ts
2178
- const toRgb$1 = converter("rgb");
2179
- const MAX_STOPS$1 = 128;
2180
- function toWebGLColor$1(input) {
2181
- const color = toRgb$1(input);
3550
+ const toRgb$3 = converter("rgb");
3551
+ const MAX_STOPS$3 = 128;
3552
+ function toWebGLColor$3(input) {
3553
+ const color = toRgb$3(input);
2182
3554
  if (!color) throw new Error(`Failed to convert color: ${input}`);
2183
3555
  return [
2184
3556
  color.r ?? 0,
@@ -2200,14 +3572,14 @@ function getStopRange(stops) {
2200
3572
  stops: colorStops
2201
3573
  };
2202
3574
  }
2203
- function normalizeStops$1(stops, min, max) {
3575
+ function normalizeStops$2(stops, min, max) {
2204
3576
  const range = max - min || 1;
2205
3577
  return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
2206
3578
  ...stop,
2207
3579
  position: (stop.position - min) / range
2208
3580
  }));
2209
3581
  }
2210
- function createShader$1(gl, type, source) {
3582
+ function createShader$4(gl, type, source) {
2211
3583
  const shader = gl.createShader(type);
2212
3584
  if (!shader) throw new Error("Failed to create WebGL shader.");
2213
3585
  gl.shaderSource(shader, source);
@@ -2219,9 +3591,9 @@ function createShader$1(gl, type, source) {
2219
3591
  }
2220
3592
  return shader;
2221
3593
  }
2222
- function createProgram$1(gl, vertexSource, fragmentSource) {
2223
- const vertexShader = createShader$1(gl, gl.VERTEX_SHADER, vertexSource);
2224
- const fragmentShader = createShader$1(gl, gl.FRAGMENT_SHADER, fragmentSource);
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);
2225
3597
  const program = gl.createProgram();
2226
3598
  if (!program) throw new Error("Failed to create WebGL program.");
2227
3599
  gl.attachShader(program, vertexShader);
@@ -2234,15 +3606,15 @@ function createProgram$1(gl, vertexSource, fragmentSource) {
2234
3606
  }
2235
3607
  return program;
2236
3608
  }
2237
- function getColorStopCount$1(stops) {
3609
+ function getColorStopCount$3(stops) {
2238
3610
  return stops.filter((stop) => stop.type === "color-stop").length;
2239
3611
  }
2240
- function getWebGLSampleCount$1(gradient, maxStops) {
2241
- const colorStopCount = getColorStopCount$1(gradient.stops);
3612
+ function getWebGLSampleCount$3(gradient, maxStops) {
3613
+ const colorStopCount = getColorStopCount$3(gradient.stops);
2242
3614
  const segmentCount = Math.max(1, colorStopCount - 1);
2243
3615
  return Math.max(2, Math.floor((maxStops - 1) / segmentCount));
2244
3616
  }
2245
- function getColorAtPosition$1(stops, position) {
3617
+ function getColorAtPosition$3(stops, position) {
2246
3618
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
2247
3619
  if (colorStops.length === 0) throw new Error("Cannot sample color from empty gradient stops.");
2248
3620
  if (position <= colorStops[0].position) return colorStops[0].value;
@@ -2257,25 +3629,640 @@ function getColorAtPosition$1(stops, position) {
2257
3629
  return formatRgb(interpolate([current.value, next.value], "rgb")(localT));
2258
3630
  }
2259
3631
  }
2260
- return lastStop.value;
2261
- }
2262
- function fitStopsToWebGLLimit$1(stops, maxStops) {
2263
- const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
2264
- if (colorStops.length <= maxStops) return colorStops;
2265
- const sampledStops = [];
2266
- for (let index = 0; index < maxStops; index += 1) {
2267
- const position = index / (maxStops - 1);
2268
- sampledStops.push({
2269
- type: "color-stop",
2270
- value: getColorAtPosition$1(colorStops, position),
2271
- position
2272
- });
2273
- }
2274
- return sampledStops;
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
3787
+ const toRgb$2 = converter("rgb");
3788
+ const MAX_STOPS$2 = 128;
3789
+ const TWO_PI = Math.PI * 2;
3790
+ function toWebGLColor$2(input) {
3791
+ const color = toRgb$2(input);
3792
+ if (!color) throw new Error(`Failed to convert color: ${input}`);
3793
+ return [
3794
+ color.r ?? 0,
3795
+ color.g ?? 0,
3796
+ color.b ?? 0,
3797
+ color.alpha ?? 1
3798
+ ];
3799
+ }
3800
+ function createShader$3(gl, type, source) {
3801
+ const shader = gl.createShader(type);
3802
+ if (!shader) throw new Error("Failed to create WebGL shader.");
3803
+ gl.shaderSource(shader, source);
3804
+ gl.compileShader(shader);
3805
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
3806
+ const error = gl.getShaderInfoLog(shader);
3807
+ gl.deleteShader(shader);
3808
+ throw new Error(`WebGL shader compile error: ${error}`);
3809
+ }
3810
+ return shader;
3811
+ }
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);
3815
+ const program = gl.createProgram();
3816
+ if (!program) throw new Error("Failed to create WebGL program.");
3817
+ gl.attachShader(program, vertexShader);
3818
+ gl.attachShader(program, fragmentShader);
3819
+ gl.linkProgram(program);
3820
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
3821
+ const error = gl.getProgramInfoLog(program);
3822
+ gl.deleteProgram(program);
3823
+ throw new Error(`WebGL program link error: ${error}`);
3824
+ }
3825
+ return program;
3826
+ }
3827
+ function getColorStopCount$2(stops) {
3828
+ return stops.filter((stop) => stop.type === "color-stop").length;
3829
+ }
3830
+ function getWebGLSampleCount$2(gradient, maxStops) {
3831
+ const colorStopCount = getColorStopCount$2(gradient.stops);
3832
+ const segmentCount = Math.max(1, colorStopCount - 1);
3833
+ return Math.max(2, Math.floor((maxStops - 1) / segmentCount));
3834
+ }
3835
+ function getColorAtPosition$2(stops, position) {
3836
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
3837
+ if (colorStops.length === 0) throw new Error("Cannot sample color from empty gradient stops.");
3838
+ if (position <= colorStops[0].position) return colorStops[0].value;
3839
+ const lastStop = colorStops[colorStops.length - 1];
3840
+ if (position >= lastStop.position) return lastStop.value;
3841
+ for (let index = 0; index < colorStops.length - 1; index += 1) {
3842
+ const current = colorStops[index];
3843
+ const next = colorStops[index + 1];
3844
+ if (position >= current.position && position <= next.position) {
3845
+ const range = next.position - current.position || 1;
3846
+ const localT = (position - current.position) / range;
3847
+ return formatRgb(interpolate([current.value, next.value], "rgb")(localT));
3848
+ }
3849
+ }
3850
+ return lastStop.value;
3851
+ }
3852
+ function fitStopsToWebGLLimit$2(stops, maxStops) {
3853
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
3854
+ if (colorStops.length <= maxStops) return colorStops;
3855
+ const sampledStops = [];
3856
+ for (let index = 0; index < maxStops; index += 1) {
3857
+ const position = index / (maxStops - 1);
3858
+ sampledStops.push({
3859
+ type: "color-stop",
3860
+ value: getColorAtPosition$2(colorStops, position),
3861
+ position
3862
+ });
3863
+ }
3864
+ return sampledStops;
3865
+ }
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 {
3908
+ target = "canvas-webgl";
3909
+ gradientType = "conic-gradient";
3910
+ to(input) {
3911
+ const gradient = input;
3912
+ return { draw: (canvas, width, height) => {
3913
+ const gl = canvas.getContext("webgl");
3914
+ if (!gl) throw new Error("WebGL is not supported.");
3915
+ canvas.width = width;
3916
+ canvas.height = height;
3917
+ gl.viewport(0, 0, width, height);
3918
+ const program = createProgram$3(gl, `
3919
+ attribute vec2 a_position;
3920
+ varying vec2 v_uv;
3921
+
3922
+ void main() {
3923
+ v_uv = a_position * 0.5 + 0.5;
3924
+ gl_Position = vec4(a_position, 0.0, 1.0);
3925
+ }
3926
+ `, `
3927
+ precision mediump float;
3928
+
3929
+ const float PI = 3.141592653589793;
3930
+ const float TWO_PI = 6.283185307179586;
3931
+
3932
+ varying vec2 v_uv;
3933
+
3934
+ uniform vec2 u_center;
3935
+ uniform float u_startAngle;
3936
+ uniform int u_stopCount;
3937
+ uniform float u_positions[${MAX_STOPS$2}];
3938
+ uniform vec4 u_colors[${MAX_STOPS$2}];
3939
+
3940
+ vec4 getGradientColor(float t) {
3941
+ vec4 result = u_colors[0];
3942
+
3943
+ for (int i = 0; i < ${MAX_STOPS$2 - 1}; i++) {
3944
+ if (i >= u_stopCount - 1) {
3945
+ break;
3946
+ }
3947
+
3948
+ float currentPosition = u_positions[i];
3949
+ float nextPosition = u_positions[i + 1];
3950
+
3951
+ if (t <= currentPosition) {
3952
+ return u_colors[i];
3953
+ }
3954
+
3955
+ if (t >= currentPosition && t <= nextPosition) {
3956
+ float localT = (t - currentPosition) / max(nextPosition - currentPosition, 0.00001);
3957
+ return mix(u_colors[i], u_colors[i + 1], localT);
3958
+ }
3959
+
3960
+ result = u_colors[i + 1];
3961
+ }
3962
+
3963
+ return result;
3964
+ }
3965
+
3966
+ void main() {
3967
+ vec2 delta = v_uv - u_center;
3968
+
3969
+ float angle = atan(delta.y, delta.x);
3970
+ float cssAngle = mod((PI * 0.5) - angle + TWO_PI, TWO_PI);
3971
+
3972
+ float t = mod(cssAngle - u_startAngle + TWO_PI, TWO_PI) / TWO_PI;
3973
+
3974
+ gl_FragColor = getGradientColor(t);
3975
+ }
3976
+ `);
3977
+ gl.useProgram(program);
3978
+ const positionBuffer = gl.createBuffer();
3979
+ gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
3980
+ gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
3981
+ -1,
3982
+ -1,
3983
+ 1,
3984
+ -1,
3985
+ -1,
3986
+ 1,
3987
+ -1,
3988
+ 1,
3989
+ 1,
3990
+ -1,
3991
+ 1,
3992
+ 1
3993
+ ]), gl.STATIC_DRAW);
3994
+ const positionLocation = gl.getAttribLocation(program, "a_position");
3995
+ gl.enableVertexAttribArray(positionLocation);
3996
+ gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
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);
3999
+ const positions = new Float32Array(MAX_STOPS$2);
4000
+ const colors = new Float32Array(MAX_STOPS$2 * 4);
4001
+ limitedStops.forEach((stop, index) => {
4002
+ const color = toWebGLColor$2(stop.value);
4003
+ positions[index] = stop.position;
4004
+ colors[index * 4 + 0] = color[0];
4005
+ colors[index * 4 + 1] = color[1];
4006
+ colors[index * 4 + 2] = color[2];
4007
+ colors[index * 4 + 3] = color[3];
4008
+ });
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));
4011
+ gl.uniform1i(gl.getUniformLocation(program, "u_stopCount"), limitedStops.length);
4012
+ gl.uniform1fv(gl.getUniformLocation(program, "u_positions"), positions);
4013
+ gl.uniform4fv(gl.getUniformLocation(program, "u_colors"), colors);
4014
+ gl.clearColor(0, 0, 0, 0);
4015
+ gl.clear(gl.COLOR_BUFFER_BIT);
4016
+ gl.drawArrays(gl.TRIANGLES, 0, 6);
4017
+ } };
4018
+ }
4019
+ };
4020
+ //#endregion
4021
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerRadialGradientToWebgl.ts
4022
+ const toRgb$1 = converter("rgb");
4023
+ const MAX_STOPS$1 = 128;
4024
+ const MAX_REPEATING_RADIAL_T = 16;
4025
+ function toWebGLColor$1(input) {
4026
+ const color = toRgb$1(input);
4027
+ if (!color) throw new Error(`Failed to convert color: ${input}`);
4028
+ return [
4029
+ color.r ?? 0,
4030
+ color.g ?? 0,
4031
+ color.b ?? 0,
4032
+ color.alpha ?? 1
4033
+ ];
4034
+ }
4035
+ function createShader$2(gl, type, source) {
4036
+ const shader = gl.createShader(type);
4037
+ if (!shader) throw new Error("Failed to create WebGL shader.");
4038
+ gl.shaderSource(shader, source);
4039
+ gl.compileShader(shader);
4040
+ if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
4041
+ const error = gl.getShaderInfoLog(shader);
4042
+ gl.deleteShader(shader);
4043
+ throw new Error(`WebGL shader compile error: ${error}`);
4044
+ }
4045
+ return shader;
4046
+ }
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);
4050
+ const program = gl.createProgram();
4051
+ if (!program) throw new Error("Failed to create WebGL program.");
4052
+ gl.attachShader(program, vertexShader);
4053
+ gl.attachShader(program, fragmentShader);
4054
+ gl.linkProgram(program);
4055
+ if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
4056
+ const error = gl.getProgramInfoLog(program);
4057
+ gl.deleteProgram(program);
4058
+ throw new Error(`WebGL program link error: ${error}`);
4059
+ }
4060
+ return program;
4061
+ }
4062
+ function getColorStopCount$1(stops) {
4063
+ return stops.filter((stop) => stop.type === "color-stop").length;
4064
+ }
4065
+ function getWebGLSampleCount$1(gradient, maxStops) {
4066
+ const colorStopCount = getColorStopCount$1(gradient.stops);
4067
+ const segmentCount = Math.max(1, colorStopCount - 1);
4068
+ return Math.max(2, Math.floor((maxStops - 1) / segmentCount));
4069
+ }
4070
+ function getColorAtPosition$1(stops, position) {
4071
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
4072
+ if (colorStops.length === 0) throw new Error("Cannot sample color from empty gradient stops.");
4073
+ if (position <= colorStops[0].position) return colorStops[0].value;
4074
+ const lastStop = colorStops[colorStops.length - 1];
4075
+ if (position >= lastStop.position) return lastStop.value;
4076
+ for (let index = 0; index < colorStops.length - 1; index += 1) {
4077
+ const current = colorStops[index];
4078
+ const next = colorStops[index + 1];
4079
+ if (position >= current.position && position <= next.position) {
4080
+ const range = next.position - current.position || 1;
4081
+ const localT = (position - current.position) / range;
4082
+ return formatRgb(interpolate([current.value, next.value], "rgb")(localT));
4083
+ }
4084
+ }
4085
+ return lastStop.value;
4086
+ }
4087
+ function fitStopsToWebGLLimit$1(stops, maxStops) {
4088
+ const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
4089
+ if (colorStops.length <= maxStops) return colorStops;
4090
+ const sampledStops = [];
4091
+ for (let index = 0; index < maxStops; index += 1) {
4092
+ const position = index / (maxStops - 1);
4093
+ sampledStops.push({
4094
+ type: "color-stop",
4095
+ value: getColorAtPosition$1(colorStops, position),
4096
+ position
4097
+ });
4098
+ }
4099
+ return sampledStops;
4100
+ }
4101
+ function parseLengthPercentage$1(value, reference) {
4102
+ if (value.kind === "percent") return value.value / 100 * reference;
4103
+ if (value.kind === "length") {
4104
+ if (value.unit === "px") return value.value;
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
+ };
4240
+ }
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)
4248
+ };
4249
+ if (size.value === "farthest-side") return {
4250
+ x: Math.max(farthestSideRadiusX, 1e-4),
4251
+ y: Math.max(farthestSideRadiusY, 1e-4)
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
+ });
2275
4262
  }
2276
- var ModuleTransformerLinearGradientToCanvasWebGL = class {
4263
+ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2277
4264
  target = "canvas-webgl";
2278
- gradientType = "linear-gradient";
4265
+ gradientType = "radial-gradient";
2279
4266
  to(input) {
2280
4267
  const gradient = input;
2281
4268
  return { draw: (canvas, width, height) => {
@@ -2284,7 +4271,7 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2284
4271
  canvas.width = width;
2285
4272
  canvas.height = height;
2286
4273
  gl.viewport(0, 0, width, height);
2287
- const program = createProgram$1(gl, `
4274
+ const program = createProgram$2(gl, `
2288
4275
  attribute vec2 a_position;
2289
4276
  varying vec2 v_uv;
2290
4277
 
@@ -2297,11 +4284,12 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2297
4284
 
2298
4285
  varying vec2 v_uv;
2299
4286
 
2300
- uniform vec2 u_start;
2301
- uniform vec2 u_end;
4287
+ uniform vec2 u_center;
4288
+ uniform vec2 u_radius;
2302
4289
  uniform int u_stopCount;
2303
4290
  uniform float u_positions[${MAX_STOPS$1}];
2304
4291
  uniform vec4 u_colors[${MAX_STOPS$1}];
4292
+ uniform float u_tMax;
2305
4293
 
2306
4294
  vec4 getGradientColor(float t) {
2307
4295
  vec4 result = u_colors[0];
@@ -2330,13 +4318,12 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2330
4318
  }
2331
4319
 
2332
4320
  void main() {
2333
- vec2 axis = u_end - u_start;
2334
- vec2 point = v_uv;
2335
-
2336
- float axisLengthSquared = dot(axis, axis);
2337
- float t = dot(point - u_start, axis) / axisLengthSquared;
4321
+ vec2 delta = v_uv - u_center;
4322
+ vec2 normalized = delta / max(u_radius, vec2(0.00001));
4323
+ float t = length(normalized);
2338
4324
 
2339
- t = clamp(t, 0.0, 1.0);
4325
+ t = clamp(t, 0.0, u_tMax);
4326
+ t = t / max(u_tMax, 0.00001);
2340
4327
 
2341
4328
  gl_FragColor = getGradientColor(t);
2342
4329
  }
@@ -2361,34 +4348,14 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2361
4348
  const positionLocation = gl.getAttribLocation(program, "a_position");
2362
4349
  gl.enableVertexAttribArray(positionLocation);
2363
4350
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
2364
- const angle = gradient.config.angle;
2365
- const dirX = Math.sin(angle);
2366
- const dirY = -Math.cos(angle);
2367
- const centerX = width / 2;
2368
- const centerY = height / 2;
2369
- const lineLength = Math.abs(width * dirX) + Math.abs(height * dirY);
2370
- let startX = centerX - dirX * lineLength / 2;
2371
- let startY = centerY - dirY * lineLength / 2;
2372
- let endX = centerX + dirX * lineLength / 2;
2373
- let endY = centerY + dirY * lineLength / 2;
2374
- const { min, max, stops } = getStopRange(resolveRenderableGradientStops(gradient, getWebGLSampleCount$1(gradient, MAX_STOPS$1)));
2375
- let normalizedStops = stops;
2376
- if (min < 0 || max > 1) {
2377
- const vx = endX - startX;
2378
- const vy = endY - startY;
2379
- const baseStartX = startX;
2380
- const baseStartY = startY;
2381
- startX = baseStartX + vx * min;
2382
- startY = baseStartY + vy * min;
2383
- endX = baseStartX + vx * max;
2384
- endY = baseStartY + vy * max;
2385
- normalizedStops = normalizeStops$1(stops, min, max);
2386
- }
2387
- const startU = startX / width;
2388
- const startV = 1 - startY / height;
2389
- const endU = endX / width;
2390
- const endV = 1 - endY / height;
2391
- const limitedStops = fitStopsToWebGLLimit$1(normalizedStops, 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);
2392
4359
  const positions = new Float32Array(MAX_STOPS$1);
2393
4360
  const colors = new Float32Array(MAX_STOPS$1 * 4);
2394
4361
  limitedStops.forEach((stop, index) => {
@@ -2399,8 +4366,9 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2399
4366
  colors[index * 4 + 2] = color[2];
2400
4367
  colors[index * 4 + 3] = color[3];
2401
4368
  });
2402
- gl.uniform2f(gl.getUniformLocation(program, "u_start"), startU, startV);
2403
- gl.uniform2f(gl.getUniformLocation(program, "u_end"), endU, endV);
4369
+ gl.uniform2f(gl.getUniformLocation(program, "u_center"), center.x / width, 1 - center.y / height);
4370
+ gl.uniform2f(gl.getUniformLocation(program, "u_radius"), radius.x / width, radius.y / height);
4371
+ gl.uniform1f(gl.getUniformLocation(program, "u_tMax"), maxT);
2404
4372
  gl.uniform1i(gl.getUniformLocation(program, "u_stopCount"), limitedStops.length);
2405
4373
  gl.uniform1fv(gl.getUniformLocation(program, "u_positions"), positions);
2406
4374
  gl.uniform4fv(gl.getUniformLocation(program, "u_colors"), colors);
@@ -2411,10 +4379,10 @@ var ModuleTransformerLinearGradientToCanvasWebGL = class {
2411
4379
  }
2412
4380
  };
2413
4381
  //#endregion
2414
- //#region src/gradient-transformer/modules/webgl/ModuleTransformerRadialGradientToWebgl.ts
4382
+ //#region src/gradient-transformer/modules/webgl/ModuleTransformerDiamondGradientToWebgl.ts
2415
4383
  const toRgb = converter("rgb");
2416
4384
  const MAX_STOPS = 128;
2417
- const MAX_REPEATING_RADIAL_T = 16;
4385
+ const MAX_REPEATING_DIAMOND_T = 16;
2418
4386
  function toWebGLColor(input) {
2419
4387
  const color = toRgb(input);
2420
4388
  if (!color) throw new Error(`Failed to convert color: ${input}`);
@@ -2425,7 +4393,7 @@ function toWebGLColor(input) {
2425
4393
  color.alpha ?? 1
2426
4394
  ];
2427
4395
  }
2428
- function createShader(gl, type, source) {
4396
+ function createShader$1(gl, type, source) {
2429
4397
  const shader = gl.createShader(type);
2430
4398
  if (!shader) throw new Error("Failed to create WebGL shader.");
2431
4399
  gl.shaderSource(shader, source);
@@ -2437,9 +4405,9 @@ function createShader(gl, type, source) {
2437
4405
  }
2438
4406
  return shader;
2439
4407
  }
2440
- function createProgram(gl, vertexSource, fragmentSource) {
2441
- const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexSource);
2442
- 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);
2443
4411
  const program = gl.createProgram();
2444
4412
  if (!program) throw new Error("Failed to create WebGL program.");
2445
4413
  gl.attachShader(program, vertexShader);
@@ -2462,7 +4430,7 @@ function getWebGLSampleCount(gradient, maxStops) {
2462
4430
  }
2463
4431
  function getColorAtPosition(stops, position) {
2464
4432
  const colorStops = stops.filter((stop) => stop.type === "color-stop" && stop.position != null).sort((a, b) => a.position - b.position);
2465
- 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.");
2466
4434
  if (position <= colorStops[0].position) return colorStops[0].value;
2467
4435
  const lastStop = colorStops[colorStops.length - 1];
2468
4436
  if (position >= lastStop.position) return lastStop.value;
@@ -2491,57 +4459,40 @@ function fitStopsToWebGLLimit(stops, maxStops) {
2491
4459
  }
2492
4460
  return sampledStops;
2493
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
+ }
2494
4469
  function parseLengthPercentage(value, reference) {
2495
4470
  if (value.kind === "percent") return value.value / 100 * reference;
2496
- if (value.kind === "length") {
2497
- if (value.unit === "px") return value.value;
2498
- throw new Error(`Unsupported gradient length unit for WebGL radial gradient: ${value.unit}`);
2499
- }
2500
- return value;
4471
+ if (value.unit === "px") return value.value;
4472
+ throw new Error(`Unsupported diamond-gradient length unit for WebGL transformer: ${value.unit}`);
2501
4473
  }
2502
4474
  function resolveKeywordPositionX(x, width) {
2503
4475
  if (x === "left") return 0;
2504
- if (x === "center") return width / 2;
2505
4476
  if (x === "right") return width;
2506
4477
  return width / 2;
2507
4478
  }
2508
4479
  function resolveKeywordPositionY(y, height) {
2509
4480
  if (y === "top") return 0;
2510
- if (y === "center") return height / 2;
2511
4481
  if (y === "bottom") return height;
2512
4482
  return height / 2;
2513
4483
  }
2514
- function resolveRadialCenter(position, width, height) {
4484
+ function resolveDiamondCenter(position, width, height) {
2515
4485
  if (position.kind === "keywords") return {
2516
4486
  x: resolveKeywordPositionX(position.x, width),
2517
4487
  y: resolveKeywordPositionY(position.y, height)
2518
4488
  };
2519
- if (position.kind === "values") return {
4489
+ return {
2520
4490
  x: parseLengthPercentage(position.x, width),
2521
4491
  y: parseLengthPercentage(position.y, height)
2522
4492
  };
2523
- return {
2524
- x: width / 2,
2525
- y: height / 2
2526
- };
2527
- }
2528
- function getDistanceToSide(center, width, height, side) {
2529
- if (side === "left") return center.x;
2530
- if (side === "right") return width - center.x;
2531
- if (side === "top") return center.y;
2532
- return height - center.y;
2533
4493
  }
2534
4494
  function getDistanceToCorner(center, corner) {
2535
- const dx = corner.x - center.x;
2536
- const dy = corner.y - center.y;
2537
- return Math.sqrt(dx * dx + dy * dy);
2538
- }
2539
- function normalizeStops(stops, min, max) {
2540
- const range = max - min || 1;
2541
- return stops.filter((stop) => stop.type === "color-stop" && stop.position != null).map((stop) => ({
2542
- ...stop,
2543
- position: (stop.position - min) / range
2544
- }));
4495
+ return Math.abs(corner.x - center.x) + Math.abs(corner.y - center.y);
2545
4496
  }
2546
4497
  function getCornerDeltas(center, width, height) {
2547
4498
  return [
@@ -2563,16 +4514,16 @@ function getCornerDeltas(center, width, height) {
2563
4514
  }
2564
4515
  ];
2565
4516
  }
2566
- function scaleEllipseRadiiToCorner(radiusX, radiusY, dx, dy) {
4517
+ function scaleDiamondRadiiToCorner(radiusX, radiusY, dx, dy) {
2567
4518
  const safeRadiusX = Math.max(radiusX, 1e-4);
2568
4519
  const safeRadiusY = Math.max(radiusY, 1e-4);
2569
- const scale = Math.sqrt(dx * dx / (safeRadiusX * safeRadiusX) + dy * dy / (safeRadiusY * safeRadiusY));
4520
+ const scale = Math.abs(dx) / safeRadiusX + Math.abs(dy) / safeRadiusY;
2570
4521
  return {
2571
4522
  x: safeRadiusX * scale,
2572
4523
  y: safeRadiusY * scale
2573
4524
  };
2574
4525
  }
2575
- function resolveRadialRadii(size, shape, center, width, height) {
4526
+ function resolveDiamondRadii(size, shape, center, width, height) {
2576
4527
  if (size.kind === "explicit") {
2577
4528
  const radiusX = parseLengthPercentage(size.x, width);
2578
4529
  const radiusY = size.y ? parseLengthPercentage(size.y, height) : radiusX;
@@ -2581,10 +4532,10 @@ function resolveRadialRadii(size, shape, center, width, height) {
2581
4532
  y: Math.max(shape === "circle" ? radiusX : radiusY, 1e-4)
2582
4533
  };
2583
4534
  }
2584
- const left = getDistanceToSide(center, width, height, "left");
2585
- const right = getDistanceToSide(center, width, height, "right");
2586
- const top = getDistanceToSide(center, width, height, "top");
2587
- 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;
2588
4539
  if (shape === "circle") {
2589
4540
  const cornerDistances = [
2590
4541
  {
@@ -2644,19 +4595,34 @@ function resolveRadialRadii(size, shape, center, width, height) {
2644
4595
  y: Math.max(farthestSideRadiusY, 1e-4)
2645
4596
  };
2646
4597
  const corners = getCornerDeltas(center, width, height);
2647
- if (size.value === "closest-corner") return corners.map((corner) => scaleEllipseRadiiToCorner(closestSideRadiusX, closestSideRadiusY, corner.dx, corner.dy)).reduce((closest, current) => {
2648
- const closestArea = closest.x * closest.y;
2649
- return current.x * current.y < closestArea ? current : closest;
2650
- });
2651
- return corners.map((corner) => scaleEllipseRadiiToCorner(farthestSideRadiusX, farthestSideRadiusY, corner.dx, corner.dy)).reduce((farthest, current) => {
2652
- const farthestArea = farthest.x * farthest.y;
2653
- return current.x * current.y > farthestArea ? current : farthest;
2654
- });
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);
2655
4600
  }
2656
- 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 {
2657
4622
  target = "canvas-webgl";
2658
- gradientType = "radial-gradient";
4623
+ gradientType = "diamond-gradient";
2659
4624
  to(input) {
4625
+ if (!(input instanceof DiamondGradient)) throw new Error("Expected DiamondGradient");
2660
4626
  const gradient = input;
2661
4627
  return { draw: (canvas, width, height) => {
2662
4628
  const gl = canvas.getContext("webgl");
@@ -2664,7 +4630,7 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2664
4630
  canvas.width = width;
2665
4631
  canvas.height = height;
2666
4632
  gl.viewport(0, 0, width, height);
2667
- const program = createProgram(gl, `
4633
+ const program = createProgram$1(gl, `
2668
4634
  attribute vec2 a_position;
2669
4635
  varying vec2 v_uv;
2670
4636
 
@@ -2712,8 +4678,8 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2712
4678
 
2713
4679
  void main() {
2714
4680
  vec2 delta = v_uv - u_center;
2715
- vec2 normalized = delta / max(u_radius, vec2(0.00001));
2716
- float t = length(normalized);
4681
+ vec2 normalized = abs(delta) / max(u_radius, vec2(0.00001));
4682
+ float t = normalized.x + normalized.y;
2717
4683
 
2718
4684
  t = clamp(t, 0.0, u_tMax);
2719
4685
  t = t / max(u_tMax, 0.00001);
@@ -2741,11 +4707,11 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2741
4707
  const positionLocation = gl.getAttribLocation(program, "a_position");
2742
4708
  gl.enableVertexAttribArray(positionLocation);
2743
4709
  gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
2744
- const center = resolveRadialCenter(gradient.config.position, width, height);
2745
- const radius = resolveRadialRadii(gradient.config.size, gradient.config.shape, center, width, height);
2746
- 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);
2747
4713
  const baseStops = resolveRenderableGradientStops(gradient, getWebGLSampleCount(gradient, MAX_STOPS));
2748
- const repeatMaxT = Math.min(maxVisibleT, MAX_REPEATING_RADIAL_T);
4714
+ const repeatMaxT = Math.min(maxVisibleT, MAX_REPEATING_DIAMOND_T);
2749
4715
  const maxT = gradient.isRepeating ? repeatMaxT : 1;
2750
4716
  const renderStops = gradient.isRepeating ? expandRepeatingStopsTo(baseStops, 0, repeatMaxT) : baseStops;
2751
4717
  const limitedStops = fitStopsToWebGLLimit(gradient.isRepeating ? normalizeStops(renderStops, 0, repeatMaxT) : renderStops, MAX_STOPS);
@@ -2772,6 +4738,107 @@ var ModuleTransformerRadialGradientToCanvasWebGL = class {
2772
4738
  }
2773
4739
  };
2774
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
2775
4842
  //#region src/gradient-transformer/GradientTransformer.ts
2776
4843
  var GradientTransformer = class {
2777
4844
  static _modules = /* @__PURE__ */ new Map();
@@ -2804,12 +4871,19 @@ var GradientTransformer = class {
2804
4871
  this._initialized = true;
2805
4872
  this.add(new ModuleTransformerLinearGradientToCss());
2806
4873
  this.add(new ModuleTransformerRadialGradientToCss());
4874
+ this.add(new ModuleTransformerDiamondGradientToCss());
2807
4875
  this.add(new ModuleTransformerConicGradientToCss());
4876
+ this.add(new ModuleTransformerMeshGradientToCss());
2808
4877
  this.add(new ModuleTransformerLinearGradientToCanvas());
2809
4878
  this.add(new ModuleTransformerRadialGradientToCanvas());
4879
+ this.add(new ModuleTransformerDiamondGradientToCanvas());
2810
4880
  this.add(new ModuleTransformerConicGradientToCanvas());
4881
+ this.add(new ModuleTransformerMeshGradientToCanvas());
2811
4882
  this.add(new ModuleTransformerLinearGradientToCanvasWebGL());
2812
4883
  this.add(new ModuleTransformerRadialGradientToCanvasWebGL());
4884
+ this.add(new ModuleTransformerDiamondGradientToCanvasWebGL());
4885
+ this.add(new ModuleTransformerConicGradientToCanvasWebGL());
4886
+ this.add(new ModuleTransformerMeshGradientToCanvasWebGL());
2813
4887
  }
2814
4888
  static _getKey(target, gradientType) {
2815
4889
  return `${target}:${gradientType}`;
@@ -2832,7 +4906,13 @@ var GradientFactory = class {
2832
4906
  return this._registry.delete(functionName);
2833
4907
  }
2834
4908
  static create(input) {
2835
- 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;
2836
4916
  const adapter = this.get(abi.functionName);
2837
4917
  if (!adapter) throw new Error(`No gradient registered for: ${abi.functionName}`);
2838
4918
  return adapter.fromAbi(abi);
@@ -2850,7 +4930,17 @@ var GradientFactory = class {
2850
4930
  this._initialized = true;
2851
4931
  this.add("linear-gradient", LinearGradient);
2852
4932
  this.add("radial-gradient", RadialGradient);
4933
+ this.add("diamond-gradient", DiamondGradient);
2853
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;
2854
4944
  }
2855
4945
  };
2856
4946
  function parse(input) {
@@ -2871,4 +4961,4 @@ function transformFrom(target, gradientType, input) {
2871
4961
  return GradientTransformer.from(target, gradientType, input);
2872
4962
  }
2873
4963
  //#endregion
2874
- export { ConicGradient, GRADIENT_COLOR_SPACE, GRADIENT_HUE_INTERPOLATIONS, GRADIENT_POLAR_COLOR_SPACES, GradientBase, GradientFactory, GradientTransformer, LinearGradient, ModuleTransformerConicGradientToCanvas, 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 };