@lingkkkk/atlas-mindmap
v0.1.1
Published
Framework-agnostic high-performance Canvas mind map for large JavaScript datasets
Maintainers
Readme
@lingkkkk/atlas-mindmap
A framework-agnostic Canvas mind-map runtime for plain JavaScript and TypeScript. It keeps topic data in a normalized store, geometry in typed arrays, viewport lookup in a spatial index, and topic rendering on one Canvas. The package has zero runtime dependencies and includes ESM, CommonJS, browser-IIFE, type declarations, and CSS builds.
Rendering preview

This production-demo capture renders 20,001 topics across 201 levels on one Canvas. The fixed
DOM toolbar and performance HUD remain interactive while topics, connectors, selection, collapse
controls, and branch colors are drawn by the renderer. The same preview file ships inside this npm
package at assets/render-preview.webp.
Performance snapshot
The following qualification ran the public dist/index.js build in headed Chromium 151 on an
Apple M1 Max, using a 1440 × 900 viewport at DPR 1. Each size used a fresh page, explicit CDP garbage
collection, 120 sampled frames per view, and seven samples per editing operation.
Version 0.1.1 is a documentation-and-preview release and does not change the measured runtime
source from 0.1.0.
| Topics | First render | Forced-GC JS heap | Page Elements | Topic Elements | | ---: | ---: | ---: | ---: | ---: | | 100 | 84.10 ms | 1.49 MB | 110 | 0 | | 500 | 66.80 ms | 1.69 MB | 110 | 0 | | 1,000 | 65.90 ms | 1.85 MB | 110 | 0 | | 2,000 | 75.50 ms | 2.17 MB | 110 | 0 | | 5,000 | 104.90 ms | 3.20 MB | 110 | 0 | | 10,000 | 153.70 ms | 5.23 MB | 110 | 0 | | 20,000 | 242.00 ms | 7.56 MB | 110 | 0 | | 50,000 | 565.50 ms | 15.87 MB | 110 | 0 | | 100,000 | 971.40 ms | 29.72 MB | 110 | 0 |
First render is measured from the page navigation timeline until the Canvas renderer completes its first draw. JS heap is V8 heap after forced garbage collection; it is not total browser, GPU, or OS memory. Page Elements are counted immediately after first render and before benchmark interaction. Topic Elements stay at zero because topics are Canvas-drawn rather than represented by DOM nodes.
| Topics | Full-map Fit FPS / frame P95 | Focused FPS / frame P95 | Text edit P95 | Drag reparent | | ---: | ---: | ---: | ---: | ---: | | 20,000 | 119.9 / 8.70 ms | 114.6 / 12.70 ms | 16.15 ms | 14.61 ms · passed | | 50,000 | 90.9 / 16.91 ms | 118.0 / 9.31 ms | 26.80 ms | 32.99 ms · passed | | 100,000 | 47.6 / 33.21 ms | 116.7 / 10.51 ms | 46.97 ms | 41.34 ms · passed |
The 50,000 and 100,000-topic startup paths cross the report's 250 ms synchronous-blocking threshold, even though focused editing remains smooth on this machine. Treat startup capacity and post-startup interaction as separate acceptance criteria.
The workload is a deterministic normalized XMind topic model containing topic kind, markers,
labels, and task data. It measures layout and rendering after import; it does not include .xmind
ZIP extraction, content.json parsing, image decoding, attachment loading, formulas, or
collaboration traffic.
Read the complete performance and technical-review report for all frame, cull, draw, style, editing, pointer-integrity, environment, and limitation data.
Install
npm install @lingkkkk/atlas-mindmapESM / plain JavaScript
import { MindMap } from '@lingkkkk/atlas-mindmap'
import '@lingkkkk/atlas-mindmap/styles.css'
const map = new MindMap({
container: '#mindmap',
document: {
id: 'root',
text: 'Product',
children: [
{ id: 'research', text: 'Research' },
{ id: 'delivery', text: 'Delivery' },
],
},
theme: 'dark',
})The host needs an explicit size:
#mindmap { width: 100%; height: 720px; }TypeScript
Types ship with the package. The root export includes MindMap, MindMapEngine, TopicStore,
MindMapLayout, CanvasRenderer, Camera, document/topic types, metrics, and the plugin contract.
import { MindMap, type TopicInput } from '@lingkkkk/atlas-mindmap'
const mapDocument: TopicInput = { id: 'root', text: 'Typed map', children: [] }
const map = new MindMap({ container: document.querySelector('#mindmap')!, document: mapDocument })CommonJS
const { MindMap, MindMapEngine } = require('@lingkkkk/atlas-mindmap')Load node_modules/@lingkkkk/atlas-mindmap/dist/index.css with your bundler or HTML stylesheet.
CDN / browser IIFE
<link rel="stylesheet" href="https://unpkg.com/@lingkkkk/[email protected]/dist/index.css">
<div id="mindmap" style="height:720px"></div>
<script src="https://unpkg.com/@lingkkkk/[email protected]/dist/index.global.js"></script>
<script>
const map = new AtlasMindMap.MindMap({
container: '#mindmap',
document: { id: 'root', text: 'CDN map', children: [] }
})
</script>20,000-topic data
Build large trees iteratively so application setup does not recurse through user-controlled depth:
function makeTree(count = 20_000, branching = 4) {
const root = { id: 'topic-0', text: '20,000 topic map', children: [] }
const queue = [root]
let cursor = 0
for (let id = 1; id < count; id += 1) {
const parent = queue[cursor]
const topic = { id: `topic-${id}`, text: `Topic ${id}`, children: [] }
parent.children.push(topic)
queue.push(topic)
if (parent.children.length === branching) cursor += 1
}
return root
}
const map = new MindMap({ container: '#mindmap', document: makeTree() })The live HUD reports total/layout/rendered topics, render rate, FPS, frame P95, Canvas cull/draw, layout time, zoom, DOM count, and JS heap when Chromium exposes it.
Editing, keyboard, and view controls
- Click a topic to select it; double-click or press F2/Space to edit.
- Press Enter after focusing a topic to create and edit a sibling.
- Press Tab after focusing a topic to create and edit a child.
- Drag a topic onto another topic to reparent it; drag blank Canvas space to pan.
- Mouse wheel zooms around the pointer.
fitView(),resetView(),zoomIn(), andzoomOut()are also public. addTopic,addSibling,updateTopic,moveTopic,deleteTopic,undo,redo,search,collapse,expand,expandAll, JSON import/export, and theme switching are public APIs.
Themes and node styles
map.setTheme('light')
map.updateTopic('research', {
style: {
fill: '#38bdf8',
border: '#0ea5e9',
color: '#082f49',
fontWeight: 700,
shape: 'pill',
},
})Visual-only updates invalidate Canvas without replacing the complete layout. Text and structural changes rebuild geometry. For a continuous color picker, coalesce changes to one update per animation frame; debounce geometry-changing controls until input commit.
Safe icon and image strategy
Version 0.1.1 stores XMind-compatible markers and image metadata, but does not claim arbitrary
remote-image icon rendering as a completed feature. A high-volume icon plugin should use cached
Path2D objects or a decoded bitmap atlas, key the cache by icon/size/DPR, cap its pixel budget,
hide icons in low-zoom LOD, and never allocate an Image, SVG, or Promise inside the frame loop.
Do not create one DOM/SVG icon per topic.
Lifecycle
Call destroy() when unmounting a page or component. It cancels animation frames and timers,
disconnects observers, removes listeners, destroys plugins, and removes the runtime DOM:
map.destroy()Performance evidence
See the complete performance report for the 100/500/1,000/2,000/5,000/10,000/20,000/50,000/100,000-topic headed-Chromium qualification, environment, interaction checks, memory scope, and limitations. The report distinguishes full-map overview from 100% focused editing.
Browser support
Use current evergreen browsers with Canvas 2D, typed arrays, requestAnimationFrame, Pointer
Events, and modern ES2020 support. ResizeObserver has a window-resize fallback. CommonJS and ESM
entry points require Node 18+ when imported by build tooling.
License
UNLICENSED. Publication makes the package installable; it does not grant redistribution or source license rights beyond the npm terms and the owner's explicit agreement.
