@weasel-js/core 1.9.2 → 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 +393 -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 +146 -92
  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 +11010 -7700
  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 +13 -2
  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 -47
  542. package/dist/tools/prefs.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"strokeMeshCache.js","names":["STROKE_CONFIGS_PER_PATH","PX_WIDTH_TOLERANCE","quantizeStrokeScale","px","scale","stepsPerOctave","cache","configKey","width","resolveStrokeWidth","stroke","insets","strokeInsets","ribbon","spaces","flattenTolerance","metricKey","strokeMesh","byConfig","path","key","entry","mesh","tessellateStroke","insetIn","head","length"],"sources":["../../../src/renderer/cache/strokeMeshCache.ts"],"sourcesContent":["/**\n * Tessellated stroke ribbons for scene paths, keyed on `Path` identity.\n *\n * The sibling of `cache.ts` (fills) and `outlineStrokeMeshCache.ts` (glyph\n * ribbons in em space), and it inherits their contract: identity, not content.\n * A `Path` rebuilt with equal coords is a distinct entry.\n *\n * Design: `docs/superpowers/specs/2026-08-15-stroke-ribbon-cache-design.md`.\n */\n\nimport type { Path } from '@weasel-js/core';\nimport type { Stroke } from '@weasel-js/paint';\nimport { tessellateStroke, resolveStrokeWidth } from 'features/paths/tessellate/stroke';\nimport { strokeInsets } from '../../core/markerInset';\nimport { metricKey, type ScreenSpace, type StrokeSpaces } from 'features/paths/tessellate/metric';\nimport type { InsetLength } from 'features/paths/tessellate/insets';\nimport type { Mesh } from '@weasel-js/geom/tessellate';\n\n/**\n * Distinct stroke configurations kept per path before that path's map is\n * dropped wholesale. A document uses a handful; a width slider passes this on\n * its first drag and then degrades to tessellating every frame, which is what\n * it did before this cache existed.\n */\nexport const STROKE_CONFIGS_PER_PATH = 8;\n\n/** Screen-pixel bound on how far a quantized `{ px }` ribbon's width may\n * drift from the width asked for: each edge moves at most half of it. */\nconst PX_WIDTH_TOLERANCE = 1 / 8;\n\n/**\n * `scale` snapped to a log-spaced grid, for resolving a `{ px }` width against.\n * Resolving against the raw scale gives a continuous zoom a new cache key every\n * frame. The grid is fine enough that the resolved ribbon stays within\n * `PX_WIDTH_TOLERANCE` screen pixels of `px`, so it is coarser for thin\n * strokes, and powers of two land on it exactly.\n */\nexport function quantizeStrokeScale(px: number, scale: number): number {\n if (!(px > 0) || !(scale > 0) || !Number.isFinite(scale)) return scale;\n const stepsPerOctave = Math.ceil(Math.LN2 / (2 * Math.log1p(PX_WIDTH_TOLERANCE / px)));\n return 2 ** (Math.round(Math.log2(scale) * stepsPerOctave) / stepsPerOctave);\n}\n\ninterface StrokeEntry {\n readonly mesh: Mesh;\n /** Compared by reference — long enough that stringifying it per frame would\n * cost what the cache saves. */\n readonly vertexWidths: number[] | undefined;\n}\n\nlet cache = new WeakMap<Path, Map<string, StrokeEntry>>();\n\n/** The stroke parameters that change the ribbon's geometry. `paint` and\n * `vertexColors` are absent on purpose: both are applied over the same\n * triangles at draw time. Marker *identity* is absent too — only the\n * resolved trim distance affects these triangles, so two heads with the\n * same inset share one entry. */\nfunction configKey(stroke: Stroke, flattenTolerance: number | undefined, spaces: StrokeSpaces): string {\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n const insets = strokeInsets(stroke, width);\n const ribbon = spaces.ribbon?.metric;\n return [\n width,\n stroke.cap ?? 'butt',\n stroke.join ?? 'miter',\n stroke.miterLimit ?? '',\n stroke.align ?? 'center',\n (stroke.dash ?? []).join(','),\n stroke.varyingWidthJoinThreshold ?? '',\n flattenTolerance ?? '',\n insets.start,\n insets.end,\n metricKey(ribbon),\n metricKey(spaces.start?.metric),\n metricKey(spaces.end?.metric),\n ].join('|');\n}\n\n/** The tessellated ribbon for `path` under `stroke`, built in the space\n * `spaces` names for it, and stopped short of each head in that head's own.\n * The same `Mesh` object comes back for as long as the entry lives. */\nexport function strokeMesh(\n path: Path,\n stroke: Stroke,\n flattenTolerance: number | undefined,\n spaces: StrokeSpaces = {},\n): Mesh {\n let byConfig = cache.get(path);\n if (byConfig === undefined) {\n byConfig = new Map<string, StrokeEntry>();\n cache.set(path, byConfig);\n }\n\n const key = configKey(stroke, flattenTolerance, spaces);\n const entry = byConfig.get(key);\n if (entry !== undefined && entry.vertexWidths === stroke.vertexWidths) {\n return entry.mesh;\n }\n\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n const insets = strokeInsets(stroke, width);\n const mesh = tessellateStroke(path, stroke, {\n flattenTolerance,\n startInset: insetIn(insets.start, spaces.start, spaces.ribbon),\n endInset: insetIn(insets.end, spaces.end, spaces.ribbon),\n metric: spaces.ribbon?.metric,\n });\n // Only a new key grows the map; replacing one under a churning\n // `vertexWidths` must not evict the other configurations alongside it.\n if (entry === undefined && byConfig.size >= STROKE_CONFIGS_PER_PATH) byConfig.clear();\n byConfig.set(key, { mesh, vertexWidths: stroke.vertexWidths });\n return mesh;\n}\n\n/** `length`, measured in `head`'s space, as the tessellator reads it. */\nfunction insetIn(length: number, head: ScreenSpace | undefined, ribbon: ScreenSpace | undefined): InsetLength {\n return head?.metric === ribbon?.metric ? length : { length, metric: head?.metric ?? null };\n}\n\n/** Test helper. Do not call from product code. */\nexport function _resetStrokeMeshCacheForTests(): void {\n cache = new WeakMap();\n}\n"],"mappings":";;;;AAwBA,IAAaA,IAA0B,GAIjCC,IAAqB,IAAI;AAS/B,SAAgBC,EAAoB,GAAY,GAAuB;CACrE,IAAI,EAAEC,IAAK,MAAM,EAAEC,IAAQ,MAAM,CAAC,OAAO,SAASA,CAAK,GAAG,OAAOA;CACjE,IAAMC,IAAiB,KAAK,KAAK,KAAK,OAAO,IAAI,KAAK,MAAMJ,IAAqBE,CAAE,EAAE;CACrF,OAAO,MAAM,KAAK,MAAM,KAAK,KAAKC,CAAK,IAAIC,CAAc,IAAIA;AAC/D;AASA,IAAIC,oBAAQ,IAAI,QAAwC;AAOxD,SAASC,EAAU,GAAgB,GAAsC,GAA8B;CACrG,IAAMC,IAAQC,EAAmBC,EAAO,SAAS,GAAG,CAAC,GAC/CC,IAASC,EAAaF,GAAQF,CAAK,GACnCK,IAASC,EAAO,QAAQ;CAC9B,OAAO;EACLN;EACAE,EAAO,OAAO;EACdA,EAAO,QAAQ;EACfA,EAAO,cAAc;EACrBA,EAAO,SAAS;GACfA,EAAO,QAAQ,CAAC,EAAA,CAAG,KAAK,GAAG;EAC5BA,EAAO,6BAA6B;EACpCK,KAAoB;EACpBJ,EAAO;EACPA,EAAO;EACPK,EAAUH,CAAM;EAChBG,EAAUF,EAAO,OAAO,MAAM;EAC9BE,EAAUF,EAAO,KAAK,MAAM;CAC9B,CAAC,CAAC,KAAK,GAAG;AACZ;AAKA,SAAgBG,EACd,GACA,GACA,GACA,IAAuB,CAAC,GAClB;CACN,IAAIC,IAAWZ,EAAM,IAAIa,CAAI;CAC7B,AAAID,MAAa,KAAA,MACf,oBAAW,IAAI,IAAyB,GACxCZ,EAAM,IAAIa,GAAMD,CAAQ;CAG1B,IAAME,IAAMb,EAAUG,GAAQK,GAAkBD,CAAM,GAChDO,IAAQH,EAAS,IAAIE,CAAG;CAC9B,IAAIC,MAAU,KAAA,KAAaA,EAAM,iBAAiBX,EAAO,cACvD,OAAOW,EAAM;CAGf,IAAMb,IAAQC,EAAmBC,EAAO,SAAS,GAAG,CAAC,GAC/CC,IAASC,EAAaF,GAAQF,CAAK,GACnCc,IAAOC,EAAiBJ,GAAMT,GAAQ;EAC1C;EACA,YAAYc,EAAQb,EAAO,OAAOG,EAAO,OAAOA,EAAO,MAAM;EAC7D,UAAUU,EAAQb,EAAO,KAAKG,EAAO,KAAKA,EAAO,MAAM;EACvD,QAAQA,EAAO,QAAQ;CACzB,CAAC;CAKD,OAFIO,MAAU,KAAA,KAAaH,EAAS,QAAQlB,KAAyBkB,EAAS,MAAM,GACpFA,EAAS,IAAIE,GAAK;EAAE;EAAM,cAAcV,EAAO;CAAa,CAAC,GACtDY;AACT;AAGA,SAASE,EAAQ,GAAgB,GAA+B,GAA8C;CAC5G,OAAOC,GAAM,WAAWZ,GAAQ,SAASa,IAAS;EAAE;EAAQ,QAAQD,GAAM,UAAU;CAAK;AAC3F"}
1
+ {"version":3,"file":"strokeMeshCache.js","names":["STROKE_CONFIGS_PER_PATH","PX_WIDTH_TOLERANCE","quantizeStrokeScale","px","scale","stepsPerOctave","cache","configKey","width","resolveStrokeWidth","stroke","insets","strokeInsets","ribbon","spaces","flattenTolerance","metricKey","strokeMesh","byConfig","path","key","entry","mesh","tessellateStroke","insetIn","head","length"],"sources":["../../../src/renderer/cache/strokeMeshCache.ts"],"sourcesContent":["/**\n * Tessellated stroke ribbons for scene paths, keyed on `Path` identity.\n *\n * The sibling of `cache.ts` (fills) and `outlineStrokeMeshCache.ts` (glyph\n * ribbons in em space), and it inherits their contract: identity, not content.\n * A `Path` rebuilt with equal coords is a distinct entry.\n *\n * Design: `docs/superpowers/specs/2026-08-15-stroke-ribbon-cache-design.md`.\n */\n\nimport type { Path } from '@weasel-js/geom';\nimport type { Stroke } from '@weasel-js/paint';\nimport { tessellateStroke, resolveStrokeWidth } from 'features/paths/tessellate/stroke';\nimport { strokeInsets } from '../../core/markerInset';\nimport { metricKey, type ScreenSpace, type StrokeSpaces } from 'features/paths/tessellate/metric';\nimport type { InsetLength } from 'features/paths/tessellate/insets';\nimport type { Mesh } from '@weasel-js/geom/tessellate';\n\n/**\n * Distinct stroke configurations kept per path before that path's map is\n * dropped wholesale. A document uses a handful; a width slider passes this on\n * its first drag and then degrades to tessellating every frame, which is what\n * it did before this cache existed.\n */\nexport const STROKE_CONFIGS_PER_PATH = 8;\n\n/** Screen-pixel bound on how far a quantized `{ px }` ribbon's width may\n * drift from the width asked for: each edge moves at most half of it. */\nconst PX_WIDTH_TOLERANCE = 1 / 8;\n\n/**\n * `scale` snapped to a log-spaced grid, for resolving a `{ px }` width against.\n * Resolving against the raw scale gives a continuous zoom a new cache key every\n * frame. The grid is fine enough that the resolved ribbon stays within\n * `PX_WIDTH_TOLERANCE` screen pixels of `px`, so it is coarser for thin\n * strokes, and powers of two land on it exactly.\n */\nexport function quantizeStrokeScale(px: number, scale: number): number {\n if (!(px > 0) || !(scale > 0) || !Number.isFinite(scale)) return scale;\n const stepsPerOctave = Math.ceil(Math.LN2 / (2 * Math.log1p(PX_WIDTH_TOLERANCE / px)));\n return 2 ** (Math.round(Math.log2(scale) * stepsPerOctave) / stepsPerOctave);\n}\n\ninterface StrokeEntry {\n readonly mesh: Mesh;\n /** Compared by reference — long enough that stringifying it per frame would\n * cost what the cache saves. */\n readonly vertexWidths: number[] | undefined;\n}\n\nlet cache = new WeakMap<Path, Map<string, StrokeEntry>>();\n\n/** The stroke parameters that change the ribbon's geometry. `paint` and\n * `vertexColors` are absent on purpose: both are applied over the same\n * triangles at draw time. Marker *identity* is absent too — only the\n * resolved trim distance affects these triangles, so two heads with the\n * same inset share one entry. */\nfunction configKey(stroke: Stroke, flattenTolerance: number | undefined, spaces: StrokeSpaces): string {\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n const insets = strokeInsets(stroke, width);\n const ribbon = spaces.ribbon?.metric;\n return [\n width,\n stroke.cap ?? 'butt',\n stroke.join ?? 'miter',\n stroke.miterLimit ?? '',\n stroke.align ?? 'center',\n (stroke.dash ?? []).join(','),\n stroke.varyingWidthJoinThreshold ?? '',\n flattenTolerance ?? '',\n insets.start,\n insets.end,\n metricKey(ribbon),\n metricKey(spaces.start?.metric),\n metricKey(spaces.end?.metric),\n ].join('|');\n}\n\n/** The tessellated ribbon for `path` under `stroke`, built in the space\n * `spaces` names for it, and stopped short of each head in that head's own.\n * The same `Mesh` object comes back for as long as the entry lives. */\nexport function strokeMesh(\n path: Path,\n stroke: Stroke,\n flattenTolerance: number | undefined,\n spaces: StrokeSpaces = {},\n): Mesh {\n let byConfig = cache.get(path);\n if (byConfig === undefined) {\n byConfig = new Map<string, StrokeEntry>();\n cache.set(path, byConfig);\n }\n\n const key = configKey(stroke, flattenTolerance, spaces);\n const entry = byConfig.get(key);\n if (entry !== undefined && entry.vertexWidths === stroke.vertexWidths) {\n return entry.mesh;\n }\n\n const width = resolveStrokeWidth(stroke.width ?? 1, 1);\n const insets = strokeInsets(stroke, width);\n const mesh = tessellateStroke(path, stroke, {\n flattenTolerance,\n startInset: insetIn(insets.start, spaces.start, spaces.ribbon),\n endInset: insetIn(insets.end, spaces.end, spaces.ribbon),\n metric: spaces.ribbon?.metric,\n });\n // Only a new key grows the map; replacing one under a churning\n // `vertexWidths` must not evict the other configurations alongside it.\n if (entry === undefined && byConfig.size >= STROKE_CONFIGS_PER_PATH) byConfig.clear();\n byConfig.set(key, { mesh, vertexWidths: stroke.vertexWidths });\n return mesh;\n}\n\n/** `length`, measured in `head`'s space, as the tessellator reads it. */\nfunction insetIn(length: number, head: ScreenSpace | undefined, ribbon: ScreenSpace | undefined): InsetLength {\n return head?.metric === ribbon?.metric ? length : { length, metric: head?.metric ?? null };\n}\n\n/** Test helper. Do not call from product code. */\nexport function _resetStrokeMeshCacheForTests(): void {\n cache = new WeakMap();\n}\n"],"mappings":";;;;AAwBA,IAAaA,IAA0B,GAIjCC,IAAqB,IAAI;AAS/B,SAAgBC,EAAoB,GAAY,GAAuB;CACrE,IAAI,EAAEC,IAAK,MAAM,EAAEC,IAAQ,MAAM,CAAC,OAAO,SAASA,CAAK,GAAG,OAAOA;CACjE,IAAMC,IAAiB,KAAK,KAAK,KAAK,OAAO,IAAI,KAAK,MAAMJ,IAAqBE,CAAE,EAAE;CACrF,OAAO,MAAM,KAAK,MAAM,KAAK,KAAKC,CAAK,IAAIC,CAAc,IAAIA;AAC/D;AASA,IAAIC,oBAAQ,IAAI,QAAwC;AAOxD,SAASC,EAAU,GAAgB,GAAsC,GAA8B;CACrG,IAAMC,IAAQC,EAAmBC,EAAO,SAAS,GAAG,CAAC,GAC/CC,IAASC,EAAaF,GAAQF,CAAK,GACnCK,IAASC,EAAO,QAAQ;CAC9B,OAAO;EACLN;EACAE,EAAO,OAAO;EACdA,EAAO,QAAQ;EACfA,EAAO,cAAc;EACrBA,EAAO,SAAS;GACfA,EAAO,QAAQ,CAAC,EAAA,CAAG,KAAK,GAAG;EAC5BA,EAAO,6BAA6B;EACpCK,KAAoB;EACpBJ,EAAO;EACPA,EAAO;EACPK,EAAUH,CAAM;EAChBG,EAAUF,EAAO,OAAO,MAAM;EAC9BE,EAAUF,EAAO,KAAK,MAAM;CAC9B,CAAC,CAAC,KAAK,GAAG;AACZ;AAKA,SAAgBG,EACd,GACA,GACA,GACA,IAAuB,CAAC,GAClB;CACN,IAAIC,IAAWZ,EAAM,IAAIa,CAAI;CAC7B,AAAID,MAAa,KAAA,MACf,oBAAW,IAAI,IAAyB,GACxCZ,EAAM,IAAIa,GAAMD,CAAQ;CAG1B,IAAME,IAAMb,EAAUG,GAAQK,GAAkBD,CAAM,GAChDO,IAAQH,EAAS,IAAIE,CAAG;CAC9B,IAAIC,MAAU,KAAA,KAAaA,EAAM,iBAAiBX,EAAO,cACvD,OAAOW,EAAM;CAGf,IAAMb,IAAQC,EAAmBC,EAAO,SAAS,GAAG,CAAC,GAC/CC,IAASC,EAAaF,GAAQF,CAAK,GACnCc,IAAOC,EAAiBJ,GAAMT,GAAQ;EAC1C;EACA,YAAYc,EAAQb,EAAO,OAAOG,EAAO,OAAOA,EAAO,MAAM;EAC7D,UAAUU,EAAQb,EAAO,KAAKG,EAAO,KAAKA,EAAO,MAAM;EACvD,QAAQA,EAAO,QAAQ;CACzB,CAAC;CAKD,OAFIO,MAAU,KAAA,KAAaH,EAAS,QAAQlB,KAAyBkB,EAAS,MAAM,GACpFA,EAAS,IAAIE,GAAK;EAAE;EAAM,cAAcV,EAAO;CAAa,CAAC,GACtDY;AACT;AAGA,SAASE,EAAQ,GAAgB,GAA+B,GAA8C;CAC5G,OAAOC,GAAM,WAAWZ,GAAQ,SAASa,IAAS;EAAE;EAAQ,QAAQD,GAAM,UAAU;CAAK;AAC3F"}
@@ -1,7 +1,7 @@
1
1
  import { mat3 as e } from "./math/mat3.js";
2
- import { SPRITE_STRIDE as t } from "./DrawCommand.js";
3
- import { resolveStrokeWidth as n } from "../features/paths/tessellate/stroke.js";
4
- import { markerReach as r } from "../features/paths/markerCommands.js";
2
+ import { resolveStrokeWidth as t } from "../features/paths/tessellate/stroke.js";
3
+ import { markerReach as n } from "../features/paths/markerCommands.js";
4
+ import { SPRITE_STRIDE as r } from "./DrawCommand.js";
5
5
  import { resolveScreenLength as i } from "@weasel-js/paint";
6
6
  //#region src/renderer/cullDrawCommands.ts
7
7
  var a = 1, o = 4;
@@ -54,19 +54,19 @@ function u(e, t, n, r) {
54
54
  function d(t, n) {
55
55
  return f(t, e.meanScaleOf(n), e.minScaleOf(n));
56
56
  }
57
- function f(e, t, a = t) {
58
- let s = a > 0 ? a : t, c = n(e.width ?? 1, typeof e.width == "object" ? s : t);
57
+ function f(e, r, a = r) {
58
+ let s = a > 0 ? a : r, c = t(e.width ?? 1, typeof e.width == "object" ? s : r);
59
59
  if (e.vertexWidths) for (let t of e.vertexWidths) t > c && (c = t);
60
- let l = Math.max(e.miterLimit ?? o, Math.SQRT2), u = r(e);
60
+ let l = Math.max(e.miterLimit ?? o, Math.SQRT2), u = n(e);
61
61
  return Math.max(Math.abs(c) * l, u.world, i({ px: u.px }, s));
62
62
  }
63
- function p(e, n, r) {
63
+ function p(e, t, n) {
64
64
  let i = Infinity, a = Infinity, o = -Infinity, s = -Infinity;
65
- for (let n = 0; n + t <= e.length; n += t) {
66
- let t = e[n], r = e[n + 1], c = t + e[n + 2], l = r + e[n + 3];
67
- i = Math.min(i, t, c), o = Math.max(o, t, c), a = Math.min(a, r, l), s = Math.max(s, r, l);
65
+ for (let t = 0; t + r <= e.length; t += r) {
66
+ let n = e[t], r = e[t + 1], c = n + e[t + 2], l = r + e[t + 3];
67
+ i = Math.min(i, n, c), o = Math.max(o, n, c), a = Math.min(a, r, l), s = Math.max(s, r, l);
68
68
  }
69
- return i !== Infinity && g(i, a, o, s, n, r);
69
+ return i !== Infinity && g(i, a, o, s, t, n);
70
70
  }
71
71
  function m(e, t, n) {
72
72
  let r = Math.min(e.x, e.x + e.width), i = Math.max(e.x, e.x + e.width);
@@ -0,0 +1,133 @@
1
+ import { BATCH_TEXTURE_SLOTS as e } from "../shaders/batchFill.js";
2
+ import { resolveColor as t } from "../math/color.js";
3
+ import { IDENTITY_COLOR_MATRIX as n } from "../state/GroupState.js";
4
+ import { sameValues as r } from "./uniforms.js";
5
+ import { flushBatch as i } from "./flushBatch.js";
6
+ import { flushForOwnDraw as a, retryUncut as o, runClipDepth as s } from "./clip.js";
7
+ import { rampVertices as c } from "./gradient.js";
8
+ //#region src/renderer/draw/batch.ts
9
+ function l(e) {
10
+ return e === n || r(n, e);
11
+ }
12
+ function u(e, t, n, i, a = 0) {
13
+ if (t.clipDepth !== (e.clipStack.length === 0 ? e.clipDepth : s(e)) || t.synthBold !== a || !t.foldsAlpha && t.alpha !== e.state.alpha || n !== void 0 && d(t, n, i) < 0) return !1;
14
+ let o = e.state.colorMatrix;
15
+ return t.colorMatrix === o || r(t.colorMatrix, o);
16
+ }
17
+ function d(e, t, n) {
18
+ for (let r = 0; r < e.textures.length; r++) {
19
+ let i = e.textures[r];
20
+ if (i.kind === "bitmap" && i.image === t) return i.sampling === n ? r + 1 : -1;
21
+ }
22
+ return m(e);
23
+ }
24
+ function f(e) {
25
+ for (let t = 0; t < e.textures.length; t++) if (e.textures[t].kind === "ramps") return t + 1;
26
+ return m(e);
27
+ }
28
+ function p(e, t) {
29
+ for (let n = 0; n < e.textures.length; n++) {
30
+ let r = e.textures[n];
31
+ if (r.kind === "atlas" && r.id === t) return n + 1;
32
+ }
33
+ return m(e);
34
+ }
35
+ function m(t) {
36
+ return t.textures.length + 1 < e ? t.textures.length + 1 : -1;
37
+ }
38
+ var h = {
39
+ maxVertices: 96,
40
+ maxVerticesInRun: 1024
41
+ };
42
+ function g(e, t) {
43
+ if (t.requiresStencil) return !1;
44
+ let n = e.drawBatch.length > 0 ? h.maxVerticesInRun : h.maxVertices;
45
+ return t.vertices.length >> 1 <= n;
46
+ }
47
+ function _(e, t) {
48
+ return e.batchState !== void 0 && !u(e, e.batchState) && i(e), e.drawBatch.wouldOverflow(t) && i(e), v(e);
49
+ }
50
+ function v(e) {
51
+ if (e.batchState === void 0) {
52
+ let t = e.state.colorMatrix, n = l(t);
53
+ e.batchState = {
54
+ alpha: n ? 1 : e.state.alpha,
55
+ colorMatrix: t,
56
+ clipDepth: s(e),
57
+ synthBold: 0,
58
+ foldsAlpha: n,
59
+ textures: []
60
+ };
61
+ }
62
+ return e.batchState;
63
+ }
64
+ function y(e, t, n) {
65
+ e.batchState !== void 0 && !u(e, e.batchState, t, n) && i(e), e.drawBatch.wouldOverflow(4) && i(e);
66
+ let r = v(e), a = d(r, t, n);
67
+ return a > r.textures.length && (r.textures.push({
68
+ kind: "bitmap",
69
+ image: t,
70
+ sampling: n
71
+ }), a = r.textures.length), {
72
+ staged: r,
73
+ slot: a
74
+ };
75
+ }
76
+ function b(e, t, n, r) {
77
+ e.batchState !== void 0 && (!u(e, e.batchState, void 0, void 0, r) || p(e.batchState, t) < 0) && i(e), e.drawBatch.wouldOverflow(4) && i(e);
78
+ let a = v(e);
79
+ a.synthBold = r;
80
+ let o = p(a, t);
81
+ return o > a.textures.length && (a.textures.push({
82
+ kind: "atlas",
83
+ id: t,
84
+ fieldScale: n
85
+ }), o = a.textures.length), {
86
+ staged: a,
87
+ slot: o
88
+ };
89
+ }
90
+ function x(e, t, n, r) {
91
+ e.gradRamps.wouldReshape(t, n) && i(e), e.batchState !== void 0 && (!u(e, e.batchState) || f(e.batchState) < 0) && i(e), e.drawBatch.wouldOverflow(r) && i(e);
92
+ let a = v(e), o = f(a);
93
+ return o > a.textures.length && (a.textures.push({ kind: "ramps" }), o = a.textures.length), {
94
+ staged: a,
95
+ slot: o,
96
+ rowV: e.gradRamps.rowV(e.gradRamps.upload(t, n))
97
+ };
98
+ }
99
+ function S(e, t, n) {
100
+ return (n ?? 1) * (t.foldsAlpha ? e.state.alpha : 1);
101
+ }
102
+ function C(e, n, r) {
103
+ let [i, a, o, s] = t(r.color);
104
+ return [
105
+ i,
106
+ a,
107
+ o,
108
+ s * S(e, n, r.opacity)
109
+ ];
110
+ }
111
+ function w(e, t, n) {
112
+ let [r, i, a, s] = C(e, _(e, 4), n);
113
+ e.drawBatch.pushRect(t.x, t.y, t.width, t.height, e.state.transform, r, i, a, s) || o(e, t, n, w);
114
+ }
115
+ function T(e, t, n) {
116
+ let [r, i, a, s] = C(e, _(e, t.vertices.length >> 1), n);
117
+ e.drawBatch.pushMesh(t, e.state.transform, r, i, a, s) || o(e, t, n, T);
118
+ }
119
+ function E(e, t, n) {
120
+ let { staged: r, slot: i, rowV: a } = x(e, n.stops, n.space, 4), { uv: s, post: l } = c(n, a);
121
+ e.drawBatch.pushGradientRect(t.x, t.y, t.width, t.height, e.state.transform, s, l, i, n.mode, 1, 1, 1, S(e, r, n.opacity)) || o(e, t, n, E);
122
+ }
123
+ function D(e, t, n) {
124
+ let { staged: r, slot: i, rowV: a } = x(e, n.stops, n.space, t.vertices.length >> 1), { uv: s, post: l } = c(n, a);
125
+ e.drawBatch.pushGradientMesh(t, e.state.transform, s, l, i, n.mode, 1, 1, 1, S(e, r, n.opacity)) || o(e, t, n, D);
126
+ }
127
+ function O(e, t, n) {
128
+ return n !== void 0 && g(e, t) ? (n.kind === "ramp" ? D(e, t, n) : T(e, t, n), !0) : (a(e), !1);
129
+ }
130
+ //#endregion
131
+ export { h as meshBatching, E as pushRampRect, w as pushRect, b as stageGlyphs, y as stageImage, _ as stageSolid, O as tryStageFill };
132
+
133
+ //# sourceMappingURL=batch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"batch.js","names":["isIdentityColorMatrix","cm","IDENTITY_COLOR_MATRIX","sameValues","stagedStateIsLive","staged","ctx","runClipDepth","synthBold","image","slotForBitmap","sampling","colorMatrix","i","entry","nextFreeSlot","slotForRamps","slotForAtlas","id","BATCH_TEXTURE_SLOTS","meshBatching","canBatchMesh","mesh","cap","stageSolid","flushBatch","vertices","openRun","foldsAlpha","stageImage","slot","stageGlyphs","atlasId","stageRamps","stops","space","stagedAlpha","opacity","stagedColor","r","g","b","a","resolveColor","paint","pushRect","fill","rect","retryUncut","pushMesh","pushRampRect","rampVertices","rowV","uv","post","pushRampMesh","tryStageFill","flushForOwnDraw"],"sources":["../../../src/renderer/draw/batch.ts"],"sourcesContent":["import type { ColorSpace, GradStop } from '@weasel-js/paint';\nimport { IDENTITY_COLOR_MATRIX } from '../state/GroupState';\nimport type { Mesh } from '@weasel-js/geom/tessellate';\nimport { resolveColor } from '../math/color';\nimport { BATCH_TEXTURE_SLOTS } from '../shaders/batchFill';\nimport type { DrawContext } from './drawContext';\nimport { sameValues } from './uniforms';\nimport { runClipDepth, retryUncut, flushForOwnDraw } from './clip';\nimport { flushBatch } from './flushBatch';\nimport { type BatchPaint, rampVertices } from './gradient';\n\n/**\n * The group state a staged run was built under.\n *\n * A run outlives the group it started in, so the state live when the flush\n * happens is not the state the rects belong to — the flush draws with these\n * values instead. Transform is absent because it rides the vertices; `alpha`\n * is 1 whenever it rode them too.\n */\nexport interface StagedBatchState {\n alpha: number;\n colorMatrix: Float32Array;\n clipDepth: number;\n /**\n * The SDF threshold shift `u_synthBold` draws this run under.\n *\n * A uniform rather than a vertex attribute, and so a thing that breaks a run.\n * A per-vertex float costs every rect and quad in the run (see \"Mode and slot\n * share one attribute\" in `shaders/batchFill.ts`): the batch's whole point is\n * one cheap buffer write a frame, and a float only glyphs read still widens the write\n * for every rect and quad beside them. What it costs instead is a break\n * wherever faked-bold text meets text that is not, which is a fallback path:\n * a registered bold face never sets this at all.\n */\n synthBold: number;\n /** Whether group alpha folded into the vertex colors. */\n foldsAlpha: boolean;\n /**\n * The textures this run samples, in the order they joined. A quad's vertices\n * carry `index + 1`, because slot 0 is the white texel every solid samples.\n *\n * Two kinds, because two caches own them: an image quad names an\n * `ImageBitmap` that `GLImageCache` keys by identity, a glyph names the\n * string id of a font atlas in `GLTextureCache`. They share the slot list so\n * a caption and the thumbnail above it share a draw.\n *\n * A bitmap's `sampling` is per entry and set per flush rather than at upload:\n * MAG_FILTER is state on the texture object, so the same bitmap drawn at both\n * filters in one frame needs two flushes, not two slots. An atlas carries no\n * sampling because `GLTextureCache` owns its filtering — and must keep\n * owning it: filtering a distance field destroys it, so a font atlas is\n * never mipmapped and never joins a shared image atlas.\n */\n textures: BatchTexture[];\n}\n\n/** One entry in a run's slot list. */\ntype BatchTexture =\n | { kind: 'bitmap'; image: ImageBitmap; sampling: 'linear' | 'nearest' }\n | { kind: 'atlas'; id: string; fieldScale: readonly [number, number] }\n | { kind: 'ramps' };\n\n/** Identity in row-major 4×5 leaves `src` untouched *and* leaves the shader's\n * clamp with nothing to do, which is what makes the alpha fold exact. */\nfunction isIdentityColorMatrix(cm: Float32Array): boolean {\n return cm === IDENTITY_COLOR_MATRIX || sameValues(IDENTITY_COLOR_MATRIX, cm);\n}\n\n/**\n * Whether the live group state would draw the staged run identically.\n *\n * By value, not by reference: a group carrying an identity color matrix still\n * goes through `compose4x5`, which allocates a new array holding equal numbers.\n * Twenty float compares are nothing against the draw call they save.\n */\nfunction stagedStateIsLive(\n ctx: DrawContext, staged: StagedBatchState,\n image?: ImageBitmap, sampling?: 'linear' | 'nearest',\n synthBold = 0,\n): boolean {\n if (staged.clipDepth !== (ctx.clipStack.length === 0 ? ctx.clipDepth : runClipDepth(ctx))) return false;\n // Solids and image quads ask with 0, which is what a run of them carries, so\n // this only ever breaks between two kinds of glyph.\n if (staged.synthBold !== synthBold) return false;\n if (!staged.foldsAlpha && staged.alpha !== ctx.state.alpha) return false;\n if (image !== undefined && slotForBitmap(staged, image, sampling!) < 0) return false;\n const colorMatrix = ctx.state.colorMatrix;\n return staged.colorMatrix === colorMatrix || sameValues(staged.colorMatrix, colorMatrix);\n}\n\n/**\n * The slot `image` would sample from in this run, or -1 if it cannot join.\n *\n * A bitmap already in the run reuses its slot — but only at the filter it went\n * in under, since MAG_FILTER belongs to the texture object and one draw cannot\n * have it both ways. Otherwise it takes the next free slot, and a run with none\n * left is a run this quad has to break.\n */\nfunction slotForBitmap(\n staged: StagedBatchState, image: ImageBitmap, sampling: 'linear' | 'nearest',\n): number {\n for (let i = 0; i < staged.textures.length; i++) {\n const entry = staged.textures[i];\n if (entry.kind !== 'bitmap' || entry.image !== image) continue;\n return entry.sampling === sampling ? i + 1 : -1;\n }\n return nextFreeSlot(staged);\n}\n\n/** The same for the ramp atlas, of which there is one — so every gradient in a\n * run shares the slot, however many distinct ramps they are. */\nfunction slotForRamps(staged: StagedBatchState): number {\n for (let i = 0; i < staged.textures.length; i++) {\n if (staged.textures[i].kind === 'ramps') return i + 1;\n }\n return nextFreeSlot(staged);\n}\n\n/** The same for a font atlas, which has no filter to disagree about. */\nfunction slotForAtlas(staged: StagedBatchState, id: string): number {\n for (let i = 0; i < staged.textures.length; i++) {\n const entry = staged.textures[i];\n if (entry.kind === 'atlas' && entry.id === id) return i + 1;\n }\n return nextFreeSlot(staged);\n}\n\n/** The slot a texture new to this run would take, or -1 if it is full. */\nfunction nextFreeSlot(staged: StagedBatchState): number {\n return staged.textures.length + 1 < BATCH_TEXTURE_SLOTS ? staged.textures.length + 1 : -1;\n}\n\n/**\n * Vertices above which a mesh keeps its own draw, by whether a run is open.\n *\n * Batching trades a draw call for copying and re-uploading the mesh every\n * frame, where a mesh already in the persistent cache costs nothing per frame\n * beyond the draw. Drawn alone with a run open, a mesh also closes that run and\n * switches program twice, so it breaks even far later there. Both values sit\n * below what `tests/perf/mesh-batch.spec.ts` measured, recorded in\n * `docs/TODO.md`: being wrong on the open-run side costs ten times more.\n */\nconst MAX_BATCHED_MESH_VERTICES = 96;\n\nconst MAX_BATCHED_MESH_VERTICES_IN_RUN = 1024;\n\n/** The caps {@link canBatchMesh} reads. Mutable only so `mesh-batch.spec.ts`\n * can time both sides of them in one page; the barrel does not export it. */\nexport const meshBatching = {\n maxVertices: MAX_BATCHED_MESH_VERTICES,\n maxVerticesInRun: MAX_BATCHED_MESH_VERTICES_IN_RUN,\n};\n\n/** Whether a mesh can join a run. Stencil fills need their own two-pass dance,\n * and a mesh past the cap is cheaper as its own draw. */\nfunction canBatchMesh(ctx: DrawContext, mesh: Mesh): boolean {\n if (mesh.requiresStencil) return false;\n const cap = ctx.drawBatch.length > 0 ? meshBatching.maxVerticesInRun : meshBatching.maxVertices;\n return (mesh.vertices.length >> 1) <= cap;\n}\n\n/**\n * Open or continue a run for `vertices` more, flushing first if the run would\n * overflow or if the live group state no longer matches what it was staged\n * under. Returns the staged state, which the caller reads to resolve alpha.\n *\n * Fill opacity folds into the vertex alpha, exactly as `u_color` carried it\n * when each shape was its own draw. Group alpha folds in too, but only under an\n * identity color matrix: the shader is `a = clamp(CM * src + bias).a * u_alpha`,\n * so with a real matrix between them a pre-multiplied vertex alpha is a\n * different number. There it stays a uniform, and a differing alpha breaks the\n * run as before.\n */\nexport function stageSolid(ctx: DrawContext, vertices: number): StagedBatchState {\n if (ctx.batchState !== undefined && !stagedStateIsLive(ctx, ctx.batchState)) flushBatch(ctx);\n if (ctx.drawBatch.wouldOverflow(vertices)) flushBatch(ctx);\n return openRun(ctx);\n}\n\n/** The staged state, opening a run under the live group state if none is. */\nfunction openRun(ctx: DrawContext): StagedBatchState {\n if (ctx.batchState === undefined) {\n const colorMatrix = ctx.state.colorMatrix;\n const foldsAlpha = isIdentityColorMatrix(colorMatrix);\n ctx.batchState = {\n alpha: foldsAlpha ? 1 : ctx.state.alpha,\n colorMatrix,\n clipDepth: runClipDepth(ctx),\n synthBold: 0,\n foldsAlpha,\n textures: [],\n };\n }\n return ctx.batchState;\n}\n\n/**\n * Open or continue a run for one more image quad, flushing first if the run\n * would overflow or cannot give this bitmap a slot.\n *\n * A run adopts a bitmap it has not seen rather than breaking, which is what\n * lets a wall's ground rect and its atlas quad share a draw, and what lets a\n * cell's art and its badge share one too. Returns the staged state and the slot\n * the quad's vertices must carry.\n */\nexport function stageImage(\n ctx: DrawContext, image: ImageBitmap, sampling: 'linear' | 'nearest',\n): { staged: StagedBatchState; slot: number } {\n if (ctx.batchState !== undefined\n && !stagedStateIsLive(ctx, ctx.batchState, image, sampling)) {\n flushBatch(ctx);\n }\n if (ctx.drawBatch.wouldOverflow(4)) flushBatch(ctx);\n const staged = openRun(ctx);\n let slot = slotForBitmap(staged, image, sampling);\n if (slot > staged.textures.length) {\n staged.textures.push({ kind: 'bitmap', image, sampling });\n slot = staged.textures.length;\n }\n return { staged, slot };\n}\n\n/**\n * Open or continue a run for a glyph off the font atlas `atlasId`, flushing\n * first if the run would overflow or has no slot left for it.\n *\n * The atlas is the unit of coalescing the way a sprite sheet is: every glyph a\n * face contributes to a frame shares one texture, so a paragraph is one run\n * however many glyphs it is, and a second face costs one more slot rather than\n * a flush per word.\n */\nexport function stageGlyphs(\n ctx: DrawContext, atlasId: string, fieldScale: readonly [number, number], synthBold: number,\n): { staged: StagedBatchState; slot: number } {\n if (ctx.batchState !== undefined\n && (!stagedStateIsLive(ctx, ctx.batchState, undefined, undefined, synthBold)\n || slotForAtlas(ctx.batchState, atlasId) < 0)) {\n flushBatch(ctx);\n }\n if (ctx.drawBatch.wouldOverflow(4)) flushBatch(ctx);\n const staged = openRun(ctx);\n // An empty run adopts the threshold; one that already has vertices agreed to\n // it above, since a mismatch flushed.\n staged.synthBold = synthBold;\n let slot = slotForAtlas(staged, atlasId);\n if (slot > staged.textures.length) {\n staged.textures.push({ kind: 'atlas', id: atlasId, fieldScale });\n slot = staged.textures.length;\n }\n return { staged, slot };\n}\n\n/**\n * Open or continue a run for geometry filled from the ramp atlas, flushing\n * first if the run would overflow, has no slot left, or if baking `stops` would\n * move the rows already staged.\n *\n * **That last one is the trap.** A staged vertex names its ramp by where the\n * row sits, so growing the atlas — which changes every row's `v` — or recycling\n * a row repaints geometry already staged with somebody else's gradient. Both\n * are irreversible once done, so the question is asked before the bake, not\n * after.\n */\nfunction stageRamps(\n ctx: DrawContext, stops: GradStop[], space: ColorSpace, vertices: number,\n): { staged: StagedBatchState; slot: number; rowV: number } {\n if (ctx.gradRamps.wouldReshape(stops, space)) flushBatch(ctx);\n if (ctx.batchState !== undefined\n && (!stagedStateIsLive(ctx, ctx.batchState) || slotForRamps(ctx.batchState) < 0)) {\n flushBatch(ctx);\n }\n if (ctx.drawBatch.wouldOverflow(vertices)) flushBatch(ctx);\n const staged = openRun(ctx);\n let slot = slotForRamps(staged);\n if (slot > staged.textures.length) {\n staged.textures.push({ kind: 'ramps' });\n slot = staged.textures.length;\n }\n return { staged, slot, rowV: ctx.gradRamps.rowV(ctx.gradRamps.upload(stops, space)) };\n}\n\n/** Alpha a batched paint's vertices carry: its own opacity, and the group's\n * under an identity color matrix. */\nfunction stagedAlpha(\n ctx: DrawContext, staged: StagedBatchState, opacity: number | undefined,\n): number {\n return (opacity ?? 1) * (staged.foldsAlpha ? ctx.state.alpha : 1);\n}\n\n/** Straight-alpha rgba for a solid paint under the staged state. */\nfunction stagedColor(\n ctx: DrawContext, staged: StagedBatchState,\n paint: { color: string; opacity?: number },\n): [number, number, number, number] {\n const [r, g, b, a] = resolveColor(paint.color);\n return [r, g, b, a * stagedAlpha(ctx, staged, paint.opacity)];\n}\n\nexport function pushRect(\n ctx: DrawContext,\n rect: { x: number; y: number; width: number; height: number },\n fill: { color: string; opacity?: number },\n): void {\n const staged = stageSolid(ctx, 4);\n const [r, g, b, a] = stagedColor(ctx, staged, fill);\n if (!ctx.drawBatch.pushRect(\n rect.x, rect.y, rect.width, rect.height, ctx.state.transform, r, g, b, a,\n )) retryUncut(ctx, rect, fill, pushRect);\n}\n\nfunction pushMesh(\n ctx: DrawContext,\n mesh: Mesh,\n paint: { color: string; opacity?: number },\n): void {\n const staged = stageSolid(ctx, mesh.vertices.length >> 1);\n const [r, g, b, a] = stagedColor(ctx, staged, paint);\n if (!ctx.drawBatch.pushMesh(mesh, ctx.state.transform, r, g, b, a)) {\n retryUncut(ctx, mesh, paint, pushMesh);\n }\n}\n\nexport function pushRampRect(\n ctx: DrawContext,\n rect: { x: number; y: number; width: number; height: number },\n paint: Extract<BatchPaint, { kind: 'ramp' }>,\n): void {\n const { staged, slot, rowV } = stageRamps(ctx, paint.stops, paint.space, 4);\n const { uv, post } = rampVertices(paint, rowV);\n // White vertices, so the ramp texel passes through as its own color and the\n // alpha channel carries what `u_opacity` and `u_alpha` used to.\n if (!ctx.drawBatch.pushGradientRect(\n rect.x, rect.y, rect.width, rect.height, ctx.state.transform,\n uv, post, slot, paint.mode, 1, 1, 1, stagedAlpha(ctx, staged, paint.opacity),\n )) retryUncut(ctx, rect, paint, pushRampRect);\n}\n\nfunction pushRampMesh(\n ctx: DrawContext, mesh: Mesh, paint: Extract<BatchPaint, { kind: 'ramp' }>,\n): void {\n const { staged, slot, rowV } = stageRamps(ctx, paint.stops, paint.space, mesh.vertices.length >> 1);\n const { uv, post } = rampVertices(paint, rowV);\n if (!ctx.drawBatch.pushGradientMesh(\n mesh, ctx.state.transform,\n uv, post, slot, paint.mode, 1, 1, 1, stagedAlpha(ctx, staged, paint.opacity),\n )) retryUncut(ctx, mesh, paint, pushRampMesh);\n}\n\n/**\n * Stage `mesh` into the run, or drain the run so the caller can draw it itself.\n *\n * `true` means the mesh is in the batch and the caller is done. `false` comes\n * back only *after* a flush, so an emitter cannot earn permission to draw for\n * itself without also draining the batch. `paint` is `undefined` when it is one\n * no run can express — see `batchPaint`.\n */\nexport function tryStageFill(\n ctx: DrawContext,\n mesh: Mesh,\n paint: BatchPaint | undefined,\n): boolean {\n if (paint !== undefined && canBatchMesh(ctx, mesh)) {\n if (paint.kind === 'ramp') pushRampMesh(ctx, mesh, paint);\n else pushMesh(ctx, mesh, paint);\n return true;\n }\n flushForOwnDraw(ctx);\n return false;\n}\n"],"mappings":";;;;;;;;AAgEA,SAASA,EAAsB,GAA2B;CACxD,OAAOC,MAAOC,KAAyBC,EAAWD,GAAuBD,CAAE;AAC7E;AASA,SAASG,EACP,GAAkB,GAClB,GAAqB,GACrB,IAAY,GACH;CAMT,IALIC,EAAO,eAAeC,EAAI,UAAU,WAAW,IAAIA,EAAI,YAAYC,EAAaD,CAAG,MAGnFD,EAAO,cAAcG,KACrB,CAACH,EAAO,cAAcA,EAAO,UAAUC,EAAI,MAAM,SACjDG,MAAU,KAAA,KAAaC,EAAcL,GAAQI,GAAOE,CAAS,IAAI,GAAG,OAAO;CAC/E,IAAMC,IAAcN,EAAI,MAAM;CAC9B,OAAOD,EAAO,gBAAgBO,KAAeT,EAAWE,EAAO,aAAaO,CAAW;AACzF;AAUA,SAASF,EACP,GAA0B,GAAoB,GACtC;CACR,KAAK,IAAIG,IAAI,GAAGA,IAAIR,EAAO,SAAS,QAAQ,KAAK;EAC/C,IAAMS,IAAQT,EAAO,SAASQ;EAC9B,IAAIC,EAAM,SAAS,YAAYA,EAAM,UAAUL,GAC/C,OAAOK,EAAM,aAAaH,IAAWE,IAAI,IAAI;CAC/C;CACA,OAAOE,EAAaV,CAAM;AAC5B;AAIA,SAASW,EAAa,GAAkC;CACtD,KAAK,IAAIH,IAAI,GAAGA,IAAIR,EAAO,SAAS,QAAQ,KAC1C,IAAIA,EAAO,SAASQ,EAAE,CAAC,SAAS,SAAS,OAAOA,IAAI;CAEtD,OAAOE,EAAaV,CAAM;AAC5B;AAGA,SAASY,EAAa,GAA0B,GAAoB;CAClE,KAAK,IAAIJ,IAAI,GAAGA,IAAIR,EAAO,SAAS,QAAQ,KAAK;EAC/C,IAAMS,IAAQT,EAAO,SAASQ;EAC9B,IAAIC,EAAM,SAAS,WAAWA,EAAM,OAAOI,GAAI,OAAOL,IAAI;CAC5D;CACA,OAAOE,EAAaV,CAAM;AAC5B;AAGA,SAASU,EAAa,GAAkC;CACtD,OAAOV,EAAO,SAAS,SAAS,IAAIc,IAAsBd,EAAO,SAAS,SAAS,IAAI;AACzF;AAkBA,IAAae,IAAe;CAC1B,aAAa;CACb,kBAAkB;AACpB;AAIA,SAASC,EAAa,GAAkB,GAAqB;CAC3D,IAAIC,EAAK,iBAAiB,OAAO;CACjC,IAAMC,IAAMjB,EAAI,UAAU,SAAS,IAAIc,EAAa,mBAAmBA,EAAa;CACpF,OAAQE,EAAK,SAAS,UAAU,KAAMC;AACxC;AAcA,SAAgBC,EAAW,GAAkB,GAAoC;CAG/E,OAFIlB,EAAI,eAAe,KAAA,KAAa,CAACF,EAAkBE,GAAKA,EAAI,UAAU,KAAGmB,EAAWnB,CAAG,GACvFA,EAAI,UAAU,cAAcoB,CAAQ,KAAGD,EAAWnB,CAAG,GAClDqB,EAAQrB,CAAG;AACpB;AAGA,SAASqB,EAAQ,GAAoC;CACnD,IAAIrB,EAAI,eAAe,KAAA,GAAW;EAChC,IAAMM,IAAcN,EAAI,MAAM,aACxBsB,IAAa5B,EAAsBY,CAAW;EACpD,EAAI,aAAa;GACf,OAAOgB,IAAa,IAAItB,EAAI,MAAM;GAClC;GACA,WAAWC,EAAaD,CAAG;GAC3B,WAAW;GACX;GACA,UAAU,CAAC;EACb;CACF;CACA,OAAOA,EAAI;AACb;AAWA,SAAgBuB,EACd,GAAkB,GAAoB,GACM;CAK5C,AAJIvB,EAAI,eAAe,KAAA,KAChB,CAACF,EAAkBE,GAAKA,EAAI,YAAYG,GAAOE,CAAQ,KAC5Dc,EAAWnB,CAAG,GAEZA,EAAI,UAAU,cAAc,CAAC,KAAGmB,EAAWnB,CAAG;CAClD,IAAMD,IAASsB,EAAQrB,CAAG,GACtBwB,IAAOpB,EAAcL,GAAQI,GAAOE,CAAQ;CAKhD,OAJImB,IAAOzB,EAAO,SAAS,WACzBA,EAAO,SAAS,KAAK;EAAE,MAAM;EAAU;EAAO;CAAS,CAAC,GACxD,IAAOA,EAAO,SAAS,SAElB;EAAE;EAAQ;CAAK;AACxB;AAWA,SAAgB0B,EACd,GAAkB,GAAiB,GAAuC,GAC9B;CAM5C,AALIzB,EAAI,eAAe,KAAA,MACf,CAACF,EAAkBE,GAAKA,EAAI,YAAY,KAAA,GAAW,KAAA,GAAWE,CAAS,KACpES,EAAaX,EAAI,YAAY0B,CAAO,IAAI,MACjDP,EAAWnB,CAAG,GAEZA,EAAI,UAAU,cAAc,CAAC,KAAGmB,EAAWnB,CAAG;CAClD,IAAMD,IAASsB,EAAQrB,CAAG;CAG1B,EAAO,YAAYE;CACnB,IAAIsB,IAAOb,EAAaZ,GAAQ2B,CAAO;CAKvC,OAJIF,IAAOzB,EAAO,SAAS,WACzBA,EAAO,SAAS,KAAK;EAAE,MAAM;EAAS,IAAI2B;EAAS;CAAW,CAAC,GAC/D,IAAO3B,EAAO,SAAS,SAElB;EAAE;EAAQ;CAAK;AACxB;AAaA,SAAS4B,EACP,GAAkB,GAAmB,GAAmB,GACE;CAM1D,AALI3B,EAAI,UAAU,aAAa4B,GAAOC,CAAK,KAAGV,EAAWnB,CAAG,GACxDA,EAAI,eAAe,KAAA,MACf,CAACF,EAAkBE,GAAKA,EAAI,UAAU,KAAKU,EAAaV,EAAI,UAAU,IAAI,MAChFmB,EAAWnB,CAAG,GAEZA,EAAI,UAAU,cAAcoB,CAAQ,KAAGD,EAAWnB,CAAG;CACzD,IAAMD,IAASsB,EAAQrB,CAAG,GACtBwB,IAAOd,EAAaX,CAAM;CAK9B,OAJIyB,IAAOzB,EAAO,SAAS,WACzBA,EAAO,SAAS,KAAK,EAAE,MAAM,QAAQ,CAAC,GACtC,IAAOA,EAAO,SAAS,SAElB;EAAE;EAAQ;EAAM,MAAMC,EAAI,UAAU,KAAKA,EAAI,UAAU,OAAO4B,GAAOC,CAAK,CAAC;CAAE;AACtF;AAIA,SAASC,EACP,GAAkB,GAA0B,GACpC;CACR,QAAQC,KAAW,MAAMhC,EAAO,aAAaC,EAAI,MAAM,QAAQ;AACjE;AAGA,SAASgC,EACP,GAAkB,GAClB,GACkC;CAClC,IAAM,CAACC,GAAGC,GAAGC,GAAGC,KAAKC,EAAaC,EAAM,KAAK;CAC7C,OAAO;EAACL;EAAGC;EAAGC;EAAGC,IAAIN,EAAY9B,GAAKD,GAAQuC,EAAM,OAAO;CAAC;AAC9D;AAEA,SAAgBC,EACd,GACA,GACA,GACM;CAEN,IAAM,CAAC,GAAGL,GAAGC,GAAGC,KAAKJ,EAAYhC,GADlBkB,EAAWlB,GAAK,CACO,GAAQwC,CAAI;CAClD,AAAKxC,EAAI,UAAU,SACjByC,EAAK,GAAGA,EAAK,GAAGA,EAAK,OAAOA,EAAK,QAAQzC,EAAI,MAAM,WAAW,GAAGkC,GAAGC,GAAGC,CACzE,KAAGM,EAAW1C,GAAKyC,GAAMD,GAAMD,CAAQ;AACzC;AAEA,SAASI,EACP,GACA,GACA,GACM;CAEN,IAAM,CAAC,GAAGT,GAAGC,GAAGC,KAAKJ,EAAYhC,GADlBkB,EAAWlB,GAAKgB,EAAK,SAAS,UAAU,CACjB,GAAQsB,CAAK;CACnD,AAAKtC,EAAI,UAAU,SAASgB,GAAMhB,EAAI,MAAM,WAAW,GAAGkC,GAAGC,GAAGC,CAAC,KAC/DM,EAAW1C,GAAKgB,GAAMsB,GAAOK,CAAQ;AAEzC;AAEA,SAAgBC,EACd,GACA,GACA,GACM;CACN,IAAM,EAAE,WAAQ,SAAM,YAASjB,EAAW3B,GAAKsC,EAAM,OAAOA,EAAM,OAAO,CAAC,GACpE,EAAE,OAAI,YAASO,EAAaP,GAAOQ,CAAI;CAG7C,AAAK9C,EAAI,UAAU,iBACjByC,EAAK,GAAGA,EAAK,GAAGA,EAAK,OAAOA,EAAK,QAAQzC,EAAI,MAAM,WACnD+C,GAAIC,GAAMxB,GAAMc,EAAM,MAAM,GAAG,GAAG,GAAGR,EAAY9B,GAAKD,GAAQuC,EAAM,OAAO,CAC7E,KAAGI,EAAW1C,GAAKyC,GAAMH,GAAOM,CAAY;AAC9C;AAEA,SAASK,EACP,GAAkB,GAAY,GACxB;CACN,IAAM,EAAE,WAAQ,SAAM,YAAStB,EAAW3B,GAAKsC,EAAM,OAAOA,EAAM,OAAOtB,EAAK,SAAS,UAAU,CAAC,GAC5F,EAAE,OAAI,YAAS6B,EAAaP,GAAOQ,CAAI;CAC7C,AAAK9C,EAAI,UAAU,iBACjBgB,GAAMhB,EAAI,MAAM,WAChB+C,GAAIC,GAAMxB,GAAMc,EAAM,MAAM,GAAG,GAAG,GAAGR,EAAY9B,GAAKD,GAAQuC,EAAM,OAAO,CAC7E,KAAGI,EAAW1C,GAAKgB,GAAMsB,GAAOW,CAAY;AAC9C;AAUA,SAAgBC,EACd,GACA,GACA,GACS;CAOT,OANIZ,MAAU,KAAA,KAAavB,EAAaf,GAAKgB,CAAI,KAC3CsB,EAAM,SAAS,SAAQW,EAAajD,GAAKgB,GAAMsB,CAAK,IACnDK,EAAS3C,GAAKgB,GAAMsB,CAAK,GACvB,OAETa,EAAgBnD,CAAG,GACZ;AACT"}
@@ -0,0 +1,89 @@
1
+ import { drawTriangles as e } from "./drawTriangles.js";
2
+ import { ancestorMask as t } from "./stencil.js";
3
+ import { setProjAndModel as n } from "./uniforms.js";
4
+ import { axisAlignedClipRect as r, intersectClipRects as i } from "../batchClip.js";
5
+ import { fillMeshHandle as a } from "./mesh.js";
6
+ import { flushBatch as o } from "./flushBatch.js";
7
+ //#region src/renderer/draw/clip.ts
8
+ function s(e, t) {
9
+ let n = e.clipStack.reduce((e, t) => e + +(t.depth === 0), 0);
10
+ if (e.clipDepth + n + 1 > 7) throw Error("weasel: clip nesting depth exceeded (max 7). You can't nest more than 7 levels of clipped containers in a single draw tree. Flatten the hierarchy or compose poses outside the scene graph.");
11
+ c(e, t);
12
+ }
13
+ function c(e, t) {
14
+ let n = e.state.transform, i = r(t, n);
15
+ if (i === null) {
16
+ u(e);
17
+ let r = e.clipDepth + 1;
18
+ v(e, t, r), e.clipDepth = r, e.clipStack.push({
19
+ path: t,
20
+ transform: n,
21
+ rect: null,
22
+ depth: r
23
+ });
24
+ } else e.clipStack.push({
25
+ path: t,
26
+ transform: n,
27
+ rect: i,
28
+ depth: 0
29
+ });
30
+ d(e);
31
+ }
32
+ function l(e) {
33
+ let t = e.clipStack.pop();
34
+ t.depth > 0 && (y(e, t.path, t.depth - 1, t.transform), e.clipDepth = t.depth - 1), d(e);
35
+ }
36
+ function u(e) {
37
+ for (let t of e.clipStack) {
38
+ if (t.depth !== 0) continue;
39
+ let n = e.clipDepth + 1;
40
+ v(e, t.path, n, t.transform), t.depth = n, e.clipDepth = n;
41
+ }
42
+ }
43
+ function d(e) {
44
+ let t = null;
45
+ for (let n of e.clipStack) n.rect && (t = t ? i(t, n.rect) : n.rect);
46
+ e.drawBatch.clip = t;
47
+ }
48
+ function f(e) {
49
+ let t = e.clipStack;
50
+ if (t.length === 0 || e.uncut) return e.clipDepth;
51
+ for (let e = t.length - 1; e >= 0; e--) if (t[e].rect === null) return t[e].depth;
52
+ for (let e of t) if (e.depth > 0) return e.depth - 1;
53
+ return e.clipDepth;
54
+ }
55
+ function p(e) {
56
+ u(e);
57
+ let t = e.drawBatch.clip;
58
+ return e.drawBatch.clip = null, e.uncut = !0, t;
59
+ }
60
+ function m(e, t) {
61
+ e.drawBatch.clip = t, e.uncut = !1;
62
+ }
63
+ function h(e, t, n, r) {
64
+ let i = p(e);
65
+ r(e, t, n), m(e, i);
66
+ }
67
+ function g(e) {
68
+ o(e), e.clipStack.length > 0 && u(e);
69
+ }
70
+ function _(t, r, i) {
71
+ let o = t.gl, s = a(t, r);
72
+ o.useProgram(t.pathFill.handle), o.bindVertexArray(s.vao), n(t, t.pathFill, i), e(t, s.indexCount, t.gl.UNSIGNED_INT), o.bindVertexArray(null);
73
+ }
74
+ function v(e, n, r, i = e.state.transform) {
75
+ o(e);
76
+ let s = e.gl, c = t(r - 1), l = 1 << r, u = c | l;
77
+ s.enable(s.STENCIL_TEST), s.colorMask(!1, !1, !1, !1), a(e, n).requiresStencil ? (s.stencilMask(1), s.stencilFunc(s.ALWAYS, 0, 1), s.stencilOp(s.KEEP, s.KEEP, s.INVERT), _(e, n, i), s.stencilMask(l), s.stencilFunc(s.EQUAL, u | 1, c | 1), s.stencilOp(s.KEEP, s.KEEP, s.REPLACE), _(e, n, i), s.stencilMask(1), s.stencilFunc(s.ALWAYS, 0, 1), s.stencilOp(s.KEEP, s.KEEP, s.INVERT), _(e, n, i)) : (s.stencilMask(l), s.stencilFunc(s.EQUAL, u, c), s.stencilOp(s.KEEP, s.KEEP, s.REPLACE), _(e, n, i)), s.colorMask(!0, !0, !0, !0), s.stencilMask(255);
78
+ }
79
+ function y(e, n, r, i = e.state.transform) {
80
+ e.batchState !== void 0 && e.batchState.clipDepth > r && o(e);
81
+ let a = e.gl;
82
+ a.enable(a.STENCIL_TEST);
83
+ let s = 1 << r + 1, c = t(r) | s;
84
+ a.colorMask(!1, !1, !1, !1), a.stencilMask(s), a.stencilFunc(a.EQUAL, c, c), a.stencilOp(a.KEEP, a.KEEP, a.ZERO), _(e, n, i), a.colorMask(!0, !0, !0, !0), a.stencilMask(255);
85
+ }
86
+ //#endregion
87
+ export { s as enterGroupClip, p as enterUncut, g as flushForOwnDraw, l as leaveClip, m as leaveUncut, y as popClip, v as pushClip, h as retryUncut, f as runClipDepth };
88
+
89
+ //# sourceMappingURL=clip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"clip.js","names":["enterGroupClip","pending","ctx","n","clip","enterClip","transform","rect","axisAlignedClipRect","path","depth","pushClip","leaveClip","entry","popClip","syncBatchClip","materializeClips","intersectClipRects","runClipDepth","stack","i","enterUncut","cut","leaveUncut","retryUncut","fn","a","b","flushForOwnDraw","flushBatch","rasterizePathToStencil","gl","handle","fillMeshHandle","setProjAndModel","model","drawTriangles","ancestors","ancestorMask","newDepth","newBit","ref","oldDepth","oldBit"],"sources":["../../../src/renderer/draw/clip.ts"],"sourcesContent":["import type { Path } from '@weasel-js/geom';\nimport type { GlMat3 } from '../math/mat3';\nimport { axisAlignedClipRect, intersectClipRects, type ClipRect } from '../batchClip';\nimport type { DrawContext } from './drawContext';\nimport { drawTriangles } from './drawTriangles';\nimport { fillMeshHandle } from './mesh';\nimport { setProjAndModel } from './uniforms';\nimport { ancestorMask } from './stencil';\nimport { flushBatch } from './flushBatch';\n\n/** `enterClip` for a group command, refusing one past the stencil's budget. */\nexport function enterGroupClip(ctx: DrawContext, clip: Path): void {\n const pending = ctx.clipStack.reduce((n, e) => n + (e.depth === 0 ? 1 : 0), 0);\n if (ctx.clipDepth + pending + 1 > 7) {\n throw new Error(\n 'weasel: clip nesting depth exceeded (max 7). You can\\'t nest more than 7 levels ' +\n 'of clipped containers in a single draw tree. Flatten the hierarchy or compose ' +\n 'poses outside the scene graph.',\n );\n }\n enterClip(ctx, clip);\n}\n\n/**\n * Push a group's clip.\n *\n * A clip only the stencil can express takes its bit now. An axis-aligned rect\n * takes none: staged geometry is cut to it on the CPU (`batchClip.ts`), so\n * content inside it joins the run outside it instead of costing a flush on\n * the way in and another on the way out. It takes a bit only if something that\n * draws for itself turns up inside it — see `flushForOwnDraw`.\n */\nfunction enterClip(ctx: DrawContext, path: Path): void {\n const transform = ctx.state.transform;\n const rect = axisAlignedClipRect(path, transform);\n if (rect === null) {\n // Bits nest in stack order, so any rect clip still without one takes it\n // first.\n materializeClips(ctx);\n const depth = ctx.clipDepth + 1;\n pushClip(ctx, path, depth);\n ctx.clipDepth = depth;\n ctx.clipStack.push({ path, transform, rect: null, depth });\n } else {\n ctx.clipStack.push({ path, transform, rect, depth: 0 });\n }\n syncBatchClip(ctx);\n}\n\nexport function leaveClip(ctx: DrawContext): void {\n const entry = ctx.clipStack.pop()!;\n if (entry.depth > 0) {\n popClip(ctx, entry.path, entry.depth - 1, entry.transform);\n ctx.clipDepth = entry.depth - 1;\n }\n syncBatchClip(ctx);\n}\n\n/** Give every rect clip on the stack its stencil bit, for a draw the CPU cut\n * cannot reach. */\nfunction materializeClips(ctx: DrawContext): void {\n for (const entry of ctx.clipStack) {\n if (entry.depth !== 0) continue;\n const depth = ctx.clipDepth + 1;\n pushClip(ctx, entry.path, depth, entry.transform);\n entry.depth = depth;\n ctx.clipDepth = depth;\n }\n}\n\nfunction syncBatchClip(ctx: DrawContext): void {\n let rect: ClipRect | null = null;\n for (const entry of ctx.clipStack) {\n if (entry.rect) rect = rect ? intersectClipRects(rect, entry.rect) : entry.rect;\n }\n ctx.drawBatch.clip = rect;\n}\n\n/**\n * The clip depth a run is staged and drawn at: the innermost clip only the\n * stencil can express. Rect clips are left out whether or not they hold a bit,\n * because the CPU cut already applies them — which is what lets a run cross\n * them.\n */\nexport function runClipDepth(ctx: DrawContext): number {\n const stack = ctx.clipStack;\n if (stack.length === 0 || ctx.uncut) return ctx.clipDepth;\n for (let i = stack.length - 1; i >= 0; i--) {\n if (stack[i].rect === null) return stack[i].depth;\n }\n // Only rect clips: whatever depth held before the first of them took a bit.\n for (const entry of stack) if (entry.depth > 0) return entry.depth - 1;\n return ctx.clipDepth;\n}\n\n/**\n * Put the rect clips on the stencil and stop cutting, for an item the batch\n * refused to cut — one with a slanted edge across a clip (see\n * `DrawBatch.clipQuad`). Staged again between this and `leaveUncut`, the item\n * sees the full stencil depth and lands in a run of its own under every clip.\n * Returns the cut to hand back.\n *\n * A pair rather than a callback: the staging paths are hot, and a closure\n * over their arguments would cost an allocation on every call, refused or not.\n */\nexport function enterUncut(ctx: DrawContext): ClipRect | null {\n materializeClips(ctx);\n const cut = ctx.drawBatch.clip;\n ctx.drawBatch.clip = null;\n ctx.uncut = true;\n return cut;\n}\n\nexport function leaveUncut(ctx: DrawContext, cut: ClipRect | null): void {\n ctx.drawBatch.clip = cut;\n ctx.uncut = false;\n}\n\n/** `fn(ctx, a, b)` again, uncut — for the stage-and-push helpers, which pass\n * themselves. */\nexport function retryUncut<A, B>(\n ctx: DrawContext, a: A, b: B, fn: (ctx: DrawContext, a: A, b: B) => void,\n): void {\n const cut = enterUncut(ctx);\n fn(ctx, a, b);\n leaveUncut(ctx, cut);\n}\n\n/**\n * Drain the run before a draw that does not go through it, and give that draw\n * the stencil it tests against. Every such draw starts here or behind a\n * `tryStageFill` that returned `false`, which ends the same way.\n */\nexport function flushForOwnDraw(ctx: DrawContext): void {\n flushBatch(ctx);\n if (ctx.clipStack.length > 0) materializeClips(ctx);\n}\n\n/**\n * Rasterize a path into the stencil buffer using the pathFill shader geometry.\n * The caller is responsible for setting stencilFunc / stencilOp / stencilMask\n * and colorMask before calling.\n */\nfunction rasterizePathToStencil(ctx: DrawContext, path: Path, model: GlMat3): void {\n const gl = ctx.gl;\n const handle = fillMeshHandle(ctx, path);\n gl.useProgram(ctx.pathFill.handle);\n gl.bindVertexArray(handle.vao);\n setProjAndModel(ctx, ctx.pathFill, model);\n drawTriangles(ctx, handle.indexCount, ctx.gl.UNSIGNED_INT);\n gl.bindVertexArray(null);\n}\n\n/**\n * Push a clip level. Rasterizes the clip path into the stencil buffer,\n * setting bit `newDepth` where (a) the path's fragment passes AND (b) all\n * ancestor clip bits are already set.\n *\n * Invariant: restores stencilMask(0xFF) on exit so callers (draw functions)\n * can rely on an unnarrowed mask after clip ops complete.\n */\nexport function pushClip(\n ctx: DrawContext, path: Path, newDepth: number, model: GlMat3 = ctx.state.transform,\n): void {\n // First, not last: a run staged outside the clip would otherwise draw under\n // a mask it never had.\n flushBatch(ctx);\n const gl = ctx.gl;\n const ancestors = ancestorMask(newDepth - 1);\n const newBit = 1 << newDepth;\n const ref = ancestors | newBit;\n\n gl.enable(gl.STENCIL_TEST);\n gl.colorMask(false, false, false, false);\n if (fillMeshHandle(ctx, path).requiresStencil) {\n // Fans, one per contour: their union is not the path. Parity goes on\n // bit 0, the clip bit is written where parity is odd, and drawing the\n // fans a third time returns bit 0 to zero.\n gl.stencilMask(0x01);\n gl.stencilFunc(gl.ALWAYS, 0, 0x01);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT);\n rasterizePathToStencil(ctx, path, model);\n gl.stencilMask(newBit);\n gl.stencilFunc(gl.EQUAL, ref | 0x01, ancestors | 0x01);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);\n rasterizePathToStencil(ctx, path, model);\n gl.stencilMask(0x01);\n gl.stencilFunc(gl.ALWAYS, 0, 0x01);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.INVERT);\n rasterizePathToStencil(ctx, path, model);\n } else {\n gl.stencilMask(newBit);\n gl.stencilFunc(gl.EQUAL, ref, ancestors);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.REPLACE);\n rasterizePathToStencil(ctx, path, model);\n }\n\n gl.colorMask(true, true, true, true);\n // Restore full mask so subsequent draw functions don't inherit a narrowed mask.\n gl.stencilMask(0xFF);\n}\n\n/**\n * Pop a clip level. Rasterizes the same path again, clearing bit\n * `oldDepth + 1` where it was set during the matching push.\n *\n * Must re-enable STENCIL_TEST because child draw functions (drawPathFillStencil,\n * drawPathStrokeStenciled) call gl.disable(STENCIL_TEST) at their end. If\n * one of those was the last child before popClip runs, the test would be off\n * and rasterizePathToStencil would write nothing.\n *\n * Invariant: restores stencilMask(0xFF) on exit so callers are not left with\n * a narrowed mask.\n */\nexport function popClip(\n ctx: DrawContext, path: Path, oldDepth: number, model: GlMat3 = ctx.state.transform,\n): void {\n // First, not last: past here the mask is gone, and these pixels belonged\n // inside it. A run staged below this bit does not test it, so it lives on.\n if (ctx.batchState !== undefined && ctx.batchState.clipDepth > oldDepth) flushBatch(ctx);\n const gl = ctx.gl;\n // Re-enable stencil: child draw functions (evenodd/stenciled-stroke) disable\n // it at their end; we must set it before writing the clear pass.\n gl.enable(gl.STENCIL_TEST);\n\n const oldBit = 1 << (oldDepth + 1);\n const ref = ancestorMask(oldDepth) | oldBit;\n\n gl.colorMask(false, false, false, false);\n gl.stencilMask(oldBit);\n gl.stencilFunc(gl.EQUAL, ref, ref);\n gl.stencilOp(gl.KEEP, gl.KEEP, gl.ZERO);\n\n rasterizePathToStencil(ctx, path, model);\n\n gl.colorMask(true, true, true, true);\n // Restore full mask so subsequent draw functions don't inherit a narrowed mask.\n gl.stencilMask(0xFF);\n}\n"],"mappings":"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"}
@@ -0,0 +1,230 @@
1
+ import { getTexture as e } from "../textures/registerTexture.js";
2
+ import { mat3 as t } from "../math/mat3.js";
3
+ import { drawTriangles as n } from "./drawTriangles.js";
4
+ import { applyClipTest as r } from "./stencil.js";
5
+ //#region src/renderer/draw/customShader.ts
6
+ var i = /* @__PURE__ */ new Set();
7
+ function a(e, t) {
8
+ let n = `${e}:${t}`;
9
+ i.has(n) || (i.add(n), (typeof process > "u" || process.env.NODE_ENV !== "production") && console.warn(`weasel drawShader: uniform "${t}" not found in program "${e}". Check spelling, ensure it's used in the shader (unused uniforms are optimized away by the driver).`));
10
+ }
11
+ function o(t, n, r, i, a) {
12
+ if (typeof r == "object" && r && !Array.isArray(r) && !(r instanceof Float32Array) && "id" in r && typeof r.id == "string") {
13
+ let o = r, s = e(o.id);
14
+ if (!s) {
15
+ (typeof process > "u" || process.env.NODE_ENV !== "production") && console.warn(`weasel setUniform: TextureHandle "${o.id}" not registered`);
16
+ return;
17
+ }
18
+ let c = a.value++;
19
+ t.activeTexture(t.TEXTURE0 + c), i.uploadRegistered(o.id, s.source), i.bind(o.id, c), t.uniform1i(n, c);
20
+ return;
21
+ }
22
+ if (r instanceof Float64Array && (r = Float32Array.from(r)), r instanceof Float32Array) {
23
+ if (r.length === 9) t.uniformMatrix3fv(n, !1, r);
24
+ else if (r.length === 16) t.uniformMatrix4fv(n, !1, r);
25
+ else if (typeof process > "u" || process.env.NODE_ENV !== "production") throw TypeError(`weasel setUniform: Float32Array must be length 9 (mat3) or 16 (mat4), got ${r.length}`);
26
+ return;
27
+ }
28
+ if (Array.isArray(r)) {
29
+ let e = r;
30
+ switch (e.length) {
31
+ case 2:
32
+ t.uniform2fv(n, e);
33
+ break;
34
+ case 3:
35
+ t.uniform3fv(n, e);
36
+ break;
37
+ case 4:
38
+ t.uniform4fv(n, e);
39
+ break;
40
+ default: if (typeof process > "u" || process.env.NODE_ENV !== "production") throw TypeError(`weasel setUniform: array length ${e.length} not supported`);
41
+ }
42
+ return;
43
+ }
44
+ if (typeof r == "number") {
45
+ t.uniform1f(n, r);
46
+ return;
47
+ }
48
+ }
49
+ var s = {
50
+ float: {
51
+ fn: "uniform1fv",
52
+ n: 1
53
+ },
54
+ vec2: {
55
+ fn: "uniform2fv",
56
+ n: 2
57
+ },
58
+ vec3: {
59
+ fn: "uniform3fv",
60
+ n: 3
61
+ },
62
+ vec4: {
63
+ fn: "uniform4fv",
64
+ n: 4
65
+ },
66
+ int: {
67
+ fn: "uniform1iv",
68
+ n: 1
69
+ },
70
+ ivec2: {
71
+ fn: "uniform2iv",
72
+ n: 2
73
+ },
74
+ ivec3: {
75
+ fn: "uniform3iv",
76
+ n: 3
77
+ },
78
+ ivec4: {
79
+ fn: "uniform4iv",
80
+ n: 4
81
+ },
82
+ bool: {
83
+ fn: "uniform1iv",
84
+ n: 1
85
+ },
86
+ bvec2: {
87
+ fn: "uniform2iv",
88
+ n: 2
89
+ },
90
+ bvec3: {
91
+ fn: "uniform3iv",
92
+ n: 3
93
+ },
94
+ bvec4: {
95
+ fn: "uniform4iv",
96
+ n: 4
97
+ },
98
+ uint: {
99
+ fn: "uniform1uiv",
100
+ n: 1
101
+ },
102
+ uvec2: {
103
+ fn: "uniform2uiv",
104
+ n: 2
105
+ },
106
+ uvec3: {
107
+ fn: "uniform3uiv",
108
+ n: 3
109
+ },
110
+ uvec4: {
111
+ fn: "uniform4uiv",
112
+ n: 4
113
+ },
114
+ mat2: {
115
+ fn: "uniformMatrix2fv",
116
+ n: 4,
117
+ matrix: !0
118
+ },
119
+ mat3: {
120
+ fn: "uniformMatrix3fv",
121
+ n: 9,
122
+ matrix: !0
123
+ },
124
+ mat4: {
125
+ fn: "uniformMatrix4fv",
126
+ n: 16,
127
+ matrix: !0
128
+ },
129
+ mat2x2: {
130
+ fn: "uniformMatrix2fv",
131
+ n: 4,
132
+ matrix: !0
133
+ },
134
+ mat3x3: {
135
+ fn: "uniformMatrix3fv",
136
+ n: 9,
137
+ matrix: !0
138
+ },
139
+ mat4x4: {
140
+ fn: "uniformMatrix4fv",
141
+ n: 16,
142
+ matrix: !0
143
+ },
144
+ mat2x3: {
145
+ fn: "uniformMatrix2x3fv",
146
+ n: 6,
147
+ matrix: !0
148
+ },
149
+ mat2x4: {
150
+ fn: "uniformMatrix2x4fv",
151
+ n: 8,
152
+ matrix: !0
153
+ },
154
+ mat3x2: {
155
+ fn: "uniformMatrix3x2fv",
156
+ n: 6,
157
+ matrix: !0
158
+ },
159
+ mat3x4: {
160
+ fn: "uniformMatrix3x4fv",
161
+ n: 12,
162
+ matrix: !0
163
+ },
164
+ mat4x2: {
165
+ fn: "uniformMatrix4x2fv",
166
+ n: 8,
167
+ matrix: !0
168
+ },
169
+ mat4x3: {
170
+ fn: "uniformMatrix4x3fv",
171
+ n: 12,
172
+ matrix: !0
173
+ }
174
+ };
175
+ function c(e) {
176
+ return Array.isArray(e) || e instanceof Float32Array || e instanceof Int32Array || e instanceof Uint32Array;
177
+ }
178
+ function l(e, t, n, r) {
179
+ let i = typeof process < "u" ? process.env.NODE_ENV !== "production" : !0, a = s[n.type];
180
+ if (!a) {
181
+ i && console.warn(`weasel setUniform: array uniform "${t}" has type ${n.type}, which cannot be written as a whole`);
182
+ return;
183
+ }
184
+ if (r.length % a.n !== 0 || r.length > a.n * n.size) {
185
+ if (i) throw TypeError(`weasel setUniform: "${t}" is ${n.type}[${n.size}], so its value must hold a multiple of ${a.n} numbers, at most ${a.n * n.size}; got ${r.length}`);
186
+ return;
187
+ }
188
+ if (r.length === 0) return;
189
+ let o = e[a.fn];
190
+ a.matrix ? o.call(e, n.location, !1, r) : o.call(e, n.location, r);
191
+ }
192
+ function u(e, t, n, r, i, s) {
193
+ for (let [u, d] of Object.entries(r)) {
194
+ let r = t.uniformArray(u);
195
+ if (r && c(d)) {
196
+ l(e, u, r, d);
197
+ continue;
198
+ }
199
+ let f = t.uniform(u);
200
+ if (f === void 0) {
201
+ a(n, u);
202
+ continue;
203
+ }
204
+ o(e, f, d, i, s);
205
+ }
206
+ }
207
+ function d(e, i) {
208
+ let { gl: a, programRegistry: o, quadVbo: s, quadIbo: c, textureCache: l } = e, d = o.get(i.program.id);
209
+ if (!d) {
210
+ console.warn(`weasel drawShader: program "${i.program.id}" not compiled on this renderer. Call renderer.registerProgram(handle) after the module-level registerProgram().`);
211
+ return;
212
+ }
213
+ if (!s || !c) {
214
+ console.warn("weasel drawShader: quad geometry not initialized");
215
+ return;
216
+ }
217
+ a.useProgram(d.handle);
218
+ let f = d.attribute("a_position"), p = d.attribute("a_uv");
219
+ a.bindBuffer(a.ARRAY_BUFFER, s), f !== void 0 && (a.enableVertexAttribArray(f), a.vertexAttribPointer(f, 2, a.FLOAT, !1, 16, 0)), p !== void 0 && (a.enableVertexAttribArray(p), a.vertexAttribPointer(p, 2, a.FLOAT, !1, 16, 8)), a.bindBuffer(a.ELEMENT_ARRAY_BUFFER, c);
220
+ let m = t.screenToClip(e.widthCss, e.heightCss), h = d.uniform("u_proj");
221
+ h !== void 0 && a.uniformMatrix3fv(h, !1, t.toUniform(m));
222
+ let g = d.uniform("u_bounds");
223
+ g !== void 0 && a.uniform4f(g, i.bounds.x, i.bounds.y, i.bounds.w, i.bounds.h);
224
+ let _ = d.uniform("u_view");
225
+ _ !== void 0 && a.uniformMatrix3fv(_, !1, t.toUniform(e.state.transform)), u(a, d, i.program.id, i.uniforms, l, { value: 1 }), r(e), n(e, 6, e.gl.UNSIGNED_SHORT), f !== void 0 && a.disableVertexAttribArray(f), p !== void 0 && a.disableVertexAttribArray(p), a.bindBuffer(a.ARRAY_BUFFER, null), a.bindBuffer(a.ELEMENT_ARRAY_BUFFER, null);
226
+ }
227
+ //#endregion
228
+ export { d as drawShader, o as setUniform, u as setUniforms, a as warnOnceUniform };
229
+
230
+ //# sourceMappingURL=customShader.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"customShader.js","names":["warnedUniforms","warnOnceUniform","key","programId","name","setUniform","value","handle","entry","getTexture","unit","gl","textureCache","loc","arr","ARRAY_UPLOADS","isArrayValue","setUniformArray","isDev","upload","fn","setUniforms","uniforms","program","nextTexUnit","drawShader","ctx","programRegistry","cmd","quadVbo","quadIbo","aPosLoc","aUvLoc","proj","mat3","uProj","uBounds","uView","applyClipTest","drawTriangles"],"sources":["../../../src/renderer/draw/customShader.ts"],"sourcesContent":["import type { ShaderDrawCommand } from '../DrawCommand';\nimport { getTexture, type TextureHandle } from '../textures/registerTexture';\nimport type { ShaderUniform } from '../shaders/registerProgram';\nimport type { GLTextureCache } from '../cache/GLTextureCache';\nimport type { ShaderProgram, UniformArray } from '../shaders/ShaderProgram';\nimport { mat3 } from '../math/mat3';\nimport type { DrawContext } from './drawContext';\nimport { drawTriangles } from './drawTriangles';\nimport { applyClipTest } from './stencil';\n\nconst warnedUniforms = new Set<string>();\n\nexport function warnOnceUniform(programId: string, name: string): void {\n const key = `${programId}:${name}`;\n if (warnedUniforms.has(key)) return;\n warnedUniforms.add(key);\n const isDev = typeof process !== 'undefined' ? process.env.NODE_ENV !== 'production' : true;\n if (isDev) {\n console.warn(`weasel drawShader: uniform \"${name}\" not found in program \"${programId}\". ` +\n `Check spelling, ensure it's used in the shader (unused uniforms are optimized away by the driver).`);\n }\n}\n\n/**\n * Bind a single ShaderUniform value to a GL uniform location.\n *\n * Type detection order:\n * 1. TextureHandle (object with string `.id`) — bind to next tex unit, set sampler.\n * 2. Float32Array — length 9 → mat3, length 16 → mat4. Other lengths throw in dev.\n * 3. Array — uniform2fv / uniform3fv / uniform4fv based on length.\n * 4. number — uniform1f.\n */\nexport function setUniform(\n gl: WebGL2RenderingContext,\n loc: WebGLUniformLocation,\n value: ShaderUniform,\n textureCache: GLTextureCache,\n nextTexUnit: { value: number },\n): void {\n if (value !== null && typeof value === 'object' && !Array.isArray(value) && !(value instanceof Float32Array)\n && 'id' in value && typeof (value as TextureHandle).id === 'string') {\n const handle = value as TextureHandle;\n const entry = getTexture(handle.id);\n if (!entry) {\n const isDev = typeof process !== 'undefined' ? process.env.NODE_ENV !== 'production' : true;\n if (isDev) console.warn(`weasel setUniform: TextureHandle \"${handle.id}\" not registered`);\n return;\n }\n const unit = nextTexUnit.value++;\n // An upload binds and unbinds on the active unit, so it has to be this\n // uniform's own unit and not one an earlier sampler already holds.\n gl.activeTexture(gl.TEXTURE0 + unit);\n textureCache.uploadRegistered(handle.id, entry.source);\n textureCache.bind(handle.id, unit);\n gl.uniform1i(loc, unit);\n return;\n }\n\n // A kit matrix is in doubles; GL wants float32.\n if (value instanceof Float64Array) value = Float32Array.from(value);\n\n if (value instanceof Float32Array) {\n if (value.length === 9) {\n gl.uniformMatrix3fv(loc, false, value);\n } else if (value.length === 16) {\n gl.uniformMatrix4fv(loc, false, value);\n } else {\n const isDev = typeof process !== 'undefined' ? process.env.NODE_ENV !== 'production' : true;\n if (isDev) throw new TypeError(`weasel setUniform: Float32Array must be length 9 (mat3) or 16 (mat4), got ${value.length}`);\n }\n return;\n }\n\n if (Array.isArray(value)) {\n const arr = value as readonly number[];\n switch (arr.length) {\n case 2: gl.uniform2fv(loc, arr as [number, number]); break;\n case 3: gl.uniform3fv(loc, arr as [number, number, number]); break;\n case 4: gl.uniform4fv(loc, arr as [number, number, number, number]); break;\n default: {\n const isDev = typeof process !== 'undefined' ? process.env.NODE_ENV !== 'production' : true;\n if (isDev) throw new TypeError(`weasel setUniform: array length ${arr.length} not supported`);\n }\n }\n return;\n }\n\n if (typeof value === 'number') {\n gl.uniform1f(loc, value);\n return;\n }\n}\n\n/** How an array's element type is uploaded: the `uniform*v` call and the\n * number of components per element. */\nconst ARRAY_UPLOADS: Readonly<Record<string, { fn: string; n: number; matrix?: true }>> = {\n float: { fn: 'uniform1fv', n: 1 }, vec2: { fn: 'uniform2fv', n: 2 },\n vec3: { fn: 'uniform3fv', n: 3 }, vec4: { fn: 'uniform4fv', n: 4 },\n int: { fn: 'uniform1iv', n: 1 }, ivec2: { fn: 'uniform2iv', n: 2 },\n ivec3: { fn: 'uniform3iv', n: 3 }, ivec4: { fn: 'uniform4iv', n: 4 },\n bool: { fn: 'uniform1iv', n: 1 }, bvec2: { fn: 'uniform2iv', n: 2 },\n bvec3: { fn: 'uniform3iv', n: 3 }, bvec4: { fn: 'uniform4iv', n: 4 },\n uint: { fn: 'uniform1uiv', n: 1 }, uvec2: { fn: 'uniform2uiv', n: 2 },\n uvec3: { fn: 'uniform3uiv', n: 3 }, uvec4: { fn: 'uniform4uiv', n: 4 },\n mat2: { fn: 'uniformMatrix2fv', n: 4, matrix: true },\n mat3: { fn: 'uniformMatrix3fv', n: 9, matrix: true },\n mat4: { fn: 'uniformMatrix4fv', n: 16, matrix: true },\n mat2x2: { fn: 'uniformMatrix2fv', n: 4, matrix: true },\n mat3x3: { fn: 'uniformMatrix3fv', n: 9, matrix: true },\n mat4x4: { fn: 'uniformMatrix4fv', n: 16, matrix: true },\n mat2x3: { fn: 'uniformMatrix2x3fv', n: 6, matrix: true },\n mat2x4: { fn: 'uniformMatrix2x4fv', n: 8, matrix: true },\n mat3x2: { fn: 'uniformMatrix3x2fv', n: 6, matrix: true },\n mat3x4: { fn: 'uniformMatrix3x4fv', n: 12, matrix: true },\n mat4x2: { fn: 'uniformMatrix4x2fv', n: 8, matrix: true },\n mat4x3: { fn: 'uniformMatrix4x3fv', n: 12, matrix: true },\n};\n\ntype ArrayValue = readonly number[] | Float32Array | Int32Array | Uint32Array;\n\nfunction isArrayValue(value: ShaderUniform): value is ArrayValue {\n return Array.isArray(value) || value instanceof Float32Array\n || value instanceof Int32Array || value instanceof Uint32Array;\n}\n\n/** Fill an array uniform from slot 0 with one call. Throws in dev on a value\n * that is not a whole number of elements or overruns the declaration. */\nfunction setUniformArray(\n gl: WebGL2RenderingContext,\n name: string,\n arr: UniformArray,\n value: ArrayValue,\n): void {\n const isDev = typeof process !== 'undefined' ? process.env.NODE_ENV !== 'production' : true;\n const upload = ARRAY_UPLOADS[arr.type];\n if (!upload) {\n if (isDev) console.warn(`weasel setUniform: array uniform \"${name}\" has type ${arr.type}, which cannot be written as a whole`);\n return;\n }\n if (value.length % upload.n !== 0 || value.length > upload.n * arr.size) {\n if (isDev) {\n throw new TypeError(\n `weasel setUniform: \"${name}\" is ${arr.type}[${arr.size}], so its value must hold a multiple of ${upload.n} `\n + `numbers, at most ${upload.n * arr.size}; got ${value.length}`,\n );\n }\n return;\n }\n if (value.length === 0) return;\n const fn = (gl as unknown as Record<string, (...args: unknown[]) => void>)[upload.fn];\n if (upload.matrix) fn.call(gl, arr.location, false, value);\n else fn.call(gl, arr.location, value);\n}\n\n/** Write every entry of a command's `uniforms` map. A key naming an array\n * uniform with an array value fills the array; anything else goes to the\n * location of that exact name. */\nexport function setUniforms(\n gl: WebGL2RenderingContext,\n program: ShaderProgram,\n programId: string,\n uniforms: Record<string, ShaderUniform>,\n textureCache: GLTextureCache,\n nextTexUnit: { value: number },\n): void {\n for (const [name, value] of Object.entries(uniforms)) {\n const arr = program.uniformArray(name);\n if (arr && isArrayValue(value)) {\n setUniformArray(gl, name, arr, value);\n continue;\n }\n const loc = program.uniform(name);\n if (loc === undefined) {\n warnOnceUniform(programId, name);\n continue;\n }\n setUniform(gl, loc, value, textureCache, nextTexUnit);\n }\n}\n\nexport function drawShader(ctx: DrawContext, cmd: ShaderDrawCommand): void {\n const { gl, programRegistry, quadVbo, quadIbo, textureCache } = ctx;\n\n const program = programRegistry.get(cmd.program.id);\n if (!program) {\n console.warn(\n `weasel drawShader: program \"${cmd.program.id}\" not compiled on this renderer. ` +\n `Call renderer.registerProgram(handle) after the module-level registerProgram().`,\n );\n return;\n }\n if (!quadVbo || !quadIbo) {\n console.warn('weasel drawShader: quad geometry not initialized');\n return;\n }\n\n gl.useProgram(program.handle);\n\n const aPosLoc = program.attribute('a_position');\n const aUvLoc = program.attribute('a_uv');\n\n gl.bindBuffer(gl.ARRAY_BUFFER, quadVbo);\n if (aPosLoc !== undefined) {\n gl.enableVertexAttribArray(aPosLoc);\n gl.vertexAttribPointer(aPosLoc, 2, gl.FLOAT, false, 16, 0);\n }\n if (aUvLoc !== undefined) {\n gl.enableVertexAttribArray(aUvLoc);\n gl.vertexAttribPointer(aUvLoc, 2, gl.FLOAT, false, 16, 8);\n }\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, quadIbo);\n\n const proj = mat3.screenToClip(ctx.widthCss, ctx.heightCss);\n const uProj = program.uniform('u_proj');\n if (uProj !== undefined) gl.uniformMatrix3fv(uProj, false, mat3.toUniform(proj));\n\n const uBounds = program.uniform('u_bounds');\n if (uBounds !== undefined) {\n gl.uniform4f(uBounds, cmd.bounds.x, cmd.bounds.y, cmd.bounds.w, cmd.bounds.h);\n }\n\n const uView = program.uniform('u_view');\n if (uView !== undefined) gl.uniformMatrix3fv(uView, false, mat3.toUniform(ctx.state.transform));\n\n setUniforms(gl, program, cmd.program.id, cmd.uniforms, textureCache, { value: 1 });\n\n applyClipTest(ctx);\n drawTriangles(ctx, 6, ctx.gl.UNSIGNED_SHORT);\n\n if (aPosLoc !== undefined) gl.disableVertexAttribArray(aPosLoc);\n if (aUvLoc !== undefined) gl.disableVertexAttribArray(aUvLoc);\n gl.bindBuffer(gl.ARRAY_BUFFER, null);\n gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);\n}\n"],"mappings":";;;;;AAUA,IAAMA,oBAAiB,IAAI,IAAY;AAEvC,SAAgBC,EAAgB,GAAmB,GAAoB;CACrE,IAAMC,IAAM,GAAGC,EAAU,GAAGC;CAC5B,AAAIJ,EAAe,IAAIE,CAAG,MAC1BF,EAAe,IAAIE,CAAG,IACR,OAAO,UAAY,OAAA,QAAA,IAAA,aAAuC,iBAEtE,QAAQ,KAAK,+BAA+BE,EAAK,0BAA0BD,EAAU,sGACiB;AAE1G;AAWA,SAAgBE,EACd,GACA,GACA,GACA,GACA,GACM;CACN,IAAsB,OAAOC,KAAU,YAAnCA,KAA+C,CAAC,MAAM,QAAQA,CAAK,KAAK,EAAEA,aAAiB,iBACxF,QAAQA,KAAS,OAAQA,EAAwB,MAAO,UAAU;EACvE,IAAMC,IAASD,GACTE,IAAQC,EAAWF,EAAO,EAAE;EAClC,IAAI,CAACC,GAAO;GAEV,CADc,OAAO,UAAY,OAAA,QAAA,IAAA,aAAuC,iBAC7D,QAAQ,KAAK,qCAAqCD,EAAO,GAAG,iBAAiB;GACxF;EACF;EACA,IAAMG,IAAO,EAAY;EAMzB,AAHAC,EAAG,cAAcA,EAAG,WAAWD,CAAI,GACnCE,EAAa,iBAAiBL,EAAO,IAAIC,EAAM,MAAM,GACrDI,EAAa,KAAKL,EAAO,IAAIG,CAAI,GACjCC,EAAG,UAAUE,GAAKH,CAAI;EACtB;CACF;CAKA,IAFIJ,aAAiB,iBAAc,IAAQ,aAAa,KAAKA,CAAK,IAE9DA,aAAiB,cAAc;EACjC,IAAIA,EAAM,WAAW,GACnB,EAAG,iBAAiBO,GAAK,IAAOP,CAAK;OAChC,IAAIA,EAAM,WAAW,IAC1B,EAAG,iBAAiBO,GAAK,IAAOP,CAAK;OAGrC,IADc,OAAO,UAAY,OAAA,QAAA,IAAA,aAAuC,cAC7D,MAAU,UAAU,6EAA6EA,EAAM,QAAQ;EAE5H;CACF;CAEA,IAAI,MAAM,QAAQA,CAAK,GAAG;EACxB,IAAMQ,IAAMR;EACZ,QAAQQ,EAAI,QAAZ;GACE,KAAK;IAAG,EAAG,WAAWD,GAAKC,CAAuB;IAAG;GACrD,KAAK;IAAG,EAAG,WAAWD,GAAKC,CAA+B;IAAG;GAC7D,KAAK;IAAG,EAAG,WAAWD,GAAKC,CAAuC;IAAG;GACrE,SAEE,IADc,OAAO,UAAY,OAAA,QAAA,IAAA,aAAuC,cAC7D,MAAU,UAAU,mCAAmCA,EAAI,OAAO,eAAe;EAEhG;EACA;CACF;CAEA,IAAI,OAAOR,KAAU,UAAU;EAC7B,EAAG,UAAUO,GAAKP,CAAK;EACvB;CACF;AACF;AAIA,IAAMS,IAAoF;CACxF,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CAAG,MAAM;EAAE,IAAI;EAAc,GAAG;CAAE;CAClE,MAAM;EAAE,IAAI;EAAc,GAAG;CAAE;CAAG,MAAM;EAAE,IAAI;EAAc,GAAG;CAAE;CACjE,KAAK;EAAE,IAAI;EAAc,GAAG;CAAE;CAAG,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CACjE,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CAAG,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CACnE,MAAM;EAAE,IAAI;EAAc,GAAG;CAAE;CAAG,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CAClE,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CAAG,OAAO;EAAE,IAAI;EAAc,GAAG;CAAE;CACnE,MAAM;EAAE,IAAI;EAAe,GAAG;CAAE;CAAG,OAAO;EAAE,IAAI;EAAe,GAAG;CAAE;CACpE,OAAO;EAAE,IAAI;EAAe,GAAG;CAAE;CAAG,OAAO;EAAE,IAAI;EAAe,GAAG;CAAE;CACrE,MAAM;EAAE,IAAI;EAAoB,GAAG;EAAG,QAAQ;CAAK;CACnD,MAAM;EAAE,IAAI;EAAoB,GAAG;EAAG,QAAQ;CAAK;CACnD,MAAM;EAAE,IAAI;EAAoB,GAAG;EAAI,QAAQ;CAAK;CACpD,QAAQ;EAAE,IAAI;EAAoB,GAAG;EAAG,QAAQ;CAAK;CACrD,QAAQ;EAAE,IAAI;EAAoB,GAAG;EAAG,QAAQ;CAAK;CACrD,QAAQ;EAAE,IAAI;EAAoB,GAAG;EAAI,QAAQ;CAAK;CACtD,QAAQ;EAAE,IAAI;EAAsB,GAAG;EAAG,QAAQ;CAAK;CACvD,QAAQ;EAAE,IAAI;EAAsB,GAAG;EAAG,QAAQ;CAAK;CACvD,QAAQ;EAAE,IAAI;EAAsB,GAAG;EAAG,QAAQ;CAAK;CACvD,QAAQ;EAAE,IAAI;EAAsB,GAAG;EAAI,QAAQ;CAAK;CACxD,QAAQ;EAAE,IAAI;EAAsB,GAAG;EAAG,QAAQ;CAAK;CACvD,QAAQ;EAAE,IAAI;EAAsB,GAAG;EAAI,QAAQ;CAAK;AAC1D;AAIA,SAASC,EAAa,GAA2C;CAC/D,OAAO,MAAM,QAAQV,CAAK,KAAKA,aAAiB,gBAC3CA,aAAiB,cAAcA,aAAiB;AACvD;AAIA,SAASW,EACP,GACA,GACA,GACA,GACM;CACN,IAAMC,IAAQ,OAAO,UAAY,MAAA,QAAA,IAAA,aAAuC,eAAe,IACjFC,IAASJ,EAAcD,EAAI;CACjC,IAAI,CAACK,GAAQ;EACX,AAAID,KAAO,QAAQ,KAAK,qCAAqCd,EAAK,aAAaU,EAAI,KAAK,qCAAqC;EAC7H;CACF;CACA,IAAIR,EAAM,SAASa,EAAO,MAAM,KAAKb,EAAM,SAASa,EAAO,IAAIL,EAAI,MAAM;EACvE,IAAII,GACF,MAAU,UACR,uBAAuBd,EAAK,OAAOU,EAAI,KAAK,GAAGA,EAAI,KAAK,0CAA0CK,EAAO,EAAE,oBACrFA,EAAO,IAAIL,EAAI,KAAK,QAAQR,EAAM,QAC1D;EAEF;CACF;CACA,IAAIA,EAAM,WAAW,GAAG;CACxB,IAAMc,IAAMT,EAA+DQ,EAAO;CAClF,AAAIA,EAAO,SAAQC,EAAG,KAAKT,GAAIG,EAAI,UAAU,IAAOR,CAAK,IACpDc,EAAG,KAAKT,GAAIG,EAAI,UAAUR,CAAK;AACtC;AAKA,SAAgBe,EACd,GACA,GACA,GACA,GACA,GACA,GACM;CACN,KAAK,IAAM,CAACjB,GAAME,MAAU,OAAO,QAAQgB,CAAQ,GAAG;EACpD,IAAMR,IAAMS,EAAQ,aAAanB,CAAI;EACrC,IAAIU,KAAOE,EAAaV,CAAK,GAAG;GAC9B,EAAgBK,GAAIP,GAAMU,GAAKR,CAAK;GACpC;EACF;EACA,IAAMO,IAAMU,EAAQ,QAAQnB,CAAI;EAChC,IAAIS,MAAQ,KAAA,GAAW;GACrB,EAAgBV,GAAWC,CAAI;GAC/B;EACF;EACA,EAAWO,GAAIE,GAAKP,GAAOM,GAAcY,CAAW;CACtD;AACF;AAEA,SAAgBC,EAAW,GAAkB,GAA8B;CACzE,IAAM,EAAE,OAAI,oBAAiB,YAAS,YAAS,oBAAiBC,GAE1DH,IAAUI,EAAgB,IAAIC,EAAI,QAAQ,EAAE;CAClD,IAAI,CAACL,GAAS;EACZ,QAAQ,KACN,+BAA+BK,EAAI,QAAQ,GAAG,iHAEhD;EACA;CACF;CACA,IAAI,CAACC,KAAW,CAACC,GAAS;EACxB,QAAQ,KAAK,kDAAkD;EAC/D;CACF;CAEA,EAAG,WAAWP,EAAQ,MAAM;CAE5B,IAAMQ,IAAUR,EAAQ,UAAU,YAAY,GACxCS,IAAUT,EAAQ,UAAU,MAAM;CAWxC,AATAZ,EAAG,WAAWA,EAAG,cAAckB,CAAO,GAClCE,MAAY,KAAA,MACdpB,EAAG,wBAAwBoB,CAAO,GAClCpB,EAAG,oBAAoBoB,GAAS,GAAGpB,EAAG,OAAO,IAAO,IAAI,CAAC,IAEvDqB,MAAW,KAAA,MACbrB,EAAG,wBAAwBqB,CAAM,GACjCrB,EAAG,oBAAoBqB,GAAQ,GAAGrB,EAAG,OAAO,IAAO,IAAI,CAAC,IAE1DA,EAAG,WAAWA,EAAG,sBAAsBmB,CAAO;CAE9C,IAAMG,IAAOC,EAAK,aAAaR,EAAI,UAAUA,EAAI,SAAS,GACpDS,IAAQZ,EAAQ,QAAQ,QAAQ;CACtC,AAAIY,MAAU,KAAA,KAAWxB,EAAG,iBAAiBwB,GAAO,IAAOD,EAAK,UAAUD,CAAI,CAAC;CAE/E,IAAMG,IAAUb,EAAQ,QAAQ,UAAU;CAC1C,AAAIa,MAAY,KAAA,KACdzB,EAAG,UAAUyB,GAASR,EAAI,OAAO,GAAGA,EAAI,OAAO,GAAGA,EAAI,OAAO,GAAGA,EAAI,OAAO,CAAC;CAG9E,IAAMS,IAAQd,EAAQ,QAAQ,QAAQ;CAWtC,AAVIc,MAAU,KAAA,KAAW1B,EAAG,iBAAiB0B,GAAO,IAAOH,EAAK,UAAUR,EAAI,MAAM,SAAS,CAAC,GAE9FL,EAAYV,GAAIY,GAASK,EAAI,QAAQ,IAAIA,EAAI,UAAUhB,GAAc,EAAE,OAAO,EAAE,CAAC,GAEjF0B,EAAcZ,CAAG,GACjBa,EAAcb,GAAK,GAAGA,EAAI,GAAG,cAAc,GAEvCK,MAAY,KAAA,KAAWpB,EAAG,yBAAyBoB,CAAO,GAC1DC,MAAY,KAAA,KAAWrB,EAAG,yBAAyBqB,CAAM,GAC7DrB,EAAG,WAAWA,EAAG,cAAc,IAAI,GACnCA,EAAG,WAAWA,EAAG,sBAAsB,IAAI;AAC7C"}