@weasel-js/core 1.13.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (741) hide show
  1. package/CHANGELOG.md +300 -0
  2. package/README.md +8 -12
  3. package/dist/affordances/hitAffordanceRegions.js +1 -1
  4. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  5. package/dist/affordances/pathAnchors.js.map +1 -1
  6. package/dist/animation/clipTargets.js +1 -1
  7. package/dist/animation/clipTargets.js.map +1 -1
  8. package/dist/animation/poseTarget.js +5 -32
  9. package/dist/animation/poseTarget.js.map +1 -1
  10. package/dist/{autoPoseDescriptor-CZ1eXbzY.d.ts → autoPoseDescriptor-C25QVb0W.d.ts} +1 -1
  11. package/dist/barrel/canvas.js +8 -8
  12. package/dist/barrel/chrome.js +9 -9
  13. package/dist/barrel/input.js +1 -1
  14. package/dist/barrel/interactions.js +3 -3
  15. package/dist/barrel/paint.js +2 -2
  16. package/dist/barrel/paths.js +19 -17
  17. package/dist/barrel/renderer.js +11 -7
  18. package/dist/barrel/routing.js +4 -1
  19. package/dist/barrel/scene.js +16 -12
  20. package/dist/barrel/text.js +5 -5
  21. package/dist/barrel/viewport.js +8 -8
  22. package/dist/canvas/Canvas.js +2 -2
  23. package/dist/canvas/Canvas.js.map +1 -1
  24. package/dist/canvas/CanvasView.js +20 -14
  25. package/dist/canvas/CanvasView.js.map +1 -1
  26. package/dist/canvas/GestureReason.js +64 -0
  27. package/dist/canvas/GestureReason.js.map +1 -0
  28. package/dist/canvas/GestureReason.module.js +7 -0
  29. package/dist/canvas/GestureReason.module.js.map +1 -0
  30. package/dist/canvas/LeanSceneCanvas.js +3 -1
  31. package/dist/canvas/LeanSceneCanvas.js.map +1 -1
  32. package/dist/canvas/NodeShape.js +2 -0
  33. package/dist/canvas/NodeShape.js.map +1 -1
  34. package/dist/canvas/PickHud.js +7 -3
  35. package/dist/canvas/PickHud.js.map +1 -1
  36. package/dist/canvas/SceneCanvas/CanvasKitProviders.js +1 -1
  37. package/dist/canvas/SceneCanvas/CanvasKitProviders.js.map +1 -1
  38. package/dist/canvas/SceneCanvas/DevHuds.js +2 -2
  39. package/dist/canvas/SceneCanvas/DevHuds.js.map +1 -1
  40. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +4 -2
  41. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js.map +1 -1
  42. package/dist/canvas/SceneCanvas/SceneCanvasInput.js +3 -1
  43. package/dist/canvas/SceneCanvas/SceneCanvasInput.js.map +1 -1
  44. package/dist/canvas/SceneCanvas/brushOverlay.js.map +1 -1
  45. package/dist/canvas/SceneCanvas/builtinToolSets.js +17 -9
  46. package/dist/canvas/SceneCanvas/builtinToolSets.js.map +1 -1
  47. package/dist/canvas/SceneCanvas/canvasPassThrough.js +2 -1
  48. package/dist/canvas/SceneCanvas/canvasPassThrough.js.map +1 -1
  49. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +75 -19
  50. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  51. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +7 -1
  52. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  53. package/dist/canvas/SceneCanvas/defaultTextEditor.js +108 -0
  54. package/dist/canvas/SceneCanvas/defaultTextEditor.js.map +1 -0
  55. package/dist/canvas/SceneCanvas/describePresets.js +47 -0
  56. package/dist/canvas/SceneCanvas/describePresets.js.map +1 -0
  57. package/dist/canvas/SceneCanvas/features.js +57 -16
  58. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/mergeLayers.js +10 -1
  60. package/dist/canvas/SceneCanvas/mergeLayers.js.map +1 -1
  61. package/dist/canvas/SceneCanvas/namedPresets.js +52 -24
  62. package/dist/canvas/SceneCanvas/namedPresets.js.map +1 -1
  63. package/dist/canvas/SceneCanvas/presets/arrange.js +35 -10
  64. package/dist/canvas/SceneCanvas/presets/arrange.js.map +1 -1
  65. package/dist/canvas/SceneCanvas/presets/baseline.js +9 -0
  66. package/dist/canvas/SceneCanvas/presets/baseline.js.map +1 -0
  67. package/dist/canvas/SceneCanvas/presets/chrome.js.map +1 -1
  68. package/dist/canvas/SceneCanvas/presets/composites.js +43 -0
  69. package/dist/canvas/SceneCanvas/presets/composites.js.map +1 -0
  70. package/dist/canvas/SceneCanvas/presets/edit.js +79 -26
  71. package/dist/canvas/SceneCanvas/presets/edit.js.map +1 -1
  72. package/dist/canvas/SceneCanvas/presets/ingest.js +1 -0
  73. package/dist/canvas/SceneCanvas/presets/ingest.js.map +1 -1
  74. package/dist/canvas/SceneCanvas/presets/paths.js +58 -16
  75. package/dist/canvas/SceneCanvas/presets/paths.js.map +1 -1
  76. package/dist/canvas/SceneCanvas/presets/select.js +4 -2
  77. package/dist/canvas/SceneCanvas/presets/select.js.map +1 -1
  78. package/dist/canvas/SceneCanvas/presets/tools.js +24 -0
  79. package/dist/canvas/SceneCanvas/presets/tools.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/presets/transform.js +4 -0
  81. package/dist/canvas/SceneCanvas/presets/transform.js.map +1 -1
  82. package/dist/canvas/SceneCanvas/presets/view.js +3 -1
  83. package/dist/canvas/SceneCanvas/presets/view.js.map +1 -1
  84. package/dist/canvas/SceneCanvas/props.js.map +1 -1
  85. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js +1 -1
  86. package/dist/canvas/SceneCanvas/shapeGeneratorProperties.js.map +1 -1
  87. package/dist/canvas/SceneCanvas/toolRegistry.js +5 -4
  88. package/dist/canvas/SceneCanvas/toolRegistry.js.map +1 -1
  89. package/dist/canvas/SceneCanvas/useCanvasTools.js +26 -10
  90. package/dist/canvas/SceneCanvas/useCanvasTools.js.map +1 -1
  91. package/dist/canvas/SceneCanvas/useContributionRoles.js +15 -2
  92. package/dist/canvas/SceneCanvas/useContributionRoles.js.map +1 -1
  93. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js +5 -4
  94. package/dist/canvas/SceneCanvas/useDepartureGhostLayer.js.map +1 -1
  95. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js +1 -1
  96. package/dist/canvas/SceneCanvas/useNodeAtPoint.js.map +1 -1
  97. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js +9 -8
  98. package/dist/canvas/SceneCanvas/useSceneCanvasLayers.js.map +1 -1
  99. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js +2 -2
  100. package/dist/canvas/SceneCanvas/useSceneCanvasPathEdit.js.map +1 -1
  101. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js +4 -1
  102. package/dist/canvas/SceneCanvas/useSceneCanvasTools.js.map +1 -1
  103. package/dist/canvas/SceneCanvas/useSceneChrome.js +7 -4
  104. package/dist/canvas/SceneCanvas/useSceneChrome.js.map +1 -1
  105. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js +9 -9
  106. package/dist/canvas/SceneCanvas/useSceneGestureDispatcher.js.map +1 -1
  107. package/dist/canvas/SceneCanvas/useScenePicking.js +4 -7
  108. package/dist/canvas/SceneCanvas/useScenePicking.js.map +1 -1
  109. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js +2 -1
  110. package/dist/canvas/SceneCanvas/useSceneRedrawSources.js.map +1 -1
  111. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +6 -6
  112. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  113. package/dist/canvas/SceneCanvas/useSceneStandardActions.js +2 -2
  114. package/dist/canvas/SceneCanvas/useSceneStandardActions.js.map +1 -1
  115. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js +1 -1
  116. package/dist/canvas/SceneCanvas/useSelectionOverlayLayer.js.map +1 -1
  117. package/dist/canvas/SceneCanvas/useSurfaceViewInputs.js.map +1 -1
  118. package/dist/canvas/SceneCanvas/useToolKeybindings.js +2 -2
  119. package/dist/canvas/SceneCanvas/useToolKeybindings.js.map +1 -1
  120. package/dist/canvas/SceneCanvas/useViewportActions.js +5 -2
  121. package/dist/canvas/SceneCanvas/useViewportActions.js.map +1 -1
  122. package/dist/canvas/SceneCanvas/worldPointAt.js.map +1 -1
  123. package/dist/canvas/SceneCanvas.js +22 -11
  124. package/dist/canvas/SceneCanvas.js.map +1 -1
  125. package/dist/canvas/SceneViewCanvas.js +1 -0
  126. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  127. package/dist/canvas/ViewMarker.js.map +1 -1
  128. package/dist/canvas/accentColor.js +14 -1
  129. package/dist/canvas/accentColor.js.map +1 -1
  130. package/dist/canvas/affordanceAt.js +2 -2
  131. package/dist/canvas/affordanceAt.js.map +1 -1
  132. package/dist/canvas/buildSceneTree.js +5 -3
  133. package/dist/canvas/buildSceneTree.js.map +1 -1
  134. package/dist/canvas/deps/editAnchors.js +4 -4
  135. package/dist/canvas/deps/editAnchors.js.map +1 -1
  136. package/dist/canvas/deps/enteredGroup.js +14 -5
  137. package/dist/canvas/deps/enteredGroup.js.map +1 -1
  138. package/dist/canvas/deps/ingestion.js +5 -1
  139. package/dist/canvas/deps/ingestion.js.map +1 -1
  140. package/dist/canvas/deps/insert.js.map +1 -1
  141. package/dist/canvas/deps/insertSite.js +5 -3
  142. package/dist/canvas/deps/insertSite.js.map +1 -1
  143. package/dist/canvas/deps/nodeAtPoint.js +1 -12
  144. package/dist/canvas/deps/nodeAtPoint.js.map +1 -1
  145. package/dist/canvas/deps/pathEditCommits.js +3 -3
  146. package/dist/canvas/deps/pathEditCommits.js.map +1 -1
  147. package/dist/canvas/deps/slice.js +16 -2
  148. package/dist/canvas/deps/slice.js.map +1 -1
  149. package/dist/canvas/deps/snap.js +5 -5
  150. package/dist/canvas/deps/snap.js.map +1 -1
  151. package/dist/canvas/deps/textEdit.js +5 -6
  152. package/dist/canvas/deps/textEdit.js.map +1 -1
  153. package/dist/canvas/derivedPath.js +8 -3
  154. package/dist/canvas/derivedPath.js.map +1 -1
  155. package/dist/canvas/getNodeAtPoint.js +2 -2
  156. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  157. package/dist/canvas/insertPreviewExtent.js.map +1 -1
  158. package/dist/canvas/layerSlots.js.map +1 -1
  159. package/dist/canvas/nodeShapes/measurePainter.js +1 -1
  160. package/dist/canvas/nodeShapes/measurePainter.js.map +1 -1
  161. package/dist/canvas/nodeShapes/strokedBounds.js +5 -3
  162. package/dist/canvas/nodeShapes/strokedBounds.js.map +1 -1
  163. package/dist/canvas/overlayRoleStrokes.js +6 -0
  164. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  165. package/dist/canvas/pickIndex/scenePickIndex.js +10 -12
  166. package/dist/canvas/pickIndex/scenePickIndex.js.map +1 -1
  167. package/dist/canvas/sceneAdapter.js +10 -19
  168. package/dist/canvas/sceneAdapter.js.map +1 -1
  169. package/dist/canvas/sceneClipboard.js +17 -4
  170. package/dist/canvas/sceneClipboard.js.map +1 -1
  171. package/dist/canvas/sceneViewRender.js +3 -2
  172. package/dist/canvas/sceneViewRender.js.map +1 -1
  173. package/dist/canvas/surfaceContribution.js.map +1 -1
  174. package/dist/canvas/useCanvasPaint.js +10 -4
  175. package/dist/canvas/useCanvasPaint.js.map +1 -1
  176. package/dist/canvas/useHitObserver.js +1 -1
  177. package/dist/canvas/useHitObserver.js.map +1 -1
  178. package/dist/canvas/useViewAim.js +1 -1
  179. package/dist/canvas/useViewAim.js.map +1 -1
  180. package/dist/canvas/useViewHelpers.js +8 -5
  181. package/dist/canvas/useViewHelpers.js.map +1 -1
  182. package/dist/canvas/useViewNesting.js +39 -12
  183. package/dist/canvas/useViewNesting.js.map +1 -1
  184. package/dist/canvas/viewInputs.js.map +1 -1
  185. package/dist/canvas/viewMarkers.js +2 -2
  186. package/dist/canvas/viewMarkers.js.map +1 -1
  187. package/dist/canvas/viewRegistry.js +2 -2
  188. package/dist/canvas/viewRegistry.js.map +1 -1
  189. package/dist/canvas/viewSnap.js +67 -0
  190. package/dist/canvas/viewSnap.js.map +1 -0
  191. package/dist/clipboard.d.ts +6 -12
  192. package/dist/{clone-qb2e1F5p.d.ts → clone-Bz4iqGfE.d.ts} +10 -5
  193. package/dist/clone.d.ts +5 -5
  194. package/dist/core/geometry/booleanOfPaths.js +23 -0
  195. package/dist/core/geometry/booleanOfPaths.js.map +1 -0
  196. package/dist/core/geometry/pathPoseDescriptor.js +12 -9
  197. package/dist/core/geometry/pathPoseDescriptor.js.map +1 -1
  198. package/dist/core/geometry/poseDescriptor.js +12 -3
  199. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  200. package/dist/core/geometry/targetFrame.js +2 -13
  201. package/dist/core/geometry/targetFrame.js.map +1 -1
  202. package/dist/core/layers/render.js +2 -1
  203. package/dist/core/layers/render.js.map +1 -1
  204. package/dist/core/layers/retain.js +5 -3
  205. package/dist/core/layers/retain.js.map +1 -1
  206. package/dist/core/ops/setPath.js +3 -0
  207. package/dist/core/ops/setPath.js.map +1 -1
  208. package/dist/core/paint/meshKindLazy.js.map +1 -1
  209. package/dist/core/paint/paintKindEntry.js.map +1 -1
  210. package/dist/core/paint/paintKinds.js +8 -1
  211. package/dist/core/paint/paintKinds.js.map +1 -1
  212. package/dist/core/scene/NodeProperties.js.map +1 -1
  213. package/dist/core/scene/NodeRouting.js.map +1 -1
  214. package/dist/core/scene/booleanGroup.js +33 -0
  215. package/dist/core/scene/booleanGroup.js.map +1 -0
  216. package/dist/core/scene/booleanOfChildren.js +53 -0
  217. package/dist/core/scene/booleanOfChildren.js.map +1 -0
  218. package/dist/core/scene/carryDescendants.js +18 -6
  219. package/dist/core/scene/carryDescendants.js.map +1 -1
  220. package/dist/core/scene/composeFrame.js +42 -5
  221. package/dist/core/scene/composeFrame.js.map +1 -1
  222. package/dist/core/scene/composePose.js +35 -16
  223. package/dist/core/scene/composePose.js.map +1 -1
  224. package/dist/core/scene/depMemo.js +36 -18
  225. package/dist/core/scene/depMemo.js.map +1 -1
  226. package/dist/core/scene/derivedParts.js +2 -23
  227. package/dist/core/scene/derivedParts.js.map +1 -1
  228. package/dist/core/scene/effectivePose.js +10 -0
  229. package/dist/core/scene/effectivePose.js.map +1 -1
  230. package/dist/core/scene/historyForm.js +5 -4
  231. package/dist/core/scene/historyForm.js.map +1 -1
  232. package/dist/core/scene/kitOps.js +5 -71
  233. package/dist/core/scene/kitOps.js.map +1 -1
  234. package/dist/core/scene/kitRegistry.js +5 -0
  235. package/dist/core/scene/kitRegistry.js.map +1 -1
  236. package/dist/core/scene/layerOps.js +82 -0
  237. package/dist/core/scene/layerOps.js.map +1 -0
  238. package/dist/core/scene/layoutPass.js +14 -12
  239. package/dist/core/scene/layoutPass.js.map +1 -1
  240. package/dist/core/scene/lockGuard.js +9 -3
  241. package/dist/core/scene/lockGuard.js.map +1 -1
  242. package/dist/core/scene/nestedHit.js +5 -5
  243. package/dist/core/scene/nestedHit.js.map +1 -1
  244. package/dist/core/scene/nodeFlags.js +8 -2
  245. package/dist/core/scene/nodeFlags.js.map +1 -1
  246. package/dist/core/scene/nodeGates.js +31 -2
  247. package/dist/core/scene/nodeGates.js.map +1 -1
  248. package/dist/core/scene/pathEffects/effects.js +22 -3
  249. package/dist/core/scene/pathEffects/effects.js.map +1 -1
  250. package/dist/core/scene/pathEffects/textAlong.js +16 -3
  251. package/dist/core/scene/pathEffects/textAlong.js.map +1 -1
  252. package/dist/core/scene/pathEffects/textAlongBands.js +65 -0
  253. package/dist/core/scene/pathEffects/textAlongBands.js.map +1 -0
  254. package/dist/core/scene/reconcileSpecs.js +1 -1
  255. package/dist/core/scene/reconcileSpecs.js.map +1 -1
  256. package/dist/core/scene/scene.js +11 -5
  257. package/dist/core/scene/scene.js.map +1 -1
  258. package/dist/core/scene/sceneEdits.js +5 -2
  259. package/dist/core/scene/sceneEdits.js.map +1 -1
  260. package/dist/core/scene/scenePoseAdapter.js +10 -1
  261. package/dist/core/scene/scenePoseAdapter.js.map +1 -1
  262. package/dist/core/scene/scrollOffsets.js +93 -0
  263. package/dist/core/scene/scrollOffsets.js.map +1 -0
  264. package/dist/core/scene/serialization.js +15 -5
  265. package/dist/core/scene/serialization.js.map +1 -1
  266. package/dist/core/scene/statedFields.js +2 -1
  267. package/dist/core/scene/statedFields.js.map +1 -1
  268. package/dist/core/scene/strategyView.js +35 -0
  269. package/dist/core/scene/strategyView.js.map +1 -0
  270. package/dist/core/scene/types.js.map +1 -1
  271. package/dist/core/scene/useScene.js +2 -0
  272. package/dist/core/scene/useScene.js.map +1 -1
  273. package/dist/core/scene/worldSave.js +87 -0
  274. package/dist/core/scene/worldSave.js.map +1 -0
  275. package/dist/core/selection/selectionTarget.js +1 -1
  276. package/dist/core/selection/selectionTarget.js.map +1 -1
  277. package/dist/{cornerHandles-CNCb7aTY.d.ts → cornerHandles-DpmQM_z5.d.ts} +1 -1
  278. package/dist/{depSchema-CpIQzKWQ.d.ts → depSchema-C3BwxitB.d.ts} +119 -99
  279. package/dist/devtools-protocol.d.ts +2 -2
  280. package/dist/devtools.d.ts +2 -2
  281. package/dist/{features → domains}/chrome-caps/buildChromeCtx.js +1 -1
  282. package/dist/domains/chrome-caps/buildChromeCtx.js.map +1 -0
  283. package/dist/{features → domains}/chrome-caps/conditions.js +1 -1
  284. package/dist/domains/chrome-caps/conditions.js.map +1 -0
  285. package/dist/{features → domains}/chrome-caps/defaults.js +1 -1
  286. package/dist/domains/chrome-caps/defaults.js.map +1 -0
  287. package/dist/{features → domains}/chrome-caps/resolve.js +1 -1
  288. package/dist/domains/chrome-caps/resolve.js.map +1 -0
  289. package/dist/{features → domains}/chrome-caps/useChromeCaps.js +1 -1
  290. package/dist/domains/chrome-caps/useChromeCaps.js.map +1 -0
  291. package/dist/{features → domains}/chrome-caps/useHoverTracking.js +1 -1
  292. package/dist/domains/chrome-caps/useHoverTracking.js.map +1 -0
  293. package/dist/{features → domains}/ingestion/contentHandlers.js +20 -3
  294. package/dist/domains/ingestion/contentHandlers.js.map +1 -0
  295. package/dist/domains/ingestion/ghost.js +56 -0
  296. package/dist/domains/ingestion/ghost.js.map +1 -0
  297. package/dist/{features → domains}/ingestion/imageHandler.js +1 -1
  298. package/dist/domains/ingestion/imageHandler.js.map +1 -0
  299. package/dist/domains/ingestion/kitHandlers.js +22 -0
  300. package/dist/domains/ingestion/kitHandlers.js.map +1 -0
  301. package/dist/{features → domains}/ingestion/openFilePicker.js +1 -1
  302. package/dist/domains/ingestion/openFilePicker.js.map +1 -0
  303. package/dist/{features → domains}/ingestion/placement.js +1 -1
  304. package/dist/domains/ingestion/placement.js.map +1 -0
  305. package/dist/{features → domains}/ingestion/svgHandler.js +1 -1
  306. package/dist/domains/ingestion/svgHandler.js.map +1 -0
  307. package/dist/{features → domains}/ingestion/textHandler.js +9 -7
  308. package/dist/domains/ingestion/textHandler.js.map +1 -0
  309. package/dist/{features → domains}/ingestion/useCanvasIngestion.js +13 -15
  310. package/dist/domains/ingestion/useCanvasIngestion.js.map +1 -0
  311. package/dist/{features → domains}/ingestion/weaselJsonHandler.js +1 -1
  312. package/dist/domains/ingestion/weaselJsonHandler.js.map +1 -0
  313. package/dist/{features → domains}/longPress/longPressFeedback.js +1 -1
  314. package/dist/domains/longPress/longPressFeedback.js.map +1 -0
  315. package/dist/{features → domains}/measure/actionIds.js +1 -1
  316. package/dist/domains/measure/actionIds.js.map +1 -0
  317. package/dist/{features → domains}/measure/measureCommands.js +1 -1
  318. package/dist/domains/measure/measureCommands.js.map +1 -0
  319. package/dist/{features → domains}/measure/measureContribution.js +1 -1
  320. package/dist/domains/measure/measureContribution.js.map +1 -0
  321. package/dist/{features → domains}/measure/measureEdits.js +1 -1
  322. package/dist/domains/measure/measureEdits.js.map +1 -0
  323. package/dist/{features → domains}/measure/measureGestures.js +4 -7
  324. package/dist/domains/measure/measureGestures.js.map +1 -0
  325. package/dist/{features → domains}/measure/measureHit.js +1 -1
  326. package/dist/domains/measure/measureHit.js.map +1 -0
  327. package/dist/{features → domains}/measure/measureLayer.js +1 -1
  328. package/dist/domains/measure/measureLayer.js.map +1 -0
  329. package/dist/{features → domains}/measure/measurement.js +1 -1
  330. package/dist/domains/measure/measurement.js.map +1 -0
  331. package/dist/{features → domains}/measure/measurements.js +2 -2
  332. package/dist/domains/measure/measurements.js.map +1 -0
  333. package/dist/{features → domains}/modes/modeLayers.js +1 -1
  334. package/dist/domains/modes/modeLayers.js.map +1 -0
  335. package/dist/{features → domains}/modes/modeTriggers.js +3 -6
  336. package/dist/domains/modes/modeTriggers.js.map +1 -0
  337. package/dist/{features → domains}/pathEffects/effectSources.js +1 -1
  338. package/dist/domains/pathEffects/effectSources.js.map +1 -0
  339. package/dist/{features → domains}/pathEffects/index.js +1 -1
  340. package/dist/domains/pathEffects/index.js.map +1 -0
  341. package/dist/{features → domains}/pathEffects/readSource.js +1 -1
  342. package/dist/domains/pathEffects/readSource.js.map +1 -0
  343. package/dist/{features → domains}/pathEffects/textItems.js +11 -2
  344. package/dist/domains/pathEffects/textItems.js.map +1 -0
  345. package/dist/{features → domains}/pathEffects/useEffectSourcesLayer.js +1 -1
  346. package/dist/domains/pathEffects/useEffectSourcesLayer.js.map +1 -0
  347. package/dist/{features → domains}/paths/anchorData.js +1 -1
  348. package/dist/domains/paths/anchorData.js.map +1 -0
  349. package/dist/{features → domains}/paths/anchorMarkers.js +9 -7
  350. package/dist/domains/paths/anchorMarkers.js.map +1 -0
  351. package/dist/{features → domains}/paths/editablePath.js +1 -1
  352. package/dist/domains/paths/editablePath.js.map +1 -0
  353. package/dist/{features → domains}/paths/index.js +3 -3
  354. package/dist/{features → domains}/paths/originProjection.js +1 -1
  355. package/dist/domains/paths/originProjection.js.map +1 -0
  356. package/dist/{features → domains}/paths/pathEditExtension.js +1 -1
  357. package/dist/domains/paths/pathEditExtension.js.map +1 -0
  358. package/dist/{features → domains}/paths/pathEditState.js +1 -1
  359. package/dist/domains/paths/pathEditState.js.map +1 -0
  360. package/dist/{features → domains}/paths/pathEditingOverlayLayer.js +1 -1
  361. package/dist/domains/paths/pathEditingOverlayLayer.js.map +1 -0
  362. package/dist/{features → domains}/paths/pathLayer.js +1 -1
  363. package/dist/domains/paths/pathLayer.js.map +1 -0
  364. package/dist/{features → domains}/paths/pathRepresentation.js +1 -1
  365. package/dist/domains/paths/pathRepresentation.js.map +1 -0
  366. package/dist/{features → domains}/paths/pathSnap/glyphs.js +1 -1
  367. package/dist/domains/paths/pathSnap/glyphs.js.map +1 -0
  368. package/dist/{features → domains}/paths/pathSnap/pathSnapSource.js +1 -1
  369. package/dist/domains/paths/pathSnap/pathSnapSource.js.map +1 -0
  370. package/dist/{features → domains}/paths/pathSnap/sceneIndex.js +1 -1
  371. package/dist/domains/paths/pathSnap/sceneIndex.js.map +1 -0
  372. package/dist/{features → domains}/paths/pathSnap/snapGeometry.js +3 -2
  373. package/dist/domains/paths/pathSnap/snapGeometry.js.map +1 -0
  374. package/dist/{features → domains}/paths/penPreviewLayer.js +1 -1
  375. package/dist/domains/paths/penPreviewLayer.js.map +1 -0
  376. package/dist/{features → domains}/paths/shapeGenerator.js +6 -4
  377. package/dist/domains/paths/shapeGenerator.js.map +1 -0
  378. package/dist/{features → domains}/paths/strokeOutline.js +1 -1
  379. package/dist/domains/paths/strokeOutline.js.map +1 -0
  380. package/dist/{features → domains}/paths/useAnchorFields.js +1 -1
  381. package/dist/domains/paths/useAnchorFields.js.map +1 -0
  382. package/dist/{features → domains}/paths/usePathEdit.js +1 -1
  383. package/dist/domains/paths/usePathEdit.js.map +1 -0
  384. package/dist/{features → domains}/poseRun/usePoseRun.js +1 -1
  385. package/dist/domains/poseRun/usePoseRun.js.map +1 -0
  386. package/dist/{features → domains}/selection/enteredGroupFrame.js +49 -10
  387. package/dist/domains/selection/enteredGroupFrame.js.map +1 -0
  388. package/dist/{features → domains}/selection/enteredGroupScope.js +1 -1
  389. package/dist/domains/selection/enteredGroupScope.js.map +1 -0
  390. package/dist/domains/selection/enteredOperands.js +29 -0
  391. package/dist/domains/selection/enteredOperands.js.map +1 -0
  392. package/dist/{features → domains}/selection/handleCommands.js +1 -1
  393. package/dist/domains/selection/handleCommands.js.map +1 -0
  394. package/dist/{features → domains}/selection/overlay.js +1 -1
  395. package/dist/domains/selection/overlay.js.map +1 -0
  396. package/dist/{features → domains}/selection/selectionPose.js +1 -1
  397. package/dist/domains/selection/selectionPose.js.map +1 -0
  398. package/dist/{features → domains}/snap/angle2d.js +1 -1
  399. package/dist/domains/snap/angle2d.js.map +1 -0
  400. package/dist/{features → domains}/snap/debugCandidates.js +1 -1
  401. package/dist/domains/snap/debugCandidates.js.map +1 -0
  402. package/dist/{features → domains}/snap/gather.js +1 -1
  403. package/dist/domains/snap/gather.js.map +1 -0
  404. package/dist/{features → domains}/snap/inputSubspace.js +1 -1
  405. package/dist/domains/snap/inputSubspace.js.map +1 -0
  406. package/dist/{features → domains}/snap/lazySession.js +1 -1
  407. package/dist/domains/snap/lazySession.js.map +1 -0
  408. package/dist/{features → domains}/snap/marks.js +1 -1
  409. package/dist/domains/snap/marks.js.map +1 -0
  410. package/dist/{features → domains}/snap/outcomeStore.js +1 -1
  411. package/dist/domains/snap/outcomeStore.js.map +1 -0
  412. package/dist/{features → domains}/snap/pointSnap.js +1 -1
  413. package/dist/domains/snap/pointSnap.js.map +1 -0
  414. package/dist/{features → domains}/snap/probes2d.js +1 -1
  415. package/dist/domains/snap/probes2d.js.map +1 -0
  416. package/dist/{features → domains}/snap/readoutDraw.js +1 -1
  417. package/dist/domains/snap/readoutDraw.js.map +1 -0
  418. package/dist/{features → domains}/snap/readoutLayer.js +1 -1
  419. package/dist/domains/snap/readoutLayer.js.map +1 -0
  420. package/dist/{features → domains}/snap/registry.js +1 -1
  421. package/dist/domains/snap/registry.js.map +1 -0
  422. package/dist/{features → domains}/snap/resizeBox.js +1 -1
  423. package/dist/domains/snap/resizeBox.js.map +1 -0
  424. package/dist/{features → domains}/snap/roles.js +1 -1
  425. package/dist/domains/snap/roles.js.map +1 -0
  426. package/dist/{features → domains}/snap/rotationSource.js +1 -1
  427. package/dist/domains/snap/rotationSource.js.map +1 -0
  428. package/dist/{features → domains}/snap/sceneReads.js +24 -3
  429. package/dist/domains/snap/sceneReads.js.map +1 -0
  430. package/dist/{features → domains}/snap/sceneSession2d.js +3 -2
  431. package/dist/domains/snap/sceneSession2d.js.map +1 -0
  432. package/dist/{features → domains}/snap/screen.js +1 -1
  433. package/dist/domains/snap/screen.js.map +1 -0
  434. package/dist/{features → domains}/snap/session2d.js +3 -2
  435. package/dist/domains/snap/session2d.js.map +1 -0
  436. package/dist/{features → domains}/snap/spanSnap.js +1 -1
  437. package/dist/domains/snap/spanSnap.js.map +1 -0
  438. package/dist/{features → domains}/snap/stepAngles.js +1 -1
  439. package/dist/domains/snap/stepAngles.js.map +1 -0
  440. package/dist/{features → domains}/text/editingDrawOne.js +4 -4
  441. package/dist/domains/text/editingDrawOne.js.map +1 -0
  442. package/dist/domains/text/hostTextEditors.js +24 -0
  443. package/dist/domains/text/hostTextEditors.js.map +1 -0
  444. package/dist/{features → domains}/text/index.js +1 -1
  445. package/dist/{features → domains}/text/sceneTextDrafts.js +1 -1
  446. package/dist/domains/text/sceneTextDrafts.js.map +1 -0
  447. package/dist/{features → domains}/text/textHitAt.js +18 -2
  448. package/dist/domains/text/textHitAt.js.map +1 -0
  449. package/dist/{features → domains}/text/textLayer.js +1 -1
  450. package/dist/domains/text/textLayer.js.map +1 -0
  451. package/dist/{features → domains}/text/useSceneTextEdit.js +11 -3
  452. package/dist/domains/text/useSceneTextEdit.js.map +1 -0
  453. package/dist/{features → domains}/viewports/aim.js +1 -1
  454. package/dist/domains/viewports/aim.js.map +1 -0
  455. package/dist/{features → domains}/viewports/viewMarker.js +23 -5
  456. package/dist/domains/viewports/viewMarker.js.map +1 -0
  457. package/dist/{features → domains}/viewports/viewMarkerDrag.js +3 -3
  458. package/dist/domains/viewports/viewMarkerDrag.js.map +1 -0
  459. package/dist/{features → domains}/viewports/viewResolver.js +1 -1
  460. package/dist/domains/viewports/viewResolver.js.map +1 -0
  461. package/dist/{features → domains}/viewports/viewportLayer.js +1 -1
  462. package/dist/domains/viewports/viewportLayer.js.map +1 -0
  463. package/dist/icons.table.js +1 -1
  464. package/dist/icons.table.js.map +1 -1
  465. package/dist/icons.table.json +106 -6
  466. package/dist/index.d.ts +1441 -1050
  467. package/dist/index.js +90 -77
  468. package/dist/interactions/actions/admitsChild.js +6 -2
  469. package/dist/interactions/actions/admitsChild.js.map +1 -1
  470. package/dist/interactions/actions/align/align.js +1 -4
  471. package/dist/interactions/actions/align/align.js.map +1 -1
  472. package/dist/interactions/actions/booleans/booleanGroupAction.js +66 -0
  473. package/dist/interactions/actions/booleans/booleanGroupAction.js.map +1 -0
  474. package/dist/interactions/actions/booleans/keymap.js +52 -0
  475. package/dist/interactions/actions/booleans/keymap.js.map +1 -0
  476. package/dist/interactions/actions/booleans/operands.js +1 -1
  477. package/dist/interactions/actions/booleans/pieces.js +4 -11
  478. package/dist/interactions/actions/booleans/pieces.js.map +1 -1
  479. package/dist/interactions/actions/clipboard/action.js +3 -7
  480. package/dist/interactions/actions/clipboard/action.js.map +1 -1
  481. package/dist/interactions/actions/clipboard/clipboardOps.js +1 -1
  482. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  483. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  484. package/dist/interactions/actions/defaults/anchorEditing.js +6 -6
  485. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  486. package/dist/interactions/actions/defaults/bendSegment.js +1 -1
  487. package/dist/interactions/actions/defaults/bendSegment.js.map +1 -1
  488. package/dist/interactions/actions/defaults/containerScroll.js +170 -0
  489. package/dist/interactions/actions/defaults/containerScroll.js.map +1 -0
  490. package/dist/interactions/actions/defaults/contextMenu.js +2 -5
  491. package/dist/interactions/actions/defaults/contextMenu.js.map +1 -1
  492. package/dist/interactions/actions/defaults/delete.js +1 -1
  493. package/dist/interactions/actions/defaults/delete.js.map +1 -1
  494. package/dist/interactions/actions/defaults/duplicate.js +1 -3
  495. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  496. package/dist/interactions/actions/defaults/enterGroup.js +7 -12
  497. package/dist/interactions/actions/defaults/enterGroup.js.map +1 -1
  498. package/dist/interactions/actions/defaults/enterPathEdit.js +4 -8
  499. package/dist/interactions/actions/defaults/enterPathEdit.js.map +1 -1
  500. package/dist/interactions/actions/defaults/group.js +12 -24
  501. package/dist/interactions/actions/defaults/group.js.map +1 -1
  502. package/dist/interactions/actions/defaults/ingest.js +18 -10
  503. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  504. package/dist/interactions/actions/defaults/insertPathAnchor.js +3 -3
  505. package/dist/interactions/actions/defaults/insertPathAnchor.js.map +1 -1
  506. package/dist/interactions/actions/defaults/nudgeSteps.js +3 -21
  507. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -1
  508. package/dist/interactions/actions/defaults/pathEditMarks.js.map +1 -1
  509. package/dist/interactions/actions/defaults/selectDeep.js +2 -2
  510. package/dist/interactions/actions/defaults/selectDeep.js.map +1 -1
  511. package/dist/interactions/actions/distribute/distribute.js.map +1 -1
  512. package/dist/interactions/actions/dropVerdict.js +9 -0
  513. package/dist/interactions/actions/dropVerdict.js.map +1 -0
  514. package/dist/interactions/actions/edit-anchors/action.js +2 -2
  515. package/dist/interactions/actions/edit-anchors/action.js.map +1 -1
  516. package/dist/interactions/actions/edit-anchors/extensionDrags.js.map +1 -1
  517. package/dist/interactions/actions/edit-anchors/geometry.js +8 -6
  518. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  519. package/dist/interactions/actions/edit-anchors/handleDrag.js.map +1 -1
  520. package/dist/interactions/actions/edit-anchors/preview.js +1 -1
  521. package/dist/interactions/actions/edit-anchors/preview.js.map +1 -1
  522. package/dist/interactions/actions/flip/action.js +3 -2
  523. package/dist/interactions/actions/flip/action.js.map +1 -1
  524. package/dist/interactions/actions/geometryProjection.js +8 -3
  525. package/dist/interactions/actions/geometryProjection.js.map +1 -1
  526. package/dist/interactions/actions/gestureFrames.js +1 -0
  527. package/dist/interactions/actions/gestureFrames.js.map +1 -1
  528. package/dist/interactions/actions/insert/action.js +6 -2
  529. package/dist/interactions/actions/insert/action.js.map +1 -1
  530. package/dist/interactions/actions/insert/frame.js +1 -1
  531. package/dist/interactions/actions/insert/frame.js.map +1 -1
  532. package/dist/interactions/actions/insert/placeAction.js +6 -8
  533. package/dist/interactions/actions/insert/placeAction.js.map +1 -1
  534. package/dist/interactions/actions/insert/session.js +2 -2
  535. package/dist/interactions/actions/insert/session.js.map +1 -1
  536. package/dist/interactions/actions/move/action.js +6 -15
  537. package/dist/interactions/actions/move/action.js.map +1 -1
  538. package/dist/interactions/actions/move/behaviors/layoutDrop.js +12 -2
  539. package/dist/interactions/actions/move/behaviors/layoutDrop.js.map +1 -1
  540. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js +29 -10
  541. package/dist/interactions/actions/move/behaviors/reparentOnDrop.js.map +1 -1
  542. package/dist/interactions/actions/move/behaviors/snapToContainer.js +42 -6
  543. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  544. package/dist/interactions/actions/move/capture.js +4 -8
  545. package/dist/interactions/actions/move/capture.js.map +1 -1
  546. package/dist/interactions/actions/move/commit/index.js.map +1 -1
  547. package/dist/interactions/actions/move/commit/layoutDrop.js +4 -3
  548. package/dist/interactions/actions/move/commit/layoutDrop.js.map +1 -1
  549. package/dist/interactions/actions/move/commit/layoutRelease.js +15 -9
  550. package/dist/interactions/actions/move/commit/layoutRelease.js.map +1 -1
  551. package/dist/interactions/actions/move/commit/reparent.js +19 -13
  552. package/dist/interactions/actions/move/commit/reparent.js.map +1 -1
  553. package/dist/interactions/actions/move/delta.js +51 -5
  554. package/dist/interactions/actions/move/delta.js.map +1 -1
  555. package/dist/interactions/actions/move/frame.js +8 -4
  556. package/dist/interactions/actions/move/frame.js.map +1 -1
  557. package/dist/interactions/actions/move/layout/container.js +19 -9
  558. package/dist/interactions/actions/move/layout/container.js.map +1 -1
  559. package/dist/interactions/actions/move/layout/dragged.js +2 -2
  560. package/dist/interactions/actions/move/layout/dragged.js.map +1 -1
  561. package/dist/interactions/actions/move/layout/dropPass.js +36 -18
  562. package/dist/interactions/actions/move/layout/dropPass.js.map +1 -1
  563. package/dist/interactions/actions/move/layout/exits.js +2 -2
  564. package/dist/interactions/actions/move/layout/exits.js.map +1 -1
  565. package/dist/interactions/actions/move/layout/glide.js +5 -5
  566. package/dist/interactions/actions/move/layout/glide.js.map +1 -1
  567. package/dist/interactions/actions/move/layout/view.js +55 -0
  568. package/dist/interactions/actions/move/layout/view.js.map +1 -0
  569. package/dist/interactions/actions/move/refusal.js +52 -0
  570. package/dist/interactions/actions/move/refusal.js.map +1 -0
  571. package/dist/interactions/actions/move/session.js +9 -8
  572. package/dist/interactions/actions/move/session.js.map +1 -1
  573. package/dist/interactions/actions/move/translate.js +10 -4
  574. package/dist/interactions/actions/move/translate.js.map +1 -1
  575. package/dist/interactions/actions/moveNodes.js +21 -5
  576. package/dist/interactions/actions/moveNodes.js.map +1 -1
  577. package/dist/interactions/actions/pathCommands/pathNodes.js +3 -3
  578. package/dist/interactions/actions/pathCommands/pathNodes.js.map +1 -1
  579. package/dist/interactions/actions/planeInput.js +14 -13
  580. package/dist/interactions/actions/planeInput.js.map +1 -1
  581. package/dist/interactions/actions/poseFrame.js +21 -8
  582. package/dist/interactions/actions/poseFrame.js.map +1 -1
  583. package/dist/interactions/actions/resize/action.js +1 -1
  584. package/dist/interactions/actions/resize/action.js.map +1 -1
  585. package/dist/interactions/actions/resize/aspect.js +1 -1
  586. package/dist/interactions/actions/resize/aspect.js.map +1 -1
  587. package/dist/interactions/actions/resize/commit.js +10 -1
  588. package/dist/interactions/actions/resize/commit.js.map +1 -1
  589. package/dist/interactions/actions/resize/frame.js +3 -2
  590. package/dist/interactions/actions/resize/frame.js.map +1 -1
  591. package/dist/interactions/actions/resize/held.js +44 -0
  592. package/dist/interactions/actions/resize/held.js.map +1 -0
  593. package/dist/interactions/actions/resize/session.js +3 -1
  594. package/dist/interactions/actions/resize/session.js.map +1 -1
  595. package/dist/interactions/actions/resolveOverlays.js +9 -0
  596. package/dist/interactions/actions/resolveOverlays.js.map +1 -1
  597. package/dist/interactions/actions/resolvePreviews.js +23 -7
  598. package/dist/interactions/actions/resolvePreviews.js.map +1 -1
  599. package/dist/interactions/actions/rotate/action.js +1 -1
  600. package/dist/interactions/actions/rotate/action.js.map +1 -1
  601. package/dist/interactions/actions/rotate/frame.js +1 -1
  602. package/dist/interactions/actions/rotate/frame.js.map +1 -1
  603. package/dist/interactions/actions/rotate/session.js +2 -2
  604. package/dist/interactions/actions/rotate/session.js.map +1 -1
  605. package/dist/interactions/actions/selectionSubtree.js +2 -4
  606. package/dist/interactions/actions/selectionSubtree.js.map +1 -1
  607. package/dist/interactions/actions/spatialReference.js +4 -9
  608. package/dist/interactions/actions/spatialReference.js.map +1 -1
  609. package/dist/interactions/gestures/dragRadial/dragRadial.js.map +1 -1
  610. package/dist/interactions/gestures/dragRect/dragRect.js.map +1 -1
  611. package/dist/kitSettingsSchema.js +2 -2
  612. package/dist/kitSettingsSchema.js.map +1 -1
  613. package/dist/{math-C_elShP_.d.ts → math-B_unOnF4.d.ts} +2 -2
  614. package/dist/math.d.ts +3 -3
  615. package/dist/move.d.ts +6 -6
  616. package/dist/{options-ClEm3SEl.d.ts → options-DAjkhbcs.d.ts} +5 -5
  617. package/dist/{poseDescriptor-DN2yfnq_.d.ts → poseDescriptor-CvSxVhCd.d.ts} +17 -4
  618. package/dist/resize.d.ts +6 -6
  619. package/dist/style.css +14 -0
  620. package/dist/test-seams.d.ts +11 -15
  621. package/dist/test-seams.js +1 -1
  622. package/dist/tools/builtin/eyedropper/useEyedropperTool.js +3 -6
  623. package/dist/tools/builtin/eyedropper/useEyedropperTool.js.map +1 -1
  624. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  625. package/dist/tools/builtin/measure/useMeasureTool.js +2 -2
  626. package/dist/tools/builtin/measure/useMeasureTool.js.map +1 -1
  627. package/dist/tools/builtin/pen/penHandle.js +2 -2
  628. package/dist/tools/builtin/pen/penHandle.js.map +1 -1
  629. package/dist/tools/builtin/pen/usePenTool.js +13 -19
  630. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  631. package/dist/tools/builtin/polygon/usePolygonTool.js +1 -1
  632. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  633. package/dist/tools/builtin/select/groupEntry.js +1 -1
  634. package/dist/tools/builtin/select/groupEntry.js.map +1 -1
  635. package/dist/tools/builtin/select/selectionContributions.js +1 -1
  636. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  637. package/dist/tools/builtin/select/useSelectTool.js +7 -7
  638. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  639. package/dist/tools/builtin/slice/useSliceTool.js +5 -8
  640. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  641. package/dist/tools/builtin/star/useStarTool.js +1 -1
  642. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  643. package/dist/tools/index.js +2 -1
  644. package/dist/{types-49uYJN3j.d.ts → types-A_sNJYRd.d.ts} +8 -0
  645. package/dist/{types-BEdRIhNc.d.ts → types-DW14eu9B.d.ts} +131 -36
  646. package/dist/{types-p2alu-R1.d.ts → types-VCtfchp-.d.ts} +4 -6
  647. package/dist/util/color.js +12 -14
  648. package/dist/util/color.js.map +1 -1
  649. package/dist/version.js +1 -1
  650. package/package.json +25 -24
  651. package/dist/canvas/poseCascade.js +0 -65
  652. package/dist/canvas/poseCascade.js.map +0 -1
  653. package/dist/features/chrome-caps/buildChromeCtx.js.map +0 -1
  654. package/dist/features/chrome-caps/conditions.js.map +0 -1
  655. package/dist/features/chrome-caps/defaults.js.map +0 -1
  656. package/dist/features/chrome-caps/resolve.js.map +0 -1
  657. package/dist/features/chrome-caps/useChromeCaps.js.map +0 -1
  658. package/dist/features/chrome-caps/useHoverTracking.js.map +0 -1
  659. package/dist/features/ingestion/contentHandlers.js.map +0 -1
  660. package/dist/features/ingestion/imageHandler.js.map +0 -1
  661. package/dist/features/ingestion/openFilePicker.js.map +0 -1
  662. package/dist/features/ingestion/placement.js.map +0 -1
  663. package/dist/features/ingestion/registerKitHandlers.js +0 -43
  664. package/dist/features/ingestion/registerKitHandlers.js.map +0 -1
  665. package/dist/features/ingestion/svgHandler.js.map +0 -1
  666. package/dist/features/ingestion/textHandler.js.map +0 -1
  667. package/dist/features/ingestion/useCanvasIngestion.js.map +0 -1
  668. package/dist/features/ingestion/weaselJsonHandler.js.map +0 -1
  669. package/dist/features/longPress/longPressFeedback.js.map +0 -1
  670. package/dist/features/measure/actionIds.js.map +0 -1
  671. package/dist/features/measure/measureCommands.js.map +0 -1
  672. package/dist/features/measure/measureContribution.js.map +0 -1
  673. package/dist/features/measure/measureEdits.js.map +0 -1
  674. package/dist/features/measure/measureGestures.js.map +0 -1
  675. package/dist/features/measure/measureHit.js.map +0 -1
  676. package/dist/features/measure/measureLayer.js.map +0 -1
  677. package/dist/features/measure/measurement.js.map +0 -1
  678. package/dist/features/measure/measurements.js.map +0 -1
  679. package/dist/features/modes/modeLayers.js.map +0 -1
  680. package/dist/features/modes/modeTriggers.js.map +0 -1
  681. package/dist/features/pathEffects/effectSources.js.map +0 -1
  682. package/dist/features/pathEffects/index.js.map +0 -1
  683. package/dist/features/pathEffects/readSource.js.map +0 -1
  684. package/dist/features/pathEffects/textItems.js.map +0 -1
  685. package/dist/features/pathEffects/useEffectSourcesLayer.js.map +0 -1
  686. package/dist/features/paths/anchorData.js.map +0 -1
  687. package/dist/features/paths/anchorMarkers.js.map +0 -1
  688. package/dist/features/paths/editablePath.js.map +0 -1
  689. package/dist/features/paths/originProjection.js.map +0 -1
  690. package/dist/features/paths/pathEditExtension.js.map +0 -1
  691. package/dist/features/paths/pathEditState.js.map +0 -1
  692. package/dist/features/paths/pathEditingOverlayLayer.js.map +0 -1
  693. package/dist/features/paths/pathLayer.js.map +0 -1
  694. package/dist/features/paths/pathRepresentation.js.map +0 -1
  695. package/dist/features/paths/pathSnap/glyphs.js.map +0 -1
  696. package/dist/features/paths/pathSnap/pathSnapSource.js.map +0 -1
  697. package/dist/features/paths/pathSnap/sceneIndex.js.map +0 -1
  698. package/dist/features/paths/pathSnap/snapGeometry.js.map +0 -1
  699. package/dist/features/paths/penPreviewLayer.js.map +0 -1
  700. package/dist/features/paths/shapeGenerator.js.map +0 -1
  701. package/dist/features/paths/strokeOutline.js.map +0 -1
  702. package/dist/features/paths/useAnchorFields.js.map +0 -1
  703. package/dist/features/paths/usePathEdit.js.map +0 -1
  704. package/dist/features/poseRun/usePoseRun.js.map +0 -1
  705. package/dist/features/selection/enteredGroupFrame.js.map +0 -1
  706. package/dist/features/selection/enteredGroupScope.js.map +0 -1
  707. package/dist/features/selection/handleCommands.js.map +0 -1
  708. package/dist/features/selection/overlay.js.map +0 -1
  709. package/dist/features/selection/selectionPose.js.map +0 -1
  710. package/dist/features/snap/angle2d.js.map +0 -1
  711. package/dist/features/snap/debugCandidates.js.map +0 -1
  712. package/dist/features/snap/gather.js.map +0 -1
  713. package/dist/features/snap/inputSubspace.js.map +0 -1
  714. package/dist/features/snap/lazySession.js.map +0 -1
  715. package/dist/features/snap/marks.js.map +0 -1
  716. package/dist/features/snap/outcomeStore.js.map +0 -1
  717. package/dist/features/snap/pointSnap.js.map +0 -1
  718. package/dist/features/snap/probes2d.js.map +0 -1
  719. package/dist/features/snap/readoutDraw.js.map +0 -1
  720. package/dist/features/snap/readoutLayer.js.map +0 -1
  721. package/dist/features/snap/registry.js.map +0 -1
  722. package/dist/features/snap/resizeBox.js.map +0 -1
  723. package/dist/features/snap/roles.js.map +0 -1
  724. package/dist/features/snap/rotationSource.js.map +0 -1
  725. package/dist/features/snap/sceneReads.js.map +0 -1
  726. package/dist/features/snap/sceneSession2d.js.map +0 -1
  727. package/dist/features/snap/screen.js.map +0 -1
  728. package/dist/features/snap/session2d.js.map +0 -1
  729. package/dist/features/snap/spanSnap.js.map +0 -1
  730. package/dist/features/snap/stepAngles.js.map +0 -1
  731. package/dist/features/text/editingDrawOne.js.map +0 -1
  732. package/dist/features/text/sceneTextDrafts.js.map +0 -1
  733. package/dist/features/text/textHitAt.js.map +0 -1
  734. package/dist/features/text/textLayer.js.map +0 -1
  735. package/dist/features/text/useSceneTextEdit.js.map +0 -1
  736. package/dist/features/viewports/aim.js.map +0 -1
  737. package/dist/features/viewports/viewMarker.js.map +0 -1
  738. package/dist/features/viewports/viewMarkerDrag.js.map +0 -1
  739. package/dist/features/viewports/viewResolver.js.map +0 -1
  740. package/dist/features/viewports/viewportLayer.js.map +0 -1
  741. /package/dist/{features → domains}/chrome-caps/index.js +0 -0
@@ -7,7 +7,7 @@ import { addMeasureOp, moveEndOps, moveMeasureOps, translatedMeasure } from "./m
7
7
  import { MEASURE_ACTION_IDS } from "./actionIds.js";
8
8
  import { resolveParams } from "@weasel-js/routing";
9
9
 
10
- //#region src/features/measure/measureGestures.ts
10
+ //#region src/domains/measure/measureGestures.ts
11
11
  /** Screen-px radius around a measurement that picks it. */
12
12
  var MEASURE_HIT_PX = 6;
13
13
  var pointOf = (at) => at.drag?.current ?? at.world;
@@ -77,13 +77,10 @@ function measurePickAtAction(ms) {
77
77
  invoker: {
78
78
  timing: "immediate",
79
79
  run: (deps, params) => {
80
- const p = params;
80
+ const press = params?.press;
81
81
  const scene = deps.scene;
82
- if (!scene || p?.pressX === void 0 || p.pressY === void 0) return;
83
- const hit = measureAt(scene, ms, {
84
- x: p.pressX,
85
- y: p.pressY
86
- }, pxToWorld(deps, MEASURE_HIT_PX));
82
+ if (!scene || !press) return;
83
+ const hit = measureAt(scene, ms, press, pxToWorld(deps, MEASURE_HIT_PX));
87
84
  ms.picked.set(hit?.id ?? null);
88
85
  }
89
86
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measureGestures.js","names":[],"sources":["../../../src/domains/measure/measureGestures.ts"],"sourcesContent":["import type { Action, ActionDeps, BindingOpts, InvocationCtx, OngoingHandle } from '@weasel-js/routing';\nimport { resolveParams } from '@weasel-js/routing';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { commitOps } from 'interactions/actions/defaultCommitAdapter';\nimport { SNAP_ANGLE_STEP, SNAP_ROLES, snapMods } from 'domains/snap/roles';\nimport { spanSnap } from 'domains/snap/spanSnap';\nimport { measureBetween, measureEndsOf, withMeasureEnd, type MeasureEnd, type MeasurePoint } from './measurement';\nimport type { Measurements } from './measurements';\nimport { measureAt, type MeasureHit } from './measureHit';\nimport { addMeasureOp, moveEndOps, moveMeasureOps, translatedMeasure } from './measureEdits';\nimport { MEASURE_ACTION_IDS } from './actionIds';\nimport type { ImmediateParams } from '@weasel-js/routing';\n\ntype AnyScene = Scene<unknown, string, unknown>;\n\n/** Screen-px radius around a measurement that picks it. */\nexport const MEASURE_HIT_PX = 6;\n\nconst pointOf = (at: InvocationCtx): MeasurePoint => at.drag?.current ?? at.world;\n\n/** World units `px` screen pixels span at the deps' view. */\nexport function pxToWorld(deps: ActionDeps | undefined, px: number): number {\n const scale = deps?.view?.get().scale.x ?? 1;\n return px / (scale || 1);\n}\n\n/**\n * The measure tool's drag: from press to pointer, each end through a `point`\n * session of the `snap` dep. While `snap.constrain` (Shift) is held the end\n * stays on the line through the snapped start at the nearest step of the\n * binding param `angleStep` (radians, default 15°), and lands where that line\n * meets a target. The drawing shows in `ms.draft`; on release it becomes a\n * measurement node, one undo step, and the picked one.\n */\nexport function measureCreateAction(ms: Measurements): Action {\n return {\n id: MEASURE_ACTION_IDS.measure,\n label: 'Measure',\n modifierRoles: SNAP_ROLES,\n requires: ['snap', 'scene', 'applyOps', 'selection'],\n invoker: {\n timing: 'ongoing',\n // The dispatcher builds deps once, for `start`; later events carry none.\n start(ctx: InvocationCtx, opts?: BindingOpts): OngoingHandle {\n const deps = ctx.deps;\n // Read on every event, so a step changed mid-drag reaches it.\n const snap = spanSnap(deps.snap, () => {\n const step = resolveParams(opts?.params)?.['angleStep'];\n return { step: typeof step === 'number' ? step : SNAP_ANGLE_STEP };\n });\n const start = snap.start(ctx.drag?.start ?? ctx.world, snapMods(ctx)).point;\n const endAt = (at: InvocationCtx): MeasurePoint => snap.end(pointOf(at), snapMods(at)).point;\n ms.draft.set(measureBetween(start, start));\n return {\n kind: 'measure',\n onMove: (moveCtx) => ms.draft.set(measureBetween(start, endAt(moveCtx))),\n onEnd: (endCtx, reason) => {\n try {\n ms.draft.set(null);\n const scene = deps.scene as AnyScene | undefined;\n if (reason !== 'commit' || !scene) return;\n const end = endAt(endCtx);\n if (end.x === start.x && end.y === start.y) return;\n const { id, op } = addMeasureOp(scene, ms.layer, start, end);\n commitOps(deps, [op], 'Measure');\n ms.picked.set(id);\n } finally {\n snap.close();\n }\n },\n };\n },\n },\n };\n}\n\n/** The measure tool's click: picks the measurement under it, or drops the\n * pick on empty canvas. */\nexport function measurePickAtAction(ms: Measurements): Action {\n return {\n id: MEASURE_ACTION_IDS.pickAt,\n label: 'Pick Measurement',\n requires: ['scene', 'view'],\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const press = (params as ImmediateParams | undefined)?.press;\n const scene = deps.scene as AnyScene | undefined;\n if (!scene || !press) return;\n const hit = measureAt(scene, ms, press, pxToWorld(deps, MEASURE_HIT_PX));\n ms.picked.set(hit?.id ?? null);\n },\n },\n };\n}\n\n/** What a press on the measurements layer resolved, as its hit-test claims it. */\nexport const hitOf = (affordance: unknown): MeasureHit | null =>\n (affordance as { payload?: MeasureHit } | null | undefined)?.payload ?? null;\n\n/** A click on a measurement under any tool: picks it, leaving the content\n * selection as it was. */\nexport function measurePickAction(ms: Measurements): Action {\n return {\n id: MEASURE_ACTION_IDS.pick,\n label: 'Pick Measurement',\n invoker: {\n timing: 'immediate',\n run: (_deps, params) => {\n const hit = hitOf((params as { affordance?: unknown } | undefined)?.affordance);\n if (hit) ms.picked.set(hit.id);\n },\n },\n };\n}\n\n/** The node `id` on `scene`, as a measurement edit reads it. */\nfunction nodeOf(scene: AnyScene | undefined, id: NodeId) {\n return scene?.get(id);\n}\n\n/**\n * A drag on a measurement under any tool. On an end of the picked\n * measurement it moves that end, keeping its offset from the press, through\n * a `point` session of the `snap` dep in which the measurement's own ends\n * offer nothing; anywhere else on a\n * measurement it carries the whole measurement with the pointer. Previewed\n * while it runs; one undo step on release.\n */\nexport function measureDragAction(ms: Measurements): Action {\n return {\n id: MEASURE_ACTION_IDS.drag,\n label: 'Drag Measurement',\n modifierRoles: SNAP_ROLES,\n requires: ['scene', 'snap', 'applyOps', 'selection'],\n invoker: {\n timing: 'ongoing',\n start(ctx: InvocationCtx): OngoingHandle {\n const hit = hitOf(ctx.drag?.affordance);\n const deps = ctx.deps;\n const scene = deps.scene as AnyScene | undefined;\n const node = hit ? nodeOf(scene, hit.id) : undefined;\n if (!hit || !node) return {};\n const end: MeasureEnd | null = hit.part !== 'line' && ms.picked.get() === hit.id ? hit.part : null;\n const from = ctx.drag?.start ?? ctx.world;\n const grabbed = (end && measureEndsOf(node)?.[end]) || from;\n const snap = end ? deps.snap?.begin({ gesture: 'point', press: grabbed, ids: [hit.id] }) ?? null : null;\n let at = from;\n let landed = grabbed;\n const next = () => (end\n ? withMeasureEnd(node, end, landed)\n : translatedMeasure(node, at.x - from.x, at.y - from.y));\n const follow = (c: InvocationCtx) => {\n at = pointOf(c);\n const held = { x: grabbed.x + at.x - from.x, y: grabbed.y + at.y - from.y };\n landed = snap ? snap.at(held, snapMods(c)).point : held;\n };\n ms.picked.set(hit.id);\n return {\n kind: MEASURE_ACTION_IDS.drag,\n onMove: follow,\n onEnd: (endCtx, reason) => {\n try {\n if (reason !== 'commit') return;\n follow(endCtx);\n const ops = end ? moveEndOps(node, end, landed) : moveMeasureOps(node, at.x - from.x, at.y - from.y);\n commitOps(deps, ops, ops[0]?.label ?? 'Move Measurement');\n } finally {\n snap?.end();\n }\n },\n previewIds: () => [hit.id],\n previewOpaqueIds: () => [hit.id],\n previewPose: () => next()?.pose ?? null,\n previewData: () => next()?.data ?? null,\n };\n },\n },\n };\n}\n"],"mappings":"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"}
@@ -3,7 +3,7 @@ import { measureEndsOf } from "./measurement.js";
3
3
  import { nodeGates } from "../../core/scene/nodeGates.js";
4
4
  import { measureIds } from "./measurements.js";
5
5
 
6
- //#region src/features/measure/measureHit.ts
6
+ //#region src/domains/measure/measureHit.ts
7
7
  function distanceToSegment(p, a, b) {
8
8
  const dx = b.x - a.x;
9
9
  const dy = b.y - a.y;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measureHit.js","names":[],"sources":["../../../src/domains/measure/measureHit.ts"],"sourcesContent":["import type { NodeId, Scene } from 'core/scene/types';\nimport { measureEndsOf, type MeasureEnd, type MeasurePoint } from './measurement';\nimport { measureIds, type Measurements } from './measurements';\nimport { nodesAsShown, shownLookup } from 'core/scene/nodeAsShown';\nimport { nodeGates } from 'core/scene/nodeGates';\nimport type { SnapSource } from 'domains/snap/types';\n\n/** Which part of which measurement lies under a point. */\nexport interface MeasureHit {\n id: NodeId;\n part: MeasureEnd | 'line';\n}\n\n\nfunction distanceToSegment(p: MeasurePoint, a: MeasurePoint, b: MeasurePoint): number {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const len2 = dx * dx + dy * dy;\n const t = len2 === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / len2));\n return Math.hypot(p.x - (a.x + t * dx), p.y - (a.y + t * dy));\n}\n\n/**\n * The measurement under `p`, newest first: an end within `tolerance` world\n * units of it, else a line within the same distance. A hidden or locked\n * measurement (`nodeGates`) is passed over.\n */\nexport function measureAt(\n scene: Pick<Scene<unknown, string, unknown>, 'nodesOnLayer' | 'get' | 'layers' | 'overrides'>,\n ms: Pick<Measurements, 'layer'>,\n p: MeasurePoint,\n tolerance: number,\n): MeasureHit | null {\n const gates = nodeGates(scene);\n // Hit where the ends are shown: a gesture moving one publishes it as a data override.\n const shown = shownLookup(scene);\n const ids = measureIds(scene, ms).reverse().filter((id) => !gates.hidden(id) && !gates.locked(id));\n for (const id of ids) {\n const ends = measureEndsOf(shown.get(id));\n if (!ends) continue;\n for (const part of ['end', 'start'] as const) {\n if (Math.hypot(p.x - ends[part].x, p.y - ends[part].y) <= tolerance) return { id, part };\n }\n }\n for (const id of ids) {\n const ends = measureEndsOf(shown.get(id));\n if (ends && distanceToSegment(p, ends.start, ends.end) <= tolerance) return { id, part: 'line' };\n }\n return null;\n}\n\n/** Options for `measureEndSource`. */\nexport interface MeasureEndSourceOptions {\n /** Overrides the canvas's reach for measurement ends, in screen px. */\n reachPx?: number;\n}\n\n/** The ends of every shown measurement as snap targets for a pointer probe. */\nexport function measureEndSource(opts: MeasureEndSourceOptions = {}): SnapSource {\n return {\n id: 'measure-ends',\n roles: ['pointer'],\n ...(opts.reachPx !== undefined ? { reachPx: opts.reachPx } : {}),\n *collect(q) {\n if (!q.scene) return;\n const gates = nodeGates(q.scene);\n const skip = new Set(q.exclude);\n const reach = q.reachWorld(q.reachPx);\n for (const node of nodesAsShown(q.scene.overrides, q.scene.renderOrderNodes())) {\n const ends = measureEndsOf(node);\n if (!ends || skip.has(node.id) || gates.hidden(node.id)) continue;\n for (const end of [ends.start, ends.end]) {\n const at = { x: end.x, y: end.y };\n for (const p of q.probes) {\n if (Math.hypot(at.x - p.at.x, at.y - p.at.y) > reach) continue;\n yield { probe: p.id, locus: { at, dirs: [] }, mark: { kind: 'point', at, glyph: 'center' } };\n }\n }\n }\n },\n };\n}\n"],"mappings":";;;;;;AAcA,SAAS,kBAAkB,GAAiB,GAAiB,GAAyB;CACpF,MAAM,KAAK,EAAE,IAAI,EAAE;CACnB,MAAM,KAAK,EAAE,IAAI,EAAE;CACnB,MAAM,OAAO,KAAK,KAAK,KAAK;CAC5B,MAAM,IAAI,SAAS,IAAI,IAAI,KAAK,IAAI,GAAG,KAAK,IAAI,KAAK,EAAE,IAAI,EAAE,KAAK,MAAM,EAAE,IAAI,EAAE,KAAK,MAAM,IAAI,CAAC;CAChG,OAAO,KAAK,MAAM,EAAE,KAAK,EAAE,IAAI,IAAI,KAAK,EAAE,KAAK,EAAE,IAAI,IAAI,GAAG;AAC9D;;;;;;AAOA,SAAgB,UACd,OACA,IACA,GACA,WACmB;CACnB,MAAM,QAAQ,UAAU,KAAK;CAE7B,MAAM,QAAQ,YAAY,KAAK;CAC/B,MAAM,MAAM,WAAW,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,QAAQ,OAAO,CAAC,MAAM,OAAO,EAAE,KAAK,CAAC,MAAM,OAAO,EAAE,CAAC;CACjG,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,cAAc,MAAM,IAAI,EAAE,CAAC;EACxC,IAAI,CAAC,MAAM;EACX,KAAK,MAAM,QAAQ,CAAC,OAAO,OAAO,GAChC,IAAI,KAAK,MAAM,EAAE,IAAI,KAAK,KAAK,CAAC,GAAG,EAAE,IAAI,KAAK,KAAK,CAAC,CAAC,KAAK,WAAW,OAAO;GAAE;GAAI;EAAK;CAE3F;CACA,KAAK,MAAM,MAAM,KAAK;EACpB,MAAM,OAAO,cAAc,MAAM,IAAI,EAAE,CAAC;EACxC,IAAI,QAAQ,kBAAkB,GAAG,KAAK,OAAO,KAAK,GAAG,KAAK,WAAW,OAAO;GAAE;GAAI,MAAM;EAAO;CACjG;CACA,OAAO;AACT;;AASA,SAAgB,iBAAiB,OAAgC,CAAC,GAAe;CAC/E,OAAO;EACL,IAAI;EACJ,OAAO,CAAC,SAAS;EACjB,GAAI,KAAK,YAAY,SAAY,EAAE,SAAS,KAAK,QAAQ,IAAI,CAAC;EAC9D,CAAC,QAAQ,GAAG;GACV,IAAI,CAAC,EAAE,OAAO;GACd,MAAM,QAAQ,UAAU,EAAE,KAAK;GAC/B,MAAM,OAAO,IAAI,IAAI,EAAE,OAAO;GAC9B,MAAM,QAAQ,EAAE,WAAW,EAAE,OAAO;GACpC,KAAK,MAAM,QAAQ,aAAa,EAAE,MAAM,WAAW,EAAE,MAAM,iBAAiB,CAAC,GAAG;IAC9E,MAAM,OAAO,cAAc,IAAI;IAC/B,IAAI,CAAC,QAAQ,KAAK,IAAI,KAAK,EAAE,KAAK,MAAM,OAAO,KAAK,EAAE,GAAG;IACzD,KAAK,MAAM,OAAO,CAAC,KAAK,OAAO,KAAK,GAAG,GAAG;KACxC,MAAM,KAAK;MAAE,GAAG,IAAI;MAAG,GAAG,IAAI;KAAE;KAChC,KAAK,MAAM,KAAK,EAAE,QAAQ;MACxB,IAAI,KAAK,MAAM,GAAG,IAAI,EAAE,GAAG,GAAG,GAAG,IAAI,EAAE,GAAG,CAAC,IAAI,OAAO;MACtD,MAAM;OAAE,OAAO,EAAE;OAAI,OAAO;QAAE;QAAI,MAAM,CAAC;OAAE;OAAG,MAAM;QAAE,MAAM;QAAS;QAAI,OAAO;OAAS;MAAE;KAC7F;IACF;GACF;EACF;CACF;AACF"}
@@ -7,7 +7,7 @@ import { measureAt } from "./measureHit.js";
7
7
  import { MEASURE_HIT_PX } from "./measureGestures.js";
8
8
  import { rectPath } from "@weasel-js/geom";
9
9
 
10
- //#region src/features/measure/measureLayer.ts
10
+ //#region src/domains/measure/measureLayer.ts
11
11
  /** The registered layer's id; a press it claims routes as `layer:<id>`. */
12
12
  var MEASURE_LAYER_ID = "weasel-measure";
13
13
  /** The affordance kind a press on a measurement routes under. */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measureLayer.js","names":[],"sources":["../../../src/domains/measure/measureLayer.ts"],"sourcesContent":["import type { RenderLayer } from 'core/layers/render';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { LayerHit } from 'affordances/types';\nimport type { Scene } from 'core/scene/types';\nimport { worldToScreen } from 'core/viewport/viewTransform';\nimport { viewToTransform } from 'core/viewport/view';\nimport { rectPath } from '@weasel-js/geom';\nimport { OVERLAY_ROLE_STROKES } from 'canvas/overlayRoleStrokes';\nimport { measureCommands } from 'canvas/nodeShapes/measurePainter';\nimport { measureEndsOf, type MeasurePoint } from './measurement';\nimport type { Measurements } from './measurements';\nimport { measureAt, type MeasureHit } from './measureHit';\nimport { MEASURE_HIT_PX } from './measureGestures';\n\n/** The registered layer's id; a press it claims routes as `layer:<id>`. */\nexport const MEASURE_LAYER_ID = 'weasel-measure';\n/** The affordance kind a press on a measurement routes under. */\nexport const MEASURE_AFFORDANCE_KIND = `layer:${MEASURE_LAYER_ID}`;\n\nconst HANDLE_PX = 3.5;\n\ntype AnyScene = Scene<unknown, string, unknown>;\n\n/**\n * The measurements' interactive layer, under every tool: it draws the\n * measurement a measure drag is making and a handle on each end of the picked\n * one, and claims a press on a measurement so a click picks it and a drag\n * edits it rather than reaching the tool. Under the measure tool it claims\n * only the picked measurement's ends, so a drag from anywhere else measures.\n */\nexport function measurementsLayer(scene: AnyScene, ms: Measurements): RenderLayer<unknown> {\n return {\n id: MEASURE_LAYER_ID,\n label: 'Measurements',\n space: 'screen',\n subscribe: (listener) => {\n const offs = [ms.picked.subscribe(listener), ms.draft.subscribe(listener), ms.measuring.subscribe(listener)];\n return () => { for (const off of offs) off(); };\n },\n draw: (_data, view) => {\n const t = viewToTransform(view);\n const toScreen = (p: MeasurePoint): MeasurePoint => {\n const [x, y] = worldToScreen(p.x, p.y, t);\n return { x, y };\n };\n const out: DrawCommand[] = [];\n const draft = ms.draft.get();\n if (draft) out.push(...measureCommands(toScreen(draft.start), toScreen(draft.end), 1));\n const picked = ms.picked.get();\n const ends = picked === null ? null : measureEndsOf(scene.get(picked));\n if (ends && !scene.isHidden(picked!)) {\n const stroke = { ...OVERLAY_ROLE_STROKES['measure'], width: 1 };\n for (const p of [ends.start, ends.end].map(toScreen)) {\n out.push({\n kind: 'path',\n path: rectPath(p.x - HANDLE_PX, p.y - HANDLE_PX, HANDLE_PX * 2, HANDLE_PX * 2),\n fill: { paint: { color: '#ffffff' } },\n stroke,\n });\n }\n }\n return out;\n },\n hitTest: (wx, wy, _data, view): LayerHit<MeasureHit> | null => {\n const hit = measureAt(scene, ms, { x: wx, y: wy }, MEASURE_HIT_PX / (view.scale.x || 1));\n if (!hit) return null;\n const onPickedEnd = hit.part !== 'line' && hit.id === ms.picked.get();\n if (ms.measuring.get() && !onPickedEnd) return null;\n return {\n initialScratch: hit,\n strength: 'exclusive',\n claimedKinds: ['pointer'],\n cursor: onPickedEnd ? 'crosshair' : 'move',\n };\n },\n };\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAa,mBAAmB;;AAEhC,IAAa,0BAA0B,SAAS;AAEhD,IAAM,YAAY;;;;;;;;AAWlB,SAAgB,kBAAkB,OAAiB,IAAwC;CACzF,OAAO;EACL,IAAI;EACJ,OAAO;EACP,OAAO;EACP,YAAY,aAAa;GACvB,MAAM,OAAO;IAAC,GAAG,OAAO,UAAU,QAAQ;IAAG,GAAG,MAAM,UAAU,QAAQ;IAAG,GAAG,UAAU,UAAU,QAAQ;GAAC;GAC3G,aAAa;IAAE,KAAK,MAAM,OAAO,MAAM,IAAI;GAAG;EAChD;EACA,OAAO,OAAO,SAAS;GACrB,MAAM,IAAI,gBAAgB,IAAI;GAC9B,MAAM,YAAY,MAAkC;IAClD,MAAM,CAAC,GAAG,KAAK,cAAc,EAAE,GAAG,EAAE,GAAG,CAAC;IACxC,OAAO;KAAE;KAAG;IAAE;GAChB;GACA,MAAM,MAAqB,CAAC;GAC5B,MAAM,QAAQ,GAAG,MAAM,IAAI;GAC3B,IAAI,OAAO,IAAI,KAAK,GAAG,gBAAgB,SAAS,MAAM,KAAK,GAAG,SAAS,MAAM,GAAG,GAAG,CAAC,CAAC;GACrF,MAAM,SAAS,GAAG,OAAO,IAAI;GAC7B,MAAM,OAAO,WAAW,OAAO,OAAO,cAAc,MAAM,IAAI,MAAM,CAAC;GACrE,IAAI,QAAQ,CAAC,MAAM,SAAS,MAAO,GAAG;IACpC,MAAM,SAAS;KAAE,GAAG,qBAAqB;KAAY,OAAO;IAAE;IAC9D,KAAK,MAAM,KAAK,CAAC,KAAK,OAAO,KAAK,GAAG,CAAC,CAAC,IAAI,QAAQ,GACjD,IAAI,KAAK;KACP,MAAM;KACN,MAAM,SAAS,EAAE,IAAI,WAAW,EAAE,IAAI,WAAW,YAAY,GAAG,YAAY,CAAC;KAC7E,MAAM,EAAE,OAAO,EAAE,OAAO,UAAU,EAAE;KACpC;IACF,CAAC;GAEL;GACA,OAAO;EACT;EACA,UAAU,IAAI,IAAI,OAAO,SAAsC;GAC7D,MAAM,MAAM,UAAU,OAAO,IAAI;IAAE,GAAG;IAAI,GAAG;GAAG,GAAG,kBAAkB,KAAK,MAAM,KAAK,EAAE;GACvF,IAAI,CAAC,KAAK,OAAO;GACjB,MAAM,cAAc,IAAI,SAAS,UAAU,IAAI,OAAO,GAAG,OAAO,IAAI;GACpE,IAAI,GAAG,UAAU,IAAI,KAAK,CAAC,aAAa,OAAO;GAC/C,OAAO;IACL,gBAAgB;IAChB,UAAU;IACV,cAAc,CAAC,SAAS;IACxB,QAAQ,cAAc,cAAc;GACtC;EACF;CACF;AACF"}
@@ -1,4 +1,4 @@
1
- //#region src/features/measure/measurement.ts
1
+ //#region src/domains/measure/measurement.ts
2
2
  /** Measure from `start` to `end`. */
3
3
  function measureBetween(start, end) {
4
4
  const dx = end.x - start.x;
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measurement.js","names":[],"sources":["../../../src/domains/measure/measurement.ts"],"sourcesContent":["import type { Node, NodeId, RectPose } from 'core/scene/types';\nimport type { Point } from '@weasel-js/geom';\n\n/** A world-space point. */\nexport type MeasurePoint = Point;\n\n/**\n * The offset from `start` to `end`, in world units. `dx` and `dy` are on the\n * world's own axes, where y grows downward; `angle` reads like a protractor\n * instead, counterclockwise-positive on screen, so a line rising up and to\n * the right at 30° reads +30°. The canvas's own rotations are\n * clockwise-positive: a rotate that follows the line turns by `-angle`.\n */\nexport interface Measurement {\n readonly start: MeasurePoint;\n readonly end: MeasurePoint;\n readonly dx: number;\n readonly dy: number;\n readonly distance: number;\n /** `atan2(-dy, dx)`, in `(-π, π]`. Zero for a zero-length measurement. */\n readonly angle: number;\n}\n\n/** Measure from `start` to `end`. */\nexport function measureBetween(start: MeasurePoint, end: MeasurePoint): Measurement {\n const dx = end.x - start.x;\n const dy = end.y - start.y;\n return {\n start: { x: start.x, y: start.y },\n end: { x: end.x, y: end.y },\n dx,\n dy,\n distance: Math.hypot(dx, dy),\n // `|| 0` drops the sign of a negated zero, which would read a leftward line as -π.\n angle: dx === 0 && dy === 0 ? 0 : Math.atan2(-dy || 0, dx),\n };\n}\n\n/** What a measurement node keeps in `data`: its two ends, in world units. A\n * `label` beside it names the node in a layer list. */\nexport interface MeasureData {\n measure: { start: MeasurePoint; end: MeasurePoint };\n label?: string;\n}\n\n/** Which end of a measurement. */\nexport type MeasureEnd = 'start' | 'end';\n\n\n/** The ends `node` measures between, or null when it is not a measurement. */\nexport function measureEndsOf(node: Pick<Node<unknown, string, unknown>, 'data'> | undefined): MeasureData['measure'] | null {\n const m = (node?.data as Partial<MeasureData> | null | undefined)?.measure;\n if (!m || typeof m !== 'object' || !m.start || !m.end) return null;\n return m;\n}\n\n/** The measurement `node` holds, or null when it is not one. */\nexport function measurementOf(node: Pick<Node<unknown, string, unknown>, 'data'> | undefined): Measurement | null {\n const ends = measureEndsOf(node);\n return ends ? measureBetween(ends.start, ends.end) : null;\n}\n\n/** The box a measurement's pose holds: its two ends' bounds, which is what\n * culling, area queries, and fitting the view read. */\nexport function measurePose(start: MeasurePoint, end: MeasurePoint): RectPose {\n return {\n x: Math.min(start.x, end.x),\n y: Math.min(start.y, end.y),\n width: Math.abs(end.x - start.x),\n height: Math.abs(end.y - start.y),\n };\n}\n\n/** A measurement node on `layer`, ready to insert. */\nexport function measureNode(id: NodeId, layer: string, start: MeasurePoint, end: MeasurePoint): Node<unknown, string, unknown> {\n const data: MeasureData = { measure: { start: { ...start }, end: { ...end } } };\n return { id, kind: 'mark', layer, parent: null, pose: measurePose(start, end), data };\n}\n\n/** `node`'s data and pose with its `which` end moved to `to`. */\nexport function withMeasureEnd(\n node: Node<unknown, string, unknown>,\n which: MeasureEnd,\n to: MeasurePoint,\n): { data: MeasureData; pose: RectPose } | null {\n const ends = measureEndsOf(node);\n if (!ends) return null;\n const next = { ...ends, [which]: { x: to.x, y: to.y } };\n const data: MeasureData = { ...(node.data as MeasureData), measure: next };\n return { data, pose: measurePose(next.start, next.end) };\n}\n"],"mappings":";;AAwBA,SAAgB,eAAe,OAAqB,KAAgC;CAClF,MAAM,KAAK,IAAI,IAAI,MAAM;CACzB,MAAM,KAAK,IAAI,IAAI,MAAM;CACzB,OAAO;EACL,OAAO;GAAE,GAAG,MAAM;GAAG,GAAG,MAAM;EAAE;EAChC,KAAK;GAAE,GAAG,IAAI;GAAG,GAAG,IAAI;EAAE;EAC1B;EACA;EACA,UAAU,KAAK,MAAM,IAAI,EAAE;EAE3B,OAAO,OAAO,KAAK,OAAO,IAAI,IAAI,KAAK,MAAM,CAAC,MAAM,GAAG,EAAE;CAC3D;AACF;;AAcA,SAAgB,cAAc,MAA+F;CAC3H,MAAM,KAAK,MAAM,KAAA,EAAkD;CACnE,IAAI,CAAC,KAAK,OAAO,MAAM,YAAY,CAAC,EAAE,SAAS,CAAC,EAAE,KAAK,OAAO;CAC9D,OAAO;AACT;;AAGA,SAAgB,cAAc,MAAoF;CAChH,MAAM,OAAO,cAAc,IAAI;CAC/B,OAAO,OAAO,eAAe,KAAK,OAAO,KAAK,GAAG,IAAI;AACvD;;;AAIA,SAAgB,YAAY,OAAqB,KAA6B;CAC5E,OAAO;EACL,GAAG,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;EAC1B,GAAG,KAAK,IAAI,MAAM,GAAG,IAAI,CAAC;EAC1B,OAAO,KAAK,IAAI,IAAI,IAAI,MAAM,CAAC;EAC/B,QAAQ,KAAK,IAAI,IAAI,IAAI,MAAM,CAAC;CAClC;AACF;;AAGA,SAAgB,YAAY,IAAY,OAAe,OAAqB,KAAmD;CAC7H,MAAM,OAAoB,EAAE,SAAS;EAAE,OAAO,EAAE,GAAG,MAAM;EAAG,KAAK,EAAE,GAAG,IAAI;CAAE,EAAE;CAC9E,OAAO;EAAE;EAAI,MAAM;EAAQ;EAAO,QAAQ;EAAM,MAAM,YAAY,OAAO,GAAG;EAAG;CAAK;AACtF;;AAGA,SAAgB,eACd,MACA,OACA,IAC8C;CAC9C,MAAM,OAAO,cAAc,IAAI;CAC/B,IAAI,CAAC,MAAM,OAAO;CAClB,MAAM,OAAO;EAAE,GAAG;GAAO,QAAQ;GAAE,GAAG,GAAG;GAAG,GAAG,GAAG;EAAE;CAAE;CAEtD,OAAO;EAAE;GADmB,GAAI,KAAK;GAAsB,SAAS;EAC3D;EAAM,MAAM,YAAY,KAAK,OAAO,KAAK,GAAG;CAAE;AACzD"}
@@ -1,7 +1,7 @@
1
1
  import { measurementOf } from "./measurement.js";
2
2
  import { createEmitter } from "@weasel-js/registry";
3
3
 
4
- //#region src/features/measure/measurements.ts
4
+ //#region src/domains/measure/measurements.ts
5
5
  function cell(initial) {
6
6
  let value = initial;
7
7
  const changed = createEmitter();
@@ -26,7 +26,7 @@ function createMeasurements(options) {
26
26
  }
27
27
  /** The measurement nodes on `ms.layer`, oldest first. */
28
28
  function measureIds(scene, ms) {
29
- return scene.renderOrderNodes().filter((n) => n.layer === ms.layer && measurementOf(n) !== null).map((n) => n.id);
29
+ return scene.nodesOnLayer(ms.layer).filter((n) => measurementOf(n) !== null).map((n) => n.id);
30
30
  }
31
31
  /** The measurement commands act on: the picked one while it is still in the
32
32
  * scene, else the newest. */
@@ -0,0 +1 @@
1
+ {"version":3,"file":"measurements.js","names":[],"sources":["../../../src/domains/measure/measurements.ts"],"sourcesContent":["import { createEmitter } from '@weasel-js/registry';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { measurementOf, type Measurement } from './measurement';\n\n/** One value, readable and watchable — what a readout re-renders from. */\nexport interface MeasureCell<T> {\n get(): T;\n set(next: T): void;\n subscribe(listener: () => void): () => void;\n}\n\nfunction cell<T>(initial: T): MeasureCell<T> {\n let value = initial;\n const changed = createEmitter();\n return {\n get: () => value,\n set: (next) => {\n if (Object.is(next, value)) return;\n value = next;\n changed.emit();\n },\n subscribe: changed.subscribe,\n };\n}\n\n/**\n * Where a scene's measurements go, and the state around them that is not\n * the document's: which one is picked, and the one a measure drag is still\n * drawing. The measurements themselves are nodes on `layer`, an annotation\n * layer (`isAnnotationLayer`), so they save with the scene, undo with it,\n * and stay out of export and content picking.\n *\n * The pick sits beside the content selection rather than in it: picking a\n * measurement leaves the selection alone, so Move by can carry the selection\n * by the picked measurement.\n */\nexport interface Measurements {\n /** The annotation layer new measurements are added to. */\n readonly layer: string;\n /** The picked measurement's id. */\n readonly picked: MeasureCell<NodeId | null>;\n /** The measurement a measure drag is drawing, before it is added. */\n readonly draft: MeasureCell<Measurement | null>;\n /** Whether the measure tool is active, which changes what a press on a\n * measurement does: under it, only the picked one's ends take a drag, so a\n * drag from anywhere else starts a new measurement. */\n readonly measuring: MeasureCell<boolean>;\n}\n\n/** The measurements on `layer`, none picked and none in progress. */\nexport function createMeasurements(options: { layer: string }): Measurements {\n return {\n layer: options.layer,\n picked: cell<NodeId | null>(null),\n draft: cell<Measurement | null>(null),\n measuring: cell(false),\n };\n}\n\n\n/** The measurement nodes on `ms.layer`, oldest first. */\nexport function measureIds(scene: Pick<Scene<unknown, string, unknown>, 'nodesOnLayer'>, ms: Pick<Measurements, 'layer'>): NodeId[] {\n return scene.nodesOnLayer(ms.layer).filter((n) => measurementOf(n) !== null).map((n) => n.id);\n}\n\n/** The measurement commands act on: the picked one while it is still in the\n * scene, else the newest. */\nexport function currentMeasureId(\n scene: Pick<Scene<unknown, string, unknown>, 'nodesOnLayer' | 'get'>,\n ms: Pick<Measurements, 'layer' | 'picked'>,\n): NodeId | null {\n const picked = ms.picked.get();\n if (picked !== null && measurementOf(scene.get(picked)) !== null) return picked;\n return measureIds(scene, ms).at(-1) ?? null;\n}\n"],"mappings":";;;;AAWA,SAAS,KAAQ,SAA4B;CAC3C,IAAI,QAAQ;CACZ,MAAM,UAAU,cAAc;CAC9B,OAAO;EACL,WAAW;EACX,MAAM,SAAS;GACb,IAAI,OAAO,GAAG,MAAM,KAAK,GAAG;GAC5B,QAAQ;GACR,QAAQ,KAAK;EACf;EACA,WAAW,QAAQ;CACrB;AACF;;AA2BA,SAAgB,mBAAmB,SAA0C;CAC3E,OAAO;EACL,OAAO,QAAQ;EACf,QAAQ,KAAoB,IAAI;EAChC,OAAO,KAAyB,IAAI;EACpC,WAAW,KAAK,KAAK;CACvB;AACF;;AAIA,SAAgB,WAAW,OAA8D,IAA2C;CAClI,OAAO,MAAM,aAAa,GAAG,KAAK,CAAC,CAAC,QAAQ,MAAM,cAAc,CAAC,MAAM,IAAI,CAAC,CAAC,KAAK,MAAM,EAAE,EAAE;AAC9F;;;AAIA,SAAgB,iBACd,OACA,IACe;CACf,MAAM,SAAS,GAAG,OAAO,IAAI;CAC7B,IAAI,WAAW,QAAQ,cAAc,MAAM,IAAI,MAAM,CAAC,MAAM,MAAM,OAAO;CACzE,OAAO,WAAW,OAAO,EAAE,CAAC,CAAC,GAAG,EAAE,KAAK;AACzC"}
@@ -1,7 +1,7 @@
1
1
  import { viewToTransform } from "../../core/viewport/view.js";
2
2
  import { worldToScreen } from "../../core/viewport/viewTransform.js";
3
3
 
4
- //#region src/features/modes/modeLayers.ts
4
+ //#region src/domains/modes/modeLayers.ts
5
5
  var DEFAULT_INTENSITY = .12;
6
6
  /**
7
7
  * A screen-space layer painting the active mode's `WorkspaceVisual`, or the `fallback`'s in a
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modeLayers.js","names":[],"sources":["../../../src/domains/modes/modeLayers.ts"],"sourcesContent":["import type { Rect } from '@weasel-js/geom';\nimport type { ModeDecorations, ModeRegistry, WorkspaceVisual } from '@weasel-js/modes';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { RenderLayer } from 'core/layers/render';\nimport { viewToTransform } from 'core/viewport/view';\nimport { worldToScreen } from 'core/viewport/viewTransform';\n\n/** Options for {@link workspaceTintLayer}. */\nexport interface WorkspaceTintLayerOptions {\n registry: ModeRegistry;\n /** The page, in world coordinates. When given, the tint covers only the\n * workspace around it, each strip fading toward the page edge if the mode\n * names a gradient. Without it the tint covers the whole canvas. */\n page?: () => Rect | null;\n /** Opacity for every mode's tint, in place of its `workspace.intensity`. */\n intensity?: number;\n /** The tint shown in a mode with none of its own, and what announces a change to it. */\n fallback?: { visual: () => WorkspaceVisual | null; subscribe: (fn: () => void) => () => void };\n id?: string;\n label?: string;\n}\n\nconst DEFAULT_INTENSITY = 0.12;\n\n/**\n * A screen-space layer painting the active mode's `WorkspaceVisual`, or the `fallback`'s in a\n * mode without one: a wash at `intensity`, else that visual's own, bottom-up or top-down when it\n * names a gradient.\n */\nexport function workspaceTintLayer(opts: WorkspaceTintLayerOptions): RenderLayer<unknown> {\n const { registry } = opts;\n return {\n id: opts.id ?? 'mode-tint',\n label: opts.label ?? 'Mode tint',\n space: 'screen',\n subscribe: (repaint) => {\n const offMode = registry.subscribe(repaint);\n const offFallback = opts.fallback?.subscribe(repaint);\n return () => { offMode(); offFallback?.(); };\n },\n draw: (_data, view, dims) => {\n const own = registry.current().workspace;\n const ws = own?.tint && own.tint !== 'transparent' ? own : opts.fallback?.visual() ?? undefined;\n const tint = ws?.tint;\n if (!ws || !tint || tint === 'transparent') return [];\n const opacity = opts.intensity ?? ws.intensity ?? DEFAULT_INTENSITY;\n const { width: W, height: H } = dims;\n\n const strip = (\n x: number, y: number, width: number, height: number,\n from: { x: number; y: number }, to: { x: number; y: number },\n ): DrawCommand => ({\n kind: 'path',\n path: { kind: 'rect', x, y, width, height },\n fill: { paint: ws.gradient\n ? { kind: 'linear-gradient', from, to, stops: [{ offset: 0, color: tint }, { offset: 1, color: 'transparent' }], opacity }\n : { kind: 'solid', color: tint, opacity } },\n });\n\n const whole = (): DrawCommand[] => [\n ws.gradient === 'top-down'\n ? strip(0, 0, W, H, { x: 0, y: 0 }, { x: 0, y: H })\n : strip(0, 0, W, H, { x: 0, y: H }, { x: 0, y: 0 }),\n ];\n\n const page = opts.page?.();\n if (!page) return whole();\n\n const t = viewToTransform(view);\n const [sx0, sy0] = worldToScreen(page.x, page.y, t);\n const [sx1, sy1] = worldToScreen(page.x + page.width, page.y + page.height, t);\n const pl = Math.max(0, Math.min(sx0, sx1));\n const pt = Math.max(0, Math.min(sy0, sy1));\n const pr = Math.min(W, Math.max(sx0, sx1));\n const pb = Math.min(H, Math.max(sy0, sy1));\n if (pr <= pl || pb <= pt) {\n return [{ kind: 'path', path: { kind: 'rect', x: 0, y: 0, width: W, height: H }, fill: { paint: { kind: 'solid', color: tint, opacity } } }];\n }\n\n const cmds: DrawCommand[] = [];\n const push = (\n x: number, y: number, w: number, h: number,\n from: { x: number; y: number }, to: { x: number; y: number },\n ): void => { if (w > 0 && h > 0) cmds.push(strip(x, y, w, h, from, to)); };\n push(0, 0, W, pt, { x: 0, y: 0 }, { x: 0, y: pt });\n push(0, pb, W, H - pb, { x: 0, y: H }, { x: 0, y: pb });\n push(0, pt, pl, pb - pt, { x: 0, y: 0 }, { x: pl, y: 0 });\n push(pr, pt, W - pr, pb - pt, { x: W, y: 0 }, { x: pr, y: 0 });\n return cmds;\n },\n };\n}\n\n/** A world-space layer drawing a `ModeDecorations`' active painter. It\n * subscribes to the decorations, so a mode switch or a new painter repaints\n * it. */\nexport function modeDecorationLayer(\n decorations: ModeDecorations,\n opts: { id?: string; label?: string } = {},\n): RenderLayer<unknown> {\n return {\n id: opts.id ?? 'mode-decorations',\n label: opts.label ?? 'Mode decorations',\n subscribe: decorations.subscribe,\n draw: () => decorations.paint() as DrawCommand[],\n };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { ActionDisabledReason } from "@weasel-js/routing";
2
2
  import { modeLabel } from "@weasel-js/modes";
3
3
 
4
- //#region src/features/modes/modeTriggers.ts
4
+ //#region src/domains/modes/modeTriggers.ts
5
5
  /**
6
6
  * The registry's double-click entries as an always-on contribution: for each mode whose
7
7
  * `entry.trigger` is `'double-click-target'`, one action bound to a double-click on each routing
@@ -54,11 +54,8 @@ function triggerAction(mode, targets, enter, canEnter) {
54
54
  invoker: {
55
55
  timing: "immediate",
56
56
  run: (deps, params) => {
57
- const x = params?.worldX, y = params?.worldY;
58
- const id = typeof x === "number" && typeof y === "number" ? targetAt(deps, {
59
- x,
60
- y
61
- }) : null;
57
+ const world = params?.world;
58
+ const id = world ? targetAt(deps, world) : null;
62
59
  if (id !== null) enter(mode.id, id);
63
60
  }
64
61
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"modeTriggers.js","names":[],"sources":["../../../src/domains/modes/modeTriggers.ts"],"sourcesContent":["import { modeLabel, type ModeDefinition, type ModeRegistry } from '@weasel-js/modes';\nimport { ActionDisabledReason, type Action, type ActionDeps, type Contribution } from '@weasel-js/routing';\nimport type { ImmediateParams } from '@weasel-js/routing';\n\n/** What a mode's double-click trigger does. */\nexport interface ModeTriggerHandlers {\n /** Enter mode `id` on the node `targetId`. Without it nothing is bound. */\n enter?: (id: string, targetId: string) => void;\n /**\n * Whether mode `id` can be entered on `targetId` now. Where it says no the double-click falls\n * through to the next binding on it, so a canvas action that already enters the mode on some\n * of those nodes keeps them: `enterPathEdit` on a path with anchors, say. Default yes.\n */\n canEnter?: (id: string, targetId: string) => boolean;\n}\n\n/**\n * The registry's double-click entries as an always-on contribution: for each mode whose\n * `entry.trigger` is `'double-click-target'`, one action bound to a double-click on each routing\n * kind its `entry.targets` names, entering the mode on the node double-clicked. Install it with\n * `<SceneCanvas ambient>`, beside `modeShortcuts`.\n *\n * The target is the node the dispatcher classified the double-click on (the `hitAt` dep's\n * `doubleClick`, else its hit), the one the binding's `kind:` target matched: a double-click on\n * a grouped member names its outermost group inside the entered group (`<SceneCanvas enteredGroup>`).\n * The action is live in every mode, the target mode included, so a double-click on another node\n * moves a mode onto it; `canEnter` and `enter` decide what a switch from the current mode means.\n *\n * The bindings ride the ambient tier: a tool that claims the double-click itself, the pen\n * finishing a stroke, keeps it.\n */\nexport function modeTriggers(registry: ModeRegistry, handlers: ModeTriggerHandlers): Contribution<never> {\n const actions: Action[] = [];\n const { enter } = handlers;\n if (enter) {\n for (const mode of registry.list()) {\n const targets = mode.entry?.trigger === 'double-click-target' ? mode.entry.targets ?? [] : [];\n if (targets.length > 0) actions.push(triggerAction(mode, targets, enter, handlers.canEnter));\n }\n }\n return { id: 'modes.triggers', eligibility: { always: true }, actions };\n}\n\nfunction triggerAction(\n mode: ModeDefinition,\n targets: readonly string[],\n enter: (id: string, targetId: string) => void,\n canEnter: ModeTriggerHandlers['canEnter'],\n): Action {\n const targetAt = (deps: ActionDeps | undefined, at: { x: number; y: number } | undefined): string | null => {\n if (!at) return null;\n const hit = deps?.hitAt?.(at);\n const id = (hit?.doubleClick ?? hit)?.id;\n if (id === undefined) return null;\n return canEnter?.(mode.id, id) === false ? null : id;\n };\n const id = `mode.${mode.id}.trigger`;\n return {\n id,\n label: `Enter ${modeLabel(mode)}`,\n defaultBinding: targets.map((kind) => ({\n spec: { kind: 'doubleClick' as const, target: `kind:${kind}` as const },\n opts: { id: `${id}.doubleClick.${kind}` },\n })),\n requires: ['hitAt'],\n enabled: (deps, at) => (targetAt(deps, at) !== null ? true : ActionDisabledReason.NotApplicable),\n invoker: {\n timing: 'immediate',\n run: (deps, params) => {\n const world = (params as ImmediateParams | undefined)?.world;\n const id = world ? targetAt(deps, world) : null;\n if (id !== null) enter(mode.id, id);\n },\n },\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA+BA,SAAgB,aAAa,UAAwB,UAAoD;CACvG,MAAM,UAAoB,CAAC;CAC3B,MAAM,EAAE,UAAU;CAClB,IAAI,OACF,KAAK,MAAM,QAAQ,SAAS,KAAK,GAAG;EAClC,MAAM,UAAU,KAAK,OAAO,YAAY,wBAAwB,KAAK,MAAM,WAAW,CAAC,IAAI,CAAC;EAC5F,IAAI,QAAQ,SAAS,GAAG,QAAQ,KAAK,cAAc,MAAM,SAAS,OAAO,SAAS,QAAQ,CAAC;CAC7F;CAEF,OAAO;EAAE,IAAI;EAAkB,aAAa,EAAE,QAAQ,KAAK;EAAG;CAAQ;AACxE;AAEA,SAAS,cACP,MACA,SACA,OACA,UACQ;CACR,MAAM,YAAY,MAA8B,OAA4D;EAC1G,IAAI,CAAC,IAAI,OAAO;EAChB,MAAM,MAAM,MAAM,QAAQ,EAAE;EAC5B,MAAM,MAAM,KAAK,eAAe,IAAA,EAAM;EACtC,IAAI,OAAO,QAAW,OAAO;EAC7B,OAAO,WAAW,KAAK,IAAI,EAAE,MAAM,QAAQ,OAAO;CACpD;CACA,MAAM,KAAK,QAAQ,KAAK,GAAG;CAC3B,OAAO;EACL;EACA,OAAO,SAAS,UAAU,IAAI;EAC9B,gBAAgB,QAAQ,KAAK,UAAU;GACrC,MAAM;IAAE,MAAM;IAAwB,QAAQ,QAAQ;GAAgB;GACtE,MAAM,EAAE,IAAI,GAAG,GAAG,eAAe,OAAO;EAC1C,EAAE;EACF,UAAU,CAAC,OAAO;EAClB,UAAU,MAAM,OAAQ,SAAS,MAAM,EAAE,MAAM,OAAO,OAAO,qBAAqB;EAClF,SAAS;GACP,QAAQ;GACR,MAAM,MAAM,WAAW;IACrB,MAAM,QAAS,QAAwC;IACvD,MAAM,KAAK,QAAQ,SAAS,MAAM,KAAK,IAAI;IAC3C,IAAI,OAAO,MAAM,MAAM,KAAK,IAAI,EAAE;GACpC;EACF;CACF;AACF"}
@@ -2,7 +2,7 @@ import { sourcesOf } from "../../core/scene/dependents.js";
2
2
  import { pathEffectOf } from "../../core/scene/pathEffects/derive.js";
3
3
  import { isTextData } from "@weasel-js/text";
4
4
 
5
- //#region src/features/pathEffects/effectSources.ts
5
+ //#region src/domains/pathEffects/effectSources.ts
6
6
  /**
7
7
  * A path effect that hides its sources is edited through itself: its text and
8
8
  * its path are reached from the effect node.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"effectSources.js","names":[],"sources":["../../../src/domains/pathEffects/effectSources.ts"],"sourcesContent":["/**\n * A path effect that hides its sources is edited through itself: its text and\n * its path are reached from the effect node.\n */\nimport { isTextData } from '@weasel-js/text';\nimport { pathEffectOf } from 'core/scene/pathEffects/derive';\nimport { sourcesOf } from 'core/scene/dependents';\nimport type { NodeId, Scene } from 'core/scene/types';\n\n/**\n * For a path-effect node with `hideSources`, the source an edit of `role`\n * goes to: `'text'`, its first source when that is a text node; `'path'`, the\n * path it lays along — the second source of an along kind, a blend's spine.\n * `null` otherwise. The one answer every edit route asks. It takes a source\n * hidden before the effect was made too: either way the effect is what shows it.\n */\nexport function effectSourceFor<TData, TLayer extends string, TPose>(\n scene: Pick<Scene<TData, TLayer, TPose>, 'get'>,\n id: NodeId,\n role: 'text' | 'path',\n): NodeId | null {\n const node = scene.get(id);\n const effect = pathEffectOf(node);\n if (effect === null || effect.hideSources !== true) return null;\n const at = role === 'text' ? 0 : effect.kind === 'blend' ? 2 : 1;\n const source = sourcesOf(node)[at];\n const found = source === undefined ? undefined : scene.get(source);\n if (found === undefined) return null;\n return role === 'text' && !isTextData(found.data) ? null : source!;\n}\n\n/**\n * The sources path-effect node `id` holds hidden: with `hideSources`, each of\n * its sources but those it found hidden. Empty for any other node.\n */\nexport function sourcesHiddenBy<TData, TLayer extends string, TPose>(\n scene: Pick<Scene<TData, TLayer, TPose>, 'get'>,\n id: NodeId,\n): NodeId[] {\n const node = scene.get(id);\n const effect = pathEffectOf(node);\n if (effect?.hideSources !== true) return [];\n const found = effect.foundHidden ?? [];\n return sourcesOf(node).filter((_, at) => !found.includes(at));\n}\n\n/**\n * The sources a removal of `ids` takes with it: those that a path effect with\n * `hideSources` in the removal hid, and that nothing staying still derives\n * from. A source another effect still reads stays, and so does one shown\n * again since or named in `keep`. Transitive, so an effect's hidden effect\n * takes its own too.\n */\nexport function hiddenSourcesTakenWith<TData, TLayer extends string, TPose>(\n scene: Pick<Scene<TData, TLayer, TPose>, 'get' | 'removalClosure'>,\n ids: readonly NodeId[],\n keep: ReadonlySet<NodeId> = new Set(),\n): NodeId[] {\n const going = new Set<NodeId>(scene.removalClosure(ids));\n const taken: NodeId[] = [];\n const within = (node: NodeId, root: NodeId): boolean => {\n for (let at: NodeId | null | undefined = node; at != null; at = scene.get(at)?.parent) if (at === root) return true;\n return false;\n };\n let grew = true;\n while (grew) {\n grew = false;\n for (const id of [...going]) {\n for (const source of sourcesHiddenBy(scene, id)) {\n if (going.has(source) || keep.has(source) || scene.get(source)?.hidden !== true) continue;\n const closure = scene.removalClosure([source]);\n if (!closure.every((n) => going.has(n) || within(n, source))) continue;\n for (const n of closure) going.add(n);\n taken.push(source);\n grew = true;\n }\n }\n }\n return taken;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAgBA,SAAgB,gBACd,OACA,IACA,MACe;CACf,MAAM,OAAO,MAAM,IAAI,EAAE;CACzB,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,WAAW,QAAQ,OAAO,gBAAgB,MAAM,OAAO;CAC3D,MAAM,KAAK,SAAS,SAAS,IAAI,OAAO,SAAS,UAAU,IAAI;CAC/D,MAAM,SAAS,UAAU,IAAI,CAAC,CAAC;CAC/B,MAAM,QAAQ,WAAW,SAAY,SAAY,MAAM,IAAI,MAAM;CACjE,IAAI,UAAU,QAAW,OAAO;CAChC,OAAO,SAAS,UAAU,CAAC,WAAW,MAAM,IAAI,IAAI,OAAO;AAC7D;;;;;AAMA,SAAgB,gBACd,OACA,IACU;CACV,MAAM,OAAO,MAAM,IAAI,EAAE;CACzB,MAAM,SAAS,aAAa,IAAI;CAChC,IAAI,QAAQ,gBAAgB,MAAM,OAAO,CAAC;CAC1C,MAAM,QAAQ,OAAO,eAAe,CAAC;CACrC,OAAO,UAAU,IAAI,CAAC,CAAC,QAAQ,GAAG,OAAO,CAAC,MAAM,SAAS,EAAE,CAAC;AAC9D;;;;;;;;AASA,SAAgB,uBACd,OACA,KACA,uBAA4B,IAAI,IAAI,GAC1B;CACV,MAAM,QAAQ,IAAI,IAAY,MAAM,eAAe,GAAG,CAAC;CACvD,MAAM,QAAkB,CAAC;CACzB,MAAM,UAAU,MAAc,SAA0B;EACtD,KAAK,IAAI,KAAgC,MAAM,MAAM,MAAM,KAAK,MAAM,IAAI,EAAE,CAAC,EAAE,QAAQ,IAAI,OAAO,MAAM,OAAO;EAC/G,OAAO;CACT;CACA,IAAI,OAAO;CACX,OAAO,MAAM;EACX,OAAO;EACP,KAAK,MAAM,MAAM,CAAC,GAAG,KAAK,GACxB,KAAK,MAAM,UAAU,gBAAgB,OAAO,EAAE,GAAG;GAC/C,IAAI,MAAM,IAAI,MAAM,KAAK,KAAK,IAAI,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,EAAE,WAAW,MAAM;GACjF,MAAM,UAAU,MAAM,eAAe,CAAC,MAAM,CAAC;GAC7C,IAAI,CAAC,QAAQ,OAAO,MAAM,MAAM,IAAI,CAAC,KAAK,OAAO,GAAG,MAAM,CAAC,GAAG;GAC9D,KAAK,MAAM,KAAK,SAAS,MAAM,IAAI,CAAC;GACpC,MAAM,KAAK,MAAM;GACjB,OAAO;EACT;CAEJ;CACA,OAAO;AACT"}
@@ -1,7 +1,7 @@
1
1
  import { PATH_EFFECT, createPathEffectDerivations } from "../../core/scene/pathEffects/derive.js";
2
2
  import { readEffectSource } from "./readSource.js";
3
3
 
4
- //#region src/features/pathEffects/index.ts
4
+ //#region src/domains/pathEffects/index.ts
5
5
  /**
6
6
  * The kit's path effects, wired to its painters: the derivations a scene
7
7
  * holding blends, bends and repeats registers, and the registry helper that
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/domains/pathEffects/index.ts"],"sourcesContent":["/**\n * The kit's path effects, wired to its painters: the derivations a scene\n * holding blends, bends and repeats registers, and the registry helper that\n * registers them.\n */\nimport {\n createPathEffectDerivations, PATH_EFFECT, type PathEffectDerivations,\n} from 'core/scene/pathEffects/derive';\nimport type { SceneRegistry } from 'core/scene/types';\nimport { readEffectSource } from './readSource';\n\nexport { readEffectSource };\n\n/** The kit's path-effect derivations, reading sources through the painter\n * registry. One pair for every scene, so a saved node finds them by key. */\nexport const PATH_EFFECT_DERIVATIONS: PathEffectDerivations = createPathEffectDerivations(readEffectSource);\n\n/**\n * `registry` with the path-effect derivations under `kit:pathEffect`, for\n * `createScene({ registry })` or `sceneFromJSON(json, { registry })`. A scene\n * built without them cannot hold a path effect: the actions that make one are\n * disabled there, and a saved one does not load.\n */\nexport function withPathEffectsRegistry<TPose, TData = unknown, TLayer extends string = string>(\n registry: SceneRegistry<TPose, TData, TLayer> = {},\n): SceneRegistry<TPose, TData, TLayer> {\n type Fns<K extends 'derivePath' | 'derivePose'> = NonNullable<SceneRegistry<TPose, TData, TLayer>[K]>[string];\n return {\n ...registry,\n derivePath: { [PATH_EFFECT]: PATH_EFFECT_DERIVATIONS.derivePath as unknown as Fns<'derivePath'>, ...registry.derivePath },\n derivePose: { [PATH_EFFECT]: PATH_EFFECT_DERIVATIONS.derivePose as unknown as Fns<'derivePose'>, ...registry.derivePose },\n };\n}\n"],"mappings":";;;;;;;;;;;AAeA,IAAa,0BAAiD,4BAA4B,gBAAgB;;;;;;;AAQ1G,SAAgB,wBACd,WAAgD,CAAC,GACZ;CAErC,OAAO;EACL,GAAG;EACH,YAAY;IAAG,cAAc,wBAAwB;GAA4C,GAAG,SAAS;EAAW;EACxH,YAAY;IAAG,cAAc,wBAAwB;GAA4C,GAAG,SAAS;EAAW;CAC1H;AACF"}
@@ -6,7 +6,7 @@ import { textEffectItems } from "./textItems.js";
6
6
  import { pathThroughPoseFrame, poseLinearOf } from "@weasel-js/geom";
7
7
  import { isTextData } from "@weasel-js/text";
8
8
 
9
- //#region src/features/pathEffects/readSource.ts
9
+ //#region src/domains/pathEffects/readSource.ts
10
10
  /**
11
11
  * How the kit's path effects read a source node: its outline from its
12
12
  * painter's silhouette, its paint as `kit:path` resolves it.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readSource.js","names":[],"sources":["../../../src/domains/pathEffects/readSource.ts"],"sourcesContent":["/**\n * How the kit's path effects read a source node: its outline from its\n * painter's silhouette, its paint as `kit:path` resolves it.\n */\nimport { pathThroughPoseFrame, poseLinearOf, type PathInWorldPose } from '@weasel-js/geom';\nimport type { Fill, Stroke } from '@weasel-js/paint';\nimport { isTextData, type TextOutlineSource } from '@weasel-js/text';\nimport { findNodeShape } from 'canvas/NodeShape';\nimport { isRectPose } from 'core/geometry/autoPoseDescriptor';\nimport { noteFontRead } from 'core/scene/fontReads';\nimport type { EffectSource } from 'core/scene/pathEffects/source';\nimport type { DerivedDep } from 'core/scene/types';\nimport { pathPaintOf } from 'canvas/nodeShapes/nodePaint';\nimport { textEffectItems } from './textItems';\n\n/** `dep` as a path effect's source, or `null` when it has no outline. A text\n * node's source also carries its grapheme clusters as items. */\nexport function readEffectSource(dep: DerivedDep<unknown>): EffectSource | null {\n const data = dep.node.data;\n const text = isTextData(data);\n // A text node's outline is laid out in its face, which may not have landed: without this read, an effect that found\n // no outline while the face loads would never look again.\n if (text) noteFontRead();\n const source = readShape(dep);\n const pose = dep.pose;\n if (source === null || !text || !isRectPose(pose)) return source;\n return { ...source, items: () => textEffectItems(data as TextOutlineSource, pose as PathInWorldPose) };\n}\n\nfunction readShape(dep: DerivedDep<unknown>): EffectSource | null {\n const data = (dep.node.data ?? {}) as { fill?: Fill | null; stroke?: Stroke | null };\n const { fill, stroke } = pathPaintOf(data, dep.inherited);\n const paint = { fill, stroke: stroke ?? null };\n const shown = dep.path;\n if (shown !== null) return { world: shown, ...paint };\n const local = findNodeShape(dep.node)?.silhouette?.(dep.node, dep.pose) ?? null;\n if (local === null) return null;\n const world = pathThroughPoseFrame(local, dep.pose);\n const pose = dep.pose;\n if (!isRectPose(pose) || poseLinearOf(pose) !== null) return { world, ...paint };\n return {\n world,\n framed: { path: local, cx: pose.x + pose.width / 2, cy: pose.y + pose.height / 2, rotation: pose.rotation ?? 0 },\n ...paint,\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAiBA,SAAgB,iBAAiB,KAA+C;CAC9E,MAAM,OAAO,IAAI,KAAK;CACtB,MAAM,OAAO,WAAW,IAAI;CAG5B,IAAI,MAAM,aAAa;CACvB,MAAM,SAAS,UAAU,GAAG;CAC5B,MAAM,OAAO,IAAI;CACjB,IAAI,WAAW,QAAQ,CAAC,QAAQ,CAAC,WAAW,IAAI,GAAG,OAAO;CAC1D,OAAO;EAAE,GAAG;EAAQ,aAAa,gBAAgB,MAA2B,IAAuB;CAAE;AACvG;AAEA,SAAS,UAAU,KAA+C;CAChE,MAAM,OAAQ,IAAI,KAAK,QAAQ,CAAC;CAChC,MAAM,EAAE,MAAM,WAAW,YAAY,MAAM,IAAI,SAAS;CACxD,MAAM,QAAQ;EAAE;EAAM,QAAQ,UAAU;CAAK;CAC7C,MAAM,QAAQ,IAAI;CAClB,IAAI,UAAU,MAAM,OAAO;EAAE,OAAO;EAAO,GAAG;CAAM;CACpD,MAAM,QAAQ,cAAc,IAAI,IAAI,CAAC,EAAE,aAAa,IAAI,MAAM,IAAI,IAAI,KAAK;CAC3E,IAAI,UAAU,MAAM,OAAO;CAC3B,MAAM,QAAQ,qBAAqB,OAAO,IAAI,IAAI;CAClD,MAAM,OAAO,IAAI;CACjB,IAAI,CAAC,WAAW,IAAI,KAAK,aAAa,IAAI,MAAM,MAAM,OAAO;EAAE;EAAO,GAAG;CAAM;CAC/E,OAAO;EACL;EACA,QAAQ;GAAE,MAAM;GAAO,IAAI,KAAK,IAAI,KAAK,QAAQ;GAAG,IAAI,KAAK,IAAI,KAAK,SAAS;GAAG,UAAU,KAAK,YAAY;EAAE;EAC/G,GAAG;CACL;AACF"}
@@ -2,10 +2,11 @@ import { noteFontRead } from "../../core/scene/fontReads.js";
2
2
  import { poseFrameOf, transformPath } from "@weasel-js/geom";
3
3
  import { TextOutlinesError, loadTextOutlines, textClusters } from "@weasel-js/text";
4
4
 
5
- //#region src/features/pathEffects/textItems.ts
5
+ //#region src/domains/pathEffects/textItems.ts
6
6
  /**
7
7
  * A text node as a path effect's items: its first line's grapheme clusters,
8
- * each one's outlines in its own frame, sized as the node draws them.
8
+ * each one's outlines and decoration rules in its own frame, sized as the node
9
+ * draws them.
9
10
  */
10
11
  /**
11
12
  * The clusters of `data`'s first line as items, laid in `pose`'s box width.
@@ -40,6 +41,14 @@ function textEffectItems(data, pose) {
40
41
  path: grow === null ? p.path : transformPath(p.path, grow),
41
42
  fill: p.fill,
42
43
  stroke: p.stroke ?? null
44
+ })),
45
+ bands: c.rules.map((r) => ({
46
+ x0: r.x0 * k,
47
+ x1: r.x1 * k,
48
+ y0: r.y0 * k,
49
+ y1: r.y1 * k,
50
+ fill: r.fill,
51
+ stroke: r.stroke ?? null
43
52
  }))
44
53
  }));
45
54
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textItems.js","names":[],"sources":["../../../src/domains/pathEffects/textItems.ts"],"sourcesContent":["/**\n * A text node as a path effect's items: its first line's grapheme clusters,\n * each one's outlines and decoration rules in its own frame, sized as the node\n * draws them.\n */\nimport { poseFrameOf, transformPath, type Affine, type PathInWorldPose } from '@weasel-js/geom';\nimport {\n loadTextOutlines, textClusters, TextOutlinesError, type TextCluster, type TextOutlineSource,\n} from '@weasel-js/text';\nimport { noteFontRead } from 'core/scene/fontReads';\nimport type { EffectItem } from 'core/scene/pathEffects/source';\n\n/**\n * The clusters of `data`'s first line as items, laid in `pose`'s box width.\n * The pose's scale grows them; its rotation and skew are dropped, since the\n * path an effect lays them along decides their turn. `[]` while a face's\n * outlines are loading — the load is started, and the font read is noted so\n * the derivation re-runs once it lands.\n */\nexport function textEffectItems(data: TextOutlineSource, pose: PathInWorldPose): readonly EffectItem[] {\n noteFontRead();\n let clusters: TextCluster[];\n try {\n clusters = textClusters(data, { width: pose.width });\n } catch (err) {\n if (!(err instanceof TextOutlinesError)) throw err;\n loadTextOutlines(data).catch(() => {});\n return [];\n }\n const k = scaleOf(pose);\n const grow: Affine | null = k === 1 ? null : [k, 0, 0, k, 0, 0];\n return clusters.map((c) => ({\n length: c.advance * k,\n middle: c.middle * k,\n parts: c.paths.map((p) => ({\n path: grow === null ? p.path : transformPath(p.path, grow),\n fill: p.fill,\n stroke: p.stroke ?? null,\n })),\n bands: c.rules.map((r) => ({\n x0: r.x0 * k, x1: r.x1 * k, y0: r.y0 * k, y1: r.y1 * k, fill: r.fill, stroke: r.stroke ?? null,\n })),\n }));\n}\n\nfunction scaleOf(pose: PathInWorldPose): number {\n const m = poseFrameOf(pose);\n return m === null ? 1 : Math.sqrt(Math.abs(m[0] * m[3] - m[1] * m[2]));\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAmBA,SAAgB,gBAAgB,MAAyB,MAA8C;CACrG,aAAa;CACb,IAAI;CACJ,IAAI;EACF,WAAW,aAAa,MAAM,EAAE,OAAO,KAAK,MAAM,CAAC;CACrD,SAAS,KAAK;EACZ,IAAI,EAAE,eAAe,oBAAoB,MAAM;EAC/C,iBAAiB,IAAI,CAAC,CAAC,YAAY,CAAC,CAAC;EACrC,OAAO,CAAC;CACV;CACA,MAAM,IAAI,QAAQ,IAAI;CACtB,MAAM,OAAsB,MAAM,IAAI,OAAO;EAAC;EAAG;EAAG;EAAG;EAAG;EAAG;CAAC;CAC9D,OAAO,SAAS,KAAK,OAAO;EAC1B,QAAQ,EAAE,UAAU;EACpB,QAAQ,EAAE,SAAS;EACnB,OAAO,EAAE,MAAM,KAAK,OAAO;GACzB,MAAM,SAAS,OAAO,EAAE,OAAO,cAAc,EAAE,MAAM,IAAI;GACzD,MAAM,EAAE;GACR,QAAQ,EAAE,UAAU;EACtB,EAAE;EACF,OAAO,EAAE,MAAM,KAAK,OAAO;GACzB,IAAI,EAAE,KAAK;GAAG,IAAI,EAAE,KAAK;GAAG,IAAI,EAAE,KAAK;GAAG,IAAI,EAAE,KAAK;GAAG,MAAM,EAAE;GAAM,QAAQ,EAAE,UAAU;EAC5F,EAAE;CACJ,EAAE;AACJ;AAEA,SAAS,QAAQ,MAA+B;CAC9C,MAAM,IAAI,YAAY,IAAI;CAC1B,OAAO,MAAM,OAAO,IAAI,KAAK,KAAK,KAAK,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,CAAC;AACvE"}
@@ -6,7 +6,7 @@ import { readEffectSource } from "./readSource.js";
6
6
  import { useMemo } from "react";
7
7
  import { useLatest } from "@weasel-js/react";
8
8
 
9
- //#region src/features/pathEffects/useEffectSourcesLayer.ts
9
+ //#region src/domains/pathEffects/useEffectSourcesLayer.ts
10
10
  /**
11
11
  * The layer that shows what a selected path effect was made from: the outlines
12
12
  * of the sources it hides, drawn faintly under the selection chrome.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useEffectSourcesLayer.js","names":[],"sources":["../../../src/domains/pathEffects/useEffectSourcesLayer.ts"],"sourcesContent":["/**\n * The layer that shows what a selected path effect was made from: the outlines\n * of the sources it hides, drawn faintly under the selection chrome.\n */\nimport { useMemo } from 'react';\nimport { useLatest } from '@weasel-js/react';\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport { PATH_OVERLAY_ROLES } from 'canvas/pathOverlay';\nimport { sceneDepLookup } from 'canvas/derivedPath';\nimport { chromeStateFrom } from 'canvas/drawEnvelope';\nimport type { RenderLayer } from 'core/layers/render';\nimport { sourcesHiddenBy } from './effectSources';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport { readEffectSource } from './readSource';\n\nconst FAINT = 0.4;\n\n/** For each selected path-effect node, the outlines of the sources it holds hidden (`sourcesHiddenBy`) as the effect\n * reads them, in a one-screen-pixel stroke of the `'chrome'` overlay color at 40% opacity. The selection comes off the draw envelope. */\nexport function useEffectSourcesLayer<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n): RenderLayer<unknown> {\n const sceneRef = useLatest(scene);\n return useMemo<RenderLayer<unknown>>(() => ({\n id: 'effect-sources',\n label: 'Hidden effect sources',\n space: 'world',\n draw: (data) => {\n const selected = chromeStateFrom(data)?.selection ?? [];\n const sc = sceneRef.current;\n const stroke = PATH_OVERLAY_ROLES['chrome']!.stroke!;\n const depOf = sceneDepLookup(sc);\n const lines: DrawCommand[] = [];\n for (const id of selected) {\n for (const source of sourcesHiddenBy(sc, id as NodeId)) {\n if (!sc.isHidden(source)) continue;\n const dep = depOf(source);\n const path = dep === undefined ? null : readEffectSource(dep as never)?.world ?? null;\n if (path !== null) lines.push({ kind: 'path', path, stroke: { paint: stroke, width: { px: 1 } } });\n }\n }\n return lines.length === 0 ? [] : [{ kind: 'group', alpha: FAINT, children: lines }];\n },\n }), [sceneRef]);\n}\n"],"mappings":";;;;;;;;;;;;;AAeA,IAAM,QAAQ;;;AAId,SAAgB,sBACd,OACsB;CACtB,MAAM,WAAW,UAAU,KAAK;CAChC,OAAO,eAAqC;EAC1C,IAAI;EACJ,OAAO;EACP,OAAO;EACP,OAAO,SAAS;GACd,MAAM,WAAW,gBAAgB,IAAI,CAAC,EAAE,aAAa,CAAC;GACtD,MAAM,KAAK,SAAS;GACpB,MAAM,SAAS,mBAAmB,SAAS,CAAE;GAC7C,MAAM,QAAQ,eAAe,EAAE;GAC/B,MAAM,QAAuB,CAAC;GAC9B,KAAK,MAAM,MAAM,UACf,KAAK,MAAM,UAAU,gBAAgB,IAAI,EAAY,GAAG;IACtD,IAAI,CAAC,GAAG,SAAS,MAAM,GAAG;IAC1B,MAAM,MAAM,MAAM,MAAM;IACxB,MAAM,OAAO,QAAQ,SAAY,OAAO,iBAAiB,GAAY,CAAC,EAAE,SAAS;IACjF,IAAI,SAAS,MAAM,MAAM,KAAK;KAAE,MAAM;KAAQ;KAAM,QAAQ;MAAE,OAAO;MAAQ,OAAO,EAAE,IAAI,EAAE;KAAE;IAAE,CAAC;GACnG;GAEF,OAAO,MAAM,WAAW,IAAI,CAAC,IAAI,CAAC;IAAE,MAAM;IAAS,OAAO;IAAO,UAAU;GAAM,CAAC;EACpF;CACF,IAAI,CAAC,QAAQ,CAAC;AAChB"}
@@ -2,7 +2,7 @@ import { remapSkin } from "../../animation/rig/skinBinding.js";
2
2
  import { anchorOriginsOf, remapAnchorValues } from "@weasel-js/geom";
3
3
  import { vertexHalfWidths, vertexWidthFromSides } from "@weasel-js/paint";
4
4
 
5
- //#region src/features/paths/anchorData.ts
5
+ //#region src/domains/paths/anchorData.ts
6
6
  /**
7
7
  * What a node keeps per anchor or per point of its path beside the geometry,
8
8
  * carried through an anchor edit: a skin's weights, the fill's and the
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchorData.js","names":[],"sources":["../../../src/domains/paths/anchorData.ts"],"sourcesContent":["/**\n * What a node keeps per anchor or per point of its path beside the geometry,\n * carried through an anchor edit: a skin's weights, the fill's and the\n * stroke's vertex colors, and the stroke's widths. The edit says where each\n * new point came from (`editAnchorSetTracked`); everything here follows it.\n */\nimport {\n anchorOriginsOf, remapAnchorValues, type PointOrigin, type PolygonPath,\n} from '@weasel-js/geom';\nimport { vertexHalfWidths, vertexWidthFromSides, type VertexWidth } from '@weasel-js/paint';\nimport type { Skin } from '@weasel-js/animator';\nimport { remapSkin } from '../../animation/rig/skinBinding';\n\n/** Channels per anchor in a `vertexColors` array. */\nconst COLOR_STRIDE = 4;\n\ninterface AnchorDataCarrier {\n skin?: Skin;\n vertexColors?: number[];\n stroke?: { vertexColors?: number[]; vertexWidths?: VertexWidth[]; width?: unknown } | null;\n}\n\ntype Edit = { before: PolygonPath; after: PolygonPath; origins: readonly (PointOrigin | null)[] };\n\nconst swapped = (w: VertexWidth): VertexWidth => (typeof w === 'number' ? w : { left: w.right, right: w.left });\n\n/**\n * A stroke's `vertexWidths` through an edit. A kept anchor keeps its entry,\n * its sides traded where its subpath now runs the other way; a made one\n * blends the sides of the two it came between, an unset side reading the\n * stroke's own `width`; a deleted one's entry goes. Unset stays `NaN`.\n */\nfunction carryWidths(widths: readonly VertexWidth[], width: unknown, { before, after, origins }: Edit): VertexWidth[] {\n const fallback = typeof width === 'number' ? width : Number.NaN;\n return anchorOriginsOf(before, after, origins).map((o) => {\n if (!o) return Number.NaN;\n let entry: VertexWidth = widths[o.a] ?? Number.NaN;\n if (o.t !== 0 && o.b !== o.a) {\n const a = vertexHalfWidths(widths[o.a], fallback);\n const b = vertexHalfWidths(widths[o.b], fallback);\n entry = vertexWidthFromSides(a.left + (b.left - a.left) * o.t, a.right + (b.right - a.right) * o.t);\n }\n return o.reversed ? swapped(entry) : entry;\n });\n}\n\n/**\n * The per-anchor fields of `data`, renumbered for the edit from `before` to\n * `after`, to lay over it; empty when it holds none. Only what `data`\n * already has is written.\n */\nexport function anchorDataPatch(\n data: unknown,\n before: PolygonPath,\n after: PolygonPath,\n origins: readonly (PointOrigin | null)[],\n): Record<string, unknown> {\n if (!data || typeof data !== 'object') return {};\n const d = data as AnchorDataCarrier;\n const edit = { before, after, origins };\n const colors = (values: number[]) => remapAnchorValues(values, COLOR_STRIDE, before, after, origins);\n const patch: AnchorDataCarrier = {};\n if (d.skin) patch.skin = remapSkin(d.skin, origins);\n if (d.vertexColors) patch.vertexColors = colors(d.vertexColors);\n const stroke = d.stroke;\n if (stroke?.vertexColors || stroke?.vertexWidths) {\n patch.stroke = {\n ...stroke,\n ...(stroke.vertexColors ? { vertexColors: colors(stroke.vertexColors) } : {}),\n ...(stroke.vertexWidths ? { vertexWidths: carryWidths(stroke.vertexWidths, stroke.width, edit) } : {}),\n };\n }\n return patch as Record<string, unknown>;\n}\n"],"mappings":";;;;;;;;;;;;AAcA,IAAM,eAAe;AAUrB,IAAM,WAAW,MAAiC,OAAO,MAAM,WAAW,IAAI;CAAE,MAAM,EAAE;CAAO,OAAO,EAAE;AAAK;;;;;;;AAQ7G,SAAS,YAAY,QAAgC,OAAgB,EAAE,QAAQ,OAAO,WAAgC;CACpH,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ;CACrD,OAAO,gBAAgB,QAAQ,OAAO,OAAO,CAAC,CAAC,KAAK,MAAM;EACxD,IAAI,CAAC,GAAG,OAAO;EACf,IAAI,QAAqB,OAAO,EAAE,MAAM;EACxC,IAAI,EAAE,MAAM,KAAK,EAAE,MAAM,EAAE,GAAG;GAC5B,MAAM,IAAI,iBAAiB,OAAO,EAAE,IAAI,QAAQ;GAChD,MAAM,IAAI,iBAAiB,OAAO,EAAE,IAAI,QAAQ;GAChD,QAAQ,qBAAqB,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;EACpG;EACA,OAAO,EAAE,WAAW,QAAQ,KAAK,IAAI;CACvC,CAAC;AACH;;;;;;AAOA,SAAgB,gBACd,MACA,QACA,OACA,SACyB;CACzB,IAAI,CAAC,QAAQ,OAAO,SAAS,UAAU,OAAO,CAAC;CAC/C,MAAM,IAAI;CACV,MAAM,OAAO;EAAE;EAAQ;EAAO;CAAQ;CACtC,MAAM,UAAU,WAAqB,kBAAkB,QAAQ,cAAc,QAAQ,OAAO,OAAO;CACnG,MAAM,QAA2B,CAAC;CAClC,IAAI,EAAE,MAAM,MAAM,OAAO,UAAU,EAAE,MAAM,OAAO;CAClD,IAAI,EAAE,cAAc,MAAM,eAAe,OAAO,EAAE,YAAY;CAC9D,MAAM,SAAS,EAAE;CACjB,IAAI,QAAQ,gBAAgB,QAAQ,cAClC,MAAM,SAAS;EACb,GAAG;EACH,GAAI,OAAO,eAAe,EAAE,cAAc,OAAO,OAAO,YAAY,EAAE,IAAI,CAAC;EAC3E,GAAI,OAAO,eAAe,EAAE,cAAc,YAAY,OAAO,cAAc,OAAO,OAAO,IAAI,EAAE,IAAI,CAAC;CACtG;CAEF,OAAO;AACT"}
@@ -1,6 +1,6 @@
1
- import { circlePath, linePath, pathToAnchors, resolveCorners, squarePath } from "@weasel-js/geom";
1
+ import { circlePath, linePath, pathToAnchors, resolveCorners, squarePath, worldCoords } from "@weasel-js/geom";
2
2
 
3
- //#region src/features/paths/anchorMarkers.ts
3
+ //#region src/domains/paths/anchorMarkers.ts
4
4
  /** The path-edit overlay's look where a {@link PathEditingOverlayStyle} leaves a field out. */
5
5
  var DEFAULT_OVERLAY_STYLE = {
6
6
  anchorSizePx: 8,
@@ -25,14 +25,16 @@ function worldToScreen(p, view) {
25
25
  /** `path`, its corners expanded, with every coordinate carried to screen
26
26
  * through `view`: a radius left on it would stay in world units. */
27
27
  function onScreen(path, view) {
28
- path = resolveCorners(path);
29
- const coords = new Float32Array(path.coords.length);
28
+ const resolved = resolveCorners(path);
29
+ const world = worldCoords(resolved);
30
+ const { origin: _measuredFrom, ...drawn } = resolved;
31
+ const coords = new Float32Array(world.length);
30
32
  for (let i = 0; i < coords.length; i += 2) {
31
- coords[i] = (path.coords[i] - view.x) * view.scale.x;
32
- coords[i + 1] = (path.coords[i + 1] - view.y) * view.scale.y;
33
+ coords[i] = (world[i] - view.x) * view.scale.x;
34
+ coords[i + 1] = (world[i + 1] - view.y) * view.scale.y;
33
35
  }
34
36
  return {
35
- ...path,
37
+ ...drawn,
36
38
  coords
37
39
  };
38
40
  }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anchorMarkers.js","names":[],"sources":["../../../src/domains/paths/anchorMarkers.ts"],"sourcesContent":["/**\n * The draw commands path edit paints for the open path, in screen space: its\n * outline, then each anchor's handles and marker.\n */\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { WorldPoint } from '@weasel-js/routing';\nimport {\n circlePath, linePath, pathToAnchors, resolveCorners, squarePath, worldCoords, type PenAnchor, type PolygonPath, type View, type Point,\n} from '@weasel-js/geom';\nimport type { AnchorMarkerShape } from './pathRepresentation';\n\n/** Appearance of the outline and of the anchor and handle markers. */\nexport interface PathEditingOverlayStyle {\n anchorSizePx?: number;\n handleDotRadiusPx?: number;\n anchorFill?: string;\n anchorStroke?: string;\n handleStroke?: string;\n /** Fill of the control-point circle. Defaults to the handleStroke color\n * at 50% alpha. */\n handleDotFill?: string;\n /** Fill of a selected anchor square. Defaults to the anchor stroke color. */\n anchorFillSelected?: string;\n /** The open path's outline, drawn over its own fill and stroke so the path\n * shows however its paint and its markers cover it. */\n outlineStroke?: string;\n outlineWidthPx?: number;\n /** Radius of the dot an unselected anchor shrinks to where anchors sit\n * closer together on screen than a marker is wide. */\n denseDotRadiusPx?: number;\n /** Stroke of the marquee rubber band. */\n marqueeStroke?: string;\n /** Fill of the marquee rubber band. */\n marqueeFill?: string;\n}\n\n/** The path-edit overlay's look where a {@link PathEditingOverlayStyle} leaves a field out. */\nexport const DEFAULT_OVERLAY_STYLE: Required<PathEditingOverlayStyle> = {\n anchorSizePx: 8,\n handleDotRadiusPx: 5,\n anchorFill: '#ffffff',\n anchorStroke: '#3478f6',\n handleStroke: '#7da7e8',\n // 50%-opacity handle-stroke color. #7da7e8 → rgba(125, 167, 232, 0.5).\n handleDotFill: 'rgba(125, 167, 232, 0.5)',\n anchorFillSelected: '#3478f6',\n outlineStroke: '#3478f6',\n outlineWidthPx: 1,\n denseDotRadiusPx: 1.5,\n marqueeStroke: '#3478f6',\n marqueeFill: 'rgba(52, 120, 246, 0.08)',\n};\n\nexport function worldToScreen(p: WorldPoint, view: View): Point {\n return { x: (p.x - view.x) * view.scale.x, y: (p.y - view.y) * view.scale.y };\n}\n\n/** `path`, its corners expanded, with every coordinate carried to screen\n * through `view`: a radius left on it would stay in world units. */\nfunction onScreen(path: PolygonPath, view: View): PolygonPath {\n const resolved = resolveCorners(path);\n const world = worldCoords(resolved);\n const { origin: _measuredFrom, ...drawn } = resolved;\n const coords = new Float32Array(world.length);\n for (let i = 0; i < coords.length; i += 2) {\n coords[i] = (world[i] - view.x) * view.scale.x;\n coords[i + 1] = (world[i + 1] - view.y) * view.scale.y;\n }\n return { ...drawn, coords };\n}\n\n/** Whether `sub[i]` sits closer to a neighbor along its subpath than `px` on screen. */\nfunction crowded(sub: readonly Point[], closed: boolean, i: number, px: number): boolean {\n const n = sub.length;\n const near = (j: number): boolean => {\n if (!closed && (j < 0 || j >= n)) return false;\n const q = sub[(j + n) % n];\n return q !== sub[i] && Math.hypot(q.x - sub[i].x, q.y - sub[i].y) < px;\n };\n return near(i - 1) || near(i + 1);\n}\n\n/** The on-screen neighbors of `sub[i]` along its subpath, null past an open end. */\nfunction neighbors(sub: readonly Point[], closed: boolean, i: number): [Point | null, Point | null] {\n const n = sub.length;\n const prev = i > 0 || closed ? sub[(i - 1 + n) % n] : null;\n const next = i < n - 1 || closed ? sub[(i + 1) % n] : null;\n return [prev, next];\n}\n\nfunction handleCommands(a: Point, handle: Point, style: Required<PathEditingOverlayStyle>): DrawCommand[] {\n return [\n { kind: 'path', path: linePath(a, handle), stroke: { paint: { kind: 'solid', color: style.handleStroke }, width: 1 } },\n {\n kind: 'path',\n path: circlePath(handle.x, handle.y, style.handleDotRadiusPx),\n fill: { paint: { kind: 'solid', color: style.handleDotFill } },\n },\n ];\n}\n\n/**\n * The open path's outline, then its anchors in walk order — each anchor's\n * handles under its marker. A selected anchor's marker is filled, an\n * unselected one's hollow, or a dot where its neighbors crowd it. The marker\n * is a square, or the shape `markers` gives the anchor's flat index. Flat\n * indices count the way `enumerateAnchors` does, as the selection does.\n */\nexport function anchorMarkerCommands(\n path: PolygonPath,\n view: View,\n selected: ReadonlySet<number>,\n style: Required<PathEditingOverlayStyle>,\n markers: readonly (AnchorMarkerShape | null)[] | null = null,\n): DrawCommand[] {\n const out: DrawCommand[] = [{\n kind: 'path',\n path: onScreen(path, view),\n stroke: { paint: { kind: 'solid', color: style.outlineStroke }, width: style.outlineWidthPx },\n }];\n const { anchors, closed } = pathToAnchors(path);\n let flat = 0;\n anchors.forEach((sub: PenAnchor[], s) => {\n const screen = sub.map((a) => worldToScreen(a, view));\n const isClosed = closed[s];\n sub.forEach((a, i) => {\n const shape = markers?.[flat] ?? null;\n const isSelected = selected.has(flat++);\n const at = screen[i];\n if (a.inHandle) out.push(...handleCommands(at, worldToScreen(a.inHandle, view), style));\n if (a.outHandle) out.push(...handleCommands(at, worldToScreen(a.outHandle, view), style));\n if (!isSelected && crowded(screen, closed[s], i, style.anchorSizePx)) {\n out.push({\n kind: 'path',\n path: circlePath(at.x, at.y, style.denseDotRadiusPx),\n fill: { paint: { kind: 'solid', color: style.anchorStroke } },\n });\n return;\n }\n out.push({\n kind: 'path',\n path: shape ? shape(at, style.anchorSizePx, ...neighbors(screen, isClosed, i)) : squarePath(at.x, at.y, style.anchorSizePx),\n fill: { paint: { kind: 'solid', color: isSelected ? style.anchorFillSelected : style.anchorFill } },\n stroke: { paint: { kind: 'solid', color: style.anchorStroke }, width: 1 },\n });\n });\n });\n return out;\n}\n"],"mappings":"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"}
@@ -5,7 +5,7 @@ import { pathFromPlane } from "../../canvas/planeClips.js";
5
5
  import { pathFormOf, representationOf, withoutPathForm } from "./pathRepresentation.js";
6
6
  import { asPolygonPath, pathInWorld, rectPath, worldEditToStorage } from "@weasel-js/geom";
7
7
 
8
- //#region src/features/paths/editablePath.ts
8
+ //#region src/domains/paths/editablePath.ts
9
9
  /**
10
10
  * A node's editable polygon. It lives in one of two places: the pose itself
11
11
  * (`pose.kind === 'polygon'`), or `data.path` with a rect pose, stored pose-local.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editablePath.js","names":[],"sources":["../../../src/domains/paths/editablePath.ts"],"sourcesContent":["/**\n * A node's editable polygon. It lives in one of two places: the pose itself\n * (`pose.kind === 'polygon'`), or `data.path` with a rect pose, stored pose-local.\n * A rect `data.path` is edited as its four corners and is stored as a polygon\n * from the first edit on; reading it changes nothing. A leaf drawn as its rect\n * pose alone reads as a rect `data.path` the size of its pose, and gains one\n * on the first edit.\n */\nimport { asPolygonPath, pathInWorld, rectPath, worldEditToStorage, type Path, type PolygonPath } from '@weasel-js/geom';\nimport type { GesturePreviewSource } from 'canvas/gestureBounds';\nimport { findNodeShape } from 'canvas/NodeShape';\nimport { RECT_FALLBACK_PAINTER } from 'canvas/nodeShapes/rectFallbackPainter';\nimport { pathFromPlane } from 'canvas/planeClips';\nimport { isRectPose } from 'core/geometry/autoPoseDescriptor';\nimport type { RectPose } from 'core/scene/types';\nimport type { PlaneMap } from 'core/viewport/parallax';\nimport type { PathEditExtension } from './pathEditExtension';\nimport { pathFormOf, representationOf, withoutPathForm, type AnchorMarkerShape } from './pathRepresentation';\n\n/** The fields of a node the editable path is read from. A node's `kind`\n * says whether a rect pose with no path is a leaf drawn as that rect. */\nexport interface EditableShape {\n pose: unknown;\n data: unknown;\n kind?: string;\n}\n\n/** Whether `node` is a leaf whose only geometry is its rect pose, drawn by\n * the kit's rect fallback. */\nfunction drawsPoseAlone(node: EditableShape): boolean {\n if (node.kind !== 'mark' || (node.data as { path?: unknown } | null)?.path != null) return false;\n return findNodeShape(node as never) === RECT_FALLBACK_PAINTER;\n}\n\n/** Resolve where a node's editable polygon lives. Returns null when the\n * node has neither a polygon pose nor a polygon or rect on `data.path`.\n * A rect comes back as the polygon it draws. */\nexport function classifyPathStorage(\n node: EditableShape | undefined | null,\n): { kind: 'pose' } | { kind: 'data'; pose: RectPose; data: { path: PolygonPath } } | null {\n if (!node) return null;\n const pose = node.pose as { kind?: string } | undefined;\n if (pose?.kind === 'polygon') return { kind: 'pose' };\n if (isRectPose(node.pose) && drawsPoseAlone(node)) {\n const { width, height } = node.pose;\n return { kind: 'data', pose: node.pose, data: { ...(node.data as object), path: asPolygonPath(rectPath(0, 0, width, height)) } };\n }\n const data = node.data as { path?: Path } | null;\n const kind = (data?.path as { kind?: string } | undefined)?.kind;\n if (!data?.path || (kind !== 'polygon' && kind !== 'rect') || !isRectPose(node.pose)) return null;\n const path = asPolygonPath(data.path);\n return {\n kind: 'data',\n pose: node.pose,\n data: (path === data.path ? data : { ...data, path }) as { path: PolygonPath },\n };\n}\n\n/** Whether `node` has a path that path edit can show anchors for. */\nexport function hasEditablePath(node: EditableShape | undefined | null): boolean {\n return classifyPathStorage(node) !== null;\n}\n\n/** A node's editable polygon in world coords. Does NOT consult any preview state —\n * callers that want live state read in-flight handles themselves. */\nexport function resolveEditablePathOf(\n node: EditableShape | undefined | null,\n): PolygonPath | null {\n if (!node) return null;\n const storage = classifyPathStorage(node);\n if (!storage) return null;\n // Pose-as-polygon: the pose IS the polygon (polygon poses can't carry\n // rotation), so it's already world.\n if (storage.kind === 'pose') return (node as { pose: PolygonPath }).pose;\n // data.path: translate to the pose origin AND bake `pose.rotation`, so anchors render on\n // the rotated contour the renderer draws.\n return pathInWorld(storage.data.path, storage.pose) as PolygonPath;\n}\n\n/**\n * What path edit edits on a node, in world coords: the edit path of the form\n * the node's path was drawn from, where one of `extensions` reads it\n * (`PathRepresentation`), and otherwise its editable polygon. Null when the\n * node has no editable polygon.\n */\nexport function pathEditPathOf(\n node: EditableShape | undefined | null,\n extensions: readonly PathEditExtension[] = [],\n): PolygonPath | null {\n const path = resolveEditablePathOf(node);\n const held = path ? representationOf(extensions, node!.data) : null;\n return (held && held.representation.editPath(path!, held.form)) ?? path;\n}\n\n/**\n * The pose and data that store `worldPath` where `node` stores its editable\n * polygon — the inverse of {@link resolveEditablePathOf}, so a `data.path`\n * node keeps its rotation. On a node whose path was drawn from a form one of\n * `extensions` reads, `worldPath` is an edit of what {@link pathEditPathOf}\n * gave, and the representation turns it into the drawn path; a form none\n * reads, or that no longer describes the path, is dropped. Null when `node`\n * has no editable polygon.\n */\nexport function storeEditablePath(\n node: EditableShape | undefined | null,\n worldPath: PolygonPath,\n extensions: readonly PathEditExtension[] = [],\n): EditableShape | null {\n const storage = classifyPathStorage(node);\n if (!storage) return null;\n let path = worldPath;\n let data = node!.data;\n if (pathFormOf(data)) {\n const held = representationOf(extensions, data);\n const solved = held ? held.representation.store(resolveEditablePathOf(node)!, held.form, worldPath) : null;\n path = solved?.path ?? worldPath;\n data = solved ? { ...(data as object), representation: solved.form } : withoutPathForm(data);\n }\n if (storage.kind === 'pose') return { pose: path, data };\n const stored = worldEditToStorage(storage.pose, path);\n return { pose: stored.pose, data: { ...(data as object), path: stored.path } };\n}\n\n/** `node` as the in-flight gestures in `previews` would leave it: a handle\n * previewing `id` contributes its pose and its data. */\nfunction previewedShape(\n id: string,\n node: EditableShape,\n previews: readonly GesturePreviewSource[],\n): EditableShape {\n let pose = node.pose;\n let data = node.data;\n let touched = false;\n const kind = node.kind;\n for (const source of previews) {\n const previewIds = source.previewIds?.();\n if (!previewIds) continue;\n let owns = false;\n for (const pid of previewIds) {\n if (pid === id) { owns = true; break; }\n }\n if (!owns) continue;\n const p = source.previewPose?.(id);\n if (p != null && !touched) { pose = p; touched = true; }\n const d = source.previewData?.(id);\n if (d != null) { data = d; touched = true; }\n }\n return { pose, data, kind };\n}\n\n/**\n * What path edit shows of node `id` right now ({@link pathEditPathOf}): following any\n * in-flight gesture in `previews`, and in the world of the camera whose\n * `plane` this is — a path on a parallax plane is stored in the plane's.\n */\nexport function liveEditablePath(\n id: string,\n node: EditableShape | undefined | null,\n previews: readonly GesturePreviewSource[],\n plane: PlaneMap | null,\n extensions: readonly PathEditExtension[] = [],\n): PolygonPath | null {\n if (!node) return null;\n return pathFromPlane(pathEditPathOf(previewedShape(id, node, previews), extensions), plane);\n}\n\n/** The marker of each anchor {@link liveEditablePath} shows for node `id`, as\n * the representation reading its form draws them; null for a node it reads\n * none of. */\nexport function liveAnchorMarkers(\n id: string,\n node: EditableShape | undefined | null,\n previews: readonly GesturePreviewSource[],\n extensions: readonly PathEditExtension[],\n): readonly (AnchorMarkerShape | null)[] | null {\n if (!node) return null;\n const held = representationOf(extensions, previewedShape(id, node, previews).data);\n return held?.representation.anchorMarkers?.(held.form) ?? null;\n}\n"],"mappings":"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"}
@@ -5,9 +5,9 @@ import { PATH_SNAP_LABELS, pathSnapGlyph } from "./pathSnap/glyphs.js";
5
5
  import { createPathEditingOverlayLayer } from "./pathEditingOverlayLayer.js";
6
6
  import { createPathLayer } from "./pathLayer.js";
7
7
  import { pathOriginProjection } from "./originProjection.js";
8
- import { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, PATH_C as PATH_C$1, PATH_CMD_LENGTHS, PATH_L as PATH_L$1, PATH_M as PATH_M$1, PATH_Q as PATH_Q$1, PATH_SNAP_KINDS as PATH_SNAP_KINDS$1, PATH_Z as PATH_Z$1, PathBuilder, asPolygonPath as asPolygonPath$1, averageAnchorsAt as averageAnchorsAt$1, bendAlongPath as bendAlongPath$1, blendPaths, boundsOfPath as boundsOfPath$1, circlePath as circlePath$1, composePath, cornerAt, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerSpecAt, countPathAnchors as countPathAnchors$1, createPathSnapIndex as createPathSnapIndex$1, decomposePath, ellipsePath as ellipsePath$1, extendToMeet, findPathSnap as findPathSnap$1, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, hasCorners, hasOpenSubpath as hasOpenSubpath$1, intersectSegments, isCornerShape, joinAnchorsAt as joinAnchorsAt$1, lengthenOpenEnd, linePath as linePath$1, measurePath as measurePath$1, nextCornerShape, openEndRay, openPathEnds, pathCommandCoordCount, pathContainsPoint as pathContainsPoint$1, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathFromD as pathFromD$1, pathInPoseFrame as pathInPoseFrame$1, pathInWorld as pathInWorld$1, pathIntersectsPolygon, pathIntersectsRect as pathIntersectsRect$1, pathSegments, pathSignedArea, pathThroughPoseFrame as pathThroughPoseFrame$1, pathToAnchors as pathToAnchors$1, pathToD, pointAlongPath, pointInPath as pointInPath$1, polygonFromPoints as polygonFromPoints$1, polylineFromPoints as polylineFromPoints$1, poseFrameInverseOf as poseFrameInverseOf$1, poseFrameOf as poseFrameOf$1, poseLinearOf as poseLinearOf$1, poseRotationOf, prepareBlend as prepareBlend$1, rectMarkerPath as rectMarkerPath$1, rectPath as rectPath$1, regularPolygonPath as regularPolygonPath$1, remapPerAnchor, repeatAlongPath as repeatAlongPath$1, resolveCorners as resolveCorners$1, resolveCornersWithSources, reversePath, rotatePathAround as rotatePathAround$1, roundRectPath, scalePathToBounds, simplifyAnchorsAt, simplifyPath as simplifyPath$1, smudgePath, splitByClosure, splitSubpaths, squarePath as squarePath$1, starPath as starPath$1, stationsAlongPath, transformPath as transformPath$1, translatePath as translatePath$1, trimPathAt, unionBoundsPath, withCorner, withoutCorners, worldEditToStorage as worldEditToStorage$1 } from "@weasel-js/geom";
9
- import { offsetPath as offsetPath$1, strokeToPath as strokeToPath$1 } from "@weasel-js/stroke";
8
+ import { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, PATH_C as PATH_C$1, PATH_CMD_LENGTHS, PATH_L as PATH_L$1, PATH_M as PATH_M$1, PATH_Q as PATH_Q$1, PATH_SNAP_KINDS as PATH_SNAP_KINDS$1, PATH_Z as PATH_Z$1, PathBuilder, asPolygonPath as asPolygonPath$1, averageAnchorsAt as averageAnchorsAt$1, bendAlongPath as bendAlongPath$1, blendPaths, boundsOfPath as boundsOfPath$1, circlePath as circlePath$1, composePath, cornerAt, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerSpecAt, countPathAnchors as countPathAnchors$1, createPathSnapIndex as createPathSnapIndex$1, decomposePath, ellipsePath as ellipsePath$1, extendToMeet, findPathSnap as findPathSnap$1, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, hasCorners, hasOpenSubpath as hasOpenSubpath$1, intersectSegments, isCornerShape, joinAnchorsAt as joinAnchorsAt$1, lengthenOpenEnd, linePath as linePath$1, measurePath as measurePath$1, nextCornerShape, openEndRay, openPathEnds, pathCommandCoordCount, pathContainsPoint as pathContainsPoint$1, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathFromD as pathFromD$1, pathInPoseFrame as pathInPoseFrame$1, pathInWorld as pathInWorld$1, pathIntersectsPolygon, pathIntersectsRect as pathIntersectsRect$1, pathSegments, pathSignedArea, pathThroughPoseFrame as pathThroughPoseFrame$1, pathToAnchors as pathToAnchors$1, pathToD, pointAlongPath, pointInPath as pointInPath$1, polygonFromPoints as polygonFromPoints$1, polylineFromPoints as polylineFromPoints$1, poseFrameInverseOf as poseFrameInverseOf$1, poseFrameOf as poseFrameOf$1, poseLinearOf as poseLinearOf$1, poseRotationOf, prepareBlend as prepareBlend$1, puckerBloatPath as puckerBloatPath$1, rectMarkerPath as rectMarkerPath$1, rectPath as rectPath$1, regularPolygonPath as regularPolygonPath$1, remapPerAnchor, repeatAlongPath as repeatAlongPath$1, resolveCorners as resolveCorners$1, resolveCornersWithSources, reversePath, rotatePathAround as rotatePathAround$1, roughenPath as roughenPath$1, roundRectPath, scalePathToBounds, simplifyAnchorsAt, simplifyPath as simplifyPath$1, smudgePath, splitByClosure, splitSubpaths, squarePath as squarePath$1, starPath as starPath$1, stationsAlongPath, transformPath as transformPath$1, translatePath as translatePath$1, trimPathAt, unionBoundsPath, withCorner, withoutCorners, worldEditToStorage as worldEditToStorage$1, zigzagPath as zigzagPath$1 } from "@weasel-js/geom";
10
9
  import { pathDivide, pathExclude as pathExclude$1, pathIntersect as pathIntersect$1, pathSubtract as pathSubtract$1, pathUnion as pathUnion$1, snipPathByPolyline as snipPathByPolyline$1, snipPathsAtCrossings as snipPathsAtCrossings$1, splitPathByPolyline as splitPathByPolyline$1, splitPathBySegment, trianglesToPath } from "@weasel-js/geom/booleans";
10
+ import { offsetPath as offsetPath$1, strokeToPath as strokeToPath$1 } from "@weasel-js/stroke";
11
11
  import "@weasel-js/geom/curves";
12
12
 
13
- export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, GEOMETRY_BOUND_DATA, PATH_C$1 as PATH_C, PATH_CMD_LENGTHS, PATH_L$1 as PATH_L, PATH_M$1 as PATH_M, PATH_Q$1 as PATH_Q, PATH_SNAP_KINDS$1 as PATH_SNAP_KINDS, PATH_SNAP_LABELS, PATH_Z$1 as PATH_Z, PathBuilder, asPolygonPath$1 as asPolygonPath, averageAnchorsAt$1 as averageAnchorsAt, bendAlongPath$1 as bendAlongPath, blendPaths, boundsOfPath$1 as boundsOfPath, circlePath$1 as circlePath, composePath, cornerAt, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerSpecAt, countPathAnchors$1 as countPathAnchors, createPathEditingOverlayLayer, createPathLayer, createPathSnapIndex$1 as createPathSnapIndex, createPenPreviewLayer, decomposePath, ellipsePath$1 as ellipsePath, extendToMeet, findPathSnap$1 as findPathSnap, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, hasCorners, hasOpenSubpath$1 as hasOpenSubpath, intersectSegments, isCornerShape, joinAnchorsAt$1 as joinAnchorsAt, lengthenOpenEnd, linePath$1 as linePath, measurePath$1 as measurePath, nextCornerShape, offsetPath$1 as offsetPath, openEndRay, openPathEnds, pathCommandCoordCount, pathContainsPoint$1 as pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathDivide, pathExclude$1 as pathExclude, pathFromD$1 as pathFromD, pathInPoseFrame$1 as pathInPoseFrame, pathInWorld$1 as pathInWorld, pathIntersect$1 as pathIntersect, pathIntersectsPolygon, pathIntersectsRect$1 as pathIntersectsRect, pathOriginProjection, pathPoseDescriptor, pathSegments, pathSignedArea, pathSnapGlyph, pathSubtract$1 as pathSubtract, pathThroughPoseFrame$1 as pathThroughPoseFrame, pathToAnchors$1 as pathToAnchors, pathToD, pathUnion$1 as pathUnion, pointAlongPath, pointInPath$1 as pointInPath, polygonFromPoints$1 as polygonFromPoints, polylineFromPoints$1 as polylineFromPoints, poseFrameInverseOf$1 as poseFrameInverseOf, poseFrameOf$1 as poseFrameOf, poseLinearOf$1 as poseLinearOf, poseRotationOf, prepareBlend$1 as prepareBlend, rectMarkerPath$1 as rectMarkerPath, rectPath$1 as rectPath, regularPolygonPath$1 as regularPolygonPath, remapPerAnchor, repeatAlongPath$1 as repeatAlongPath, resolveCorners$1 as resolveCorners, resolveCornersWithSources, reversePath, rotatePathAround$1 as rotatePathAround, roundRectPath, scalePathToBounds, simplifyAnchorsAt, simplifyPath$1 as simplifyPath, smudgePath, snipPathByPolyline$1 as snipPathByPolyline, snipPathsAtCrossings$1 as snipPathsAtCrossings, splitByClosure, splitPathByPolyline$1 as splitPathByPolyline, splitPathBySegment, splitSubpaths, squarePath$1 as squarePath, starPath$1 as starPath, stationsAlongPath, strokeToPath$1 as strokeToPath, transformPath$1 as transformPath, translatePath$1 as translatePath, trianglesToPath, trimPathAt, unionBoundsPath, withCorner, withoutCorners, withoutGeometryBoundData, worldEditToStorage$1 as worldEditToStorage };
13
+ export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, GEOMETRY_BOUND_DATA, PATH_C$1 as PATH_C, PATH_CMD_LENGTHS, PATH_L$1 as PATH_L, PATH_M$1 as PATH_M, PATH_Q$1 as PATH_Q, PATH_SNAP_KINDS$1 as PATH_SNAP_KINDS, PATH_SNAP_LABELS, PATH_Z$1 as PATH_Z, PathBuilder, asPolygonPath$1 as asPolygonPath, averageAnchorsAt$1 as averageAnchorsAt, bendAlongPath$1 as bendAlongPath, blendPaths, boundsOfPath$1 as boundsOfPath, circlePath$1 as circlePath, composePath, cornerAt, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerSpecAt, countPathAnchors$1 as countPathAnchors, createPathEditingOverlayLayer, createPathLayer, createPathSnapIndex$1 as createPathSnapIndex, createPenPreviewLayer, decomposePath, ellipsePath$1 as ellipsePath, extendToMeet, findPathSnap$1 as findPathSnap, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, hasCorners, hasOpenSubpath$1 as hasOpenSubpath, intersectSegments, isCornerShape, joinAnchorsAt$1 as joinAnchorsAt, lengthenOpenEnd, linePath$1 as linePath, measurePath$1 as measurePath, nextCornerShape, offsetPath$1 as offsetPath, openEndRay, openPathEnds, pathCommandCoordCount, pathContainsPoint$1 as pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathDivide, pathExclude$1 as pathExclude, pathFromD$1 as pathFromD, pathInPoseFrame$1 as pathInPoseFrame, pathInWorld$1 as pathInWorld, pathIntersect$1 as pathIntersect, pathIntersectsPolygon, pathIntersectsRect$1 as pathIntersectsRect, pathOriginProjection, pathPoseDescriptor, pathSegments, pathSignedArea, pathSnapGlyph, pathSubtract$1 as pathSubtract, pathThroughPoseFrame$1 as pathThroughPoseFrame, pathToAnchors$1 as pathToAnchors, pathToD, pathUnion$1 as pathUnion, pointAlongPath, pointInPath$1 as pointInPath, polygonFromPoints$1 as polygonFromPoints, polylineFromPoints$1 as polylineFromPoints, poseFrameInverseOf$1 as poseFrameInverseOf, poseFrameOf$1 as poseFrameOf, poseLinearOf$1 as poseLinearOf, poseRotationOf, prepareBlend$1 as prepareBlend, puckerBloatPath$1 as puckerBloatPath, rectMarkerPath$1 as rectMarkerPath, rectPath$1 as rectPath, regularPolygonPath$1 as regularPolygonPath, remapPerAnchor, repeatAlongPath$1 as repeatAlongPath, resolveCorners$1 as resolveCorners, resolveCornersWithSources, reversePath, rotatePathAround$1 as rotatePathAround, roughenPath$1 as roughenPath, roundRectPath, scalePathToBounds, simplifyAnchorsAt, simplifyPath$1 as simplifyPath, smudgePath, snipPathByPolyline$1 as snipPathByPolyline, snipPathsAtCrossings$1 as snipPathsAtCrossings, splitByClosure, splitPathByPolyline$1 as splitPathByPolyline, splitPathBySegment, splitSubpaths, squarePath$1 as squarePath, starPath$1 as starPath, stationsAlongPath, strokeToPath$1 as strokeToPath, transformPath$1 as transformPath, translatePath$1 as translatePath, trianglesToPath, trimPathAt, unionBoundsPath, withCorner, withoutCorners, withoutGeometryBoundData, worldEditToStorage$1 as worldEditToStorage, zigzagPath$1 as zigzagPath };
@@ -1,6 +1,6 @@
1
1
  import { boundsOfPath, translatePath } from "@weasel-js/geom";
2
2
 
3
- //#region src/features/paths/originProjection.ts
3
+ //#region src/domains/paths/originProjection.ts
4
4
  /**
5
5
  * `OriginProjection` for `Path` poses. The "origin" is the top-left of the
6
6
  * path's AABB; `translate` shifts every coord by the requested delta. It is
@@ -0,0 +1 @@
1
+ {"version":3,"file":"originProjection.js","names":[],"sources":["../../../src/domains/paths/originProjection.ts"],"sourcesContent":["import { boundsOfPath, translatePath, type Path } from '@weasel-js/geom';\nimport type { OriginProjection } from 'interactions/gestures/shared/originProjection';\n\n/**\n * `OriginProjection` for `Path` poses. The \"origin\" is the top-left of the\n * path's AABB; `translate` shifts every coord by the requested delta. It is\n * where a snap session puts a Path's `origin` probe, so a grid source snaps a\n * Path's bounds top-left.\n */\nexport const pathOriginProjection: OriginProjection<Path> = {\n getOrigin: (path) => {\n const b = boundsOfPath(path);\n return { x: b.x, y: b.y };\n },\n translate: translatePath,\n};\n"],"mappings":";;;;;;;;;AASA,IAAa,uBAA+C;CAC1D,YAAY,SAAS;EACnB,MAAM,IAAI,aAAa,IAAI;EAC3B,OAAO;GAAE,GAAG,EAAE;GAAG,GAAG,EAAE;EAAE;CAC1B;CACA,WAAW;AACb"}
@@ -1,4 +1,4 @@
1
- //#region src/features/paths/pathEditExtension.ts
1
+ //#region src/domains/paths/pathEditExtension.ts
2
2
  /**
3
3
  * Data fields that describe how a node's geometry was made, or name its
4
4
  * anchors, and so mean nothing once the geometry is replaced some other way.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathEditExtension.js","names":[],"sources":["../../../src/domains/paths/pathEditExtension.ts"],"sourcesContent":["/**\n * What a feature adds to path edit without path edit knowing it: marks drawn\n * on the open path, parts of it to press, marks a click selects and Delete\n * removes, a share in shaping an anchor or handle drag, what an edit must keep\n * true when it commits, and how a path drawn from another form is edited. A\n * preset carries its extensions as `FeaturePreset.pathEdit`; core consults\n * them in preset order.\n */\nimport type { DrawCommand } from '@weasel-js/renderer';\nimport type { AnchorSet, PointOrigin, PolygonPath, View } from '@weasel-js/geom';\nimport type { OngoingOverlay, WorldPoint } from '@weasel-js/routing';\nimport type { HandleLocks } from 'interactions/actions/edit-anchors/params';\nimport type { SnapDep } from 'interactions/actions/snapDep';\nimport type { PathRepresentation } from './pathRepresentation';\n\n/** A mark an extension drew that is selected in place of anchors: Delete\n * acts on it, and selecting anchors clears it. */\nexport interface PathEditMark {\n /** The extension that drew it. */\n owner: string;\n /** Which of its marks, in the extension's own numbering. */\n index: number;\n}\n\n/** The open path as an extension's marks and parts read it. */\nexport interface PathEditTarget {\n /** The node being edited. */\n id: string;\n /** Its committed pose and data. */\n node: { pose: unknown; data: unknown };\n /** The path as drawn now, in-flight edits included, in world space. */\n path: PolygonPath;\n /** `path`'s anchors. */\n anchors: AnchorSet;\n}\n\n/** What {@link PathEditExtension.marks} draws with. */\nexport interface PathEditMarksCtx extends PathEditTarget {\n view: View;\n /** World space to the screen space the marks are drawn in. */\n toScreen(p: { x: number; y: number }): { x: number; y: number };\n /** Chrome-caps' answer for a chrome id; marks gated by one ask it. */\n isVisible(chromeId: string): boolean;\n /** The selected mark's index when this extension owns it, else null. */\n selected: number | null;\n}\n\n/** A grabbable point an extension adds to the open path. A press on it\n * routes as an affordance hit of kind `hitKind`. */\nexport interface PathEditPart {\n x: number;\n y: number;\n hitKind: string;\n /** Chrome-caps id it is hit-tested under, beside `path-edit.anchors`. */\n chromeId?: string;\n /** Hit radius in screen px; path edit's anchor radius when left out. */\n hitRadiusPx?: number;\n /** Pushes the part `px` screen pixels from (x, y) along the world-space\n * `normal`, so it keeps its distance at any zoom. */\n standoff?: { px: number; normal: { x: number; y: number } };\n}\n\n/** An anchor or handle drag on the open path, as it starts. */\nexport interface PathEditDragStart extends Omit<PathEditTarget, 'node'> {\n /** The node's committed pose and data; null when it cannot be read. */\n node: PathEditTarget['node'] | null;\n /** What the press grabbed: an anchor, or one of its handles. */\n part: 'anchor' | 'controlIn' | 'controlOut';\n /** The pressed anchor, as a flat index. */\n anchorIndex: number;\n /** The anchors an anchor drag moves, as flat indices; empty for a handle\n * drag, or when Shift took the pressed anchor out of the selection. */\n dragging: readonly number[];\n /** The view's world-to-screen scale at the press, to measure in screen\n * pixels by; absent without a view. */\n scale?: { x: number; y: number };\n /** The canvas's `snap` dep, to begin a session on; absent without one. */\n snap?: SnapDep;\n}\n\n/** A handle drag's move, as {@link PathEditDrag.handle} reads it. */\nexport interface PathEditHandleMove {\n /** The handle locks in force this move, modifiers included. */\n locks: HandleLocks;\n}\n\n/** One extension's share of a drag in flight. Every member is optional. */\nexport interface PathEditDrag {\n /**\n * For an anchor drag, anchors that follow it and the share of its delta\n * each moves by, keyed by flat index. Read every move. When any extension\n * gives one, the drag moves its dragged anchors in full and every anchor\n * named by the largest share given, and moves no symmetric images.\n */\n weights?(): ReadonlyMap<number, number>;\n /** For a handle drag, where the handle goes, given `to`: where the pointer\n * and the locks in force put it. Extensions answer in turn, each from the\n * last one's answer. */\n handle?(to: WorldPoint, move: PathEditHandleMove): WorldPoint;\n /** A wheel turned while the drag is in flight. Return true to claim it;\n * the drag then redoes its last move. */\n wheel?(wheel: { deltaX: number; deltaY: number; deltaZ: number }): boolean;\n /** Overlays to draw while the drag is in flight, for `current`, the path\n * as the drag has made it. */\n overlays?(current: AnchorSet): readonly OngoingOverlay[];\n /** The drag is over, committed or canceled. */\n end?(): void;\n}\n\n/** Another node an edit changes along with the edited one. */\nexport interface PathEditOther {\n id: string;\n /** Its new path, in world space, stored where the node keeps its own. */\n path?: PolygonPath;\n /** Data fields to set on it. */\n data?: Record<string, unknown>;\n /** Delete it: what it kept true no longer has anything to hold. */\n remove?: boolean;\n}\n\n/** What an edit commits once an extension has finished it. */\nexport interface FinishedPathEdit {\n path: PolygonPath;\n /** Data fields to set beside the path. */\n data?: Record<string, unknown>;\n /** Other nodes the edit changes, committed in the same history entry and previewed with it. */\n others?: readonly PathEditOther[];\n}\n\n/** The scene as {@link PathEditExtension.finishEdit} reads it, for an edit that reaches past one node. */\nexport interface PathEditFinishCtx {\n /** The edited node's id. */\n id: string;\n /** A node's committed pose, data and dependencies; null when there is none. */\n node(id: string): { pose: unknown; data: unknown; dependsOn?: readonly string[] | 'children' } | null;\n /** A node's committed editable path, in world space; null when it has none. */\n path(id: string): PolygonPath | null;\n /** The nodes that list `id` in their `dependsOn`, directly or through others. */\n dependents(id: string): readonly string[];\n}\n\n/**\n * The scene as {@link PathEditExtension.finishTransform} reads it: `node` and\n * `path` answer each node as the transform leaves it, `before` as it was.\n */\nexport interface PathTransformFinishCtx extends Omit<PathEditFinishCtx, 'id'> {\n /** The nodes the transform moves, resizes or turns. */\n ids: readonly string[];\n /** A node's committed editable path before the transform, in world space; null when it has none. */\n before(id: string): PolygonPath | null;\n}\n\n/** One feature's share of path edit. Every member is optional. */\nexport interface PathEditExtension {\n /** Names it as a {@link PathEditMark}'s owner. Unique per canvas. */\n readonly id: string;\n /** Draw commands for the open path, in screen space, under its anchor\n * markers. Called every frame the overlay paints. */\n marks?(ctx: PathEditMarksCtx): DrawCommand[];\n /** Grabbable points on the open path, pressed ahead of its segments and\n * behind its anchors. */\n parts?(target: PathEditTarget): readonly PathEditPart[];\n /** The index of this extension's mark a click at `screen` (in the\n * overlay's screen space) lands on, or -1. Asked when a click misses\n * every anchor. */\n markAt?(target: PathEditTarget, toScreen: PathEditMarksCtx['toScreen'], screen: { x: number; y: number }): number;\n /** Remove mark `index` of the node `target` names, committing through\n * `store`. Delete in path edit calls it on the selected mark. */\n deleteMark?(target: PathEditTarget, index: number, store: PathEditStore): void;\n /** Its share of an anchor or handle drag starting on the open path, or\n * null to sit it out. Asked once, at the press. */\n drag?(start: PathEditDragStart): PathEditDrag | null;\n /**\n * `worldPath`, an edit of `node`'s committed path, finished so whatever\n * this extension keeps true holds — the path, and any data fields that\n * change with it, and any other nodes it has to move to keep it. Null when\n * it cannot hold, and the edit should then not happen. Runs on every commit\n * of an edit and every frame of one in flight. `ctx` reads the rest of the\n * scene; it is absent where an edit has no scene behind it.\n */\n finishEdit?(\n node: { pose: unknown; data: unknown },\n worldPath: PolygonPath,\n origins?: readonly (PointOrigin | null)[],\n ctx?: PathEditFinishCtx,\n ): FinishedPathEdit | null;\n /**\n * The other nodes a whole-node transform — a move, resize, rotate, flip or\n * nudge — changes along with the nodes it transforms, so whatever this\n * extension keeps true across nodes holds; committed in the transform's\n * history entry. Null when the transform should not happen. An entry\n * naming a node the transform itself moves is ignored.\n */\n finishTransform?(ctx: PathTransformFinishCtx): readonly PathEditOther[] | null;\n /** How path edit reads and writes the nodes whose `data.representation`\n * is of its kind. */\n representation?: PathRepresentation;\n}\n\n/** Commits a node's new path and data as one history entry, with no\n * extension finishing it. */\nexport type PathEditStore = (id: string, worldPath: PolygonPath, label: string, data?: Record<string, unknown>) => void;\n\n/**\n * Data fields that describe how a node's geometry was made, or name its\n * anchors, and so mean nothing once the geometry is replaced some other way.\n * A writer replacing a node's path drops them: a held warp, path\n * constraints, a skin, the form a path was drawn from.\n */\nexport const GEOMETRY_BOUND_DATA: readonly string[] = ['skin', 'constraints', 'warp', 'representation'];\n\n/** `data` without the fields in {@link GEOMETRY_BOUND_DATA}, other than `keep`. */\nexport function withoutGeometryBoundData<T>(data: T, keep: readonly string[] = []): T {\n if (data === null || typeof data !== 'object') return data;\n const drop = GEOMETRY_BOUND_DATA.filter((k) => k in (data as object) && !keep.includes(k));\n if (drop.length === 0) return data;\n const out = { ...(data as Record<string, unknown>) };\n for (const k of drop) delete out[k];\n return out as T;\n}\n"],"mappings":";;;;;;;AAiNA,IAAa,sBAAyC;CAAC;CAAQ;CAAe;CAAQ;AAAgB;;AAGtG,SAAgB,yBAA4B,MAAS,OAA0B,CAAC,GAAM;CACpF,IAAI,SAAS,QAAQ,OAAO,SAAS,UAAU,OAAO;CACtD,MAAM,OAAO,oBAAoB,QAAQ,MAAM,KAAM,QAAmB,CAAC,KAAK,SAAS,CAAC,CAAC;CACzF,IAAI,KAAK,WAAW,GAAG,OAAO;CAC9B,MAAM,MAAM,EAAE,GAAI,KAAiC;CACnD,KAAK,MAAM,KAAK,MAAM,OAAO,IAAI;CACjC,OAAO;AACT"}
@@ -1,7 +1,7 @@
1
1
  import { effectSourceFor } from "../pathEffects/effectSources.js";
2
2
  import { createEmitter } from "@weasel-js/registry";
3
3
 
4
- //#region src/features/paths/pathEditState.ts
4
+ //#region src/domains/paths/pathEditState.ts
5
5
  /**
6
6
  * Which path is being anchor-edited, which of its anchors are selected, and
7
7
  * the anchor marquee in flight: one object every reader shares — the