@dxos/react-ui-canvas 0.13.0 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (341) hide show
  1. package/README.md +1 -1
  2. package/dist/lib/index.mjs +9044 -1135
  3. package/dist/lib/index.mjs.map +1 -1
  4. package/dist/types/src/components/About/About.d.ts +13 -0
  5. package/dist/types/src/components/About/About.d.ts.map +1 -0
  6. package/dist/types/src/components/About/About.stories.d.ts +7 -0
  7. package/dist/types/src/components/About/About.stories.d.ts.map +1 -0
  8. package/dist/types/src/components/About/index.d.ts +2 -0
  9. package/dist/types/src/components/About/index.d.ts.map +1 -0
  10. package/dist/types/src/components/Breadcrumbs/Breadcrumbs.d.ts.map +1 -1
  11. package/dist/types/src/components/ControlFrame/ControlFrame.d.ts +8 -2
  12. package/dist/types/src/components/ControlFrame/ControlFrame.d.ts.map +1 -1
  13. package/dist/types/src/components/Layers/Layers.d.ts +30 -0
  14. package/dist/types/src/components/Layers/Layers.d.ts.map +1 -0
  15. package/dist/types/src/components/Layers/Layers.stories.d.ts +11 -0
  16. package/dist/types/src/components/Layers/Layers.stories.d.ts.map +1 -0
  17. package/dist/types/src/components/Layers/index.d.ts +2 -0
  18. package/dist/types/src/components/Layers/index.d.ts.map +1 -0
  19. package/dist/types/src/components/Palette/Palette.d.ts +20 -4
  20. package/dist/types/src/components/Palette/Palette.d.ts.map +1 -1
  21. package/dist/types/src/components/Palette/Palette.stories.d.ts +22 -0
  22. package/dist/types/src/components/Palette/Palette.stories.d.ts.map +1 -0
  23. package/dist/types/src/components/PartEditor/PartEditor.d.ts.map +1 -1
  24. package/dist/types/src/components/Properties/AlignField.d.ts +23 -0
  25. package/dist/types/src/components/Properties/AlignField.d.ts.map +1 -0
  26. package/dist/types/src/components/Properties/ClassField.d.ts +23 -0
  27. package/dist/types/src/components/Properties/ClassField.d.ts.map +1 -0
  28. package/dist/types/src/components/Properties/FontField.d.ts +7 -0
  29. package/dist/types/src/components/Properties/FontField.d.ts.map +1 -0
  30. package/dist/types/src/components/Properties/LayerField.d.ts +17 -0
  31. package/dist/types/src/components/Properties/LayerField.d.ts.map +1 -0
  32. package/dist/types/src/components/Properties/Properties.d.ts +27 -3
  33. package/dist/types/src/components/Properties/Properties.d.ts.map +1 -1
  34. package/dist/types/src/components/Properties/Properties.stories.d.ts +20 -0
  35. package/dist/types/src/components/Properties/Properties.stories.d.ts.map +1 -0
  36. package/dist/types/src/components/Properties/SceneField.d.ts +8 -0
  37. package/dist/types/src/components/Properties/SceneField.d.ts.map +1 -0
  38. package/dist/types/src/components/Properties/StyleGrid.d.ts +15 -5
  39. package/dist/types/src/components/Properties/StyleGrid.d.ts.map +1 -1
  40. package/dist/types/src/components/Properties/StyleGrid.stories.d.ts +7 -0
  41. package/dist/types/src/components/Properties/StyleGrid.stories.d.ts.map +1 -0
  42. package/dist/types/src/components/SceneLayer/SceneLayer.d.ts +31 -7
  43. package/dist/types/src/components/SceneLayer/SceneLayer.d.ts.map +1 -1
  44. package/dist/types/src/components/SceneView/Dock.d.ts +22 -0
  45. package/dist/types/src/components/SceneView/Dock.d.ts.map +1 -0
  46. package/dist/types/src/components/SceneView/Dock.stories.d.ts +15 -0
  47. package/dist/types/src/components/SceneView/Dock.stories.d.ts.map +1 -0
  48. package/dist/types/src/components/SceneView/SceneView.d.ts +33 -7
  49. package/dist/types/src/components/SceneView/SceneView.d.ts.map +1 -1
  50. package/dist/types/src/components/SceneView/SceneView.stories.d.ts +16 -6
  51. package/dist/types/src/components/SceneView/SceneView.stories.d.ts.map +1 -1
  52. package/dist/types/src/components/SceneView/SceneViewContext.d.ts +36 -4
  53. package/dist/types/src/components/SceneView/SceneViewContext.d.ts.map +1 -1
  54. package/dist/types/src/components/SceneView/Scored.stories.d.ts +4 -4
  55. package/dist/types/src/components/SceneView/Scored.stories.d.ts.map +1 -1
  56. package/dist/types/src/components/SceneView/usePointerMachine.d.ts +3 -1
  57. package/dist/types/src/components/SceneView/usePointerMachine.d.ts.map +1 -1
  58. package/dist/types/src/components/SceneView/useSceneCamera.d.ts +2 -2
  59. package/dist/types/src/components/SceneView/useSceneCamera.d.ts.map +1 -1
  60. package/dist/types/src/components/SceneView/useSceneClipboard.d.ts.map +1 -1
  61. package/dist/types/src/components/SceneView/useSceneKeys.d.ts.map +1 -1
  62. package/dist/types/src/components/SceneView/useSceneNavigation.d.ts +7 -4
  63. package/dist/types/src/components/SceneView/useSceneNavigation.d.ts.map +1 -1
  64. package/dist/types/src/components/Toolbar/Toolbar.d.ts +2 -0
  65. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  66. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -1
  67. package/dist/types/src/components/index.d.ts +2 -0
  68. package/dist/types/src/components/index.d.ts.map +1 -1
  69. package/dist/types/src/hooks/useWheel.d.ts +5 -0
  70. package/dist/types/src/hooks/useWheel.d.ts.map +1 -1
  71. package/dist/types/src/index.d.ts +4 -1
  72. package/dist/types/src/index.d.ts.map +1 -1
  73. package/dist/types/src/model/atoms.d.ts +21 -3
  74. package/dist/types/src/model/atoms.d.ts.map +1 -1
  75. package/dist/types/src/model/projection.d.ts.map +1 -1
  76. package/dist/types/src/model/projections/constrained.d.ts +2 -1
  77. package/dist/types/src/model/projections/constrained.d.ts.map +1 -1
  78. package/dist/types/src/model/projections/dynamic.d.ts.map +1 -1
  79. package/dist/types/src/model/projections/lattice.d.ts.map +1 -1
  80. package/dist/types/src/model/registry.d.ts +21 -3
  81. package/dist/types/src/model/registry.d.ts.map +1 -1
  82. package/dist/types/src/model/store.d.ts +10 -2
  83. package/dist/types/src/model/store.d.ts.map +1 -1
  84. package/dist/types/src/model/types.d.ts +699 -338
  85. package/dist/types/src/model/types.d.ts.map +1 -1
  86. package/dist/types/src/playwright/SceneManager.d.ts +1 -1
  87. package/dist/types/src/playwright/SceneManager.d.ts.map +1 -1
  88. package/dist/types/src/utils/builder.d.ts +22 -41
  89. package/dist/types/src/utils/builder.d.ts.map +1 -1
  90. package/dist/types/src/utils/camera.d.ts +19 -10
  91. package/dist/types/src/utils/camera.d.ts.map +1 -1
  92. package/dist/types/src/utils/clipboard.d.ts +4 -2
  93. package/dist/types/src/utils/clipboard.d.ts.map +1 -1
  94. package/dist/types/src/utils/diagram.d.ts.map +1 -1
  95. package/dist/types/src/utils/group.d.ts +14 -0
  96. package/dist/types/src/utils/group.d.ts.map +1 -0
  97. package/dist/types/src/utils/group.test.d.ts +2 -0
  98. package/dist/types/src/utils/group.test.d.ts.map +1 -0
  99. package/dist/types/src/utils/gutter-route.d.ts +7 -0
  100. package/dist/types/src/utils/gutter-route.d.ts.map +1 -1
  101. package/dist/types/src/utils/hit.d.ts +3 -20
  102. package/dist/types/src/utils/hit.d.ts.map +1 -1
  103. package/dist/types/src/utils/index.d.ts +3 -0
  104. package/dist/types/src/utils/index.d.ts.map +1 -1
  105. package/dist/types/src/utils/lattice.d.ts +5 -0
  106. package/dist/types/src/utils/lattice.d.ts.map +1 -1
  107. package/dist/types/src/utils/layers.d.ts +35 -0
  108. package/dist/types/src/utils/layers.d.ts.map +1 -0
  109. package/dist/types/src/utils/layers.test.d.ts +2 -0
  110. package/dist/types/src/utils/layers.test.d.ts.map +1 -0
  111. package/dist/types/src/utils/parts.d.ts +25 -9
  112. package/dist/types/src/utils/parts.d.ts.map +1 -1
  113. package/dist/types/src/utils/ports.d.ts +2 -0
  114. package/dist/types/src/utils/ports.d.ts.map +1 -1
  115. package/dist/types/src/utils/properties.d.ts +4 -3
  116. package/dist/types/src/utils/properties.d.ts.map +1 -1
  117. package/dist/types/src/utils/route.d.ts +5 -0
  118. package/dist/types/src/utils/route.d.ts.map +1 -1
  119. package/dist/types/src/utils/scenes.d.ts +14 -0
  120. package/dist/types/src/utils/scenes.d.ts.map +1 -0
  121. package/dist/types/src/utils/scenes.test.d.ts +2 -0
  122. package/dist/types/src/utils/scenes.test.d.ts.map +1 -0
  123. package/dist/types/src/utils/shapes.d.ts +23 -9
  124. package/dist/types/src/utils/shapes.d.ts.map +1 -1
  125. package/dist/types/src/utils/style.d.ts +29 -6
  126. package/dist/types/src/utils/style.d.ts.map +1 -1
  127. package/dist/types/src/utils/style.test.d.ts +2 -0
  128. package/dist/types/src/utils/style.test.d.ts.map +1 -0
  129. package/dist/types/src/utils/testing.d.ts +2 -2
  130. package/dist/types/src/utils/testing.d.ts.map +1 -1
  131. package/dist/types/src/utils/undo.d.ts +15 -4
  132. package/dist/types/src/utils/undo.d.ts.map +1 -1
  133. package/dist/types/tsconfig.tsbuildinfo +1 -1
  134. package/package.json +20 -26
  135. package/src/components/About/About.stories.tsx +32 -0
  136. package/src/components/About/About.tsx +38 -0
  137. package/src/components/About/index.ts +5 -0
  138. package/src/components/Breadcrumbs/Breadcrumbs.tsx +17 -3
  139. package/src/components/ControlFrame/ControlFrame.tsx +138 -82
  140. package/src/components/Grid/Grid.stories.tsx +1 -1
  141. package/src/components/Layers/Layers.stories.tsx +131 -0
  142. package/src/components/Layers/Layers.tsx +216 -0
  143. package/src/components/Layers/index.ts +5 -0
  144. package/src/components/Palette/Palette.stories.tsx +135 -0
  145. package/src/components/Palette/Palette.tsx +230 -39
  146. package/src/components/PartEditor/PartEditor.tsx +4 -3
  147. package/src/components/Properties/AlignField.tsx +117 -0
  148. package/src/components/Properties/ClassField.tsx +44 -0
  149. package/src/components/Properties/FontField.tsx +73 -0
  150. package/src/components/Properties/LayerField.tsx +61 -0
  151. package/src/components/Properties/Properties.stories.tsx +113 -0
  152. package/src/components/Properties/Properties.tsx +240 -60
  153. package/src/components/Properties/SceneField.tsx +22 -0
  154. package/src/components/Properties/StyleGrid.stories.tsx +50 -0
  155. package/src/components/Properties/StyleGrid.tsx +54 -26
  156. package/src/components/SceneLayer/SceneLayer.tsx +497 -188
  157. package/src/components/SceneView/Constrained.stories.tsx +1 -1
  158. package/src/components/SceneView/Dock.stories.tsx +95 -0
  159. package/src/components/SceneView/Dock.tsx +146 -0
  160. package/src/components/SceneView/Dynamic.stories.tsx +1 -1
  161. package/src/components/SceneView/SceneView.stories.tsx +170 -18
  162. package/src/components/SceneView/SceneView.tsx +565 -151
  163. package/src/components/SceneView/SceneViewContext.ts +23 -2
  164. package/src/components/SceneView/Scored.stories.tsx +11 -11
  165. package/src/components/SceneView/usePointerMachine.ts +80 -20
  166. package/src/components/SceneView/useSceneCamera.ts +15 -8
  167. package/src/components/SceneView/useSceneClipboard.ts +4 -0
  168. package/src/components/SceneView/useSceneKeys.ts +6 -4
  169. package/src/components/SceneView/useSceneNavigation.ts +44 -33
  170. package/src/components/Toolbar/Toolbar.stories.tsx +14 -15
  171. package/src/components/Toolbar/Toolbar.tsx +15 -4
  172. package/src/components/index.ts +2 -0
  173. package/src/hooks/useWheel.ts +35 -0
  174. package/src/index.ts +4 -3
  175. package/src/model/atoms.ts +27 -3
  176. package/src/model/projection.ts +5 -0
  177. package/src/model/projections/constrained.test.ts +18 -10
  178. package/src/model/projections/constrained.ts +19 -8
  179. package/src/model/projections/dynamic.ts +5 -2
  180. package/src/model/projections/lattice.ts +15 -3
  181. package/src/model/registry.test.ts +14 -9
  182. package/src/model/registry.ts +39 -34
  183. package/src/model/store.ts +12 -2
  184. package/src/model/types.ts +124 -36
  185. package/src/playwright/SceneManager.ts +2 -2
  186. package/src/playwright/create.spec.ts +5 -3
  187. package/src/playwright/demo.spec.ts +2 -2
  188. package/src/playwright/lattice.spec.ts +4 -5
  189. package/src/playwright/scene.spec.ts +27 -25
  190. package/src/utils/builder.test.ts +46 -9
  191. package/src/utils/builder.ts +42 -18
  192. package/src/utils/camera.test.ts +22 -51
  193. package/src/utils/camera.ts +39 -32
  194. package/src/utils/clipboard.test.ts +23 -2
  195. package/src/utils/clipboard.ts +8 -4
  196. package/src/utils/diagram.test.ts +3 -1
  197. package/src/utils/diagram.ts +3 -25
  198. package/src/utils/group.test.ts +69 -0
  199. package/src/utils/group.ts +94 -0
  200. package/src/utils/gutter-route.test.ts +49 -0
  201. package/src/utils/gutter-route.ts +142 -16
  202. package/src/utils/hit.test.ts +4 -38
  203. package/src/utils/hit.ts +4 -26
  204. package/src/utils/index.ts +3 -0
  205. package/src/utils/lattice.ts +7 -1
  206. package/src/utils/layers.test.ts +139 -0
  207. package/src/utils/layers.ts +175 -0
  208. package/src/utils/parts.test.ts +66 -32
  209. package/src/utils/parts.ts +63 -41
  210. package/src/utils/ports.ts +7 -4
  211. package/src/utils/properties.test.ts +23 -6
  212. package/src/utils/properties.ts +66 -16
  213. package/src/utils/route.test.ts +51 -2
  214. package/src/utils/route.ts +133 -23
  215. package/src/utils/scenes.test.ts +38 -0
  216. package/src/utils/scenes.ts +54 -0
  217. package/src/utils/shapes.test.ts +33 -8
  218. package/src/utils/shapes.ts +51 -35
  219. package/src/utils/style.test.ts +54 -0
  220. package/src/utils/style.ts +153 -40
  221. package/src/utils/testing.test.ts +3 -3
  222. package/src/utils/testing.ts +21 -30
  223. package/src/utils/undo.test.ts +25 -2
  224. package/src/utils/undo.ts +50 -13
  225. package/dist/lib/chunk-Grid.mjs +0 -99
  226. package/dist/lib/chunk-Grid.mjs.map +0 -1
  227. package/dist/lib/scene.mjs +0 -6835
  228. package/dist/lib/scene.mjs.map +0 -1
  229. package/dist/lib/types.mjs +0 -16
  230. package/dist/lib/types.mjs.map +0 -1
  231. package/dist/types/src/archive/components/Canvas/Canvas.d.ts +0 -15
  232. package/dist/types/src/archive/components/Canvas/Canvas.d.ts.map +0 -1
  233. package/dist/types/src/archive/components/Canvas/Canvas.stories.d.ts +0 -18
  234. package/dist/types/src/archive/components/Canvas/Canvas.stories.d.ts.map +0 -1
  235. package/dist/types/src/archive/components/Canvas/index.d.ts +0 -2
  236. package/dist/types/src/archive/components/Canvas/index.d.ts.map +0 -1
  237. package/dist/types/src/archive/components/CellGrid/CellGrid.d.ts +0 -21
  238. package/dist/types/src/archive/components/CellGrid/CellGrid.d.ts.map +0 -1
  239. package/dist/types/src/archive/components/CellGrid/CellGrid.stories.d.ts +0 -21
  240. package/dist/types/src/archive/components/CellGrid/CellGrid.stories.d.ts.map +0 -1
  241. package/dist/types/src/archive/components/CellGrid/headers/Ruler.d.ts +0 -15
  242. package/dist/types/src/archive/components/CellGrid/headers/Ruler.d.ts.map +0 -1
  243. package/dist/types/src/archive/components/CellGrid/headers/TrackHeader.d.ts +0 -19
  244. package/dist/types/src/archive/components/CellGrid/headers/TrackHeader.d.ts.map +0 -1
  245. package/dist/types/src/archive/components/CellGrid/headers/index.d.ts +0 -3
  246. package/dist/types/src/archive/components/CellGrid/headers/index.d.ts.map +0 -1
  247. package/dist/types/src/archive/components/CellGrid/index.d.ts +0 -6
  248. package/dist/types/src/archive/components/CellGrid/index.d.ts.map +0 -1
  249. package/dist/types/src/archive/components/CellGrid/input/index.d.ts +0 -3
  250. package/dist/types/src/archive/components/CellGrid/input/index.d.ts.map +0 -1
  251. package/dist/types/src/archive/components/CellGrid/input/pointer.d.ts +0 -33
  252. package/dist/types/src/archive/components/CellGrid/input/pointer.d.ts.map +0 -1
  253. package/dist/types/src/archive/components/CellGrid/input/wheel.d.ts +0 -14
  254. package/dist/types/src/archive/components/CellGrid/input/wheel.d.ts.map +0 -1
  255. package/dist/types/src/archive/components/CellGrid/render/index.d.ts +0 -3
  256. package/dist/types/src/archive/components/CellGrid/render/index.d.ts.map +0 -1
  257. package/dist/types/src/archive/components/CellGrid/render/overlay-layer.d.ts +0 -21
  258. package/dist/types/src/archive/components/CellGrid/render/overlay-layer.d.ts.map +0 -1
  259. package/dist/types/src/archive/components/CellGrid/render/static-layer.d.ts +0 -36
  260. package/dist/types/src/archive/components/CellGrid/render/static-layer.d.ts.map +0 -1
  261. package/dist/types/src/archive/components/CellGrid/state/atoms.d.ts +0 -23
  262. package/dist/types/src/archive/components/CellGrid/state/atoms.d.ts.map +0 -1
  263. package/dist/types/src/archive/components/CellGrid/state/index.d.ts +0 -4
  264. package/dist/types/src/archive/components/CellGrid/state/index.d.ts.map +0 -1
  265. package/dist/types/src/archive/components/CellGrid/state/types.d.ts +0 -39
  266. package/dist/types/src/archive/components/CellGrid/state/types.d.ts.map +0 -1
  267. package/dist/types/src/archive/components/CellGrid/state/viewport.d.ts +0 -52
  268. package/dist/types/src/archive/components/CellGrid/state/viewport.d.ts.map +0 -1
  269. package/dist/types/src/archive/components/CellGrid/state/viewport.test.d.ts +0 -2
  270. package/dist/types/src/archive/components/CellGrid/state/viewport.test.d.ts.map +0 -1
  271. package/dist/types/src/archive/components/FPS.d.ts +0 -9
  272. package/dist/types/src/archive/components/FPS.d.ts.map +0 -1
  273. package/dist/types/src/archive/components/Grid/Grid.d.ts +0 -6
  274. package/dist/types/src/archive/components/Grid/Grid.d.ts.map +0 -1
  275. package/dist/types/src/archive/components/Grid/index.d.ts +0 -2
  276. package/dist/types/src/archive/components/Grid/index.d.ts.map +0 -1
  277. package/dist/types/src/archive/components/index.d.ts +0 -5
  278. package/dist/types/src/archive/components/index.d.ts.map +0 -1
  279. package/dist/types/src/archive/hooks/index.d.ts +0 -5
  280. package/dist/types/src/archive/hooks/index.d.ts.map +0 -1
  281. package/dist/types/src/archive/hooks/projection.d.ts +0 -60
  282. package/dist/types/src/archive/hooks/projection.d.ts.map +0 -1
  283. package/dist/types/src/archive/hooks/useCanvasContext.d.ts +0 -13
  284. package/dist/types/src/archive/hooks/useCanvasContext.d.ts.map +0 -1
  285. package/dist/types/src/archive/hooks/useDrag.d.ts +0 -6
  286. package/dist/types/src/archive/hooks/useDrag.d.ts.map +0 -1
  287. package/dist/types/src/archive/hooks/useWheel.d.ts +0 -8
  288. package/dist/types/src/archive/hooks/useWheel.d.ts.map +0 -1
  289. package/dist/types/src/archive/index.d.ts +0 -5
  290. package/dist/types/src/archive/index.d.ts.map +0 -1
  291. package/dist/types/src/archive/types.d.ts +0 -19
  292. package/dist/types/src/archive/types.d.ts.map +0 -1
  293. package/dist/types/src/archive/util/index.d.ts +0 -4
  294. package/dist/types/src/archive/util/index.d.ts.map +0 -1
  295. package/dist/types/src/archive/util/svg-path.d.ts +0 -4
  296. package/dist/types/src/archive/util/svg-path.d.ts.map +0 -1
  297. package/dist/types/src/archive/util/svg.d.ts +0 -32
  298. package/dist/types/src/archive/util/svg.d.ts.map +0 -1
  299. package/dist/types/src/archive/util/svg.stories.d.ts +0 -15
  300. package/dist/types/src/archive/util/svg.stories.d.ts.map +0 -1
  301. package/dist/types/src/archive/util/util.d.ts +0 -17
  302. package/dist/types/src/archive/util/util.d.ts.map +0 -1
  303. package/dist/types/src/scene.d.ts +0 -5
  304. package/dist/types/src/scene.d.ts.map +0 -1
  305. package/src/archive/components/Canvas/Canvas.stories.tsx +0 -111
  306. package/src/archive/components/Canvas/Canvas.tsx +0 -87
  307. package/src/archive/components/Canvas/index.ts +0 -5
  308. package/src/archive/components/CellGrid/CellGrid.stories.tsx +0 -239
  309. package/src/archive/components/CellGrid/CellGrid.tsx +0 -270
  310. package/src/archive/components/CellGrid/headers/Ruler.tsx +0 -71
  311. package/src/archive/components/CellGrid/headers/TrackHeader.tsx +0 -58
  312. package/src/archive/components/CellGrid/headers/index.ts +0 -6
  313. package/src/archive/components/CellGrid/index.ts +0 -9
  314. package/src/archive/components/CellGrid/input/index.ts +0 -6
  315. package/src/archive/components/CellGrid/input/pointer.ts +0 -236
  316. package/src/archive/components/CellGrid/input/wheel.ts +0 -68
  317. package/src/archive/components/CellGrid/render/index.ts +0 -6
  318. package/src/archive/components/CellGrid/render/overlay-layer.ts +0 -66
  319. package/src/archive/components/CellGrid/render/static-layer.ts +0 -112
  320. package/src/archive/components/CellGrid/state/atoms.ts +0 -43
  321. package/src/archive/components/CellGrid/state/index.ts +0 -7
  322. package/src/archive/components/CellGrid/state/types.ts +0 -40
  323. package/src/archive/components/CellGrid/state/viewport.test.ts +0 -50
  324. package/src/archive/components/CellGrid/state/viewport.ts +0 -94
  325. package/src/archive/components/FPS.tsx +0 -98
  326. package/src/archive/components/Grid/Grid.tsx +0 -17
  327. package/src/archive/components/Grid/index.ts +0 -5
  328. package/src/archive/components/index.ts +0 -8
  329. package/src/archive/hooks/index.ts +0 -8
  330. package/src/archive/hooks/projection.tsx +0 -156
  331. package/src/archive/hooks/useCanvasContext.ts +0 -32
  332. package/src/archive/hooks/useDrag.tsx +0 -96
  333. package/src/archive/hooks/useWheel.tsx +0 -80
  334. package/src/archive/index.ts +0 -8
  335. package/src/archive/types.ts +0 -14
  336. package/src/archive/util/index.ts +0 -7
  337. package/src/archive/util/svg-path.ts +0 -13
  338. package/src/archive/util/svg.stories.tsx +0 -46
  339. package/src/archive/util/svg.tsx +0 -128
  340. package/src/archive/util/util.ts +0 -50
  341. package/src/scene.ts +0 -9
@@ -1 +0,0 @@
1
- {"version":3,"file":"scene.mjs","names":[],"sources":["../../src/components/Breadcrumbs/Breadcrumbs.tsx","../../src/model/node-def.ts","../../src/model/types.ts","../../src/utils/order.ts","../../src/utils/parts.ts","../../src/utils/shapes.ts","../../src/utils/hit.ts","../../src/utils/ports.ts","../../src/utils/gutter-route.ts","../../src/utils/route.ts","../../src/components/ControlFrame/ControlFrame.tsx","../../src/utils/lattice.ts","../../src/components/LatticeGrid/LatticeGrid.tsx","../../src/utils/dnd.ts","../../src/components/Palette/Palette.tsx","../../src/components/PartEditor/PartEditor.tsx","../../src/utils/camera.ts","../../src/utils/style.ts","../../src/components/SceneLayer/SceneLayer.tsx","../../src/model/registry.ts","../../src/utils/properties.ts","../../src/components/Properties/StyleGrid.tsx","../../src/components/Properties/Properties.tsx","../../src/hooks/useRegistry.ts","../../src/utils/layout.ts","../../src/model/store.ts","../../src/model/projection.ts","../../src/utils/undo.ts","../../src/hooks/useSceneProjection.ts","../../src/hooks/useViewport.ts","../../src/hooks/useWheel.ts","../../src/model/atoms.ts","../../src/utils/clipboard.ts","../../src/model/keys.ts","../../src/components/Toolbar/Toolbar.tsx","../../src/components/SceneView/SceneViewContext.ts","../../src/utils/resize.ts","../../src/components/SceneView/usePointerMachine.ts","../../src/components/SceneView/useSceneCamera.ts","../../src/components/SceneView/useSceneClipboard.ts","../../src/components/SceneView/useSceneKeys.ts","../../src/components/SceneView/useSceneNavigation.ts","../../src/components/SceneView/useSceneSnap.ts","../../src/components/SceneView/SceneView.tsx","../../src/model/projections/constrained.ts","../../src/model/projections/dynamic.ts","../../src/model/projections/lattice.ts","../../src/utils/builder.ts","../../src/utils/diagram.ts"],"sourcesContent":["//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { Fragment } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\n\nimport { type SceneId } from '../../model/index.ts';\n\nexport type BreadcrumbsProps = {\n path: SceneId[];\n nameOf: (id: SceneId) => string;\n /** Jump to the scene at `index` of the path (drill-out by several levels at once). */\n onSelect: (index: number) => void;\n};\n\n// TODO(burdon): Reconcile with react-ui.\nexport const Breadcrumbs = ({ path, nameOf, onSelect }: BreadcrumbsProps) => (\n <nav className='flex items-center gap-1 text-sm font-mono'>\n {path.map((id, index) => (\n <Fragment key={`${index}:${id}`}>\n {index > 0 && <span className='text-fg-subtle'>›</span>}\n <Button.Root variant='ghost' size='sm' disabled={index === path.length - 1} onClick={() => onSelect(index)}>\n {nameOf(id)}\n </Button.Root>\n </Fragment>\n ))}\n </nav>\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\n// Kept apart from `registry.ts`, which imports the built-in node views: views look definitions up through\n// this module, so loading a view never has to load the registry that refers back to it.\n\nimport { type NodeDef, type NodeRegistry } from './registry.ts';\nimport { type Node } from './types.ts';\n\n/** The definition of a node's type, when the registry has it. */\nexport const nodeDef = (registry: NodeRegistry, node: Node): NodeDef | undefined => registry[node.type];\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Scene engine types (docs/DESIGN.md §4). Plain Effect schemas: no ECHO yet, so the same shapes wrap\n// into an ECHO type later without change. A diagram is one scene of typed nodes and typed links; every\n// node is a `NodeBase` (centre, size, ports, style) plus the properties its type adds, so the engine\n// works on the base and a host composes the scene schema from its own node types (decision 1).\n//\n\nimport * as Schema from 'effect/Schema';\n\nimport { Annotation } from '@dxos/echo';\nimport { HueAnnotationId, StepAnnotationId } from '@dxos/ui-types';\n\nexport const Point = Schema.Struct({ x: Schema.Number, y: Schema.Number });\nexport type Point = Schema.Schema.Type<typeof Point>;\n\nexport const Size = Schema.Struct({ width: Schema.Number, height: Schema.Number });\nexport type Size = Schema.Schema.Type<typeof Size>;\n\n/** Minor grid spacing in scene px (the finest line the grid draws at zoom 1). */\nexport const DEFAULT_GRID = 16;\n\n/** Major lines every N minor lines; the grid draws both and snapping uses the major one. */\nexport const MAJOR_GRID_RATIO = 4;\n\n/** Snap unit: nodes, layout defaults and scene bounds align to it. */\nexport const MAJOR_GRID = DEFAULT_GRID * MAJOR_GRID_RATIO;\n\n/** Two fields side by side in a form, rather than one row each. */\nconst pairLayout = (first: string, second: string) =>\n `<grid cols=\"2\" fixed=\"true\"><field name=\"${first}\"/><field name=\"${second}\"/></grid>`;\n\n/** A node coordinate as a form edits it: the stepper moves by one minor grid cell, as an arrow nudge does. */\nconst gridNumber = (title: string) => Schema.Number.annotate({ title, [StepAnnotationId]: DEFAULT_GRID });\n\n/** `Point` and `Size` for a node's own frame, laid out as one row each in the properties form. */\nconst NodeCenter = Schema.Struct({ x: gridNumber('X'), y: gridNumber('Y') }).pipe(\n Annotation.FormLayoutAnnotation.set({ [Annotation.DEFAULT_LAYOUT_NAME]: pairLayout('x', 'y') }),\n);\nconst NodeSize = Schema.Struct({ width: gridNumber('Width'), height: gridNumber('Height') }).pipe(\n Annotation.FormLayoutAnnotation.set({ [Annotation.DEFAULT_LAYOUT_NAME]: pairLayout('width', 'height') }),\n);\n\nexport const Bounds = Schema.Struct({\n x: Schema.Number,\n y: Schema.Number,\n width: Schema.Number,\n height: Schema.Number,\n});\nexport type Bounds = Schema.Schema.Type<typeof Bounds>;\n\n/** screen = (scene + {x, y}) * zoom */\nexport const Camera = Schema.Struct({ x: Schema.Number, y: Schema.Number, zoom: Schema.Number });\nexport type Camera = Schema.Schema.Type<typeof Camera>;\n\nexport type NodeId = string;\nexport type LinkId = string;\n/** A node or link id; the two namespaces never collide within a scene. */\nexport type ElementId = string;\nexport type SceneId = string;\nexport type PortId = string;\n\nexport const Side = Schema.Literals(['n', 'e', 's', 'w']);\nexport type Side = Schema.Schema.Type<typeof Side>;\n\n/** What a port takes: links leaving it, links arriving at it, or either (the default). */\nexport const PortDirection = Schema.Literals(['in', 'out', 'any']);\nexport type PortDirection = Schema.Schema.Type<typeof PortDirection>;\n\n/** An attachment point on a node's frame: a side, a 0..1 offset along it, and what it accepts. */\nexport const Port = Schema.Struct({\n id: Schema.String,\n side: Side,\n offset: Schema.Number,\n accepts: Schema.optional(PortDirection),\n});\nexport type Port = Schema.Schema.Type<typeof Port>;\n\n//\n// Nodes\n//\n\n/** How strongly a hue fills a frame: 0 is an outline (transparent), 1 to 3 are lighter to stronger fills. */\nexport const NodeTone = Schema.Literals([0, 1, 2, 3]);\nexport type NodeTone = Schema.Schema.Type<typeof NodeTone>;\n\n/** Presentation choices a node carries; every field is optional and the frame supplies the default look. */\nexport const NodeStyle = Schema.Struct({\n /** One of the theme's hues, colouring fill, text and border together. */\n hue: Schema.optional(Schema.String.annotate({ title: 'Hue', [HueAnnotationId]: true })),\n /** The hue's fill; unset is 2, the look a hue had before tones. */\n tone: Schema.optional(NodeTone),\n rounded: Schema.optional(Schema.Boolean),\n fill: Schema.optional(Schema.Boolean),\n border: Schema.optional(Schema.Boolean),\n /** A guide: drawn dashed and unfilled, an annotation rather than content. */\n guide: Schema.optional(Schema.Boolean),\n /** Text size in the node's own scene units (the editor offers a readable range; stored values are not checked). */\n fontSize: Schema.optional(Schema.Number.annotate({ title: 'Font size' })),\n /** Extra classes on the frame, for a host's own look. */\n className: Schema.optional(Schema.String),\n});\nexport type NodeStyle = Schema.Schema.Type<typeof NodeStyle>;\n\n/** The fields every node type shares; a type's schema is `Schema.Struct({ ...nodeBase, type: Literal, ... })`. */\nexport const nodeBase = {\n id: Schema.String,\n /** Fractional z-order key (see `order.ts`). */\n z: Schema.String,\n locked: Schema.optional(Schema.Boolean),\n center: NodeCenter,\n /** The frame is `size` centred on `center`, whatever the type draws inside it. */\n size: NodeSize,\n /** Per-node ports; absent means the node type's definition supplies them (decision 12). */\n ports: Schema.optional(Schema.Array(Port)),\n /** Ports spread along each side, overriding the type's layout; ignored when the node carries `ports`. */\n portsPerSide: Schema.optional(Schema.Number.annotate({ title: 'Ports per side' })),\n style: Schema.optional(NodeStyle),\n};\n\n/** Any node as the engine sees it: the shared fields and a type name; the registry knows the rest. */\nexport const NodeBase = Schema.Struct({ type: Schema.String, ...nodeBase });\nexport type NodeBase = Schema.Schema.Type<typeof NodeBase>;\n\n/** The fields of the `box` prototype (a framed shape with a centred label), shared by the types built on it. */\nexport const boxFields = {\n label: Schema.optional(Schema.String),\n};\n\nexport const RectNode = Schema.Struct({\n type: Schema.Literal('rect'),\n ...nodeBase,\n ...boxFields,\n});\nexport type RectNode = Schema.Schema.Type<typeof RectNode>;\n\n/** An ellipse inscribed in the frame. */\nexport const EllipseNode = Schema.Struct({\n type: Schema.Literal('ellipse'),\n ...nodeBase,\n label: Schema.optional(Schema.String),\n});\nexport type EllipseNode = Schema.Schema.Type<typeof EllipseNode>;\n\n/** UML class box: a name compartment over attribute and method compartments. */\nexport const ClassNode = Schema.Struct({\n type: Schema.Literal('class'),\n ...nodeBase,\n name: Schema.String,\n attributes: Schema.Array(Schema.String),\n methods: Schema.Array(Schema.String),\n});\nexport type ClassNode = Schema.Schema.Type<typeof ClassNode>;\n\n/** Free text on the canvas. Named for what it is, so a host may keep `text` for a type of its own. */\nexport const NoteNode = Schema.Struct({\n type: Schema.Literal('note'),\n ...nodeBase,\n text: Schema.String,\n});\nexport type NoteNode = Schema.Schema.Type<typeof NoteNode>;\n\n/** Portal to the next depth: renders the referenced scene scaled into this node's bounds. */\nexport const PortalNode = Schema.Struct({\n type: Schema.Literal('scene'),\n ...nodeBase,\n ...boxFields,\n scene: Schema.String,\n /** Draw the child scene inside the frame rather than the label; unset, it does so while there is no label. */\n contents: Schema.optional(Schema.Boolean.annotate({ title: 'Show contents' })),\n});\nexport type PortalNode = Schema.Schema.Type<typeof PortalNode>;\n\n/** The engine's own node types. A host may add its own (decision 1); those are `NodeBase` to the engine. */\nexport const BuiltinNode = Schema.Union([RectNode, EllipseNode, ClassNode, NoteNode, PortalNode]);\nexport type BuiltinNode = Schema.Schema.Type<typeof BuiltinNode>;\nexport type BuiltinNodeType = BuiltinNode['type'];\nexport const NODE_TYPES: readonly BuiltinNodeType[] = ['rect', 'ellipse', 'class', 'note', 'scene'];\n\n/** A node of the scene: the engine handles any `NodeBase`; built-in code narrows with the guards below. */\nexport type Node = NodeBase;\n/** A node type name; the engine's own are `BuiltinNodeType`. */\nexport type NodeType = string;\n\n/** Narrows a node to one built-in type; sound because the registry maps each type name to one schema. */\nexport const isRectNode = (node: NodeBase): node is RectNode => node.type === 'rect';\nexport const isEllipseNode = (node: NodeBase): node is EllipseNode => node.type === 'ellipse';\nexport const isClassNode = (node: NodeBase): node is ClassNode => node.type === 'class';\nexport const isNoteNode = (node: NodeBase): node is NoteNode => node.type === 'note';\nexport const isPortalNode = (node: NodeBase): node is PortalNode => node.type === 'scene';\n/** A node built on the `box` prototype, carrying a centred, editable label. */\nexport const isBoxNode = (node: NodeBase): node is RectNode | PortalNode => isRectNode(node) || isPortalNode(node);\n/** Whether a portal draws its child scene: as set, else while it has no label to show instead. */\nexport const showsContents = (node: PortalNode): boolean => node.contents ?? node.label === undefined;\nexport const isBuiltinNode = (node: NodeBase): node is BuiltinNode => NODE_TYPES.some((type) => type === node.type);\n\n//\n// Links\n//\n\n/** A link end on a node; no `port` means automatic (the closest appropriate pair, recomputed on every projection). */\nexport const PortEndpoint = Schema.Struct({\n node: Schema.String,\n port: Schema.optional(Schema.String),\n});\nexport type PortEndpoint = Schema.Schema.Type<typeof PortEndpoint>;\n\n/** A free link end at a scene point (decision 3): an arrow or path that starts or ends on nothing. */\nexport const PointEndpoint = Schema.Struct({ point: Point });\nexport type PointEndpoint = Schema.Schema.Type<typeof PointEndpoint>;\n\nexport const Endpoint = Schema.Union([PortEndpoint, PointEndpoint]);\nexport type Endpoint = Schema.Schema.Type<typeof Endpoint>;\n\nexport const isPointEndpoint = (end: Endpoint): end is PointEndpoint => 'point' in end;\n/** The node an end is attached to; a free end has none. */\nexport const endpointNode = (end: Endpoint): NodeId | undefined => ('node' in end ? end.node : undefined);\n\n/** What is drawn at a link end. */\nexport const Marker = Schema.Literals(['arrow', 'circle']);\nexport type Marker = Schema.Schema.Type<typeof Marker>;\n\n/** Markers at the source (`start`) and target (`end`) of a link. */\n/** A link's end markers; the properties form shows them side by side, as the two ends of the line. */\nexport const LinkEnds = Schema.Struct({\n start: Schema.optional(Marker),\n end: Schema.optional(Marker),\n}).pipe(Annotation.FormLayoutAnnotation.set({ [Annotation.DEFAULT_LAYOUT_NAME]: pairLayout('start', 'end') }));\nexport type LinkEnds = Schema.Schema.Type<typeof LinkEnds>;\n\nconst linkBase = {\n id: Schema.String,\n z: Schema.String,\n locked: Schema.optional(Schema.Boolean),\n source: Endpoint,\n target: Endpoint,\n /** Shorthand for `ends: { end: 'arrow' }`; ports with `accepts` constrain which end lands where. */\n directed: Schema.optional(Schema.Boolean),\n /** Explicit end markers; when present they replace what `directed` implies. */\n ends: Schema.optional(LinkEnds),\n};\n\nexport const LineLink = Schema.Struct({ type: Schema.Literal('line'), ...linkBase });\nexport type LineLink = Schema.Schema.Type<typeof LineLink>;\n\n/** Cubic Bézier leaving each port along its side's normal. */\nexport const CurveLink = Schema.Struct({ type: Schema.Literal('curve'), ...linkBase });\nexport type CurveLink = Schema.Schema.Type<typeof CurveLink>;\n\n/** Smooth curve through the ports and the control `points` in between, in order. */\nexport const SplineLink = Schema.Struct({\n type: Schema.Literal('spline'),\n ...linkBase,\n points: Schema.Array(Point),\n});\nexport type SplineLink = Schema.Schema.Type<typeof SplineLink>;\n\n/**\n * Routed between its ends rather than drawn: a stub leaves each port along its side's normal and the\n * route joins the two. Nothing is stored, so the path follows the nodes as they move.\n */\nexport const SmartLink = Schema.Struct({ type: Schema.Literal('smart'), ...linkBase });\nexport type SmartLink = Schema.Schema.Type<typeof SmartLink>;\n\nexport const Link = Schema.Union([LineLink, CurveLink, SplineLink, SmartLink]);\nexport type Link = Schema.Schema.Type<typeof Link>;\nexport type LinkType = Link['type'];\nexport const LINK_TYPES: readonly LinkType[] = ['line', 'curve', 'spline', 'smart'];\n\nexport type Element = Node | Link;\n\n/** The markers a link draws: its explicit `ends`, else an arrowhead at the target when it is `directed`. */\nexport const linkMarkers = (link: Link): LinkEnds => link.ends ?? (link.directed ? { end: 'arrow' } : {});\n\nexport const isNode = (element: Element): element is Node => 'center' in element;\nexport const isLink = (element: Element): element is Link => 'source' in element;\n\n//\n// Scene\n//\n\n/**\n * The scene schema over a set of node schemas: a host composes it from its registry's types, so the\n * schema stays exact for every type while the engine only ever sees `NodeBase`.\n */\nexport const createSceneSchema = <const Nodes extends readonly Schema.Codec<NodeBase, unknown>[]>(nodes: Nodes) =>\n Schema.Struct({\n id: Schema.String,\n name: Schema.optional(Schema.String),\n nodes: Schema.Record(Schema.String, Schema.Union(nodes)),\n links: Schema.Record(Schema.String, Link),\n });\n\n/** The scene schema over the built-in node types. */\nexport const Scene = createSceneSchema([RectNode, EllipseNode, ClassNode, NoteNode, PortalNode]);\n\n/** The scene schema over any node with the shared fields: what the engine itself can validate for a host. */\nexport const OpenScene = createSceneSchema([NodeBase]);\nexport type Scene = {\n readonly id: SceneId;\n readonly name?: string;\n readonly nodes: Readonly<Record<NodeId, Node>>;\n readonly links: Readonly<Record<LinkId, Link>>;\n};\n\n/** A node or link of the scene by id. */\nexport const getElement = (scene: Scene, id: ElementId): Element | undefined => scene.nodes[id] ?? scene.links[id];\n\n/** Property edits: the shared fields typed, a type's own fields by name. */\nexport type NodeValues = Partial<Omit<NodeBase, 'id' | 'type'>> & { readonly [key: string]: unknown };\nexport type LinkValues = Partial<Omit<Link, 'id' | 'type'>>;\n\n/**\n * What the surface asks of a projection (§3). The surface never writes coordinates itself: a\n * projection may apply, rewrite or reject each intent and then re-emits the positioned scene.\n */\nexport type Intent =\n | { kind: 'move'; ids: NodeId[]; delta: Point }\n | { kind: 'resize'; id: NodeId; bounds: Bounds }\n | { kind: 'link'; link: Link }\n | { kind: 'create'; node: Node }\n | { kind: 'delete'; ids: ElementId[] }\n | { kind: 'reorder'; id: ElementId; z: string }\n /** Property edits (label, text, geometry, control points); `id` and `type` never change. */\n | { kind: 'update'; id: ElementId; values: NodeValues | LinkValues }\n /**\n * Arrange the scene (or just `ids`, when the selection is what the user asked to tidy). An intent\n * rather than a view action, so a projection that owns its own positions may rewrite or refuse it.\n */\n | { kind: 'layout'; ids?: ElementId[] }\n /** Several intents applied as one model change (one undo step), e.g. a paste. */\n | { kind: 'batch'; intents: Intent[] };\n\nexport type Capabilities = {\n move?: boolean;\n resize?: boolean;\n link?: boolean;\n create?: boolean;\n delete?: boolean;\n update?: boolean;\n layout?: boolean;\n};\n\n/** The active tool: a node type draws that node, a link type is what port drags create. */\nexport type Tool =\n | { kind: 'select' }\n | { kind: 'hand' }\n | { kind: 'node'; type: NodeType }\n | { kind: 'link'; type: LinkType };\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Fractional z-order keys: strings that sort lexicographically, with a key constructible between any\n// two, so a reorder touches one element instead of renumbering the scene (which would be a conflict\n// magnet once elements live in a CRDT map).\n//\n\nconst DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';\n\nexport type Ordered = { id: string; z: string };\n\n/**\n * A key strictly between `a` and `b` (each a base-62 fraction in (0, 1) without trailing zeros);\n * `undefined` stands for the open end on that side.\n */\nexport const between = (a?: string, b?: string): string => midpoint(a ?? '', b);\n\nconst midpoint = (a: string, b: string | undefined): string => {\n if (b !== undefined && a >= b) {\n throw new Error(`order: ${JSON.stringify(a)} >= ${JSON.stringify(b)}`);\n }\n if (a.endsWith('0') || b?.endsWith('0')) {\n throw new Error('order: trailing zero');\n }\n if (b !== undefined) {\n let prefix = 0;\n while (prefix < b.length && (a[prefix] ?? '0') === b[prefix]) {\n prefix++;\n }\n if (prefix > 0) {\n return b.slice(0, prefix) + midpoint(a.slice(prefix), b.slice(prefix));\n }\n }\n const digitA = a ? DIGITS.indexOf(a[0]) : 0;\n const digitB = b !== undefined ? DIGITS.indexOf(b[0]) : DIGITS.length;\n if (digitB - digitA > 1) {\n return DIGITS[Math.round((digitA + digitB) / 2)];\n }\n if (b !== undefined && b.length > 1) {\n return b[0];\n }\n return DIGITS[digitA] + midpoint(a.slice(1), undefined);\n};\n\n/** Elements in paint order (bottom first). */\nexport const sortByZ = <T extends Ordered>(elements: readonly T[]): T[] =>\n [...elements].sort((left, right) => (left.z < right.z ? -1 : left.z > right.z ? 1 : left.id < right.id ? -1 : 1));\n\n/** A key above every element, so a new one paints on top. */\nexport const topZ = (elements: readonly Ordered[]): string => {\n let max: string | undefined;\n for (const element of elements) {\n if (max === undefined || element.z > max) {\n max = element.z;\n }\n }\n return between(max, undefined);\n};\n\n/** Keys for `count` elements in paint order, evenly spread from the open bottom. */\nexport const initialKeys = (count: number): string[] => {\n const keys: string[] = [];\n let previous: string | undefined;\n for (let index = 0; index < count; index++) {\n previous = between(previous, undefined);\n keys.push(previous);\n }\n return keys;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Text parts of a node: the pieces a node type renders as text and lets the user edit in place. A\n// part is named by the node property it edits; list properties read and write as one entry per line.\n//\n\nimport { type Node, type NodeValues, isBoxNode, isClassNode, isEllipseNode, isNoteNode } from '../model/types.ts';\n\nexport type PartKey = 'label' | 'text' | 'name' | 'attributes' | 'methods';\n\n/** A part edited in place: which one, and how the editor hands its result back. */\nexport type PartEditing = {\n part: PartKey;\n commit: (text: string) => void;\n cancel: () => void;\n};\n\nconst PARTS: readonly PartKey[] = ['label', 'text', 'name', 'attributes', 'methods'];\n\n/** The part a `data-part` attribute names, if it names one. */\nexport const partKey = (value: string | null | undefined): PartKey | undefined => PARTS.find((part) => part === value);\n\nconst LINES: readonly PartKey[] = ['text', 'attributes', 'methods'];\n\n/** Enter inserts a line in a multi-line part; Mod-Enter commits. */\nexport const isMultiline = (part: PartKey): boolean => LINES.includes(part);\n\nconst lines = (text: string): string[] =>\n text\n .split('\\n')\n .map((line) => line.trim())\n .filter((line) => line.length > 0);\n\n/** The part's text, or none when the node type has no such part. */\nexport const partText = (node: Node, part: PartKey): string | undefined => {\n switch (part) {\n case 'label':\n return isBoxNode(node) || isEllipseNode(node) ? (node.label ?? '') : undefined;\n case 'text':\n return isNoteNode(node) ? node.text : undefined;\n case 'name':\n return isClassNode(node) ? node.name : undefined;\n case 'attributes':\n return isClassNode(node) ? node.attributes.join('\\n') : undefined;\n case 'methods':\n return isClassNode(node) ? node.methods.join('\\n') : undefined;\n }\n};\n\n/** The `update` values that set the part's text, or none when the node type has no such part. */\nexport const partValues = (node: Node, part: PartKey, text: string): NodeValues | undefined => {\n switch (part) {\n case 'label':\n return isBoxNode(node) || isEllipseNode(node) ? { label: text } : undefined;\n case 'text':\n return isNoteNode(node) ? { text } : undefined;\n case 'name':\n return isClassNode(node) ? { name: text.trim() } : undefined;\n case 'attributes':\n return isClassNode(node) ? { attributes: lines(text) } : undefined;\n case 'methods':\n return isClassNode(node) ? { methods: lines(text) } : undefined;\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Pure geometry of the node and link types (§4): every node's frame is its `size` centred on `center`,\n// so the engine needs no registry to place, hit or route any type; the built-in types' defaults and\n// display text live here too. Rendering lives in the registry.\n//\n\nimport {\n type Bounds,\n type BuiltinNode,\n type BuiltinNodeType,\n type Endpoint,\n type Link,\n type LinkEnds,\n type LinkType,\n type Node,\n type Point,\n type Size,\n isClassNode,\n isEllipseNode,\n isNoteNode,\n isRectNode,\n} from '../model/types.ts';\nimport { partKey } from './parts.ts';\n\n/** Axis-aligned frame of a node: its size centred on its centre. */\nexport const nodeBounds = (node: Node): Bounds => ({\n x: node.center.x - node.size.width / 2,\n y: node.center.y - node.size.height / 2,\n width: node.size.width,\n height: node.size.height,\n});\n\nexport const nodeSize = (node: Node): Size => node.size;\n\n/** The node re-framed to `bounds`. */\nexport const resizeNode = <N extends Node>(node: N, bounds: Bounds): N => ({\n ...node,\n center: { x: bounds.x + bounds.width / 2, y: bounds.y + bounds.height / 2 },\n size: { width: bounds.width, height: bounds.height },\n});\n\n/** The bounding box a new basic shape gets: rectangle, ellipse and class share it, so a new circle matches a new square. */\nexport const DEFAULT_SHAPE_SIZE: Size = { width: 256, height: 256 };\n\nexport const DEFAULT_SIZES: Record<BuiltinNodeType, Size> = {\n rect: DEFAULT_SHAPE_SIZE,\n ellipse: DEFAULT_SHAPE_SIZE,\n class: DEFAULT_SHAPE_SIZE,\n note: { width: 256, height: 128 },\n scene: { width: 512, height: 256 },\n};\n\nexport type CreateNodeProps = {\n type: BuiltinNodeType;\n id: string;\n z: string;\n center: Point;\n size?: Size;\n /** A portal's child scene id. */\n scene?: string;\n};\n\n/** A new built-in node of `type` with its type's default content; a host type creates through its `NodeDef`. */\nexport const createNode = ({\n type,\n id,\n z,\n center,\n size = DEFAULT_SIZES[type],\n scene,\n}: CreateNodeProps): BuiltinNode => {\n switch (type) {\n // A new box carries no label: a placeholder would have to be cleared before a real one is typed.\n case 'rect':\n return { type, id, z, center, size };\n case 'ellipse':\n return { type, id, z, center, size };\n case 'class':\n return { type, id, z, center, size, name: 'Class', attributes: ['id: string'], methods: ['save(): void'] };\n case 'note':\n return { type, id, z, center, size, text: 'Note' };\n case 'scene':\n return { type, id, z, center, size, scene: scene ?? id };\n }\n};\n\n/** What a shape copy keeps of its own (the fresh node's) rather than the source's: identity, place and child scene. */\nconst OWN_FIELDS = new Set(['id', 'type', 'z', 'center', 'scene']);\n\n/**\n * A new shape like `source` (its size, look and ports) built on `fresh`, the type's own new node at the\n * new place: it keeps its own identity and child scene, and the type's text rather than the source's.\n */\nexport const cloneShape = (source: Node, fresh: Node): Node => ({\n ...fresh,\n ...Object.fromEntries(Object.entries(source).filter(([key]) => !OWN_FIELDS.has(key) && !partKey(key))),\n});\n\n/** The node's display text, in the field its type uses for it; a type without one is returned as is. */\nexport const withLabel = <N extends Node>(node: N, label: string): N => {\n if (isRectNode(node) || isEllipseNode(node)) {\n return { ...node, label };\n }\n if (isClassNode(node)) {\n return { ...node, name: label };\n }\n if (isNoteNode(node)) {\n return { ...node, text: label };\n }\n return node;\n};\n\nexport type CreateLinkProps = {\n type: LinkType;\n id: string;\n z: string;\n source: Endpoint;\n target: Endpoint;\n /** Where a new spline gets its first control point; ignored by the other types. */\n midpoint?: Point;\n directed?: boolean;\n ends?: LinkEnds;\n};\n\n/** A new link of `type`; a spline starts with one control point so it is editable at once. */\nexport const createLink = ({ type, id, z, source, target, midpoint, directed, ends }: CreateLinkProps): Link => {\n const base = { id, z, source, target, ...(directed ? { directed } : {}), ...(ends ? { ends } : {}) };\n switch (type) {\n case 'line':\n case 'curve':\n case 'smart':\n return { type, ...base };\n case 'spline':\n return { type, ...base, points: midpoint ? [midpoint] : [] };\n }\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Hit testing from the model in scene coordinates, never from `getClientRects`, so it is pure and the\n// same for every renderer.\n//\n\nimport { type Bounds, MAJOR_GRID, type Node, type Point, type Scene } from '../model/types.ts';\nimport { sortByZ } from './order.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/**\n * Centred on the origin, not anchored at it: a scene is laid out around (0, 0), so an extent running\n * from the origin to (1600, 1024) puts its own centre well below and right of the content and the\n * initial fit — which centres the frame — pushes everything into the top-left corner. Each half is a\n * whole number of major cells, so the frame still lands on grid lines.\n */\nexport const DEFAULT_EXTENT: Bounds = { x: -832, y: -512, width: 1664, height: 1024 };\nexport const BOUNDS_PADDING = MAJOR_GRID;\n\nexport const containsPoint = (bounds: Bounds, point: Point) =>\n point.x >= bounds.x &&\n point.x <= bounds.x + bounds.width &&\n point.y >= bounds.y &&\n point.y <= bounds.y + bounds.height;\n\nexport const intersects = (left: Bounds, right: Bounds) =>\n left.x < right.x + right.width &&\n left.x + left.width > right.x &&\n left.y < right.y + right.height &&\n left.y + left.height > right.y;\n\nexport const unionBounds = (list: readonly Bounds[]): Bounds | undefined => {\n if (list.length === 0) {\n return undefined;\n }\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n for (const bounds of list) {\n minX = Math.min(minX, bounds.x);\n minY = Math.min(minY, bounds.y);\n maxX = Math.max(maxX, bounds.x + bounds.width);\n maxY = Math.max(maxY, bounds.y + bounds.height);\n }\n return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };\n};\n\nexport const padBounds = (bounds: Bounds, padding: number): Bounds => ({\n x: bounds.x - padding,\n y: bounds.y - padding,\n width: bounds.width + 2 * padding,\n height: bounds.height + 2 * padding,\n});\n\nexport const boundsFromPoints = (from: Point, to: Point): Bounds => ({\n x: Math.min(from.x, to.x),\n y: Math.min(from.y, to.y),\n width: Math.abs(to.x - from.x),\n height: Math.abs(to.y - from.y),\n});\n\n/** Grow `bounds` outward to the nearest multiples of `unit`. */\nexport const alignBounds = (bounds: Bounds, unit: number): Bounds => {\n const x = Math.floor(bounds.x / unit) * unit;\n const y = Math.floor(bounds.y / unit) * unit;\n return {\n x,\n y,\n width: Math.ceil((bounds.x + bounds.width) / unit) * unit - x,\n height: Math.ceil((bounds.y + bounds.height) / unit) * unit - y,\n };\n};\n\nexport const nodeList = (scene: Scene): Node[] => Object.values(scene.nodes);\n\n/**\n * Derived scene bounds (decision 6): the union of nodes plus padding, grown to the major grid so the\n * frame sits on grid lines. The default extent is a floor rather than a fallback for an empty scene:\n * content only ever grows the frame, so drawing the first node does not collapse the scene around it.\n *\n * This is the frame of a scene shown on its own — the surface the user edits on. A scene shown through\n * a portal is framed by {@link contentBounds} instead.\n */\nexport const sceneBounds = (scene: Scene, padding = BOUNDS_PADDING, unit = MAJOR_GRID): Bounds => {\n const content = unionBounds(nodeList(scene).map(nodeBounds));\n const union = unionBounds(content ? [DEFAULT_EXTENT, padBounds(content, padding)] : [DEFAULT_EXTENT]);\n return alignBounds(union ?? DEFAULT_EXTENT, unit);\n};\n\n/**\n * What a scene is worth showing: the same frame without the floor under it, so a child drawn in a portal\n * fills its tile rather than being shrunk to fit an editing surface it is not being edited on. An empty\n * scene has no content to frame, so there the floor is the frame.\n */\nexport const contentBounds = (scene: Scene, padding = BOUNDS_PADDING, unit = MAJOR_GRID): Bounds => {\n const content = unionBounds(nodeList(scene).map(nodeBounds));\n return content ? alignBounds(padBounds(content, padding), unit) : alignBounds(DEFAULT_EXTENT, unit);\n};\n\n/** Topmost node under `point`, or none; `margin` widens every node, e.g. to reach its ports. */\nexport const hitTest = (scene: Scene, point: Point, margin = 0): Node | undefined => {\n const nodes = sortByZ(nodeList(scene));\n for (let index = nodes.length - 1; index >= 0; index--) {\n if (containsPoint(padBounds(nodeBounds(nodes[index]), margin), point)) {\n return nodes[index];\n }\n }\n return undefined;\n};\n\n/** Nodes whose bounds intersect `bounds` (marquee semantics). */\nexport const nodesIntersecting = (scene: Scene, bounds: Bounds): Node[] =>\n nodeList(scene).filter((node) => intersects(nodeBounds(node), bounds));\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Ports come from the node type's definition unless the node carries its own (decision 12). A link end\n// without a `port` is automatic: the closest pair is chosen from the two nodes' ports on every projection, so rearranging\n// the diagram re-attaches its links.\n//\n\nimport { nodeDef } from '../model/node-def.ts';\nimport { type NodeRegistry } from '../model/registry.ts';\nimport { type Bounds, type Node, type Point, type Port, type PortDirection, type Side } from '../model/types.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport const SIDES: readonly Side[] = ['n', 'e', 's', 'w'];\n\nexport const DEFAULT_PORTS_PER_SIDE = 3;\n\n/** The most ports a side may carry; a stored count is clamped to `1..MAX_PORTS_PER_SIDE` whole ports. */\nexport const MAX_PORTS_PER_SIDE = 9;\n\nconst clampPorts = (count: number) =>\n Number.isFinite(count) ? Math.min(MAX_PORTS_PER_SIDE, Math.max(1, Math.round(count))) : DEFAULT_PORTS_PER_SIDE;\n\n/**\n * The id of the `index`th port along `side`, counting from 1 at the side's start: `e1` is the top of the\n * east side, `s2` the middle of the south side. Pin a link end to one by naming `<node>#<portId>`.\n */\nexport const portId = (side: Side, index = 1): string => `${side}${index}`;\n\n/**\n * `count` ports spread evenly along each side, named by `portId`. Each side lists its centre port first\n * so an automatic link ties to the centre.\n */\nexport const sidePorts = (count = DEFAULT_PORTS_PER_SIDE): readonly Port[] => {\n const middle = (count + 1) / 2;\n const indices = Array.from({ length: count }, (_, index) => index + 1).sort(\n (left, right) => Math.abs(left - middle) - Math.abs(right - middle) || left - right,\n );\n return SIDES.flatMap((side) =>\n indices.map((index) => ({ id: portId(side, index), side, offset: index / (count + 1) })),\n );\n};\n\nexport const defaultPorts: readonly Port[] = sidePorts();\n\n/** How many ports a node spreads along each side: its own count, else its type's, else the default. */\nexport const portsPerSideOf = (registry: NodeRegistry, node: Node): number =>\n clampPorts(node.portsPerSide ?? nodeDef(registry, node)?.portsPerSide ?? DEFAULT_PORTS_PER_SIDE);\n\n/**\n * A node's ports: its own when it carries them, else its own `portsPerSide` spread along each side, else\n * its type's layout or count. Ports landing on the same point collapse to the first, so a definition\n * cannot stack two at one place.\n */\nexport const nodePorts = (registry: NodeRegistry, node: Node): readonly Port[] => {\n const def = nodeDef(registry, node);\n const ports =\n node.ports ??\n (node.portsPerSide !== undefined ? sidePorts(clampPorts(node.portsPerSide)) : undefined) ??\n def?.ports?.(node) ??\n sidePorts(def?.portsPerSide);\n const bounds = nodeBounds(node);\n const seen = new Set<string>();\n return ports.filter((port) => {\n const { x, y } = portPoint(bounds, port);\n const key = `${x},${y}`;\n if (seen.has(key)) {\n return false;\n }\n seen.add(key);\n return true;\n });\n};\n\n/** A port's point on the frame: exactly its offset along the side, whatever the grid. */\nexport const portPoint = (bounds: Bounds, port: Port): Point => {\n const along = (origin: number, length: number) => origin + length * port.offset;\n switch (port.side) {\n case 'n':\n return { x: along(bounds.x, bounds.width), y: bounds.y };\n case 's':\n return { x: along(bounds.x, bounds.width), y: bounds.y + bounds.height };\n case 'w':\n return { x: bounds.x, y: along(bounds.y, bounds.height) };\n case 'e':\n return { x: bounds.x + bounds.width, y: along(bounds.y, bounds.height) };\n }\n};\n\nconst OPPOSITE: Record<Side, Side> = { n: 's', s: 'n', e: 'w', w: 'e' };\n\nexport const oppositeSide = (side: Side): Side => OPPOSITE[side];\n\n/** Outward unit normal of a side. */\nexport const sideNormal = (side: Side): Point => {\n switch (side) {\n case 'n':\n return { x: 0, y: -1 };\n case 's':\n return { x: 0, y: 1 };\n case 'w':\n return { x: -1, y: 0 };\n case 'e':\n return { x: 1, y: 0 };\n }\n};\n\n/** Whether a port takes a link end of `direction` (`out` leaves it, `in` arrives); an unlabelled port takes either. */\nexport const portAccepts = (port: Port, direction: Exclude<PortDirection, 'any'>): boolean =>\n (port.accepts ?? 'any') === 'any' || port.accepts === direction;\n\nexport type PortTerminal = {\n bounds: Bounds;\n ports: readonly Port[];\n /** Pinned port id; absent means automatic. */\n port?: string;\n};\n\nexport type PortPair = { source: Port; target: Port };\n\nconst distance2 = (left: Point, right: Point) => (left.x - right.x) ** 2 + (left.y - right.y) ** 2;\n\n/**\n * The port pair joining two nodes: pinned ports are honoured, automatic ends take the port that\n * minimises the distance to the other end (ties broken by port order, so the result is stable). The\n * source end only leaves a port that accepts `out`, the target end only lands on one that accepts `in`.\n */\nexport const pairPorts = (source: PortTerminal, target: PortTerminal): PortPair | undefined => {\n const sources = candidates(source, 'out');\n const targets = candidates(target, 'in');\n if (sources.length === 0 || targets.length === 0) {\n return undefined;\n }\n let best: PortPair | undefined;\n let bestDistance = Infinity;\n for (const from of sources) {\n const fromPoint = portPoint(source.bounds, from);\n for (const to of targets) {\n const value = distance2(fromPoint, portPoint(target.bounds, to));\n if (value < bestDistance) {\n bestDistance = value;\n best = { source: from, target: to };\n }\n }\n }\n return best;\n};\n\n/** The port of `terminal` closest to `point` among those taking `direction`, for a link whose other end is free. */\nexport const nearestPort = (\n terminal: PortTerminal,\n point: Point,\n direction: Exclude<PortDirection, 'any'>,\n): Port | undefined => {\n let best: Port | undefined;\n let bestDistance = Infinity;\n for (const port of candidates(terminal, direction)) {\n const value = distance2(portPoint(terminal.bounds, port), point);\n if (value < bestDistance) {\n bestDistance = value;\n best = port;\n }\n }\n return best;\n};\n\n/** The ports an end may use: those accepting its direction, narrowed to the pinned one when it is among them. */\nconst candidates = ({ ports, port }: PortTerminal, direction: Exclude<PortDirection, 'any'>): readonly Port[] => {\n const allowed = ports.filter((candidate) => portAccepts(candidate, direction));\n if (port === undefined) {\n return allowed;\n }\n const pinned = allowed.find((candidate) => candidate.id === port);\n // A pinned port the definition no longer has, or that refuses the end, falls back to automatic rather\n // than dropping the link.\n return pinned ? [pinned] : allowed;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Gutter routing for smart links on a lattice scene (docs/DESIGN.md §8b): each end leaves its port\n// straight out to the centre line of the gutter beside it, and the route between runs at right angles, with\n// as few bends as it can, along gutter centre lines and the lines through its own ports. A port line runs\n// straight through free cells, so a route detours into the gutters only around occupied ones; a gutter a\n// multi-cell shape spans is covered by the shape, so it is not a track.\n//\n\nimport { type Bounds, type Node, type Point } from '../model/types.ts';\nimport { type LatticeSpec } from './lattice.ts';\nimport { sideNormal } from './ports.ts';\nimport { type RouteEnd } from './route.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** A bend costs as much as this much distance: turns dominate, length breaks ties. */\nconst TURN_COST = 100_000;\n\n/** Gutter lines beyond the two ends the search may use, so a route can go round an obstacle. */\nconst MARGIN = 3;\n\nconst EPSILON = 1e-6;\n\n/** Whether an axis-aligned segment passes through a frame's interior (touching its edge does not count). */\nconst crosses = (from: Point, to: Point, bounds: Bounds): boolean => {\n const [left, right] = [Math.min(from.x, to.x), Math.max(from.x, to.x)];\n const [top, bottom] = [Math.min(from.y, to.y), Math.max(from.y, to.y)];\n return (\n left < bounds.x + bounds.width - EPSILON &&\n right > bounds.x + EPSILON &&\n top < bounds.y + bounds.height - EPSILON &&\n bottom > bounds.y + EPSILON\n );\n};\n\n/** Where an end meets the gutter beside its port: straight out along the side's normal, half a gutter. */\nconst gutterExit = (end: RouteEnd, spec: LatticeSpec): Point => {\n const normal = sideNormal(end.side);\n return { x: end.point.x + (normal.x * spec.gutterX) / 2, y: end.point.y + (normal.y * spec.gutterY) / 2 };\n};\n\n/** The gutter centre lines (`(k + 1/2) x pitch`) in `[low, high]`, widened by `MARGIN` lines either side. */\nconst gutterLines = (low: number, high: number, pitch: number): number[] => {\n const first = Math.floor(low / pitch - 0.5) - MARGIN;\n const last = Math.ceil(high / pitch - 0.5) + MARGIN;\n return Array.from({ length: last - first + 1 }, (_, index) => (first + index + 0.5) * pitch);\n};\n\nconst sortedUnique = (values: number[]): number[] =>\n [...new Set(values.map((value) => Math.round(value * 1000) / 1000))].sort((left, right) => left - right);\n\ntype Axis = 'h' | 'v';\n\n/**\n * The polyline a smart link follows through the gutters, from `from`'s port to `to`'s: undefined when the\n * gutters offer no way round (the caller then falls back to the plain smart route).\n */\nexport const gutterRoute = (\n nodes: readonly Node[],\n spec: LatticeSpec,\n from: RouteEnd,\n to: RouteEnd,\n): Point[] | undefined => {\n const [pitchX, pitchY] = [spec.width + spec.gutterX, spec.height + spec.gutterY];\n const start = gutterExit(from, spec);\n const end = gutterExit(to, spec);\n const verticals = gutterLines(Math.min(start.x, end.x), Math.max(start.x, end.x), pitchX);\n const horizontals = gutterLines(Math.min(start.y, end.y), Math.max(start.y, end.y), pitchY);\n const xs = sortedUnique([...verticals, start.x, end.x]);\n const ys = sortedUnique([...horizontals, start.y, end.y]);\n const frames = nodes.map(nodeBounds);\n const clear = (a: Point, b: Point) => !frames.some((frame) => crosses(a, b, frame));\n\n const indexOf = (values: number[], value: number) => values.indexOf(Math.round(value * 1000) / 1000);\n const [startI, startJ] = [indexOf(xs, start.x), indexOf(ys, start.y)];\n const [endI, endJ] = [indexOf(xs, end.x), indexOf(ys, end.y)];\n // The stub leaves along the side's normal, so the first run continuing that axis is not a bend.\n const axisOf = (end: RouteEnd): Axis => (end.side === 'e' || end.side === 'w' ? 'h' : 'v');\n\n // Dijkstra over (column, row, arriving axis); the grid is a few dozen lines a side, so a linear scan of\n // the open set is cheap enough.\n type State = { i: number; j: number; axis: Axis };\n const key = ({ i, j, axis }: State) => `${i},${j},${axis}`;\n const cost = new Map<string, number>();\n const previous = new Map<string, State>();\n const open: State[] = [];\n const startState: State = { i: startI, j: startJ, axis: axisOf(from) };\n cost.set(key(startState), 0);\n open.push(startState);\n let best: State | undefined;\n let bestCost = Infinity;\n while (open.length > 0) {\n open.sort((left, right) => (cost.get(key(left)) ?? Infinity) - (cost.get(key(right)) ?? Infinity));\n const current = open.shift();\n if (!current) {\n break;\n }\n const currentCost = cost.get(key(current)) ?? Infinity;\n if (currentCost >= bestCost) {\n break;\n }\n if (current.i === endI && current.j === endJ) {\n // Entering the target's stub off its axis is one more bend.\n const total = currentCost + (current.axis === axisOf(to) ? 0 : TURN_COST);\n if (total < bestCost) {\n bestCost = total;\n best = current;\n }\n continue;\n }\n const here = { x: xs[current.i], y: ys[current.j] };\n const steps: [number, number, Axis][] = [\n [current.i - 1, current.j, 'h'],\n [current.i + 1, current.j, 'h'],\n [current.i, current.j - 1, 'v'],\n [current.i, current.j + 1, 'v'],\n ];\n for (const [i, j, axis] of steps) {\n if (i < 0 || j < 0 || i >= xs.length || j >= ys.length) {\n continue;\n }\n const there = { x: xs[i], y: ys[j] };\n if (!clear(here, there)) {\n continue;\n }\n const next: State = { i, j, axis };\n const nextCost =\n currentCost + Math.abs(there.x - here.x) + Math.abs(there.y - here.y) + (axis === current.axis ? 0 : TURN_COST);\n if (nextCost < (cost.get(key(next)) ?? Infinity)) {\n cost.set(key(next), nextCost);\n previous.set(key(next), current);\n open.push(next);\n }\n }\n }\n if (!best) {\n return undefined;\n }\n\n const corners: Point[] = [];\n for (let state: State | undefined = best; state; state = previous.get(key(state))) {\n corners.unshift({ x: xs[state.i], y: ys[state.j] });\n }\n return collapse([from.point, ...corners, to.point]);\n};\n\n/** Drops repeated points and the middle of any three collinear ones, so only the real bends remain. */\nconst collapse = (points: Point[]): Point[] => {\n const unique = points.filter(\n (point, index) => index === 0 || point.x !== points[index - 1].x || point.y !== points[index - 1].y,\n );\n return unique.filter((point, index) => {\n if (index === 0 || index === unique.length - 1) {\n return true;\n }\n const [before, after] = [unique[index - 1], unique[index + 1]];\n return !((before.x === point.x && point.x === after.x) || (before.y === point.y && point.y === after.y));\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Link routes as SVG path data in scene coordinates, one per link type: `line` is straight, `curve`\n// leaves each port along its side's normal and bends toward the other end, `spline` is the polyline\n// through the link's control points with its corners rounded. `ortho` (phase 2) will come from\n// `@dxos/diagram`'s router.\n//\n\nimport { Nudge } from '@dxos/diagram';\n\nimport { type NodeRegistry } from '../model/registry.ts';\nimport {\n DEFAULT_GRID,\n type Endpoint,\n type Link,\n MAJOR_GRID,\n type Node,\n type Point,\n type Port,\n type PortEndpoint,\n type Scene,\n type Side,\n isPointEndpoint,\n} from '../model/types.ts';\nimport { gutterRoute } from './gutter-route.ts';\nimport { type LatticeSpec } from './lattice.ts';\nimport { type PortTerminal, nearestPort, nodePorts, pairPorts, portPoint, sideNormal } from './ports.ts';\nimport { nodeBounds } from './shapes.ts';\n\nconst MIN_TANGENT = 40;\nconst TANGENT_RATIO = 0.4;\n\n/**\n * How far a rounded corner reaches back along each of its segments, in scene px: one minor grid cell, so\n * every corner of a route has the same radius (a gutter route's port stubs are half a gutter, two cells).\n */\nconst CORNER_RADIUS = DEFAULT_GRID;\n\n/** How far a smart link's stub leaves its port, in scene px (half a major cell). */\nconst SMART_STUB = MAJOR_GRID / 2;\n\nexport type RouteEnd = { point: Point; side: Side };\n\nconst pt = ({ x, y }: Point) => `${x} ${y}`;\n\nexport const linePath = (from: Point, to: Point): string => `M ${pt(from)} L ${pt(to)}`;\n\nconst curveControls = (from: RouteEnd, to: RouteEnd): [Point, Point] => {\n const dx = to.point.x - from.point.x;\n const dy = to.point.y - from.point.y;\n const tangent = Math.max(MIN_TANGENT, Math.hypot(dx, dy) * TANGENT_RATIO);\n const fromNormal = sideNormal(from.side);\n const toNormal = sideNormal(to.side);\n return [\n { x: from.point.x + fromNormal.x * tangent, y: from.point.y + fromNormal.y * tangent },\n { x: to.point.x + toNormal.x * tangent, y: to.point.y + toNormal.y * tangent },\n ];\n};\n\n/** Cubic Bézier whose control points sit `tangent` px out along each port's normal. */\nexport const curvePath = (from: RouteEnd, to: RouteEnd): string => {\n const [control1, control2] = curveControls(from, to);\n return `M ${pt(from.point)} C ${pt(control1)}, ${pt(control2)}, ${pt(to.point)}`;\n};\n\n/** Point on the curve at parameter `t`, for placing a label at the midpoint. */\nexport const curvePoint = (from: RouteEnd, to: RouteEnd, t: number): Point => {\n const [p1, p2] = curveControls(from, to);\n const p0 = from.point;\n const p3 = to.point;\n const u = 1 - t;\n return {\n x: u ** 3 * p0.x + 3 * u ** 2 * t * p1.x + 3 * u * t ** 2 * p2.x + t ** 3 * p3.x,\n y: u ** 3 * p0.y + 3 * u ** 2 * t * p1.y + 3 * u * t ** 2 * p2.y + t ** 3 * p3.y,\n };\n};\n\nconst distance = (from: Point, to: Point): number => Math.hypot(to.x - from.x, to.y - from.y);\n\n/** The point `length` along the way from `from` towards `to`, or `from` when the two coincide. */\nconst towards = (from: Point, to: Point, length: number): Point => {\n const span = distance(from, to);\n return span === 0\n ? from\n : { x: from.x + ((to.x - from.x) / span) * length, y: from.y + ((to.y - from.y) / span) * length };\n};\n\n/**\n * The polyline through every point with its corners rounded: each interior point becomes a quadratic\n * Bézier that takes the point as its control, so the route bends around a control point rather than\n * through it and a corner reads as a corner. The radius shrinks to half the shorter adjoining segment\n * where a point is close to its neighbours, so two corners never eat into each other.\n */\nexport const splinePath = (points: readonly Point[]): string => {\n if (points.length < 2) {\n return '';\n }\n const last = points.length - 1;\n const segments: string[] = [`M ${pt(points[0])}`];\n for (let index = 1; index < last; index++) {\n const previous = points[index - 1];\n const vertex = points[index];\n const next = points[index + 1];\n const radius = Math.min(CORNER_RADIUS, distance(previous, vertex) / 2, distance(vertex, next) / 2);\n segments.push(`L ${pt(towards(vertex, previous, radius))}`);\n segments.push(`Q ${pt(vertex)}, ${pt(towards(vertex, next, radius))}`);\n }\n segments.push(`L ${pt(points[last])}`);\n return segments.join(' ');\n};\n\n/** The path of a link between two resolved ends, by its type; on a lattice a smart link takes the gutters. */\nexport const linkPath = (link: Link, from: RouteEnd, to: RouteEnd, lattice?: LatticeRoute): string => {\n switch (link.type) {\n case 'line':\n return linePath(from.point, to.point);\n case 'curve':\n return curvePath(from, to);\n case 'spline':\n return splinePath([from.point, ...link.points, to.point]);\n case 'smart':\n return splinePath((lattice && gutterRoute(lattice.nodes, lattice.spec, from, to)) ?? smartPoints(from, to));\n }\n};\n\n/** What gutter routing needs: the lattice and the nodes whose frames block it. */\nexport type LatticeRoute = { spec: LatticeSpec; nodes: readonly Node[] };\n\n/**\n * The polyline a smart link follows: a stub out of each port along its side's normal, then one segment\n * joining them. `splinePath` rounds where they meet, so a pair of facing ports reads as the elbow the\n * ports imply rather than a straight line cutting across their own nodes.\n */\nexport const smartPoints = (from: RouteEnd, to: RouteEnd): Point[] => {\n const fromNormal = sideNormal(from.side);\n const toNormal = sideNormal(to.side);\n return [\n from.point,\n { x: from.point.x + fromNormal.x * SMART_STUB, y: from.point.y + fromNormal.y * SMART_STUB },\n { x: to.point.x + toNormal.x * SMART_STUB, y: to.point.y + toNormal.y * SMART_STUB },\n to.point,\n ];\n};\n\nexport type LinkGeometry = { link: Link; path: string; source: RouteEnd; target: RouteEnd };\n\n/** The side of a free end: the one facing the other end, so the route leaves it toward that end. */\nexport const sideToward = (from: Point, to: Point): Side => {\n const dx = to.x - from.x;\n const dy = to.y - from.y;\n return Math.abs(dx) >= Math.abs(dy) ? (dx >= 0 ? 'e' : 'w') : dy >= 0 ? 's' : 'n';\n};\n\n/** A node end as the port picker sees it, or nothing when the node is gone. */\nconst terminalOf = (scene: Scene, registry: NodeRegistry, end: PortEndpoint): PortTerminal | undefined => {\n const node = scene.nodes[end.node];\n return node ? { bounds: nodeBounds(node), ports: nodePorts(registry, node), port: end.port } : undefined;\n};\n\nconst routeEnd = (terminal: PortTerminal, port: Port): RouteEnd => ({\n point: portPoint(terminal.bounds, port),\n side: port.side,\n});\n\n/**\n * Resolve a link's ends and route it by its type: two node ends take the automatic (or pinned) port pair,\n * a node end facing a free point takes the port nearest that point, and two free points face each other.\n */\nexport const linkGeometry = (\n scene: Scene,\n registry: NodeRegistry,\n link: Link,\n lattice?: LatticeSpec,\n): LinkGeometry | undefined => {\n const ends = resolveEnds(scene, registry, link.source, link.target);\n if (!ends) {\n return undefined;\n }\n const [from, to] = ends;\n const route = lattice ? { spec: lattice, nodes: Object.values(scene.nodes) } : undefined;\n return { link, path: linkPath(link, from, to, route), source: from, target: to };\n};\n\nconst resolveEnds = (\n scene: Scene,\n registry: NodeRegistry,\n source: Endpoint,\n target: Endpoint,\n): [RouteEnd, RouteEnd] | undefined => {\n if (isPointEndpoint(source)) {\n if (isPointEndpoint(target)) {\n return [\n { point: source.point, side: sideToward(source.point, target.point) },\n { point: target.point, side: sideToward(target.point, source.point) },\n ];\n }\n const terminal = terminalOf(scene, registry, target);\n const port = terminal && nearestPort(terminal, source.point, 'in');\n if (!terminal || !port) {\n return undefined;\n }\n const to = routeEnd(terminal, port);\n return [{ point: source.point, side: sideToward(source.point, to.point) }, to];\n }\n if (isPointEndpoint(target)) {\n const terminal = terminalOf(scene, registry, source);\n const port = terminal && nearestPort(terminal, target.point, 'out');\n if (!terminal || !port) {\n return undefined;\n }\n const from = routeEnd(terminal, port);\n return [from, { point: target.point, side: sideToward(target.point, from.point) }];\n }\n const sourceTerminal = terminalOf(scene, registry, source);\n const targetTerminal = terminalOf(scene, registry, target);\n const pair = sourceTerminal && targetTerminal && pairPorts(sourceTerminal, targetTerminal);\n if (!sourceTerminal || !targetTerminal || !pair) {\n return undefined;\n }\n return [routeEnd(sourceTerminal, pair.source), routeEnd(targetTerminal, pair.target)];\n};\n\n/**\n * Every link's geometry, routed together: on a lattice scene the smart links take the gutters and are\n * then nudged apart (`@dxos/diagram`'s `Nudge`, one minor grid unit between lanes) so links sharing a\n * gutter run side by side in their own lanes, ordered so their turn-offs do not cross (DESIGN §8b).\n * Other links, and any scene without a lattice, route one by one as `linkGeometry` does.\n */\nexport const sceneLinkGeometry = (\n scene: Scene,\n registry: NodeRegistry,\n links: readonly Link[],\n lattice?: LatticeSpec,\n): LinkGeometry[] => {\n if (!lattice) {\n return links.flatMap((link) => linkGeometry(scene, registry, link) ?? []);\n }\n const nodes = Object.values(scene.nodes);\n const rect = (bounds: { x: number; y: number; width: number; height: number }) => ({\n x: bounds.x,\n y: bounds.y,\n w: bounds.width,\n h: bounds.height,\n });\n const frameOf = (end: Endpoint) => {\n const node = isPointEndpoint(end) ? undefined : scene.nodes[end.node];\n return node ? rect(nodeBounds(node)) : undefined;\n };\n const routed = links.flatMap((link) => {\n const ends = resolveEnds(scene, registry, link.source, link.target);\n if (!ends) {\n return [];\n }\n const [from, to] = ends;\n const points = link.type === 'smart' ? (gutterRoute(nodes, lattice, from, to) ?? smartPoints(from, to)) : undefined;\n return [{ link, from, to, points }];\n });\n const smart = routed.filter((entry) => entry.points !== undefined);\n const nudged = Nudge.nudge(\n smart.map(({ link, points }) => ({\n points: points ?? [],\n source: frameOf(link.source),\n target: frameOf(link.target),\n })),\n { spacing: DEFAULT_GRID, obstacles: nodes.map((node) => rect(nodeBounds(node))) },\n );\n const lanes = new Map(smart.map((entry, index) => [entry.link.id, nudged[index]]));\n return routed.map(({ link, from, to }) => {\n const points = lanes.get(link.id);\n if (!points || points.length < 2) {\n return { link, path: linkPath(link, from, to), source: from, target: to };\n }\n // A nudged port may slide along its side, so the ends are read back from the lane.\n const source = { point: points[0], side: from.side };\n const target = { point: points[points.length - 1], side: to.side };\n return { link, path: splinePath(points), source, target };\n });\n};\n\n/** Index at which a new control point at `point` keeps the polyline `ends`+`points` in order. */\nexport const insertIndex = (from: Point, points: readonly Point[], to: Point, point: Point): number => {\n const polyline = [from, ...points, to];\n let best = 0;\n let bestDistance = Infinity;\n for (let index = 0; index < polyline.length - 1; index++) {\n const distance = segmentDistance(polyline[index], polyline[index + 1], point);\n if (distance < bestDistance) {\n bestDistance = distance;\n best = index;\n }\n }\n return best;\n};\n\nconst segmentDistance = (a: Point, b: Point, p: Point): number => {\n const dx = b.x - a.x;\n const dy = b.y - a.y;\n const length2 = dx * dx + dy * dy;\n const t = length2 === 0 ? 0 : Math.max(0, Math.min(1, ((p.x - a.x) * dx + (p.y - a.y) * dy) / length2));\n return Math.hypot(a.x + t * dx - p.x, a.y + t * dy - p.y);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Overlay in scene coordinates (§7 layer 3): selection outlines, resize handles, ports, link end and\n// control points, the marquee and the link rubber band. Sizes are divided by zoom because the parent\n// transform scales the SVG.\n//\n\nimport React, { memo } from 'react';\n\nimport { mx } from '@dxos/ui-theme';\n\nimport { type ControlPointRef, type Drag, type Handle } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type NodeRegistry } from '../../model/registry.ts';\nimport {\n type Bounds,\n type Capabilities,\n type ElementId,\n type Endpoint,\n type Link,\n type Node,\n type Point,\n type Port,\n type Scene,\n type SplineLink,\n endpointNode,\n isPointEndpoint,\n} from '../../model/types.ts';\nimport { boundsFromPoints } from '../../utils/hit.ts';\nimport { type LatticeSpec } from '../../utils/lattice.ts';\nimport { nodePorts, oppositeSide, portPoint } from '../../utils/ports.ts';\nimport { curvePath, linkGeometry, sceneLinkGeometry } from '../../utils/route.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\n\nconst HANDLES: readonly Handle[] = ['nw', 'n', 'ne', 'e', 'se', 's', 'sw', 'w'];\n\nexport const handlePoint = (bounds: Bounds, handle: Handle): Point => {\n const x = handle.includes('w')\n ? bounds.x\n : handle.includes('e')\n ? bounds.x + bounds.width\n : bounds.x + bounds.width / 2;\n const y = handle.includes('n')\n ? bounds.y\n : handle.includes('s')\n ? bounds.y + bounds.height\n : bounds.y + bounds.height / 2;\n return { x, y };\n};\n\nconst cursorFor = (handle: Handle) =>\n ({ n: 'ns', s: 'ns', e: 'ew', w: 'ew', ne: 'nesw', sw: 'nesw', nw: 'nwse', se: 'nwse' })[handle] + '-resize';\n\nexport type LinkEnd = 'source' | 'target';\n\nexport type ControlFrameProps = {\n scene: Scene;\n registry: NodeRegistry;\n /** What the view may do: no handle is drawn for a gesture that could not apply. */\n capabilities: Capabilities;\n selection: ReadonlySet<ElementId>;\n hover?: ElementId;\n selectedPoint?: ControlPointRef;\n zoom: number;\n drag?: Drag;\n /** The bounds a create gesture in flight would land, drawn as a provisional frame. */\n createFrame?: Bounds;\n /** The gesture in flight would be refused (an overlap on the lattice): its outlines turn red. */\n blocked?: boolean;\n /** The scene's lattice, so a selected smart link's handles sit on its gutter route. */\n lattice?: LatticeSpec;\n onHandlePointerDown?: (node: Node, handle: Handle, event: React.PointerEvent) => void;\n onPortPointerDown?: (node: Node, port: Port, event: React.PointerEvent) => void;\n onEndPointerDown?: (link: Link, end: LinkEnd, event: React.PointerEvent) => void;\n onPointPointerDown?: (link: SplineLink, index: number, event: React.PointerEvent) => void;\n /** `index` is where in the link's points a control point at `point` would be inserted. */\n onMidpointPointerDown?: (link: SplineLink, index: number, point: Point, event: React.PointerEvent) => void;\n onPointContextMenu?: (link: SplineLink, index: number, event: React.MouseEvent) => void;\n};\n\n/** The midpoint of every span of a spline's polyline, each with the index a control point there takes. */\nconst midpoints = (source: Point, points: readonly Point[], target: Point) => {\n const vertices = [source, ...points, target];\n return vertices.slice(1).map((vertex, index) => ({\n index,\n point: { x: (vertices[index].x + vertex.x) / 2, y: (vertices[index].y + vertex.y) / 2 },\n }));\n};\n\nexport const ControlFrame = memo(\n ({\n scene,\n registry,\n capabilities,\n selection,\n hover,\n selectedPoint,\n zoom,\n drag,\n createFrame,\n blocked,\n lattice,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n }: ControlFrameProps) => {\n const unit = 1 / Math.max(zoom, 0.05);\n const handleSize = 8 * unit;\n const portRadius = 5 * unit;\n const midpointRadius = 4 * unit;\n const selectedNodes = [...selection].map((id) => scene.nodes[id]).filter((node) => node !== undefined);\n const selectedLinks = [...selection].map((id) => scene.links[id]).filter((link) => link !== undefined);\n const lanes =\n lattice && selectedLinks.length > 0\n ? new Map(\n sceneLinkGeometry(scene, registry, Object.values(scene.links), lattice).map((geometry) => [\n geometry.link.id,\n geometry,\n ]),\n )\n : undefined;\n const single = selectedNodes.length === 1 ? selectedNodes[0] : undefined;\n // Only the node under the pointer: every node's ports at once is a field of dots that hides the\n // diagram the user is drawing, and a link can start from a body now, so they are a refinement\n // rather than the only way in.\n const portNodes = new Set<Node>();\n const hovered = hover ? scene.nodes[hover] : undefined;\n // A selected node shows its handles instead: ports on the same frame crowd them and the label.\n if (hovered && capabilities.link && !selection.has(hovered.id)) {\n portNodes.add(hovered);\n }\n // Pointer capture during a link drag suppresses hover, so the drop target shows its ports itself.\n const dropNode = (drag?.kind === 'link' || drag?.kind === 'end') && drag.target && endpointNode(drag.target);\n const dropTarget = dropNode ? scene.nodes[dropNode] : undefined;\n if (dropTarget) {\n portNodes.add(dropTarget);\n }\n const marquee = drag?.kind === 'marquee' ? boundsFromPoints(drag.from, drag.to) : undefined;\n // The layer draws every provisional link that will land (over a target, or free-ended); the band is only\n // a port drag over free space, where dropping would create a node rather than a free end.\n const band =\n drag?.kind === 'link' && !drag.target && !isPointEndpoint(drag.source)\n ? { from: { point: drag.from, side: drag.fromSide }, to: drag.to }\n : undefined;\n\n return (\n <svg className='absolute overflow-visible pointer-events-none' width={1} height={1}>\n {selectedNodes.map((node) => {\n const bounds = nodeBounds(node);\n return (\n <rect\n key={node.id}\n x={bounds.x}\n y={bounds.y}\n width={bounds.width}\n height={bounds.height}\n className={mx('fill-none', blocked ? 'stroke-error-border' : 'stroke-primary-500')}\n strokeWidth={unit}\n data-blocked={blocked || undefined}\n />\n );\n })}\n {[...portNodes].map((node) => {\n const bounds = nodeBounds(node);\n return nodePorts(registry, node).map((port) => {\n const point = portPoint(bounds, port);\n // Filled while it is an end of the drag in progress: the source, or the port it would drop on.\n const isEnd = (end: Endpoint | undefined) =>\n end !== undefined && !isPointEndpoint(end) && end.node === node.id && end.port === port.id;\n const active =\n (drag?.kind === 'link' && isEnd(drag.source)) ||\n ((drag?.kind === 'link' || drag?.kind === 'end') && isEnd(drag.target));\n return (\n <circle\n key={`${node.id}/${port.id}`}\n cx={point.x}\n cy={point.y}\n r={portRadius}\n className={mx(\n 'stroke-primary-500 pointer-events-auto cursor-crosshair hover:fill-primary-500',\n active ? 'fill-primary-500' : 'fill-base-surface',\n )}\n strokeWidth={unit}\n onPointerDown={(event) => onPortPointerDown?.(node, port, event)}\n />\n );\n });\n })}\n {/* Handles after the ports so a handle wins where a port sits on the same point (a side centre). */}\n {single && capabilities.resize && nodeDef(registry, single)?.resizable && !single.locked && (\n <g>\n {HANDLES.map((handle) => {\n const point = handlePoint(nodeBounds(single), handle);\n return (\n <rect\n key={handle}\n x={point.x - handleSize / 2}\n y={point.y - handleSize / 2}\n width={handleSize}\n height={handleSize}\n className='fill-base-surface stroke-primary-500 pointer-events-auto'\n strokeWidth={unit}\n style={{ cursor: cursorFor(handle) }}\n onPointerDown={(event) => onHandlePointerDown?.(single, handle, event)}\n />\n );\n })}\n </g>\n )}\n {/* A link's end and control-point handles all move it, so they follow the `update` capability together. */}\n {selectedLinks.map((link) => {\n // On a lattice the handles sit on the link's lane, which depends on the links around it.\n const geometry = capabilities.update\n ? (lanes?.get(link.id) ?? linkGeometry(scene, registry, link, lattice))\n : undefined;\n if (!geometry) {\n return null;\n }\n const points =\n link.type === 'spline' ? (drag?.kind === 'point' && drag.id === link.id ? drag.points : link.points) : [];\n const ends: [LinkEnd, Point][] = [\n ['source', geometry.source.point],\n ['target', geometry.target.point],\n ];\n return (\n <g key={link.id}>\n {ends.map(([end, point]) => (\n <circle\n key={end}\n cx={point.x}\n cy={point.y}\n r={portRadius}\n className={mx(\n 'stroke-primary-500 pointer-events-auto cursor-move hover:fill-primary-500',\n drag?.kind === 'end' && drag.id === link.id && drag.end === end\n ? 'fill-primary-500'\n : 'fill-base-surface',\n )}\n strokeWidth={unit}\n onPointerDown={(event) => onEndPointerDown?.(link, end, event)}\n />\n ))}\n {/* Midpoints first, so a control point wins wherever the two land on each other. */}\n {link.type === 'spline' &&\n midpoints(geometry.source.point, points, geometry.target.point).map(({ index, point }) => (\n <circle\n key={`midpoint-${index}`}\n cx={point.x}\n cy={point.y}\n r={midpointRadius}\n className='fill-primary-500/40 pointer-events-auto cursor-copy hover:fill-primary-500'\n onPointerDown={(event) => onMidpointPointerDown?.(link, index, point, event)}\n />\n ))}\n {link.type === 'spline' &&\n points.map((point, index) => (\n <rect\n key={index}\n x={point.x - handleSize / 2}\n y={point.y - handleSize / 2}\n width={handleSize}\n height={handleSize}\n transform={`rotate(45 ${point.x} ${point.y})`}\n className={mx(\n 'stroke-primary-500 pointer-events-auto cursor-move hover:fill-primary-500',\n selectedPoint?.link === link.id && selectedPoint.index === index\n ? 'fill-primary-500'\n : 'fill-base-surface',\n )}\n strokeWidth={unit}\n onPointerDown={(event) => onPointPointerDown?.(link, index, event)}\n onContextMenu={(event) => onPointContextMenu?.(link, index, event)}\n />\n ))}\n </g>\n );\n })}\n {band && (\n <path\n d={curvePath(band.from, { point: band.to, side: oppositeSide(band.from.side) })}\n className='fill-none stroke-primary-500'\n strokeWidth={2 * unit}\n strokeDasharray={`${6 * unit} ${4 * unit}`}\n />\n )}\n {marquee && (\n <rect\n x={marquee.x}\n y={marquee.y}\n width={marquee.width}\n height={marquee.height}\n className='fill-primary-500/10 stroke-primary-500'\n strokeWidth={unit}\n />\n )}\n {createFrame && (\n <rect\n data-testid='create-frame'\n x={createFrame.x}\n y={createFrame.y}\n width={createFrame.width}\n height={createFrame.height}\n className={blocked ? 'fill-error-surface stroke-error-border' : 'fill-primary-500/10 stroke-primary-500'}\n data-blocked={blocked || undefined}\n strokeWidth={unit}\n />\n )}\n </svg>\n );\n },\n);\n\nControlFrame.displayName = 'ControlFrame';\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Lattice mode geometry (docs/DESIGN.md §8b): shapes occupy whole cells of a coarse lattice, separated by\n// fixed gutters. A cell's pitch is a one-cell shape plus a gutter; a shape spans any whole number of cells\n// on each axis and covers the gutters between them, so every channel between shapes is one gutter wide.\n//\n\nimport { type Bounds, type ElementId, type Node } from '../model/types.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** The size of a one-cell shape and the gutter between shapes, in scene units. */\nexport type LatticeSpec = { width: number; height: number; gutterX: number; gutterY: number };\n\nexport const DEFAULT_LATTICE: LatticeSpec = { width: 256, height: 128, gutterX: 128, gutterY: 64 };\n\n/** A shape on the lattice: its first (top-left) cell and how many cells it spans on each axis. */\nexport type LatticeCell = { col: number; row: number; spanX: number; spanY: number };\n\nconst pitchX = (spec: LatticeSpec) => spec.width + spec.gutterX;\nconst pitchY = (spec: LatticeSpec) => spec.height + spec.gutterY;\n\n/** The nearest whole span (at least 1) for a frame `length` long, one cell being `cell` plus `gutter`. */\nconst spanOf = (length: number, cell: number, gutter: number): number =>\n Math.max(1, Math.round((length + gutter) / (cell + gutter)));\n\n/** The lattice cells nearest a frame: the nearest whole spans, placed so their centre is nearest the frame's. */\nexport const toCell = (bounds: Bounds, spec: LatticeSpec): LatticeCell => {\n const spanX = spanOf(bounds.width, spec.width, spec.gutterX);\n const spanY = spanOf(bounds.height, spec.height, spec.gutterY);\n return {\n // `+ 0` folds -0 into 0, so a cell just left of the origin is the same key as the origin's.\n col: Math.round((bounds.x + bounds.width / 2) / pitchX(spec) - (spanX - 1) / 2) + 0,\n row: Math.round((bounds.y + bounds.height / 2) / pitchY(spec) - (spanY - 1) / 2) + 0,\n spanX,\n spanY,\n };\n};\n\n/** The frame a lattice cell range draws: its spanned shapes and the gutters between them. */\nexport const cellBounds = ({ col, row, spanX, spanY }: LatticeCell, spec: LatticeSpec): Bounds => ({\n x: col * pitchX(spec) - spec.width / 2,\n y: row * pitchY(spec) - spec.height / 2,\n width: spanX * spec.width + (spanX - 1) * spec.gutterX,\n height: spanY * spec.height + (spanY - 1) * spec.gutterY,\n});\n\n/**\n * A cell range resized to the frame a handle drag left (`from` was the frame before): on each axis the\n * moved edge snaps to the nearest cell edge and the opposite edge stays where it was, so a dragged face\n * steps one cell at a time; the range never shrinks below one cell, and an axis with no moved edge keeps\n * its cells.\n */\nexport const resizeCell = (cell: LatticeCell, from: Bounds, to: Bounds, spec: LatticeSpec): LatticeCell => {\n const axis = (\n [fromLow, fromHigh, toLow, toHigh]: [number, number, number, number],\n first: number,\n span: number,\n size: number,\n pitch: number,\n ): [first: number, span: number] => {\n const last = first + span - 1;\n if (Math.abs(toLow - fromLow) > Math.abs(toHigh - fromHigh)) {\n // The low edge moved: the cell whose low edge (`k x pitch - size / 2`) is nearest, up to the last cell.\n const next = Math.min(last, Math.round((toLow + size / 2) / pitch));\n return [next, last - next + 1];\n }\n if (toHigh !== fromHigh) {\n // The high edge moved: the cell whose high edge (`k x pitch + size / 2`) is nearest, from the first cell.\n const next = Math.max(first, Math.round((toHigh - size / 2) / pitch));\n return [first, next - first + 1];\n }\n return [first, span];\n };\n const [col, spanX] = axis(\n [from.x, from.x + from.width, to.x, to.x + to.width],\n cell.col,\n cell.spanX,\n spec.width,\n pitchX(spec),\n );\n const [row, spanY] = axis(\n [from.y, from.y + from.height, to.y, to.y + to.height],\n cell.row,\n cell.spanY,\n spec.height,\n pitchY(spec),\n );\n return { col, row, spanX, spanY };\n};\n\n/** A frame snapped onto the lattice: the nearest whole spans at the nearest cells. */\nexport const quantize = (bounds: Bounds, spec: LatticeSpec): Bounds => cellBounds(toCell(bounds, spec), spec);\n\nconst cellKey = (col: number, row: number) => `${col},${row}`;\n\n/** Every lattice position a cell covers, as `col,row` keys. */\nexport const coveredCells = ({ col, row, spanX, spanY }: LatticeCell): string[] => {\n const keys: string[] = [];\n for (let x = col; x < col + spanX; x++) {\n for (let y = row; y < row + spanY; y++) {\n keys.push(cellKey(x, y));\n }\n }\n return keys;\n};\n\n/** Which node covers each lattice position, for the nodes not in `except` (those being moved or resized). */\nexport type Occupancy = ReadonlyMap<string, ElementId>;\n\nexport const occupancy = (\n nodes: Iterable<Node>,\n spec: LatticeSpec,\n except: ReadonlySet<ElementId> = new Set(),\n): Occupancy => {\n const cells = new Map<string, ElementId>();\n for (const node of nodes) {\n if (!except.has(node.id)) {\n for (const key of coveredCells(toCell(nodeBounds(node), spec))) {\n cells.set(key, node.id);\n }\n }\n }\n return cells;\n};\n\n/** Whether a cell overlaps a position another node already covers. */\nexport const collides = (cell: LatticeCell, occupied: Occupancy): boolean =>\n coveredCells(cell).some((key) => occupied.has(key));\n\n/**\n * The free cell of the same span nearest `cell`, searched ring by ring outwards (by the larger of the\n * column and row distances, then by row and column so the result is deterministic); `cell` itself when it is free.\n */\nexport const nearestFree = (cell: LatticeCell, occupied: Occupancy, maxRadius = 64): LatticeCell | undefined => {\n for (let radius = 0; radius <= maxRadius; radius++) {\n for (let dy = -radius; dy <= radius; dy++) {\n for (let dx = -radius; dx <= radius; dx++) {\n if (Math.max(Math.abs(dx), Math.abs(dy)) !== radius) {\n continue;\n }\n const candidate = { ...cell, col: cell.col + dx, row: cell.row + dy };\n if (!collides(candidate, occupied)) {\n return candidate;\n }\n }\n }\n }\n return undefined;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React, { memo } from 'react';\n\nimport { type Bounds } from '../../model/types.ts';\nimport { type LatticeSpec, cellBounds } from '../../utils/lattice.ts';\n\n/** Above this many cells the lattice reads as texture rather than places, so it is not drawn. */\nconst MAX_CELLS = 4096;\n\nexport type LatticeGridProps = {\n spec: LatticeSpec;\n /** The scene area to cover, in scene units. */\n bounds: Bounds;\n /** One screen pixel in scene units, so the outline stays a hairline at any zoom. */\n unit: number;\n};\n\n/**\n * The cells of a lattice scene (DESIGN §8b), drawn in scene coordinates as faint one-cell frames, so the\n * places a shape can land and the gutters between them are visible before anything is dropped.\n */\nexport const LatticeGrid = memo(({ spec, bounds, unit }: LatticeGridProps) => {\n const [pitchX, pitchY] = [spec.width + spec.gutterX, spec.height + spec.gutterY];\n const [fromCol, toCol] = [Math.floor(bounds.x / pitchX), Math.ceil((bounds.x + bounds.width) / pitchX)];\n const [fromRow, toRow] = [Math.floor(bounds.y / pitchY), Math.ceil((bounds.y + bounds.height) / pitchY)];\n if ((toCol - fromCol + 1) * (toRow - fromRow + 1) > MAX_CELLS) {\n return null;\n }\n\n const cells: Bounds[] = [];\n for (let row = fromRow; row <= toRow; row++) {\n for (let col = fromCol; col <= toCol; col++) {\n cells.push(cellBounds({ col, row, spanX: 1, spanY: 1 }, spec));\n }\n }\n\n return (\n <svg className='absolute overflow-visible pointer-events-none' width={1} height={1} data-testid='lattice-grid'>\n {cells.map((cell) => (\n <rect\n key={`${cell.x},${cell.y}`}\n x={cell.x}\n y={cell.y}\n width={cell.width}\n height={cell.height}\n className='fill-none stroke-separator'\n strokeWidth={unit}\n strokeDasharray={`${4 * unit} ${4 * unit}`}\n />\n ))}\n </svg>\n );\n});\n\nLatticeGrid.displayName = 'LatticeGrid';\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The drag payload a node type travels as between the palette (or a host's own draggable) and the\n// canvas drop target (DESIGN.md §8 \"external drag-in\"); internal gestures stay pointer-driven.\n//\n\nimport { type NodeType } from '../model/types.ts';\n\nconst NODE_DRAG_TYPE = 'dx-canvas/node';\n\n/** The pragmatic-dnd data of a drag that creates a node of `type` where it drops. */\nexport const nodeDragData = (type: NodeType): Record<string, unknown> => ({ type: NODE_DRAG_TYPE, node: type });\n\n/** The node type a drag carries, or nothing when the drag is not one of ours. */\nexport const nodeDragType = (data: Record<string | symbol, unknown>): NodeType | undefined =>\n data.type === NODE_DRAG_TYPE && typeof data.node === 'string' ? data.node : undefined;\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { draggable } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { disableNativeDragPreview } from '@atlaskit/pragmatic-drag-and-drop/element/disable-native-drag-preview';\nimport React, { useEffect, useRef } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type LinkRegistry, type NodeRegistry } from '../../model/registry.ts';\nimport { type Capabilities, type Tool } from '../../model/types.ts';\nimport { nodeDragData } from '../../utils/dnd.ts';\n\ntype Entry = { tool: Tool; icon: string; label: string; key?: string };\n\nconst BASE: Entry[] = [\n { tool: { kind: 'select' }, icon: 'ph--cursor--regular', label: 'Select', key: 'V' },\n { tool: { kind: 'hand' }, icon: 'ph--hand--regular', label: 'Pan', key: 'H' },\n];\n\n/** Node types by their `group`, in registry order; types without one share the first, unnamed group. */\nconst nodeGroups = (nodes: NodeRegistry): Entry[][] => {\n const groups = new Map<string, Entry[]>();\n for (const def of Object.values(nodes)) {\n const name = def.group ?? '';\n groups.set(name, [\n ...(groups.get(name) ?? []),\n { tool: { kind: 'node' as const, type: def.type }, icon: def.icon, label: def.name, key: def.key },\n ]);\n }\n return [...groups.values()];\n};\n\n/**\n * Palette entries: the fixed tools, then the node types by group, then a link per link type; a group the\n * projection cannot apply (`create`, `link`) is left out rather than offered and silently dropped.\n */\nexport const paletteEntries = (nodes: NodeRegistry, links: LinkRegistry, capabilities: Capabilities): Entry[][] =>\n [\n BASE,\n ...(capabilities.create ? nodeGroups(nodes) : []),\n capabilities.link\n ? Object.values(links).map((def) => ({\n tool: { kind: 'link' as const, type: def.type },\n icon: def.icon,\n label: def.name,\n key: def.key,\n }))\n : [],\n ].filter((group) => group.length > 0);\n\nexport const sameTool = (left: Tool, right: Tool): boolean =>\n left.kind === right.kind && ('type' in left ? left.type === ('type' in right ? right.type : undefined) : true);\n\nexport const toolForKey = (\n nodes: NodeRegistry,\n links: LinkRegistry,\n capabilities: Capabilities,\n key: string,\n): Tool | undefined =>\n paletteEntries(nodes, links, capabilities)\n .flat()\n .find((entry) => entry.key !== undefined && entry.key === key.toUpperCase())?.tool;\n\nexport type PaletteProps = {\n tool: Tool;\n nodes: NodeRegistry;\n links: LinkRegistry;\n capabilities: Capabilities;\n onToolChange: (tool: Tool) => void;\n};\n\n/**\n * Tool palette: a click picks the tool; a node type can also be dragged onto the canvas, which creates\n * it where it drops (the canvas is a pragmatic-dnd drop target for `nodeDragData`).\n */\nexport const Palette = ({ tool, nodes, links, capabilities, onToolChange }: PaletteProps) => (\n <div\n className='flex flex-col rounded-sm bg-modal-surface border border-separator divide-y divide-separator'\n data-testid='palette'\n >\n {paletteEntries(nodes, links, capabilities).map((group, index) => (\n <div key={index} className='flex flex-col gap-1 p-1'>\n {group.map((entry) => (\n <PaletteButton\n key={entry.label}\n entry={entry}\n active={sameTool(tool, entry.tool)}\n onToolChange={onToolChange}\n />\n ))}\n </div>\n ))}\n </div>\n);\n\nconst PaletteButton = ({\n entry,\n active,\n onToolChange,\n}: {\n entry: Entry;\n active: boolean;\n onToolChange: (tool: Tool) => void;\n}) => {\n const ref = useRef<HTMLButtonElement>(null);\n const nodeType = entry.tool.kind === 'node' ? entry.tool.type : undefined;\n useEffect(() => {\n if (!ref.current || nodeType === undefined) {\n return;\n }\n return draggable({\n element: ref.current,\n getInitialData: () => nodeDragData(nodeType),\n // The canvas draws a ghost of the node that will land, so the browser's image of the icon is noise.\n onGenerateDragPreview: ({ nativeSetDragImage }) => disableNativeDragPreview({ nativeSetDragImage }),\n });\n }, [nodeType]);\n return (\n <Button.Root\n ref={ref}\n variant='ghost'\n iconOnly\n icon={entry.icon}\n label={entry.key ? `${entry.label} (${entry.key})` : entry.label}\n classNames={mx(active && 'bg-primary-500/20')}\n data-testid={`palette-${entry.key ?? ('type' in entry.tool ? entry.tool.type : entry.tool.kind)}`}\n onClick={() => onToolChange(entry.tool)}\n />\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// A node's text part: static text, or, while it is the part being edited, an in-place editor over the\n// same box. Enter commits (Mod-Enter in a multi-line part, where Enter breaks the line), Escape rejects,\n// and leaving the editor commits. Pointer and key events stay inside so the canvas neither drags nor\n// handles shortcuts while the user types.\n//\n\nimport { Prec } from '@codemirror/state';\nimport { EditorView, keymap } from '@codemirror/view';\nimport React, { type PropsWithChildren, useRef } from 'react';\n\nimport { useTextEditor } from '@dxos/react-ui-editor';\nimport * as Hooks from '@dxos/react-ui/Hooks';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { createBasicExtensions, createThemeExtensions } from '@dxos/ui-editor';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type PartEditing, type PartKey, isMultiline } from '../../utils/parts.ts';\n\nexport type TextPartProps = Util.ThemedClassName<\n PropsWithChildren<{\n part: PartKey;\n /** The part's current text, which the editor starts from. */\n text: string;\n editing?: PartEditing;\n }>\n>;\n\n/** Renders `children` as the part's text, or the editor when `editing` names this part. */\nexport const TextPart = ({ classNames, part, text, editing, children }: TextPartProps) =>\n editing?.part === part ? (\n <PartEditor classNames={classNames} part={part} text={text} editing={editing} />\n ) : (\n <div className={mx(classNames)} data-part={part}>\n {children}\n </div>\n );\n\ntype PartEditorProps = Util.ThemedClassName<{ part: PartKey; text: string; editing: PartEditing }>;\n\nconst stop = (event: React.SyntheticEvent) => event.stopPropagation();\n\nconst PartEditor = ({ classNames, part, text, editing }: PartEditorProps) => {\n const themeMode = Hooks.useThemeMode();\n const multiline = isMultiline(part);\n // Commit or cancel once: the editor unmounts on either, and its focus loss must not commit again.\n const done = useRef(false);\n const finish = (action: () => void) => {\n if (!done.current) {\n done.current = true;\n action();\n }\n };\n const { parentRef, focusAttributes } = useTextEditor(\n () => ({\n id: `part-${part}`,\n initialValue: text,\n autoFocus: true,\n selectionEnd: true,\n extensions: [\n createBasicExtensions({ lineWrapping: true, history: false, search: false }),\n createThemeExtensions({\n themeMode,\n // Content height, not full height, so the part's own layout places the editor where it puts the\n // static text (a label centred in its cell).\n slots: { editor: { className: 'w-full max-h-full [&>.cm-scroller]:scrollbar-none' } },\n }),\n // The part's own leading, not the editor theme's, so the lines do not shift when editing starts.\n Prec.highest(EditorView.theme({ '.cm-scroller, .cm-content, .cm-line': { lineHeight: 'inherit' } })),\n EditorView.focusChangeEffect.of((state, focusing) => {\n if (!focusing) {\n finish(() => editing.commit(state.doc.toString()));\n }\n return null;\n }),\n Prec.highest(\n keymap.of([\n {\n key: 'Enter',\n run: (view) => {\n if (multiline) {\n view.dispatch(view.state.replaceSelection('\\n'));\n } else {\n finish(() => editing.commit(view.state.doc.toString()));\n }\n return true;\n },\n },\n {\n key: 'Mod-Enter',\n run: (view) => {\n finish(() => editing.commit(view.state.doc.toString()));\n return true;\n },\n },\n {\n key: 'Escape',\n run: () => {\n finish(() => editing.cancel());\n return true;\n },\n },\n ]),\n ),\n ],\n }),\n [part, text, multiline, themeMode, editing],\n );\n\n return (\n <div\n ref={parentRef}\n {...focusAttributes}\n className={mx('select-text cursor-text', classNames)}\n data-part={part}\n data-testid='part-editor'\n onPointerDown={stop}\n onDoubleClick={stop}\n onKeyDown={stop}\n />\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Camera math (docs/DESIGN.md §5): per-scene coordinates, one CSS transform for the camera, and the\n// portal mapping that lets a camera be re-expressed in a child scene's space so drill-in is seamless.\n//\n\nimport { interpolateZoom } from 'd3';\n\nimport {\n type Bounds,\n type Camera,\n MAJOR_GRID,\n MAJOR_GRID_RATIO,\n type Node,\n type Point,\n type Size,\n} from '../model/types.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport const MIN_ZOOM = 1 / 32;\nexport const MAX_ZOOM = 32;\n\nexport const clampZoom = (zoom: number) => Math.min(MAX_ZOOM, Math.max(MIN_ZOOM, zoom));\n\nexport const sceneToScreen = (camera: Camera, point: Point): Point => ({\n x: (point.x + camera.x) * camera.zoom,\n y: (point.y + camera.y) * camera.zoom,\n});\n\nexport const screenToScene = (camera: Camera, point: Point): Point => ({\n x: point.x / camera.zoom - camera.x,\n y: point.y / camera.zoom - camera.y,\n});\n\n/** Change zoom while keeping the scene point under `screen` fixed. */\nexport const zoomAt = (camera: Camera, screen: Point, zoom: number): Camera => {\n const clamped = clampZoom(zoom);\n const anchor = screenToScene(camera, screen);\n return { zoom: clamped, x: screen.x / clamped - anchor.x, y: screen.y / clamped - anchor.y };\n};\n\nexport const panBy = (camera: Camera, delta: Point): Camera => ({\n ...camera,\n x: camera.x + delta.x,\n y: camera.y + delta.y,\n});\n\nexport const cameraTransform = (camera: Camera) => `scale(${camera.zoom}) translate(${camera.x}px, ${camera.y}px)`;\n\nexport const boundsCenter = (bounds: Bounds): Point => ({\n x: bounds.x + bounds.width / 2,\n y: bounds.y + bounds.height / 2,\n});\n\nexport const screenBounds = (camera: Camera, bounds: Bounds): Bounds => {\n const origin = sceneToScreen(camera, bounds);\n return { ...origin, width: bounds.width * camera.zoom, height: bounds.height * camera.zoom };\n};\n\n/**\n * Camera that centres `bounds` in the viewport at the largest zoom that fits it with `inset` px around,\n * never above `maxZoom` (a small region is centred rather than blown up past it).\n */\nexport const fitBounds = (bounds: Bounds, viewport: Size, inset = 0, maxZoom = MAX_ZOOM): Camera => {\n const zoom = clampZoom(\n Math.min(maxZoom, viewport.width / (bounds.width + 2 * inset), viewport.height / (bounds.height + 2 * inset)),\n );\n return {\n zoom,\n x: viewport.width / (2 * zoom) - (bounds.x + bounds.width / 2),\n y: viewport.height / (2 * zoom) - (bounds.y + bounds.height / 2),\n };\n};\n\n/** Uniform scale that maps a child-space region into the portal node (letterboxed). */\nexport const portalScale = (portal: Node, region: Bounds) => {\n const { width, height } = nodeBounds(portal);\n return Math.min(width / region.width, height / region.height);\n};\n\n/**\n * The frame a portal gives its child: the child-space region that maps exactly onto the portal. It is\n * the portal's box scaled by the smallest power of the grid ratio, at least one, that contains the child's\n * derived bounds, placed on the major grid scaled by that factor as near their centre as containing them\n * allows. A power of the ratio maps every child grid level onto a parent level (the child's major grid is\n * the parent's minor one, one level down), and placing the frame on the scaled grid puts the child's lines\n * on the parent's, not merely at their spacing, so the grids stay aligned through a drill-in. Drilling in\n * shows this frame; a portal draws the child centred in it.\n */\nexport const portalFrame = (portal: Node, child: Bounds, unit = MAJOR_GRID, ratio = MAJOR_GRID_RATIO): Bounds => {\n const { width, height } = nodeBounds(portal);\n let factor = ratio;\n while (factor * width < child.width || factor * height < child.height) {\n factor *= ratio;\n }\n const frame = { width: width * factor, height: height * factor };\n return {\n x: place(child.x, child.width, frame.width, unit * factor),\n y: place(child.y, child.height, frame.height, unit * factor),\n ...frame,\n };\n};\n\n/** The grid-aligned start of a span of `length` centred on `[start, start + inner]` as far as containing it allows. */\nconst place = (start: number, inner: number, length: number, unit: number): number => {\n const centred = Math.round((start + inner / 2 - length / 2) / unit) * unit;\n // Rounding a small negative yields -0, which `toEqual` and `Object.is` tell apart from 0.\n return Math.max(Math.min(centred, start), start + inner - length) + 0;\n};\n\n/** Child-scene CSS transform inside a portal node whose own origin is the node's top-left. */\nexport const portalTransform = (portal: Node, frame: Bounds) => {\n const scale = portalScale(portal, frame);\n return `scale(${scale}) translate(${-frame.x}px, ${-frame.y}px)`;\n};\n\n/**\n * Re-express a parent-space camera in child-scene space so the swap is visually seamless:\n * screen = (parentPoint + cam) * zoom and parentPoint = portalOrigin + (childPoint - childOrigin) * s.\n */\nexport const enterPortal = (camera: Camera, portal: Node, child: Bounds): Camera => {\n const scale = portalScale(portal, child);\n const origin = nodeBounds(portal);\n return {\n zoom: camera.zoom * scale,\n x: (origin.x - child.x * scale + camera.x) / scale,\n y: (origin.y - child.y * scale + camera.y) / scale,\n };\n};\n\n/** Inverse of `enterPortal`. */\nexport const exitPortal = (camera: Camera, portal: Node, child: Bounds): Camera => {\n const scale = portalScale(portal, child);\n const origin = nodeBounds(portal);\n return {\n zoom: camera.zoom / scale,\n x: camera.x * scale - origin.x + child.x * scale,\n y: camera.y * scale - origin.y + child.y * scale,\n };\n};\n\n/** Fraction of the viewport covered by the bounds' screen rectangle. */\nexport const coverage = (camera: Camera, bounds: Bounds, viewport: Size) => {\n if (viewport.width === 0 || viewport.height === 0) {\n return 0;\n }\n const rect = screenBounds(camera, bounds);\n const width = Math.max(0, Math.min(rect.x + rect.width, viewport.width) - Math.max(rect.x, 0));\n const height = Math.max(0, Math.min(rect.y + rect.height, viewport.height) - Math.max(rect.y, 0));\n return (width * height) / (viewport.width * viewport.height);\n};\n\n// van Wijk & Nuij: the camera is (centre, visible width) so a zoom-out-then-in trajectory falls out of d3.\nconst toView = (camera: Camera, viewport: Size): [number, number, number] => [\n viewport.width / (2 * camera.zoom) - camera.x,\n viewport.height / (2 * camera.zoom) - camera.y,\n viewport.width / camera.zoom,\n];\n\nconst fromView = ([cx, cy, width]: [number, number, number], viewport: Size): Camera => {\n const zoom = viewport.width / width;\n return { zoom, x: viewport.width / (2 * zoom) - cx, y: viewport.height / (2 * zoom) - cy };\n};\n\nexport const MIN_ANIMATION_MS = 250;\nexport const MAX_ANIMATION_MS = 800;\n\n/** Animate between cameras; returns a cancel function. */\nexport const animateCamera = (\n from: Camera,\n to: Camera,\n viewport: Size,\n apply: (camera: Camera) => void,\n done?: () => void,\n): (() => void) => {\n const interpolate = interpolateZoom(toView(from, viewport), toView(to, viewport));\n const duration = Math.min(MAX_ANIMATION_MS, Math.max(MIN_ANIMATION_MS, interpolate.duration));\n const start = performance.now();\n let frame = 0;\n const tick = (now: number) => {\n const t = Math.min(1, (now - start) / duration);\n const eased = t < 0.5 ? 2 * t * t : 1 - (-2 * t + 2) ** 2 / 2;\n apply(fromView(interpolate(eased), viewport));\n if (t < 1) {\n frame = requestAnimationFrame(tick);\n } else {\n done?.();\n }\n };\n frame = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(frame);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The frame classes a node's `style` resolves to. Tailwind only emits classes it can read verbatim, so\n// every hue is spelled out here rather than composed from the hue name.\n//\n\nimport { type Node, type NodeStyle, type NodeTone, isEllipseNode } from '../model/types.ts';\n\nexport type HueClasses = { surface: string; text: string; border: string };\n\nconst HUES: Record<string, HueClasses> = {\n neutral: { surface: 'bg-neutral-surface', text: 'text-neutral-fg', border: 'border-neutral-border' },\n red: { surface: 'bg-red-surface', text: 'text-red-fg', border: 'border-red-border' },\n orange: { surface: 'bg-orange-surface', text: 'text-orange-fg', border: 'border-orange-border' },\n amber: { surface: 'bg-amber-surface', text: 'text-amber-fg', border: 'border-amber-border' },\n yellow: { surface: 'bg-yellow-surface', text: 'text-yellow-fg', border: 'border-yellow-border' },\n lime: { surface: 'bg-lime-surface', text: 'text-lime-fg', border: 'border-lime-border' },\n green: { surface: 'bg-green-surface', text: 'text-green-fg', border: 'border-green-border' },\n emerald: { surface: 'bg-emerald-surface', text: 'text-emerald-fg', border: 'border-emerald-border' },\n teal: { surface: 'bg-teal-surface', text: 'text-teal-fg', border: 'border-teal-border' },\n cyan: { surface: 'bg-cyan-surface', text: 'text-cyan-fg', border: 'border-cyan-border' },\n sky: { surface: 'bg-sky-surface', text: 'text-sky-fg', border: 'border-sky-border' },\n blue: { surface: 'bg-blue-surface', text: 'text-blue-fg', border: 'border-blue-border' },\n indigo: { surface: 'bg-indigo-surface', text: 'text-indigo-fg', border: 'border-indigo-border' },\n violet: { surface: 'bg-violet-surface', text: 'text-violet-fg', border: 'border-violet-border' },\n purple: { surface: 'bg-purple-surface', text: 'text-purple-fg', border: 'border-purple-border' },\n fuchsia: { surface: 'bg-fuchsia-surface', text: 'text-fuchsia-fg', border: 'border-fuchsia-border' },\n pink: { surface: 'bg-pink-surface', text: 'text-pink-fg', border: 'border-pink-border' },\n rose: { surface: 'bg-rose-surface', text: 'text-rose-fg', border: 'border-rose-border' },\n};\n\n/** The hues the style picker offers, neutral first; any theme hue still renders, at its `medium` tone. */\nexport const STYLE_HUES = ['neutral', 'red', 'orange', 'amber', 'green', 'teal', 'blue', 'violet', 'pink'] as const;\nexport type StyleHue = (typeof STYLE_HUES)[number];\n\nexport const TONES: readonly NodeTone[] = [0, 1, 2, 3];\n\n/** What each tone is called, for labels. */\nexport const TONE_NAMES: Record<NodeTone, string> = { 0: 'outline', 1: 'light', 2: 'medium', 3: 'strong' };\n\n/** The tone a hue without one draws at: the look a hue had before tones. */\nexport const DEFAULT_TONE: NodeTone = 2;\n\ntype ToneClasses = { surface: string; text: string };\n\n/**\n * The fills lighter and stronger than a hue's `surface` role: the scale's 200 under its darkest text, and the\n * hue's solid `bg` role under light text (tones 1 and 3). Tone 2 is the role pair in `HUES`; tone 0 has no fill.\n */\nconst TONE_FILLS: Record<StyleHue, Record<1 | 3, ToneClasses>> = {\n neutral: {\n 1: { surface: 'bg-neutral-200', text: 'text-neutral-900' },\n 3: { surface: 'bg-neutral-bg', text: 'text-neutral-50' },\n },\n red: {\n 1: { surface: 'bg-red-200', text: 'text-red-900' },\n 3: { surface: 'bg-red-bg', text: 'text-neutral-50' },\n },\n orange: {\n 1: { surface: 'bg-orange-200', text: 'text-orange-900' },\n 3: { surface: 'bg-orange-bg', text: 'text-neutral-50' },\n },\n amber: {\n 1: { surface: 'bg-amber-200', text: 'text-amber-900' },\n 3: { surface: 'bg-amber-bg', text: 'text-neutral-50' },\n },\n green: {\n 1: { surface: 'bg-green-200', text: 'text-green-900' },\n 3: { surface: 'bg-green-bg', text: 'text-neutral-50' },\n },\n teal: {\n 1: { surface: 'bg-teal-200', text: 'text-teal-900' },\n 3: { surface: 'bg-teal-bg', text: 'text-neutral-50' },\n },\n blue: {\n 1: { surface: 'bg-blue-200', text: 'text-blue-900' },\n 3: { surface: 'bg-blue-bg', text: 'text-neutral-50' },\n },\n violet: {\n 1: { surface: 'bg-violet-200', text: 'text-violet-900' },\n 3: { surface: 'bg-violet-bg', text: 'text-neutral-50' },\n },\n pink: {\n 1: { surface: 'bg-pink-200', text: 'text-pink-900' },\n 3: { surface: 'bg-pink-bg', text: 'text-neutral-50' },\n },\n};\n\nconst isStyleHue = (hue: string): hue is StyleHue => STYLE_HUES.some((candidate) => candidate === hue);\n\n/** The default look: the base surface, the base text and the separator border. */\nconst DEFAULT: HueClasses = { surface: 'bg-base-surface', text: '', border: 'border-separator' };\n\n/**\n * The classes a hue at a tone draws with. Every tone keeps the hue's border; tone 0 drops the fill and\n * keeps the default text, and a tone a hue has no fills for draws as `medium`.\n */\nexport const hueClasses = (hue: string | undefined, tone: NodeTone = DEFAULT_TONE): HueClasses => {\n const base = (hue && HUES[hue]) || DEFAULT;\n if (!hue || base === DEFAULT) {\n return base;\n }\n if (tone === 0) {\n return { surface: 'bg-transparent', text: '', border: base.border };\n }\n if ((tone === 1 || tone === 3) && isStyleHue(hue)) {\n return { ...TONE_FILLS[hue][tone], border: base.border };\n }\n return base;\n};\n\n/**\n * A node's style with the defaults the frame draws spelled out: an unset `fill` or `border` is drawn, so\n * the properties panel must show it as on rather than as an unset (off) toggle.\n */\nexport const resolveStyle = (style: NodeStyle = {}): NodeStyle => ({\n ...style,\n fill: style.fill ?? true,\n border: style.border ?? true,\n});\n\n/**\n * Frame classes for a node: fill and text colour, border and corner radius from its style; a guide is\n * dashed and unfilled, and the host's `className` comes last so it wins.\n */\nexport const frameClasses = (node: Node, selected: boolean, hovered = false): string[] => {\n const style = resolveStyle(node.style);\n const hue = hueClasses(style.hue, style.tone);\n const filled = style.fill && !style.guide;\n return [\n filled ? hue.surface : '',\n hue.text,\n selected\n ? 'border-primary-500'\n : hovered\n ? 'border-primary-500/50'\n : style.border === false && !style.guide\n ? 'border-transparent'\n : hue.border,\n style.guide ? 'border-dashed' : '',\n isEllipseNode(node) ? 'rounded-[50%]' : style.rounded ? 'rounded-2xl' : 'rounded-sm',\n style.className ?? '',\n ];\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Renders one scene's nodes and links in scene coordinates under the camera transform (§7). Nodes are\n// HTML so they can host live content; links are one SVG per scene; live portals nest another layer.\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport React, { memo, useId, useMemo } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport { mx } from '@dxos/ui-theme';\n\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type NodeRegistry, type NodeViewProps } from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type ElementId,\n type Link,\n type Marker,\n type Node,\n type NodeId,\n type Scene,\n isBoxNode,\n isClassNode,\n isEllipseNode,\n isNoteNode,\n isPortalNode,\n linkMarkers,\n showsContents,\n} from '../../model/types.ts';\nimport { portalFrame, portalScale, portalTransform } from '../../utils/camera.ts';\nimport { contentBounds } from '../../utils/hit.ts';\nimport { type LatticeSpec } from '../../utils/lattice.ts';\nimport { sortByZ } from '../../utils/order.ts';\nimport { type PartEditing, type PartKey } from '../../utils/parts.ts';\nimport { sceneLinkGeometry } from '../../utils/route.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\nimport { frameClasses } from '../../utils/style.ts';\nimport { TextPart } from '../PartEditor/PartEditor.tsx';\n\n/** Screen px below which a portal is a solid tile; above `PREVIEW_PX` it mounts the child scene live. */\nexport const DOT_PX = 40;\nexport const PREVIEW_PX = 260;\n/** Default for `liveDepth`: root plus this many live nested levels (decision 10). */\nexport const MAX_LIVE_DEPTH = 1;\n/** Hysteresis at the tier boundaries so a portal does not flicker while zooming across one. */\nconst TIER_HYSTERESIS = 0.1;\n\nexport type Tier = 'dot' | 'preview' | 'live';\n\nexport const tierFor = (node: Node, zoom: number, depth: number, liveDepth: number, previous?: Tier): Tier => {\n const { width, height } = nodeBounds(node);\n const px = Math.min(width, height) * zoom;\n const dot = previous === 'dot' ? DOT_PX * (1 + TIER_HYSTERESIS) : DOT_PX * (1 - TIER_HYSTERESIS);\n const preview = previous === 'preview' ? PREVIEW_PX * (1 + TIER_HYSTERESIS) : PREVIEW_PX * (1 - TIER_HYSTERESIS);\n if (px < dot) {\n return 'dot';\n }\n if (px < preview || depth >= liveDepth) {\n return 'preview';\n }\n return 'live';\n};\n\nexport type ElementHandlers = {\n onNodePointerDown?: (node: Node, event: React.PointerEvent) => void;\n onLinkPointerDown?: (link: Link, event: React.PointerEvent) => void;\n onLinkDoubleClick?: (link: Link, event: React.MouseEvent) => void;\n onLinkContextMenu?: (link: Link, event: React.MouseEvent) => void;\n /** The in-place editor of `part` finished with `text` (commit) or was dismissed (cancel). */\n onPartCommit?: (node: Node, part: PartKey, text: string) => void;\n onPartCancel?: () => void;\n /** A node's own open control was pressed (a portal's zoom-in icon). */\n onNodeOpen?: (node: Node) => void;\n};\n\nexport type SceneLayerProps = {\n store: SceneStore;\n scene: Scene;\n registry: NodeRegistry;\n /** Effective screen zoom of this layer (camera zoom × portal scales). */\n zoom: number;\n depth: number;\n liveDepth: number;\n selected?: ReadonlySet<ElementId>;\n hover?: NodeId;\n /** The portal a drill-in is animating into, while it is. */\n opening?: ElementId;\n /** The text part being edited in place, if any. */\n editing?: { id: NodeId; part: PartKey };\n /** A node drawn as a preview of what a gesture will create: translucent, dashed, and not pressable. */\n ghost?: NodeId;\n /** Frames show their id, type and geometry. */\n debug?: boolean;\n /** Absent on nested (read-only) layers. */\n handlers?: ElementHandlers;\n /** The scene's lattice, when it has one: smart links route through its gutters. */\n lattice?: LatticeSpec;\n};\n\nexport const SceneLayer = memo(\n ({\n store,\n scene,\n registry,\n zoom,\n depth,\n liveDepth,\n selected,\n hover,\n opening,\n editing,\n ghost,\n debug,\n handlers,\n lattice,\n }: SceneLayerProps) => {\n // Paint order is z, with the selection on top of it: a selected node is being worked on and must not\n // hide under a neighbour, while the model's z stays what the user arranged.\n const nodes = useMemo(() => {\n const sorted = sortByZ(Object.values(scene.nodes));\n return selected?.size\n ? [...sorted.filter((node) => !selected.has(node.id)), ...sorted.filter((node) => selected.has(node.id))]\n : sorted;\n }, [scene.nodes, selected]);\n const links = useMemo(\n () => sceneLinkGeometry(scene, registry, sortByZ(Object.values(scene.links)), lattice),\n [scene, registry, lattice],\n );\n const unit = 1 / Math.max(zoom, 0.05);\n // One set of end markers per layer, sized in scene units so they scale with the stroke.\n const markerId = useId();\n const markerUrl = (marker: Marker | undefined, end: 'start' | 'end') =>\n marker ? `url(#${markerId}-${marker}-${end})` : undefined;\n\n return (\n <>\n <svg className='absolute overflow-visible pointer-events-none' width={1} height={1}>\n <defs>\n <Markers id={markerId} unit={unit} />\n </defs>\n {links.map(({ link, path }) => (\n <g key={link.id}>\n {/* A wide transparent twin makes the thin stroke easy to press. */}\n {handlers && (\n <path\n d={path}\n className='fill-none stroke-transparent pointer-events-auto cursor-pointer'\n style={{ pointerEvents: 'stroke' }}\n strokeWidth={12 * unit}\n onPointerDown={(event) => handlers.onLinkPointerDown?.(link, event)}\n onDoubleClick={(event) => handlers.onLinkDoubleClick?.(link, event)}\n onContextMenu={(event) => handlers.onLinkContextMenu?.(link, event)}\n />\n )}\n <path\n d={path}\n className={mx('fill-none', selected?.has(link.id) ? 'stroke-primary-500' : 'stroke-neutral-500')}\n strokeWidth={2 * unit}\n data-link-id={link.id}\n markerStart={markerUrl(linkMarkers(link).start, 'start')}\n markerEnd={markerUrl(linkMarkers(link).end, 'end')}\n />\n </g>\n ))}\n </svg>\n {nodes.map((node) => (\n <NodeFrame\n key={node.id}\n store={store}\n scene={scene}\n registry={registry}\n node={node}\n zoom={zoom}\n depth={depth}\n liveDepth={liveDepth}\n selected={selected?.has(node.id) ?? false}\n hovered={hover === node.id}\n opening={opening === node.id}\n editingPart={editing?.id === node.id ? editing.part : undefined}\n ghost={ghost === node.id}\n debug={debug}\n handlers={handlers}\n />\n ))}\n </>\n );\n },\n);\n\nSceneLayer.displayName = 'SceneLayer';\n\n/** The end markers, one per kind and end: a start marker points back along the path, an end marker along it. */\nconst Markers = ({ id, unit }: { id: string; unit: number }) => {\n const size = 6 * unit;\n // An arrowhead has to read as a direction at a glance, so it carries twice the weight of an end dot.\n const arrow = 2 * size;\n const ends = ['start', 'end'] as const;\n return (\n <>\n {ends.map((end) => (\n <marker\n key={`arrow-${end}`}\n id={`${id}-arrow-${end}`}\n viewBox='0 0 10 10'\n refX={9}\n refY={5}\n markerWidth={arrow}\n markerHeight={arrow}\n markerUnits='userSpaceOnUse'\n orient={end === 'start' ? 'auto-start-reverse' : 'auto'}\n >\n <path d='M 0 0 L 10 5 L 0 10 z' className='fill-neutral-500' />\n </marker>\n ))}\n {ends.map((end) => (\n <marker\n key={`circle-${end}`}\n id={`${id}-circle-${end}`}\n viewBox='0 0 10 10'\n refX={5}\n refY={5}\n markerWidth={size}\n markerHeight={size}\n markerUnits='userSpaceOnUse'\n >\n <circle cx={5} cy={5} r={4} className='fill-neutral-500' />\n </marker>\n ))}\n </>\n );\n};\n\ntype NodeFrameProps = Omit<NodeViewProps, 'editing'> & {\n hovered?: boolean;\n editingPart?: PartKey;\n ghost?: boolean;\n debug?: boolean;\n handlers?: ElementHandlers;\n};\n\n/** Positions a node, owns its frame styling and pointer events; the node definition renders the body. */\nconst NodeFrame = memo(({ handlers, hovered, editingPart, ghost, debug, ...props }: NodeFrameProps) => {\n const { node, registry, selected } = props;\n const bounds = nodeBounds(node);\n const interactive = handlers !== undefined && !ghost;\n const Component = nodeDef(registry, node)?.component ?? UnknownNodeView;\n const editing = useMemo<PartEditing | undefined>(\n () =>\n editingPart && handlers\n ? {\n part: editingPart,\n commit: (text) => handlers.onPartCommit?.(node, editingPart, text),\n cancel: () => handlers.onPartCancel?.(),\n }\n : undefined,\n [editingPart, handlers, node],\n );\n const onOpen = useMemo(\n () => (interactive && handlers.onNodeOpen ? () => handlers.onNodeOpen?.(node) : undefined),\n [interactive, handlers, node],\n );\n return (\n <div\n className={mx(\n 'absolute box-border border-4 overflow-hidden',\n // Being zoomed into, the frame becomes the child scene's canvas, so it drops its fill (the first class)\n // at once and keeps only its own border, not the selection's or the hover's.\n ...(props.opening ? frameClasses(node, false).slice(1) : frameClasses(node, selected, hovered)),\n interactive && !node.locked && 'cursor-grab',\n ghost && 'opacity-50 border-dashed pointer-events-none',\n )}\n // `fontSize` is inherited by every text part, so an override set on the node reaches the label,\n // the class compartments and the editor alike; unset, the parts keep their own theme sizes.\n style={{\n left: bounds.x,\n top: bounds.y,\n width: bounds.width,\n height: bounds.height,\n fontSize: node.style?.fontSize,\n }}\n data-node-id={node.id}\n data-ghost={ghost || undefined}\n onPointerDown={interactive ? (event) => handlers.onNodePointerDown?.(node, event) : undefined}\n >\n <Component {...props} editing={editing} onOpen={onOpen} />\n {debug && (\n <div\n className='absolute top-0 left-0 px-1 text-[10px] leading-4 font-mono whitespace-nowrap bg-modal-surface text-fg-muted pointer-events-none'\n data-testid='node-debug'\n >\n {node.id} · {node.type} · {bounds.x},{bounds.y} {bounds.width}×{bounds.height} · z {node.z}\n </div>\n )}\n </div>\n );\n});\n\nNodeFrame.displayName = 'NodeFrame';\n\n/**\n * A part's own size class, or nothing when the node overrides `fontSize`: a Tailwind size wins over the\n * inherited value, so the override only reaches the text if the class is left off.\n */\nconst sizeClass = (node: Node, className: string) => (node.style?.fontSize === undefined ? className : undefined);\n\ntype LabelPartProps = Pick<NodeViewProps, 'node' | 'editing'> & { label: string };\n\n/** The centred, editable label of a box (and an ellipse). */\nconst LabelPart = ({ node, editing, label }: LabelPartProps) => (\n <TextPart\n part='label'\n text={label}\n editing={editing}\n classNames={mx(\n 'dx-cover flex items-center justify-center text-center whitespace-pre-wrap',\n sizeClass(node, 'text-2xl'),\n )}\n >\n {label}\n </TextPart>\n);\n\nconst LabelNodeView = ({ node, editing }: NodeViewProps) => (\n <LabelPart node={node} editing={editing} label={isBoxNode(node) || isEllipseNode(node) ? (node.label ?? '') : ''} />\n);\n\n/** The `box` prototype's body: its centred label. */\nexport const BoxNodeView = LabelNodeView;\n\nexport const EllipseNodeView = LabelNodeView;\n\nexport const ClassNodeView = ({ node, editing }: NodeViewProps) => {\n if (!isClassNode(node)) {\n return null;\n }\n return (\n <div className={mx('dx-cover flex flex-col font-mono divide-y divide-separator', sizeClass(node, 'text-sm'))}>\n <TextPart part='name' text={node.name} editing={editing} classNames='px-2 py-1 text-center font-bold'>\n {node.name}\n </TextPart>\n <TextPart\n part='attributes'\n text={node.attributes.join('\\n')}\n editing={editing}\n classNames='px-2 py-1 flex-1 min-h-4'\n >\n {node.attributes.map((attribute, index) => (\n <div key={index}>{attribute}</div>\n ))}\n </TextPart>\n <TextPart part='methods' text={node.methods.join('\\n')} editing={editing} classNames='px-2 py-1 flex-1 min-h-4'>\n {node.methods.map((method, index) => (\n <div key={index}>{method}</div>\n ))}\n </TextPart>\n </div>\n );\n};\n\n/** A node whose type the registry does not know: its frame and type name, so the scene still reads. */\nexport const UnknownNodeView = ({ node }: NodeViewProps) => (\n <div className='dx-cover flex items-center justify-center text-xs text-fg-muted'>{node.type}</div>\n);\n\nexport const NoteNodeView = ({ node, editing }: NodeViewProps) => {\n const text = isNoteNode(node) ? node.text : '';\n return (\n <TextPart part='text' text={text} editing={editing} classNames='dx-cover p-3 whitespace-pre-wrap'>\n {text}\n </TextPart>\n );\n};\n\n/**\n * A box over a child scene: the centred label, or with `contents` the child drawn inside the frame (a\n * preview, then the live scene as it grows on screen), and a zoom-in control at the top-right.\n */\nexport const PortalNodeView = (props: NodeViewProps) => {\n const { node, store, registry, zoom, depth, liveDepth, opening, editing, onOpen } = props;\n const child = useAtomValue(store.scene(isPortalNode(node) ? node.scene : ''));\n const contents = opening || (isPortalNode(node) && showsContents(node));\n // Being entered, the portal is already the child scene on the canvas: live, and without the tile tint.\n const tier = !child ? 'dot' : opening ? 'live' : tierFor(node, zoom, depth, liveDepth);\n const bounds = useMemo(() => (child ? portalFrame(node, contentBounds(child)) : undefined), [node, child]);\n const title = (isPortalNode(node) ? node.label : undefined) ?? child?.name ?? child?.id ?? '';\n if (!contents) {\n return (\n <>\n <LabelPart node={node} editing={editing} label={title} />\n {onOpen && <OpenControl onOpen={onOpen} />}\n </>\n );\n }\n return (\n <div className={mx('dx-cover', tier === 'dot' && 'bg-primary-500/40')}>\n {tier === 'preview' && child && (\n <div className='dx-cover flex flex-col items-center justify-center gap-1 pointer-events-none'>\n <span className='text-2xl'>{title}</span>\n <span>\n {Object.keys(child.nodes).length} nodes · {Object.keys(child.links).length} links\n </span>\n </div>\n )}\n {tier === 'live' &&\n child &&\n bounds && (\n // The nested layer is read-only: only the root scene receives handlers.\n // Pulled out by the frame's border, so the child's origin is the node's corner as\n // `portalTransform` and `enterPortal` assume; inside the padding box it sat a border in and\n // the scene jumped by that at the drill-in swap.\n <div\n className='absolute -top-1 -left-1 pointer-events-none'\n style={{ transform: portalTransform(node, bounds), transformOrigin: '0 0' }}\n >\n <SceneLayer\n store={store}\n scene={child}\n registry={registry}\n zoom={zoom * portalScale(node, bounds)}\n depth={depth + 1}\n liveDepth={liveDepth}\n />\n </div>\n )}\n {/* The preview centres the title already; the live scene fills the frame, so it names it in the corner. */}\n {!opening && tier === 'live' && (\n <span className='absolute top-1 left-2 text-xs text-fg-subtle pointer-events-none'>{title}</span>\n )}\n {!opening && onOpen && <OpenControl onOpen={onOpen} />}\n </div>\n );\n};\n\n/** The zoom-in control at a portal's top-right; it takes the press, so it neither drags nor selects the node. */\nconst OpenControl = ({ onOpen }: { onOpen: () => void }) => (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrows-out--regular'\n label='Open scene'\n classNames='absolute top-1 right-1'\n data-testid='portal-open'\n onPointerDown={(event) => event.stopPropagation()}\n onDoubleClick={(event) => event.stopPropagation()}\n onClick={(event) => {\n event.stopPropagation();\n onOpen();\n }}\n />\n);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Node and link type definitions (decision 12): what a type's schema is, what it renders, where its\n// ports are, how it may be manipulated, and how the palette presents it. Per type, not per instance, so\n// the data stays small and ports come for free; a node may still carry its own `ports`. A host composes\n// its own registry (and with `createSceneSchema` its scene schema) from the built-ins and its types.\n//\n// A type may be built on a prototype (`extends`): it inherits every definition field it leaves unset, so\n// shapes that look and behave alike share one definition and differ only where they say so. Prototypes\n// are resolved once, when the registry is created, so a lookup is still one record read.\n//\n\nimport type * as Schema from 'effect/Schema';\nimport { type ComponentType } from 'react';\n\nimport {\n BoxNodeView,\n ClassNodeView,\n EllipseNodeView,\n NoteNodeView,\n PortalNodeView,\n} from '../components/SceneLayer/SceneLayer.tsx';\nimport { type PartEditing } from '../utils/parts.ts';\nimport { DEFAULT_SIZES, createNode } from '../utils/shapes.ts';\nimport { type SceneStore } from './store.ts';\nimport {\n ClassNode,\n EllipseNode,\n type LinkType,\n type Node,\n type NodeBase,\n type NodeType,\n NoteNode,\n type Point,\n type Port,\n PortalNode,\n RectNode,\n type Scene,\n type Size,\n} from './types.ts';\n\nexport type NodeViewProps = {\n node: Node;\n scene: Scene;\n store: SceneStore;\n registry: NodeRegistry;\n /** Effective screen zoom of the layer (camera zoom × portal scales), for level-of-detail choices. */\n zoom: number;\n /** Nesting depth of the layer; 0 is the root. */\n depth: number;\n /** Nested levels below the root that may mount live (decision 10). */\n liveDepth: number;\n selected: boolean;\n /** The view is being zoomed into: a portal shows its child plainly, as the child will look once entered. */\n opening?: boolean;\n /** The text part of this node being edited in place, with the editor's callbacks. */\n editing?: PartEditing;\n /** Opens the node (drills into a portal); absent where the layer is read-only. */\n onOpen?: () => void;\n};\n\nexport type CreateProps = { id: string; z: string; center: Point; size: Size };\n\nexport type NodeDef = {\n type: NodeType;\n name: string;\n icon: string;\n /** Palette shortcut; a registry of many types leaves most without one. */\n key?: string;\n /** Palette group; types without one share the default group. */\n group?: string;\n /** The type's schema; the host's scene schema is the union of its registry's (`createSceneSchema`). */\n schema: Schema.Codec<NodeBase, unknown>;\n component: ComponentType<NodeViewProps>;\n /** A new node of the type with its default content, for the palette tool and drop-on-canvas. */\n create: (props: CreateProps) => Node;\n defaultSize: Size;\n /** Explicit port layout; absent, the type gets `portsPerSide` ports spread along each side. */\n ports?: (node: Node) => readonly Port[];\n /** Defaults to `DEFAULT_PORTS_PER_SIDE`. */\n portsPerSide?: number;\n resizable?: boolean;\n minSize?: Size;\n maxSize?: Size;\n /** Double-click opens the node (a portal drills in; a text node edits, later). */\n openable?: boolean;\n};\n\n/**\n * A node type as declared: a `NodeDef` whose fields may be left to its prototype. A prototype (a spec in\n * `prototypes`) is never a type of its own: it is not in the registry, the palette or the scene schema.\n */\nexport type NodeDefSpec = Partial<Omit<NodeDef, 'type'>> & {\n /** The prototype this type inherits unset fields from. */\n extends?: string;\n};\n\n/**\n * A registry from type specs and the prototypes they extend: each type takes its own fields over its\n * prototype's, recursively. Throws when a type names a missing prototype, a cycle, or ends up without a\n * field every type needs.\n */\nexport const createNodeRegistry = (\n types: Readonly<Record<NodeType, NodeDefSpec>>,\n prototypes: Readonly<Record<string, NodeDefSpec>> = {},\n): NodeRegistry => {\n const inherit = (spec: NodeDefSpec, chain: readonly string[]): NodeDefSpec => {\n if (spec.extends === undefined) {\n return spec;\n }\n if (chain.includes(spec.extends)) {\n throw new Error(`Node prototype cycle: ${[...chain, spec.extends].join(' -> ')}`);\n }\n const prototype = prototypes[spec.extends];\n if (!prototype) {\n throw new Error(`Unknown node prototype: ${spec.extends}`);\n }\n const { extends: _, ...own } = spec;\n return { ...inherit(prototype, [...chain, spec.extends]), ...own };\n };\n return Object.fromEntries(\n Object.entries(types).map(([type, spec]) => {\n const { extends: _, ...resolved } = inherit(spec, [type]);\n const { name, icon, schema, component, create, defaultSize } = resolved;\n if (!name || !icon || !schema || !component || !create || !defaultSize) {\n throw new Error(`Node type ${type} is missing a required field`);\n }\n const def: NodeDef = { ...resolved, type, name, icon, schema, component, create, defaultSize };\n return [type, def];\n }),\n );\n};\n\nexport type LinkDef = {\n type: LinkType;\n name: string;\n icon: string;\n key: string;\n};\n\nexport type NodeRegistry = Readonly<Record<NodeType, NodeDef>>;\nexport type LinkRegistry = Readonly<Record<LinkType, LinkDef>>;\n\nconst MIN_SIZE: Size = { width: 64, height: 32 };\n\n/**\n * A framed shape with a centred, editable label: resizable, with ports spread along every side. The\n * built-in rectangle and scene are both boxes; a host type can extend it too.\n */\nexport const boxPrototype: NodeDefSpec = {\n component: BoxNodeView,\n defaultSize: DEFAULT_SIZES.rect,\n resizable: true,\n minSize: MIN_SIZE,\n};\n\nexport const defaultNodePrototypes: Readonly<Record<string, NodeDefSpec>> = { box: boxPrototype };\n\nexport const defaultNodeTypes: Readonly<Record<NodeType, NodeDefSpec>> = {\n rect: {\n extends: 'box',\n name: 'Rectangle',\n icon: 'ph--rectangle--regular',\n key: 'R',\n schema: RectNode,\n create: (props) => createNode({ type: 'rect', ...props }),\n },\n ellipse: {\n name: 'Ellipse',\n icon: 'ph--circle--regular',\n key: 'E',\n schema: EllipseNode,\n component: EllipseNodeView,\n create: (props) => createNode({ type: 'ellipse', ...props }),\n defaultSize: DEFAULT_SIZES.ellipse,\n // Only the side centres of the frame lie on the curve.\n portsPerSide: 1,\n resizable: true,\n minSize: MIN_SIZE,\n },\n class: {\n name: 'Class',\n icon: 'ph--rows--regular',\n key: 'C',\n schema: ClassNode,\n component: ClassNodeView,\n create: (props) => createNode({ type: 'class', ...props }),\n defaultSize: DEFAULT_SIZES.class,\n resizable: true,\n minSize: { width: 128, height: 96 },\n },\n note: {\n name: 'Note',\n icon: 'ph--text-t--regular',\n key: 'T',\n schema: NoteNode,\n component: NoteNodeView,\n create: (props) => createNode({ type: 'note', ...props }),\n defaultSize: DEFAULT_SIZES.note,\n resizable: true,\n minSize: MIN_SIZE,\n },\n scene: {\n extends: 'box',\n name: 'Scene',\n icon: 'ph--frame-corners--regular',\n key: 'S',\n schema: PortalNode,\n component: PortalNodeView,\n create: (props) => createNode({ type: 'scene', ...props }),\n defaultSize: DEFAULT_SIZES.scene,\n minSize: { width: 96, height: 60 },\n openable: true,\n },\n};\n\nexport const defaultNodeRegistry: NodeRegistry = createNodeRegistry(defaultNodeTypes, defaultNodePrototypes);\n\nexport const defaultLinkRegistry: LinkRegistry = {\n line: { type: 'line', name: 'Line', icon: 'ph--line-segment--regular', key: 'L' },\n curve: { type: 'curve', name: 'Curve', icon: 'ph--bezier-curve--regular', key: 'K' },\n spline: { type: 'spline', name: 'Spline', icon: 'ph--wave-sine--regular', key: 'P' },\n smart: { type: 'smart', name: 'Smart line', icon: 'ph--flow-arrow--regular', key: 'O' },\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Editing several elements in one form: the properties every selected type declares alike, the values\n// they share (and the paths they disagree on), and the patch an edit makes to each element.\n//\n\nimport * as Schema from 'effect/Schema';\nimport type * as SchemaAST from 'effect/SchemaAST';\n\nimport { getChecks, getPropertySignatures, pick } from '@dxos/effect/SchemaAST';\n\ntype Values = Readonly<Record<string, unknown>>;\n\nconst isPlainObject = (value: unknown): value is Values =>\n typeof value === 'object' && value !== null && !Array.isArray(value);\n\nconst isOptional = (ast: SchemaAST.AST) => ast.context?.isOptional ?? false;\n\n/** A check as comparable data: the filter and its payload (`isBetween` with its bounds), if it declares them. */\nconst checkKey = (check: SchemaAST.Check<any>): string | undefined => {\n const representation = check.annotations?.representation;\n return representation === undefined ? undefined : JSON.stringify(representation);\n};\n\n/** Whether two types carry the same checks, so a value one accepts the other does too. */\nconst sameChecks = (left: SchemaAST.AST, right: SchemaAST.AST): boolean => {\n const [leftChecks, rightChecks] = [getChecks(left), getChecks(right)];\n // A check that declares no representation cannot be compared, so only the same check matches it.\n const same = (check: SchemaAST.Check<any>, other: SchemaAST.Check<any>) => {\n const key = checkKey(check);\n return check === other || (key !== undefined && key === checkKey(other));\n };\n return (\n leftChecks.length === rightChecks.length && leftChecks.every((check, index) => same(check, rightChecks[index]))\n );\n};\n\n/**\n * Whether two property types describe the same values, so one field can edit both. Separately declared\n * types compare by structure and by their checks: `locked` on a node and on a link is the same optional\n * boolean, but numbers bounded differently are not, since the form validates against only one of them.\n */\nexport const sameType = (left: SchemaAST.AST, right: SchemaAST.AST): boolean => {\n if (left === right) {\n return true;\n }\n if (left._tag !== right._tag || isOptional(left) !== isOptional(right) || !sameChecks(left, right)) {\n return false;\n }\n if (left._tag === 'Literal' && right._tag === 'Literal') {\n return left.literal === right.literal;\n }\n if (left._tag === 'Union' && right._tag === 'Union') {\n return sameList(left.types, right.types);\n }\n if (left._tag === 'Arrays' && right._tag === 'Arrays') {\n return sameList(left.elements, right.elements) && sameList(left.rest, right.rest);\n }\n if (left._tag === 'Objects' && right._tag === 'Objects') {\n const others = new Map(right.propertySignatures.map((property) => [property.name, property.type]));\n return (\n left.propertySignatures.length === right.propertySignatures.length &&\n left.propertySignatures.every((property) => {\n const other = others.get(property.name);\n return other !== undefined && sameType(property.type, other);\n })\n );\n }\n return true;\n};\n\nconst sameList = (left: readonly SchemaAST.AST[], right: readonly SchemaAST.AST[]) =>\n left.length === right.length && left.every((type, index) => sameType(type, right[index]));\n\n/**\n * The properties every schema declares alike, as one struct over the first schema's declarations;\n * `undefined` when they share none. One schema is its own common schema.\n */\nexport const commonSchema = (schemas: readonly Schema.Codec<any, any>[]): Schema.Codec<any, any> | undefined => {\n const [first, ...rest] = schemas;\n if (!first) {\n return undefined;\n }\n const shared = getPropertySignatures(first.ast)\n .filter((property) =>\n rest.every((schema) =>\n getPropertySignatures(schema.ast).some(\n (other) => other.name === property.name && sameType(property.type, other.type),\n ),\n ),\n )\n .map((property) => property.name);\n return shared.length > 0 ? Schema.make<Schema.Codec<any, any>>(pick(first.ast, shared)) : undefined;\n};\n\nconst equal = (left: unknown, right: unknown): boolean => {\n if (left === right) {\n return true;\n }\n if (Array.isArray(left) && Array.isArray(right)) {\n return left.length === right.length && left.every((value, index) => equal(value, right[index]));\n }\n if (isPlainObject(left) && isPlainObject(right)) {\n const keys = new Set([...Object.keys(left), ...Object.keys(right)]);\n return [...keys].every((key) => equal(left[key], right[key]));\n }\n return false;\n};\n\nexport type MergedValues = {\n /** The shared value at every path; where the objects disagree, the first object's, so the form still validates. */\n values: Values;\n /** Json-paths (`style.hue`) whose value differs between the objects. */\n mixed: Set<string>;\n};\n\n/** Merges the objects' `keys` for one form, descending into nested objects so a struct is mixed field by field. */\nexport const mergeValues = (objects: readonly Values[], keys: readonly PropertyKey[]): MergedValues => {\n const mixed = new Set<string>();\n const merge = (sources: readonly Values[], names: readonly string[], prefix: string): Values =>\n Object.fromEntries(\n names.flatMap((name) => {\n const path = prefix ? `${prefix}.${name}` : name;\n const values = sources.map((source) => source[name]);\n if (values.every(isPlainObject)) {\n const nested = [...new Set(values.flatMap((value) => Object.keys(value)))];\n return [[name, merge(values, nested, path)]];\n }\n if (!values.every((value) => equal(value, values[0]))) {\n mixed.add(path);\n }\n const value = values.find((value) => value !== undefined);\n return value === undefined ? [] : [[name, value]];\n }),\n );\n const names = keys.filter((key): key is string => typeof key === 'string');\n return { values: merge(objects, names, ''), mixed };\n};\n\nconst getIn = (value: unknown, path: readonly string[]): unknown =>\n path.reduce<unknown>((current, key) => (isPlainObject(current) ? current[key] : undefined), value);\n\nconst setIn = (value: unknown, path: readonly string[], next: unknown): unknown => {\n const [head, ...rest] = path;\n if (head === undefined) {\n return next;\n }\n const current = isPlainObject(value) ? value : {};\n return { ...current, [head]: setIn(current[head], rest, next) };\n};\n\n/**\n * The top-level values an edit writes to one element: each changed json-path set to the form's value,\n * leaving the element's other nested fields (the rest of its `style`) as they were.\n */\nexport const patchValues = (element: Values, values: Values, paths: readonly string[]): Record<string, unknown> => {\n const patch: Record<string, unknown> = {};\n for (const path of paths) {\n const [head, ...rest] = path.split('.');\n patch[head] = setIn(head in patch ? patch[head] : element[head], rest, getIn(values, path.split('.')));\n }\n return patch;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport React from 'react';\n\nimport { Form, type FormFieldRenderer, useFormFieldState } from '@dxos/react-ui-form';\nimport * as ToggleGroup from '@dxos/react-ui/ToggleGroup';\nimport { mx } from '@dxos/ui-theme';\n\nimport { NodeStyle, type NodeTone } from '../../model/types.ts';\nimport { DEFAULT_TONE, STYLE_HUES, type StyleHue, TONE_NAMES, TONES, hueClasses } from '../../utils/style.ts';\n\nexport type StyleChoice = { hue: StyleHue; tone: NodeTone };\n\nconst SEPARATOR = ':';\n\nconst choiceKey = ({ hue, tone }: StyleChoice) => `${hue}${SEPARATOR}${tone}`;\n\nconst parseChoice = (key: string): StyleChoice | undefined => {\n const [hue, tone] = key.split(SEPARATOR);\n const styleHue = STYLE_HUES.find((candidate) => candidate === hue);\n const nodeTone = TONES.find((candidate) => String(candidate) === tone);\n return styleHue !== undefined && nodeTone !== undefined ? { hue: styleHue, tone: nodeTone } : undefined;\n};\n\nconst capitalize = (text: string) => text.charAt(0).toUpperCase() + text.slice(1);\n\n/** The pressed item keeps the panel's background; the selection is drawn around the swatch instead. */\nconst ITEM_CLASSES = 'min-w-0 px-0 aria-checked:bg-transparent aria-checked:hover:bg-hover-surface';\n\nexport type StyleGridProps = {\n hue?: string;\n /** Unset is the default tone, as the frame draws it. */\n tone?: NodeTone;\n /** Several nodes disagree: no swatch is selected until one is picked. */\n indeterminate?: boolean;\n readonly?: boolean;\n onValueChange: (choice: StyleChoice) => void;\n};\n\n/**\n * Each offered hue in a column and its tones down the rows, every swatch drawn with the classes the node\n * itself would take, so a pick is a preview. A hue the grid does not offer, or none, selects nothing.\n */\nexport const StyleGrid = ({ hue, tone = DEFAULT_TONE, indeterminate, readonly, onValueChange }: StyleGridProps) => {\n const selected = indeterminate || !hue ? '' : `${hue}${SEPARATOR}${tone}`;\n return (\n <ToggleGroup.Root\n type='single'\n classNames='grid grid-cols-9 gap-1'\n value={selected}\n aria-label='Style'\n data-testid='style-grid'\n onValueChange={(next) => {\n // Pressing the selected swatch again deselects it in the group; the style keeps its value.\n const choice = parseChoice(next);\n if (choice) {\n onValueChange(choice);\n }\n }}\n >\n {TONES.flatMap((rowTone) =>\n STYLE_HUES.map((columnHue) => {\n const key = choiceKey({ hue: columnHue, tone: rowTone });\n const classes = hueClasses(columnHue, rowTone);\n return (\n <ToggleGroup.Item\n key={key}\n value={key}\n variant='ghost'\n classNames={ITEM_CLASSES}\n disabled={readonly}\n data-style-option={key}\n >\n <span\n role='img'\n aria-label={`${capitalize(columnHue)}, ${TONE_NAMES[rowTone]}`}\n className={mx(\n 'size-5 rounded-xs border-2',\n classes.surface,\n classes.border,\n selected === key && 'outline-2 outline-offset-2 outline-primary-500',\n )}\n />\n </ToggleGroup.Item>\n );\n }),\n )}\n </ToggleGroup.Root>\n );\n};\n\n/**\n * The properties panel's style field, rendered at `style.hue`: one pick sets the hue and its tone together,\n * so it writes the enclosing `style`.\n */\nexport const StyleGridField: FormFieldRenderer = ({ label, jsonPath, readonly, indeterminate, getValue, onBlur }) => {\n // Hue and tone change together, so the pick writes their parent once; two field writes would race.\n const stylePath = (jsonPath ?? 'style.hue').split('.').slice(0, -1);\n const styleField = useFormFieldState('StyleGridField', stylePath);\n const style: NodeStyle = styleField.getValue() ?? {};\n return (\n <Form.Field path={jsonPath} label={label} readonly={readonly}>\n <StyleGrid\n hue={getValue()}\n tone={style.tone}\n indeterminate={indeterminate}\n readonly={!!readonly}\n onValueChange={({ hue, tone }) => {\n // A pick is a commit: the grid never blurs, so it commits itself.\n styleField.onValueChange(NodeStyle.ast, { ...style, hue, tone });\n onBlur();\n }}\n />\n </Form.Field>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Property panel for the selection: a schema-driven form over the properties every selected element\n// declares alike (one element: its whole schema; a node's from its registry definition), so every field\n// a type has is editable without a per-type form. Values the elements disagree on show as mixed; an edit\n// writes only the changed fields, to every element, as one batch of `update` intents.\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport type * as Schema from 'effect/Schema';\nimport React, { useCallback, useMemo } from 'react';\n\nimport {\n Form,\n type FormFieldMap,\n type FormFieldOverride,\n type FormFieldRenderer,\n type FormUpdateMeta,\n} from '@dxos/react-ui-form';\nimport * as Input from '@dxos/react-ui/Input';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type NodeRegistry, defaultNodeRegistry } from '../../model/registry.ts';\nimport {\n CurveLink,\n type Element,\n LineLink,\n type LinkType,\n NodeBase,\n SmartLink,\n SplineLink,\n getElement,\n isLink,\n} from '../../model/types.ts';\nimport { MAX_PORTS_PER_SIDE, portsPerSideOf } from '../../utils/ports.ts';\nimport { commonSchema, mergeValues, patchValues } from '../../utils/properties.ts';\nimport { resolveStyle } from '../../utils/style.ts';\nimport { StyleGridField } from './StyleGrid.tsx';\n\n/** Identity, ordering and geometry lists are the surface's, not the user's. */\nconst HIDDEN = ['id', 'type', 'z', 'ports', 'points', 'source', 'target'];\n\n/**\n * A string list as one entry per line: a UML compartment reads as a block of text, so a textarea\n * beats the generic array field's row of inputs. Blank lines survive while typing (they round-trip\n * through split/join) and are dropped on blur, when the form saves.\n */\nconst LinesField: FormFieldRenderer = ({ type, label, jsonPath, readonly, getValue, onValueChange, onBlur }) => {\n const lines: string[] = getValue() ?? [];\n return (\n <Form.Field path={jsonPath} label={label} readonly={readonly}>\n <Input.Textarea\n rows={4}\n classNames='font-mono'\n disabled={!!readonly}\n value={lines.join('\\n')}\n onChange={(event) => onValueChange(type, event.target.value.split('\\n'))}\n onBlur={(event) => {\n onValueChange(\n type,\n lines.map((line) => line.trim()).filter((line) => line.length > 0),\n );\n onBlur(event);\n }}\n />\n </Form.Field>\n );\n};\n\n/** Renderers by field path for the built-in types' list fields and the style grid; a host may pass its own. */\nexport const DEFAULT_FIELDS: FormFieldMap = {\n 'attributes': LinesField,\n 'methods': LinesField,\n 'style.hue': StyleGridField,\n};\n\nconst LINK_SCHEMAS: Record<LinkType, Schema.Codec<any, any>> = {\n line: LineLink,\n curve: CurveLink,\n spline: SplineLink,\n smart: SmartLink,\n};\n\n/** An element's own schema; a node type the registry does not know gets the shared fields. */\nconst schemaOf = (nodes: NodeRegistry, element: Element): Schema.Codec<any, any> =>\n isLink(element) ? LINK_SCHEMAS[element.type] : (nodeDef(nodes, element)?.schema ?? NodeBase);\n\n/**\n * What the form shows for an element: what the frame draws, so an unset fill or border reads as on and an\n * unset port count as the type's.\n */\nconst formValues = (nodes: NodeRegistry, element: Element): Record<string, unknown> =>\n isLink(element)\n ? element\n : { ...element, style: resolveStyle(element.style), portsPerSide: portsPerSideOf(nodes, element) };\n\n/**\n * How the panel presents fields. Ranges are the editor's, not the model's: a check on the stored schema would\n * make a record outside them (an older or imported scene) fail validation and drop out of the scene. The style\n * grid at `style.hue` also sets `style.tone`, which has no field of its own.\n */\nconst FIELD_OVERRIDES: Record<string, FormFieldOverride> = {\n 'style.hue': { label: 'Style' },\n 'style.tone': { hidden: true },\n 'style.fontSize': { min: 8, max: 80, step: 1 },\n 'portsPerSide': { min: 1, max: MAX_PORTS_PER_SIDE, step: 1 },\n};\n\nconst plural = (count: number, noun: string) => `${count} ${noun}${count === 1 ? '' : 's'}`;\n\n/** The selection by kind, e.g. \"3 nodes, 2 links\". */\nconst describeSelection = (elements: readonly Element[]) => {\n const links = elements.filter(isLink).length;\n const nodes = elements.length - links;\n return [nodes > 0 && plural(nodes, 'node'), links > 0 && plural(links, 'link')].filter(Boolean).join(', ');\n};\n\nexport type PropertiesProps = Util.ThemedClassName<{\n projection: Projection;\n atoms: SceneViewAtoms;\n nodes?: NodeRegistry;\n fields?: FormFieldMap;\n /** Show the fields without letting them change; also implied by a projection that cannot `update`. */\n readonly?: boolean;\n}>;\n\nexport const Properties = ({\n classNames,\n projection,\n atoms,\n nodes = defaultNodeRegistry,\n fields = DEFAULT_FIELDS,\n readonly: readonlyProp = false,\n}: PropertiesProps) => {\n const scene = useAtomValue(projection.scene);\n const selection = useAtomValue(atoms.selection);\n const elements = useMemo(() => [...selection].flatMap((id) => getElement(scene, id) ?? []), [scene, selection]);\n const readonly = readonlyProp || !projection.capabilities.update;\n\n // Keyed by the selected types, so the schema (and the form built on it) holds while values change under it.\n const typesKey = [...new Set(elements.map((element) => element.type))].sort().join();\n // eslint-disable-next-line react-hooks/exhaustive-deps\n const schema = useMemo(() => commonSchema(elements.map((element) => schemaOf(nodes, element))), [typesKey, nodes]);\n const { values, fieldOverrides } = useMemo(() => {\n const shown = elements.map((element) => formValues(nodes, element));\n const { values, mixed } = mergeValues(shown, Object.keys(shown[0] ?? {}));\n // A value the elements disagree on shows as indeterminate until it is edited, then applies to all of them.\n const fieldOverrides: Record<string, FormFieldOverride> = { ...FIELD_OVERRIDES };\n for (const path of mixed) {\n fieldOverrides[path] = { ...fieldOverrides[path], indeterminate: true };\n }\n return { values, fieldOverrides };\n }, [elements, nodes]);\n\n const onSave = useCallback(\n (values: Record<string, unknown>, { changed }: FormUpdateMeta<Record<string, unknown>>) => {\n const paths = Object.keys(changed).filter((path) => changed[path as keyof typeof changed]);\n projection.apply({\n kind: 'batch',\n intents: elements.map((element) => ({\n kind: 'update' as const,\n id: element.id,\n values: patchValues(formValues(nodes, element), values, paths),\n })),\n });\n },\n [projection, elements, nodes],\n );\n\n if (elements.length === 0) {\n return (\n <div className={mx('flex flex-col overflow-hidden', classNames)} data-testid='properties'>\n <div className='p-2 text-sm text-fg-muted'>Select a node or link to edit its properties.</div>\n </div>\n );\n }\n\n const summary = elements.length > 1 && `${describeSelection(elements)}${schema ? '' : ' — no shared properties'}`;\n return (\n <div className={mx('flex flex-col overflow-hidden', classNames)} data-testid='properties'>\n {schema ? (\n <Form.Root\n key={[...selection].join()}\n schema={schema}\n values={values}\n fieldOverrides={fieldOverrides}\n fieldMap={fields}\n readonly={readonly}\n autoSave\n onSave={onSave}\n >\n {/* Scrolling: the panel is as tall as its host, and a long form (a class with many members) scrolls inside it. */}\n <Form.Viewport scroll>\n <Form.Content>\n <Form.Fields exclude={HIDDEN} />\n {summary && (\n <p className='text-sm text-fg-muted' data-testid='properties-summary'>\n {summary}\n </p>\n )}\n </Form.Content>\n </Form.Viewport>\n </Form.Root>\n ) : (\n <p className='p-2 text-sm text-fg-muted' data-testid='properties-summary'>\n {summary}\n </p>\n )}\n </div>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { RegistryContext } from '@effect/atom-react/RegistryContext';\nimport { useContext } from 'react';\n\n/** The view's atom registry; components read atoms through `useAtomValue` and write through this. */\nexport const useRegistry = () => useContext(RegistryContext);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Auto layout (MIGRATION.md M4): the scene's own nodes arranged into ranked rows along its links,\n// through `@dxos/diagram`'s ranking — the same engine the dynamic projection lays its graph out with,\n// rather than a second one. Unlike the editor's `@antv` layout this keeps each node: its type, its\n// size and its content are untouched and only the centre moves, so laying out is an arrangement of\n// the diagram rather than a replacement of it.\n//\n\nimport { Layout } from '@dxos/diagram';\n\nimport { type ElementId, MAJOR_GRID, type Point, type Scene, type Size, endpointNode } from '../model/types.ts';\n\nexport type LayoutOptions = {\n /** Gap between rows and between the columns within a row, in scene px. */\n gap?: Size;\n /** Where the arrangement's top-left corner goes. */\n origin?: Point;\n};\n\nconst DEFAULTS: Required<LayoutOptions> = {\n gap: { width: MAJOR_GRID * 2, height: MAJOR_GRID * 2 },\n origin: { x: MAJOR_GRID * 2, y: MAJOR_GRID * 2 },\n};\n\n/**\n * The scene with its nodes ranked into rows: a node sits one row below its deepest predecessor, and\n * the nodes of a row are laid left to right in their current left-to-right order, so an arrangement a\n * user has already tidied along a row survives. Rows are as tall as their tallest node and columns as\n * wide as their widest, so mixed sizes never overlap. Everything lands on the major grid.\n *\n * `ids`, when given, narrows what moves: the rest of the scene stays exactly where it is, which is how\n * \"lay out the selection\" differs from \"lay out the board\".\n */\nexport const layoutScene = (scene: Scene, ids?: readonly ElementId[], options: LayoutOptions = {}): Scene => {\n const { gap, origin } = { ...DEFAULTS, ...options };\n const subject = new Set(ids ?? Object.keys(scene.nodes));\n const moving = Object.values(scene.nodes).filter((node) => subject.has(node.id) && !node.locked);\n if (moving.length === 0) {\n return scene;\n }\n\n const known = new Set(moving.map(({ id }) => id));\n const edges = Object.values(scene.links)\n .map((link) => ({ from: endpointNode(link.source) ?? '', to: endpointNode(link.target) ?? '' }))\n .filter(({ from, to }) => known.has(from) && known.has(to));\n // Sorted, so the ranking (and with it the arrangement) does not depend on the map's insertion order.\n const ordered = [...moving].sort((left, right) => (left.id < right.id ? -1 : 1));\n const ranks = Layout.rank(\n ordered.map(({ id }) => id),\n edges,\n );\n\n const rows = new Map<number, typeof ordered>();\n for (const node of ordered) {\n const rank = ranks.get(node.id) ?? 0;\n rows.set(rank, [...(rows.get(rank) ?? []), node]);\n }\n\n const centers = new Map<string, Point>();\n let top = origin.y;\n for (const rank of [...rows.keys()].sort((left, right) => left - right)) {\n // Their current order along the row, so a row the user has already arranged keeps its reading order.\n const members = [...(rows.get(rank) ?? [])].sort((left, right) => left.center.x - right.center.x);\n const height = Math.max(...members.map(({ size }) => size.height));\n let left = origin.x;\n for (const node of members) {\n centers.set(node.id, snap({ x: left + node.size.width / 2, y: top + height / 2 }));\n left += node.size.width + gap.width;\n }\n top += height + gap.height;\n }\n\n const nodes = { ...scene.nodes };\n let changed = false;\n for (const [id, center] of centers) {\n const node = nodes[id];\n if (node.center.x !== center.x || node.center.y !== center.y) {\n nodes[id] = { ...node, center };\n changed = true;\n }\n }\n return changed ? { ...scene, nodes } : scene;\n};\n\nconst snap = ({ x, y }: Point): Point => ({\n x: Math.round(x / MAJOR_GRID) * MAJOR_GRID,\n y: Math.round(y / MAJOR_GRID) * MAJOR_GRID,\n});\n\nexport type GridExtent = { columns: number; rows: number };\n\n/**\n * Where the first slot's centre goes for a grid of `extent` equal slots, `size` each and `pitch` apart,\n * placed so the whole arrangement straddles the origin. A slot spans an odd number of major cells, so\n * its run's exact midpoint falls half a cell off the grid; the leading edge is rounded to the grid\n * instead, which keeps every slot snapped at the cost of the arrangement sitting up to half a cell off\n * centre.\n */\nexport const centeredOrigin = (extent: GridExtent, pitch: Size, size: Size): Point => ({\n x: leadingEdge(extent.columns, pitch.width, size.width) + size.width / 2,\n y: leadingEdge(extent.rows, pitch.height, size.height) + size.height / 2,\n});\n\nconst leadingEdge = (count: number, pitch: number, extent: number): number =>\n Math.round(-(Math.max(count - 1, 0) * pitch + extent) / 2 / MAJOR_GRID) * MAJOR_GRID;\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Scene store seam: scenes by id behind atoms, so a view subscribes to exactly the scene it shows and\n// an ECHO-backed store (phase 3) can replace the in-memory one without touching the surface.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { type Scene, type SceneId } from './types.ts';\n\nexport type SceneMap = Readonly<Record<SceneId, Scene>>;\n\nexport type SceneStore = {\n /** Every scene, keyed by id. Written through the registry. */\n readonly scenes: Atom.Writable<SceneMap>;\n /** Derived atom for one scene; stable per id so subscriptions do not churn. */\n scene: (id: SceneId) => Atom.Atom<Scene | undefined>;\n};\n\nexport const createMemoryStore = (initial: readonly Scene[] = []): SceneStore => {\n const scenes = Atom.keepAlive(Atom.make<SceneMap>(Object.fromEntries(initial.map((scene) => [scene.id, scene]))));\n const derived = new Map<SceneId, Atom.Atom<Scene | undefined>>();\n return {\n scenes,\n scene: (id) => {\n let atom = derived.get(id);\n if (!atom) {\n atom = Atom.keepAlive(Atom.make((get) => get(scenes)[id]));\n derived.set(id, atom);\n }\n return atom;\n },\n };\n};\n\n/** Replace one scene in the store (a no-op when the updater returns the same object). */\nexport const updateScene = (\n registry: Registry.AtomRegistry,\n store: SceneStore,\n id: SceneId,\n update: (scene: Scene) => Scene,\n): void => {\n const scenes = registry.get(store.scenes);\n const current = scenes[id];\n if (!current) {\n return;\n }\n const next = update(current);\n if (next !== current) {\n registry.set(store.scenes, { ...scenes, [id]: next });\n }\n};\n\nexport const putScene = (registry: Registry.AtomRegistry, store: SceneStore, scene: Scene): void => {\n registry.set(store.scenes, { ...registry.get(store.scenes), [scene.id]: scene });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The projection seam (docs/DESIGN.md §3): the only thing the surface knows. It reads a positioned\n// scene and sends intents; the projection owns the drawing model and decides what an intent means.\n// `freehand` is the identity projection: intents write coordinates straight into the scene.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\nimport * as Schema from 'effect/Schema';\n\nimport { type LatticeSpec } from '../utils/lattice.ts';\nimport { layoutScene } from '../utils/layout.ts';\nimport { resizeNode } from '../utils/shapes.ts';\nimport { type SceneStore, putScene, updateScene } from './store.ts';\nimport {\n type Capabilities,\n type Intent,\n type Link,\n type Node,\n OpenScene,\n type Scene,\n type SceneId,\n endpointNode,\n} from './types.ts';\n\nexport type Projection = {\n /** Positioned nodes and links; re-emitted on every model change. */\n readonly scene: Atom.Atom<Scene>;\n /** May apply, partially apply, rewrite the model, or reject. */\n apply: (intent: Intent) => void;\n readonly capabilities: Capabilities;\n /**\n * The model as an opaque immutable value, identical (`===`) when nothing changed, so the view can\n * keep an undo log without knowing what the model is (`undo.ts`).\n */\n snapshot: () => unknown;\n restore: (snapshot: unknown) => void;\n /**\n * What `apply` would make of `intent`, without applying it: the rewritten intent, or undefined when it\n * would be refused. Absent means intents apply as given. Previews of a gesture in flight read it, so a\n * drag shows where the drop will land.\n */\n constrain?: (intent: Intent) => Intent | undefined;\n /** The lattice the projection keeps shapes on, for the grid layer that draws it (DESIGN §8b). */\n lattice?: LatticeSpec;\n};\n\nconst EMPTY: Scene = { id: '', nodes: {}, links: {} };\n\n/** Freehand semantics as a pure reducer, so it is testable and reusable by other projections. */\nexport const reduceIntent = (scene: Scene, intent: Intent): Scene => {\n switch (intent.kind) {\n case 'move': {\n const nodes = { ...scene.nodes };\n let changed = false;\n for (const id of intent.ids) {\n const node = nodes[id];\n if (node && !node.locked) {\n nodes[id] = { ...node, center: { x: node.center.x + intent.delta.x, y: node.center.y + intent.delta.y } };\n changed = true;\n }\n }\n return changed ? { ...scene, nodes } : scene;\n }\n\n case 'resize': {\n const node = scene.nodes[intent.id];\n if (!node || node.locked) {\n return scene;\n }\n return { ...scene, nodes: { ...scene.nodes, [intent.id]: resizeNode(node, intent.bounds) } };\n }\n\n case 'link': {\n const { link } = intent;\n // Every node end must exist, and a link never joins a node to itself; free ends need nothing.\n const nodes = [link.source, link.target].map(endpointNode);\n if (nodes.some((id) => id !== undefined && scene.nodes[id] === undefined)) {\n return scene;\n }\n if (nodes[0] !== undefined && nodes[0] === nodes[1]) {\n return scene;\n }\n return { ...scene, links: { ...scene.links, [link.id]: link } };\n }\n\n case 'create': {\n return { ...scene, nodes: { ...scene.nodes, [intent.node.id]: intent.node } };\n }\n\n case 'delete': {\n const ids = new Set(intent.ids);\n const nodes: Record<string, Node> = {};\n for (const node of Object.values(scene.nodes)) {\n if (!ids.has(node.id)) {\n nodes[node.id] = node;\n }\n }\n const links: Record<string, Link> = {};\n for (const link of Object.values(scene.links)) {\n // A link loses its meaning with either end, so it goes too.\n if (\n !ids.has(link.id) &&\n !ids.has(endpointNode(link.source) ?? '') &&\n !ids.has(endpointNode(link.target) ?? '')\n ) {\n links[link.id] = link;\n }\n }\n return { ...scene, nodes, links };\n }\n\n case 'reorder': {\n const node = scene.nodes[intent.id];\n if (node) {\n return node.z === intent.z\n ? scene\n : { ...scene, nodes: { ...scene.nodes, [intent.id]: { ...node, z: intent.z } } };\n }\n const link = scene.links[intent.id];\n if (link) {\n return link.z === intent.z\n ? scene\n : { ...scene, links: { ...scene.links, [intent.id]: { ...link, z: intent.z } } };\n }\n return scene;\n }\n\n case 'layout':\n return layoutScene(scene, intent.ids);\n\n case 'batch':\n return intent.intents.reduce(reduceIntent, scene);\n\n case 'update': {\n const node = scene.nodes[intent.id];\n if (node) {\n const next = Object.assign({}, node, intent.values, { id: node.id, type: node.type });\n return { ...scene, nodes: { ...scene.nodes, [intent.id]: next } };\n }\n const link = scene.links[intent.id];\n if (link) {\n const next = Object.assign({}, link, intent.values, { id: link.id, type: link.type });\n return { ...scene, links: { ...scene.links, [intent.id]: next } };\n }\n return scene;\n }\n }\n};\n\nexport type FreehandProjectionOptions = {\n registry: Registry.AtomRegistry;\n store: SceneStore;\n sceneId: SceneId;\n /**\n * Whether a constraining projection (the lattice) applies its constraint now; the view passes its snap\n * toggle. Read per intent, so turning it off frees the next gesture without rebuilding the projection.\n */\n constrained?: () => boolean;\n};\n\nexport const freehandCapabilities: Capabilities = {\n move: true,\n resize: true,\n link: true,\n create: true,\n delete: true,\n update: true,\n layout: true,\n};\n\n/** What a read-only view may do: look, select and navigate, nothing that reaches the model. */\nexport const readonlyCapabilities: Capabilities = {\n move: false,\n resize: false,\n link: false,\n create: false,\n delete: false,\n update: false,\n layout: false,\n};\n\n/** Identity projection over the store: what the surface asks for is what the model becomes. */\nexport const createFreehandProjection = ({ registry, store, sceneId }: FreehandProjectionOptions): Projection => ({\n scene: Atom.keepAlive(Atom.make((get) => get(store.scene(sceneId)) ?? EMPTY)),\n apply: (intent) => updateScene(registry, store, sceneId, (scene) => reduceIntent(scene, intent)),\n capabilities: freehandCapabilities,\n snapshot: () => registry.get(store.scene(sceneId)),\n restore: (snapshot) => {\n // A host's nodes are `NodeBase` to the engine, so a snapshot is checked against the open schema.\n if (Schema.is(OpenScene)(snapshot)) {\n putScene(registry, store, snapshot);\n }\n },\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Undo as a per-view log of projection snapshots (§8): every `apply` that changes the model pushes the\n// snapshot taken before it, so the undo unit is the intent, whatever the projection made of it. The\n// snapshot is opaque to the view; each projection knows how to take and restore its own.\n//\n\nimport type * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { type Projection } from '../model/projection.ts';\n\n/** Entries older than this are dropped rather than growing without bound. */\nexport const UNDO_LIMIT = 100;\n\nexport type UndoState = {\n /** Which projection the snapshots belong to; a different one starts an empty log. */\n key: string;\n past: unknown[];\n future: unknown[];\n};\n\nexport const emptyUndo = (key = ''): UndoState => ({ key, past: [], future: [] });\n\nconst stateFor = (registry: Registry.AtomRegistry, atom: Atom.Writable<UndoState>, key: string): UndoState => {\n const current = registry.get(atom);\n return current.key === key ? current : emptyUndo(key);\n};\n\n/**\n * The projection with `apply` recording into `atom` under `key`; a rejected intent (same snapshot\n * before and after) records nothing.\n */\nexport const withUndo = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n): Projection => ({\n ...projection,\n apply: (intent) => {\n const before = projection.snapshot();\n projection.apply(intent);\n if (projection.snapshot() === before) {\n return;\n }\n const state = stateFor(registry, atom, key);\n registry.set(atom, { key, past: [...state.past.slice(-(UNDO_LIMIT - 1)), before], future: [] });\n },\n});\n\nexport const undo = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n): boolean => {\n const state = stateFor(registry, atom, key);\n const snapshot = state.past[state.past.length - 1];\n if (state.past.length === 0) {\n return false;\n }\n const current = projection.snapshot();\n projection.restore(snapshot);\n registry.set(atom, { key, past: state.past.slice(0, -1), future: [...state.future, current] });\n return true;\n};\n\nexport const redo = (\n projection: Projection,\n registry: Registry.AtomRegistry,\n atom: Atom.Writable<UndoState>,\n key: string,\n): boolean => {\n const state = stateFor(registry, atom, key);\n const snapshot = state.future[state.future.length - 1];\n if (state.future.length === 0) {\n return false;\n }\n const current = projection.snapshot();\n projection.restore(snapshot);\n registry.set(atom, { key, past: [...state.past, current], future: state.future.slice(0, -1) });\n return true;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport { useMemo } from 'react';\n\nimport { type SceneViewAtoms } from '../model/atoms.ts';\nimport { type FreehandProjectionOptions, type Projection, createFreehandProjection } from '../model/projection.ts';\nimport { type SceneStore } from '../model/store.ts';\nimport { withUndo } from '../utils/undo.ts';\nimport { useRegistry } from './useRegistry.ts';\n\nexport type UseSceneProjectionOptions = {\n store: SceneStore;\n atoms: SceneViewAtoms;\n createProjection?: (options: FreehandProjectionOptions) => Projection;\n /**\n * A host-owned projection, already obtained from this hook, used for every scene on the path: for a host\n * that owns one scene and its side effects and shares the projection with the view.\n */\n projection?: Projection;\n};\n\n/**\n * The projection of the scene at the head of the view's path, recording into the view's undo log;\n * shared by the view and its panels so every edit is undoable.\n */\nexport const useSceneProjection = ({\n store,\n atoms,\n createProjection = createFreehandProjection,\n projection,\n}: UseSceneProjectionOptions): Projection => {\n const registry = useRegistry();\n const path = useAtomValue(atoms.path);\n const sceneId = path[path.length - 1];\n return useMemo(\n () =>\n projection ??\n withUndo(\n createProjection({\n registry,\n store,\n sceneId,\n // Snap lands on the lattice only while both snap and the lattice toggle are on.\n constrained: () => registry.get(atoms.snap) && registry.get(atoms.lattice),\n }),\n registry,\n atoms.undo,\n sceneId,\n ),\n [projection, createProjection, registry, store, sceneId, atoms.undo, atoms.snap, atoms.lattice],\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useLayoutEffect, useState } from 'react';\n\nimport { type Size } from '../model/types.ts';\n\n/**\n * Content size of an element, tracked with a ResizeObserver. Measured in a layout effect so the\n * first paint already knows the size: a passive measurement paints one unfitted frame first.\n */\nexport const useViewport = (ref: RefObject<HTMLElement | null>): Size => {\n const [viewport, setViewport] = useState<Size>({ width: 0, height: 0 });\n useLayoutEffect(() => {\n const element = ref.current;\n if (!element) {\n return;\n }\n const update = (width: number, height: number) =>\n setViewport((current) => (current.width === width && current.height === height ? current : { width, height }));\n update(element.clientWidth, element.clientHeight);\n const observer = new ResizeObserver(([entry]) => {\n const { width, height } = entry.contentRect;\n update(width, height);\n });\n observer.observe(element);\n return () => observer.disconnect();\n }, [ref]);\n return viewport;\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type RefObject, useEffect } from 'react';\n\nexport type WheelHandler = (event: WheelEvent, pointer: { x: number; y: number }) => void;\n\n/** Non-passive wheel listener with the pointer in element coordinates, so the page never scrolls. */\nexport const useWheel = (ref: RefObject<HTMLElement | null>, handler: WheelHandler) => {\n useEffect(() => {\n const element = ref.current;\n if (!element) {\n return;\n }\n const onWheel = (event: WheelEvent) => {\n event.preventDefault();\n const rect = element.getBoundingClientRect();\n handler(event, { x: event.clientX - rect.left, y: event.clientY - rect.top });\n };\n element.addEventListener('wheel', onWheel, { passive: false });\n return () => element.removeEventListener('wheel', onWheel);\n }, [ref, handler]);\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Per-view ephemeral state (§4): selection, hover, drag, camera and the scene path live in atoms\n// owned by the view, never in the model, so two views of one scene stay independent.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\n\nimport { type Clipboard } from '../utils/clipboard.ts';\nimport { type PartKey } from '../utils/parts.ts';\nimport { type UndoState, emptyUndo } from '../utils/undo.ts';\nimport {\n type Bounds,\n type Camera,\n type ElementId,\n type Endpoint,\n type LinkId,\n type LinkType,\n type NodeId,\n type NodeType,\n type Point,\n type SceneId,\n type Side,\n type Tool,\n} from './types.ts';\n\nexport type Handle = 'n' | 'ne' | 'e' | 'se' | 's' | 'sw' | 'w' | 'nw';\n\n/**\n * The pointer machine's state. A node gesture (move, resize, create, a spline point) shows its geometry\n * snapped as it goes; a link band follows the pointer exactly and snaps once, as it lands.\n */\nexport type Drag =\n /** Screen-space pan; `last` is the previous pointer position. */\n | { kind: 'pan'; last: Point }\n /** Marquee in scene coordinates; shift adds the hits to the selection, alt subtracts them. */\n | { kind: 'marquee'; from: Point; to: Point; mode: 'replace' | 'add' | 'subtract' }\n /**\n * Moving the selection; `anchor` is the pressed node's top-left, which is what snaps to the grid,\n * and `delta` the resulting scene-space offset applied transiently to every selected node. With\n * `copy` (⌘ held) the originals stay and copies land at `delta` instead.\n */\n | { kind: 'move'; ids: NodeId[]; origin: Point; anchor: Point; delta: Point; copy?: boolean }\n /** Resizing one node by a handle; `bounds` is the transient result. */\n | { kind: 'resize'; id: NodeId; handle: Handle; start: Bounds; bounds: Bounds }\n /**\n * Rubber band from a port, or from a free point under a link tool; `target` is set while hovering a\n * valid drop, and the link is then previewed as created.\n */\n | { kind: 'link'; type: LinkType; source: Endpoint; from: Point; fromSide: Side; to: Point; target?: Endpoint }\n /**\n * Drawing a new node with a tool. `dropped` marks one dragged in from the palette or a host's\n * draggable, which previews as its frame alone: the pointer already carries the drag's own preview.\n */\n | { kind: 'create'; type: NodeType; from: Point; to: Point; dropped?: boolean }\n /** Moving one control point of a spline; `points` is the transient list. */\n | { kind: 'point'; id: LinkId; index: number; points: Point[] }\n /** Re-attaching one end of a link; `fixed` is the other end's resolved port for the rubber band. */\n | { kind: 'end'; id: LinkId; end: 'source' | 'target'; fixed: Point; fixedSide: Side; to: Point; target?: Endpoint };\n\nexport type HistoryEntry = { path: SceneId[]; camera: Camera };\n\nexport type ControlPointRef = { link: LinkId; index: number };\n\n/** The text part being edited in place (`parts.ts`). */\nexport type EditingPart = { id: NodeId; part: PartKey };\n\nexport type SceneViewAtoms = {\n camera: Atom.Writable<Camera>;\n path: Atom.Writable<SceneId[]>;\n selection: Atom.Writable<ReadonlySet<ElementId>>;\n hover: Atom.Writable<NodeId | undefined>;\n /** The selected control point of a selected spline, if any. */\n point: Atom.Writable<ControlPointRef | undefined>;\n tool: Atom.Writable<Tool>;\n /** The link type a port drag creates under the select tool (the last link tool picked). */\n linkType: Atom.Writable<LinkType>;\n /** Grid shown and moves/resizes snapped to it. */\n snap: Atom.Writable<boolean>;\n /** Guides shown: the scene's page frame and, on a lattice, its cells. */\n guides: Atom.Writable<boolean>;\n /** On a lattice scene, snap lands on the lattice's cells rather than the basic grid. */\n lattice: Atom.Writable<boolean>;\n drag: Atom.Writable<Drag | undefined>;\n history: Atom.Writable<{ entries: HistoryEntry[]; index: number }>;\n /** Projection snapshots for undo and redo (`undo.ts`). */\n undo: Atom.Writable<UndoState>;\n /** The last cut or copied fragment (`clipboard.ts`). */\n clipboard: Atom.Writable<Clipboard | undefined>;\n editing: Atom.Writable<EditingPart | undefined>;\n /** Frames show their id, type and geometry. */\n debug: Atom.Writable<boolean>;\n};\n\n/**\n * Fresh atoms for one view. Marked keepAlive so they survive React strict-mode remounts; the owner\n * decides their lifetime.\n */\nexport const createSceneViewAtoms = (root: SceneId): SceneViewAtoms => ({\n camera: Atom.keepAlive(Atom.make<Camera>({ x: 0, y: 0, zoom: 1 })),\n path: Atom.keepAlive(Atom.make<SceneId[]>([root])),\n selection: Atom.keepAlive(Atom.make<ReadonlySet<ElementId>>(new Set<ElementId>())),\n hover: Atom.keepAlive(Atom.make<NodeId | undefined>(undefined)),\n point: Atom.keepAlive(Atom.make<ControlPointRef | undefined>(undefined)),\n tool: Atom.keepAlive(Atom.make<Tool>({ kind: 'select' })),\n linkType: Atom.keepAlive(Atom.make<LinkType>('curve')),\n snap: Atom.keepAlive(Atom.make<boolean>(true)),\n guides: Atom.keepAlive(Atom.make<boolean>(true)),\n lattice: Atom.keepAlive(Atom.make<boolean>(true)),\n drag: Atom.keepAlive(Atom.make<Drag | undefined>(undefined)),\n history: Atom.keepAlive(Atom.make<{ entries: HistoryEntry[]; index: number }>({ entries: [], index: -1 })),\n undo: Atom.keepAlive(Atom.make<UndoState>(emptyUndo())),\n clipboard: Atom.keepAlive(Atom.make<Clipboard | undefined>(undefined)),\n editing: Atom.keepAlive(Atom.make<EditingPart | undefined>(undefined)),\n debug: Atom.keepAlive(Atom.make<boolean>(false)),\n});\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Cut, copy and paste as pure functions over the model (§8): the clipboard holds a fragment of nodes\n// and the links between them; a paste mints fresh ids, offsets the fragment and returns one `batch`\n// intent so the projection applies it atomically and undo takes it back in one step.\n//\n\nimport {\n type Bounds,\n type ElementId,\n type Endpoint,\n type Intent,\n type Link,\n type Node,\n type Point,\n type Scene,\n isPointEndpoint,\n} from '../model/types.ts';\nimport { unionBounds } from './hit.ts';\nimport { between, topZ } from './order.ts';\nimport { nodeBounds } from './shapes.ts';\n\nexport type Clipboard = {\n nodes: Node[];\n /** Links whose both ends are in `nodes`. */\n links: Link[];\n /** How many times this fragment has been pasted, so each paste lands one step further. */\n pasted: number;\n};\n\n/** The selected nodes and the links joining them; a link is copied whether or not it was selected. */\nexport const copySelection = (scene: Scene, selection: Iterable<ElementId>): Clipboard | undefined => {\n const ids = new Set(selection);\n const nodes = Object.values(scene.nodes).filter((node) => ids.has(node.id));\n const nodeIds = new Set(nodes.map(({ id }) => id));\n // A link comes along when every node end is in the fragment and at least one end is (a free end travels\n // with the node it is drawn to); a link with two free ends comes only when it is selected itself.\n const inFragment = (end: Endpoint) => isPointEndpoint(end) || nodeIds.has(end.node);\n const attached = (end: Endpoint) => !isPointEndpoint(end) && nodeIds.has(end.node);\n const links = Object.values(scene.links).filter(\n (link) =>\n inFragment(link.source) &&\n inFragment(link.target) &&\n (ids.has(link.id) || attached(link.source) || attached(link.target)),\n );\n return nodes.length > 0 ? { nodes, links, pasted: 0 } : undefined;\n};\n\nexport const clipboardBounds = (clipboard: Clipboard): Bounds | undefined =>\n unionBounds(clipboard.nodes.map(nodeBounds));\n\nexport type PasteOptions = {\n clipboard: Clipboard;\n /** Scene-space offset applied to every node and control point. */\n offset: Point;\n createId: (prefix: string) => string;\n /** Z keys for the pasted nodes and links, above the scene. */\n nodeZ: (index: number) => string;\n linkZ: (index: number) => string;\n};\n\nexport type Paste = { intent: Intent; ids: ElementId[] };\n\n/** The batch that recreates the fragment with fresh ids at `offset`, and the ids it will create. */\nexport const pasteFragment = ({ clipboard, offset, createId, nodeZ, linkZ }: PasteOptions): Paste => {\n const idMap = new Map<ElementId, ElementId>();\n const shift = (point: Point): Point => ({ x: point.x + offset.x, y: point.y + offset.y });\n const nodes: Node[] = clipboard.nodes.map((node, index) => {\n const id = createId(node.type);\n idMap.set(node.id, id);\n // A pasted portal shares the child scene: two portals to one scene are Muse \"linked cards\" (§4).\n return { ...node, id, z: nodeZ(index), center: shift(node.center) };\n });\n const links: Link[] = clipboard.links.map((link, index) => {\n const id = createId(link.type);\n idMap.set(link.id, id);\n const remap = (end: Endpoint): Endpoint =>\n isPointEndpoint(end) ? { point: shift(end.point) } : { ...end, node: idMap.get(end.node) ?? end.node };\n const ends = { source: remap(link.source), target: remap(link.target) };\n return link.type === 'spline'\n ? { ...link, id, z: linkZ(index), ...ends, points: link.points.map(shift) }\n : { ...link, id, z: linkZ(index), ...ends };\n });\n return {\n intent: {\n kind: 'batch',\n intents: [\n ...nodes.map((node): Intent => ({ kind: 'create', node })),\n ...links.map((link): Intent => ({ kind: 'link', link })),\n ],\n },\n ids: [...nodes.map(({ id }) => id), ...links.map(({ id }) => id)],\n };\n};\n\n/**\n * The batch that copies the selected nodes (and the links between them) `offset` away, above everything\n * else, and the ids it creates; nothing when the selection holds no node.\n */\nexport const duplicateSelection = (\n scene: Scene,\n selection: Iterable<ElementId>,\n offset: Point,\n createId: (prefix: string) => string,\n): Paste | undefined => {\n const clipboard = copySelection(scene, selection);\n if (!clipboard) {\n return undefined;\n }\n let nodeZ = topZ(Object.values(scene.nodes));\n let linkZ = topZ(Object.values(scene.links));\n return pasteFragment({\n clipboard,\n offset,\n createId,\n nodeZ: () => (nodeZ = between(nodeZ, undefined)),\n linkZ: () => (linkZ = between(linkZ, undefined)),\n });\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The editor's keyboard bindings in one table, so the view matches events against it and the toolbar\n// and palette print the same shortcuts it honours. Tool keys (R, E, L, ...) live on the registry entries\n// and are matched by the palette; everything else is here.\n//\n\n/** One chord: `key` as `KeyboardEvent.key` (letters lower-case), with the modifiers it needs. */\nexport type KeyBinding = {\n key: string;\n /** The platform command key: Meta on macOS, Control elsewhere; either satisfies it. */\n meta?: boolean;\n /** Required when set; ignored when absent, so a chord may be held with or without Shift. */\n shift?: boolean;\n alt?: boolean;\n};\n\nexport type KeyAction =\n | 'cancel'\n | 'delete'\n | 'open'\n | 'fit'\n | 'fitSelection'\n | 'zoomReset'\n | 'back'\n | 'forward'\n | 'nudge'\n | 'copy'\n | 'cut'\n | 'paste'\n | 'undo'\n | 'redo'\n | 'selectAll'\n | 'snap'\n | 'guides'\n | 'lattice'\n | 'debug';\n\n/** Every action's chords; the first is the one shown in labels. */\nexport const KEY_BINDINGS: Record<KeyAction, KeyBinding[]> = {\n cancel: [{ key: 'Escape' }],\n delete: [{ key: 'Delete' }, { key: 'Backspace' }],\n open: [{ key: 'Enter' }],\n fit: [{ key: 'Home' }, { key: '!', shift: true }],\n fitSelection: [{ key: '@', shift: true }],\n zoomReset: [{ key: ')', shift: true }],\n back: [{ key: 'ArrowLeft', alt: true }],\n forward: [{ key: 'ArrowRight', alt: true }],\n nudge: [{ key: 'ArrowUp' }, { key: 'ArrowDown' }, { key: 'ArrowLeft' }, { key: 'ArrowRight' }],\n copy: [{ key: 'c', meta: true }],\n cut: [{ key: 'x', meta: true }],\n paste: [{ key: 'v', meta: true }],\n undo: [{ key: 'z', meta: true, shift: false }],\n redo: [{ key: 'z', meta: true, shift: true }],\n selectAll: [{ key: 'a', meta: true }],\n // Not with Shift: Shift+G is the lattice toggle.\n snap: [{ key: 'g', shift: false }],\n guides: [{ key: ';' }],\n lattice: [{ key: 'G', shift: true }],\n debug: [{ key: 'd' }],\n};\n\n/** The subset of a keyboard event the bindings read, so tests and non-React callers can pass a literal. */\nexport type KeyEventLike = {\n key: string;\n metaKey: boolean;\n ctrlKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n};\n\n/** The command modifier, held: the same test on a pointer event reveals a node's ports for linking. */\nexport const hasCommandKey = (event: { metaKey: boolean; ctrlKey: boolean }): boolean => event.metaKey || event.ctrlKey;\n\nexport const matchesBinding = (event: KeyEventLike, binding: KeyBinding): boolean => {\n const key =\n binding.key.length === 1 ? event.key.toLowerCase() === binding.key.toLowerCase() : event.key === binding.key;\n return (\n key &&\n hasCommandKey(event) === (binding.meta ?? false) &&\n event.altKey === (binding.alt ?? false) &&\n (binding.shift === undefined || event.shiftKey === binding.shift)\n );\n};\n\n/** The action an event asks for, if any; a plain letter that binds no action is left to the tool palette. */\nexport const keyAction = (event: KeyEventLike): KeyAction | undefined => {\n for (const [action, bindings] of Object.entries(KEY_BINDINGS)) {\n if (bindings.some((binding) => matchesBinding(event, binding))) {\n return action as KeyAction;\n }\n }\n return undefined;\n};\n\n/** A key that reaches the tool palette: no command or option modifier, so typing a tool letter is unambiguous. */\nexport const isToolKey = (event: KeyEventLike): boolean => !hasCommandKey(event) && !event.altKey;\n\nconst IS_MAC = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/.test(navigator.platform);\n\nconst KEY_GLYPHS: Record<string, string> = {\n ArrowUp: '↑',\n ArrowDown: '↓',\n ArrowLeft: '←',\n ArrowRight: '→',\n Escape: 'Esc',\n Backspace: '⌫',\n Delete: '⌦',\n Enter: '↩',\n Home: 'Home',\n};\n\n/** The chord as a label reads it: modifiers in the platform's order, then the key. */\nexport const shortcutLabel = (binding: KeyBinding): string => {\n const key = KEY_GLYPHS[binding.key] ?? binding.key.toUpperCase();\n const modifiers = [\n binding.alt ? (IS_MAC ? '⌥' : 'Alt+') : '',\n binding.shift ? (IS_MAC ? '⇧' : 'Shift+') : '',\n binding.meta ? (IS_MAC ? '⌘' : 'Ctrl+') : '',\n ].join('');\n return `${modifiers}${key}`;\n};\n\n/** The label for an action's first chord. */\nexport const shortcutFor = (action: KeyAction): string => shortcutLabel(KEY_BINDINGS[action][0]);\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// The optional editor toolbars (decision 5): every button is an action the view exposes, so a host may\n// render these bars, its own, or none; the palette stays a separate component. They are separate bars so\n// where a control sits says what it does: `NavigationToolbar` says where the view is in the scene tree,\n// `ActionToolbar` changes the scene, and `CameraToolbar` fits and zooms the view beside its own numbers.\n//\n\nimport React, { type ReactNode } from 'react';\n\nimport * as Button from '@dxos/react-ui/Button';\nimport * as Menu from '@dxos/react-ui/Menu';\nimport * as Toolbar from '@dxos/react-ui/Toolbar';\nimport type * as Util from '@dxos/react-ui/Util';\nimport { mx } from '@dxos/ui-theme';\n\nimport { shortcutFor } from '../../model/keys.ts';\nimport { type NodeRegistry } from '../../model/registry.ts';\nimport { type Capabilities, type NodeType, type SceneId } from '../../model/types.ts';\nimport { Breadcrumbs } from '../Breadcrumbs/Breadcrumbs.tsx';\n\n/** What the toolbars can ask of the view; a missing action hides or disables its control. */\nexport type ToolbarActions = {\n /** Navigation: the scene path, a name per scene, and drill-out by path index. */\n path: SceneId[];\n nameOf: (id: SceneId) => string;\n onPath: (index: number) => void;\n fit: () => void;\n zoomIn: () => void;\n zoomOut: () => void;\n snap: boolean;\n toggleSnap: () => void;\n guides: boolean;\n toggleGuides: () => void;\n /** On a lattice scene: whether snap lands on the lattice rather than the basic grid; absent elsewhere. */\n lattice?: boolean;\n toggleLattice?: () => void;\n debug: boolean;\n toggleDebug: () => void;\n canUndo: boolean;\n canRedo: boolean;\n undo: () => void;\n redo: () => void;\n hasSelection: boolean;\n hasClipboard: boolean;\n cut: () => void;\n copy: () => void;\n paste: () => void;\n delete: () => void;\n /** A new node of `type` at the centre of the view. */\n create: (type: NodeType) => void;\n /** Auto layout; absent when the projection does not offer it (`Capabilities.layout`). */\n layout?: () => void;\n};\n\n// A bar fills the frame its host floats it in and scrolls what does not fit; the toolbar's own layout\n// supplies `overflow-x-auto scrollbar-none`, leaving no bar over the diagram.\nconst barClasses = 'w-full gap-1 px-2 py-1 rounded-sm bg-modal-surface border border-separator';\n\nconst readoutClasses = 'text-fg-muted font-mono text-sm whitespace-nowrap';\n\nexport type NavigationToolbarProps = Util.ThemedClassName<{\n actions: ToolbarActions;\n /** Trailing status, e.g. the depth readout. */\n children?: ReactNode;\n}>;\n\n/** Where the view is: the drilled path and the readout that follows it. */\nexport const NavigationToolbar = ({ classNames, actions, children }: NavigationToolbarProps) => {\n const { path } = actions;\n return (\n <Toolbar.Root size='sm' classNames={mx(barClasses, classNames)} data-testid='canvas-toolbar'>\n <Button.Root\n variant='ghost'\n disabled={path.length < 2}\n data-testid='toolbar-up'\n onClick={() => actions.onPath(path.length - 2)}\n >\n Up\n </Button.Root>\n <Breadcrumbs path={path} nameOf={actions.nameOf} onSelect={actions.onPath} />\n {children && (\n <>\n <Toolbar.Separator variant='line' />\n <Toolbar.Text classNames={readoutClasses}>{children}</Toolbar.Text>\n </>\n )}\n </Toolbar.Root>\n );\n};\n\nexport type CameraToolbarProps = Util.ThemedClassName<{ actions: ToolbarActions; children?: ReactNode }>;\n\n/** The camera: fit and zoom, beside its own numbers; nothing here changes the scene. */\nexport const CameraToolbar = ({ classNames, actions, children }: CameraToolbarProps) => {\n return (\n <Toolbar.Root size='sm' classNames={mx(barClasses, classNames)} data-testid='canvas-debug'>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrows-out--regular'\n label={`Fit (${shortcutFor('fit')})`}\n data-testid='toolbar-fit'\n onClick={actions.fit}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--magnifying-glass-plus--regular'\n label='Zoom in'\n data-testid='toolbar-zoom-in'\n onClick={actions.zoomIn}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--magnifying-glass-minus--regular'\n label='Zoom out'\n data-testid='toolbar-zoom-out'\n onClick={actions.zoomOut}\n />\n <Toolbar.Separator variant='line' />\n <Toolbar.Text classNames={readoutClasses}>{children}</Toolbar.Text>\n </Toolbar.Root>\n );\n};\n\nexport type ActionToolbarProps = Util.ThemedClassName<{\n actions: ToolbarActions;\n nodes: NodeRegistry;\n capabilities: Capabilities;\n}>;\n\n/** Everything that changes the scene, plus snap, history, clipboard, creation and debug. */\nexport const ActionToolbar = ({ classNames, actions, nodes, capabilities }: ActionToolbarProps) => {\n return (\n <Toolbar.Root size='sm' classNames={mx(barClasses, classNames)} data-testid='canvas-actions'>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--grid-four--regular'\n label={`Snap (${shortcutFor('snap')}): snap moves, resizes and new nodes to the major grid, or with the lattice on to its cells`}\n classNames={mx(actions.snap && 'bg-primary-500/20')}\n data-testid='toolbar-snap'\n onClick={actions.toggleSnap}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--frame-corners--regular'\n label={`Guides (${shortcutFor('guides')}): show the page frame and the lattice cells`}\n classNames={mx(actions.guides && 'bg-primary-500/20')}\n data-testid='toolbar-guides'\n onClick={actions.toggleGuides}\n />\n {actions.toggleLattice && (\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--squares-four--regular'\n label={`Lattice (${shortcutFor('lattice')}): snap to the lattice's cells rather than the basic grid`}\n classNames={mx(actions.lattice && 'bg-primary-500/20')}\n data-testid='toolbar-lattice'\n onClick={actions.toggleLattice}\n />\n )}\n <Toolbar.Separator variant='line' />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrow-u-up-left--regular'\n label={`Undo (${shortcutFor('undo')})`}\n disabled={!actions.canUndo}\n data-testid='undo'\n onClick={actions.undo}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--arrow-u-up-right--regular'\n label={`Redo (${shortcutFor('redo')})`}\n disabled={!actions.canRedo}\n data-testid='redo'\n onClick={actions.redo}\n />\n <Toolbar.Separator variant='line' />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--scissors--regular'\n label={`Cut (${shortcutFor('cut')})`}\n disabled={!actions.hasSelection || !capabilities.delete}\n data-testid='cut'\n onClick={actions.cut}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--copy--regular'\n label={`Copy (${shortcutFor('copy')})`}\n disabled={!actions.hasSelection}\n data-testid='copy'\n onClick={actions.copy}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--clipboard-text--regular'\n label={`Paste (${shortcutFor('paste')})`}\n disabled={!actions.hasClipboard || !capabilities.create}\n data-testid='paste'\n onClick={actions.paste}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--trash--regular'\n label={`Delete (${shortcutFor('delete')})`}\n disabled={!actions.hasSelection || !capabilities.delete}\n data-testid='toolbar-delete'\n onClick={actions.delete}\n />\n <Toolbar.Separator variant='line' />\n <Menu.Root positioning={{ placement: 'bottom-end', gutter: 4 }}>\n <Menu.Trigger asChild>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--plus--regular'\n label='Create a node at the centre of the view'\n disabled={!capabilities.create}\n data-testid='toolbar-create'\n />\n </Menu.Trigger>\n {/* Portalled: inside the bar's flex flow the items would sit under the readout and the canvas. */}\n <Menu.Content>\n {Object.values(nodes).map((def) => (\n <Menu.Item\n key={def.type}\n data-testid={`create-${def.type}`}\n onSelect={() => actions.create(def.type)}\n item={{ value: def.type, label: def.name }}\n />\n ))}\n </Menu.Content>\n </Menu.Root>\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--tree-structure--regular'\n label={actions.layout ? 'Auto layout' : 'Auto layout (not offered by this projection)'}\n disabled={!actions.layout}\n data-testid='toolbar-layout'\n onClick={actions.layout}\n />\n <Button.Root\n variant='ghost'\n iconOnly\n icon='ph--bug--regular'\n label={`Debug (${shortcutFor('debug')}): label every frame with its id, type and geometry`}\n classNames={mx(actions.debug && 'bg-primary-500/20')}\n data-testid='toolbar-debug'\n onClick={actions.toggleDebug}\n />\n </Toolbar.Root>\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type KeyboardEvent, type MouseEvent, type RefObject } from 'react';\n\nimport { createContext } from '@dxos/react-hooks';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type ControlPointRef, type Drag, type EditingPart, type SceneViewAtoms } from '../../model/atoms.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type LinkRegistry, type NodeRegistry } from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Bounds,\n type Camera,\n type Capabilities,\n type ElementId,\n type Scene,\n type SceneId,\n type Tool,\n} from '../../model/types.ts';\nimport { type Clipboard } from '../../utils/clipboard.ts';\nimport { type ElementHandlers } from '../SceneLayer/SceneLayer.tsx';\nimport { type ToolbarActions } from '../Toolbar/Toolbar.tsx';\nimport { type PointerMachine } from './usePointerMachine.ts';\nimport { type SceneCamera } from './useSceneCamera.ts';\nimport { type SceneClipboard } from './useSceneClipboard.ts';\nimport { type SceneNavigation } from './useSceneNavigation.ts';\n\n/**\n * What `SceneView.Root` composes and every part reads. The parts are a view onto one machine rather than\n * components with state of their own, so the whole of it is here rather than threaded part by part: a\n * toolbar and the canvas act on the same camera, the same selection and the same projection.\n */\nexport type SceneViewContextValue = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n store: SceneStore;\n projection: Projection;\n capabilities: Capabilities;\n nodeRegistry: NodeRegistry;\n linkRegistry: LinkRegistry;\n\n /** The scene as stored, and as it is drawn while a gesture is in flight. */\n scene: Scene;\n displayScene: Scene;\n /** The gesture in flight would be refused by the projection (e.g. an overlap on the lattice). */\n blocked: boolean;\n /** The current scene's frame. */\n bounds: Bounds;\n path: SceneId[];\n camera: Camera;\n /** The zoom against this level's own 1:1 rather than the root's; display only. */\n nominalZoom: number;\n /** The centre of the view in scene coordinates. */\n pointer: { x: number; y: number };\n /** Whether the viewport has been measured; the scene stays hidden until it has. */\n measured: boolean;\n /** One screen pixel in scene units, for chrome that should not grow with the camera. */\n frameUnit: number;\n /** Minor grid spacing in scene px. */\n grid: number;\n snapEnabled: boolean;\n guides: boolean;\n /** On a lattice scene, snap lands on the lattice rather than the basic grid. */\n latticeOn: boolean;\n\n selection: ReadonlySet<ElementId>;\n hover: ElementId | undefined;\n selectedPoint: ControlPointRef | undefined;\n editing: EditingPart | undefined;\n clipboard: Clipboard | undefined;\n drag: Drag | undefined;\n tool: Tool;\n debug: boolean;\n\n /** The bounds a create gesture would land, drawn whether or not the node itself previews. */\n createFrame: Bounds | undefined;\n handlers: ElementHandlers;\n select: (ids: Iterable<ElementId>) => void;\n toolbarActions: ToolbarActions;\n} & Pick<SceneCamera, 'navigating' | 'opening'> &\n Pick<SceneNavigation, 'drillIn'> &\n Pick<SceneClipboard, 'copy' | 'cut' | 'paste'> &\n Pick<\n PointerMachine,\n | 'onBackgroundPointerDown'\n | 'onPointerMove'\n | 'onPointerUp'\n | 'onContextMenu'\n | 'cancelDrag'\n | 'updateHover'\n | 'onHandlePointerDown'\n | 'onPortPointerDown'\n | 'onEndPointerDown'\n | 'onPointPointerDown'\n | 'onMidpointPointerDown'\n | 'onPointContextMenu'\n | 'setTool'\n | 'removePoint'\n | 'menu'\n | 'closeMenu'\n | 'menuAnchorRef'\n > & {\n onDoubleClick: (event: MouseEvent) => void;\n onKeyDown: (event: KeyboardEvent) => void;\n rootRef: RefObject<HTMLDivElement | null>;\n };\n\nexport const [SceneViewProvider, useSceneViewContext] = createContext<SceneViewContextValue>('SceneView.Root');\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Resize geometry as a pure function of the start frame, the handle and the pointer offset, so the\n// view only feeds it the drag and the projection receives one `resize` intent.\n//\n\nimport { type Handle } from '../model/atoms.ts';\nimport { type Bounds, type Point, type Size } from '../model/types.ts';\n\nexport type ResizeOptions = {\n minSize: Size;\n maxSize?: Size;\n /** Both edges of a moved axis move by the same amount, so the centre stays put (shift-drag). */\n symmetric?: boolean;\n /** Snaps a moving edge; the fixed edge (or the centre when symmetric) never moves. */\n snap?: (value: number) => number;\n};\n\nconst identity = (value: number) => value;\n\n/** Resize by a handle: the moving edges land on `snap`, the opposite edges stay put, sizes clamp to the limits. */\nexport const resizeBounds = (\n start: Bounds,\n handle: Handle,\n delta: Point,\n { minSize, maxSize, symmetric = false, snap = identity }: ResizeOptions,\n): Bounds => {\n const horizontal = resizeAxis(\n { origin: start.x, length: start.width },\n { start: handle.includes('w'), end: handle.includes('e') },\n delta.x,\n { min: minSize.width, max: maxSize?.width, symmetric, snap },\n );\n const vertical = resizeAxis(\n { origin: start.y, length: start.height },\n { start: handle.includes('n'), end: handle.includes('s') },\n delta.y,\n { min: minSize.height, max: maxSize?.height, symmetric, snap },\n );\n return { x: horizontal.origin, y: vertical.origin, width: horizontal.length, height: vertical.length };\n};\n\ntype Axis = { origin: number; length: number };\ntype AxisOptions = { min: number; max?: number; symmetric: boolean; snap: (value: number) => number };\n\nconst resizeAxis = (\n axis: Axis,\n moving: { start: boolean; end: boolean },\n delta: number,\n { min, max, symmetric, snap }: AxisOptions,\n): Axis => {\n if (!moving.start && !moving.end) {\n return axis;\n }\n const center = axis.origin + axis.length / 2;\n let start = axis.origin;\n let end = axis.origin + axis.length;\n if (moving.end) {\n end = snap(end + delta);\n }\n if (moving.start) {\n start = snap(start + delta);\n }\n if (symmetric) {\n const half = moving.end ? end - center : center - start;\n const length = clamp(2 * half, min, max);\n return { origin: center - length / 2, length };\n }\n const length = clamp(end - start, min, max);\n return moving.start ? { origin: end - length, length } : { origin: start, length };\n};\n\nconst clamp = (value: number, min: number, max: number | undefined): number =>\n Math.min(Math.max(value, min), max ?? Infinity);\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport {\n type MouseEvent,\n type MutableRefObject,\n type PointerEvent,\n type RefObject,\n useCallback,\n useRef,\n useState,\n} from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type ControlPointRef, type Drag, type Handle, type SceneViewAtoms } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type CreateProps, type NodeRegistry } from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Camera,\n type Capabilities,\n type ElementId,\n type Endpoint,\n type Link,\n type Node,\n type NodeId,\n type NodeType,\n type Point,\n type Port,\n type Scene,\n type SplineLink,\n type Tool,\n endpointNode,\n isPointEndpoint,\n isPortalNode,\n} from '../../model/types.ts';\nimport { boundsCenter, panBy, screenToScene } from '../../utils/camera.ts';\nimport { duplicateSelection } from '../../utils/clipboard.ts';\nimport { boundsFromPoints, hitTest, nodesIntersecting } from '../../utils/hit.ts';\nimport { topZ } from '../../utils/order.ts';\nimport { nodePorts, portAccepts, portPoint } from '../../utils/ports.ts';\nimport { resizeBounds } from '../../utils/resize.ts';\nimport { insertIndex, linkGeometry, sideToward } from '../../utils/route.ts';\nimport { DEFAULT_SIZES, cloneShape, createLink, createNode, nodeBounds } from '../../utils/shapes.ts';\nimport { type LinkEnd, handlePoint } from '../ControlFrame/ControlFrame.tsx';\nimport { type SceneCamera } from './useSceneCamera.ts';\nimport { type SceneSnap } from './useSceneSnap.ts';\n\n/** How near a port the pointer must be, in screen px, for the port rather than the body to take a link. */\nconst PORT_SNAP_PX = 16;\n\n/** The node drawn as a preview during a create drag; it never reaches the model. */\nexport const PREVIEW_NODE_ID = 'preview-node';\n\nexport const createId = (prefix: string) => `${prefix}-${Math.random().toString(36).slice(2, 10)}`;\n\nconst distance = (left: Point, right: Point): [number, number] => [left.x - right.x, left.y - right.y];\n\n/**\n * Whether a link gesture has gone far enough to be a link: at least one grid cell (`minimum`, scene\n * units) from where it started. Short of that it is a click, so it neither previews nor lands.\n */\nexport const isLinkDrawn = ({ from, to }: { from: Point; to: Point }, minimum: number): boolean =>\n Math.hypot(to.x - from.x, to.y - from.y) >= minimum;\n\n/** Whether a link between two endpoints has a direction: either pinned port declares `in` or `out`. */\nconst isDirected = (scene: Scene, registry: NodeRegistry, source: Endpoint, target: Endpoint): boolean =>\n [source, target].some((end) => {\n if (isPointEndpoint(end)) {\n return false;\n }\n const node = scene.nodes[end.node];\n const port = node && nodePorts(registry, node).find((candidate) => candidate.id === end.port);\n return port !== undefined && port.accepts !== undefined && port.accepts !== 'any';\n });\n\nexport type ContextMenu = { at: Point; scene: Point; kind: 'point' | 'element' | 'canvas' };\n\nexport type UsePointerMachineOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n store: SceneStore;\n scene: Scene;\n nodeRegistry: NodeRegistry;\n projection: Projection;\n capabilities: Capabilities;\n camera: Camera;\n rootRef: RefObject<HTMLDivElement | null>;\n /** Set once the user takes the camera over, which stops the view re-fitting itself. */\n interactedRef: MutableRefObject<boolean>;\n select: (ids: Iterable<ElementId>) => void;\n} & Pick<SceneCamera, 'setCamera' | 'cancelAnimation' | 'isNavigating'> &\n Pick<SceneSnap, 'minor' | 'major' | 'snap' | 'snapMinor'>;\n\nexport type PointerMachine = {\n /** Root element handlers. */\n onBackgroundPointerDown: (event: PointerEvent) => void;\n onPointerMove: (event: PointerEvent) => void;\n /** Ends the gesture in flight; `event` is the release (absent for a drop from outside the canvas). */\n onPointerUp: (event?: { clientX: number; clientY: number }) => void;\n onContextMenu: (event: MouseEvent) => void;\n /** A gesture abandoned (Escape, a drag leaving the canvas). */\n cancelDrag: () => void;\n updateHover: (point: Point | undefined) => void;\n\n /** Element handlers, threaded to the layer and the control frame. */\n onNodePointerDown: (node: Node, event: PointerEvent) => void;\n onLinkPointerDown: (link: Link, event: PointerEvent) => void;\n onLinkDoubleClick: (link: Link, event: MouseEvent) => void;\n onLinkContextMenu: (link: Link, event: MouseEvent) => void;\n onHandlePointerDown: (node: Node, handle: Handle, event: PointerEvent) => void;\n onPortPointerDown: (node: Node, port: Port, event: PointerEvent) => void;\n onEndPointerDown: (link: Link, end: LinkEnd, event: PointerEvent) => void;\n onPointPointerDown: (link: SplineLink, index: number, event: PointerEvent) => void;\n onMidpointPointerDown: (link: SplineLink, index: number, point: Point, event: PointerEvent) => void;\n onPointContextMenu: (link: SplineLink, index: number, event: MouseEvent) => void;\n\n setTool: (next: Tool) => void;\n setDrag: (next: Drag | undefined) => void;\n /** A pointer event's position in scene coordinates. */\n toScene: (event: { clientX: number; clientY: number }) => Point;\n removePoint: (point: ControlPointRef) => void;\n\n /** The node a create drag would make; the ghost, the frame and the drop all read it. */\n createdNode: (drag: Extract<Drag, { kind: 'create' }>, id: NodeId) => Node | undefined;\n commitCreated: (node: Node) => void;\n\n menu: ContextMenu | undefined;\n closeMenu: () => void;\n menuAnchorRef: RefObject<HTMLSpanElement | null>;\n};\n\n/**\n * Every gesture the canvas takes: what a press starts, what a move does to the drag in flight, and what a\n * release commits. The drag lives in an atom rather than in React state, so a handler reads the gesture it\n * is continuing rather than the one the last render closed over, and the view renders the drag by\n * projecting it onto a copy of the scene.\n */\nexport const usePointerMachine = ({\n registry,\n atoms,\n store,\n scene,\n nodeRegistry,\n projection,\n capabilities,\n camera,\n rootRef,\n interactedRef,\n select,\n setCamera,\n cancelAnimation,\n isNavigating,\n minor,\n major,\n snap,\n snapMinor,\n}: UsePointerMachineOptions): PointerMachine => {\n const toScene = useCallback(\n (event: { clientX: number; clientY: number }): Point => {\n const rect = rootRef.current?.getBoundingClientRect();\n const camera = registry.get(atoms.camera);\n return screenToScene(camera, { x: event.clientX - (rect?.left ?? 0), y: event.clientY - (rect?.top ?? 0) });\n },\n [registry, atoms.camera, rootRef],\n );\n\n const setDrag = useCallback((next: Drag | undefined) => registry.set(atoms.drag, next), [registry, atoms.drag]);\n\n const setTool = useCallback(\n (next: Tool) => {\n registry.set(atoms.tool, next);\n if (next.kind === 'link') {\n registry.set(atoms.linkType, next.type);\n }\n // A creation tool is about what comes next, so the outgoing selection's outline and handles would\n // only sit over the drawing; the node the gesture makes becomes the selection.\n if (next.kind === 'node' || next.kind === 'link') {\n registry.set(atoms.selection, new Set<ElementId>());\n registry.set(atoms.point, undefined);\n }\n },\n [registry, atoms.tool, atoms.linkType, atoms.selection, atoms.point],\n );\n\n const startDrag = useCallback(\n (next: Drag, event: PointerEvent) => {\n interactedRef.current = true;\n cancelAnimation();\n // A gesture has no hover: the pointer is captured, so the highlight would stick to where it began.\n registry.set(atoms.hover, undefined);\n setDrag(next);\n rootRef.current?.setPointerCapture(event.pointerId);\n },\n [cancelAnimation, setDrag, interactedRef, rootRef, registry, atoms.hover],\n );\n\n const onBackgroundPointerDown = useCallback(\n (event: PointerEvent) => {\n if (event.target !== event.currentTarget) {\n return;\n }\n const currentTool = registry.get(atoms.tool);\n const point = toScene(event);\n if (event.button === 1 || currentTool.kind === 'hand') {\n startDrag({ kind: 'pan', last: { x: event.clientX, y: event.clientY } }, event);\n } else if (event.button !== 0) {\n return;\n } else if (currentTool.kind === 'node') {\n if (capabilities.create) {\n const from = { x: snap(point.x), y: snap(point.y) };\n startDrag({ kind: 'create', type: currentTool.type, from, to: from }, event);\n }\n } else if (currentTool.kind === 'link') {\n // A link tool on empty canvas draws a free-ended link (decision 3); dropping on a node attaches that end.\n if (capabilities.link) {\n startDrag(\n { kind: 'link', type: currentTool.type, source: { point }, from: point, fromSide: 'e', to: point },\n event,\n );\n }\n } else {\n const mode = event.altKey ? 'subtract' : event.shiftKey ? 'add' : 'replace';\n if (mode === 'replace') {\n select([]);\n }\n startDrag({ kind: 'marquee', from: point, to: point, mode }, event);\n }\n },\n [registry, atoms.tool, toScene, startDrag, select, capabilities.create, capabilities.link, snap],\n );\n\n /** Click selection shared by nodes and links: shift toggles, a plain click on an unselected element replaces. */\n const clickSelect = useCallback(\n (id: ElementId, event: PointerEvent): Set<ElementId> => {\n const current = registry.get(atoms.selection);\n const next = new Set(event.shiftKey ? current : current.has(id) ? current : []);\n if (event.shiftKey && current.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n select(next);\n return next;\n },\n [registry, atoms.selection, select],\n );\n\n const onNodePointerDown = useCallback(\n (node: Node, event: PointerEvent) => {\n const currentTool = registry.get(atoms.tool);\n if ((currentTool.kind !== 'select' && currentTool.kind !== 'link') || event.button !== 0) {\n return;\n }\n event.stopPropagation();\n // With a link tool the body is a source like a port is, so a link can be drawn between two shapes\n // without aiming at their dots; the endpoint carries no port and routing picks the side.\n if (currentTool.kind === 'link' && capabilities.link) {\n const from = toScene(event);\n // The band leaves the side of the node the press is nearest; routing picks the real side on drop.\n const fromSide = sideToward(boundsCenter(nodeBounds(node)), from);\n startDrag({ kind: 'link', type: currentTool.type, source: { node: node.id }, from, fromSide, to: from }, event);\n return;\n }\n const next = clickSelect(node.id, event);\n if (capabilities.move && !node.locked) {\n const { x, y } = nodeBounds(node);\n const ids = [...next].filter((id) => scene.nodes[id] !== undefined);\n startDrag(\n { kind: 'move', ids, origin: toScene(event), anchor: { x, y }, delta: { x: 0, y: 0 }, copy: event.metaKey },\n event,\n );\n }\n },\n [registry, atoms.tool, clickSelect, capabilities.move, capabilities.link, scene.nodes, toScene, startDrag],\n );\n\n const onLinkPointerDown = useCallback(\n (link: Link, event: PointerEvent) => {\n const currentTool = registry.get(atoms.tool);\n if (currentTool.kind === 'hand' || event.button !== 0) {\n return;\n }\n event.stopPropagation();\n clickSelect(link.id, event);\n },\n [registry, atoms.tool, clickSelect],\n );\n\n const onHandlePointerDown = useCallback(\n (node: Node, handle: Handle, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.resize) {\n return;\n }\n event.stopPropagation();\n const start = nodeBounds(node);\n startDrag({ kind: 'resize', id: node.id, handle, start, bounds: start }, event);\n },\n [capabilities.resize, startDrag],\n );\n\n const onPortPointerDown = useCallback(\n (node: Node, port: Port, event: PointerEvent) => {\n // A link leaves a port that accepts `out`; an input-only port is a drop target, not a source.\n if (event.button !== 0 || !capabilities.link || !portAccepts(port, 'out')) {\n return;\n }\n event.stopPropagation();\n const from = portPoint(nodeBounds(node), port);\n const currentTool = registry.get(atoms.tool);\n const type = currentTool.kind === 'link' ? currentTool.type : registry.get(atoms.linkType);\n startDrag(\n { kind: 'link', type, source: { node: node.id, port: port.id }, from, fromSide: port.side, to: from },\n event,\n );\n },\n [capabilities.link, registry, atoms.tool, atoms.linkType, startDrag],\n );\n\n const removePoint = useCallback(\n ({ link: id, index }: ControlPointRef) => {\n const link = scene.links[id];\n if (link?.type === 'spline' && capabilities.update) {\n projection.apply({ kind: 'update', id, values: { points: link.points.filter((_, i) => i !== index) } });\n }\n registry.set(atoms.point, undefined);\n },\n [scene.links, capabilities.update, projection, registry, atoms.point],\n );\n\n /** A spline's control point: press selects it, drag moves it, alt-click removes it. */\n const onPointPointerDown = useCallback(\n (link: SplineLink, index: number, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n if (event.altKey) {\n removePoint({ link: link.id, index });\n return;\n }\n registry.set(atoms.point, { link: link.id, index });\n startDrag({ kind: 'point', id: link.id, index, points: [...link.points] }, event);\n },\n [capabilities.update, removePoint, registry, atoms.point, startDrag],\n );\n\n /** The midpoint of a span: pressing it adds a control point there and moves it in the same gesture. */\n const onMidpointPointerDown = useCallback(\n (link: SplineLink, index: number, point: Point, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n registry.set(atoms.point, { link: link.id, index });\n const points = [...link.points.slice(0, index), point, ...link.points.slice(index)];\n startDrag({ kind: 'point', id: link.id, index, points }, event);\n },\n [capabilities.update, registry, atoms.point, startDrag],\n );\n\n // The right-click menu opens at the pointer, anchored to an empty element parked under the cursor\n // (the menu positions itself at a real element); what it offers depends on what was pressed.\n const menuAnchorRef = useRef<HTMLSpanElement>(null);\n const [menu, setMenu] = useState<ContextMenu | undefined>(undefined);\n const closeMenu = useCallback(() => setMenu(undefined), []);\n const openMenu = useCallback(\n (event: MouseEvent, kind: ContextMenu['kind']) => {\n event.preventDefault();\n event.stopPropagation();\n const rect = rootRef.current?.getBoundingClientRect();\n setMenu({\n at: { x: event.clientX - (rect?.left ?? 0), y: event.clientY - (rect?.top ?? 0) },\n scene: toScene(event),\n kind,\n });\n },\n [toScene, rootRef],\n );\n\n const onPointContextMenu = useCallback(\n (link: SplineLink, index: number, event: MouseEvent) => {\n registry.set(atoms.point, { link: link.id, index });\n openMenu(event, 'point');\n },\n [registry, atoms.point, openMenu],\n );\n\n /** Right-click on an element adds it to the selection unless it is already in it, then offers edit actions. */\n const onElementContextMenu = useCallback(\n (id: ElementId, event: MouseEvent) => {\n if (!registry.get(atoms.selection).has(id)) {\n select([id]);\n }\n openMenu(event, 'element');\n },\n [registry, atoms.selection, select, openMenu],\n );\n\n const onLinkContextMenu = useCallback(\n (link: Link, event: MouseEvent) => onElementContextMenu(link.id, event),\n [onElementContextMenu],\n );\n\n const onContextMenu = useCallback(\n (event: MouseEvent) => {\n const node = hitTest(scene, toScene(event));\n if (node) {\n onElementContextMenu(node.id, event);\n } else {\n openMenu(event, 'canvas');\n }\n },\n [scene, toScene, onElementContextMenu, openMenu],\n );\n\n /** Dragging a link's end re-attaches it; the other end stays put and anchors the rubber band. */\n const onEndPointerDown = useCallback(\n (link: Link, end: LinkEnd, event: PointerEvent) => {\n if (event.button !== 0 || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n const geometry = linkGeometry(scene, nodeRegistry, link);\n if (!geometry) {\n return;\n }\n const other = end === 'source' ? geometry.target : geometry.source;\n const to = end === 'source' ? geometry.source.point : geometry.target.point;\n startDrag({ kind: 'end', id: link.id, end, fixed: other.point, fixedSide: other.side, to }, event);\n },\n [capabilities.update, scene, nodeRegistry, startDrag],\n );\n\n /** Double-click on a spline adds a control point there; other link types have no points to edit. */\n const onLinkDoubleClick = useCallback(\n (link: Link, event: MouseEvent) => {\n if (link.type !== 'spline' || !capabilities.update) {\n return;\n }\n event.stopPropagation();\n const geometry = linkGeometry(scene, nodeRegistry, link);\n if (!geometry) {\n return;\n }\n const point = toScene(event);\n const index = insertIndex(geometry.source.point, link.points, geometry.target.point, point);\n const points = [\n ...link.points.slice(0, index),\n { x: snap(point.x), y: snap(point.y) },\n ...link.points.slice(index),\n ];\n projection.apply({ kind: 'update', id: link.id, values: { points } });\n select([link.id]);\n },\n [capabilities.update, scene, nodeRegistry, toScene, snap, projection, select],\n );\n\n /**\n * The drop target for a link end: over a node (with a port-sized margin), the port nearest the pointer\n * among those that accept the end (`in` for a target, `out` for a source); a node with none takes no drop.\n */\n const linkTarget = useCallback(\n (point: Point, exclude: NodeId | undefined, direction: 'in' | 'out'): Endpoint | undefined => {\n const reach = PORT_SNAP_PX / registry.get(atoms.camera).zoom;\n const node = hitTest(scene, point, reach);\n if (!node || node.id === exclude) {\n return undefined;\n }\n const boundsOf = nodeBounds(node);\n let nearest: Port | undefined;\n let best = Infinity;\n for (const candidate of nodePorts(nodeRegistry, node).filter((port) => portAccepts(port, direction))) {\n const value = Math.hypot(...distance(portPoint(boundsOf, candidate), point));\n if (value < best) {\n best = value;\n nearest = candidate;\n }\n }\n // A port claims the drop only while the pointer is within reach of it; anywhere else on the node\n // the link binds to the body, which is also what a node with no port accepting this end takes.\n return nearest && best <= reach ? { node: node.id, port: nearest.id } : { node: node.id };\n },\n [scene, registry, atoms.camera, nodeRegistry],\n );\n\n // Hover comes from the model with a margin, not from the node element, so it survives the pointer\n // crossing onto a port that sits on the frame edge.\n const updateHover = useCallback(\n (point: Point | undefined) => {\n const zoom = registry.get(atoms.camera).zoom;\n const next = point ? hitTest(scene, point, PORT_SNAP_PX / zoom)?.id : undefined;\n if (registry.get(atoms.hover) !== next) {\n registry.set(atoms.hover, next);\n }\n },\n [registry, atoms.camera, atoms.hover, scene],\n );\n\n const onPointerMove = useCallback(\n (event: PointerEvent) => {\n const current = registry.get(atoms.drag);\n if (!current) {\n if (!isNavigating()) {\n updateHover(toScene(event));\n }\n return;\n }\n switch (current.kind) {\n case 'pan': {\n const zoom = registry.get(atoms.camera).zoom;\n setCamera((camera) =>\n panBy(camera, { x: (event.clientX - current.last.x) / zoom, y: (event.clientY - current.last.y) / zoom }),\n );\n setDrag({ ...current, last: { x: event.clientX, y: event.clientY } });\n break;\n }\n case 'marquee':\n case 'create': {\n const point = toScene(event);\n setDrag({ ...current, to: current.kind === 'create' ? { x: snap(point.x), y: snap(point.y) } : point });\n break;\n }\n case 'move': {\n // Snap the pressed node's top-left to the minor grid; the selection moves by the same offset.\n const point = toScene(event);\n const raw = { x: point.x - current.origin.x, y: point.y - current.origin.y };\n setDrag({\n ...current,\n delta: {\n x: snapMinor(current.anchor.x + raw.x) - current.anchor.x,\n y: snapMinor(current.anchor.y + raw.y) - current.anchor.y,\n },\n // Read on every move, so pressing or releasing ⌘ mid-drag switches between moving and copying.\n copy: event.metaKey && capabilities.create === true,\n });\n break;\n }\n case 'resize': {\n const point = toScene(event);\n const anchor = handlePoint(current.start, current.handle);\n const delta = { x: point.x - anchor.x, y: point.y - anchor.y };\n const node = scene.nodes[current.id];\n const def = node && nodeDef(nodeRegistry, node);\n const bounds = resizeBounds(current.start, current.handle, delta, {\n minSize: def?.minSize ?? { width: major, height: major },\n maxSize: def?.maxSize,\n symmetric: event.shiftKey,\n // The moving edge lands on the minor grid, as a move does: a node's size is no coarser than\n // its position, while a new node still arrives on the major one.\n snap: snapMinor,\n });\n setDrag({ ...current, bounds });\n break;\n }\n case 'link': {\n // The band follows the pointer exactly; it snaps as it lands (`settle`). A free source keeps\n // facing the far end.\n const point = toScene(event);\n const target = linkTarget(point, endpointNode(current.source), 'in');\n const fromSide = isPointEndpoint(current.source) ? sideToward(current.from, point) : current.fromSide;\n setDrag({ ...current, to: point, fromSide, target });\n break;\n }\n case 'point': {\n // A control point moves on the minor grid, as a node does; the double-click that adds one is a\n // creation and stays on the major grid.\n const point = toScene(event);\n const points = [...current.points];\n points[current.index] = { x: snapMinor(point.x), y: snapMinor(point.y) };\n setDrag({ ...current, points });\n break;\n }\n case 'end': {\n const point = toScene(event);\n const link = scene.links[current.id];\n const other = link ? endpointNode(current.end === 'source' ? link.target : link.source) : undefined;\n const target = linkTarget(point, other, current.end === 'source' ? 'out' : 'in');\n setDrag({ ...current, to: point, target });\n break;\n }\n }\n },\n [\n registry,\n atoms.drag,\n atoms.camera,\n setCamera,\n setDrag,\n toScene,\n snap,\n snapMinor,\n scene.nodes,\n scene.links,\n nodeRegistry,\n major,\n linkTarget,\n updateHover,\n isNavigating,\n capabilities.create,\n ],\n );\n\n /**\n * A link band follows the pointer exactly while it is drawn; this is where its free ends snap to the\n * major grid, once, as it lands. An end dropped on a node keeps the node.\n */\n const settle = useCallback(\n (current: Drag): Drag => {\n const snapPoint = (point: Point): Point => ({ x: snap(point.x), y: snap(point.y) });\n switch (current.kind) {\n case 'link': {\n const free = isPointEndpoint(current.source);\n const from = free ? snapPoint(current.from) : current.from;\n return {\n ...current,\n from,\n source: free ? { point: from } : current.source,\n to: current.target ? current.to : snapPoint(current.to),\n };\n }\n case 'end':\n return current.target ? current : { ...current, to: snapPoint(current.to) };\n default:\n return current;\n }\n },\n [snap],\n );\n\n // The node the current create gesture made, re-framed by every ghost frame and by the drop, so a\n // definition whose `create` has effects (a trigger mints an object) runs it once, for the node that lands.\n const pendingRef = useRef<{ type: NodeType; node: Node } | undefined>(undefined);\n\n /**\n * The node a create drag would make: what was drawn, or the type's default size at the press when the\n * drag was a click. Shared by the ghost preview and the drop, so the preview is what lands.\n */\n const createdNode = useCallback(\n (drag: Extract<Drag, { kind: 'create' }>, id: NodeId): Node | undefined => {\n const def = nodeRegistry[drag.type];\n if (!def) {\n return undefined;\n }\n const drawn = boundsFromPoints(drag.from, drag.to);\n // Dropped from the palette there is no drawn box, so the type's default size stands in, in scene\n // units whatever the zoom. A box drawn on the canvas is exactly what the pointer swept:\n // it follows the cursor as the frame shows it, and a gesture that snapped to nothing creates nothing\n // rather than planting a default-sized node under the click.\n if (!drag.dropped && (drawn.width === 0 || drawn.height === 0)) {\n return undefined;\n }\n const size = drag.dropped ? { ...def.defaultSize } : { ...drawn };\n const center = drag.dropped\n ? { x: drag.from.x + size.width / 2, y: drag.from.y + size.height / 2 }\n : { x: drawn.x + drawn.width / 2, y: drawn.y + drawn.height / 2 };\n const props: CreateProps = { id, z: topZ(Object.values(scene.nodes)), center, size };\n const pending = pendingRef.current;\n // No `fontSize`: a new node inherits the view's default, as one created by dropping a link does.\n const node: Node = pending?.type === drag.type ? { ...pending.node, ...props } : def.create(props);\n pendingRef.current = { type: drag.type, node };\n return node;\n },\n [nodeRegistry, scene.nodes],\n );\n\n /** Adds a new node; a new portal opens onto a fresh scene of its own, whichever path created it. */\n const addNode = useCallback(\n (node: Node) => {\n if (isPortalNode(node)) {\n registry.set(store.scenes, {\n ...registry.get(store.scenes),\n [node.scene]: { id: node.scene, name: 'Untitled', nodes: {}, links: {} },\n });\n }\n projection.apply({ kind: 'create', node });\n },\n [projection, registry, store],\n );\n\n /** The node the gesture made, committed: the next gesture starts from a fresh `create`. */\n const commitCreated = useCallback(\n (node: Node) => {\n pendingRef.current = undefined;\n addNode(node);\n select([node.id]);\n },\n [addNode, select],\n );\n\n /** A gesture abandoned (Escape, a drag leaving the canvas): its pending node is dropped with it. */\n const cancelDrag = useCallback(() => {\n pendingRef.current = undefined;\n setDrag(undefined);\n }, [setDrag]);\n\n const onPointerUp = useCallback(\n (event?: { clientX: number; clientY: number }) => {\n const raw = registry.get(atoms.drag);\n if (!raw) {\n return;\n }\n setDrag(undefined);\n // Hover is not tracked during a captured drag, so it still names the node the gesture started on;\n // re-read it where the pointer was released.\n updateHover(event ? toScene(event) : undefined);\n const current = settle(raw);\n switch (current.kind) {\n case 'marquee': {\n const hits = nodesIntersecting(scene, boundsFromPoints(current.from, current.to)).map(({ id }) => id);\n const previous = registry.get(atoms.selection);\n select(\n current.mode === 'add'\n ? [...previous, ...hits]\n : current.mode === 'subtract'\n ? [...previous].filter((id) => !hits.includes(id))\n : hits,\n );\n break;\n }\n case 'move': {\n if (current.delta.x === 0 && current.delta.y === 0) {\n break;\n }\n // ⌘-drag leaves the selection where it was and drops a copy, which becomes the selection.\n const copy = current.copy ? duplicateSelection(scene, current.ids, current.delta, createId) : undefined;\n if (copy) {\n projection.apply(copy.intent);\n select(copy.ids);\n } else {\n projection.apply({ kind: 'move', ids: current.ids, delta: current.delta });\n }\n break;\n }\n case 'resize': {\n projection.apply({ kind: 'resize', id: current.id, bounds: current.bounds });\n break;\n }\n case 'link': {\n // A press that moved less than a grid cell is a click, not a link: with a link tool selected,\n // pressing and releasing draws nothing. Read from the raw gesture, since settling has already\n // snapped the landing point away from it.\n if (raw.kind === 'link' && !isLinkDrawn(raw, minor)) {\n // A click on the background with a link tool is a way out of the tool, as Escape is.\n if (isPointEndpoint(raw.source)) {\n setTool({ kind: 'select' });\n }\n break;\n }\n let target = current.target;\n if (!target && isPointEndpoint(current.source)) {\n // A free-ended link that never reached a node ends free too.\n target = { point: current.to };\n } else if (!target && capabilities.create) {\n // Dropping a link drag on empty canvas creates a node there and links to it (canvas-editor\n // behaviour): a copy of the shape it left, without its text, else a rectangle. Its top-left is\n // what snaps, so the edges land on the grid.\n const source = scene.nodes[endpointNode(current.source) ?? ''];\n const def = source ? nodeRegistry[source.type] : undefined;\n const size = source?.size ?? DEFAULT_SIZES.rect;\n const props = {\n id: createId(source?.type ?? 'rect'),\n z: topZ(Object.values(scene.nodes)),\n center: {\n x: snap(current.to.x - size.width / 2) + size.width / 2,\n y: snap(current.to.y - size.height / 2) + size.height / 2,\n },\n size,\n };\n const node = source && def ? cloneShape(source, def.create(props)) : createNode({ type: 'rect', ...props });\n addNode(node);\n target = { node: node.id };\n }\n if (target) {\n const link = createLink({\n type: current.type,\n id: createId(current.type),\n z: topZ(Object.values(scene.links)),\n source: current.source,\n target,\n midpoint: { x: snap((current.from.x + current.to.x) / 2), y: snap((current.from.y + current.to.y) / 2) },\n // A link between ports that declare a direction is drawn with one.\n directed: isDirected(scene, nodeRegistry, current.source, target),\n });\n projection.apply({ kind: 'link', link });\n // The new link is what the user just made, so it is what they act on next (style, delete).\n select([link.id]);\n }\n break;\n }\n case 'create': {\n const node = createdNode(current, createId(current.type));\n if (!node) {\n break;\n }\n commitCreated(node);\n setTool({ kind: 'select' });\n break;\n }\n case 'point': {\n projection.apply({ kind: 'update', id: current.id, values: { points: current.points } });\n break;\n }\n case 'end': {\n // Dropped on a node it attaches there; dropped on empty canvas it becomes a free end at that point.\n const end: Endpoint = current.target ?? { point: current.to };\n projection.apply({ kind: 'update', id: current.id, values: { [current.end]: end } });\n break;\n }\n case 'pan':\n break;\n }\n },\n [\n registry,\n atoms.drag,\n updateHover,\n toScene,\n atoms.selection,\n setDrag,\n scene,\n select,\n projection,\n capabilities.create,\n snap,\n settle,\n nodeRegistry,\n setTool,\n createdNode,\n commitCreated,\n addNode,\n minor,\n ],\n );\n\n return {\n onBackgroundPointerDown,\n onPointerMove,\n onPointerUp,\n onContextMenu,\n cancelDrag,\n updateHover,\n\n onNodePointerDown,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n\n setTool,\n setDrag,\n toScene,\n removePoint,\n\n createdNode,\n commitCreated,\n\n menu,\n closeMenu,\n menuAnchorRef,\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { type Camera, type ElementId, type Size } from '../../model/types.ts';\nimport { animateCamera } from '../../utils/camera.ts';\n\n/** Quiet time after the last wheel step before the canvas takes pointer events again. */\nconst NAVIGATION_SETTLE_MS = 150;\n\nexport type SceneCamera = {\n /** Write the camera, from a value or from its predecessor. */\n setCamera: (next: Camera | ((camera: Camera) => Camera)) => void;\n /** Animate to `target`, calling `done` when the last frame lands. */\n animateTo: (target: Camera, done?: () => void) => void;\n /** Abandon an animation in flight, leaving the camera where it reached. */\n cancelAnimation: () => void;\n /** The camera is moving on its own, so the canvas ignores the pointer. */\n navigating: boolean;\n /** The same, read at call time: a handler closes over the render's value, which is a frame behind. */\n isNavigating: () => boolean;\n /** Whether an animation is in flight, read at call time for the same reason. */\n isAnimating: () => boolean;\n setNavigation: (active: boolean) => void;\n /** Navigation that ends on its own: active until no further step arrives for a beat. */\n touchNavigation: () => void;\n /** The portal a drill-in is zooming into, while it is. */\n opening: ElementId | undefined;\n setOpening: (id: ElementId | undefined) => void;\n};\n\n/**\n * The camera and the animations that move it. While the camera moves on its own — a wheel zoom, a pan,\n * a drill-in — the canvas ignores the pointer: nothing under it is where it will be, so hover and\n * presses would land on passing content.\n */\nexport const useSceneCamera = (\n registry: ReturnType<typeof useRegistry>,\n atoms: SceneViewAtoms,\n viewport: Size,\n): SceneCamera => {\n const setCamera = useCallback(\n (next: Camera | ((camera: Camera) => Camera)) => {\n registry.set(atoms.camera, typeof next === 'function' ? next(registry.get(atoms.camera)) : next);\n },\n [registry, atoms.camera],\n );\n\n // Cleared as well as called: a cancelled frame never runs the completion callback that would.\n const cancelRef = useRef<() => void>(undefined);\n const [opening, setOpening] = useState<ElementId>();\n const [navigating, setNavigating] = useState(false);\n const navigatingRef = useRef(false);\n const settleRef = useRef<ReturnType<typeof setTimeout>>(undefined);\n\n const setNavigation = useCallback(\n (active: boolean) => {\n clearTimeout(settleRef.current);\n settleRef.current = undefined;\n if (navigatingRef.current !== active) {\n navigatingRef.current = active;\n setNavigating(active);\n if (active) {\n registry.set(atoms.hover, undefined);\n }\n }\n },\n [registry, atoms.hover],\n );\n\n const touchNavigation = useCallback(() => {\n setNavigation(true);\n settleRef.current = setTimeout(() => setNavigation(false), NAVIGATION_SETTLE_MS);\n }, [setNavigation]);\n useEffect(() => () => clearTimeout(settleRef.current), []);\n\n const cancelAnimation = useCallback(() => {\n if (cancelRef.current) {\n cancelRef.current();\n cancelRef.current = undefined;\n setNavigation(false);\n }\n setOpening(undefined);\n }, [setNavigation]);\n\n const animateTo = useCallback(\n (target: Camera, done?: () => void) => {\n cancelAnimation();\n setNavigation(true);\n cancelRef.current = animateCamera(registry.get(atoms.camera), target, viewport, setCamera, () => {\n cancelRef.current = undefined;\n setNavigation(false);\n done?.();\n });\n },\n [registry, atoms.camera, viewport, setCamera, cancelAnimation, setNavigation],\n );\n\n const isNavigating = useCallback(() => navigatingRef.current, []);\n const isAnimating = useCallback(() => cancelRef.current !== undefined, []);\n\n return {\n setCamera,\n animateTo,\n cancelAnimation,\n navigating,\n isNavigating,\n isAnimating,\n setNavigation,\n touchNavigation,\n opening,\n setOpening,\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type Capabilities, type ElementId, type Point, type Scene } from '../../model/types.ts';\nimport { clipboardBounds, copySelection, pasteFragment } from '../../utils/clipboard.ts';\nimport { between, topZ } from '../../utils/order.ts';\nimport { type SceneSnap } from './useSceneSnap.ts';\n\nexport type UseSceneClipboardOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n scene: Scene;\n projection: Projection;\n capabilities: Capabilities;\n select: (ids: Iterable<ElementId>) => void;\n createId: (prefix: string) => string;\n} & Pick<SceneSnap, 'major' | 'snap'>;\n\nexport type SceneClipboard = {\n /** Whether anything was copied: a cut only deletes once the fragment is safely in the clipboard. */\n copy: () => boolean;\n cut: () => void;\n paste: (at?: Point) => void;\n};\n\n/**\n * Copy, cut and paste over the scene's own clipboard atom rather than the system one, so a fragment keeps\n * its links and z keys. Pasting repeatedly walks the copy away from the original instead of stacking it.\n */\nexport const useSceneClipboard = ({\n registry,\n atoms,\n scene,\n projection,\n capabilities,\n select,\n createId,\n major,\n snap,\n}: UseSceneClipboardOptions): SceneClipboard => {\n const copy = useCallback(() => {\n const fragment = copySelection(scene, registry.get(atoms.selection));\n if (fragment) {\n registry.set(atoms.clipboard, fragment);\n }\n return fragment !== undefined;\n }, [scene, registry, atoms.selection, atoms.clipboard]);\n\n const cut = useCallback(() => {\n if (!capabilities.delete || !copy()) {\n return;\n }\n projection.apply({ kind: 'delete', ids: [...registry.get(atoms.selection)] });\n select([]);\n }, [capabilities.delete, copy, projection, registry, atoms.selection, select]);\n\n /** Paste one grid step further each time, or with the fragment's top-left at `at` when given. */\n const paste = useCallback(\n (at?: Point) => {\n const fragment = registry.get(atoms.clipboard);\n if (!fragment || !capabilities.create) {\n return;\n }\n const bounds = clipboardBounds(fragment);\n const step = major * (fragment.pasted + 1);\n const offset = at && bounds ? { x: snap(at.x) - bounds.x, y: snap(at.y) - bounds.y } : { x: step, y: step };\n let nodeZ = topZ(Object.values(scene.nodes));\n let linkZ = topZ(Object.values(scene.links));\n const { intent, ids } = pasteFragment({\n clipboard: fragment,\n offset,\n createId,\n nodeZ: () => (nodeZ = between(nodeZ, undefined)),\n linkZ: () => (linkZ = between(linkZ, undefined)),\n });\n projection.apply(intent);\n registry.set(atoms.clipboard, { ...fragment, pasted: at ? fragment.pasted : fragment.pasted + 1 });\n select(ids);\n },\n [\n registry,\n atoms.clipboard,\n capabilities.create,\n major,\n snap,\n scene.nodes,\n scene.links,\n projection,\n select,\n createId,\n ],\n );\n\n return { copy, cut, paste };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type KeyboardEvent, useCallback } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type SceneViewAtoms } from '../../model/atoms.ts';\nimport { isToolKey, keyAction } from '../../model/keys.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport { type Projection } from '../../model/projection.ts';\nimport { type LinkRegistry, type NodeRegistry } from '../../model/registry.ts';\nimport { type Bounds, type Capabilities, type ElementId, type Scene, type Size } from '../../model/types.ts';\nimport { fitBounds, zoomAt } from '../../utils/camera.ts';\nimport { unionBounds } from '../../utils/hit.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\nimport { toolForKey } from '../Palette/Palette.tsx';\nimport { type PointerMachine } from './usePointerMachine.ts';\nimport { type SceneCamera } from './useSceneCamera.ts';\nimport { type SceneClipboard } from './useSceneClipboard.ts';\nimport { type SceneNavigation } from './useSceneNavigation.ts';\nimport { type SceneSnap } from './useSceneSnap.ts';\n\nexport type UseSceneKeysOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n scene: Scene;\n nodeRegistry: NodeRegistry;\n linkRegistry: LinkRegistry;\n projection: Projection;\n capabilities: Capabilities;\n viewport: Size;\n /** The current scene's frame, which `fit` frames. */\n bounds: Bounds;\n /** Least gap between that frame and a viewport edge when fitting, in scene units. */\n inset: number;\n /** Minor grid spacing in scene px; an arrow nudges by it. */\n grid: number;\n select: (ids: Iterable<ElementId>) => void;\n toggleSnap: () => void;\n toggleGuides: () => void;\n toggleLattice: () => void;\n toggleDebug: () => void;\n onUndo: () => void;\n onRedo: () => void;\n} & Pick<SceneCamera, 'animateTo'> &\n Pick<SceneNavigation, 'drillIn' | 'drillOut' | 'goHistory'> &\n Pick<SceneSnap, 'major'> &\n Pick<SceneClipboard, 'copy' | 'cut' | 'paste'> &\n Pick<PointerMachine, 'cancelDrag' | 'removePoint' | 'setTool'>;\n\n/**\n * What a chord does in the state the view is in. Every chord itself comes from `KEY_BINDINGS`, so this\n * decides only what the action means here — Escape backs out of whatever is innermost (a drag, then a\n * selected control point, then the selection, then the scene itself), and Delete reads the same way.\n */\nexport const useSceneKeys = ({\n registry,\n atoms,\n scene,\n nodeRegistry,\n linkRegistry,\n projection,\n capabilities,\n viewport,\n bounds,\n inset,\n grid,\n select,\n toggleSnap,\n toggleGuides,\n toggleLattice,\n toggleDebug,\n onUndo,\n onRedo,\n animateTo,\n drillIn,\n drillOut,\n goHistory,\n major,\n copy,\n cut,\n paste,\n cancelDrag,\n removePoint,\n setTool,\n}: UseSceneKeysOptions): ((event: KeyboardEvent) => void) => {\n return useCallback(\n (event: KeyboardEvent) => {\n const selected = [...registry.get(atoms.selection)];\n const selectedNodes = selected.filter((id) => scene.nodes[id] !== undefined);\n const point = registry.get(atoms.point);\n const action = keyAction(event);\n switch (action) {\n case 'cancel':\n if (registry.get(atoms.drag)) {\n cancelDrag();\n } else if (point) {\n registry.set(atoms.point, undefined);\n } else if (selected.length > 0) {\n select([]);\n } else {\n drillOut();\n }\n break;\n case 'delete':\n if (point) {\n removePoint(point);\n } else if (selected.length > 0 && capabilities.delete) {\n projection.apply({ kind: 'delete', ids: selected });\n select([]);\n }\n break;\n case 'open': {\n const node = selected.length === 1 ? scene.nodes[selected[0]] : undefined;\n if (node && nodeDef(nodeRegistry, node)?.openable) {\n drillIn(node);\n }\n break;\n }\n case 'fit':\n animateTo(fitBounds(bounds, viewport, inset));\n event.preventDefault();\n break;\n case 'fitSelection': {\n const union = unionBounds(selectedNodes.map((id) => nodeBounds(scene.nodes[id])));\n if (union) {\n animateTo(fitBounds(union, viewport, inset));\n }\n break;\n }\n case 'zoomReset':\n animateTo(zoomAt(registry.get(atoms.camera), { x: viewport.width / 2, y: viewport.height / 2 }, 1));\n break;\n case 'back':\n goHistory(-1);\n break;\n case 'forward':\n goHistory(1);\n break;\n case 'nudge': {\n if (selectedNodes.length === 0 || !capabilities.move) {\n break;\n }\n // Shift moves by a major cell rather than a minor one.\n const step = event.shiftKey ? major : grid;\n const delta = {\n x: event.key === 'ArrowLeft' ? -step : event.key === 'ArrowRight' ? step : 0,\n y: event.key === 'ArrowUp' ? -step : event.key === 'ArrowDown' ? step : 0,\n };\n projection.apply({ kind: 'move', ids: selectedNodes, delta });\n event.preventDefault();\n break;\n }\n case 'copy':\n copy();\n event.preventDefault();\n break;\n case 'cut':\n cut();\n event.preventDefault();\n break;\n case 'paste':\n paste();\n event.preventDefault();\n break;\n case 'undo':\n onUndo();\n event.preventDefault();\n break;\n case 'redo':\n onRedo();\n event.preventDefault();\n break;\n case 'selectAll':\n select([...Object.keys(scene.nodes), ...Object.keys(scene.links)]);\n event.preventDefault();\n break;\n case 'snap':\n toggleSnap();\n break;\n case 'guides':\n toggleGuides();\n break;\n case 'lattice':\n toggleLattice();\n break;\n case 'debug':\n toggleDebug();\n break;\n case undefined:\n if (isToolKey(event)) {\n const next = toolForKey(nodeRegistry, linkRegistry, capabilities, event.key);\n if (next) {\n setTool(next);\n }\n }\n break;\n }\n },\n [\n registry,\n atoms.selection,\n atoms.drag,\n atoms.camera,\n atoms.point,\n removePoint,\n cancelDrag,\n select,\n drillOut,\n drillIn,\n capabilities,\n projection,\n scene,\n nodeRegistry,\n linkRegistry,\n animateTo,\n bounds,\n viewport,\n inset,\n goHistory,\n grid,\n major,\n setTool,\n toggleSnap,\n toggleGuides,\n toggleLattice,\n toggleDebug,\n onUndo,\n onRedo,\n copy,\n cut,\n paste,\n ],\n );\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { type MutableRefObject, useCallback, useEffect, useMemo, useRef } from 'react';\n\nimport { type useRegistry } from '../../hooks/index.ts';\nimport { type Drag, type HistoryEntry, type SceneViewAtoms } from '../../model/atoms.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n type Bounds,\n type Camera,\n type ElementId,\n type Node,\n type Scene,\n type SceneId,\n type Size,\n isPortalNode,\n} from '../../model/types.ts';\nimport { coverage, enterPortal, exitPortal, fitBounds, portalFrame, portalScale } from '../../utils/camera.ts';\nimport { contentBounds, sceneBounds } from '../../utils/hit.ts';\nimport { nodeBounds } from '../../utils/shapes.ts';\nimport { type SceneCamera } from './useSceneCamera.ts';\n\n/** A portal covering this much of the viewport becomes the root; a root below this yields to its parent. */\nconst AUTO_ENTER = 0.85;\nconst AUTO_EXIT = 0.3;\nconst AUTO_DRILL_MS = 150;\n\nexport type UseSceneNavigationOptions = {\n registry: ReturnType<typeof useRegistry>;\n atoms: SceneViewAtoms;\n store: SceneStore;\n scenes: Record<SceneId, Scene>;\n scene: Scene;\n path: SceneId[];\n camera: Camera;\n viewport: Size;\n /** Least gap between the scene's frame and a viewport edge when fitting, in scene units. */\n inset: number;\n drag: Drag | undefined;\n /** Set once the user takes the camera over, which stops the view re-fitting itself. */\n interactedRef: MutableRefObject<boolean>;\n select: (ids: Iterable<ElementId>) => void;\n} & Pick<SceneCamera, 'animateTo' | 'setCamera' | 'setOpening' | 'isAnimating'>;\n\nexport type SceneNavigation = {\n nameOf: (id: SceneId) => string;\n /** The portal in `parent` that shows `childId`, if any. */\n portalTo: (parentId: SceneId | undefined, childId: SceneId) => Node | undefined;\n /** The frame of the scene at the head of `path`: its parent portal's frame, or its derived bounds. */\n frameOf: (path: SceneId[], scene: Scene) => Bounds;\n /** The current scene's frame, held for the visit rather than re-derived as its content changes. */\n bounds: Bounds;\n /** The zoom against this level's own 1:1 rather than the root's; display only. */\n nominalZoom: number;\n pushHistory: (entry: HistoryEntry) => void;\n drillIn: (portal: Node, animate?: boolean) => void;\n drillOut: (levels?: number, animate?: boolean) => void;\n goHistory: (offset: number) => void;\n};\n\n/**\n * Moving between scenes: the path, the frame each level is seen through, and the drill in and out that\n * swap the root under a camera transition. Auto-drill lives here too, since it is the same two moves\n * driven by how much of the viewport a portal covers rather than by a gesture.\n */\nexport const useSceneNavigation = ({\n registry,\n atoms,\n scenes,\n scene,\n path,\n camera,\n viewport,\n inset,\n drag,\n interactedRef,\n select,\n animateTo,\n setCamera,\n setOpening,\n isAnimating,\n}: UseSceneNavigationOptions): SceneNavigation => {\n const nameOf = useCallback((id: SceneId) => scenes[id]?.name ?? id, [scenes]);\n\n const portalTo = useCallback(\n (parentId: SceneId | undefined, childId: SceneId): Node | undefined => {\n const parent = parentId ? scenes[parentId] : undefined;\n return parent\n ? Object.values(parent.nodes).find((node) => isPortalNode(node) && node.scene === childId)\n : undefined;\n },\n [scenes],\n );\n\n const frameOf = useCallback(\n (scenePath: SceneId[], current: Scene): Bounds => {\n const portal = portalTo(scenePath[scenePath.length - 2], current.id);\n return portal ? portalFrame(portal, contentBounds(current)) : sceneBounds(current);\n },\n [portalTo],\n );\n\n // A scene entered through a portal keeps the frame it arrived with. Deriving it from the content on\n // every edit moves the child under the user as they work, and maps a drill-out differently from the\n // drill-in that opened it; the root has no portal to sit in, so its bounds stay derived.\n const frameRef = useRef<{ key: string; frame: Bounds } | undefined>(undefined);\n const bounds = useMemo(() => {\n if (path.length < 2) {\n frameRef.current = undefined;\n return frameOf(path, scene);\n }\n const key = path.join(' ');\n if (frameRef.current?.key !== key) {\n frameRef.current = { key, frame: frameOf(path, scene) };\n }\n return frameRef.current.frame;\n }, [frameOf, path, scene]);\n\n /**\n * A portal frame is the portal's box times a power of the grid ratio, so entering one divides the\n * camera by that factor; reported raw, the number would drop fourfold on a drill-in that changed\n * nothing the user can see. Display only — nothing derives geometry from it, so the frame growing\n * with its content cannot feed back.\n */\n const nominalZoom = useMemo(() => {\n const scale = path.slice(1).reduce((accumulated, sceneId, index) => {\n const parent = scenes[path[index]];\n const child = scenes[sceneId];\n const portal = parent && child ? portalTo(parent.id, sceneId) : undefined;\n return portal && child\n ? accumulated * portalScale(portal, portalFrame(portal, contentBounds(child)))\n : accumulated;\n }, 1);\n return camera.zoom / scale;\n }, [path, scenes, portalTo, camera.zoom]);\n\n const pushHistory = useCallback(\n (entry: HistoryEntry) => {\n const history = registry.get(atoms.history);\n const entries = [...history.entries.slice(0, history.index + 1), entry];\n registry.set(atoms.history, { entries, index: entries.length - 1 });\n },\n [registry, atoms.history],\n );\n\n const drillIn = useCallback(\n (portal: Node, animate = true) => {\n const child = isPortalNode(portal) ? scenes[portal.scene] : undefined;\n if (!child) {\n return;\n }\n interactedRef.current = true;\n // The zoom is into the child, so the portal's selection outline and ports go before it starts.\n select([]);\n registry.set(atoms.hover, undefined);\n registry.set(atoms.editing, undefined);\n const childBounds = portalFrame(portal, contentBounds(child));\n const swap = (next: Camera) => {\n const entered = enterPortal(next, portal, childBounds);\n registry.set(atoms.path, [...registry.get(atoms.path), child.id]);\n setCamera(entered);\n setOpening(undefined);\n pushHistory({ path: registry.get(atoms.path), camera: entered });\n };\n if (animate) {\n // Land the child where fitting it would, margin and all, but never past 1:1, so its text lands at\n // its natural size rather than magnified to fill the view. Expressed in the child's own space and\n // mapped back out, so the zoom ends exactly where the swap puts the camera.\n const target = exitPortal(fitBounds(childBounds, viewport, inset, 1), portal, childBounds);\n animateTo(target, () => swap(target));\n setOpening(portal.id);\n } else {\n swap(registry.get(atoms.camera));\n }\n },\n [\n scenes,\n registry,\n atoms.path,\n atoms.camera,\n atoms.hover,\n atoms.editing,\n viewport,\n inset,\n interactedRef,\n animateTo,\n setCamera,\n setOpening,\n select,\n pushHistory,\n ],\n );\n\n const drillOut = useCallback(\n (levels = 1, animate = true) => {\n const current = registry.get(atoms.path);\n if (current.length < 2 || levels < 1) {\n return;\n }\n let next = current;\n let exited = registry.get(atoms.camera);\n for (let level = 0; level < levels && next.length > 1; level++) {\n const child = scenes[next[next.length - 1]];\n const parent = scenes[next[next.length - 2]];\n const portal = parent\n ? Object.values(parent.nodes).find((node) => isPortalNode(node) && node.scene === child?.id)\n : undefined;\n if (!child || !portal) {\n break;\n }\n // The level being left exits through the frame it was entered with, so the camera lands where\n // the drill-in took it from however the child was edited in between.\n exited = exitPortal(exited, portal, level === 0 ? bounds : portalFrame(portal, contentBounds(child)));\n next = next.slice(0, -1);\n }\n registry.set(atoms.path, next);\n select([]);\n setCamera(exited);\n const parent = scenes[next[next.length - 1]];\n if (animate && parent) {\n animateTo(fitBounds(frameOf(next, parent), viewport, inset));\n }\n pushHistory({ path: next, camera: exited });\n },\n [\n registry,\n atoms.path,\n atoms.camera,\n scenes,\n viewport,\n inset,\n animateTo,\n setCamera,\n select,\n pushHistory,\n frameOf,\n bounds,\n ],\n );\n\n const goHistory = useCallback(\n (offset: number) => {\n const history = registry.get(atoms.history);\n const index = history.index + offset;\n const entry = history.entries[index];\n if (!entry) {\n return;\n }\n registry.set(atoms.history, { ...history, index });\n registry.set(atoms.path, entry.path);\n select([]);\n animateTo(entry.camera);\n },\n [registry, atoms.history, atoms.path, select, animateTo],\n );\n\n // Auto drill: a portal filling the viewport becomes the root; a root shrunk well below its size on\n // arrival yields to its parent. Arrival is the history entry for this path, so a child capped at 1:1\n // (or a frame that shrinks under a stationary camera) is measured against itself rather than an\n // absolute coverage.\n useEffect(() => {\n if (isAnimating() || drag || viewport.width === 0) {\n return;\n }\n const timer = setTimeout(() => {\n const portal = Object.values(scene.nodes).find(\n (node) => isPortalNode(node) && coverage(camera, nodeBounds(node), viewport) >= AUTO_ENTER,\n );\n if (portal) {\n drillIn(portal, false);\n } else if (path.length > 1) {\n const history = registry.get(atoms.history);\n const arrival = history.entries[history.index];\n const arrived =\n arrival && arrival.path.length === path.length && arrival.path.every((id, index) => id === path[index]);\n const reference = arrived ? coverage(arrival.camera, bounds, viewport) : 1;\n if (coverage(camera, bounds, viewport) < AUTO_EXIT * reference) {\n drillOut(1, false);\n }\n }\n }, AUTO_DRILL_MS);\n return () => clearTimeout(timer);\n }, [camera, scene, bounds, path, viewport, drag, drillIn, drillOut, registry, atoms.history, isAnimating]);\n\n return { nameOf, portalTo, frameOf, bounds, nominalZoom, pushHistory, drillIn, drillOut, goHistory };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\nimport { useCallback, useMemo } from 'react';\n\nimport { MAJOR_GRID_RATIO } from '../../model/types.ts';\n\n/**\n * Grid levels a fourfold apart, from a quarter of the minor grid to far past the major one, so the levels\n * on screen depend on the zoom alone: a child scene seen at a quarter scale draws the same lines as its\n * parent, and a far zoom-out still shows a grid.\n */\nexport const GRID_LEVELS = [1 / MAJOR_GRID_RATIO, 1, MAJOR_GRID_RATIO, MAJOR_GRID_RATIO ** 2, MAJOR_GRID_RATIO ** 3];\n\n/** Screen px a cell must cover to be drawn, and the most lines a level may draw before it is dropped. */\nexport const GRID_RANGE: [number, number] = [6, 2048];\n\nexport type SceneSnap = {\n /** The finest level drawn, in scene units; moves and control points land on it. */\n minor: number;\n /** `MAJOR_GRID_RATIO` of those; creation and resizing land on it. */\n major: number;\n snap: (value: number) => number;\n snapMinor: (value: number) => number;\n};\n\n/**\n * What a gesture lands on: the grid levels actually drawn, which is what the user is aiming at. A level\n * fixed in scene units parts company with the lines as soon as the zoom moves — `Grid` keeps a level only\n * while its cells are legible on screen, so far enough in the drawn lines are finer than the snap and far\n * enough out (a nested scene, entered at a fraction of the parent's zoom) they are coarser and the snap\n * stops landing on anything visible. Reading the level back from the same rule keeps the two the same by\n * construction.\n */\nexport const useSceneSnap = (grid: number, zoom: number, enabled: boolean): SceneSnap => {\n const minor = useMemo(() => {\n const levels = GRID_LEVELS.map((ratio) => ratio * grid);\n return levels.find((size) => size * zoom >= GRID_RANGE[0]) ?? levels[levels.length - 1];\n }, [grid, zoom]);\n const major = minor * MAJOR_GRID_RATIO;\n\n const snap = useCallback((value: number) => (enabled ? Math.round(value / major) * major : value), [enabled, major]);\n // Moving is finer than creating or resizing: a placed node keeps its major-grid size and edges land on\n // minor lines, so ports (drawn at the nearest major line) stay aligned while placement is not coarse.\n const snapMinor = useCallback(\n (value: number) => (enabled ? Math.round(value / minor) * minor : value),\n [enabled, minor],\n );\n\n return { minor, major, snap, snapMinor };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Root view of the scene engine (§6–§8): owns the camera, the scene path, selection and the pointer\n// state machine; renders the current scene through `SceneLayer` under one CSS transform and drills\n// in and out of portals with a camera transition then a root swap. Every model change goes through\n// the projection as an intent; the view never writes coordinates itself (decision 11).\n//\n\nimport { dropTargetForElements } from '@atlaskit/pragmatic-drag-and-drop/element/adapter';\nimport { useAtomValue } from '@effect/atom-react/Hooks';\nimport React, { type ReactNode, useCallback, useEffect, useLayoutEffect, useMemo, useRef } from 'react';\n\nimport * as Menu from '@dxos/react-ui/Menu';\nimport type * as Util from '@dxos/react-ui/Util';\nimport * as VirtualAnchor from '@dxos/react-ui/VirtualAnchor';\nimport { mx } from '@dxos/ui-theme';\n\nimport { useRegistry, useSceneProjection, useViewport, useWheel } from '../../hooks/index.ts';\nimport { type Drag, type SceneViewAtoms, createSceneViewAtoms } from '../../model/atoms.ts';\nimport { nodeDef } from '../../model/node-def.ts';\nimport {\n type FreehandProjectionOptions,\n type Projection,\n readonlyCapabilities,\n reduceIntent,\n} from '../../model/projection.ts';\nimport {\n type LinkRegistry,\n type NodeRegistry,\n defaultLinkRegistry,\n defaultNodeRegistry,\n} from '../../model/registry.ts';\nimport { type SceneStore } from '../../model/store.ts';\nimport {\n DEFAULT_GRID,\n type ElementId,\n type Endpoint,\n type Intent,\n MAJOR_GRID_RATIO,\n type Node,\n type NodeType,\n type Scene,\n type SceneId,\n isPointEndpoint,\n} from '../../model/types.ts';\nimport { MIN_ZOOM, cameraTransform, fitBounds, panBy, screenToScene, zoomAt } from '../../utils/camera.ts';\nimport { duplicateSelection } from '../../utils/clipboard.ts';\nimport { nodeDragType } from '../../utils/dnd.ts';\nimport { hitTest } from '../../utils/hit.ts';\nimport { topZ } from '../../utils/order.ts';\nimport { type PartKey, partKey, partText, partValues } from '../../utils/parts.ts';\nimport { createLink, nodeBounds } from '../../utils/shapes.ts';\nimport { redo, undo } from '../../utils/undo.ts';\nimport { ControlFrame } from '../ControlFrame/ControlFrame.tsx';\nimport { GridComponent } from '../Grid/index.ts';\nimport { LatticeGrid } from '../LatticeGrid/index.ts';\nimport { Palette } from '../Palette/Palette.tsx';\nimport { Properties, type PropertiesProps } from '../Properties/Properties.tsx';\nimport { type ElementHandlers, MAX_LIVE_DEPTH, SceneLayer } from '../SceneLayer/SceneLayer.tsx';\nimport { ActionToolbar, CameraToolbar, NavigationToolbar, type ToolbarActions } from '../Toolbar/Toolbar.tsx';\nimport { SceneViewProvider, useSceneViewContext } from './SceneViewContext.ts';\nimport { PREVIEW_NODE_ID, createId, isLinkDrawn, usePointerMachine } from './usePointerMachine.ts';\nimport { useSceneCamera } from './useSceneCamera.ts';\nimport { useSceneClipboard } from './useSceneClipboard.ts';\nimport { useSceneKeys } from './useSceneKeys.ts';\nimport { useSceneNavigation } from './useSceneNavigation.ts';\nimport { GRID_LEVELS, GRID_RANGE, useSceneSnap } from './useSceneSnap.ts';\n\n/** Major cells between the scene's frame and the viewport edge when fitting; `margin` overrides it. */\nconst DEFAULT_MARGIN = 1;\n/** Zoom factor of one toolbar step. */\nconst ZOOM_STEP = 1.25;\n/** Length of a dash of the scene's frame, in screen px. */\nconst FRAME_DASH = 4;\n/** The link drawn as a preview during a drag; it never reaches the model. */\nconst PREVIEW_LINK_ID = 'preview-link';\n\nexport type SceneViewRootProps = Util.ThemedClassName<{\n store: SceneStore;\n root: SceneId;\n nodes?: NodeRegistry;\n links?: LinkRegistry;\n /** Projection per scene; freehand (identity) by default. */\n createProjection?: (options: FreehandProjectionOptions) => Projection;\n /** A host-owned projection instead, shared with the host's panels (see `useSceneProjection`). */\n projection?: Projection;\n /** Externally owned view state, e.g. to drive two views or persist the camera. */\n atoms?: SceneViewAtoms;\n /** Minor grid spacing in scene px; moves snap to it, creation and resizing to the major grid, `MAJOR_GRID_RATIO` times it. */\n grid?: number;\n /** Least gap between the scene's frame and each viewport edge when fitting, in whole major cells. */\n margin?: number;\n /**\n * Look, select and navigate only: no gesture or key reaches the model, and no handle or port is drawn,\n * whatever the projection would allow.\n */\n readonly?: boolean;\n children?: ReactNode;\n}>;\n\nconst SceneViewRoot = ({\n classNames,\n store,\n root,\n nodes: nodeRegistry = defaultNodeRegistry,\n links: linkRegistry = defaultLinkRegistry,\n createProjection,\n projection: projectionProp,\n atoms: atomsProp,\n grid = DEFAULT_GRID,\n margin = DEFAULT_MARGIN,\n readonly = false,\n children,\n}: SceneViewRootProps) => {\n const registry = useRegistry();\n const atoms = useMemo(() => atomsProp ?? createSceneViewAtoms(root), [atomsProp, root]);\n const rootRef = useRef<HTMLDivElement>(null);\n const viewport = useViewport(rootRef);\n\n const path = useAtomValue(atoms.path);\n const projection = useSceneProjection({ store, atoms, createProjection, projection: projectionProp });\n const scene = useAtomValue(projection.scene);\n const scenes = useAtomValue(store.scenes);\n const camera = useAtomValue(atoms.camera);\n const selection = useAtomValue(atoms.selection);\n const hover = useAtomValue(atoms.hover);\n const selectedPoint = useAtomValue(atoms.point);\n const tool = useAtomValue(atoms.tool);\n const snapEnabled = useAtomValue(atoms.snap);\n // The margin is in major cells, taken from the model's grid rather than the level currently drawn,\n // so a fit puts the same gap around the scene whatever the zoom.\n const inset = margin * grid * MAJOR_GRID_RATIO;\n\n const drag = useAtomValue(atoms.drag);\n const undoState = useAtomValue(atoms.undo);\n const clipboard = useAtomValue(atoms.clipboard);\n const editing = useAtomValue(atoms.editing);\n const debug = useAtomValue(atoms.debug);\n const guides = useAtomValue(atoms.guides);\n const latticeOn = useAtomValue(atoms.lattice);\n const sceneId = path[path.length - 1];\n const canUndo = !readonly && undoState.key === sceneId && undoState.past.length > 0;\n const canRedo = !readonly && undoState.key === sceneId && undoState.future.length > 0;\n\n // Every gesture, key and control is gated on these, so a read-only view is the projection with nothing allowed.\n const capabilities = readonly ? readonlyCapabilities : projection.capabilities;\n\n //\n // Camera.\n //\n\n const {\n setCamera,\n animateTo,\n cancelAnimation,\n navigating,\n isNavigating,\n isAnimating,\n setNavigation,\n touchNavigation,\n opening,\n setOpening,\n } = useSceneCamera(registry, atoms, viewport);\n\n // Keep the scene fitted while the viewport settles, until the user takes the camera over. A layout\n // effect, so the fit lands before the first paint instead of one frame after it.\n const interactedRef = useRef(false);\n\n const select = useCallback(\n (ids: Iterable<ElementId>) => {\n registry.set(atoms.selection, new Set(ids));\n registry.set(atoms.point, undefined);\n },\n [registry, atoms.selection, atoms.point],\n );\n\n const { nameOf, portalTo, frameOf, bounds, nominalZoom, pushHistory, drillIn, drillOut, goHistory } =\n useSceneNavigation({\n registry,\n atoms,\n store,\n scenes,\n scene,\n path,\n camera,\n viewport,\n inset,\n drag,\n interactedRef,\n select,\n animateTo,\n setCamera,\n setOpening,\n isAnimating,\n });\n\n const measured = viewport.width > 0 && viewport.height > 0;\n useLayoutEffect(() => {\n if (!interactedRef.current && measured) {\n setCamera(fitBounds(bounds, viewport, inset));\n }\n }, [measured, viewport, bounds, inset, setCamera]);\n\n useWheel(\n rootRef,\n useCallback(\n (event, pointer) => {\n interactedRef.current = true;\n cancelAnimation();\n touchNavigation();\n if (event.ctrlKey || event.metaKey) {\n setCamera((camera) => zoomAt(camera, pointer, camera.zoom * Math.exp(-event.deltaY * 0.01)));\n } else {\n setCamera((camera) => panBy(camera, { x: -event.deltaX / camera.zoom, y: -event.deltaY / camera.zoom }));\n }\n },\n [setCamera, cancelAnimation, touchNavigation],\n ),\n );\n\n //\n // Navigation.\n //\n\n // Undo restores a whole model snapshot, so the selection may name elements that no longer exist.\n const onUndo = useCallback(() => {\n if (!readonly && undo(projection, registry, atoms.undo, sceneId)) {\n select([]);\n }\n }, [readonly, projection, registry, atoms.undo, sceneId, select]);\n const onRedo = useCallback(() => {\n if (!readonly && redo(projection, registry, atoms.undo, sceneId)) {\n select([]);\n }\n }, [readonly, projection, registry, atoms.undo, sceneId, select]);\n\n //\n // Pointer state machine.\n //\n\n const { minor, major, snap, snapMinor } = useSceneSnap(grid, camera.zoom, snapEnabled);\n const toggleSnap = useCallback(() => registry.set(atoms.snap, !registry.get(atoms.snap)), [registry, atoms.snap]);\n const toggleGuides = useCallback(\n () => registry.set(atoms.guides, !registry.get(atoms.guides)),\n [registry, atoms.guides],\n );\n const toggleLattice = useCallback(\n () => registry.set(atoms.lattice, !registry.get(atoms.lattice)),\n [registry, atoms.lattice],\n );\n const toggleDebug = useCallback(() => registry.set(atoms.debug, !registry.get(atoms.debug)), [registry, atoms.debug]);\n const {\n onBackgroundPointerDown,\n onPointerMove,\n onPointerUp,\n onContextMenu,\n cancelDrag,\n updateHover,\n onNodePointerDown,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n setTool,\n setDrag,\n toScene,\n removePoint,\n createdNode,\n commitCreated,\n menu,\n closeMenu,\n menuAnchorRef,\n } = usePointerMachine({\n registry,\n atoms,\n store,\n scene,\n nodeRegistry,\n projection,\n capabilities,\n camera,\n rootRef,\n interactedRef,\n select,\n setCamera,\n cancelAnimation,\n isNavigating,\n minor,\n major,\n snap,\n snapMinor,\n });\n\n //\n // Clipboard.\n //\n\n const { copy, cut, paste } = useSceneClipboard({\n registry,\n atoms,\n scene,\n projection,\n capabilities,\n select,\n createId,\n major,\n snap,\n });\n\n const onSceneKey = useSceneKeys({\n registry,\n atoms,\n scene,\n nodeRegistry,\n linkRegistry,\n projection,\n capabilities,\n viewport,\n bounds,\n inset,\n grid,\n select,\n toggleSnap,\n toggleGuides,\n toggleLattice,\n toggleDebug,\n onUndo,\n onRedo,\n animateTo,\n drillIn,\n drillOut,\n goHistory,\n major,\n copy,\n cut,\n paste,\n cancelDrag,\n removePoint,\n setTool,\n });\n\n // Shortcuts belong to the canvas itself: keys typed into a control the view hosts (the properties\n // panel, a toolbar) bubble here too, and must not toggle debug or delete the selection.\n const onKeyDown = useCallback<typeof onSceneKey>(\n (event) => {\n if (event.target === event.currentTarget) {\n onSceneKey(event);\n }\n },\n [onSceneKey],\n );\n\n //\n // Render.\n //\n\n /** The node a create gesture would land while one is in flight; the ghost and the frame both read it. */\n const createPreview = useMemo(\n () => (drag?.kind === 'create' ? createdNode(drag, PREVIEW_NODE_ID) : undefined),\n [drag, createdNode],\n );\n\n // Transient drag state is rendered by projecting it onto a copy, so links re-route while dragging and\n // a link being drawn or re-attached over a drop target looks exactly as it will once dropped. Geometry\n // previews pass through the projection's `constrain`, so a drag shows where the drop will land, and\n // `blocked` says when the drop would be refused (drawn as is, outlined in red).\n const { displayScene, blocked } = useMemo<{ displayScene: Scene; blocked: boolean }>(() => {\n const preview = (intent: Intent) => {\n const constrained = projection.constrain ? projection.constrain(intent) : intent;\n return { displayScene: reduceIntent(scene, constrained ?? intent), blocked: constrained === undefined };\n };\n if (drag?.kind === 'move') {\n // A copy previews beside the originals, which stay; the drop mints the copies' real ids.\n let next = 0;\n const copy = drag.copy\n ? duplicateSelection(scene, drag.ids, drag.delta, (prefix) => `${PREVIEW_NODE_ID}-${prefix}-${next++}`)\n : undefined;\n return preview(copy ? copy.intent : { kind: 'move', ids: drag.ids, delta: drag.delta });\n }\n if (drag?.kind === 'resize') {\n return preview({ kind: 'resize', id: drag.id, bounds: drag.bounds });\n }\n // A node being created previews as the type's own view inside its frame, whether drawn on the canvas\n // or dragged in from the palette (whose drag carries no image of its own).\n if (drag?.kind === 'create') {\n return createPreview ? preview({ kind: 'create', node: createPreview }) : { displayScene: scene, blocked: false };\n }\n if (drag?.kind === 'point') {\n return {\n displayScene: reduceIntent(scene, { kind: 'update', id: drag.id, values: { points: drag.points } }),\n blocked: false,\n };\n }\n // A link previews only once it has gone a grid cell, so a click with a link tool draws nothing.\n if (drag?.kind === 'link' && isLinkDrawn(drag, minor) && (drag.target || isPointEndpoint(drag.source))) {\n // A port drag previews once it reaches a target; a free-ended link previews as it will land.\n const link = createLink({\n type: drag.type,\n id: PREVIEW_LINK_ID,\n z: topZ(Object.values(scene.links)),\n source: drag.source,\n target: drag.target ?? { point: drag.to },\n midpoint: { x: (drag.from.x + drag.to.x) / 2, y: (drag.from.y + drag.to.y) / 2 },\n });\n return { displayScene: reduceIntent(scene, { kind: 'link', link }), blocked: false };\n }\n if (drag?.kind === 'end') {\n // The link is drawn as it will land: re-attached over a target, free-ended over empty canvas.\n const end: Endpoint = drag.target ?? { point: drag.to };\n return {\n displayScene: reduceIntent(scene, { kind: 'update', id: drag.id, values: { [drag.end]: end } }),\n blocked: false,\n };\n }\n return { displayScene: scene, blocked: false };\n }, [scene, drag, createPreview, projection, minor]);\n\n /** The bounds a create gesture would land, drawn as a frame whether or not the node itself previews. */\n const createFrame = useMemo(() => {\n const preview = createPreview && displayScene.nodes[createPreview.id];\n return preview ? nodeBounds(preview) : undefined;\n }, [createPreview, displayScene]);\n\n const onPartCommit = useCallback(\n (node: Node, part: PartKey, text: string) => {\n registry.set(atoms.editing, undefined);\n const values = partValues(node, part, text);\n if (values && capabilities.update && text !== partText(node, part)) {\n projection.apply({ kind: 'update', id: node.id, values });\n }\n },\n [registry, atoms.editing, capabilities.update, projection],\n );\n const onPartCancel = useCallback(() => registry.set(atoms.editing, undefined), [registry, atoms.editing]);\n\n const handlers = useMemo<ElementHandlers>(\n () => ({\n onNodePointerDown,\n onLinkPointerDown,\n onLinkDoubleClick,\n onLinkContextMenu,\n onPartCommit,\n onPartCancel,\n onNodeOpen: drillIn,\n }),\n [onNodePointerDown, onLinkPointerDown, onLinkDoubleClick, onLinkContextMenu, onPartCommit, onPartCancel, drillIn],\n );\n\n // Resolved at the root from the model: pointer capture during a drag retargets the click, so a\n // double-click never reaches the node element itself. A text part under the pointer opens its editor;\n // the DOM is asked only which part, and the node comes from the model, so a part of a nested (live)\n // scene never matches the root node over it.\n const onDoubleClick = useCallback(\n (event: React.MouseEvent) => {\n const node = hitTest(scene, toScene(event));\n if (!node) {\n return;\n }\n const target = document.elementFromPoint(event.clientX, event.clientY);\n // A floating panel over the node took the clicks, so the node beneath is not the one meant.\n if (!(target instanceof Element) || !target.closest('[data-node-id]')) {\n return;\n }\n const partElement = target.closest('[data-part]');\n const part =\n partElement?.closest('[data-node-id]')?.getAttribute('data-node-id') === node.id\n ? partKey(partElement?.getAttribute('data-part'))\n : undefined;\n if (part && capabilities.update && partText(node, part) !== undefined) {\n select([node.id]);\n registry.set(atoms.editing, { id: node.id, part });\n } else if (nodeDef(nodeRegistry, node)?.openable) {\n drillIn(node);\n }\n },\n [scene, toScene, nodeRegistry, drillIn, capabilities.update, select, registry, atoms.editing],\n );\n\n // A node type dragged in (from the palette or a host's draggable) previews as a create drag would and\n // lands through the same drop, so what the ghost shows is what is created.\n const onPointerUpRef = useRef(onPointerUp);\n onPointerUpRef.current = onPointerUp;\n useEffect(() => {\n const element = rootRef.current;\n if (!element) {\n return;\n }\n // The pointer is the shape's centre; its top-left is what snaps, so the edges land on the grid.\n const dragAt = (type: NodeType, input: { clientX: number; clientY: number }): Drag => {\n const point = toScene(input);\n const size = nodeRegistry[type]?.defaultSize ?? { width: 0, height: 0 };\n const from = { x: snap(point.x - size.width / 2), y: snap(point.y - size.height / 2) };\n return { kind: 'create', type, from, to: from, dropped: true };\n };\n return dropTargetForElements({\n element,\n canDrop: ({ source }) => capabilities.create === true && nodeDragType(source.data) !== undefined,\n onDragEnter: ({ source, location }) => {\n const type = nodeDragType(source.data);\n if (type !== undefined) {\n setDrag(dragAt(type, location.current.input));\n }\n },\n onDrag: ({ source, location }) => {\n const type = nodeDragType(source.data);\n if (type !== undefined) {\n setDrag(dragAt(type, location.current.input));\n }\n },\n onDragLeave: cancelDrag,\n onDrop: () => onPointerUpRef.current(),\n });\n }, [capabilities.create, nodeRegistry, toScene, snap, setDrag, cancelDrag]);\n\n const pointer = useMemo(\n () => screenToScene(camera, { x: viewport.width / 2, y: viewport.height / 2 }),\n [camera, viewport],\n );\n\n const zoomBy = useCallback(\n (factor: number) => {\n interactedRef.current = true;\n const centre = { x: viewport.width / 2, y: viewport.height / 2 };\n animateTo(zoomAt(registry.get(atoms.camera), centre, registry.get(atoms.camera).zoom * factor));\n },\n [viewport, animateTo, registry, atoms.camera],\n );\n\n const deleteSelection = useCallback(() => {\n const ids = [...registry.get(atoms.selection)];\n if (ids.length > 0 && capabilities.delete) {\n projection.apply({ kind: 'delete', ids });\n select([]);\n }\n }, [registry, atoms.selection, capabilities.delete, projection, select]);\n\n /** A default-sized node of `type` centred in the view, its top-left on the grid. */\n const createAtCentre = useCallback(\n (type: NodeType) => {\n const def = nodeRegistry[type];\n if (!def || !capabilities.create) {\n return;\n }\n const size = def.defaultSize;\n const from = { x: snap(pointer.x - size.width / 2), y: snap(pointer.y - size.height / 2) };\n // `dropped`: there is no drawn box, so the type's default size applies, as for a palette drop.\n const node = createdNode({ kind: 'create', type, from, to: from, dropped: true }, createId(type));\n if (node) {\n commitCreated(node);\n }\n },\n [nodeRegistry, capabilities.create, snap, pointer, createdNode, commitCreated],\n );\n\n const toolbarActions = useMemo<ToolbarActions>(\n () => ({\n path,\n nameOf,\n onPath: (index) => drillOut(path.length - 1 - index),\n fit: () => animateTo(fitBounds(bounds, viewport, inset)),\n zoomIn: () => zoomBy(ZOOM_STEP),\n zoomOut: () => zoomBy(1 / ZOOM_STEP),\n snap: snapEnabled,\n toggleSnap,\n guides,\n toggleGuides,\n // Only a lattice scene has a lattice to snap to.\n ...(projection.lattice ? { lattice: latticeOn, toggleLattice } : {}),\n debug,\n toggleDebug,\n canUndo,\n canRedo,\n undo: onUndo,\n redo: onRedo,\n hasSelection: selection.size > 0,\n hasClipboard: clipboard !== undefined,\n cut,\n copy,\n paste: () => paste(),\n delete: deleteSelection,\n create: createAtCentre,\n // A selection of two or more is what the user asked to tidy; one node alone means the board.\n layout: capabilities.layout\n ? () => projection.apply({ kind: 'layout', ids: selection.size > 1 ? [...selection] : undefined })\n : undefined,\n }),\n [\n path,\n nameOf,\n drillOut,\n animateTo,\n bounds,\n viewport,\n inset,\n zoomBy,\n snapEnabled,\n toggleSnap,\n guides,\n toggleGuides,\n latticeOn,\n toggleLattice,\n debug,\n toggleDebug,\n canUndo,\n canRedo,\n onUndo,\n onRedo,\n selection,\n clipboard,\n cut,\n copy,\n paste,\n deleteSelection,\n createAtCentre,\n capabilities.layout,\n projection,\n ],\n );\n\n /** One screen pixel in scene units, for chrome that should not grow with the camera. */\n const frameUnit = 1 / Math.max(camera.zoom, MIN_ZOOM);\n\n return (\n <SceneViewProvider\n registry={registry}\n atoms={atoms}\n store={store}\n projection={projection}\n capabilities={capabilities}\n nodeRegistry={nodeRegistry}\n linkRegistry={linkRegistry}\n scene={scene}\n displayScene={displayScene}\n blocked={blocked}\n bounds={bounds}\n path={path}\n camera={camera}\n nominalZoom={nominalZoom}\n pointer={pointer}\n measured={measured}\n frameUnit={frameUnit}\n grid={grid}\n snapEnabled={snapEnabled}\n guides={guides}\n latticeOn={latticeOn}\n selection={selection}\n hover={hover}\n selectedPoint={selectedPoint}\n editing={editing}\n clipboard={clipboard}\n drag={drag}\n tool={tool}\n debug={debug}\n createFrame={createFrame}\n handlers={handlers}\n select={select}\n toolbarActions={toolbarActions}\n navigating={navigating}\n opening={opening}\n drillIn={drillIn}\n copy={copy}\n cut={cut}\n paste={paste}\n onBackgroundPointerDown={onBackgroundPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n onContextMenu={onContextMenu}\n cancelDrag={cancelDrag}\n updateHover={updateHover}\n onHandlePointerDown={onHandlePointerDown}\n onPortPointerDown={onPortPointerDown}\n onEndPointerDown={onEndPointerDown}\n onPointPointerDown={onPointPointerDown}\n onMidpointPointerDown={onMidpointPointerDown}\n onPointContextMenu={onPointContextMenu}\n setTool={setTool}\n removePoint={removePoint}\n menu={menu}\n closeMenu={closeMenu}\n menuAnchorRef={menuAnchorRef}\n onDoubleClick={onDoubleClick}\n onKeyDown={onKeyDown}\n rootRef={rootRef}\n >\n <div\n ref={rootRef}\n tabIndex={0}\n className={mx(\n 'relative dx-fill overflow-hidden bg-base-surface outline-none touch-none select-none',\n tool.kind === 'hand' && 'cursor-grab',\n tool.kind === 'node' && 'cursor-crosshair',\n classNames,\n )}\n style={{ contain: 'strict' }}\n data-testid='scene-view'\n onPointerDown={onBackgroundPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerUp}\n // A cancelled pointer (a touch the browser took over) abandons the gesture rather than landing it.\n onPointerCancel={cancelDrag}\n onPointerLeave={() => updateHover(undefined)}\n onDoubleClick={onDoubleClick}\n onContextMenu={onContextMenu}\n onKeyDown={onKeyDown}\n >\n {children}\n </div>\n </SceneViewProvider>\n );\n};\n\nSceneViewRoot.displayName = 'SceneView.Root';\n\n//\n// Canvas\n//\n\nexport type SceneViewCanvasProps = {\n /** Nested levels below the root that may mount live; deeper portals stay previews (decision 10). */\n liveDepth?: number;\n /** Extra layers drawn in scene coordinates under the camera, above the scene (e.g. a host's animations). */\n overlay?: ReactNode;\n};\n\n/** The scene itself under the camera: the grid, the layer, the control frame and the menu a gesture opens. */\nconst SceneViewCanvas = ({ liveDepth = MAX_LIVE_DEPTH, overlay }: SceneViewCanvasProps) => {\n const {\n registry,\n atoms,\n store,\n capabilities,\n projection,\n nodeRegistry,\n displayScene,\n blocked,\n bounds,\n camera,\n measured,\n frameUnit,\n grid,\n snapEnabled,\n guides,\n latticeOn,\n selection,\n hover,\n selectedPoint,\n editing,\n clipboard,\n drag,\n debug,\n createFrame,\n handlers,\n select,\n navigating,\n opening,\n copy,\n cut,\n paste,\n onHandlePointerDown,\n onPortPointerDown,\n onEndPointerDown,\n onPointPointerDown,\n onMidpointPointerDown,\n onPointContextMenu,\n removePoint,\n menu,\n closeMenu,\n menuAnchorRef,\n } = useSceneViewContext('SceneView.Canvas');\n\n return (\n <>\n {/* Only while snapping: the lines are what a gesture lands on, so drawing them when nothing snaps\n states a constraint the canvas is not applying. The minor level goes when its cells get too\n small to read. */}\n {snapEnabled && (\n <GridComponent\n size={grid}\n scale={camera.zoom}\n offset={{ x: camera.x * camera.zoom, y: camera.y * camera.zoom }}\n showAxes={false}\n ratios={GRID_LEVELS}\n range={GRID_RANGE}\n />\n )}\n <div\n className={mx('absolute pointer-events-none', !measured && 'invisible')}\n style={{ transform: cameraTransform(camera), transformOrigin: '0 0' }}\n >\n {/* The frame is chrome rather than content, so its stroke and dashes are divided by the zoom\n the parent applies, the way the control frame's are. It is drawn as a stroke rather than a\n CSS border because a border's width is rounded to whole local pixels, which puts a floor of\n one scene unit under it — exactly the thickening that zooming in would cause. */}\n {/* A lattice scene shows its cells: the places a shape may land, separated by the gutters. */}\n {guides && latticeOn && projection.lattice && (\n <LatticeGrid spec={projection.lattice} bounds={bounds} unit={frameUnit} />\n )}\n {guides && (\n <svg className='absolute overflow-visible pointer-events-none' width={1} height={1}>\n <rect\n data-testid='scene-frame'\n x={bounds.x}\n y={bounds.y}\n width={bounds.width}\n height={bounds.height}\n className='fill-none stroke-orange-border opacity-50'\n strokeWidth={frameUnit}\n strokeDasharray={`${FRAME_DASH * frameUnit} ${FRAME_DASH * frameUnit}`}\n />\n </svg>\n )}\n <div className='pointer-events-auto'>\n <SceneLayer\n store={store}\n scene={displayScene}\n registry={nodeRegistry}\n zoom={camera.zoom}\n depth={0}\n liveDepth={liveDepth}\n selected={selection}\n hover={hover}\n opening={opening}\n editing={editing}\n ghost={drag?.kind === 'create' ? PREVIEW_NODE_ID : undefined}\n debug={debug}\n handlers={handlers}\n // Routes follow the gutters in lattice mode, whether or not snap is on.\n lattice={latticeOn ? projection.lattice : undefined}\n />\n </div>\n <ControlFrame\n scene={displayScene}\n registry={nodeRegistry}\n selection={selection}\n hover={hover}\n selectedPoint={selectedPoint}\n zoom={camera.zoom}\n drag={drag}\n capabilities={capabilities}\n createFrame={createFrame}\n blocked={blocked}\n lattice={latticeOn ? projection.lattice : undefined}\n onHandlePointerDown={onHandlePointerDown}\n onPortPointerDown={onPortPointerDown}\n onEndPointerDown={onEndPointerDown}\n onPointPointerDown={onPointPointerDown}\n onMidpointPointerDown={onMidpointPointerDown}\n onPointContextMenu={onPointContextMenu}\n />\n {overlay}\n </div>\n {/* Wheel events still bubble to the root through the shield, so a zoom keeps zooming. */}\n {navigating && <div className='dx-cover' data-testid='navigation-shield' />}\n <span\n ref={menuAnchorRef}\n className='absolute size-0 pointer-events-none'\n style={{ left: menu?.at.x ?? 0, top: menu?.at.y ?? 0 }}\n />\n <Menu.Root\n open={menu !== undefined}\n onOpenChange={({ open }) => !open && closeMenu()}\n positioning={{\n ...VirtualAnchor.virtualAnchor(menuAnchorRef),\n placement: 'right',\n gutter: 4,\n overflowPadding: 8,\n }}\n >\n <Menu.Content>\n {menu?.kind === 'point' && (\n <Menu.Item\n data-testid='remove-point'\n onSelect={() => {\n const point = registry.get(atoms.point);\n if (point) {\n removePoint(point);\n }\n }}\n item={{ value: 'Remove control point', label: 'Remove control point' }}\n />\n )}\n {menu?.kind === 'element' && (\n <>\n <Menu.Item\n data-testid='menu-cut'\n disabled={!capabilities.delete}\n onSelect={cut}\n item={{ value: 'Cut', label: 'Cut' }}\n />\n <Menu.Item data-testid='menu-copy' onSelect={copy} item={{ value: 'Copy', label: 'Copy' }} />\n <Menu.Item\n data-testid='menu-delete'\n disabled={!capabilities.delete}\n onSelect={() => {\n projection.apply({ kind: 'delete', ids: [...registry.get(atoms.selection)] });\n select([]);\n }}\n item={{ value: 'Delete', label: 'Delete' }}\n />\n </>\n )}\n {menu?.kind === 'canvas' && (\n <Menu.Item\n data-testid='menu-paste'\n disabled={!clipboard || !capabilities.create}\n onSelect={() => paste(menu.scene)}\n item={{ value: 'Paste', label: 'Paste' }}\n />\n )}\n </Menu.Content>\n </Menu.Root>\n </>\n );\n};\n\nSceneViewCanvas.displayName = 'SceneView.Canvas';\n\n//\n// Toolbars\n//\n\nexport type SceneViewBarProps = Util.ThemedClassName<{}>;\n\n/**\n * The frame a bar floats in: its content's width, but half the view at most (the bar scrolls beyond that).\n * The toolbar's own scroll frame is zero-height in flow, so `classNames` positions this frame, not the bar.\n */\nconst barFrame = 'absolute w-max max-w-[50%]';\n\n/** Where the view is in the scene tree. */\nconst SceneViewNavigation = ({ classNames = 'top-2 left-2' }: SceneViewBarProps) => {\n const { toolbarActions, path } = useSceneViewContext('SceneView.Navigation');\n return (\n <div className={mx(barFrame, classNames)}>\n <NavigationToolbar actions={toolbarActions}>depth {path.length - 1}</NavigationToolbar>\n </div>\n );\n};\n\nSceneViewNavigation.displayName = 'SceneView.Navigation';\n\n/** Everything that changes the view or the scene. */\nconst SceneViewActions = ({ classNames = 'bottom-2 left-1/2 -translate-x-1/2' }: SceneViewBarProps) => {\n const { toolbarActions, nodeRegistry, capabilities } = useSceneViewContext('SceneView.Actions');\n return (\n <div className={mx(barFrame, classNames)}>\n <ActionToolbar actions={toolbarActions} nodes={nodeRegistry} capabilities={capabilities} />\n </div>\n );\n};\n\nSceneViewActions.displayName = 'SceneView.Actions';\n\n/** The camera's controls and numbers; nothing here changes the scene. */\nconst SceneViewDebug = ({ classNames = 'bottom-2 left-2' }: SceneViewBarProps) => {\n const { toolbarActions, nominalZoom, pointer } = useSceneViewContext('SceneView.Debug');\n return (\n <div className={mx(barFrame, classNames)}>\n <CameraToolbar actions={toolbarActions}>\n {Math.round(nominalZoom * 100)}% · ({Math.round(pointer.x)}, {Math.round(pointer.y)})\n </CameraToolbar>\n </div>\n );\n};\n\nSceneViewDebug.displayName = 'SceneView.Debug';\n\n//\n// Palette\n//\n\n/** The tool rail: what the next gesture will draw. */\nconst SceneViewPalette = ({ classNames = 'absolute top-14 left-2' }: SceneViewBarProps) => {\n const { tool, nodeRegistry, linkRegistry, capabilities, setTool } = useSceneViewContext('SceneView.Palette');\n return (\n <div className={mx(classNames)}>\n <Palette\n tool={tool}\n nodes={nodeRegistry}\n links={linkRegistry}\n capabilities={capabilities}\n onToolChange={setTool}\n />\n </div>\n );\n};\n\nSceneViewPalette.displayName = 'SceneView.Palette';\n\n//\n// Properties\n//\n\nexport type SceneViewPropertiesProps = Util.ThemedClassName<Pick<PropertiesProps, 'fields'>>;\n\n/** The selected element's properties as a floating panel; absent while nothing is selected. */\nconst SceneViewProperties = ({\n classNames = 'absolute top-2 right-2 w-80 max-h-[calc(100%-1rem)]',\n fields,\n}: SceneViewPropertiesProps) => {\n const { projection, atoms, nodeRegistry, capabilities, selection } = useSceneViewContext('SceneView.Properties');\n if (selection.size === 0) {\n return null;\n }\n\n return (\n <Properties\n classNames={mx('rounded-sm bg-modal-surface border border-separator', classNames)}\n projection={projection}\n atoms={atoms}\n nodes={nodeRegistry}\n fields={fields}\n readonly={!capabilities.update}\n />\n );\n};\n\nSceneViewProperties.displayName = 'SceneView.Properties';\n\nexport const SceneView = {\n Root: SceneViewRoot,\n Canvas: SceneViewCanvas,\n Navigation: SceneViewNavigation,\n Actions: SceneViewActions,\n Debug: SceneViewDebug,\n Palette: SceneViewPalette,\n Properties: SceneViewProperties,\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Variant 2 of §3: the model is a set of cardinal constraints between named nodes; the projection\n// solves them into a positioned scene and a `move` intent rewrites the moved node's constraints\n// against its nearest neighbour, then re-solves. Uses `@dxos/diagram`'s longest-path ranking per axis.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { Layout } from '@dxos/diagram';\n\nimport { centeredOrigin } from '../../utils/layout.ts';\nimport { initialKeys } from '../../utils/order.ts';\nimport { createNode, withLabel } from '../../utils/shapes.ts';\nimport { type Projection } from '../projection.ts';\nimport {\n type BuiltinNodeType,\n type Capabilities,\n type Intent,\n type Node,\n type Point,\n type Scene,\n type Size,\n isBuiltinNode,\n isPortalNode,\n} from '../types.ts';\n\n/** `subject <relation> object`: \"A east of B\", \"A aligned with B\" (same row). */\nexport type Relation = 'east' | 'west' | 'north' | 'south' | 'aligned';\n\nexport type Constraint = { subject: string; relation: Relation; object: string };\n\n/** `type` is the node's shape; the solver places every type on the same grid. */\nexport type ConstrainedNode = { id: string; label?: string; type?: BuiltinNodeType };\n\nexport type ConstrainedModel = {\n nodes: ConstrainedNode[];\n constraints: Constraint[];\n};\n\nexport type ConstrainedOptions = {\n /** Distance between grid slots. */\n pitch?: Size;\n /** Every node has the same size (§3: equal sizes, snapped to the grid). */\n size?: Size;\n /** The first slot's centre; by default the layout straddles the origin. */\n origin?: Point;\n};\n\n/** Multiples of the major grid, so a solved layout is already snapped. */\nconst DEFAULTS: Required<Omit<ConstrainedOptions, 'origin'>> = {\n pitch: { width: 256, height: 192 },\n size: { width: 192, height: 128 },\n};\n\nexport const CONSTRAINED_SCENE_ID = 'constrained';\n\ntype Edge = { from: string; to: string };\n\nconst reaches = (edges: readonly Edge[], from: string, to: string): boolean => {\n const seen = new Set<string>([from]);\n const queue = [from];\n while (queue.length > 0) {\n const current = queue.shift();\n for (const edge of edges) {\n if (edge.from === current && !seen.has(edge.to)) {\n if (edge.to === to) {\n return true;\n }\n seen.add(edge.to);\n queue.push(edge.to);\n }\n }\n }\n return false;\n};\n\n/** Union-find over `aligned` pairs: members of a group share a row. */\nconst rowGroups = (model: ConstrainedModel): Map<string, string> => {\n const parent = new Map<string, string>(model.nodes.map(({ id }) => [id, id]));\n const find = (id: string): string => {\n const root = parent.get(id) ?? id;\n if (root === id) {\n return id;\n }\n const top = find(root);\n parent.set(id, top);\n return top;\n };\n for (const { subject, relation, object } of model.constraints) {\n if (relation === 'aligned') {\n parent.set(find(subject), find(object));\n }\n }\n return new Map(model.nodes.map(({ id }) => [id, find(id)]));\n};\n\nexport type Solution = {\n rows: Map<string, number>;\n columns: Map<string, number>;\n};\n\n/** Longest-path ranks per axis: `south`/`north` order rows, `east`/`west` order columns within a row. */\nexport const solveRanks = (model: ConstrainedModel): Solution => {\n const ids = model.nodes.map(({ id }) => id);\n const groups = rowGroups(model);\n const groupIds = [...new Set(groups.values())];\n\n const rowEdges: Edge[] = [];\n const columnEdges: Edge[] = [];\n for (const { subject, relation, object } of model.constraints) {\n switch (relation) {\n case 'south':\n rowEdges.push({ from: groups.get(object) ?? object, to: groups.get(subject) ?? subject });\n break;\n case 'north':\n rowEdges.push({ from: groups.get(subject) ?? subject, to: groups.get(object) ?? object });\n break;\n case 'east':\n columnEdges.push({ from: object, to: subject });\n break;\n case 'west':\n columnEdges.push({ from: subject, to: object });\n break;\n default:\n break;\n }\n }\n // A constraint that would close a cycle is dropped rather than breaking the solve.\n const acyclic = (edges: Edge[]): Edge[] => {\n const kept: Edge[] = [];\n for (const edge of edges) {\n if (!reaches(kept, edge.to, edge.from)) {\n kept.push(edge);\n }\n }\n return kept;\n };\n const groupRanks = Layout.rank(groupIds, acyclic(rowEdges));\n const rows = new Map(ids.map((id) => [id, groupRanks.get(groups.get(id) ?? id) ?? 0]));\n\n const columns = new Map<string, number>();\n const byRow = new Map<number, string[]>();\n for (const id of ids) {\n const row = rows.get(id) ?? 0;\n byRow.set(row, [...(byRow.get(row) ?? []), id]);\n }\n for (const members of byRow.values()) {\n const set = new Set(members);\n const edges = acyclic(columnEdges.filter(({ from, to }) => set.has(from) && set.has(to)));\n const ranks = Layout.rank(members, edges);\n // Unconstrained members of a row take the next free column after the constrained ones.\n const used = new Set<number>();\n for (const id of members) {\n if (edges.some(({ from, to }) => from === id || to === id)) {\n const column = ranks.get(id) ?? 0;\n columns.set(id, column);\n used.add(column);\n }\n }\n let free = 0;\n for (const id of members) {\n if (!columns.has(id)) {\n while (used.has(free)) {\n free++;\n }\n columns.set(id, free);\n used.add(free);\n }\n }\n }\n return { rows, columns };\n};\n\n/** Solve the model to a positioned scene. */\nexport const solve = (model: ConstrainedModel, options: ConstrainedOptions = {}): Scene => {\n const { pitch, size } = { ...DEFAULTS, ...options };\n const { rows, columns } = solveRanks(model);\n const extent = {\n columns: Math.max(...columns.values(), 0) + 1,\n rows: Math.max(...rows.values(), 0) + 1,\n };\n const origin = options.origin ?? centeredOrigin(extent, pitch, size);\n const keys = initialKeys(model.nodes.length);\n const nodes: Record<string, Node> = {};\n model.nodes.forEach((node, index) => {\n const center = {\n x: origin.x + (columns.get(node.id) ?? 0) * pitch.width,\n y: origin.y + (rows.get(node.id) ?? 0) * pitch.height,\n };\n nodes[node.id] = withLabel(\n createNode({ type: node.type ?? 'rect', id: node.id, z: keys[index], center, size }),\n node.label ?? node.id,\n );\n });\n return { id: CONSTRAINED_SCENE_ID, name: 'Constrained', nodes, links: {} };\n};\n\n/**\n * Rewrite the constraints of `id` from where it was dropped: the nearest other node becomes its\n * reference; a mostly horizontal offset makes it east/west of and aligned with that node, a mostly\n * vertical one north/south of it. Returns the model unchanged when there is no neighbour.\n */\nexport const rewriteForDrop = (model: ConstrainedModel, scene: Scene, id: string, delta: Point): ConstrainedModel => {\n const moved = scene.nodes[id];\n if (!moved) {\n return model;\n }\n const target = { x: moved.center.x + delta.x, y: moved.center.y + delta.y };\n let nearest: { id: string; dx: number; dy: number } | undefined;\n let best = Infinity;\n for (const node of Object.values(scene.nodes)) {\n if (node.id === id) {\n continue;\n }\n const dx = target.x - node.center.x;\n const dy = target.y - node.center.y;\n const distance = dx * dx + dy * dy;\n if (distance < best) {\n best = distance;\n nearest = { id: node.id, dx, dy };\n }\n }\n if (!nearest) {\n return model;\n }\n const kept = model.constraints.filter(({ subject, object }) => subject !== id && object !== id);\n const horizontal = Math.abs(nearest.dx) >= Math.abs(nearest.dy);\n const added: Constraint[] = horizontal\n ? [\n { subject: id, relation: nearest.dx > 0 ? 'east' : 'west', object: nearest.id },\n { subject: id, relation: 'aligned', object: nearest.id },\n ]\n : [{ subject: id, relation: nearest.dy > 0 ? 'south' : 'north', object: nearest.id }];\n return { ...model, constraints: [...kept, ...added] };\n};\n\n/** The display text of a node or a partial update, whichever field its type uses. */\nexport const labelOf = (values: object): string | undefined => {\n if ('label' in values && typeof values.label === 'string') {\n return values.label;\n }\n if ('name' in values && typeof values.name === 'string') {\n return values.name;\n }\n if ('text' in values && typeof values.text === 'string') {\n return values.text;\n }\n return undefined;\n};\n\nconst isConstrainedModel = (value: unknown): value is ConstrainedModel =>\n typeof value === 'object' && value !== null && 'nodes' in value && 'constraints' in value;\n\nexport const constrainedCapabilities: Capabilities = { move: true, create: true, delete: true, update: true };\n\nexport type ConstrainedProjectionOptions = {\n registry: Registry.AtomRegistry;\n model: Atom.Writable<ConstrainedModel>;\n options?: ConstrainedOptions;\n};\n\nexport const createConstrainedProjection = ({ registry, model, options }: ConstrainedProjectionOptions): Projection => {\n const scene = Atom.keepAlive(Atom.make((get) => solve(get(model), options)));\n const apply = (intent: Intent) => {\n const current = registry.get(model);\n switch (intent.kind) {\n case 'move': {\n let next = current;\n for (const id of intent.ids) {\n next = rewriteForDrop(next, registry.get(scene), id, intent.delta);\n }\n if (next !== current) {\n registry.set(model, next);\n }\n break;\n }\n case 'create': {\n // The model records built-in types only; a portal or a host type has no place in it and is refused.\n if (!isBuiltinNode(intent.node) || isPortalNode(intent.node)) {\n return;\n }\n const node: ConstrainedNode = {\n id: intent.node.id,\n type: intent.node.type,\n label: labelOf(intent.node),\n };\n const added = { ...current, nodes: [...current.nodes, node] };\n // Constrain the new node as if it had been dropped where it was drawn.\n const solved = registry.get(scene);\n const provisional: Scene = { ...solved, nodes: { ...solved.nodes, [node.id]: intent.node } };\n registry.set(model, rewriteForDrop(added, provisional, node.id, { x: 0, y: 0 }));\n break;\n }\n case 'delete': {\n const ids = new Set(intent.ids);\n registry.set(model, {\n nodes: current.nodes.filter(({ id }) => !ids.has(id)),\n constraints: current.constraints.filter(({ subject, object }) => !ids.has(subject) && !ids.has(object)),\n });\n break;\n }\n case 'batch':\n intent.intents.forEach(apply);\n break;\n case 'update': {\n // Only the label lives in the model; geometry is solved, so those edits are dropped.\n const label = labelOf(intent.values);\n if (label !== undefined) {\n registry.set(model, {\n ...current,\n nodes: current.nodes.map((node) => (node.id === intent.id ? { ...node, label } : node)),\n });\n }\n break;\n }\n default:\n break;\n }\n };\n return {\n scene,\n apply,\n capabilities: constrainedCapabilities,\n snapshot: () => registry.get(model),\n restore: (snapshot) => {\n if (isConstrainedModel(snapshot)) {\n registry.set(model, snapshot);\n }\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Dynamic projection (§3 variant 3): the model is an external graph of nodes and edges. A layout\n// engine ranks it into rows; an overlay of user overrides applies on top, so a `move` intent writes\n// an override rather than a coordinate, graph edits re-run the engine, and an override whose node\n// vanished is dropped.\n//\n\nimport * as Atom from 'effect/reactivity/Atom';\nimport type * as Registry from 'effect/reactivity/AtomRegistry';\n\nimport { Layout } from '@dxos/diagram';\n\nimport { centeredOrigin } from '../../utils/layout.ts';\nimport { initialKeys } from '../../utils/order.ts';\nimport { createNode, withLabel } from '../../utils/shapes.ts';\nimport { type Projection } from '../projection.ts';\nimport {\n type BuiltinNodeType,\n type Capabilities,\n type Intent,\n type Link,\n type Node,\n type Point,\n type Scene,\n type Size,\n endpointNode,\n} from '../types.ts';\nimport { labelOf } from './constrained.ts';\n\nexport type GraphNode = { id: string; label?: string; type?: BuiltinNodeType };\nexport type GraphEdge = { id: string; from: string; to: string };\n\nexport type GraphModel = {\n nodes: GraphNode[];\n edges: GraphEdge[];\n};\n\n/** User adjustments layered over the engine's layout (react-ui-diagram's pattern). */\nexport type Overlay = {\n positions: Record<string, Point>;\n};\n\nexport type DynamicOptions = {\n pitch?: Size;\n size?: Size;\n /** The first slot's centre; by default the layout straddles the origin. */\n origin?: Point;\n};\n\n/** Multiples of the major grid, so a laid-out graph is already snapped. */\nconst DEFAULTS: Required<Omit<DynamicOptions, 'origin'>> = {\n pitch: { width: 256, height: 192 },\n size: { width: 192, height: 128 },\n};\n\nexport const DYNAMIC_SCENE_ID = 'dynamic';\n\n/** Rank rows top-down along the edges; columns are the order within a row. Overrides win. */\nexport const layoutGraph = (graph: GraphModel, overlay: Overlay, options: DynamicOptions = {}): Scene => {\n const { pitch, size } = { ...DEFAULTS, ...options };\n const ids = graph.nodes.map(({ id }) => id);\n const known = new Set(ids);\n const ranks = Layout.rank(\n ids,\n graph.edges.filter(({ from, to }) => known.has(from) && known.has(to)),\n );\n const byRow = new Map<number, string[]>();\n for (const id of ids) {\n const row = ranks.get(id) ?? 0;\n byRow.set(row, [...(byRow.get(row) ?? []), id]);\n }\n const columns = new Map<string, number>();\n for (const members of byRow.values()) {\n [...members].sort().forEach((id, index) => columns.set(id, index));\n }\n\n // Taken from the ranks rather than from the placed nodes, so dragging a node (which only writes an\n // override) leaves the rest of the graph where it is.\n const extent = {\n columns: Math.max(...[...byRow.values()].map(({ length }) => length), 1),\n rows: Math.max(...byRow.keys(), 0) + 1,\n };\n const origin = options.origin ?? centeredOrigin(extent, pitch, size);\n\n const keys = initialKeys(graph.nodes.length + graph.edges.length);\n const nodes: Record<string, Node> = {};\n graph.nodes.forEach((node, index) => {\n const override = overlay.positions[node.id];\n const center = override ?? {\n x: origin.x + (columns.get(node.id) ?? 0) * pitch.width,\n y: origin.y + (ranks.get(node.id) ?? 0) * pitch.height,\n };\n nodes[node.id] = withLabel(\n createNode({ type: node.type ?? 'rect', id: node.id, z: keys[graph.edges.length + index], center, size }),\n node.label ?? node.id,\n );\n });\n const links: Record<string, Link> = {};\n graph.edges.forEach((edge, index) => {\n if (known.has(edge.from) && known.has(edge.to)) {\n links[edge.id] = {\n type: 'curve',\n id: edge.id,\n z: keys[index],\n source: { node: edge.from },\n target: { node: edge.to },\n };\n }\n });\n return { id: DYNAMIC_SCENE_ID, name: 'Dynamic', nodes, links };\n};\n\n/** Drop overrides whose nodes are gone. */\nexport const pruneOverlay = (graph: GraphModel, overlay: Overlay): Overlay => {\n const known = new Set(graph.nodes.map(({ id }) => id));\n const positions = Object.fromEntries(Object.entries(overlay.positions).filter(([id]) => known.has(id)));\n return Object.keys(positions).length === Object.keys(overlay.positions).length ? overlay : { positions };\n};\n\ntype DynamicSnapshot = { graph: GraphModel; overlay: Overlay };\n\nconst isDynamicSnapshot = (value: unknown): value is DynamicSnapshot =>\n typeof value === 'object' && value !== null && 'graph' in value && 'overlay' in value;\n\nexport const dynamicCapabilities: Capabilities = { move: true, link: true, delete: true, update: true };\n\nexport type DynamicProjectionOptions = {\n registry: Registry.AtomRegistry;\n graph: Atom.Writable<GraphModel>;\n overlay: Atom.Writable<Overlay>;\n options?: DynamicOptions;\n};\n\nexport const createDynamicProjection = ({\n registry,\n graph,\n overlay,\n options,\n}: DynamicProjectionOptions): Projection => {\n const scene = Atom.keepAlive(\n Atom.make((get) => layoutGraph(get(graph), pruneOverlay(get(graph), get(overlay)), options)),\n );\n const apply = (intent: Intent) => {\n switch (intent.kind) {\n case 'move': {\n const current = registry.get(scene);\n const positions = { ...registry.get(overlay).positions };\n for (const id of intent.ids) {\n const node = current.nodes[id];\n if (node) {\n positions[id] = { x: node.center.x + intent.delta.x, y: node.center.y + intent.delta.y };\n }\n }\n registry.set(overlay, { positions });\n break;\n }\n case 'link': {\n const model = registry.get(graph);\n const { link } = intent;\n const from = endpointNode(link.source);\n const to = endpointNode(link.target);\n // The graph has edges between nodes only; a free-ended link has no place in it.\n if (from === undefined || to === undefined || model.edges.some((edge) => edge.id === link.id)) {\n return;\n }\n registry.set(graph, { ...model, edges: [...model.edges, { id: link.id, from, to }] });\n break;\n }\n case 'delete': {\n const ids = new Set(intent.ids);\n const model = registry.get(graph);\n registry.set(graph, {\n nodes: model.nodes.filter(({ id }) => !ids.has(id)),\n edges: model.edges.filter(({ id, from, to }) => !ids.has(id) && !ids.has(from) && !ids.has(to)),\n });\n break;\n }\n case 'batch':\n intent.intents.forEach(apply);\n break;\n case 'update': {\n // The label is the graph's; a geometry edit becomes an override like a move would.\n const model = registry.get(graph);\n const label = labelOf(intent.values);\n if (label !== undefined) {\n registry.set(graph, {\n ...model,\n nodes: model.nodes.map((node) => (node.id === intent.id ? { ...node, label } : node)),\n });\n }\n if ('center' in intent.values && intent.values.center) {\n const center = intent.values.center;\n registry.set(overlay, { positions: { ...registry.get(overlay).positions, [intent.id]: center } });\n }\n break;\n }\n default:\n break;\n }\n };\n return {\n scene,\n apply,\n capabilities: dynamicCapabilities,\n // Both atoms in one value, so an undo restores the layout and the overrides together.\n snapshot: () => ({ graph: registry.get(graph), overlay: registry.get(overlay) }),\n restore: (snapshot) => {\n if (isDynamicSnapshot(snapshot)) {\n registry.set(graph, snapshot.graph);\n registry.set(overlay, snapshot.overlay);\n }\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Lattice projection (docs/DESIGN.md §8b): freehand semantics, with every change to a node's geometry\n// snapped onto the lattice and refused when it would overlap another node's cells. Nodes stay in scene\n// pixels, so a lattice scene is stored exactly as a freehand one; the rule lives here, not in the data.\n//\n\nimport {\n DEFAULT_LATTICE,\n type LatticeSpec,\n cellBounds,\n collides,\n coveredCells,\n occupancy,\n quantize,\n resizeCell,\n toCell,\n} from '../../utils/lattice.ts';\nimport { nodeBounds, resizeNode } from '../../utils/shapes.ts';\nimport {\n type FreehandProjectionOptions,\n type Projection,\n createFreehandProjection,\n freehandCapabilities,\n reduceIntent,\n} from '../projection.ts';\nimport { type Bounds, type Capabilities, type ElementId, type Intent, type Node, type Scene } from '../types.ts';\n\n/** Freehand, without auto layout: arranging by a layout engine would not respect the lattice. */\nexport const latticeCapabilities: Capabilities = { ...freehandCapabilities, layout: false };\n\n/** The bounds `node` would have after `values` (a geometry `update`), or undefined when they touch no geometry. */\nconst updatedBounds = (node: Node, values: object): Bounds | undefined => {\n const center = 'center' in values && isPoint(values.center) ? values.center : undefined;\n const size = 'size' in values && isSize(values.size) ? values.size : undefined;\n if (!center && !size) {\n return undefined;\n }\n return nodeBounds({ ...node, center: center ?? node.center, size: size ?? node.size });\n};\n\nconst isPoint = (value: unknown): value is { x: number; y: number } =>\n typeof value === 'object' && value !== null && 'x' in value && 'y' in value;\n\nconst isSize = (value: unknown): value is { width: number; height: number } =>\n typeof value === 'object' && value !== null && 'width' in value && 'height' in value;\n\n/** Whether `bounds` (snapped) would overlap a node other than `except`. */\nconst blocked = (scene: Scene, spec: LatticeSpec, bounds: Bounds, except: ReadonlySet<ElementId>): boolean =>\n collides(toCell(bounds, spec), occupancy(Object.values(scene.nodes), spec, except));\n\n/**\n * `intent` rewritten onto the lattice, or undefined when it would overlap occupied cells. Geometry\n * (create, move, resize, a centre or size `update`) is snapped; everything else passes through. A batch\n * is checked step by step against the scene each step leaves, and is refused whole if any step is.\n */\nexport const constrainIntent = (scene: Scene, intent: Intent, spec: LatticeSpec): Intent | undefined => {\n switch (intent.kind) {\n case 'create': {\n const bounds = quantize(nodeBounds(intent.node), spec);\n return blocked(scene, spec, bounds, new Set())\n ? undefined\n : { kind: 'create', node: resizeNode(intent.node, bounds) };\n }\n\n case 'resize': {\n // The dragged edge snaps to a cell edge and the opposite edge stays, so a face steps one cell at a time.\n const node = scene.nodes[intent.id];\n const from = node && nodeBounds(node);\n const bounds = from\n ? cellBounds(resizeCell(toCell(from, spec), from, intent.bounds, spec), spec)\n : quantize(intent.bounds, spec);\n return blocked(scene, spec, bounds, new Set([intent.id])) ? undefined : { kind: 'resize', id: intent.id, bounds };\n }\n\n case 'move': {\n // Each moved node snaps on its own; together they must clear the nodes left behind and each other.\n const moving = new Set(intent.ids);\n const others = occupancy(Object.values(scene.nodes), spec, moving);\n const taken = new Map<string, ElementId>();\n const intents: Intent[] = [];\n for (const id of intent.ids) {\n const node = scene.nodes[id];\n if (!node || node.locked) {\n continue;\n }\n const from = nodeBounds(node);\n const bounds = quantize({ ...from, x: from.x + intent.delta.x, y: from.y + intent.delta.y }, spec);\n const cell = toCell(bounds, spec);\n if (collides(cell, others) || collides(cell, taken)) {\n return undefined;\n }\n for (const key of coveredCells(cell)) {\n taken.set(key, id);\n }\n intents.push({ kind: 'resize', id, bounds });\n }\n return { kind: 'batch', intents };\n }\n\n case 'update': {\n const node = scene.nodes[intent.id];\n const bounds = node && updatedBounds(node, intent.values);\n if (!node || !bounds) {\n return intent;\n }\n const snapped = quantize(bounds, spec);\n if (blocked(scene, spec, snapped, new Set([intent.id]))) {\n return undefined;\n }\n const placed = resizeNode(node, snapped);\n return { kind: 'update', id: intent.id, values: { ...intent.values, center: placed.center, size: placed.size } };\n }\n\n case 'batch': {\n let working = scene;\n const intents: Intent[] = [];\n for (const step of intent.intents) {\n const constrained = constrainIntent(working, step, spec);\n if (!constrained) {\n return undefined;\n }\n intents.push(constrained);\n working = reduceIntent(working, constrained);\n }\n return { kind: 'batch', intents };\n }\n\n case 'layout':\n return undefined;\n\n default:\n return intent;\n }\n};\n\nexport type LatticeProjectionOptions = FreehandProjectionOptions & {\n spec?: LatticeSpec;\n};\n\n/**\n * Freehand over the store, with geometry kept on the lattice; an intent that would overlap is refused. While\n * `constrained` says no (the view's snap is off) intents pass through as freehand, and a shape left off the\n * lattice snaps onto it the next time it is moved.\n */\nexport const createLatticeProjection = ({\n registry,\n store,\n sceneId,\n constrained = () => true,\n spec = DEFAULT_LATTICE,\n}: LatticeProjectionOptions): Projection => {\n const freehand = createFreehandProjection({ registry, store, sceneId });\n const constrain = (intent: Intent) =>\n constrained() ? constrainIntent(registry.get(freehand.scene), intent, spec) : intent;\n return {\n ...freehand,\n capabilities: latticeCapabilities,\n lattice: spec,\n constrain,\n apply: (intent) => {\n const constrained = constrain(intent);\n if (constrained) {\n freehand.apply(constrained);\n }\n },\n };\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Declarative scene fixtures for stories and tests: a scene is a tree of element values, each made by a\n// factory and refined with `properties()`, so a fixture reads like the diagram it describes. A nested\n// `scene` is a scene shape and its child scene in one; `build()` flattens the tree into the scenes a\n// store holds. Boxes are top-left; refs like `a#e2` name a port and `@x,y` a free end.\n//\n\nimport * as Exit from 'effect/Exit';\nimport * as Schema from 'effect/Schema';\n\nimport { type NodeRegistry, defaultNodeRegistry } from '../model/registry.ts';\nimport {\n type BuiltinNode,\n type BuiltinNodeType,\n type Endpoint,\n type Link,\n type LinkType,\n type Node,\n type NodeBase,\n type NodeStyle,\n type Point,\n type PortalNode,\n type Scene,\n type SceneId,\n} from '../model/types.ts';\nimport { initialKeys } from './order.ts';\nimport { createNode } from './shapes.ts';\n\n/** Top-left box geometry; the builder stores the centre. */\nexport type Box = { x: number; y: number; width: number; height: number };\n\nconst center = ({ x, y, width, height }: Box): Point => ({ x: x + width / 2, y: y + height / 2 });\n\n/** `node`, `node#port`, or a free end `@x,y`. */\nconst endpoint = (ref: string): Endpoint => {\n if (ref.startsWith('@')) {\n const [x, y] = ref.slice(1).split(',').map(Number);\n return { point: { x, y } };\n }\n const [node, port] = ref.split('#');\n return port ? { node, port } : { node };\n};\n\ntype NodeOf<T extends BuiltinNodeType> = Extract<BuiltinNode, { type: T }>;\ntype LinkOf<T extends LinkType> = Extract<Link, { type: T }>;\n\n/** What `properties()` may set on a node: everything but its identity, its paint order and the frame its box fixes. */\nexport type NodeProperties<N> = Partial<Omit<N, 'id' | 'type' | 'z' | 'center' | 'size'>>;\n\n/** What `properties()` may set on a link: everything but its identity, its paint order and its ends. */\nexport type LinkProperties<L> = Partial<Omit<L, 'id' | 'type' | 'z' | 'source' | 'target'>>;\n\ntype NodeBody = Omit<NodeBase, 'z'> & Record<string, unknown>;\ntype LinkBody = DistributiveOmit<Link, 'z' | 'id'>;\n\n/** `Omit` over each member of a union, not over their intersection. */\ntype DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;\n\n/** Later values win; `style` merges key by key, so one call can add a hue without dropping another's fill. */\nconst mergeStyle = (base: { style?: NodeStyle }, values: { style?: NodeStyle }) =>\n base.style || values.style ? { style: { ...base.style, ...values.style } } : {};\n\n/**\n * A node of the scene, as written: refine it with `properties()`, which returns a new value. `N` types\n * the properties; `build()` checks the result against the type's schema.\n */\nexport class NodeElement<N extends NodeBase> {\n readonly kind = 'node';\n\n constructor(readonly node: NodeBody) {}\n\n properties(values: NodeProperties<N>): NodeElement<N> {\n return new NodeElement<N>({ ...this.node, ...values, ...mergeStyle(this.node, values) });\n }\n}\n\n/** A link of the scene, as written; its id defaults to its ends (`a-b`), unique within the scene. */\nexport class LinkElement<L extends Link> {\n readonly kind = 'link';\n\n constructor(\n readonly link: LinkBody,\n readonly linkId?: string,\n ) {}\n\n id(id: string): LinkElement<L> {\n return new LinkElement<L>(this.link, id);\n }\n\n properties(values: LinkProperties<L>): LinkElement<L> {\n return new LinkElement<L>({ ...this.link, ...values }, this.linkId);\n }\n}\n\nexport type BuilderElement = NodeElement<NodeBase> | LinkElement<Link> | SceneElement;\n\n/**\n * A scene and its elements in paint order. At the top it is the root scene; nested, it is also a scene\n * shape placed with `at()`, whose child scene shares its id.\n */\nexport class SceneElement {\n readonly kind = 'scene';\n\n constructor(\n readonly id: SceneId,\n readonly elements: readonly BuilderElement[],\n readonly frame?: Box,\n readonly sceneName?: string,\n readonly portal: NodeProperties<PortalNode> = {},\n ) {}\n\n /** The scene's name (breadcrumbs, previews). */\n name(name: string): SceneElement {\n return new SceneElement(this.id, this.elements, this.frame, name, this.portal);\n }\n\n /** Where the scene shape sits in its parent scene; required for a nested scene. */\n at(box: Box): SceneElement {\n return new SceneElement(this.id, this.elements, box, this.sceneName, this.portal);\n }\n\n /** The scene shape's own properties (label, contents, style). */\n properties(values: NodeProperties<PortalNode>): SceneElement {\n return new SceneElement(this.id, this.elements, this.frame, this.sceneName, {\n ...this.portal,\n ...values,\n ...mergeStyle(this.portal, values),\n });\n }\n\n /** Every scene of the tree, the root first, checked against `registry`'s node schemas. */\n build(registry: NodeRegistry = defaultNodeRegistry): SceneTree {\n const scenes: Scene[] = [];\n buildScene(this, registry, scenes);\n return { root: this.id, scenes };\n }\n}\n\nexport type SceneTree = { root: SceneId; scenes: Scene[] };\n\nconst buildScene = (element: SceneElement, registry: NodeRegistry, scenes: Scene[]): void => {\n const nodes: Record<string, Node> = {};\n const links: Record<string, Link> = {};\n const keys = initialKeys(element.elements.length);\n const index = scenes.push({ id: element.id, name: element.sceneName, nodes, links }) - 1;\n element.elements.forEach((child, order) => {\n const z = keys[order];\n switch (child.kind) {\n case 'node': {\n const node = { ...child.node, z };\n check(registry, node);\n nodes[node.id] = node;\n break;\n }\n case 'link': {\n const id = child.linkId ?? uniqueId(links, linkId(child.link.source, child.link.target));\n links[id] = { ...child.link, id, z };\n break;\n }\n case 'scene': {\n if (!child.frame) {\n throw new Error(`Nested scene ${child.id} needs a frame: call at(box).`);\n }\n const node: PortalNode = {\n ...createNode({ type: 'scene', id: child.id, z, center: center(child.frame), size: sizeOf(child.frame) }),\n ...child.portal,\n type: 'scene',\n scene: child.id,\n };\n check(registry, node);\n nodes[node.id] = node;\n buildScene(child, registry, scenes);\n break;\n }\n }\n });\n scenes[index] = { ...scenes[index], nodes, links };\n};\n\n/** A node its type does not describe (a wrong value, or a property the type does not have) fails the build. */\nconst check = (registry: NodeRegistry, node: Node): void => {\n const def = registry[node.type];\n if (!def) {\n return;\n }\n const result = Schema.encodeExit(def.schema, { onExcessProperty: 'error' })(node);\n if (Exit.isFailure(result)) {\n throw new Error(`Node ${node.id} is not a valid ${node.type}: ${result.cause}`);\n }\n};\n\nconst linkId = (source: Endpoint, target: Endpoint): string => {\n const name = (end: Endpoint) => ('node' in end ? end.node : `${end.point.x},${end.point.y}`);\n return `${name(source)}-${name(target)}`;\n};\n\nconst uniqueId = (taken: Record<string, unknown>, id: string): string => {\n let candidate = id;\n for (let suffix = 2; candidate in taken; ++suffix) {\n candidate = `${id}-${suffix}`;\n }\n return candidate;\n};\n\nconst sizeOf = ({ width, height }: Box) => ({ width, height });\n\n/** A built-in node of `type` with the type's default content, refined by `properties()`. */\nfunction node<T extends BuiltinNodeType>(type: T, id: string, box: Box): NodeElement<NodeOf<T>>;\n/** A host node type: whatever the host's registry schema accepts. */\nfunction node(type: string, id: string, box: Box): NodeElement<NodeBase & Record<string, unknown>>;\nfunction node(type: string, id: string, box: Box): NodeElement<NodeBase> {\n const base = { type, id, center: center(box), size: sizeOf(box) };\n if (isBuiltinType(type)) {\n const { z: _, ...fresh } = createNode({ ...base, type, z: '' });\n return new NodeElement<NodeBase>({ ...fresh });\n }\n return new NodeElement<NodeBase>(base);\n}\n\nconst BUILTIN_TYPES: readonly string[] = ['rect', 'ellipse', 'class', 'note', 'scene'] satisfies BuiltinNodeType[];\nconst isBuiltinType = (type: string): type is BuiltinNodeType => BUILTIN_TYPES.includes(type);\n\ntype Ends = Pick<Link, 'source' | 'target'>;\n\nconst LINKS: Record<LinkType, (ends: Ends) => LinkBody> = {\n line: (ends) => ({ type: 'line', ...ends }),\n curve: (ends) => ({ type: 'curve', ...ends }),\n spline: (ends) => ({ type: 'spline', ...ends, points: [] }),\n smart: (ends) => ({ type: 'smart', ...ends }),\n};\n\n/** A link of `type` from one ref to another; a spline starts with no control points. */\nconst link = <T extends LinkType>(type: T, from: string, to: string): LinkElement<LinkOf<T>> =>\n new LinkElement<LinkOf<T>>(LINKS[type]({ source: endpoint(from), target: endpoint(to) }));\n\n/** Factories for scene fixtures; see the module comment. */\nexport const SceneBuilder = {\n /** A scene of `elements`; the root of a fixture, or nested, a scene shape and its child scene. */\n scene: (id: SceneId, elements: readonly BuilderElement[] = []) => new SceneElement(id, elements),\n node,\n rect: (id: string, box: Box) => node('rect', id, box),\n ellipse: (id: string, box: Box) => node('ellipse', id, box),\n class: (id: string, box: Box) => node('class', id, box),\n note: (id: string, box: Box) => node('note', id, box),\n link,\n};\n","//\n// Copyright 2026 DXOS.org\n//\n\n//\n// Bridge from the scene engine to `@dxos/diagram`'s scene, so its `Diagnostics` and `Objective` —\n// the measurements the layout engines are selected by — can grade a scene a person is editing.\n//\n\nimport { type Scene as Diagram } from '@dxos/diagram';\n\nimport { type NodeRegistry } from '../model/registry.ts';\nimport {\n type ElementId,\n type Link,\n type Node,\n type Point,\n type Scene,\n isClassNode,\n isEllipseNode,\n isNoteNode,\n isRectNode,\n} from '../model/types.ts';\nimport { curvePoint, linkGeometry, smartPoints } from './route.ts';\nimport { nodeBounds } from './shapes.ts';\n\n/** Samples per curve: enough for crossings and routes-through-node to see the arc, not just its chord. */\nconst CURVE_SAMPLES = 8;\n\nexport type DiagramObjects = {\n objects: Diagram.WorldObject[];\n /** Scene element id for each diagram object id, to map a diagnostic's refs back onto the scene. */\n elementOf: ReadonlyMap<string, ElementId>;\n};\n\n/**\n * `Diagnostics` reads the owning object as the ref's prefix up to `/`, and `#` as a port; percent-encoding\n * removes both and stays injective, so distinct ids never merge into one owner.\n */\nconst objectId = (id: ElementId): string => encodeURIComponent(id);\n\nconst nodeText = (node: Node): string | undefined => {\n if (isRectNode(node) || isEllipseNode(node)) {\n return node.label;\n }\n if (isClassNode(node)) {\n return node.name;\n }\n if (isNoteNode(node)) {\n return node.text;\n }\n return undefined;\n};\n\n/** The polyline a link is drawn along, in scene coordinates. */\nconst linkPoints = (scene: Scene, registry: NodeRegistry, link: Link): Point[] | undefined => {\n const geometry = linkGeometry(scene, registry, link);\n if (!geometry) {\n return undefined;\n }\n const { source, target } = geometry;\n switch (link.type) {\n case 'line':\n return [source.point, target.point];\n case 'spline':\n return [source.point, ...link.points, target.point];\n case 'smart':\n return smartPoints(source, target);\n case 'curve':\n return Array.from({ length: CURVE_SAMPLES + 1 }, (_, index) => curvePoint(source, target, index / CURVE_SAMPLES));\n }\n};\n\n/**\n * One diagram object per node (a box with its label) and per link (a polyline), so `Diagnostics`\n * compares nodes across objects exactly as it does for an engine's output. Nodes that enclose\n * others read as containers there, which is what a guide frame around a group is.\n */\nexport const toDiagramObjects = (scene: Scene, registry: NodeRegistry): DiagramObjects => {\n const elementOf = new Map<string, ElementId>();\n const objects: Diagram.WorldObject[] = [];\n for (const node of Object.values(scene.nodes)) {\n const { x, y, width, height } = nodeBounds(node);\n const id = objectId(node.id);\n elementOf.set(id, node.id);\n objects.push({\n id,\n elements: [\n {\n kind: isEllipseNode(node) ? 'ellipse' : 'rect',\n id: 'box',\n x,\n y,\n w: width,\n h: height,\n ...(node.style?.guide ? {} : { text: nodeText(node) }),\n },\n ],\n });\n }\n for (const link of Object.values(scene.links)) {\n const points = linkPoints(scene, registry, link);\n if (!points || points.length < 2) {\n continue;\n }\n const id = objectId(link.id);\n elementOf.set(id, link.id);\n objects.push({ id, elements: [{ kind: 'line', id: 'path', points }] });\n }\n return { objects, elementOf };\n};\n\n/** The scene elements a diagnostic implicates, from its `object/element` refs. */\nexport const diagnosticElements = ({ elementOf }: DiagramObjects, refs: readonly string[]): ElementId[] =>\n refs.flatMap((ref) => {\n const element = elementOf.get(ref.slice(0, ref.indexOf('/')));\n return element ? [element] : [];\n });\n"],"mappings":"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"}