@pixerate/editor 0.163.0 → 0.165.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.
Files changed (159) hide show
  1. package/dist/agent/index.cjs +54 -39
  2. package/dist/agent/index.js +24 -9
  3. package/dist/animation/index.cjs +6 -5
  4. package/dist/animation/index.js +5 -4
  5. package/dist/animation-editor/index.cjs +65 -64
  6. package/dist/animation-editor/index.js +8 -7
  7. package/dist/bridge/cli.cjs +3 -3
  8. package/dist/bridge/cli.js +2 -2
  9. package/dist/bridge/index.cjs +3 -3
  10. package/dist/bridge/index.js +2 -2
  11. package/dist/canvas/displacement.d.cts +34 -2
  12. package/dist/canvas/displacement.d.ts +34 -2
  13. package/dist/canvas/explosion-tools.d.cts +43 -0
  14. package/dist/canvas/explosion-tools.d.ts +43 -0
  15. package/dist/canvas/explosionLayout.d.cts +50 -0
  16. package/dist/canvas/explosionLayout.d.ts +50 -0
  17. package/dist/canvas/explosionState.d.cts +52 -0
  18. package/dist/canvas/explosionState.d.ts +52 -0
  19. package/dist/canvas/index.cjs +512 -168
  20. package/dist/canvas/index.d.cts +3 -0
  21. package/dist/canvas/index.d.ts +3 -0
  22. package/dist/canvas/index.js +434 -90
  23. package/dist/canvas/types.d.cts +27 -2
  24. package/dist/canvas/types.d.ts +27 -2
  25. package/dist/chart/controller.d.cts +31 -2
  26. package/dist/chart/controller.d.ts +31 -2
  27. package/dist/chart/index.cjs +504 -132
  28. package/dist/chart/index.d.cts +2 -0
  29. package/dist/chart/index.d.ts +2 -0
  30. package/dist/chart/index.js +386 -14
  31. package/dist/chart/layout-families.d.cts +7 -0
  32. package/dist/chart/layout-families.d.ts +7 -0
  33. package/dist/chart/links.d.cts +34 -0
  34. package/dist/chart/links.d.ts +34 -0
  35. package/dist/chart/mermaid.d.cts +9 -6
  36. package/dist/chart/mermaid.d.ts +9 -6
  37. package/dist/chart/schemas.d.cts +3 -0
  38. package/dist/chart/schemas.d.ts +3 -0
  39. package/dist/chart/spec.d.cts +3 -2
  40. package/dist/chart/spec.d.ts +3 -2
  41. package/dist/chart/style.d.cts +33 -0
  42. package/dist/chart/style.d.ts +33 -0
  43. package/dist/chart/types.d.cts +24 -2
  44. package/dist/chart/types.d.ts +24 -2
  45. package/dist/{chunk-TALQONZ5.js → chunk-2J5VLJHC.js} +3 -3
  46. package/dist/{chunk-3NEZJCBY.js → chunk-2ZRN43IN.js} +340 -201
  47. package/dist/{chunk-ZVNAMTFO.cjs → chunk-3FSUJIXN.cjs} +18 -174
  48. package/dist/{chunk-RQCMSEM5.cjs → chunk-4QUUHTGJ.cjs} +2 -2
  49. package/dist/{chunk-CIPIESX4.cjs → chunk-4ZC5QJE2.cjs} +3 -3
  50. package/dist/{chunk-S6X2QRVU.cjs → chunk-5UEFBM2M.cjs} +1 -138
  51. package/dist/{chunk-YSAGBIRW.cjs → chunk-64VWWR5U.cjs} +16 -16
  52. package/dist/{chunk-QYZGBVNC.js → chunk-7272D3K2.js} +10 -8
  53. package/dist/{chunk-462WGGXX.cjs → chunk-AMX23CSN.cjs} +27 -16
  54. package/dist/{chunk-3VLOOO3G.js → chunk-BDIM6NVW.js} +1 -1
  55. package/dist/{chunk-POR54B55.js → chunk-CRFSQWKQ.js} +4 -1
  56. package/dist/{chunk-GZ2FM3ZB.js → chunk-DKNEQX7T.js} +6 -162
  57. package/dist/{chunk-JCXMJUQO.cjs → chunk-EGZM52EO.cjs} +3 -3
  58. package/dist/{chunk-ES3UEVUT.cjs → chunk-EUIDTZNQ.cjs} +112 -110
  59. package/dist/{chunk-H3OEM3Q2.js → chunk-F6R67I3A.js} +1 -1
  60. package/dist/{chunk-5FNGLV2D.js → chunk-FEU2XVQH.js} +15 -3
  61. package/dist/{chunk-SZA42R4N.js → chunk-FRBRLKNQ.js} +154 -16
  62. package/dist/chunk-HIDFL5LQ.js +484 -0
  63. package/dist/{chunk-MKTDELCD.js → chunk-I5MRJW7B.js} +1 -1
  64. package/dist/{chunk-SDHZG5TF.js → chunk-ILP77UD6.js} +160 -2
  65. package/dist/{chunk-GKNEJ6EN.cjs → chunk-IMRXC7OA.cjs} +241 -103
  66. package/dist/chunk-KGRZMHZB.js +204 -0
  67. package/dist/{chunk-SET6KJOP.js → chunk-LPIKXPBM.js} +1 -1
  68. package/dist/{chunk-BQWGN5WH.js → chunk-M2TPMYJE.js} +1 -1
  69. package/dist/{chunk-GTELFJRE.cjs → chunk-M5GLQQWG.cjs} +2 -2
  70. package/dist/{chunk-4VU4CP7R.js → chunk-MHLU6GRJ.js} +1 -138
  71. package/dist/{chunk-D54JHQK2.cjs → chunk-MKXK6E4O.cjs} +51 -51
  72. package/dist/{chunk-DAPQGA55.js → chunk-N7NBGT2Y.js} +2 -2
  73. package/dist/chunk-O6OGNDND.js +164 -0
  74. package/dist/{chunk-22KLZZGH.cjs → chunk-ODFCS7HF.cjs} +8 -8
  75. package/dist/{chunk-PA3IMPPS.cjs → chunk-OVYQAYGH.cjs} +81 -81
  76. package/dist/{chunk-YXOW456B.js → chunk-PPEDZ5WR.js} +1 -1
  77. package/dist/{chunk-YGG7WDWT.cjs → chunk-Q25WAFTD.cjs} +21 -18
  78. package/dist/{chunk-SBQVEBSU.cjs → chunk-QO2T6KA5.cjs} +165 -67
  79. package/dist/{chunk-24M7VD6M.cjs → chunk-S4EIAIEW.cjs} +7 -7
  80. package/dist/{chunk-M4MIZPQI.cjs → chunk-SJ2CPTQC.cjs} +189 -15
  81. package/dist/chunk-TFF2GTGN.cjs +153 -0
  82. package/dist/chunk-TTCJPX4U.cjs +204 -0
  83. package/dist/{chunk-NZD2MZJC.cjs → chunk-TVQW26AV.cjs} +35 -23
  84. package/dist/{chunk-R3P2M7HU.cjs → chunk-UVXTOZ2B.cjs} +346 -207
  85. package/dist/{chunk-WI7QJA7A.cjs → chunk-UXETV2NC.cjs} +161 -3
  86. package/dist/{chunk-Z4P2RBMJ.js → chunk-V5GSY3NC.js} +101 -3
  87. package/dist/{chunk-QY4KUDMY.js → chunk-VRXXAXUT.js} +2 -2
  88. package/dist/chunk-VU6WQSMB.cjs +164 -0
  89. package/dist/{chunk-OXERWBKE.js → chunk-X5W645RI.js} +3 -3
  90. package/dist/{chunk-NHLYK3AX.js → chunk-XBQX76CT.js} +182 -8
  91. package/dist/{chunk-5AARIS3R.cjs → chunk-XCDGM7TD.cjs} +37 -37
  92. package/dist/{chunk-EVXQNQND.js → chunk-XZB3TJ6K.js} +16 -5
  93. package/dist/chunk-YBAPT7NL.js +153 -0
  94. package/dist/chunk-Z2UQYMPS.cjs +484 -0
  95. package/dist/color/index.cjs +5 -3
  96. package/dist/color/index.js +12 -10
  97. package/dist/diagram/index.cjs +55 -243
  98. package/dist/diagram/index.js +12 -200
  99. package/dist/export/index.cjs +7 -6
  100. package/dist/export/index.js +6 -5
  101. package/dist/extensions/index.cjs +12 -9
  102. package/dist/extensions/index.js +11 -8
  103. package/dist/gradient/index.cjs +29 -27
  104. package/dist/gradient/index.js +6 -4
  105. package/dist/image-editor/index.cjs +644 -643
  106. package/dist/image-editor/index.js +7 -6
  107. package/dist/index.cjs +21 -18
  108. package/dist/index.js +14 -11
  109. package/dist/paint-editor/index.cjs +19 -18
  110. package/dist/paint-editor/index.js +7 -6
  111. package/dist/parameters/index.cjs +2 -2
  112. package/dist/parameters/index.js +1 -1
  113. package/dist/persistence/assetWrites.d.cts +22 -0
  114. package/dist/persistence/assetWrites.d.ts +22 -0
  115. package/dist/persistence/assets.d.cts +71 -0
  116. package/dist/persistence/assets.d.ts +71 -0
  117. package/dist/persistence/documentStore.d.cts +17 -1
  118. package/dist/persistence/documentStore.d.ts +17 -1
  119. package/dist/persistence/documentTools.d.cts +5 -1
  120. package/dist/persistence/documentTools.d.ts +5 -1
  121. package/dist/persistence/editorAutosave.d.cts +7 -0
  122. package/dist/persistence/editorAutosave.d.ts +7 -0
  123. package/dist/persistence/index.cjs +141 -21
  124. package/dist/persistence/index.js +130 -10
  125. package/dist/persistence/storage.d.cts +13 -1
  126. package/dist/persistence/storage.d.ts +13 -1
  127. package/dist/spreadsheet/index.cjs +3 -3
  128. package/dist/spreadsheet/index.js +2 -2
  129. package/dist/tokens/index.cjs +11 -3
  130. package/dist/tokens/index.d.cts +1 -0
  131. package/dist/tokens/index.d.ts +1 -0
  132. package/dist/tokens/index.js +10 -2
  133. package/dist/tokens/style.d.cts +36 -0
  134. package/dist/tokens/style.d.ts +36 -0
  135. package/dist/tools/index.cjs +15 -3
  136. package/dist/tools/index.d.cts +2 -0
  137. package/dist/tools/index.d.ts +2 -0
  138. package/dist/tools/index.js +14 -2
  139. package/dist/tools/style-tools.d.cts +19 -0
  140. package/dist/tools/style-tools.d.ts +19 -0
  141. package/dist/tools/style.d.cts +212 -0
  142. package/dist/tools/style.d.ts +212 -0
  143. package/dist/tools/view.d.cts +6 -0
  144. package/dist/tools/view.d.ts +6 -0
  145. package/dist/typography/index.cjs +8 -6
  146. package/dist/typography/index.js +5 -3
  147. package/dist/vector/index.cjs +953 -952
  148. package/dist/vector/index.js +7 -6
  149. package/dist/video-editor/index.cjs +8 -7
  150. package/dist/video-editor/index.js +6 -5
  151. package/package.json +1 -1
  152. package/skills/README.md +12 -0
  153. package/skills/pixerate-agent-tools/SKILL.md +34 -1
  154. package/skills/pixerate-chart/SKILL.md +41 -9
  155. package/skills/pixerate-image-editor/SKILL.md +2 -0
  156. package/skills/pixerate-paint-editor/SKILL.md +2 -0
  157. package/skills/pixerate-tokens/SKILL.md +5 -0
  158. package/dist/chunk-ERAGQL2N.cjs +0 -68
  159. package/dist/chunk-KMU6QJB7.js +0 -68
@@ -1,6 +1,7 @@
1
1
  export * from './types.cjs';
2
2
  export * from './spec.cjs';
3
3
  export * from './tree.cjs';
4
+ export * from './links.cjs';
4
5
  export * from './scale.cjs';
5
6
  export * from './numfmt.cjs';
6
7
  export * from './color.cjs';
@@ -28,3 +29,4 @@ export * from './office-files.cjs';
28
29
  export * from './file-tools.cjs';
29
30
  export * from './playback.cjs';
30
31
  export * from './editorDocument.cjs';
32
+ export * from './style.cjs';
@@ -1,6 +1,7 @@
1
1
  export * from './types.js';
2
2
  export * from './spec.js';
3
3
  export * from './tree.js';
4
+ export * from './links.js';
4
5
  export * from './scale.js';
5
6
  export * from './numfmt.js';
6
7
  export * from './color.js';
@@ -28,3 +29,4 @@ export * from './office-files.js';
28
29
  export * from './file-tools.js';
29
30
  export * from './playback.js';
30
31
  export * from './editorDocument.js';
32
+ export * from './style.js';
@@ -2,6 +2,8 @@ import {
2
2
  CATEGORY_REF,
3
3
  CHART_UPDATE_PROPERTIES,
4
4
  HEIGHT,
5
+ LINK_INDEX,
6
+ LINK_PROPS,
5
7
  REFERENCE_BAND_PATCH,
6
8
  REFERENCE_BAND_PROPS,
7
9
  REFERENCE_INDEX,
@@ -14,7 +16,7 @@ import {
14
16
  TRENDLINE_PROPS,
15
17
  VALUE,
16
18
  WIDTH
17
- } from "../chunk-5FNGLV2D.js";
19
+ } from "../chunk-FEU2XVQH.js";
18
20
  import {
19
21
  CHART_OOXML_CONTENT_TYPE,
20
22
  CHART_OOXML_NS,
@@ -22,7 +24,7 @@ import {
22
24
  chartFormatToCode,
23
25
  chartFromOoxml,
24
26
  chartToOoxml
25
- } from "../chunk-POR54B55.js";
27
+ } from "../chunk-CRFSQWKQ.js";
26
28
  import {
27
29
  CHART_COLOR_SCHEMES,
28
30
  CHART_LAYOUT_PRESETS,
@@ -44,7 +46,8 @@ import {
44
46
  monochromeChartPalette,
45
47
  sparklineToSvg,
46
48
  summarizeChart
47
- } from "../chunk-SZA42R4N.js";
49
+ } from "../chunk-FRBRLKNQ.js";
50
+ import "../chunk-KGRZMHZB.js";
48
51
  import {
49
52
  CHART_DATE_STEPS,
50
53
  MAX_CHART_DATA_LABELS,
@@ -84,7 +87,7 @@ import {
84
87
  suggestChartReferences,
85
88
  summarizeChartSeries,
86
89
  trendNumberText
87
- } from "../chunk-Z4P2RBMJ.js";
90
+ } from "../chunk-V5GSY3NC.js";
88
91
  import {
89
92
  CHART_AXIS_KINDS,
90
93
  CHART_AXIS_SCALES,
@@ -102,6 +105,7 @@ import {
102
105
  CHART_PALETTE_SHADES,
103
106
  CHART_RADAR_GRATICULES,
104
107
  CHART_REFERENCE_AXES,
108
+ CHART_SANKEY_LINK_COLORS,
105
109
  CHART_SERIES_TYPES,
106
110
  CHART_STACKINGS,
107
111
  CHART_TRENDLINE_TYPES,
@@ -110,8 +114,10 @@ import {
110
114
  CSS_VARIABLE_CHART_THEME,
111
115
  DEFAULT_CHART_PALETTE,
112
116
  DEFAULT_CHART_THEME,
117
+ MAX_CHART_LINKS,
113
118
  MAX_CHART_TREE_DEPTH,
114
119
  MAX_CHART_TREE_NODES,
120
+ addChartLink,
115
121
  addChartTreeRow,
116
122
  chartColorDistance,
117
123
  chartColorInputValue,
@@ -123,10 +129,13 @@ import {
123
129
  chartErrorBarsOfType,
124
130
  chartFamily,
125
131
  chartLikertColor,
132
+ chartLinksFromTable,
126
133
  chartLuminance,
127
134
  chartPointColor,
128
135
  chartRgbToHex,
129
136
  chartRgbToOklab,
137
+ chartSankeyNodeValues,
138
+ chartSankeyNodes,
130
139
  chartSeriesColor,
131
140
  chartSeriesType,
132
141
  chartSliceColor,
@@ -155,6 +164,7 @@ import {
155
164
  isXyChart,
156
165
  normalizeChartAxis,
157
166
  normalizeChartErrorBars,
167
+ normalizeChartLinks,
158
168
  normalizeChartReferenceBand,
159
169
  normalizeChartReferenceLine,
160
170
  normalizeChartSpec,
@@ -165,12 +175,14 @@ import {
165
175
  parseChartColor,
166
176
  parseChartValue,
167
177
  removeChartTreeRow,
178
+ setChartLinkField,
168
179
  setChartTreeRowName,
169
180
  setChartTreeRowValue,
170
181
  shadeChartColor,
171
182
  simulateChartVision,
172
183
  uniqueChartSeriesId
173
- } from "../chunk-3NEZJCBY.js";
184
+ } from "../chunk-2ZRN43IN.js";
185
+ import "../chunk-O6OGNDND.js";
174
186
  import "../chunk-II2WIF5Z.js";
175
187
  import {
176
188
  parseCsv
@@ -188,11 +200,12 @@ import {
188
200
  } from "../chunk-CIQIM2IP.js";
189
201
  import {
190
202
  defineEditorDocument
191
- } from "../chunk-NHLYK3AX.js";
203
+ } from "../chunk-XBQX76CT.js";
192
204
  import "../chunk-HF5QZS7Z.js";
193
205
  import "../chunk-RNSANXPT.js";
194
- import "../chunk-QYZGBVNC.js";
195
- import "../chunk-4VU4CP7R.js";
206
+ import "../chunk-7272D3K2.js";
207
+ import "../chunk-YBAPT7NL.js";
208
+ import "../chunk-MHLU6GRJ.js";
196
209
  import "../chunk-6ONMQ6WF.js";
197
210
 
198
211
  // src/chart/raster.ts
@@ -800,6 +813,80 @@ function createChartCommands(controller, options = {}) {
800
813
  return { groups: controller.getSpec().tree.map((n) => ({ name: n.name, total: chartTreeTotal(n) })) };
801
814
  }
802
815
  },
816
+ {
817
+ ...base,
818
+ id: `${prefix}setLinks`,
819
+ label: "Replace Flows\u2026",
820
+ keywords: ["chart", "sankey", "flow", "links", "funnel", "budget"],
821
+ description: "Replaces the data with flows between named nodes for a Sankey diagram; [] goes back to plain data.",
822
+ params: object(
823
+ {
824
+ links: { type: "array", items: { type: "object", properties: LINK_PROPS, required: ["source", "target", "value"], additionalProperties: false }, description: "All the flows; [] removes them." },
825
+ nodes: { type: "array", items: { type: "string" }, description: "Node names in stacking order." }
826
+ },
827
+ ["links"]
828
+ ),
829
+ run: (_ctx, params) => {
830
+ check(controller.setLinks(params.links, { nodes: params.nodes }));
831
+ return { links: controller.getSpec().links, nodes: controller.getSpec().sankeyNodes };
832
+ }
833
+ },
834
+ {
835
+ ...base,
836
+ id: `${prefix}importLinksCsv`,
837
+ label: "Import Flows from CSV\u2026",
838
+ keywords: ["chart", "sankey", "flow", "csv", "import"],
839
+ description: "Replaces the data with flows from CSV / TSV rows of source, target and value.",
840
+ params: object(
841
+ {
842
+ csv: { type: "string", description: "CSV or TSV text." },
843
+ header: { type: ["boolean", "string"], enum: [true, false, "auto"], description: "The first row holds column names (default auto)." }
844
+ },
845
+ ["csv"]
846
+ ),
847
+ run: (_ctx, params) => {
848
+ check(controller.importLinksTable(parseCsv(params.csv, { delimiter: params.csv.includes(" ") ? " " : "," }), { header: params.header }));
849
+ return { links: controller.getSpec().links };
850
+ }
851
+ },
852
+ {
853
+ ...base,
854
+ id: `${prefix}addLink`,
855
+ label: "Add Flow\u2026",
856
+ keywords: ["chart", "sankey", "flow", "link", "add"],
857
+ description: "Adds a flow between two nodes. Returns its index.",
858
+ params: object(LINK_PROPS, ["source", "target", "value"]),
859
+ run: (_ctx, params) => {
860
+ const result = controller.addLink(params);
861
+ check(result);
862
+ return { index: result.index };
863
+ }
864
+ },
865
+ {
866
+ ...base,
867
+ id: `${prefix}updateLink`,
868
+ label: "Change Flow\u2026",
869
+ keywords: ["chart", "sankey", "flow", "link", "value"],
870
+ description: "Changes a flow by index (color null for the default).",
871
+ params: object({ index: LINK_INDEX, ...LINK_PROPS, color: { type: ["string", "null"], description: "CSS colour, or null for the default." } }, ["index"]),
872
+ run: (_ctx, params) => {
873
+ const { index, ...patch } = params;
874
+ check(controller.updateLink(index, patch));
875
+ return { link: controller.getSpec().links[index] };
876
+ }
877
+ },
878
+ {
879
+ ...base,
880
+ id: `${prefix}removeLink`,
881
+ label: "Delete Flow",
882
+ keywords: ["chart", "sankey", "flow", "link", "remove"],
883
+ description: "Deletes a flow by index.",
884
+ params: object({ index: LINK_INDEX }, ["index"]),
885
+ run: (_ctx, params) => {
886
+ check(controller.removeLink(params.index));
887
+ return { links: controller.getSpec().links };
888
+ }
889
+ },
803
890
  {
804
891
  ...base,
805
892
  id: `${prefix}applyPreset`,
@@ -851,11 +938,11 @@ function createChartCommands(controller, options = {}) {
851
938
  id: `${prefix}importMermaid`,
852
939
  label: "Import Mermaid Chart\u2026",
853
940
  keywords: ["chart", "mermaid", "markdown", "xychart", "pie", "radar", "import"],
854
- description: "Replaces the chart with Mermaid xychart-beta, pie or radar-beta text (one undo step). Unreadable lines are listed with line numbers.",
941
+ description: "Replaces the chart with Mermaid xychart-beta, pie, radar-beta, sankey-beta or treemap-beta text (one undo step). Unreadable lines are listed with line numbers.",
855
942
  params: object({ mermaid: { type: "string", description: "Mermaid text." } }, ["mermaid"]),
856
943
  run: (_ctx, params) => {
857
944
  const read = chartFromMermaid(params.mermaid);
858
- if (!read.family) fail(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie or radar-beta.");
945
+ if (!read.family) fail(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie, radar-beta, sankey-beta or treemap-beta.");
859
946
  check(controller.update({ ...read.spec }, { label: "Import Mermaid chart" }));
860
947
  return { spec: controller.toJSON(), issues: read.issues };
861
948
  }
@@ -1366,6 +1453,11 @@ function planChartToolPlayback(tool, args) {
1366
1453
  case "add_chart_tree_node":
1367
1454
  case "update_chart_tree_node":
1368
1455
  case "remove_chart_tree_node":
1456
+ case "set_chart_links":
1457
+ case "import_chart_links_csv":
1458
+ case "add_chart_link":
1459
+ case "update_chart_link":
1460
+ case "remove_chart_link":
1369
1461
  case "import_chart_csv":
1370
1462
  case "import_chart_mermaid":
1371
1463
  case "import_chart_ooxml":
@@ -1456,6 +1548,7 @@ function createChartToolProvider(controller, options = {}) {
1456
1548
  const depth = chartTreeDepth(spec().tree);
1457
1549
  return [[...Array.from({ length: depth }, (_, k) => k === 0 ? "Group" : k === depth - 1 ? "Item" : `Level ${k + 1}`), "Value"], ...rows.map((r) => [...r.path, ...Array(depth - r.path.length).fill(""), r.value])];
1458
1550
  };
1551
+ const linksSummary = () => ({ links: spec().links, nodes: spec().sankeyNodes.map((name, i) => ({ name, value: chartSankeyNodeValues(spec().links, spec().sankeyNodes)[i] })) });
1459
1552
  const treeSummary = () => ({ tree: spec().tree, groups: spec().tree.map((n) => ({ name: n.name, total: chartTreeTotal(n) })), depth: chartTreeDepth(spec().tree) });
1460
1553
  const Parser = () => options.DOMParser ?? globalThis.DOMParser;
1461
1554
  const getChart = {
@@ -1580,7 +1673,7 @@ function createChartToolProvider(controller, options = {}) {
1580
1673
  const exportMermaid = {
1581
1674
  name: "export_chart_mermaid",
1582
1675
  title: "Export chart as Mermaid",
1583
- description: 'Returns the chart as Mermaid text (xychart-beta, pie or radar-beta) for Markdown or chat. With meta (default true) one "%% @pixerate {\u2026}" comment keeps what Mermaid cannot express, so import_chart_mermaid gets the chart back exactly.',
1676
+ description: 'Returns the chart as Mermaid text for Markdown or chat: xychart-beta, pie or radar-beta, sankey-beta for Sankey diagrams with flows, treemap-beta for treemaps and sunbursts (with their levels). With meta (default true) one "%% @pixerate {\u2026}" comment keeps what Mermaid cannot express, so import_chart_mermaid gets the chart back exactly.',
1584
1677
  inputSchema: { type: "object", properties: { meta: { type: "boolean", description: "Include the round-trip comment (default true)." } }, additionalProperties: false },
1585
1678
  annotations: { title: "Export chart as Mermaid", ...READ },
1586
1679
  handler: ({ meta = true }) => ({ mermaid: chartToMermaid(controller.toJSON(), { meta }) })
@@ -1767,13 +1860,13 @@ function createChartToolProvider(controller, options = {}) {
1767
1860
  const importMermaid = {
1768
1861
  name: "import_chart_mermaid",
1769
1862
  title: "Import a Mermaid chart",
1770
- description: 'Replaces the chart with Mermaid xychart-beta, pie or radar-beta text as one undo step (a "%% @pixerate" comment from export_chart_mermaid restores everything else). Lines that cannot be read are skipped and listed with their line numbers. Returns the spec.',
1863
+ description: 'Replaces the chart with Mermaid xychart-beta, pie, radar-beta, sankey-beta or treemap-beta text as one undo step (a "%% @pixerate" comment from export_chart_mermaid restores everything else). Lines that cannot be read are skipped and listed with their line numbers. Returns the spec.',
1771
1864
  inputSchema: { type: "object", properties: { mermaid: { type: "string", description: "Mermaid text, optionally inside a ```mermaid fence." } }, required: ["mermaid"], additionalProperties: false },
1772
1865
  annotations: { title: "Import a Mermaid chart", ...DESTRUCTIVE },
1773
1866
  handler: ({ mermaid }) => {
1774
1867
  const fenced = /```(?:mermaid)?\s*\n([\s\S]*?)```/.exec(mermaid);
1775
1868
  const read = chartFromMermaid(fenced ? fenced[1] : mermaid);
1776
- if (!read.family) fail2(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie or radar-beta.");
1869
+ if (!read.family) fail2(read.issues.map((i) => i.message).join(" ") || "Expected Mermaid starting with xychart-beta, pie, radar-beta, sankey-beta or treemap-beta.");
1777
1870
  resolve(controller.update({ ...read.spec }, { label: "Import Mermaid chart" }));
1778
1871
  return { spec: controller.toJSON(), issues: read.issues };
1779
1872
  }
@@ -1982,6 +2075,81 @@ function createChartToolProvider(controller, options = {}) {
1982
2075
  return { groups: treeSummary().groups };
1983
2076
  }
1984
2077
  };
2078
+ const setLinks = {
2079
+ name: "set_chart_links",
2080
+ title: "Replace the flows",
2081
+ description: `Replaces the chart's data with flows between named nodes for a Sankey diagram, as one undo step: each {"source", "target", "value"} with a value above 0. Flows only go forwards (no loops) and a source-target pair appears once. The nodes become the categories and how much passes through each the first series. nodes (optional) sets the stacking order. [] goes back to plain data. Returns the flows and each node's throughput.`,
2082
+ inputSchema: {
2083
+ type: "object",
2084
+ properties: {
2085
+ links: { type: "array", items: { type: "object", properties: LINK_PROPS, required: ["source", "target", "value"], additionalProperties: false }, description: "All the flows; [] removes them." },
2086
+ nodes: { type: "array", items: { type: "string" }, description: "Node names in stacking order (default: as the flows first name them)." }
2087
+ },
2088
+ required: ["links"],
2089
+ additionalProperties: false
2090
+ },
2091
+ annotations: { title: "Replace the flows", ...WRITE_IDEMPOTENT },
2092
+ handler: ({ links, nodes }) => {
2093
+ resolve(controller.setLinks(links, { nodes }));
2094
+ return linksSummary();
2095
+ }
2096
+ };
2097
+ const importLinksCsv = {
2098
+ name: "import_chart_links_csv",
2099
+ title: "Import flows from CSV",
2100
+ description: "Replaces the data with flows from CSV or TSV rows of source, target and value (as Mermaid sankey-beta and spreadsheets write them). One undo step. Returns the flows and each node's throughput.",
2101
+ inputSchema: {
2102
+ type: "object",
2103
+ properties: {
2104
+ csv: { type: "string", description: 'CSV or TSV text, e.g. "Website,Signup,120\\nSignup,Paid,30".' },
2105
+ header: { type: ["boolean", "string"], enum: [true, false, "auto"], description: "The first row holds column names (default auto: when its third cell is not a number)." }
2106
+ },
2107
+ required: ["csv"],
2108
+ additionalProperties: false
2109
+ },
2110
+ annotations: { title: "Import flows from CSV", ...WRITE },
2111
+ handler: ({ csv, header }) => {
2112
+ resolve(controller.importLinksTable(parseCsv(csv, { delimiter: csv.includes(" ") ? " " : "," }), { header }));
2113
+ return linksSummary();
2114
+ }
2115
+ };
2116
+ const addLink = {
2117
+ name: "add_chart_link",
2118
+ title: "Add a flow",
2119
+ description: "Adds a flow from one node to another (new names add nodes). Refused when the pair exists already or it would close a loop. Returns its index and the throughput of its two nodes.",
2120
+ inputSchema: { type: "object", properties: LINK_PROPS, required: ["source", "target", "value"], additionalProperties: false },
2121
+ annotations: { title: "Add a flow", ...WRITE },
2122
+ handler: (args) => {
2123
+ const result = resolve(controller.addLink(args));
2124
+ const s = spec();
2125
+ const through = (n) => s.series[0]?.values[s.sankeyNodes.indexOf(n)] ?? 0;
2126
+ const link = s.links[result.index];
2127
+ return { index: result.index, link, nodes: [link.source, link.target].map((name) => ({ name, value: through(name) })) };
2128
+ }
2129
+ };
2130
+ const updateLink = {
2131
+ name: "update_chart_link",
2132
+ title: "Change a flow",
2133
+ description: "Changes a flow by index: its source, target, value or colour (null goes back to the default). Checked like a new flow. Returns the flow as stored.",
2134
+ inputSchema: { type: "object", properties: { index: LINK_INDEX, ...LINK_PROPS, color: { type: ["string", "null"], description: "CSS colour, or null for the default." } }, required: ["index"], additionalProperties: false },
2135
+ annotations: { title: "Change a flow", ...WRITE_IDEMPOTENT },
2136
+ handler: ({ index, ...patch }) => {
2137
+ if (!Object.keys(patch).length) fail2(`Nothing to change: pass source, target, value or color with the index, e.g. {"index": ${index}, "value": 40}.`);
2138
+ resolve(controller.updateLink(index, patch));
2139
+ return { index, link: spec().links[index] };
2140
+ }
2141
+ };
2142
+ const removeLink = {
2143
+ name: "remove_chart_link",
2144
+ title: "Delete a flow",
2145
+ description: "Deletes a flow by index; the ones after it move up one, and nodes no flow uses any more go. Returns the flows left.",
2146
+ inputSchema: { type: "object", properties: { index: LINK_INDEX }, required: ["index"], additionalProperties: false },
2147
+ annotations: { title: "Delete a flow", ...DESTRUCTIVE },
2148
+ handler: ({ index }) => {
2149
+ resolve(controller.removeLink(index));
2150
+ return { links: spec().links };
2151
+ }
2152
+ };
1985
2153
  const applyPreset = {
1986
2154
  name: "apply_chart_preset",
1987
2155
  title: "Apply a chart style",
@@ -2174,6 +2342,11 @@ function createChartToolProvider(controller, options = {}) {
2174
2342
  addTreeNode,
2175
2343
  updateTreeNode,
2176
2344
  removeTreeNode,
2345
+ setLinks,
2346
+ importLinksCsv,
2347
+ addLink,
2348
+ updateLink,
2349
+ removeLink,
2177
2350
  applyPreset,
2178
2351
  transpose,
2179
2352
  select,
@@ -2186,7 +2359,7 @@ function createChartToolProvider(controller, options = {}) {
2186
2359
  id: options.id ?? "chart",
2187
2360
  namespace: options.namespace,
2188
2361
  title: "Chart editor",
2189
- description: "One chart: its spec, data and values, series and categories, trendlines, reference lines and bands, callouts, highlight, grouped data and presets, CSV, Mermaid and OOXML import, rendering and colour checks.",
2362
+ description: "One chart: its spec, data and values, series and categories, trendlines, reference lines and bands, callouts, highlight, grouped data, flows and presets, CSV, Mermaid and OOXML import, rendering and colour checks.",
2190
2363
  skill: "pixerate-chart",
2191
2364
  tools: () => {
2192
2365
  if (readOnlyReason()) return reads;
@@ -2669,6 +2842,194 @@ function createChartEditorDocument(controller) {
2669
2842
  }
2670
2843
  });
2671
2844
  }
2845
+
2846
+ // src/chart/style.ts
2847
+ var CHART_TYPES3 = ["bar", "line", "area", "scatter", "bubble", "pie", "donut", "radar", "waterfall", "histogram", "box", "funnel", "treemap"];
2848
+ var COLOR = { type: "string", minLength: 1, description: 'A CSS colour (hex or rgb()), or a { "$token": ... } reference.' };
2849
+ function chartColors(spec) {
2850
+ const out = [];
2851
+ const visible = spec.series.map((s, i) => ({ s, i })).filter(({ s }) => !s.hidden);
2852
+ if (chartColorsByCategory(spec.type)) {
2853
+ const first = visible[0];
2854
+ spec.categories.forEach((name, index) => {
2855
+ const color = first?.s.pointColors?.[index] || chartSliceColor(spec, index);
2856
+ out.push({ color, label: `Slice "${name}"`, target: first ? { kind: "point", seriesId: first.s.id, index } : { kind: "category", index } });
2857
+ });
2858
+ return out;
2859
+ }
2860
+ for (const { s, i } of visible) {
2861
+ out.push({ color: chartSeriesColor(spec, i), label: `Series "${s.name}"`, target: { kind: "series", seriesId: s.id } });
2862
+ s.pointColors?.forEach((c, index) => {
2863
+ if (c) out.push({ color: c, label: `Point ${index + 1} of "${s.name}"`, target: { kind: "point", seriesId: s.id, index } });
2864
+ });
2865
+ }
2866
+ return out;
2867
+ }
2868
+ var paletteOf = (profile) => {
2869
+ const palette = profile.palette;
2870
+ if (!palette?.length) throw new Error("the profile has no palette.");
2871
+ return palette;
2872
+ };
2873
+ var paletteOnly = {
2874
+ id: "palette-only",
2875
+ description: "Every series, slice and point colour comes from the house palette (or a lighter or darker shade the chart cycles to once the palette runs out).",
2876
+ optionsSchema: {
2877
+ type: "object",
2878
+ properties: { tolerance: { type: "number", minimum: 0, maximum: 1, description: "Largest OKLab distance still counted as the same colour (default 0.02)." } },
2879
+ additionalProperties: false
2880
+ },
2881
+ run(spec, profile, { tolerance = 0.02 }) {
2882
+ const palette = paletteOf(profile);
2883
+ const allowed = palette.flatMap((c) => CHART_PALETTE_SHADES.map((t) => shadeChartColor(c, t))).map((c) => ({ c, rgb: parseChartColor(c) }));
2884
+ return chartColors(spec).flatMap(({ color, label, target }) => {
2885
+ const rgb = parseChartColor(color);
2886
+ if (!rgb) return [];
2887
+ let best = { c: palette[0], d: Infinity };
2888
+ for (const a of allowed) {
2889
+ if (!a.rgb) continue;
2890
+ const d = chartColorDistance(rgb, a.rgb);
2891
+ if (d < best.d) best = { c: a.c, d };
2892
+ }
2893
+ if (best.d <= tolerance) return [];
2894
+ const nearest = palette.map((c) => ({ c, d: parseChartColor(c) ? chartColorDistance(rgb, parseChartColor(c)) : Infinity })).sort((a, b) => a.d - b.d)[0].c;
2895
+ return [{ severity: "error", message: `${label} uses ${color}, which is not in the house palette; use ${nearest} or another palette colour (${palette.join(", ")}).`, target }];
2896
+ });
2897
+ }
2898
+ };
2899
+ var distinguishable = {
2900
+ id: "distinguishable",
2901
+ description: "Series (or slice) colours can be told apart with normal vision and with protanopia, deuteranopia and tritanopia.",
2902
+ optionsSchema: {
2903
+ type: "object",
2904
+ properties: { minDistance: { type: "number", minimum: 0, maximum: 1, description: "Smallest OKLab distance between two colours after simulation (default 0.08)." } },
2905
+ additionalProperties: false
2906
+ },
2907
+ run(spec, _profile, { minDistance = 0.08 }) {
2908
+ const colors = chartColors(spec).filter((c) => c.target.kind !== "point" || chartColorsByCategory(spec.type));
2909
+ const result = checkChartColors(colors.map((c) => c.color), { minDistance, minContrast: 0 });
2910
+ const findings = [];
2911
+ for (const [vision, pair] of Object.entries(result.closest)) {
2912
+ if (!pair || pair.distance >= minDistance) continue;
2913
+ const who = vision === "normal" ? "" : ` with ${vision}`;
2914
+ findings.push({
2915
+ severity: "warning",
2916
+ message: `${colors[pair.a].label} (${pair.colors[0]}) and ${colors[pair.b].label} (${pair.colors[1]}) are hard to tell apart${who} (distance ${pair.distance}, want ${minDistance}); give the second another palette colour.`,
2917
+ target: colors[pair.b].target
2918
+ });
2919
+ }
2920
+ return findings;
2921
+ }
2922
+ };
2923
+ var minContrast = {
2924
+ id: "min-contrast",
2925
+ description: "Marks stand out from the background: each series or slice colour against the profile theme's background (or surface, default white).",
2926
+ optionsSchema: {
2927
+ type: "object",
2928
+ properties: { ratio: { type: "number", minimum: 1, maximum: 21, description: "Smallest contrast ratio (default 3, the WCAG ratio for graphics)." } },
2929
+ additionalProperties: false
2930
+ },
2931
+ run(spec, profile, { ratio = 3 }) {
2932
+ const theme = profile.theme ?? {};
2933
+ const background = theme.background && theme.background !== "transparent" ? theme.background : theme.surface ?? "#ffffff";
2934
+ return chartColors(spec).flatMap(({ color, label, target }) => {
2935
+ const r = chartContrastRatio(color, background);
2936
+ if (r === null || r >= ratio) return [];
2937
+ return [{ severity: "warning", message: `${label} (${color}) has contrast ${Math.round(r * 100) / 100}:1 against the background ${background}; want at least ${ratio}:1, so use a darker or lighter palette colour.`, target }];
2938
+ });
2939
+ }
2940
+ };
2941
+ var allowedType = {
2942
+ id: "allowed-type",
2943
+ description: "The chart is one of the chart types the house style allows.",
2944
+ optionsSchema: {
2945
+ type: "object",
2946
+ properties: { types: { type: "array", items: { type: "string", enum: [...CHART_TYPES3] }, minItems: 1, description: "Allowed chart types." } },
2947
+ required: ["types"],
2948
+ additionalProperties: false
2949
+ },
2950
+ run(spec, _profile, { types }) {
2951
+ const allowed = types;
2952
+ if (allowed.includes(spec.type)) return [];
2953
+ return [{ severity: "error", message: `This is a ${spec.type} chart; the house style allows ${allowed.join(", ")}. Change the type with update_chart.`, target: { kind: "chart" } }];
2954
+ }
2955
+ };
2956
+ var chartStyleDomain = {
2957
+ id: "chart",
2958
+ title: "Charts",
2959
+ description: "The house palette and theme for charts, which colour schemes and layouts are allowed, defaults for new charts, and the checks to run.",
2960
+ profileSchema: {
2961
+ type: "object",
2962
+ properties: {
2963
+ palette: { type: "array", items: COLOR, minItems: 1, description: "Series colours in order." },
2964
+ colorSchemes: { type: "array", items: { type: "string", enum: CHART_COLOR_SCHEMES.map((s) => s.id) }, description: "Colour scheme ids allowed besides the palette (empty: none)." },
2965
+ layouts: { type: "array", items: { type: "string", enum: CHART_LAYOUT_PRESETS.map((p) => p.id) }, description: "Layout preset ids allowed." },
2966
+ theme: {
2967
+ type: "object",
2968
+ properties: {
2969
+ background: COLOR,
2970
+ surface: COLOR,
2971
+ text: COLOR,
2972
+ mutedText: COLOR,
2973
+ grid: COLOR,
2974
+ axis: COLOR,
2975
+ positive: COLOR,
2976
+ negative: COLOR,
2977
+ fontFamily: { type: "string", minLength: 1, description: "CSS font family." },
2978
+ fontSize: { type: "number", minimum: 6, maximum: 48, description: "Body text size in px." },
2979
+ titleSize: { type: "number", minimum: 6, maximum: 72, description: "Title size in px." }
2980
+ },
2981
+ additionalProperties: false,
2982
+ description: "Colours and type to draw charts with."
2983
+ },
2984
+ defaults: {
2985
+ type: "object",
2986
+ properties: {
2987
+ dataLabels: { type: "boolean", description: "Value labels on." },
2988
+ points: { type: "boolean", description: "Dots on lines." },
2989
+ curve: { type: "string", enum: ["linear", "smooth", "step"], description: "Line interpolation." },
2990
+ stacking: { type: "string", enum: ["none", "stacked", "percent"], description: "Stacking." },
2991
+ orientation: { type: "string", enum: ["vertical", "horizontal"], description: "Bar direction." },
2992
+ labelPosition: { type: "string", enum: ["auto", "inside", "outside", "center"], description: "Bar label position." }
2993
+ },
2994
+ additionalProperties: false,
2995
+ description: "Spec values new charts start from."
2996
+ }
2997
+ },
2998
+ additionalProperties: false
2999
+ },
3000
+ checks: [paletteOnly, distinguishable, minContrast, allowedType]
3001
+ };
3002
+ function chartStylePatch(profile) {
3003
+ const p = profile;
3004
+ return { ...p.defaults ?? {}, ...p.palette?.length ? { palette: [...p.palette] } : {} };
3005
+ }
3006
+ function createChartStyleToolProvider(controller, styles, options = {}) {
3007
+ if (!styles.domains.some((d) => d.id === "chart")) throw new Error('The style resolver has no "chart" domain; add chartStyleDomain to its domains.');
3008
+ const check2 = {
3009
+ name: "check_chart_style",
3010
+ title: "Check chart house style",
3011
+ description: 'Checks the chart against the house style (see get_style with domain "chart"): runs the checks its profile turns on (palette-only, distinguishable, min-contrast, allowed-type). Returns findings with a severity, a sentence saying how to fix it, a target selection (series id or point) for update_chart_series or update_chart, and the layer that asked for it; plus the checks that ran and the ones skipped with the reason. Check after a batch of edits and again after fixing.',
3012
+ inputSchema: { type: "object", properties: {}, additionalProperties: false },
3013
+ annotations: { title: "Check chart house style", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
3014
+ handler: async () => {
3015
+ const { style, ...report } = await styles.check("chart", controller.getSpec());
3016
+ return {
3017
+ ...report,
3018
+ ok: report.findings.length === 0,
3019
+ ...style.skills.length ? {} : { note: "No house style applies to charts." },
3020
+ ...style.issues.length ? { issues: style.issues } : {}
3021
+ };
3022
+ }
3023
+ };
3024
+ return {
3025
+ id: options.id ?? "chart-style",
3026
+ namespace: options.namespace ?? "chart",
3027
+ title: "Chart house style",
3028
+ description: "Check a chart against the house style.",
3029
+ skill: "pixerate-chart",
3030
+ tools: [check2]
3031
+ };
3032
+ }
2672
3033
  export {
2673
3034
  CHART_AXIS_KINDS,
2674
3035
  CHART_AXIS_SCALES,
@@ -2695,6 +3056,7 @@ export {
2695
3056
  CHART_RADAR_GRATICULES,
2696
3057
  CHART_RASTER_MAX_SIZE,
2697
3058
  CHART_REFERENCE_AXES,
3059
+ CHART_SANKEY_LINK_COLORS,
2698
3060
  CHART_SERIES_TYPES,
2699
3061
  CHART_STACKINGS,
2700
3062
  CHART_TRENDLINE_TYPES,
@@ -2709,11 +3071,13 @@ export {
2709
3071
  DEFAULT_CHART_THEME,
2710
3072
  MAX_CHART_DATA_LABELS,
2711
3073
  MAX_CHART_LINE_POINTS,
3074
+ MAX_CHART_LINKS,
2712
3075
  MAX_CHART_MARKERS,
2713
3076
  MAX_CHART_TREE_DEPTH,
2714
3077
  MAX_CHART_TREE_NODES,
2715
3078
  OfficeChartsError,
2716
3079
  RENDER_CHART_INSTRUCTIONS,
3080
+ addChartLink,
2717
3081
  addChartTreeRow,
2718
3082
  analyzeChartTable,
2719
3083
  blendChartScenes,
@@ -2739,6 +3103,7 @@ export {
2739
3103
  chartHistogram,
2740
3104
  chartHitTest,
2741
3105
  chartLikertColor,
3106
+ chartLinksFromTable,
2742
3107
  chartLuminance,
2743
3108
  chartMermaidFamily,
2744
3109
  chartMovingAverage,
@@ -2750,6 +3115,8 @@ export {
2750
3115
  chartRasterSize,
2751
3116
  chartRgbToHex,
2752
3117
  chartRgbToOklab,
3118
+ chartSankeyNodeValues,
3119
+ chartSankeyNodes,
2753
3120
  chartScaleFromPixel,
2754
3121
  chartScaleToPixel,
2755
3122
  chartSceneToDomSpec,
@@ -2760,6 +3127,8 @@ export {
2760
3127
  chartSliceColor,
2761
3128
  chartSpecColorsByCategory,
2762
3129
  chartSquarify,
3130
+ chartStyleDomain,
3131
+ chartStylePatch,
2763
3132
  chartSupportsTrendlines,
2764
3133
  chartTextBaseline,
2765
3134
  chartTextOn,
@@ -2789,6 +3158,7 @@ export {
2789
3158
  createChartEditorDocument,
2790
3159
  createChartRasterizer,
2791
3160
  createChartSpec,
3161
+ createChartStyleToolProvider,
2792
3162
  createChartToolProvider,
2793
3163
  createInstantChartClock,
2794
3164
  createOfficeChartToolProvider,
@@ -2827,6 +3197,7 @@ export {
2827
3197
  niceStep,
2828
3198
  normalizeChartAxis,
2829
3199
  normalizeChartErrorBars,
3200
+ normalizeChartLinks,
2830
3201
  normalizeChartReferenceBand,
2831
3202
  normalizeChartReferenceLine,
2832
3203
  normalizeChartSpec,
@@ -2847,6 +3218,7 @@ export {
2847
3218
  removeChartTreeRow,
2848
3219
  resolveChartSvgPaints,
2849
3220
  sameChartSelection,
3221
+ setChartLinkField,
2850
3222
  setChartTreeRowName,
2851
3223
  setChartTreeRowValue,
2852
3224
  shadeChartColor,
@@ -38,3 +38,10 @@ export declare function layoutTreemapTree(ctx: LayoutCtx, area: ChartRect, serie
38
38
  * wide enough for them; the total and `sunburstLabel` sit in the centre.
39
39
  */
40
40
  export declare function layoutSunburst(ctx: LayoutCtx, area: ChartRect, series: ChartSeries | undefined): FamilyResult;
41
+ /**
42
+ * Sankey: `spec.links` as flows between columns of nodes. A node's column is the longest chain
43
+ * of flows into it, and nodes nothing flows out of line up in the last column. Node heights and
44
+ * flow widths share one scale (the tightest column fills the height); flows leave and arrive
45
+ * in the order of the nodes at their other end, so they cross as little as the order allows.
46
+ */
47
+ export declare function layoutSankey(ctx: LayoutCtx, area: ChartRect, series: ChartSeries | undefined): FamilyResult;
@@ -38,3 +38,10 @@ export declare function layoutTreemapTree(ctx: LayoutCtx, area: ChartRect, serie
38
38
  * wide enough for them; the total and `sunburstLabel` sit in the centre.
39
39
  */
40
40
  export declare function layoutSunburst(ctx: LayoutCtx, area: ChartRect, series: ChartSeries | undefined): FamilyResult;
41
+ /**
42
+ * Sankey: `spec.links` as flows between columns of nodes. A node's column is the longest chain
43
+ * of flows into it, and nodes nothing flows out of line up in the last column. Node heights and
44
+ * flow widths share one scale (the tightest column fills the height); flows leave and arrive
45
+ * in the order of the nodes at their other end, so they cross as little as the order allows.
46
+ */
47
+ export declare function layoutSankey(ctx: LayoutCtx, area: ChartRect, series: ChartSeries | undefined): FamilyResult;