@weasel-js/core 1.9.3 → 1.9.4

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 (542) hide show
  1. package/CHANGELOG.md +356 -0
  2. package/README.md +2 -2
  3. package/dist/WeaselProvider.js +5 -5
  4. package/dist/affordances/composeAffordanceLayer.js +10 -20
  5. package/dist/affordances/composeAffordanceLayer.js.map +1 -1
  6. package/dist/affordances/cornerResize.js +25 -17
  7. package/dist/affordances/cornerResize.js.map +1 -1
  8. package/dist/affordances/hitAffordanceRegions.js +27 -20
  9. package/dist/affordances/hitAffordanceRegions.js.map +1 -1
  10. package/dist/affordances/rotationHandle.js +18 -18
  11. package/dist/affordances/rotationHandle.js.map +1 -1
  12. package/dist/animation/behaviors/momentum.js +93 -55
  13. package/dist/animation/behaviors/momentum.js.map +1 -1
  14. package/dist/animation/loop.js +10 -12
  15. package/dist/animation/loop.js.map +1 -1
  16. package/dist/animation/reflow.js +8 -8
  17. package/dist/animation/reflow.js.map +1 -1
  18. package/dist/animation/stagger.js +64 -56
  19. package/dist/animation/stagger.js.map +1 -1
  20. package/dist/animation/timeline/booking.js +62 -54
  21. package/dist/animation/timeline/booking.js.map +1 -1
  22. package/dist/animation/timeline/createTimeline.js +85 -76
  23. package/dist/animation/timeline/createTimeline.js.map +1 -1
  24. package/dist/animation/timeline/sampleTrack.js +13 -5
  25. package/dist/animation/timeline/sampleTrack.js.map +1 -1
  26. package/dist/animation/useAnimator.js +45 -35
  27. package/dist/animation/useAnimator.js.map +1 -1
  28. package/dist/animation/wrappers/animateLifecycle.js +31 -24
  29. package/dist/animation/wrappers/animateLifecycle.js.map +1 -1
  30. package/dist/animation/wrappers/animateOnSetPose.js +28 -26
  31. package/dist/animation/wrappers/animateOnSetPose.js.map +1 -1
  32. package/dist/animation/wrappers/instantPose.js +13 -0
  33. package/dist/animation/wrappers/instantPose.js.map +1 -0
  34. package/dist/{poseDescriptor-D-OH-tu5.d.ts → autoPoseDescriptor-Ct7yqivU.d.ts} +28 -3
  35. package/dist/barrel/chrome.js +16 -0
  36. package/dist/barrel/input.js +19 -0
  37. package/dist/barrel/interactions.js +42 -0
  38. package/dist/barrel/paint.js +18 -0
  39. package/dist/barrel/paths.js +19 -0
  40. package/dist/barrel/renderer.js +20 -0
  41. package/dist/barrel/routing.js +51 -0
  42. package/dist/barrel/text.js +18 -0
  43. package/dist/barrel/viewport.js +52 -0
  44. package/dist/builtins-DPcdghtB.d.ts +1223 -0
  45. package/dist/canvas/Canvas.js +363 -448
  46. package/dist/canvas/Canvas.js.map +1 -1
  47. package/dist/canvas/CanvasView.js +164 -165
  48. package/dist/canvas/CanvasView.js.map +1 -1
  49. package/dist/canvas/CursorCoordsHud.js +37 -32
  50. package/dist/canvas/CursorCoordsHud.js.map +1 -1
  51. package/dist/canvas/DrawCanvas.js +49 -43
  52. package/dist/canvas/DrawCanvas.js.map +1 -1
  53. package/dist/canvas/MinimapCanvas.js +26 -25
  54. package/dist/canvas/MinimapCanvas.js.map +1 -1
  55. package/dist/canvas/NodeShape.js +59 -377
  56. package/dist/canvas/NodeShape.js.map +1 -1
  57. package/dist/canvas/PickHud.js +50 -47
  58. package/dist/canvas/PickHud.js.map +1 -1
  59. package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js +167 -0
  60. package/dist/canvas/SceneCanvas/GestureDispatcherMounter.js.map +1 -0
  61. package/dist/canvas/SceneCanvas/PointerProviderIfRoot.js +13 -13
  62. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js +67 -0
  63. package/dist/canvas/SceneCanvas/StandardActionsRegistrar.js.map +1 -0
  64. package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js +16 -0
  65. package/dist/canvas/SceneCanvas/ToolKeybindingsMounter.js.map +1 -0
  66. package/dist/canvas/SceneCanvas/coordTrace.js +10 -0
  67. package/dist/canvas/SceneCanvas/coordTrace.js.map +1 -0
  68. package/dist/canvas/SceneCanvas/defaultNodeProperties.js +112 -70
  69. package/dist/canvas/SceneCanvas/defaultNodeProperties.js.map +1 -1
  70. package/dist/canvas/SceneCanvas/defaultNodeRouting.js +9 -8
  71. package/dist/canvas/SceneCanvas/defaultNodeRouting.js.map +1 -1
  72. package/dist/canvas/SceneCanvas/features.js +1 -0
  73. package/dist/canvas/SceneCanvas/features.js.map +1 -1
  74. package/dist/canvas/SceneCanvas/isDev.js +12 -0
  75. package/dist/canvas/SceneCanvas/isDev.js.map +1 -0
  76. package/dist/canvas/SceneCanvas/poseGeometry.js +29 -28
  77. package/dist/canvas/SceneCanvas/poseGeometry.js.map +1 -1
  78. package/dist/canvas/SceneCanvas/poseRegistrars.js +13 -0
  79. package/dist/canvas/SceneCanvas/poseRegistrars.js.map +1 -0
  80. package/dist/canvas/SceneCanvas/props.js +38 -0
  81. package/dist/canvas/SceneCanvas/props.js.map +1 -0
  82. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js +21 -62
  83. package/dist/canvas/SceneCanvas/useBuiltinShapeTools.js.map +1 -1
  84. package/dist/canvas/SceneCanvas/useDispatcherOverlayLayer.js.map +1 -1
  85. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js +46 -48
  86. package/dist/canvas/SceneCanvas/usePreviewGhostLayer.js.map +1 -1
  87. package/dist/canvas/SceneCanvas/useSceneSelectTool.js +33 -33
  88. package/dist/canvas/SceneCanvas/useSceneSelectTool.js.map +1 -1
  89. package/dist/canvas/SceneCanvas.js +534 -788
  90. package/dist/canvas/SceneCanvas.js.map +1 -1
  91. package/dist/canvas/SceneViewCanvas.js +45 -43
  92. package/dist/canvas/SceneViewCanvas.js.map +1 -1
  93. package/dist/canvas/buildSceneLayer.js +91 -0
  94. package/dist/canvas/buildSceneLayer.js.map +1 -0
  95. package/dist/canvas/buildSceneTree.js +16 -19
  96. package/dist/canvas/buildSceneTree.js.map +1 -1
  97. package/dist/canvas/canvasRenderer.js +68 -52
  98. package/dist/canvas/canvasRenderer.js.map +1 -1
  99. package/dist/canvas/deps/changes.js +13 -0
  100. package/dist/canvas/deps/changes.js.map +1 -0
  101. package/dist/canvas/deps/editAnchors.js +28 -28
  102. package/dist/canvas/deps/insert.js +119 -91
  103. package/dist/canvas/deps/insert.js.map +1 -1
  104. package/dist/canvas/deps/slice.js +46 -45
  105. package/dist/canvas/deps/slice.js.map +1 -1
  106. package/dist/canvas/deps/textEdit.js +10 -9
  107. package/dist/canvas/deps/textEdit.js.map +1 -1
  108. package/dist/canvas/derivedPath.js +46 -23
  109. package/dist/canvas/derivedPath.js.map +1 -1
  110. package/dist/canvas/getNodeAtPoint.js +7 -7
  111. package/dist/canvas/getNodeAtPoint.js.map +1 -1
  112. package/dist/canvas/hud.module.js +1 -1
  113. package/dist/canvas/hud.module.js.map +1 -1
  114. package/dist/canvas/kitRequirements.js +2 -2
  115. package/dist/canvas/kitRequirements.js.map +1 -1
  116. package/dist/canvas/layerOrder.js +13 -6
  117. package/dist/canvas/layerOrder.js.map +1 -1
  118. package/dist/canvas/minimapMath.js +12 -10
  119. package/dist/canvas/minimapMath.js.map +1 -1
  120. package/dist/canvas/nodeShapes/derivedPainter.js +34 -0
  121. package/dist/canvas/nodeShapes/derivedPainter.js.map +1 -0
  122. package/dist/canvas/nodeShapes/imagePainter.js +87 -0
  123. package/dist/canvas/nodeShapes/imagePainter.js.map +1 -0
  124. package/dist/canvas/nodeShapes/memo.js +9 -0
  125. package/dist/canvas/nodeShapes/memo.js.map +1 -0
  126. package/dist/canvas/nodeShapes/nodePaint.js +57 -0
  127. package/dist/canvas/nodeShapes/nodePaint.js.map +1 -0
  128. package/dist/canvas/nodeShapes/pathPainter.js +38 -0
  129. package/dist/canvas/nodeShapes/pathPainter.js.map +1 -0
  130. package/dist/canvas/nodeShapes/poseBox.js +20 -0
  131. package/dist/canvas/nodeShapes/poseBox.js.map +1 -0
  132. package/dist/canvas/nodeShapes/rectFallbackPainter.js +38 -0
  133. package/dist/canvas/nodeShapes/rectFallbackPainter.js.map +1 -0
  134. package/dist/canvas/nodeShapes/shapePainter.js +72 -0
  135. package/dist/canvas/nodeShapes/shapePainter.js.map +1 -0
  136. package/dist/canvas/nodeShapes/textPainter.js +55 -0
  137. package/dist/canvas/nodeShapes/textPainter.js.map +1 -0
  138. package/dist/canvas/overlayRoleStrokes.js.map +1 -1
  139. package/dist/canvas/paintCull.js +10 -11
  140. package/dist/canvas/paintCull.js.map +1 -1
  141. package/dist/canvas/pickWalk.js +52 -63
  142. package/dist/canvas/pickWalk.js.map +1 -1
  143. package/dist/canvas/poseRotation.js +11 -23
  144. package/dist/canvas/poseRotation.js.map +1 -1
  145. package/dist/canvas/renderDebugSnapshot.js +5 -5
  146. package/dist/canvas/renderSceneToPixels.js +3 -1
  147. package/dist/canvas/renderSceneToPixels.js.map +1 -1
  148. package/dist/canvas/sceneAdapter.js +66 -148
  149. package/dist/canvas/sceneAdapter.js.map +1 -1
  150. package/dist/canvas/sceneClipboard.js +112 -0
  151. package/dist/canvas/sceneClipboard.js.map +1 -0
  152. package/dist/canvas/sceneSlotWiring.js +4 -4
  153. package/dist/canvas/sceneSlotWiring.js.map +1 -1
  154. package/dist/canvas/sceneViewRender.js +39 -40
  155. package/dist/canvas/sceneViewRender.js.map +1 -1
  156. package/dist/canvas/useCanvasRenderer.js +14 -6
  157. package/dist/canvas/useCanvasRenderer.js.map +1 -1
  158. package/dist/canvas/useCanvasView.js +58 -0
  159. package/dist/canvas/useCanvasView.js.map +1 -0
  160. package/dist/canvas/useFrameLoop.js +35 -26
  161. package/dist/canvas/useFrameLoop.js.map +1 -1
  162. package/dist/canvas/useSceneLayerList.js +21 -0
  163. package/dist/canvas/useSceneLayerList.js.map +1 -0
  164. package/dist/clipboard.d.ts +10 -6
  165. package/dist/clone.d.ts +4 -3
  166. package/dist/core/adapters/arrayAdapter.js +48 -39
  167. package/dist/core/adapters/arrayAdapter.js.map +1 -1
  168. package/dist/core/device/index.js +5 -4
  169. package/dist/core/device/useDeviceProfile.js +38 -44
  170. package/dist/core/device/useDeviceProfile.js.map +1 -1
  171. package/dist/core/device/watchDevicePixelRatio.js +17 -0
  172. package/dist/core/device/watchDevicePixelRatio.js.map +1 -0
  173. package/dist/core/fillInPoseFrame.js.map +1 -1
  174. package/dist/core/geometry/poseDescriptor.js +21 -19
  175. package/dist/core/geometry/poseDescriptor.js.map +1 -1
  176. package/dist/core/geometry/poseFrame.js +44 -0
  177. package/dist/core/geometry/poseFrame.js.map +1 -0
  178. package/dist/core/geometry/poseRotation.js.map +1 -1
  179. package/dist/core/geometry/regionHit.js +9 -10
  180. package/dist/core/geometry/regionHit.js.map +1 -1
  181. package/dist/core/geometry/unionBounds.js +31 -29
  182. package/dist/core/geometry/unionBounds.js.map +1 -1
  183. package/dist/core/isPlainObject.js +2 -11
  184. package/dist/core/ops/arrange.js +1 -0
  185. package/dist/core/ops/arrange.js.map +1 -1
  186. package/dist/core/ops/create.js +10 -5
  187. package/dist/core/ops/create.js.map +1 -1
  188. package/dist/core/ops/delete.js +12 -24
  189. package/dist/core/ops/delete.js.map +1 -1
  190. package/dist/core/ops/reorder/index.js +43 -40
  191. package/dist/core/ops/reorder/index.js.map +1 -1
  192. package/dist/core/ops/reorder/setChildOrder.js +34 -0
  193. package/dist/core/ops/reorder/setChildOrder.js.map +1 -0
  194. package/dist/core/paintKinds.js +5 -5
  195. package/dist/core/paintKinds.js.map +1 -1
  196. package/dist/core/scene/NodeProperties.js.map +1 -1
  197. package/dist/core/scene/appliedLog.js +37 -0
  198. package/dist/core/scene/appliedLog.js.map +1 -0
  199. package/dist/core/scene/arrivalWindow.js +101 -0
  200. package/dist/core/scene/arrivalWindow.js.map +1 -0
  201. package/dist/core/scene/derivedPath.js.map +1 -1
  202. package/dist/core/scene/historyFacade.js +84 -0
  203. package/dist/core/scene/historyFacade.js.map +1 -0
  204. package/dist/core/scene/kitOps.js +173 -0
  205. package/dist/core/scene/kitOps.js.map +1 -0
  206. package/dist/core/scene/layerStack.js +38 -0
  207. package/dist/core/scene/layerStack.js.map +1 -0
  208. package/dist/core/scene/lockGuard.js +37 -0
  209. package/dist/core/scene/lockGuard.js.map +1 -0
  210. package/dist/core/scene/nodeFnFields.js +5 -6
  211. package/dist/core/scene/nodeFnFields.js.map +1 -1
  212. package/dist/core/scene/nodeMemo.js +45 -19
  213. package/dist/core/scene/nodeMemo.js.map +1 -1
  214. package/dist/core/scene/nodeStore.js +126 -0
  215. package/dist/core/scene/nodeStore.js.map +1 -0
  216. package/dist/core/scene/pickability.js +6 -0
  217. package/dist/core/scene/pickability.js.map +1 -0
  218. package/dist/core/scene/poseFeed.js +38 -38
  219. package/dist/core/scene/poseFeed.js.map +1 -1
  220. package/dist/core/scene/poseOverrides.js +34 -38
  221. package/dist/core/scene/poseOverrides.js.map +1 -1
  222. package/dist/core/scene/renderOrder.js +84 -0
  223. package/dist/core/scene/renderOrder.js.map +1 -0
  224. package/dist/core/scene/scene.js +289 -866
  225. package/dist/core/scene/scene.js.map +1 -1
  226. package/dist/core/scene/serialization.js +68 -0
  227. package/dist/core/scene/serialization.js.map +1 -0
  228. package/dist/core/scene/treeOrder.js +13 -0
  229. package/dist/core/scene/treeOrder.js.map +1 -0
  230. package/dist/core/scene/types.js.map +1 -1
  231. package/dist/core/viewport/meanScale.js +1 -1
  232. package/dist/core/viewport/meanScale.js.map +1 -1
  233. package/dist/core/viewport/view.js +12 -12
  234. package/dist/core/viewport/view.js.map +1 -1
  235. package/dist/core/viewport/zoomBounds.js +10 -8
  236. package/dist/core/viewport/zoomBounds.js.map +1 -1
  237. package/dist/{cornerHandles-BCrDp_mH.d.ts → cornerHandles-CtCb8a3G.d.ts} +1 -1
  238. package/dist/debug/createDebugOverlayLayer.js +14 -14
  239. package/dist/debug/createDebugOverlayLayer.js.map +1 -1
  240. package/dist/debug/flag.js +2 -41
  241. package/dist/features/chrome-caps/useHoverTracking.js +22 -17
  242. package/dist/features/chrome-caps/useHoverTracking.js.map +1 -1
  243. package/dist/features/focus/gateLayer.js +3 -4
  244. package/dist/features/focus/gateLayer.js.map +1 -1
  245. package/dist/features/images/imageCache.js +19 -9
  246. package/dist/features/images/imageCache.js.map +1 -1
  247. package/dist/features/ingestion/contentHandlers.js +14 -11
  248. package/dist/features/ingestion/contentHandlers.js.map +1 -1
  249. package/dist/features/ingestion/index.js +1 -1
  250. package/dist/features/ingestion/registerKitHandlers.js +7 -7
  251. package/dist/features/ingestion/weaselJsonHandler.js +17 -14
  252. package/dist/features/ingestion/weaselJsonHandler.js.map +1 -1
  253. package/dist/features/meshPaint/lazyKind.js +201 -35
  254. package/dist/features/meshPaint/lazyKind.js.map +1 -1
  255. package/dist/features/meshPaint/meshPaint.js +82 -79
  256. package/dist/features/meshPaint/meshPaint.js.map +1 -1
  257. package/dist/features/minimap/createMinimapContribution.js +42 -42
  258. package/dist/features/minimap/layers.js +44 -62
  259. package/dist/features/minimap/layers.js.map +1 -1
  260. package/dist/features/parallax/createParallaxPlane.js +10 -14
  261. package/dist/features/parallax/createParallaxPlane.js.map +1 -1
  262. package/dist/features/paths/anchorEdits.js +19 -8
  263. package/dist/features/paths/anchorEdits.js.map +1 -1
  264. package/dist/features/paths/anchors.js +31 -26
  265. package/dist/features/paths/anchors.js.map +1 -1
  266. package/dist/features/paths/booleans.js +2 -2
  267. package/dist/features/paths/index.js +13 -11
  268. package/dist/features/paths/markerCommands.js +37 -36
  269. package/dist/features/paths/markerCommands.js.map +1 -1
  270. package/dist/features/paths/pathInWorld.js +19 -19
  271. package/dist/features/paths/pathInWorld.js.map +1 -1
  272. package/dist/features/paths/pathLayer.js.map +1 -1
  273. package/dist/features/paths/strokeToPath.js +40 -0
  274. package/dist/features/paths/strokeToPath.js.map +1 -0
  275. package/dist/features/paths/tessellate/stroke.js.map +1 -1
  276. package/dist/features/patterns/commandPaint.js +18 -0
  277. package/dist/features/patterns/commandPaint.js.map +1 -0
  278. package/dist/features/patterns/index.js +5 -17
  279. package/dist/features/patterns/index.js.map +1 -1
  280. package/dist/features/patterns/rasterizeTile.js +17 -0
  281. package/dist/features/patterns/rasterizeTile.js.map +1 -0
  282. package/dist/features/patterns/resolveSpec.js +52 -44
  283. package/dist/features/patterns/resolveSpec.js.map +1 -1
  284. package/dist/features/poseRun/usePoseRun.js +8 -3
  285. package/dist/features/poseRun/usePoseRun.js.map +1 -1
  286. package/dist/features/selection/SelectionContext.js +5 -0
  287. package/dist/features/selection/SelectionContext.js.map +1 -1
  288. package/dist/features/selection/overlay.js +18 -18
  289. package/dist/features/selection/overlay.js.map +1 -1
  290. package/dist/features/text/domOffsets.js +82 -0
  291. package/dist/features/text/domOffsets.js.map +1 -0
  292. package/dist/features/text/domRuns.js +103 -131
  293. package/dist/features/text/domRuns.js.map +1 -1
  294. package/dist/features/text/hitTest.js +5 -2
  295. package/dist/features/text/hitTest.js.map +1 -1
  296. package/dist/features/text/isTextData.js +8 -0
  297. package/dist/features/text/isTextData.js.map +1 -0
  298. package/dist/features/text/overlayDirection.js +15 -0
  299. package/dist/features/text/overlayDirection.js.map +1 -0
  300. package/dist/features/text/runs/rangeStyle.js +32 -34
  301. package/dist/features/text/runs/rangeStyle.js.map +1 -1
  302. package/dist/features/text/textCommand.js +34 -33
  303. package/dist/features/text/textCommand.js.map +1 -1
  304. package/dist/features/text/textToPath.js +40 -40
  305. package/dist/features/text/textToPath.js.map +1 -1
  306. package/dist/features/text/useSceneTextEdit.js +76 -82
  307. package/dist/features/text/useSceneTextEdit.js.map +1 -1
  308. package/dist/features/text/useTextEdit.js +184 -160
  309. package/dist/features/text/useTextEdit.js.map +1 -1
  310. package/dist/features/tiling/createTiledLayer.js +24 -22
  311. package/dist/features/tiling/createTiledLayer.js.map +1 -1
  312. package/dist/index.d.ts +11033 -7749
  313. package/dist/index.js +316 -309
  314. package/dist/input/keyState.js +42 -43
  315. package/dist/input/keyState.js.map +1 -1
  316. package/dist/input/useKeyModifiers.js +11 -0
  317. package/dist/input/useKeyModifiers.js.map +1 -0
  318. package/dist/interactions/actions/align/align.js +8 -8
  319. package/dist/interactions/actions/clipboard/clipboardOps.js +34 -32
  320. package/dist/interactions/actions/clipboard/clipboardOps.js.map +1 -1
  321. package/dist/interactions/actions/clipboard/materializePaste.js +10 -7
  322. package/dist/interactions/actions/clipboard/materializePaste.js.map +1 -1
  323. package/dist/interactions/actions/clipboard/wireFormat.js.map +1 -1
  324. package/dist/interactions/actions/clone/behaviors/cloneByAltDrag.js.map +1 -1
  325. package/dist/interactions/actions/defaultCommitAdapter.js +20 -18
  326. package/dist/interactions/actions/defaultCommitAdapter.js.map +1 -1
  327. package/dist/interactions/actions/defaults/align.js +9 -10
  328. package/dist/interactions/actions/defaults/align.js.map +1 -1
  329. package/dist/interactions/actions/defaults/anchorEditing.js +59 -81
  330. package/dist/interactions/actions/defaults/anchorEditing.js.map +1 -1
  331. package/dist/interactions/actions/defaults/areaSelect.js +35 -38
  332. package/dist/interactions/actions/defaults/areaSelect.js.map +1 -1
  333. package/dist/interactions/actions/defaults/clipboard.js +26 -10
  334. package/dist/interactions/actions/defaults/clipboard.js.map +1 -1
  335. package/dist/interactions/actions/defaults/clone.js +44 -60
  336. package/dist/interactions/actions/defaults/clone.js.map +1 -1
  337. package/dist/interactions/actions/defaults/copySubtree.js +40 -0
  338. package/dist/interactions/actions/defaults/copySubtree.js.map +1 -0
  339. package/dist/interactions/actions/defaults/distribute.js +14 -13
  340. package/dist/interactions/actions/defaults/distribute.js.map +1 -1
  341. package/dist/interactions/actions/defaults/duplicate.js +17 -57
  342. package/dist/interactions/actions/defaults/duplicate.js.map +1 -1
  343. package/dist/interactions/actions/defaults/editAnchors.js +18 -18
  344. package/dist/interactions/actions/defaults/enterTextEdit.js.map +1 -1
  345. package/dist/interactions/actions/defaults/flip.js +52 -46
  346. package/dist/interactions/actions/defaults/flip.js.map +1 -1
  347. package/dist/interactions/actions/defaults/group.js +43 -48
  348. package/dist/interactions/actions/defaults/group.js.map +1 -1
  349. package/dist/interactions/actions/defaults/ingest.js +35 -33
  350. package/dist/interactions/actions/defaults/ingest.js.map +1 -1
  351. package/dist/interactions/actions/defaults/insert.js +50 -51
  352. package/dist/interactions/actions/defaults/insert.js.map +1 -1
  353. package/dist/interactions/actions/defaults/insertPathAnchor.js +7 -7
  354. package/dist/interactions/actions/defaults/lassoSelect.js +67 -70
  355. package/dist/interactions/actions/defaults/lassoSelect.js.map +1 -1
  356. package/dist/interactions/actions/defaults/move.js +267 -249
  357. package/dist/interactions/actions/defaults/move.js.map +1 -1
  358. package/dist/interactions/actions/defaults/nudge.js +40 -68
  359. package/dist/interactions/actions/defaults/nudge.js.map +1 -1
  360. package/dist/interactions/actions/defaults/nudgeSteps.js +37 -0
  361. package/dist/interactions/actions/defaults/nudgeSteps.js.map +1 -0
  362. package/dist/interactions/actions/defaults/reorder.js +2 -0
  363. package/dist/interactions/actions/defaults/reorder.js.map +1 -1
  364. package/dist/interactions/actions/defaults/resize.js +104 -98
  365. package/dist/interactions/actions/defaults/resize.js.map +1 -1
  366. package/dist/interactions/actions/defaults/rotate.js +111 -110
  367. package/dist/interactions/actions/defaults/rotate.js.map +1 -1
  368. package/dist/interactions/actions/defaults/setFill.js +7 -7
  369. package/dist/interactions/actions/defaults/setFillOpacity.js +4 -4
  370. package/dist/interactions/actions/defaults/setStroke.js +12 -12
  371. package/dist/interactions/actions/defaults/setStrokeOpacity.js +6 -6
  372. package/dist/interactions/actions/defaults/sliceOps.js +19 -19
  373. package/dist/interactions/actions/defaults/viewportDragPan.js +37 -26
  374. package/dist/interactions/actions/defaults/viewportDragPan.js.map +1 -1
  375. package/dist/interactions/actions/edit-anchors/geometry.js +28 -23
  376. package/dist/interactions/actions/edit-anchors/geometry.js.map +1 -1
  377. package/dist/interactions/actions/flip/helpers.js +30 -17
  378. package/dist/interactions/actions/flip/helpers.js.map +1 -1
  379. package/dist/interactions/actions/hitSelection.js +8 -0
  380. package/dist/interactions/actions/hitSelection.js.map +1 -0
  381. package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js +14 -18
  382. package/dist/interactions/actions/lasso-select/behaviors/selectFromLasso.js.map +1 -1
  383. package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js +5 -5
  384. package/dist/interactions/actions/move/behaviors/snapBackOrDelete.js.map +1 -1
  385. package/dist/interactions/actions/move/behaviors/snapToContainer.js +32 -21
  386. package/dist/interactions/actions/move/behaviors/snapToContainer.js.map +1 -1
  387. package/dist/interactions/actions/move/gestureAdapter.js +32 -15
  388. package/dist/interactions/actions/move/gestureAdapter.js.map +1 -1
  389. package/dist/interactions/actions/move/landedDescendants.js +33 -0
  390. package/dist/interactions/actions/move/landedDescendants.js.map +1 -0
  391. package/dist/interactions/actions/outlines/createOutlines.js +18 -18
  392. package/dist/interactions/actions/poseDescriptorDep.js +16 -4
  393. package/dist/interactions/actions/poseDescriptorDep.js.map +1 -1
  394. package/dist/interactions/actions/poseFrame.js +11 -6
  395. package/dist/interactions/actions/poseFrame.js.map +1 -1
  396. package/dist/interactions/actions/previewOverrides.js +5 -5
  397. package/dist/interactions/actions/previewOverrides.js.map +1 -1
  398. package/dist/interactions/actions/selectionSubtree.js +69 -0
  399. package/dist/interactions/actions/selectionSubtree.js.map +1 -0
  400. package/dist/interactions/actions/useStandardActions.js +66 -62
  401. package/dist/interactions/actions/useStandardActions.js.map +1 -1
  402. package/dist/interactions/gestures/dragGesture/dragGesture.js +4 -7
  403. package/dist/interactions/gestures/dragGesture/dragGesture.js.map +1 -1
  404. package/dist/interactions/gestures/dragGesture/dragPointOf.js +23 -0
  405. package/dist/interactions/gestures/dragGesture/dragPointOf.js.map +1 -0
  406. package/dist/interactions/gestures/handleDrag/handleDrag.js +21 -26
  407. package/dist/interactions/gestures/handleDrag/handleDrag.js.map +1 -1
  408. package/dist/interactions/gestures/pointerDrag/pointerDrag.js +8 -6
  409. package/dist/interactions/gestures/pointerDrag/pointerDrag.js.map +1 -1
  410. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js +8 -4
  411. package/dist/interactions/gestures/thresholdDrag/thresholdDrag.js.map +1 -1
  412. package/dist/{math-Drrw4ewZ.d.ts → math-J-ACHyEg.d.ts} +1 -2
  413. package/dist/math.d.ts +2 -3
  414. package/dist/move.d.ts +12 -11
  415. package/dist/{originProjection-DEklpDc_.d.ts → originProjection-gHnOup4e.d.ts} +1 -1
  416. package/dist/{registerProgram-BMZRDgrh.d.ts → registerProgram-T9S_PfAX.d.ts} +18 -7
  417. package/dist/renderer/DrawCommand.js.map +1 -1
  418. package/dist/renderer/WeaselRenderer.js +75 -73
  419. package/dist/renderer/WeaselRenderer.js.map +1 -1
  420. package/dist/renderer/cache/GLImageCache.js +15 -5
  421. package/dist/renderer/cache/GLImageCache.js.map +1 -1
  422. package/dist/renderer/cache/GLMeshCache.js +23 -23
  423. package/dist/renderer/cache/GLMeshCache.js.map +1 -1
  424. package/dist/renderer/cache/GLTextureCache.js +18 -1
  425. package/dist/renderer/cache/GLTextureCache.js.map +1 -1
  426. package/dist/renderer/cache/cache.js.map +1 -1
  427. package/dist/renderer/cache/markerCommandCache.js.map +1 -1
  428. package/dist/renderer/cache/strokeMeshCache.js.map +1 -1
  429. package/dist/renderer/cullDrawCommands.js +11 -11
  430. package/dist/renderer/draw/batch.js +133 -0
  431. package/dist/renderer/draw/batch.js.map +1 -0
  432. package/dist/renderer/draw/clip.js +89 -0
  433. package/dist/renderer/draw/clip.js.map +1 -0
  434. package/dist/renderer/draw/customShader.js +230 -0
  435. package/dist/renderer/draw/customShader.js.map +1 -0
  436. package/dist/renderer/draw/drawTriangles.js +8 -0
  437. package/dist/renderer/draw/drawTriangles.js.map +1 -0
  438. package/dist/renderer/draw/effects.js +28 -0
  439. package/dist/renderer/draw/effects.js.map +1 -0
  440. package/dist/renderer/draw/flushBatch.js +35 -0
  441. package/dist/renderer/draw/flushBatch.js.map +1 -0
  442. package/dist/renderer/draw/gradient.js +90 -0
  443. package/dist/renderer/draw/gradient.js.map +1 -0
  444. package/dist/renderer/draw/image.js +38 -0
  445. package/dist/renderer/draw/image.js.map +1 -0
  446. package/dist/renderer/draw/mesh.js +16 -0
  447. package/dist/renderer/draw/mesh.js.map +1 -0
  448. package/dist/renderer/draw/paintBind.js +70 -0
  449. package/dist/renderer/draw/paintBind.js.map +1 -0
  450. package/dist/renderer/draw/pathPaint.js +142 -0
  451. package/dist/renderer/draw/pathPaint.js.map +1 -0
  452. package/dist/renderer/draw/scratchPass.js +83 -0
  453. package/dist/renderer/draw/scratchPass.js.map +1 -0
  454. package/dist/renderer/draw/stencil.js +28 -0
  455. package/dist/renderer/draw/stencil.js.map +1 -0
  456. package/dist/renderer/draw/text.js +167 -0
  457. package/dist/renderer/draw/text.js.map +1 -0
  458. package/dist/renderer/draw/uniforms.js +77 -0
  459. package/dist/renderer/draw/uniforms.js.map +1 -0
  460. package/dist/renderer/draw.js +60 -1116
  461. package/dist/renderer/draw.js.map +1 -1
  462. package/dist/renderer/effects/EffectTargets.js +3 -0
  463. package/dist/renderer/effects/EffectTargets.js.map +1 -1
  464. package/dist/renderer/effects/composite.js +7 -5
  465. package/dist/renderer/effects/composite.js.map +1 -1
  466. package/dist/renderer/index.js +18 -17
  467. package/dist/renderer/math/color.js +63 -83
  468. package/dist/renderer/math/color.js.map +1 -1
  469. package/dist/renderer/math/mat3.js +15 -11
  470. package/dist/renderer/math/mat3.js.map +1 -1
  471. package/dist/renderer/math/viewToMat3.js +1 -1
  472. package/dist/renderer/math/viewToMat3.js.map +1 -1
  473. package/dist/renderer/shaders/ShaderProgram.js +13 -13
  474. package/dist/renderer/shaders/ShaderProgram.js.map +1 -1
  475. package/dist/renderer/shaders/glyphPaint.js +3 -3
  476. package/dist/renderer/shaders/glyphPaint.js.map +1 -1
  477. package/dist/renderer/shaders/gradFill.js +2 -1
  478. package/dist/renderer/shaders/gradFill.js.map +1 -1
  479. package/dist/renderer/shaders/pathFill.js +2 -1
  480. package/dist/renderer/shaders/pathFill.js.map +1 -1
  481. package/dist/renderer/shaders/patternFill.js +2 -1
  482. package/dist/renderer/shaders/patternFill.js.map +1 -1
  483. package/dist/renderer/shaders/registerProgram.js.map +1 -1
  484. package/dist/renderer/strokeLengths.js.map +1 -1
  485. package/dist/renderer/textures/registerTexture.js +25 -5
  486. package/dist/renderer/textures/registerTexture.js.map +1 -1
  487. package/dist/renderer.d.ts +16 -15
  488. package/dist/renderer.js +17 -16
  489. package/dist/resize.d.ts +5 -6
  490. package/dist/resize.js +5 -5
  491. package/dist/style.css +1 -1
  492. package/dist/test-hook/install.js +12 -6
  493. package/dist/test-hook/install.js.map +1 -1
  494. package/dist/{test-seams-CuIxe0xY.d.ts → test-seams-DM2B87-g.d.ts} +4 -4
  495. package/dist/test-seams.d.ts +2 -2
  496. package/dist/tools/builtin/ellipse/useEllipseTool.js +1 -0
  497. package/dist/tools/builtin/ellipse/useEllipseTool.js.map +1 -1
  498. package/dist/tools/builtin/hand/useHandTool.js +1 -0
  499. package/dist/tools/builtin/hand/useHandTool.js.map +1 -1
  500. package/dist/tools/builtin/lasso/useLassoTool.js +11 -11
  501. package/dist/tools/builtin/lasso/useLassoTool.js.map +1 -1
  502. package/dist/tools/builtin/line/useLineTool.js +1 -0
  503. package/dist/tools/builtin/line/useLineTool.js.map +1 -1
  504. package/dist/tools/builtin/pen/usePenTool.js +153 -103
  505. package/dist/tools/builtin/pen/usePenTool.js.map +1 -1
  506. package/dist/tools/builtin/pencil/usePencilTool.js +1 -0
  507. package/dist/tools/builtin/pencil/usePencilTool.js.map +1 -1
  508. package/dist/tools/builtin/polygon/usePolygonTool.js +13 -8
  509. package/dist/tools/builtin/polygon/usePolygonTool.js.map +1 -1
  510. package/dist/tools/builtin/rect/useRectTool.js +1 -0
  511. package/dist/tools/builtin/rect/useRectTool.js.map +1 -1
  512. package/dist/tools/builtin/select/selectionContributions.js +24 -23
  513. package/dist/tools/builtin/select/selectionContributions.js.map +1 -1
  514. package/dist/tools/builtin/select/useSelectTool.js +51 -48
  515. package/dist/tools/builtin/select/useSelectTool.js.map +1 -1
  516. package/dist/tools/builtin/shared/pointerFollower.js +17 -0
  517. package/dist/tools/builtin/shared/pointerFollower.js.map +1 -0
  518. package/dist/tools/builtin/slice/useSliceTool.js +49 -54
  519. package/dist/tools/builtin/slice/useSliceTool.js.map +1 -1
  520. package/dist/tools/builtin/star/useStarTool.js +22 -16
  521. package/dist/tools/builtin/star/useStarTool.js.map +1 -1
  522. package/dist/tools/builtin/text/useTextTool.js +1 -0
  523. package/dist/tools/builtin/text/useTextTool.js.map +1 -1
  524. package/dist/tools/useKeybindings.js +14 -30
  525. package/dist/tools/useKeybindings.js.map +1 -1
  526. package/dist/{types-B_9g6hMM.d.ts → types-B4iJRHC3.d.ts} +5 -1
  527. package/dist/{types-A37hYkeR.d.ts → types-k-5Oqh-U.d.ts} +31 -7
  528. package/dist/util/color.js +3 -3
  529. package/dist/util/color.js.map +1 -1
  530. package/dist/util/paint.js.map +1 -1
  531. package/dist/version.js +1 -1
  532. package/package.json +20 -18
  533. package/dist/autoPoseDescriptor-vCdt55xm.d.ts +0 -27
  534. package/dist/builtins-C-VgUlWI.d.ts +0 -4514
  535. package/dist/core/isPlainObject.js.map +0 -1
  536. package/dist/debug/flag.js.map +0 -1
  537. package/dist/interactions/actions/defaults/freshNodeId.js +0 -10
  538. package/dist/interactions/actions/defaults/freshNodeId.js.map +0 -1
  539. package/dist/renderer/shaders/imageFill.js +0 -14
  540. package/dist/renderer/shaders/imageFill.js.map +0 -1
  541. package/dist/tools/prefs.js +0 -62
  542. package/dist/tools/prefs.js.map +0 -1
@@ -1,54 +1,56 @@
1
1
  import { normalizeView as e } from "../core/viewport/view.js";
2
- import { useLateContentRedraw as t } from "./useLateContentRedraw.js";
3
- import { useFrameLoop as n } from "./useFrameLoop.js";
4
- import { useCanvasRenderer as r } from "./useCanvasRenderer.js";
5
- import { sceneViewFrame as i } from "./sceneViewRender.js";
6
- import { useCallback as a, useEffect as o, useLayoutEffect as s, useRef as c, useSyncExternalStore as l } from "react";
7
- import { assignRef as u, useLatest as d } from "@weasel-js/react";
8
- import { jsx as f } from "react/jsx-runtime";
2
+ import { useFrameLoop as t } from "./useFrameLoop.js";
3
+ import { useLateContentRedraw as n } from "./useLateContentRedraw.js";
4
+ import { useCanvasRenderer as r, useRedrawOnDensityChange as i, useRedrawOnRestore as a } from "./useCanvasRenderer.js";
5
+ import { sceneViewFrame as o } from "./sceneViewRender.js";
6
+ import { useCallback as s, useEffect as c, useLayoutEffect as l, useRef as u, useSyncExternalStore as d } from "react";
7
+ import { assignRef as f, useLatest as p } from "@weasel-js/react";
8
+ import { jsx as m } from "react/jsx-runtime";
9
9
  //#region src/canvas/SceneViewCanvas.tsx
10
- function p(p) {
11
- let { scene: m, width: h, height: g, drawOne: _, extraCommands: v, alphaFor: y, layerVisibility: b, layerOrder: x, animator: S, className: C, canvasRef: w, cull: T, paintBounds: E } = p, D = e(p.view);
12
- l(m.subscribe, m.getVersion, m.getVersion);
13
- let O = c(null), k = a((e) => {
14
- O.current = e, u(w, e);
15
- }, [w]), { paint: A } = r(), j = d(() => {
16
- let e = O.current;
10
+ function h(h) {
11
+ let { scene: g, width: _, height: v, drawOne: y, extraCommands: b, alphaFor: x, layerVisibility: S, layerOrder: C, animator: w, className: T, canvasRef: E, cull: D, paintBounds: O } = h, k = e(h.view);
12
+ d(g.subscribe, g.getVersion, g.getVersion);
13
+ let A = u(null), j = s((e) => {
14
+ A.current = e, f(E, e);
15
+ }, [E]), M = r(), N = p(() => {
16
+ let e = A.current;
17
17
  if (!e) return !1;
18
- let t = i({
19
- scene: m,
20
- view: D,
21
- width: h,
22
- height: g,
23
- drawOne: _,
24
- extraCommands: v,
25
- alphaFor: y,
26
- layerVisibility: b,
27
- layerOrder: x,
28
- colorOverrides: S?.colorOverrides,
29
- cull: T,
30
- paintBounds: E
18
+ let t = o({
19
+ scene: g,
20
+ view: k,
21
+ width: _,
22
+ height: v,
23
+ drawOne: y,
24
+ extraCommands: b,
25
+ alphaFor: x,
26
+ layerVisibility: S,
27
+ layerOrder: C,
28
+ colorOverrides: w?.colorOverrides,
29
+ cull: D,
30
+ paintBounds: O
31
31
  });
32
- return A(e, t, D, {
33
- width: h,
34
- height: g
35
- }), !0;
36
- }), { requestRedraw: M } = n(a(() => j.current(), [j])), N = c(!1);
37
- return s(() => {
38
- if (N.current) {
39
- M();
32
+ return M.paint(e, t, k, {
33
+ width: _,
34
+ height: v
35
+ });
36
+ }), { requestRedraw: P } = t(s(() => N.current(), [N]), { target: A }), F = u(!1);
37
+ return l(() => {
38
+ if (F.current) {
39
+ P();
40
40
  return;
41
41
  }
42
- N.current = j.current(), N.current || M();
43
- }), o(() => m.overrides.subscribe(M), [m, M]), o(() => S?.onTick(M), [S, M]), t(M), /* @__PURE__ */ f("canvas", {
44
- ref: k,
45
- width: h,
46
- height: g,
47
- className: C
42
+ F.current = N.current(), F.current || P();
43
+ }), c(() => g.overrides.subscribe(P), [g, P]), c(() => w?.onTick(P), [w, P]), n(P), a(M, P), i(P), c(() => () => {
44
+ F.current = !1;
45
+ }, []), /* @__PURE__ */ m("canvas", {
46
+ ref: j,
47
+ width: _,
48
+ height: v,
49
+ className: T
48
50
  });
49
51
  }
50
- var m = p;
52
+ var g = h;
51
53
  //#endregion
52
- export { m as SceneViewCanvas };
54
+ export { g as SceneViewCanvas };
53
55
 
54
56
  //# sourceMappingURL=SceneViewCanvas.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"SceneViewCanvas.js","names":["SceneViewCanvasInner","props","view","normalizeView","scene","localRef","useRef","setCanvasRef","useCallback","el","assignRef","canvasRef","paintCanvas","useCanvasRenderer","paintRef","useLatest","canvas","commands","sceneViewFrame","animator","useFrameLoop","paintedRef","useLayoutEffect","requestRedraw","useEffect","useLateContentRedraw","SceneViewCanvas"],"sources":["../../src/canvas/SceneViewCanvas.tsx"],"sourcesContent":["/**\n * `<SceneViewCanvas>` — pointer-inert, read-only render of a `Scene` at a\n * given `View` into its own `<canvas>` DOM element.\n *\n * The component:\n * - mounts its own `<canvas>`,\n * - subscribes to the scene via `useSyncExternalStore(scene.subscribe,\n * scene.getVersion)` so any scene mutation triggers a re-render,\n * - subscribes to `scene.overrides` as well, since override writes never\n * bump the scene version — without this the view would paint document\n * poses while `<SceneCanvas>` paints overridden ones,\n * - paints through `useFrameLoop` rather than from React, so both a render\n * (prop change or version bump) and an override commit just mark the\n * surface dirty and one `requestAnimationFrame` coalesces them. The mount\n * paint is synchronous so the first frame the user sees is the scene, not\n * a blank canvas,\n * - attaches **no** event listeners (consumers attach their own via\n * `canvasRef`),\n * - frees its renderer and every GL object it owns on unmount\n * (`useCanvasRenderer`).\n *\n * Sizing follows `<SceneCanvas>`'s convention: the consumer passes `width` /\n * `height` in CSS pixels. The HTML `width` / `height` attributes of the\n * `<canvas>` (drawing-buffer size) are set to `width × dpr` and `height × dpr`\n * by the canvas renderer (via the underlying renderer's `resize`). The CSS\n * size — what the consumer sees on screen — is managed via the `className`\n * prop; no inline styles are emitted (per project rules).\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport type { Ref } from 'react';\nimport { assignRef, useLatest } from '@weasel-js/react';\nimport { useFrameLoop } from './useFrameLoop';\nimport { useLateContentRedraw } from './useLateContentRedraw';\nimport { useCanvasRenderer } from './useCanvasRenderer';\nimport { sceneViewFrame } from './sceneViewRender';\nimport type { RenderSceneToCanvasArgs, SceneViewDrawOne, SceneViewLayers } from './sceneViewRender';\nimport type { DrawCommand } from '../renderer/DrawCommand';\nimport { normalizeView, type View } from '../core/viewport/view';\nimport type { Scene } from '../core/scene/types';\nimport type { Animator } from '../animation/types';\n\n/** Props for `<SceneViewCanvas>`. */\nexport interface SceneViewCanvasProps<TData, TLayer extends string, TPose> {\n /** Scene to render. Must be the same `Scene` instance passed to whoever\n * is mutating it; the component subscribes to its version stream and\n * repaints when the version advances. */\n scene: Scene<TData, TLayer, TPose>;\n /** Camera. Applied to scene + `extraCommands` via the renderer's group\n * transform. */\n view: View;\n /** CSS-pixel width. Drives both layout (via the rendered drawing-buffer\n * size) and the renderer's coordinate space. */\n width: number;\n /** CSS-pixel height. */\n height: number;\n /** Per-node draw callback. See `SceneViewDrawOne`. The consumer is\n * responsible for what gets painted — there is no AABB-fill default. */\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Optional extra commands appended after scene commands, inside the same\n * view transform. Used by `<MinimapCanvas>` for its visible-window\n * indicator; available to other consumers that want to overlay a\n * world-space annotation. */\n extraCommands?: ReadonlyArray<DrawCommand>;\n /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Pass the same function the main canvas uses to keep a\n * scoping-dim treatment consistent across both. Defaults to `() => 1`. */\n alphaFor?: (id: string) => number;\n /** Hide scene layers in this view only, keyed `scene:<layerId>` as on\n * `<SceneCanvas>` — pass the main canvas's map to keep the two in step. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Paint order for this view, keyed as `layerVisibility`. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Skip nodes and commands that cannot reach this view — the scene slot's\n * `cull`. Off by default; worth it when the view shows a small part of a\n * large scene. */\n cull?: boolean;\n /** Where `drawOne`'s output for a node can reach — the scene slot's\n * `paintBounds`. Defaults to `defaultPaintBounds` when `drawOne` is\n * `defaultDrawOne`. */\n paintBounds?: RenderSceneToCanvasArgs<TData, TLayer, TPose>['paintBounds'];\n /** Optional animator, as on `<SceneCanvas>`: the view repaints on its ticks\n * and paints its `colorOverrides`. Pass the main canvas's animator so both\n * show the same colors. */\n animator?: Animator;\n /** Optional CSS class for sizing / positioning the `<canvas>`. The kit\n * does not emit inline styles for layout — use a class. */\n className?: string;\n /** Forwarded ref to the underlying `<canvas>`. Consumers attach their own\n * pointer listeners or call `toBlob` for snapshots through this. */\n canvasRef?: Ref<HTMLCanvasElement>;\n}\n\nfunction SceneViewCanvasInner<TData, TLayer extends string, TPose>(\n props: SceneViewCanvasProps<TData, TLayer, TPose>,\n) {\n const {\n scene, width, height, drawOne, extraCommands, alphaFor, layerVisibility, layerOrder,\n animator, className, canvasRef, cull, paintBounds,\n } = props;\n const view = normalizeView(props.view);\n\n // Subscribe to scene version. The snapshot value isn't used directly —\n // we only need React to re-render the component when the scene mutates.\n useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);\n\n const localRef = useRef<HTMLCanvasElement | null>(null);\n\n const setCanvasRef = useCallback((el: HTMLCanvasElement | null): void => {\n localRef.current = el;\n assignRef(canvasRef, el);\n }, [canvasRef]);\n\n // The frame loop paints, not React — so an override commit can repaint\n // without a render. The thunk defers to `paintRef`, which every committed\n // render republishes from an insertion effect — ahead of the layout effect\n // below, and never from a render React abandoned.\n const { paint: paintCanvas } = useCanvasRenderer();\n const paint = (): boolean => {\n const canvas = localRef.current;\n if (!canvas) return false;\n const commands = sceneViewFrame({\n scene,\n view,\n width,\n height,\n drawOne,\n extraCommands: extraCommands as DrawCommand[] | undefined,\n alphaFor,\n layerVisibility,\n layerOrder,\n colorOverrides: animator?.colorOverrides,\n cull,\n paintBounds,\n });\n paintCanvas(canvas, commands, view, { width, height });\n return true;\n };\n const paintRef = useLatest(paint);\n\n const { requestRedraw } = useFrameLoop(useCallback(() => paintRef.current(), [paintRef]));\n\n // Every render — a prop change or a scene-version bump — marks the surface\n // dirty. No dependency array: the paint reads all of them.\n //\n // The mount paint is the exception: it runs here, in the caller's stack, so\n // the first frame the user sees is the scene rather than a blank canvas.\n const paintedRef = useRef(false);\n useLayoutEffect(() => {\n if (paintedRef.current) { requestRedraw(); return; }\n paintedRef.current = paintRef.current();\n if (!paintedRef.current) requestRedraw();\n });\n\n // Override writes never bump the scene version, so the version subscription\n // above cannot see them.\n useEffect(() => scene.overrides.subscribe(requestRedraw), [scene, requestRedraw]);\n useEffect(() => animator?.onTick(requestRedraw), [animator, requestRedraw]);\n useLateContentRedraw(requestRedraw);\n\n return (\n <canvas\n ref={setCanvasRef}\n width={width}\n height={height}\n className={className}\n />\n );\n}\n\n/**\n * Pointer-inert read-only scene view. See `SceneViewCanvasProps` for the\n * full surface and the module docstring for the rendering model.\n *\n * `forwardRef` is not used because the component is generic over `<TData,\n * TLayer, TPose>` and React's `forwardRef` erases generics. The\n * `canvasRef` prop is the plain-prop equivalent (the spec calls it out as\n * the public surface).\n */\nexport const SceneViewCanvas = SceneViewCanvasInner;\n"],"mappings":";;;;;;;;;AAkGA,SAASA,EACP,GACA;CACA,IAAM,EACJ,UAAO,UAAO,WAAQ,YAAS,kBAAe,aAAU,oBAAiB,eACzE,aAAU,cAAW,cAAW,SAAM,mBACpCC,GACEC,IAAOC,EAAcF,EAAM,IAAI;CAIrC,EAAqBG,EAAM,WAAWA,EAAM,YAAYA,EAAM,UAAU;CAExE,IAAMC,IAAWC,EAAiC,IAAI,GAEhDC,IAAeC,GAAa,MAAuC;EAEvE,AADA,EAAS,UAAUC,GACnBC,EAAUC,GAAWF,CAAE;CACzB,GAAG,CAACE,CAAS,CAAC,GAMR,EAAE,OAAOC,MAAgBC,EAAkB,GAqB3CC,IAAWC,QApBY;EAC3B,IAAMC,IAASX,EAAS;EACxB,IAAI,CAACW,GAAQ,OAAO;EACpB,IAAMC,IAAWC,EAAe;GAC9B;GACA;GACA;GACA;GACA;GACe;GACf;GACA;GACA;GACA,gBAAgBC,GAAU;GAC1B;GACA;EACF,CAAC;EAED,OADAP,EAAYI,GAAQC,GAAUf,GAAM;GAAE;GAAO;EAAO,CAAC,GAC9C;CACT,CACgC,GAE1B,EAAE,qBAAkBkB,EAAaZ,QAAkBM,EAAS,QAAQ,GAAG,CAACA,CAAQ,CAAC,CAAC,GAOlFO,IAAaf,EAAO,EAAK;CAa/B,OAZAgB,QAAsB;EACpB,IAAID,EAAW,SAAS;GAAE,EAAc;GAAG;EAAQ;EAEnD,AADA,EAAW,UAAUP,EAAS,QAAQ,GACjCO,EAAW,WAASE,EAAc;CACzC,CAAC,GAIDC,QAAgBpB,EAAM,UAAU,UAAUmB,CAAa,GAAG,CAACnB,GAAOmB,CAAa,CAAC,GAChFC,QAAgBL,GAAU,OAAOI,CAAa,GAAG,CAACJ,GAAUI,CAAa,CAAC,GAC1EE,EAAqBF,CAAa,GAGhC,kBAAC,UAAD;EACE,KAAKhB;EACE;EACC;EACG;CACZ,CAAA;AAEL;AAWA,IAAamB,IAAkB1B"}
1
+ {"version":3,"file":"SceneViewCanvas.js","names":["SceneViewCanvasInner","props","view","normalizeView","scene","localRef","useRef","setCanvasRef","useCallback","el","assignRef","canvasRef","lease","useCanvasRenderer","paintRef","useLatest","canvas","commands","sceneViewFrame","animator","useFrameLoop","paintedRef","useLayoutEffect","requestRedraw","useEffect","useLateContentRedraw","useRedrawOnRestore","useRedrawOnDensityChange","SceneViewCanvas"],"sources":["../../src/canvas/SceneViewCanvas.tsx"],"sourcesContent":["/**\n * `<SceneViewCanvas>` — pointer-inert, read-only render of a `Scene` at a\n * given `View` into its own `<canvas>` DOM element.\n *\n * The component:\n * - mounts its own `<canvas>`,\n * - subscribes to the scene via `useSyncExternalStore(scene.subscribe,\n * scene.getVersion)` so any scene mutation triggers a re-render,\n * - subscribes to `scene.overrides` as well, since override writes never\n * bump the scene version — without this the view would paint document\n * poses while `<SceneCanvas>` paints overridden ones,\n * - paints through `useFrameLoop` rather than from React, so both a render\n * (prop change or version bump) and an override commit just mark the\n * surface dirty and one `requestAnimationFrame` coalesces them. The mount\n * paint is synchronous so the first frame the user sees is the scene, not\n * a blank canvas, and nothing paints while the canvas is off screen or the\n * tab is hidden,\n * - attaches **no** event listeners (consumers attach their own via\n * `canvasRef`),\n * - frees its renderer and every GL object it owns on unmount\n * (`useCanvasRenderer`).\n *\n * Sizing follows `<SceneCanvas>`'s convention: the consumer passes `width` /\n * `height` in CSS pixels. The HTML `width` / `height` attributes of the\n * `<canvas>` (drawing-buffer size) are set to `width × dpr` and `height × dpr`\n * by the canvas renderer (via the underlying renderer's `resize`), which also\n * writes the element's inline `width` and `height` style in CSS pixels. That\n * beats a size set through `className`, so the class positions the canvas and\n * the `width` / `height` props size it.\n */\nimport {\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n useSyncExternalStore,\n} from 'react';\nimport type { Ref } from 'react';\nimport { assignRef, useLatest } from '@weasel-js/react';\nimport { useFrameLoop } from './useFrameLoop';\nimport { useLateContentRedraw } from './useLateContentRedraw';\nimport { useCanvasRenderer, useRedrawOnDensityChange, useRedrawOnRestore } from './useCanvasRenderer';\nimport { sceneViewFrame } from './sceneViewRender';\nimport type { RenderSceneToCanvasArgs, SceneViewDrawOne, SceneViewLayers } from './sceneViewRender';\nimport type { DrawCommand } from '../renderer/DrawCommand';\nimport { normalizeView, type View } from '../core/viewport/view';\nimport type { Scene } from '../core/scene/types';\nimport type { Animator } from '../animation/types';\n\n/** Props for `<SceneViewCanvas>`. */\nexport interface SceneViewCanvasProps<TData, TLayer extends string, TPose> {\n /** Scene to render. Must be the same `Scene` instance passed to whoever\n * is mutating it; the component subscribes to its version stream and\n * repaints when the version advances. */\n scene: Scene<TData, TLayer, TPose>;\n /** Camera. Applied to scene + `extraCommands` via the renderer's group\n * transform. */\n view: View;\n /** CSS-pixel width. Drives both layout (via the rendered drawing-buffer\n * size) and the renderer's coordinate space. */\n width: number;\n /** CSS-pixel height. */\n height: number;\n /** Per-node draw callback. See `SceneViewDrawOne`. The consumer is\n * responsible for what gets painted — there is no AABB-fill default. */\n drawOne: SceneViewDrawOne<TData, TLayer, TPose>;\n /** Optional extra commands appended after scene commands, inside the same\n * view transform. Used by `<MinimapCanvas>` for its visible-window\n * indicator; available to other consumers that want to overlay a\n * world-space annotation. */\n extraCommands?: ReadonlyArray<DrawCommand>;\n /** Optional per-id alpha multiplier, mirroring `<SceneCanvas>`'s scene-slot\n * `alphaFor`. Pass the same function the main canvas uses to keep a\n * scoping-dim treatment consistent across both. Defaults to `() => 1`. */\n alphaFor?: (id: string) => number;\n /** Hide scene layers in this view only, keyed `scene:<layerId>` as on\n * `<SceneCanvas>` — pass the main canvas's map to keep the two in step. */\n layerVisibility?: SceneViewLayers['layerVisibility'];\n /** Paint order for this view, keyed as `layerVisibility`. */\n layerOrder?: SceneViewLayers['layerOrder'];\n /** Skip nodes and commands that cannot reach this view — the scene slot's\n * `cull`. Off by default; worth it when the view shows a small part of a\n * large scene. */\n cull?: boolean;\n /** Where `drawOne`'s output for a node can reach — the scene slot's\n * `paintBounds`. Defaults to `defaultPaintBounds` when `drawOne` is\n * `defaultDrawOne`. */\n paintBounds?: RenderSceneToCanvasArgs<TData, TLayer, TPose>['paintBounds'];\n /** Optional animator, as on `<SceneCanvas>`: the view repaints on its ticks\n * and paints its `colorOverrides`. Pass the main canvas's animator so both\n * show the same colors. */\n animator?: Animator;\n /** Optional CSS class for positioning the `<canvas>`. Its size is `width` ×\n * `height`, which the renderer writes as inline style. */\n className?: string;\n /** Forwarded ref to the underlying `<canvas>`. Consumers attach their own\n * pointer listeners or call `toBlob` for snapshots through this. */\n canvasRef?: Ref<HTMLCanvasElement>;\n}\n\nfunction SceneViewCanvasInner<TData, TLayer extends string, TPose>(\n props: SceneViewCanvasProps<TData, TLayer, TPose>,\n) {\n const {\n scene, width, height, drawOne, extraCommands, alphaFor, layerVisibility, layerOrder,\n animator, className, canvasRef, cull, paintBounds,\n } = props;\n const view = normalizeView(props.view);\n\n // Subscribe to scene version. The snapshot value isn't used directly —\n // we only need React to re-render the component when the scene mutates.\n useSyncExternalStore(scene.subscribe, scene.getVersion, scene.getVersion);\n\n const localRef = useRef<HTMLCanvasElement | null>(null);\n\n const setCanvasRef = useCallback((el: HTMLCanvasElement | null): void => {\n localRef.current = el;\n assignRef(canvasRef, el);\n }, [canvasRef]);\n\n // The frame loop paints, not React — so an override commit can repaint\n // without a render. The thunk defers to `paintRef`, which every committed\n // render republishes from an insertion effect — ahead of the layout effect\n // below, and never from a render React abandoned.\n const lease = useCanvasRenderer();\n const paint = (): boolean => {\n const canvas = localRef.current;\n if (!canvas) return false;\n const commands = sceneViewFrame({\n scene,\n view,\n width,\n height,\n drawOne,\n extraCommands: extraCommands as DrawCommand[] | undefined,\n alphaFor,\n layerVisibility,\n layerOrder,\n colorOverrides: animator?.colorOverrides,\n cull,\n paintBounds,\n });\n return lease.paint(canvas, commands, view, { width, height });\n };\n const paintRef = useLatest(paint);\n\n const { requestRedraw } = useFrameLoop(\n useCallback(() => paintRef.current(), [paintRef]),\n { target: localRef },\n );\n\n // Every render — a prop change or a scene-version bump — marks the surface\n // dirty. No dependency array: the paint reads all of them.\n //\n // The mount paint is the exception: it runs here, in the caller's stack, so\n // the first frame the user sees is the scene rather than a blank canvas.\n const paintedRef = useRef(false);\n useLayoutEffect(() => {\n if (paintedRef.current) { requestRedraw(); return; }\n paintedRef.current = paintRef.current();\n if (!paintedRef.current) requestRedraw();\n });\n\n // Override writes never bump the scene version, so the version subscription\n // above cannot see them.\n useEffect(() => scene.overrides.subscribe(requestRedraw), [scene, requestRedraw]);\n useEffect(() => animator?.onTick(requestRedraw), [animator, requestRedraw]);\n useLateContentRedraw(requestRedraw);\n useRedrawOnRestore(lease, requestRedraw);\n useRedrawOnDensityChange(requestRedraw);\n\n // A remount (StrictMode) paints its first frame in place again.\n useEffect(() => () => { paintedRef.current = false; }, []);\n\n return (\n <canvas\n ref={setCanvasRef}\n width={width}\n height={height}\n className={className}\n />\n );\n}\n\n/**\n * Pointer-inert read-only scene view. See `SceneViewCanvasProps` for the\n * full surface and the module docstring for the rendering model.\n *\n * `forwardRef` is not used because the component is generic over `<TData,\n * TLayer, TPose>` and React's `forwardRef` erases generics. The\n * `canvasRef` prop is the plain-prop equivalent (the spec calls it out as\n * the public surface).\n */\nexport const SceneViewCanvas = SceneViewCanvasInner;\n"],"mappings":";;;;;;;;;AAoGA,SAASA,EACP,GACA;CACA,IAAM,EACJ,UAAO,UAAO,WAAQ,YAAS,kBAAe,aAAU,oBAAiB,eACzE,aAAU,cAAW,cAAW,SAAM,mBACpCC,GACEC,IAAOC,EAAcF,EAAM,IAAI;CAIrC,EAAqBG,EAAM,WAAWA,EAAM,YAAYA,EAAM,UAAU;CAExE,IAAMC,IAAWC,EAAiC,IAAI,GAEhDC,IAAeC,GAAa,MAAuC;EAEvE,AADA,EAAS,UAAUC,GACnBC,EAAUC,GAAWF,CAAE;CACzB,GAAG,CAACE,CAAS,CAAC,GAMRC,IAAQC,EAAkB,GAoB1BC,IAAWC,QAnBY;EAC3B,IAAMC,IAASX,EAAS;EACxB,IAAI,CAACW,GAAQ,OAAO;EACpB,IAAMC,IAAWC,EAAe;GAC9B;GACA;GACA;GACA;GACA;GACe;GACf;GACA;GACA;GACA,gBAAgBC,GAAU;GAC1B;GACA;EACF,CAAC;EACD,OAAOP,EAAM,MAAMI,GAAQC,GAAUf,GAAM;GAAE;GAAO;EAAO,CAAC;CAC9D,CACgC,GAE1B,EAAE,qBAAkBkB,EACxBZ,QAAkBM,EAAS,QAAQ,GAAG,CAACA,CAAQ,CAAC,GAChD,EAAE,QAAQT,EAAS,CACrB,GAOMgB,IAAaf,EAAO,EAAK;CAkB/B,OAjBAgB,QAAsB;EACpB,IAAID,EAAW,SAAS;GAAE,EAAc;GAAG;EAAQ;EAEnD,AADA,EAAW,UAAUP,EAAS,QAAQ,GACjCO,EAAW,WAASE,EAAc;CACzC,CAAC,GAIDC,QAAgBpB,EAAM,UAAU,UAAUmB,CAAa,GAAG,CAACnB,GAAOmB,CAAa,CAAC,GAChFC,QAAgBL,GAAU,OAAOI,CAAa,GAAG,CAACJ,GAAUI,CAAa,CAAC,GAC1EE,EAAqBF,CAAa,GAClCG,EAAmBd,GAAOW,CAAa,GACvCI,EAAyBJ,CAAa,GAGtCC,cAAsB;EAAE,EAAW,UAAU;CAAO,GAAG,CAAC,CAAC,GAGvD,kBAAC,UAAD;EACE,KAAKjB;EACE;EACC;EACG;CACZ,CAAA;AAEL;AAWA,IAAaqB,IAAkB5B"}
@@ -0,0 +1,91 @@
1
+ import { viewToMat3 as e } from "../renderer/math/viewToMat3.js";
2
+ import { cullDrawCommands as t } from "../renderer/cullDrawCommands.js";
3
+ import { sceneLayerKey as n } from "./sceneLayerPaint.js";
4
+ import { wrapNodeOutput as r } from "./wrapNodeOutput.js";
5
+ import { buildSceneTree as i } from "./buildSceneTree.js";
6
+ import { paintMissesView as a } from "./paintCull.js";
7
+ //#region src/canvas/buildSceneLayer.ts
8
+ function o(n, o, s, c, l, u) {
9
+ let d = n.toPose ?? ((e) => o ? o.getPose(e.id) : e), f = n.drawOne, p = n.postProcess, m = n.cull ? (n, r, i) => t(n, e(r), {
10
+ x: 0,
11
+ y: 0,
12
+ width: i.width,
13
+ height: i.height
14
+ }) : (e) => e, h = n.cull ? n.paintBounds : void 0, g = (e, t) => h ? a(h, e, {
15
+ x: 0,
16
+ y: 0,
17
+ width: t.width,
18
+ height: t.height
19
+ }) : void 0;
20
+ return {
21
+ id: u?.id ?? "scene",
22
+ label: u ? `Scene: ${u.forLayer}` : "Scene",
23
+ draw: (e, t, a) => {
24
+ let h = l(), _ = o;
25
+ if (_ && n.objects === void 0 && typeof _.getLayers == "function" && typeof _.getNode == "function" && typeof _.getChildren == "function" && f) {
26
+ let e = (e, t, i) => {
27
+ if (h && h.has(e.id)) return [];
28
+ let a = f(e, t, i);
29
+ if (s) {
30
+ let n = c ? c(e.id) : null;
31
+ n && s.recordBounds(e.id, n);
32
+ let r = t.x ?? (n ? n.x : 0), i = t.y ?? (n ? n.y : 0);
33
+ s.recordOrigin(e.id, {
34
+ x: r,
35
+ y: i
36
+ });
37
+ }
38
+ return r(a, t, n.alphaFor ? n.alphaFor(e.id) : 1);
39
+ }, o = n.toPose ? {
40
+ ..._,
41
+ getPose: (e) => {
42
+ let t = _.getNode(e);
43
+ return t ? d(t) : _.getPose(e);
44
+ }
45
+ } : _, l = i(o, e, t, u?.forLayer, n.derivedPathOf, g(t, a));
46
+ return m(p ? p(l, t, a) : l, t, a);
47
+ }
48
+ let v = n.objects ?? o?.getNodes() ?? [], y = [], b = g(t, a);
49
+ for (let e of v) {
50
+ if (h && h.has(e.id)) continue;
51
+ let i = d(e);
52
+ if (f && !b?.(e, i)) {
53
+ let a = f(e, i, t), o = r(a, i, n.alphaFor ? n.alphaFor(e.id) : 1);
54
+ for (let e of o) y.push(e);
55
+ }
56
+ if (s) {
57
+ let t = c ? c(e.id) : null;
58
+ t && s.recordBounds(e.id, {
59
+ x: t.x,
60
+ y: t.y,
61
+ width: t.width,
62
+ height: t.height
63
+ });
64
+ let n = i.x ?? (t ? t.x : 0), r = i.y ?? (t ? t.y : 0);
65
+ s.recordOrigin(e.id, {
66
+ x: n,
67
+ y: r
68
+ });
69
+ }
70
+ }
71
+ return m(p ? p(y, t, a) : y, t, a);
72
+ }
73
+ };
74
+ }
75
+ function s(e, t, r, i, a) {
76
+ let s = e.objects === void 0 && typeof t?.getLayers == "function" ? t.getLayers().map((e) => e.id) : null;
77
+ return !s || s.length === 0 ? [{
78
+ key: "scene",
79
+ layer: o(e, t, r, i, a)
80
+ }] : s.map((s) => ({
81
+ key: n(s),
82
+ layer: o(e, t, r, i, a, {
83
+ id: n(s),
84
+ forLayer: s
85
+ })
86
+ }));
87
+ }
88
+ //#endregion
89
+ export { o as buildSceneLayer, s as buildSceneLayers };
90
+
91
+ //# sourceMappingURL=buildSceneLayer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildSceneLayer.js","names":["buildSceneLayer","toPose","cfg","adapter","obj","drawOne","postProcess","finish","cullDrawCommands","cmds","viewToMat3","view","dims","paintBounds","culledIn","paintMissesView","slot","hidden","hideIds","a","filteredDrawOne","pose","v","debugSink","b","boundsOfFn","ox","oy","wrapNodeOutput","hierarchicalAdapter","id","tree","buildSceneTree","objects","children","culled","wrapped","cmd","buildSceneLayers","sceneLayerIds","l","sceneLayerKey"],"sources":["../../src/canvas/buildSceneLayer.ts"],"sourcesContent":["/**\n * The scene slot: how `<Canvas>` turns an adapter's nodes into render layers.\n * One layer for a flat adapter, one per scene layer for a hierarchical one.\n */\nimport type { Path } from '@weasel-js/geom';\nimport type { MoveAdapter, ResizeAdapter, RotateAdapter } from 'core/adapters/types';\nimport type { Dims, RenderLayer } from 'core/layers/render';\nimport type { Bounds } from 'core/viewport/fitViewToBounds';\nimport type { View } from 'core/viewport/view';\nimport type { DebugSink } from '../debug/types';\nimport { cullDrawCommands, viewToMat3, type DrawCommand } from '../renderer';\nimport { buildSceneTree, type HierarchicalAdapter } from './buildSceneTree';\nimport type { NodePaintCtx } from './NodeShape';\nimport { paintMissesView, type PaintBoundsFn } from './paintCull';\nimport { sceneLayerKey } from './sceneLayerPaint';\nimport { wrapNodeOutput } from './wrapNodeOutput';\n\n/**\n * The scene-tree reading methods Canvas feature-detects at draw time, as an\n * *optional* mixin. A `SceneCanvasAdapter` supplies them; flat / bare-Canvas\n * adapters don't. `getPose` already lives on the base move adapter, so only the\n * three tree-walk methods are added here.\n */\ntype OptionalSceneHierarchy<TNode, TPose> = Partial<\n Pick<HierarchicalAdapter<TNode, TPose>, 'getLayers' | 'getNode' | 'getChildren'>\n>;\n\n/** The full adapter shape Canvas threads through layers + gesture hooks: the\n * move/resize/rotate intersection plus the optional scene-tree methods. */\nexport type CanvasAdapter<TNode extends { id: string }, TPose> = MoveAdapter<TNode, TPose> &\n ResizeAdapter<TNode, TPose> &\n RotateAdapter<TNode, TPose> &\n OptionalSceneHierarchy<TNode, TPose>;\n\n/** Scene slot config — describes how to draw one object with its effective pose. */\nexport interface SceneSlotConfig<TNode extends { id: string }, TPose> {\n /** Override `adapter.getNodes()` for the object iteration. */\n objects?: TNode[];\n /** Project an object to its committed pose. Defaults to `adapter.getPose(obj.id)`. */\n toPose?: (obj: TNode) => TPose;\n /** Draw a single object as a `DrawCommand` tree. `ctx` carries what only a\n * scene-aware caller can supply (a node's derived path); `<SceneCanvas>`\n * fills it in, bare `<Canvas>` never does. */\n drawOne: (obj: TNode, pose: TPose, view: View, ctx?: NodePaintCtx) => DrawCommand[];\n /** The path a container derives from its dependencies' poses, for the clip\n * it imposes on its subtree. The other half of what only a scene-aware\n * caller can supply — `drawOne`'s `ctx` carries the derived path a node\n * *paints*, this one the clip it *imposes*. */\n derivedPathOf?: (obj: TNode, pose: TPose) => Path | null;\n /** Default ghost alpha for the move-overlay slot. Default 0.85. */\n ghostAlpha?: number;\n /**\n * Optional per-id alpha multiplier. When supplied, each node's emitted\n * `DrawCommand[]` is wrapped in a `{ kind: 'group', alpha }` when the\n * returned value is not 1. The scoping-dim integration supplies this to\n * dim non-active nodes during a mode transition.\n *\n * Defaults to `() => 1` (no effect).\n */\n alphaFor?: (id: string) => number;\n /**\n * Optional post-processor for the scene slot's emitted commands. Called\n * with the final world-space `DrawCommand[]` each time a scene canvas\n * layer draws (after per-node rotation wrapping and `alphaFor`); the\n * return value replaces the array handed to the renderer. When the scene\n * slot is split into per-scene-layer canvas layers (`scene:<layerId>`),\n * it runs once per layer. Identity by default.\n *\n * Commands are world-space — `drawLayers` applies the view transform\n * afterward, so e.g. a `clip` path in a wrapping group is authored in\n * world coordinates. Note clip nesting is capped at 7 levels; a wrapping\n * group with `clip` consumes one.\n *\n * The move-overlay ghost (drag preview) is not post-processed.\n */\n postProcess?: (cmds: DrawCommand[], view: View, dims: Dims) => DrawCommand[];\n /**\n * Skip what cannot reach the view. A node `paintBounds` places outside the\n * `dims` rectangle under `view` is not painted at all; then, after\n * `postProcess`, `cullDrawCommands` drops any remaining command that cannot\n * reach it — see there for what it can and cannot bound. So `postProcess`\n * sees an empty group where a culled node would have painted.\n *\n * Off by default because it makes the layer's world-space output depend on\n * the view: anything that draws this layer once and shows the result under\n * another view — a cache keyed without `view`, a consumer re-wrapping the\n * commands — would show the first view's cull.\n */\n cull?: boolean;\n /**\n * Where `drawOne`'s output for a node can reach, in the frame it paints in\n * — before the pose rotation the slot wraps it in. `null` for a node it\n * cannot bound cheaply. Read only under `cull`, which skips `drawOne` for a\n * node whose box misses the view, so it must enclose everything `drawOne`\n * paints: a box too small makes a node vanish before it leaves the screen.\n *\n * `<SceneCanvas>` supplies `defaultPaintBounds` while `drawOne` is\n * `defaultDrawOne`. Omit it with any other `drawOne` and culling only\n * trims commands after painting.\n */\n paintBounds?: PaintBoundsFn<TNode, TPose>;\n}\n\n/**\n * Build the scene layer. Tool ghosts (in-flight drag/resize/rotate poses) are\n * published via the active tool's `previewPose`/`previewIds` and rendered on\n * top of this layer (see SceneCanvas's preview-ghost layer); we draw committed\n * poses here, and `hideIds()` lets us skip the committed paint of ids the\n * active tool is currently ghosting so the source doesn't show through.\n */\nexport function buildSceneLayer<TNode extends { id: string }, TPose>(\n cfg: SceneSlotConfig<TNode, TPose>,\n adapter: CanvasAdapter<TNode, TPose> | undefined,\n debugSink: DebugSink | null,\n boundsOfFn: ((id: string) => Bounds | null) | undefined,\n hideIds: () => Set<string> | null,\n /** When set, the returned layer carries this `id` and paints ONLY the named\n * scene layer (the rest are walked for ancestor clips). Used to split the\n * scene slot into per-scene-layer, individually-orderable canvas layers\n * (`scene:<layerId>`) so consumers can interleave custom layers between\n * them. Omit for the single bundled `scene` layer. */\n slot?: { id: string; forLayer: string },\n): RenderLayer<unknown> {\n const toPose =\n cfg.toPose ??\n ((obj: TNode) => (adapter ? adapter.getPose(obj.id) : (obj as unknown as TPose)));\n const drawOne = cfg.drawOne;\n const postProcess = cfg.postProcess;\n const finish = cfg.cull\n ? (cmds: DrawCommand[], view: View, dims: Dims): DrawCommand[] =>\n cullDrawCommands(cmds, viewToMat3(view), { x: 0, y: 0, width: dims.width, height: dims.height })\n : (cmds: DrawCommand[]): DrawCommand[] => cmds;\n const paintBounds = cfg.cull ? cfg.paintBounds : undefined;\n const culledIn = (view: View, dims: Dims) => paintBounds\n ? paintMissesView(paintBounds, view, { x: 0, y: 0, width: dims.width, height: dims.height })\n : undefined;\n return {\n id: slot?.id ?? 'scene',\n label: slot ? `Scene: ${slot.forLayer}` : 'Scene',\n draw: (_data, view, dims) => {\n const hidden = hideIds();\n const a = adapter;\n if (\n a &&\n cfg.objects === undefined &&\n typeof a.getLayers === 'function' &&\n typeof a.getNode === 'function' &&\n typeof a.getChildren === 'function' &&\n drawOne\n ) {\n const filteredDrawOne = (obj: TNode, pose: TPose, v: View): DrawCommand[] => {\n if (hidden && hidden.has(obj.id)) return [];\n const cmds = drawOne(obj, pose, v);\n if (debugSink) {\n const b = boundsOfFn ? boundsOfFn(obj.id) : null;\n if (b) debugSink.recordBounds(obj.id, b);\n const ox = (pose as { x?: number }).x ?? (b ? b.x : 0);\n const oy = (pose as { y?: number }).y ?? (b ? b.y : 0);\n debugSink.recordOrigin(obj.id, { x: ox, y: oy });\n }\n return wrapNodeOutput(cmds, pose, cfg.alphaFor ? cfg.alphaFor(obj.id) : 1);\n };\n // Honor cfg.toPose on the hierarchical path by shimming getPose on the\n // adapter so buildSceneTree routes through it instead of the raw adapter.\n const hierarchicalAdapter = cfg.toPose\n ? {\n ...a,\n getPose: (id: string) => {\n const obj = a.getNode!(id);\n return obj ? toPose(obj) : a.getPose(id);\n },\n }\n : a;\n // World-space commands; drawLayers wraps in viewToMat3 automatically.\n const tree = buildSceneTree(\n hierarchicalAdapter as Parameters<typeof buildSceneTree>[0],\n filteredDrawOne as unknown as Parameters<typeof buildSceneTree>[1],\n view,\n slot?.forLayer,\n cfg.derivedPathOf as Parameters<typeof buildSceneTree>[4],\n culledIn(view, dims) as Parameters<typeof buildSceneTree>[5],\n );\n return finish(postProcess ? postProcess(tree, view, dims) : tree, view, dims);\n }\n // Flat fallback — keep existing body verbatim. (Per-layer slotting only\n // applies on the hierarchical path; a flat adapter has no scene layers,\n // so the `scene:<layer>` split is a no-op and we emit the whole scene.)\n const objects = cfg.objects ?? adapter?.getNodes() ?? [];\n const children: DrawCommand[] = [];\n const culled = culledIn(view, dims);\n for (const obj of objects) {\n if (hidden && hidden.has(obj.id)) continue;\n const pose: TPose = toPose(obj);\n if (drawOne && !culled?.(obj, pose)) {\n const cmds = drawOne(obj, pose, view);\n const wrapped = wrapNodeOutput(cmds, pose, cfg.alphaFor ? cfg.alphaFor(obj.id) : 1);\n for (const cmd of wrapped) children.push(cmd);\n }\n if (debugSink) {\n const b = boundsOfFn ? boundsOfFn(obj.id) : null;\n if (b) debugSink.recordBounds(obj.id, { x: b.x, y: b.y, width: b.width, height: b.height });\n const ox = (pose as { x?: number }).x ?? (b ? b.x : 0);\n const oy = (pose as { y?: number }).y ?? (b ? b.y : 0);\n debugSink.recordOrigin(obj.id, { x: ox, y: oy });\n }\n }\n // World-space commands; drawLayers wraps in viewToMat3 automatically.\n return finish(postProcess ? postProcess(children, view, dims) : children, view, dims);\n },\n };\n}\n\n/**\n * Build the scene slot as one canvas layer **per scene layer** — keyed\n * `scene:<layerId>` — when the adapter is hierarchical (exposes `getLayers`).\n * This lets consumers interleave custom layers *between* scene layers via the\n * standard slot anchoring (`before: 'scene:plantings'`). Each per-layer canvas\n * layer re-runs the scene walk for its own layer only (others are still walked\n * for ancestor clips). Falls back to a single `scene` layer for flat adapters\n * or adapters with no declared layers.\n */\nexport function buildSceneLayers<TNode extends { id: string }, TPose>(\n cfg: SceneSlotConfig<TNode, TPose>,\n adapter: CanvasAdapter<TNode, TPose> | undefined,\n debugSink: DebugSink | null,\n boundsOfFn: ((id: string) => Bounds | null) | undefined,\n hideIds: () => Set<string> | null,\n): Array<{ key: string; layer: RenderLayer<unknown> }> {\n const sceneLayerIds =\n cfg.objects === undefined && typeof adapter?.getLayers === 'function'\n ? adapter.getLayers().map((l) => l.id)\n : null;\n if (!sceneLayerIds || sceneLayerIds.length === 0) {\n return [{ key: 'scene', layer: buildSceneLayer(cfg, adapter, debugSink, boundsOfFn, hideIds) }];\n }\n return sceneLayerIds.map((id) => ({\n key: sceneLayerKey(id),\n layer: buildSceneLayer(cfg, adapter, debugSink, boundsOfFn, hideIds, {\n id: sceneLayerKey(id),\n forLayer: id,\n }),\n }));\n}\n"],"mappings":";;;;;;;AA8GA,SAAgBA,EACd,GACA,GACA,GACA,GACA,GAMA,GACsB;CACtB,IAAMC,IACJC,EAAI,YACF,MAAgBC,IAAUA,EAAQ,QAAQC,EAAI,EAAE,IAAKA,IACnDC,IAAUH,EAAI,SACdI,IAAcJ,EAAI,aAClBK,IAASL,EAAI,QACd,GAAqB,GAAY,MAClCM,EAAiBC,GAAMC,EAAWC,CAAI,GAAG;EAAE,GAAG;EAAG,GAAG;EAAG,OAAOC,EAAK;EAAO,QAAQA,EAAK;CAAO,CAAC,KAC9F,MAAuCH,GACtCI,IAAcX,EAAI,OAAOA,EAAI,cAAc,KAAA,GAC3CY,KAAY,GAAY,MAAeD,IACzCE,EAAgBF,GAAaF,GAAM;EAAE,GAAG;EAAG,GAAG;EAAG,OAAOC,EAAK;EAAO,QAAQA,EAAK;CAAO,CAAC,IACzF,KAAA;CACJ,OAAO;EACL,IAAII,GAAM,MAAM;EAChB,OAAOA,IAAO,UAAUA,EAAK,aAAa;EAC1C,OAAO,GAAO,GAAM,MAAS;GAC3B,IAAMC,IAASC,EAAQ,GACjBC,IAAIhB;GACV,IACEgB,KACAjB,EAAI,YAAY,KAAA,KAChB,OAAOiB,EAAE,aAAc,cACvB,OAAOA,EAAE,WAAY,cACrB,OAAOA,EAAE,eAAgB,cACzBd,GACA;IACA,IAAMe,KAAmB,GAAY,GAAa,MAA2B;KAC3E,IAAIH,KAAUA,EAAO,IAAIb,EAAI,EAAE,GAAG,OAAO,CAAC;KAC1C,IAAMK,IAAOJ,EAAQD,GAAKiB,GAAMC,CAAC;KACjC,IAAIC,GAAW;MACb,IAAMC,IAAIC,IAAaA,EAAWrB,EAAI,EAAE,IAAI;MAC5C,AAAIoB,KAAGD,EAAU,aAAanB,EAAI,IAAIoB,CAAC;MACvC,IAAME,IAAML,EAAwB,MAAMG,IAAIA,EAAE,IAAI,IAC9CG,IAAMN,EAAwB,MAAMG,IAAIA,EAAE,IAAI;MACpD,EAAU,aAAapB,EAAI,IAAI;OAAE,GAAGsB;OAAI,GAAGC;MAAG,CAAC;KACjD;KACA,OAAOC,EAAenB,GAAMY,GAAMnB,EAAI,WAAWA,EAAI,SAASE,EAAI,EAAE,IAAI,CAAC;IAC3E,GAGMyB,IAAsB3B,EAAI,SAC5B;KACE,GAAGiB;KACH,UAAU,MAAe;MACvB,IAAMf,IAAMe,EAAE,QAASW,CAAE;MACzB,OAAO1B,IAAMH,EAAOG,CAAG,IAAIe,EAAE,QAAQW,CAAE;KACzC;IACF,IACAX,GAEEY,IAAOC,EACXH,GACAT,GACAT,GACAK,GAAM,UACNd,EAAI,eACJY,EAASH,GAAMC,CAAI,CACrB;IACA,OAAOL,EAAOD,IAAcA,EAAYyB,GAAMpB,GAAMC,CAAI,IAAImB,GAAMpB,GAAMC,CAAI;GAC9E;GAIA,IAAMqB,IAAU/B,EAAI,WAAWC,GAAS,SAAS,KAAK,CAAC,GACjD+B,IAA0B,CAAC,GAC3BC,IAASrB,EAASH,GAAMC,CAAI;GAClC,KAAK,IAAMR,KAAO6B,GAAS;IACzB,IAAIhB,KAAUA,EAAO,IAAIb,EAAI,EAAE,GAAG;IAClC,IAAMiB,IAAcpB,EAAOG,CAAG;IAC9B,IAAIC,KAAW,CAAC8B,IAAS/B,GAAKiB,CAAI,GAAG;KACnC,IAAMZ,IAAOJ,EAAQD,GAAKiB,GAAMV,CAAI,GAC9ByB,IAAUR,EAAenB,GAAMY,GAAMnB,EAAI,WAAWA,EAAI,SAASE,EAAI,EAAE,IAAI,CAAC;KAClF,KAAK,IAAMiC,KAAOD,GAAS,EAAS,KAAKC,CAAG;IAC9C;IACA,IAAId,GAAW;KACb,IAAMC,IAAIC,IAAaA,EAAWrB,EAAI,EAAE,IAAI;KAC5C,AAAIoB,KAAGD,EAAU,aAAanB,EAAI,IAAI;MAAE,GAAGoB,EAAE;MAAG,GAAGA,EAAE;MAAG,OAAOA,EAAE;MAAO,QAAQA,EAAE;KAAO,CAAC;KAC1F,IAAME,IAAML,EAAwB,MAAMG,IAAIA,EAAE,IAAI,IAC9CG,IAAMN,EAAwB,MAAMG,IAAIA,EAAE,IAAI;KACpD,EAAU,aAAapB,EAAI,IAAI;MAAE,GAAGsB;MAAI,GAAGC;KAAG,CAAC;IACjD;GACF;GAEA,OAAOpB,EAAOD,IAAcA,EAAY4B,GAAUvB,GAAMC,CAAI,IAAIsB,GAAUvB,GAAMC,CAAI;EACtF;CACF;AACF;AAWA,SAAgB0B,EACd,GACA,GACA,GACA,GACA,GACqD;CACrD,IAAMC,IACJrC,EAAI,YAAY,KAAA,KAAa,OAAOC,GAAS,aAAc,aACvDA,EAAQ,UAAU,CAAC,CAAC,KAAK,MAAMqC,EAAE,EAAE,IACnC;CAIN,OAHI,CAACD,KAAiBA,EAAc,WAAW,IACtC,CAAC;EAAE,KAAK;EAAS,OAAOvC,EAAgBE,GAAKC,GAASoB,GAAWE,GAAYP,CAAO;CAAE,CAAC,IAEzFqB,EAAc,KAAK,OAAQ;EAChC,KAAKE,EAAcX,CAAE;EACrB,OAAO9B,EAAgBE,GAAKC,GAASoB,GAAWE,GAAYP,GAAS;GACnE,IAAIuB,EAAcX,CAAE;GACpB,UAAUA;EACZ,CAAC;CACH,EAAE;AACJ"}
@@ -1,7 +1,7 @@
1
1
  import { deriveParallaxView as e, planeMap as t } from "../core/viewport/parallax.js";
2
2
  import { definesFrame as n } from "../core/scene/effectivePose.js";
3
- import { findShapeSilhouette as r } from "./NodeShape.js";
4
- import { clipCarrier as i, planeTransform as a } from "./planeClips.js";
3
+ import { clipCarrier as r, planeTransform as i } from "./planeClips.js";
4
+ import { findShapeSilhouette as a } from "./NodeShape.js";
5
5
  import { scenePlaneOf as o } from "./pickWalk.js";
6
6
  //#region src/canvas/buildSceneTree.ts
7
7
  function s(e, t, n, r) {
@@ -18,36 +18,33 @@ function s(e, t, n, r) {
18
18
  }
19
19
  function c(c, l, u, d, f, p) {
20
20
  let m = c.getLayers(), h = /* @__PURE__ */ new Map();
21
- for (let e of m) h.set(e.id, []);
21
+ for (let e of m) e.visible && h.set(e.id, []);
22
22
  let g = null;
23
23
  for (let t of m) t.parallax && (g ??= /* @__PURE__ */ new Map()).set(t.id, e(u, t.parallax));
24
- let _ = c.composePose?.bind(c), v = i(g ? o(m, u) : null);
25
- function y(e, t, i) {
26
- let a = c.getNode(e);
27
- if (!a) return;
28
- let o = c.getPose(e), m = _ && i !== null ? _(i, o) : o, b = d === void 0 || a.layer === d, x = g?.get(a.layer) ?? u, S = b && !p?.(a, m, x) ? l(a, m, x) : [], C = t, w = a;
24
+ let _ = c.composePose?.bind(c), v = r(g ? o(m, u) : null);
25
+ function y(e, t, r) {
26
+ let i = c.getNode(e);
27
+ if (!i) return;
28
+ let o = c.getPose(e), m = _ && r !== null ? _(r, o) : o, b = d === void 0 || i.layer === d ? h.get(i.layer) : void 0, x = g?.get(i.layer) ?? u, S = b && !p?.(i, m, x) ? l(i, m, x) : [], C = t, w = i;
29
29
  if (w.kind === "container") {
30
30
  let e;
31
- e = typeof w.clipFromPose == "function" ? w.clipFromPose(m) : r(a, m, { derivedPath: f?.(a, m) }), e && (C = [...t, {
31
+ e = typeof w.clipFromPose == "function" ? w.clipFromPose(m) : a(i, m, { derivedPath: f?.(i, m) }), e && (C = [...t, {
32
32
  path: e,
33
- layer: a.layer
33
+ layer: i.layer
34
34
  }]);
35
35
  }
36
- if (b) {
37
- let e = h.get(a.layer);
38
- e && e.push(C.length > 0 ? s(S, C, a.layer, v) : {
39
- kind: "group",
40
- children: S
41
- });
42
- }
43
- let T = n(a) ? m : i;
36
+ b && b.push(C.length > 0 ? s(S, C, i.layer, v) : {
37
+ kind: "group",
38
+ children: S
39
+ });
40
+ let T = n(i) ? m : r;
44
41
  for (let t of c.getChildren(e)) y(t, C, T);
45
42
  }
46
43
  for (let e of c.getChildren(null)) y(e, [], null);
47
44
  let b = [];
48
45
  for (let e of m) {
49
46
  if (!e.visible || d !== void 0 && e.id !== d) continue;
50
- let n = h.get(e.id) ?? [], r = e.parallax ? a(t(u, e.parallax), null) : void 0;
47
+ let n = h.get(e.id) ?? [], r = e.parallax ? i(t(u, e.parallax), null) : void 0;
51
48
  b.push(r ? {
52
49
  kind: "group",
53
50
  transform: r,
@@ -1 +1 @@
1
- {"version":3,"file":"buildSceneTree.js","names":["wrapInClips","node","cmds","i","clips","carry","toLayer","buildSceneTree","layers","adapter","buckets","l","planeViews","deriveParallaxView","view","compose","clipCarrier","scenePlaneOf","visit","id","local","pose","parentFrame","paints","forLayer","v","self","culled","drawOne","ownClips","ancestorClips","maybeContainer","clip","findShapeSilhouette","derivedPathOf","bucket","childFrame","definesFrame","cid","rootId","out","layer","children","transform","planeTransform","planeMap"],"sources":["../../src/canvas/buildSceneTree.ts"],"sourcesContent":["import type { DrawCommand, GroupDrawCommand } from '../renderer';\nimport type { View } from 'core/viewport/view';\nimport { findShapeSilhouette } from './NodeShape';\nimport type { Node } from 'core/scene/types';\nimport type { Path } from '@weasel-js/geom';\nimport { definesFrame } from 'core/scene/effectivePose';\nimport { deriveParallaxView, planeMap, type ParallaxOpts } from 'core/viewport/parallax';\nimport { scenePlaneOf } from './pickWalk';\nimport { clipCarrier, planeTransform } from './planeClips';\n\n/**\n * The scene-tree reading surface `buildSceneTree` walks. A `SceneCanvasAdapter`\n * satisfies this; flat (non-hierarchical) adapters don't. Canvas exposes these\n * as *optional* methods on `CanvasProps.adapter` (see `OptionalSceneHierarchy`)\n * and feature-detects them at draw time.\n */\nexport interface HierarchicalAdapter<TNode, TPose> {\n getLayers(): readonly { id: string; visible: boolean; parallax?: ParallaxOpts }[];\n getNode(id: string): TNode | undefined;\n getChildren(parentId: string | null): readonly string[];\n getPose(id: string): TPose;\n /** Folds a child's local pose into its parent's frame. Absent means the\n * scene stores absolute poses and a parent contributes no transform —\n * see `PoseComposition`. */\n composePose?(parent: TPose, child: TPose): TPose;\n}\n\n/** A clip on the chain, with the layer whose world it is drawn in. */\ninterface ChainClip { path: Path; layer: string }\n\n/** Wrap `cmds` in one nested group per clip so the renderer intersects them.\n * Outermost group carries the ancestor-most clip; innermost holds `cmds`. */\nfunction wrapInClips(\n cmds: DrawCommand[],\n clips: readonly ChainClip[],\n toLayer: string,\n carry: ReturnType<typeof clipCarrier>,\n): DrawCommand {\n let node: GroupDrawCommand = { kind: 'group', children: cmds };\n for (let i = clips.length - 1; i >= 0; i--) {\n node = { kind: 'group', children: [node], clip: carry(clips[i].path, clips[i].layer, toLayer) };\n }\n return node;\n}\n\n/**\n * Walk the adapter's scene tree once and emit each node's own paint into the\n * bucket for **that node's own `layer`** — not its parent's. So a child whose\n * `layer` differs from its parent (e.g. a planting tagged into a top-most\n * `plantings` layer while remaining a scene child of its container) draws in\n * its own layer's pass, on top of every container body, while staying a tree\n * child for hit-testing / move / reparent.\n *\n * Output is one group per visible layer, in adapter (`getLayers`) order.\n *\n * **Positioning** is world-space: `drawOne` returns world-coord commands (the\n * caller wraps the whole thing in the view transform). Because a node may be\n * drawn outside its parent's group, the tree nesting cannot carry geometry as\n * renderer state; instead the walk folds each node's pose into its parent's\n * frame on the way down and hands the painter a **world** pose. Clips are\n * accumulated the same way and are world-space for the same reason — each in\n * its container's plane, carried into the plane of the node it clips.\n *\n * With no `composePose` on the adapter the fold is the identity, every node\n * paints at its stored pose, and this is the absolute-pose behavior the kit\n * shipped before frames existed.\n *\n * A layer carrying `parallax` is a plane: its painters and its cull see the\n * view derived for it, and its group carries the transform from its world to\n * the camera's, so the caller's single camera wrap still lands it right.\n */\nexport function buildSceneTree<\n TNode extends { id: string; layer: string },\n TPose,\n>(\n adapter: HierarchicalAdapter<TNode, TPose>,\n drawOne: (obj: TNode, pose: TPose, view: View) => DrawCommand[],\n view: View,\n /** When set, only nodes on this layer paint (others are still walked for\n * ancestor clips) and only this layer's group is returned. Used to render\n * scene layers as separate, individually-orderable canvas slots. */\n forLayer?: string,\n /** The path a container computes from its dependencies' poses. Only a\n * scene-backed caller can answer — deriving needs the dependencies' poses —\n * so the bare-adapter path omits it and a derived container contributes no\n * clip there, exactly as before. */\n derivedPathOf?: (node: TNode, pose: TPose) => Path | null,\n /** True for a node whose paint cannot be seen — see `paintMissesView`. Its\n * painter is not called; its clip and its children are walked as usual. */\n culled?: (node: TNode, pose: TPose, view: View) => boolean,\n): DrawCommand[] {\n const layers = adapter.getLayers();\n const buckets = new Map<string, DrawCommand[]>();\n for (const l of layers) buckets.set(l.id, []);\n let planeViews: Map<string, View> | null = null;\n for (const l of layers) {\n if (l.parallax) (planeViews ??= new Map()).set(l.id, deriveParallaxView(view, l.parallax));\n }\n\n const compose = adapter.composePose?.bind(adapter);\n const carry = clipCarrier(planeViews ? scenePlaneOf(layers, view) : null);\n\n function visit(\n id: string,\n ancestorClips: readonly ChainClip[],\n parentFrame: TPose | null,\n ): void {\n const node = adapter.getNode(id);\n if (!node) return;\n const local = adapter.getPose(id);\n // Fold once, on the way down: O(1) per node where walking the parent chain\n // per node would be O(depth).\n const pose = compose && parentFrame !== null ? compose(parentFrame, local) : local;\n // Skip the (potentially expensive) painter for nodes we won't emit; their\n // clip still extends the chain for descendants below.\n const paints = forLayer === undefined || node.layer === forLayer;\n const v = planeViews?.get(node.layer) ?? view;\n const self = paints && !culled?.(node, pose, v) ? drawOne(node, pose, v) : [];\n\n // Extend the clip chain with this node's own clip when it is a container.\n let ownClips = ancestorClips;\n const maybeContainer = node as { kind?: string; clipFromPose?: (pose: TPose) => unknown };\n if (maybeContainer.kind === 'container') {\n let clip: unknown;\n if (typeof maybeContainer.clipFromPose === 'function') {\n // Explicit per-node clip wins — no fallback to the painter silhouette.\n clip = maybeContainer.clipFromPose(pose);\n } else {\n // No explicit clip → fall back to the painter silhouette for the\n // container's shape kind. Built-ins give rect-fallback containers\n // their own AABB as a clip; consumer painters can provide arbitrary\n // closed shapes (ellipse, polygon, …) without per-node wiring.\n clip = findShapeSilhouette(\n node as unknown as Node<unknown, string, TPose>,\n pose,\n { derivedPath: derivedPathOf?.(node, pose) },\n );\n }\n if (clip) ownClips = [...ancestorClips, { path: clip as Path, layer: node.layer }];\n }\n\n // Emit this node's own paint into its own layer's bucket, clipped by the\n // accumulated chain (ancestors + own). Every node emits a wrapper group\n // even with empty paint, keeping the per-node tree shape stable.\n if (paints) {\n const bucket = buckets.get(node.layer);\n if (bucket) {\n bucket.push(ownClips.length > 0 ? wrapInClips(self, ownClips, node.layer, carry) : { kind: 'group', children: self });\n }\n }\n\n // An envelope's children share its own parent's frame.\n const childFrame = definesFrame(node as never) ? pose : parentFrame;\n for (const cid of adapter.getChildren(id)) visit(cid, ownClips, childFrame);\n }\n\n for (const rootId of adapter.getChildren(null)) visit(rootId, [], null);\n\n const out: DrawCommand[] = [];\n for (const layer of layers) {\n if (!layer.visible) continue;\n if (forLayer !== undefined && layer.id !== forLayer) continue;\n const children = buckets.get(layer.id) ?? [];\n const transform = layer.parallax ? planeTransform(planeMap(view, layer.parallax), null) : undefined;\n out.push(transform ? { kind: 'group', transform, children } : { kind: 'group', children });\n }\n return out;\n}\n"],"mappings":";;;;;;AAgCA,SAASA,EACP,GACA,GACA,GACA,GACa;CACb,IAAIC,IAAyB;EAAE,MAAM;EAAS,UAAUC;CAAK;CAC7D,KAAK,IAAIC,IAAIC,EAAM,SAAS,GAAGD,KAAK,GAAG,KACrC,IAAO;EAAE,MAAM;EAAS,UAAU,CAACF,CAAI;EAAG,MAAMI,EAAMD,EAAMD,EAAE,CAAC,MAAMC,EAAMD,EAAE,CAAC,OAAOG,CAAO;CAAE;CAEhG,OAAOL;AACT;AA4BA,SAAgBM,EAId,GACA,GACA,GAIA,GAKA,GAGA,GACe;CACf,IAAMC,IAASC,EAAQ,UAAU,GAC3BC,oBAAU,IAAI,IAA2B;CAC/C,KAAK,IAAMC,KAAKH,GAAQ,EAAQ,IAAIG,EAAE,IAAI,CAAC,CAAC;CAC5C,IAAIC,IAAuC;CAC3C,KAAK,IAAMD,KAAKH,GACd,AAAIG,EAAE,aAAW,sBAAe,IAAI,IAAI,EAAA,CAAG,IAAIA,EAAE,IAAIE,EAAmBC,GAAMH,EAAE,QAAQ,CAAC;CAG3F,IAAMI,IAAUN,EAAQ,aAAa,KAAKA,CAAO,GAC3CJ,IAAQW,EAAYJ,IAAaK,EAAaT,GAAQM,CAAI,IAAI,IAAI;CAExE,SAASI,EACP,GACA,GACA,GACM;EACN,IAAMjB,IAAOQ,EAAQ,QAAQU,CAAE;EAC/B,IAAI,CAAClB,GAAM;EACX,IAAMmB,IAAQX,EAAQ,QAAQU,CAAE,GAG1BE,IAAON,KAAWO,MAAgB,OAAOP,EAAQO,GAAaF,CAAK,IAAIA,GAGvEG,IAASC,MAAa,KAAA,KAAavB,EAAK,UAAUuB,GAClDC,IAAIb,GAAY,IAAIX,EAAK,KAAK,KAAKa,GACnCY,IAAOH,KAAU,CAACI,IAAS1B,GAAMoB,GAAMI,CAAC,IAAIG,EAAQ3B,GAAMoB,GAAMI,CAAC,IAAI,CAAC,GAGxEI,IAAWC,GACTC,IAAiB9B;EACvB,IAAI8B,EAAe,SAAS,aAAa;GACvC,IAAIC;GAeJ,AAdA,AAQEA,IARE,OAAOD,EAAe,gBAAiB,aAElCA,EAAe,aAAaV,CAAI,IAMhCY,EACLhC,GACAoB,GACA,EAAE,aAAaa,IAAgBjC,GAAMoB,CAAI,EAAE,CAC7C,GAEEW,MAAM,IAAW,CAAC,GAAGF,GAAe;IAAE,MAAME;IAAc,OAAO/B,EAAK;GAAM,CAAC;EACnF;EAKA,IAAIsB,GAAQ;GACV,IAAMY,IAASzB,EAAQ,IAAIT,EAAK,KAAK;GACrC,AAAIkC,KACFA,EAAO,KAAKN,EAAS,SAAS,IAAI7B,EAAY0B,GAAMG,GAAU5B,EAAK,OAAOI,CAAK,IAAI;IAAE,MAAM;IAAS,UAAUqB;GAAK,CAAC;EAExH;EAGA,IAAMU,IAAaC,EAAapC,CAAa,IAAIoB,IAAOC;EACxD,KAAK,IAAMgB,KAAO7B,EAAQ,YAAYU,CAAE,GAAG,EAAMmB,GAAKT,GAAUO,CAAU;CAC5E;CAEA,KAAK,IAAMG,KAAU9B,EAAQ,YAAY,IAAI,GAAG,EAAM8B,GAAQ,CAAC,GAAG,IAAI;CAEtE,IAAMC,IAAqB,CAAC;CAC5B,KAAK,IAAMC,KAASjC,GAAQ;EAE1B,IADI,CAACiC,EAAM,WACPjB,MAAa,KAAA,KAAaiB,EAAM,OAAOjB,GAAU;EACrD,IAAMkB,IAAWhC,EAAQ,IAAI+B,EAAM,EAAE,KAAK,CAAC,GACrCE,IAAYF,EAAM,WAAWG,EAAeC,EAAS/B,GAAM2B,EAAM,QAAQ,GAAG,IAAI,IAAI,KAAA;EAC1F,EAAI,KAAKE,IAAY;GAAE,MAAM;GAAS;GAAW;EAAS,IAAI;GAAE,MAAM;GAAS;EAAS,CAAC;CAC3F;CACA,OAAOH;AACT"}
1
+ {"version":3,"file":"buildSceneTree.js","names":["wrapInClips","node","cmds","i","clips","carry","toLayer","buildSceneTree","layers","adapter","buckets","l","planeViews","deriveParallaxView","view","compose","clipCarrier","scenePlaneOf","visit","id","local","pose","parentFrame","bucket","forLayer","v","self","culled","drawOne","ownClips","ancestorClips","maybeContainer","clip","findShapeSilhouette","derivedPathOf","childFrame","definesFrame","cid","rootId","out","layer","children","transform","planeTransform","planeMap"],"sources":["../../src/canvas/buildSceneTree.ts"],"sourcesContent":["import type { DrawCommand, GroupDrawCommand } from '../renderer';\nimport type { View } from 'core/viewport/view';\nimport { findShapeSilhouette } from './NodeShape';\nimport type { Node } from 'core/scene/types';\nimport type { Path } from '@weasel-js/geom';\nimport { definesFrame } from 'core/scene/effectivePose';\nimport { deriveParallaxView, planeMap, type ParallaxOpts } from 'core/viewport/parallax';\nimport { scenePlaneOf } from './pickWalk';\nimport { clipCarrier, planeTransform } from './planeClips';\n\n/**\n * The scene-tree reading surface `buildSceneTree` walks. A `SceneCanvasAdapter`\n * satisfies this; flat (non-hierarchical) adapters don't. Canvas exposes these\n * as *optional* methods on `CanvasProps.adapter` (see `OptionalSceneHierarchy`)\n * and feature-detects them at draw time.\n */\nexport interface HierarchicalAdapter<TNode, TPose> {\n getLayers(): readonly { id: string; visible: boolean; parallax?: ParallaxOpts }[];\n getNode(id: string): TNode | undefined;\n getChildren(parentId: string | null): readonly string[];\n getPose(id: string): TPose;\n /** Folds a child's local pose into its parent's frame. Absent means the\n * scene stores absolute poses and a parent contributes no transform —\n * see `PoseComposition`. */\n composePose?(parent: TPose, child: TPose): TPose;\n}\n\n/** A clip on the chain, with the layer whose world it is drawn in. */\ninterface ChainClip { path: Path; layer: string }\n\n/** Wrap `cmds` in one nested group per clip so the renderer intersects them.\n * Outermost group carries the ancestor-most clip; innermost holds `cmds`. */\nfunction wrapInClips(\n cmds: DrawCommand[],\n clips: readonly ChainClip[],\n toLayer: string,\n carry: ReturnType<typeof clipCarrier>,\n): DrawCommand {\n let node: GroupDrawCommand = { kind: 'group', children: cmds };\n for (let i = clips.length - 1; i >= 0; i--) {\n node = { kind: 'group', children: [node], clip: carry(clips[i].path, clips[i].layer, toLayer) };\n }\n return node;\n}\n\n/**\n * Walk the adapter's scene tree once and emit each node's own paint into the\n * bucket for **that node's own `layer`** — not its parent's. So a child whose\n * `layer` differs from its parent (e.g. a planting tagged into a top-most\n * `plantings` layer while remaining a scene child of its container) draws in\n * its own layer's pass, on top of every container body, while staying a tree\n * child for hit-testing / move / reparent.\n *\n * Output is one group per visible layer, in adapter (`getLayers`) order.\n *\n * **Positioning** is world-space: `drawOne` returns world-coord commands (the\n * caller wraps the whole thing in the view transform). Because a node may be\n * drawn outside its parent's group, the tree nesting cannot carry geometry as\n * renderer state; instead the walk folds each node's pose into its parent's\n * frame on the way down and hands the painter a **world** pose. Clips are\n * accumulated the same way and are world-space for the same reason — each in\n * its container's plane, carried into the plane of the node it clips.\n *\n * With no `composePose` on the adapter the fold is the identity, every node\n * paints at its stored pose, and this is the absolute-pose behavior the kit\n * shipped before frames existed.\n *\n * A layer carrying `parallax` is a plane: its painters and its cull see the\n * view derived for it, and its group carries the transform from its world to\n * the camera's, so the caller's single camera wrap still lands it right.\n */\nexport function buildSceneTree<\n TNode extends { id: string; layer: string },\n TPose,\n>(\n adapter: HierarchicalAdapter<TNode, TPose>,\n drawOne: (obj: TNode, pose: TPose, view: View) => DrawCommand[],\n view: View,\n /** When set, only nodes on this layer paint (others are still walked for\n * ancestor clips) and only this layer's group is returned. Used to render\n * scene layers as separate, individually-orderable canvas slots. */\n forLayer?: string,\n /** The path a container computes from its dependencies' poses. Only a\n * scene-backed caller can answer — deriving needs the dependencies' poses —\n * so the bare-adapter path omits it and a derived container contributes no\n * clip there, exactly as before. */\n derivedPathOf?: (node: TNode, pose: TPose) => Path | null,\n /** True for a node whose paint cannot be seen — see `paintMissesView`. Its\n * painter is not called; its clip and its children are walked as usual. */\n culled?: (node: TNode, pose: TPose, view: View) => boolean,\n): DrawCommand[] {\n const layers = adapter.getLayers();\n // A hidden layer gets no bucket, and a node with no bucket is not painted.\n const buckets = new Map<string, DrawCommand[]>();\n for (const l of layers) if (l.visible) buckets.set(l.id, []);\n let planeViews: Map<string, View> | null = null;\n for (const l of layers) {\n if (l.parallax) (planeViews ??= new Map()).set(l.id, deriveParallaxView(view, l.parallax));\n }\n\n const compose = adapter.composePose?.bind(adapter);\n const carry = clipCarrier(planeViews ? scenePlaneOf(layers, view) : null);\n\n function visit(\n id: string,\n ancestorClips: readonly ChainClip[],\n parentFrame: TPose | null,\n ): void {\n const node = adapter.getNode(id);\n if (!node) return;\n const local = adapter.getPose(id);\n // Fold once, on the way down: O(1) per node where walking the parent chain\n // per node would be O(depth).\n const pose = compose && parentFrame !== null ? compose(parentFrame, local) : local;\n // Skip the (potentially expensive) painter for nodes we won't emit; their\n // clip still extends the chain for descendants below.\n const bucket = forLayer === undefined || node.layer === forLayer\n ? buckets.get(node.layer) : undefined;\n const v = planeViews?.get(node.layer) ?? view;\n const self = bucket && !culled?.(node, pose, v) ? drawOne(node, pose, v) : [];\n\n // Extend the clip chain with this node's own clip when it is a container.\n let ownClips = ancestorClips;\n const maybeContainer = node as { kind?: string; clipFromPose?: (pose: TPose) => unknown };\n if (maybeContainer.kind === 'container') {\n let clip: unknown;\n if (typeof maybeContainer.clipFromPose === 'function') {\n // Explicit per-node clip wins — no fallback to the painter silhouette.\n clip = maybeContainer.clipFromPose(pose);\n } else {\n // No explicit clip → fall back to the painter silhouette for the\n // container's shape kind. Built-ins give rect-fallback containers\n // their own AABB as a clip; consumer painters can provide arbitrary\n // closed shapes (ellipse, polygon, …) without per-node wiring.\n clip = findShapeSilhouette(\n node as unknown as Node<unknown, string, TPose>,\n pose,\n { derivedPath: derivedPathOf?.(node, pose) },\n );\n }\n if (clip) ownClips = [...ancestorClips, { path: clip as Path, layer: node.layer }];\n }\n\n // Emit this node's own paint into its own layer's bucket, clipped by the\n // accumulated chain (ancestors + own). Every node emits a wrapper group\n // even with empty paint, keeping the per-node tree shape stable.\n if (bucket) {\n bucket.push(ownClips.length > 0 ? wrapInClips(self, ownClips, node.layer, carry) : { kind: 'group', children: self });\n }\n\n // An envelope's children share its own parent's frame.\n const childFrame = definesFrame(node as never) ? pose : parentFrame;\n for (const cid of adapter.getChildren(id)) visit(cid, ownClips, childFrame);\n }\n\n for (const rootId of adapter.getChildren(null)) visit(rootId, [], null);\n\n const out: DrawCommand[] = [];\n for (const layer of layers) {\n if (!layer.visible) continue;\n if (forLayer !== undefined && layer.id !== forLayer) continue;\n const children = buckets.get(layer.id) ?? [];\n const transform = layer.parallax ? planeTransform(planeMap(view, layer.parallax), null) : undefined;\n out.push(transform ? { kind: 'group', transform, children } : { kind: 'group', children });\n }\n return out;\n}\n"],"mappings":";;;;;;AAgCA,SAASA,EACP,GACA,GACA,GACA,GACa;CACb,IAAIC,IAAyB;EAAE,MAAM;EAAS,UAAUC;CAAK;CAC7D,KAAK,IAAIC,IAAIC,EAAM,SAAS,GAAGD,KAAK,GAAG,KACrC,IAAO;EAAE,MAAM;EAAS,UAAU,CAACF,CAAI;EAAG,MAAMI,EAAMD,EAAMD,EAAE,CAAC,MAAMC,EAAMD,EAAE,CAAC,OAAOG,CAAO;CAAE;CAEhG,OAAOL;AACT;AA4BA,SAAgBM,EAId,GACA,GACA,GAIA,GAKA,GAGA,GACe;CACf,IAAMC,IAASC,EAAQ,UAAU,GAE3BC,oBAAU,IAAI,IAA2B;CAC/C,KAAK,IAAMC,KAAKH,GAAQ,AAAIG,EAAE,WAASD,EAAQ,IAAIC,EAAE,IAAI,CAAC,CAAC;CAC3D,IAAIC,IAAuC;CAC3C,KAAK,IAAMD,KAAKH,GACd,AAAIG,EAAE,aAAW,sBAAe,IAAI,IAAI,EAAA,CAAG,IAAIA,EAAE,IAAIE,EAAmBC,GAAMH,EAAE,QAAQ,CAAC;CAG3F,IAAMI,IAAUN,EAAQ,aAAa,KAAKA,CAAO,GAC3CJ,IAAQW,EAAYJ,IAAaK,EAAaT,GAAQM,CAAI,IAAI,IAAI;CAExE,SAASI,EACP,GACA,GACA,GACM;EACN,IAAMjB,IAAOQ,EAAQ,QAAQU,CAAE;EAC/B,IAAI,CAAClB,GAAM;EACX,IAAMmB,IAAQX,EAAQ,QAAQU,CAAE,GAG1BE,IAAON,KAAWO,MAAgB,OAAOP,EAAQO,GAAaF,CAAK,IAAIA,GAGvEG,IAASC,MAAa,KAAA,KAAavB,EAAK,UAAUuB,IACpDd,EAAQ,IAAIT,EAAK,KAAK,IAAI,KAAA,GACxBwB,IAAIb,GAAY,IAAIX,EAAK,KAAK,KAAKa,GACnCY,IAAOH,KAAU,CAACI,IAAS1B,GAAMoB,GAAMI,CAAC,IAAIG,EAAQ3B,GAAMoB,GAAMI,CAAC,IAAI,CAAC,GAGxEI,IAAWC,GACTC,IAAiB9B;EACvB,IAAI8B,EAAe,SAAS,aAAa;GACvC,IAAIC;GAeJ,AAdA,AAQEA,IARE,OAAOD,EAAe,gBAAiB,aAElCA,EAAe,aAAaV,CAAI,IAMhCY,EACLhC,GACAoB,GACA,EAAE,aAAaa,IAAgBjC,GAAMoB,CAAI,EAAE,CAC7C,GAEEW,MAAM,IAAW,CAAC,GAAGF,GAAe;IAAE,MAAME;IAAc,OAAO/B,EAAK;GAAM,CAAC;EACnF;EAKA,AAAIsB,KACFA,EAAO,KAAKM,EAAS,SAAS,IAAI7B,EAAY0B,GAAMG,GAAU5B,EAAK,OAAOI,CAAK,IAAI;GAAE,MAAM;GAAS,UAAUqB;EAAK,CAAC;EAItH,IAAMS,IAAaC,EAAanC,CAAa,IAAIoB,IAAOC;EACxD,KAAK,IAAMe,KAAO5B,EAAQ,YAAYU,CAAE,GAAG,EAAMkB,GAAKR,GAAUM,CAAU;CAC5E;CAEA,KAAK,IAAMG,KAAU7B,EAAQ,YAAY,IAAI,GAAG,EAAM6B,GAAQ,CAAC,GAAG,IAAI;CAEtE,IAAMC,IAAqB,CAAC;CAC5B,KAAK,IAAMC,KAAShC,GAAQ;EAE1B,IADI,CAACgC,EAAM,WACPhB,MAAa,KAAA,KAAagB,EAAM,OAAOhB,GAAU;EACrD,IAAMiB,IAAW/B,EAAQ,IAAI8B,EAAM,EAAE,KAAK,CAAC,GACrCE,IAAYF,EAAM,WAAWG,EAAeC,EAAS9B,GAAM0B,EAAM,QAAQ,GAAG,IAAI,IAAI,KAAA;EAC1F,EAAI,KAAKE,IAAY;GAAE,MAAM;GAAS;GAAW;EAAS,IAAI;GAAE,MAAM;GAAS;EAAS,CAAC;CAC3F;CACA,OAAOH;AACT"}
@@ -1,89 +1,105 @@
1
1
  import { WeaselRenderer as e } from "../renderer/WeaselRenderer.js";
2
2
  import { viewToMat3 as t } from "../renderer/math/viewToMat3.js";
3
3
  //#region src/canvas/canvasRenderer.ts
4
- var n = /* @__PURE__ */ new WeakMap(), r = (e) => e?.map((e) => e.id).join("|") ?? "";
5
- function i(e, t) {
4
+ var n = /* @__PURE__ */ new WeakMap(), r = /* @__PURE__ */ new WeakSet(), i = (e) => e?.map((e) => e.id).join("|") ?? "";
5
+ function a(e, t) {
6
6
  if (t) for (let n of t) try {
7
7
  e.registerProgram(n);
8
8
  } catch (e) {
9
9
  console.warn(`weasel: failed to register shader "${n.id}":`, e);
10
10
  }
11
11
  }
12
- function a(e) {
12
+ function o(e) {
13
13
  let t = n.get(e.canvas);
14
- t?.delete(e.renderer), t && t.size === 0 && n.delete(e.canvas), e.renderer.dispose();
14
+ t?.delete(e.renderer), e.canvas.removeEventListener("webglcontextlost", e.onLost), e.canvas.removeEventListener("webglcontextrestored", e.onRestored), t && t.size === 0 && n.delete(e.canvas), e.renderer.dispose();
15
15
  }
16
- function o() {
17
- let o = null, s = (t, s, c = {}) => {
18
- let { width: l, height: u } = s, d = s.dpr ?? (typeof window < "u" && window.devicePixelRatio || 1), f = c.tile ?? null, p = f !== null;
19
- if (o && (o.canvas !== t || o.shared !== p) && (a(o), o = null), o) (o.width !== l || o.height !== u || o.dpr !== d) && (o.renderer.resize({
20
- width: l,
21
- height: u,
22
- dpr: d
23
- }), o.width = l, o.height = u, o.dpr = d), o.flattenTolerance !== c.flattenTolerance && (o.renderer.setFlattenTolerance(c.flattenTolerance), o.flattenTolerance = c.flattenTolerance);
16
+ function s() {
17
+ let s = null, c = /* @__PURE__ */ new Set(), l = (t, l, u = {}) => {
18
+ let { width: d, height: f } = l, p = l.dpr ?? (typeof window < "u" && window.devicePixelRatio || 1), m = u.tile ?? null, h = m !== null;
19
+ if (s && (s.canvas !== t || s.shared !== h) && (o(s), s = null), s) (!h && (t.width !== Math.round(d * p) || t.height !== Math.round(f * p)) || s.width !== d || s.height !== f || s.dpr !== p) && (s.renderer.resize({
20
+ width: d,
21
+ height: f,
22
+ dpr: p
23
+ }), s.width = d, s.height = f, s.dpr = p), s.flattenTolerance !== u.flattenTolerance && (s.renderer.setFlattenTolerance(u.flattenTolerance), s.flattenTolerance = u.flattenTolerance);
24
24
  else {
25
- let r = t.getContext("webgl2", {
25
+ if (r.has(t)) return null;
26
+ let i = t.getContext("webgl2", {
26
27
  preserveDrawingBuffer: !0,
27
28
  stencil: !0
28
29
  });
29
- if (!r || typeof r.enable != "function") return null;
30
- let i;
30
+ if (!i || typeof i.enable != "function") return null;
31
+ let a;
31
32
  try {
32
- i = new e({
33
- gl: r,
34
- ...p ? {} : { canvas: t },
35
- width: l,
36
- height: u,
37
- dpr: d,
38
- flattenTolerance: c.flattenTolerance
33
+ a = new e({
34
+ gl: i,
35
+ ...h ? {} : { canvas: t },
36
+ width: d,
37
+ height: f,
38
+ dpr: p,
39
+ flattenTolerance: u.flattenTolerance
39
40
  });
40
- } catch {
41
- return null;
41
+ } catch (e) {
42
+ return i.isContextLost?.() || (r.add(t), console.warn("weasel: this canvas cannot be painted:", e)), null;
42
43
  }
43
- o = {
44
+ let o = s = {
44
45
  canvas: t,
45
- renderer: i,
46
- shared: p,
47
- width: l,
48
- height: u,
49
- dpr: d,
46
+ renderer: a,
47
+ shared: h,
48
+ width: d,
49
+ height: f,
50
+ dpr: p,
50
51
  tileX: null,
51
52
  tileY: null,
52
- flattenTolerance: c.flattenTolerance,
53
- shaderKey: ""
53
+ flattenTolerance: u.flattenTolerance,
54
+ shaderKey: "",
55
+ lost: !1,
56
+ onLost: () => {
57
+ o.lost = !0;
58
+ },
59
+ onRestored: () => {
60
+ o.lost = !1;
61
+ for (let e of [...c]) e();
62
+ }
54
63
  };
55
- let a = n.get(t);
56
- a || (a = /* @__PURE__ */ new Set(), n.set(t, a)), a.add(i);
64
+ t.addEventListener("webglcontextlost", s.onLost), t.addEventListener("webglcontextrestored", s.onRestored);
65
+ let l = n.get(t);
66
+ l || (l = /* @__PURE__ */ new Set(), n.set(t, l)), l.add(a);
57
67
  }
58
- let { renderer: m } = o, h = r(c.shaders);
59
- h !== o.shaderKey && (i(m, c.shaders), o.shaderKey = h);
60
- let g = f?.x ?? null, _ = f?.y ?? null;
61
- return (g !== o.tileX || _ !== o.tileY) && (m.setTarget(f ? { origin: {
62
- x: f.x,
63
- y: f.y
64
- } } : null), o.tileX = g, o.tileY = _), m;
68
+ if (s.lost) return null;
69
+ let { renderer: g } = s, _ = i(u.shaders);
70
+ _ !== s.shaderKey && (a(g, u.shaders), s.shaderKey = _);
71
+ let v = m?.x ?? null, y = m?.y ?? null;
72
+ return (v !== s.tileX || y !== s.tileY) && (g.setTarget(m ? { origin: {
73
+ x: m.x,
74
+ y: m.y
75
+ } } : null), s.tileX = v, s.tileY = y), g;
65
76
  };
66
77
  return {
67
- bind: s,
78
+ bind: l,
68
79
  paint(e, n, r, i, a) {
69
- let o = s(e, i, a);
80
+ let o = l(e, i, a);
70
81
  return o ? (o.render(n, t(r), a?.render), !0) : !1;
71
82
  },
83
+ subscribeRestored(e) {
84
+ return c.add(e), () => {
85
+ c.delete(e);
86
+ };
87
+ },
72
88
  release() {
73
- o && a(o), o = null;
89
+ s && o(s), s = null;
74
90
  }
75
91
  };
76
92
  }
77
- var s = /* @__PURE__ */ new WeakMap();
78
- function c(e, t, n, r) {
79
- let i = s.get(e);
80
- return i || (i = o(), s.set(e, i)), i.paint(e, t, n, r);
93
+ var c = /* @__PURE__ */ new WeakMap();
94
+ function l(e, t, n, r) {
95
+ let i = c.get(e);
96
+ return i || (i = s(), c.set(e, i)), i.paint(e, t, n, r);
81
97
  }
82
- function l(e) {
83
- let t = s.get(e);
84
- t && (s.delete(e), t.release());
98
+ function u(e) {
99
+ let t = c.get(e);
100
+ t && (c.delete(e), t.release());
85
101
  }
86
102
  //#endregion
87
- export { o as leaseCanvasRenderer, c as paintCanvas, l as releaseCanvasRenderer };
103
+ export { s as leaseCanvasRenderer, l as paintCanvas, u as releaseCanvasRenderer };
88
104
 
89
105
  //# sourceMappingURL=canvasRenderer.js.map