@visualli/core 0.1.7 → 0.2.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 (127) hide show
  1. package/README.md +37 -105
  2. package/dist/chunk-25AJTPMS.js +68 -0
  3. package/dist/chunk-25AJTPMS.js.map +1 -0
  4. package/dist/{chunk-6NXADJK2.js → chunk-7NJWM7ZE.js} +84 -117
  5. package/dist/chunk-7NJWM7ZE.js.map +1 -0
  6. package/dist/chunk-KVSM3APM.js +96 -0
  7. package/dist/chunk-KVSM3APM.js.map +1 -0
  8. package/dist/{chunk-PDP5CVUL.js → chunk-LOQLNYB3.js} +2 -2
  9. package/dist/chunk-LV3EXUQY.js +753 -0
  10. package/dist/chunk-LV3EXUQY.js.map +1 -0
  11. package/dist/chunk-N7HCYULH.js +12 -0
  12. package/dist/chunk-N7HCYULH.js.map +1 -0
  13. package/dist/{chunk-I75TMOE4.js → chunk-P6PKWVYF.js} +2 -2
  14. package/dist/chunk-TPLJJKAU.js +151 -0
  15. package/dist/chunk-TPLJJKAU.js.map +1 -0
  16. package/dist/chunk-UAMEJG2C.js +267 -0
  17. package/dist/chunk-UAMEJG2C.js.map +1 -0
  18. package/dist/{chunk-LJYSKSCE.js → chunk-W2CAOOJJ.js} +6 -6
  19. package/dist/chunk-W2CAOOJJ.js.map +1 -0
  20. package/dist/config/index.cjs +250 -349
  21. package/dist/config/index.cjs.map +1 -1
  22. package/dist/config/index.d.cts +107 -66
  23. package/dist/config/index.d.ts +107 -66
  24. package/dist/config/index.js +52 -34
  25. package/dist/constants/index.cjs +14 -333
  26. package/dist/constants/index.cjs.map +1 -1
  27. package/dist/constants/index.d.cts +5 -243
  28. package/dist/constants/index.d.ts +5 -243
  29. package/dist/constants/index.js +5 -75
  30. package/dist/designSystem-BOrZHfEq.d.cts +150 -0
  31. package/dist/designSystem-BOrZHfEq.d.ts +150 -0
  32. package/dist/document-BFBwn93X.d.ts +26 -0
  33. package/dist/document-MEJEfxl3.d.cts +26 -0
  34. package/dist/ideaSize-CLDKeyqD.d.cts +11 -0
  35. package/dist/ideaSize-DxxGy2E8.d.ts +11 -0
  36. package/dist/index-BmILeKj6.d.cts +99 -0
  37. package/dist/index-CcPRwVUL.d.ts +99 -0
  38. package/dist/index.cjs +1636 -961
  39. package/dist/index.cjs.map +1 -1
  40. package/dist/index.d.cts +350 -27
  41. package/dist/index.d.ts +350 -27
  42. package/dist/index.js +434 -179
  43. package/dist/index.js.map +1 -1
  44. package/dist/{document-B3hnNr-F.d.cts → layer-B2A3Ki48.d.cts} +2 -16
  45. package/dist/{document-B3hnNr-F.d.ts → layer-B2A3Ki48.d.ts} +2 -16
  46. package/dist/layout/index.d.cts +2 -1
  47. package/dist/layout/index.d.ts +2 -1
  48. package/dist/mindmap-C3Qr0qKW.d.cts +182 -0
  49. package/dist/mindmap-DHeVa86G.d.ts +182 -0
  50. package/dist/parser/index.cjs +745 -179
  51. package/dist/parser/index.cjs.map +1 -1
  52. package/dist/parser/index.d.cts +23 -8
  53. package/dist/parser/index.d.ts +23 -8
  54. package/dist/parser/index.js +7 -2
  55. package/dist/performance/index.cjs +13 -0
  56. package/dist/performance/index.cjs.map +1 -1
  57. package/dist/performance/index.js +2 -2
  58. package/dist/theme/index.cjs +884 -0
  59. package/dist/theme/index.cjs.map +1 -0
  60. package/dist/theme/index.d.cts +2 -0
  61. package/dist/theme/index.d.ts +2 -0
  62. package/dist/theme/index.js +53 -0
  63. package/dist/types/index.d.cts +4 -2
  64. package/dist/types/index.d.ts +4 -2
  65. package/dist/viewport/index.cjs +17 -6
  66. package/dist/viewport/index.cjs.map +1 -1
  67. package/dist/viewport/index.d.cts +6 -4
  68. package/dist/viewport/index.d.ts +6 -4
  69. package/dist/viewport/index.js +2 -2
  70. package/licenses/visualli-design-system/LICENSE +9 -0
  71. package/licenses/visualli-design-system/NOTICE.md +6 -0
  72. package/package.json +12 -4
  73. package/src/config/README.md +2 -4
  74. package/src/config/USAGE_EXAMPLES.md +0 -4
  75. package/src/config/index.ts +3 -4
  76. package/src/constants/index.ts +1 -1
  77. package/src/constants/layout.ts +11 -0
  78. package/src/constants/performanceConstants.ts +8 -27
  79. package/src/generated/README.md +12 -0
  80. package/src/generated/designSystem.ts +758 -0
  81. package/src/generated/geometry/blob.ts +99 -0
  82. package/src/generated/geometry/blobShapes.ts +4 -0
  83. package/src/generated/geometry/color.ts +37 -0
  84. package/src/generated/geometry/container.ts +84 -0
  85. package/src/generated/geometry/detail.ts +22 -0
  86. package/src/generated/geometry/idea.ts +56 -0
  87. package/src/generated/geometry/interaction.ts +122 -0
  88. package/src/generated/geometry/motion.ts +140 -0
  89. package/src/index.ts +18 -1
  90. package/src/parser/configUtils.ts +12 -19
  91. package/src/parser/visualliConverter.ts +71 -112
  92. package/src/parser/visualliParser.ts +16 -1
  93. package/src/rendering/culling.ts +16 -12
  94. package/src/rendering/ideaSize.ts +21 -0
  95. package/src/rendering/nodeGeometry.ts +97 -0
  96. package/src/theme/index.ts +136 -0
  97. package/src/types/document.ts +9 -0
  98. package/src/types/layer.ts +1 -1
  99. package/src/types/mindmap.ts +13 -0
  100. package/src/utils/navigation.ts +33 -63
  101. package/src/viewport/viewportUtils.ts +6 -4
  102. package/dist/animations/index.cjs +0 -146
  103. package/dist/animations/index.cjs.map +0 -1
  104. package/dist/animations/index.d.cts +0 -81
  105. package/dist/animations/index.d.ts +0 -81
  106. package/dist/animations/index.js +0 -35
  107. package/dist/chunk-6NXADJK2.js.map +0 -1
  108. package/dist/chunk-F36SMC3K.js +0 -106
  109. package/dist/chunk-F36SMC3K.js.map +0 -1
  110. package/dist/chunk-G5H3P4YZ.js +0 -273
  111. package/dist/chunk-G5H3P4YZ.js.map +0 -1
  112. package/dist/chunk-LDJRGT2Q.js +0 -163
  113. package/dist/chunk-LDJRGT2Q.js.map +0 -1
  114. package/dist/chunk-LJYSKSCE.js.map +0 -1
  115. package/dist/chunk-LNTJTDB2.js +0 -349
  116. package/dist/chunk-LNTJTDB2.js.map +0 -1
  117. package/dist/mindmap-DWS0WZT_.d.cts +0 -118
  118. package/dist/mindmap-DWS0WZT_.d.ts +0 -118
  119. package/src/animations/constants.ts +0 -72
  120. package/src/animations/easing.ts +0 -70
  121. package/src/animations/index.ts +0 -2
  122. package/src/config/blobShapes.ts +0 -146
  123. package/src/config/textScaling.ts +0 -54
  124. package/src/constants/design.ts +0 -281
  125. /package/dist/{chunk-PDP5CVUL.js.map → chunk-LOQLNYB3.js.map} +0 -0
  126. /package/dist/{chunk-I75TMOE4.js.map → chunk-P6PKWVYF.js.map} +0 -0
  127. /package/dist/{animations → theme}/index.js.map +0 -0
package/dist/index.js CHANGED
@@ -9,42 +9,26 @@ import {
9
9
  setViewportCenter,
10
10
  worldToScreen,
11
11
  zoomViewport
12
- } from "./chunk-LJYSKSCE.js";
12
+ } from "./chunk-W2CAOOJJ.js";
13
13
  import {
14
- ANIMATION_DURATION,
15
- ANIMATION_PHASES,
16
- COOLDOWN,
17
- OPACITY,
18
- TARGET_ZOOM,
19
- VIEWPORT_FRAMING,
20
- ZOOM_THRESHOLDS,
21
- createCubicBezier,
22
- easeInCubic,
23
- easeInOutCubic,
24
- easeInOutQuart,
25
- easeInOutSine,
26
- easeOutCubic,
27
- easeOutQuad,
28
- easeZoomTransition
29
- } from "./chunk-F36SMC3K.js";
30
- import {
31
- ACTIVE_BLOB_TYPES,
32
- ALL_BLOB_SHAPES,
33
- BLOB_LAYER_CONFIG,
34
- BLOB_TEXT_OFFSETS,
35
- CONTAINER_LABEL_BASE_FONT_PX,
36
- DESCRIPTION_TEXT_BASE_FONT_PX,
37
- EDGE_LABEL_BASE_FONT_PX,
38
- NODE_LAYER_CONFIG,
39
- NODE_TEXT_BASE_FONT_PX,
40
- OVERLAY_FONT_UPPER_BOOST_PX,
41
- computeEdgeLabelScale,
42
- computeNodeTextScreenScale,
43
- computeNodeTextWorldScale,
44
- computeOverlayScale,
45
- drawBlobPath,
46
- getBlobTypeForLayer
47
- } from "./chunk-LNTJTDB2.js";
14
+ BLOB_SHAPES,
15
+ MAX_RINGS,
16
+ RINGS,
17
+ SHAPE,
18
+ arrowPath,
19
+ blobPath,
20
+ blobRadius,
21
+ connectorGeometry,
22
+ drawBlob,
23
+ edgePath,
24
+ nodeBounds,
25
+ nodeRadii,
26
+ outlineRadius,
27
+ ringCount,
28
+ ringsFor,
29
+ shapeForLevel,
30
+ shapeOfLevel
31
+ } from "./chunk-TPLJJKAU.js";
48
32
  import {
49
33
  DEFAULT_RENDER_CONFIG,
50
34
  FEATURE_FLAGS,
@@ -56,7 +40,7 @@ import {
56
40
  getRecommendedRenderConfig,
57
41
  getRenderConfigForQuality,
58
42
  isFeatureEnabled
59
- } from "./chunk-I75TMOE4.js";
43
+ } from "./chunk-P6PKWVYF.js";
60
44
  import {
61
45
  checkCollision,
62
46
  getNodeBounds,
@@ -76,34 +60,26 @@ import {
76
60
  getChildLayers,
77
61
  getNodeConnections,
78
62
  getNodesForLayer,
63
+ getSemanticAnchors,
79
64
  getTopLevelConnections,
80
65
  getVisibleNodes,
81
66
  loadVisualliFileFromFile,
82
67
  parseVisualliFile,
83
68
  parseVisualliFromMongoDB,
84
69
  resolveNodeOverlaps
85
- } from "./chunk-6NXADJK2.js";
70
+ } from "./chunk-7NJWM7ZE.js";
86
71
  import {
87
- BRAND_COLORS,
88
- CANVAS_COLORS,
89
- DS_COLORS,
90
- DS_RADII,
91
- DS_TYPOGRAPHY,
92
- FONTS,
93
- FONT_SIZES,
94
- LAYOUT_SPACING,
95
- LEVEL_COLORS,
96
- LEVEL_COLOR_ARRAY,
97
- PARENT_FALLBACK_COLORS,
98
- SEMANTIC_COLORS,
99
- SPACING,
100
- THEME_COLORS,
101
- darkenHexColor,
102
- getColorForLevel,
103
- getThemeBackground,
104
- getThemeBorder,
105
- getThemeText
106
- } from "./chunk-G5H3P4YZ.js";
72
+ IDEA,
73
+ LABEL_GROWTH,
74
+ approximateMeasure,
75
+ ideaKindOf,
76
+ ideaSize,
77
+ labelGrowth,
78
+ wrapLines
79
+ } from "./chunk-25AJTPMS.js";
80
+ import {
81
+ LAYOUT_SPACING
82
+ } from "./chunk-N7HCYULH.js";
107
83
  import {
108
84
  applyCircularLayout,
109
85
  applyLinearHorizontalLayout,
@@ -115,18 +91,10 @@ import {
115
91
  FPSMonitor,
116
92
  MemoryMonitor,
117
93
  PerformanceProfiler
118
- } from "./chunk-PDP5CVUL.js";
94
+ } from "./chunk-LOQLNYB3.js";
119
95
  import {
120
- BORDER_WIDTH_NORMAL,
121
- BORDER_WIDTH_SELECTED,
122
- CHAR_WIDTH,
123
96
  CIRCULAR_REFERENCE_MAX_DEPTH,
124
97
  CLICK_THRESHOLD,
125
- COLOR_BORDER_DARK,
126
- COLOR_BORDER_LIGHT,
127
- COLOR_DEFAULT_NODE,
128
- COLOR_SELECTED,
129
- CORNER_RADIUS,
130
98
  CULLING_QUERY_TIME_BUDGET,
131
99
  DEFAULT_CANVAS_HEIGHT,
132
100
  DEFAULT_CANVAS_WIDTH,
@@ -141,6 +109,8 @@ import {
141
109
  FPS_UPDATE_INTERVAL,
142
110
  FPS_UPGRADE_THRESHOLD,
143
111
  FPS_WARNING_THRESHOLD,
112
+ FRAME,
113
+ GESTURE,
144
114
  MAX_FRAME_TIME,
145
115
  MAX_NODES,
146
116
  MAX_VISIBLE_NODES,
@@ -150,9 +120,8 @@ import {
150
120
  MEMORY_TARGET_MB,
151
121
  MEMORY_WARNING_MB,
152
122
  NODE_COUNT_THRESHOLDS,
153
- NODE_HEIGHT,
154
- NODE_MIN_WIDTH,
155
- NODE_PADDING,
123
+ PEEK,
124
+ PEEK_PLACEMENT,
156
125
  PERFORMANCE_TOAST_COOLDOWN,
157
126
  QUALITY_HIGH,
158
127
  QUALITY_LOW,
@@ -161,22 +130,57 @@ import {
161
130
  RESIZE_DEBOUNCE,
162
131
  SCROLL_THROTTLE,
163
132
  SEARCH_DEBOUNCE,
133
+ SHEET,
164
134
  SPATIAL_INDEX_BUILD_BUDGET,
165
135
  TARGET_FRAME_TIME,
166
- TEXT_LABEL_HIDE_BELOW_ZOOM,
136
+ TERM,
167
137
  TIMING_THRESHOLDS,
168
- TITLE_MAX_LENGTH,
138
+ TRAIL,
139
+ VIEW,
169
140
  VIEWPORT_CONFIG,
170
141
  VIEWPORT_MARGIN,
171
142
  ZOOM_DEFAULT,
172
143
  ZOOM_MAX,
173
144
  ZOOM_MIN,
174
- ZOOM_NAV_IN_THRESHOLD,
175
- ZOOM_NAV_OUT_THRESHOLD,
176
- ZOOM_STEP,
177
- ZOOM_WHEEL_SENSITIVITY
178
- } from "./chunk-LDJRGT2Q.js";
145
+ fitView,
146
+ hoverOpensTerm,
147
+ layerBounds,
148
+ peekPosition,
149
+ pinchZoom,
150
+ pointerModeFor,
151
+ zoomAround
152
+ } from "./chunk-UAMEJG2C.js";
179
153
  import "./chunk-VLGR5PZX.js";
154
+ import {
155
+ CUSTOM,
156
+ TOPIC_ORDER,
157
+ customColor,
158
+ getTokens,
159
+ ideaColor,
160
+ ideaStyle,
161
+ isContrastTheme,
162
+ isDarkTheme,
163
+ isFocusTheme,
164
+ isThemeName,
165
+ labelScale,
166
+ metricsFor,
167
+ resolveComfort,
168
+ resolveTheme,
169
+ token,
170
+ topicFor,
171
+ topicFromName,
172
+ topicStyle
173
+ } from "./chunk-KVSM3APM.js";
174
+ import {
175
+ CANVAS_STYLE,
176
+ DESIGN_SYSTEM_VERSION,
177
+ METRICS,
178
+ METRICS_REDUCED_MOTION,
179
+ THEME_NAMES,
180
+ TOKENS,
181
+ TOPICS,
182
+ TYPE_STYLES
183
+ } from "./chunk-LV3EXUQY.js";
180
184
 
181
185
  // src/spatial/spatialIndex.ts
182
186
  import RBush from "rbush";
@@ -275,6 +279,73 @@ var renderConfigStore = createStore((set, get) => ({
275
279
  isFeatureEnabled: (feature) => isFeatureEnabled(feature, get())
276
280
  }));
277
281
 
282
+ // src/generated/geometry/container.ts
283
+ var HULL = { padX: 150, padY: 125, radius: 48 };
284
+ var WEIGHT = { idea: 1e3, label: 1e3, connector: 60, preference: 1 };
285
+ var HULL_CLEAR = { x: 50, y: 51 };
286
+ function containerHull(members) {
287
+ if (!members.length) return null;
288
+ let x0 = Infinity, y0 = Infinity, x1 = -Infinity, y1 = -Infinity;
289
+ for (const m of members) {
290
+ const px = Math.max(HULL.padX, (m.rx ?? 0) + HULL_CLEAR.x), py = Math.max(HULL.padY, (m.ry ?? 0) + HULL_CLEAR.y);
291
+ x0 = Math.min(x0, m.x - px);
292
+ x1 = Math.max(x1, m.x + px);
293
+ y0 = Math.min(y0, m.y - py);
294
+ y1 = Math.max(y1, m.y + py);
295
+ }
296
+ return { x0, x1, y0, y1, radius: HULL.radius };
297
+ }
298
+ function labelCandidates(hull, w, h) {
299
+ const { x0, x1, y0, y1, radius } = hull;
300
+ const cx = (x0 + x1) / 2, cy = (y0 + y1) / 2;
301
+ const minX = x0 + radius + w / 2, maxX = x1 - radius - w / 2;
302
+ const minY = y0 + radius + h / 2, maxY = y1 - radius - h / 2;
303
+ const along = (lo, hi, f) => lo > hi ? (lo + hi) / 2 : lo + (hi - lo) * f;
304
+ const out = [
305
+ { x: cx, y: y1, side: "bottom" },
306
+ { x: cx, y: y0, side: "top" },
307
+ { x: along(minX, maxX, 0.2), y: y1, side: "bottom" },
308
+ { x: along(minX, maxX, 0.8), y: y1, side: "bottom" },
309
+ { x: along(minX, maxX, 0.2), y: y0, side: "top" },
310
+ { x: along(minX, maxX, 0.8), y: y0, side: "top" },
311
+ { x: x1, y: cy, side: "right" },
312
+ { x: x0, y: cy, side: "left" },
313
+ { x: x1, y: along(minY, maxY, 0.25), side: "right" },
314
+ { x: x1, y: along(minY, maxY, 0.75), side: "right" },
315
+ { x: x0, y: along(minY, maxY, 0.25), side: "left" },
316
+ { x: x0, y: along(minY, maxY, 0.75), side: "left" }
317
+ ];
318
+ out.push(
319
+ { x: along(minX, maxX, 0), y: y1, side: "bottom" },
320
+ { x: along(minX, maxX, 1), y: y1, side: "bottom" },
321
+ { x: along(minX, maxX, 0), y: y0, side: "top" },
322
+ { x: along(minX, maxX, 1), y: y0, side: "top" }
323
+ );
324
+ return out;
325
+ }
326
+ var overlap = (a, b) => Math.max(0, Math.min(a.x1, b.x1) - Math.max(a.x0, b.x0)) * Math.max(0, Math.min(a.y1, b.y1) - Math.max(a.y0, b.y0));
327
+ function placeContainerLabel(hull, size, obstacles, gap = 10) {
328
+ const { w, h } = size;
329
+ let best = null;
330
+ labelCandidates(hull, w, h).forEach((c, i) => {
331
+ const box = { x0: c.x - w / 2 - gap, x1: c.x + w / 2 + gap, y0: c.y - h / 2 - gap, y1: c.y + h / 2 + gap };
332
+ const area = w * h;
333
+ let score = i * WEIGHT.preference;
334
+ for (const b of obstacles.ideas) score += overlap(box, b) / area * WEIGHT.idea;
335
+ for (const b of obstacles.labels || []) score += overlap(box, b) / area * WEIGHT.label;
336
+ for (const line of obstacles.connectors || []) if (line.some((p) => p.x > box.x0 && p.x < box.x1 && p.y > box.y0 && p.y < box.y1)) score += WEIGHT.connector;
337
+ if (!best || score < best.score) best = { x: c.x, y: c.y, side: c.side, score };
338
+ });
339
+ return best;
340
+ }
341
+ function connectorSamples(a, mid, b, n = 16) {
342
+ const c1 = { x: a.x + (mid.x - a.x) * 0.66, y: a.y + (mid.y - a.y) * 0.66 }, c2 = { x: b.x + (mid.x - b.x) * 0.66, y: b.y + (mid.y - b.y) * 0.66 };
343
+ return Array.from({ length: n + 1 }, (_, k) => {
344
+ const t = k / n, u = 1 - t;
345
+ return { x: u * u * u * a.x + 3 * u * u * t * c1.x + 3 * u * t * t * c2.x + t * t * t * b.x, y: u * u * u * a.y + 3 * u * u * t * c1.y + 3 * u * t * t * c2.y + t * t * t * b.y };
346
+ });
347
+ }
348
+
278
349
  // src/utils/navigation.ts
279
350
  function getConnectionsForLayer(doc, layerId) {
280
351
  const layer = doc.layers.get(layerId);
@@ -283,7 +354,8 @@ function getConnectionsForLayer(doc, layerId) {
283
354
  from: c.from,
284
355
  to: c.to,
285
356
  level: layer.level,
286
- label: c.data?.label
357
+ label: c.data?.label,
358
+ style: c.data?.style === "dashed" ? "dashed" : "solid"
287
359
  }));
288
360
  }
289
361
  function getChildLayerForNode(doc, nodeId, currentLayerId) {
@@ -297,53 +369,49 @@ function getChildLayerForNode(doc, nodeId, currentLayerId) {
297
369
  function getLayerForNavigation(doc, nodeId, currentLayerId) {
298
370
  return getChildLayerForNode(doc, nodeId, currentLayerId);
299
371
  }
300
- function calculateFitZoom(nodes, canvasWidth, canvasHeight, padding = 0.15) {
301
- if (nodes.length === 0) return 1;
302
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
303
- for (const n of nodes) {
304
- minX = Math.min(minX, n.x - n.width / 2);
305
- minY = Math.min(minY, n.y - n.height / 2);
306
- maxX = Math.max(maxX, n.x + n.width / 2);
307
- maxY = Math.max(maxY, n.y + n.height / 2);
372
+ function layerFrame(nodes, containers = []) {
373
+ const byId = new Map(nodes.map((n) => [n.id, n]));
374
+ const hulls = [];
375
+ for (const c of containers) {
376
+ const hull = containerHull(c.nodeIds.flatMap((id) => {
377
+ const n = byId.get(id);
378
+ return n ? [{ x: n.x, y: n.y, rx: n.width / 2, ry: n.height / 2 }] : [];
379
+ }));
380
+ if (hull) hulls.push(hull);
308
381
  }
309
- const rawW = maxX - minX;
310
- const rawH = maxY - minY;
311
- const spreadW = nodes.length === 1 ? Math.max(rawW, 600) : rawW;
312
- const spreadH = nodes.length === 1 ? Math.max(rawH, 400) : rawH;
313
- const zoomX = canvasWidth * (1 - padding) / spreadW;
314
- const zoomY = canvasHeight * (1 - padding) / spreadH;
315
- const z = Math.min(zoomX, zoomY);
316
- return Math.max(z * 0.8, ZOOM_NAV_OUT_THRESHOLD);
382
+ return layerBounds(nodes.map((n) => ({ x: n.x, y: n.y, rx: n.width / 2, ry: n.height / 2 })), hulls);
383
+ }
384
+ function calculateFitZoom(nodes, canvasWidth, canvasHeight, containers = []) {
385
+ if (nodes.length === 0) return 1;
386
+ return fitView(layerFrame(nodes, containers), canvasWidth, canvasHeight).scale;
317
387
  }
318
- function calculateFitCenter(nodes) {
388
+ function calculateFitCenter(nodes, containers = []) {
319
389
  if (nodes.length === 0) return { x: 0, y: 0 };
320
- let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
321
- for (const n of nodes) {
322
- minX = Math.min(minX, n.x - n.width / 2);
323
- minY = Math.min(minY, n.y - n.height / 2);
324
- maxX = Math.max(maxX, n.x + n.width / 2);
325
- maxY = Math.max(maxY, n.y + n.height / 2);
326
- }
327
- return { x: (minX + maxX) / 2, y: (minY + maxY) / 2 };
390
+ const f = layerFrame(nodes, containers);
391
+ return { x: (f.x0 + f.x1) / 2, y: (f.y0 + f.y1) / 2 };
328
392
  }
329
393
  function getContainersForLayer(doc, layerId) {
330
394
  const layer = doc.layers.get(layerId);
331
395
  if (!layer) return [];
332
396
  const containers = layer.containers ?? [];
333
397
  if (!Array.isArray(containers)) return [];
334
- return containers.map((c) => {
398
+ return containers.filter((c) => c.data?.style !== "none").map((c) => {
335
399
  const label = c.data?.label ?? c.id;
336
400
  return { id: c.id, label, nodeIds: c.nodes, level: layer.level };
337
401
  });
338
402
  }
339
- function calculateFitView(nodes, canvasWidth, canvasHeight) {
340
- const center = calculateFitCenter(nodes);
341
- const zoom = calculateFitZoom(nodes, canvasWidth, canvasHeight);
342
- return { centerX: center.x, centerY: center.y, zoomLevel: zoom };
403
+ function calculateFitView(nodes, canvasWidth, canvasHeight, containers = []) {
404
+ if (nodes.length === 0) return { centerX: 0, centerY: 0, zoomLevel: 1 };
405
+ const { scale, center } = fitView(layerFrame(nodes, containers), canvasWidth, canvasHeight);
406
+ return { centerX: center.x, centerY: center.y, zoomLevel: scale };
343
407
  }
344
408
 
345
409
  // src/rendering/culling.ts
346
410
  var DEFAULT_SPATIAL_INDEX_THRESHOLD = 200;
411
+ function intersectsViewport(n, bounds) {
412
+ const b = nodeBounds(n);
413
+ return b.maxX >= bounds.minX && b.minX <= bounds.maxX && b.maxY >= bounds.minY && b.minY <= bounds.maxY;
414
+ }
347
415
  function getViewportVisibleNodes(options) {
348
416
  const {
349
417
  nodes,
@@ -361,9 +429,7 @@ function getViewportVisibleNodes(options) {
361
429
  if (skipCulling || isDragging) return filtered;
362
430
  const bounds = calculateViewportBounds(viewport, canvasWidth, canvasHeight);
363
431
  if (filtered.length < spatialIndexThreshold) {
364
- return filtered.filter(
365
- (n) => n.x + n.width >= bounds.minX && n.x <= bounds.maxX && n.y + n.height >= bounds.minY && n.y <= bounds.maxY
366
- );
432
+ return filtered.filter((n) => intersectsViewport(n, bounds));
367
433
  }
368
434
  if (spatialIndex) {
369
435
  const nodeIds = spatialIndex.query({
@@ -375,45 +441,191 @@ function getViewportVisibleNodes(options) {
375
441
  const idSet = new Set(nodeIds);
376
442
  return filtered.filter((n) => idSet.has(n.id));
377
443
  }
378
- return filtered.filter(
379
- (n) => n.x + n.width >= bounds.minX && n.x <= bounds.maxX && n.y + n.height >= bounds.minY && n.y <= bounds.maxY
380
- );
444
+ return filtered.filter((n) => intersectsViewport(n, bounds));
445
+ }
446
+
447
+ // src/generated/geometry/motion.ts
448
+ var EASE = {
449
+ /** ease-standard — UI and connector drawing. */
450
+ standard: [0.4, 0, 0.2, 1],
451
+ /** ease-zoom — diving into and out of layers. */
452
+ zoom: [0.2, 0.8, 0.2, 1],
453
+ /** ease-bloom — ideas arriving, with a little overshoot. */
454
+ bloom: [0.34, 1.4, 0.64, 1]
455
+ };
456
+ var MOTION = {
457
+ /** A layer arrives: ideas bloom one by one in sibling order, center first, then connectors draw. */
458
+ reveal: {
459
+ /** duration-reveal: each idea's bloom. */
460
+ duration: 420,
461
+ /** stagger-reveal: delay between consecutive ideas. */
462
+ stagger: 70,
463
+ /** An idea starts at this scale… */
464
+ fromScale: 0.55,
465
+ /** …and this fraction of the way from its place toward the layer's center. */
466
+ fromCenter: 0.5,
467
+ ease: EASE.bloom,
468
+ /** Settle time after the last bloom before the map is idle (interactive again). */
469
+ tail: 200
470
+ },
471
+ /** Connectors of an arriving layer: they start once the ideas are mostly in. */
472
+ connector: {
473
+ /** Lead time before the first connector, on top of the ideas' stagger. */
474
+ lead: 240,
475
+ /** Delay between consecutive connectors. */
476
+ stagger: 60,
477
+ /** A solid connector draws from source to target; a dashed one fades in instead. */
478
+ draw: 500,
479
+ /** The connector group's fade (duration-base). */
480
+ fade: 240,
481
+ ease: EASE.standard
482
+ },
483
+ /** Step inside: the current layer zooms toward the idea and fades; the inner layer then arrives (reveal). */
484
+ dive: {
485
+ /** The old layer's zoom, toward the idea's position. */
486
+ scale: 3.2,
487
+ /** duration-zoom. */
488
+ duration: 500,
489
+ /** It fades out after this delay, over `fade`. */
490
+ fadeDelay: 150,
491
+ fade: 160,
492
+ /** The layers swap (and the reveal starts) this long after the dive starts. */
493
+ swapAfter: 320,
494
+ ease: EASE.zoom
495
+ },
496
+ /** Back out (depth trail): the current layer shrinks toward the center and fades; the outer layer arrives. */
497
+ surface: {
498
+ scale: 0.6,
499
+ duration: 220,
500
+ fade: 200,
501
+ swapAfter: 220,
502
+ ease: EASE.zoom
503
+ },
504
+ /** The arriving layer as a whole settles from slightly small. */
505
+ settle: { fromScale: 0.94, duration: 260, ease: EASE.standard },
506
+ /** Hover (pointer) or select: the idea lifts; its rings turn and grow a touch — a nudge, not a wobble. */
507
+ hover: {
508
+ lift: 2,
509
+ ringRotate: -2,
510
+ ringScale: 1.015,
511
+ /** duration-base, for both the lift (ease-bloom) and the rings (ease-standard). */
512
+ duration: 240,
513
+ liftEase: EASE.bloom,
514
+ ringEase: EASE.standard
515
+ },
516
+ /** Reduced motion, or Gradual reveal off: everything appears together with a short fade; dives become cross-fades. */
517
+ reduced: { fade: 120 },
518
+ /** Large layers. The stagger is written for a dozen ideas; a layer of hundreds would take minutes to arrive and
519
+ * every frame of a bloom repaints the whole layer. Above `staggerSlots` ideas (and connectors), they share that many
520
+ * slots, so a layer never takes longer to arrive than `staggerSlots` ideas would. Above `bloomMax` ideas the layer
521
+ * fades in together (the reduced fade) and hover lifts snap instead of easing. */
522
+ largeLayer: { staggerSlots: 30, bloomMax: 150 }
523
+ };
524
+ function revealDelay(i) {
525
+ return i * MOTION.reveal.stagger;
526
+ }
527
+ function connectorDelay(i, nodeCount) {
528
+ return MOTION.connector.lead + nodeCount * MOTION.reveal.stagger + i * MOTION.connector.stagger;
529
+ }
530
+ function revealTotal(nodeCount, reduced = false) {
531
+ return reduced ? 0 : MOTION.reveal.duration + nodeCount * MOTION.reveal.stagger + MOTION.reveal.tail;
532
+ }
533
+ function bloomOffset(node, center) {
534
+ const k = MOTION.reveal.fromCenter;
535
+ return { x: (center.x - node.x) * k, y: (center.y - node.y) * k };
536
+ }
537
+ function swapDelay(dir, reduced = false) {
538
+ return reduced ? 0 : dir === "in" ? MOTION.dive.swapAfter : MOTION.surface.swapAfter;
539
+ }
540
+ function revealSlot(i, count) {
541
+ const slots = Math.min(count, MOTION.largeLayer.staggerSlots);
542
+ return count > slots ? Math.floor(i * slots / count) : i;
543
+ }
544
+ function layerBlooms(nodeCount) {
545
+ return nodeCount <= MOTION.largeLayer.bloomMax;
546
+ }
547
+ function layerReveal(nodeCount, connectorCount, reduced = false) {
548
+ const instant = reduced || !layerBlooms(nodeCount);
549
+ const slots = Math.min(nodeCount, MOTION.largeLayer.staggerSlots);
550
+ const edgeSlots = Math.min(connectorCount, MOTION.largeLayer.staggerSlots);
551
+ return {
552
+ /** Fades in together (reduced motion, Gradual reveal off, or a layer past `bloomMax`). */
553
+ instant,
554
+ ideaDelay: (i) => instant ? 0 : revealDelay(revealSlot(i, nodeCount)),
555
+ connectorDelay: (i) => instant ? 0 : connectorDelay(revealSlot(i, connectorCount), slots),
556
+ /** Until the map is idle again. */
557
+ total: instant ? reduced ? 0 : MOTION.reduced.fade : Math.max(revealTotal(slots), edgeSlots ? connectorDelay(edgeSlots - 1, slots) + MOTION.connector.draw : 0)
558
+ };
559
+ }
560
+ function cssEase(e) {
561
+ return `cubic-bezier(${e.join(", ")})`;
562
+ }
563
+ function ease(e, t) {
564
+ const [x1, y1, x2, y2] = e;
565
+ if (t <= 0) return 0;
566
+ if (t >= 1) return 1;
567
+ const bx = (u2) => 3 * x1 * u2 * (1 - u2) ** 2 + 3 * x2 * u2 * u2 * (1 - u2) + u2 ** 3;
568
+ const by = (u2) => 3 * y1 * u2 * (1 - u2) ** 2 + 3 * y2 * u2 * u2 * (1 - u2) + u2 ** 3;
569
+ let lo = 0, hi = 1, u = t;
570
+ for (let k = 0; k < 24; k++) {
571
+ u = (lo + hi) / 2;
572
+ if (bx(u) < t) lo = u;
573
+ else hi = u;
574
+ }
575
+ return by(u);
576
+ }
577
+ function motionVars() {
578
+ const m = MOTION;
579
+ return {
580
+ "--vi-bloom-from": String(m.reveal.fromScale),
581
+ "--vi-line-draw": `${m.connector.draw}ms`,
582
+ "--vi-dive-scale": String(m.dive.scale),
583
+ "--vi-dive-fade": `${m.dive.fade}ms`,
584
+ "--vi-dive-fade-delay": `${m.dive.fadeDelay}ms`,
585
+ "--vi-surface-scale": String(m.surface.scale),
586
+ "--vi-surface-dur": `${m.surface.duration}ms`,
587
+ "--vi-surface-fade": `${m.surface.fade}ms`,
588
+ "--vi-settle-from": String(m.settle.fromScale),
589
+ "--vi-settle-dur": `${m.settle.duration}ms`,
590
+ "--vi-reduced-fade": `${m.reduced.fade}ms`,
591
+ "--vi-lift": `${m.hover.lift}px`,
592
+ "--vi-ring-turn": `${m.hover.ringRotate}deg`,
593
+ "--vi-ring-grow": String(m.hover.ringScale)
594
+ };
595
+ }
596
+
597
+ // src/generated/geometry/detail.ts
598
+ var DETAIL = {
599
+ /** Below this on-screen width an idea draws only its body: no rings, label or shadow. */
600
+ bodyOnlyBelow: 24,
601
+ /** Below this it may be drawn as a plain filled speck in its topic fill (no outline) — indistinguishable at this size. */
602
+ speckBelow: 12,
603
+ /** Above this many ideas in view, idea shadows are skipped (the costliest effect to draw). */
604
+ shadowsMaxVisible: 150
605
+ };
606
+ function ideaDetail(screenWidth, emphasised = false) {
607
+ if (emphasised || screenWidth >= DETAIL.bodyOnlyBelow) return "full";
608
+ return screenWidth < DETAIL.speckBelow ? "speck" : "body";
609
+ }
610
+ function shadowsShown(visibleIdeas) {
611
+ return visibleIdeas <= DETAIL.shadowsMaxVisible;
381
612
  }
382
613
  export {
383
- ACTIVE_BLOB_TYPES,
384
- ALL_BLOB_SHAPES,
385
- ANIMATION_DURATION,
386
- ANIMATION_PHASES,
387
- BLOB_LAYER_CONFIG,
388
- BLOB_TEXT_OFFSETS,
389
- BORDER_WIDTH_NORMAL,
390
- BORDER_WIDTH_SELECTED,
391
- BRAND_COLORS,
392
- CANVAS_COLORS,
393
- CHAR_WIDTH,
614
+ BLOB_SHAPES,
615
+ CANVAS_STYLE,
394
616
  CIRCULAR_REFERENCE_MAX_DEPTH,
395
617
  CLICK_THRESHOLD,
396
- COLOR_BORDER_DARK,
397
- COLOR_BORDER_LIGHT,
398
- COLOR_DEFAULT_NODE,
399
- COLOR_SELECTED,
400
- CONTAINER_LABEL_BASE_FONT_PX,
401
- COOLDOWN,
402
- CORNER_RADIUS,
403
618
  CULLING_QUERY_TIME_BUDGET,
619
+ CUSTOM,
404
620
  DEFAULT_CANVAS_HEIGHT,
405
621
  DEFAULT_CANVAS_WIDTH,
406
622
  DEFAULT_RENDER_CONFIG,
407
- DESCRIPTION_TEXT_BASE_FONT_PX,
623
+ DESIGN_SYSTEM_VERSION,
624
+ DETAIL,
408
625
  DOUBLE_CLICK_DELAY,
409
626
  DRAG_START_DISTANCE,
410
- DS_COLORS,
411
- DS_RADII,
412
- DS_TYPOGRAPHY,
413
- EDGE_LABEL_BASE_FONT_PX,
627
+ EASE,
414
628
  FEATURE_FLAGS,
415
- FONTS,
416
- FONT_SIZES,
417
629
  FPSMonitor,
418
630
  FPS_CRITICAL_THRESHOLD,
419
631
  FPS_DOWNGRADE_THRESHOLD,
@@ -424,27 +636,29 @@ export {
424
636
  FPS_UPDATE_INTERVAL,
425
637
  FPS_UPGRADE_THRESHOLD,
426
638
  FPS_WARNING_THRESHOLD,
639
+ FRAME,
640
+ GESTURE,
641
+ HULL,
642
+ HULL_CLEAR,
643
+ IDEA,
644
+ LABEL_GROWTH,
427
645
  LAYOUT_SPACING,
428
- LEVEL_COLORS,
429
- LEVEL_COLOR_ARRAY,
430
646
  MAX_FRAME_TIME,
431
647
  MAX_NODES,
648
+ MAX_RINGS,
432
649
  MAX_VISIBLE_NODES,
433
650
  MEMORY_CHECK_INTERVAL,
434
651
  MEMORY_CRITICAL_MB,
435
652
  MEMORY_LIMITS,
436
653
  MEMORY_TARGET_MB,
437
654
  MEMORY_WARNING_MB,
655
+ METRICS,
656
+ METRICS_REDUCED_MOTION,
657
+ MOTION,
438
658
  MemoryMonitor,
439
659
  NODE_COUNT_THRESHOLDS,
440
- NODE_HEIGHT,
441
- NODE_LAYER_CONFIG,
442
- NODE_MIN_WIDTH,
443
- NODE_PADDING,
444
- NODE_TEXT_BASE_FONT_PX,
445
- OPACITY,
446
- OVERLAY_FONT_UPPER_BOOST_PX,
447
- PARENT_FALLBACK_COLORS,
660
+ PEEK,
661
+ PEEK_PLACEMENT,
448
662
  PERFORMANCE_TOAST_COOLDOWN,
449
663
  PerformanceProfiler,
450
664
  QUALITY_HIGH,
@@ -456,33 +670,37 @@ export {
456
670
  RBushSpatialIndex,
457
671
  RENDER_MODES,
458
672
  RESIZE_DEBOUNCE,
673
+ RINGS,
459
674
  SCROLL_THROTTLE,
460
675
  SEARCH_DEBOUNCE,
461
- SEMANTIC_COLORS,
676
+ SHAPE,
677
+ SHEET,
462
678
  SIMPLIFIED_RENDER_CONFIG,
463
- SPACING,
464
679
  SPATIAL_INDEX_BUILD_BUDGET,
465
680
  TARGET_FRAME_TIME,
466
- TARGET_ZOOM,
467
- TEXT_LABEL_HIDE_BELOW_ZOOM,
468
- THEME_COLORS,
681
+ TERM,
682
+ THEME_NAMES,
469
683
  TIMING_THRESHOLDS,
470
- TITLE_MAX_LENGTH,
684
+ TOKENS,
685
+ TOPICS,
686
+ TOPIC_ORDER,
687
+ TRAIL,
688
+ TYPE_STYLES,
689
+ VIEW,
471
690
  VIEWPORT_CONFIG,
472
- VIEWPORT_FRAMING,
473
691
  VIEWPORT_MARGIN,
474
692
  VisualliParseError,
475
693
  ZOOM_DEFAULT,
476
694
  ZOOM_MAX,
477
695
  ZOOM_MIN,
478
- ZOOM_NAV_IN_THRESHOLD,
479
- ZOOM_NAV_OUT_THRESHOLD,
480
- ZOOM_STEP,
481
- ZOOM_THRESHOLDS,
482
- ZOOM_WHEEL_SENSITIVITY,
483
696
  applyCircularLayout,
484
697
  applyLinearHorizontalLayout,
485
698
  applyLinearVerticalLayout,
699
+ approximateMeasure,
700
+ arrowPath,
701
+ blobPath,
702
+ blobRadius,
703
+ bloomOffset,
486
704
  calculateDistance,
487
705
  calculateFitCenter,
488
706
  calculateFitView,
@@ -492,32 +710,26 @@ export {
492
710
  calculateViewportBounds,
493
711
  checkCollision,
494
712
  clampZoom,
495
- computeEdgeLabelScale,
496
- computeNodeTextScreenScale,
497
- computeNodeTextWorldScale,
498
- computeOverlayScale,
713
+ connectorDelay,
714
+ connectorGeometry,
715
+ connectorSamples,
716
+ containerHull,
499
717
  convertLayerToFlatNodes,
500
718
  convertVisualliToFlatNodes,
501
719
  countLayersBeneath,
502
- createCubicBezier,
503
720
  createMindMapConfig,
504
- darkenHexColor,
505
- drawBlobPath,
506
- easeInCubic,
507
- easeInOutCubic,
508
- easeInOutQuart,
509
- easeInOutSine,
510
- easeOutCubic,
511
- easeOutQuad,
512
- easeZoomTransition,
721
+ cssEase,
722
+ customColor,
723
+ drawBlob,
724
+ ease as easeBezier,
725
+ edgePath,
513
726
  fetchAndParseVisualli,
727
+ fitView,
514
728
  flattenNodes,
515
729
  focusOnNode,
516
730
  generateSampleConfig,
517
- getBlobTypeForLayer,
518
731
  getChildLayerForNode,
519
732
  getChildLayers,
520
- getColorForLevel,
521
733
  getConnectionsForLayer,
522
734
  getContainersForLayer,
523
735
  getLayerForNavigation,
@@ -527,27 +739,70 @@ export {
527
739
  getOptimalQualityLevel,
528
740
  getRecommendedRenderConfig,
529
741
  getRenderConfigForQuality,
530
- getThemeBackground,
531
- getThemeBorder,
532
- getThemeText,
742
+ getSemanticAnchors,
743
+ getTokens,
533
744
  getTopLevelConnections,
534
745
  getViewportVisibleNodes,
535
746
  getVisibleNodes,
747
+ hoverOpensTerm,
748
+ ideaColor,
749
+ ideaDetail,
750
+ ideaKindOf,
751
+ ideaSize,
752
+ ideaStyle,
753
+ intersectsViewport,
754
+ isContrastTheme,
755
+ isDarkTheme,
536
756
  isFeatureEnabled,
757
+ isFocusTheme,
537
758
  isNodeInViewport,
759
+ isThemeName,
760
+ labelCandidates,
761
+ labelGrowth,
762
+ labelScale,
763
+ layerBlooms,
764
+ layerBounds,
765
+ layerFrame,
766
+ layerReveal,
538
767
  loadVisualliFileFromFile,
768
+ metricsFor,
769
+ motionVars,
770
+ nodeBounds,
771
+ nodeRadii,
539
772
  optimizeLayout,
773
+ outlineRadius,
540
774
  panViewport,
541
775
  parseVisualliFile,
542
776
  parseVisualliFromMongoDB,
777
+ peekPosition,
778
+ pinchZoom,
779
+ placeContainerLabel,
780
+ pointerModeFor,
543
781
  recalculateViewportBounds,
544
782
  renderConfigStore,
545
783
  resolveCollisions,
784
+ resolveComfort,
546
785
  resolveNodeOverlaps,
786
+ resolveTheme,
787
+ revealDelay,
788
+ revealSlot,
789
+ revealTotal,
790
+ ringCount,
791
+ ringsFor,
547
792
  screenToWorld,
548
793
  selectionStore,
549
794
  setViewportCenter,
795
+ shadowsShown,
796
+ shapeForLevel,
797
+ shapeOfLevel,
798
+ swapDelay,
799
+ token,
800
+ topicFor,
801
+ topicFromName,
802
+ topicStyle,
550
803
  worldToScreen,
804
+ wrapLines,
805
+ zoomAround,
551
806
  zoomViewport
552
807
  };
553
808
  //# sourceMappingURL=index.js.map