@weasel-js/labkit 1.6.1 → 1.7.1

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 (256) hide show
  1. package/README.md +3 -3
  2. package/dist/_dts/{CanvasStackContext-Wo6OwIVM.d.ts → CanvasStackContext-Cjy6I-Iv.d.ts} +4 -1
  3. package/dist/_dts/{Stage-DWBBi8IU.d.ts → Stage-D6t7o0pF.d.ts} +59 -18
  4. package/dist/_dts/{index-CKyX0ME_.d.ts → index-BTmaRy6a.d.ts} +10 -6
  5. package/dist/_dts/{types-B7yBTTF9.d.ts → index-DCMA4Fy1.d.ts} +59 -113
  6. package/dist/_dts/{types-DTuViBvc.d.ts → types-BUBSIZuV.d.ts} +18 -8
  7. package/dist/_dts/{useTrialState-CMaV6UD4.d.ts → useTrialState-Bh8bzFgE.d.ts} +1 -1
  8. package/dist/canvas/index.d.ts +8 -6
  9. package/dist/canvas/index.js +6 -6
  10. package/dist/chrome/index.d.ts +6 -4
  11. package/dist/chrome/index.js +11 -10
  12. package/dist/chunk-2ES4W47N.js +8 -0
  13. package/dist/chunk-2ES4W47N.js.map +1 -0
  14. package/dist/{chunk-WPLAANH4.js → chunk-2N7UBSS2.js} +12 -12
  15. package/dist/chunk-2N7UBSS2.js.map +1 -0
  16. package/dist/chunk-4KSC7NXL.js +15491 -0
  17. package/dist/chunk-4KSC7NXL.js.map +1 -0
  18. package/dist/{chunk-SLAQPUI4.js → chunk-CEGFXTBD.js} +10 -63
  19. package/dist/chunk-CEGFXTBD.js.map +1 -0
  20. package/dist/chunk-CZZPXUOU.js +3 -0
  21. package/dist/{chunk-SBXNQW4G.js.map → chunk-CZZPXUOU.js.map} +1 -1
  22. package/dist/{chunk-QGMOA2YE.js → chunk-E23Q6A3Y.js} +296 -104
  23. package/dist/chunk-E23Q6A3Y.js.map +1 -0
  24. package/dist/{chunk-GHGO52SO.js → chunk-E6NARGU7.js} +5 -5
  25. package/dist/{chunk-GHGO52SO.js.map → chunk-E6NARGU7.js.map} +1 -1
  26. package/dist/{chunk-IJJUK4FU.js → chunk-EESJUSYR.js} +5 -6
  27. package/dist/chunk-EESJUSYR.js.map +1 -0
  28. package/dist/{chunk-HXXTULDN.js → chunk-EFXRM6XQ.js} +8 -11
  29. package/dist/chunk-EFXRM6XQ.js.map +1 -0
  30. package/dist/chunk-F4ACIK7Z.js +210 -0
  31. package/dist/chunk-F4ACIK7Z.js.map +1 -0
  32. package/dist/{chunk-6FLXL3I7.js → chunk-FB4MIZOO.js} +77 -45
  33. package/dist/chunk-FB4MIZOO.js.map +1 -0
  34. package/dist/{chunk-AWQG7FCC.js → chunk-FG3EXZDV.js} +3 -3
  35. package/dist/{chunk-AWQG7FCC.js.map → chunk-FG3EXZDV.js.map} +1 -1
  36. package/dist/{chunk-4TT3PNPR.js → chunk-GAHELLJT.js} +95 -95
  37. package/dist/chunk-GAHELLJT.js.map +1 -0
  38. package/dist/{chunk-HKV7LRHY.js → chunk-IBVRMHW5.js} +5 -5
  39. package/dist/{chunk-HKV7LRHY.js.map → chunk-IBVRMHW5.js.map} +1 -1
  40. package/dist/{chunk-ASOK76ZH.js → chunk-JFOJESJF.js} +72 -29
  41. package/dist/chunk-JFOJESJF.js.map +1 -0
  42. package/dist/{chunk-RWNDDKOH.js → chunk-PMLZP7RT.js} +18 -15
  43. package/dist/chunk-PMLZP7RT.js.map +1 -0
  44. package/dist/{chunk-TJ77A4A3.js → chunk-READTDQX.js} +5 -9
  45. package/dist/chunk-READTDQX.js.map +1 -0
  46. package/dist/{chunk-JVBYV6TL.js → chunk-ROGJWDQA.js} +3 -3
  47. package/dist/{chunk-JVBYV6TL.js.map → chunk-ROGJWDQA.js.map} +1 -1
  48. package/dist/{chunk-CGHF6RZV.js → chunk-T6DLGEJB.js} +18 -18
  49. package/dist/chunk-T6DLGEJB.js.map +1 -0
  50. package/dist/{chunk-24W5VEJW.js → chunk-ULYYNWGP.js} +2 -2
  51. package/dist/{chunk-24W5VEJW.js.map → chunk-ULYYNWGP.js.map} +1 -1
  52. package/dist/{chunk-DWMSB4CA.js → chunk-VYVGVBGY.js} +95 -32
  53. package/dist/chunk-VYVGVBGY.js.map +1 -0
  54. package/dist/{chunk-IRTGUQ5O.js → chunk-WLMDTI2Q.js} +16 -6
  55. package/dist/chunk-WLMDTI2Q.js.map +1 -0
  56. package/dist/{chunk-NEXR37YJ.js → chunk-XE5HJOPL.js} +6 -8
  57. package/dist/chunk-XE5HJOPL.js.map +1 -0
  58. package/dist/chunk-XVUKDSYV.js +38 -0
  59. package/dist/chunk-XVUKDSYV.js.map +1 -0
  60. package/dist/{chunk-O6FFFOHS.js → chunk-YCFKW5RX.js} +16 -8
  61. package/dist/chunk-YCFKW5RX.js.map +1 -0
  62. package/dist/{chunk-CQLQPQ4P.js → chunk-ZQIHJXP4.js} +2 -2
  63. package/dist/chunk-ZQIHJXP4.js.map +1 -0
  64. package/dist/config/index.d.ts +28 -13
  65. package/dist/config/index.js +4 -4
  66. package/dist/controls/index.d.ts +4 -7
  67. package/dist/controls/index.js +6 -5
  68. package/dist/dragdrop/index.d.ts +23 -3
  69. package/dist/dragdrop/index.js +4 -3
  70. package/dist/fonts/oswald-tabular-digits.woff2 +0 -0
  71. package/dist/index.d.ts +72 -487
  72. package/dist/index.js +603 -441
  73. package/dist/index.js.map +1 -1
  74. package/dist/job/index.d.ts +8 -0
  75. package/dist/job/index.js +1 -1
  76. package/dist/layers/index.d.ts +6 -5
  77. package/dist/layers/index.js +3 -2
  78. package/dist/loupe/index.d.ts +100 -30
  79. package/dist/loupe/index.js +585 -6
  80. package/dist/loupe/index.js.map +1 -1
  81. package/dist/overview/index.d.ts +4 -2
  82. package/dist/overview/index.js +20 -18
  83. package/dist/overview/index.js.map +1 -1
  84. package/dist/passthrough/weasel-canvas.d.ts +2 -0
  85. package/dist/passthrough/weasel-ui.d.ts +2 -2701
  86. package/dist/passthrough/weasel-ui.js +4 -3
  87. package/dist/primitives/index.d.ts +37 -2
  88. package/dist/primitives/index.js +9 -8
  89. package/dist/state/index.d.ts +7 -5
  90. package/dist/state/index.js +6 -6
  91. package/dist/styles.css +150 -126
  92. package/dist/surface/index.d.ts +10 -2
  93. package/dist/surface/index.js +1 -1
  94. package/dist/undo/index.d.ts +5 -3
  95. package/package.json +14 -13
  96. package/src/annotations/AnnotationOverlay.abandon.test.tsx +143 -0
  97. package/src/annotations/AnnotationOverlay.tsx +52 -33
  98. package/src/annotations/Annotations.less +0 -10
  99. package/src/annotations/Annotations.overlay.test.tsx +31 -0
  100. package/src/annotations/MarkList.tsx +4 -8
  101. package/src/annotations/capture.browser.test.ts +41 -0
  102. package/src/annotations/capture.ts +14 -7
  103. package/src/annotations/drawOne.ts +2 -2
  104. package/src/annotations/frac.test.ts +44 -1
  105. package/src/annotations/frac.ts +46 -18
  106. package/src/annotations/index.ts +1 -0
  107. package/src/annotations/paint.test.ts +76 -46
  108. package/src/annotations/paint.ts +65 -43
  109. package/src/annotations/store.test.ts +212 -2
  110. package/src/annotations/store.ts +130 -27
  111. package/src/annotations/svgNodes.test.ts +28 -19
  112. package/src/annotations/svgNodes.ts +6 -6
  113. package/src/annotations/types.ts +29 -10
  114. package/src/canvas/AGENTS.md +1 -0
  115. package/src/canvas/CameraInput.test.tsx +30 -0
  116. package/src/canvas/CameraInput.tsx +60 -48
  117. package/src/canvas/CanvasStack.tsx +11 -6
  118. package/src/canvas/CanvasStackContext.ts +4 -1
  119. package/src/canvas/LinkedCursor.less +1 -1
  120. package/src/canvas/Stage.test.tsx +33 -4
  121. package/src/canvas/Stage.tsx +9 -4
  122. package/src/canvas/cameraRegistry.test.ts +55 -0
  123. package/src/canvas/cameraRegistry.ts +87 -0
  124. package/src/canvas/cameraZoom.test.ts +46 -0
  125. package/src/canvas/cameraZoom.ts +24 -0
  126. package/src/canvas/index.ts +14 -2
  127. package/src/canvas/sharedScope.test.tsx +94 -0
  128. package/src/canvas/worldSpec.ts +3 -1
  129. package/src/chrome/ChromeRegions.stories.tsx +1 -0
  130. package/src/chrome/builtins.test.ts +7 -6
  131. package/src/chrome/builtins.tsx +5 -1
  132. package/src/chrome/index.ts +1 -1
  133. package/src/chrome/merge.test.ts +5 -0
  134. package/src/chrome/merge.ts +4 -2
  135. package/src/chrome/regions/PaletteRegion.less +0 -7
  136. package/src/chrome/regions/PaletteRegion.test.tsx +2 -3
  137. package/src/chrome/regions/PaletteRegion.tsx +3 -4
  138. package/src/chrome/regions/SidebarRegion.less +12 -2
  139. package/src/chrome/regions/ViewportRegion.browser.test.less +6 -0
  140. package/src/chrome/regions/ViewportRegion.browser.test.tsx +38 -0
  141. package/src/chrome/regions/ViewportRegion.less +6 -0
  142. package/src/chrome/regions/ViewportRegion.tsx +10 -4
  143. package/src/chrome/types.ts +4 -2
  144. package/src/config/auto.ts +1 -0
  145. package/src/config/builder.test.ts +2 -1
  146. package/src/config/builder.ts +18 -5
  147. package/src/config/fromConfigField.test.ts +14 -0
  148. package/src/config/fromConfigField.ts +18 -4
  149. package/src/config/path.ts +2 -5
  150. package/src/config/resolve.ts +4 -0
  151. package/src/config/types.ts +14 -9
  152. package/src/controls/ControlPanel.less +1 -1
  153. package/src/controls/ControlPanel.stories.tsx +3 -2
  154. package/src/controls/ControlPanel.test.tsx +98 -11
  155. package/src/controls/ControlPanel.tsx +61 -2
  156. package/src/dragdrop/DragDropRuntime.tsx +22 -13
  157. package/src/dragdrop/DragGhost.tsx +3 -0
  158. package/src/dragdrop/Palette.tsx +2 -0
  159. package/src/index.test.ts +5 -0
  160. package/src/index.ts +16 -2
  161. package/src/instrument/types.ts +0 -6
  162. package/src/job/useJob.ts +14 -9
  163. package/src/lab/Lab.tsx +88 -73
  164. package/src/lab/{LabFit.stories.less → LabFit.browser.test.less} +1 -1
  165. package/src/lab/{LabFit.stories.tsx → LabFit.browser.test.tsx} +41 -63
  166. package/src/lab/LabFullChrome.stories.tsx +1 -0
  167. package/src/lab/LabHeader.test.tsx +24 -14
  168. package/src/lab/LabHeader.tsx +11 -12
  169. package/src/lab/LabShell.less +9 -17
  170. package/src/lab/LabSwitcher.browser.test.tsx +27 -0
  171. package/src/lab/LabSwitcher.less +8 -6
  172. package/src/lab/LabZoom.test.tsx +223 -0
  173. package/src/lab/LabZoom.tsx +170 -0
  174. package/src/lab/Workspace.tsx +48 -52
  175. package/src/lab/index.ts +1 -0
  176. package/src/loupe/AGENTS.md +28 -15
  177. package/src/loupe/CanvasLoupe.tsx +2 -3
  178. package/src/loupe/DomLoupe.tsx +1 -7
  179. package/src/loupe/Loupe.less +16 -0
  180. package/src/loupe/LoupeGestures.tsx +1 -1
  181. package/src/loupe/TrialLoupe.tsx +120 -57
  182. package/src/loupe/index.ts +1 -6
  183. package/src/loupe/types.test.ts +3 -3
  184. package/src/loupe/types.ts +24 -27
  185. package/src/loupe/useLoupe.test.tsx +29 -4
  186. package/src/loupe/useLoupe.ts +20 -17
  187. package/src/overview/OverviewMarks.tsx +12 -4
  188. package/src/overview/TrialOverview.tsx +10 -8
  189. package/src/passthrough/weasel-ui.test.ts +2 -0
  190. package/src/passthrough/weasel-ui.ts +17 -5
  191. package/src/primitives/FloatingPanel.test.tsx +11 -0
  192. package/src/primitives/FloatingPanel.tsx +8 -7
  193. package/src/primitives/JobProgress.less +2 -1
  194. package/src/primitives/Legend.stories.tsx +1 -0
  195. package/src/primitives/Readout.browser.test.tsx +137 -0
  196. package/src/primitives/Readout.less +12 -0
  197. package/src/primitives/Readout.stories.tsx +58 -0
  198. package/src/primitives/Readout.test.tsx +93 -0
  199. package/src/primitives/Readout.tsx +56 -0
  200. package/src/primitives/Split.tsx +69 -41
  201. package/src/primitives/Toolbar.tsx +3 -3
  202. package/src/primitives/ZoomControl.less +1 -2
  203. package/src/primitives/index.ts +2 -0
  204. package/src/specimen/Specimen.stories.tsx +1 -0
  205. package/src/specimen/Specimen.tsx +2 -3
  206. package/src/state/Persistence.browser.test.tsx +47 -0
  207. package/src/state/store.test.ts +5 -1
  208. package/src/state/undock.ts +3 -0
  209. package/src/state/useOpenOnce.ts +20 -16
  210. package/src/state/usePersistedState.test.tsx +1 -1
  211. package/src/state/view.ts +1 -0
  212. package/src/styles.less +1 -0
  213. package/src/surface/index.ts +1 -1
  214. package/src/surface/useTiledSurface.test.tsx +14 -0
  215. package/src/surface/useTiledSurface.ts +11 -3
  216. package/src/theme/Interstellar.stories.tsx +3 -1
  217. package/src/theme/base.less +21 -47
  218. package/src/theme/interstellar.test.ts +1 -1
  219. package/src/theme/interstellar.theme.json +10 -3
  220. package/src/trial/Trial.annotations.test.tsx +73 -0
  221. package/src/trial/Trial.less +0 -29
  222. package/src/trial/Trial.loupe.test.tsx +28 -11
  223. package/src/trial/Trial.tsx +85 -67
  224. package/src/trial/TrialChrome.tsx +27 -6
  225. package/src/trial/index.ts +2 -0
  226. package/src/trial/loupeSwitch.ts +15 -0
  227. package/dist/_dts/LayerList.d-BoELAMsM.d.ts +0 -83
  228. package/dist/_dts/PrefsRow.d-DFpPIeIC.d.ts +0 -39
  229. package/dist/_dts/PropertyField.d-D0ndfIIt.d.ts +0 -404
  230. package/dist/_dts/Select.d-Cr8-zoup.d.ts +0 -569
  231. package/dist/chunk-4TT3PNPR.js.map +0 -1
  232. package/dist/chunk-6FLXL3I7.js.map +0 -1
  233. package/dist/chunk-ASOK76ZH.js.map +0 -1
  234. package/dist/chunk-CGHF6RZV.js.map +0 -1
  235. package/dist/chunk-CQLQPQ4P.js.map +0 -1
  236. package/dist/chunk-DWMSB4CA.js.map +0 -1
  237. package/dist/chunk-HXXTULDN.js.map +0 -1
  238. package/dist/chunk-IJJUK4FU.js.map +0 -1
  239. package/dist/chunk-IRTGUQ5O.js.map +0 -1
  240. package/dist/chunk-KHK5FGER.js +0 -145
  241. package/dist/chunk-KHK5FGER.js.map +0 -1
  242. package/dist/chunk-NEXR37YJ.js.map +0 -1
  243. package/dist/chunk-O6FFFOHS.js.map +0 -1
  244. package/dist/chunk-QGMOA2YE.js.map +0 -1
  245. package/dist/chunk-RWNDDKOH.js.map +0 -1
  246. package/dist/chunk-S4NCI32V.js +0 -549
  247. package/dist/chunk-S4NCI32V.js.map +0 -1
  248. package/dist/chunk-SBXNQW4G.js +0 -3
  249. package/dist/chunk-SLAQPUI4.js.map +0 -1
  250. package/dist/chunk-TJ77A4A3.js.map +0 -1
  251. package/dist/chunk-TYN6MLXX.js +0 -13864
  252. package/dist/chunk-TYN6MLXX.js.map +0 -1
  253. package/dist/chunk-WPLAANH4.js.map +0 -1
  254. package/src/primitives/useRovingTabIndex.test.ts +0 -48
  255. package/src/primitives/useRovingTabIndex.ts +0 -88
  256. package/src/state/Persistence.stories.tsx +0 -75
@@ -1,145 +0,0 @@
1
- import { textCommand, ellipsePath, linePath, markerDrawCommands, rectPath, PathBuilder } from '@weasel-js/core';
2
-
3
- // src/annotations/paint.ts
4
- var MARK_COLOR = "#e5484d";
5
- var MARK_WIDTH = 2;
6
- var TEXT_SIZE = 14;
7
- var POINT_RADIUS = 4;
8
- var toWorld = (p, content) => ({
9
- x: p.x * content.w,
10
- y: p.y * content.h
11
- });
12
- function vertices(m, content) {
13
- const stored = m.data.points;
14
- if (stored && stored.length >= 2) return stored.map((p) => toWorld(p, content));
15
- const { x, y, width, height } = m.pose;
16
- return [
17
- { x, y },
18
- { x: x + width, y: y + height }
19
- ];
20
- }
21
- function polyline(points) {
22
- const b = new PathBuilder();
23
- const first = points[0];
24
- if (!first) return rectPath(0, 0, 0, 0);
25
- b.moveTo(first.x, first.y);
26
- for (const p of points.slice(1)) b.lineTo(p.x, p.y);
27
- return b.build();
28
- }
29
- function markCommands(m, content, style = {}) {
30
- const color = style.color ?? MARK_COLOR;
31
- const stroke = {
32
- paint: { color },
33
- width: MARK_WIDTH,
34
- cap: "round",
35
- join: "round",
36
- ...style.stale ? { dash: [6, 4] } : {}
37
- };
38
- switch (m.data.kind) {
39
- case "rect":
40
- return [
41
- { kind: "path", path: rectPath(m.pose.x, m.pose.y, m.pose.width, m.pose.height), stroke }
42
- ];
43
- case "ellipse":
44
- return [{ kind: "path", path: ellipsePath(m.pose), stroke }];
45
- case "line": {
46
- const [a, b] = vertices(m, content);
47
- return [{ kind: "path", path: linePath(a, b), stroke }];
48
- }
49
- case "arrow": {
50
- const [a, b] = vertices(m, content);
51
- const marked = { ...stroke, markerEnd: "arrow" };
52
- const path = linePath(a, b);
53
- return [
54
- { kind: "path", path, stroke: marked },
55
- ...markerDrawCommands(path, marked, MARK_WIDTH, void 0)
56
- ];
57
- }
58
- case "stroke":
59
- return [{ kind: "path", path: polyline(vertices(m, content)), stroke }];
60
- case "point": {
61
- const stored = m.data.points?.[0];
62
- const c = stored ? toWorld(stored, content) : { x: m.pose.x, y: m.pose.y };
63
- const ring = {
64
- x: c.x - POINT_RADIUS,
65
- y: c.y - POINT_RADIUS,
66
- width: 2 * POINT_RADIUS,
67
- height: 2 * POINT_RADIUS
68
- };
69
- return [{ kind: "path", path: ellipsePath(ring), stroke }];
70
- }
71
- case "text": {
72
- const text = m.data.title;
73
- if (!text) return [];
74
- return [
75
- textCommand(
76
- m.pose.x,
77
- m.pose.y,
78
- text,
79
- { fontSize: TEXT_SIZE },
80
- void 0,
81
- void 0,
82
- void 0,
83
- {
84
- fill: { color }
85
- }
86
- )
87
- ];
88
- }
89
- }
90
- }
91
-
92
- // src/annotations/svgNodes.ts
93
- var NO_PAINT = { kind: "none" };
94
- function toSvgPaint(paint) {
95
- if (!paint) return NO_PAINT;
96
- if ("color" in paint && typeof paint.color === "string") {
97
- return {
98
- kind: "solid",
99
- color: paint.color,
100
- ...paint.opacity != null ? { opacity: paint.opacity } : {}
101
- };
102
- }
103
- return { kind: "gradient", paint };
104
- }
105
- function toSvgStroke(stroke) {
106
- return {
107
- paint: toSvgPaint(stroke.paint),
108
- width: stroke.width ?? 1,
109
- ...stroke.cap ? { cap: stroke.cap } : {},
110
- ...stroke.join ? { join: stroke.join } : {},
111
- ...stroke.dash ? { dash: [...stroke.dash] } : {},
112
- ...stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {},
113
- ...stroke.align ? { align: stroke.align } : {}
114
- };
115
- }
116
- function toSvgNode(cmd, m) {
117
- if (cmd.kind === "path") {
118
- return {
119
- kind: "path",
120
- path: cmd.path,
121
- fill: toSvgPaint(cmd.fill),
122
- ...cmd.stroke ? { stroke: toSvgStroke(cmd.stroke) } : {}
123
- };
124
- }
125
- if (cmd.kind === "text") {
126
- return {
127
- kind: "text",
128
- x: cmd.x,
129
- y: cmd.y,
130
- width: m.pose.width,
131
- height: m.pose.height,
132
- text: cmd.runs.map((run) => run.text).join(""),
133
- style: cmd.style,
134
- ...cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}
135
- };
136
- }
137
- throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);
138
- }
139
- function markSvgNodes(m, content, style = {}) {
140
- return markCommands(m, content, style).map((cmd) => toSvgNode(cmd, m));
141
- }
142
-
143
- export { markCommands, markSvgNodes };
144
- //# sourceMappingURL=chunk-KHK5FGER.js.map
145
- //# sourceMappingURL=chunk-KHK5FGER.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/annotations/paint.ts","../src/annotations/svgNodes.ts"],"names":[],"mappings":"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","file":"chunk-KHK5FGER.js","sourcesContent":["import type { DrawCommand, Path, Stroke } from '@weasel-js/core';\nimport {\n ellipsePath,\n linePath,\n markerDrawCommands,\n PathBuilder,\n rectPath,\n textCommand,\n} from '@weasel-js/core';\nimport type { WorldRect } from './frac';\nimport type { AnnotationData, FracPoint } from './types';\n\n/** One loud color, not a themed one: a mark sits over the instrument's own\n * picture and has to be legible against whatever that picture is. */\nconst MARK_COLOR = '#e5484d';\n/** World units, so a mark thickens with the picture it annotates — and so the\n * marker geometry can be resolved here, which needs a resolved width. */\nconst MARK_WIDTH = 2;\nconst TEXT_SIZE = 14;\nconst POINT_RADIUS = 4;\n\n/** The subset of a mark's scene node this needs: where it is, and what it is. */\nexport interface PaintableMark {\n pose: WorldRect;\n data: AnnotationData;\n}\n\n/** How a mark is drawn, as opposed to where. Resolved by the overlay from the\n * instrument's vocabulary and the mark's own staleness. */\nexport interface MarkStyle {\n /** The status's color, or the default. */\n color?: string;\n /** A mark whose stored position no longer describes the picture. Drawn\n * dashed rather than hidden: it still describes *something*, and dropping\n * it would lose it. */\n stale?: boolean;\n}\n\nconst toWorld = (p: FracPoint, content: { w: number; h: number }) => ({\n x: p.x * content.w,\n y: p.y * content.h,\n});\n\n/** A mark's stored vertices in world units, or the pose's diagonal — a stored\n * mark whose `points` did not survive still has to draw somewhere. */\nfunction vertices(m: PaintableMark, content: { w: number; h: number }): { x: number; y: number }[] {\n const stored = m.data.points;\n if (stored && stored.length >= 2) return stored.map((p) => toWorld(p, content));\n const { x, y, width, height } = m.pose;\n return [\n { x, y },\n { x: x + width, y: y + height },\n ];\n}\n\nfunction polyline(points: { x: number; y: number }[]): Path {\n const b = new PathBuilder();\n const first = points[0];\n if (!first) return rectPath(0, 0, 0, 0);\n b.moveTo(first.x, first.y);\n for (const p of points.slice(1)) b.lineTo(p.x, p.y);\n return b.build();\n}\n\n/**\n * What one mark draws, in its target's world.\n *\n * Pure: a node and the target's content box in, draw commands out. Geometry\n * that a bounding box cannot describe — a line's ends, a stroke's path — comes\n * from `data.points`, which is in fractions like the bounds.\n */\nexport function markCommands(\n m: PaintableMark,\n content: { w: number; h: number },\n style: MarkStyle = {},\n): DrawCommand[] {\n const color = style.color ?? MARK_COLOR;\n const stroke: Stroke = {\n paint: { color },\n width: MARK_WIDTH,\n cap: 'round',\n join: 'round',\n ...(style.stale ? { dash: [6, 4] } : {}),\n };\n\n switch (m.data.kind) {\n case 'rect':\n return [\n { kind: 'path', path: rectPath(m.pose.x, m.pose.y, m.pose.width, m.pose.height), stroke },\n ];\n case 'ellipse':\n return [{ kind: 'path', path: ellipsePath(m.pose), stroke }];\n case 'line': {\n const [a, b] = vertices(m, content);\n return [{ kind: 'path', path: linePath(a, b), stroke }];\n }\n case 'arrow': {\n const [a, b] = vertices(m, content);\n // The spec's arrow: a line carrying an end marker, not its own geometry.\n // Markers are separate commands — a stroke's `markerEnd` is inert unless\n // something turns it into geometry, and only the kit's own node painter\n // does that, for the nodes it owns.\n const marked: Stroke = { ...stroke, markerEnd: 'arrow' };\n const path = linePath(a, b);\n return [\n { kind: 'path', path, stroke: marked },\n ...markerDrawCommands(path, marked, MARK_WIDTH, undefined),\n ];\n }\n case 'stroke':\n return [{ kind: 'path', path: polyline(vertices(m, content)), stroke }];\n case 'point': {\n const stored = m.data.points?.[0];\n const c = stored ? toWorld(stored, content) : { x: m.pose.x, y: m.pose.y };\n const ring = {\n x: c.x - POINT_RADIUS,\n y: c.y - POINT_RADIUS,\n width: 2 * POINT_RADIUS,\n height: 2 * POINT_RADIUS,\n };\n return [{ kind: 'path', path: ellipsePath(ring), stroke }];\n }\n case 'text': {\n const text = m.data.title;\n if (!text) return [];\n return [\n textCommand(\n m.pose.x,\n m.pose.y,\n text,\n { fontSize: TEXT_SIZE },\n undefined,\n undefined,\n undefined,\n {\n fill: { color },\n },\n ),\n ];\n }\n }\n}\n","import type { DrawCommand, FillStyle, Stroke } from '@weasel-js/core';\nimport type { SvgNode, SvgPaint, SvgStroke } from '@weasel-js/svg';\nimport { type MarkStyle, markCommands, type PaintableMark } from './paint';\n\nconst NO_PAINT: SvgPaint = { kind: 'none' };\n\nfunction toSvgPaint(paint: FillStyle | undefined): SvgPaint {\n if (!paint) return NO_PAINT;\n if ('color' in paint && typeof paint.color === 'string') {\n return {\n kind: 'solid',\n color: paint.color,\n ...(paint.opacity != null ? { opacity: paint.opacity } : {}),\n };\n }\n return { kind: 'gradient', paint };\n}\n\n/** Marker references are deliberately dropped: `markCommands` already resolves\n * a marker into its own path command, and keeping the reference would make\n * the serializer emit a `<marker>` def that draws the head a second time. */\nfunction toSvgStroke(stroke: Stroke): SvgStroke {\n return {\n paint: toSvgPaint(stroke.paint),\n width: stroke.width ?? 1,\n ...(stroke.cap ? { cap: stroke.cap } : {}),\n ...(stroke.join ? { join: stroke.join } : {}),\n ...(stroke.dash ? { dash: [...stroke.dash] } : {}),\n ...(stroke.miterLimit != null ? { miterLimit: stroke.miterLimit } : {}),\n ...(stroke.align ? { align: stroke.align } : {}),\n };\n}\n\nfunction toSvgNode(cmd: DrawCommand, m: PaintableMark): SvgNode {\n if (cmd.kind === 'path') {\n return {\n kind: 'path',\n path: cmd.path,\n fill: toSvgPaint(cmd.fill),\n ...(cmd.stroke ? { stroke: toSvgStroke(cmd.stroke) } : {}),\n };\n }\n if (cmd.kind === 'text') {\n return {\n kind: 'text',\n x: cmd.x,\n y: cmd.y,\n width: m.pose.width,\n height: m.pose.height,\n text: cmd.runs.map((run) => run.text).join(''),\n style: cmd.style,\n ...(cmd.runs[0]?.fill ? { fill: cmd.runs[0].fill } : {}),\n };\n }\n // Unreachable while `markCommands` emits only paths and text. A throw rather\n // than a skip: a new mark kind silently vanishing from every export is a\n // worse afternoon than a loud one.\n throw new Error(`[labkit] a mark drew a '${cmd.kind}' command, which has no vector form`);\n}\n\n/**\n * One mark as SVG nodes, converted from the very commands the pane paints.\n *\n * Deliberately not a second switch over `data.kind`: geometry has one source,\n * and this is a translation of it. `serializeSvg` turns the result into a\n * document.\n */\nexport function markSvgNodes(\n m: PaintableMark,\n content: { w: number; h: number },\n style: MarkStyle = {},\n): SvgNode[] {\n return markCommands(m, content, style).map((cmd) => toSvgNode(cmd, m));\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/primitives/FloatingPanel.tsx"],"names":[],"mappings":"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","file":"chunk-NEXR37YJ.js","sourcesContent":["import { openPointerSession, type PointerSession } from '@weasel-js/core';\nimport type React from 'react';\nimport { type CSSProperties, type ReactNode, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n type Corner,\n DEFAULT_ANCHOR,\n DEFAULT_INSET,\n FLOATING_DRAG_PREFIX,\n type FloatingPlacement,\n floatingStrategy,\n} from 'windease';\nimport { usePersistedState } from '../state/usePersistedState';\n\n/** The strategy holds a map keyed by item id; a panel is always a lone item. */\nconst ITEM_ID = 'panel';\n\n/** Props for `<FloatingPanel>`. */\nexport interface FloatingPanelProps {\n children: ReactNode;\n /** Corner it rests in before it has ever been dragged. Default `'bottom-left'`. */\n anchor?: Corner;\n /** Corners that may capture it. Default: all four. */\n snapCorners?: readonly Corner[];\n /** Pixels in from a corner when snapped. Default 12. */\n inset?: number;\n /** Name to remember its position under, through `usePersistedState` — so it\n * is remembered only inside a lab or a `<Persistence>`. Omit to forget on\n * reload. */\n persist?: string;\n className?: string;\n}\n\n/**\n * The panel's footprint is its border box — `contentRect` excludes padding and\n * border, which would place a panel that then overflows its corner by exactly\n * that much.\n */\nfunction borderBoxOf(entry: ResizeObserverEntry): { w: number; h: number } {\n const box = entry.borderBoxSize?.[0];\n if (box) return { w: box.inlineSize, h: box.blockSize };\n return { w: entry.contentRect.width, h: entry.contentRect.height };\n}\n\n/** How far the pointer must travel before a press becomes a drag. */\nconst DRAG_THRESHOLD = 3;\n\n/** A pointerdown on one of these is the child's, not a drag. */\nfunction isInteractive(target: EventTarget | null): boolean {\n if (!(target instanceof Element)) return false;\n return target.closest('input, button, a, select, textarea, [data-no-drag]') !== null;\n}\n\n/**\n * A draggable box that floats over its offset parent and snaps to its corners.\n *\n * Drives windease's `floatingStrategy` as a pure function rather than mounting a\n * windease container: a lab overlay has one item and no zone tree, so the node\n * model would be all cost. Pointer handling is therefore this component's, and\n * windease's own affordance rendering never participates.\n */\nexport function FloatingPanel({\n children,\n anchor = DEFAULT_ANCHOR,\n snapCorners,\n inset = DEFAULT_INSET,\n persist,\n className,\n}: FloatingPanelProps) {\n const ref = useRef<HTMLDivElement>(null);\n const strategy = useMemo(() => floatingStrategy(), []);\n const options = useMemo(() => ({ defaultAnchor: anchor, inset }), [anchor, inset]);\n\n const [container, setContainer] = useState({ w: 0, h: 0 });\n const [size, setSize] = useState({ w: 0, h: 0 });\n const [place, setPlace] = usePersistedState<FloatingPlacement>(persist, () => ({\n x: 0,\n y: 0,\n anchor,\n }));\n\n const item = useMemo(\n () => ({\n id: ITEM_ID,\n meta: { floating: true, ...(snapCorners ? { snapCorners: [...snapCorners] } : {}) },\n natural: size,\n }),\n [size, snapCorners],\n );\n\n useEffect(() => {\n const el = ref.current;\n const parent = el?.offsetParent ?? el?.parentElement;\n if (!el || !parent) return;\n // Sizes come off the entry, not the DOM: jsdom reports 0 for every\n // clientWidth/offsetWidth, and an unmeasured item is withheld from layout.\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === parent) {\n setContainer({ w: entry.contentRect.width, h: entry.contentRect.height });\n } else {\n setSize(borderBoxOf(entry));\n }\n }\n });\n observer.observe(parent);\n observer.observe(el);\n return () => observer.disconnect();\n }, []);\n\n const rect = strategy\n .layout({\n items: [item],\n container,\n state: { at: { [ITEM_ID]: place }, inner: undefined },\n options,\n })\n .placements.get(ITEM_ID);\n\n const dragging = useRef<{ x: number; y: number } | null>(null);\n const session = useRef<PointerSession | null>(null);\n const [isDragging, setDragging] = useState(false);\n // A drag outlives the render that started it, so the reducer's inputs are\n // read here and not from that render's closure — a container resized\n // mid-drag would otherwise place the panel against its old box.\n const layout = useRef({ container, options, item });\n layout.current = { container, options, item };\n\n useEffect(() => () => session.current?.cancel(), []);\n\n const onPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {\n if (isInteractive(e.target)) return;\n // The canvas stack underneath owns pan/zoom on the same pointer events.\n e.stopPropagation();\n const origin = e.currentTarget;\n const pointerId = e.pointerId;\n const start = { x: e.clientX, y: e.clientY };\n\n const end = () => {\n session.current = null;\n if (!dragging.current) return;\n dragging.current = null;\n setDragging(false);\n try {\n origin.releasePointerCapture?.(pointerId);\n } catch {\n // Capture is already gone whenever the session ended by losing it.\n }\n };\n\n // Armed, not capturing. Capture retargets mouseup to this element, and the\n // browser then synthesizes no `click` on the child under the cursor — so\n // capturing on press makes every non-native control in the panel dead to a\n // real mouse, silently. `isInteractive` only exempts the names it lists; a\n // `role=\"button\"` span, a react-aria control or a canvas is not among them.\n session.current = openPointerSession(\n origin,\n e,\n {\n onMove: (ev) => {\n if (!dragging.current) {\n if (Math.hypot(ev.clientX - start.x, ev.clientY - start.y) < DRAG_THRESHOLD) return;\n dragging.current = { ...start };\n setDragging(true);\n origin.setPointerCapture?.(pointerId);\n }\n const from = dragging.current;\n const dx = ev.clientX - from.x;\n const dy = ev.clientY - from.y;\n if (dx === 0 && dy === 0) return;\n dragging.current = { x: ev.clientX, y: ev.clientY };\n const { container: box, options: opts, item: only } = layout.current;\n setPlace(\n (prev) =>\n strategy.reduce?.(\n { at: { [ITEM_ID]: prev }, inner: undefined },\n {\n affordanceId: `${FLOATING_DRAG_PREFIX}${ITEM_ID}`,\n kind: 'drag',\n payload: { dx, dy },\n },\n { container: box, options: opts, items: [only] },\n ).at[ITEM_ID] ?? prev,\n );\n },\n onEnd: end,\n onCancel: end,\n },\n { capture: false },\n );\n };\n\n return (\n <div\n className={className ? `lk-floating-panel ${className}` : 'lk-floating-panel'}\n data-dragging={isDragging ? 'true' : undefined}\n data-placed={rect ? 'true' : undefined}\n onPointerDown={onPointerDown}\n ref={ref}\n style={\n {\n position: 'absolute',\n left: `${rect?.x ?? 0}px`,\n top: `${rect?.y ?? 0}px`,\n } as CSSProperties\n }\n >\n {children}\n </div>\n );\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/config/builder.ts","../src/config/rules.ts","../src/config/resolve.ts","../src/config/useResolvedConfig.ts"],"names":[],"mappings":"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","file":"chunk-O6FFFOHS.js","sourcesContent":["import type { PrefLeaf, PrefNumberFormat, PrefNumberUnit } from '@weasel-js/ui';\nimport { type Auto, isAuto } from './auto';\nimport type {\n Annotations,\n BranchAnnotations,\n BranchOptions,\n ConfigBranch,\n ConfigEntry,\n ConfigNode,\n ConfigOption,\n ConfigSchema,\n ConfigShape,\n ControlRenderer,\n InDialogOptions,\n InferConfig,\n NodeOptions,\n SectionOption,\n} from './types';\n\n/** Whether a schema entry is a branch rather than a leaf. */\nexport function isConfigBranch(entry: ConfigEntry): entry is ConfigBranch {\n return 'children' in entry;\n}\n\n/** Shared chaining surface. Every method clones, so a node can be reused as a\n * base for several leaves without one bleeding into the next. */\nexport abstract class BaseNode<T> implements ConfigNode<T> {\n abstract readonly kind: string | null;\n\n // `default` is a reserved word in a parameter position, so the field is\n // declared rather than taken as a parameter property.\n readonly default: T;\n\n constructor(\n defaultValue: T,\n readonly annotations: Readonly<Annotations> = {},\n readonly options: Readonly<NodeOptions> = {},\n ) {\n this.default = defaultValue;\n }\n\n /** Clone into the same subclass. Subclasses with extra constructor\n * arguments override this. */\n protected with(annotations: Annotations, options: NodeOptions): this {\n const Ctor = this.constructor as new (d: T, a: Annotations, o: NodeOptions) => this;\n return new Ctor(this.default, annotations, options);\n }\n\n protected ann(patch: Annotations): this {\n return this.with({ ...this.annotations, ...patch }, this.options);\n }\n\n protected opt(patch: NodeOptions): this {\n return this.with(this.annotations, { ...this.options, ...patch });\n }\n\n /** Human-readable label. Defaults to the key, title-cased. */\n label(name: string): this {\n return this.ann({ name });\n }\n\n /** Longer help text, surfaced as a tooltip on the row label. */\n describe(description: string): this {\n return this.ann({ description });\n }\n\n /** Omit from the panel unless it is asked to show hidden leaves. */\n hidden(): this {\n return this.ann({ hidden: true });\n }\n\n /** Pair with a sibling sharing this id, side-by-side on one row. */\n pair(pair: string): this {\n return this.ann({ pair });\n }\n\n /** Render under a named section heading. `collapsed` opens the section\n * folded, and `layout` and `pack` lay out its rows — say each on any one of\n * the section's leaves. */\n section(label: string, opts: Omit<SectionOption, 'label'> = {}): this {\n return this.opt({ section: { label, ...opts } });\n }\n\n /** Show this row only while the predicate holds. Presentational — the value\n * stays in config and the instrument still reads it. */\n showIf(predicate: (config: Record<string, unknown>) => boolean): this {\n return this.opt({ showIf: predicate });\n }\n\n /** Draw this one row yourself, keeping the kind, default and validation. */\n render(renderer: ControlRenderer): this {\n return this.opt({ render: renderer, dialog: undefined });\n }\n\n /** Draw this row as a button that opens a dialog, with `body` as the\n * dialog's content — for an editor too big for the row. */\n dialog(body: ControlRenderer, opts?: InDialogOptions): this {\n return this.opt({ dialog: { ...opts, body }, render: undefined });\n }\n\n /**\n * Compute this leaf's value while it is auto, instead of leaving it\n * `undefined`. The resolver is given the config with every other auto path\n * already resolved.\n */\n auto(resolve: (config: Record<string, unknown>) => T): this {\n return this.opt({ autoResolve: resolve as (c: Record<string, unknown>) => unknown });\n }\n\n /**\n * Start this leaf auto rather than pinned at its default. Takes `auto` and\n * nothing else — the constructor argument already declares the value, and a\n * second way to say it would fight with the first.\n */\n initial(value: Auto): this {\n if (!isAuto(value)) throw new Error('[labkit] .initial() takes `auto` and nothing else');\n return this.opt({ unpinned: true });\n }\n\n /** Never auto. The row's label does not toggle. */\n manual(): this {\n return this.opt({ manual: true });\n }\n}\n\nexport class NumberNode extends BaseNode<number> {\n readonly kind = 'number';\n\n /** Bound the value. A number with both bounds renders as a slider. */\n range(min: number, max: number): this {\n return this.ann({ min, max });\n }\n\n step(step: number): this {\n return this.ann({ step });\n }\n\n /** A display suffix for the value — `'px'`, `'ms'`, `'°'`. Presentation only:\n * it is never parsed, and the stored value stays a plain number. */\n suffix(suffix: string): this {\n return this.ann({ suffix });\n }\n\n /** Show the value in a named format — `'compact'` reads `2.00M`. Presentation\n * only: the stored value stays a plain number, and a typed `2.5m` reads back. */\n format(format: PrefNumberFormat): this {\n return this.ann({ format });\n }\n\n /**\n * Store the value in one unit and edit it in another — radians stored,\n * degrees typed. `min`, `max` and `step` are declared in the stored unit\n * alongside the value, and convert with it. `prefUnit` builds one from a\n * `UnitSystem`.\n */\n unit(unit: PrefNumberUnit): this {\n return this.ann({ unit });\n }\n\n /** Force a slider even without both bounds. */\n slider(): this {\n return this.ann({ control: 'slider' });\n }\n\n /** Force a typed input even when both bounds are set. */\n input(): this {\n return this.ann({ control: 'input' });\n }\n}\n\nexport class BooleanNode extends BaseNode<boolean> {\n readonly kind = 'boolean';\n\n /** Ask for a switch rather than a checkbox. */\n toggle(): this {\n return this.ann({ control: 'switch' });\n }\n}\n\nexport class StringNode extends BaseNode<string> {\n readonly kind = 'string';\n\n placeholder(placeholder: string): this {\n return this.ann({ placeholder });\n }\n\n maxLength(maxLength: number): this {\n return this.ann({ maxLength });\n }\n\n /** Milliseconds to debounce live writes. 0 commits every keystroke. */\n debounce(debounceMs: number): this {\n return this.ann({ debounceMs });\n }\n}\n\nexport class ListNode extends BaseNode<string[]> {\n readonly kind = 'list';\n\n /** Shown in an empty entry. */\n placeholder(placeholder: string): this {\n return this.ann({ placeholder });\n }\n}\n\nexport class ColorNode extends BaseNode<string> {\n readonly kind = 'color';\n\n /** The value carries alpha as `#rrggbbaa`, and the row gets an opacity\n * track beside the swatch. */\n alpha(): this {\n return this.ann({ alpha: true });\n }\n}\n\nexport class EnumNode<T extends string> extends BaseNode<T> {\n readonly kind = 'enum';\n\n /** Render as a segmented control rather than a select. */\n radio(): this {\n return this.ann({ control: 'radio' });\n }\n\n /** Relabel the choices. Named `labels` rather than `options` because\n * `options` is the node's own extras bag. */\n labels(options: readonly ConfigOption[]): this {\n return this.ann({ options });\n }\n}\n\n/** A leaf whose kind the rule chain decides. */\nexport class ValueNode<T> extends BaseNode<T> {\n readonly kind = null;\n}\n\n/** A leaf of a kind labkit does not ship a row for. */\nexport class CustomNode<T> extends BaseNode<T> {\n constructor(\n readonly kind: string,\n defaultValue: T,\n annotations: Readonly<Annotations> = {},\n options: Readonly<NodeOptions> = {},\n ) {\n super(defaultValue, annotations, options);\n }\n\n protected override with(annotations: Annotations, options: NodeOptions): this {\n return new CustomNode(this.kind, this.default, annotations, options) as this;\n }\n}\n\n/**\n * A branch of the schema: its children nest under its key, so a leaf inside\n * one is read and written at a dotted path. Distinct from `.section()`, which\n * puts a heading over sibling leaves and leaves their paths alone.\n */\nexport class GroupNode<S extends ConfigShape> implements ConfigBranch<S> {\n constructor(\n readonly children: S,\n readonly annotations: Readonly<BranchAnnotations> = {},\n readonly options: Readonly<BranchOptions> = {},\n ) {}\n\n private with(annotations: BranchAnnotations, options: BranchOptions): GroupNode<S> {\n return new GroupNode(this.children, annotations, options);\n }\n\n /** Heading for the group's rows. Defaults to the key, title-cased. */\n label(name: string): GroupNode<S> {\n return this.with({ ...this.annotations, name }, this.options);\n }\n\n /** Longer help text. Carried on the resolved `PrefGroup`; both weasel-ui's\n * `PrefsForm` and `ControlPanel` draw it under the heading. */\n describe(description: string): GroupNode<S> {\n return this.with({ ...this.annotations, description }, this.options);\n }\n\n /** Render this whole group under a named section heading. */\n section(label: string, opts: Omit<SectionOption, 'label'> = {}): GroupNode<S> {\n return this.with(this.annotations, { ...this.options, section: { label, ...opts } });\n }\n\n /** Show this group only while the predicate holds. Presentational — every\n * value beneath it stays in config and the instrument still reads it. */\n showIf(predicate: (config: Record<string, unknown>) => boolean): GroupNode<S> {\n return this.with(this.annotations, { ...this.options, showIf: predicate });\n }\n}\n\n/** Every default in a shape, nested the way the shape is. */\nfunction shapeDefaults(shape: ConfigShape): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(shape)) {\n out[key] = isConfigBranch(entry) ? shapeDefaults(entry.children) : entry.default;\n }\n return out;\n}\n\nconst expand = <T extends string>(\n options: readonly T[] | readonly ConfigOption[],\n): readonly ConfigOption[] =>\n options.map((o) => (typeof o === 'string' ? { value: o, label: o } : o));\n\n/**\n * Builds an instrument's config: the values, their types, and how each is\n * edited, in one declaration.\n *\n * ```ts\n * const config = f.schema({\n * showGrid: f.boolean(true),\n * cellSize: f.number(20).range(5, 80).step(5).label('Grid spacing'),\n * // Nested: read and written at `grid.color`.\n * grid: f.group({ color: f.color('#ffffff') }),\n * })\n * ```\n */\nexport const f = {\n number: (def: number): NumberNode => new NumberNode(def),\n boolean: (def: boolean): BooleanNode => new BooleanNode(def),\n string: (def: string): StringNode => new StringNode(def),\n color: (def: string): ColorNode => new ColorNode(def),\n /** A list of strings. Its row summarizes the list, and opens a dialog to\n * edit it one entry per field. */\n list: (def: readonly string[]): ListNode => new ListNode([...def]),\n\n /** A fixed set of choices. The default's literal type flows into the config\n * type, so `f.enum('fast', ['fast', 'accurate'])` gives\n * `'fast' | 'accurate'` with no `as const`. */\n enum: <const T extends string>(\n def: T,\n options: readonly T[] | readonly ConfigOption[],\n ): EnumNode<T> => new EnumNode<T>(def, { options: expand(options) }),\n\n /** A leaf with no declared kind: the rule chain decides, which is how a lab\n * states a convention like \"every `*Color` key is a color picker\". */\n value: <T>(def: T): ValueNode<T> => new ValueNode(def),\n\n /** A branch: its children nest under this key, so `grid: f.group({ size })`\n * puts the value at `config.grid.size` and addresses it as `'grid.size'`.\n * Groups nest as deeply as the schema wants. */\n group: <const S extends ConfigShape>(children: S): GroupNode<S> => new GroupNode(children),\n\n /** A leaf of a kind a lab supplies the control for, through `controls`. */\n custom: <T>(\n kind: string,\n def: T,\n validate?: (leaf: PrefLeaf, config: Record<string, unknown>) => string[],\n ): CustomNode<T> => new CustomNode(kind, def, {}, validate ? { validate } : {}),\n\n /** Collect leaves and groups into an instrument's config. */\n schema<S extends ConfigShape>(nodes: S): ConfigSchema<InferConfig<S>> {\n return { nodes, defaults: () => shapeDefaults(nodes) as InferConfig<S> };\n },\n};\n","import type { ConfigRule, ConfigRuleContext, LeafPatch } from './types';\n\n/** `cellSize` -> `Cell size`. Splits camelCase without shattering acronyms. */\nexport function titleCase(key: string): string {\n const words = key\n .replace(/[_-]+/g, ' ')\n .split(/(?<=[a-z0-9])(?=[A-Z])/)\n .join(' ')\n .trim()\n .toLowerCase();\n return words.length === 0 ? words : words[0].toUpperCase() + words.slice(1);\n}\n\n/** An `f.value` leaf takes its kind from the shape of its default. */\nconst kindFromValue: ConfigRule = (ctx) => {\n const t = typeof ctx.default;\n if (t === 'boolean' || t === 'number' || t === 'string') return { kind: t };\n const d = ctx.default;\n if (Array.isArray(d) && d.every((v) => typeof v === 'string')) return { kind: 'list' };\n return null;\n};\n\nconst labelFromKey: ConfigRule = (ctx) => ({ name: titleCase(ctx.key) });\n\n/** A number bounded on both sides is a slider; one bound or none is an input. */\nconst sliderWhenBounded: ConfigRule = (ctx) => {\n if (ctx.leaf.kind !== 'number') return null;\n const bounded = ctx.leaf.min !== undefined && ctx.leaf.max !== undefined;\n return bounded ? { control: 'slider' } : null;\n};\n\n/** `PrefBase.description` is required, so every leaf must end up with one. */\nconst descriptionDefault: ConfigRule = () => ({ description: '' });\n\n/**\n * labkit's own inference, expressed in the same vocabulary a consumer\n * extends. Runs after the consumer's rules, so a lab always wins.\n *\n * If one of these ever needs something a `ConfigRule` cannot express, the\n * seam is too weak — that is the point of writing them this way.\n */\nexport const builtinRules: readonly ConfigRule[] = [\n kindFromValue,\n labelFromKey,\n sliderWhenBounded,\n descriptionDefault,\n];\n\n/**\n * Fold a rule chain into one leaf patch. Gap-filling: a property already\n * settled is never overwritten, so the accumulator seeded with the author's\n * annotations beats every rule, and earlier rules beat later ones.\n */\nexport function applyRules(\n seed: LeafPatch,\n ctx: Omit<ConfigRuleContext, 'leaf'>,\n rules: readonly ConfigRule[],\n): LeafPatch {\n const acc: LeafPatch = { ...seed };\n for (const rule of rules) {\n const patch = rule({ ...ctx, leaf: acc });\n if (patch === null) continue;\n for (const [k, v] of Object.entries(patch)) {\n if (v !== undefined && acc[k as keyof LeafPatch] === undefined) {\n (acc as Record<string, unknown>)[k] = v;\n }\n }\n }\n return acc;\n}\n","import type { PrefGroup, PrefLeaf } from '@weasel-js/ui';\nimport { isConfigBranch } from './builder';\nimport { applyRules, builtinRules, titleCase } from './rules';\nimport type {\n ConfigEntry,\n ConfigRule,\n ConfigSchema,\n ConfigShape,\n ControlRenderer,\n DialogSpec,\n LeafPatch,\n ResolvedConfig,\n SectionSpec,\n} from './types';\n\n/** Drop keys whose value is undefined, so an unset annotation stays a gap the\n * rule chain can fill rather than a settled `undefined`. */\nfunction defined(annotations: Record<string, unknown>): LeafPatch {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(annotations)) if (v !== undefined) out[k] = v;\n return out as LeafPatch;\n}\n\n/** What the walk collects on the side of the `PrefGroup` tree. */\ninterface Sink {\n sections: SectionSpec[];\n showIf: Map<string, (config: Record<string, unknown>) => boolean>;\n renderers: Record<string, ControlRenderer>;\n dialogs: Record<string, DialogSpec>;\n chain: readonly ConfigRule[];\n}\n\n/**\n * Resolve a schema into the vocabulary weasel-ui renders, running each leaf\n * through the consumer's rules and then labkit's own.\n *\n * The group mirrors the schema's own nesting: an `f.group` becomes a nested\n * `PrefGroup`, so a leaf's dotted path within the tree is the path its value\n * is written at, and both `ControlPanel` and `PrefsForm` address it\n * identically.\n */\nexport function resolveConfigSchema<TC>(\n schema: ConfigSchema<TC>,\n rules: readonly ConfigRule[] = [],\n): ResolvedConfig {\n const sink: Sink = {\n sections: [],\n showIf: new Map(),\n renderers: {},\n dialogs: {},\n chain: [...rules, ...builtinRules],\n };\n const group = resolveShape(schema.nodes, '', '', sink);\n return {\n group,\n sections: sink.sections,\n showIf: sink.showIf,\n renderers: sink.renderers,\n dialogs: sink.dialogs,\n };\n}\n\n/** A section while it is still being filled. */\ntype OpenSection = Omit<SectionSpec, 'paths'> & { paths: string[] };\n\nfunction resolveShape(shape: ConfigShape, at: string, name: string, sink: Sink): PrefGroup {\n const children: Record<string, PrefLeaf | PrefGroup> = {};\n const sections = new Map<string, OpenSection>();\n\n for (const [key, entry] of Object.entries(shape)) {\n const path = at === '' ? key : `${at}.${key}`;\n children[key] = resolveEntry(entry, key, path, sink);\n\n const { section, showIf: predicate } = entry.options;\n if (section !== undefined) {\n let spec = sections.get(section.label);\n if (!spec) {\n spec = { at, label: section.label, paths: [] };\n sections.set(section.label, spec);\n sink.sections.push(spec);\n }\n spec.paths.push(path);\n // One node saying `collapsed` settles the section, so a schema does not\n // have to repeat it on every node under the heading.\n if (section.collapsed !== undefined) {\n spec.collapsed = (spec.collapsed ?? false) || section.collapsed;\n }\n if (section.layout !== undefined && spec.layout === undefined) spec.layout = section.layout;\n if (section.pack !== undefined && spec.pack === undefined) spec.pack = section.pack;\n }\n if (predicate) sink.showIf.set(path, predicate);\n if (!isConfigBranch(entry) && entry.options.render) sink.renderers[path] = entry.options.render;\n if (!isConfigBranch(entry) && entry.options.dialog) sink.dialogs[path] = entry.options.dialog;\n }\n\n return { name, children };\n}\n\nfunction resolveEntry(\n entry: ConfigEntry,\n key: string,\n path: string,\n sink: Sink,\n): PrefLeaf | PrefGroup {\n if (isConfigBranch(entry)) {\n const group = resolveShape(\n entry.children,\n path,\n entry.annotations.name ?? titleCase(key),\n sink,\n );\n return entry.annotations.description === undefined\n ? group\n : { ...group, description: entry.annotations.description };\n }\n if (entry.options.manual && entry.options.unpinned) {\n throw new Error(\n `[labkit] \"${path}\" is both .manual() and .initial(auto) — a field that can never be auto cannot start auto`,\n );\n }\n const seed: LeafPatch = defined({\n ...entry.annotations,\n ...(entry.kind === null ? {} : { kind: entry.kind }),\n });\n const patch = applyRules(seed, { key, path, default: entry.default }, sink.chain);\n const { autoResolve, unpinned, manual } = entry.options;\n return {\n ...patch,\n default: entry.default,\n // Extra keys survive onto the leaf at runtime; `ControlPanel` reads them\n // back with its `extra<T>` helper, the same as `min`, `step` and the rest.\n ...(autoResolve === undefined ? {} : { autoResolve }),\n ...(unpinned === undefined ? {} : { unpinned }),\n ...(manual === undefined ? {} : { manual }),\n } as PrefLeaf;\n}\n","import { useMemo } from 'react';\nimport { resolveAutoConfig } from './autoConfig';\nimport type { ResolvedConfig } from './types';\n\nconst NONE: ReadonlySet<string> = new Set();\n\n/**\n * The config an instrument reads: the stored one with every unpinned path\n * resolved. The single place resolution happens, so `Trial` and\n * `useTrialState` cannot disagree about what an instrument is looking at.\n */\nexport function useResolvedConfig<TC>(\n schema: ResolvedConfig | undefined,\n config: TC,\n autoPaths: readonly string[] | undefined,\n): { config: TC; auto: ReadonlySet<string> } {\n const auto = useMemo(\n () => (autoPaths && autoPaths.length > 0 ? new Set(autoPaths) : NONE),\n [autoPaths],\n );\n const resolvedConfig = useMemo(\n () => (schema ? resolveAutoConfig(schema, config, auto) : config),\n [schema, config, auto],\n );\n return { config: resolvedConfig, auto };\n}\n"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../geom/src/mat3.ts","../../svg/src/types.ts","../../svg/src/transform.ts","../../svg/src/textAnchor.ts","../../svg/src/patterns.ts","../../svg/src/path-serializer.ts","../../svg/src/gradients.ts","../../svg/src/serialize.ts"],"names":["PATH_M","PATH_L","PATH_C","PATH_Q","PATH_Z","escapeAttr","localName","resolveScreenLength","boundsOfPath"],"mappings":"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","file":"chunk-QGMOA2YE.js","sourcesContent":["/**\n * 2D affine transforms in canvas/DOMMatrix order: [a, b, c, d, e, f].\n * x' = a·x + c·y + e\n * y' = b·x + d·y + f\n * Represented as a readonly 6-tuple (f64). The affine tier of the kernel.\n *\n * Convention alignment: the renderer already has a `Mat3` in\n * `src/renderer/math/mat3.ts`. That one is a 9-element column-major\n * `Float32Array` (a full 3×3) shaped for `uniformMatrix3fv` — a deliberately\n * different *representation* for the WebGL upload path. Its *logical element\n * order* is identical to ours: `create(a, b, c, d, tx, ty)` maps\n * `x' = a·x + c·y + tx`, `y' = b·x + d·y + ty` (canvas/DOMMatrix a,b,c,d,e,f).\n * We keep the pure 6-tuple f64 form here (the kernel form); the 9-element f32\n * form stays a render-layer concern. No second logical convention is created.\n */\nimport { SINGULAR_RATIO } from './scalar';\n\nexport type Mat3 = readonly [number, number, number, number, number, number];\n\n/** The transform that leaves a point where it is. */\nexport function identity(): Mat3 {\n return [1, 0, 0, 1, 0, 0];\n}\n\n/** A pure translation by `(tx, ty)`. */\nexport function translate(tx: number, ty: number): Mat3 {\n return [1, 0, 0, 1, tx, ty];\n}\n\n/** A pure scale about the origin. Scale about another point by composing\n * translate → scale → inverse translate with `multiply`. */\nexport function scale(sx: number, sy: number): Mat3 {\n return [sx, 0, 0, sy, 0, 0];\n}\n\n/** A pure rotation about the origin, in radians, clockwise in canvas\n * coordinates (y down). */\nexport function rotate(rad: number): Mat3 {\n const c = Math.cos(rad);\n const s = Math.sin(rad);\n return [c, s, -s, c, 0, 0];\n}\n\n/** Compose: result applies `n` first, then `m` (m·n). */\nexport function multiply(m: Mat3, n: Mat3): Mat3 {\n return [\n m[0] * n[0] + m[2] * n[1],\n m[1] * n[0] + m[3] * n[1],\n m[0] * n[2] + m[2] * n[3],\n m[1] * n[2] + m[3] * n[3],\n m[0] * n[4] + m[2] * n[5] + m[4],\n m[1] * n[4] + m[3] * n[5] + m[5],\n ];\n}\n\n/** Inverse, or null when the matrix is singular, non-finite, or too\n * ill-conditioned to invert meaningfully at its own scale. */\nexport function invert(m: Mat3): Mat3 | null {\n const det = m[0] * m[3] - m[1] * m[2];\n // The determinant is an area, so it is judged against the squared column norms.\n const norm2 = Math.max(m[0] * m[0] + m[1] * m[1], m[2] * m[2] + m[3] * m[3]);\n // Negated so a non-finite determinant falls out as singular.\n if (!(Math.abs(det) > SINGULAR_RATIO * norm2)) return null;\n const id = 1 / det;\n const a = m[3] * id;\n const b = -m[1] * id;\n const c = -m[2] * id;\n const d = m[0] * id;\n return [a, b, c, d, -(m[4] * a + m[5] * c), -(m[4] * b + m[5] * d)];\n}\n\n/** Apply to a point, returning a tuple. Cold-path use; hot loops inline. */\nexport function applyToPoint(m: Mat3, x: number, y: number): [number, number] {\n return [m[0] * x + m[2] * y + m[4], m[1] * x + m[3] * y + m[5]];\n}\n\n/** Affine that maps source box (sx,sy,sw,sh) onto destination box (dx,dy,dw,dh). */\nexport function boxToBox(\n sx: number, sy: number, sw: number, sh: number,\n dx: number, dy: number, dw: number, dh: number,\n): Mat3 {\n const kx = sw === 0 ? 1 : dw / sw;\n const ky = sh === 0 ? 1 : dh / sh;\n // translate(dx,dy) · scale(kx,ky) · translate(-sx,-sy)\n return [kx, 0, 0, ky, dx - sx * kx, dy - sy * ky];\n}\n\n/** Rotation by `rad` about pivot (cx,cy): translate(c)·rotate·translate(-c). */\nexport function rotateAboutPoint(cx: number, cy: number, rad: number): Mat3 {\n return multiply(translate(cx, cy), multiply(rotate(rad), translate(-cx, -cy)));\n}\n","/**\n * Public types for `@weasel-js/svg`. The package exposes a flat,\n * discriminated-union node model (`SvgNode`) that mirrors the SVG element\n * tree but uses weasel-native leaf data (`Path`, `FillStyle`) for geometry and\n * paint.\n *\n * Parsing collapses every `transform=\"...\"` onto its descendants' geometry,\n * so the `SvgNode` tree returned from `parseSvg` never has a non-identity\n * group transform. Consumers may still construct groups with explicit\n * transforms before serializing, in which case the serializer emits a\n * single `matrix(a b c d e f)` on the `<g>`.\n */\n\nimport { identity, type Mat3 } from '@weasel-js/geom';\nimport type {\n Path, FillStyle, MarkerEntry, ScreenLength, Stroke, StrokeAlign, StyledRun, TextStyle,\n TextVerticalAlign,\n} from '@weasel-js/core';\n\n/**\n * Opaque pass-through bag for namespaced XML content.\n *\n * weasel-svg does not interpret the contents — it only ensures that any\n * attributes or child elements in a *declared* XML namespace round-trip\n * losslessly through parse → serialize. Consumers (e.g. an app-specific\n * bridge layer) hang their domain semantics off this structure.\n *\n * Keyed by namespace prefix (the prefix is a write-time choice; the URI\n * is the canonical identifier and is supplied via `ParseOptions.namespaces`\n * / `SerializeOptions.namespaces`).\n */\nexport interface NamespaceMeta {\n [prefix: string]: {\n /** Local-name → string-value map for attributes in this namespace. */\n attrs?: Record<string, string>;\n /**\n * Child elements in this namespace, keyed by local name. Each entry\n * is an array because a namespace can host multiple sibling elements\n * with the same tag (e.g. `<wd:layer/><wd:layer/>`).\n */\n elements?: Record<string, NamespacedElement[]>;\n };\n}\n\n/** Opaque structured representation of a namespaced element. */\nexport interface NamespacedElement {\n /** Attribute local-name → string-value. */\n attrs: Record<string, string>;\n /** Text content, when the element contains only text (no child elements). */\n text?: string;\n /** Nested namespaced children, keyed by local name (recursive). */\n children?: Record<string, NamespacedElement[]>;\n}\n\n/**\n * 2x3 affine matrix in SVG's `matrix(a b c d e f)` order, mapping\n * `[x', y'] = [a*x + c*y + e, b*x + d*y + f]`.\n *\n * The same order the kernel's affine tier uses, so this is that type under\n * the name the SVG spec gives it — not a parallel one. An `SvgGroupNode`'s\n * transform and a geom `Mat3` are interchangeable without a conversion.\n */\nexport type Matrix = Mat3;\n\n/** Re-exported so this package's own stroke widths are namable beside the\n * rest of the SVG model. It is core's type; there is no second one. */\nexport type { ScreenLength };\n\n/** Identity matrix — useful as a default in tests / constructors. */\nexport const IDENTITY_MATRIX: Matrix = identity();\n\n/**\n * FillStyle description in the SVG sense — either explicit `none`, a solid\n * color, or a reference to a weasel-native gradient `FillStyle`. Solid colors\n * are normalized to `#rrggbb` strings; opacity is carried separately so\n * `fill-opacity` and `stroke-opacity` round-trip cleanly.\n */\nexport type SvgPaint =\n | { kind: 'none' }\n | { kind: 'solid'; color: string; opacity?: number }\n | { kind: 'gradient'; paint: FillStyle };\n\n/** Stroke description: a paint plus structural line parameters. */\nexport interface SvgStroke {\n paint: SvgPaint;\n /** World units, or `{ px }` for a width that holds its rendered thickness\n * however the document is scaled — SVG's `vector-effect=\"non-scaling-stroke\"`.\n * Literally the kit's own unit, not a second spelling of it. */\n width: ScreenLength;\n opacity?: number;\n /** `stroke-linecap`. Default per SVG spec is `'butt'`. */\n cap?: 'butt' | 'round' | 'square';\n /** `stroke-linejoin`. Default per SVG spec is `'miter'`. SVG's `arcs` / `miter-clip` map to `'miter'` with a warning. */\n join?: 'miter' | 'round' | 'bevel';\n /** `stroke-dasharray` as a flat number array. Odd-length inputs are doubled per SVG spec. */\n dash?: number[];\n /**\n * `stroke-miterlimit`. SVG's default is 4. Weasel's renderer defaults to\n * 10 (Canvas2D) when unset, so parsed strokes without an explicit\n * attribute may render with longer miters than the source SVG intended.\n */\n miterLimit?: number;\n /** The kit stroke's `align`. SVG has no stroke alignment, so the serializer\n * writes the stroke centered and says so through `onWarn`; the parser\n * never sets it. */\n align?: StrokeAlign;\n /** `marker-start` / `marker-mid` / `marker-end`, as the bare `url(#id)` key. */\n markerStart?: string;\n markerMid?: string;\n markerEnd?: string;\n}\n\n/**\n * Leaf node: a path geometry plus fill/stroke. All other v1 shapes\n * (`<rect>`, `<ellipse>`, etc.) are lowered to this representation on\n * parse — `<rect>` uses weasel's `RectPath` fast-path subtype when\n * possible, everything else becomes a `PolygonPath`.\n */\nexport interface SvgPathNode {\n kind: 'path';\n path: Path;\n fill: SvgPaint;\n stroke?: SvgStroke;\n /** Element-level opacity (`opacity=\"...\"`), 0..1. */\n opacity?: number;\n /** Element-level rotation in **radians**, pivoting around the AABB\n * center of the underlying `path` geometry. Emitted as SVG\n * `transform=\"rotate(angleDegrees cx cy)\"`. */\n rotation?: number;\n /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */\n meta?: NamespaceMeta;\n}\n\n/**\n * Group node: an SVG `<g>`. On parse, `transform` is always omitted (any\n * `transform` attribute is collapsed onto descendants' geometry). On\n * serialize, a non-identity `transform` is emitted as\n * `matrix(a b c d e f)`.\n */\nexport interface SvgGroupNode {\n kind: 'group';\n children: SvgNode[];\n transform?: Matrix;\n /** Clips the group's contents. Serializes to a `<clipPath>` def plus\n * `clip-path=\"url(#id)\"`, and lives in the same space as `children` —\n * SVG applies the group's own `transform` to the clip as well.\n * A `<clipPath>` of more than one shape parses back as no clip: SVG\n * unions them and a `Path` holds one outline. */\n clip?: Path;\n opacity?: number;\n /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */\n meta?: NamespaceMeta;\n}\n\n/**\n * Text leaf node. Mirrors the kit's `TextPose` shape — a bounding box plus\n * text content, optional rich-text `runs` (per-range styling), and an\n * optional `TextStyle` for the node-wide defaults.\n *\n * Note on SVG text geometry: native `<text>` flows from a baseline; it\n * doesn't have width/height attributes. The serializer emits\n * `dominant-baseline=\"text-before-edge\"` so `y` is the top of the text\n * box, plus `data-weasel-width` / `data-weasel-height` so weasel's\n * explicit box dimensions round-trip losslessly. External SVG text\n * (lacking the data-* attrs) imports with the width the kit's text layout\n * measures — an em-based estimate when no registered font can — and\n * `height = fontSize * lineHeight * (lineCount || 1)`.\n *\n * `x` here is always the box's left edge. In the SVG it is the\n * `text-anchor` point, and the parser and serializer convert between them.\n */\nexport interface SvgTextNode {\n kind: 'text';\n x: number;\n y: number;\n width: number;\n height: number;\n /** Plain text. When `runs` is set, `runsToPlainText(runs)` must equal `text`. */\n text: string;\n /** Optional per-range styling — same shape as `TextPose.runs`. */\n runs?: StyledRun[];\n /** Node-wide typography. Defaults applied at render time via `resolveTextStyle`. */\n style?: TextStyle;\n /** Where the laid-out text sits inside the box — `kit:text`'s\n * `data.verticalAlign`. SVG text has no box to align in, so this rides in\n * `data-weasel-vertical-align` and other readers draw the text top-aligned. */\n verticalAlign?: TextVerticalAlign;\n /**\n * Node-wide glyph paint, the `FillStyle` / `Stroke` a kit text node holds\n * in `data.fill` / `data.stroke`. Not `SvgPaint`, which is the path\n * nodes' shape — a text paint reaches the renderer through the runs, and\n * `StyledRun.fill` / `.stroke` override these per range.\n *\n * `null` is SVG's `fill=\"none\"`: outline-only text, painted by its stroke\n * alone. Absent takes the default black.\n */\n fill?: FillStyle | null;\n stroke?: Stroke;\n /** Element-level opacity (`opacity=\"...\"`), 0..1. */\n opacity?: number;\n /** Element-level rotation in **radians**, pivoting around the unrotated\n * AABB center `(x + width/2, y + height/2)`. Emitted as SVG\n * `transform=\"rotate(angleDegrees cx cy)\"`. */\n rotation?: number;\n /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */\n meta?: NamespaceMeta;\n}\n\n/**\n * Raster-image leaf — an SVG `<image>`. `href` is the element's `href` (or\n * legacy `xlink:href`) verbatim: an external URL or a `data:` URI. The\n * package neither fetches nor decodes it, so an external URL round-trips as\n * a reference and only resolves when something downstream loads it.\n *\n * SVG's `preserveAspectRatio` is not modeled; the box is taken literally.\n *\n * With a `source` rect or a flip, the element is written as a `<g\n * data-weasel-image>` holding a nested `<svg>` viewport at the box, whose\n * `viewBox` is the source window over a unit-square `<image>` — plain SVG 1.1,\n * which any reader crops and mirrors the same way, and which `parseSvg` reads\n * back as one image node.\n */\nexport interface SvgImageNode {\n kind: 'image';\n href: string;\n x: number;\n y: number;\n width: number;\n height: number;\n /** The part of the bitmap drawn into the box, as fractions of the bitmap's\n * width and height from its top-left. Omitted draws the whole bitmap.\n * Fractions rather than bitmap pixels because this package never decodes\n * the image, so it cannot know its size. */\n source?: { x: number; y: number; width: number; height: number };\n /** Mirror the drawn region within the box, as `ImageDrawCommand` does. The\n * box does not move. */\n flipX?: boolean;\n flipY?: boolean;\n /** Element-level opacity (`opacity=\"...\"`), 0..1. */\n opacity?: number;\n /** Element-level rotation in **radians**, pivoting around the unrotated\n * AABB center `(x + width/2, y + height/2)`. Emitted as SVG\n * `transform=\"rotate(angleDegrees cx cy)\"`. */\n rotation?: number;\n /** Opaque per-element bag for declared namespaces. See `NamespaceMeta`. */\n meta?: NamespaceMeta;\n}\n\n/** Discriminated-union node — the leaf of the public tree. */\nexport type SvgNode = SvgPathNode | SvgGroupNode | SvgTextNode | SvgImageNode;\n\n/** Options for {@link parseSvg}. */\nexport interface ParseOptions {\n /**\n * Map of prefix → URI for XML namespaces the caller wants surfaced.\n * Attributes / child elements in any declared namespace are collected\n * into `SvgNode.meta` (per element) or `ParseResult.documentMeta` (root).\n * Undeclared namespaces are preserved in the DOM but not promoted into\n * the structured `meta` bag; they are silently dropped at serialize time.\n */\n namespaces?: Record<string, string>;\n}\n\n/** Output of {@link parseSvg}. */\nexport interface ParseResult {\n nodes: SvgNode[];\n /** Non-fatal notices (unsupported elements, unrecognized attributes). */\n warnings: string[];\n /**\n * Opaque per-document bag for declared namespaces. Holds root-level\n * namespaced attributes (`documentMeta.<prefix>.attrs`) and namespaced\n * root children (`documentMeta.<prefix>.elements`).\n */\n documentMeta?: NamespaceMeta;\n /** Root `viewBox` attribute, parsed from `\"x y width height\"`. */\n viewBox?: { x: number; y: number; width: number; height: number };\n /** Root `width` attribute, parsed as a unitless number when present. */\n width?: number;\n /** Root `height` attribute, parsed as a unitless number when present. */\n height?: number;\n /** Text content of the first `<title>` child of `<svg>`, when present. */\n title?: string;\n /**\n * An entry for each document `<marker>` a stroke references under a key the\n * marker registry does not know, keyed as the strokes in `nodes` now name\n * them. Nothing draws them until they are registered (`registerMarker`),\n * which `unpackSvgFiles` does.\n */\n markers?: MarkerEntry[];\n}\n\n/** Options for {@link serializeSvg}. */\nexport interface SerializeOptions {\n /**\n * Override the root `viewBox`. When omitted, the serializer computes\n * a tight bounding box from the supplied nodes.\n */\n viewBox?: { x: number; y: number; width: number; height: number };\n /**\n * Called for what the document cannot carry the way weasel draws it: a\n * paint SVG cannot express (a pattern carrying a `TextureHandle` instead of\n * a `TilePatternSpec`), a stroke aligned off its edge, text that wraps or\n * sits lower than the top of its box. Each message is said once per call.\n * Without this the loss is silent.\n */\n onWarn?: (message: string) => void;\n /** Emit `width=\"...\"` on the root `<svg>`. */\n width?: number;\n /** Emit `height=\"...\"` on the root `<svg>`. */\n height?: number;\n /**\n * Emit `<title>...</title>` as the first child of the root `<svg>`. The\n * value is XML-escaped on output. Empty strings are skipped.\n */\n title?: string;\n /**\n * Map of prefix → URI for XML namespaces to declare on the root\n * `<svg>`. The serializer reads `documentMeta[prefix]` and\n * `node.meta[prefix]` to write the actual attributes and elements.\n */\n namespaces?: Record<string, string>;\n /**\n * Opaque per-document namespaced extras. Each `<prefix>.attrs` becomes\n * `<prefix>:<name>=\"...\"` attributes on the root `<svg>`. Each\n * `<prefix>.elements[localName]` becomes `<prefix>:<localName>...>`\n * children placed immediately before any geometry.\n */\n documentMeta?: NamespaceMeta;\n /** Pretty-print with newlines + indentation. Default `false`. */\n pretty?: boolean;\n}\n","/**\n * SVG transform attribute helpers. Parses the four primitive transform\n * functions weasel-svg supports (`matrix`, `translate`, `scale`, `rotate`)\n * into a single 2x3 affine matrix, and exposes the point/path mappers we\n * need to collapse `transform=` onto leaf geometry at parse time.\n */\n\nimport { invert, multiply } from '@weasel-js/geom';\nimport type { Matrix } from './types';\nimport { IDENTITY_MATRIX } from './types';\n\n/** Compose two 2x3 affines, `a` then `b` applied to a column vector. The\n * kernel's own composition — `Matrix` is `Mat3`, so nothing converts. */\nexport { multiply };\n\n/** Apply a 2x3 affine to a 2D point. The `{x, y}` spelling the rest of this\n * package works in; geom's `applyToPoint` returns the same numbers as a\n * tuple. */\nexport function applyMatrix(m: Matrix, x: number, y: number): { x: number; y: number } {\n return { x: m[0] * x + m[2] * y + m[4], y: m[1] * x + m[3] * y + m[5] };\n}\n\n/** True if `m` is the identity within a small epsilon. */\nexport function isIdentity(m: Matrix, eps = 1e-9): boolean {\n return (\n Math.abs(m[0] - 1) < eps &&\n Math.abs(m[1]) < eps &&\n Math.abs(m[2]) < eps &&\n Math.abs(m[3] - 1) < eps &&\n Math.abs(m[4]) < eps &&\n Math.abs(m[5]) < eps\n );\n}\n\nconst NUM_RE = /[-+]?(?:\\d*\\.\\d+|\\d+\\.?)(?:[eE][-+]?\\d+)?/g;\n\nfunction readNumbers(s: string): number[] {\n const out: number[] = [];\n const matches = s.match(NUM_RE);\n if (!matches) return out;\n for (const m of matches) {\n const n = Number(m);\n if (Number.isFinite(n)) out.push(n);\n }\n return out;\n}\n\n/**\n * Parse an SVG `transform=\"...\"` string into a single 2x3 matrix.\n * Functions compose right-to-left in SVG's coordinate model: in\n * `transform=\"A B\"`, the rightmost function is applied first to a point's\n * local coordinates. We accumulate accordingly: `result = result * fn`.\n *\n * Unrecognized functions emit a warning via the optional callback and are\n * skipped (the rest of the transform list still applies).\n */\nexport function parseTransform(\n attr: string | null | undefined,\n onWarn?: (message: string) => void,\n): Matrix {\n if (!attr) return IDENTITY_MATRIX;\n let result: Matrix = IDENTITY_MATRIX;\n // Split into \"name(args)\" chunks.\n const fnRe = /([A-Za-z]+)\\s*\\(([^)]*)\\)/g;\n let match: RegExpExecArray | null;\n while ((match = fnRe.exec(attr)) !== null) {\n const name = match[1].toLowerCase();\n const nums = readNumbers(match[2]);\n let local: Matrix | null = null;\n if (name === 'matrix' && nums.length >= 6) {\n local = [nums[0], nums[1], nums[2], nums[3], nums[4], nums[5]];\n } else if (name === 'translate') {\n const tx = nums[0] ?? 0;\n const ty = nums[1] ?? 0;\n local = [1, 0, 0, 1, tx, ty];\n } else if (name === 'scale') {\n const sx = nums[0] ?? 1;\n const sy = nums.length >= 2 ? nums[1] : sx;\n local = [sx, 0, 0, sy, 0, 0];\n } else if (name === 'rotate') {\n const ang = ((nums[0] ?? 0) * Math.PI) / 180;\n const c = Math.cos(ang);\n const s = Math.sin(ang);\n const rot: Matrix = [c, s, -s, c, 0, 0];\n if (nums.length >= 3) {\n // rotate(angle, cx, cy) = translate(cx,cy) * rotate * translate(-cx,-cy)\n const cx = nums[1];\n const cy = nums[2];\n local = multiply(multiply([1, 0, 0, 1, cx, cy], rot), [1, 0, 0, 1, -cx, -cy]);\n } else {\n local = rot;\n }\n } else if (name === 'skewx' || name === 'skewy') {\n const ang = ((nums[0] ?? 0) * Math.PI) / 180;\n const t = Math.tan(ang);\n local = name === 'skewx' ? [1, 0, t, 1, 0, 0] : [1, t, 0, 1, 0, 0];\n } else {\n onWarn?.(`unsupported transform function: ${name}`);\n continue;\n }\n result = multiply(result, local);\n }\n return result;\n}\n\n/**\n * Re-express an element's own `transform` in the frame its inherited `ctm`\n * maps into: `ctm * local * ctm⁻¹`.\n *\n * A leaf's geometry is baked through `ctm` at parse time, so its own\n * transform has to move with it. Decomposing the raw local matrix against\n * bounds that have already been through `ctm` compares two different\n * coordinate spaces, and a rotation inside a translated `<g>` fails to\n * decompose for no reason but the offset.\n *\n * `null` when `@weasel-js/geom`'s `invert` finds `ctm` singular: the geometry\n * has collapsed through it, and the local transform has no frame to live in.\n */\nexport function rebaseTransform(ctm: Matrix, local: Matrix): Matrix | null {\n const inv = invert(ctm);\n if (!inv) return null;\n return multiply(multiply(ctm, local), inv);\n}\n\n/** Try to factor `m` as \"rotation by theta about (cx, cy)\". Returns the\n * angle in radians when `m` is (within `eps`) a pure rotation about the\n * given pivot. Returns `null` otherwise.\n *\n * Pure rotation about (cx, cy) has the matrix form:\n * [ cos -sin cx - cx*cos + cy*sin ]\n * [ sin cos cy - cx*sin - cy*cos ]\n * i.e. m[0] = m[3] = cos, m[1] = -m[2] = sin, with a translation that\n * equals the pivot's \"rotate-then-translate-back\" residue. We reconstruct\n * theta from atan2(m[1], m[0]) and verify the rest.\n */\nexport function decomposeRotation(\n m: Matrix,\n cx: number,\n cy: number,\n eps = 1e-4,\n): number | null {\n const [a, b, c, d, e, f] = m;\n // Pure rotation requires a == d and b == -c.\n if (Math.abs(a - d) > eps) return null;\n if (Math.abs(b + c) > eps) return null;\n // Determinant must be 1 (no scale, no flip).\n const det = a * d - b * c;\n if (Math.abs(det - 1) > eps) return null;\n const theta = Math.atan2(b, a);\n // Verify translation = (cx - cx*cos + cy*sin, cy - cx*sin - cy*cos).\n const expectedE = cx - cx * a + cy * b;\n const expectedF = cy - cx * b - cy * a;\n if (Math.abs(e - expectedE) > eps) return null;\n if (Math.abs(f - expectedF) > eps) return null;\n return theta;\n}\n\n/** Best-effort rotational-component extraction for a general matrix (any\n * scale + rotation, ignoring translation). Used for parse-time warnings\n * on un-decomposable matrices: we can detect \"there is a rotation here\"\n * even if we won't preserve it as `node.rotation`. For a non-uniform\n * matrix the \"rotation\" is ambiguous; we report atan2(b, a) which\n * corresponds to where the +x basis vector points.\n */\nexport function rotationComponent(m: Matrix): number {\n return Math.atan2(m[1], m[0]);\n}\n\n/**\n * Format a matrix as an SVG `matrix(a b c d e f)` value. Returns `null`\n * when `m` is (effectively) the identity, so the caller can omit the\n * attribute entirely.\n */\nexport function formatMatrix(m: Matrix): string | null {\n if (isIdentity(m)) return null;\n return `matrix(${m.map((n) => trimNumber(n)).join(' ')})`;\n}\n\n/** Trim trailing zeros from a numeric value for compact SVG output. */\nexport function trimNumber(n: number): string {\n if (!Number.isFinite(n)) return '0';\n // Round to ~6 decimal places to avoid floating-point cruft.\n const r = Math.round(n * 1e6) / 1e6;\n if (Number.isInteger(r)) return String(r);\n return String(r);\n}\n","import { resolveAlign, type TextStyle } from '@weasel-js/core';\n\n/**\n * Distance from a text box's left edge to its SVG anchor point: `x` on a\n * `<text>` is where `text-anchor` lands, which is the box's left edge, center\n * or right edge once `align` and `direction` resolve to an absolute edge.\n */\nexport function anchorOffset(style: TextStyle | undefined, width: number): number {\n const edge = resolveAlign(style?.align ?? 'left', style?.direction ?? 'ltr');\n return edge === 'center' ? width / 2 : edge === 'right' ? width : 0;\n}\n","/**\n * Map between SVG `<pattern>` elements and weasel's `pattern` `FillStyle`.\n * The counterpart to `gradients.ts` for the other paint-server kind.\n *\n * The tile's shapes come from `tileGeometry` in core, so the vector form a\n * viewer sees is generated from the same description that rasterizes the GL\n * texture. Alongside them we write the spec itself onto a `data-weasel-tile`\n * attribute: any SVG consumer renders the shapes, and weasel reads the\n * attribute back to recover the exact spec rather than reverse-engineering\n * it from geometry.\n *\n * A pattern whose payload is a `TextureHandle` has no vector form — the\n * handle is a session-scoped registry key with no tile description behind\n * it — and exports as nothing, with a warning. Same treatment conic\n * gradients get.\n */\n\nimport { tileGeometry, type TileShape } from '@weasel-js/core/patterns-builtin';\nimport type { FillStyle, TilePatternSpec } from '@weasel-js/core';\nimport { collectElementsByTag } from './elements';\nimport { trimNumber } from './transform';\n\ntype PatternFill = Extract<FillStyle, { fill: 'pattern' }>;\n\n/** Collected pattern definitions, keyed by element id. */\nexport type PatternTable = Map<string, FillStyle>;\n\n/** Whether a pattern paint carries a serializable spec. */\nexport function patternSpecOf(paint: PatternFill): TilePatternSpec | null {\n return 'tile' in paint.pattern ? paint.pattern : null;\n}\n\nexport function patternXml(id: string, paint: PatternFill, onWarn?: (m: string) => void): string {\n const spec = patternSpecOf(paint);\n if (!spec) {\n onWarn?.('pattern fill carries a TextureHandle, which has no vector form — omitted from <defs>');\n return '';\n }\n const geometry = tileGeometry(spec);\n const body = geometry.shapes.map(shapeXml).join('');\n const origin = paint.origin ?? { x: 0, y: 0 };\n const attrs = [\n `id=\"${id}\"`,\n 'patternUnits=\"userSpaceOnUse\"',\n `width=\"${trimNumber(geometry.size)}\"`,\n `height=\"${trimNumber(geometry.size)}\"`,\n ];\n if (origin.x !== 0 || origin.y !== 0) {\n attrs.push(`x=\"${trimNumber(origin.x)}\"`, `y=\"${trimNumber(origin.y)}\"`);\n }\n attrs.push(`data-weasel-tile=\"${escapeAttr(JSON.stringify(spec))}\"`);\n return `<pattern ${attrs.join(' ')}>${body}</pattern>`;\n}\n\n/**\n * A single tile as a standalone `<svg>` document, sized to its own extent.\n * For UI that needs to show a tile outside a document — a picker swatch,\n * set as a repeating CSS `background-image` via a data URI. Shares the shape\n * mapper with `patternXml`, so a preview can't drift from what paints.\n */\nexport function tilePreviewSvg(spec: TilePatternSpec, background?: string): string {\n const geometry = tileGeometry(spec);\n const s = trimNumber(geometry.size);\n const bg = background\n ? `<rect width=\"${s}\" height=\"${s}\" fill=\"${background}\"/>`\n : '';\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${s}\" height=\"${s}\" `\n + `viewBox=\"0 0 ${s} ${s}\">${bg}${geometry.shapes.map(shapeXml).join('')}</svg>`;\n}\n\n/** `tilePreviewSvg` packed as a `url(...)` value for CSS `background-image`. */\nexport function tilePreviewCssUrl(spec: TilePatternSpec, background?: string): string {\n return `url(\"data:image/svg+xml,${encodeURIComponent(tilePreviewSvg(spec, background))}\")`;\n}\n\nfunction shapeXml(shape: TileShape): string {\n switch (shape.kind) {\n case 'line':\n return `<line x1=\"${trimNumber(shape.x1)}\" y1=\"${trimNumber(shape.y1)}\" `\n + `x2=\"${trimNumber(shape.x2)}\" y2=\"${trimNumber(shape.y2)}\" `\n + `stroke=\"${shape.color}\" stroke-width=\"${trimNumber(shape.width)}\"/>`;\n case 'circle':\n return `<circle cx=\"${trimNumber(shape.cx)}\" cy=\"${trimNumber(shape.cy)}\" `\n + `r=\"${trimNumber(shape.r)}\" fill=\"${shape.color}\"/>`;\n case 'ellipse': {\n const deg = (shape.rotation * 180) / Math.PI;\n const transform = deg === 0\n ? ''\n : ` transform=\"rotate(${trimNumber(deg)} ${trimNumber(shape.cx)} ${trimNumber(shape.cy)})\"`;\n return `<ellipse cx=\"${trimNumber(shape.cx)}\" cy=\"${trimNumber(shape.cy)}\" `\n + `rx=\"${trimNumber(shape.rx)}\" ry=\"${trimNumber(shape.ry)}\" `\n + `fill=\"${shape.color}\"${transform}/>`;\n }\n case 'rect':\n return `<rect x=\"${trimNumber(shape.x)}\" y=\"${trimNumber(shape.y)}\" `\n + `width=\"${trimNumber(shape.width)}\" height=\"${trimNumber(shape.height)}\" `\n + `fill=\"${shape.color}\"/>`;\n default:\n return '';\n }\n}\n\n/** Read every `<pattern>` in the document back into pattern paints. */\nexport function collectPatterns(svg: Element, onWarn?: (m: string) => void): PatternTable {\n const out: PatternTable = new Map();\n for (const [id, el] of collectElementsByTag(svg, PATTERN_TAGS)) {\n const paint = readPattern(el, onWarn);\n if (paint) out.set(id, paint);\n }\n return out;\n}\n\nconst PATTERN_TAGS = new Set(['pattern']);\n\nfunction readPattern(el: Element, onWarn?: (m: string) => void): FillStyle | null {\n const raw = el.getAttribute('data-weasel-tile');\n if (!raw) {\n // A hand-authored pattern (Illustrator, Inkscape) holds arbitrary\n // geometry no `TilePatternSpec` can express. Recognizing it would mean\n // reverse-engineering a tile from its children; dropping it with a\n // warning is honest, and the element survives in the source file.\n onWarn?.(`<pattern id=\"${el.getAttribute('id')}\"> has no data-weasel-tile — unsupported pattern, dropped`);\n return null;\n }\n let spec: TilePatternSpec;\n try {\n spec = JSON.parse(raw) as TilePatternSpec;\n } catch {\n onWarn?.(`<pattern id=\"${el.getAttribute('id')}\"> has malformed data-weasel-tile — dropped`);\n return null;\n }\n if (typeof spec?.tile !== 'string' || typeof spec?.color !== 'string') {\n onWarn?.(`<pattern id=\"${el.getAttribute('id')}\"> data-weasel-tile is not a tile spec — dropped`);\n return null;\n }\n const x = parseFloat(el.getAttribute('x') ?? '0');\n const y = parseFloat(el.getAttribute('y') ?? '0');\n const paint: PatternFill = { fill: 'pattern', pattern: spec };\n if (x !== 0 || y !== 0) paint.origin = { x, y };\n return paint;\n}\n\nfunction escapeAttr(s: string): string {\n return s\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;');\n}\n","/**\n * Serialize a weasel `Path` to an SVG `d=` attribute string. `RectPath`\n * lowers to `M h v h Z`; `PolygonPath` walks the (commands, coords)\n * arrays, emitting one SVG command per kit command.\n *\n * Output uses absolute commands only and a small amount of whitespace\n * compression (no leading zeros stripped beyond what `Number.toString`\n * already does). Numbers are rounded to ~6 decimals via `trimNumber`.\n */\n\nimport {\n PATH_C, PATH_L, PATH_M, PATH_Q, PATH_Z,\n type Path,\n} from '@weasel-js/core';\nimport { trimNumber } from './transform';\n\n/** Serialize a weasel `Path` to an SVG `d=` attribute string. */\nexport function serializePathD(path: Path): string {\n if (path.kind === 'rect') {\n const { x, y, width, height } = path;\n return `M${trimNumber(x)} ${trimNumber(y)}h${trimNumber(width)}v${trimNumber(height)}h${trimNumber(-width)}Z`;\n }\n const cmds = path.commands;\n const xs = path.coords;\n const out: string[] = [];\n let ci = 0;\n for (let i = 0; i < cmds.length; i++) {\n const c = cmds[i];\n if (c === PATH_M) {\n out.push(`M${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])}`);\n ci += 2;\n } else if (c === PATH_L) {\n out.push(`L${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])}`);\n ci += 2;\n } else if (c === PATH_C) {\n out.push(\n `C${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])} ` +\n `${trimNumber(xs[ci + 2])} ${trimNumber(xs[ci + 3])} ` +\n `${trimNumber(xs[ci + 4])} ${trimNumber(xs[ci + 5])}`,\n );\n ci += 6;\n } else if (c === PATH_Q) {\n out.push(\n `Q${trimNumber(xs[ci])} ${trimNumber(xs[ci + 1])} ` +\n `${trimNumber(xs[ci + 2])} ${trimNumber(xs[ci + 3])}`,\n );\n ci += 4;\n } else if (c === PATH_Z) {\n out.push('Z');\n }\n }\n return out.join('');\n}\n","/**\n * Map between SVG `<linearGradient>` / `<radialGradient>` elements and\n * weasel's `FillStyle` gradient variants. Definitions are indexed by id\n * wherever in the document they appear, and looked up when a `fill` /\n * `stroke` attribute references one as `url(#id)`. On serialize, we\n * emit a fresh `<defs>` block with stable generated ids.\n */\n\nimport { getPaintKind, getMarker } from '@weasel-js/core';\nimport type { FillStyle, GradStop, GradientUnits, MarkerEntry, MarkerPaint, Path } from '@weasel-js/core';\nimport { ownProp } from './cascade';\nimport { parsePaintAttr } from './color';\nimport { trimNumber } from './transform';\nimport { patternXml } from './patterns';\nimport { collectElementsByTag, type ElementTable } from './elements';\nimport { serializePathD } from './path-serializer';\n\n/** Collected gradient definitions, keyed by element id. */\nexport type GradientTable = Map<string, FillStyle>;\n\n/**\n * The namespace weasel's own paint servers are written in, and the prefix they\n * are written under. A conic gradient has no SVG element to target — SVG has\n * `linearGradient` and `radialGradient` and nothing else — so it goes out as a\n * foreign-namespaced def that this package reads back and every other renderer\n * skips in favor of the paint fallback color beside the reference.\n *\n * A registered paint kind's own `toSvg` may use this prefix too: the root\n * declares it whenever any paint in the document lacks a native SVG form.\n */\nexport const WEASEL_NS = 'urn:weasel-js:svg';\nexport const WEASEL_NS_PREFIX = 'wzl';\n\n/** `true` when SVG has a paint server for this kind, so the reference needs no\n * fallback color and the root needs no foreign namespace. */\nfunction hasNativeSvgForm(paint: FillStyle): boolean {\n const kind = paint.fill ?? 'solid';\n return kind === 'solid' || kind === 'linear-gradient' || kind === 'radial-gradient' || kind === 'pattern';\n}\n\n/**\n * The spaces `interpolate` can name, as SVG spells them. SVG's own\n * `color-interpolation` carries `sRGB` and `linearRGB` only, so anything\n * perceptual goes out as a namespaced attribute a foreign renderer ignores —\n * which leaves it interpolating in sRGB. That is a shifted midpoint rather\n * than a lost paint, so these gradients keep their native element and take no\n * fallback color.\n */\nconst INTERPOLATE_SPACES = new Set(['rgb', 'oklab', 'oklch']);\n\n/** The `wzl:interpolate` attribute a gradient needs, or `''` for the sRGB\n * default every other renderer already assumes. */\nfunction interpolateAttr(space: string | undefined): string {\n if (!space || space === 'rgb') return '';\n return ` ${WEASEL_NS_PREFIX}:interpolate=\"${space}\"`;\n}\n\n/** `interpolate` off a gradient element, or `undefined` — for the field's\n * absence and for a space this package does not model alike. */\nfunction readInterpolate(el: Element, elements: ElementTable): 'oklab' | 'oklch' | undefined {\n const raw = inheritedAttr(el, elements, `${WEASEL_NS_PREFIX}:interpolate`)\n ?? el.getAttributeNS(WEASEL_NS, 'interpolate');\n if (raw === 'oklab' || raw === 'oklch') return raw;\n return undefined;\n}\n\n/** Whether any gradient in the document names a space SVG cannot, so the root\n * has to declare the namespace the attribute is written in. */\nfunction usesInterpolateAttr(paint: FillStyle): boolean {\n const space = (paint as { interpolate?: string }).interpolate;\n return space != null && space !== 'rgb' && INTERPOLATE_SPACES.has(space);\n}\n\n/** The local name of a tag, prefix stripped. */\nfunction localName(tag: string): string {\n const i = tag.indexOf(':');\n return (i < 0 ? tag : tag.slice(i + 1)).toLowerCase();\n}\n\nconst GRADIENT_TAGS = new Set([\n 'lineargradient', 'radialgradient', 'conicgradient', `${WEASEL_NS_PREFIX}:conicgradient`,\n 'meshgradient', `${WEASEL_NS_PREFIX}:meshgradient`,\n]);\n\nconst XLINK_NS = 'http://www.w3.org/1999/xlink';\n\n/** Read every gradient definition in the document, keyed by element id. */\nexport function collectGradients(svg: Element, onWarn?: (m: string) => void): GradientTable {\n const out: GradientTable = new Map();\n const elements = collectElementsByTag(svg, GRADIENT_TAGS);\n for (const [id, el] of elements) {\n const tag = localName(el.tagName);\n const paint = tag === 'lineargradient'\n ? readLinearGradient(el, elements, onWarn)\n : tag === 'conicgradient'\n ? readConicGradient(el, elements, onWarn)\n : tag === 'meshgradient'\n ? readMeshGradient(el, onWarn)\n : readRadialGradient(el, elements, onWarn);\n if (paint) out.set(id, paint);\n }\n warnUnsupportedDefsChildren(svg, onWarn);\n return out;\n}\n\n/** Paint servers, `<marker>`, `<clipPath>` and `<style>` aside, a `<defs>` child is\n * something this package does not model (a `<use>` template, a `<filter>`).\n * Say so once here. */\nfunction warnUnsupportedDefsChildren(svg: Element, onWarn?: (m: string) => void): void {\n if (!onWarn) return;\n const defs = svg.getElementsByTagName('defs');\n for (let d = 0; d < defs.length; d++) {\n const root = defs[d];\n for (let i = 0; i < root.children.length; i++) {\n const child = root.children[i];\n const tag = child.tagName.toLowerCase();\n if (GRADIENT_TAGS.has(tag) || GRADIENT_TAGS.has(localName(tag))) continue;\n if (tag === 'pattern' || tag === 'marker' || tag === 'clippath' || tag === 'style') continue;\n onWarn(`unsupported <defs> child: <${child.tagName}>`);\n }\n }\n}\n\n/**\n * The gradient a `href` / `xlink:href` attribute points at, or null. SVG lets\n * one gradient inherit another's stops and attributes this way, and authoring\n * tools lean on it heavily — a chain that isn't followed resolves to a\n * gradient with no stops, which paints nothing.\n */\nfunction hrefTarget(el: Element, elements: ElementTable): Element | null {\n const raw = el.getAttribute('href')\n ?? el.getAttributeNS(XLINK_NS, 'href')\n ?? el.getAttribute('xlink:href');\n if (!raw || !raw.startsWith('#')) return null;\n return elements.get(raw.slice(1)) ?? null;\n}\n\n/** An attribute's value on `el` or, when absent, on the gradient it inherits\n * from. `seen` breaks a reference cycle. */\nfunction inheritedAttr(\n el: Element, elements: ElementTable, name: string, seen: Set<Element> = new Set(),\n): string | null {\n if (el.hasAttribute(name)) return el.getAttribute(name);\n seen.add(el);\n const ref = hrefTarget(el, elements);\n if (!ref || seen.has(ref)) return null;\n return inheritedAttr(ref, elements, name, seen);\n}\n\n/** `el`'s own stops or, when it declares none, the stops it inherits. */\nfunction inheritedStops(\n el: Element, elements: ElementTable, onWarn?: (m: string) => void,\n seen: Set<Element> = new Set(),\n): GradStop[] {\n const own = readStops(el, onWarn);\n if (own.length > 0) return own;\n seen.add(el);\n const ref = hrefTarget(el, elements);\n if (!ref || seen.has(ref)) return own;\n return inheritedStops(ref, elements, onWarn, seen);\n}\n\n/** Parse a `stop-opacity` / offset value that may carry a `%` suffix. */\nfunction parseRatio(raw: string): number {\n const n = parseFloat(raw);\n if (!Number.isFinite(n)) return NaN;\n return raw.trimEnd().endsWith('%') ? n / 100 : n;\n}\n\nfunction readStops(el: Element, onWarn?: (m: string) => void): GradStop[] {\n const stops: GradStop[] = [];\n for (let i = 0; i < el.children.length; i++) {\n const c = el.children[i];\n if (c.tagName.toLowerCase() !== 'stop') continue;\n const offsetRaw = parseRatio(c.getAttribute('offset') ?? '0');\n const offset = Number.isFinite(offsetRaw) ? offsetRaw : 0;\n const colorAttr = ownProp(c, 'stop-color') ?? '#000000';\n const parsed = parsePaintAttr(colorAttr);\n if (parsed && parsed.kind === 'solid') {\n const opacityAttr = ownProp(c, 'stop-opacity');\n const own = opacityAttr != null ? parseRatio(opacityAttr) : NaN;\n const alpha = Number.isFinite(own) ? own : parsed.alpha;\n stops.push({ offset, color: alpha < 1 ? applyAlpha(parsed.color, alpha) : parsed.color });\n } else {\n onWarn?.(`gradient stop has unrecognized stop-color: ${colorAttr}`);\n stops.push({ offset, color: '#000000' });\n }\n }\n return stops;\n}\n\nfunction applyAlpha(hex: string, alpha: number): string {\n // Pack alpha into an 8-digit hex so it round-trips through weasel's\n // string-color storage. This is non-standard CSS hex but parses cleanly\n // back via our color.ts parser.\n const a = Math.max(0, Math.min(255, Math.round(alpha * 255)));\n return `${hex}${a.toString(16).padStart(2, '0')}`;\n}\n\n/** SVG `gradientUnits` → the kit's `GradientUnits`. SVG's default is\n * `objectBoundingBox`, which is what the attribute defaults above assume\n * (`x2=\"1\"`, `r=\"0.5\"`), so the two have to be read together. */\nfunction readGradientUnits(el: Element, elements: ElementTable): 'bounds' | 'world' {\n return inheritedAttr(el, elements, 'gradientUnits') === 'userSpaceOnUse' ? 'world' : 'bounds';\n}\n\n/** `gradientTransform` has no slot in the kit's gradient model, so a gradient\n * carrying one paints in the wrong place rather than not at all. */\nfunction warnGradientTransform(\n el: Element, elements: ElementTable, onWarn?: (m: string) => void,\n): void {\n const t = inheritedAttr(el, elements, 'gradientTransform');\n if (t != null && t.trim() !== '') {\n onWarn?.(`gradientTransform=\"${t}\" is not modeled; the gradient paints untransformed`);\n }\n}\n\nfunction num(raw: string | null, fallback: number): number {\n if (raw == null) return fallback;\n const n = parseRatio(raw);\n return Number.isFinite(n) ? n : fallback;\n}\n\nfunction readLinearGradient(\n el: Element, elements: ElementTable, onWarn?: (m: string) => void,\n): FillStyle | null {\n warnGradientTransform(el, elements, onWarn);\n return {\n fill: 'linear-gradient',\n from: {\n x: num(inheritedAttr(el, elements, 'x1'), 0),\n y: num(inheritedAttr(el, elements, 'y1'), 0),\n },\n to: {\n x: num(inheritedAttr(el, elements, 'x2'), 1),\n y: num(inheritedAttr(el, elements, 'y2'), 0),\n },\n stops: inheritedStops(el, elements, onWarn),\n units: readGradientUnits(el, elements),\n interpolate: readInterpolate(el, elements),\n };\n}\n\nfunction readRadialGradient(\n el: Element, elements: ElementTable, onWarn?: (m: string) => void,\n): FillStyle | null {\n warnGradientTransform(el, elements, onWarn);\n return {\n fill: 'radial-gradient',\n center: {\n x: num(inheritedAttr(el, elements, 'cx'), 0.5),\n y: num(inheritedAttr(el, elements, 'cy'), 0.5),\n },\n radius: num(inheritedAttr(el, elements, 'r'), 0.5),\n stops: inheritedStops(el, elements, onWarn),\n units: readGradientUnits(el, elements),\n interpolate: readInterpolate(el, elements),\n };\n}\n\nfunction readConicGradient(\n el: Element, elements: ElementTable, onWarn?: (m: string) => void,\n): FillStyle | null {\n warnGradientTransform(el, elements, onWarn);\n return {\n fill: 'conic-gradient',\n center: {\n x: num(inheritedAttr(el, elements, 'cx'), 0.5),\n y: num(inheritedAttr(el, elements, 'cy'), 0.5),\n },\n angle: num(inheritedAttr(el, elements, 'angle'), 0),\n stops: inheritedStops(el, elements, onWarn),\n units: readGradientUnits(el, elements),\n interpolate: readInterpolate(el, elements),\n };\n}\n\n/**\n * A `<wzl:meshGradient>` back into the `mesh-gradient` paint core registers.\n *\n * Every patch carries all twelve (or sixteen) of its points, so nothing here\n * infers a shared edge — the trap that makes SVG's own abandoned\n * `<meshgradient>` hard to read correctly. A patch whose attributes do not\n * parse is dropped with a warning rather than guessed at: a mesh missing a\n * patch is visibly wrong, where a mesh holding an invented one is not.\n */\nfunction readMeshGradient(el: Element, onWarn?: (m: string) => void): FillStyle | null {\n const patches: { points: { x: number; y: number }[]; colors: string[] }[] = [];\n for (let i = 0; i < el.children.length; i++) {\n const child = el.children[i];\n if (localName(child.tagName) !== 'patch') continue;\n const points = (child.getAttribute('points') ?? '').trim().split(/\\s+/)\n .filter(Boolean)\n .map((pair) => {\n const [x, y] = pair.split(',').map(Number);\n return { x, y };\n });\n const colors = (child.getAttribute('colors') ?? '').trim().split(/\\s+/).filter(Boolean);\n const sane = (points.length === 12 || points.length === 16)\n && points.every((p) => Number.isFinite(p.x) && Number.isFinite(p.y))\n && colors.length === 4;\n if (!sane) {\n onWarn?.(`<${WEASEL_NS_PREFIX}:patch> with ${points.length} points and ${colors.length} colors — dropped`);\n continue;\n }\n patches.push({ points, colors });\n }\n if (patches.length === 0) return null;\n const space = el.getAttribute('interpolate') ?? el.getAttributeNS(WEASEL_NS, 'interpolate');\n return {\n fill: 'mesh-gradient',\n patches,\n units: el.getAttribute('gradientUnits') === 'objectBoundingBox' ? 'bounds' : 'world',\n ...(space === 'oklab' || space === 'oklch' ? { interpolate: space } : {}),\n } as unknown as FillStyle;\n}\n\n/**\n * Pre-pass that assigns stable serialization ids to the paint servers —\n * gradients and patterns — used by any leaf in the tree. We key on object\n * identity so two leaves sharing the exact same `FillStyle` reference reuse\n * one `<defs>` entry; structurally equal but distinct objects get separate\n * ids.\n */\nexport class PaintServerRegistry {\n private byPaint = new Map<FillStyle, string>();\n private order: FillStyle[] = [];\n private counter = 0;\n\n // Marker keys referenced by any stroke, in first-use order. The `<defs>`\n // id is the marker key itself, not a minted counter id: `parseSvg` reads a\n // `marker-end=\"url(#id)\"` fragment back as the marker key directly when the\n // registry knows it, so a synthetic id would come back as a stranger.\n private markerKeys: string[] = [];\n private markerKeySet = new Set<string>();\n\n // Clip paths, in first-use order. Identity, not value: two groups clipped by\n // equal outlines get a def each, which costs bytes and misleads nobody.\n private clips: Path[] = [];\n private clipIds = new Map<Path, string>();\n\n register(paint: FillStyle): string {\n const existing = this.byPaint.get(paint);\n if (existing) return existing;\n const id = paint.fill === 'pattern' ? `pat${this.counter++}` : `grad${this.counter++}`;\n this.byPaint.set(paint, id);\n this.order.push(paint);\n return id;\n }\n\n /**\n * The `fill` / `stroke` attribute value referencing this paint server: a\n * `url(#id)` reference, plus the fallback paint SVG's own grammar allows\n * after one for any kind SVG cannot express. A renderer that cannot resolve\n * the reference takes the fallback instead of dropping the fill, which is\n * the difference between a flat shape and a vanished one.\n */\n ref(paint: FillStyle): string {\n const id = this.register(paint);\n if (hasNativeSvgForm(paint)) return `url(#${id})`;\n return `url(#${id}) ${paintFallback(paint)}`;\n }\n\n /** Whether any registered paint serializes outside SVG's own vocabulary, so\n * the root has to declare {@link WEASEL_NS}. */\n usesPrivateNamespace(): boolean {\n return this.order.some((paint) => !hasNativeSvgForm(paint) || usesInterpolateAttr(paint));\n }\n\n /** The `<defs>` id for a marker key — the key itself, minting nothing.\n * `undefined` when nothing is registered under `key`, so a caller emits no\n * attribute at all rather than a `url(#…)` pointing at a def that will\n * never be written. */\n markerId(key: string): string | undefined {\n if (getMarker(key) === undefined) return undefined;\n if (!this.markerKeySet.has(key)) {\n this.markerKeySet.add(key);\n this.markerKeys.push(key);\n }\n return key;\n }\n\n /** Mint (or recall) the `<defs>` id for a clip outline. */\n clipId(path: Path): string {\n const existing = this.clipIds.get(path);\n if (existing) return existing;\n const id = `clip${this.clips.length}`;\n this.clipIds.set(path, id);\n this.clips.push(path);\n return id;\n }\n\n /** Emit `<defs>...</defs>` XML for every registered paint server, marker\n * and clip path. */\n toDefsXml(onWarn?: (m: string) => void): string {\n if (this.order.length === 0 && this.markerKeys.length === 0 && this.clips.length === 0) {\n return '';\n }\n const parts: string[] = ['<defs>'];\n for (const paint of this.order) {\n parts.push(paintServerXml(this.byPaint.get(paint)!, paint, onWarn));\n }\n for (const key of this.markerKeys) {\n const entry = getMarker(key);\n if (!entry) continue;\n parts.push(entry.toSvg ? entry.toSvg(key, entry) : defaultMarkerXml(key, entry, onWarn));\n }\n for (const path of this.clips) {\n parts.push(\n `<clipPath id=\"${this.clipIds.get(path)!}\">`\n + `<path d=\"${serializePathD(path)}\"/>`\n + '</clipPath>',\n );\n }\n parts.push('</defs>');\n return parts.join('');\n }\n}\n\n/** The `<marker>` def for an entry with no `toSvg` of its own. */\nfunction defaultMarkerXml(id: string, entry: MarkerEntry, onWarn?: (m: string) => void): string {\n const path = entry.path({ size: 1, stroke: { paint: { fill: 'solid', color: '#000' } } });\n const d = serializePathD(path);\n const fill = markerPaintAttrs('fill', entry.fill, id, onWarn);\n const outline = entry.outline\n ? ` ${markerPaintAttrs('stroke', entry.outline.paint, id, onWarn)} stroke-width=\"${trimNumber(entry.outline.width)}\"`\n + ' stroke-linecap=\"round\" stroke-linejoin=\"round\"'\n : '';\n // The kit turns every start marker around, which is what SVG 2 spells\n // `auto-start-reverse`; plain `auto` would point a start head into the line.\n const orient = typeof entry.orient === 'number'\n ? trimNumber((entry.orient * 180) / Math.PI)\n : 'auto-start-reverse';\n // `overflow=\"visible\"` overrides the UA default of `hidden`, which would\n // otherwise clip the arrowhead to the marker's viewport.\n return (\n `<marker id=\"${id}\" markerUnits=\"strokeWidth\" markerWidth=\"8\" markerHeight=\"8\"` +\n ` refX=\"0\" refY=\"0\" orient=\"${orient}\" overflow=\"visible\">` +\n `<path d=\"${d}\" ${fill}${outline}/></marker>`\n );\n}\n\n/** A marker paint as `fill` / `stroke` attributes. `'line'` is SVG 2's\n * `context-stroke`; a paint server has no `<defs>` slot from here, so it\n * falls back to the line's paint and says so. */\nfunction markerPaintAttrs(\n attr: 'fill' | 'stroke',\n paint: MarkerPaint | undefined,\n id: string,\n onWarn?: (m: string) => void,\n): string {\n if (paint === 'none') return `${attr}=\"none\"`;\n if (paint === undefined || paint === 'line') return `${attr}=\"context-stroke\"`;\n if ('color' in paint && (paint.fill === undefined || paint.fill === 'solid')) {\n return paint.opacity != null && paint.opacity !== 1\n ? `${attr}=\"${paint.color}\" ${attr}-opacity=\"${trimNumber(paint.opacity)}\"`\n : `${attr}=\"${paint.color}\"`;\n }\n onWarn?.(`marker \"${id}\" ${attr} is a paint server, which a <marker> def cannot reference here; written as the line's paint`);\n return `${attr}=\"context-stroke\"`;\n}\n\n/** One paint server's `<defs>` entry: the built-in mapping, else the kind's\n * own `toSvg`, else nothing plus a warning. The referencing element already\n * carries `fill=\"url(#id)\"`, so a silent omission is a dangling reference and\n * the shape vanishes in a viewer. */\nfunction paintServerXml(id: string, paint: FillStyle, onWarn?: (m: string) => void): string {\n if (paint.fill === 'pattern') return patternXml(id, paint, onWarn);\n const builtin = gradientXml(id, paint);\n if (builtin) return builtin;\n const custom = getPaintKind(paint.fill)?.toSvg?.(id, paint);\n if (custom) return custom;\n onWarn?.(`${paint.fill} fill has no vector form — omitted from <defs>`);\n return '';\n}\n\n/** `GradientUnits` → SVG `gradientUnits`. `'screen'` (the kit's default, and\n * a viewport-fixed wash) has no SVG analog at all; it lowers to user space,\n * which at least puts the paint somewhere the geometry is. */\nfunction gradientUnitsAttr(units: GradientUnits | undefined): string {\n return units === 'bounds' ? 'objectBoundingBox' : 'userSpaceOnUse';\n}\n\nfunction gradientXml(id: string, paint: FillStyle): string {\n if (paint.fill === 'linear-gradient') {\n const stops = paint.stops.map(stopXml).join('');\n return (\n `<linearGradient id=\"${id}\" gradientUnits=\"${gradientUnitsAttr(paint.units)}\" ` +\n `x1=\"${trimNumber(paint.from.x)}\" y1=\"${trimNumber(paint.from.y)}\" ` +\n `x2=\"${trimNumber(paint.to.x)}\" y2=\"${trimNumber(paint.to.y)}\"` +\n `${interpolateAttr(paint.interpolate)}>${stops}</linearGradient>`\n );\n }\n if (paint.fill === 'conic-gradient') {\n const stops = paint.stops.map(stopXml).join('');\n const P = WEASEL_NS_PREFIX;\n return (\n `<${P}:conicGradient id=\"${id}\" gradientUnits=\"${gradientUnitsAttr(paint.units)}\" ` +\n `cx=\"${trimNumber(paint.center.x)}\" cy=\"${trimNumber(paint.center.y)}\" ` +\n `angle=\"${trimNumber(paint.angle)}\"` +\n `${interpolateAttr(paint.interpolate)}>${stops}</${P}:conicGradient>`\n );\n }\n if (paint.fill === 'radial-gradient') {\n const stops = paint.stops.map(stopXml).join('');\n return (\n `<radialGradient id=\"${id}\" gradientUnits=\"${gradientUnitsAttr(paint.units)}\" ` +\n `cx=\"${trimNumber(paint.center.x)}\" cy=\"${trimNumber(paint.center.y)}\" ` +\n `r=\"${trimNumber(paint.radius)}\"` +\n `${interpolateAttr(paint.interpolate)}>${stops}</radialGradient>`\n );\n }\n return '';\n}\n\n/**\n * The color a renderer that cannot resolve the reference should paint. `none`\n * when the paint has no single color to name — nothing painted is at least\n * honest, where an invented black is not.\n */\nfunction paintFallback(paint: FillStyle): string {\n const color = getPaintKind(paint.fill)?.colorOf(paint);\n if (!color) return 'none';\n // Whoever reads the fallback is by definition an older renderer, so the\n // packed alpha comes off rather than riding out as an 8-digit hex.\n const packed = /^#([0-9a-f]{6})[0-9a-f]{2}$/i.exec(color);\n return packed ? `#${packed[1].toLowerCase()}` : color;\n}\n\nfunction stopXml(s: GradStop): string {\n // Detect packed-alpha hex (#rrggbbaa) and split out stop-opacity.\n const m = /^#([0-9a-f]{6})([0-9a-f]{2})$/i.exec(s.color);\n if (m) {\n const alpha = parseInt(m[2], 16) / 255;\n return `<stop offset=\"${trimNumber(s.offset)}\" stop-color=\"#${m[1].toLowerCase()}\" stop-opacity=\"${trimNumber(alpha)}\"/>`;\n }\n return `<stop offset=\"${trimNumber(s.offset)}\" stop-color=\"${s.color}\"/>`;\n}\n","/**\n * Serialize a `SvgNode[]` tree to an SVG document string. Every leaf is\n * emitted as a `<path>` (even shapes that started as `<rect>` etc.) —\n * lossless geometry round-trip beats round-tripping the element-kind\n * label. Gradient paints are gathered into a single `<defs>` block.\n */\n\nimport type { Path, Stroke, StrokeAlign } from '@weasel-js/core';\nimport { boundsOfPath, resolveScreenLength, SCRIPT_METRICS } from '@weasel-js/core';\nimport type {\n Matrix, NamespaceMeta, NamespacedElement, SerializeOptions, SvgGroupNode,\n SvgNode, SvgPaint, SvgPathNode, SvgStroke, SvgTextNode, SvgImageNode,\n ScreenLength,\n} from './types';\nimport { IDENTITY_MATRIX } from './types';\nimport { serializePathD } from './path-serializer';\nimport { formatMatrix, multiply, trimNumber } from './transform';\nimport { PaintServerRegistry, WEASEL_NS, WEASEL_NS_PREFIX } from './gradients';\nimport { anchorOffset } from './textAnchor';\n\n/**\n * Walk the tree and produce an SVG document string. The root `<svg>`'s\n * `viewBox` is taken from `opts.viewBox` if supplied, otherwise computed\n * as a tight bounding box around every leaf.\n */\nexport function serializeSvg(nodes: SvgNode[], opts: SerializeOptions = {}): string {\n const registry = new PaintServerRegistry();\n registerPaintServers(nodes, registry);\n\n const bounds = opts.viewBox ?? computeBounds(nodes);\n const vb = `${trimNumber(bounds.x)} ${trimNumber(bounds.y)} ${trimNumber(bounds.width)} ${trimNumber(bounds.height)}`;\n const namespaces = opts.namespaces ?? {};\n\n const rootAttrs: string[] = [`xmlns=\"http://www.w3.org/2000/svg\"`];\n // Declared before the caller's namespaces and only when something needs it,\n // so a document of ordinary paints carries no trace of it. The paint pre-pass\n // above has already seen every paint, so this answer is final.\n if (registry.usesPrivateNamespace() && namespaces[WEASEL_NS_PREFIX] == null) {\n rootAttrs.push(`xmlns:${WEASEL_NS_PREFIX}=\"${WEASEL_NS}\"`);\n }\n for (const [prefix, uri] of Object.entries(namespaces)) {\n rootAttrs.push(`xmlns:${prefix}=\"${escapeAttr(uri)}\"`);\n }\n rootAttrs.push(`viewBox=\"${vb}\"`);\n if (opts.width != null) rootAttrs.push(`width=\"${trimNumber(opts.width)}\"`);\n if (opts.height != null) rootAttrs.push(`height=\"${trimNumber(opts.height)}\"`);\n // documentMeta attrs onto the root, in declared-namespace order.\n if (opts.documentMeta) {\n for (const prefix of Object.keys(namespaces)) {\n const bucket = opts.documentMeta[prefix];\n if (!bucket?.attrs) continue;\n for (const [name, value] of Object.entries(bucket.attrs)) {\n rootAttrs.push(`${prefix}:${name}=\"${escapeAttr(value)}\"`);\n }\n }\n }\n\n // documentMeta elements after <defs>, before geometry body.\n let docMetaXml = '';\n if (opts.documentMeta) {\n for (const prefix of Object.keys(namespaces)) {\n const bucket = opts.documentMeta[prefix];\n if (!bucket?.elements) continue;\n for (const [localName, list] of Object.entries(bucket.elements)) {\n for (const el of list) docMetaXml += namespacedElementXml(prefix, localName, el);\n }\n }\n }\n\n const defsXml = registry.toDefsXml(opts.onWarn);\n // Once per message: a hundred inner-aligned strokes are one fact.\n const said = new Set<string>();\n const warn: Warn = (m) => {\n if (!opts.onWarn || said.has(m)) return;\n said.add(m);\n opts.onWarn(m);\n };\n const bodyXml = nodes.map((n) => nodeXml(n, registry, namespaces, warn)).join('');\n\n // `<title>` goes immediately inside `<svg>` per SVG-spec convention; it's\n // an accessibility hook and (for our purposes) a stable place to round-trip\n // the user-visible document title.\n const titleXml = opts.title && opts.title.length > 0\n ? `<title>${escapeText(opts.title)}</title>`\n : '';\n\n return `<svg ${rootAttrs.join(' ')}>${titleXml}${defsXml}${docMetaXml}${bodyXml}</svg>`;\n}\n\nfunction namespacedElementXml(prefix: string, localName: string, el: NamespacedElement): string {\n const attrs: string[] = [];\n for (const [name, value] of Object.entries(el.attrs)) {\n attrs.push(`${name}=\"${escapeAttr(value)}\"`);\n }\n const head = attrs.length > 0 ? `<${prefix}:${localName} ${attrs.join(' ')}>` : `<${prefix}:${localName}>`;\n let body = '';\n if (el.children) {\n for (const [childName, list] of Object.entries(el.children)) {\n for (const child of list) body += namespacedElementXml(prefix, childName, child);\n }\n } else if (el.text != null) {\n body = escapeText(el.text);\n }\n return `${head}${body}</${prefix}:${localName}>`;\n}\n\nfunction metaAttrsXml(meta: NamespaceMeta | undefined, namespaces: Record<string, string>): string {\n if (!meta) return '';\n const parts: string[] = [];\n for (const prefix of Object.keys(namespaces)) {\n const bucket = meta[prefix];\n if (!bucket?.attrs) continue;\n for (const [name, value] of Object.entries(bucket.attrs)) {\n parts.push(`${prefix}:${name}=\"${escapeAttr(value)}\"`);\n }\n }\n return parts.length > 0 ? ` ${parts.join(' ')}` : '';\n}\n\nfunction metaElementsXml(meta: NamespaceMeta | undefined, namespaces: Record<string, string>): string {\n if (!meta) return '';\n let out = '';\n for (const prefix of Object.keys(namespaces)) {\n const bucket = meta[prefix];\n if (!bucket?.elements) continue;\n for (const [localName, list] of Object.entries(bucket.elements)) {\n for (const el of list) out += namespacedElementXml(prefix, localName, el);\n }\n }\n return out;\n}\n\nfunction registerPaintServers(nodes: SvgNode[], registry: PaintServerRegistry): void {\n for (const n of nodes) {\n if (n.kind === 'group') {\n if (n.clip) registry.clipId(n.clip);\n registerPaintServers(n.children, registry);\n } else if (n.kind === 'path') {\n if (n.fill.kind === 'gradient') registry.register(n.fill.paint);\n if (n.stroke && n.stroke.paint.kind === 'gradient') registry.register(n.stroke.paint.paint);\n registerMarkers(n.stroke, registry);\n } else if (n.kind === 'text') {\n // Text paints flow through `style` / `runs` rather than a top-level\n // SvgPaint, so register direct FillStyle references when present. This\n // pre-pass is load-bearing: `<defs>` is emitted before the body, so a\n // paint first seen while writing an element would be referenced by an\n // id that no definition backs.\n registerTextPaint(n.fill, registry);\n registerTextPaint(n.stroke?.paint, registry);\n registerMarkers(n.stroke, registry);\n for (const run of n.runs ?? []) {\n registerTextPaint(run.fill, registry);\n registerTextPaint(run.stroke?.paint, registry);\n }\n }\n }\n}\n\n/** Register one text paint if it is a paint server rather than a colour. */\nfunction registerTextPaint(\n paint: import('@weasel-js/core').FillStyle | null | undefined,\n registry: PaintServerRegistry,\n): void {\n if (paint && !('color' in paint)) registry.register(paint);\n}\n\n/** A marker reference in either shape — `SvgStroke` stores a bare key, the kit\n * `Stroke` stores a `MarkerRef`. */\nfunction markerKeyOfRef(ref: unknown): string | undefined {\n if (typeof ref === 'string') return ref;\n if (ref && typeof ref === 'object' && 'key' in ref) return String((ref as { key: string }).key);\n return undefined;\n}\n\n/** Mint a `<defs>` id for every marker a stroke names, before the body is\n * written — same reason as the paint pre-pass above. */\nfunction registerMarkers(\n stroke: { markerStart?: unknown; markerMid?: unknown; markerEnd?: unknown } | undefined,\n registry: PaintServerRegistry,\n): void {\n if (!stroke) return;\n for (const ref of [stroke.markerStart, stroke.markerMid, stroke.markerEnd]) {\n const key = markerKeyOfRef(ref);\n if (key) registry.markerId(key);\n }\n}\n\ntype Warn = (message: string) => void;\n\nfunction nodeXml(\n node: SvgNode, registry: PaintServerRegistry, namespaces: Record<string, string>, warn: Warn,\n): string {\n if (node.kind === 'group') return groupXml(node, registry, namespaces, warn);\n if (node.kind === 'text') return textXml(node, registry, namespaces, warn);\n if (node.kind === 'image') return imageXml(node, namespaces);\n return pathXml(node, registry, namespaces, warn);\n}\n\n/** SVG 1.1 has no stroke alignment; SVG 2's `stroke-alignment` never shipped\n * in a browser. */\nfunction warnStrokeAlign(align: StrokeAlign | undefined, warn: Warn): void {\n if (align && align !== 'center') {\n warn(`a stroke aligned \"${align}\" of its edge is written centered: SVG has no stroke alignment`);\n }\n}\n\n/**\n * Emit an `<image>`. `preserveAspectRatio=\"none\"` is unconditional: the node\n * carries a literal box and nothing else, so letting a viewer letterbox it\n * would place the pixels somewhere the model never said.\n *\n * A source rect or a flip takes the cropped form described on `SvgImageNode`.\n * The nested `<svg>` cannot carry the rotation itself — SVG 1.1 gives it no\n * `transform` — so the rotation, opacity and meta go on the wrapping `<g>`.\n */\nfunction imageXml(node: SvgImageNode, namespaces: Record<string, string>): string {\n const box = `x=\"${trimNumber(node.x)}\" y=\"${trimNumber(node.y)}\"`\n + ` width=\"${trimNumber(node.width)}\" height=\"${trimNumber(node.height)}\"`;\n const outer: string[] = [];\n if (node.opacity != null && node.opacity !== 1) {\n outer.push(`opacity=\"${trimNumber(node.opacity)}\"`);\n }\n if (node.rotation != null && node.rotation !== 0) {\n const cx = node.x + node.width / 2;\n const cy = node.y + node.height / 2;\n const deg = (node.rotation * 180) / Math.PI;\n outer.push(`transform=\"rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})\"`);\n }\n const metaAttrs = metaAttrsXml(node.meta, namespaces);\n const metaEls = metaElementsXml(node.meta, namespaces);\n const href = `href=\"${escapeAttr(node.href)}\"`;\n\n if (!node.source && !node.flipX && !node.flipY) {\n const attrs = [href, box, 'preserveAspectRatio=\"none\"', ...outer].join(' ');\n if (metaEls) return `<image ${attrs}${metaAttrs}>${metaEls}</image>`;\n return `<image ${attrs}${metaAttrs}/>`;\n }\n\n const src = node.source ?? { x: 0, y: 0, width: 1, height: 1 };\n const viewBox = [src.x, src.y, src.width, src.height].map(trimNumber).join(' ');\n // A mirror about the source window's center, so the flipped image still\n // fills exactly the window the viewport shows.\n const flip = node.flipX || node.flipY\n ? ` transform=\"matrix(${node.flipX ? -1 : 1} 0 0 ${node.flipY ? -1 : 1}`\n + ` ${trimNumber(node.flipX ? 2 * src.x + src.width : 0)}`\n + ` ${trimNumber(node.flipY ? 2 * src.y + src.height : 0)})\"`\n : '';\n const head = ['<g data-weasel-image=\"true\"', ...outer].join(' ');\n return `${head}${metaAttrs}>`\n + `<svg ${box} viewBox=\"${viewBox}\" preserveAspectRatio=\"none\">`\n + `<image ${href} x=\"0\" y=\"0\" width=\"1\" height=\"1\" preserveAspectRatio=\"none\"${flip}/>`\n + `</svg>${metaEls}</g>`;\n}\n\nfunction groupXml(\n node: SvgGroupNode, registry: PaintServerRegistry, namespaces: Record<string, string>, warn: Warn,\n): string {\n const attrs: string[] = [];\n if (node.transform) {\n const m = formatMatrix(node.transform);\n if (m) attrs.push(`transform=\"${m}\"`);\n }\n if (node.clip) {\n attrs.push(`clip-path=\"url(#${registry.clipId(node.clip)})\"`);\n }\n if (node.opacity != null && node.opacity !== 1) {\n attrs.push(`opacity=\"${trimNumber(node.opacity)}\"`);\n }\n const metaAttrs = metaAttrsXml(node.meta, namespaces);\n // `metaAttrs` already starts with a leading space (or is empty), so we\n // can splice it after the existing attr list without extra logic.\n const head = attrs.length > 0\n ? `<g ${attrs.join(' ')}${metaAttrs}>`\n : `<g${metaAttrs}>`;\n const body = node.children.map((c) => nodeXml(c, registry, namespaces, warn)).join('');\n return `${head}${body}${metaElementsXml(node.meta, namespaces)}</g>`;\n}\n\nfunction pathXml(\n node: SvgPathNode, registry: PaintServerRegistry, namespaces: Record<string, string>, warn: Warn,\n): string {\n const attrs: string[] = [`d=\"${serializePathD(node.path)}\"`];\n const fillAttrs = paintAttrs(node.fill, 'fill', registry);\n for (const a of fillAttrs) attrs.push(a);\n // Emit fill-rule only when it diverges from SVG's default ('nonzero').\n // RectPath has no fillRule field — only PolygonPath carries one.\n if (node.path.kind === 'polygon' && node.path.fillRule === 'evenodd') {\n attrs.push(`fill-rule=\"evenodd\"`);\n }\n if (node.stroke) {\n const strokeAttrs = strokeAttrsFor(node.stroke, registry, warn);\n for (const a of strokeAttrs) attrs.push(a);\n } else {\n attrs.push('stroke=\"none\"');\n }\n if (node.opacity != null && node.opacity !== 1) {\n attrs.push(`opacity=\"${trimNumber(node.opacity)}\"`);\n }\n if (node.rotation != null && node.rotation !== 0) {\n const b = pathBounds(node.path);\n const cx = b.minX + (b.maxX - b.minX) / 2;\n const cy = b.minY + (b.maxY - b.minY) / 2;\n const deg = (node.rotation * 180) / Math.PI;\n attrs.push(`transform=\"rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})\"`);\n }\n const metaAttrs = metaAttrsXml(node.meta, namespaces);\n const metaEls = metaElementsXml(node.meta, namespaces);\n if (metaEls) {\n return `<path ${attrs.join(' ')}${metaAttrs}>${metaEls}</path>`;\n }\n return `<path ${attrs.join(' ')}${metaAttrs}/>`;\n}\n\nfunction paintAttrs(\n paint: SvgPaint,\n name: 'fill' | 'stroke',\n registry: PaintServerRegistry,\n includeOpacity = true,\n): string[] {\n if (paint.kind === 'none') return [`${name}=\"none\"`];\n if (paint.kind === 'solid') {\n const out = [`${name}=\"${paint.color}\"`];\n if (includeOpacity && paint.opacity != null && paint.opacity !== 1) {\n out.push(`${name}-opacity=\"${trimNumber(paint.opacity)}\"`);\n }\n return out;\n }\n // gradient\n return [`${name}=\"${registry.ref(paint.paint)}\"`];\n}\n\n/**\n * Attributes for a kit `Stroke` — the shape text carries, whose `paint` is a\n * `FillStyle` rather than an `SvgPaint`. Text strokes ride inside\n * `TextStyle` / `StyledRun` rather than as a node-level `SvgStroke`, because\n * that is where the kit's text model puts them.\n *\n * Absent, unpainted, or zero-width emits nothing at all: unstroked text should\n * not carry a `stroke` attribute, and SVG's own default (`none`) already says\n * so.\n */\n/**\n * `stroke-width`, plus `vector-effect` when the width is in screen pixels.\n *\n * A `{ px }` width means \"this thickness once rendered, whatever the view is\n * doing\", which is exactly what `non-scaling-stroke` says — so the number goes\n * out unresolved and the attribute carries the unit. There is no accumulated\n * transform scale here to resolve it against, and picking one would bake a\n * single zoom level into the document.\n */\nfunction strokeWidthAttrs(width: ScreenLength): string[] {\n if (typeof width === 'number') return [`stroke-width=\"${trimNumber(width)}\"`];\n return [`stroke-width=\"${trimNumber(width.px)}\"`, 'vector-effect=\"non-scaling-stroke\"'];\n}\n\nfunction coreStrokeAttrs(stroke: Stroke | undefined, registry: PaintServerRegistry, warn: Warn): string[] {\n const paint = stroke?.paint;\n if (!stroke || !paint) return [];\n const width = stroke.width ?? 1;\n if (!((typeof width === 'object' ? width.px : width) > 0)) return [];\n warnStrokeAlign(stroke.align, warn);\n const attrs: string[] = [];\n if ('color' in paint) {\n attrs.push(`stroke=\"${paint.color}\"`);\n if (paint.opacity != null && paint.opacity !== 1) {\n attrs.push(`stroke-opacity=\"${trimNumber(paint.opacity)}\"`);\n }\n } else {\n attrs.push(`stroke=\"${registry.ref(paint)}\"`);\n }\n attrs.push(...strokeWidthAttrs(width));\n if (stroke.cap) attrs.push(`stroke-linecap=\"${stroke.cap}\"`);\n if (stroke.join) attrs.push(`stroke-linejoin=\"${stroke.join}\"`);\n if (stroke.dash && stroke.dash.length > 0) {\n attrs.push(`stroke-dasharray=\"${stroke.dash.map(trimNumber).join(' ')}\"`);\n }\n if (stroke.miterLimit != null) attrs.push(`stroke-miterlimit=\"${trimNumber(stroke.miterLimit)}\"`);\n for (const [field, attr] of [\n ['markerStart', 'marker-start'],\n ['markerMid', 'marker-mid'],\n ['markerEnd', 'marker-end'],\n ] as const) {\n const ref = stroke[field];\n if (ref === undefined) continue;\n const key = typeof ref === 'string' ? ref : ref.key;\n const id = registry.markerId(key);\n if (id === undefined) continue;\n attrs.push(`${attr}=\"url(#${id})\"`);\n }\n return attrs;\n}\n\nfunction strokeAttrsFor(stroke: SvgStroke, registry: PaintServerRegistry, warn: Warn): string[] {\n warnStrokeAlign(stroke.align, warn);\n // `SvgStroke.opacity` and the paint's own `opacity` are two models of one\n // SVG attribute, and parse fills in both. Emitting each would write\n // `stroke-opacity` twice, which is not well-formed XML at all.\n const attrs = paintAttrs(stroke.paint, 'stroke', registry, false);\n attrs.push(...strokeWidthAttrs(stroke.width));\n const opacity = stroke.opacity\n ?? (stroke.paint.kind === 'solid' ? stroke.paint.opacity : undefined);\n if (opacity != null && opacity !== 1) {\n attrs.push(`stroke-opacity=\"${trimNumber(opacity)}\"`);\n }\n if (stroke.cap) {\n attrs.push(`stroke-linecap=\"${stroke.cap}\"`);\n }\n if (stroke.join) {\n attrs.push(`stroke-linejoin=\"${stroke.join}\"`);\n }\n if (stroke.dash && stroke.dash.length > 0) {\n attrs.push(`stroke-dasharray=\"${stroke.dash.map(trimNumber).join(' ')}\"`);\n }\n if (stroke.miterLimit != null) {\n attrs.push(`stroke-miterlimit=\"${trimNumber(stroke.miterLimit)}\"`);\n }\n for (const [field, attr] of [\n ['markerStart', 'marker-start'],\n ['markerMid', 'marker-mid'],\n ['markerEnd', 'marker-end'],\n ] as const) {\n const ref = stroke[field];\n if (ref === undefined) continue;\n const id = registry.markerId(ref);\n if (id === undefined) continue;\n attrs.push(`${attr}=\"url(#${id})\"`);\n }\n return attrs;\n}\n\n/**\n * Tight bounding box around everything the tree draws, in the root's\n * coordinates — the fallback `viewBox` when the caller supplies none. A\n * node's `rotation` and a group's `transform` both move ink, so both are\n * applied here; a box taken from unrotated geometry crops the document.\n */\nfunction computeBounds(nodes: SvgNode[]): { x: number; y: number; width: number; height: number } {\n let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;\n const visit = (n: SvgNode, ctm: Matrix): void => {\n if (n.kind === 'group') {\n const childCtm = n.transform ? multiply(ctm, n.transform) : ctm;\n n.children.forEach((c) => visit(c, childCtm));\n return;\n }\n const b = n.kind === 'text' || n.kind === 'image'\n ? { minX: n.x, minY: n.y, maxX: n.x + n.width, maxY: n.y + n.height }\n : pathBounds(n.path);\n const local = n.rotation ? rotateAboutCenter(ctm, b, n.rotation) : ctm;\n for (const [x, y] of corners(b)) {\n const px = local[0] * x + local[2] * y + local[4];\n const py = local[1] * x + local[3] * y + local[5];\n if (px < minX) minX = px;\n if (py < minY) minY = py;\n if (px > maxX) maxX = px;\n if (py > maxY) maxY = py;\n }\n };\n nodes.forEach((n) => visit(n, IDENTITY_MATRIX));\n if (!Number.isFinite(minX)) {\n return { x: 0, y: 0, width: 0, height: 0 };\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n}\n\nfunction corners(b: { minX: number; minY: number; maxX: number; maxY: number }): [number, number][] {\n return [[b.minX, b.minY], [b.maxX, b.minY], [b.maxX, b.maxY], [b.minX, b.maxY]];\n}\n\n/** `ctm` composed with the same `rotate(angle cx cy)` the element emits. */\nfunction rotateAboutCenter(\n ctm: Matrix,\n b: { minX: number; minY: number; maxX: number; maxY: number },\n angle: number,\n): Matrix {\n const cx = (b.minX + b.maxX) / 2;\n const cy = (b.minY + b.maxY) / 2;\n const c = Math.cos(angle);\n const s = Math.sin(angle);\n return multiply(ctm, [c, s, -s, c, cx - cx * c + cy * s, cy - cx * s - cy * c]);\n}\n\n/**\n * Emit a `<text>` element. `x` is the `text-anchor` point, per the SVG spec:\n * the box's left edge, center or right edge as its alignment resolves. Uses\n * `dominant-baseline=\"text-before-edge\"` so `y` matches weasel's top-of-box\n * pose; stashes the explicit width/height (which native SVG text doesn't\n * model) in `data-weasel-*` attributes so they round-trip through the parser\n * losslessly.\n */\nfunction textXml(\n node: SvgTextNode, registry: PaintServerRegistry, namespaces: Record<string, string>, warn: Warn,\n): string {\n const attrs: string[] = [\n `x=\"${trimNumber(node.x + anchorOffset(node.style, node.width))}\"`,\n `y=\"${trimNumber(node.y)}\"`,\n `dominant-baseline=\"text-before-edge\"`,\n // The runs model stores real line breaks; SVG's default whitespace\n // handling would collapse them (and any indentation) away on re-import.\n `xml:space=\"preserve\"`,\n `data-weasel-width=\"${trimNumber(node.width)}\"`,\n `data-weasel-height=\"${trimNumber(node.height)}\"`,\n ];\n\n const style = node.style;\n // SVG user space has no camera, so a `{ px }` size writes as that many\n // user units — the reading it already has at scale 1.\n if (style?.fontSize != null) attrs.push(`font-size=\"${trimNumber(resolveScreenLength(style.fontSize, 1))}\"`);\n if (style?.fontFamily) attrs.push(`font-family=\"${escapeAttr(style.fontFamily)}\"`);\n if (style?.fontWeight != null) attrs.push(`font-weight=\"${String(style.fontWeight)}\"`);\n if (style?.fontStyle && style.fontStyle !== 'normal') attrs.push(`font-style=\"${style.fontStyle}\"`);\n const direction = style?.direction ?? 'ltr';\n if (direction === 'rtl') attrs.push('direction=\"rtl\"');\n if (style?.align != null || direction === 'rtl') {\n // `text-anchor` is reading-order relative in SVG exactly as `start` / `end`\n // are here, so the two relative values pass straight through and only the\n // absolute pair has to be turned into an edge the reader resolves the same\n // way. Under `ltr` this collapses to what it always wrote.\n const align = style?.align ?? 'left';\n const anchor = align === 'center' ? 'middle'\n : align === 'start' ? 'start'\n : align === 'end' ? 'end'\n : (align === 'left') === (direction === 'ltr') ? 'start' : 'end';\n if (anchor !== 'start') attrs.push(`text-anchor=\"${anchor}\"`);\n }\n if (style?.letterSpacing != null && style.letterSpacing !== 0) {\n attrs.push(`letter-spacing=\"${trimNumber(resolveScreenLength(style.letterSpacing, 1))}\"`);\n }\n const decoration = textDecorationValue(style?.underline, style?.strikethrough, style?.overline);\n if (decoration) attrs.push(`text-decoration=\"${decoration}\"`);\n // A CSS property rather than an SVG 1.1 presentation attribute, so it goes\n // where every CSS-aware reader looks for it.\n if (style?.textTransform && style.textTransform !== 'none') {\n attrs.push(`style=\"text-transform:${style.textTransform}\"`);\n }\n // SVG text never wraps, so this is for weasel's own reader, beside the box\n // width it wraps at.\n if (style?.wrap) {\n attrs.push('data-weasel-wrap=\"true\"');\n warn('text that wraps at its box width is written unwrapped: SVG text does not wrap, so other'\n + ' readers draw one line per hard break (weasel reads the wrap back)');\n }\n if (node.verticalAlign && node.verticalAlign !== 'top') {\n attrs.push(`data-weasel-vertical-align=\"${node.verticalAlign}\"`);\n warn(`text aligned to the ${node.verticalAlign} of its box is written top-aligned: SVG text has`\n + ' no box, so other readers draw it at the top (weasel reads the alignment back)');\n }\n // Note: `lineHeight` is NOT emitted here. The bridge layer (svgInterop)\n // lifts it into `meta.wd.attrs['line-height']`, which `metaAttrsXml`\n // below emits as `wd:line-height=\"...\"`. There is no compat write of\n // `data-weasel-line-height` — per the SVG-native plan's Migration section,\n // no installed base exists to compat against.\n if (node.fill === null) {\n attrs.push('fill=\"none\"');\n } else if (node.fill) {\n if ('color' in node.fill) {\n attrs.push(`fill=\"${node.fill.color}\"`);\n if (node.fill.opacity != null && node.fill.opacity !== 1) {\n attrs.push(`fill-opacity=\"${trimNumber(node.fill.opacity)}\"`);\n }\n } else {\n attrs.push(`fill=\"${registry.ref(node.fill)}\"`);\n }\n }\n for (const a of coreStrokeAttrs(node.stroke, registry, warn)) attrs.push(a);\n if (node.opacity != null && node.opacity !== 1) {\n attrs.push(`opacity=\"${trimNumber(node.opacity)}\"`);\n }\n if (node.rotation != null && node.rotation !== 0) {\n const cx = node.x + node.width / 2;\n const cy = node.y + node.height / 2;\n const deg = (node.rotation * 180) / Math.PI;\n attrs.push(`transform=\"rotate(${trimNumber(deg)} ${trimNumber(cx)} ${trimNumber(cy)})\"`);\n }\n\n const body = node.runs && node.runs.length > 0\n ? node.runs.map((r) => runXml(r, registry, warn)).join('')\n : escapeText(node.text);\n const metaAttrs = metaAttrsXml(node.meta, namespaces);\n const metaEls = metaElementsXml(node.meta, namespaces);\n return `<text ${attrs.join(' ')}${metaAttrs}>${body}${metaEls}</text>`;\n}\n\nfunction runXml(run: import('@weasel-js/core').StyledRun, registry: PaintServerRegistry, warn: Warn): string {\n const attrs: string[] = [];\n if (run.bold) attrs.push(`font-weight=\"700\"`);\n if (run.italic) attrs.push(`font-style=\"italic\"`);\n if (run.fontFamily) attrs.push(`font-family=\"${escapeAttr(run.fontFamily)}\"`);\n // A percentage `font-size` is relative to the parent's, which is what\n // `fontScale` means; an absolute `fontSize` wins over it here as it does in\n // the runs model.\n //\n // `baseline-shift=\"super\"` carries the preset's *size* as well as its rise,\n // so a run that overrode only the rise has no keyword left to say the size\n // with and must spell it out — without this the superscript comes back\n // full-size at a raised baseline.\n const presetScale = run.script != null && run.baselineShift != null\n ? SCRIPT_METRICS[run.script].size\n : undefined;\n const scale = run.fontScale ?? presetScale;\n if (run.fontSize != null) attrs.push(`font-size=\"${trimNumber(resolveScreenLength(run.fontSize, 1))}\"`);\n else if (scale != null) attrs.push(`font-size=\"${trimNumber(scale * 100)}%\"`);\n // Same story for `baseline-shift`: an SVG percentage resolves against the\n // parent's font size, which is the unit `baselineShift` is already in.\n if (run.baselineShift != null) {\n attrs.push(`baseline-shift=\"${trimNumber(run.baselineShift * 100)}%\"`);\n } else if (run.script) {\n attrs.push(`baseline-shift=\"${run.script}\"`);\n }\n // Unlike the node-level style guard above, a run-level `0` is a meaningful\n // *override* (distinct from \"inherit the node's letterSpacing\") per the\n // runs model's additive-flags contract — emit it whenever it's set.\n if (run.letterSpacing != null) {\n attrs.push(`letter-spacing=\"${trimNumber(resolveScreenLength(run.letterSpacing, 1))}\"`);\n }\n const runDecoration = textDecorationValue(run.underline, run.strikethrough, run.overline);\n if (runDecoration) attrs.push(`text-decoration=\"${runDecoration}\"`);\n if (run.fill) {\n if ('color' in run.fill) {\n attrs.push(`fill=\"${run.fill.color}\"`);\n } else {\n attrs.push(`fill=\"${registry.ref(run.fill)}\"`);\n }\n }\n for (const a of coreStrokeAttrs(run.stroke, registry, warn)) attrs.push(a);\n // `none` included: on a run it overrides a transform the node would pass down.\n if (run.textTransform) attrs.push(`style=\"text-transform:${run.textTransform}\"`);\n const head = attrs.length > 0 ? `<tspan ${attrs.join(' ')}>` : '<tspan>';\n return `${head}${escapeText(run.text)}</tspan>`;\n}\n\n/**\n * Combine the decoration flags into an SVG `text-decoration` value —\n * `\"underline line-through\"` when both are set, a single token when only\n * one is, or `null` (omit the attribute) when none is set.\n */\nfunction textDecorationValue(\n underline: boolean | undefined,\n strikethrough: boolean | undefined,\n overline: boolean | undefined,\n): string | null {\n const tokens: string[] = [];\n if (underline) tokens.push('underline');\n if (strikethrough) tokens.push('line-through');\n if (overline) tokens.push('overline');\n return tokens.length > 0 ? tokens.join(' ') : null;\n}\n\nfunction escapeAttr(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/\"/g, '&quot;').replace(/</g, '&lt;');\n}\n\nfunction escapeText(s: string): string {\n return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\nfunction pathBounds(path: Path): { minX: number; minY: number; maxX: number; maxY: number } {\n if (path.kind === 'rect') {\n return {\n minX: path.x, minY: path.y,\n maxX: path.x + path.width, maxY: path.y + path.height,\n };\n }\n const b = boundsOfPath(path);\n return { minX: b.x, minY: b.y, maxX: b.x + b.width, maxY: b.y + b.height };\n}\n\n"]}