project-graph-mcp 2.3.2 → 2.4.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 (279) hide show
  1. package/package.json +3 -2
  2. package/src/analysis/analysis-cache.ctx +9 -0
  3. package/src/analysis/analysis-cache.js +1 -1
  4. package/src/analysis/complexity.ctx +6 -0
  5. package/src/analysis/complexity.js +1 -1
  6. package/src/analysis/custom-rules.ctx +14 -0
  7. package/src/analysis/custom-rules.js +1 -1
  8. package/src/analysis/db-analysis.ctx +7 -0
  9. package/src/analysis/db-analysis.js +1 -1
  10. package/src/analysis/dead-code.ctx +6 -0
  11. package/src/analysis/dead-code.js +1 -1
  12. package/src/analysis/full-analysis.ctx +9 -0
  13. package/src/analysis/full-analysis.js +1 -1
  14. package/src/analysis/jsdoc-checker.ctx +10 -0
  15. package/src/analysis/jsdoc-checker.js +1 -1
  16. package/src/analysis/jsdoc-generator.ctx +9 -0
  17. package/src/analysis/jsdoc-generator.js +1 -1
  18. package/src/analysis/large-files.ctx +6 -0
  19. package/src/analysis/large-files.js +1 -1
  20. package/src/analysis/outdated-patterns.ctx +7 -0
  21. package/src/analysis/outdated-patterns.js +1 -1
  22. package/src/analysis/similar-functions.ctx +6 -0
  23. package/src/analysis/similar-functions.js +1 -1
  24. package/src/analysis/test-annotations.ctx +11 -0
  25. package/src/analysis/test-annotations.js +1 -1
  26. package/src/analysis/type-checker.ctx +6 -0
  27. package/src/analysis/type-checker.js +1 -1
  28. package/src/analysis/undocumented.ctx +8 -0
  29. package/src/analysis/undocumented.js +1 -1
  30. package/src/cli/cli-handlers.ctx +7 -0
  31. package/src/cli/cli-handlers.js +1 -1
  32. package/src/cli/cli.ctx +6 -0
  33. package/src/cli/cli.js +1 -1
  34. package/src/compact/ai-context.ctx +6 -0
  35. package/src/compact/ai-context.js +1 -1
  36. package/src/compact/compact-migrate.ctx +8 -0
  37. package/src/compact/compact-migrate.js +1 -1
  38. package/src/compact/compact.ctx +11 -0
  39. package/src/compact/compact.js +1 -1
  40. package/src/compact/compress.ctx +7 -0
  41. package/src/compact/compress.js +1 -1
  42. package/src/compact/ctx-resolver.ctx +2 -0
  43. package/src/compact/ctx-resolver.js +1 -1
  44. package/src/compact/ctx-to-jsdoc.ctx +11 -0
  45. package/src/compact/ctx-to-jsdoc.js +1 -1
  46. package/src/compact/doc-dialect.ctx +11 -0
  47. package/src/compact/doc-dialect.js +2 -2
  48. package/src/compact/expand.ctx +14 -0
  49. package/src/compact/expand.js +1 -1
  50. package/src/compact/framework-references.ctx +7 -0
  51. package/src/compact/framework-references.js +1 -1
  52. package/src/compact/instructions.ctx +6 -0
  53. package/src/compact/instructions.js +1 -1
  54. package/src/compact/jsdoc-builder.ctx +4 -0
  55. package/src/compact/jsdoc-builder.js +1 -1
  56. package/src/compact/mode-config.ctx +8 -0
  57. package/src/compact/mode-config.js +1 -1
  58. package/src/compact/split-declarations.ctx +6 -0
  59. package/src/compact/split-declarations.js +1 -1
  60. package/src/compact/validate-pipeline.ctx +12 -0
  61. package/src/compact/validate-pipeline.js +1 -1
  62. package/src/core/event-bus.ctx +9 -0
  63. package/src/core/event-bus.js +1 -1
  64. package/src/core/file-walker.ctx +1 -0
  65. package/src/core/file-walker.js +1 -1
  66. package/src/core/filters.ctx +12 -0
  67. package/src/core/filters.js +1 -1
  68. package/src/core/graph-builder.ctx +7 -0
  69. package/src/core/graph-builder.js +1 -1
  70. package/src/core/parser.ctx +12 -0
  71. package/src/core/parser.js +1 -1
  72. package/src/core/utils.ctx +1 -0
  73. package/src/core/utils.js +1 -1
  74. package/src/core/workspace.ctx +7 -0
  75. package/src/core/workspace.js +1 -1
  76. package/src/lang/lang-go.ctx +8 -0
  77. package/src/lang/lang-go.js +1 -1
  78. package/src/lang/lang-python.ctx +5 -0
  79. package/src/lang/lang-python.js +1 -1
  80. package/src/lang/lang-sql.ctx +10 -0
  81. package/src/lang/lang-sql.js +1 -1
  82. package/src/lang/lang-typescript.ctx +6 -0
  83. package/src/lang/lang-typescript.js +1 -1
  84. package/src/lang/lang-utils.ctx +5 -0
  85. package/src/lang/lang-utils.js +1 -1
  86. package/src/mcp/mcp-server.ctx +6 -0
  87. package/src/mcp/mcp-server.js +1 -1
  88. package/src/mcp/tool-defs.ctx +2 -0
  89. package/src/mcp/tool-defs.js +1 -1
  90. package/src/mcp/tools.ctx +13 -0
  91. package/src/mcp/tools.js +1 -1
  92. package/src/network/backend-lifecycle.ctx +10 -0
  93. package/src/network/backend-lifecycle.js +1 -1
  94. package/src/network/backend.ctx +5 -0
  95. package/src/network/backend.js +1 -1
  96. package/src/network/local-gateway.ctx +9 -0
  97. package/src/network/local-gateway.js +1 -1
  98. package/src/network/mdns.ctx +6 -0
  99. package/src/network/mdns.js +1 -1
  100. package/src/network/server.ctx +2 -0
  101. package/src/network/server.js +2 -2
  102. package/src/network/web-server.ctx +17 -0
  103. package/src/network/web-server.js +2 -2
  104. package/web/follow-controller.js +94 -25
  105. package/web/panels/dep-graph.js +207 -21
  106. package/project-graph-mcp-2.3.0.tgz +0 -0
  107. package/vendor/symbiote-node/CHANGELOG.md +0 -31
  108. package/vendor/symbiote-node/LICENSE +0 -21
  109. package/vendor/symbiote-node/README.md +0 -206
  110. package/vendor/symbiote-node/canvas/AutoLayout.js +0 -725
  111. package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.css.js +0 -73
  112. package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.js +0 -93
  113. package/vendor/symbiote-node/canvas/Breadcrumb/Breadcrumb.tpl.js +0 -9
  114. package/vendor/symbiote-node/canvas/CanvasConnectionRenderer.js +0 -962
  115. package/vendor/symbiote-node/canvas/ConnectionRenderer.js +0 -1468
  116. package/vendor/symbiote-node/canvas/FlowSimulator.js +0 -323
  117. package/vendor/symbiote-node/canvas/ForceLayout.js +0 -189
  118. package/vendor/symbiote-node/canvas/ForceWorker.js +0 -1325
  119. package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.css.js +0 -97
  120. package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.js +0 -176
  121. package/vendor/symbiote-node/canvas/GraphTabs/GraphTabs.tpl.js +0 -12
  122. package/vendor/symbiote-node/canvas/LODManager.js +0 -88
  123. package/vendor/symbiote-node/canvas/Minimap/Minimap.css.js +0 -71
  124. package/vendor/symbiote-node/canvas/Minimap/Minimap.js +0 -207
  125. package/vendor/symbiote-node/canvas/Minimap/Minimap.tpl.js +0 -9
  126. package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.css.js +0 -261
  127. package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.js +0 -1840
  128. package/vendor/symbiote-node/canvas/NodeCanvas/NodeCanvas.tpl.js +0 -22
  129. package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.css.js +0 -97
  130. package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.js +0 -132
  131. package/vendor/symbiote-node/canvas/NodeSearch/NodeSearch.tpl.js +0 -21
  132. package/vendor/symbiote-node/canvas/NodeViewManager.js +0 -584
  133. package/vendor/symbiote-node/canvas/PinExpansion.js +0 -131
  134. package/vendor/symbiote-node/canvas/PseudoConnection.js +0 -80
  135. package/vendor/symbiote-node/canvas/SubgraphManager.js +0 -201
  136. package/vendor/symbiote-node/canvas/SubgraphRouter.js +0 -443
  137. package/vendor/symbiote-node/canvas/ViewportActions.js +0 -446
  138. package/vendor/symbiote-node/core/Connection.js +0 -45
  139. package/vendor/symbiote-node/core/Editor.js +0 -451
  140. package/vendor/symbiote-node/core/Frame.js +0 -31
  141. package/vendor/symbiote-node/core/GraphMermaid.js +0 -348
  142. package/vendor/symbiote-node/core/GraphText.js +0 -210
  143. package/vendor/symbiote-node/core/Node.js +0 -143
  144. package/vendor/symbiote-node/core/Portal.js +0 -104
  145. package/vendor/symbiote-node/core/Socket.js +0 -185
  146. package/vendor/symbiote-node/core/SubgraphNode.js +0 -125
  147. package/vendor/symbiote-node/engine/AgentUICommands.js +0 -100
  148. package/vendor/symbiote-node/engine/Executor.js +0 -371
  149. package/vendor/symbiote-node/engine/Graph.js +0 -314
  150. package/vendor/symbiote-node/engine/GraphServer.js +0 -353
  151. package/vendor/symbiote-node/engine/HandlerLoader.js +0 -145
  152. package/vendor/symbiote-node/engine/History.js +0 -83
  153. package/vendor/symbiote-node/engine/Lifecycle.js +0 -118
  154. package/vendor/symbiote-node/engine/Persistence.js +0 -84
  155. package/vendor/symbiote-node/engine/Registry.js +0 -264
  156. package/vendor/symbiote-node/engine/SocketTypes.js +0 -79
  157. package/vendor/symbiote-node/engine/cli.js +0 -404
  158. package/vendor/symbiote-node/engine/index.js +0 -56
  159. package/vendor/symbiote-node/engine/nanoid.js +0 -28
  160. package/vendor/symbiote-node/engine/package.json +0 -26
  161. package/vendor/symbiote-node/engine/packs/ai/beat-detect.handler.js +0 -215
  162. package/vendor/symbiote-node/engine/packs/ai/content-adapt.handler.js +0 -238
  163. package/vendor/symbiote-node/engine/packs/ai/face-detect.handler.js +0 -287
  164. package/vendor/symbiote-node/engine/packs/ai/grok-generate.handler.js +0 -565
  165. package/vendor/symbiote-node/engine/packs/ai/kling-lipsync.handler.js +0 -414
  166. package/vendor/symbiote-node/engine/packs/ai/lesson-generate.handler.js +0 -343
  167. package/vendor/symbiote-node/engine/packs/ai/opencode.handler.js +0 -164
  168. package/vendor/symbiote-node/engine/packs/ai/replicate-lipsync.handler.js +0 -341
  169. package/vendor/symbiote-node/engine/packs/ai/tts.handler.js +0 -241
  170. package/vendor/symbiote-node/engine/packs/ai/whisper.handler.js +0 -191
  171. package/vendor/symbiote-node/engine/packs/data/db-query.handler.js +0 -67
  172. package/vendor/symbiote-node/engine/packs/data/news-accumulate.handler.js +0 -281
  173. package/vendor/symbiote-node/engine/packs/data/personas.handler.js +0 -160
  174. package/vendor/symbiote-node/engine/packs/data/prompt-loader.handler.js +0 -193
  175. package/vendor/symbiote-node/engine/packs/data/roles.handler.js +0 -216
  176. package/vendor/symbiote-node/engine/packs/data/rss-feed.handler.js +0 -244
  177. package/vendor/symbiote-node/engine/packs/debug/inject.handler.js +0 -52
  178. package/vendor/symbiote-node/engine/packs/flow/agent.handler.js +0 -73
  179. package/vendor/symbiote-node/engine/packs/flow/if.handler.js +0 -107
  180. package/vendor/symbiote-node/engine/packs/flow/loop.handler.js +0 -58
  181. package/vendor/symbiote-node/engine/packs/flow/merge.handler.js +0 -60
  182. package/vendor/symbiote-node/engine/packs/flow/retry.handler.js +0 -65
  183. package/vendor/symbiote-node/engine/packs/flow/switch.handler.js +0 -64
  184. package/vendor/symbiote-node/engine/packs/flow/wait-all.handler.js +0 -39
  185. package/vendor/symbiote-node/engine/packs/io/http-request.handler.js +0 -82
  186. package/vendor/symbiote-node/engine/packs/io/read-file.handler.js +0 -60
  187. package/vendor/symbiote-node/engine/packs/io/write-file.handler.js +0 -63
  188. package/vendor/symbiote-node/engine/packs/transform/anchor-match.handler.js +0 -494
  189. package/vendor/symbiote-node/engine/packs/transform/effects-skeleton.handler.js +0 -417
  190. package/vendor/symbiote-node/engine/packs/transform/json-parse.handler.js +0 -43
  191. package/vendor/symbiote-node/engine/packs/transform/lipsync-select.handler.js +0 -339
  192. package/vendor/symbiote-node/engine/packs/transform/riopla-adapt.handler.js +0 -432
  193. package/vendor/symbiote-node/engine/packs/transform/set.handler.js +0 -57
  194. package/vendor/symbiote-node/engine/packs/transform/template-builder.handler.js +0 -134
  195. package/vendor/symbiote-node/engine/packs/transform/template.handler.js +0 -79
  196. package/vendor/symbiote-node/engine/packs/transform/timeline-build.handler.js +0 -399
  197. package/vendor/symbiote-node/engine/packs/util/delay.handler.js +0 -39
  198. package/vendor/symbiote-node/engine/packs/util/log.handler.js +0 -44
  199. package/vendor/symbiote-node/engine/packs/video-pack.js +0 -323
  200. package/vendor/symbiote-node/index.js +0 -103
  201. package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.css.js +0 -361
  202. package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.js +0 -332
  203. package/vendor/symbiote-node/inspector/InspectorPanel/InspectorPanel.tpl.js +0 -96
  204. package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.css.js +0 -104
  205. package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.js +0 -133
  206. package/vendor/symbiote-node/inspector/TemplatePreview/TemplatePreview.tpl.js +0 -33
  207. package/vendor/symbiote-node/interactions/ConnectFlow.js +0 -307
  208. package/vendor/symbiote-node/interactions/Drag.js +0 -102
  209. package/vendor/symbiote-node/interactions/Selector.js +0 -132
  210. package/vendor/symbiote-node/interactions/SnapGrid.js +0 -65
  211. package/vendor/symbiote-node/interactions/Zoom.js +0 -140
  212. package/vendor/symbiote-node/layout/ActionZone/ActionZone.css.js +0 -88
  213. package/vendor/symbiote-node/layout/ActionZone/ActionZone.js +0 -254
  214. package/vendor/symbiote-node/layout/ActionZone/ActionZone.tpl.js +0 -11
  215. package/vendor/symbiote-node/layout/Layout/Layout.css.js +0 -88
  216. package/vendor/symbiote-node/layout/Layout/Layout.js +0 -622
  217. package/vendor/symbiote-node/layout/Layout/Layout.tpl.js +0 -25
  218. package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.css.js +0 -293
  219. package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.js +0 -467
  220. package/vendor/symbiote-node/layout/LayoutNode/LayoutNode.tpl.js +0 -33
  221. package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.css.js +0 -46
  222. package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.js +0 -102
  223. package/vendor/symbiote-node/layout/LayoutPreview/LayoutPreview.tpl.js +0 -6
  224. package/vendor/symbiote-node/layout/LayoutRouter/LayoutRouter.js +0 -156
  225. package/vendor/symbiote-node/layout/LayoutRouter/routerSync.js +0 -250
  226. package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.css.js +0 -379
  227. package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.js +0 -263
  228. package/vendor/symbiote-node/layout/LayoutSidebar/LayoutSidebar.tpl.js +0 -20
  229. package/vendor/symbiote-node/layout/LayoutSidebar/SidebarSection.js +0 -183
  230. package/vendor/symbiote-node/layout/LayoutTree.js +0 -246
  231. package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.css.js +0 -43
  232. package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.js +0 -89
  233. package/vendor/symbiote-node/layout/PanelMenu/PanelMenu.tpl.js +0 -14
  234. package/vendor/symbiote-node/layout/index.js +0 -16
  235. package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.css.js +0 -61
  236. package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.js +0 -79
  237. package/vendor/symbiote-node/menu/ContextMenu/ContextMenu.tpl.js +0 -19
  238. package/vendor/symbiote-node/node/CtrlItem/CtrlItem.css.js +0 -41
  239. package/vendor/symbiote-node/node/CtrlItem/CtrlItem.js +0 -24
  240. package/vendor/symbiote-node/node/CtrlItem/CtrlItem.tpl.js +0 -16
  241. package/vendor/symbiote-node/node/GraphFrame/GraphFrame.css.js +0 -65
  242. package/vendor/symbiote-node/node/GraphFrame/GraphFrame.js +0 -29
  243. package/vendor/symbiote-node/node/GraphFrame/GraphFrame.tpl.js +0 -13
  244. package/vendor/symbiote-node/node/GraphNode/GraphNode.css.js +0 -683
  245. package/vendor/symbiote-node/node/GraphNode/GraphNode.js +0 -92
  246. package/vendor/symbiote-node/node/GraphNode/GraphNode.tpl.js +0 -17
  247. package/vendor/symbiote-node/node/NodeSocket/NodeSocket.js +0 -25
  248. package/vendor/symbiote-node/node/NodeSocket/NodeSocket.tpl.js +0 -7
  249. package/vendor/symbiote-node/node/PortItem/PortItem.css.js +0 -90
  250. package/vendor/symbiote-node/node/PortItem/PortItem.js +0 -87
  251. package/vendor/symbiote-node/node/PortItem/PortItem.tpl.js +0 -10
  252. package/vendor/symbiote-node/package.json +0 -59
  253. package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.css.js +0 -143
  254. package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.js +0 -131
  255. package/vendor/symbiote-node/palette/PaletteBrowser/PaletteBrowser.tpl.js +0 -16
  256. package/vendor/symbiote-node/plugins/History.js +0 -384
  257. package/vendor/symbiote-node/plugins/Readonly.js +0 -59
  258. package/vendor/symbiote-node/shapes/CircleShape.js +0 -80
  259. package/vendor/symbiote-node/shapes/CommentShape.js +0 -35
  260. package/vendor/symbiote-node/shapes/DiamondShape.js +0 -115
  261. package/vendor/symbiote-node/shapes/NodeShape.js +0 -80
  262. package/vendor/symbiote-node/shapes/PillShape.js +0 -91
  263. package/vendor/symbiote-node/shapes/RectShape.js +0 -72
  264. package/vendor/symbiote-node/shapes/SVGShape.js +0 -494
  265. package/vendor/symbiote-node/shapes/index.js +0 -53
  266. package/vendor/symbiote-node/themes/Palette.js +0 -32
  267. package/vendor/symbiote-node/themes/Skin.js +0 -113
  268. package/vendor/symbiote-node/themes/Theme.js +0 -84
  269. package/vendor/symbiote-node/themes/carbon.js +0 -137
  270. package/vendor/symbiote-node/themes/dark.js +0 -137
  271. package/vendor/symbiote-node/themes/ebook.js +0 -138
  272. package/vendor/symbiote-node/themes/grey.js +0 -137
  273. package/vendor/symbiote-node/themes/light.js +0 -137
  274. package/vendor/symbiote-node/themes/neon.js +0 -138
  275. package/vendor/symbiote-node/themes/pcb.js +0 -273
  276. package/vendor/symbiote-node/themes/synthwave.js +0 -137
  277. package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.css.js +0 -86
  278. package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.js +0 -128
  279. package/vendor/symbiote-node/toolbar/QuickToolbar/QuickToolbar.tpl.js +0 -29
@@ -1,494 +0,0 @@
1
- /**
2
- * SVGShape — universal shape from any SVG path
3
- *
4
- * Uses SVGPathElement.getPointAtLength() for dynamic connector placement.
5
- * Any SVG icon path can become a node shape — the outer contour defines
6
- * the visual fill and connector positions are computed along the perimeter.
7
- *
8
- * Port placement strategy:
9
- * - Inputs placed on left portion of path perimeter
10
- * - Outputs placed on right portion of path perimeter
11
- * - Connector angle = normal from center → edge point
12
- * - Aspect ratio of original SVG is preserved (xMidYMid meet)
13
- *
14
- * @module symbiote-node/shapes/SVGShape
15
- */
16
-
17
- import { NodeShape } from './NodeShape.js';
18
-
19
- /**
20
- * Offscreen SVG namespace for path computation
21
- * @type {SVGSVGElement|null}
22
- */
23
- let _offscreenSVG = null;
24
-
25
- /**
26
- * Get or create an offscreen SVG element for path calculations
27
- * @returns {SVGSVGElement}
28
- */
29
- function getOffscreenSVG() {
30
- if (_offscreenSVG) return _offscreenSVG;
31
- if (typeof document === 'undefined') return null;
32
- _offscreenSVG = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
33
- _offscreenSVG.style.position = 'absolute';
34
- _offscreenSVG.style.width = '0';
35
- _offscreenSVG.style.height = '0';
36
- _offscreenSVG.style.overflow = 'hidden';
37
- document.body.appendChild(_offscreenSVG);
38
- return _offscreenSVG;
39
- }
40
-
41
- /**
42
- * Compute scaling params for viewBox → element mapping
43
- * Preserves aspect ratio (equivalent to SVG preserveAspectRatio="xMidYMid meet")
44
- *
45
- * @param {number[]} vb - [x, y, w, h] viewBox
46
- * @param {{ width: number, height: number }} size - element size
47
- * @returns {{ scale: number, offsetX: number, offsetY: number }}
48
- */
49
- function computeMapping(vb, size) {
50
- const [vx, vy, vw, vh] = vb;
51
- const scale = Math.min(size.width / vw, size.height / vh);
52
- const renderedW = vw * scale;
53
- const renderedH = vh * scale;
54
- return {
55
- scale,
56
- offsetX: (size.width - renderedW) / 2 - vx * scale,
57
- offsetY: (size.height - renderedH) / 2 - vy * scale,
58
- };
59
- }
60
-
61
- export class SVGShape extends NodeShape {
62
- /** @type {string} */
63
- name;
64
-
65
- /** @type {string} - SVG path d attribute */
66
- pathData;
67
-
68
- /** @type {string} - viewBox of original SVG */
69
- viewBox;
70
-
71
- /** @type {number[]} - parsed viewBox [x, y, w, h] */
72
- #vb;
73
-
74
- /** @type {boolean} - whether shape has standard header */
75
- #header;
76
-
77
- /** @type {{ minWidth: number, minHeight: number }} */
78
- #minSize;
79
-
80
- /** @type {Map<string, {x:number,y:number,angle:number}>} - position cache */
81
- #posCache = new Map();
82
-
83
- /**
84
- * @param {string} name - Shape identifier
85
- * @param {object} options
86
- * @param {string} options.pathData - SVG path d attribute
87
- * @param {string} [options.viewBox='0 0 24 24'] - Original SVG viewBox
88
- * @param {boolean} [options.header=false] - Show header/controls
89
- * @param {{ minWidth?: number, minHeight?: number }} [options.minSize]
90
- */
91
- constructor(name, { pathData, viewBox = '0 0 24 24', header = false, minSize = {} }) {
92
- super();
93
- this.name = name;
94
- this.pathData = pathData;
95
- this.viewBox = viewBox;
96
- this.#vb = viewBox.split(' ').map(Number);
97
- this.#header = header;
98
- this.#minSize = {
99
- minWidth: minSize.minWidth || 100,
100
- minHeight: minSize.minHeight || 100,
101
- };
102
- }
103
-
104
- /**
105
- * Scale a point from viewBox coordinates to element pixel coordinates
106
- * Uses aspect-ratio-preserving mapping (xMidYMid meet)
107
- *
108
- * @param {number} px - x in viewBox
109
- * @param {number} py - y in viewBox
110
- * @param {{ width: number, height: number }} size - element size
111
- * @returns {{ x: number, y: number }}
112
- */
113
- #scalePoint(px, py, size) {
114
- const { scale, offsetX, offsetY } = computeMapping(this.#vb, size);
115
- return {
116
- x: px * scale + offsetX,
117
- y: py * scale + offsetY,
118
- };
119
- }
120
-
121
- /**
122
- * Get center of SVG shape in viewBox coordinates
123
- * @returns {{ x: number, y: number }}
124
- */
125
- #getCenter() {
126
- const [vx, vy, vw, vh] = this.#vb;
127
- return { x: vx + vw / 2, y: vy + vh / 2 };
128
- }
129
-
130
- /**
131
- * Get a path element for computations (uses offscreen SVG)
132
- * @returns {SVGPathElement|null}
133
- */
134
- #getPathElement() {
135
- const svg = getOffscreenSVG();
136
- if (!svg) return null;
137
- let pathEl = svg.querySelector(`[data-shape="${this.name}"]`);
138
- if (!pathEl) {
139
- pathEl = document.createElementNS('http://www.w3.org/2000/svg', 'path');
140
- pathEl.setAttribute('d', this.pathData);
141
- pathEl.setAttribute('data-shape', this.name);
142
- svg.appendChild(pathEl);
143
- }
144
- return pathEl;
145
- }
146
-
147
- /**
148
- * Find the point on the SVG path that a ray from center at a given angle hits.
149
- * Uses dense sampling along the path perimeter and finds the point
150
- * whose angle from center best matches the target angle.
151
- *
152
- * @param {number} targetAngle - angle in radians from center
153
- * @param {SVGPathElement} pathEl
154
- * @returns {{ x: number, y: number }} - point in viewBox coordinates
155
- */
156
- #findPointAtAngle(targetAngle, pathEl) {
157
- const totalLen = pathEl.getTotalLength();
158
- const center = this.#getCenter();
159
-
160
- // Phase 1: coarse scan (128 samples)
161
- let bestDist = Infinity;
162
- let bestLen = 0;
163
- const COARSE = 128;
164
-
165
- for (let i = 0; i <= COARSE; i++) {
166
- const len = (totalLen * i) / COARSE;
167
- const pt = pathEl.getPointAtLength(len);
168
- const angle = Math.atan2(pt.y - center.y, pt.x - center.x);
169
- let diff = Math.abs(angle - targetAngle);
170
- if (diff > Math.PI) diff = 2 * Math.PI - diff;
171
- if (diff < bestDist) {
172
- bestDist = diff;
173
- bestLen = len;
174
- }
175
- }
176
-
177
- // Phase 2: refine with binary-like search around bestLen
178
- const searchRadius = totalLen / COARSE;
179
- const FINE = 32;
180
- const startLen = Math.max(0, bestLen - searchRadius);
181
- const endLen = Math.min(totalLen, bestLen + searchRadius);
182
-
183
- for (let i = 0; i <= FINE; i++) {
184
- const len = startLen + ((endLen - startLen) * i) / FINE;
185
- const pt = pathEl.getPointAtLength(len);
186
- const angle = Math.atan2(pt.y - center.y, pt.x - center.x);
187
- let diff = Math.abs(angle - targetAngle);
188
- if (diff > Math.PI) diff = 2 * Math.PI - diff;
189
- if (diff < bestDist) {
190
- bestDist = diff;
191
- bestLen = len;
192
- }
193
- }
194
-
195
- return pathEl.getPointAtLength(bestLen);
196
- }
197
-
198
- /**
199
- * Get socket position on the shape outline.
200
- * Results are cached — same params always return same position.
201
- *
202
- * @param {'input'|'output'} side
203
- * @param {number} index - ordinal index of this port
204
- * @param {number} total - total ports on this side
205
- * @param {{ width: number, height: number }} size - node dimensions
206
- * @returns {{ x: number, y: number, angle: number }}
207
- */
208
- getSocketPosition(side, index, total, size) {
209
- // Cache key: position depends on side, index, total, and element size
210
- const key = `${side}|${index}|${total}|${size.width}|${size.height}`;
211
- if (this.#posCache.has(key)) return this.#posCache.get(key);
212
-
213
- const pathEl = this.#getPathElement();
214
-
215
- if (!pathEl) {
216
- const y = size.height * (index + 1) / (total + 1);
217
- const result = side === 'input'
218
- ? { x: 0, y, angle: 180 }
219
- : { x: size.width, y, angle: 0 };
220
- this.#posCache.set(key, result);
221
- return result;
222
- }
223
-
224
- // Distribute ports along the relevant side of the path perimeter
225
- const centerAngle = side === 'input' ? Math.PI : 0;
226
- const arcSpan = Math.PI * 0.6; // 108° spread
227
- let targetAngle;
228
-
229
- if (total === 1) {
230
- targetAngle = centerAngle;
231
- } else {
232
- const startAngle = centerAngle - arcSpan / 2;
233
- const step = arcSpan / (total - 1);
234
- targetAngle = startAngle + step * index;
235
- }
236
-
237
- const pt = this.#findPointAtAngle(targetAngle, pathEl);
238
- const scaled = this.#scalePoint(pt.x, pt.y, size);
239
-
240
- // Compute outward surface normal (same as getEdgePoint)
241
- const totalLen = pathEl.getTotalLength();
242
- const center = this.#getCenter();
243
- let bestLen = 0, bestDist = Infinity;
244
- const SCAN = 128;
245
- for (let i = 0; i <= SCAN; i++) {
246
- const len = (totalLen * i) / SCAN;
247
- const p = pathEl.getPointAtLength(len);
248
- const dist = (p.x - pt.x) ** 2 + (p.y - pt.y) ** 2;
249
- if (dist < bestDist) { bestDist = dist; bestLen = len; }
250
- }
251
- const delta = 0.5;
252
- const prevPt = pathEl.getPointAtLength(Math.max(0, bestLen - delta));
253
- const nextPt = pathEl.getPointAtLength(Math.min(totalLen, bestLen + delta));
254
- const tx = nextPt.x - prevPt.x, ty = nextPt.y - prevPt.y;
255
- let nx = -ty, ny = tx;
256
- const radX = pt.x - center.x, radY = pt.y - center.y;
257
- if (nx * radX + ny * radY < 0) { nx = ty; ny = -tx; }
258
- const angleDeg = Math.atan2(ny, nx) * 180 / Math.PI;
259
-
260
- const result = { x: scaled.x, y: scaled.y, angle: angleDeg };
261
- this.#posCache.set(key, result);
262
- return result;
263
- }
264
-
265
- /**
266
- * Get edge point at a specific angle (direction toward target node).
267
- * Used for dynamic connectors that slide along the perimeter.
268
- *
269
- * @param {number} angle - angle in radians from center to target
270
- * @param {{ width: number, height: number }} size - element dimensions
271
- * @returns {{ x: number, y: number, angle: number }}
272
- */
273
- getEdgePoint(angle, size) {
274
- // Round to 3 decimal places (~0.06° precision, invisible jitter)
275
- const rounded = Math.round(angle * 1000) / 1000;
276
- const key = `edge|${rounded}|${size.width}|${size.height}`;
277
- if (this.#posCache.has(key)) return this.#posCache.get(key);
278
-
279
- const pathEl = this.#getPathElement();
280
- if (!pathEl) {
281
- const cx = size.width / 2;
282
- const cy = size.height / 2;
283
- return { x: cx + Math.cos(angle) * cx, y: cy + Math.sin(angle) * cy, angle: angle * 180 / Math.PI };
284
- }
285
-
286
- const pt = this.#findPointAtAngle(angle, pathEl);
287
- const scaled = this.#scalePoint(pt.x, pt.y, size);
288
-
289
- // Compute outward surface normal (perpendicular to edge), NOT radial angle.
290
- // For polygons, the radial angle varies across a flat edge,
291
- // but the surface normal is constant — this gives correct perpendicular stubs.
292
- const totalLen = pathEl.getTotalLength();
293
- const center = this.#getCenter();
294
-
295
- // Find the path length for this point (re-use findPointAtAngle's logic)
296
- let bestLen = 0, bestDist = Infinity;
297
- const SCAN = 128;
298
- for (let i = 0; i <= SCAN; i++) {
299
- const len = (totalLen * i) / SCAN;
300
- const p = pathEl.getPointAtLength(len);
301
- const dist = (p.x - pt.x) ** 2 + (p.y - pt.y) ** 2;
302
- if (dist < bestDist) { bestDist = dist; bestLen = len; }
303
- }
304
-
305
- // Sample neighbors to get tangent vector
306
- const delta = 0.5; // small step along path
307
- const prevLen = Math.max(0, bestLen - delta);
308
- const nextLen = Math.min(totalLen, bestLen + delta);
309
- const prevPt = pathEl.getPointAtLength(prevLen);
310
- const nextPt = pathEl.getPointAtLength(nextLen);
311
-
312
- // Tangent = direction along edge
313
- const tx = nextPt.x - prevPt.x;
314
- const ty = nextPt.y - prevPt.y;
315
-
316
- // Normal = tangent rotated 90° (two candidates: +90° and -90°)
317
- // Pick the one pointing outward (away from center)
318
- let nx = -ty, ny = tx; // candidate 1: rotate -90°
319
- const radX = pt.x - center.x;
320
- const radY = pt.y - center.y;
321
- // Dot product with radial vector — if negative, flip
322
- if (nx * radX + ny * radY < 0) {
323
- nx = ty; ny = -tx; // candidate 2: rotate +90°
324
- }
325
-
326
- const angleDeg = Math.atan2(ny, nx) * 180 / Math.PI;
327
-
328
- const result = { x: scaled.x, y: scaled.y, angle: angleDeg };
329
-
330
- // Bounded cache: evict oldest when exceeding 360 entries
331
- if (this.#posCache.size > 360) {
332
- const first = this.#posCache.keys().next().value;
333
- this.#posCache.delete(first);
334
- }
335
- this.#posCache.set(key, result);
336
- return result;
337
- }
338
-
339
- /**
340
- * Get a pin position on a specific side of the shape.
341
- *
342
- * Side-based placement: pins are placed along a side edge (top/right/bottom/left).
343
- * The position within the side is controlled by t (0 = start, 1 = end).
344
- *
345
- * @param {'top'|'right'|'bottom'|'left'} side - which side to place pin on
346
- * @param {number} t - position along the side (0..1), 0.5 = center
347
- * @param {{ width: number, height: number }} size - element dimensions
348
- * @returns {{ x: number, y: number, angle: number }} - angle is outward normal in degrees
349
- */
350
- getSidePosition(side, t, size) {
351
- const key = `side|${side}|${(t * 100) | 0}|${size.width}|${size.height}`;
352
- if (this.#posCache.has(key)) return this.#posCache.get(key);
353
-
354
- // Outward normal angles for each side (screen coords: Y down)
355
- const NORMALS = { top: -90, right: 0, bottom: 90, left: 180 };
356
- const angleDeg = NORMALS[side];
357
-
358
- // For shapes with pathData: sample points on the side's angular range
359
- // and interpolate along the edge
360
- const pathEl = this.#getPathElement();
361
- if (pathEl) {
362
- // Angular ranges for each side (radians, screen coords)
363
- // Generous ranges that cover the flat + diagonal edges
364
- const RANGES = {
365
- right: { from: -Math.PI / 4, to: Math.PI / 4 },
366
- bottom: { from: Math.PI / 4, to: 3 * Math.PI / 4 },
367
- left: { from: 3 * Math.PI / 4, to: 5 * Math.PI / 4 },
368
- top: { from: -3 * Math.PI / 4, to: -Math.PI / 4 },
369
- };
370
-
371
- const range = RANGES[side];
372
- // Use side-level caching for points to prevent SVG DOM explosion
373
- const sideKey = `sidepts|${side}|${size.width}|${size.height}`;
374
- let sidePoints;
375
-
376
- if (this.#posCache.has(sideKey)) {
377
- sidePoints = this.#posCache.get(sideKey);
378
- } else {
379
- sidePoints = [];
380
- const SAMPLES = 16;
381
- for (let i = 0; i <= SAMPLES; i++) {
382
- const a = range.from + (range.to - range.from) * (i / SAMPLES);
383
- const pt = this.#findPointAtAngle(a, pathEl);
384
- const sp = this.#scalePoint(pt.x, pt.y, size);
385
- sidePoints.push(sp);
386
- }
387
- this.#posCache.set(sideKey, sidePoints);
388
- }
389
-
390
- // Use inset range (20%-80%) to avoid placing on corners
391
- const MARGIN = 0.2;
392
- const effectiveT = MARGIN + t * (1 - 2 * MARGIN);
393
- const idx = effectiveT * (sidePoints.length - 1);
394
- const lo = Math.floor(idx);
395
- const hi = Math.min(lo + 1, sidePoints.length - 1);
396
- const frac = idx - lo;
397
-
398
- const x = sidePoints[lo].x + (sidePoints[hi].x - sidePoints[lo].x) * frac;
399
- const y = sidePoints[lo].y + (sidePoints[hi].y - sidePoints[lo].y) * frac;
400
-
401
- const result = { x, y, angle: angleDeg };
402
- this.#posCache.set(key, result);
403
- return result;
404
- }
405
-
406
- // Fallback for shapes without path: rectangle approximation
407
- let x, y;
408
- switch (side) {
409
- case 'top': x = size.width * (0.2 + t * 0.6); y = 0; break;
410
- case 'right': x = size.width; y = size.height * (0.2 + t * 0.6); break;
411
- case 'bottom': x = size.width * (0.2 + t * 0.6); y = size.height; break;
412
- case 'left': x = 0; y = size.height * (0.2 + t * 0.6); break;
413
- }
414
-
415
- const result = { x, y, angle: angleDeg };
416
- this.#posCache.set(key, result);
417
- return result;
418
- }
419
-
420
- getClipPath(size) {
421
- return null; // We use SVG background layer instead of clip-path
422
- }
423
-
424
- getOutlinePath(size) {
425
- return this.pathData;
426
- }
427
-
428
- getBorderRadius() {
429
- return '0';
430
- }
431
-
432
- get hasHeader() {
433
- return this.#header;
434
- }
435
-
436
- get hasControls() {
437
- return this.#header;
438
- }
439
-
440
- getMinSize() {
441
- return this.#minSize;
442
- }
443
- }
444
-
445
- // --- Preset SVG shapes (Material Symbols paths) ---
446
-
447
- /**
448
- * Register an SVG shape from a path string
449
- * @param {string} name
450
- * @param {string} pathData - SVG d attribute
451
- * @param {object} [options]
452
- */
453
- export function createSVGShape(name, pathData, options = {}) {
454
- return new SVGShape(name, { pathData, ...options });
455
- }
456
-
457
- // Common icon paths from Material Symbols (24x24 viewBox)
458
- export const SVG_PRESETS = {
459
- // Hexagon
460
- hexagon: 'M12 2L22 8.5V15.5L12 22L2 15.5V8.5Z',
461
-
462
- // Pentagon
463
- pentagon: 'M12 2L22 9.27L18.18 21H5.82L2 9.27Z',
464
-
465
- // Star (5-pointed)
466
- star: 'M12 2L15.09 8.26L22 9.27L17 14.14L18.18 21.02L12 17.77L5.82 21.02L7 14.14L2 9.27L8.91 8.26Z',
467
-
468
- // Cloud
469
- cloud: 'M19.35 10.04A7.49 7.49 0 0012 4C9.11 4 6.6 5.64 5.35 8.04A5.994 5.994 0 000 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96z',
470
-
471
- // Shield
472
- shield: 'M12 1L3 5v6c0 5.55 3.84 10.74 9 12 5.16-1.26 9-6.45 9-12V5l-9-4z',
473
-
474
- // Octagon
475
- octagon: 'M7.86 2H16.14L22 7.86V16.14L16.14 22H7.86L2 16.14V7.86Z',
476
-
477
- // Parallelogram
478
- parallelogram: 'M6 2H22L18 22H2Z',
479
-
480
- // Trapezoid
481
- trapezoid: 'M4 22H20L23 2H1Z',
482
-
483
- // Cylinder (approximation)
484
- cylinder: 'M4 6C4 4 8 2 12 2S20 4 20 6V18C20 20 16 22 12 22S4 20 4 18Z',
485
-
486
- // Database
487
- database: 'M12 3C7.58 3 4 4.79 4 7V17C4 19.21 7.59 21 12 21S20 19.21 20 17V7C20 4.79 16.42 3 12 3Z',
488
-
489
- // Lightning bolt
490
- bolt: 'M7 2V13H10V22L17 10H13L17 2Z',
491
-
492
- // Heart
493
- heart: 'M12 21.35L10.55 20.03C5.4 15.36 2 12.28 2 8.5C2 5.42 4.42 3 7.5 3C9.24 3 10.91 3.81 12 5.09C13.09 3.81 14.76 3 16.5 3C19.58 3 22 5.42 22 8.5C22 12.28 18.6 15.36 13.45 20.04L12 21.35Z',
494
- };
@@ -1,53 +0,0 @@
1
- /**
2
- * Shape registry — maps shape names to implementations
3
- * @module symbiote-node/shapes/index
4
- */
5
-
6
- import { NodeShape } from './NodeShape.js';
7
- import { RectShape } from './RectShape.js';
8
- import { PillShape } from './PillShape.js';
9
- import { CircleShape } from './CircleShape.js';
10
- import { DiamondShape } from './DiamondShape.js';
11
- import { CommentShape } from './CommentShape.js';
12
- import { SVGShape, createSVGShape, SVG_PRESETS } from './SVGShape.js';
13
-
14
- /** @type {Map<string, NodeShape>} */
15
- const registry = new Map();
16
-
17
- // Register built-in shapes
18
- const RECT = new RectShape();
19
- const PILL = new PillShape();
20
- const CIRCLE = new CircleShape();
21
- const DIAMOND = new DiamondShape();
22
- const COMMENT = new CommentShape();
23
-
24
- registry.set('rect', RECT);
25
- registry.set('pill', PILL);
26
- registry.set('circle', CIRCLE);
27
- registry.set('diamond', DIAMOND);
28
- registry.set('comment', COMMENT);
29
-
30
- // Register SVG preset shapes
31
- for (const [name, pathData] of Object.entries(SVG_PRESETS)) {
32
- registry.set(name, createSVGShape(name, pathData));
33
- }
34
-
35
- /**
36
- * Get shape by name
37
- * @param {string} name
38
- * @returns {NodeShape}
39
- */
40
- export function getShape(name) {
41
- return registry.get(name) || RECT;
42
- }
43
-
44
- /**
45
- * Register custom shape
46
- * @param {string} name
47
- * @param {NodeShape} shape
48
- */
49
- export function registerShape(name, shape) {
50
- registry.set(name, shape);
51
- }
52
-
53
- export { NodeShape, RectShape, PillShape, CircleShape, DiamondShape, CommentShape, SVGShape, createSVGShape, SVG_PRESETS };
@@ -1,32 +0,0 @@
1
- /**
2
- * Palette — color-only design tokens
3
- *
4
- * Contains only chromatic properties: backgrounds, text colors,
5
- * accents, category colors, connection colors.
6
- * Separated from geometry (Skin) for independent swapping.
7
- *
8
- * @module symbiote-node/themes/Palette
9
- */
10
-
11
- /**
12
- * @typedef {Object} PaletteDefinition
13
- * @property {string} name
14
- * @property {Object<string, string>} colors
15
- */
16
-
17
- // Re-export all built-in palettes
18
- export { DARK_PALETTE } from './dark.js';
19
- export { LIGHT_PALETTE } from './light.js';
20
- export { SYNTHWAVE_PALETTE } from './synthwave.js';
21
- export { GREY_PALETTE } from './grey.js';
22
-
23
- /**
24
- * Apply palette to element
25
- * @param {HTMLElement} element
26
- * @param {PaletteDefinition} palette
27
- */
28
- export function applyPalette(element, palette) {
29
- for (const [key, value] of Object.entries(palette.colors)) {
30
- element.style.setProperty(key, value);
31
- }
32
- }
@@ -1,113 +0,0 @@
1
- /**
2
- * Skin — geometry-only design tokens
3
- *
4
- * Built on a T-shirt spacing scale: change the scale values and all
5
- * semantic tokens (radius, sockets, grid) update harmoniously.
6
- * Shadow is split into geometry (here) and color (from Palette).
7
- *
8
- * @module symbiote-node/themes/Skin
9
- */
10
-
11
- /**
12
- * @typedef {Object} SkinDefinition
13
- * @property {string} name
14
- * @property {Object<string, string>} geometry
15
- */
16
-
17
- /** @type {SkinDefinition} */
18
- export const MODERN_SKIN = {
19
- name: 'modern',
20
- geometry: {
21
- // === Spacing scale (atomic — AI changes these) ===
22
- '--sn-space-xs': '4px',
23
- '--sn-space-sm': '8px',
24
- '--sn-space-md': '12px',
25
- '--sn-space-lg': '16px',
26
- '--sn-space-xl': '24px',
27
-
28
- // === Semantic geometry (references scale) ===
29
- '--sn-node-radius': 'var(--sn-space-md)',
30
- '--sn-comment-radius': 'var(--sn-space-sm)',
31
- '--sn-socket-size': 'var(--sn-space-md)',
32
- '--sn-socket-border-width': '2px',
33
- '--sn-grid-size': 'var(--sn-space-xl)',
34
- '--sn-conn-width': '2',
35
-
36
- // === Typography ===
37
- '--sn-font': "'Inter', sans-serif",
38
- '--sn-font-size': '13px',
39
-
40
- // === Shadow geometry (color comes from Palette) ===
41
- '--sn-shadow-geometry': '0 4px 16px',
42
- '--sn-node-shadow': 'var(--sn-shadow-geometry) var(--sn-shadow-color, rgba(0, 0, 0, 0.3))',
43
- },
44
- };
45
-
46
- /** @type {SkinDefinition} */
47
- export const COMPACT_SKIN = {
48
- name: 'compact',
49
- geometry: {
50
- // === Spacing scale ===
51
- '--sn-space-xs': '3px',
52
- '--sn-space-sm': '5px',
53
- '--sn-space-md': '8px',
54
- '--sn-space-lg': '12px',
55
- '--sn-space-xl': '16px',
56
-
57
- // === Semantic geometry ===
58
- '--sn-node-radius': 'var(--sn-space-md)',
59
- '--sn-comment-radius': 'var(--sn-space-sm)',
60
- '--sn-socket-size': 'var(--sn-space-md)',
61
- '--sn-socket-border-width': '1.5px',
62
- '--sn-grid-size': 'var(--sn-space-xl)',
63
- '--sn-conn-width': '1.5',
64
-
65
- // === Typography ===
66
- '--sn-font': "'Inter', sans-serif",
67
- '--sn-font-size': '12px',
68
-
69
- // === Shadow geometry ===
70
- '--sn-shadow-geometry': '0 2px 8px',
71
- '--sn-node-shadow': 'var(--sn-shadow-geometry) var(--sn-shadow-color, rgba(0, 0, 0, 0.2))',
72
- },
73
- };
74
-
75
- /** @type {SkinDefinition} */
76
- export const ROUNDED_SKIN = {
77
- name: 'rounded',
78
- geometry: {
79
- // === Spacing scale ===
80
- '--sn-space-xs': '5px',
81
- '--sn-space-sm': '10px',
82
- '--sn-space-md': '14px',
83
- '--sn-space-lg': '20px',
84
- '--sn-space-xl': '28px',
85
-
86
- // === Semantic geometry ===
87
- '--sn-node-radius': 'var(--sn-space-lg)', // larger radius for "rounded" feel
88
- '--sn-comment-radius': 'var(--sn-space-md)',
89
- '--sn-socket-size': 'var(--sn-space-md)',
90
- '--sn-socket-border-width': '2.5px',
91
- '--sn-grid-size': 'var(--sn-space-xl)',
92
- '--sn-conn-width': '2.5',
93
-
94
- // === Typography ===
95
- '--sn-font': "'Space Grotesk', sans-serif",
96
- '--sn-font-size': '14px',
97
-
98
- // === Shadow geometry ===
99
- '--sn-shadow-geometry': '0 6px 24px',
100
- '--sn-node-shadow': 'var(--sn-shadow-geometry) var(--sn-shadow-color, rgba(0, 0, 0, 0.25))',
101
- },
102
- };
103
-
104
- /**
105
- * Apply skin to element
106
- * @param {HTMLElement} element
107
- * @param {SkinDefinition} skin
108
- */
109
- export function applySkin(element, skin) {
110
- for (const [key, value] of Object.entries(skin.geometry)) {
111
- element.style.setProperty(key, value);
112
- }
113
- }