From cbda1c940ae507eeed1639b7db37395baec3e090 Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Sat, 13 Jun 2026 13:16:35 -0400 Subject: [PATCH 1/8] refactor(js)!: redesign loader and session API Replace the scattered VtkWASMLoader/createNamespace entry points with a single loadVtkWasm() that returns a cached VtkWasmRuntime, the factory for StandaloneSession and RemoteSession. Both sessions wrap their C++ handle as a private #native and expose dispose()/[Symbol.dispose] for clean teardown. - runtime.js: loadVtkWasm + VtkWasmRuntime (module cache, session factories) - standaloneSession.js / remoteSession.js: session wrappers with lifecycle - remoteSession: rely on user-provided canvas ids (bindCanvas) instead of a hard-coded internal selector; never create/remove canvas elements - index.js: public exports + diff --git a/docs/public/demo/plain-javascript.html b/docs/public/demo/plain-javascript.html index 501c97d..cd7a40c 100644 --- a/docs/public/demo/plain-javascript.html +++ b/docs/public/demo/plain-javascript.html @@ -6,9 +6,10 @@ diff --git a/examples/js/simple-app/src/main.js b/examples/js/simple-app/src/main.js index fc55e1d..4001b17 100644 --- a/examples/js/simple-app/src/main.js +++ b/examples/js/simple-app/src/main.js @@ -1,8 +1,9 @@ import "./style.css"; -import { VtkWASMLoader } from "@kitware/vtk-wasm/vtk"; +import { loadVtkWasm } from "@kitware/vtk-wasm"; import { buildWASMScene } from "./example"; -const loader = new VtkWASMLoader(); -await loader.load("https://gitlab.kitware.com/api/v4/projects/13/packages/generic/vtk-wasm32-emscripten/9.5.20251215/vtk-9.5.20251215-wasm32-emscripten.tar.gz"); -const vtk = loader.createNamespace(); -buildWASMScene(vtk, "#app > canvas", "This scene passes the VTK.wasm bundle from GitLab registry to createNamespace()"); +const runtime = await loadVtkWasm({ + url: "https://gitlab.kitware.com/api/v4/projects/13/packages/generic/vtk-wasm32-emscripten/9.5.20251215/vtk-9.5.20251215-wasm32-emscripten.tar.gz", +}); +const session = runtime.createStandaloneSession(); +buildWASMScene(session.vtk, "#app > canvas", "This scene passes the VTK.wasm bundle from GitLab registry to loadVtkWasm()"); From f6b38801c2eab0421a1c6201e72f135cf8ce9aeb Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Sat, 13 Jun 2026 13:16:56 -0400 Subject: [PATCH 3/8] build: package exports, deps, and API-doc tooling - package.json: collapse exports to the new "." (index) + "./viewer" entry points; add docs:api script (run before docs:dev/docs:build) - add TypeDoc (+ markdown/vitepress theme) and mermaid dev deps - typedoc.json + tsconfig.json: generate the API reference from source JSDoc into docs/api (allowJs, no TS migration) - gitignore the generated docs/api output --- .gitignore | 1 + package-lock.json | 1508 ++++++++++++++++++++++++++++++++++++++++++++- package.json | 17 +- tsconfig.json | 13 + typedoc.json | 15 + 5 files changed, 1516 insertions(+), 38 deletions(-) create mode 100644 tsconfig.json create mode 100644 typedoc.json diff --git a/.gitignore b/.gitignore index 64440fb..104d01c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ node_modules docs/.vitepress/dist docs/.vitepress/cache +docs/api docs/public/demo/playground docs/public/demo/simple-app examples/cpp/vtk diff --git a/package-lock.json b/package-lock.json index d184a6d..c380771 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20,11 +20,16 @@ "conventional-changelog-conventionalcommits": "9.1.0", "eslint": "^9.22.0", "globals": "^16.0.0", + "mermaid": "^11.15.0", "prettier": "3.5.3", "rimraf": "^6.0.1", "semantic-release": "25.0.2", + "typedoc": "^0.28.19", + "typedoc-plugin-markdown": "^4.12.0", + "typedoc-vitepress-theme": "^1.1.3", "vite": "^6.2.4", - "vitepress": "^1.6.3" + "vitepress": "^1.6.3", + "vitepress-plugin-mermaid": "^2.0.17" } }, "node_modules/@actions/core": { @@ -334,6 +339,20 @@ "node": ">= 14.0.0" } }, + "node_modules/@antfu/install-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@antfu/install-pkg/-/install-pkg-1.1.0.tgz", + "integrity": "sha512-MGQsmw10ZyI+EJo45CdSER4zEb+p31LpDAFp2Z3gkSd1yqVZGi0Ebx++YTEMonJy4oChEMLsxZ64j8FH6sSqtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "package-manager-detector": "^1.3.0", + "tinyexec": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, "node_modules/@babel/code-frame": { "version": "7.27.1", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz", @@ -399,6 +418,20 @@ "node": ">=6.9.0" } }, + "node_modules/@braintree/sanitize-url": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-7.1.2.tgz", + "integrity": "sha512-jigsZK+sMF/cuiB7sERuo9V7N9jx+dhmHHnQyDSVdpZwVutaBu7WvNYqMDLSgFgfB30n452TP3vjDAvFC973mA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@chevrotain/types": { + "version": "11.1.2", + "resolved": "https://registry.npmjs.org/@chevrotain/types/-/types-11.1.2.tgz", + "integrity": "sha512-U+HFai5+zmJCkK86QsaJtoITlboZHBqrVketcO2ROv865xfCMSFpELQoz1GkX5GzME8pTa+3kbKrZHQtI0gdbw==", + "dev": true, + "license": "Apache-2.0" + }, "node_modules/@codemirror/autocomplete": { "version": "6.20.1", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.20.1.tgz", @@ -1221,6 +1254,62 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@gerrit0/mini-shiki": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.23.0.tgz", + "integrity": "sha512-bEMORlG0cqdjVyCEuU0cDQbORWX+kYCeo0kV1lbxF5bt4r7SID2l9bqsxJEM0zndaxpOUT7riCyIVEuqq/Ynxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/engine-oniguruma": "^3.23.0", + "@shikijs/langs": "^3.23.0", + "@shikijs/themes": "^3.23.0", + "@shikijs/types": "^3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@gerrit0/mini-shiki/node_modules/@shikijs/engine-oniguruma": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.23.0.tgz", + "integrity": "sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0", + "@shikijs/vscode-textmate": "^10.0.2" + } + }, + "node_modules/@gerrit0/mini-shiki/node_modules/@shikijs/langs": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.23.0.tgz", + "integrity": "sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@gerrit0/mini-shiki/node_modules/@shikijs/themes": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.23.0.tgz", + "integrity": "sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/types": "3.23.0" + } + }, + "node_modules/@gerrit0/mini-shiki/node_modules/@shikijs/types": { + "version": "3.23.0", + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.23.0.tgz", + "integrity": "sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@shikijs/vscode-textmate": "^10.0.2", + "@types/hast": "^3.0.4" + } + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1304,27 +1393,16 @@ "dev": true, "license": "MIT" }, - "node_modules/@isaacs/balanced-match": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/balanced-match/-/balanced-match-4.0.1.tgz", - "integrity": "sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@isaacs/brace-expansion": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@isaacs/brace-expansion/-/brace-expansion-5.0.0.tgz", - "integrity": "sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==", + "node_modules/@iconify/utils": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@iconify/utils/-/utils-3.1.3.tgz", + "integrity": "sha512-LPKOXPn/zV+zis1oOfGWogaXVpqUybF3ZS6SCZIsz8vg0ivVp9+fVqyYB7xq0aiST/VhUQYGO1qo6uoYSiEJqw==", "dev": true, "license": "MIT", "dependencies": { - "@isaacs/balanced-match": "^4.0.1" - }, - "engines": { - "node": "20 || >=22" + "@antfu/install-pkg": "^1.1.0", + "@iconify/types": "^2.0.0", + "import-meta-resolve": "^4.2.0" } }, "node_modules/@isaacs/cliui": { @@ -1415,6 +1493,41 @@ "integrity": "sha512-l0h88YhZFyKdXIFNfSWpyjStDjGHwZ/U7iobcK1cQQD8sejsONdQtTVU+1wVN1PBw40PiiHB1vA5S7VTfQiP9g==", "license": "MIT" }, + "node_modules/@mermaid-js/mermaid-mindmap": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@mermaid-js/mermaid-mindmap/-/mermaid-mindmap-9.3.0.tgz", + "integrity": "sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@braintree/sanitize-url": "^6.0.0", + "cytoscape": "^3.23.0", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.1.0", + "d3": "^7.0.0", + "khroma": "^2.0.0", + "non-layered-tidy-tree-layout": "^2.0.2" + } + }, + "node_modules/@mermaid-js/mermaid-mindmap/node_modules/@braintree/sanitize-url": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@braintree/sanitize-url/-/sanitize-url-6.0.4.tgz", + "integrity": "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@mermaid-js/parser": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@mermaid-js/parser/-/parser-1.1.1.tgz", + "integrity": "sha512-VuHdsYMK1bT6X2JbcAaWAhugTRvRBRyuZgd+c22swUeI9g/ntaxF7CY7dYarhZovofCbUNO0G7JesfmNtjYOCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@chevrotain/types": "~11.1.1" + } + }, "node_modules/@octokit/auth-token": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-6.0.0.tgz", @@ -2267,6 +2380,290 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@types/d3": { + "version": "7.4.3", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-7.4.3.tgz", + "integrity": "sha512-lZXZ9ckh5R8uiFVt8ogUNf+pIrK4EsWrx2Np75WvF/eTpJ0FMHNhjXk8CKEx/+gpHbNQyJWehbFaTvqmHWB3ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/d3-axis": "*", + "@types/d3-brush": "*", + "@types/d3-chord": "*", + "@types/d3-color": "*", + "@types/d3-contour": "*", + "@types/d3-delaunay": "*", + "@types/d3-dispatch": "*", + "@types/d3-drag": "*", + "@types/d3-dsv": "*", + "@types/d3-ease": "*", + "@types/d3-fetch": "*", + "@types/d3-force": "*", + "@types/d3-format": "*", + "@types/d3-geo": "*", + "@types/d3-hierarchy": "*", + "@types/d3-interpolate": "*", + "@types/d3-path": "*", + "@types/d3-polygon": "*", + "@types/d3-quadtree": "*", + "@types/d3-random": "*", + "@types/d3-scale": "*", + "@types/d3-scale-chromatic": "*", + "@types/d3-selection": "*", + "@types/d3-shape": "*", + "@types/d3-time": "*", + "@types/d3-time-format": "*", + "@types/d3-timer": "*", + "@types/d3-transition": "*", + "@types/d3-zoom": "*" + } + }, + "node_modules/@types/d3-array": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.2.2.tgz", + "integrity": "sha512-hOLWVbm7uRza0BYXpIIW5pxfrKe0W+D5lrFiAEYR+pb6w3N2SwSMaJbXdUfSEv+dT4MfHBLtn5js0LAWaO6otw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-axis": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-3.0.6.tgz", + "integrity": "sha512-pYeijfZuBd87T0hGn0FO1vQ/cgLk6E1ALJjfkC0oJ8cbwkZl3TpgS8bVBLZN+2jjGgg38epgxb2zmoGtSfvgMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-brush": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-3.0.6.tgz", + "integrity": "sha512-nH60IZNNxEcrh6L1ZSMNA28rj27ut/2ZmI3r96Zd+1jrZD++zD3LsMIjWlvg4AYrHn/Pqz4CF3veCxGjtbqt7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-chord": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-3.0.6.tgz", + "integrity": "sha512-LFYWWd8nwfwEmTZG9PfQxd17HbNPksHBiJHaKuY1XeqscXacsS2tyoo6OdRsjf+NQYeB6XrNL3a25E3gH69lcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-color": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.3.tgz", + "integrity": "sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-contour": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-3.0.6.tgz", + "integrity": "sha512-BjzLgXGnCWjUSYGfH1cpdo41/hgdWETu4YxpezoztawmqsvCeep+8QGfiY6YbDvfgHz/DkjeIkkZVJavB4a3rg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-array": "*", + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-ZMaSKu4THYCU6sV64Lhg6qjf1orxBthaC161plr5KuPHo3CNm8DTHiLw/5Eq2b6TsNP0W0iJrUOFscY6Q450Hw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-dispatch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-3.0.7.tgz", + "integrity": "sha512-5o9OIAdKkhN1QItV2oqaE5KMIiXAvDWBDPrD85e58Qlz1c1kI/J0NcqbEG88CoTwJrYe7ntUCVfeUl2UJKbWgA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-drag": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-3.0.7.tgz", + "integrity": "sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-dsv": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-3.0.7.tgz", + "integrity": "sha512-n6QBF9/+XASqcKK6waudgL0pf/S5XHPPI8APyMLLUHd8NqouBGLsU8MgtO7NINGtPBtk9Kko/W4ea0oAspwh9g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-ease": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-3.0.2.tgz", + "integrity": "sha512-NcV1JjO5oDzoK26oMzbILE6HW7uVXOHLQvHshBUW4UMdZGfiY6v5BeQwh9a9tCzv+CeefZQHJt5SRgK154RtiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-fetch": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-3.0.7.tgz", + "integrity": "sha512-fTAfNmxSb9SOWNB9IoG5c8Hg6R+AzUHDRlsXsDZsNp6sxAEOP0tkP3gKkNSO/qmHPoBFTxNrjDprVHDQDvo5aA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-dsv": "*" + } + }, + "node_modules/@types/d3-force": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-3.0.10.tgz", + "integrity": "sha512-ZYeSaCF3p73RdOKcjj+swRlZfnYpK1EbaDiYICEEp5Q6sUiqFaFQ9qgoshp5CzIyyb/yD09kD9o2zEltCexlgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-format": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.4.tgz", + "integrity": "sha512-fALi2aI6shfg7vM5KiR1wNJnZ7r6UuggVqtDA+xiEdPZQwy/trcQaHnwShLuLdta2rTymCNpxYTiMZX/e09F4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, + "node_modules/@types/d3-hierarchy": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-3.1.7.tgz", + "integrity": "sha512-tJFtNoYBtRtkNysX1Xq4sxtjK8YgoWUNpIiUee0/jHGRwqvzYxkq0hGVbbOGSz+JgFxxRu4K8nb3YpG3CMARtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-interpolate": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.4.tgz", + "integrity": "sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } + }, + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-polygon": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-3.0.2.tgz", + "integrity": "sha512-ZuWOtMaHCkN9xoeEMr1ubW2nGWsp4nIql+OPQRstu4ypeZ+zk3YKqQT0CXVe/PYqrKpZAi+J9mTs05TKwjXSRA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-quadtree": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-3.0.6.tgz", + "integrity": "sha512-oUzyO1/Zm6rsxKRHA1vH0NEDG58HrT5icx/azi9MF1TWdtttWl0UIUsjEQBBh+SIkrpd21ZjEv7ptxWys1ncsg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-random": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-3.0.3.tgz", + "integrity": "sha512-Imagg1vJ3y76Y2ea0871wpabqp613+8/r0mCLEBfdtqC7xMSfj9idOnmBYyMoULfHePJyxMAw3nWhJxzc+LFwQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-scale": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.9.tgz", + "integrity": "sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-iWMJgwkK7yTRmWqRB5plb1kadXyQ5Sj8V/zYlFGMUBbIPKQScw+Dku9cAAMgJG+z5GYDoMjWGLVOvjghDEFnKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-selection": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-3.0.11.tgz", + "integrity": "sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-shape": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.8.tgz", + "integrity": "sha512-lae0iWfcDeR7qt7rA88BNiqdvPS5pFVPpo5OfjElwNaT2yyekbM0C9vK+yqBqEmHr6lDkRnYNoTBYlAgJa7a4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.4.tgz", + "integrity": "sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-4.0.3.tgz", + "integrity": "sha512-5xg9rC+wWL8kdDj153qZcsJ0FWiFt0J5RB6LYUNZjwSnesfblqrI/bJ1wBdJ8OQfncgbJG5+2F+qfqnqyzYxyg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-timer": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-3.0.2.tgz", + "integrity": "sha512-Ps3T8E8dZDam6fUyNiMkekK3XUsaUEik+idO9/YjPtfj2qruF8tFBXS7XhtE4iIXBLxhmLjP3SXpLhVf21I9Lw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/d3-transition": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-3.0.9.tgz", + "integrity": "sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-selection": "*" + } + }, + "node_modules/@types/d3-zoom": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-3.0.8.tgz", + "integrity": "sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/d3-interpolate": "*", + "@types/d3-selection": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -2274,6 +2671,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/hast": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", @@ -2333,6 +2737,14 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/@types/unist": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", @@ -2354,6 +2766,17 @@ "dev": true, "license": "ISC" }, + "node_modules/@upsetjs/venn.js": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@upsetjs/venn.js/-/venn.js-2.0.0.tgz", + "integrity": "sha512-WbBhLrooyePuQ1VZxrJjtLvTc4NVfpOyKx0sKqioq9bX1C1m7Jgykkn8gLrtwumBioXIqam8DLxp88Adbue6Hw==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "d3-selection": "^3.0.0", + "d3-transition": "^3.0.1" + } + }, "node_modules/@vitejs/plugin-vue": { "version": "5.2.4", "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz", @@ -3259,6 +3682,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/compare-func": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/compare-func/-/compare-func-2.0.0.tgz", @@ -3394,6 +3827,16 @@ "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, + "node_modules/cose-base": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-1.0.3.tgz", + "integrity": "sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^1.0.0" + } + }, "node_modules/cosmiconfig": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", @@ -3471,10 +3914,558 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/csstype": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", - "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/cytoscape": { + "version": "3.34.0", + "resolved": "https://registry.npmjs.org/cytoscape/-/cytoscape-3.34.0.tgz", + "integrity": "sha512-62rNSrioXw93uliKFBwjukeQyeWwH2PqDrTac31r2P6464u3AUvTk0xS4LVvT251g7IgkFunrI48ZEZGjywSOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/cytoscape-cose-bilkent": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cytoscape-cose-bilkent/-/cytoscape-cose-bilkent-4.1.0.tgz", + "integrity": "sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cose-base": "^1.0.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cytoscape-fcose/-/cytoscape-fcose-2.2.0.tgz", + "integrity": "sha512-ki1/VuRIHFCzxWNrsshHYPs6L7TvLu3DL+TyIGEsRcvVERmxokbf5Gdk7mFxZnTdiGtnA4cfSmjZJMviqSuZrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "cose-base": "^2.2.0" + }, + "peerDependencies": { + "cytoscape": "^3.2.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/cose-base": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/cose-base/-/cose-base-2.2.0.tgz", + "integrity": "sha512-AzlgcsCbUMymkADOJtQm3wO9S3ltPfYOFD5033keQn9NJzIbtnZj+UdBJe7DYml/8TdbtHJW3j58SOnKhWY/5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "layout-base": "^2.0.0" + } + }, + "node_modules/cytoscape-fcose/node_modules/layout-base": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-2.0.1.tgz", + "integrity": "sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==", + "dev": true, + "license": "MIT" + }, + "node_modules/d3": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/d3/-/d3-7.9.0.tgz", + "integrity": "sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "3", + "d3-axis": "3", + "d3-brush": "3", + "d3-chord": "3", + "d3-color": "3", + "d3-contour": "4", + "d3-delaunay": "6", + "d3-dispatch": "3", + "d3-drag": "3", + "d3-dsv": "3", + "d3-ease": "3", + "d3-fetch": "3", + "d3-force": "3", + "d3-format": "3", + "d3-geo": "3", + "d3-hierarchy": "3", + "d3-interpolate": "3", + "d3-path": "3", + "d3-polygon": "3", + "d3-quadtree": "3", + "d3-random": "3", + "d3-scale": "4", + "d3-scale-chromatic": "3", + "d3-selection": "3", + "d3-shape": "3", + "d3-time": "3", + "d3-time-format": "4", + "d3-timer": "3", + "d3-transition": "3", + "d3-zoom": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dev": true, + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-axis": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-3.0.0.tgz", + "integrity": "sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-chord": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-3.0.1.tgz", + "integrity": "sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-contour": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-4.0.2.tgz", + "integrity": "sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "^3.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-delaunay": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.4.tgz", + "integrity": "sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==", + "dev": true, + "license": "ISC", + "dependencies": { + "delaunator": "5" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dsv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-3.0.1.tgz", + "integrity": "sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "commander": "7", + "iconv-lite": "0.6", + "rw": "1" + }, + "bin": { + "csv2json": "bin/dsv2json.js", + "csv2tsv": "bin/dsv2dsv.js", + "dsv2dsv": "bin/dsv2dsv.js", + "dsv2json": "bin/dsv2json.js", + "json2csv": "bin/json2dsv.js", + "json2dsv": "bin/json2dsv.js", + "json2tsv": "bin/json2dsv.js", + "tsv2csv": "bin/dsv2dsv.js", + "tsv2json": "bin/dsv2json.js" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-fetch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-3.0.1.tgz", + "integrity": "sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dsv": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-force": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-3.0.0.tgz", + "integrity": "sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-quadtree": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.2.tgz", + "integrity": "sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-geo": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.1.tgz", + "integrity": "sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.5.0 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-polygon": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-3.0.1.tgz", + "integrity": "sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-quadtree": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-3.0.1.tgz", + "integrity": "sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-random": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-3.0.1.tgz", + "integrity": "sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "dev": true, + "license": "ISC" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-scale-chromatic": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-3.1.0.tgz", + "integrity": "sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-interpolate": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, + "node_modules/d3-zoom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-3.0.0.tgz", + "integrity": "sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==", + "dev": true, + "license": "ISC", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "2 - 3", + "d3-transition": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/dagre-d3-es": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/dagre-d3-es/-/dagre-d3-es-7.0.14.tgz", + "integrity": "sha512-P4rFMVq9ESWqmOgK+dlXvOtLwYg0i7u0HBGJER0LZDJT2VHIPAMZ/riPxqJceWMStH5+E61QxFra9kIS3AqdMg==", + "dev": true, + "license": "MIT", + "dependencies": { + "d3": "^7.9.0", + "lodash-es": "^4.17.21" + } + }, + "node_modules/dayjs": { + "version": "1.11.21", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.21.tgz", + "integrity": "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA==", "dev": true, "license": "MIT" }, @@ -3513,6 +4504,16 @@ "dev": true, "license": "MIT" }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "robust-predicates": "^3.0.2" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -3550,6 +4551,16 @@ "node": ">=8" } }, + "node_modules/dompurify": { + "version": "3.4.10", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.10.tgz", + "integrity": "sha512-0xzNv0e7oYC6yyuOGZIABPM4qtg3QxLFniDNPP4ZP90wR8Yq3zgwpRbrNiT4N3IKqDbbYFEJLV+JWEs19aZ//w==", + "dev": true, + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/dot-prop": { "version": "5.3.0", "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-5.3.0.tgz", @@ -3763,6 +4774,17 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/es-toolkit": { + "version": "1.47.1", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.1.tgz", + "integrity": "sha512-5RAqEwf4P4E17p+W75KLOWw/nOvKZzSQpxM32IpI2KZLaVonjTrZ0Ai5ghMaVI9eKC2p8eoQgcBdkEDgzFk6+Q==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/esbuild": { "version": "0.25.8", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz", @@ -4399,6 +5421,13 @@ "dev": true, "license": "ISC" }, + "node_modules/hachure-fill": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/hachure-fill/-/hachure-fill-0.5.2.tgz", + "integrity": "sha512-3GKBOn+m2LX9iq+JC1064cSFprJY4jL1jCXTcpnfER5HYE2l/4EfWSGzkPa/ZDBmYI0ZOEj5VHV/eKnPGkHuOg==", + "dev": true, + "license": "MIT" + }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -4561,6 +5590,19 @@ "node": ">=18.18.0" } }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -4609,9 +5651,9 @@ } }, "node_modules/import-meta-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.2.0.tgz", + "integrity": "sha512-Iqv2fzaTQN28s/FwZAoFq0ZSs/7hMAHJVX+w8PZl3cY19Pxk6jFFalxQoIfW2826i/fDLXv8IiEZRIT0lDuWcg==", "dev": true, "license": "MIT", "funding": { @@ -4668,6 +5710,16 @@ "dev": true, "license": "ISC" }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=12" + } + }, "node_modules/into-stream": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/into-stream/-/into-stream-7.0.0.tgz", @@ -4946,6 +5998,33 @@ "setimmediate": "^1.0.5" } }, + "node_modules/katex": { + "version": "0.16.47", + "resolved": "https://registry.npmjs.org/katex/-/katex-0.16.47.tgz", + "integrity": "sha512-Eeo8Ys1doU1z+x8AZsPpQu+p/QcZBI5PeOo7QGQdy2x2m0MU/hYagBbGOmXwr5KVbEfVuWv9LpnQWeehogurjg==", + "dev": true, + "funding": [ + "https://opencollective.com/katex", + "https://github.com/sponsors/katex" + ], + "license": "MIT", + "dependencies": { + "commander": "^8.3.0" + }, + "bin": { + "katex": "cli.js" + } + }, + "node_modules/katex/node_modules/commander": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", + "integrity": "sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4956,6 +6035,19 @@ "json-buffer": "3.0.1" } }, + "node_modules/khroma": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/khroma/-/khroma-2.1.0.tgz", + "integrity": "sha512-Ls993zuzfayK269Svk9hzpeGUKob/sIgZzyHYdjQoAdQetRKpOLj+k/QQQ/6Qi0Yz65mlROrfd+Ev+1+7dz9Kw==", + "dev": true + }, + "node_modules/layout-base": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/layout-base/-/layout-base-1.0.2.tgz", + "integrity": "sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==", + "dev": true, + "license": "MIT" + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4986,6 +6078,26 @@ "dev": true, "license": "MIT" }, + "node_modules/linkify-it": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", + "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -5091,6 +6203,13 @@ "node": "20 || >=22" } }, + "node_modules/lunr": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", + "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", + "dev": true, + "license": "MIT" + }, "node_modules/magic-string": { "version": "0.30.17", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", @@ -5108,6 +6227,34 @@ "dev": true, "license": "MIT" }, + "node_modules/markdown-it": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz", + "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.4.0", + "linkify-it": "^5.0.1", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, "node_modules/marked": { "version": "15.0.12", "resolved": "https://registry.npmjs.org/marked/-/marked-15.0.12.tgz", @@ -5178,6 +6325,13 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdurl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", + "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", + "dev": true, + "license": "MIT" + }, "node_modules/meow": { "version": "13.2.0", "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", @@ -5198,6 +6352,49 @@ "dev": true, "license": "MIT" }, + "node_modules/mermaid": { + "version": "11.15.0", + "resolved": "https://registry.npmjs.org/mermaid/-/mermaid-11.15.0.tgz", + "integrity": "sha512-pTMbcf3rWdtLiYGpmoTjHEpeY8seiy6sR+9nD7LOs8KfUbHE4lOUAprTRqRAcWSQ6MQpdX+YEsxShtGsINtPtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@braintree/sanitize-url": "^7.1.1", + "@iconify/utils": "^3.0.2", + "@mermaid-js/parser": "^1.1.1", + "@types/d3": "^7.4.3", + "@upsetjs/venn.js": "^2.0.0", + "cytoscape": "^3.33.1", + "cytoscape-cose-bilkent": "^4.1.0", + "cytoscape-fcose": "^2.2.0", + "d3": "^7.9.0", + "d3-sankey": "^0.12.3", + "dagre-d3-es": "7.0.14", + "dayjs": "^1.11.19", + "dompurify": "^3.3.1", + "es-toolkit": "^1.45.1", + "katex": "^0.16.25", + "khroma": "^2.1.0", + "marked": "^16.3.0", + "roughjs": "^4.6.6", + "stylis": "^4.3.6", + "ts-dedent": "^2.2.0", + "uuid": "^11.1.0 || ^12 || ^13 || ^14.0.0" + } + }, + "node_modules/mermaid/node_modules/marked": { + "version": "16.4.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-16.4.2.tgz", + "integrity": "sha512-TI3V8YYWvkVf3KJe1dRkpnjs68JUPyEa5vjKrp1XEEJUAOaQc+Qj+L1qWbPd0SJuAdQkFU0h73sXXqwDYxsiDA==", + "dev": true, + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 20" + } + }, "node_modules/micromark-util-character": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", @@ -5349,21 +6546,44 @@ } }, "node_modules/minimatch": { - "version": "10.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.3.tgz", - "integrity": "sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==", + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", "dev": true, - "license": "ISC", + "license": "BlueOak-1.0.0", "dependencies": { - "@isaacs/brace-expansion": "^5.0.0" + "brace-expansion": "^5.0.5" }, "engines": { - "node": "20 || >=22" + "node": "18 || 20 || >=22" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/minimatch/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/minimatch/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -5473,6 +6693,14 @@ "node": ">=18" } }, + "node_modules/non-layered-tidy-tree-layout": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/non-layered-tidy-tree-layout/-/non-layered-tidy-tree-layout-2.0.2.tgz", + "integrity": "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw==", + "dev": true, + "license": "MIT", + "optional": true + }, "node_modules/normalize-package-data": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-8.0.0.tgz", @@ -7691,6 +8919,13 @@ "dev": true, "license": "BlueOak-1.0.0" }, + "node_modules/package-manager-detector": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/package-manager-detector/-/package-manager-detector-1.6.0.tgz", + "integrity": "sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==", + "dev": true, + "license": "MIT" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -7766,6 +9001,13 @@ "dev": true, "license": "MIT" }, + "node_modules/path-data-parser": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/path-data-parser/-/path-data-parser-0.1.0.tgz", + "integrity": "sha512-NOnmBpt5Y2RWbuv0LMzsayp3lVylAHLPUTut412ZA3l+C4uw4ZVkQbjShYCQ8TCpUMdPapr4YjUqLYD6v68j+w==", + "dev": true, + "license": "MIT" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -7927,6 +9169,24 @@ "node": ">=4" } }, + "node_modules/points-on-curve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/points-on-curve/-/points-on-curve-0.2.0.tgz", + "integrity": "sha512-0mYKnYYe9ZcqMCWhUjItv/oHjvgEsfKvnUTg8sAtnHr3GVy7rGkXCb6d5cSyqrWqL4k81b9CPg3urd+T7aop3A==", + "dev": true, + "license": "MIT" + }, + "node_modules/points-on-path": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/points-on-path/-/points-on-path-0.2.1.tgz", + "integrity": "sha512-25ClnWWuw7JbWZcgqY/gJ4FQWadKxGWk+3kR/7kD0tCaDtPPMj7oHu2ToLaVhfpnHrZzYby2w6tUA0eOIuUg8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-data-parser": "0.1.0", + "points-on-curve": "0.2.0" + } + }, "node_modules/postcss": { "version": "8.5.6", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", @@ -8043,6 +9303,16 @@ "node": ">=6" } }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/rc": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", @@ -8253,6 +9523,13 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "dev": true, + "license": "Unlicense" + }, "node_modules/rollup": { "version": "4.40.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.1.tgz", @@ -8293,12 +9570,39 @@ "fsevents": "~2.3.2" } }, + "node_modules/roughjs": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/roughjs/-/roughjs-4.6.6.tgz", + "integrity": "sha512-ZUz/69+SYpFN/g/lUlo2FXcIjRkSu3nDarreVdGGndHEBJ6cXPdKguS8JGxwj5HA5xIbVKSmLgr5b3AWxtRfvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "hachure-fill": "^0.5.2", + "path-data-parser": "^0.1.0", + "points-on-curve": "^0.2.0", + "points-on-path": "^0.2.1" + } + }, + "node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "dev": true, + "license": "BSD-3-Clause" + }, "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, "node_modules/search-insights": { "version": "2.17.3", "resolved": "https://registry.npmjs.org/search-insights/-/search-insights-2.17.3.tgz", @@ -8857,6 +10161,13 @@ "integrity": "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==", "license": "MIT" }, + "node_modules/stylis": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.4.0.tgz", + "integrity": "sha512-5Z9ZpRzfuH6l/UAvCPAPUo3665Nk2wLaZU3x+TLHKVzIz33+sbJqbtrYoC3KD4/uVOr2Zp+L0LySezP9OHV9yA==", + "dev": true, + "license": "MIT" + }, "node_modules/super-regex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/super-regex/-/super-regex-1.0.0.tgz", @@ -9042,6 +10353,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/tinyexec": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/tinyglobby": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz", @@ -9096,6 +10417,16 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/ts-dedent": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/ts-dedent/-/ts-dedent-2.3.0.tgz", + "integrity": "sha512-JfJeIHke7y2egdGGgRAvpCwYFUsHlM2gPcrVOxFkznt/4uzQ7HFmvE63iFHVLBJNDuyDOQgijDK/tXH/f6Msjg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.10" + } + }, "node_modules/tunnel": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", @@ -9135,6 +10466,75 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/typedoc": { + "version": "0.28.19", + "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.19.tgz", + "integrity": "sha512-wKh+lhdmMFivMlc6vRRcMGXeGEHGU2g8a2CkPTJjJlwRf1iXbimWIPcFolCqe4E0d/FRtGszpIrsp3WLpDB8Pw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@gerrit0/mini-shiki": "^3.23.0", + "lunr": "^2.3.9", + "markdown-it": "^14.1.1", + "minimatch": "^10.2.5", + "yaml": "^2.8.3" + }, + "bin": { + "typedoc": "bin/typedoc" + }, + "engines": { + "node": ">= 18", + "pnpm": ">= 10" + }, + "peerDependencies": { + "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x || 6.0.x" + } + }, + "node_modules/typedoc-plugin-markdown": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.12.0.tgz", + "integrity": "sha512-eJDEMAfxCmede22c/Jw7d0FA13ggAQv+KkwQYKYCdqI02cin6Rc9QRwbG/7XvvHWinuFejySnZVUWDtvGk3Vbg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "typedoc": "0.28.x" + } + }, + "node_modules/typedoc-vitepress-theme": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/typedoc-vitepress-theme/-/typedoc-vitepress-theme-1.1.3.tgz", + "integrity": "sha512-EK9iV7e3+R8lFNigdc0rIPWMxqfmDku0uGac3qYUu9tS4Qf1rhWZnyZJ4zu4G3iXrP5mqNPkv2wpODzRlA7jLw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typedoc-plugin-markdown": ">=4.11.0" + } + }, + "node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, "node_modules/uglify-js": { "version": "3.19.3", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", @@ -9314,6 +10714,20 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/uuid": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-14.0.0.tgz", + "integrity": "sha512-Qo+uWgilfSmAhXCMav1uYFynlQO7fMFiMVZsQqZRMIXp0O7rR7qjkj+cPvBHLgBqi960QCoo/PH2/6ZtVqKvrg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "bin": { + "uuid": "dist-node/bin/uuid" + } + }, "node_modules/validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -9472,6 +10886,20 @@ } } }, + "node_modules/vitepress-plugin-mermaid": { + "version": "2.0.17", + "resolved": "https://registry.npmjs.org/vitepress-plugin-mermaid/-/vitepress-plugin-mermaid-2.0.17.tgz", + "integrity": "sha512-IUzYpwf61GC6k0XzfmAmNrLvMi9TRrVRMsUyCA8KNXhg/mQ1VqWnO0/tBVPiX5UoKF1mDUwqn5QV4qAJl6JnUg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@mermaid-js/mermaid-mindmap": "^9.3.0" + }, + "peerDependencies": { + "mermaid": "10 || 11", + "vitepress": "^1.0.0 || ^1.0.0-alpha" + } + }, "node_modules/vitepress/node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", @@ -10141,6 +11569,22 @@ "node": ">=10" } }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "18.0.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", diff --git a/package.json b/package.json index d794556..5efe793 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,10 @@ "build": "npm run build:esm && npm run build:vtk && npm run build:viewer", "build:example:simple-app": "npm install --no-save --prefix examples/js/simple-app && npm run build --prefix examples/js/simple-app", "build:examples": "npm run build:example:simple-app", - "docs:build": "npm run build && npm run build:examples && vitepress build docs", - "docs:dev": "vitepress dev docs", - "docs:clean": "rimraf docs/.vitepress/dist", + "docs:api": "typedoc", + "docs:build": "npm run build && npm run build:examples && npm run docs:api && vitepress build docs", + "docs:dev": "npm run docs:api && vitepress dev docs", + "docs:clean": "rimraf docs/.vitepress/dist docs/api", "docs:preview": "vitepress preview docs", "format": "prettier . --write", "lint": "eslint --fix src", @@ -39,19 +40,23 @@ "conventional-changelog-conventionalcommits": "9.1.0", "eslint": "^9.22.0", "globals": "^16.0.0", + "mermaid": "^11.15.0", "prettier": "3.5.3", "rimraf": "^6.0.1", "semantic-release": "25.0.2", + "typedoc": "^0.28.19", + "typedoc-plugin-markdown": "^4.12.0", + "typedoc-vitepress-theme": "^1.1.3", "vite": "^6.2.4", - "vitepress": "^1.6.3" + "vitepress": "^1.6.3", + "vitepress-plugin-mermaid": "^2.0.17" }, "files": [ "dist/**/*" ], "exports": { + ".": "./dist/esm/index.mjs", "./style.css": "./dist/esm/vtk-wasm.css", - "./remote": "./dist/esm/remote.mjs", - "./vtk": "./dist/esm/vtk.mjs", "./viewer": "./dist/esm/viewer.mjs", "./viewer-umd.js": "./dist/umd/viewer.umd.js", "./vtk-umd.js": "./dist/umd/vtk.umd.js", diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..5ee229d --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": false, + "noEmit": true, + "module": "esnext", + "target": "esnext", + "moduleResolution": "bundler", + "skipLibCheck": true, + "strict": false + }, + "include": ["src"] +} diff --git a/typedoc.json b/typedoc.json new file mode 100644 index 0000000..5d32565 --- /dev/null +++ b/typedoc.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "plugin": ["typedoc-plugin-markdown", "typedoc-vitepress-theme"], + "entryPoints": ["src/index.js", "src/viewer.js"], + "tsconfig": "tsconfig.json", + "out": "docs/api", + "readme": "none", + "githubPages": false, + "hideGenerator": true, + "entryFileName": "index", + "useCodeBlocks": true, + "expandObjects": true, + "parametersFormat": "table", + "docsRoot": "docs" +} From 564e1a5a1b2b6a3f7e1befbb1f32f5fec5f35a2d Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Sat, 13 Jun 2026 13:17:16 -0400 Subject: [PATCH 4/8] docs(js): restructure JavaScript guides and add API reference - new conceptual guides: Loading VTK.wasm (with a mermaid path diagram), Standalone Session, and Remote Session, each linking into the generated API reference rather than restating signatures - merge HTML Script Tag + Bundler Integration into "Adding VTK.wasm to a Project"; remove the JS Getting started page - reorder the "For JavaScript developers" sidebar and repoint inbound links - wire the TypeDoc-generated API reference into the nav/sidebar (expanded by default) and enable mermaid via vitepress-plugin-mermaid --- docs/.vitepress/config.mjs | 37 ++++++++++++-- docs/guide/js/bundler.md | 28 ---------- docs/guide/js/index.md | 31 ----------- docs/guide/js/integration.md | 79 +++++++++++++++++++++++++++++ docs/guide/js/loading.md | 75 +++++++++++++++++++++++++++ docs/guide/js/plain.md | 61 ---------------------- docs/guide/js/primer.md | 2 +- docs/guide/js/remote-session.md | 59 +++++++++++++++++++++ docs/guide/js/standalone-session.md | 45 ++++++++++++++++ docs/index.md | 24 +-------- 10 files changed, 292 insertions(+), 149 deletions(-) delete mode 100644 docs/guide/js/bundler.md delete mode 100644 docs/guide/js/index.md create mode 100644 docs/guide/js/integration.md create mode 100644 docs/guide/js/loading.md delete mode 100644 docs/guide/js/plain.md create mode 100644 docs/guide/js/remote-session.md create mode 100644 docs/guide/js/standalone-session.md diff --git a/docs/.vitepress/config.mjs b/docs/.vitepress/config.mjs index fbec974..40569c3 100644 --- a/docs/.vitepress/config.mjs +++ b/docs/.vitepress/config.mjs @@ -1,7 +1,28 @@ +import { existsSync, readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; import { defineConfig } from "vitepress"; +import { withMermaid } from "vitepress-plugin-mermaid"; + +// API reference sidebar generated by TypeDoc (npm run docs:api). Falls back to +// an empty list so the docs still build before the API has been generated. +const __dirname = dirname(fileURLToPath(import.meta.url)); +const apiSidebarFile = resolve(__dirname, "../api/typedoc-sidebar.json"); + +// TypeDoc marks every group `collapsed: true`; expand them by default. +const expandSidebar = (items) => + items.map((item) => + item.items + ? { ...item, collapsed: false, items: expandSidebar(item.items) } + : item, + ); + +const apiSidebar = existsSync(apiSidebarFile) + ? expandSidebar(JSON.parse(readFileSync(apiSidebarFile, "utf-8"))) + : []; // https://vitepress.dev/reference/site-config -export default defineConfig({ +export default withMermaid(defineConfig({ base: "/vtk-wasm", title: "VTK.wasm", description: "Guides and documentation around VTK.wasm", @@ -50,6 +71,7 @@ export default defineConfig({ nav: [ { text: "Home", link: "/" }, { text: "News", link: "/news" }, + { text: "API", link: "/api/" }, { text: "Guides", link: "/guide/" }, { text: "Roadmap", items: [ @@ -91,10 +113,11 @@ export default defineConfig({ { text: "For JavaScript developers", items: [ - { text: "Getting started", link: "/guide/js/" }, + { text: "Loading VTK.wasm", link: "/guide/js/loading" }, + { text: "Standalone Session", link: "/guide/js/standalone-session" }, { text: "Primer on VTK.wasm", link: "/guide/js/primer" }, - { text: "HTML Script Tag", link: "/guide/js/plain" }, - { text: "Bundler Integration", link: "/guide/js/bundler" }, + { text: "Remote Session", link: "/guide/js/remote-session" }, + { text: "Adding VTK.wasm to a Project", link: "/guide/js/integration" }, ], }, { @@ -113,6 +136,10 @@ export default defineConfig({ ], }, ], + "/api/": [ + { text: "API Reference", link: "/api/" }, + ...apiSidebar, + ], "/roadmap/": [ { text: "Overview", link: "/roadmap/" }, { text: "Module Availability", link: "/roadmap/modules" }, @@ -124,4 +151,4 @@ export default defineConfig({ { icon: 'github', link: 'https://github.com/Kitware/vtk-wasm' } ] }, -}); +})); diff --git a/docs/guide/js/bundler.md b/docs/guide/js/bundler.md deleted file mode 100644 index 0409b81..0000000 --- a/docs/guide/js/bundler.md +++ /dev/null @@ -1,28 +0,0 @@ -# Bundler Integration - -Modern web development rely on package manager to bring project dependencies. This section covers how published releases can be used within a JavaScript project. - -## Project setup - -In the simple example we are going to use [Vite](https://vite.dev/) with Vanilla JavaScript. The full code is available for reference [here](https://github.com/Kitware/vtk-wasm/tree/main/examples/js/simple-app). Please note that you should use a concrete version, or "latest" for the `@kitware/vtk-wasm` package. Here, the example uses a relative path to the `vtk-wasm` project root, so the in-repo documentation stays relevant. - -::: code-group -<<< ../../../examples/js/simple-app/package.json -<<< ../../../examples/js/simple-app/index.html -<<< ../../../examples/js/simple-app/src/main.js [src/main.js] -<<< ../../../examples/js/simple-app/src/example.js [src/example.js] -<<< ../../../examples/js/simple-app/src/style.css [src/style.css] -```bash [Install/Build] -npm install -npm run build -``` -::: - -Here, the VTK.wasm bundle is downloaded in the browser directly from the Gitlab package registry. See the `src/main.js` file for the relevant code. - - -## Result - - - -[Full Screen Viewer](../../demo/simple-app/index.html){target="_blank"} diff --git a/docs/guide/js/index.md b/docs/guide/js/index.md deleted file mode 100644 index 99f4a1b..0000000 --- a/docs/guide/js/index.md +++ /dev/null @@ -1,31 +0,0 @@ -# VTK.wasm from JavaScript - -This guide focuses on using the VTK WASM bundle from plain JavaScript, requiring no prior C++ knowledge. VTK.wasm allows you to use [VTK](https://www.vtk.org) without needing to learn C++. This can be particularly beneficial for web developers who are already familiar with JavaScript and want to integrate advanced visualization capabilities into their web applications. - -## Overview -Most C++ classes from the [VTK C++ Documentation](https://vtk.org/doc/nightly/html/) are available through a single JavaScript object, which we refer to as the **vtk** namespace. - -Once you have access to the **vtk** namespace (see [Bundler Integration](./bundler.md)), you can interact with VTK classes using standard JavaScript. - - - -
const vtk = await window.vtkReady;
-
-
- -The following sections will guide you through the essential aspects of using VTK.wasm with JavaScript: - -- [Primer on VTK.wasm](./primer.md) -- [HTML Script Tag](./plain.md) -- [Bundler Integration](./bundler.md) diff --git a/docs/guide/js/integration.md b/docs/guide/js/integration.md new file mode 100644 index 0000000..93778ad --- /dev/null +++ b/docs/guide/js/integration.md @@ -0,0 +1,79 @@ +# Adding VTK.wasm to a Project + +There are two ways to get VTK.wasm into a web project: + +- **HTML Script Tag** — load a prebuilt bundle from a CDN, no build step required. Best for quick prototypes, demos, and embedding into existing pages. +- **Bundler** — install the `@kitware/vtk-wasm` package and `import` it. Best for application development with a tool like Vite. + +Either way you end up calling [`loadVtkWasm`](./loading.md); only how it reaches the page differs. + +## HTML Script Tag + +Use VTK.wasm directly in an HTML file using a ` ``` -### RemoteSession progress +See the [Loading VTK.wasm guide](https://kitware.github.io/vtk-wasm/guide/js/loading) to get started and the [API reference](https://kitware.github.io/vtk-wasm/api/) for every export. -```js -import { RemoteSession } from "@kitware/vtk-wasm/remote" +## Contributing -const session = new RemoteSession() -const removeProgress = session.addProgressCallback(({ active, state, hash }) => { - // state: { current, total }, hash: { current, total } - // active is true while states/blobs are being fetched -}) +Requires [Node.js](https://nodejs.org/) (LTS). -// Later, to stop listening: -removeProgress() +```bash +npm install # install dependencies +npm run build # build the ESM + UMD bundles into dist/ +npm run docs:dev # run the documentation site locally +npm run lint # lint the source ``` -### UMD imports +### Repository layout -```js -import "@kitware/vtk-wasm/viewer.css"; -import "@kitware/vtk-wasm/viewer-umd.js"; - -import "@kitware/vtk-wasm/vtk-umd.js"; -``` +- `src/` — library source. +- `examples/` — example applications. +- `docs/` — documentation site (VitePress); the API reference is generated from source JSDoc. +- `dist/` — build output. From 4ca47a6209036945fda2515f46414916d6b5f584 Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Sat, 13 Jun 2026 13:31:43 -0400 Subject: [PATCH 6/8] feat(js): guard create/destroy on unsupported sessions The C++ vtkRemoteSession has no create/destroy, so creating or deleting objects through a remote session's vtk proxy would throw. Gate both on typeof checks: warn and return undefined/false instead. Document that a remote session can only control server-owned objects via getVtkObject. --- docs/guide/js/remote-session.md | 14 ++++++++++++++ src/core/proxy.js | 12 ++++++++++++ 2 files changed, 26 insertions(+) diff --git a/docs/guide/js/remote-session.md b/docs/guide/js/remote-session.md index 73c94f7..996d014 100644 --- a/docs/guide/js/remote-session.md +++ b/docs/guide/js/remote-session.md @@ -46,6 +46,20 @@ To surface download progress (state + blob counts), register a callback with [`a Once synchronized, inspect objects locally without another round trip via [`getState`](/api/@kitware/vtk-wasm/classes/RemoteSession#getstate) and [`getStateValue`](/api/@kitware/vtk-wasm/classes/RemoteSession#getstatevalue), or get a controllable proxy with [`getVtkObject`](/api/@kitware/vtk-wasm/classes/RemoteSession#getvtkobject). +## Objects are owned by the server + +The server owns the scene's object lifecycle, so a remote session **cannot create or destroy objects** from the client. The `remote.vtk` namespace exists only to *control existing* objects: use [`getVtkObject`](/api/@kitware/vtk-wasm/classes/RemoteSession#getvtkobject) (or `remote.vtk.getVtkObject(id)`) to obtain a proxy for an object the server already created. + +Calling a constructor such as `remote.vtk.vtkActor()` or `proxy.delete()` is a no-op: it logs a warning to the console and returns `undefined` / `false` rather than mutating the scene. To add or remove objects, do it on the server and pull the change in with [`update`](#drive-updates). + +```js +const actor = remote.getVtkObject(actorId); // ✅ control an existing object +actor.visibility = false; + +remote.vtk.vtkActor(); // ⚠️ warns, returns undefined +actor.delete(); // ⚠️ warns, returns false +``` + ## Cleaning up [`remote.dispose()`](/api/@kitware/vtk-wasm/classes/RemoteSession#dispose) frees the C++ session and detaches the interaction listeners from your canvases (the canvas elements are left in place). As with standalone sessions, `using` works too: diff --git a/src/core/proxy.js b/src/core/proxy.js index 0c4f404..e0ab328 100644 --- a/src/core/proxy.js +++ b/src/core/proxy.js @@ -37,6 +37,12 @@ export function createVtkObjectProxy( // Create methods const observerTags = []; function deleteObject() { + if (typeof wasm.destroy !== "function") { + console.warn( + "Cannot delete object: this session does not support destroying objects.", + ); + return false; + } const result = wasm.destroy(vtkId); if (result) { const removedProxy = idToRef.delete(vtkId); @@ -187,6 +193,12 @@ export function createInstantiatorProxy(wasm, vtkProxyCache, idToRef) { } function create(name, args) { + if (typeof wasm.create !== "function") { + console.warn( + `Cannot create '${name}': this session does not support creating objects.`, + ); + return undefined; + } const vtkId = wasm.create(name); if (args) { wasm.set(vtkId, decorateKwargs(toCxxKeys(args))); From 7d22494c8c4c15a61f0fd0a546ee3ccf69d78f5a Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Mon, 15 Jun 2026 19:01:13 -0400 Subject: [PATCH 7/8] feat(js): register canvas elements directly via specialHTMLTargets RemoteSession can now bind a render window to a canvas element passed directly, not just by DOM id. When the Emscripten build exposes specialHTMLTargets, the element is registered there so it needs neither an id nor to be attached to the document; otherwise a CSS selector built from the element id is used as a fallback. - patch the glue source to expose Module.specialHTMLTargets - pass the module into RemoteSession and track the canvas->target mapping (canvasTargets) plus bound render windows (boundRenderWindows) - bind render windows lazily during update() once their state arrives, and clean up specialHTMLTargets entries on unbindCanvas/dispose --- docs/guide/js/remote-session.md | 152 ++++++++++++++++++++++++++++-- src/remoteSession.js | 162 +++++++++++++++++++++----------- src/runtime.js | 27 +++++- src/viewer.js | 4 +- 4 files changed, 279 insertions(+), 66 deletions(-) diff --git a/docs/guide/js/remote-session.md b/docs/guide/js/remote-session.md index 996d014..26550f2 100644 --- a/docs/guide/js/remote-session.md +++ b/docs/guide/js/remote-session.md @@ -15,29 +15,167 @@ const remote = runtime.createRemoteSession(); ## Wire up the network -A remote session does not know how to reach your server. You provide three fetchers through [`bindNetwork`](/api/@kitware/vtk-wasm/classes/RemoteSession#bindnetwork): one to fetch an object's state, one to fetch a blob by hash, and one to fetch the server's status (what changed since last time). +A remote session does not know how to reach your server. You supply three async fetchers through [`bindNetwork`](/api/@kitware/vtk-wasm/classes/RemoteSession#bindnetwork) — one for state, one for blobs, one for status — and the session calls them whenever it needs data: ```js remote.bindNetwork(fetchState, fetchHash, fetchStatus); ``` +Each fetcher wraps one server RPC. The trame server side lives in [protocol.py](https://github.com/Kitware/trame-vtklocal/blob/master/src/trame_vtklocal/module/protocol.py); a typical client implementation just forwards the arguments over your transport (e.g. `session.call("vtklocal.get.state", [vtkId])`). + +- **`fetchState(vtkId) => Promise`** — given an object id, return that object's serialized **state** as a JSON string (the wire format). Backs `vtklocal.get.state`. + +- **`fetchHash(hash) => Promise`** — given a content hash, return the corresponding binary **blob**. The transport may hand you a `Blob` or a `TypedArray`, so convert the result to a `Uint8Array` before returning. Backs `vtklocal.get.hash`. + +- **`fetchStatus(renderWindowId) => Promise`** — given a render window id, return a manifest of **what exists and what changed since last time**, so the session knows what to pull on the next [`update`](#drive-updates). Backs `vtklocal.get.status`. The returned object carries: + - `ids` — `[id, mtime]` pairs for every object reachable from the render window + - `hashes` — content hashes of the blobs those objects reference + - `cameras` — ids of the active cameras; `force_push` and `ignore_ids` select which to push to the server or leave alone (e.g. to keep the client's local camera) + - `interactor` — the interactor id for the render window + +## Hydrate a scene + +The example below stands in for a server with a handful of **canned object states**: a render window that owns a renderer whose `Background` is gray. The three fetchers read from that in-memory scene exactly as they would read from the wire, so the session hydrates and renders without any backend. + +The state objects mirror what `vtklocal.get.state` returns: each carries an `Id`, a `ClassName`, its `SuperClassNames`, and the properties to apply. References to other objects are `{ "Id": n }`, and `fetchStatus` advertises every object so the session knows what to pull on the first [`update`](#drive-updates). This scene has no binary data, so `fetchHash` is never called. + + + +
import { loadVtkWasm } from "/vtk-wasm/data/esm/index.mjs";
+const runtime = await loadVtkWasm({
+  url: "https://gitlab.kitware.com/api/v4/projects/13/packages/generic/vtk-wasm32-emscripten/9.6.20260228/vtk-9.6.20260228-wasm32-emscripten.tar.gz",
+});
+const remote = runtime.createRemoteSession();
+// The "server": 
+// a render window (1)
+//  -> interactor (2)
+//  -> renderer collection (3)
+//     -> renderer (4) with a gray background
+//        -> a prop collection (5)
+//        -> a vtkTextActor (6)
+//           -> a vtkTextProperty (7)
+const RENDER_WINDOW_ID = 1;
+const SCENE = {
+  1: {
+    ClassName: "vtkRenderWindow",
+    SuperClassNames: ["vtkObjectBase", "vtkObject", "vtkWindow"],
+    Id: 1, MTime: 10,
+    Interactor: { Id: 2 },
+    NumberOfLayers: 1,
+    Renderers: { Id: 3 },
+    "vtk-object-manager-kept-alive": true,
+  },
+  2: {
+    ClassName: "vtkRenderWindowInteractor",
+    SuperClassNames: ["vtkObjectBase", "vtkObject"],
+    Id: 2, MTime: 10,
+    RenderWindow: { Id: 1 },
+  },  
+  3: {
+    ClassName: "vtkRendererCollection",
+    SuperClassNames: ["vtkObjectBase", "vtkObject", "vtkCollection"],
+    Id: 3, MTime: 10,
+    Items: [{ Id: 4 }],
+  },
+  4: {
+    ClassName: "vtkRenderer",
+    SuperClassNames: ["vtkObjectBase", "vtkObject", "vtkViewport"],
+    Id: 4, MTime: 10,
+    Background: [0.2, 0.2, 0.2], // gray
+    RenderWindow: { Id: 1 },
+    ViewProps: { Id: 5 },
+  },
+  5: {
+    ClassName: "vtkPropCollection",
+    SuperClassNames: ["vtkObjectBase", "vtkObject", "vtkCollection"],
+    Id: 5, MTime: 10,
+    Items: [{ Id: 6 },],
+  },
+  6: {
+    ClassName: "vtkTextActor",
+    SuperClassNames: ["vtkObjectBase", "vtkObject",
+        "vtkProp", "vtkActor2D", "vtkTexturedActor2D"],
+    Id: 6, MTime: 10,
+    Input: "Hello VTK.wasm RemoteSession",
+    DisplayPosition: [20, 20],
+    TextProperty: { Id: 7 },
+  },
+  7: {
+    ClassName: "vtkTextProperty",
+    SuperClassNames: ["vtkObjectBase", "vtkObject"],
+    Id: 7, MTime: 10,
+    FontSize: 36,
+  }
+};
+// One object's serialized state, as a JSON string (the wire format).
+async function fetchState(vtkId) {
+  return JSON.stringify(SCENE[vtkId]);
+}
+// A binary blob by hash. This scene has none, so this is never called.
+async function fetchHash(hash) {
+  return new Uint8Array();
+}
+// What exists and what changed since last time.
+async function fetchStatus(vtkId) {
+  return {
+    ids: Object.values(SCENE).map((s) => [s.Id, s.MTime]),
+    hashes: [],
+    cameras: [],
+    force_push: [],
+    ignore_ids: [],
+  };
+}
+remote.bindNetwork(fetchState, fetchHash, fetchStatus);
+// Own the canvas, size it, then pull the scene in and render it.
+const container = document.getElementById("container");
+const canvas = document.createElement("canvas");
+canvas.tabindex = -1;
+container.appendChild(canvas);
+remote.bindCanvas(RENDER_WINDOW_ID, canvas);
+const resizeObserver = new ResizeObserver((entries) => {
+  // Content box already in device pixels — no devicePixelRatio math needed.
+  const { inlineSize, blockSize } = entries[0].devicePixelContentBoxSize[0];
+  remote.setSize(RENDER_WINDOW_ID, inlineSize, blockSize);
+});
+resizeObserver.observe(container);
+await remote.update(RENDER_WINDOW_ID);
+    
+
+ ## Bring your own canvas -The session never creates, moves, or removes canvas elements — you own them. Create a `` with an `id`, add it to the DOM, then associate it with a render window via [`bindCanvas`](/api/@kitware/vtk-wasm/classes/RemoteSession#bindcanvas): +The session never creates, moves, or removes canvas elements — you own them. Create a `` and associate it with a render window via [`bindCanvas`](/api/@kitware/vtk-wasm/classes/RemoteSession#bindcanvas), passing either the element itself or the `id` of one already in the DOM: ```js -remote.bindCanvas(renderWindowId, "my-canvas"); // install interaction listeners -remote.setSize(renderWindowId, 800, 600); // size the canvas + render window +const canvas = document.createElement("canvas"); +remote.bindCanvas(renderWindowId, canvas); // pass the element directly… +// remote.bindCanvas(renderWindowId, "my-canvas"); // …or the id of a canvas in the DOM +remote.setSize(renderWindowId, 800, 600); // size the canvas + render window ``` -When the canvas goes away, [`unbindCanvas`](/api/@kitware/vtk-wasm/classes/RemoteSession#unbindcanvas) removes the listeners and forgets the mapping, leaving the element itself untouched. +Passing the element directly registers it with Emscripten's `specialHTMLTargets`, so the canvas needs neither an `id` nor to be attached to the document — handy for off-screen or framework-managed canvases. (On builds that don't expose `specialHTMLTargets`, the canvas must have an `id` so a CSS selector can be used instead.) + +When the canvas goes away, [`unbindCanvas`](/api/@kitware/vtk-wasm/classes/RemoteSession#unbindcanvas) removes the listeners, unregisters the target, and forgets the mapping, leaving the element itself untouched. ## Drive updates -Call [`update`](/api/@kitware/vtk-wasm/classes/RemoteSession#update) to pull the latest server state for a render window and render it. Pass `bindCanvas: true` the first time so the render window is connected to its canvas: +Call [`update`](/api/@kitware/vtk-wasm/classes/RemoteSession#update) to pull the latest server state for a render window and render it. ```js -await remote.update(renderWindowId, /* bindCanvas */ true); +await remote.update(renderWindowId); ``` To surface download progress (state + blob counts), register a callback with [`addProgressCallback`](/api/@kitware/vtk-wasm/classes/RemoteSession#addprogresscallback); it returns a function that removes the callback. diff --git a/src/remoteSession.js b/src/remoteSession.js index a072733..77ff96d 100644 --- a/src/remoteSession.js +++ b/src/remoteSession.js @@ -11,15 +11,18 @@ import { addCanvasEventListeners, removeCanvasEventListeners } from "./core/canv */ export class RemoteSession { #native = null; + #module = null; #disposed = false; #vtkProxyCache = null; #idToRef = null; /** * @param {object} native - the C++ vtkRemoteSession instance. + * @param {object} wasmModule - the Emscripten module the session belongs to. */ - constructor(native) { + constructor(native, wasmModule) { this.#native = native; + this.#module = wasmModule; // this.updateInProgress = 0; this.currentMTime = 1; @@ -34,9 +37,12 @@ export class RemoteSession { this.progressCallbacks = new Set(); this.progressState = null; this.renderWindowSizes = {}; + this.boundRenderWindows = new Set(); - // renderWindowId -> user-provided canvas DOM id - this.canvasIds = new Map(); + // renderWindowId -> { canvas, target } where `canvas` is the user-provided + // element and `target` is the string handed to native.bindRenderWindow + // (a specialHTMLTargets key when available, otherwise a CSS selector). + this.canvasTargets = new Map(); // vtkObject proxy handling (create + getVtkObject + result wrapping) this.#vtkProxyCache = new WeakMap(); @@ -224,7 +230,7 @@ export class RemoteSession { * * @param {int} vtkId */ - async update(vtkId, bindCanvas = false) { + async update(vtkId) { this.updateInProgress++; if (this.updateInProgress !== 1) { // console.error("Skip concurrent update"); @@ -293,18 +299,22 @@ export class RemoteSession { // Bump local mtime and process states to reflect server state try { this.#native.updateObjectsFromStates(); - if (vtkId in this.renderWindowSizes) { - const [w, h] = this.renderWindowSizes[vtkId]; - this.#native.setSize(vtkId, w, h); - } - - if (bindCanvas) { - this.#native.bindRenderWindow(vtkId, this.getCanvasSelector(vtkId)); + const state = this.getVtkObject(vtkId).state; + const isRenderWindow = + state?.className === "vtkRenderWindow" || + state?.superClassNames?.includes("vtkRenderWindow"); + if (isRenderWindow) { + const rwId = Number(vtkId); + if (this.canvasTargets.has(rwId) && !this.boundRenderWindows.has(rwId)) { + this.#native.bindRenderWindow(rwId, this.getCanvasTarget(rwId)); + this.boundRenderWindows.add(rwId); + } + if (rwId in this.renderWindowSizes) { + const [w, h] = this.renderWindowSizes[rwId]; + this.#native.setSize(rwId, w, h); + } + await this.#native.render(rwId); } - - await this.#native.render(vtkId); - // TODO outside: - // - freeMemory: to keep memory in check } catch (e) { console.error("WASM update failed"); console.log(e); @@ -370,41 +380,71 @@ export class RemoteSession { } /** - * Return the CSS selector for the canvas registered to a render window. + * Return the native event-target string for the canvas registered to a render + * window. This is a `specialHTMLTargets` key when the build exposes that map, + * otherwise a CSS selector. Pass it to `native.bindRenderWindow`. * * @param {int} renderWindowId - * @returns {string} the selector string to find the given canvas + * @returns {string} the event-target string for the given canvas */ - getCanvasSelector(renderWindowId) { - const canvasId = this.canvasIds.get(Number(renderWindowId)); - if (!canvasId) { + getCanvasTarget(renderWindowId) { + const entry = this.canvasTargets.get(Number(renderWindowId)); + if (!entry) { throw new Error( `No canvas registered for render window ${renderWindowId}. ` + - `Call bindCanvas(renderWindowId, canvasId) first.`, + `Call bindCanvas(renderWindowId, canvas) first.`, ); } - return `#${canvasId}`; + return entry.target; } /** - * Associate a render window with a user-provided canvas (by its DOM id) and - * install the interaction listeners on it. + * Associate a render window with a user-provided canvas and install the + * interaction listeners on it. * * RemoteSession never creates, moves, or removes canvas elements: the caller - * owns the canvas lifecycle and must have added it to the DOM beforehand. + * owns the canvas lifecycle. The canvas may be passed as the element itself or + * as the `id` of an element already in the DOM. When the Emscripten build + * exposes `specialHTMLTargets`, the element is registered there directly, so it + * needs neither an `id` nor to be attached to the document; otherwise the + * element must have an `id` so a CSS selector can be used as a fallback. * * @param {int} renderWindowId - * @param {string} canvasId - the `id` attribute of the user's ``. - * @returns {string} the canvas selector string + * @param {HTMLCanvasElement|string} canvasOrId - the canvas element or its DOM `id`. + * @returns {string} the native event-target string (see {@link RemoteSession#getCanvasTarget}). */ - bindCanvas(renderWindowId, canvasId) { - this.canvasIds.set(Number(renderWindowId), canvasId); - const canvasSelector = this.getCanvasSelector(renderWindowId); - const canvas = document.querySelector(canvasSelector); - if (canvas) { - addCanvasEventListeners(canvas); + bindCanvas(renderWindowId, canvasOrId) { + const rwId = Number(renderWindowId); + const canvas = + typeof canvasOrId === "string" + ? document.getElementById(canvasOrId) + : canvasOrId; + if (!canvas) { + throw new Error( + `bindCanvas: no canvas found for render window ${renderWindowId}.`, + ); } - return canvasSelector; + + let target; + const specialHTMLTargets = this.#module?.specialHTMLTargets; + if (specialHTMLTargets) { + // Register the element directly; the canvas needs no id and need not be + // attached to the document. + target = `!vtk-canvas-${rwId}`; + specialHTMLTargets[target] = canvas; + } else if (canvas.id) { + // Fallback: resolve via CSS selector at bind time inside Emscripten. + target = `#${canvas.id}`; + } else { + throw new Error( + `bindCanvas: this build does not expose specialHTMLTargets, so the ` + + `canvas for render window ${renderWindowId} must have an 'id'.`, + ); + } + + this.canvasTargets.set(rwId, { canvas, target }); + addCanvasEventListeners(canvas); + return target; } /** @@ -415,15 +455,21 @@ export class RemoteSession { * @param {int} renderWindowId */ unbindCanvas(renderWindowId) { - const canvasId = this.canvasIds.get(Number(renderWindowId)); - if (!canvasId) { + const rwId = Number(renderWindowId); + const entry = this.canvasTargets.get(rwId); + if (!entry) { return; } - const canvas = document.getElementById(canvasId); - if (canvas) { - removeCanvasEventListeners(canvas); + removeCanvasEventListeners(entry.canvas); + if (this.boundRenderWindows.has(rwId)) { + this.#native.bindRenderWindow(rwId, ""); + this.boundRenderWindows.delete(rwId); + } + const specialHTMLTargets = this.#module?.specialHTMLTargets; + if (specialHTMLTargets) { + delete specialHTMLTargets[entry.target]; } - this.canvasIds.delete(Number(renderWindowId)); + this.canvasTargets.delete(rwId); } /** @@ -433,18 +479,19 @@ export class RemoteSession { * @param {int} width * @param {int} height */ - async setSize(renderWindowId, width, height) { - this.renderWindowSizes[renderWindowId] = [width, height]; - if (!this.canvasIds.has(Number(renderWindowId))) { - return; + async setSize(renderWindowId, width, height) { + const rwId = Number(renderWindowId); + this.renderWindowSizes[rwId] = [width, height]; + + const entry = this.canvasTargets.get(rwId); + if (entry?.canvas) { + entry.canvas.width = width; + entry.canvas.height = height; } - const canvas = document.querySelector(this.getCanvasSelector(renderWindowId)); - if (canvas) { - canvas.width = width; - canvas.height = height; - this.#native.setSize(renderWindowId, width, height); - await this.#native.render(renderWindowId); + if (this.boundRenderWindows.has(rwId)) { // RW exists in C++ + this.#native.setSize(rwId, width, height); + await this.#native.render(rwId); } } @@ -478,17 +525,22 @@ export class RemoteSession { this.#disposed = true; this.progressCallbacks.clear(); this.#idToRef.clear(); - this.canvasIds.forEach((canvasId) => { - const canvas = document.getElementById(canvasId); - if (canvas) { - removeCanvasEventListeners(canvas); + const specialHTMLTargets = this.#module?.specialHTMLTargets; + this.canvasTargets.forEach(({ canvas, target }) => { + removeCanvasEventListeners(canvas); + if (specialHTMLTargets) { + delete specialHTMLTargets[target]; } }); - this.canvasIds.clear(); + this.canvasTargets.clear(); + // The native session is destroyed below, so no need to unbind render + // windows individually; just drop our bookkeeping. + this.boundRenderWindows.clear(); if (typeof this.#native?.delete === "function") { this.#native.delete(); } this.#native = null; + this.#module = null; } [Symbol.dispose]() { diff --git a/src/runtime.js b/src/runtime.js index e7fbc16..cc9862e 100644 --- a/src/runtime.js +++ b/src/runtime.js @@ -19,6 +19,29 @@ function cacheKey(url, wasmBaseName, config) { return `${url}::${wasmBaseName}::${config.rendering}::${config.exec}`; } +// Emscripten keeps `specialHTMLTargets` as a module-private variable, so there +// is no way to register a canvas element (vs. a CSS selector) from the outside. +// Alias it onto `Module` at its declaration so the runtime can expose it. The +// symbol is a non-minified library name, so this string match is stable. +const SPECIAL_TARGETS_DECL = "var specialHTMLTargets=["; +const SPECIAL_TARGETS_PATCH = "var specialHTMLTargets=Module.specialHTMLTargets=["; + +/** + * Patch the Emscripten glue source so `specialHTMLTargets` is reachable as + * `Module.specialHTMLTargets`. No-op if the pattern is absent or already + * patched (e.g. a build that already exports it). + * + * @param {ArrayBufferLike} buffer - the glue JavaScript source bytes. + * @returns {ArrayBufferLike} the (possibly patched) source bytes. + */ +function exposeSpecialHTMLTargets(buffer) { + const text = new TextDecoder().decode(buffer); + if (text.includes(SPECIAL_TARGETS_PATCH) || !text.includes(SPECIAL_TARGETS_DECL)) { + return buffer; + } + return new TextEncoder().encode(text.replace(SPECIAL_TARGETS_DECL, SPECIAL_TARGETS_PATCH)).buffer; +} + /** * Ensure `window.createVTKWASM` is available, loading the glue script if needed. * Returns the wasm binary descriptor when it had to be extracted from a gzip @@ -35,7 +58,7 @@ async function prepareModuleFactory(url, urlIsGzip, wasmBaseName, config) { if (urlIsGzip) { const gzipArrayBuffer = await fetchGzipBundle(url); const { js, wasm } = await extractFilesFromGzipBundle(gzipArrayBuffer, config, wasmBaseName); - const javaScriptBlobURL = createBlobURL(js.buffer, MIME_TYPES.JAVASCRIPT); + const javaScriptBlobURL = createBlobURL(exposeSpecialHTMLTargets(js.buffer), MIME_TYPES.JAVASCRIPT); try { await loadWebAssemblyModuleFromScript(javaScriptBlobURL); } finally { @@ -156,7 +179,7 @@ export class VtkWasmRuntime { */ createRemoteSession() { this.#assertLive(); - return new RemoteSession(new this.#module.vtkRemoteSession()); + return new RemoteSession(new this.#module.vtkRemoteSession(), this.#module); } /** diff --git a/src/viewer.js b/src/viewer.js index 99d3efb..39c6fa1 100644 --- a/src/viewer.js +++ b/src/viewer.js @@ -67,8 +67,8 @@ export class ExportViewer { ); this.container.appendChild(canvas); - const selector = this.remoting.bindCanvas(rwId, canvas.id); - this.remoting.native.bindRenderWindow(rwId, selector); + const target = this.remoting.bindCanvas(rwId, canvas); + this.remoting.native.bindRenderWindow(rwId, target); this.remoting.native.startEventLoop(rwId); } } From 33fb47baeda943cde709c4b9f649a444e4873157 Mon Sep 17 00:00:00 2001 From: Jaswant Panchumarti Date: Mon, 15 Jun 2026 19:01:46 -0400 Subject: [PATCH 8/8] refactor(js)!: suffix promise-returning methods with Async Rename every method and function under src/ that returns a promise so its name ends in `Async`, leaving synchronous methods (e.g. VtkWasmRuntime.isAsync) untouched. Docs and examples are updated to match. BREAKING CHANGE: the following promise-returning APIs were renamed: - loadVtkWasm -> loadVtkWasmAsync - createViewer -> createViewerAsync - RemoteSession.update/setSize/fetchState/fetchHash/pushHash gain the `Async` suffix (updateAsync, setSizeAsync, fetchStateAsync, fetchHashAsync, pushHashAsync) - ExportViewer.load -> loadAsync Callers must update to the new names. --- README.md | 4 +-- docs/guide/js/integration.md | 4 +-- docs/guide/js/loading.md | 20 +++++++------- docs/guide/js/remote-session.md | 22 ++++++++-------- docs/guide/js/standalone-session.md | 4 +-- docs/guide/viewer/index.md | 2 +- .../public/demo/plain-javascript-preload.html | 2 +- docs/public/demo/plain-javascript.html | 4 +-- docs/public/demo/viewer-basic.html | 2 +- docs/public/demo/viewer-porsche.html | 2 +- docs/public/demo/viewer-starfighter.html | 2 +- docs/public/demo/viewer-starfighter2.html | 2 +- examples/js/simple-app/src/main.js | 6 ++--- src/core/gzipBundle.js | 4 +-- src/core/scriptLoader.js | 6 ++--- src/index.js | 6 ++--- src/remoteSession.js | 18 ++++++------- src/runtime.js | 26 +++++++++---------- src/viewer.js | 10 +++---- 19 files changed, 73 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index 614d2ad..19d5154 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ npm install @kitware/vtk-wasm Load the runtime, create a session, and use its `vtk` namespace: ```js -import { loadVtkWasm } from "@kitware/vtk-wasm"; +import { loadVtkWasmAsync } from "@kitware/vtk-wasm"; -const runtime = await loadVtkWasm({ url: VTK_WASM_BUNDLE_URL }); +const runtime = await loadVtkWasmAsync({ url: VTK_WASM_BUNDLE_URL }); const session = runtime.createStandaloneSession(); const vtk = session.vtk; diff --git a/docs/guide/js/integration.md b/docs/guide/js/integration.md index 93778ad..0a54ce6 100644 --- a/docs/guide/js/integration.md +++ b/docs/guide/js/integration.md @@ -5,7 +5,7 @@ There are two ways to get VTK.wasm into a web project: - **HTML Script Tag** — load a prebuilt bundle from a CDN, no build step required. Best for quick prototypes, demos, and embedding into existing pages. - **Bundler** — install the `@kitware/vtk-wasm` package and `import` it. Best for application development with a tool like Vite. -Either way you end up calling [`loadVtkWasm`](./loading.md); only how it reaches the page differs. +Either way you end up calling [`loadVtkWasmAsync`](./loading.md); only how it reaches the page differs. ## HTML Script Tag @@ -48,7 +48,7 @@ Here we tag the script to autoload WASM directly from the VTK repository's packa [Full Screen Viewer](../../demo/plain-javascript-annotation-wasm-registry.html){target="_blank"} -The `data-config` attribute on the annotation ` diff --git a/docs/public/demo/plain-javascript.html b/docs/public/demo/plain-javascript.html index cd7a40c..c6d1abe 100644 --- a/docs/public/demo/plain-javascript.html +++ b/docs/public/demo/plain-javascript.html @@ -6,10 +6,10 @@ diff --git a/docs/public/demo/viewer-basic.html b/docs/public/demo/viewer-basic.html index a261787..0aadb90 100644 --- a/docs/public/demo/viewer-basic.html +++ b/docs/public/demo/viewer-basic.html @@ -9,7 +9,7 @@