@visualli/core 0.1.1
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.
- package/README.md +263 -0
- package/dist/index.cjs +2325 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1181 -0
- package/dist/index.d.ts +1181 -0
- package/dist/index.js +2119 -0
- package/dist/index.js.map +1 -0
- package/package.json +80 -0
- package/src/animations/constants.ts +72 -0
- package/src/animations/easing.ts +70 -0
- package/src/animations/index.ts +2 -0
- package/src/config/blobShapes.ts +146 -0
- package/src/config/textScaling.ts +54 -0
- package/src/constants/design.ts +281 -0
- package/src/constants/index.ts +3 -0
- package/src/constants/performanceConstants.ts +157 -0
- package/src/constants/renderConfig.ts +134 -0
- package/src/index.ts +18 -0
- package/src/layout/circularLayout.ts +95 -0
- package/src/layout/index.ts +3 -0
- package/src/layout/layoutUtils.ts +132 -0
- package/src/layout/linearLayout.ts +84 -0
- package/src/parser/configUtils.ts +129 -0
- package/src/parser/index.ts +4 -0
- package/src/parser/middleware.ts +24 -0
- package/src/parser/mindmapUtils.ts +76 -0
- package/src/parser/visualliConverter.ts +328 -0
- package/src/parser/visualliParser.ts +191 -0
- package/src/performance/index.ts +1 -0
- package/src/performance/performanceMonitor.ts +145 -0
- package/src/rendering/culling.ts +71 -0
- package/src/spatial/index.ts +1 -0
- package/src/spatial/spatialIndex.ts +83 -0
- package/src/stores/index.ts +61 -0
- package/src/types/document.ts +15 -0
- package/src/types/index.ts +17 -0
- package/src/types/layer.ts +67 -0
- package/src/types/meta.ts +9 -0
- package/src/types/mindmap.ts +136 -0
- package/src/types/schema.ts +36 -0
- package/src/utils/navigation.ts +161 -0
- package/src/viewport/index.ts +1 -0
- package/src/viewport/viewportUtils.ts +195 -0
package/README.md
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
# @visualli/core
|
|
2
|
+
|
|
3
|
+
Framework-agnostic core logic, types, and algorithms for Visualli. Zero React / DOM dependencies.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
| Module | What it provides |
|
|
8
|
+
|--------|------------------|
|
|
9
|
+
| **Types** | Full TypeScript interfaces for `VisualliDocument`, `VisualliLayer`, `FlatNode`, `ViewportState`, `RenderConfig`, `Connection`, and more |
|
|
10
|
+
| **Parser** | Parse `.visualli` JSONL files, convert layers to flat nodes, resolve spatial overlaps |
|
|
11
|
+
| **Layout** | Circular and linear layout algorithms with automatic radius/spacing calculation |
|
|
12
|
+
| **Viewport** | Pure pan/zoom/bounds math — world↔screen coordinate transforms, fit-to-screen |
|
|
13
|
+
| **Spatial index** | RBush-backed O(log n) spatial index for viewport culling of large node graphs |
|
|
14
|
+
| **Animations** | Easing functions (cubic, quartic, sine, bezier LUT) and timing phase constants |
|
|
15
|
+
| **Performance** | rAF-based FPS monitor, memory monitor, profiler |
|
|
16
|
+
| **Constants** | Design tokens (colors, spacing, typography), zoom limits, FPS targets, render config |
|
|
17
|
+
|
|
18
|
+
## Installation
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install @visualli/core
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
> **Only dependency:** [`rbush`](https://github.com/mourner/rbush) — no React, no Zod, no network code.
|
|
25
|
+
|
|
26
|
+
## Quick Start
|
|
27
|
+
|
|
28
|
+
### Parse a document
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { parseVisualliFile, getNodesForLayer } from '@visualli/core';
|
|
32
|
+
|
|
33
|
+
// Parse from a raw JSONL string
|
|
34
|
+
const doc = parseVisualliFile(rawJsonlString);
|
|
35
|
+
|
|
36
|
+
// Get the root layer
|
|
37
|
+
const rootLayerId = [...doc.layers.keys()][0];
|
|
38
|
+
const nodes = getNodesForLayer(doc, rootLayerId); // FlatNode[]
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Apply layouts
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
import { applyCircularLayout, applyLinearHorizontalLayout } from '@visualli/core';
|
|
45
|
+
|
|
46
|
+
applyCircularLayout(nodes); // mutates x/y in-place
|
|
47
|
+
applyLinearHorizontalLayout(nodes); // horizontal tree layout
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Viewport math
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
import {
|
|
54
|
+
zoomViewport, panViewport, setViewportCenter,
|
|
55
|
+
calculateViewportBounds, worldToScreen, screenToWorld,
|
|
56
|
+
} from '@visualli/core';
|
|
57
|
+
|
|
58
|
+
const next = zoomViewport(delta, viewport, pivotX, pivotY, canvasW, canvasH);
|
|
59
|
+
const bounds = calculateViewportBounds(viewport, canvasW, canvasH);
|
|
60
|
+
const screenPt = worldToScreen(worldX, worldY, viewport, canvasW, canvasH);
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Spatial culling
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import { RBushSpatialIndex } from '@visualli/core';
|
|
67
|
+
|
|
68
|
+
const index = new RBushSpatialIndex();
|
|
69
|
+
index.bulkLoad(nodes.map(n => ({
|
|
70
|
+
nodeId: n.id,
|
|
71
|
+
bounds: { minX: n.x, minY: n.y, maxX: n.x + n.width, maxY: n.y + n.height },
|
|
72
|
+
})));
|
|
73
|
+
|
|
74
|
+
// Query visible nodes
|
|
75
|
+
const visible = index.query(viewportBounds); // string[] — node IDs
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Easing
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import { easeInOutCubic, easeOutCubic, createCubicBezier } from '@visualli/core';
|
|
82
|
+
|
|
83
|
+
const t = easeInOutCubic(progress); // 0..1 → 0..1
|
|
84
|
+
const custom = createCubicBezier(0.4, 0, 0.2, 1); // CSS timing function
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Colors & design tokens
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import {
|
|
91
|
+
getColorForLevel, getThemeBackground,
|
|
92
|
+
LEVEL_COLOR_ARRAY, DS_COLORS, BRAND_COLORS,
|
|
93
|
+
} from '@visualli/core';
|
|
94
|
+
|
|
95
|
+
const nodeColor = getColorForLevel(2); // '#...' for level 2
|
|
96
|
+
const bg = getThemeBackground(isDark); // canvas background
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Module Reference
|
|
100
|
+
|
|
101
|
+
### `types/`
|
|
102
|
+
|
|
103
|
+
| Export | Description |
|
|
104
|
+
|--------|-------------|
|
|
105
|
+
| `VisualliDocument` | Top-level document (layers Map, extensions Map) |
|
|
106
|
+
| `VisualliLayer` | A single layer: level, nodes, connections, containers |
|
|
107
|
+
| `FlatNode` | Renderable node (position, size, title, color, level, parentId) |
|
|
108
|
+
| `NodeMap` | `Map<string, FlatNode>` |
|
|
109
|
+
| `ViewportState` | `centerX/Y`, `zoomLevel`, `rotation`, `visibleBounds` |
|
|
110
|
+
| `RenderConfig` | Quality level, FPS target, culling flag, render mode |
|
|
111
|
+
| `Connection` | Edge: `from`, `to`, `level`, optional `label` |
|
|
112
|
+
|
|
113
|
+
### `parser/`
|
|
114
|
+
|
|
115
|
+
| Export | Description |
|
|
116
|
+
|--------|-------------|
|
|
117
|
+
| `parseVisualliFile(str)` | Parse JSONL → `VisualliDocument` |
|
|
118
|
+
| `loadVisualliFileFromFile(file)` | Parse a browser `File` object |
|
|
119
|
+
| `getNodesForLayer(doc, layerId)` | `FlatNode[]` for one layer |
|
|
120
|
+
| `convertVisualliToFlatNodes(doc)` | All layers → `NodeMap` |
|
|
121
|
+
| `getChildLayers(doc, layerId)` | Direct child layers |
|
|
122
|
+
|
|
123
|
+
### `layout/`
|
|
124
|
+
|
|
125
|
+
| Export | Description |
|
|
126
|
+
|--------|-------------|
|
|
127
|
+
| `applyCircularLayout(nodes)` | Radial arrangement |
|
|
128
|
+
| `applyLinearHorizontalLayout(nodes)` | Left-to-right tree |
|
|
129
|
+
| `applyLinearVerticalLayout(nodes)` | Top-to-bottom tree |
|
|
130
|
+
| `resolveCollisions(nodes)` | Push apart overlapping nodes |
|
|
131
|
+
|
|
132
|
+
### `viewport/`
|
|
133
|
+
|
|
134
|
+
| Export | Description |
|
|
135
|
+
|--------|-------------|
|
|
136
|
+
| `calculateViewportBounds(vp, w, h)` | Visible world rect |
|
|
137
|
+
| `zoomViewport(delta, vp, px, py, w, h)` | Zoom to cursor |
|
|
138
|
+
| `panViewport(dx, dy, vp)` | Translate camera |
|
|
139
|
+
| `setViewportCenter(x, y, vp)` | Teleport center |
|
|
140
|
+
| `clampZoom(level)` | Clamp to `[ZOOM_MIN, ZOOM_MAX]` |
|
|
141
|
+
| `worldToScreen(x, y, vp, w, h)` | World → screen px |
|
|
142
|
+
| `screenToWorld(x, y, vp, w, h)` | Screen px → world |
|
|
143
|
+
|
|
144
|
+
### `constants/`
|
|
145
|
+
|
|
146
|
+
| Export | Description |
|
|
147
|
+
|--------|-------------|
|
|
148
|
+
| `ZOOM_MIN` / `ZOOM_MAX` | `0.3` / `5.0` |
|
|
149
|
+
| `ZOOM_NAV_IN_THRESHOLD` | `2.7` — zoom level that triggers drill-in |
|
|
150
|
+
| `ZOOM_NAV_OUT_THRESHOLD` | `0.4` — zoom level that triggers back navigation |
|
|
151
|
+
| `LEVEL_COLOR_ARRAY` | 10-color palette indexed by node level |
|
|
152
|
+
| `DEFAULT_RENDER_CONFIG` | Baseline quality settings |
|
|
153
|
+
| `ANIMATION_PHASES` | Duration constants for layer transitions |
|
|
154
|
+
|
|
155
|
+
## TypeScript
|
|
156
|
+
|
|
157
|
+
The package ships `.d.ts` declarations alongside source maps. `moduleResolution: "bundler"` is recommended (compatible with Vite / esbuild).
|
|
158
|
+
|
|
159
|
+
```jsonc
|
|
160
|
+
// tsconfig.json
|
|
161
|
+
{
|
|
162
|
+
"compilerOptions": {
|
|
163
|
+
"moduleResolution": "bundler",
|
|
164
|
+
"target": "ES2020"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Build
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
npm run build # tsc → dist/
|
|
173
|
+
npm run typecheck # tsc --noEmit (0 errors expected)
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
## Structure
|
|
178
|
+
|
|
179
|
+
```
|
|
180
|
+
src/
|
|
181
|
+
├── types/ TypeScript interfaces, enums, Zod schemas
|
|
182
|
+
│ ├── mindmap.ts MindMapNode, FlatNode, NodeMap, ViewportState, RenderConfig …
|
|
183
|
+
│ ├── meta.ts VisualliMeta
|
|
184
|
+
│ ├── layer.ts VisualliLayer, LayerNode, LayerConnection, LayerContainer …
|
|
185
|
+
│ ├── extension.ts VisualliExtension
|
|
186
|
+
│ ├── document.ts VisualliDocument
|
|
187
|
+
│ ├── schema.ts JSON-schema-aligned types + re-exports
|
|
188
|
+
│ ├── processing.ts ConnectionState, ProcessingState, type guards
|
|
189
|
+
│ └── sse.ts SSEEvent discriminated union + Zod validation + helpers
|
|
190
|
+
│
|
|
191
|
+
├── layout/ Pure layout algorithms (no side-effects)
|
|
192
|
+
│ ├── circularLayout.ts applyCircularLayout, calculateOptimalRadiusPercentage
|
|
193
|
+
│ ├── linearLayout.ts applyLinearHorizontalLayout, applyLinearVerticalLayout
|
|
194
|
+
│ └── layoutUtils.ts getNodeBounds, resolveCollisions, optimizeLayout
|
|
195
|
+
│
|
|
196
|
+
├── parser/ File parsing and data conversion
|
|
197
|
+
│ ├── visualliParser.ts parseVisualliFile, loadVisualliFile, getChildLayers …
|
|
198
|
+
│ ├── visualliConverter.ts convertVisualliToFlatNodes, resolveNodeOverlaps …
|
|
199
|
+
│ ├── mindmapUtils.ts flattenNodes, getVisibleNodes, calculateDistance …
|
|
200
|
+
│ └── configUtils.ts createMindMapConfig, generateSampleConfig
|
|
201
|
+
│
|
|
202
|
+
├── services/ Network utilities (fetch, SSE, logging)
|
|
203
|
+
│ ├── api.ts initApi, apiRequest, ApiError, mindmapApi, correlationId helpers
|
|
204
|
+
│ ├── logger.ts Logger class (buffered remote + console)
|
|
205
|
+
│ └── sseClient.ts createSSEClient (fetch ReadableStream, reconnection)
|
|
206
|
+
│
|
|
207
|
+
├── constants/ Design tokens, performance thresholds, render config
|
|
208
|
+
│ ├── performanceConstants.ts FPS targets, zoom limits, node dimensions …
|
|
209
|
+
│ ├── design.ts DS_COLORS, LEVEL_COLORS, BRAND_COLORS, helpers …
|
|
210
|
+
│ └── renderConfig.ts DEFAULT_RENDER_CONFIG, FEATURE_FLAGS, helpers …
|
|
211
|
+
│
|
|
212
|
+
├── viewport/ Coordinate math and pan/zoom operations
|
|
213
|
+
│ └── viewportUtils.ts calculateViewportBounds, worldToScreen, zoomViewport …
|
|
214
|
+
│
|
|
215
|
+
├── performance/ FPS / memory monitoring (browser APIs, no React)
|
|
216
|
+
│ └── performanceMonitor.ts FPSMonitor, MemoryMonitor, PerformanceProfiler
|
|
217
|
+
│
|
|
218
|
+
├── animations/ Easing functions and timing constants
|
|
219
|
+
│ ├── easing.ts easeInOutCubic, createCubicBezier …
|
|
220
|
+
│ └── constants.ts ANIMATION_DURATION, ANIMATION_PHASES, COOLDOWN …
|
|
221
|
+
│
|
|
222
|
+
└── spatial/ RBush spatial index for O(log n) viewport culling
|
|
223
|
+
└── spatialIndex.ts RBushSpatialIndex, ISpatialIndex, BoundingBox
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Installation
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
npm install @visualli/core
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
> **Dependencies:** `zod` (schema validation) · `rbush` (spatial index)
|
|
233
|
+
|
|
234
|
+
## Quick Start
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
// Parse a .visualli document
|
|
238
|
+
import { parseVisualliFile, convertVisualliToFlatNodes } from '@visualli/core/parser';
|
|
239
|
+
|
|
240
|
+
const doc = parseVisualliFile(rawJsonlString);
|
|
241
|
+
const nodeMap = convertVisualliToFlatNodes(doc);
|
|
242
|
+
|
|
243
|
+
// Apply a circular layout
|
|
244
|
+
import { applyCircularLayout } from '@visualli/core/layout';
|
|
245
|
+
const nodes = [...nodeMap.values()];
|
|
246
|
+
applyCircularLayout(nodes);
|
|
247
|
+
|
|
248
|
+
// Viewport math
|
|
249
|
+
import { zoomViewport } from '@visualli/core/viewport';
|
|
250
|
+
const next = zoomViewport(0.1, currentViewport, pivotX, pivotY);
|
|
251
|
+
|
|
252
|
+
// API client
|
|
253
|
+
import { initApi, mindmapApi } from '@visualli/core/services';
|
|
254
|
+
initApi({ baseUrl: 'https://api.example.com/api' });
|
|
255
|
+
const list = await mindmapApi.getAllMindmaps();
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Design Principles
|
|
259
|
+
|
|
260
|
+
- **No React** — no hooks, no JSX, no Context
|
|
261
|
+
- **No DOM manipulation** — pure data transforms; browser APIs (`fetch`, `FileReader`) are used only at IO boundaries
|
|
262
|
+
- **No Vite env vars** — configure at runtime via `initApi()`
|
|
263
|
+
- **Tree-shakeable** — import from sub-paths to avoid bundling unused modules
|