From 2904c13c41ad8e5016e9560f96159306a08955dc Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 19 Jan 2026 16:25:29 +0100 Subject: [PATCH 01/14] feat: init --- .../lib/graph-interface/graph-state.svelte.ts | 14 ++++++++-- app/src/lib/graph-interface/graph/events.ts | 26 ++++++++++++++++++- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index 717cd97..a5a6b7a 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -1,8 +1,8 @@ import type { NodeInstance, Socket } from "@nodarium/types"; import { getContext, setContext } from "svelte"; -import { SvelteSet } from "svelte/reactivity"; +import { SvelteMap, SvelteSet } from "svelte/reactivity"; import type { GraphManager } from "./graph-manager.svelte"; -import type { OrthographicCamera } from "three"; +import type { Mesh, OrthographicCamera, Vector3 } from "three"; const graphStateKey = Symbol("graph-state"); @@ -46,6 +46,8 @@ export class GraphState { width = $state(100); height = $state(100); + edgeGeometries = new SvelteMap(); + wrapper = $state(null!); rect: DOMRect = $derived( (this.wrapper && this.width && this.height) ? this.wrapper.getBoundingClientRect() : new DOMRect(0, 0, 0, 0), @@ -97,6 +99,14 @@ export class GraphState { isBodyFocused = () => document?.activeElement?.nodeName !== "INPUT"; + setEdgeGeometry(edgeId: string, edgeGeometry: { geo: Mesh, points: Vector3[] }) { + this.edgeGeometries.set(edgeId, edgeGeometry); + } + + removeEdgeGeometry(edgeId: string) { + this.edgeGeometries.delete(edgeId); + } + updateNodePosition(node: NodeInstance) { if ( node.state.x === node.position[0] && diff --git a/app/src/lib/graph-interface/graph/events.ts b/app/src/lib/graph-interface/graph/events.ts index fda0513..9a1ddd3 100644 --- a/app/src/lib/graph-interface/graph/events.ts +++ b/app/src/lib/graph-interface/graph/events.ts @@ -112,16 +112,38 @@ export class FileDropEventManager { } +class EdgeInteractionManager { + constructor( + private graph: GraphManager, + private state: GraphState) { }; + + handleMouseDown() { + const edges = this.graph.edges; + console.log(edges) + } + + handleMouseMove() { + } + + handleMouseUp() { + } +} + + export class MouseEventManager { + edgeInteractionManager: EdgeInteractionManager constructor( private graph: GraphManager, private state: GraphState - ) { } + ) { + this.edgeInteractionManager = new EdgeInteractionManager(graph, state); + } handleMouseUp(event: MouseEvent) { + this.edgeInteractionManager.handleMouseUp(); this.state.isPanning = false; if (!this.state.mouseDown) return; @@ -312,6 +334,7 @@ export class MouseEventManager { this.state.activeNodeId = clickedNodeId; this.state.clearSelection(); } + this.edgeInteractionManager.handleMouseDown(); } else if (event.ctrlKey) { this.state.boxSelection = true; } @@ -397,6 +420,7 @@ export class MouseEventManager { // here we are handling dragging of nodes if (this.state.activeNodeId !== -1 && this.state.mouseDownNodeId !== -1) { + this.edgeInteractionManager.handleMouseMove(); const node = this.graph.getNode(this.state.activeNodeId); if (!node || event.buttons !== 1) return; From cdef71265e722980e1cead51ff13df87bf6f2df5 Mon Sep 17 00:00:00 2001 From: Niklas Koll Date: Mon, 19 Jan 2026 16:26:15 +0100 Subject: [PATCH 02/14] Add svelte language server --- flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/flake.nix b/flake.nix index b8d7bcc..9d9dbad 100644 --- a/flake.nix +++ b/flake.nix @@ -33,6 +33,7 @@ pkgs.typescript-language-server pkgs.prettier pkgs.tailwindcss-language-server + pkgs.svelte-language-server ]; }; }); From 4485cef82ba4bce59cbc023af880dabf6c776cd0 Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:30:45 +0100 Subject: [PATCH 03/14] chore(app): remove old (pnpm v6 - now 9) pnpm lock --- app/pnpm-lock.yaml | 1576 -------------------------------------------- 1 file changed, 1576 deletions(-) delete mode 100644 app/pnpm-lock.yaml diff --git a/app/pnpm-lock.yaml b/app/pnpm-lock.yaml deleted file mode 100644 index 86fd2bd..0000000 --- a/app/pnpm-lock.yaml +++ /dev/null @@ -1,1576 +0,0 @@ -lockfileVersion: '6.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -dependencies: - '@sveltejs/kit': - specifier: ^2.5.0 - version: 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.4) - '@tauri-apps/api': - specifier: 2.0.0-beta.2 - version: 2.0.0-beta.2 - '@tauri-apps/plugin-shell': - specifier: ^2.0.0-beta.0 - version: 2.0.0-beta.1 - '@threlte/core': - specifier: ^7.1.0 - version: 7.1.0(svelte@4.2.11)(three@0.159.0) - '@threlte/extras': - specifier: ^8.7.5 - version: 8.8.0(svelte@4.2.11)(three@0.159.0) - '@threlte/flex': - specifier: ^1.0.1 - version: 1.0.1(svelte@4.2.11)(three@0.159.0) - '@types/three': - specifier: ^0.159.0 - version: 0.159.0 - three: - specifier: ^0.159.0 - version: 0.159.0 - -devDependencies: - '@sveltejs/adapter-static': - specifier: ^3.0.1 - version: 3.0.1(@sveltejs/kit@2.5.0) - '@sveltejs/vite-plugin-svelte': - specifier: ^3.0.1 - version: 3.0.2(svelte@4.2.11)(vite@5.1.4) - '@tauri-apps/cli': - specifier: 2.0.0-beta.3 - version: 2.0.0-beta.3 - '@tsconfig/svelte': - specifier: ^5.0.2 - version: 5.0.2 - internal-ip: - specifier: ^7.0.0 - version: 7.0.0 - svelte: - specifier: ^4.2.8 - version: 4.2.11 - svelte-check: - specifier: ^3.4.6 - version: 3.6.4(svelte@4.2.11) - tslib: - specifier: ^2.6.0 - version: 2.6.2 - typescript: - specifier: ^5.0.2 - version: 5.3.3 - vite: - specifier: ^5.0.0 - version: 5.1.4 - -packages: - - /@ampproject/remapping@2.2.1: - resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/gen-mapping': 0.3.3 - '@jridgewell/trace-mapping': 0.3.22 - - /@esbuild/aix-ppc64@0.19.12: - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - requiresBuild: true - optional: true - - /@esbuild/android-arm64@0.19.12: - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - optional: true - - /@esbuild/android-arm@0.19.12: - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - requiresBuild: true - optional: true - - /@esbuild/android-x64@0.19.12: - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - optional: true - - /@esbuild/darwin-arm64@0.19.12: - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - optional: true - - /@esbuild/darwin-x64@0.19.12: - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true - optional: true - - /@esbuild/freebsd-arm64@0.19.12: - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true - optional: true - - /@esbuild/freebsd-x64@0.19.12: - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true - optional: true - - /@esbuild/linux-arm64@0.19.12: - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-arm@0.19.12: - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-ia32@0.19.12: - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-loong64@0.19.12: - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-mips64el@0.19.12: - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-ppc64@0.19.12: - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-riscv64@0.19.12: - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-s390x@0.19.12: - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/linux-x64@0.19.12: - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true - optional: true - - /@esbuild/netbsd-x64@0.19.12: - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - optional: true - - /@esbuild/openbsd-x64@0.19.12: - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - optional: true - - /@esbuild/sunos-x64@0.19.12: - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true - optional: true - - /@esbuild/win32-arm64@0.19.12: - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true - optional: true - - /@esbuild/win32-ia32@0.19.12: - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true - optional: true - - /@esbuild/win32-x64@0.19.12: - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true - optional: true - - /@jridgewell/gen-mapping@0.3.3: - resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} - engines: {node: '>=6.0.0'} - dependencies: - '@jridgewell/set-array': 1.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 - - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - /@jridgewell/set-array@1.1.2: - resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} - engines: {node: '>=6.0.0'} - - /@jridgewell/sourcemap-codec@1.4.15: - resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - - /@jridgewell/trace-mapping@0.3.22: - resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.4.15 - - /@nodelib/fs.scandir@2.1.5: - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - dev: true - - /@nodelib/fs.stat@2.0.5: - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - dev: true - - /@nodelib/fs.walk@1.2.8: - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.17.1 - dev: true - - /@polka/url@1.0.0-next.24: - resolution: {integrity: sha512-2LuNTFBIO0m7kKIQvvPHN6UE63VjpmL9rnEEaOOaiSPbZK+zUOYIzBAWcED+3XYzhYsd/0mD57VdxAEqqV52CQ==} - - /@rollup/rollup-android-arm-eabi@4.12.0: - resolution: {integrity: sha512-+ac02NL/2TCKRrJu2wffk1kZ+RyqxVUlbjSagNgPm94frxtr+XDL12E5Ll1enWskLrtrZ2r8L3wED1orIibV/w==} - cpu: [arm] - os: [android] - requiresBuild: true - optional: true - - /@rollup/rollup-android-arm64@4.12.0: - resolution: {integrity: sha512-OBqcX2BMe6nvjQ0Nyp7cC90cnumt8PXmO7Dp3gfAju/6YwG0Tj74z1vKrfRz7qAv23nBcYM8BCbhrsWqO7PzQQ==} - cpu: [arm64] - os: [android] - requiresBuild: true - optional: true - - /@rollup/rollup-darwin-arm64@4.12.0: - resolution: {integrity: sha512-X64tZd8dRE/QTrBIEs63kaOBG0b5GVEd3ccoLtyf6IdXtHdh8h+I56C2yC3PtC9Ucnv0CpNFJLqKFVgCYe0lOQ==} - cpu: [arm64] - os: [darwin] - requiresBuild: true - optional: true - - /@rollup/rollup-darwin-x64@4.12.0: - resolution: {integrity: sha512-cc71KUZoVbUJmGP2cOuiZ9HSOP14AzBAThn3OU+9LcA1+IUqswJyR1cAJj3Mg55HbjZP6OLAIscbQsQLrpgTOg==} - cpu: [x64] - os: [darwin] - requiresBuild: true - optional: true - - /@rollup/rollup-linux-arm-gnueabihf@4.12.0: - resolution: {integrity: sha512-a6w/Y3hyyO6GlpKL2xJ4IOh/7d+APaqLYdMf86xnczU3nurFTaVN9s9jOXQg97BE4nYm/7Ga51rjec5nfRdrvA==} - cpu: [arm] - os: [linux] - requiresBuild: true - optional: true - - /@rollup/rollup-linux-arm64-gnu@4.12.0: - resolution: {integrity: sha512-0fZBq27b+D7Ar5CQMofVN8sggOVhEtzFUwOwPppQt0k+VR+7UHMZZY4y+64WJ06XOhBTKXtQB/Sv0NwQMXyNAA==} - cpu: [arm64] - os: [linux] - requiresBuild: true - optional: true - - /@rollup/rollup-linux-arm64-musl@4.12.0: - resolution: {integrity: sha512-eTvzUS3hhhlgeAv6bfigekzWZjaEX9xP9HhxB0Dvrdbkk5w/b+1Sxct2ZuDxNJKzsRStSq1EaEkVSEe7A7ipgQ==} - cpu: [arm64] - os: [linux] - requiresBuild: true - optional: true - - /@rollup/rollup-linux-riscv64-gnu@4.12.0: - resolution: {integrity: sha512-ix+qAB9qmrCRiaO71VFfY8rkiAZJL8zQRXveS27HS+pKdjwUfEhqo2+YF2oI+H/22Xsiski+qqwIBxVewLK7sw==} - cpu: [riscv64] - os: [linux] - requiresBuild: true - optional: true - - /@rollup/rollup-linux-x64-gnu@4.12.0: - resolution: {integrity: sha512-TenQhZVOtw/3qKOPa7d+QgkeM6xY0LtwzR8OplmyL5LrgTWIXpTQg2Q2ycBf8jm+SFW2Wt/DTn1gf7nFp3ssVA==} - cpu: [x64] - os: [linux] - requiresBuild: true - optional: true - - /@rollup/rollup-linux-x64-musl@4.12.0: - resolution: {integrity: sha512-LfFdRhNnW0zdMvdCb5FNuWlls2WbbSridJvxOvYWgSBOYZtgBfW9UGNJG//rwMqTX1xQE9BAodvMH9tAusKDUw==} - cpu: [x64] - os: [linux] - requiresBuild: true - optional: true - - /@rollup/rollup-win32-arm64-msvc@4.12.0: - resolution: {integrity: sha512-JPDxovheWNp6d7AHCgsUlkuCKvtu3RB55iNEkaQcf0ttsDU/JZF+iQnYcQJSk/7PtT4mjjVG8N1kpwnI9SLYaw==} - cpu: [arm64] - os: [win32] - requiresBuild: true - optional: true - - /@rollup/rollup-win32-ia32-msvc@4.12.0: - resolution: {integrity: sha512-fjtuvMWRGJn1oZacG8IPnzIV6GF2/XG+h71FKn76OYFqySXInJtseAqdprVTDTyqPxQOG9Exak5/E9Z3+EJ8ZA==} - cpu: [ia32] - os: [win32] - requiresBuild: true - optional: true - - /@rollup/rollup-win32-x64-msvc@4.12.0: - resolution: {integrity: sha512-ZYmr5mS2wd4Dew/JjT0Fqi2NPB/ZhZ2VvPp7SmvPZb4Y1CG/LRcS6tcRo2cYU7zLK5A7cdbhWnnWmUjoI4qapg==} - cpu: [x64] - os: [win32] - requiresBuild: true - optional: true - - /@sveltejs/adapter-static@3.0.1(@sveltejs/kit@2.5.0): - resolution: {integrity: sha512-6lMvf7xYEJ+oGeR5L8DFJJrowkefTK6ZgA4JiMqoClMkKq0s6yvsd3FZfCFvX1fQ0tpCD7fkuRVHsnUVgsHyNg==} - peerDependencies: - '@sveltejs/kit': ^2.0.0 - dependencies: - '@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.4) - dev: true - - /@sveltejs/kit@2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.4): - resolution: {integrity: sha512-1uyXvzC2Lu1FZa30T4y5jUAC21R309ZMRG0TPt+PPPbNUoDpy8zSmSNVWYaBWxYDqLGQ5oPNWvjvvF2IjJ1jmA==} - engines: {node: '>=18.13'} - hasBin: true - requiresBuild: true - peerDependencies: - '@sveltejs/vite-plugin-svelte': ^3.0.0 - svelte: ^4.0.0 || ^5.0.0-next.0 - vite: ^5.0.3 - dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.4) - '@types/cookie': 0.6.0 - cookie: 0.6.0 - devalue: 4.3.2 - esm-env: 1.0.0 - import-meta-resolve: 4.0.0 - kleur: 4.1.5 - magic-string: 0.30.7 - mrmime: 2.0.0 - sade: 1.8.1 - set-cookie-parser: 2.6.0 - sirv: 2.0.4 - svelte: 4.2.11 - tiny-glob: 0.2.9 - vite: 5.1.4 - - /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.4): - resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==} - engines: {node: ^18.0.0 || >=20} - peerDependencies: - '@sveltejs/vite-plugin-svelte': ^3.0.0 - svelte: ^4.0.0 || ^5.0.0-next.0 - vite: ^5.0.0 - dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.4) - debug: 4.3.4 - svelte: 4.2.11 - vite: 5.1.4 - transitivePeerDependencies: - - supports-color - - /@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.11)(vite@5.1.4): - resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==} - engines: {node: ^18.0.0 || >=20} - peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.0 - vite: ^5.0.0 - dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.4) - debug: 4.3.4 - deepmerge: 4.3.1 - kleur: 4.1.5 - magic-string: 0.30.7 - svelte: 4.2.11 - svelte-hmr: 0.15.3(svelte@4.2.11) - vite: 5.1.4 - vitefu: 0.2.5(vite@5.1.4) - transitivePeerDependencies: - - supports-color - - /@tauri-apps/api@2.0.0-beta.2: - resolution: {integrity: sha512-4r1r6kgttzIWxJ3HxkZQH+b7EiUtKhdUCPbi0KSalD+2T3j6klw+v8VyxhKwEdjM/eo60NE+J33v1E/Urq8puw==} - engines: {node: '>= 18', npm: '>= 6.6.0', yarn: '>= 1.19.1'} - dev: false - - /@tauri-apps/cli-darwin-arm64@2.0.0-beta.3: - resolution: {integrity: sha512-gHcn3jI/4MDXDIlK/4Zz0ftTosgN3OimWlKxEz777QrA1hldrQweYIhdZXkqE9KgoE+u6w80vWIcr0InHAf7Iw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-darwin-x64@2.0.0-beta.3: - resolution: {integrity: sha512-kRCaukT2IAGMmNuAOUBhdZRlKujTy2lSsdNKmgGEMnzQLKJwWO9Gpq1NmPY7ZVqyXK/X8QnGHuasDEQsSO6B4w==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-linux-arm-gnueabihf@2.0.0-beta.3: - resolution: {integrity: sha512-cpNZOQDotNSdjoZT16s1JtZvnkM0wgLwU39AhKhRCco4KEH3/8G1ngKF9JKalWUN8zDTcuCigEAr37gEv4mLAA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-linux-arm64-gnu@2.0.0-beta.3: - resolution: {integrity: sha512-8q86V6P9bkeoFcnvSsnvOwmKY6ijIN4ueRVXCj5cVpsw392VF9vud1Nq7/l+QDgn9OWbZNNVDl30iyoSuaykBA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-linux-arm64-musl@2.0.0-beta.3: - resolution: {integrity: sha512-L7fokh4aqyV6yDPoeKwFN3Yt0pCAuZMWeP5tOeSBiom1pU7ppKH+4KHeTekNEIecZG+Ah250DkVCdmWS+aRFTA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-linux-x64-gnu@2.0.0-beta.3: - resolution: {integrity: sha512-/crp3K6PathqicVWPj8Kh1120NNVV7nagJ7oZW9OFch7nBS1tmDnSB5k5LgA4yYu+lDKNUREnATMWHL6i0gNeg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-linux-x64-musl@2.0.0-beta.3: - resolution: {integrity: sha512-jX1ZT0UQwdBGbpCwlpv2bsLDO7KFMeDJQ/ZZVMfWyjuYrGBG5zhJ2NXwTMkHVnxfvE6BVmnybWcykeSqTATeOw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-win32-arm64-msvc@2.0.0-beta.3: - resolution: {integrity: sha512-UCEZNKocENLX3HYKid4FEbrCMjCX9e58klBIvJKxT8HTjvpgFYDoKccswDNfszLhmineKMlkUvm7j7U0sMh8MQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-win32-ia32-msvc@2.0.0-beta.3: - resolution: {integrity: sha512-O8syGXDHyKN/cv1ktD76dTcbkQ1nNEPhnT1Z+r0GKxNsw4/MyIVglzEcou3aPq0/1MQ0PEGVyG1x0JMaPw7oHQ==} - engines: {node: '>= 10'} - cpu: [ia32] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli-win32-x64-msvc@2.0.0-beta.3: - resolution: {integrity: sha512-YDdF3XWaptjKtKz33sZhC+uNAZwp6QtAmZSRCQQlC1W7uJwLD00/3QF4vO/c6Qm+BGFsazVh1+YmBF1p0kV0rg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - requiresBuild: true - dev: true - optional: true - - /@tauri-apps/cli@2.0.0-beta.3: - resolution: {integrity: sha512-xLAL2DNNUJWqHBKvanc3V9bG9kkwtFwc40X/DrfgEKnkajEm79wqnkaT8LUnmbe0WZ8bzBRO1fLIgKlOH6GiCA==} - engines: {node: '>= 10'} - hasBin: true - optionalDependencies: - '@tauri-apps/cli-darwin-arm64': 2.0.0-beta.3 - '@tauri-apps/cli-darwin-x64': 2.0.0-beta.3 - '@tauri-apps/cli-linux-arm-gnueabihf': 2.0.0-beta.3 - '@tauri-apps/cli-linux-arm64-gnu': 2.0.0-beta.3 - '@tauri-apps/cli-linux-arm64-musl': 2.0.0-beta.3 - '@tauri-apps/cli-linux-x64-gnu': 2.0.0-beta.3 - '@tauri-apps/cli-linux-x64-musl': 2.0.0-beta.3 - '@tauri-apps/cli-win32-arm64-msvc': 2.0.0-beta.3 - '@tauri-apps/cli-win32-ia32-msvc': 2.0.0-beta.3 - '@tauri-apps/cli-win32-x64-msvc': 2.0.0-beta.3 - dev: true - - /@tauri-apps/plugin-shell@2.0.0-beta.1: - resolution: {integrity: sha512-yMf9CMHCRkGnx0pv420MptEeUdk+bVrXyM5zwFisy75GBhXgvEEtSjAkubTsC0jkzLfn4EInizaW2GER9ub7cQ==} - dependencies: - '@tauri-apps/api': 2.0.0-beta.2 - dev: false - - /@threlte/core@7.1.0(svelte@4.2.11)(three@0.159.0): - resolution: {integrity: sha512-Qshrrt1Bqu8B0rWuNtFqGJpbmxrFUBNYTHOJZ29Tiqy2kpmwYZfzVSPRoGUfJTqUtpfxGCrDU3S2etWnB0KsUA==} - peerDependencies: - svelte: '>=4' - three: '>=0.133' - dependencies: - mitt: 3.0.1 - svelte: 4.2.11 - three: 0.159.0 - dev: false - - /@threlte/extras@8.8.0(svelte@4.2.11)(three@0.159.0): - resolution: {integrity: sha512-NNGywihQlPGbDoWnr0ZHV59Gkg8nKM4kzdxPY0CVZ93pSxXpGdoua0mQBTaQbJ6w3Qeiz867va+4SQXeVRHs8w==} - peerDependencies: - svelte: '>=4' - three: '>=0.133' - dependencies: - svelte: 4.2.11 - three: 0.159.0 - three-mesh-bvh: 0.7.3(three@0.159.0) - three-perf: 1.0.10(three@0.159.0) - troika-three-text: 0.49.0(three@0.159.0) - dev: false - - /@threlte/flex@1.0.1(svelte@4.2.11)(three@0.159.0): - resolution: {integrity: sha512-GKuf9v4GPBLHloL6sJhvXCZXTh5HxNra8wyvhDIxdf5YlNNbRfqnm6ffWx3wjOZCNcn9QBz46Lqh+W/9dwc9CA==} - peerDependencies: - svelte: '>=4' - three: '>=0.133' - dependencies: - mitt: 3.0.1 - svelte: 4.2.11 - three: 0.159.0 - yoga-layout: 2.0.1 - dev: false - - /@tsconfig/svelte@5.0.2: - resolution: {integrity: sha512-BRbo1fOtyVbhfLyuCWw6wAWp+U8UQle+ZXu84MYYWzYSEB28dyfnRBIE99eoG+qdAC0po6L2ScIEivcT07UaMA==} - dev: true - - /@types/cookie@0.6.0: - resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - - /@types/estree@1.0.5: - resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - - /@types/pug@2.0.10: - resolution: {integrity: sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==} - dev: true - - /@types/stats.js@0.17.3: - resolution: {integrity: sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==} - dev: false - - /@types/three@0.159.0: - resolution: {integrity: sha512-2gybdh7HtX+rGUgslzK7QEJfzD2I0qrbUGzKk+dK0FDx49UHkNX0rqZVRzIgeFjBd1HzzhNNgwNoMacm3Wyc7w==} - dependencies: - '@types/stats.js': 0.17.3 - '@types/webxr': 0.5.14 - fflate: 0.6.10 - meshoptimizer: 0.18.1 - dev: false - - /@types/webxr@0.5.14: - resolution: {integrity: sha512-UEMMm/Xn3DtEa+gpzUrOcDj+SJS1tk5YodjwOxcqStNhCfPcwgyC5Srg2ToVKyg2Fhq16Ffpb0UWUQHqoT9AMA==} - dev: false - - /acorn@8.11.3: - resolution: {integrity: sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==} - engines: {node: '>=0.4.0'} - hasBin: true - - /anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - dev: true - - /aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - dependencies: - dequal: 2.0.3 - - /axobject-query@4.0.0: - resolution: {integrity: sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==} - dependencies: - dequal: 2.0.3 - - /balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - - /bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - dependencies: - require-from-string: 2.0.2 - dev: false - - /binary-extensions@2.2.0: - resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} - engines: {node: '>=8'} - dev: true - - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - - /braces@3.0.2: - resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} - engines: {node: '>=8'} - dependencies: - fill-range: 7.0.1 - dev: true - - /buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - dev: true - - /callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - dev: true - - /chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - dependencies: - anymatch: 3.1.3 - braces: 3.0.2 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - dev: true - - /code-red@1.0.4: - resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - '@types/estree': 1.0.5 - acorn: 8.11.3 - estree-walker: 3.0.3 - periscopic: 3.1.0 - - /concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - - /cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - - /cross-spawn@7.0.3: - resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} - engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - - /css-tree@2.3.1: - resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} - dependencies: - mdn-data: 2.0.30 - source-map-js: 1.0.2 - - /debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - dependencies: - ms: 2.1.2 - - /deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - /default-gateway@6.0.3: - resolution: {integrity: sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==} - engines: {node: '>= 10'} - dependencies: - execa: 5.1.1 - dev: true - - /dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - /detect-indent@6.1.0: - resolution: {integrity: sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA==} - engines: {node: '>=8'} - dev: true - - /devalue@4.3.2: - resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} - - /es6-promise@3.3.1: - resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} - dev: true - - /esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - - /esm-env@1.0.0: - resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} - - /estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - dependencies: - '@types/estree': 1.0.5 - - /execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - dependencies: - cross-spawn: 7.0.3 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - dev: true - - /fast-glob@3.3.2: - resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} - engines: {node: '>=8.6.0'} - dependencies: - '@nodelib/fs.stat': 2.0.5 - '@nodelib/fs.walk': 1.2.8 - glob-parent: 5.1.2 - merge2: 1.4.1 - micromatch: 4.0.5 - dev: true - - /fastq@1.17.1: - resolution: {integrity: sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==} - dependencies: - reusify: 1.0.4 - dev: true - - /fflate@0.6.10: - resolution: {integrity: sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==} - dev: false - - /fill-range@7.0.1: - resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} - engines: {node: '>=8'} - dependencies: - to-regex-range: 5.0.1 - dev: true - - /fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - dev: true - - /fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - requiresBuild: true - optional: true - - /get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - dev: true - - /glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - dependencies: - is-glob: 4.0.3 - dev: true - - /glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - dev: true - - /globalyzer@0.1.0: - resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} - - /globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - /graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: true - - /human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - dev: true - - /import-fresh@3.3.0: - resolution: {integrity: sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==} - engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - - /import-meta-resolve@4.0.0: - resolution: {integrity: sha512-okYUR7ZQPH+efeuMJGlq4f8ubUgO50kByRPyt/Cy1Io4PSRsPjxME+YlVaCOx+NIToW7hCsZNFJyTPFFKepRSA==} - - /inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - dev: true - - /inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - dev: true - - /internal-ip@7.0.0: - resolution: {integrity: sha512-qE4TeD4brqC45Vq/+VASeMiS1KRyfBkR6HT2sh9pZVVCzSjPkaCEfKFU+dL0PRv7NHJtvoKN2r82G6wTfzorkw==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - dependencies: - default-gateway: 6.0.3 - ipaddr.js: 2.1.0 - is-ip: 3.1.0 - p-event: 4.2.0 - dev: true - - /ip-regex@4.3.0: - resolution: {integrity: sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q==} - engines: {node: '>=8'} - dev: true - - /ipaddr.js@2.1.0: - resolution: {integrity: sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==} - engines: {node: '>= 10'} - dev: true - - /is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - dependencies: - binary-extensions: 2.2.0 - dev: true - - /is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - dev: true - - /is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - - /is-ip@3.1.0: - resolution: {integrity: sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q==} - engines: {node: '>=8'} - dependencies: - ip-regex: 4.3.0 - dev: true - - /is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - dev: true - - /is-reference@3.0.2: - resolution: {integrity: sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==} - dependencies: - '@types/estree': 1.0.5 - - /is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - dev: true - - /isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - - /kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - - /locate-character@3.0.0: - resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} - - /magic-string@0.30.7: - resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} - engines: {node: '>=12'} - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - - /mdn-data@2.0.30: - resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - - /merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: true - - /merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} - dev: true - - /meshoptimizer@0.18.1: - resolution: {integrity: sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==} - dev: false - - /micromatch@4.0.5: - resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} - engines: {node: '>=8.6'} - dependencies: - braces: 3.0.2 - picomatch: 2.3.1 - dev: true - - /mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - dev: true - - /min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - dev: true - - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - dependencies: - brace-expansion: 1.1.11 - dev: true - - /minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - dev: true - - /mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - dev: false - - /mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - dependencies: - minimist: 1.2.8 - dev: true - - /mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - - /mrmime@2.0.0: - resolution: {integrity: sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==} - engines: {node: '>=10'} - - /ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - - /nanoid@3.3.7: - resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - /normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - dev: true - - /npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - dependencies: - path-key: 3.1.1 - dev: true - - /once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - dependencies: - wrappy: 1.0.2 - dev: true - - /onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - dependencies: - mimic-fn: 2.1.0 - dev: true - - /p-event@4.2.0: - resolution: {integrity: sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ==} - engines: {node: '>=8'} - dependencies: - p-timeout: 3.2.0 - dev: true - - /p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} - dev: true - - /p-timeout@3.2.0: - resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} - engines: {node: '>=8'} - dependencies: - p-finally: 1.0.0 - dev: true - - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - dependencies: - callsites: 3.1.0 - dev: true - - /path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - dev: true - - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true - - /periscopic@3.1.0: - resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} - dependencies: - '@types/estree': 1.0.5 - estree-walker: 3.0.3 - is-reference: 3.0.2 - - /picocolors@1.0.0: - resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - - /picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - dev: true - - /postcss@8.4.35: - resolution: {integrity: sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==} - engines: {node: ^10 || ^12 || >=14} - dependencies: - nanoid: 3.3.7 - picocolors: 1.0.0 - source-map-js: 1.0.2 - - /queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: true - - /readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - dependencies: - picomatch: 2.3.1 - dev: true - - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: false - - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true - - /reusify@1.0.4: - resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: true - - /rimraf@2.7.1: - resolution: {integrity: sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==} - hasBin: true - dependencies: - glob: 7.2.3 - dev: true - - /rollup@4.12.0: - resolution: {integrity: sha512-wz66wn4t1OHIJw3+XU7mJJQV/2NAfw5OAk6G6Hoo3zcvz/XOfQ52Vgi+AN4Uxoxi0KBBwk2g8zPrTDA4btSB/Q==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - dependencies: - '@types/estree': 1.0.5 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.12.0 - '@rollup/rollup-android-arm64': 4.12.0 - '@rollup/rollup-darwin-arm64': 4.12.0 - '@rollup/rollup-darwin-x64': 4.12.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.12.0 - '@rollup/rollup-linux-arm64-gnu': 4.12.0 - '@rollup/rollup-linux-arm64-musl': 4.12.0 - '@rollup/rollup-linux-riscv64-gnu': 4.12.0 - '@rollup/rollup-linux-x64-gnu': 4.12.0 - '@rollup/rollup-linux-x64-musl': 4.12.0 - '@rollup/rollup-win32-arm64-msvc': 4.12.0 - '@rollup/rollup-win32-ia32-msvc': 4.12.0 - '@rollup/rollup-win32-x64-msvc': 4.12.0 - fsevents: 2.3.3 - - /run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - dependencies: - queue-microtask: 1.2.3 - dev: true - - /sade@1.8.1: - resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} - engines: {node: '>=6'} - dependencies: - mri: 1.2.0 - - /sander@0.5.1: - resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} - dependencies: - es6-promise: 3.3.1 - graceful-fs: 4.2.11 - mkdirp: 0.5.6 - rimraf: 2.7.1 - dev: true - - /set-cookie-parser@2.6.0: - resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} - - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - dependencies: - shebang-regex: 3.0.0 - dev: true - - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true - - /signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: true - - /sirv@2.0.4: - resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} - engines: {node: '>= 10'} - dependencies: - '@polka/url': 1.0.0-next.24 - mrmime: 2.0.0 - totalist: 3.0.1 - - /sorcery@0.11.0: - resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} - hasBin: true - dependencies: - '@jridgewell/sourcemap-codec': 1.4.15 - buffer-crc32: 0.2.13 - minimist: 1.2.8 - sander: 0.5.1 - dev: true - - /source-map-js@1.0.2: - resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} - engines: {node: '>=0.10.0'} - - /strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - dev: true - - /strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - dependencies: - min-indent: 1.0.1 - dev: true - - /svelte-check@3.6.4(svelte@4.2.11): - resolution: {integrity: sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==} - hasBin: true - peerDependencies: - svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 - dependencies: - '@jridgewell/trace-mapping': 0.3.22 - chokidar: 3.6.0 - fast-glob: 3.3.2 - import-fresh: 3.3.0 - picocolors: 1.0.0 - sade: 1.8.1 - svelte: 4.2.11 - svelte-preprocess: 5.1.3(svelte@4.2.11)(typescript@5.3.3) - typescript: 5.3.3 - transitivePeerDependencies: - - '@babel/core' - - coffeescript - - less - - postcss - - postcss-load-config - - pug - - sass - - stylus - - sugarss - dev: true - - /svelte-hmr@0.15.3(svelte@4.2.11): - resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} - engines: {node: ^12.20 || ^14.13.1 || >= 16} - peerDependencies: - svelte: ^3.19.0 || ^4.0.0 - dependencies: - svelte: 4.2.11 - - /svelte-preprocess@5.1.3(svelte@4.2.11)(typescript@5.3.3): - resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==} - engines: {node: '>= 16.0.0', pnpm: ^8.0.0} - requiresBuild: true - peerDependencies: - '@babel/core': ^7.10.2 - coffeescript: ^2.5.1 - less: ^3.11.3 || ^4.0.0 - postcss: ^7 || ^8 - postcss-load-config: ^2.1.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 - pug: ^3.0.0 - sass: ^1.26.8 - stylus: ^0.55.0 - sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 - svelte: ^3.23.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0 - typescript: '>=3.9.5 || ^4.0.0 || ^5.0.0' - peerDependenciesMeta: - '@babel/core': - optional: true - coffeescript: - optional: true - less: - optional: true - postcss: - optional: true - postcss-load-config: - optional: true - pug: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - typescript: - optional: true - dependencies: - '@types/pug': 2.0.10 - detect-indent: 6.1.0 - magic-string: 0.30.7 - sorcery: 0.11.0 - strip-indent: 3.0.0 - svelte: 4.2.11 - typescript: 5.3.3 - dev: true - - /svelte@4.2.11: - resolution: {integrity: sha512-YIQk3J4X89wOLhjsqIW8tqY3JHPuBdtdOIkASP2PZeAMcSW9RsIjQzMesCrxOF3gdWYC0mKknlKF7OqmLM+Zqg==} - engines: {node: '>=16'} - dependencies: - '@ampproject/remapping': 2.2.1 - '@jridgewell/sourcemap-codec': 1.4.15 - '@jridgewell/trace-mapping': 0.3.22 - '@types/estree': 1.0.5 - acorn: 8.11.3 - aria-query: 5.3.0 - axobject-query: 4.0.0 - code-red: 1.0.4 - css-tree: 2.3.1 - estree-walker: 3.0.3 - is-reference: 3.0.2 - locate-character: 3.0.0 - magic-string: 0.30.7 - periscopic: 3.1.0 - - /three-mesh-bvh@0.7.3(three@0.159.0): - resolution: {integrity: sha512-3W6KjzmupjfE89GuHPT31kxKWZ4YGZPEZJNysJpiOZfQRsBQQgmK7v/VJPpjG6syhAvTnY+5Fr77EvIkTLpGSw==} - peerDependencies: - three: '>= 0.151.0' - dependencies: - three: 0.159.0 - dev: false - - /three-perf@1.0.10(three@0.159.0): - resolution: {integrity: sha512-lCur/i8U6m0ysWYhQ1yFGWOZB0QA2oVsDsfynYd65HhXxLxJfiAt8OsXmpv9PnTLacfaZclBcZHUOB9QKk3eaw==} - peerDependencies: - three: '>=0.151' - dependencies: - three: 0.159.0 - troika-three-text: 0.47.2(three@0.159.0) - tweakpane: 3.1.10 - dev: false - - /three@0.159.0: - resolution: {integrity: sha512-eCmhlLGbBgucuo4VEA9IO3Qpc7dh8Bd4VKzr7WfW4+8hMcIfoAVi1ev0pJYN9PTTsCslbcKgBwr2wNZ1EvLInA==} - dev: false - - /tiny-glob@0.2.9: - resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} - dependencies: - globalyzer: 0.1.0 - globrex: 0.1.2 - - /to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - dependencies: - is-number: 7.0.0 - dev: true - - /totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - - /troika-three-text@0.47.2(three@0.159.0): - resolution: {integrity: sha512-qylT0F+U7xGs+/PEf3ujBdJMYWbn0Qci0kLqI5BJG2kW1wdg4T1XSxneypnF05DxFqJhEzuaOR9S2SjiyknMng==} - peerDependencies: - three: '>=0.125.0' - dependencies: - bidi-js: 1.0.3 - three: 0.159.0 - troika-three-utils: 0.47.2(three@0.159.0) - troika-worker-utils: 0.47.2 - webgl-sdf-generator: 1.1.1 - dev: false - - /troika-three-text@0.49.0(three@0.159.0): - resolution: {integrity: sha512-sn9BNC6eIX8OO3iAkPwjecJ7Pn21Ve8P1UNFMNeQzXx759rrqS4i4pSZs7FLMYdWyCKVXBFGimBySFwRKLjq/Q==} - peerDependencies: - three: '>=0.125.0' - dependencies: - bidi-js: 1.0.3 - three: 0.159.0 - troika-three-utils: 0.49.0(three@0.159.0) - troika-worker-utils: 0.49.0 - webgl-sdf-generator: 1.1.1 - dev: false - - /troika-three-utils@0.47.2(three@0.159.0): - resolution: {integrity: sha512-/28plhCxfKtH7MSxEGx8e3b/OXU5A0xlwl+Sbdp0H8FXUHKZDoksduEKmjQayXYtxAyuUiCRunYIv/8Vi7aiyg==} - peerDependencies: - three: '>=0.125.0' - dependencies: - three: 0.159.0 - dev: false - - /troika-three-utils@0.49.0(three@0.159.0): - resolution: {integrity: sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==} - peerDependencies: - three: '>=0.125.0' - dependencies: - three: 0.159.0 - dev: false - - /troika-worker-utils@0.47.2: - resolution: {integrity: sha512-mzss4MeyzUkYBppn4x5cdAqrhBHFEuVmMMgLMTyFV23x6GvQMyo+/R5E5Lsbrt7WSt5RfvewjcwD1DChRTA9lA==} - dev: false - - /troika-worker-utils@0.49.0: - resolution: {integrity: sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg==} - dev: false - - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} - dev: true - - /tweakpane@3.1.10: - resolution: {integrity: sha512-rqwnl/pUa7+inhI2E9ayGTqqP0EPOOn/wVvSWjZsRbZUItzNShny7pzwL3hVlaN4m9t/aZhsP0aFQ9U5VVR2VQ==} - dev: false - - /typescript@5.3.3: - resolution: {integrity: sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==} - engines: {node: '>=14.17'} - hasBin: true - dev: true - - /vite@5.1.4: - resolution: {integrity: sha512-n+MPqzq+d9nMVTKyewqw6kSt+R3CkvF9QAKY8obiQn8g1fwTscKxyfaYnC632HtBXAQGc1Yjomphwn1dtwGAHg==} - engines: {node: ^18.0.0 || >=20.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || >=20.0.0 - less: '*' - lightningcss: ^1.21.0 - sass: '*' - stylus: '*' - sugarss: '*' - terser: ^5.4.0 - peerDependenciesMeta: - '@types/node': - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - dependencies: - esbuild: 0.19.12 - postcss: 8.4.35 - rollup: 4.12.0 - optionalDependencies: - fsevents: 2.3.3 - - /vitefu@0.2.5(vite@5.1.4): - resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - vite: - optional: true - dependencies: - vite: 5.1.4 - - /webgl-sdf-generator@1.1.1: - resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==} - dev: false - - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - dependencies: - isexe: 2.0.0 - dev: true - - /wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - dev: true - - /yoga-layout@2.0.1: - resolution: {integrity: sha512-tT/oChyDXelLo2A+UVnlW9GU7CsvFMaEnd9kVFsaiCQonFAXd3xrHhkLYu+suwwosrAEQ746xBU+HvYtm1Zs2Q==} - dev: false From edbc71ed8f82e72ec2b679fd39d2dbed96be2091 Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:31:27 +0100 Subject: [PATCH 04/14] add dprint config --- .dprint.jsonc | 59 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 .dprint.jsonc diff --git a/.dprint.jsonc b/.dprint.jsonc new file mode 100644 index 0000000..ac227f6 --- /dev/null +++ b/.dprint.jsonc @@ -0,0 +1,59 @@ +{ + "$schema": "https://dprint.dev/schemas/v0.json", + "indentWidth": 2, + "typescript": { + // https://dprint.dev/plugins/typescript/config/ + "quoteStyle": "preferSingle", + "trailingCommas": "never" + }, + "json": { + }, + "markdown": { + }, + "toml": { + }, + "dockerfile": { + }, + "ruff": { + }, + "jupyter": { + }, + "malva": { + }, + "markup": { + }, + "yaml": { + }, + "graphql": { + }, + "exec": { + "cwd": "${configDir}", + "commands": [{ + "command": "rustfmt --edition 2024", + "exts": ["rs"], + // add the config files for automatic cache invalidation when the rust version or rustfmt config changes + "cacheKeyFiles": [ + "rustfmt.toml", + "rust-toolchain.toml" + ] + }] + }, + "excludes": [ + "**/node_modules", + "**/*-lock.json" + ], + "plugins": [ + "https://plugins.dprint.dev/typescript-0.95.13.wasm", + "https://plugins.dprint.dev/json-0.21.1.wasm", + "https://plugins.dprint.dev/markdown-0.20.0.wasm", + "https://plugins.dprint.dev/toml-0.7.0.wasm", + "https://plugins.dprint.dev/dockerfile-0.3.3.wasm", + "https://plugins.dprint.dev/ruff-0.6.11.wasm", + "https://plugins.dprint.dev/jupyter-0.2.1.wasm", + "https://plugins.dprint.dev/g-plane/malva-v0.15.1.wasm", + "https://plugins.dprint.dev/g-plane/markup_fmt-v0.25.3.wasm", + "https://plugins.dprint.dev/g-plane/pretty_yaml-v0.5.1.wasm", + "https://plugins.dprint.dev/g-plane/pretty_graphql-v0.2.3.wasm", + "https://plugins.dprint.dev/exec-0.6.0.json@a054130d458f124f9b5c91484833828950723a5af3f8ff2bd1523bd47b83b364" + ] +} From 0bd00b0192520e608f3834265c4dbecce86cbf03 Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:32:19 +0100 Subject: [PATCH 05/14] feat(app): add description and input debug info to node params --- app/src/lib/graph-interface/node/NodeParameter.svelte | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/src/lib/graph-interface/node/NodeParameter.svelte b/app/src/lib/graph-interface/node/NodeParameter.svelte index c7695c7..9244644 100644 --- a/app/src/lib/graph-interface/node/NodeParameter.svelte +++ b/app/src/lib/graph-interface/node/NodeParameter.svelte @@ -73,8 +73,14 @@ {#key id && graphId}
{#if inputType.label !== ""} - + {/if} + {#if inputType.external !== true} {/if} @@ -181,9 +187,6 @@ .content.disabled { opacity: 0.2; } - .content.disabled > * { - pointer-events: none; - } .disabled svg path { d: var(--hover-path-disabled) !important; From 03102fdc75927083f304fa8f39d43ac348c6d76a Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:33:24 +0100 Subject: [PATCH 06/14] ci: improve dev setup --- docs/DEVELOPING_NODES.md | 10 +- package.json | 5 +- packages/ui/package.json | 3 +- pnpm-lock.yaml | 404 +++++++++++++++++++++++++++++++++++++-- 4 files changed, 404 insertions(+), 18 deletions(-) diff --git a/docs/DEVELOPING_NODES.md b/docs/DEVELOPING_NODES.md index 45a6f15..3376151 100644 --- a/docs/DEVELOPING_NODES.md +++ b/docs/DEVELOPING_NODES.md @@ -4,7 +4,7 @@ This guide will help you developing your first Nodarium Node written in Rust. As ## Prerequesites -You need to have [Rust](https://www.rust-lang.org/tools/install) and [wasm-pack](https://rustwasm.github.io/wasm-pack/book/) installed. Rust is the language we are going to develop our node in and wasm-pack helps us compile our rust code into a webassembly file. +You need to have [Rust](https://www.rust-lang.org/tools/install) and [wasm-pack](https://rustwasm.github.io/docs/wasm-pack/) installed. Rust is the language we are going to develop our node in and wasm-pack helps us compile our rust code into a webassembly file. ```bash # install rust @@ -22,11 +22,12 @@ cd my-new-node ## Setup Definition -Now we create the definition file of the node. +Now we create the definition file of the node. Here we define what kind of inputs our node will expect and what kind of output it produces. If you want to dive deeper into this topic, have a look at [NODE_DEFINITION.md](./NODE_DEFINITION.md). `src/definition.json` -```json + +```json { "id": "my-name/my-namespace/zylinder-node", "outputs": [ @@ -35,7 +36,7 @@ Here we define what kind of inputs our node will expect and what kind of output "inputs": { "height": { "type": "float", - "value": 2, + "value": 2 }, "radius": { "type": "float", @@ -44,6 +45,7 @@ Here we define what kind of inputs our node will expect and what kind of output } } ``` + If we take a look at the `src/lib.rs` file we see that `src/definition.json` is included with the following line: ```rust diff --git a/package.json b/package.json index ad06e21..11efdcd 100644 --- a/package.json +++ b/package.json @@ -4,9 +4,10 @@ "build:story": "pnpm -r --filter 'ui' story:build", "build:app": "BASE_PATH=/ui pnpm -r --filter 'ui' build && pnpm -r --filter 'app' build", "build:nodes": "pnpm -r --filter './nodes/**' build", - "dev:nodes": "pnpm -r --parallel --filter './nodes/**' dev", "build:deploy": "pnpm build", - "dev": "pnpm -r --filter 'app' --filter './packages/node-registry' dev" + "dev:all": "pnpm -r dev", + "dev:nodes": "pnpm -r --parallel --filter './nodes/**' dev", + "dev": "pnpm -r --filter 'app' --filter './packages/ui' dev" }, "packageManager": "pnpm@10.24.0" } diff --git a/packages/ui/package.json b/packages/ui/package.json index 9eccefd..c7e1c83 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,7 +2,7 @@ "name": "@nodarium/ui", "version": "0.0.1", "scripts": { - "dev": "vite dev", + "dev": "chokidar './src/**' --initial -c 'pnpm build'", "build": "vite build && npm run package", "preview": "vite preview", "package": "svelte-kit sync && svelte-package && publint", @@ -37,6 +37,7 @@ "@types/three": "^0.182.0", "@typescript-eslint/eslint-plugin": "^8.53.0", "@typescript-eslint/parser": "^8.53.0", + "chokidar-cli": "^3.0.0", "eslint": "^9.39.2", "eslint-plugin-svelte": "^3.14.0", "publint": "^0.3.16", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dbc3f1e..cda2a5f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: specifier: link:../packages/registry version: link:../packages/registry '@nodarium/ui': - specifier: link:../packages/ui + specifier: ../packages/ui version: link:../packages/ui '@nodarium/utils': specifier: link:../packages/utils @@ -24,7 +24,7 @@ importers: version: 2.50.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.46.4)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.46.4)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) '@tailwindcss/vite': specifier: ^4.1.18 - version: 4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) + version: 4.1.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) '@threlte/core': specifier: 8.3.1 version: 8.3.1(svelte@5.46.4)(three@0.182.0) @@ -88,7 +88,7 @@ importers: version: 5.9.3 vite: specifier: ^7.3.1 - version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + version: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) vite-plugin-comlink: specifier: ^5.3.0 version: 5.3.0(comlink@4.4.2)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) @@ -100,7 +100,7 @@ importers: version: 3.5.0(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) vitest: specifier: ^4.0.17 - version: 4.0.17(@types/node@22.8.6)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + version: 4.0.17(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) nodes/max/plantarium/box: {} @@ -194,6 +194,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.53.0 version: 8.53.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + chokidar-cli: + specifier: ^3.0.0 + version: 3.0.0 eslint: specifier: ^9.39.2 version: 9.39.2(jiti@2.6.1) @@ -1245,10 +1248,22 @@ packages: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} + ansi-regex@4.1.1: + resolution: {integrity: sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==} + engines: {node: '>=6'} + + ansi-styles@3.2.1: + resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} + engines: {node: '>=4'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + arg@4.1.3: resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} @@ -1276,6 +1291,10 @@ packages: bidi-js@1.0.3: resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} @@ -1285,6 +1304,10 @@ packages: brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} @@ -1308,6 +1331,10 @@ packages: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + camera-controls@3.1.2: resolution: {integrity: sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==} engines: {node: '>=22.0.0', npm: '>=10.5.1'} @@ -1322,6 +1349,15 @@ packages: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} + chokidar-cli@3.0.0: + resolution: {integrity: sha512-xVW+Qeh7z15uZRxHOkP93Ux8A0xbPzwK4GaqD8dQOYc34TlkqUhVSS59fK36DOp5WdJlrRzlYSy02Ht99FjZqQ==} + engines: {node: '>= 8.10.0'} + hasBin: true + + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + chokidar@4.0.3: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} @@ -1333,14 +1369,23 @@ packages: citty@0.1.6: resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + cliui@5.0.0: + resolution: {integrity: sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} + color-convert@1.9.3: + resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} + color-name@1.1.3: + resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -1434,6 +1479,10 @@ packages: supports-color: optional: true + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} @@ -1507,6 +1556,9 @@ packages: earcut@2.2.4: resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} + emoji-regex@7.0.3: + resolution: {integrity: sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==} + enhanced-resolve@5.18.4: resolution: {integrity: sha512-LgQMM4WXU3QI+SYgEc2liRgznaD5ojbmY3sb8LxyguVkIg5FxdpTkvk72te2R38/TGKxH634oLxXRGY6d7AP+Q==} engines: {node: '>=10.13.0'} @@ -1655,6 +1707,14 @@ packages: file-saver@2.0.5: resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} @@ -1678,6 +1738,10 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} @@ -1693,6 +1757,10 @@ packages: resolution: {integrity: sha512-L5bGsVkxJbJgdnwyuheIunkGatUF/zssUoxxjACCseZYAVbaqdh9Tsmmlkl8vYan09H7sbvKt4pS8GqKLBrEzA==} hasBin: true + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} @@ -1771,6 +1839,10 @@ packages: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + is-docker@3.0.0: resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -1780,6 +1852,10 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + is-fullwidth-code-point@2.0.0: + resolution: {integrity: sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==} + engines: {node: '>=4'} + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1793,6 +1869,10 @@ packages: engines: {node: '>=14.16'} hasBin: true + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + is-potential-custom-element-name@1.0.1: resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} @@ -1941,13 +2021,23 @@ packages: locate-character@3.0.0: resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -2046,6 +2136,10 @@ packages: node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} @@ -2071,14 +2165,26 @@ packages: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + p-limit@3.1.0: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + package-manager-detector@1.6.0: resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} @@ -2093,6 +2199,10 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2110,6 +2220,10 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + picomatch@4.0.3: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} @@ -2179,6 +2293,10 @@ packages: rc9@2.1.2: resolution: {integrity: sha512-btXCnMmRIBINM2LDZoEmOogIZU7Qe7zn4BpomSKZ/ykbLObuBdvG+mFq11DL6fjH1DRwHhrlgtYWG96bJiC7Cg==} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + readdirp@4.1.2: resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} engines: {node: '>= 14.18.0'} @@ -2187,10 +2305,17 @@ packages: resolution: {integrity: sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==} engines: {node: '>= 20.19.0'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + require-from-string@2.0.2: resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} engines: {node: '>=0.10.0'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2245,6 +2370,9 @@ packages: engines: {node: '>=10'} hasBin: true + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + set-cookie-parser@2.7.2: resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} @@ -2284,6 +2412,14 @@ packages: std-env@3.10.0: resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + string-width@3.1.0: + resolution: {integrity: sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==} + engines: {node: '>=6'} + + strip-ansi@5.2.0: + resolution: {integrity: sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==} + engines: {node: '>=6'} + strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2384,6 +2520,10 @@ packages: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} @@ -2594,6 +2734,9 @@ packages: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} engines: {node: '>=18'} + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2608,6 +2751,10 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} + wrap-ansi@5.1.0: + resolution: {integrity: sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==} + engines: {node: '>=6'} + ws@8.19.0: resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} engines: {node: '>=10.0.0'} @@ -2631,10 +2778,19 @@ packages: xmlchars@2.2.0: resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + yargs-parser@13.1.2: + resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==} + + yargs@13.3.2: + resolution: {integrity: sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==} + yn@3.1.1: resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} engines: {node: '>=6'} @@ -3200,7 +3356,7 @@ snapshots: set-cookie-parser: 2.7.2 sirv: 3.0.2 svelte: 5.46.4 - vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) optionalDependencies: typescript: 5.9.3 @@ -3227,7 +3383,7 @@ snapshots: '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.46.4)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) obug: 2.1.1 svelte: 5.46.4 - vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.46.4)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))': dependencies: @@ -3246,8 +3402,8 @@ snapshots: magic-string: 0.30.21 obug: 2.1.1 svelte: 5.46.4 - vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - vitefu: 1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vitefu: 1.1.1(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) '@tailwindcss/node@4.1.18': dependencies: @@ -3317,6 +3473,13 @@ snapshots: tailwindcss: 4.1.18 vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + '@tailwindcss/vite@4.1.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))': + dependencies: + '@tailwindcss/node': 4.1.18 + '@tailwindcss/oxide': 4.1.18 + tailwindcss: 4.1.18 + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + '@threejs-kit/instanced-sprite-mesh@2.5.1(@types/three@0.182.0)(three@0.182.0)': dependencies: diet-sprite: 0.0.1 @@ -3510,6 +3673,14 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + '@vitest/mocker@4.0.17(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))': + dependencies: + '@vitest/spy': 4.0.17 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + '@vitest/pretty-format@4.0.17': dependencies: tinyrainbow: 3.0.3 @@ -3557,10 +3728,21 @@ snapshots: ansi-colors@4.1.3: {} + ansi-regex@4.1.1: {} + + ansi-styles@3.2.1: + dependencies: + color-convert: 1.9.3 + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + arg@4.1.3: optional: true @@ -3581,6 +3763,8 @@ snapshots: dependencies: require-from-string: 2.0.2 + binary-extensions@2.3.0: {} + boolbase@1.0.0: {} brace-expansion@1.1.12: @@ -3592,6 +3776,10 @@ snapshots: dependencies: balanced-match: 1.0.2 + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + buffer-from@1.1.2: optional: true @@ -3622,6 +3810,8 @@ snapshots: callsites@3.1.0: {} + camelcase@5.3.1: {} + camera-controls@3.1.2(three@0.182.0): dependencies: three: 0.182.0 @@ -3633,6 +3823,25 @@ snapshots: ansi-styles: 4.3.0 supports-color: 7.2.0 + chokidar-cli@3.0.0: + dependencies: + chokidar: 3.6.0 + lodash.debounce: 4.0.8 + lodash.throttle: 4.1.1 + yargs: 13.3.2 + + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.3 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + chokidar@4.0.3: dependencies: readdirp: 4.1.2 @@ -3645,12 +3854,24 @@ snapshots: dependencies: consola: 3.4.2 + cliui@5.0.0: + dependencies: + string-width: 3.1.0 + strip-ansi: 5.2.0 + wrap-ansi: 5.1.0 + clsx@2.1.1: {} + color-convert@1.9.3: + dependencies: + color-name: 1.1.3 + color-convert@2.0.1: dependencies: color-name: 1.1.4 + color-name@1.1.3: {} + color-name@1.1.4: {} color-support@1.1.3: {} @@ -3735,6 +3956,8 @@ snapshots: dependencies: ms: 2.1.3 + decamelize@1.2.0: {} + decimal.js@10.6.0: optional: true @@ -3798,6 +4021,8 @@ snapshots: earcut@2.2.4: {} + emoji-regex@7.0.3: {} + enhanced-resolve@5.18.4: dependencies: graceful-fs: 4.2.11 @@ -4014,6 +4239,14 @@ snapshots: file-saver@2.0.5: {} + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + find-up@5.0.0: dependencies: locate-path: 6.0.0 @@ -4041,6 +4274,8 @@ snapshots: function-bind@1.1.2: optional: true + get-caller-file@2.0.5: {} + get-intrinsic@1.3.0: dependencies: call-bind-apply-helpers: 1.0.2 @@ -4075,6 +4310,10 @@ snapshots: nypm: 0.6.2 pathe: 2.0.3 + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + glob-parent@6.0.2: dependencies: is-glob: 4.0.3 @@ -4148,10 +4387,16 @@ snapshots: imurmurhash@0.1.4: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + is-docker@3.0.0: {} is-extglob@2.1.1: {} + is-fullwidth-code-point@2.0.0: {} + is-glob@4.0.3: dependencies: is-extglob: 2.1.1 @@ -4162,6 +4407,8 @@ snapshots: dependencies: is-docker: 3.0.0 + is-number@7.0.0: {} + is-potential-custom-element-name@1.0.1: optional: true @@ -4306,12 +4553,21 @@ snapshots: locate-character@3.0.0: {} + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + locate-path@6.0.0: dependencies: p-locate: 5.0.0 + lodash.debounce@4.0.8: {} + lodash.merge@4.6.2: {} + lodash.throttle@4.1.1: {} + lodash@4.17.21: {} lru-cache@10.4.3: @@ -4399,6 +4655,8 @@ snapshots: node-fetch-native@1.6.7: {} + normalize-path@3.0.0: {} + nth-check@2.1.1: dependencies: boolbase: 1.0.0 @@ -4436,14 +4694,24 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-try@2.2.0: {} + package-manager-detector@1.6.0: {} parent-module@1.0.1: @@ -4458,6 +4726,8 @@ snapshots: entities: 6.0.1 optional: true + path-exists@3.0.0: {} + path-exists@4.0.0: {} path-key@3.1.1: {} @@ -4468,6 +4738,8 @@ snapshots: picocolors@1.1.1: {} + picomatch@2.3.1: {} + picomatch@4.0.3: {} pify@4.0.1: @@ -4533,12 +4805,20 @@ snapshots: defu: 6.1.4 destr: 2.0.5 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + readdirp@4.1.2: {} readdirp@5.0.0: {} + require-directory@2.1.1: {} + require-from-string@2.0.2: {} + require-main-filename@2.0.0: {} + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: @@ -4613,6 +4893,8 @@ snapshots: semver@7.7.3: {} + set-blocking@2.0.0: {} + set-cookie-parser@2.7.2: {} shebang-command@2.0.0: @@ -4646,6 +4928,16 @@ snapshots: std-env@3.10.0: {} + string-width@3.1.0: + dependencies: + emoji-regex: 7.0.3 + is-fullwidth-code-point: 2.0.0 + strip-ansi: 5.2.0 + + strip-ansi@5.2.0: + dependencies: + ansi-regex: 4.1.1 + strip-json-comments@3.1.1: {} supports-color@7.2.0: @@ -4765,6 +5057,10 @@ snapshots: tldts-core: 6.1.86 optional: true + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + totalist@3.0.1: {} tough-cookie@5.1.2: @@ -4852,18 +5148,18 @@ snapshots: json5: 2.2.3 magic-string: 0.30.17 source-map: 0.7.6 - vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) vite-plugin-glsl@1.5.5(@rollup/pluginutils@5.1.4(rollup@4.55.1))(esbuild@0.27.2)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): dependencies: - vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) optionalDependencies: '@rollup/pluginutils': 5.1.4(rollup@4.55.1) esbuild: 0.27.2 vite-plugin-wasm@3.5.0(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): dependencies: - vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): dependencies: @@ -4883,10 +5179,31 @@ snapshots: terser: 5.36.0 tsx: 4.19.2 + vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): + dependencies: + esbuild: 0.27.2 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.55.1 + tinyglobby: 0.2.15 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.6.1 + less: 4.2.0 + lightningcss: 1.30.2 + sass: 1.80.6 + terser: 5.36.0 + tsx: 4.19.2 + vitefu@1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): optionalDependencies: vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vitefu@1.1.1(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): + optionalDependencies: + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vitest@4.0.17(@types/node@22.8.6)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): dependencies: '@vitest/expect': 4.0.17 @@ -4925,6 +5242,43 @@ snapshots: - tsx - yaml + vitest@4.0.17(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): + dependencies: + '@vitest/expect': 4.0.17 + '@vitest/mocker': 4.0.17(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) + '@vitest/pretty-format': 4.0.17 + '@vitest/runner': 4.0.17 + '@vitest/snapshot': 4.0.17 + '@vitest/spy': 4.0.17 + '@vitest/utils': 4.0.17 + es-module-lexer: 1.7.0 + expect-type: 1.3.0 + magic-string: 0.30.21 + obug: 2.1.1 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 1.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 3.0.3 + vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + why-is-node-running: 2.3.0 + optionalDependencies: + jsdom: 25.0.1 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - terser + - tsx + - yaml + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 @@ -4949,6 +5303,8 @@ snapshots: webidl-conversions: 7.0.0 optional: true + which-module@2.0.1: {} + which@2.0.2: dependencies: isexe: 2.0.0 @@ -4960,6 +5316,12 @@ snapshots: word-wrap@1.2.5: {} + wrap-ansi@5.1.0: + dependencies: + ansi-styles: 3.2.1 + string-width: 3.1.0 + strip-ansi: 5.2.0 + ws@8.19.0: optional: true @@ -4974,8 +5336,28 @@ snapshots: xmlchars@2.2.0: optional: true + y18n@4.0.3: {} + yaml@1.10.2: {} + yargs-parser@13.1.2: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs@13.3.2: + dependencies: + cliui: 5.0.0 + find-up: 3.0.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 3.1.0 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 13.1.2 + yn@3.1.1: optional: true From ecfd4d5f2fa04174fbe78c0d9a278fa5bb0998bc Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:43:07 +0100 Subject: [PATCH 07/14] feat(ui): cleanup integer input remove warnings, migrate deprecated (dispatch to prop), include min max switch from float input, include esc/enter from float input, include precision, include partial styling from float input --- packages/ui/src/lib/inputs/Integer.svelte | 73 +++++++++++++++++------ 1 file changed, 54 insertions(+), 19 deletions(-) diff --git a/packages/ui/src/lib/inputs/Integer.svelte b/packages/ui/src/lib/inputs/Integer.svelte index 800115e..083e621 100644 --- a/packages/ui/src/lib/inputs/Integer.svelte +++ b/packages/ui/src/lib/inputs/Integer.svelte @@ -1,41 +1,48 @@ {#if input.type === 'float'} @@ -20,9 +22,9 @@ {:else if input.type === 'integer'} {:else if input.type === 'boolean'} - + {:else if input.type === 'select'} - {:else if input.type === 'vec3'} - + {/if} diff --git a/packages/ui/src/lib/inputs/Checkbox.svelte b/packages/ui/src/lib/inputs/Checkbox.svelte index 7505dcb..f938851 100644 --- a/packages/ui/src/lib/inputs/Checkbox.svelte +++ b/packages/ui/src/lib/inputs/Checkbox.svelte @@ -1,9 +1,10 @@ + +
+
+ + + +
+
+ +
+
+ + From c46bf9e64fdf332a98cd2d733f3d2b80da67f283 Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Mon, 19 Jan 2026 16:57:54 +0100 Subject: [PATCH 09/14] ci: fix lockfile --- pnpm-lock.yaml | 95 ++++++-------------------------------------------- 1 file changed, 11 insertions(+), 84 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index cda2a5f..4226492 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,7 +14,7 @@ importers: specifier: link:../packages/registry version: link:../packages/registry '@nodarium/ui': - specifier: ../packages/ui + specifier: link:../packages/ui version: link:../packages/ui '@nodarium/utils': specifier: link:../packages/utils @@ -24,7 +24,7 @@ importers: version: 2.50.0(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.46.4)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)))(svelte@5.46.4)(typescript@5.9.3)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) '@tailwindcss/vite': specifier: ^4.1.18 - version: 4.1.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) + version: 4.1.18(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) '@threlte/core': specifier: 8.3.1 version: 8.3.1(svelte@5.46.4)(three@0.182.0) @@ -88,7 +88,7 @@ importers: version: 5.9.3 vite: specifier: ^7.3.1 - version: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + version: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) vite-plugin-comlink: specifier: ^5.3.0 version: 5.3.0(comlink@4.4.2)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) @@ -100,7 +100,7 @@ importers: version: 3.5.0(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) vitest: specifier: ^4.0.17 - version: 4.0.17(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + version: 4.0.17(@types/node@22.8.6)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) nodes/max/plantarium/box: {} @@ -3356,7 +3356,7 @@ snapshots: set-cookie-parser: 2.7.2 sirv: 3.0.2 svelte: 5.46.4 - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) optionalDependencies: typescript: 5.9.3 @@ -3383,7 +3383,7 @@ snapshots: '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.46.4)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) obug: 2.1.1 svelte: 5.46.4 - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.46.4)(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))': dependencies: @@ -3402,8 +3402,8 @@ snapshots: magic-string: 0.30.21 obug: 2.1.1 svelte: 5.46.4 - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - vitefu: 1.1.1(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) + vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vitefu: 1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) '@tailwindcss/node@4.1.18': dependencies: @@ -3473,13 +3473,6 @@ snapshots: tailwindcss: 4.1.18 vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - '@tailwindcss/vite@4.1.18(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))': - dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - '@threejs-kit/instanced-sprite-mesh@2.5.1(@types/three@0.182.0)(three@0.182.0)': dependencies: diet-sprite: 0.0.1 @@ -3673,14 +3666,6 @@ snapshots: optionalDependencies: vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - '@vitest/mocker@4.0.17(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2))': - dependencies: - '@vitest/spy': 4.0.17 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - '@vitest/pretty-format@4.0.17': dependencies: tinyrainbow: 3.0.3 @@ -5148,18 +5133,18 @@ snapshots: json5: 2.2.3 magic-string: 0.30.17 source-map: 0.7.6 - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) vite-plugin-glsl@1.5.5(@rollup/pluginutils@5.1.4(rollup@4.55.1))(esbuild@0.27.2)(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): dependencies: - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) optionalDependencies: '@rollup/pluginutils': 5.1.4(rollup@4.55.1) esbuild: 0.27.2 vite-plugin-wasm@3.5.0(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): dependencies: - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) + vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): dependencies: @@ -5179,31 +5164,10 @@ snapshots: terser: 5.36.0 tsx: 4.19.2 - vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): - dependencies: - esbuild: 0.27.2 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.55.1 - tinyglobby: 0.2.15 - optionalDependencies: - fsevents: 2.3.3 - jiti: 2.6.1 - less: 4.2.0 - lightningcss: 1.30.2 - sass: 1.80.6 - terser: 5.36.0 - tsx: 4.19.2 - vitefu@1.1.1(vite@7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): optionalDependencies: vite: 7.3.1(@types/node@22.8.6)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - vitefu@1.1.1(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)): - optionalDependencies: - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - vitest@4.0.17(@types/node@22.8.6)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): dependencies: '@vitest/expect': 4.0.17 @@ -5242,43 +5206,6 @@ snapshots: - tsx - yaml - vitest@4.0.17(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2): - dependencies: - '@vitest/expect': 4.0.17 - '@vitest/mocker': 4.0.17(vite@7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2)) - '@vitest/pretty-format': 4.0.17 - '@vitest/runner': 4.0.17 - '@vitest/snapshot': 4.0.17 - '@vitest/spy': 4.0.17 - '@vitest/utils': 4.0.17 - es-module-lexer: 1.7.0 - expect-type: 1.3.0 - magic-string: 0.30.21 - obug: 2.1.1 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(jiti@2.6.1)(less@4.2.0)(lightningcss@1.30.2)(sass@1.80.6)(terser@5.36.0)(tsx@4.19.2) - why-is-node-running: 2.3.0 - optionalDependencies: - jsdom: 25.0.1 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml - w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 From a8c76a846e38fb2c7ecb42212902f5c003313fea Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Tue, 20 Jan 2026 15:19:39 +0100 Subject: [PATCH 10/14] fmt: ignore pnpm-lock.YAML --- .dprint.jsonc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.dprint.jsonc b/.dprint.jsonc index ac227f6..acb637a 100644 --- a/.dprint.jsonc +++ b/.dprint.jsonc @@ -40,7 +40,7 @@ }, "excludes": [ "**/node_modules", - "**/*-lock.json" + "**/*-lock.yaml" ], "plugins": [ "https://plugins.dprint.dev/typescript-0.95.13.wasm", From 3e3d41ae98856ceba9a3b7773aeb6a6a8af1121a Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:23:21 +0100 Subject: [PATCH 11/14] feat: open keyboard shortcuts with ? --- app/src/lib/graph-interface/keymaps.ts | 103 +++++++++++------------ app/src/lib/sidebar/Panel.svelte | 6 +- app/src/lib/sidebar/PanelState.svelte.ts | 19 +++-- app/src/lib/sidebar/Sidebar.svelte | 7 +- 4 files changed, 65 insertions(+), 70 deletions(-) diff --git a/app/src/lib/graph-interface/keymaps.ts b/app/src/lib/graph-interface/keymaps.ts index 667dbfd..9fd9b54 100644 --- a/app/src/lib/graph-interface/keymaps.ts +++ b/app/src/lib/graph-interface/keymaps.ts @@ -1,16 +1,15 @@ -import { animate, lerp } from "$lib/helpers"; -import type { createKeyMap } from "$lib/helpers/createKeyMap"; -import FileSaver from "file-saver"; -import type { GraphManager } from "./graph-manager.svelte"; -import type { GraphState } from "./graph-state.svelte"; +import { animate, lerp } from '$lib/helpers'; +import type { createKeyMap } from '$lib/helpers/createKeyMap'; +import { panelState } from '$lib/sidebar/PanelState.svelte'; +import FileSaver from 'file-saver'; +import type { GraphManager } from './graph-manager.svelte'; +import type { GraphState } from './graph-state.svelte'; type Keymap = ReturnType; export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: GraphState) { - - keymap.addShortcut({ - key: "l", - description: "Select linked nodes", + key: 'l', + description: 'Select linked nodes', callback: () => { const activeNode = graph.getNode(graphState.activeNodeId); if (activeNode) { @@ -20,56 +19,54 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr graphState.selectedNodes.add(node.id); } } - }, + } }); - keymap.addShortcut({ - key: "?", - description: "Toggle Help", + key: '?', + description: 'Toggle Help', callback: () => { - // TODO: fix this - // showHelp = !showHelp; - }, + panelState.setActivePanel('shortcuts'); + } }); keymap.addShortcut({ - key: "c", + key: 'c', ctrl: true, - description: "Copy active nodes", - callback: () => graphState.copyNodes(), + description: 'Copy active nodes', + callback: () => graphState.copyNodes() }); keymap.addShortcut({ - key: "v", + key: 'v', ctrl: true, - description: "Paste nodes", - callback: () => graphState.pasteNodes(), + description: 'Paste nodes', + callback: () => graphState.pasteNodes() }); keymap.addShortcut({ - key: "Escape", - description: "Deselect nodes", + key: 'Escape', + description: 'Deselect nodes', callback: () => { graphState.activeNodeId = -1; graphState.clearSelection(); graphState.edgeEndPosition = null; (document.activeElement as HTMLElement)?.blur(); - }, + } }); keymap.addShortcut({ - key: "A", + key: 'A', shift: true, - description: "Add new Node", + description: 'Add new Node', callback: () => { graphState.addMenuPosition = [graphState.mousePosition[0], graphState.mousePosition[1]]; - }, + } }); keymap.addShortcut({ - key: ".", - description: "Center camera", + key: '.', + description: 'Center camera', callback: () => { if (!graphState.isBodyFocused()) return; @@ -90,67 +87,67 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr animate(500, (a: number) => { graphState.cameraPosition[0] = lerp(camX, average[0], ease(a)); graphState.cameraPosition[1] = lerp(camY, average[1], ease(a)); - graphState.cameraPosition[2] = lerp(camZ, 2, ease(a)) + graphState.cameraPosition[2] = lerp(camZ, 2, ease(a)); if (graphState.mouseDown) return false; }); - }, + } }); keymap.addShortcut({ - key: "a", + key: 'a', ctrl: true, preventDefault: true, - description: "Select all nodes", + description: 'Select all nodes', callback: () => { if (!graphState.isBodyFocused()) return; for (const node of graph.nodes.keys()) { graphState.selectedNodes.add(node); } - }, + } }); keymap.addShortcut({ - key: "z", + key: 'z', ctrl: true, - description: "Undo", + description: 'Undo', callback: () => { if (!graphState.isBodyFocused()) return; graph.undo(); for (const node of graph.nodes.values()) { graphState.updateNodePosition(node); } - }, + } }); keymap.addShortcut({ - key: "y", + key: 'y', ctrl: true, - description: "Redo", + description: 'Redo', callback: () => { graph.redo(); for (const node of graph.nodes.values()) { graphState.updateNodePosition(node); } - }, + } }); keymap.addShortcut({ - key: "s", + key: 's', ctrl: true, - description: "Save", + description: 'Save', preventDefault: true, callback: () => { const state = graph.serialize(); const blob = new Blob([JSON.stringify(state)], { - type: "application/json;charset=utf-8", + type: 'application/json;charset=utf-8' }); - FileSaver.saveAs(blob, "nodarium-graph.json"); - }, + FileSaver.saveAs(blob, 'nodarium-graph.json'); + } }); keymap.addShortcut({ - key: ["Delete", "Backspace", "x"], - description: "Delete selected nodes", + key: ['Delete', 'Backspace', 'x'], + description: 'Delete selected nodes', callback: (event) => { if (!graphState.isBodyFocused()) return; graph.startUndoGroup(); @@ -171,20 +168,18 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr graphState.clearSelection(); } graph.saveUndoGroup(); - }, + } }); keymap.addShortcut({ - key: "f", - description: "Smart Connect Nodes", + key: 'f', + description: 'Smart Connect Nodes', callback: () => { const nodes = [...graphState.selectedNodes.values()] .map((g) => graph.getNode(g)) .filter((n) => !!n); const edge = graph.smartConnect(nodes[0], nodes[1]); if (!edge) graph.smartConnect(nodes[1], nodes[0]); - }, + } }); - - } diff --git a/app/src/lib/sidebar/Panel.svelte b/app/src/lib/sidebar/Panel.svelte index 925dd87..19d90c0 100644 --- a/app/src/lib/sidebar/Panel.svelte +++ b/app/src/lib/sidebar/Panel.svelte @@ -1,6 +1,6 @@ From 6b6038e546a6d5e9584d397b7ebddfd6c55c6c27 Mon Sep 17 00:00:00 2001 From: Felix Hungenberg <30648730+shiftgeist@users.noreply.github.com> Date: Tue, 20 Jan 2026 16:49:56 +0100 Subject: [PATCH 12/14] feat: use new number input fix missing id in html --- packages/ui/src/lib/Input.svelte | 8 +++---- packages/ui/src/lib/inputs/Integer.svelte | 28 ++++++++++++----------- packages/ui/src/lib/inputs/Number.svelte | 22 ++++++++++++------ 3 files changed, 33 insertions(+), 25 deletions(-) diff --git a/packages/ui/src/lib/Input.svelte b/packages/ui/src/lib/Input.svelte index 49feb93..f916dd1 100644 --- a/packages/ui/src/lib/Input.svelte +++ b/packages/ui/src/lib/Input.svelte @@ -2,11 +2,9 @@ import type { NodeInput } from '@nodarium/types'; import Checkbox from './inputs/Checkbox.svelte'; - import Float from './inputs/Float.svelte'; - import Integer from './inputs/Integer.svelte'; + import Number from './inputs/Number.svelte'; import Select from './inputs/Select.svelte'; import Vec3 from './inputs/Vec3.svelte'; - // import Number from './inputs/Number.svelte'; interface Props { input: NodeInput; @@ -18,9 +16,9 @@ {#if input.type === 'float'} - + {:else if input.type === 'integer'} - + {:else if input.type === 'boolean'} {:else if input.type === 'select'} diff --git a/packages/ui/src/lib/inputs/Integer.svelte b/packages/ui/src/lib/inputs/Integer.svelte index 083e621..1446b99 100644 --- a/packages/ui/src/lib/inputs/Integer.svelte +++ b/packages/ui/src/lib/inputs/Integer.svelte @@ -112,23 +112,25 @@ onmousedown={handleMouseDown} onmouseup={handleMouseUp} > +
+ + + + +
{#if typeof min !== 'undefined' && typeof max !== 'undefined'} {/if} - - - -
From a3d10d6094a26425f3dee2226419dea50f0e7aca Mon Sep 17 00:00:00 2001 From: Max Richter Date: Tue, 20 Jan 2026 17:46:09 +0100 Subject: [PATCH 13/14] feat: drop node on edge Closes #13 --- .../lib/graph-interface/debug/Debug.svelte | 47 ++- app/src/lib/graph-interface/debug/index.ts | 26 +- app/src/lib/graph-interface/debug/store.ts | 10 +- app/src/lib/graph-interface/edges/Edge.svelte | 34 ++- .../graph-interface/graph-manager.svelte.ts | 280 ++++++++++++------ .../lib/graph-interface/graph-state.svelte.ts | 150 +++++----- .../lib/graph-interface/graph/Graph.svelte | 15 +- .../lib/graph-interface/graph/drop.events.ts | 107 +++++++ .../lib/graph-interface/graph/edge.events.ts | 110 +++++++ .../graph/{events.ts => mouse.events.ts} | 246 ++++----------- app/src/lib/graph-interface/helpers/index.ts | 75 +++-- packages/types/src/index.ts | 23 +- packages/types/src/types.ts | 26 +- 13 files changed, 710 insertions(+), 439 deletions(-) create mode 100644 app/src/lib/graph-interface/graph/drop.events.ts create mode 100644 app/src/lib/graph-interface/graph/edge.events.ts rename app/src/lib/graph-interface/graph/{events.ts => mouse.events.ts} (63%) diff --git a/app/src/lib/graph-interface/debug/Debug.svelte b/app/src/lib/graph-interface/debug/Debug.svelte index ce105f1..22fe27c 100644 --- a/app/src/lib/graph-interface/debug/Debug.svelte +++ b/app/src/lib/graph-interface/debug/Debug.svelte @@ -1,19 +1,44 @@ {#each $points as point} - - - - + + + + +{/each} + +{#each $rects as rect, i} + + + + {/each} {#each $lines as line} - - - - + + + + {/each} diff --git a/app/src/lib/graph-interface/debug/index.ts b/app/src/lib/graph-interface/debug/index.ts index fc131cb..34d66e6 100644 --- a/app/src/lib/graph-interface/debug/index.ts +++ b/app/src/lib/graph-interface/debug/index.ts @@ -1,5 +1,7 @@ -import { Vector3 } from "three/src/math/Vector3.js"; -import { lines, points } from "./store"; +import type { Box } from '@nodarium/types'; +import { Vector3 } from 'three/src/math/Vector3.js'; +import Component from './Debug.svelte'; +import { lines, points, rects } from './store'; export function debugPosition(x: number, y: number) { points.update((p) => { @@ -8,18 +10,28 @@ export function debugPosition(x: number, y: number) { }); } +export function debugRect(rect: Box) { + console.log(rect); + rects.update((r) => { + r.push(rect); + return r; + }); +} + export function clear() { points.set([]); lines.set([]); + rects.set([]); } -export function debugLine(line: Vector3[]) { +export function debugLine(points: Vector3[], color?: Color) { lines.update((l) => { - l.push(line); + l.push({ points, color }); return l; }); } -import Component from "./Debug.svelte"; - -export default Component +export default Component; +export function clearLines() { + lines.set([]); +} diff --git a/app/src/lib/graph-interface/debug/store.ts b/app/src/lib/graph-interface/debug/store.ts index 59d869f..6638180 100644 --- a/app/src/lib/graph-interface/debug/store.ts +++ b/app/src/lib/graph-interface/debug/store.ts @@ -1,6 +1,8 @@ -import { writable } from "svelte/store"; -import { Vector3 } from "three/src/math/Vector3.js"; +import type { Box } from '@nodarium/types'; +import { writable } from 'svelte/store'; +import type { Color } from 'three'; +import { Vector3 } from 'three/src/math/Vector3.js'; export const points = writable([]); - -export const lines = writable([]); +export const rects = writable([]); +export const lines = writable<{ points: Vector3[]; color?: Color }[]>([]); diff --git a/app/src/lib/graph-interface/edges/Edge.svelte b/app/src/lib/graph-interface/edges/Edge.svelte index 187eaf7..7180b5c 100644 --- a/app/src/lib/graph-interface/edges/Edge.svelte +++ b/app/src/lib/graph-interface/edges/Edge.svelte @@ -31,6 +31,10 @@ import { CubicBezierCurve } from "three/src/extras/curves/CubicBezierCurve.js"; import { Vector2 } from "three/src/math/Vector2.js"; import { appSettings } from "$lib/settings/app-settings.svelte"; + import { getGraphState } from "../graph-state.svelte"; + import { onDestroy } from "svelte"; + + const graphState = getGraphState(); type Props = { x1: number; @@ -38,20 +42,21 @@ x2: number; y2: number; z: number; + id?: string; }; - const { x1, y1, x2, y2, z }: Props = $props(); + const { x1, y1, x2, y2, z, id }: Props = $props(); const thickness = $derived(Math.max(0.001, 0.00082 * Math.exp(0.055 * z))); let points = $state([]); let lastId: string | null = null; + const curveId = $derived(`${x1}-${y1}-${x2}-${y2}`); function update() { const new_x = x2 - x1; const new_y = y2 - y1; - const curveId = `${x1}-${y1}-${x2}-${y2}`; if (lastId === curveId) { return; } @@ -72,6 +77,15 @@ .getPoints(samples) .map((p) => new Vector3(p.x, 0, p.y)) .flat(); + + if (id) { + graphState.setEdgeGeometry( + id, + x1, + y1, + $state.snapshot(points) as unknown as Vector3[], + ); + } } $effect(() => { @@ -79,6 +93,10 @@ update(); } }); + + onDestroy(() => { + if (id) graphState.removeEdgeGeometry(id); + }); +{#if graphState.hoveredEdgeId === id} + + + + +{/if} + diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index c9feb5c..0f29368 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -1,31 +1,30 @@ +import throttle from '$lib/helpers/throttle'; import type { Edge, Graph, - NodeInstance, NodeDefinition, - NodeInput, - NodeRegistry, NodeId, - Socket, -} from "@nodarium/types"; -import { fastHashString } from "@nodarium/utils"; -import { SvelteMap } from "svelte/reactivity"; -import EventEmitter from "./helpers/EventEmitter"; -import { createLogger } from "@nodarium/utils"; -import throttle from "$lib/helpers/throttle"; -import { HistoryManager } from "./history-manager"; + NodeInput, + NodeInstance, + NodeRegistry, + Socket +} from '@nodarium/types'; +import { fastHashString } from '@nodarium/utils'; +import { createLogger } from '@nodarium/utils'; +import { SvelteMap } from 'svelte/reactivity'; +import EventEmitter from './helpers/EventEmitter'; +import { HistoryManager } from './history-manager'; -const logger = createLogger("graph-manager"); +const logger = createLogger('graph-manager'); logger.mute(); -const clone = - "structuredClone" in self - ? self.structuredClone - : (args: any) => JSON.parse(JSON.stringify(args)); +const clone = 'structuredClone' in self + ? self.structuredClone + : (args: any) => JSON.parse(JSON.stringify(args)); function areSocketsCompatible( output: string | undefined, - inputs: string | (string | undefined)[] | undefined, + inputs: string | (string | undefined)[] | undefined ) { if (Array.isArray(inputs) && output) { return inputs.includes(output); @@ -34,24 +33,23 @@ function areSocketsCompatible( } function areEdgesEqual(firstEdge: Edge, secondEdge: Edge) { - if (firstEdge[0].id !== secondEdge[0].id) { return false; } if (firstEdge[1] !== secondEdge[1]) { - return false + return false; } if (firstEdge[2].id !== secondEdge[2].id) { - return false + return false; } if (firstEdge[3] !== secondEdge[3]) { - return false + return false; } - return true + return true; } export class GraphManager extends EventEmitter<{ @@ -62,7 +60,7 @@ export class GraphManager extends EventEmitter<{ values: Record; }; }> { - status = $state<"loading" | "idle" | "error">(); + status = $state<'loading' | 'idle' | 'error'>(); loaded = false; graph: Graph = { id: 0, nodes: [], edges: [] }; @@ -88,7 +86,7 @@ export class GraphManager extends EventEmitter<{ history: HistoryManager = new HistoryManager(); execute = throttle(() => { if (this.loaded === false) return; - this.emit("result", this.serialize()); + this.emit('result', this.serialize()); }, 10); constructor(public registry: NodeRegistry) { @@ -100,21 +98,21 @@ export class GraphManager extends EventEmitter<{ id: node.id, position: [...node.position], type: node.type, - props: node.props, + props: node.props })) as NodeInstance[]; const edges = this.edges.map((edge) => [ edge[0].id, edge[1], edge[2].id, - edge[3], - ]) as Graph["edges"]; + edge[3] + ]) as Graph['edges']; const serialized = { id: this.graph.id, settings: $state.snapshot(this.settings), nodes, - edges, + edges }; - logger.log("serializing graph", serialized); + logger.log('serializing graph', serialized); return clone($state.snapshot(serialized)); } @@ -148,6 +146,95 @@ export class GraphManager extends EventEmitter<{ return [...nodes.values()]; } + getEdgeId(e: Edge) { + return `${e[0].id}-${e[1]}-${e[2].id}-${e[3]}`; + } + + getEdgeById(id: string): Edge | undefined { + return this.edges.find((e) => this.getEdgeId(e) === id); + } + + dropNodeOnEdge(nodeId: number, edge: Edge) { + const draggedNode = this.getNode(nodeId); + if (!draggedNode || !draggedNode.state?.type) return; + + const [fromNode, fromSocketIdx, toNode, toSocketKey] = edge; + + const draggedInputs = Object.entries(draggedNode.state.type.inputs ?? {}); + const draggedOutputs = draggedNode.state.type.outputs ?? []; + + const edgeOutputSocketType = fromNode.state?.type?.outputs?.[fromSocketIdx]; + const targetInput = toNode.state?.type?.inputs?.[toSocketKey]; + const targetAcceptedTypes = [targetInput?.type, ...(targetInput?.accepts || [])]; + + const bestInputEntry = draggedInputs.find(([_, input]) => { + const accepted = [input.type, ...(input.accepts || [])]; + return areSocketsCompatible(edgeOutputSocketType, accepted); + }); + + const bestOutputIdx = draggedOutputs.findIndex(outputType => areSocketsCompatible(outputType, targetAcceptedTypes)); + + if (!bestInputEntry || bestOutputIdx === -1) { + logger.error('Could not find compatible sockets for drop'); + return; + } + + this.startUndoGroup(); + + this.removeEdge(edge, { applyDeletion: false }); + + this.createEdge(fromNode, fromSocketIdx, draggedNode, bestInputEntry[0], { + applyUpdate: false + }); + + this.createEdge(draggedNode, bestOutputIdx, toNode, toSocketKey, { + applyUpdate: false + }); + + this.saveUndoGroup(); + this.execute(); + } + + getPossibleDropOnEdges(nodeId: number): Edge[] { + const draggedNode = this.getNode(nodeId); + if (!draggedNode || !draggedNode.state?.type) return []; + + const draggedInputs = Object.values(draggedNode.state.type.inputs ?? {}); + const draggedOutputs = draggedNode.state.type.outputs ?? []; + + // Optimization: Pre-calculate parents to avoid cycles + const parentIds = new Set(this.getParentsOfNode(draggedNode).map(n => n.id)); + + return this.edges.filter((edge) => { + const [fromNode, fromSocketIdx, toNode, toSocketKey] = edge; + + // 1. Prevent cycles: If the target node is already a parent, we can't drop here + if (parentIds.has(toNode.id)) return false; + + // 2. Prevent self-dropping: Don't drop on edges already connected to this node + if (fromNode.id === nodeId || toNode.id === nodeId) return false; + + // 3. Check if edge.source can plug into ANY draggedNode.input + const edgeOutputSocketType = fromNode.state?.type?.outputs?.[fromSocketIdx]; + const canPlugIntoDragged = draggedInputs.some(input => { + const acceptedTypes = [input.type, ...(input.accepts || [])]; + return areSocketsCompatible(edgeOutputSocketType, acceptedTypes); + }); + + if (!canPlugIntoDragged) return false; + + // 4. Check if ANY draggedNode.output can plug into edge.target + const targetInput = toNode.state?.type?.inputs?.[toSocketKey]; + const targetAcceptedTypes = [targetInput?.type, ...(targetInput?.accepts || [])]; + + const draggedCanPlugIntoTarget = draggedOutputs.some(outputType => + areSocketsCompatible(outputType, targetAcceptedTypes) + ); + + return draggedCanPlugIntoTarget; + }); + } + getEdgesBetweenNodes(nodes: NodeInstance[]): [number, number, number, string][] { const edges = []; for (const node of nodes) { @@ -155,14 +242,14 @@ export class GraphManager extends EventEmitter<{ for (const child of children) { if (nodes.includes(child)) { const edge = this.edges.find( - (e) => e[0].id === node.id && e[2].id === child.id, + (e) => e[0].id === node.id && e[2].id === child.id ); if (edge) { edges.push([edge[0].id, edge[1], edge[2].id, edge[3]] as [ number, number, number, - string, + string ]); } } @@ -179,18 +266,18 @@ export class GraphManager extends EventEmitter<{ const n = node as NodeInstance; if (nodeType) { n.state = { - type: nodeType, + type: nodeType }; } return [node.id, n]; - }), + }) ); const edges = graph.edges.map((edge) => { const from = nodes.get(edge[0]); const to = nodes.get(edge[2]); if (!from || !to) { - throw new Error("Edge references non-existing node"); + throw new Error('Edge references non-existing node'); } from.state.children = from.state.children || []; from.state.children.push(to); @@ -214,21 +301,21 @@ export class GraphManager extends EventEmitter<{ this.loaded = false; this.graph = graph; - this.status = "loading"; + this.status = 'loading'; this.id = graph.id; - logger.info("loading graph", $state.snapshot(graph)); + logger.info('loading graph', $state.snapshot(graph)); const nodeIds = Array.from(new Set([...graph.nodes.map((n) => n.type)])); await this.registry.load(nodeIds); - logger.info("loaded node types", this.registry.getAllNodes()); + logger.info('loaded node types', this.registry.getAllNodes()); for (const node of this.graph.nodes) { const nodeType = this.registry.getNode(node.type); if (!nodeType) { logger.error(`Node type not found: ${node.type}`); - this.status = "error"; + this.status = 'error'; return; } // Turn into runtime node @@ -253,11 +340,11 @@ export class GraphManager extends EventEmitter<{ settingTypes[settingId] = { __node_type: type.id, __node_input: key, - ...type.inputs[key], + ...type.inputs[key] }; if ( - settingValues[settingId] === undefined && - "value" in type.inputs[key] + settingValues[settingId] === undefined + && 'value' in type.inputs[key] ) { settingValues[settingId] = type.inputs[key].value; } @@ -267,14 +354,14 @@ export class GraphManager extends EventEmitter<{ } this.settings = settingValues; - this.emit("settings", { types: settingTypes, values: settingValues }); + this.emit('settings', { types: settingTypes, values: settingValues }); this.history.reset(); this._init(this.graph); this.save(); - this.status = "idle"; + this.status = 'idle'; this.loaded = true; logger.log(`Graph loaded in ${performance.now() - a}ms`); @@ -307,9 +394,9 @@ export class GraphManager extends EventEmitter<{ if (settingId) { settingTypes[settingId] = nodeType.inputs[key]; if ( - settingValues && - settingValues?.[settingId] === undefined && - "value" in nodeType.inputs[key] + settingValues + && settingValues?.[settingId] === undefined + && 'value' in nodeType.inputs[key] ) { settingValues[settingId] = nodeType.inputs[key].value; } @@ -319,7 +406,7 @@ export class GraphManager extends EventEmitter<{ this.settings = settingValues; this.settingTypes = settingTypes; - this.emit("settings", { types: settingTypes, values: settingValues }); + this.emit('settings', { types: settingTypes, values: settingValues }); } getChildren(node: NodeInstance) { @@ -368,7 +455,7 @@ export class GraphManager extends EventEmitter<{ const inputType = to?.state?.type?.inputs?.[toSocket]?.type; if (outputType === inputType) { this.createEdge(from, fromSocket, to, toSocket, { - applyUpdate: false, + applyUpdate: false }); continue; } @@ -403,7 +490,7 @@ export class GraphManager extends EventEmitter<{ // map old ids to new ids const idMap = new Map(); - let startId = this.createNodeId() + let startId = this.createNodeId(); nodes = nodes.map((node) => { const id = startId++; @@ -420,7 +507,7 @@ export class GraphManager extends EventEmitter<{ const to = nodes.find((n) => n.id === idMap.get(edge[2])); if (!from || !to) { - throw new Error("Edge references non-existing node"); + throw new Error('Edge references non-existing node'); } to.state.parents = to.state.parents || []; @@ -445,11 +532,11 @@ export class GraphManager extends EventEmitter<{ createNode({ type, position, - props = {}, + props = {} }: { - type: NodeInstance["type"]; - position: NodeInstance["position"]; - props: NodeInstance["props"]; + type: NodeInstance['type']; + position: NodeInstance['position']; + props: NodeInstance['props']; }) { const nodeType = this.registry.getNode(type); if (!nodeType) { @@ -462,14 +549,14 @@ export class GraphManager extends EventEmitter<{ type, position, state: { type: nodeType }, - props, + props }); this.nodes.set(node.id, node); this.save(); - return node + return node; } createEdge( @@ -477,17 +564,16 @@ export class GraphManager extends EventEmitter<{ fromSocket: number, to: NodeInstance, toSocket: string, - { applyUpdate = true } = {}, + { applyUpdate = true } = {} ): Edge | undefined { - const existingEdges = this.getEdgesToNode(to); // check if this exact edge already exists const existingEdge = existingEdges.find( - (e) => e[0].id === from.id && e[1] === fromSocket && e[3] === toSocket, + (e) => e[0].id === from.id && e[1] === fromSocket && e[3] === toSocket ); if (existingEdge) { - logger.error("Edge already exists", existingEdge); + logger.error('Edge already exists', existingEdge); return; } @@ -500,13 +586,13 @@ export class GraphManager extends EventEmitter<{ if (!areSocketsCompatible(fromSocketType, toSocketType)) { logger.error( - `Socket types do not match: ${fromSocketType} !== ${toSocketType}`, + `Socket types do not match: ${fromSocketType} !== ${toSocketType}` ); return; } const edgeToBeReplaced = this.edges.find( - (e) => e[2].id === to.id && e[3] === toSocket, + (e) => e[2].id === to.id && e[3] === toSocket ); if (edgeToBeReplaced) { this.removeEdge(edgeToBeReplaced, { applyDeletion: false }); @@ -533,7 +619,7 @@ export class GraphManager extends EventEmitter<{ const nextState = this.history.undo(); if (nextState) { this._init(nextState); - this.emit("save", this.serialize()); + this.emit('save', this.serialize()); } } @@ -541,7 +627,7 @@ export class GraphManager extends EventEmitter<{ const nextState = this.history.redo(); if (nextState) { this._init(nextState); - this.emit("save", this.serialize()); + this.emit('save', this.serialize()); } } @@ -558,8 +644,8 @@ export class GraphManager extends EventEmitter<{ if (this.currentUndoGroup) return; const state = this.serialize(); this.history.save(state); - this.emit("save", state); - logger.log("saving graphs", state); + this.emit('save', state); + logger.log('saving graphs', state); } getParentsOfNode(node: NodeInstance) { @@ -567,7 +653,7 @@ export class GraphManager extends EventEmitter<{ const stack = node.state?.parents?.slice(0); while (stack?.length) { if (parents.length > 1000000) { - logger.warn("Infinite loop detected"); + logger.warn('Infinite loop detected'); break; } const parent = stack.pop(); @@ -586,26 +672,28 @@ export class GraphManager extends EventEmitter<{ return []; } - const definitions = typeof socket.index === "string" + const definitions = typeof socket.index === 'string' ? allDefinitions.filter(s => { - return s.outputs?.find(_s => Object - .values(nodeType?.inputs || {}) - .map(s => s.type) - .includes(_s as NodeInput["type"]) - ) + return s.outputs?.find(_s => + Object + .values(nodeType?.inputs || {}) + .map(s => s.type) + .includes(_s as NodeInput['type']) + ); }) - : allDefinitions.filter(s => Object - .values(s.inputs ?? {}) - .find(s => { - if (s.hidden) return false; - if (nodeType.outputs?.includes(s.type)) { - return true - } - return s.accepts?.find(a => nodeType.outputs?.includes(a)) - })) - - return definitions + : allDefinitions.filter(s => + Object + .values(s.inputs ?? {}) + .find(s => { + if (s.hidden) return false; + if (nodeType.outputs?.includes(s.type)) { + return true; + } + return s.accepts?.find(a => nodeType.outputs?.includes(a)); + }) + ); + return definitions; } getPossibleSockets({ node, index }: Socket): [NodeInstance, string | number][] { @@ -615,11 +703,11 @@ export class GraphManager extends EventEmitter<{ const sockets: [NodeInstance, string | number][] = []; // if index is a string, we are an input looking for outputs - if (typeof index === "string") { + if (typeof index === 'string') { // filter out self and child nodes const children = new Set(this.getChildren(node).map((n) => n.id)); const nodes = this.getAllNodes().filter( - (n) => n.id !== node.id && !children.has(n.id), + (n) => n.id !== node.id && !children.has(n.id) ); const ownType = nodeType?.inputs?.[index].type; @@ -634,20 +722,20 @@ export class GraphManager extends EventEmitter<{ } } } - } else if (typeof index === "number") { + } else if (typeof index === 'number') { // if index is a number, we are an output looking for inputs // filter out self and parent nodes const parents = new Set(this.getParentsOfNode(node).map((n) => n.id)); const nodes = this.getAllNodes().filter( - (n) => n.id !== node.id && !parents.has(n.id), + (n) => n.id !== node.id && !parents.has(n.id) ); // get edges from this socket const edges = new Map( this.getEdgesFromNode(node) .filter((e) => e[1] === index) - .map((e) => [e[2].id, e[3]]), + .map((e) => [e[2].id, e[3]]) ); const ownType = nodeType.outputs?.[index]; @@ -660,8 +748,8 @@ export class GraphManager extends EventEmitter<{ otherType.push(...(inputs[key].accepts || [])); if ( - areSocketsCompatible(ownType, otherType) && - edges.get(node.id) !== key + areSocketsCompatible(ownType, otherType) + && edges.get(node.id) !== key ) { sockets.push([node, key]); } @@ -674,7 +762,7 @@ export class GraphManager extends EventEmitter<{ removeEdge( edge: Edge, - { applyDeletion = true }: { applyDeletion?: boolean } = {}, + { applyDeletion = true }: { applyDeletion?: boolean } = {} ) { const id0 = edge[0].id; const sid0 = edge[1]; @@ -682,21 +770,20 @@ export class GraphManager extends EventEmitter<{ const sid2 = edge[3]; const _edge = this.edges.find( - (e) => - e[0].id === id0 && e[1] === sid0 && e[2].id === id2 && e[3] === sid2, + (e) => e[0].id === id0 && e[1] === sid0 && e[2].id === id2 && e[3] === sid2 ); if (!_edge) return; if (edge[0].state.children) { edge[0].state.children = edge[0].state.children.filter( - (n: NodeInstance) => n.id !== id2, + (n: NodeInstance) => n.id !== id2 ); } if (edge[2].state.parents) { edge[2].state.parents = edge[2].state.parents.filter( - (n: NodeInstance) => n.id !== id0, + (n: NodeInstance) => n.id !== id0 ); } @@ -705,7 +792,6 @@ export class GraphManager extends EventEmitter<{ this.execute(); this.save(); } - } getEdgesToNode(node: NodeInstance) { diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index a5a6b7a..7301b13 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -1,36 +1,43 @@ -import type { NodeInstance, Socket } from "@nodarium/types"; -import { getContext, setContext } from "svelte"; -import { SvelteMap, SvelteSet } from "svelte/reactivity"; -import type { GraphManager } from "./graph-manager.svelte"; -import type { Mesh, OrthographicCamera, Vector3 } from "three"; +import type { NodeInstance, Socket } from '@nodarium/types'; +import { getContext, setContext } from 'svelte'; +import { SvelteSet } from 'svelte/reactivity'; +import type { OrthographicCamera, Vector3 } from 'three'; +import type { GraphManager } from './graph-manager.svelte'; - -const graphStateKey = Symbol("graph-state"); +const graphStateKey = Symbol('graph-state'); export function getGraphState() { return getContext(graphStateKey); } export function setGraphState(graphState: GraphState) { - return setContext(graphStateKey, graphState) + return setContext(graphStateKey, graphState); } -const graphManagerKey = Symbol("graph-manager"); +const graphManagerKey = Symbol('graph-manager'); export function getGraphManager() { - return getContext(graphManagerKey) + return getContext(graphManagerKey); } export function setGraphManager(manager: GraphManager) { return setContext(graphManagerKey, manager); } -export class GraphState { +type EdgeData = { + x1: number; + y1: number; + points: Vector3[]; +}; +export class GraphState { constructor(private graph: GraphManager) { $effect.root(() => { $effect(() => { - localStorage.setItem("cameraPosition", `[${this.cameraPosition[0]},${this.cameraPosition[1]},${this.cameraPosition[2]}]`) - }) - }) - const storedPosition = localStorage.getItem("cameraPosition") + localStorage.setItem( + 'cameraPosition', + `[${this.cameraPosition[0]},${this.cameraPosition[1]},${this.cameraPosition[2]}]` + ); + }); + }); + const storedPosition = localStorage.getItem('cameraPosition'); if (storedPosition) { try { const d = JSON.parse(storedPosition); @@ -38,7 +45,7 @@ export class GraphState { this.cameraPosition[1] = d[1]; this.cameraPosition[2] = d[2]; } catch (e) { - console.log("Failed to parsed stored camera position", e); + console.log('Failed to parsed stored camera position', e); } } } @@ -46,15 +53,16 @@ export class GraphState { width = $state(100); height = $state(100); - edgeGeometries = new SvelteMap(); + hoveredEdgeId = $state(null); + edges = new Map(); wrapper = $state(null!); rect: DOMRect = $derived( - (this.wrapper && this.width && this.height) ? this.wrapper.getBoundingClientRect() : new DOMRect(0, 0, 0, 0), + (this.wrapper && this.width && this.height) ? this.wrapper.getBoundingClientRect() : new DOMRect(0, 0, 0, 0) ); camera = $state(null!); - cameraPosition: [number, number, number] = $state([0, 0, 4]); + cameraPosition: [number, number, number] = $state([0, 0, 100]); clipboard: null | { nodes: NodeInstance[]; @@ -65,7 +73,7 @@ export class GraphState { this.cameraPosition[0] - this.width / this.cameraPosition[2] / 2, this.cameraPosition[0] + this.width / this.cameraPosition[2] / 2, this.cameraPosition[1] - this.height / this.cameraPosition[2] / 2, - this.cameraPosition[1] + this.height / this.cameraPosition[2] / 2, + this.cameraPosition[1] + this.height / this.cameraPosition[2] / 2 ]); boxSelection = $state(false); @@ -73,8 +81,8 @@ export class GraphState { addMenuPosition = $state<[number, number] | null>(null); snapToGrid = $state(false); - showGrid = $state(true) - showHelp = $state(false) + showGrid = $state(true); + showHelp = $state(false); cameraDown = [0, 0]; mouseDownNodeId = -1; @@ -90,41 +98,49 @@ export class GraphState { hoveredSocket = $state(null); possibleSockets = $state([]); possibleSocketIds = $derived( - new Set(this.possibleSockets.map((s) => `${s.node.id}-${s.index}`)), + new Set(this.possibleSockets.map((s) => `${s.node.id}-${s.index}`)) ); + getEdges() { + return $state.snapshot(this.edges); + } + clearSelection() { this.selectedNodes.clear(); } - isBodyFocused = () => document?.activeElement?.nodeName !== "INPUT"; + isBodyFocused = () => document?.activeElement?.nodeName !== 'INPUT'; - setEdgeGeometry(edgeId: string, edgeGeometry: { geo: Mesh, points: Vector3[] }) { - this.edgeGeometries.set(edgeId, edgeGeometry); + setEdgeGeometry(edgeId: string, x1: number, y1: number, points: Vector3[]) { + this.edges.set(edgeId, { x1, y1, points }); } removeEdgeGeometry(edgeId: string) { - this.edgeGeometries.delete(edgeId); + this.edges.delete(edgeId); + } + + getEdgeData() { + return this.edges; } updateNodePosition(node: NodeInstance) { if ( - node.state.x === node.position[0] && - node.state.y === node.position[1] + node.state.x === node.position[0] + && node.state.y === node.position[1] ) { delete node.state.x; delete node.state.y; } - if (node.state["x"] !== undefined && node.state["y"] !== undefined) { + if (node.state['x'] !== undefined && node.state['y'] !== undefined) { if (node.state.ref) { - node.state.ref.style.setProperty("--nx", `${node.state.x * 10}px`); - node.state.ref.style.setProperty("--ny", `${node.state.y * 10}px`); + node.state.ref.style.setProperty('--nx', `${node.state.x * 10}px`); + node.state.ref.style.setProperty('--ny', `${node.state.y * 10}px`); } } else { if (node.state.ref) { - node.state.ref.style.setProperty("--nx", `${node.position[0] * 10}px`); - node.state.ref.style.setProperty("--ny", `${node.position[1] * 10}px`); + node.state.ref.style.setProperty('--nx', `${node.position[0] * 10}px`); + node.state.ref.style.setProperty('--ny', `${node.position[1] * 10}px`); } } } @@ -144,18 +160,18 @@ export class GraphState { getSocketPosition( node: NodeInstance, - index: string | number, + index: string | number ): [number, number] { - if (typeof index === "number") { + if (typeof index === 'number') { return [ (node?.state?.x ?? node.position[0]) + 20, - (node?.state?.y ?? node.position[1]) + 2.5 + 10 * index, + (node?.state?.y ?? node.position[1]) + 2.5 + 10 * index ]; } else { const _index = Object.keys(node.state?.type?.inputs || {}).indexOf(index); return [ node?.state?.x ?? node.position[0], - (node?.state?.y ?? node.position[1]) + 10 + 10 * _index, + (node?.state?.y ?? node.position[1]) + 10 + 10 * _index ]; } } @@ -169,26 +185,26 @@ export class GraphState { if (!node?.inputs) { return 5; } - const height = - 5 + - 10 * - Object.keys(node.inputs).filter( + const height = 5 + + 10 + * Object.keys(node.inputs).filter( (p) => - p !== "seed" && - node?.inputs && - !("setting" in node?.inputs?.[p]) && - node.inputs[p].hidden !== true, + p !== 'seed' + && node?.inputs + && !('setting' in node?.inputs?.[p]) + && node.inputs[p].hidden !== true ).length; this.nodeHeightCache[nodeTypeId] = height; return height; } copyNodes() { - if (this.activeNodeId === -1 && !this.selectedNodes?.size) + if (this.activeNodeId === -1 && !this.selectedNodes?.size) { return; + } let nodes = [ this.activeNodeId, - ...(this.selectedNodes?.values() || []), + ...(this.selectedNodes?.values() || []) ] .map((id) => this.graph.getNode(id)) .filter(b => !!b); @@ -198,14 +214,14 @@ export class GraphState { ...node, position: [ this.mousePosition[0] - node.position[0], - this.mousePosition[1] - node.position[1], + this.mousePosition[1] - node.position[1] ], - tmp: undefined, + tmp: undefined })); this.clipboard = { nodes: nodes, - edges: edges, + edges: edges }; } @@ -227,14 +243,13 @@ export class GraphState { } } - setDownSocket(socket: Socket) { this.activeSocket = socket; let { node, index, position } = socket; // remove existing edge - if (typeof index === "string") { + if (typeof index === 'string') { const edges = this.graph.getEdgesToNode(node); for (const edge of edges) { if (edge[3] === index) { @@ -251,7 +266,7 @@ export class GraphState { this.activeSocket = { node, index, - position, + position }; this.possibleSockets = this.graph @@ -260,18 +275,17 @@ export class GraphState { return { node, index, - position: this.getSocketPosition(node, index), + position: this.getSocketPosition(node, index) }; }); - }; - + } projectScreenToWorld(x: number, y: number): [number, number] { return [ - this.cameraPosition[0] + - (x - this.width / 2) / this.cameraPosition[2], - this.cameraPosition[1] + - (y - this.height / 2) / this.cameraPosition[2], + this.cameraPosition[0] + + (x - this.width / 2) / this.cameraPosition[2], + this.cameraPosition[1] + + (y - this.height / 2) / this.cameraPosition[2] ]; } @@ -284,8 +298,8 @@ export class GraphState { if (event.button === 0) { // check if the clicked element is a node if (event.target instanceof HTMLElement) { - const nodeElement = event.target.closest(".node"); - const nodeId = nodeElement?.getAttribute?.("data-node-id"); + const nodeElement = event.target.closest('.node'); + const nodeId = nodeElement?.getAttribute?.('data-node-id'); if (nodeId) { clickedNodeId = parseInt(nodeId, 10); } @@ -313,10 +327,10 @@ export class GraphState { const height = this.getNodeHeight(node.type); const width = 20; return ( - node.position[0] > this.cameraBounds[0] - width && - node.position[0] < this.cameraBounds[1] && - node.position[1] > this.cameraBounds[2] - height && - node.position[1] < this.cameraBounds[3] + node.position[0] > this.cameraBounds[0] - width + && node.position[0] < this.cameraBounds[1] + && node.position[1] > this.cameraBounds[2] - height + && node.position[1] < this.cameraBounds[3] ); - }; + } } diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index c6f6b57..5e7485b 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -11,8 +11,10 @@ import HelpView from "../components/HelpView.svelte"; import { getGraphManager, getGraphState } from "../graph-state.svelte"; import { HTML } from "@threlte/extras"; - import { FileDropEventManager, MouseEventManager } from "./events"; import { maxZoom, minZoom } from "./constants"; + import Debug from "../debug/Debug.svelte"; + import { FileDropEventManager } from "./drop.events"; + import { MouseEventManager } from "./mouse.events"; const { keymap, @@ -174,9 +176,18 @@ {#each graph.edges as edge} {@const [x1, y1, x2, y2] = getEdgePosition(edge)} - + {/each} + +
{ + this.graph.createNode({ + type: nodeId, + props, + position: pos + }); + }); + } else if (event.dataTransfer.files.length) { + const file = event.dataTransfer.files[0]; + + if (file.type === 'application/wasm') { + const reader = new FileReader(); + reader.onload = async (e) => { + const buffer = e.target?.result; + if (buffer?.constructor === ArrayBuffer) { + const nodeType = await this.graph.registry.register(buffer); + + this.graph.createNode({ + type: nodeType.id, + props: {}, + position: this.state.projectScreenToWorld(mx, my) + }); + } + }; + reader.readAsArrayBuffer(file); + } else if (file.type === 'application/json') { + const reader = new FileReader(); + reader.onload = (e) => { + const buffer = e.target?.result as ArrayBuffer; + if (buffer) { + const state = GraphSchema.parse(JSON.parse(buffer.toString())); + this.graph.load(state); + } + }; + reader.readAsText(file); + } + } + } + + handleMouseLeave() { + this.state.isDragging = false; + this.state.isPanning = false; + } + + handleDragEnter(e: DragEvent) { + e.preventDefault(); + this.state.isDragging = true; + this.state.isPanning = false; + } + + handleDragOver(e: DragEvent) { + e.preventDefault(); + this.state.isDragging = true; + this.state.isPanning = false; + } + + handleDragEnd(e: DragEvent) { + e.preventDefault(); + this.state.isDragging = true; + this.state.isPanning = false; + } + + getEventListenerProps() { + return { + ondragenter: (ev: DragEvent) => this.handleDragEnter(ev), + ondragover: (ev: DragEvent) => this.handleDragOver(ev), + ondragexit: (ev: DragEvent) => this.handleDragEnd(ev), + ondrop: (ev: DragEvent) => this.handleFileDrop(ev), + onmouseleave: () => this.handleMouseLeave() + }; + } +} diff --git a/app/src/lib/graph-interface/graph/edge.events.ts b/app/src/lib/graph-interface/graph/edge.events.ts new file mode 100644 index 0000000..7fb9e21 --- /dev/null +++ b/app/src/lib/graph-interface/graph/edge.events.ts @@ -0,0 +1,110 @@ +import type { Box } from '@nodarium/types'; +import type { GraphManager } from '../graph-manager.svelte'; +import type { GraphState } from '../graph-state.svelte'; +import { distanceFromPointToSegment } from '../helpers'; + +export class EdgeInteractionManager { + constructor( + private graph: GraphManager, + private state: GraphState + ) { } + + private MIN_DISTANCE = 3; + + private _boundingBoxes = new Map(); + + handleMouseDown() { + this._boundingBoxes.clear(); + + const possibleEdges = this.graph + .getPossibleDropOnEdges(this.state.activeNodeId) + .map(e => this.graph.getEdgeId(e)); + + const edges = this.state.getEdges(); + for (const edge of edges) { + const edgeId = edge[0]; + if (!possibleEdges.includes(edgeId)) { + edges.delete(edgeId); + } + } + + for (const [edgeId, data] of edges) { + const points = data.points; + let minX = points[0].x + data.x1; + let maxX = points[0].x + data.x1; + let minY = points[0].z + data.y1; + let maxY = points[0].z + data.y1; + + // Iterate through all points to find the true bounds + for (let i = 0; i < points.length; i++) { + const x = data.x1 + points[i].x; + const y = data.y1 + points[i].z; + if (x < minX) minX = x; + if (x > maxX) maxX = x; + if (y < minY) minY = y; + if (y > maxY) maxY = y; + } + + const boundingBox = { + minX: minX - this.MIN_DISTANCE, + maxX: maxX + this.MIN_DISTANCE, + minY: minY - this.MIN_DISTANCE, + maxY: maxY + this.MIN_DISTANCE + }; + + this._boundingBoxes.set(edgeId, boundingBox); + } + } + + handleMouseMove() { + const [mouseX, mouseY] = this.state.mousePosition; + const hoveredEdgeIds: string[] = []; + + const edges = this.state.getEdges(); + + // Check if mouse is inside any bounding box + for (const [edgeId, box] of this._boundingBoxes) { + const isInside = mouseX >= box.minX + && mouseX <= box.maxX + && mouseY >= box.minY + && mouseY <= box.maxY; + + if (isInside) { + hoveredEdgeIds.push(edgeId); + } + } + + let hoveredEdgeId: string | null = null; + let hoveredEdgeDistance = Infinity; + + const DENSITY = 10; // higher DENSITY = less points checked (yes density might not be the best name :-) + for (const edgeId of hoveredEdgeIds) { + const edge = edges.get(edgeId)!; + for (let i = 0; i < edge.points.length - DENSITY; i += DENSITY) { + const pointAx = edge.points[i].x + edge.x1; + const pointAy = edge.points[i].z + edge.y1; + const pointBx = edge.points[i + DENSITY].x + edge.x1; + const pointBy = edge.points[i + DENSITY].z + edge.y1; + const distance = distanceFromPointToSegment(pointAx, pointAy, pointBx, pointBy, mouseX, mouseY); + if (distance < this.MIN_DISTANCE) { + if (distance < hoveredEdgeDistance) { + hoveredEdgeDistance = distance; + hoveredEdgeId = edgeId; + } + } + } + } + + this.state.hoveredEdgeId = hoveredEdgeId; + } + + handleMouseUp() { + if (this.state.hoveredEdgeId) { + const edge = this.graph.getEdgeById(this.state.hoveredEdgeId); + if (edge) { + this.graph.dropNodeOnEdge(this.state.activeNodeId, edge); + } + this.state.hoveredEdgeId = null; + } + } +} diff --git a/app/src/lib/graph-interface/graph/events.ts b/app/src/lib/graph-interface/graph/mouse.events.ts similarity index 63% rename from app/src/lib/graph-interface/graph/events.ts rename to app/src/lib/graph-interface/graph/mouse.events.ts index 9a1ddd3..c856a77 100644 --- a/app/src/lib/graph-interface/graph/events.ts +++ b/app/src/lib/graph-interface/graph/mouse.events.ts @@ -1,144 +1,18 @@ -import { GraphSchema, type NodeId, type NodeInstance } from "@nodarium/types"; -import type { GraphManager } from "../graph-manager.svelte"; -import type { GraphState } from "../graph-state.svelte"; -import { animate, lerp } from "$lib/helpers"; -import { snapToGrid as snapPointToGrid } from "../helpers"; -import { maxZoom, minZoom, zoomSpeed } from "./constants"; - - -export class FileDropEventManager { - - constructor( - private graph: GraphManager, - private state: GraphState - ) { } - - handleFileDrop(event: DragEvent) { - event.preventDefault(); - this.state.isDragging = false; - if (!event.dataTransfer) return; - const nodeId = event.dataTransfer.getData("data/node-id") as NodeId; - let mx = event.clientX - this.state.rect.x; - let my = event.clientY - this.state.rect.y; - - if (nodeId) { - let nodeOffsetX = event.dataTransfer.getData("data/node-offset-x"); - let nodeOffsetY = event.dataTransfer.getData("data/node-offset-y"); - if (nodeOffsetX && nodeOffsetY) { - mx += parseInt(nodeOffsetX); - my += parseInt(nodeOffsetY); - } - - let props = {}; - let rawNodeProps = event.dataTransfer.getData("data/node-props"); - if (rawNodeProps) { - try { - props = JSON.parse(rawNodeProps); - } catch (e) { } - } - - const pos = this.state.projectScreenToWorld(mx, my); - this.graph.registry.load([nodeId]).then(() => { - this.graph.createNode({ - type: nodeId, - props, - position: pos, - }); - }); - } else if (event.dataTransfer.files.length) { - const file = event.dataTransfer.files[0]; - - if (file.type === "application/wasm") { - const reader = new FileReader(); - reader.onload = async (e) => { - const buffer = e.target?.result; - if (buffer?.constructor === ArrayBuffer) { - const nodeType = await this.graph.registry.register(buffer); - - this.graph.createNode({ - type: nodeType.id, - props: {}, - position: this.state.projectScreenToWorld(mx, my), - }); - } - }; - reader.readAsArrayBuffer(file); - } else if (file.type === "application/json") { - const reader = new FileReader(); - reader.onload = (e) => { - const buffer = e.target?.result as ArrayBuffer; - if (buffer) { - const state = GraphSchema.parse(JSON.parse(buffer.toString())); - this.graph.load(state); - } - }; - reader.readAsText(file); - } - } - } - - handleMouseLeave() { - this.state.isDragging = false; - this.state.isPanning = false; - } - - handleDragEnter(e: DragEvent) { - e.preventDefault(); - this.state.isDragging = true; - this.state.isPanning = false; - } - - handleDragOver(e: DragEvent) { - e.preventDefault(); - this.state.isDragging = true; - this.state.isPanning = false; - } - - handleDragEnd(e: DragEvent) { - e.preventDefault(); - this.state.isDragging = true; - this.state.isPanning = false; - } - - getEventListenerProps() { - return { - ondragenter: (ev: DragEvent) => this.handleDragEnter(ev), - ondragover: (ev: DragEvent) => this.handleDragOver(ev), - ondragexit: (ev: DragEvent) => this.handleDragEnd(ev), - ondrop: (ev: DragEvent) => this.handleFileDrop(ev), - onmouseleave: () => this.handleMouseLeave(), - } - } -} - - -class EdgeInteractionManager { - constructor( - private graph: GraphManager, - private state: GraphState) { }; - - handleMouseDown() { - const edges = this.graph.edges; - console.log(edges) - } - - handleMouseMove() { - } - - handleMouseUp() { - } -} - +import { animate, lerp } from '$lib/helpers'; +import { type NodeInstance } from '@nodarium/types'; +import type { GraphManager } from '../graph-manager.svelte'; +import type { GraphState } from '../graph-state.svelte'; +import { snapToGrid as snapPointToGrid } from '../helpers'; +import { maxZoom, minZoom, zoomSpeed } from './constants'; +import { EdgeInteractionManager } from './edge.events'; export class MouseEventManager { - - edgeInteractionManager: EdgeInteractionManager + edgeInteractionManager: EdgeInteractionManager; constructor( private graph: GraphManager, private state: GraphState ) { - this.edgeInteractionManager = new EdgeInteractionManager(graph, state); } @@ -167,25 +41,23 @@ export class MouseEventManager { const snapLevel = this.state.getSnapLevel(); activeNode.position[0] = snapPointToGrid( activeNode?.state?.x ?? activeNode.position[0], - 5 / snapLevel, + 5 / snapLevel ); activeNode.position[1] = snapPointToGrid( activeNode?.state?.y ?? activeNode.position[1], - 5 / snapLevel, + 5 / snapLevel ); } else { activeNode.position[0] = activeNode?.state?.x ?? activeNode.position[0]; activeNode.position[1] = activeNode?.state?.y ?? activeNode.position[1]; } const nodes = [ - ...[...(this.state.selectedNodes?.values() || [])].map((id) => - this.graph.getNode(id), - ), + ...[...(this.state.selectedNodes?.values() || [])].map((id) => this.graph.getNode(id)) ] as NodeInstance[]; const vec = [ activeNode.position[0] - (activeNode?.state.x || 0), - activeNode.position[1] - (activeNode?.state.y || 0), + activeNode.position[1] - (activeNode?.state.y || 0) ]; for (const node of nodes) { @@ -201,9 +73,9 @@ export class MouseEventManager { animate(500, (a: number) => { for (const node of nodes) { if ( - node?.state && - node.state["x"] !== undefined && - node.state["y"] !== undefined + node?.state + && node.state['x'] !== undefined + && node.state['y'] !== undefined ) { node.state.x = lerp(node.state.x, node.position[0], a); node.state.y = lerp(node.state.y, node.position[1], a); @@ -217,24 +89,24 @@ export class MouseEventManager { this.graph.save(); } else if (this.state.hoveredSocket && this.state.activeSocket) { if ( - typeof this.state.hoveredSocket.index === "number" && - typeof this.state.activeSocket.index === "string" + typeof this.state.hoveredSocket.index === 'number' + && typeof this.state.activeSocket.index === 'string' ) { this.graph.createEdge( this.state.hoveredSocket.node, this.state.hoveredSocket.index || 0, this.state.activeSocket.node, - this.state.activeSocket.index, + this.state.activeSocket.index ); } else if ( - typeof this.state.activeSocket.index == "number" && - typeof this.state.hoveredSocket.index === "string" + typeof this.state.activeSocket.index == 'number' + && typeof this.state.hoveredSocket.index === 'string' ) { this.graph.createEdge( this.state.activeSocket.node, this.state.activeSocket.index || 0, this.state.hoveredSocket.node, - this.state.hoveredSocket.index, + this.state.hoveredSocket.index ); } this.graph.save(); @@ -242,18 +114,18 @@ export class MouseEventManager { // Handle automatic adding of nodes on ctrl+mouseUp this.state.edgeEndPosition = [ this.state.mousePosition[0], - this.state.mousePosition[1], + this.state.mousePosition[1] ]; - if (typeof this.state.activeSocket.index === "number") { + if (typeof this.state.activeSocket.index === 'number') { this.state.addMenuPosition = [ this.state.mousePosition[0], - this.state.mousePosition[1] - 25 / this.state.cameraPosition[2], + this.state.mousePosition[1] - 25 / this.state.cameraPosition[2] ]; } else { this.state.addMenuPosition = [ this.state.mousePosition[0] - 155 / this.state.cameraPosition[2], - this.state.mousePosition[1] - 25 / this.state.cameraPosition[2], + this.state.mousePosition[1] - 25 / this.state.cameraPosition[2] ]; } return; @@ -261,11 +133,11 @@ export class MouseEventManager { // check if camera moved if ( - clickedNodeId === -1 && - !this.state.boxSelection && - this.state.cameraDown[0] === this.state.cameraPosition[0] && - this.state.cameraDown[1] === this.state.cameraPosition[1] && - this.state.isBodyFocused() + clickedNodeId === -1 + && !this.state.boxSelection + && this.state.cameraDown[0] === this.state.cameraPosition[0] + && this.state.cameraDown[1] === this.state.cameraPosition[1] + && this.state.isBodyFocused() ) { this.state.activeNodeId = -1; this.state.clearSelection(); @@ -279,16 +151,15 @@ export class MouseEventManager { this.state.addMenuPosition = null; } - handleMouseDown(event: MouseEvent) { if (this.state.mouseDown) return; this.state.edgeEndPosition = null; if (event.target instanceof HTMLElement) { if ( - event.target.nodeName !== "CANVAS" && - !event.target.classList.contains("node") && - !event.target.classList.contains("content") + event.target.nodeName !== 'CANVAS' + && !event.target.classList.contains('node') + && !event.target.classList.contains('content') ) { return; } @@ -310,7 +181,7 @@ export class MouseEventManager { this.state.activeNodeId = clickedNodeId; // if the selected node is the same as the clicked node } else if (this.state.activeNodeId === clickedNodeId) { - //$activeNodeId = -1; + // $activeNodeId = -1; // if the clicked node is different from the selected node and secondary } else if (event.ctrlKey) { this.state.selectedNodes.add(this.state.activeNodeId); @@ -358,7 +229,6 @@ export class MouseEventManager { this.state.edgeEndPosition = null; } - handleMouseMove(event: MouseEvent) { let mx = event.clientX - this.state.rect.x; let my = event.clientY - this.state.rect.y; @@ -374,8 +244,8 @@ export class MouseEventManager { let _socket; for (const socket of this.state.possibleSockets) { const dist = Math.sqrt( - (socket.position[0] - this.state.mousePosition[0]) ** 2 + - (socket.position[1] - this.state.mousePosition[1]) ** 2, + (socket.position[0] - this.state.mousePosition[0]) ** 2 + + (socket.position[1] - this.state.mousePosition[1]) ** 2 ); if (dist < smallestDist) { smallestDist = dist; @@ -398,7 +268,7 @@ export class MouseEventManager { event.stopPropagation(); const mouseD = this.state.projectScreenToWorld( this.state.mouseDown[0], - this.state.mouseDown[1], + this.state.mouseDown[1] ); const x1 = Math.min(mouseD[0], this.state.mousePosition[0]); const x2 = Math.max(mouseD[0], this.state.mousePosition[0]); @@ -429,10 +299,8 @@ export class MouseEventManager { const oldX = node.state.downX || 0; const oldY = node.state.downY || 0; - let newX = - oldX + (mx - this.state.mouseDown[0]) / this.state.cameraPosition[2]; - let newY = - oldY + (my - this.state.mouseDown[1]) / this.state.cameraPosition[2]; + let newX = oldX + (mx - this.state.mouseDown[0]) / this.state.cameraPosition[2]; + let newY = oldY + (my - this.state.mouseDown[1]) / this.state.cameraPosition[2]; if (event.ctrlKey) { const snapLevel = this.state.getSnapLevel(); @@ -472,23 +340,19 @@ export class MouseEventManager { // here we are handling panning of camera this.state.isPanning = true; - let newX = - this.state.cameraDown[0] - - (mx - this.state.mouseDown[0]) / this.state.cameraPosition[2]; - let newY = - this.state.cameraDown[1] - - (my - this.state.mouseDown[1]) / this.state.cameraPosition[2]; + let newX = this.state.cameraDown[0] + - (mx - this.state.mouseDown[0]) / this.state.cameraPosition[2]; + let newY = this.state.cameraDown[1] + - (my - this.state.mouseDown[1]) / this.state.cameraPosition[2]; this.state.cameraPosition[0] = newX; this.state.cameraPosition[1] = newY; } - handleMouseScroll(event: WheelEvent) { - const bodyIsFocused = - document.activeElement === document.body || - document.activeElement === this.state.wrapper || - document?.activeElement?.id === "graph"; + const bodyIsFocused = document.activeElement === document.body + || document.activeElement === this.state.wrapper + || document?.activeElement?.id === 'graph'; if (!bodyIsFocused) return; // Define zoom speed and clamp it between -1 and 1 @@ -503,21 +367,19 @@ export class MouseEventManager { maxZoom, isNegative ? this.state.cameraPosition[2] / delta - : this.state.cameraPosition[2] * delta, - ), + : this.state.cameraPosition[2] * delta + ) ); // Calculate the ratio of the new zoom to the original zoom const zoomRatio = newZoom / this.state.cameraPosition[2]; // Update camera position and zoom level - this.state.cameraPosition[0] = this.state.mousePosition[0] - - (this.state.mousePosition[0] - this.state.cameraPosition[0]) / - zoomRatio; - this.state.cameraPosition[1] = this.state.mousePosition[1] - - (this.state.mousePosition[1] - this.state.cameraPosition[1]) / - zoomRatio, - this.state.cameraPosition[2] = newZoom; + this.state.cameraPosition[0] = this.state.mousePosition[0] + - (this.state.mousePosition[0] - this.state.cameraPosition[0]) + / zoomRatio; + this.state.cameraPosition[1] = this.state.mousePosition[1] + - (this.state.mousePosition[1] - this.state.cameraPosition[1]) + / zoomRatio, this.state.cameraPosition[2] = newZoom; } - } diff --git a/app/src/lib/graph-interface/helpers/index.ts b/app/src/lib/graph-interface/helpers/index.ts index f3f9d0f..8a26774 100644 --- a/app/src/lib/graph-interface/helpers/index.ts +++ b/app/src/lib/graph-interface/helpers/index.ts @@ -8,7 +8,7 @@ export function lerp(a: number, b: number, t: number) { export function animate( duration: number, - callback: (progress: number) => void | false, + callback: (progress: number) => void | false ) { const start = performance.now(); const loop = (time: number) => { @@ -33,41 +33,37 @@ export function createNodePath({ cornerBottom = 0, leftBump = false, rightBump = false, - aspectRatio = 1, + aspectRatio = 1 } = {}) { return `M0,${cornerTop} - ${ - cornerTop - ? ` V${cornerTop} + ${cornerTop + ? ` V${cornerTop} Q0,0 ${cornerTop * aspectRatio},0 H${100 - cornerTop * aspectRatio} Q100,0 100,${cornerTop} ` - : ` V0 + : ` V0 H100 ` - } + } V${y - height / 2} - ${ - rightBump - ? ` C${100 - depth},${y - height / 2} ${100 - depth},${y + height / 2} 100,${y + height / 2}` - : ` H100` - } - ${ - cornerBottom - ? ` V${100 - cornerBottom} + ${rightBump + ? ` C${100 - depth},${y - height / 2} ${100 - depth},${y + height / 2} 100,${y + height / 2}` + : ` H100` + } + ${cornerBottom + ? ` V${100 - cornerBottom} Q100,100 ${100 - cornerBottom * aspectRatio},100 H${cornerBottom * aspectRatio} Q0,100 0,${100 - cornerBottom} ` - : `${leftBump ? `V100 H0` : `V100`}` - } - ${ - leftBump - ? ` V${y + height / 2} C${depth},${y + height / 2} ${depth},${y - height / 2} 0,${y - height / 2}` - : ` H0` - } - Z`.replace(/\s+/g, " "); + : `${leftBump ? `V100 H0` : `V100`}` + } + ${leftBump + ? ` V${y + height / 2} C${depth},${y + height / 2} ${depth},${y - height / 2} 0,${y - height / 2}` + : ` H0` + } + Z`.replace(/\s+/g, ' '); } export const debounce = (fn: Function, ms = 300) => { @@ -78,14 +74,13 @@ export const debounce = (fn: Function, ms = 300) => { }; }; -export const clone: (v: T) => T = - "structedClone" in globalThis - ? globalThis.structuredClone - : (obj) => JSON.parse(JSON.stringify(obj)); +export const clone: (v: T) => T = 'structedClone' in globalThis + ? globalThis.structuredClone + : (obj) => JSON.parse(JSON.stringify(obj)); export function withSubComponents>( component: A, - subcomponents: B, + subcomponents: B ): A & B { Object.keys(subcomponents).forEach((key) => { // eslint-disable-next-line @typescript-eslint/no-explicit-any @@ -93,3 +88,27 @@ export function withSubComponents>( }); return component as A & B; } + +export function distanceFromPointToSegment( + x1: number, + y1: number, + x2: number, + y2: number, + x0: number, + y0: number +): number { + const dx = x2 - x1; + const dy = y2 - y1; + + if (dx === 0 && dy === 0) { + return Math.hypot(x0 - x1, y0 - y1); + } + + const t = ((x0 - x1) * dx + (y0 - y1) * dy) / (dx * dx + dy * dy); + const clampedT = Math.max(0, Math.min(1, t)); + + const px = x1 + clampedT * dx; + const py = y1 + clampedT * dy; + + return Math.hypot(x0 - px, y0 - py); +} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 962f6bf..476c9e0 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -1,18 +1,5 @@ -export type { NodeInput } from "./inputs"; -export type { - NodeRegistry, - RuntimeExecutor, - SyncCache, - AsyncCache, -} from "./components"; -export type { - SerializedNode, - NodeInstance, - NodeDefinition, - Socket, - NodeId, - Edge, - Graph, -} from "./types"; -export { NodeSchema, GraphSchema } from "./types"; -export { NodeDefinitionSchema } from "./types"; +export type { AsyncCache, NodeRegistry, RuntimeExecutor, SyncCache } from './components'; +export type { NodeInput } from './inputs'; +export type { Box, Edge, Graph, NodeDefinition, NodeId, NodeInstance, SerializedNode, Socket } from './types'; +export { GraphSchema, NodeSchema } from './types'; +export { NodeDefinitionSchema } from './types'; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 278b7f6..2a9167b 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -1,9 +1,16 @@ -import { z } from "zod"; -import { NodeInputSchema } from "./inputs"; +import { z } from 'zod'; +import { NodeInputSchema } from './inputs'; + +export type Box = { + minX: number; + maxX: number; + minY: number; + maxY: number; +}; export const NodeIdSchema = z .string() - .regex(/^[^/]+\/[^/]+\/[^/]+$/, "Invalid NodeId format") + .regex(/^[^/]+\/[^/]+\/[^/]+$/, 'Invalid NodeId format') .transform((value) => value as `${string}/${string}/${string}`); export type NodeId = z.infer; @@ -35,9 +42,9 @@ export const NodeDefinitionSchema = z.object({ meta: z .object({ description: z.string().optional(), - title: z.string().optional(), + title: z.string().optional() }) - .optional(), + .optional() }); export const NodeSchema = z.object({ @@ -49,13 +56,12 @@ export const NodeSchema = z.object({ meta: z .object({ title: z.string().optional(), - lastModified: z.string().optional(), + lastModified: z.string().optional() }) .optional(), - position: z.tuple([z.number(), z.number()]), + position: z.tuple([z.number(), z.number()]) }); - export type SerializedNode = z.infer; export type NodeDefinition = z.infer & { @@ -75,12 +81,12 @@ export const GraphSchema = z.object({ meta: z .object({ title: z.string().optional(), - lastModified: z.string().optional(), + lastModified: z.string().optional() }) .optional(), settings: z.record(z.string(), z.any()).optional(), nodes: z.array(NodeSchema), - edges: z.array(z.tuple([z.number(), z.number(), z.number(), z.string()])), + edges: z.array(z.tuple([z.number(), z.number(), z.number(), z.string()])) }); export type Graph = z.infer; From 8693c63d168cc6a8462b909c79215a0a4066c4fe Mon Sep 17 00:00:00 2001 From: Max Richter Date: Tue, 20 Jan 2026 17:55:58 +0100 Subject: [PATCH 14/14] feat: resize canvases to fit window height Closes #16 The canvases fit their parents size, so adding a wrapper with 100vh solved it. https://threlte.xyz/docs/reference/core/canvas#size --- .../lib/graph-interface/graph/Graph.svelte | 1 + app/src/lib/result-viewer/Viewer.svelte | 20 ++++++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index 5e7485b..00da50c 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -105,6 +105,7 @@ onwheel={(ev) => mouseEvents.handleMouseScroll(ev)} bind:this={graphState.wrapper} class="graph-wrapper" + style="height: 100vh;" class:is-panning={graphState.isPanning} class:is-hovering={graphState.hoveredNodeId !== -1} aria-label="Graph" diff --git a/app/src/lib/result-viewer/Viewer.svelte b/app/src/lib/result-viewer/Viewer.svelte index e4f2553..b5735b9 100644 --- a/app/src/lib/result-viewer/Viewer.svelte +++ b/app/src/lib/result-viewer/Viewer.svelte @@ -95,12 +95,14 @@ {/if} - - - +
+ + + +