@weasel-js/core 1.13.0 → 1.14.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (741) hide show
  1. package/CHANGELOG.md +326 -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
@@ -0,0 +1,65 @@
1
+ import { polygonFromPoints, runStationAt } from "@weasel-js/geom";
2
+
3
+ //#region src/core/scene/pathEffects/textAlongBands.ts
4
+ /**
5
+ * The bands text along a path carries — decoration rules cut into clusters — joined across neighboring items and drawn
6
+ * as ribbons that bend with the path.
7
+ */
8
+ var PER_PATH = 512;
9
+ var MAX_SAMPLES = 2048;
10
+ /** Every ribbon `laid` carries, `shift` off the run. A `null` in `laid` is a dropped item, which no ribbon crosses. */
11
+ function bandParts(laid, run, shift) {
12
+ const out = [];
13
+ let live = [];
14
+ const hair = 1e-9 * Math.max(1, run.length);
15
+ for (const at of laid) {
16
+ const next = [];
17
+ for (const band of at?.item.bands ?? []) {
18
+ if (!(band.x1 > band.x0)) continue;
19
+ const y0 = band.y0 + at.lift;
20
+ const y1 = band.y1 + at.lift;
21
+ const k = band.x0 <= hair ? live.findIndex((r) => r.open && alike(r, band, y0, y1)) : -1;
22
+ const ribbon = k < 0 ? {
23
+ band,
24
+ y0,
25
+ y1,
26
+ from: at.start + band.x0,
27
+ to: 0,
28
+ open: false
29
+ } : live.splice(k, 1)[0];
30
+ ribbon.to = at.start + band.x1;
31
+ ribbon.open = band.x1 >= at.item.length - hair;
32
+ next.push(ribbon);
33
+ }
34
+ for (const r of live) out.push(ribbonPart(r, run, shift));
35
+ live = next;
36
+ }
37
+ for (const r of live) out.push(ribbonPart(r, run, shift));
38
+ return out;
39
+ }
40
+ var alike = (r, band, y0, y1) => r.y0 === y0 && r.y1 === y1 && r.band.fill === band.fill && r.band.stroke === band.stroke;
41
+ function ribbonPart(r, run, shift) {
42
+ const L = run.length;
43
+ const n = Math.min(MAX_SAMPLES, Math.max(1, Math.ceil((r.to - r.from) * PER_PATH / L)));
44
+ const top = [];
45
+ const bottom = [];
46
+ for (let i = 0; i <= n; i++) {
47
+ const d = r.from + (r.to - r.from) * i / n;
48
+ const { point, normal } = runStationAt(run, run.closed ? (d % L + L) % L : d);
49
+ const up = (y) => ({
50
+ x: point.x + (shift - y) * normal.x,
51
+ y: point.y + (shift - y) * normal.y
52
+ });
53
+ top.push(up(r.y0));
54
+ bottom.push(up(r.y1));
55
+ }
56
+ return {
57
+ path: polygonFromPoints([...top, ...bottom.reverse()]),
58
+ fill: r.band.fill,
59
+ stroke: r.band.stroke
60
+ };
61
+ }
62
+
63
+ //#endregion
64
+ export { bandParts };
65
+ //# sourceMappingURL=textAlongBands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"textAlongBands.js","names":[],"sources":["../../../../src/core/scene/pathEffects/textAlongBands.ts"],"sourcesContent":["/**\n * The bands text along a path carries — decoration rules cut into clusters — joined across neighboring items and drawn\n * as ribbons that bend with the path.\n */\nimport { polygonFromPoints, runStationAt, type Point, type TrackRun } from '@weasel-js/geom';\nimport type { DerivedPart } from '../derivedParts';\nimport type { EffectBand, EffectItem } from './source';\n\n/** One kept item as the band walk reads it: where its leading edge falls along the run, and its anchor line's lift. */\nexport interface LaidItem {\n item: EffectItem;\n /** Its leading edge, along the run in reading order, unwrapped. */\n start: number;\n lift: number;\n}\n\ninterface Ribbon {\n band: EffectBand;\n /** Its edges against the path's anchor line, y down. */\n y0: number;\n y1: number;\n from: number;\n to: number;\n /** Whether it reaches the end of the item it was last carried through. */\n open: boolean;\n}\n\n// Samples per path length, so a ribbon's chords stay as close to the path as the path's own flattening.\nconst PER_PATH = 512;\nconst MAX_SAMPLES = 2048;\n\n/** Every ribbon `laid` carries, `shift` off the run. A `null` in `laid` is a dropped item, which no ribbon crosses. */\nexport function bandParts(laid: readonly (LaidItem | null)[], run: TrackRun, shift: number): DerivedPart[] {\n const out: DerivedPart[] = [];\n let live: Ribbon[] = [];\n const hair = 1e-9 * Math.max(1, run.length);\n for (const at of laid) {\n const next: Ribbon[] = [];\n for (const band of at?.item.bands ?? []) {\n if (!(band.x1 > band.x0)) continue;\n const y0 = band.y0 + at!.lift;\n const y1 = band.y1 + at!.lift;\n const k = band.x0 <= hair ? live.findIndex((r) => r.open && alike(r, band, y0, y1)) : -1;\n const ribbon = k < 0 ? { band, y0, y1, from: at!.start + band.x0, to: 0, open: false } : live.splice(k, 1)[0]!;\n ribbon.to = at!.start + band.x1;\n ribbon.open = band.x1 >= at!.item.length - hair;\n next.push(ribbon);\n }\n for (const r of live) out.push(ribbonPart(r, run, shift));\n live = next;\n }\n for (const r of live) out.push(ribbonPart(r, run, shift));\n return out;\n}\n\nconst alike = (r: Ribbon, band: EffectBand, y0: number, y1: number): boolean =>\n r.y0 === y0 && r.y1 === y1 && r.band.fill === band.fill && r.band.stroke === band.stroke;\n\nfunction ribbonPart(r: Ribbon, run: TrackRun, shift: number): DerivedPart {\n const L = run.length;\n const n = Math.min(MAX_SAMPLES, Math.max(1, Math.ceil(((r.to - r.from) * PER_PATH) / L)));\n const top: Point[] = [];\n const bottom: Point[] = [];\n for (let i = 0; i <= n; i++) {\n const d = r.from + ((r.to - r.from) * i) / n;\n const { point, normal } = runStationAt(run, run.closed ? ((d % L) + L) % L : d);\n const up = (y: number): Point => ({ x: point.x + (shift - y) * normal.x, y: point.y + (shift - y) * normal.y });\n top.push(up(r.y0));\n bottom.push(up(r.y1));\n }\n return { path: polygonFromPoints([...top, ...bottom.reverse()]), fill: r.band.fill, stroke: r.band.stroke };\n}\n"],"mappings":";;;;;;;AA4BA,IAAM,WAAW;AACjB,IAAM,cAAc;;AAGpB,SAAgB,UAAU,MAAoC,KAAe,OAA8B;CACzG,MAAM,MAAqB,CAAC;CAC5B,IAAI,OAAiB,CAAC;CACtB,MAAM,OAAO,OAAO,KAAK,IAAI,GAAG,IAAI,MAAM;CAC1C,KAAK,MAAM,MAAM,MAAM;EACrB,MAAM,OAAiB,CAAC;EACxB,KAAK,MAAM,QAAQ,IAAI,KAAK,SAAS,CAAC,GAAG;GACvC,IAAI,EAAE,KAAK,KAAK,KAAK,KAAK;GAC1B,MAAM,KAAK,KAAK,KAAK,GAAI;GACzB,MAAM,KAAK,KAAK,KAAK,GAAI;GACzB,MAAM,IAAI,KAAK,MAAM,OAAO,KAAK,WAAW,MAAM,EAAE,QAAQ,MAAM,GAAG,MAAM,IAAI,EAAE,CAAC,IAAI;GACtF,MAAM,SAAS,IAAI,IAAI;IAAE;IAAM;IAAI;IAAI,MAAM,GAAI,QAAQ,KAAK;IAAI,IAAI;IAAG,MAAM;GAAM,IAAI,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC;GAC3G,OAAO,KAAK,GAAI,QAAQ,KAAK;GAC7B,OAAO,OAAO,KAAK,MAAM,GAAI,KAAK,SAAS;GAC3C,KAAK,KAAK,MAAM;EAClB;EACA,KAAK,MAAM,KAAK,MAAM,IAAI,KAAK,WAAW,GAAG,KAAK,KAAK,CAAC;EACxD,OAAO;CACT;CACA,KAAK,MAAM,KAAK,MAAM,IAAI,KAAK,WAAW,GAAG,KAAK,KAAK,CAAC;CACxD,OAAO;AACT;AAEA,IAAM,SAAS,GAAW,MAAkB,IAAY,OACtD,EAAE,OAAO,MAAM,EAAE,OAAO,MAAM,EAAE,KAAK,SAAS,KAAK,QAAQ,EAAE,KAAK,WAAW,KAAK;AAEpF,SAAS,WAAW,GAAW,KAAe,OAA4B;CACxE,MAAM,IAAI,IAAI;CACd,MAAM,IAAI,KAAK,IAAI,aAAa,KAAK,IAAI,GAAG,KAAK,MAAO,EAAE,KAAK,EAAE,QAAQ,WAAY,CAAC,CAAC,CAAC;CACxF,MAAM,MAAe,CAAC;CACtB,MAAM,SAAkB,CAAC;CACzB,KAAK,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;EAC3B,MAAM,IAAI,EAAE,QAAS,EAAE,KAAK,EAAE,QAAQ,IAAK;EAC3C,MAAM,EAAE,OAAO,WAAW,aAAa,KAAK,IAAI,UAAW,IAAI,IAAK,KAAK,IAAI,CAAC;EAC9E,MAAM,MAAM,OAAsB;GAAE,GAAG,MAAM,KAAK,QAAQ,KAAK,OAAO;GAAG,GAAG,MAAM,KAAK,QAAQ,KAAK,OAAO;EAAE;EAC7G,IAAI,KAAK,GAAG,EAAE,EAAE,CAAC;EACjB,OAAO,KAAK,GAAG,EAAE,EAAE,CAAC;CACtB;CACA,OAAO;EAAE,MAAM,kBAAkB,CAAC,GAAG,KAAK,GAAG,OAAO,QAAQ,CAAC,CAAC;EAAG,MAAM,EAAE,KAAK;EAAM,QAAQ,EAAE,KAAK;CAAO;AAC5G"}
@@ -60,7 +60,7 @@ function byId(specs) {
60
60
  return out;
61
61
  }
62
62
  function needsReplace(a, b) {
63
- return a.kind !== b.kind || a.pickable !== b.pickable || a.derivePath !== b.derivePath || a.derivePose !== b.derivePose || a.clipFromPose !== b.clipFromPose || a.copiesFromPose !== b.copiesFromPose || a.layout !== b.layout;
63
+ return a.kind !== b.kind || a.pickable !== b.pickable || a.consumesChildren !== b.consumesChildren || a.derivePath !== b.derivePath || a.derivePose !== b.derivePose || a.clipFromPose !== b.clipFromPose || a.copiesFromPose !== b.copiesFromPose || a.layout !== b.layout;
64
64
  }
65
65
 
66
66
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"reconcileSpecs.js","names":["same"],"sources":["../../../src/core/scene/reconcileSpecs.ts"],"sourcesContent":["import { sameValue as same } from './sameValue';\nimport type { AddNodeSpec, NodeId, Scene } from './types';\n\n/**\n * Bring `scene` from `prev` to `next`: add what `next` gained, remove what it\n * lost, and write only the fields that changed between the two.\n *\n * The diff is spec against spec, not spec against scene, so whatever the scene\n * did since `prev` — a node dragged, an edge authored by a gesture — survives\n * unless `next` changes that same field. The writes are untracked: syncing to\n * outside data is not an undo step.\n *\n * Every spec needs an `id`, and `next` must be in an order `createScene` would\n * accept — parents and dependencies before what names them. A node whose\n * `kind` or derive functions change is removed and added again, along with\n * everything its removal takes with it, and stays selected if it was.\n */\nexport function reconcileSpecs<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n prev: readonly AddNodeSpec<TData, TLayer, TPose>[],\n next: readonly AddNodeSpec<TData, TLayer, TPose>[],\n): void {\n const prevById = byId(prev);\n const nextById = byId(next);\n const gone: NodeId[] = [];\n for (const [id, before] of prevById) {\n const after = nextById.get(id);\n if (after === undefined || needsReplace(before, after)) gone.push(id);\n }\n const removing = scene.removalClosure(gone.filter((id) => scene.get(id) !== undefined));\n const removed = new Set(removing);\n\n // A replaced node is the same node to whoever selected it.\n const selected = scene.getSelection();\n\n scene.untracked(() => {\n scene.removeMany(removing);\n for (const spec of next) {\n const id = spec.id!;\n const before = prevById.get(id);\n if (scene.get(id) === undefined || before === undefined || removed.has(id)) {\n scene.add(spec);\n continue;\n }\n // An unlock goes first and a lock last, so the writes between can land.\n if (before.locked === true && spec.locked !== true) scene.setLocked(id, false);\n const parent = spec.parent ?? null;\n if (parent !== (before.parent ?? null)) scene.move(id, parent);\n if (spec.layer !== before.layer) scene.setLayer(id, spec.layer);\n if (!same(spec.data, before.data)) scene.update(id, { data: spec.data });\n if (!same(spec.dependsOn, before.dependsOn)) scene.setDependsOn(id, spec.dependsOn);\n if (!same(spec.units, before.units)) scene.setUnits(id, spec.units ?? null);\n if (spec.clip !== before.clip) scene.setClip(id, spec.clip ?? null);\n if (!same(spec.pose, before.pose)) scene.setPose(id, spec.pose);\n if ((spec.hidden === true) !== (before.hidden === true)) scene.setHidden(id, spec.hidden === true);\n if (spec.locked === true && before.locked !== true) scene.setLocked(id, true);\n }\n if (selected.some((id) => removed.has(id))) {\n scene.setSelection(selected.filter((id) => scene.get(id) !== undefined));\n }\n });\n}\n\nfunction byId<T extends { id?: NodeId }>(specs: readonly T[]): Map<NodeId, T> {\n const out = new Map<NodeId, T>();\n for (const spec of specs) {\n if (spec.id === undefined) throw new Error('reconcileSpecs: every spec needs an id');\n if (out.has(spec.id)) throw new Error(`reconcileSpecs: id \"${spec.id}\" appears more than once`);\n out.set(spec.id, spec);\n }\n return out;\n}\n\nfunction needsReplace<TData, TLayer extends string, TPose>(\n a: AddNodeSpec<TData, TLayer, TPose>,\n b: AddNodeSpec<TData, TLayer, TPose>,\n): boolean {\n return a.kind !== b.kind\n || a.pickable !== b.pickable\n || a.derivePath !== b.derivePath\n || a.derivePose !== b.derivePose\n || a.clipFromPose !== b.clipFromPose\n || a.copiesFromPose !== b.copiesFromPose\n || a.layout !== b.layout;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,eACd,OACA,MACA,MACM;CACN,MAAM,WAAW,KAAK,IAAI;CAC1B,MAAM,WAAW,KAAK,IAAI;CAC1B,MAAM,OAAiB,CAAC;CACxB,KAAK,MAAM,CAAC,IAAI,WAAW,UAAU;EACnC,MAAM,QAAQ,SAAS,IAAI,EAAE;EAC7B,IAAI,UAAU,UAAa,aAAa,QAAQ,KAAK,GAAG,KAAK,KAAK,EAAE;CACtE;CACA,MAAM,WAAW,MAAM,eAAe,KAAK,QAAQ,OAAO,MAAM,IAAI,EAAE,MAAM,MAAS,CAAC;CACtF,MAAM,UAAU,IAAI,IAAI,QAAQ;CAGhC,MAAM,WAAW,MAAM,aAAa;CAEpC,MAAM,gBAAgB;EACpB,MAAM,WAAW,QAAQ;EACzB,KAAK,MAAM,QAAQ,MAAM;GACvB,MAAM,KAAK,KAAK;GAChB,MAAM,SAAS,SAAS,IAAI,EAAE;GAC9B,IAAI,MAAM,IAAI,EAAE,MAAM,UAAa,WAAW,UAAa,QAAQ,IAAI,EAAE,GAAG;IAC1E,MAAM,IAAI,IAAI;IACd;GACF;GAEA,IAAI,OAAO,WAAW,QAAQ,KAAK,WAAW,MAAM,MAAM,UAAU,IAAI,KAAK;GAC7E,MAAM,SAAS,KAAK,UAAU;GAC9B,IAAI,YAAY,OAAO,UAAU,OAAO,MAAM,KAAK,IAAI,MAAM;GAC7D,IAAI,KAAK,UAAU,OAAO,OAAO,MAAM,SAAS,IAAI,KAAK,KAAK;GAC9D,IAAI,CAACA,UAAK,KAAK,MAAM,OAAO,IAAI,GAAG,MAAM,OAAO,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;GACvE,IAAI,CAACA,UAAK,KAAK,WAAW,OAAO,SAAS,GAAG,MAAM,aAAa,IAAI,KAAK,SAAS;GAClF,IAAI,CAACA,UAAK,KAAK,OAAO,OAAO,KAAK,GAAG,MAAM,SAAS,IAAI,KAAK,SAAS,IAAI;GAC1E,IAAI,KAAK,SAAS,OAAO,MAAM,MAAM,QAAQ,IAAI,KAAK,QAAQ,IAAI;GAClE,IAAI,CAACA,UAAK,KAAK,MAAM,OAAO,IAAI,GAAG,MAAM,QAAQ,IAAI,KAAK,IAAI;GAC9D,IAAK,KAAK,WAAW,UAAW,OAAO,WAAW,OAAO,MAAM,UAAU,IAAI,KAAK,WAAW,IAAI;GACjG,IAAI,KAAK,WAAW,QAAQ,OAAO,WAAW,MAAM,MAAM,UAAU,IAAI,IAAI;EAC9E;EACA,IAAI,SAAS,MAAM,OAAO,QAAQ,IAAI,EAAE,CAAC,GACvC,MAAM,aAAa,SAAS,QAAQ,OAAO,MAAM,IAAI,EAAE,MAAM,MAAS,CAAC;CAE3E,CAAC;AACH;AAEA,SAAS,KAAgC,OAAqC;CAC5E,MAAM,sBAAM,IAAI,IAAe;CAC/B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,OAAO,QAAW,MAAM,IAAI,MAAM,wCAAwC;EACnF,IAAI,IAAI,IAAI,KAAK,EAAE,GAAG,MAAM,IAAI,MAAM,uBAAuB,KAAK,GAAG,yBAAyB;EAC9F,IAAI,IAAI,KAAK,IAAI,IAAI;CACvB;CACA,OAAO;AACT;AAEA,SAAS,aACP,GACA,GACS;CACT,OAAO,EAAE,SAAS,EAAE,QACf,EAAE,aAAa,EAAE,YACjB,EAAE,eAAe,EAAE,cACnB,EAAE,eAAe,EAAE,cACnB,EAAE,iBAAiB,EAAE,gBACrB,EAAE,mBAAmB,EAAE,kBACvB,EAAE,WAAW,EAAE;AACtB"}
1
+ {"version":3,"file":"reconcileSpecs.js","names":["same"],"sources":["../../../src/core/scene/reconcileSpecs.ts"],"sourcesContent":["import { sameValue as same } from './sameValue';\nimport type { AddNodeSpec, NodeId, Scene } from './types';\n\n/**\n * Bring `scene` from `prev` to `next`: add what `next` gained, remove what it\n * lost, and write only the fields that changed between the two.\n *\n * The diff is spec against spec, not spec against scene, so whatever the scene\n * did since `prev` — a node dragged, an edge authored by a gesture — survives\n * unless `next` changes that same field. The writes are untracked: syncing to\n * outside data is not an undo step.\n *\n * Every spec needs an `id`, and `next` must be in an order `createScene` would\n * accept — parents and dependencies before what names them. A node whose\n * `kind` or derive functions change is removed and added again, along with\n * everything its removal takes with it, and stays selected if it was.\n */\nexport function reconcileSpecs<TData, TLayer extends string, TPose>(\n scene: Scene<TData, TLayer, TPose>,\n prev: readonly AddNodeSpec<TData, TLayer, TPose>[],\n next: readonly AddNodeSpec<TData, TLayer, TPose>[],\n): void {\n const prevById = byId(prev);\n const nextById = byId(next);\n const gone: NodeId[] = [];\n for (const [id, before] of prevById) {\n const after = nextById.get(id);\n if (after === undefined || needsReplace(before, after)) gone.push(id);\n }\n const removing = scene.removalClosure(gone.filter((id) => scene.get(id) !== undefined));\n const removed = new Set(removing);\n\n // A replaced node is the same node to whoever selected it.\n const selected = scene.getSelection();\n\n scene.untracked(() => {\n scene.removeMany(removing);\n for (const spec of next) {\n const id = spec.id!;\n const before = prevById.get(id);\n if (scene.get(id) === undefined || before === undefined || removed.has(id)) {\n scene.add(spec);\n continue;\n }\n // An unlock goes first and a lock last, so the writes between can land.\n if (before.locked === true && spec.locked !== true) scene.setLocked(id, false);\n const parent = spec.parent ?? null;\n if (parent !== (before.parent ?? null)) scene.move(id, parent);\n if (spec.layer !== before.layer) scene.setLayer(id, spec.layer);\n if (!same(spec.data, before.data)) scene.update(id, { data: spec.data });\n if (!same(spec.dependsOn, before.dependsOn)) scene.setDependsOn(id, spec.dependsOn);\n if (!same(spec.units, before.units)) scene.setUnits(id, spec.units ?? null);\n if (spec.clip !== before.clip) scene.setClip(id, spec.clip ?? null);\n if (!same(spec.pose, before.pose)) scene.setPose(id, spec.pose);\n if ((spec.hidden === true) !== (before.hidden === true)) scene.setHidden(id, spec.hidden === true);\n if (spec.locked === true && before.locked !== true) scene.setLocked(id, true);\n }\n if (selected.some((id) => removed.has(id))) {\n scene.setSelection(selected.filter((id) => scene.get(id) !== undefined));\n }\n });\n}\n\nfunction byId<T extends { id?: NodeId }>(specs: readonly T[]): Map<NodeId, T> {\n const out = new Map<NodeId, T>();\n for (const spec of specs) {\n if (spec.id === undefined) throw new Error('reconcileSpecs: every spec needs an id');\n if (out.has(spec.id)) throw new Error(`reconcileSpecs: id \"${spec.id}\" appears more than once`);\n out.set(spec.id, spec);\n }\n return out;\n}\n\nfunction needsReplace<TData, TLayer extends string, TPose>(\n a: AddNodeSpec<TData, TLayer, TPose>,\n b: AddNodeSpec<TData, TLayer, TPose>,\n): boolean {\n return a.kind !== b.kind\n || a.pickable !== b.pickable\n || a.consumesChildren !== b.consumesChildren\n || a.derivePath !== b.derivePath\n || a.derivePose !== b.derivePose\n || a.clipFromPose !== b.clipFromPose\n || a.copiesFromPose !== b.copiesFromPose\n || a.layout !== b.layout;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,eACd,OACA,MACA,MACM;CACN,MAAM,WAAW,KAAK,IAAI;CAC1B,MAAM,WAAW,KAAK,IAAI;CAC1B,MAAM,OAAiB,CAAC;CACxB,KAAK,MAAM,CAAC,IAAI,WAAW,UAAU;EACnC,MAAM,QAAQ,SAAS,IAAI,EAAE;EAC7B,IAAI,UAAU,UAAa,aAAa,QAAQ,KAAK,GAAG,KAAK,KAAK,EAAE;CACtE;CACA,MAAM,WAAW,MAAM,eAAe,KAAK,QAAQ,OAAO,MAAM,IAAI,EAAE,MAAM,MAAS,CAAC;CACtF,MAAM,UAAU,IAAI,IAAI,QAAQ;CAGhC,MAAM,WAAW,MAAM,aAAa;CAEpC,MAAM,gBAAgB;EACpB,MAAM,WAAW,QAAQ;EACzB,KAAK,MAAM,QAAQ,MAAM;GACvB,MAAM,KAAK,KAAK;GAChB,MAAM,SAAS,SAAS,IAAI,EAAE;GAC9B,IAAI,MAAM,IAAI,EAAE,MAAM,UAAa,WAAW,UAAa,QAAQ,IAAI,EAAE,GAAG;IAC1E,MAAM,IAAI,IAAI;IACd;GACF;GAEA,IAAI,OAAO,WAAW,QAAQ,KAAK,WAAW,MAAM,MAAM,UAAU,IAAI,KAAK;GAC7E,MAAM,SAAS,KAAK,UAAU;GAC9B,IAAI,YAAY,OAAO,UAAU,OAAO,MAAM,KAAK,IAAI,MAAM;GAC7D,IAAI,KAAK,UAAU,OAAO,OAAO,MAAM,SAAS,IAAI,KAAK,KAAK;GAC9D,IAAI,CAACA,UAAK,KAAK,MAAM,OAAO,IAAI,GAAG,MAAM,OAAO,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;GACvE,IAAI,CAACA,UAAK,KAAK,WAAW,OAAO,SAAS,GAAG,MAAM,aAAa,IAAI,KAAK,SAAS;GAClF,IAAI,CAACA,UAAK,KAAK,OAAO,OAAO,KAAK,GAAG,MAAM,SAAS,IAAI,KAAK,SAAS,IAAI;GAC1E,IAAI,KAAK,SAAS,OAAO,MAAM,MAAM,QAAQ,IAAI,KAAK,QAAQ,IAAI;GAClE,IAAI,CAACA,UAAK,KAAK,MAAM,OAAO,IAAI,GAAG,MAAM,QAAQ,IAAI,KAAK,IAAI;GAC9D,IAAK,KAAK,WAAW,UAAW,OAAO,WAAW,OAAO,MAAM,UAAU,IAAI,KAAK,WAAW,IAAI;GACjG,IAAI,KAAK,WAAW,QAAQ,OAAO,WAAW,MAAM,MAAM,UAAU,IAAI,IAAI;EAC9E;EACA,IAAI,SAAS,MAAM,OAAO,QAAQ,IAAI,EAAE,CAAC,GACvC,MAAM,aAAa,SAAS,QAAQ,OAAO,MAAM,IAAI,EAAE,MAAM,MAAS,CAAC;CAE3E,CAAC;AACH;AAEA,SAAS,KAAgC,OAAqC;CAC5E,MAAM,sBAAM,IAAI,IAAe;CAC/B,KAAK,MAAM,QAAQ,OAAO;EACxB,IAAI,KAAK,OAAO,QAAW,MAAM,IAAI,MAAM,wCAAwC;EACnF,IAAI,IAAI,IAAI,KAAK,EAAE,GAAG,MAAM,IAAI,MAAM,uBAAuB,KAAK,GAAG,yBAAyB;EAC9F,IAAI,IAAI,KAAK,IAAI,IAAI;CACvB;CACA,OAAO;AACT;AAEA,SAAS,aACP,GACA,GACS;CACT,OAAO,EAAE,SAAS,EAAE,QACf,EAAE,aAAa,EAAE,YACjB,EAAE,qBAAqB,EAAE,oBACzB,EAAE,eAAe,EAAE,cACnB,EAAE,eAAe,EAAE,cACnB,EAAE,iBAAiB,EAAE,gBACrB,EAAE,mBAAmB,EAAE,kBACvB,EAAE,WAAW,EAAE;AACtB"}
@@ -1,5 +1,6 @@
1
- import { IDENTITY_POSE_COMPOSITION } from "./composeFrame.js";
1
+ import { RIGID_POSE_COMPOSITION } from "./composePose.js";
2
2
  import { effectivePose } from "./effectivePose.js";
3
+ import { createScrollOffsets } from "./scrollOffsets.js";
3
4
  import { asNodeId } from "./types.js";
4
5
  import { documentReads, sceneMutators } from "./sceneMutators.js";
5
6
  import { withKitRegistry } from "./kitRegistry.js";
@@ -60,9 +61,9 @@ function buildScene(options, layers, initialNodes, initialDoc) {
60
61
  const generateId = options.generateId ?? defaultGenerateId;
61
62
  const selection = createSceneSelection(locks.reachable);
62
63
  selection.subscribe(notifier.notify);
63
- /** Ephemeral per-node overrides. Deliberately not part of `state`: not
64
- * document content, never reaches `toJSON`, and never touches history. */
64
+ /** Ephemeral, deliberately not part of `state`: not document content, never in `toJSON` or history. */
65
65
  const overrides = createPoseOverrides((id) => state.nodes.get(id), doc.store.invalidateDependents);
66
+ const scroll = createScrollOffsets();
66
67
  const recording = createSceneRecording({
67
68
  notifier,
68
69
  mode,
@@ -110,7 +111,7 @@ function buildScene(options, layers, initialNodes, initialDoc) {
110
111
  registry,
111
112
  ...reads,
112
113
  mintId: generateId,
113
- composition: options.composition ?? IDENTITY_POSE_COMPOSITION,
114
+ composition: options.composition ?? RIGID_POSE_COMPOSITION,
114
115
  ...edits.methods,
115
116
  ...recording.methods,
116
117
  unlocked: (fn) => locks.lifted(fn),
@@ -118,12 +119,17 @@ function buildScene(options, layers, initialNodes, initialDoc) {
118
119
  onReflow: arrivals.onReflow,
119
120
  onPoseWrite: poseWrites.subscribe,
120
121
  overrides,
122
+ scroll,
121
123
  getSelection: selection.get,
122
124
  setSelection: (ids) => selection.set([...ids]),
123
125
  loadState(json, opts) {
124
- const specs = specsFromSerialized(json, registry, opts);
126
+ const specs = specsFromSerialized(json, registry, {
127
+ composition: scene.composition,
128
+ ...opts
129
+ });
125
130
  if (mode.open()) throw new Error("Scene: cannot loadState inside another edit — it replaces the state that edit would revert to");
126
131
  overrides.clearAll();
132
+ scroll.clearAll();
127
133
  doc.reset(json.systemLayers.map(layerFromSerialized), json.doc);
128
134
  recording.clearHistory();
129
135
  poseWrites.quiet(() => edits.construct(specs));
@@ -1 +1 @@
1
- {"version":3,"file":"scene.js","names":[],"sources":["../../../src/core/scene/scene.ts"],"sourcesContent":["import { withKitRegistry } from './kitRegistry';\nimport { createPoseOverrides } from './poseOverrides';\nimport { createArrivalWindow } from './arrivalWindow';\nimport { documentReads, sceneMutators } from './sceneMutators';\nimport { createNotifier } from './notifier';\nimport type { SerializedDoc } from './docValues';\nimport { sceneChanges } from './sceneChanges';\nimport { createPoseWriteLog } from './poseWrites';\nimport { effectivePose } from './effectivePose';\nimport { createEditMode } from './editMode';\nimport { createSceneEdits } from './sceneEdits';\nimport { createSceneRecording } from './sceneRecording';\nimport { createSceneSelection } from './sceneSelection';\nimport { createSceneState } from './sceneState';\nimport { systemLayerRecord } from './layerStack';\nimport { layerFromSerialized, specsFromSerialized, type SpecsFromSerializedOptions } from './serialization';\nimport { resolveLayoutFrame, runLayoutPass } from './layoutPass';\nimport { IDENTITY_POSE_COMPOSITION, type PoseComposition } from './composeFrame';\nimport {\n asNodeId,\n type AddNodeSpec,\n type LayerRecord,\n type NodeId,\n type RegisteredOp,\n type Scene,\n type SceneRegistry,\n type SerializedScene,\n type SerializedSceneV1,\n type UseSceneOptions,\n} from './types';\n\n/** A node still in `scene`, with the pose it is shown at. */\nfunction shownNode<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, id: NodeId) {\n const node = scene.get(id);\n return node && { node, pose: effectivePose(scene, node) };\n}\n\nlet defaultIdCounter = 0;\nconst defaultGenerateId = (): NodeId =>\n asNodeId(`n${(defaultIdCounter++).toString(36)}-${Math.random().toString(36).slice(2, 8)}`);\n\n/** Build a scene outside React. `useScene` is the usual entry point; reach for\n * this in tests, in headless rendering, or wherever a scene must outlive a\n * component. Throws if no system layers are declared. */\nexport function createScene<TData, TLayer extends string, TPose = import('./composePose').RectPose>(\n options: UseSceneOptions<TData, TLayer, TPose>,\n): Scene<TData, TLayer, TPose> {\n return buildScene(options, (options.systemLayers ?? []).map(systemLayerRecord), () => options.initial, options.doc);\n}\n\ntype SceneConfig<TData, TLayer extends string, TPose> =\n Omit<UseSceneOptions<TData, TLayer, TPose>, 'systemLayers' | 'initial' | 'doc'>;\n\n/** A scene holding `layers`, the document values `initialDoc`, and the nodes\n * `initialNodes` answers with once it is handed the registry their functions\n * resolve against. */\nfunction buildScene<TData, TLayer extends string, TPose>(\n options: SceneConfig<TData, TLayer, TPose>,\n layers: readonly LayerRecord<TLayer>[],\n initialNodes: (registry: SceneRegistry<TPose, TData, TLayer>) => readonly AddNodeSpec<TData, TLayer, TPose>[] | undefined,\n initialDoc: SerializedDoc | undefined,\n): Scene<TData, TLayer, TPose> {\n if (layers.length === 0) throw new Error('Scene: systemLayers must declare at least one layer');\n\n // The kit's own registry entries sit under the consumer's, so a snapshot\n // carrying a kit-attached function (a grouped container's derived pose)\n // reloads in any scene, not only one whose consumer registered the key.\n const registry = withKitRegistry(options.registry ?? {});\n\n const doc = createSceneState<TData, TLayer, TPose>(registry, layers, () => arrivals.layoutDeclared(), initialDoc);\n const { state, locks, reads } = doc;\n const notifier = createNotifier();\n const mode = createEditMode();\n const poseWrites = createPoseWriteLog({ untracked: mode.untracked, changes: notifier, shown: (id) => shownNode(scene, id) });\n const writePose = (id: string, pose: unknown): void => poseWrites.layout(() => scene.setPose(asNodeId(id), pose as TPose));\n\n const layoutFrame = resolveLayoutFrame(options.layoutFrame);\n const arrivals = createArrivalWindow<TData, TLayer, TPose>({\n nodes: state.nodes,\n layoutPass: (arrived, touched, departed) =>\n runLayoutPass(scene, reads.layoutOf, arrived, touched, layoutFrame, departed),\n recordsBareEdits: () => !mode.open(),\n writePose,\n });\n\n const generateId = options.generateId ?? defaultGenerateId;\n const selection = createSceneSelection(locks.reachable);\n // A selection change is a scene change to every subscriber.\n selection.subscribe(notifier.notify);\n\n /** Ephemeral per-node overrides. Deliberately not part of `state`: not\n * document content, never reaches `toJSON`, and never touches history. */\n const overrides = createPoseOverrides<TPose, TData>((id) => state.nodes.get(id), doc.store.invalidateDependents);\n\n const recording = createSceneRecording({\n notifier,\n mode,\n passAdapter: () => ({ ...sceneMutators(scene), ...documentReads(scene) }),\n stale: doc.stale,\n lifted: locks.lifted,\n selection,\n arrivals,\n writePose,\n poseWrites,\n config: options,\n });\n\n const edits = createSceneEdits<TData, TLayer, TPose>({\n state,\n store: doc.store,\n locks,\n layers: doc.layers,\n invalidateOrder: doc.order.invalidate,\n fnFields: doc.fnFields,\n ops: { ...recording.ops, register: poseWrites.reporting(recording.ops.register) },\n recorder: recording.recorder,\n arrivals,\n layoutFrame,\n generateId,\n narrowSelection: selection.narrow,\n clearOverride: overrides.clear,\n });\n for (const [kind, handler] of Object.entries(options.ops ?? {})) recording.ops.register(kind, handler);\n\n const scene: Scene<TData, TLayer, TPose> = {\n get nodes() { return state.nodes; },\n get roots() { return state.roots; },\n get layers() { return state.layers; },\n registry,\n\n ...reads,\n\n mintId: generateId,\n composition: options.composition ?? (IDENTITY_POSE_COMPOSITION as PoseComposition<TPose>),\n\n ...edits.methods,\n ...recording.methods,\n\n unlocked: (fn) => locks.lifted(fn),\n\n setArrivalHandler: arrivals.setHandler,\n onReflow: arrivals.onReflow,\n onPoseWrite: poseWrites.subscribe,\n\n overrides,\n\n getSelection: selection.get,\n setSelection: (ids) => selection.set([...ids]),\n\n loadState(json, opts) {\n // Validate + map up front (throws before we touch live state on a bad\n // version or unknown registry key).\n const specs = specsFromSerialized(json, registry, opts);\n if (mode.open()) {\n throw new Error('Scene: cannot loadState inside another edit — it replaces the state that edit would revert to');\n }\n // Ephemeral, and every id is a new node after this.\n overrides.clearAll();\n doc.reset(json.systemLayers.map(layerFromSerialized), json.doc);\n recording.clearHistory();\n poseWrites.quiet(() => edits.construct(specs));\n selection.replace(locks.reachable(selection.get().filter((id) => state.nodes.has(id))));\n notifier.notify();\n },\n\n ...sceneChanges(notifier, selection),\n };\n\n const initial = initialNodes(registry);\n if (initial) {\n poseWrites.quiet(() => edits.construct(initial));\n notifier.notify();\n }\n\n return scene;\n}\n\n/** Reconstruct a Scene from a JSON snapshot produced by `scene.toJSON()`.\n * Function fields (e.g., `clipFromPose`) are resolved by string key via the\n * registry passed in `options`. Throws on unknown version, unknown registry\n * keys, or invalid scene shape (cross-layer subtrees, unknown layer ids).\n * The scene starts with empty history. */\nexport function sceneFromJSON<TData, TLayer extends string, TPose>(\n json: SerializedScene<TData, TLayer, TPose> | SerializedSceneV1<TData, TLayer, TPose>,\n options: {\n registry?: SceneRegistry<TPose, TData, TLayer>;\n historyLimit?: number;\n coalesceWindowMs?: number;\n generateId?: () => NodeId;\n ops?: Readonly<Record<string, RegisteredOp<unknown>>>;\n composition?: UseSceneOptions<TData, TLayer, TPose>['composition'];\n layoutFrame?: UseSceneOptions<TData, TLayer, TPose>['layoutFrame'];\n } & SpecsFromSerializedOptions<TData, TLayer, TPose> = {},\n): Scene<TData, TLayer, TPose> {\n return buildScene(\n options,\n json.systemLayers.map(layerFromSerialized),\n (registry) => specsFromSerialized(json, registry, options),\n json.doc,\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"scene.js","names":[],"sources":["../../../src/core/scene/scene.ts"],"sourcesContent":["import { withKitRegistry } from './kitRegistry';\nimport { createPoseOverrides } from './poseOverrides';\nimport { createScrollOffsets } from './scrollOffsets';\nimport { createArrivalWindow } from './arrivalWindow';\nimport { documentReads, sceneMutators } from './sceneMutators';\nimport { createNotifier } from './notifier';\nimport type { SerializedDoc } from './docValues';\nimport { sceneChanges } from './sceneChanges';\nimport { createPoseWriteLog } from './poseWrites';\nimport { effectivePose } from './effectivePose';\nimport { createEditMode } from './editMode';\nimport { createSceneEdits } from './sceneEdits';\nimport { createSceneRecording } from './sceneRecording';\nimport { createSceneSelection } from './sceneSelection';\nimport { createSceneState } from './sceneState';\nimport { systemLayerRecord } from './layerStack';\nimport { layerFromSerialized, specsFromSerialized, type SpecsFromSerializedOptions } from './serialization';\nimport { resolveLayoutFrame, runLayoutPass } from './layoutPass';\nimport type { PoseComposition } from './composeFrame';\nimport { RIGID_POSE_COMPOSITION } from './composePose';\nimport type { SceneOptions } from './useSceneOptions';\nimport {\n asNodeId,\n type AddNodeSpec,\n type LayerRecord,\n type NodeId,\n type RegisteredOp,\n type Scene,\n type SceneRegistry,\n type SavedScene,\n type UseSceneOptions,\n} from './types';\n\n/** A node still in `scene`, with the pose it is shown at. */\nfunction shownNode<TData, TLayer extends string, TPose>(scene: Scene<TData, TLayer, TPose>, id: NodeId) {\n const node = scene.get(id);\n return node && { node, pose: effectivePose(scene, node) };\n}\n\nlet defaultIdCounter = 0;\nconst defaultGenerateId = (): NodeId =>\n asNodeId(`n${(defaultIdCounter++).toString(36)}-${Math.random().toString(36).slice(2, 8)}`);\n\n/** Build a scene outside React. `useScene` is the usual entry point; reach for\n * this in tests, in headless rendering, or wherever a scene must outlive a\n * component. Throws if no system layers are declared. */\nexport function createScene<TData, TLayer extends string, TPose = import('./composePose').RectPose>(\n options: UseSceneOptions<TData, TLayer, TPose>,\n): Scene<TData, TLayer, TPose> {\n return buildScene(options, (options.systemLayers ?? []).map(systemLayerRecord), () => options.initial, options.doc);\n}\n\ntype SceneConfig<TData, TLayer extends string, TPose> =\n Omit<SceneOptions<TData, TLayer, TPose>, 'systemLayers' | 'initial' | 'doc'>;\n\n/** A scene holding `layers`, the document values `initialDoc`, and the nodes\n * `initialNodes` answers with once it is handed the registry their functions\n * resolve against. */\nfunction buildScene<TData, TLayer extends string, TPose>(\n options: SceneConfig<TData, TLayer, TPose>,\n layers: readonly LayerRecord<TLayer>[],\n initialNodes: (registry: SceneRegistry<TPose, TData, TLayer>) => readonly AddNodeSpec<TData, TLayer, TPose>[] | undefined,\n initialDoc: SerializedDoc | undefined,\n): Scene<TData, TLayer, TPose> {\n if (layers.length === 0) throw new Error('Scene: systemLayers must declare at least one layer');\n\n // The kit's own registry entries sit under the consumer's, so a snapshot carrying a kit-attached\n // function (a grouped container's derived pose) reloads in any scene, not only one that registered it.\n const registry = withKitRegistry(options.registry ?? {});\n\n const doc = createSceneState<TData, TLayer, TPose>(registry, layers, () => arrivals.layoutDeclared(), initialDoc);\n const { state, locks, reads } = doc;\n const notifier = createNotifier();\n const mode = createEditMode();\n const poseWrites = createPoseWriteLog({ untracked: mode.untracked, changes: notifier, shown: (id) => shownNode(scene, id) });\n const writePose = (id: string, pose: unknown): void => poseWrites.layout(() => scene.setPose(asNodeId(id), pose as TPose));\n\n const layoutFrame = resolveLayoutFrame(options.layoutFrame);\n const arrivals = createArrivalWindow<TData, TLayer, TPose>({\n nodes: state.nodes,\n layoutPass: (arrived, touched, departed) =>\n runLayoutPass(scene, reads.layoutOf, arrived, touched, layoutFrame, departed),\n recordsBareEdits: () => !mode.open(),\n writePose,\n });\n\n const generateId = options.generateId ?? defaultGenerateId;\n const selection = createSceneSelection(locks.reachable);\n // A selection change is a scene change to every subscriber.\n selection.subscribe(notifier.notify);\n\n /** Ephemeral, deliberately not part of `state`: not document content, never in `toJSON` or history. */\n const overrides = createPoseOverrides<TPose, TData>((id) => state.nodes.get(id), doc.store.invalidateDependents);\n const scroll = createScrollOffsets();\n\n const recording = createSceneRecording({\n notifier,\n mode,\n passAdapter: () => ({ ...sceneMutators(scene), ...documentReads(scene) }),\n stale: doc.stale,\n lifted: locks.lifted,\n selection,\n arrivals,\n writePose,\n poseWrites,\n config: options,\n });\n\n const edits = createSceneEdits<TData, TLayer, TPose>({\n state,\n store: doc.store,\n locks,\n layers: doc.layers,\n invalidateOrder: doc.order.invalidate,\n fnFields: doc.fnFields,\n ops: { ...recording.ops, register: poseWrites.reporting(recording.ops.register) },\n recorder: recording.recorder,\n arrivals,\n layoutFrame,\n generateId,\n narrowSelection: selection.narrow,\n clearOverride: overrides.clear,\n });\n for (const [kind, handler] of Object.entries(options.ops ?? {})) recording.ops.register(kind, handler);\n\n const scene: Scene<TData, TLayer, TPose> = {\n get nodes() { return state.nodes; },\n get roots() { return state.roots; },\n get layers() { return state.layers; },\n registry,\n\n ...reads,\n\n mintId: generateId,\n composition: options.composition ?? (RIGID_POSE_COMPOSITION as PoseComposition<TPose>),\n\n ...edits.methods,\n ...recording.methods,\n\n unlocked: (fn) => locks.lifted(fn),\n\n setArrivalHandler: arrivals.setHandler,\n onReflow: arrivals.onReflow,\n onPoseWrite: poseWrites.subscribe,\n\n overrides,\n scroll,\n\n getSelection: selection.get,\n setSelection: (ids) => selection.set([...ids]),\n\n loadState(json, opts) {\n // Validate + map up front: throws on a bad version or registry key before live state is touched.\n const specs = specsFromSerialized(json, registry, { composition: scene.composition, ...opts });\n if (mode.open()) {\n throw new Error('Scene: cannot loadState inside another edit — it replaces the state that edit would revert to');\n }\n // Ephemeral, and every id is a new node after this.\n overrides.clearAll();\n scroll.clearAll();\n doc.reset(json.systemLayers.map(layerFromSerialized), json.doc);\n recording.clearHistory();\n poseWrites.quiet(() => edits.construct(specs));\n selection.replace(locks.reachable(selection.get().filter((id) => state.nodes.has(id))));\n notifier.notify();\n },\n\n ...sceneChanges(notifier, selection),\n };\n\n const initial = initialNodes(registry);\n if (initial) {\n poseWrites.quiet(() => edits.construct(initial));\n notifier.notify();\n }\n\n return scene;\n}\n\n/** Reconstruct a Scene from a JSON snapshot produced by `scene.toJSON()`.\n * Function fields (e.g., `clipFromPose`) are resolved by string key via the\n * registry passed in `options`. Throws on unknown version, unknown registry\n * keys, or invalid scene shape (cross-layer subtrees, unknown layer ids).\n * The scene starts with empty history. */\nexport function sceneFromJSON<TData, TLayer extends string, TPose>(\n json: SavedScene<TData, TLayer, TPose>,\n options: {\n registry?: SceneRegistry<TPose, TData, TLayer>;\n historyLimit?: number;\n coalesceWindowMs?: number;\n generateId?: () => NodeId;\n ops?: Readonly<Record<string, RegisteredOp<unknown>>>;\n composition?: SceneOptions<TData, TLayer, TPose>['composition'];\n layoutFrame?: SceneOptions<TData, TLayer, TPose>['layoutFrame'];\n } & SpecsFromSerializedOptions<TData, TLayer, TPose> = {},\n): Scene<TData, TLayer, TPose> {\n return buildScene(\n options,\n json.systemLayers.map(layerFromSerialized),\n (registry) => specsFromSerialized(json, registry, options),\n json.doc,\n );\n}\n"],"mappings":"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"}
@@ -18,7 +18,8 @@ function createSceneEdits(env) {
18
18
  invalidateOrder: env.invalidateOrder,
19
19
  fnFields,
20
20
  narrowSelection: env.narrowSelection,
21
- clearOverride: env.clearOverride
21
+ clearOverride: env.clearOverride,
22
+ noteWritten: locks.noteWritten
22
23
  });
23
24
  const { construct, ...treeEdits } = createTreeEdits({
24
25
  nodes: state.nodes,
@@ -55,7 +56,9 @@ function createSceneEdits(env) {
55
56
  register: env.ops.register,
56
57
  requireNode: store.requireNode,
57
58
  record: recorder.record,
58
- narrowSelection: () => env.narrowSelection()
59
+ narrowSelection: () => env.narrowSelection(),
60
+ invalidateDependents: store.invalidateDependents,
61
+ noteWritten: locks.noteWritten
59
62
  });
60
63
  const declaredEdits = createDeclaredFieldSetters({
61
64
  register: env.ops.register,
@@ -1 +1 @@
1
- {"version":3,"file":"sceneEdits.js","names":[],"sources":["../../../src/core/scene/sceneEdits.ts"],"sourcesContent":["/**\n * The scene's edits to its document — tree, node fields, layers, and document values — with\n * the kit ops they record.\n */\nimport type { ArrivalWindow } from './arrivalWindow';\nimport { createSceneDoc, type SceneDocValues } from './docValues';\nimport { createDeclaredFieldSetters, type SceneDeclaredFieldSetters } from './declaredFieldSetters';\nimport { createFieldEdits, type FieldEdits } from './fieldEdits';\nimport { registerKitOps } from './kitOps';\nimport { createNodeFlags } from './nodeFlags';\nimport { createLayerEdits, type LayerEdits, type createLayerStack } from './layerStack';\nimport type { ResolvedLayoutFrame } from './layoutPass';\nimport type { LockGuard } from './lockGuard';\nimport type { NodeFnField } from './nodeFnFields';\nimport type { createNodeStore } from './nodeStore';\nimport type { OpTable } from './opTable';\nimport type { Recorder } from './recorder';\nimport { createTreeEdits, type TreeEdits } from './treeEdits';\nimport type { LayerRecord, Node, NodeId } from './types';\n\nexport interface SceneEditsEnv<TData, TLayer extends string, TPose> {\n state: {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n layers: LayerRecord<TLayer>[];\n layerIndex: Map<TLayer, number>;\n /** The scene's document values, which `doc` reads and records. */\n docValues: Map<string, unknown>;\n };\n store: ReturnType<typeof createNodeStore<TData, TLayer, TPose>>;\n locks: Pick<LockGuard<TLayer>, 'refuse' | 'refuseLayer' | 'lifted'>;\n layers: Pick<\n ReturnType<typeof createLayerStack<TLayer>>,\n 'requireLayerIndex' | 'rebuildLayerIndex' | 'assertSubtreeLayer'\n >;\n invalidateOrder(): void;\n fnFields: readonly NodeFnField[];\n ops: Pick<OpTable, 'register' | 'run'>;\n recorder: Pick<Recorder, 'record' | 'edit' | 'batch'>;\n arrivals: Pick<ArrivalWindow<TPose>, 'noteArrival' | 'noteDeparture' | 'noteChange' | 'layoutDeclared'>;\n layoutFrame: ResolvedLayoutFrame<TPose>;\n generateId(): NodeId;\n narrowSelection(gone?: ReadonlySet<NodeId>): void;\n clearOverride(id: NodeId): void;\n}\n\nexport interface SceneEdits<TData, TLayer extends string, TPose> {\n construct: TreeEdits<TData, TLayer, TPose>['construct'];\n methods: Omit<TreeEdits<TData, TLayer, TPose>, 'construct'>\n & FieldEdits<TData, TLayer, TPose>\n & LayerEdits<TData, TLayer, TPose>\n & ReturnType<typeof createNodeFlags<TData, TLayer, TPose>>\n & SceneDeclaredFieldSetters\n & SceneDocValues;\n}\n\nexport function createSceneEdits<TData, TLayer extends string, TPose>(\n env: SceneEditsEnv<TData, TLayer, TPose>,\n): SceneEdits<TData, TLayer, TPose> {\n const { state, store, locks, layers, fnFields, recorder, arrivals } = env;\n\n const { layoutRefs } = registerKitOps<TData, TLayer, TPose>({\n state,\n register: env.ops.register,\n store,\n requireLayerIndex: layers.requireLayerIndex,\n rebuildLayerIndex: layers.rebuildLayerIndex,\n invalidateOrder: env.invalidateOrder,\n fnFields,\n narrowSelection: env.narrowSelection,\n clearOverride: env.clearOverride,\n });\n\n const { construct, ...treeEdits } = createTreeEdits<TData, TLayer, TPose>({\n nodes: state.nodes,\n generateId: env.generateId,\n store,\n locks,\n layers,\n fnFields,\n runOp: env.ops.run,\n recorder,\n arrivals,\n });\n\n const fieldEdits = createFieldEdits<TData, TLayer, TPose>({\n store,\n locks,\n layers,\n recorder,\n arrivals,\n layoutFrame: env.layoutFrame,\n layoutField: fnFields.find((f) => f.spec.field === 'layout')!,\n layoutRefs,\n });\n\n const layerEdits = createLayerEdits<TData, TLayer, TPose>({\n layers: state.layers,\n layerIndex: state.layerIndex,\n nodes: state.nodes,\n requireLayerIndex: layers.requireLayerIndex,\n record: recorder.record,\n lifted: locks.lifted,\n batch: recorder.batch,\n removeMany: treeEdits.removeMany,\n });\n\n const flagEdits = createNodeFlags<TData, TLayer, TPose>({\n register: env.ops.register,\n requireNode: store.requireNode,\n record: recorder.record,\n narrowSelection: () => env.narrowSelection(),\n });\n\n const declaredEdits = createDeclaredFieldSetters<TData, TLayer, TPose>({\n register: env.ops.register,\n requireNode: store.requireNode,\n refuse: locks.refuse,\n record: recorder.record,\n });\n\n const doc = createSceneDoc({ values: state.docValues, register: env.ops.register, record: recorder.record });\n\n return { construct, methods: { ...treeEdits, ...fieldEdits, ...layerEdits, ...flagEdits, ...declaredEdits, doc } };\n}\n"],"mappings":";;;;;;;;;AAuDA,SAAgB,iBACd,KACkC;CAClC,MAAM,EAAE,OAAO,OAAO,OAAO,QAAQ,UAAU,UAAU,aAAa;CAEtE,MAAM,EAAE,eAAe,eAAqC;EAC1D;EACA,UAAU,IAAI,IAAI;EAClB;EACA,mBAAmB,OAAO;EAC1B,mBAAmB,OAAO;EAC1B,iBAAiB,IAAI;EACrB;EACA,iBAAiB,IAAI;EACrB,eAAe,IAAI;CACrB,CAAC;CAED,MAAM,EAAE,WAAW,GAAG,cAAc,gBAAsC;EACxE,OAAO,MAAM;EACb,YAAY,IAAI;EAChB;EACA;EACA;EACA;EACA,OAAO,IAAI,IAAI;EACf;EACA;CACF,CAAC;CAED,MAAM,aAAa,iBAAuC;EACxD;EACA;EACA;EACA;EACA;EACA,aAAa,IAAI;EACjB,aAAa,SAAS,MAAM,MAAM,EAAE,KAAK,UAAU,QAAQ;EAC3D;CACF,CAAC;CAED,MAAM,aAAa,iBAAuC;EACxD,QAAQ,MAAM;EACd,YAAY,MAAM;EAClB,OAAO,MAAM;EACb,mBAAmB,OAAO;EAC1B,QAAQ,SAAS;EACjB,QAAQ,MAAM;EACd,OAAO,SAAS;EAChB,YAAY,UAAU;CACxB,CAAC;CAED,MAAM,YAAY,gBAAsC;EACtD,UAAU,IAAI,IAAI;EAClB,aAAa,MAAM;EACnB,QAAQ,SAAS;EACjB,uBAAuB,IAAI,gBAAgB;CAC7C,CAAC;CAED,MAAM,gBAAgB,2BAAiD;EACrE,UAAU,IAAI,IAAI;EAClB,aAAa,MAAM;EACnB,QAAQ,MAAM;EACd,QAAQ,SAAS;CACnB,CAAC;CAED,MAAM,MAAM,eAAe;EAAE,QAAQ,MAAM;EAAW,UAAU,IAAI,IAAI;EAAU,QAAQ,SAAS;CAAO,CAAC;CAE3G,OAAO;EAAE;EAAW,SAAS;GAAE,GAAG;GAAW,GAAG;GAAY,GAAG;GAAY,GAAG;GAAW,GAAG;GAAe;EAAI;CAAE;AACnH"}
1
+ {"version":3,"file":"sceneEdits.js","names":[],"sources":["../../../src/core/scene/sceneEdits.ts"],"sourcesContent":["/**\n * The scene's edits to its document — tree, node fields, layers, and document values — with\n * the kit ops they record.\n */\nimport type { ArrivalWindow } from './arrivalWindow';\nimport { createSceneDoc, type SceneDocValues } from './docValues';\nimport { createDeclaredFieldSetters, type SceneDeclaredFieldSetters } from './declaredFieldSetters';\nimport { createFieldEdits, type FieldEdits } from './fieldEdits';\nimport { registerKitOps } from './kitOps';\nimport { createNodeFlags } from './nodeFlags';\nimport { createLayerEdits, type LayerEdits, type createLayerStack } from './layerStack';\nimport type { ResolvedLayoutFrame } from './layoutPass';\nimport type { LockGuard } from './lockGuard';\nimport type { NodeFnField } from './nodeFnFields';\nimport type { createNodeStore } from './nodeStore';\nimport type { OpTable } from './opTable';\nimport type { Recorder } from './recorder';\nimport { createTreeEdits, type TreeEdits } from './treeEdits';\nimport type { LayerRecord, Node, NodeId } from './types';\n\nexport interface SceneEditsEnv<TData, TLayer extends string, TPose> {\n state: {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n layers: LayerRecord<TLayer>[];\n layerIndex: Map<TLayer, number>;\n /** The scene's document values, which `doc` reads and records. */\n docValues: Map<string, unknown>;\n };\n store: ReturnType<typeof createNodeStore<TData, TLayer, TPose>>;\n locks: Pick<LockGuard<TLayer>, 'refuse' | 'refuseLayer' | 'lifted' | 'noteWritten'>;\n layers: Pick<\n ReturnType<typeof createLayerStack<TLayer>>,\n 'requireLayerIndex' | 'rebuildLayerIndex' | 'assertSubtreeLayer'\n >;\n invalidateOrder(): void;\n fnFields: readonly NodeFnField[];\n ops: Pick<OpTable, 'register' | 'run'>;\n recorder: Pick<Recorder, 'record' | 'edit' | 'batch'>;\n arrivals: Pick<ArrivalWindow<TPose>, 'noteArrival' | 'noteDeparture' | 'noteChange' | 'layoutDeclared'>;\n layoutFrame: ResolvedLayoutFrame<TPose>;\n generateId(): NodeId;\n narrowSelection(gone?: ReadonlySet<NodeId>): void;\n clearOverride(id: NodeId): void;\n}\n\nexport interface SceneEdits<TData, TLayer extends string, TPose> {\n construct: TreeEdits<TData, TLayer, TPose>['construct'];\n methods: Omit<TreeEdits<TData, TLayer, TPose>, 'construct'>\n & FieldEdits<TData, TLayer, TPose>\n & LayerEdits<TData, TLayer, TPose>\n & ReturnType<typeof createNodeFlags<TData, TLayer, TPose>>\n & SceneDeclaredFieldSetters\n & SceneDocValues;\n}\n\nexport function createSceneEdits<TData, TLayer extends string, TPose>(\n env: SceneEditsEnv<TData, TLayer, TPose>,\n): SceneEdits<TData, TLayer, TPose> {\n const { state, store, locks, layers, fnFields, recorder, arrivals } = env;\n\n const { layoutRefs } = registerKitOps<TData, TLayer, TPose>({\n state,\n register: env.ops.register,\n store,\n requireLayerIndex: layers.requireLayerIndex,\n rebuildLayerIndex: layers.rebuildLayerIndex,\n invalidateOrder: env.invalidateOrder,\n fnFields,\n narrowSelection: env.narrowSelection,\n clearOverride: env.clearOverride,\n noteWritten: locks.noteWritten,\n });\n\n const { construct, ...treeEdits } = createTreeEdits<TData, TLayer, TPose>({\n nodes: state.nodes,\n generateId: env.generateId,\n store,\n locks,\n layers,\n fnFields,\n runOp: env.ops.run,\n recorder,\n arrivals,\n });\n\n const fieldEdits = createFieldEdits<TData, TLayer, TPose>({\n store,\n locks,\n layers,\n recorder,\n arrivals,\n layoutFrame: env.layoutFrame,\n layoutField: fnFields.find((f) => f.spec.field === 'layout')!,\n layoutRefs,\n });\n\n const layerEdits = createLayerEdits<TData, TLayer, TPose>({\n layers: state.layers,\n layerIndex: state.layerIndex,\n nodes: state.nodes,\n requireLayerIndex: layers.requireLayerIndex,\n record: recorder.record,\n lifted: locks.lifted,\n batch: recorder.batch,\n removeMany: treeEdits.removeMany,\n });\n\n const flagEdits = createNodeFlags<TData, TLayer, TPose>({\n register: env.ops.register,\n requireNode: store.requireNode,\n record: recorder.record,\n narrowSelection: () => env.narrowSelection(),\n invalidateDependents: store.invalidateDependents,\n noteWritten: locks.noteWritten,\n });\n\n const declaredEdits = createDeclaredFieldSetters<TData, TLayer, TPose>({\n register: env.ops.register,\n requireNode: store.requireNode,\n refuse: locks.refuse,\n record: recorder.record,\n });\n\n const doc = createSceneDoc({ values: state.docValues, register: env.ops.register, record: recorder.record });\n\n return { construct, methods: { ...treeEdits, ...fieldEdits, ...layerEdits, ...flagEdits, ...declaredEdits, doc } };\n}\n"],"mappings":";;;;;;;;;AAuDA,SAAgB,iBACd,KACkC;CAClC,MAAM,EAAE,OAAO,OAAO,OAAO,QAAQ,UAAU,UAAU,aAAa;CAEtE,MAAM,EAAE,eAAe,eAAqC;EAC1D;EACA,UAAU,IAAI,IAAI;EAClB;EACA,mBAAmB,OAAO;EAC1B,mBAAmB,OAAO;EAC1B,iBAAiB,IAAI;EACrB;EACA,iBAAiB,IAAI;EACrB,eAAe,IAAI;EACnB,aAAa,MAAM;CACrB,CAAC;CAED,MAAM,EAAE,WAAW,GAAG,cAAc,gBAAsC;EACxE,OAAO,MAAM;EACb,YAAY,IAAI;EAChB;EACA;EACA;EACA;EACA,OAAO,IAAI,IAAI;EACf;EACA;CACF,CAAC;CAED,MAAM,aAAa,iBAAuC;EACxD;EACA;EACA;EACA;EACA;EACA,aAAa,IAAI;EACjB,aAAa,SAAS,MAAM,MAAM,EAAE,KAAK,UAAU,QAAQ;EAC3D;CACF,CAAC;CAED,MAAM,aAAa,iBAAuC;EACxD,QAAQ,MAAM;EACd,YAAY,MAAM;EAClB,OAAO,MAAM;EACb,mBAAmB,OAAO;EAC1B,QAAQ,SAAS;EACjB,QAAQ,MAAM;EACd,OAAO,SAAS;EAChB,YAAY,UAAU;CACxB,CAAC;CAED,MAAM,YAAY,gBAAsC;EACtD,UAAU,IAAI,IAAI;EAClB,aAAa,MAAM;EACnB,QAAQ,SAAS;EACjB,uBAAuB,IAAI,gBAAgB;EAC3C,sBAAsB,MAAM;EAC5B,aAAa,MAAM;CACrB,CAAC;CAED,MAAM,gBAAgB,2BAAiD;EACrE,UAAU,IAAI,IAAI;EAClB,aAAa,MAAM;EACnB,QAAQ,MAAM;EACd,QAAQ,SAAS;CACnB,CAAC;CAED,MAAM,MAAM,eAAe;EAAE,QAAQ,MAAM;EAAW,UAAU,IAAI,IAAI;EAAU,QAAQ,SAAS;CAAO,CAAC;CAE3G,OAAO;EAAE;EAAW,SAAS;GAAE,GAAG;GAAW,GAAG;GAAY,GAAG;GAAY,GAAG;GAAW,GAAG;GAAe;EAAI;CAAE;AACnH"}
@@ -1,4 +1,5 @@
1
1
  import { definesFrame, documentPose } from "./effectivePose.js";
2
+ import { viewPoseAdapter } from "./scrollOffsets.js";
2
3
 
3
4
  //#region src/core/scene/scenePoseAdapter.ts
4
5
  /** Build a `PoseAdapter` over a `Scene` for `composePose` helpers.
@@ -14,7 +15,15 @@ function scenePoseAdapter(scene) {
14
15
  }
15
16
  };
16
17
  }
18
+ /** `scenePoseAdapter` read as the view shows it: each scrolled container's
19
+ * children moved by its offset. For a gesture, which reads the world it
20
+ * writes back through the same fold, so what it stores is the content
21
+ * position; the layout pass and other document writers use
22
+ * `scenePoseAdapter`. */
23
+ function sceneViewPoseAdapter(scene) {
24
+ return viewPoseAdapter(scene, scenePoseAdapter(scene));
25
+ }
17
26
 
18
27
  //#endregion
19
- export { scenePoseAdapter };
28
+ export { scenePoseAdapter, sceneViewPoseAdapter };
20
29
  //# sourceMappingURL=scenePoseAdapter.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scenePoseAdapter.js","names":[],"sources":["../../../src/core/scene/scenePoseAdapter.ts"],"sourcesContent":["import { definesFrame, documentPose } from 'core/scene/effectivePose';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { PoseAdapter } from './composePose';\n\n/** Build a `PoseAdapter` over a `Scene` for `composePose` helpers.\n * `getParent` returns the live parent at call time so mid-batch\n * parent updates compose correctly. */\nexport function scenePoseAdapter(\n scene: Scene<unknown, string, unknown>,\n): PoseAdapter<unknown> {\n return {\n getPose: (id) => documentPose(scene, scene.get(id as NodeId)!),\n getParent: (id) => scene.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => {\n const node = scene.get(id as NodeId);\n return node === undefined || definesFrame(node);\n },\n };\n}\n"],"mappings":";;;;;;AAOA,SAAgB,iBACd,OACsB;CACtB,OAAO;EACL,UAAU,OAAO,aAAa,OAAO,MAAM,IAAI,EAAY,CAAE;EAC7D,YAAY,OAAO,MAAM,IAAI,EAAY,CAAC,EAAE,UAAU;EACtD,eAAe,OAAO;GACpB,MAAM,OAAO,MAAM,IAAI,EAAY;GACnC,OAAO,SAAS,UAAa,aAAa,IAAI;EAChD;CACF;AACF"}
1
+ {"version":3,"file":"scenePoseAdapter.js","names":[],"sources":["../../../src/core/scene/scenePoseAdapter.ts"],"sourcesContent":["import { definesFrame, documentPose } from 'core/scene/effectivePose';\nimport type { NodeId, Scene } from 'core/scene/types';\nimport type { PoseAdapter } from './composePose';\nimport { viewPoseAdapter } from './scrollOffsets';\n\n/** Build a `PoseAdapter` over a `Scene` for `composePose` helpers.\n * `getParent` returns the live parent at call time so mid-batch\n * parent updates compose correctly. */\nexport function scenePoseAdapter(\n scene: Scene<unknown, string, unknown>,\n): PoseAdapter<unknown> {\n return {\n getPose: (id) => documentPose(scene, scene.get(id as NodeId)!),\n getParent: (id) => scene.get(id as NodeId)?.parent ?? null,\n definesFrame: (id) => {\n const node = scene.get(id as NodeId);\n return node === undefined || definesFrame(node);\n },\n };\n}\n\n/** `scenePoseAdapter` read as the view shows it: each scrolled container's\n * children moved by its offset. For a gesture, which reads the world it\n * writes back through the same fold, so what it stores is the content\n * position; the layout pass and other document writers use\n * `scenePoseAdapter`. */\nexport function sceneViewPoseAdapter(\n scene: Scene<unknown, string, unknown>,\n): PoseAdapter<unknown> {\n return viewPoseAdapter(scene, scenePoseAdapter(scene));\n}\n"],"mappings":";;;;;;;AAQA,SAAgB,iBACd,OACsB;CACtB,OAAO;EACL,UAAU,OAAO,aAAa,OAAO,MAAM,IAAI,EAAY,CAAE;EAC7D,YAAY,OAAO,MAAM,IAAI,EAAY,CAAC,EAAE,UAAU;EACtD,eAAe,OAAO;GACpB,MAAM,OAAO,MAAM,IAAI,EAAY;GACnC,OAAO,SAAS,UAAa,aAAa,IAAI;EAChD;CACF;AACF;;;;;;AAOA,SAAgB,qBACd,OACsB;CACtB,OAAO,gBAAgB,OAAO,iBAAiB,KAAK,CAAC;AACvD"}
@@ -0,0 +1,93 @@
1
+ import { isDocument } from "./documentOf.js";
2
+ import { createEmitter } from "@weasel-js/registry";
3
+
4
+ //#region src/core/scene/scrollOffsets.ts
5
+ /**
6
+ * How far each container's content is scrolled: view state, never document.
7
+ *
8
+ * A scroll offset is part of the frame a container gives its children, so the
9
+ * document never moves: a child keeps its stored pose and is shown moved by
10
+ * minus the offset. Only the view-side fold reads it — painting, picking,
11
+ * selection chrome, previews and gestures, through `scrolledFrames` — while
12
+ * the layout pass and every writer that stores a pose fold through the
13
+ * unscrolled frame.
14
+ */
15
+ /** Build an empty {@link ScrollOffsets}. */
16
+ function createScrollOffsets() {
17
+ const offsets = /* @__PURE__ */ new Map();
18
+ const listeners = createEmitter();
19
+ let generation = 0;
20
+ const changed = () => {
21
+ generation++;
22
+ listeners.emit();
23
+ };
24
+ return {
25
+ get: (id) => offsets.get(id),
26
+ set(id, offset) {
27
+ const held = offsets.get(id);
28
+ if (offset === null || offset.x === 0 && offset.y === 0 && !offset.z) {
29
+ if (held === void 0) return;
30
+ offsets.delete(id);
31
+ } else {
32
+ if (held !== void 0 && held.x === offset.x && held.y === offset.y && (held.z ?? 0) === (offset.z ?? 0)) return;
33
+ offsets.set(id, { ...offset });
34
+ }
35
+ changed();
36
+ },
37
+ ids: () => offsets.keys(),
38
+ clearAll() {
39
+ if (offsets.size === 0) return;
40
+ offsets.clear();
41
+ changed();
42
+ },
43
+ subscribe: listeners.subscribe,
44
+ getGeneration: () => generation
45
+ };
46
+ }
47
+ var memos = /* @__PURE__ */ new WeakMap();
48
+ /** `scroll(frame, offset)`, answering the same object while the frame and the
49
+ * offset objects are the same: a paint memo keys on the pose a child is
50
+ * composed to, and an unchanged child in an unscrolled-since container must
51
+ * keep its key from one walk to the next. */
52
+ function memoScroll(scroll, frame, offset) {
53
+ if (typeof frame !== "object" || frame === null) return scroll(frame, offset);
54
+ let byFrame = memos.get(scroll);
55
+ if (byFrame === void 0) memos.set(scroll, byFrame = /* @__PURE__ */ new WeakMap());
56
+ const held = byFrame.get(frame);
57
+ if (held !== void 0 && held.offset === offset) return held.out;
58
+ const out = scroll(frame, offset);
59
+ byFrame.set(frame, {
60
+ offset,
61
+ out
62
+ });
63
+ return out;
64
+ }
65
+ /**
66
+ * The view-side fold's `PoseAdapter.childFrame` over `scene`: each scrolled
67
+ * container's frame moved by its offset. `undefined` when the scene has no
68
+ * scroll store, its composition cannot scroll, or it is a `documentOf` view,
69
+ * which reads as the document holds it, so a reader skips the step.
70
+ */
71
+ function scrolledFrames(scene) {
72
+ const store = scene.scroll;
73
+ const scroll = scene.composition?.scroll;
74
+ if (store === void 0 || scroll === void 0) return void 0;
75
+ if (scene.overrides !== void 0 && isDocument(scene)) return void 0;
76
+ return (id, world) => {
77
+ const offset = store.get(id);
78
+ return offset === void 0 ? world : memoScroll(scroll, world, offset);
79
+ };
80
+ }
81
+ /** `adapter` read as the view shows it: with `scene`'s scrolled frames as its
82
+ * `childFrame`. The same adapter when nothing can scroll. */
83
+ function viewPoseAdapter(scene, adapter) {
84
+ const childFrame = scrolledFrames(scene);
85
+ return childFrame === void 0 ? adapter : {
86
+ ...adapter,
87
+ childFrame
88
+ };
89
+ }
90
+
91
+ //#endregion
92
+ export { createScrollOffsets, scrolledFrames, viewPoseAdapter };
93
+ //# sourceMappingURL=scrollOffsets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scrollOffsets.js","names":[],"sources":["../../../src/core/scene/scrollOffsets.ts"],"sourcesContent":["/**\n * How far each container's content is scrolled: view state, never document.\n *\n * A scroll offset is part of the frame a container gives its children, so the\n * document never moves: a child keeps its stored pose and is shown moved by\n * minus the offset. Only the view-side fold reads it — painting, picking,\n * selection chrome, previews and gestures, through `scrolledFrames` — while\n * the layout pass and every writer that stores a pose fold through the\n * unscrolled frame.\n */\nimport { createEmitter } from '@weasel-js/registry';\nimport type { PoseAdapter, PoseComposition, ScrollOffset } from './composeFrame';\nimport { isDocument } from './documentOf';\nimport type { NodeId } from './types';\n\n/** The scene's scroll offsets, one per scrolled container. */\nexport interface ScrollOffsets {\n /** How far `id`'s content is scrolled, or `undefined` when it is not. */\n get(id: NodeId): ScrollOffset | undefined;\n /** Scroll `id`'s content to `offset`. `null`, or an offset of zero on every\n * axis, unscrolls it. */\n set(id: NodeId, offset: ScrollOffset | null): void;\n /** The scrolled containers. */\n ids(): IterableIterator<NodeId>;\n /** Unscroll everything. */\n clearAll(): void;\n subscribe(listener: () => void): () => void;\n /** Bumped by every change, for a cache keyed on what the view shows. */\n getGeneration(): number;\n}\n\n/** The scroll store a `Scene` carries. */\nexport interface SceneScroll {\n /** How far each container's content is scrolled. Like the selection, view\n * state shared by every view over the scene: never document content, never\n * recorded or serialized, and it does not bump the scene's version. */\n readonly scroll: ScrollOffsets;\n}\n\n/** Build an empty {@link ScrollOffsets}. */\nexport function createScrollOffsets(): ScrollOffsets {\n const offsets = new Map<NodeId, ScrollOffset>();\n const listeners = createEmitter();\n let generation = 0;\n const changed = (): void => {\n generation++;\n listeners.emit();\n };\n return {\n get: (id) => offsets.get(id),\n set(id, offset) {\n const held = offsets.get(id);\n if (offset === null || (offset.x === 0 && offset.y === 0 && !offset.z)) {\n if (held === undefined) return;\n offsets.delete(id);\n } else {\n if (held !== undefined && held.x === offset.x && held.y === offset.y && (held.z ?? 0) === (offset.z ?? 0)) return;\n offsets.set(id, { ...offset });\n }\n changed();\n },\n ids: () => offsets.keys(),\n clearAll() {\n if (offsets.size === 0) return;\n offsets.clear();\n changed();\n },\n subscribe: listeners.subscribe,\n getGeneration: () => generation,\n };\n}\n\ntype Scroll = (frame: never, offset: ScrollOffset) => unknown;\nconst memos = new WeakMap<Scroll, WeakMap<object, { offset: ScrollOffset; out: unknown }>>();\n\n/** `scroll(frame, offset)`, answering the same object while the frame and the\n * offset objects are the same: a paint memo keys on the pose a child is\n * composed to, and an unchanged child in an unscrolled-since container must\n * keep its key from one walk to the next. */\nfunction memoScroll<TPose>(scroll: (frame: TPose, offset: ScrollOffset) => TPose, frame: TPose, offset: ScrollOffset): TPose {\n if (typeof frame !== 'object' || frame === null) return scroll(frame, offset);\n let byFrame = memos.get(scroll as Scroll);\n if (byFrame === undefined) memos.set(scroll as Scroll, byFrame = new WeakMap());\n const held = byFrame.get(frame);\n if (held !== undefined && held.offset === offset) return held.out as TPose;\n const out = scroll(frame, offset);\n byFrame.set(frame, { offset, out });\n return out;\n}\n\n/** What `scrolledFrames` reads of a scene. Partial stand-ins without a\n * `scroll` store read as unscrolled. */\nexport interface ScrollSource<TPose> {\n readonly overrides?: unknown;\n readonly scroll?: ScrollOffsets;\n readonly composition?: PoseComposition<TPose>;\n}\n\n/**\n * The view-side fold's `PoseAdapter.childFrame` over `scene`: each scrolled\n * container's frame moved by its offset. `undefined` when the scene has no\n * scroll store, its composition cannot scroll, or it is a `documentOf` view,\n * which reads as the document holds it, so a reader skips the step.\n */\nexport function scrolledFrames<TPose>(\n scene: ScrollSource<TPose>,\n): ((id: string, world: TPose) => TPose) | undefined {\n const store = scene.scroll;\n const scroll = scene.composition?.scroll;\n if (store === undefined || scroll === undefined) return undefined;\n if (scene.overrides !== undefined && isDocument(scene as { overrides: unknown })) return undefined;\n return (id, world) => {\n const offset = store.get(id as NodeId);\n return offset === undefined ? world : memoScroll(scroll, world, offset);\n };\n}\n\n/** `adapter` read as the view shows it: with `scene`'s scrolled frames as its\n * `childFrame`. The same adapter when nothing can scroll. */\nexport function viewPoseAdapter<TPose, A extends PoseAdapter<TPose>>(scene: ScrollSource<TPose>, adapter: A): A {\n const childFrame = scrolledFrames(scene);\n return childFrame === undefined ? adapter : { ...adapter, childFrame };\n}\n"],"mappings":";;;;;;;;;;;;;;;AAwCA,SAAgB,sBAAqC;CACnD,MAAM,0BAAU,IAAI,IAA0B;CAC9C,MAAM,YAAY,cAAc;CAChC,IAAI,aAAa;CACjB,MAAM,gBAAsB;EAC1B;EACA,UAAU,KAAK;CACjB;CACA,OAAO;EACL,MAAM,OAAO,QAAQ,IAAI,EAAE;EAC3B,IAAI,IAAI,QAAQ;GACd,MAAM,OAAO,QAAQ,IAAI,EAAE;GAC3B,IAAI,WAAW,QAAS,OAAO,MAAM,KAAK,OAAO,MAAM,KAAK,CAAC,OAAO,GAAI;IACtE,IAAI,SAAS,QAAW;IACxB,QAAQ,OAAO,EAAE;GACnB,OAAO;IACL,IAAI,SAAS,UAAa,KAAK,MAAM,OAAO,KAAK,KAAK,MAAM,OAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,KAAK,IAAI;IAC3G,QAAQ,IAAI,IAAI,EAAE,GAAG,OAAO,CAAC;GAC/B;GACA,QAAQ;EACV;EACA,WAAW,QAAQ,KAAK;EACxB,WAAW;GACT,IAAI,QAAQ,SAAS,GAAG;GACxB,QAAQ,MAAM;GACd,QAAQ;EACV;EACA,WAAW,UAAU;EACrB,qBAAqB;CACvB;AACF;AAGA,IAAM,wBAAQ,IAAI,QAAyE;;;;;AAM3F,SAAS,WAAkB,QAAuD,OAAc,QAA6B;CAC3H,IAAI,OAAO,UAAU,YAAY,UAAU,MAAM,OAAO,OAAO,OAAO,MAAM;CAC5E,IAAI,UAAU,MAAM,IAAI,MAAgB;CACxC,IAAI,YAAY,QAAW,MAAM,IAAI,QAAkB,0BAAU,IAAI,QAAQ,CAAC;CAC9E,MAAM,OAAO,QAAQ,IAAI,KAAK;CAC9B,IAAI,SAAS,UAAa,KAAK,WAAW,QAAQ,OAAO,KAAK;CAC9D,MAAM,MAAM,OAAO,OAAO,MAAM;CAChC,QAAQ,IAAI,OAAO;EAAE;EAAQ;CAAI,CAAC;CAClC,OAAO;AACT;;;;;;;AAgBA,SAAgB,eACd,OACmD;CACnD,MAAM,QAAQ,MAAM;CACpB,MAAM,SAAS,MAAM,aAAa;CAClC,IAAI,UAAU,UAAa,WAAW,QAAW,OAAO;CACxD,IAAI,MAAM,cAAc,UAAa,WAAW,KAA+B,GAAG,OAAO;CACzF,QAAQ,IAAI,UAAU;EACpB,MAAM,SAAS,MAAM,IAAI,EAAY;EACrC,OAAO,WAAW,SAAY,QAAQ,WAAW,QAAQ,OAAO,MAAM;CACxE;AACF;;;AAIA,SAAgB,gBAAqD,OAA4B,SAAe;CAC9G,MAAM,aAAa,eAAe,KAAK;CACvC,OAAO,eAAe,SAAY,UAAU;EAAE,GAAG;EAAS;CAAW;AACvE"}
@@ -1,5 +1,7 @@
1
+ import { RIGID_POSE_COMPOSITION } from "./composePose.js";
1
2
  import { NODE_FN_FIELDS, fnKeysOf } from "./nodeFnFields.js";
2
3
  import { treePreorder } from "./treeOrder.js";
4
+ import { localizeWorldPoses } from "./worldSave.js";
3
5
 
4
6
  //#region src/core/scene/serialization.ts
5
7
  /**
@@ -9,7 +11,7 @@ import { treePreorder } from "./treeOrder.js";
9
11
  /** Whether `value` is a snapshot `specsFromSerialized` reads, as against a live scene. */
10
12
  function isSerializedScene(value) {
11
13
  const version = typeof value === "object" && value != null ? value.version : void 0;
12
- return (version === 1 || version === 2) && Array.isArray(value.nodes);
14
+ return (version === 1 || version === 2 || version === 3) && Array.isArray(value.nodes);
13
15
  }
14
16
  /** One layer record from its snapshot form. A snapshot with no `kind` predates
15
17
  * user layers, so everything in it was a system layer. */
@@ -52,13 +54,14 @@ function serializeScene(state, fnFields, doc) {
52
54
  if (n.locked === true) out.locked = true;
53
55
  if (n.units !== void 0) out.units = n.units;
54
56
  if (n.clip !== void 0) out.clip = n.clip;
57
+ if (n.consumesChildren === true) out.consumesChildren = true;
55
58
  Object.assign(out, fnKeysOf(fnFields, n, "jsonKey", (field) => {
56
59
  throw new Error(`Scene.toJSON: node '${id}' has ${field.spec.field} but no matching registry key. The function must be registered via createScene's registry option to round-trip.`);
57
60
  }));
58
61
  nodes.push(out);
59
62
  }
60
63
  return {
61
- version: 2,
64
+ version: 3,
62
65
  systemLayers: state.layers.map((l) => {
63
66
  const layer = { id: l.id };
64
67
  if (l.visible === false) layer.visible = false;
@@ -81,16 +84,22 @@ function serializeScene(state, fnFields, doc) {
81
84
  * throws on an unsupported version, and on an unknown registry key unless
82
85
  * `opts.unknownKeys` is `'skip'`. */
83
86
  function specsFromSerialized(json, registry, opts = {}) {
87
+ const specs = currentSpecs(json, registry, opts);
88
+ if (json.version === 3) return specs;
89
+ return localizeWorldPoses(specs, opts.composition ?? RIGID_POSE_COMPOSITION);
90
+ }
91
+ /** `json`'s nodes as specs, with every pose as the save stored it. */
92
+ function currentSpecs(json, registry, opts) {
84
93
  let entries;
85
94
  if (json.version === 1) entries = json.nodes.map((n) => ({
86
95
  n,
87
96
  kind: nodeKindOf(1, n, opts.classifyV1)
88
97
  }));
89
- else if (json.version === 2) entries = json.nodes.map((n) => ({
98
+ else if (json.version === 2 || json.version === 3) entries = json.nodes.map((n) => ({
90
99
  n,
91
100
  kind: nodeKindOf(2, n)
92
101
  }));
93
- else throw new Error(`Scene: unsupported version ${String(Reflect.get(json, "version"))}; versions 1 and 2 are supported`);
102
+ else throw new Error(`Scene: unsupported version ${String(Reflect.get(json, "version"))}; versions 1, 2 and 3 are supported`);
94
103
  return entries.map(({ n, kind }) => {
95
104
  const spec = {
96
105
  id: n.id,
@@ -105,6 +114,7 @@ function specsFromSerialized(json, registry, opts = {}) {
105
114
  if (n.locked === true) spec.locked = true;
106
115
  if (n.units !== void 0) spec.units = n.units;
107
116
  if (n.clip !== void 0) spec.clip = n.clip;
117
+ if (n.consumesChildren === true) spec.consumesChildren = true;
108
118
  if (n.dependsOn !== void 0) spec.dependsOn = n.dependsOn === "children" ? "children" : n.dependsOn;
109
119
  const serialized = n;
110
120
  for (const field of NODE_FN_FIELDS) {
@@ -133,7 +143,7 @@ function specsFromSerialized(json, registry, opts = {}) {
133
143
  function clipsAsV1(version, spec) {
134
144
  return version === 1 && spec.kind === "group" && spec.clipFromPose === void 0;
135
145
  }
136
- /** The kind a saved node loads as: its own on version 2; on version 1 a `leaf` is a
146
+ /** The kind a saved node loads as: its own from version 2; on version 1 a `leaf` is a
137
147
  * mark and a `container` goes to `classify`, or is a group without one. */
138
148
  function nodeKindOf(version, n, classify) {
139
149
  if (version === 2) return n.kind;
@@ -1 +1 @@
1
- {"version":3,"file":"serialization.js","names":[],"sources":["../../../src/core/scene/serialization.ts"],"sourcesContent":["/**\n * A scene to and from its JSON snapshot: the walk that writes one, and the\n * two readers that turn one back into layer records and node specs.\n */\nimport {\n NODE_FN_FIELDS, fnKeysOf, type FnBearingNode, type NodeFnField,\n} from './nodeFnFields';\nimport type { SerializedDoc } from './docValues';\nimport { treePreorder } from './treeOrder';\nimport type {\n AddNodeSpec, LayerRecord, Node, NodeId, SceneRegistry, SerializedLayer, SerializedNode, SerializedNodeV1,\n SerializedScene, SerializedSceneV1,\n} from './types';\n\n/** Whether `value` is a snapshot `specsFromSerialized` reads, as against a live scene. */\nexport function isSerializedScene<TData, TLayer extends string, TPose>(\n value: unknown,\n): value is SerializedScene<TData, TLayer, TPose> | SerializedSceneV1<TData, TLayer, TPose> {\n const version = typeof value === 'object' && value != null\n ? (value as { version?: unknown }).version : undefined;\n return (version === 1 || version === 2)\n && Array.isArray((value as { nodes?: unknown }).nodes);\n}\n\n/** What a snapshot is written from. */\nexport interface SerializableState<TData, TLayer extends string, TPose> {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n roots: NodeId[];\n layers: LayerRecord<TLayer>[];\n}\n\n/** One layer record from its snapshot form. A snapshot with no `kind` predates\n * user layers, so everything in it was a system layer. */\nexport function layerFromSerialized<TLayer extends string>(\n spec: SerializedLayer<TLayer>,\n): LayerRecord<TLayer> {\n const base = {\n id: spec.id,\n visible: spec.visible ?? true,\n locked: spec.locked ?? false,\n ...(spec.parallax ? { parallax: spec.parallax } : {}),\n ...(spec.annotation ? { annotation: true } : {}),\n };\n return spec.kind === 'user'\n ? { ...base, kind: 'user', name: spec.name ?? spec.id }\n : { ...base, kind: 'system' };\n}\n\n/** The snapshot of `state`: layers in order, nodes in tree preorder, and the\n * document values when there are any. Throws\n * when a node carries a function the registry has no key for. */\nexport function serializeScene<TData, TLayer extends string, TPose>(\n state: SerializableState<TData, TLayer, TPose>,\n fnFields: readonly NodeFnField[],\n doc?: SerializedDoc,\n): SerializedScene<TData, TLayer, TPose> {\n const nodes: SerializedNode<TData, TLayer, TPose>[] = [];\n for (const n of treePreorder(state.roots, state.nodes)) {\n const id = n.id;\n const out: SerializedNode<TData, TLayer, TPose> = {\n id,\n kind: n.kind,\n layer: n.layer,\n pose: n.pose,\n data: n.data,\n };\n if (n.parent != null) out.parent = n.parent;\n if (n.dependsOn === 'children') out.dependsOn = 'children';\n else if (n.dependsOn && n.dependsOn.length > 0) out.dependsOn = n.dependsOn;\n if (n.pickable === false) out.pickable = false;\n if (n.hidden === true) out.hidden = true;\n if (n.locked === true) out.locked = true;\n if (n.units !== undefined) out.units = n.units;\n if (n.clip !== undefined) out.clip = n.clip;\n Object.assign(\n out,\n fnKeysOf(fnFields, n as unknown as FnBearingNode, 'jsonKey', (field) => {\n throw new Error(\n `Scene.toJSON: node '${id}' has ${field.spec.field} but no matching registry key. ` +\n `The function must be registered via createScene's registry option to round-trip.`\n );\n }),\n );\n nodes.push(out);\n }\n const systemLayers = state.layers.map((l) => {\n const layer: SerializedLayer<TLayer> = { id: l.id };\n if (l.visible === false) layer.visible = false;\n if (l.locked === true) layer.locked = true;\n if (l.parallax) layer.parallax = l.parallax;\n if (l.annotation) layer.annotation = true;\n if (l.kind === 'user') {\n layer.kind = 'user';\n layer.name = l.name;\n }\n return layer;\n });\n return { version: 2, systemLayers, nodes, ...(doc ? { doc } : {}) };\n}\n\n/** Decides what a version 1 `container` becomes; `leaf` is always a mark. */\nexport type V1Classifier<TData, TLayer extends string, TPose> =\n (node: SerializedNodeV1<TData, TLayer, TPose>) => 'mark' | 'group';\n\n/** Options for {@link specsFromSerialized}. */\nexport interface SpecsFromSerializedOptions<TData, TLayer extends string, TPose> {\n /** What a version 1 `container` loads as; see {@link V1Classifier}. */\n classifyV1?: V1Classifier<TData, TLayer, TPose>;\n /** `'skip'` loads a node whose registry key is unknown without that\n * function, for a save that outlived the code that registered it.\n * Default `'throw'`. */\n unknownKeys?: 'throw' | 'skip';\n /** Hears each key `unknownKeys: 'skip'` leaves out, as it is left out. */\n onSkip?: (skipped: SkippedKey) => void;\n}\n\n/** A registry key a load left out: the node, the function field it named,\n * and the key. */\nexport interface SkippedKey {\n id: NodeId;\n field: keyof SceneRegistry<unknown>;\n key: string;\n}\n\n/** Map a `SerializedScene` to construction specs. Shared by `sceneFromJSON`\n * (new instance) and `Scene.loadState` (in-place). Validates version and\n * resolves every `NODE_FN_FIELDS` key → function via the registry;\n * throws on an unsupported version, and on an unknown registry key unless\n * `opts.unknownKeys` is `'skip'`. */\nexport function specsFromSerialized<TData, TLayer extends string, TPose>(\n json: SerializedScene<TData, TLayer, TPose> | SerializedSceneV1<TData, TLayer, TPose>,\n registry: SceneRegistry<TPose, TData, TLayer>,\n opts: SpecsFromSerializedOptions<TData, TLayer, TPose> = {},\n): AddNodeSpec<TData, TLayer, TPose>[] {\n type Entry = { n: Omit<SerializedNode<TData, TLayer, TPose>, 'kind'>; kind: 'mark' | 'group' };\n let entries: Entry[];\n if (json.version === 1) {\n entries = json.nodes.map((n) => ({ n, kind: nodeKindOf(1, n, opts.classifyV1) }));\n } else if (json.version === 2) {\n entries = json.nodes.map((n) => ({ n, kind: nodeKindOf(2, n) }));\n } else {\n throw new Error(`Scene: unsupported version ${String(Reflect.get(json, 'version'))}; versions 1 and 2 are supported`);\n }\n return entries.map(({ n, kind }) => {\n const spec: AddNodeSpec<TData, TLayer, TPose> = {\n id: n.id as NodeId,\n kind,\n layer: n.layer,\n pose: n.pose,\n data: n.data,\n };\n if (n.parent !== undefined) spec.parent = n.parent as NodeId;\n if (n.pickable !== undefined) spec.pickable = n.pickable;\n if (n.hidden === true) spec.hidden = true;\n if (n.locked === true) spec.locked = true;\n if (n.units !== undefined) spec.units = n.units;\n if (n.clip !== undefined) spec.clip = n.clip;\n if (n.dependsOn !== undefined) {\n spec.dependsOn = n.dependsOn === 'children'\n ? 'children'\n : (n.dependsOn as readonly NodeId[]);\n }\n const serialized = n as unknown as Record<string, string | undefined>;\n for (const field of NODE_FN_FIELDS) {\n const key = serialized[field.jsonKey];\n if (key === undefined) continue;\n const fn = (registry[field.field] as Record<string, unknown> | undefined)?.[key];\n if (!fn && opts.unknownKeys === 'skip') {\n opts.onSkip?.({ id: spec.id!, field: field.field, key });\n continue;\n }\n if (!fn) {\n throw new Error(\n `Scene: unknown ${field.field} key '${key}'. ` +\n `Register a function with this key in the registry option.`,\n );\n }\n (spec as unknown as Record<string, unknown>)[field.field] = fn;\n }\n if (clipsAsV1(json.version, spec)) spec.clip = 'outline';\n return spec;\n });\n}\n\n/** Version 1 clipped a container with no clip function to its outline, which\n * is what `clip: 'outline'` draws on a group. One a classifier makes a mark\n * gets no clip, since which painter claims it is not known here; one whose\n * clip key was skipped loads as it would have without it. */\nfunction clipsAsV1(version: 1 | 2, spec: { kind: string; clipFromPose?: unknown }): boolean {\n return version === 1 && spec.kind === 'group' && spec.clipFromPose === undefined;\n}\n\n/** The kind a saved node loads as: its own on version 2; on version 1 a `leaf` is a\n * mark and a `container` goes to `classify`, or is a group without one. */\nexport function nodeKindOf<TData, TLayer extends string, TPose>(\n version: 1 | 2,\n n: SerializedNode<TData, TLayer, TPose> | SerializedNodeV1<TData, TLayer, TPose>,\n classify?: V1Classifier<TData, TLayer, TPose>,\n): 'mark' | 'group' {\n if (version === 2) return (n as SerializedNode<TData, TLayer, TPose>).kind;\n if (n.kind === 'leaf') return 'mark';\n return classify ? classify(n as SerializedNodeV1<TData, TLayer, TPose>) : 'group';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"serialization.js","names":[],"sources":["../../../src/core/scene/serialization.ts"],"sourcesContent":["/**\n * A scene to and from its JSON snapshot: the walk that writes one, and the\n * two readers that turn one back into layer records and node specs.\n */\nimport {\n NODE_FN_FIELDS, fnKeysOf, type FnBearingNode, type NodeFnField,\n} from './nodeFnFields';\nimport type { SerializedDoc } from './docValues';\nimport { treePreorder } from './treeOrder';\nimport type { PoseComposition } from './composeFrame';\nimport { RIGID_POSE_COMPOSITION } from './composePose';\nimport { localizeWorldPoses } from './worldSave';\nimport type {\n AddNodeSpec, LayerRecord, Node, NodeId, SavedScene, SceneRegistry, SerializedLayer, SerializedNode, SerializedNodeV1,\n SerializedScene,\n} from './types';\n\n/** Whether `value` is a snapshot `specsFromSerialized` reads, as against a live scene. */\nexport function isSerializedScene<TData, TLayer extends string, TPose>(\n value: unknown,\n): value is SavedScene<TData, TLayer, TPose> {\n const version = typeof value === 'object' && value != null\n ? (value as { version?: unknown }).version : undefined;\n return (version === 1 || version === 2 || version === 3)\n && Array.isArray((value as { nodes?: unknown }).nodes);\n}\n\n/** What a snapshot is written from. */\nexport interface SerializableState<TData, TLayer extends string, TPose> {\n nodes: Map<NodeId, Node<TData, TLayer, TPose>>;\n roots: NodeId[];\n layers: LayerRecord<TLayer>[];\n}\n\n/** One layer record from its snapshot form. A snapshot with no `kind` predates\n * user layers, so everything in it was a system layer. */\nexport function layerFromSerialized<TLayer extends string>(\n spec: SerializedLayer<TLayer>,\n): LayerRecord<TLayer> {\n const base = {\n id: spec.id,\n visible: spec.visible ?? true,\n locked: spec.locked ?? false,\n ...(spec.parallax ? { parallax: spec.parallax } : {}),\n ...(spec.annotation ? { annotation: true } : {}),\n };\n return spec.kind === 'user'\n ? { ...base, kind: 'user', name: spec.name ?? spec.id }\n : { ...base, kind: 'system' };\n}\n\n/** The snapshot of `state`: layers in order, nodes in tree preorder, and the\n * document values when there are any. Throws\n * when a node carries a function the registry has no key for. */\nexport function serializeScene<TData, TLayer extends string, TPose>(\n state: SerializableState<TData, TLayer, TPose>,\n fnFields: readonly NodeFnField[],\n doc?: SerializedDoc,\n): SerializedScene<TData, TLayer, TPose> {\n const nodes: SerializedNode<TData, TLayer, TPose>[] = [];\n for (const n of treePreorder(state.roots, state.nodes)) {\n const id = n.id;\n const out: SerializedNode<TData, TLayer, TPose> = {\n id,\n kind: n.kind,\n layer: n.layer,\n pose: n.pose,\n data: n.data,\n };\n if (n.parent != null) out.parent = n.parent;\n if (n.dependsOn === 'children') out.dependsOn = 'children';\n else if (n.dependsOn && n.dependsOn.length > 0) out.dependsOn = n.dependsOn;\n if (n.pickable === false) out.pickable = false;\n if (n.hidden === true) out.hidden = true;\n if (n.locked === true) out.locked = true;\n if (n.units !== undefined) out.units = n.units;\n if (n.clip !== undefined) out.clip = n.clip;\n if (n.consumesChildren === true) out.consumesChildren = true;\n Object.assign(\n out,\n fnKeysOf(fnFields, n as unknown as FnBearingNode, 'jsonKey', (field) => {\n throw new Error(\n `Scene.toJSON: node '${id}' has ${field.spec.field} but no matching registry key. ` +\n `The function must be registered via createScene's registry option to round-trip.`\n );\n }),\n );\n nodes.push(out);\n }\n const systemLayers = state.layers.map((l) => {\n const layer: SerializedLayer<TLayer> = { id: l.id };\n if (l.visible === false) layer.visible = false;\n if (l.locked === true) layer.locked = true;\n if (l.parallax) layer.parallax = l.parallax;\n if (l.annotation) layer.annotation = true;\n if (l.kind === 'user') {\n layer.kind = 'user';\n layer.name = l.name;\n }\n return layer;\n });\n return { version: 3, systemLayers, nodes, ...(doc ? { doc } : {}) };\n}\n\n/** Decides what a version 1 `container` becomes; `leaf` is always a mark. */\nexport type V1Classifier<TData, TLayer extends string, TPose> =\n (node: SerializedNodeV1<TData, TLayer, TPose>) => 'mark' | 'group';\n\n/** Options for {@link specsFromSerialized}. */\nexport interface SpecsFromSerializedOptions<TData, TLayer extends string, TPose> {\n /** What a version 1 `container` loads as; see {@link V1Classifier}. */\n classifyV1?: V1Classifier<TData, TLayer, TPose>;\n /** `'skip'` loads a node whose registry key is unknown without that\n * function, for a save that outlived the code that registered it.\n * Default `'throw'`. */\n unknownKeys?: 'throw' | 'skip';\n /** Hears each key `unknownKeys: 'skip'` leaves out, as it is left out. */\n onSkip?: (skipped: SkippedKey) => void;\n /** How a version 1 or 2 save's world poses are made local to their\n * containers' frames. Default `RIGID_POSE_COMPOSITION`; a scene passes its own. */\n composition?: PoseComposition<TPose>;\n}\n\n/** A registry key a load left out: the node, the function field it named,\n * and the key. */\nexport interface SkippedKey {\n id: NodeId;\n field: keyof SceneRegistry<unknown>;\n key: string;\n}\n\n/** Map a `SerializedScene` to construction specs. Shared by `sceneFromJSON`\n * (new instance) and `Scene.loadState` (in-place). Validates version and\n * resolves every `NODE_FN_FIELDS` key → function via the registry;\n * throws on an unsupported version, and on an unknown registry key unless\n * `opts.unknownKeys` is `'skip'`. */\nexport function specsFromSerialized<TData, TLayer extends string, TPose>(\n json: SavedScene<TData, TLayer, TPose>,\n registry: SceneRegistry<TPose, TData, TLayer>,\n opts: SpecsFromSerializedOptions<TData, TLayer, TPose> = {},\n): AddNodeSpec<TData, TLayer, TPose>[] {\n const specs = currentSpecs(json, registry, opts);\n if (json.version === 3) return specs;\n return localizeWorldPoses(specs, opts.composition ?? (RIGID_POSE_COMPOSITION as PoseComposition<TPose>));\n}\n\n/** `json`'s nodes as specs, with every pose as the save stored it. */\nfunction currentSpecs<TData, TLayer extends string, TPose>(\n json: SavedScene<TData, TLayer, TPose>,\n registry: SceneRegistry<TPose, TData, TLayer>,\n opts: SpecsFromSerializedOptions<TData, TLayer, TPose>,\n): AddNodeSpec<TData, TLayer, TPose>[] {\n type Entry = { n: Omit<SerializedNode<TData, TLayer, TPose>, 'kind'>; kind: 'mark' | 'group' };\n let entries: Entry[];\n if (json.version === 1) {\n entries = json.nodes.map((n) => ({ n, kind: nodeKindOf(1, n, opts.classifyV1) }));\n } else if (json.version === 2 || json.version === 3) {\n entries = json.nodes.map((n) => ({ n, kind: nodeKindOf(2, n) }));\n } else {\n throw new Error(`Scene: unsupported version ${String(Reflect.get(json, 'version'))}; versions 1, 2 and 3 are supported`);\n }\n return entries.map(({ n, kind }) => {\n const spec: AddNodeSpec<TData, TLayer, TPose> = {\n id: n.id as NodeId,\n kind,\n layer: n.layer,\n pose: n.pose,\n data: n.data,\n };\n if (n.parent !== undefined) spec.parent = n.parent as NodeId;\n if (n.pickable !== undefined) spec.pickable = n.pickable;\n if (n.hidden === true) spec.hidden = true;\n if (n.locked === true) spec.locked = true;\n if (n.units !== undefined) spec.units = n.units;\n if (n.clip !== undefined) spec.clip = n.clip;\n if (n.consumesChildren === true) spec.consumesChildren = true;\n if (n.dependsOn !== undefined) {\n spec.dependsOn = n.dependsOn === 'children'\n ? 'children'\n : (n.dependsOn as readonly NodeId[]);\n }\n const serialized = n as unknown as Record<string, string | undefined>;\n for (const field of NODE_FN_FIELDS) {\n const key = serialized[field.jsonKey];\n if (key === undefined) continue;\n const fn = (registry[field.field] as Record<string, unknown> | undefined)?.[key];\n if (!fn && opts.unknownKeys === 'skip') {\n opts.onSkip?.({ id: spec.id!, field: field.field, key });\n continue;\n }\n if (!fn) {\n throw new Error(\n `Scene: unknown ${field.field} key '${key}'. ` +\n `Register a function with this key in the registry option.`,\n );\n }\n (spec as unknown as Record<string, unknown>)[field.field] = fn;\n }\n if (clipsAsV1(json.version, spec)) spec.clip = 'outline';\n return spec;\n });\n}\n\n/** Version 1 clipped a container with no clip function to its outline, which\n * is what `clip: 'outline'` draws on a group. One a classifier makes a mark\n * gets no clip, since which painter claims it is not known here; one whose\n * clip key was skipped loads as it would have without it. */\nfunction clipsAsV1(version: 1 | 2 | 3, spec: { kind: string; clipFromPose?: unknown }): boolean {\n return version === 1 && spec.kind === 'group' && spec.clipFromPose === undefined;\n}\n\n/** The kind a saved node loads as: its own from version 2; on version 1 a `leaf` is a\n * mark and a `container` goes to `classify`, or is a group without one. */\nexport function nodeKindOf<TData, TLayer extends string, TPose>(\n version: 1 | 2,\n n: SerializedNode<TData, TLayer, TPose> | SerializedNodeV1<TData, TLayer, TPose>,\n classify?: V1Classifier<TData, TLayer, TPose>,\n): 'mark' | 'group' {\n if (version === 2) return (n as SerializedNode<TData, TLayer, TPose>).kind;\n if (n.kind === 'leaf') return 'mark';\n return classify ? classify(n as SerializedNodeV1<TData, TLayer, TPose>) : 'group';\n}\n"],"mappings":"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"}
@@ -8,7 +8,8 @@ var statedFields = (n) => ({
8
8
  ...n.hidden === true ? { hidden: true } : {},
9
9
  ...n.locked === true ? { locked: true } : {},
10
10
  ...n.units !== void 0 ? { units: n.units } : {},
11
- ...n.clip !== void 0 ? { clip: n.clip } : {}
11
+ ...n.clip !== void 0 ? { clip: n.clip } : {},
12
+ ...n.consumesChildren === true ? { consumesChildren: true } : {}
12
13
  });
13
14
 
14
15
  //#endregion
@@ -1 +1 @@
1
- {"version":3,"file":"statedFields.js","names":[],"sources":["../../../src/core/scene/statedFields.ts"],"sourcesContent":["import type { UnitScope } from '@weasel-js/quantity';\nimport type { NodeClip } from './types';\n\n/** The plain optional fields a node or an `AddNodeSpec` may state. */\nexport interface StatedNodeFields {\n pickable?: boolean;\n hidden?: boolean;\n locked?: boolean;\n units?: UnitScope;\n clip?: NodeClip;\n}\n\n/** The plain optional fields of a node or spec as a spread for `scene.add`:\n * each present only when stated, so an unstated one keeps the scene's\n * default, and a flag states only `true`. What a copy of a node carries over\n * besides its kind, layer, pose, data and functions. */\nexport const statedFields = (n: StatedNodeFields & { kind?: string }): StatedNodeFields => ({\n ...(n.pickable !== undefined ? { pickable: n.pickable } : {}),\n ...(n.hidden === true ? { hidden: true } : {}),\n ...(n.locked === true ? { locked: true } : {}),\n ...(n.units !== undefined ? { units: n.units } : {}),\n ...(n.clip !== undefined ? { clip: n.clip } : {}),\n});\n"],"mappings":";;;;;AAgBA,IAAa,gBAAgB,OAA+D;CAC1F,GAAI,EAAE,aAAa,SAAY,EAAE,UAAU,EAAE,SAAS,IAAI,CAAC;CAC3D,GAAI,EAAE,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C,GAAI,EAAE,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C,GAAI,EAAE,UAAU,SAAY,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;CAClD,GAAI,EAAE,SAAS,SAAY,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;AACjD"}
1
+ {"version":3,"file":"statedFields.js","names":[],"sources":["../../../src/core/scene/statedFields.ts"],"sourcesContent":["import type { UnitScope } from '@weasel-js/quantity';\nimport type { NodeClip } from './types';\n\n/** The plain optional fields a node or an `AddNodeSpec` may state. */\nexport interface StatedNodeFields {\n pickable?: boolean;\n hidden?: boolean;\n locked?: boolean;\n units?: UnitScope;\n clip?: NodeClip;\n consumesChildren?: boolean;\n}\n\n/** The plain optional fields of a node or spec as a spread for `scene.add`:\n * each present only when stated, so an unstated one keeps the scene's\n * default, and a flag states only `true`. What a copy of a node carries over\n * besides its kind, layer, pose, data and functions. */\nexport const statedFields = (n: StatedNodeFields & { kind?: string }): StatedNodeFields => ({\n ...(n.pickable !== undefined ? { pickable: n.pickable } : {}),\n ...(n.hidden === true ? { hidden: true } : {}),\n ...(n.locked === true ? { locked: true } : {}),\n ...(n.units !== undefined ? { units: n.units } : {}),\n ...(n.clip !== undefined ? { clip: n.clip } : {}),\n ...(n.consumesChildren === true ? { consumesChildren: true } : {}),\n});\n"],"mappings":";;;;;AAiBA,IAAa,gBAAgB,OAA+D;CAC1F,GAAI,EAAE,aAAa,SAAY,EAAE,UAAU,EAAE,SAAS,IAAI,CAAC;CAC3D,GAAI,EAAE,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C,GAAI,EAAE,WAAW,OAAO,EAAE,QAAQ,KAAK,IAAI,CAAC;CAC5C,GAAI,EAAE,UAAU,SAAY,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;CAClD,GAAI,EAAE,SAAS,SAAY,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;CAC/C,GAAI,EAAE,qBAAqB,OAAO,EAAE,kBAAkB,KAAK,IAAI,CAAC;AAClE"}
@@ -0,0 +1,35 @@
1
+ import { samePoseValue } from "./poseSnapshot.js";
2
+
3
+ //#region src/core/scene/strategyView.ts
4
+ /**
5
+ * How a strategy sees a container at world `pose`: upright, in its own frame,
6
+ * moved so its box is centered on the box `measure` gives the world pose. A
7
+ * turned container's children are then laid out along its axes; an upright
8
+ * one is seen as it is. `place` moves a pose from one box to another of the
9
+ * same size.
10
+ */
11
+ function strategyView(pose, { compose, decompose }, measure, place) {
12
+ const own = decompose(pose, pose);
13
+ const from = measure(own);
14
+ const at = measure(pose);
15
+ if (from === null || at === null) return null;
16
+ const upright = place(own, from, {
17
+ ...from,
18
+ x: at.x + (at.width - from.width) / 2,
19
+ y: at.y + (at.height - from.height) / 2
20
+ });
21
+ const bounds = measure(upright);
22
+ if (bounds === null) return null;
23
+ const turned = !samePoseValue(upright, pose);
24
+ return {
25
+ upright,
26
+ bounds,
27
+ turned,
28
+ toStrategy: (p) => turned ? compose(upright, decompose(pose, p)) : p,
29
+ toWorld: (p) => turned ? compose(pose, decompose(upright, p)) : p
30
+ };
31
+ }
32
+
33
+ //#endregion
34
+ export { strategyView };
35
+ //# sourceMappingURL=strategyView.js.map