From 72f07d0a501fa715c40cf0e7c17527ef3f98e96b Mon Sep 17 00:00:00 2001 From: Max Richter Date: Sun, 26 Apr 2026 18:41:25 +0200 Subject: [PATCH 01/44] feat: initial node groups --- .../graph-interface/components/AddMenu.svelte | 2 +- .../graph-interface/graph-manager.svelte.ts | 119 +++++++++++-- .../lib/graph-interface/graph-state.svelte.ts | 161 +++++++++++++++++- .../lib/graph-interface/graph/Graph.svelte | 23 +-- .../graph-interface/helpers/nodeHelpers.ts | 31 +--- app/src/lib/graph-interface/keymaps.ts | 13 ++ app/src/lib/graph-interface/node/Node.svelte | 11 +- .../lib/graph-interface/node/NodeHTML.svelte | 11 +- .../graph-interface/node/NodeHeader.svelte | 3 +- .../graph-interface/node/NodeParameter.svelte | 6 +- app/src/lib/node-registry/debugNode.ts | 2 +- app/src/lib/node-registry/groupNode.ts | 13 ++ .../lib/node-registry/node-registry-client.ts | 3 + app/src/lib/runtime/runtime-executor.ts | 148 +++++++++++++++- app/src/routes/+page.svelte | 2 +- packages/types/src/index.ts | 3 +- packages/types/src/types.ts | 13 +- 17 files changed, 488 insertions(+), 76 deletions(-) create mode 100644 app/src/lib/node-registry/groupNode.ts diff --git a/app/src/lib/graph-interface/components/AddMenu.svelte b/app/src/lib/graph-interface/components/AddMenu.svelte index 36d46c6..391be4f 100644 --- a/app/src/lib/graph-interface/components/AddMenu.svelte +++ b/app/src/lib/graph-interface/components/AddMenu.svelte @@ -183,7 +183,7 @@ activeNodeId = node.id; }} > - {node.id.split('/').at(-1)} + {node.meta?.title ?? node.id.split('/').at(-1)} {/each} diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 1a8907f..31c51a0 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -10,6 +10,7 @@ import type { NodeRegistry, Socket } from '@nodarium/types'; +import { type GroupDefinition } from '@nodarium/types'; import { fastHashString } from '@nodarium/utils'; import { createLogger } from '@nodarium/utils'; import { SvelteMap, SvelteSet } from 'svelte/reactivity'; @@ -67,7 +68,7 @@ export class GraphManager extends EventEmitter<{ status = $state<'loading' | 'idle' | 'error'>(); loaded = false; - graph: Graph = { id: 0, nodes: [], edges: [] }; + graph: Graph = { id: 0, nodes: [], edges: [], groups: [] }; id = $state(0); nodes = new SvelteMap(); @@ -110,10 +111,36 @@ export class GraphManager extends EventEmitter<{ edge[2].id, edge[3] ]) as Graph['edges']; + + const groups = this.graph.groups?.map((group) => { + const groupNodes = group.nodes.map((node) => ({ + id: node.id, + position: [...node.position], + type: node.type, + props: node.props + })) as NodeInstance[]; + + const groupEdges = this.edges.map((edge) => [ + edge[0].id, + edge[1], + edge[2].id, + edge[3] + ]) as Graph['edges']; + + return { + id: group.id, + inputs: group.inputs, + outputs: group.outputs, + nodes: groupNodes, + edges: groupEdges + }; + }); + const serialized = { id: this.graph.id, settings: $state.snapshot(this.settings), meta: $state.snapshot(this.graph.meta), + groups, nodes, edges }; @@ -311,13 +338,16 @@ export class GraphManager extends EventEmitter<{ logger.info('loading graph', { nodes: graph.nodes, edges: graph.edges, id: graph.id }); - const nodeIds = Array.from(new SvelteSet([...graph.nodes.map((n) => n.type)])); + const nodeIds = Array + .from(new SvelteSet([...graph.nodes.map((n) => n.type)])) + .filter(n => !n.startsWith('__internal/')); await this.registry.load(nodeIds); // Fetch all nodes from all collections of the loaded nodes const allCollections = new SvelteSet<`${string}/${string}`>(); for (const id of nodeIds) { const [user, collection] = id.split('/'); + if (user === '__internal') continue; allCollections.add(`${user}/${collection}`); } for (const collection of allCollections) { @@ -333,7 +363,7 @@ export class GraphManager extends EventEmitter<{ for (const node of this.graph.nodes) { const nodeType = this.registry.getNode(node.type); - if (!nodeType) { + if (!nodeType && !node.type.startsWith('__internal/')) { logger.error(`Node type not found: ${node.type}`); this.status = 'error'; return; @@ -389,15 +419,47 @@ export class GraphManager extends EventEmitter<{ } getAllNodes() { - return Array.from(this.nodes.values()); + this.graph.groups ??= []; + if (!this.graph.groups.length) { + this.graph.groups.push({ + id: 0, + nodes: [], + edges: [] + }); + } + + return Array + .from(this.nodes.values()); } getNode(id: number) { return this.nodes.get(id); } - getNodeType(id: string) { - return this.registry.getNode(id); + getNodeType(node: NodeInstance) { + // Construct the inputs on the fly + if (node.type === '__internal/group/instance') { + const groupDefinition = this.getGroup(node.props?.groupId as number); + + const inputs = { + 'groupId': { + type: 'select', + label: '', + value: node.props?.groupId.toString(), + internal: true, + options: this.graph.groups.map(g => g.id.toString()) + }, + ...(node.state.type?.inputs || {}), + ...groupDefinition?.inputs + }; + + return { + ...node.state.type, + inputs + } as NodeDefinition; + } + + return node.state.type; } async loadNodeType(id: NodeId) { @@ -502,6 +564,14 @@ export class GraphManager extends EventEmitter<{ } } + createGroupId() { + return Math.max(0, ...this.graph.groups.keys()) + 1; + } + + getGroup(id: number) { + return this.graph.groups.find(g => g.id === id); + } + createNodeId() { return Math.max(0, ...this.nodes.keys()) + 1; } @@ -579,6 +649,26 @@ export class GraphManager extends EventEmitter<{ return node; } + createGroupNode(position: [number, number], groupDefinition: GroupDefinition): NodeInstance { + this.graph.groups ??= []; + this.graph.groups.push(groupDefinition); + const node = { + id: this.createNodeId(), + type: '__internal/group/instance', + meta: { + title: 'Group' + }, + props: { + groupId: groupDefinition.id + }, + position, + state: {} + } as const; + + this.nodes.set(node.id, node); + return node; + } + createEdge( from: NodeInstance, fromSocket: number, @@ -597,11 +687,14 @@ export class GraphManager extends EventEmitter<{ return; } + const fromType = this.getNodeType(from); + const toType = this.getNodeType(to); + // check if socket types match - const fromSocketType = from.state?.type?.outputs?.[fromSocket]; - const toSocketType = [to.state?.type?.inputs?.[toSocket]?.type]; - if (to.state?.type?.inputs?.[toSocket]?.accepts) { - toSocketType.push(...(to?.state?.type?.inputs?.[toSocket]?.accepts || [])); + const fromSocketType = fromType?.outputs?.[fromSocket]; + const toSocketType = [toType?.inputs?.[toSocket]?.type]; + if (toType?.inputs?.[toSocket]?.accepts) { + toSocketType.push(...(toType?.inputs?.[toSocket]?.accepts || [])); } if (!areSocketsCompatible(fromSocketType, toSocketType)) { @@ -724,7 +817,7 @@ export class GraphManager extends EventEmitter<{ } getPossibleSockets({ node, index }: Socket): [NodeInstance, string | number][] { - const nodeType = node?.state?.type; + const nodeType = this.getNodeType(node); if (!nodeType) return []; const sockets: [NodeInstance, string | number][] = []; @@ -740,7 +833,7 @@ export class GraphManager extends EventEmitter<{ const ownType = nodeType?.inputs?.[index].type; for (const node of nodes) { - const nodeType = node?.state?.type; + const nodeType = this.getNodeType(node); const inputs = nodeType?.outputs; if (!inputs) continue; for (let index = 0; index < inputs.length; index++) { @@ -772,7 +865,7 @@ export class GraphManager extends EventEmitter<{ const ownType = nodeType.outputs?.[index]; for (const node of nodes) { - const inputs = node?.state?.type?.inputs; + const inputs = this.getNodeType(node)?.inputs; if (!inputs) continue; for (const key in inputs) { const otherType = [inputs[key].type]; diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index 7127bb1..53cb68b 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -1,11 +1,11 @@ import { animate, lerp } from '$lib/helpers'; -import type { NodeInstance, Socket } from '@nodarium/types'; +import type { Box, Edge, GroupDefinition, NodeInput, NodeInstance, Socket } from '@nodarium/types'; import { getContext, setContext } from 'svelte'; import { SvelteMap, SvelteSet } from 'svelte/reactivity'; import type { OrthographicCamera, Vector3 } from 'three'; import type { GraphManager } from './graph-manager.svelte'; import { ColorGenerator } from './graph/colors'; -import { getNodeHeight, getSocketPosition } from './helpers/nodeHelpers'; +import { getNodeHeight, getParameterHeight } from './helpers/nodeHelpers'; const graphStateKey = Symbol('graph-state'); export function getGraphState() { @@ -203,7 +203,7 @@ export class GraphState { } const debugNode = this.graph.createNode({ - type: 'max/plantarium/debug', + type: '__internal/node/debug', position: [node.position[0] + 30, node.position[1]], props: {} }); @@ -240,6 +240,119 @@ export class GraphState { }; } + groupSelectedNodes(nodeIds = [...this.selectedNodes.keys(), this.activeNodeId]) { + const ids = new Set(nodeIds); + const nodes = [ + ...ids.values().map(id => this.graph.getNode(id)).filter(Boolean) + ] as NodeInstance[]; + + const incomingEdges = this.graph.edges.filter((edge) => + ids.has(edge[2].id) && !ids.has(edge[0].id) + ); + const groupInputs = new Map(); + for (const edge of incomingEdges) { + groupInputs.set(`${edge[0].id}-${edge[1]}`, edge); + } + + const outgoingEdges = this.graph.edges.filter((edge) => + ids.has(edge[0].id) && !ids.has(edge[2].id) + ); + const groupOutputs = new Map(); + for (const edge of outgoingEdges) { + groupOutputs.set(`${edge[2].id}-${edge[3]}`, edge); + } + + const inputs: Record = {}; + [...groupInputs.values()].forEach((edge, i) => { + const input = { + label: `Input ${i}`, + type: edge[0].state.type?.outputs?.[edge[1]] || '*' + }; + inputs[`input_${i}`] = input as NodeInput; + }); + + const outputs = [...groupOutputs.values()].map((edge, i) => ({ + label: `Output ${i}`, + type: edge[2].state.type?.inputs?.[edge[3]].type + })); + + const groupPosition = [0, 0] as [number, number]; + const bounds: Box = { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity }; + for (const node of nodes) { + groupPosition[0] += node.position[0]; + groupPosition[1] += node.position[1]; + bounds.minX = Math.min(bounds.minX, node.position[0]); + bounds.maxX = Math.max(bounds.maxX, node.position[0]); + bounds.minY = Math.min(bounds.minY, node.position[1]); + bounds.maxY = Math.max(bounds.maxY, node.position[1]); + } + groupPosition[0] /= nodes.length; + groupPosition[1] /= nodes.length; + + const groupInputNode: NodeInstance = { + id: this.graph.createNodeId(), + type: '__internal/group/input', + position: [bounds.minX - 50, (bounds.minY + bounds.maxY) / 2], + state: {} + }; + + const groupOutputNode: NodeInstance = { + id: this.graph.createNodeId(), + type: '__internal/group/output', + position: [bounds.maxX + 25, (bounds.minY + bounds.maxY) / 2], + state: {} + }; + + // Edges that are inside the group + const internalEdges = this.graph.edges.filter((edge) => { + return ids.has(edge[0].id) || ids.has(edge[2].id); + }).map((edge) => { + // Going in from the group + if (!ids.has(edge[0].id)) { + return [groupInputNode, 0, edge[2], edge[3]]; + // Going out to the group + } else if (!ids.has(edge[2].id)) { + return [edge[0], edge[1], groupOutputNode, 'Out']; + } + return edge; + }); + + const groupId = this.graph.createGroupId(); + const groupDefinition: GroupDefinition = { + id: groupId, + inputs: inputs, + outputs: outputs, + edges: internalEdges, + nodes: [groupInputNode, ...nodes, groupOutputNode] + }; + const groupNode = this.graph.createGroupNode(groupPosition, groupDefinition); + + // Update the edges that are now inside + // the group to be connected to that group node + const externalEdges = this.graph.edges.map((edge) => { + if (ids.has(edge[2].id)) { + // Edge going into the group + return [edge[0], edge[1], groupNode, 'input_0'] as Edge; + } else if (ids.has(edge[0].id)) { + // Edge going out of the group + return [groupNode, 0, edge[2], edge[3]] as Edge; + } + return edge; + }); + + for (const node of nodes) { + this.graph.nodes.delete(node.id); + } + this.graph.edges = externalEdges; + this.graph.saveUndoGroup(); + console.log( + $state.snapshot({ + groupNode, + groupDefinition + }) + ); + } + centerNode(node?: NodeInstance) { const average = [0, 0, 4]; if (node) { @@ -301,7 +414,7 @@ export class GraphState { if (edge[3] === index) { node = edge[0]; index = edge[1]; - position = getSocketPosition(node, index); + position = this.getSocketPosition(node, index); this.graph.removeEdge(edge); break; } @@ -321,7 +434,7 @@ export class GraphState { return { node, index, - position: getSocketPosition(node, index) + position: this.getSocketPosition(node, index) }; }); } @@ -358,7 +471,7 @@ export class GraphState { for (const node of this.graph.nodes.values()) { const x = node.position[0]; const y = node.position[1]; - const height = getNodeHeight(node.state.type!); + const height = getNodeHeight(this.graph.getNodeType(node)!); if (downX > x && downX < x + 20 && downY > y && downY < y + height) { clickedNodeId = node.id; break; @@ -370,7 +483,7 @@ export class GraphState { } isNodeInView(node: NodeInstance) { - const height = getNodeHeight(node.state.type!); + const height = getNodeHeight(this.graph.getNodeType(node)!); const width = 20; return node.position[0] > this.cameraBounds[0] - width && node.position[0] < this.cameraBounds[1] @@ -381,4 +494,38 @@ export class GraphState { openNodePalette() { this.addMenuPosition = [this.mousePosition[0], this.mousePosition[1]]; } + + enterGroupNode() { + if (this.activeNodeId === -1) return; + const selectedNode = this.graph.getNode(this.activeNodeId); + if (!selectedNode || selectedNode.type.startsWith('__internal/group/instance')) return; + } + + getSocketPosition( + node: NodeInstance, + index: string | number + ): [number, number] { + if (typeof index === 'number') { + return [ + (node?.state?.x ?? node.position[0]) + 20, + (node?.state?.y ?? node.position[1]) + 2.5 + 10 * index + ]; + } else { + let height = 5; + const nodeType = this.graph.getNodeType(node)!; + const inputs = nodeType.inputs || {}; + for (const inputKey in inputs) { + const h = getParameterHeight(nodeType, inputKey) / 10; + if (inputKey === index) { + height += h / 2; + break; + } + height += h; + } + return [ + node?.state?.x ?? node.position[0], + (node?.state?.y ?? node.position[1]) + height + ]; + } + } } diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index 2460265..108b9a3 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -11,7 +11,6 @@ import Debug from '../debug/Debug.svelte'; import EdgeEl from '../edges/Edge.svelte'; import { getGraphManager, getGraphState } from '../graph-state.svelte'; - import { getSocketPosition } from '../helpers/nodeHelpers'; import NodeEl from '../node/Node.svelte'; import { maxZoom, minZoom } from './constants'; import { FileDropEventManager } from './drop.events'; @@ -39,8 +38,8 @@ return [0, 0, 0, 0]; } - const pos1 = getSocketPosition(fromNode, edge[1]); - const pos2 = getSocketPosition(toNode, edge[3]); + const pos1 = graphState.getSocketPosition(fromNode, edge[1]); + const pos2 = graphState.getSocketPosition(toNode, edge[3]); return [pos1[0], pos1[1], pos2[0], pos2[1]]; } @@ -96,11 +95,13 @@ graphState.addMenuPosition = null; } - function getSocketType(node: NodeInstance, index: number | string): string { + function getSocketType(node: NodeInstance, index: number | string, e: unknown): string { + const nodeType = graph.getNodeType(node); + console.log($state.snapshot({ nodeType, index, e })); if (typeof index === 'string') { - return node.state.type?.inputs?.[index].type || 'unknown'; + return nodeType?.inputs?.[index].type || 'unknown'; } - return node.state.type?.outputs?.[index] || 'unknown'; + return nodeType?.outputs?.[index] || 'unknown'; } @@ -182,8 +183,8 @@ {#if graphState.activeSocket} - {#each graph.nodes.values() as node (node.id)} + {#each graph.getAllNodes() as node (node.id)} = {}; export function getNodeHeight(node: NodeDefinition) { + if (!node) { + console.trace('Node is undefined', node); + } if (node.id in nodeHeightCache) { return nodeHeightCache[node.id]; } diff --git a/app/src/lib/graph-interface/keymaps.ts b/app/src/lib/graph-interface/keymaps.ts index 3614ed1..661344e 100644 --- a/app/src/lib/graph-interface/keymaps.ts +++ b/app/src/lib/graph-interface/keymaps.ts @@ -54,6 +54,19 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr } }); + keymap.addShortcut({ + key: 'g', + ctrl: true, + description: 'Group selected nodes', + callback: () => graphState.groupSelectedNodes() + }); + + keymap.addShortcut({ + key: 'Tab', + description: 'Enter selected node group', + callback: () => graphState.enterGroupNode() + }); + keymap.addShortcut({ key: 'A', shift: true, diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index cba7fd7..438183f 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -3,13 +3,14 @@ import type { NodeInstance } from '@nodarium/types'; import { T } from '@threlte/core'; import { type Mesh } from 'three'; - import { getGraphState } from '../graph-state.svelte'; + import { getGraphManager, getGraphState } from '../graph-state.svelte'; import { colors } from '../graph/colors.svelte'; import { getNodeHeight, getParameterHeight } from '../helpers/nodeHelpers'; import NodeFrag from './Node.frag'; import NodeVert from './Node.vert'; import NodeHtml from './NodeHTML.svelte'; + const graph = getGraphManager(); const graphState = getGraphState(); type Props = { @@ -18,7 +19,7 @@ }; let { node = $bindable(), inView }: Props = $props(); - const nodeType = $derived(node.state.type!); + const nodeType = $derived(graph.getNodeType(node)!); const isActive = $derived(graphState.activeNodeId === node.id); const isSelected = $derived(graphState.selectedNodes.has(node.id)); @@ -40,7 +41,11 @@ let meshRef: Mesh | undefined = $state(); - const height = getNodeHeight(node.state.type!); + const height = $derived(getNodeHeight(nodeType)); + + if (node.type.startsWith('__internal/')) { + $inspect({ node, nodeType, height, sectionHeights }); + } const zoom = $derived(graphState.cameraPosition[2]); diff --git a/app/src/lib/graph-interface/node/NodeHTML.svelte b/app/src/lib/graph-interface/node/NodeHTML.svelte index 8cb2b8d..75f45f2 100644 --- a/app/src/lib/graph-interface/node/NodeHTML.svelte +++ b/app/src/lib/graph-interface/node/NodeHTML.svelte @@ -1,11 +1,12 @@ -
-  {graph ? convert(graph) : "No graph loaded"}
-
+
+ {#if data} + + {:else} + No graph loaded + {/if} +
diff --git a/app/src/lib/sidebar/panels/JsonNode.svelte b/app/src/lib/sidebar/panels/JsonNode.svelte new file mode 100644 index 0000000..2868476 --- /dev/null +++ b/app/src/lib/sidebar/panels/JsonNode.svelte @@ -0,0 +1,136 @@ + + + + + + {#if key !== undefined} + {key}: + {/if} + + {#if isExpandable} + {#if items.length === 0} + {open_bracket}{close_bracket} + {:else if open} + {#if depth > 0} + + {/if} + {open_bracket} +
+ {#each items as [k, v], i (k)} +
+ {#if i < items.length - 1},{/if} +
+ {/each} +
+ {close_bracket} + {:else} + + {/if} + {:else if value === null} + null + {:else if typeof value === 'boolean'} + {value} + {:else if typeof value === 'number'} + {value} + {:else if typeof value === 'string'} + "{value}" + {:else} + {String(value)} + {/if} +
diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 86558d8..a442add 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -321,7 +321,7 @@ hidden={!appSettings.value.debug.advancedMode} icon="i-[tabler--code]" > - + Date: Sun, 3 May 2026 13:51:33 +0200 Subject: [PATCH 03/44] docs: add LLM.md --- docs/LLM.md | 204 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/LLM.md diff --git a/docs/LLM.md b/docs/LLM.md new file mode 100644 index 0000000..983cd3d --- /dev/null +++ b/docs/LLM.md @@ -0,0 +1,204 @@ +# Nodarium — LLM Reference + +## What It Is + +Nodarium is a **node-based visual programming editor**. Users wire together nodes on a 2D canvas; each node is a WebAssembly module that receives typed inputs and produces typed outputs. A live Three.js viewer renders the resulting 3D geometry/paths/instances. + +--- + +## Repository Layout + +``` +/ +├── app/ # SvelteKit web app +│ └── src/ +│ ├── routes/+page.svelte # App entry point +│ └── lib/ +│ ├── graph-interface/ # Canvas editor (UI + state) +│ ├── runtime/ # WASM execution engine +│ ├── node-registry/ # Fetch & cache node definitions +│ ├── project-manager/ # IndexDB persistence +│ ├── result-viewer/ # Three.js 3D output +│ ├── sidebar/ # UI panels +│ └── settings/ # App + graph settings +├── packages/ +│ ├── types/ # Shared TypeScript types + Zod schemas +│ ├── utils/ # Logging, hashing, WASM wrapping, perf +│ ├── ui/ # Reusable Svelte UI components +│ ├── planty/ # Tutorial system +│ └── macros/ # Build-time macros +└── docs/ +``` + +--- + +## Core Architecture + +``` +User Interaction + └── GraphInterface + ├── GraphState ← UI: selection, camera, mouse, clipboard + └── GraphManager ← Logic: nodes, edges, history, serialization + ├── NodeRegistry ← fetches WASM definitions (remote API + IndexDB cache) + ├── HistoryManager ← undo/redo (jsondiffpatch deltas) + └── emit('result') → RuntimeExecutor + └── node.execute(Int32Array) per node + └── ResultViewer (Three.js/Threlte) +``` + +**Event flow:** +1. User edits graph → GraphManager mutates state +2. GraphManager emits `save` → ProjectManager persists to IndexDB +3. GraphManager emits `result` → Runtime executes graph → Viewer updates + +--- + +## Critical Files + +| File | Role | +|------|------| +| `app/src/routes/+page.svelte` | Wires all systems; creates GraphManager, runtime, registry | +| `app/src/lib/graph-interface/graph-manager.svelte.ts` | Central graph logic: createNode, createEdge, serialize, load, history | +| `app/src/lib/graph-interface/graph-state.svelte.ts` | UI state: camera, selection, mouse, clipboard, groupSelectedNodes | +| `app/src/lib/graph-interface/graph/Graph.svelte` | Canvas renderer | +| `app/src/lib/graph-interface/node/Node.svelte` | 3D mesh node (Three.js shader) | +| `app/src/lib/graph-interface/node/NodeHTML.svelte` | HTML overlay: labels + parameters | +| `app/src/lib/graph-interface/node/NodeHeader.svelte` | Node title bar | +| `app/src/lib/graph-interface/keymaps.ts` | Keyboard shortcuts | +| `app/src/lib/graph-interface/helpers/nodeHelpers.ts` | Node height calculations | +| `app/src/lib/graph-interface/graph/colors.svelte.ts` | Socket type → color mapping | +| `app/src/lib/runtime/runtime-executor.ts` | Executes nodes in DAG order; expandGroups() | +| `app/src/lib/node-registry/index.ts` | RemoteNodeRegistry entry | +| `app/src/lib/node-registry/groupNode.ts` | Built-in group node definition | +| `app/src/lib/node-registry/debugNode.ts` | Built-in debug node | +| `app/src/lib/sidebar/panels/ActiveNodeSettings.svelte` | Per-node settings panel | +| `packages/types/src/types.ts` | Graph, NodeInstance, NodeDefinition, Edge, GroupDefinition | +| `packages/types/src/inputs.ts` | NodeInput union types (float, vec3, geometry, path, …) | +| `packages/utils/src/wasm.ts` | createWasmWrapper() — wraps WASM bytes into a NodeDefinition | + +--- + +## Key Types + +```typescript +// packages/types/src/types.ts + +type NodeId = `${string}/${string}/${string}` // e.g. "max/plantarium/stem" + +type NodeInstance = { + id: number + type: NodeId + position: [number, number] + props?: Record // current parameter values + meta?: { title?: string; lastModified?: string } + state: NodeRuntimeState // runtime-only, NOT serialized +} + +type NodeRuntimeState = { + type?: NodeDefinition // resolved definition + parents?: NodeInstance[] + children?: NodeInstance[] + x?: number; y?: number // interpolated position + mesh?: Mesh // Three.js mesh reference + ref?: HTMLElement +} + +type NodeDefinition = { + id: NodeId + inputs?: Record + outputs?: string[] // output type names + meta?: { title?: string; description?: string } + execute(input: Int32Array): Int32Array // WASM function +} + +// Edge: [fromNode, outputIndex, toNode, inputSocketName] +type Edge = [NodeInstance, number, NodeInstance, string] + +type Graph = { + nodes: NodeInstance[] + edges: [number, number, number, string][] // serialized (IDs, not refs) + settings: Record + groups: GroupDefinition[] +} + +type GroupDefinition = { + id: number + nodes: NodeInstance[] + edges: Edge[] + inputs?: Record + outputs?: string[] +} +``` + +### NodeInput socket types +`float` | `integer` | `boolean` | `select` | `seed` | `vec3` | `geometry` | `path` | `shape` | `color` | `*` (wildcard) + +Each input can have: `value` (default), `label`, `hidden`, `external`, `setting` (link to graph setting), `accepts` (extra compatible types). + +--- + +## Patterns & Conventions + +### Svelte 5 reactivity +The codebase uses Svelte 5 runes throughout — `$state`, `$derived`, `$effect`. Collections use `SvelteMap` and `SvelteSet` (from `svelte/reactivity`) instead of plain Map/Set so that mutations trigger reactive updates. + +### Context API +`GraphManager` and `GraphState` are provided via Svelte context (`setContext` / `getContext`) inside `GraphInterface`. All child components (Node, Edge, etc.) consume them via context rather than props. + +### Edge representation +In memory, edges are `[NodeInstance, outputIndex, NodeInstance, inputSocketName]` — direct object references for fast traversal. On serialization (`Graph.edges`), they become `[nodeId, outputIndex, nodeId, inputSocketName]` (plain IDs). + +### Socket compatibility +```typescript +areSocketsCompatible(outputType: string, inputType: string | string[]): boolean +// '*' wildcard matches any type; 'geometry' accepts ['geometry', 'instances'] +``` + +### WASM execution interface +Every node exposes a single function: `execute(input: Int32Array): Int32Array`. +Data encoding (Plantarium): +- `[0, stemDepth, ...x,y,z,thickness]` — path +- `[1, vertexCount, faceCount, ...faces, ...vertices, ...normals]` — geometry +- `[2, vertexCount, faceCount, instanceCount, stemDepth, ...]` — instances + +### Event emitter +`GraphManager extends EventEmitter<{ save, result, settings }>`. Subscribe with `manager.on('result', cb)`. Used to decouple the editor UI from runtime execution and persistence. + +### History +Every mutation goes through `HistoryManager`. Call `this.history.save(this.serialize())` before mutations; undo/redo replays jsondiffpatch deltas. + +### Internal node IDs +Built-in nodes use the `__internal/` namespace: `__internal/group/instance`, `__internal/node/debug`. Virtual boundary nodes use `__virtual/`: `__virtual/group/input`, `__virtual/group/output`. + +--- + +## In-Progress: Node Groups (`feat/group-node-own`) + +Group selected nodes with **Ctrl+G**. A `GroupDefinition` is stored in `Graph.groups[]`; a group instance node (`__internal/group/instance`) referencing it by `props.groupId` replaces the selected nodes. + +**Known gaps as of 2026-05-03:** + +| Issue | Location | +|-------|----------| +| `createGroupNode()` called but not defined | `graph-state.svelte.ts:334` → missing in `graph-manager.svelte.ts` | +| Runtime expects `group.graph.nodes/edges`; schema has flat `nodes/edges` | `runtime-executor.ts` vs `types.ts` | +| Runtime expects `group.inputs` as array; schema defines it as `Record` | Same mismatch | +| `enterGroupNode()` is a stub — no group navigation | `graph-state.svelte.ts` | +| `serialize()` writes parent-graph edges into group instead of group-internal edges | `graph-manager.svelte.ts` | + +--- + +## Dev Commands + +Run from `app/`: + +```bash +npm run dev # start dev server (Vite) +npm run build # production build +npm run check # svelte-check + tsc +npm run lint # eslint +npm run test # unit (vitest) + e2e (playwright) +npm run test:unit # vitest only +npm run test:e2e # playwright only +npm run bench # benchmark runner +``` -- 2.52.0 From 6ef5dc28ed9a4874a7b5fb2a9dca73efd1632519 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Sun, 3 May 2026 16:11:40 +0200 Subject: [PATCH 04/44] chore: move jsonviewer into ui package --- app/src/lib/sidebar/panels/GraphSource.svelte | 10 ++--- .../ui/src/lib/JsonViewer.svelte | 39 ++++++++-------- packages/ui/src/lib/index.ts | 1 + packages/ui/src/routes/+page.svelte | 45 +++++++++++++++++++ pnpm-lock.yaml | 6 --- 5 files changed, 71 insertions(+), 30 deletions(-) rename app/src/lib/sidebar/panels/JsonNode.svelte => packages/ui/src/lib/JsonViewer.svelte (73%) diff --git a/app/src/lib/sidebar/panels/GraphSource.svelte b/app/src/lib/sidebar/panels/GraphSource.svelte index 19abd48..efd3fce 100644 --- a/app/src/lib/sidebar/panels/GraphSource.svelte +++ b/app/src/lib/sidebar/panels/GraphSource.svelte @@ -1,22 +1,22 @@
{#if data} - + {:else} No graph loaded {/if} diff --git a/app/src/lib/sidebar/panels/JsonNode.svelte b/packages/ui/src/lib/JsonViewer.svelte similarity index 73% rename from app/src/lib/sidebar/panels/JsonNode.svelte rename to packages/ui/src/lib/JsonViewer.svelte index 2868476..7ee7f94 100644 --- a/app/src/lib/sidebar/panels/JsonNode.svelte +++ b/packages/ui/src/lib/JsonViewer.svelte @@ -31,7 +31,7 @@ -- 2.52.0 From ef217b1c409c25d6054515e1f705831ddbf5a24b Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 11:27:21 +0200 Subject: [PATCH 13/44] feat: some updates --- .../graph-interface/graph-manager.svelte.ts | 165 ++++++++++++++++-- .../lib/graph-interface/graph-state.svelte.ts | 48 ++--- .../lib/graph-interface/graph/Graph.svelte | 45 ++++- .../lib/graph-interface/graph/mouse.events.ts | 2 +- .../graph-interface/helpers/nodeHelpers.ts | 7 +- app/src/lib/graph-interface/keymaps.ts | 5 + app/src/lib/graph-interface/node/Node.svelte | 4 +- .../graph-interface/node/NodeParameter.svelte | 2 +- app/src/lib/graph-templates/grid.ts | 3 +- app/src/lib/graph-templates/tree.ts | 3 +- app/src/lib/runtime/runtime-executor.ts | 2 +- 11 files changed, 222 insertions(+), 64 deletions(-) diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index d123933..5d18e90 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -19,7 +19,7 @@ import EventEmitter from './helpers/EventEmitter'; import { HistoryManager } from './history-manager'; const logger = createLogger('graph-manager'); -logger.mute(); +// logger.mute(); const remoteRegistry = new RemoteNodeRegistry(''); @@ -73,9 +73,22 @@ export class GraphManager extends EventEmitter<{ id = $state(0); nodes = new SvelteMap(); + nodeArray = $derived(Array.from(this.nodes.values())); edges = $state([]); + // Plain array — NOT $state. rootGraph items are plain-serialized (safe for structuredClone). + // savedNodes/savedEdges hold live reactive references so reactivity is preserved on exit. + graphStack: { + rootGraph: Graph; + savedNodes: Map; + savedEdges: Edge[]; + outerGraph: Graph; + groupId: number; + nodeId: number; + cameraPosition: [number, number, number]; + }[] = []; + settingTypes: Record = {}; settings = $state>(); @@ -90,9 +103,25 @@ export class GraphManager extends EventEmitter<{ }); history: HistoryManager = new HistoryManager(); + + private serializeFullGraph(): Graph { + if (this.graphStack.length === 0) return this.serialize(); + let merged = this.serialize(); + for (let i = this.graphStack.length - 1; i >= 0; i--) { + const { rootGraph, groupId } = this.graphStack[i]; + merged = { + ...rootGraph, + groups: rootGraph.groups.map(g => + g.id === groupId ? { ...g, nodes: merged.nodes, edges: merged.edges } : g + ) + }; + } + return merged; + } + execute = throttle(() => { if (this.loaded === false) return; - this.emit('result', this.serialize()); + this.emit('result', this.serializeFullGraph()); }, 10); constructor(public registry: NodeRegistry) { @@ -263,6 +292,28 @@ export class GraphManager extends EventEmitter<{ }); } + tryConnectToDebugNode(nodeId: number) { + const node = this.nodes.get(nodeId); + if (!node) return; + if (node.type.endsWith('/debug')) return; + if (!node.state.type?.outputs?.length) return; + let debugNode = this.nodes.values().find(n => n.type.endsWith('/debug')); + + if (!debugNode) { + debugNode = this.createNode({ + type: '__internal/node/debug', + position: [node.position[0] + 30, node.position[1]], + props: {} + }); + } + + if (debugNode) { + this.createEdge(node, 0, debugNode, 'input'); + } + + return debugNode; + } + getEdgesBetweenNodes(nodes: NodeInstance[]): [number, number, number, string][] { const edges = []; for (const node of nodes) { @@ -290,13 +341,11 @@ export class GraphManager extends EventEmitter<{ private _init(graph: Graph) { const nodes = new SvelteMap( graph.nodes.map((node) => { - const nodeType = this.registry.getNode(node.type); const n = node as NodeInstance; - if (nodeType) { - n.state = { - type: nodeType - }; - } + const registryType = this.registry.getNode(node.type); + n.state = registryType ? { type: registryType } : {}; + const resolvedType = this.getNodeType(n); + if (resolvedType) n.state = { type: resolvedType }; return [node.id, n]; }) ); @@ -436,6 +485,39 @@ export class GraphManager extends EventEmitter<{ } getNodeType(node: NodeInstance) { + if (!node) { + console.trace('failed to get node type'); + return; + } + + if (node.type === '__internal/group/input') { + const groupId = this.graphStack.at(-1)?.groupId; + const group = groupId !== undefined ? this.getGroup(groupId) : undefined; + if (!group) return node.state.type; + return { + id: '__internal/group/input' as NodeId, + outputs: Object.values(group.inputs ?? {}).map(i => i.type), + execute: (x: Int32Array) => x + } as NodeDefinition; + } + + if (node.type === '__internal/group/output') { + const groupId = this.graphStack.at(-1)?.groupId; + const group = groupId !== undefined ? this.getGroup(groupId) : undefined; + if (!group) return node.state.type; + return { + id: '__internal/group/output' as NodeId, + inputs: Object.fromEntries( + (group.outputs ?? []).map(( + o, + i + ) => [`out_${i}`, { type: o.type, label: o.label, external: true }]) + ), + outputs: [], + execute: (x: Int32Array) => x + } as NodeDefinition; + } + // Construct the group inputs on the fly if (node.type === '__internal/group/instance') { const groupDefinition = this.getGroup(node.props?.groupId as number); @@ -446,15 +528,15 @@ export class GraphManager extends EventEmitter<{ } const inputs = { + ...(node.state.type?.inputs || {}), + ...groupDefinition?.inputs, 'groupId': { type: 'select', label: '', value: node.props?.groupId, internal: true, options: this.graph.groups.map(g => g.id) - }, - ...(node.state.type?.inputs || {}), - ...groupDefinition?.inputs + } }; const groupType = { @@ -576,6 +658,58 @@ export class GraphManager extends EventEmitter<{ return this.graph.groups.find(g => g.id === id); } + isInsideGroup = $state(false); + + enterGroup(nodeId: number, cameraPosition: [number, number, number]): boolean { + const groupNode = this.getNode(nodeId); + if (!groupNode || groupNode.type !== '__internal/group/instance') return false; + const groupId = groupNode.props?.groupId as number; + const group = this.getGroup(groupId); + if (!group) return false; + + this.graphStack.push({ + rootGraph: this.serialize(), + savedNodes: new Map(this.nodes), + savedEdges: [...this.edges], + outerGraph: this.graph, + groupId, + nodeId, + cameraPosition + }); + this.graph = { ...this.graph, nodes: group.nodes, edges: group.edges }; + this._init(this.graph); + this.history.reset(); + this.isInsideGroup = true; + return true; + } + + exitGroup(): { camera: [number, number, number]; nodeId: number } | false { + if (!this.graphStack.length) return false; + const { savedNodes, savedEdges, outerGraph, groupId, nodeId, cameraPosition } = this.graphStack.pop()!; + const internalState = this.serialize(); + + // Restore live reactive nodes and edges so drag-reactivity is preserved + this.nodes.clear(); + for (const [id, node] of savedNodes) { + this.nodes.set(id, node); + } + this.edges = savedEdges; + + // Patch the group definition with the edited internal graph + this.graph = { + ...outerGraph, + groups: (outerGraph.groups ?? []).map(g => + g.id === groupId ? { ...g, nodes: internalState.nodes, edges: internalState.edges } : g + ) + }; + + this.history.reset(); + this.isInsideGroup = this.graphStack.length > 0; + this.execute(); + this.save(); + return { camera: cameraPosition, nodeId }; + } + createNodeId() { const ids = [ ...this.nodes.keys(), @@ -583,6 +717,8 @@ export class GraphManager extends EventEmitter<{ ...this.graph.groups.flatMap(g => g.nodes.map(n => n.id)) ]; + console.log('CREATE NODE ID', ids); + let id = 0; while (ids.includes(id)) { id++; @@ -723,7 +859,7 @@ export class GraphManager extends EventEmitter<{ return [groupInputNode.id, 0, edge[2].id, edge[3]]; // Going out to the group } else if (!ids.has(edge[2].id)) { - return [edge[0].id, edge[1], groupOutputNode.id, 'Out']; + return [edge[0].id, edge[1], groupOutputNode.id, 'out_0']; } return [edge[0].id, edge[1], edge[2].id, edge[3]]; }) as [number, number, number, string][]; @@ -900,8 +1036,9 @@ export class GraphManager extends EventEmitter<{ return; } - this.emit('save', state); - logger.log('saving graphs', state); + const fullState = this.graphStack.length > 0 ? this.serializeFullGraph() : state; + this.emit('save', fullState); + logger.log('saving graphs', fullState); } getParentsOfNode(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 ce5b24e..fb24cc4 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -152,10 +152,6 @@ export class GraphState { this.edges.delete(edgeId); } - getEdgeData() { - return this.edges; - } - updateNodePosition(node: NodeInstance) { if ( node.state.x === node.position[0] @@ -190,29 +186,6 @@ export class GraphState { return 1; } - tryConnectToDebugNode(nodeId: number) { - const node = this.graph.nodes.get(nodeId); - if (!node) return; - if (node.type.endsWith('/debug')) return; - if (!node.state.type?.outputs?.length) return; - for (const _node of this.graph.nodes.values()) { - if (_node.type.endsWith('/debug')) { - this.graph.createEdge(node, 0, _node, 'input'); - return; - } - } - - const debugNode = this.graph.createNode({ - type: '__internal/node/debug', - position: [node.position[0] + 30, node.position[1]], - props: {} - }); - - if (debugNode) { - this.graph.createEdge(node, 0, debugNode, 'input'); - } - } - copyNodes() { if (this.activeNodeId === -1 && !this.selectedNodes?.size) { return; @@ -362,7 +335,8 @@ export class GraphState { for (const node of this.graph.nodes.values()) { const x = node.position[0]; const y = node.position[1]; - const height = getNodeHeight(this.graph.getNodeType(node)!); + const nodeType = this.graph.getNodeType(node); + const height = nodeType ? getNodeHeight(nodeType) : 20; if (downX > x && downX < x + 20 && downY > y && downY < y + height) { clickedNodeId = node.id; break; @@ -374,6 +348,7 @@ export class GraphState { } isNodeInView(node: NodeInstance) { + if (!node) return false; const height = getNodeHeight(this.graph.getNodeType(node)!); const width = 20; return node.position[0] > this.cameraBounds[0] - width @@ -388,8 +363,21 @@ export class GraphState { enterGroupNode() { if (this.activeNodeId === -1) return; - const selectedNode = this.graph.getNode(this.activeNodeId); - if (!selectedNode || selectedNode.type.startsWith('__internal/group/instance')) return; + const node = this.graph.getNode(this.activeNodeId); + if (!node || node.type !== '__internal/group/instance') return; + const ok = this.graph.enterGroup(this.activeNodeId, [...this.cameraPosition]); + if (ok) { + this.activeNodeId = -1; + this.clearSelection(); + } + } + + exitGroupNode() { + const result = this.graph.exitGroup(); + if (!result) return; + this.cameraPosition = result.camera; + this.activeNodeId = -1; + this.clearSelection(); } getSocketPosition( diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index bbe40e1..f1bad0b 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -95,8 +95,9 @@ graphState.addMenuPosition = null; } - function getSocketType(node: NodeInstance, index: number | string, e: unknown): string { + function getSocketType(node: NodeInstance, index: number | string): string { const nodeType = graph.getNodeType(node); + console.log({ nodeType, index }); if (typeof index === 'string') { return nodeType?.inputs?.[index].type || 'unknown'; } @@ -169,6 +170,14 @@ {/if} {#if graph.status === 'idle'} + {#if graph.isInsideGroup} + + + + {/if} + {#if graphState.addMenuPosition} - {#each graph.getAllNodes() as node (node.id)} + {#each graph.nodeArray as node, index (node.id)} {/each}
@@ -244,6 +253,26 @@ height: 100%; } + :global(.exit-group) { + position: fixed; + top: 12px; + left: 50%; + transform: translateX(-50%); + z-index: 1000; + padding: 4px 12px; + background: var(--color-layer-2); + border: 1px solid var(--stroke); + border-radius: 4px; + color: inherit; + font-size: 0.85em; + cursor: pointer; + opacity: 0.85; + } + + :global(.exit-group:hover) { + opacity: 1; + } + .wrapper { position: absolute; z-index: 100; diff --git a/app/src/lib/graph-interface/graph/mouse.events.ts b/app/src/lib/graph-interface/graph/mouse.events.ts index 336fd1f..38bb791 100644 --- a/app/src/lib/graph-interface/graph/mouse.events.ts +++ b/app/src/lib/graph-interface/graph/mouse.events.ts @@ -190,7 +190,7 @@ export class MouseEventManager { // if we clicked on a node if (clickedNodeId !== -1) { if (event.ctrlKey && event.shiftKey) { - this.state.tryConnectToDebugNode(clickedNodeId); + this.graph.tryConnectToDebugNode(clickedNodeId); return; } if (this.state.activeNodeId === -1) { diff --git a/app/src/lib/graph-interface/helpers/nodeHelpers.ts b/app/src/lib/graph-interface/helpers/nodeHelpers.ts index 71a8d47..f4dd252 100644 --- a/app/src/lib/graph-interface/helpers/nodeHelpers.ts +++ b/app/src/lib/graph-interface/helpers/nodeHelpers.ts @@ -25,15 +25,12 @@ export function getParameterHeight(node: NodeDefinition, inputKey: string) { const nodeHeightCache: Record = {}; export function getNodeHeight(node: NodeDefinition) { - if (!node) { - console.trace('Node is undefined', node); + if (!node || !('inputs' in node)) { + return 5; } if (node.id in nodeHeightCache) { return nodeHeightCache[node.id]; } - if (!node?.inputs) { - return 5; - } let height = 5; for (const key in node.inputs) { diff --git a/app/src/lib/graph-interface/keymaps.ts b/app/src/lib/graph-interface/keymaps.ts index 3be6742..e96f6e6 100644 --- a/app/src/lib/graph-interface/keymaps.ts +++ b/app/src/lib/graph-interface/keymaps.ts @@ -47,6 +47,10 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr key: 'Escape', description: 'Deselect nodes', callback: () => { + if (graph.isInsideGroup) { + graphState.exitGroupNode(); + return; + } graphState.activeNodeId = -1; graphState.clearSelection(); graphState.edgeEndPosition = null; @@ -64,6 +68,7 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr keymap.addShortcut({ key: 'Tab', + preventDefault: true, description: 'Enter selected node group', callback: () => graphState.enterGroupNode() }); diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index 8265695..6090fe1 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -34,14 +34,14 @@ const sectionHeights = $derived( Object - .keys(nodeType.inputs || {}) + .keys(nodeType?.inputs || {}) .map(key => getParameterHeight(nodeType, key) / 10) .filter(b => !!b) ); let meshRef: Mesh | undefined = $state(); - const height = $derived(getNodeHeight(nodeType)); + const height = $derived(nodeType ? getNodeHeight(nodeType) : 20); const zoom = $derived(graphState.cameraPosition[2]); diff --git a/app/src/lib/graph-interface/node/NodeParameter.svelte b/app/src/lib/graph-interface/node/NodeParameter.svelte index 36249cb..55579aa 100644 --- a/app/src/lib/graph-interface/node/NodeParameter.svelte +++ b/app/src/lib/graph-interface/node/NodeParameter.svelte @@ -19,7 +19,7 @@ let { node = $bindable(), input, id, isLast }: Props = $props(); - const nodeType = $derived(graph.getNodeType(node)!); + let nodeType = $derived(graph.getNodeType(node)!); const inputType = $derived(nodeType.inputs?.[id]); diff --git a/app/src/lib/graph-templates/grid.ts b/app/src/lib/graph-templates/grid.ts index bc759e6..7510243 100644 --- a/app/src/lib/graph-templates/grid.ts +++ b/app/src/lib/graph-templates/grid.ts @@ -4,7 +4,8 @@ export function grid(width: number, height: number) { const graph: Graph = { id: Math.floor(Math.random() * 100000), edges: [], - nodes: [] + nodes: [], + groups: [] }; const amount = width * height; diff --git a/app/src/lib/graph-templates/tree.ts b/app/src/lib/graph-templates/tree.ts index e382a1c..6c39992 100644 --- a/app/src/lib/graph-templates/tree.ts +++ b/app/src/lib/graph-templates/tree.ts @@ -47,6 +47,7 @@ export function tree(depth: number): Graph { return { id: Math.floor(Math.random() * 100000), nodes, - edges + edges, + groups: [] }; } diff --git a/app/src/lib/runtime/runtime-executor.ts b/app/src/lib/runtime/runtime-executor.ts index d527a23..3b19183 100644 --- a/app/src/lib/runtime/runtime-executor.ts +++ b/app/src/lib/runtime/runtime-executor.ts @@ -159,7 +159,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { // Only load non-virtual types (virtual nodes are resolved locally) const nonVirtualTypes = graph.nodes .map(node => node.type) - .filter(t => !t.startsWith('__virtual/')); + .filter(t => !t.startsWith('__internal/')); await this.registry.load(nonVirtualTypes as any); const typeMap = new Map(); -- 2.52.0 From 78439b19e96e6dbdfb31cc794f5b6e1ff005e26e Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 12:45:06 +0200 Subject: [PATCH 14/44] fix: make benchmark work --- app/benchmark/index.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/app/benchmark/index.ts b/app/benchmark/index.ts index a152d3c..e06c003 100644 --- a/app/benchmark/index.ts +++ b/app/benchmark/index.ts @@ -10,7 +10,6 @@ import plantTemplate from './templates/plant.json' assert { type: 'json' }; const registry = new BenchmarkRegistry(); const r = new MemoryRuntimeExecutor(registry); -const perfStore = createPerformanceStore(); const log = createLogger('bench'); @@ -26,10 +25,12 @@ function countGeometry(result: Int32Array): { totalVertices: number; totalFaces: let totalFaces = 0; for (const part of parts) { const type = part[0]; - const vertexCount = part[1]; - const faceCount = part[2]; + // Values are stored as uint32 in the wasm output but read as signed int32; + // >>> 0 reinterprets the bit pattern as unsigned. + const vertexCount = part[1] >>> 0; + const faceCount = part[2] >>> 0; if (type === 2) { - const instanceCount = part[3]; + const instanceCount = part[3] >>> 0; totalVertices += vertexCount * instanceCount; totalFaces += faceCount * instanceCount; } else { @@ -41,17 +42,16 @@ function countGeometry(result: Int32Array): { totalVertices: number; totalFaces: } async function run(g: GraphType, amount: number) { - await registry.load(plantTemplate.nodes.map(n => n.type) as NodeId[]); + await registry.load(g.nodes.map(n => n.type) as NodeId[]); log.log('loaded ' + g.nodes.length + ' nodes'); log.log('warming up'); - - // Warm up the runtime? maybe this does something? for (let index = 0; index < 10; index++) { await r.execute(g, { randomSeed: true }); } log.log('executing'); + const perfStore = createPerformanceStore(); r.perf = perfStore; let res; for (let i = 0; i < amount; i++) { -- 2.52.0 From 317d1552cea5a234ab1ab87684be9a3724b1976f Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 12:45:45 +0200 Subject: [PATCH 15/44] fix: graph correctly restore html refs after exiting node group --- app/src/lib/graph-interface/graph-manager.svelte.ts | 13 +++++++++++-- app/src/lib/graph-interface/graph/Graph.svelte | 1 - app/src/lib/graph-interface/node/Node.svelte | 12 +++++++----- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 5d18e90..da0f928 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -486,7 +486,7 @@ export class GraphManager extends EventEmitter<{ getNodeType(node: NodeInstance) { if (!node) { - console.trace('failed to get node type'); + console.trace('failed to get node type', { node }); return; } @@ -685,9 +685,18 @@ export class GraphManager extends EventEmitter<{ exitGroup(): { camera: [number, number, number]; nodeId: number } | false { if (!this.graphStack.length) return false; - const { savedNodes, savedEdges, outerGraph, groupId, nodeId, cameraPosition } = this.graphStack.pop()!; + const { savedNodes, savedEdges, outerGraph, groupId, nodeId, cameraPosition } = this.graphStack + .pop()!; const internalState = this.serialize(); + // Clear stale DOM/mesh refs so the remounting components register fresh ones. + // The $effect guards in NodeHTML/Node only set these when undefined, so without + // this clear they'd keep pointing to the detached elements from before group entry. + for (const node of savedNodes.values()) { + node.state.ref = undefined; + node.state.mesh = undefined; + } + // Restore live reactive nodes and edges so drag-reactivity is preserved this.nodes.clear(); for (const [id, node] of savedNodes) { diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index f1bad0b..6653166 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -97,7 +97,6 @@ function getSocketType(node: NodeInstance, index: number | string): string { const nodeType = graph.getNodeType(node); - console.log({ nodeType, index }); if (typeof index === 'string') { return nodeType?.inputs?.[index].type || 'unknown'; } diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index 6090fe1..4e7f102 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -19,7 +19,7 @@ }; let { node = $bindable(), inView }: Props = $props(); - const nodeType = $derived(graph.getNodeType(node)!); + const nodeType = $derived(node ? graph.getNodeType(node) : undefined); const isActive = $derived(graphState.activeNodeId === node.id); const isSelected = $derived(graphState.selectedNodes.has(node.id)); @@ -33,10 +33,12 @@ ); const sectionHeights = $derived( - Object - .keys(nodeType?.inputs || {}) - .map(key => getParameterHeight(nodeType, key) / 10) - .filter(b => !!b) + nodeType + ? Object + .keys(nodeType?.inputs || {}) + .map(key => getParameterHeight(nodeType, key) / 10) + .filter(b => !!b) + : [5] ); let meshRef: Mesh | undefined = $state(); -- 2.52.0 From 59a1e63396635d05543fa4636de5800ce4899a2a Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 12:49:30 +0200 Subject: [PATCH 16/44] feat: add unit tests for graph state --- .../graph-state.svelte.test.ts | 285 ++++++++++++++++++ 1 file changed, 285 insertions(+) create mode 100644 app/src/lib/graph-interface/graph-state.svelte.test.ts diff --git a/app/src/lib/graph-interface/graph-state.svelte.test.ts b/app/src/lib/graph-interface/graph-state.svelte.test.ts new file mode 100644 index 0000000..7e5f175 --- /dev/null +++ b/app/src/lib/graph-interface/graph-state.svelte.test.ts @@ -0,0 +1,285 @@ +import { assert, beforeEach, describe, expect, it } from 'vitest'; +import { GraphManager } from './graph-manager.svelte'; +import { GraphState } from './graph-state.svelte'; +import { + createMockNodeRegistry, + mockFloatInputNode, + mockFloatOutputNode +} from './test-utils'; + +// GraphState constructor reads localStorage synchronously — mock before any instantiation +Object.defineProperty(globalThis, 'localStorage', { + value: { + getItem: () => null, + setItem: () => {}, + removeItem: () => {}, + clear: () => {}, + length: 0, + key: () => null + } as Storage, + writable: true, + configurable: true +}); + +function createFixture() { + const registry = createMockNodeRegistry([mockFloatOutputNode, mockFloatInputNode]); + const manager = new GraphManager(registry); + const state = new GraphState(manager); + return { manager, state }; +} + +describe('clearSelection', () => { + it('empties selectedNodes', () => { + const { state } = createFixture(); + state.selectedNodes.add(1); + state.selectedNodes.add(2); + state.clearSelection(); + expect(state.selectedNodes.size).toBe(0); + }); +}); + +describe('projectScreenToWorld', () => { + it('maps the viewport centre to the camera position', () => { + const { state } = createFixture(); + // cameraPosition default: [140, 100, 3.5], width=100, height=100 + state.width = 100; + state.height = 100; + state.cameraPosition = [140, 100, 3.5]; + const [wx, wy] = state.projectScreenToWorld(50, 50); + expect(wx).toBeCloseTo(140); + expect(wy).toBeCloseTo(100); + }); + + it('offsets correctly for a point not at centre', () => { + const { state } = createFixture(); + state.width = 100; + state.height = 100; + state.cameraPosition = [0, 0, 2]; + const [wx, wy] = state.projectScreenToWorld(100, 50); + // x: 0 + (100 - 50) / 2 = 25 + expect(wx).toBeCloseTo(25); + expect(wy).toBeCloseTo(0); + }); +}); + +describe('groupSelectedNodes', () => { + it('delegates to graph.groupNodes with selected IDs and activeNodeId', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + const nodeB = manager.createNode({ type: 'test/node/input', position: [100, 0], props: {} }); + assert.isDefined(nodeA); + assert.isDefined(nodeB); + + state.selectedNodes.add(nodeA!.id); + state.activeNodeId = nodeB!.id; + + const groupNode = state.groupSelectedNodes(); + assert.isDefined(groupNode); + + const graph = manager.serialize(); + expect(graph.groups.length).toBe(1); + expect(graph.nodes.map(n => n.id)).toContain(groupNode!.id); + }); + + it('works when only activeNodeId is set with no extra selection', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + assert.isDefined(nodeA); + + state.activeNodeId = nodeA!.id; + const groupNode = state.groupSelectedNodes(); + assert.isDefined(groupNode); + + expect(manager.graph.groups.length).toBe(1); + }); +}); + +describe('enterGroupNode', () => { + it('does nothing when activeNodeId is -1', () => { + const { manager, state } = createFixture(); + state.activeNodeId = -1; + state.enterGroupNode(); + expect(manager.graphStack.length).toBe(0); + }); + + it('does nothing when the active node is not a group instance', () => { + const { manager, state } = createFixture(); + const node = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + assert.isDefined(node); + state.activeNodeId = node!.id; + state.enterGroupNode(); + expect(manager.graphStack.length).toBe(0); + }); + + it('enters the group, pushes graphStack, and clears UI state', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + assert.isDefined(nodeA); + const groupNode = manager.groupNodes([nodeA!.id]); + assert.isDefined(groupNode); + + state.selectedNodes.add(nodeA!.id); + state.activeNodeId = groupNode!.id; + state.cameraPosition = [10, 20, 5]; + + state.enterGroupNode(); + + expect(manager.graphStack.length).toBe(1); + expect(state.activeNodeId).toBe(-1); + expect(state.selectedNodes.size).toBe(0); + expect(manager.isInsideGroup).toBe(true); + }); +}); + +describe('exitGroupNode', () => { + it('does nothing when not inside a group', () => { + const { manager, state } = createFixture(); + const before = [...state.cameraPosition]; + state.exitGroupNode(); + expect(manager.graphStack.length).toBe(0); + expect(state.cameraPosition).toEqual(before); + }); + + it('restores the camera position from before entry', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + assert.isDefined(nodeA); + const groupNode = manager.groupNodes([nodeA!.id]); + assert.isDefined(groupNode); + + state.activeNodeId = groupNode!.id; + state.cameraPosition = [77, 88, 4]; + + state.enterGroupNode(); + // Simulate camera moving inside the group + state.cameraPosition = [0, 0, 1]; + + state.exitGroupNode(); + + expect(state.cameraPosition).toEqual([77, 88, 4]); + }); + + it('clears activeNodeId and selection after exit', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + assert.isDefined(nodeA); + const groupNode = manager.groupNodes([nodeA!.id]); + assert.isDefined(groupNode); + + state.activeNodeId = groupNode!.id; + state.enterGroupNode(); + state.activeNodeId = 99; + state.selectedNodes.add(99); + + state.exitGroupNode(); + + expect(state.activeNodeId).toBe(-1); + expect(state.selectedNodes.size).toBe(0); + }); + + it('restores outer nodes to manager after exit', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + const nodeB = manager.createNode({ type: 'test/node/input', position: [100, 0], props: {} }); + assert.isDefined(nodeA); + assert.isDefined(nodeB); + + manager.createEdge(nodeA!, 0, nodeB!, 'value'); + const groupNode = manager.groupNodes([nodeA!.id]); + assert.isDefined(groupNode); + + state.activeNodeId = groupNode!.id; + state.enterGroupNode(); + + // Inside the group: nodeA is an internal node so it IS active; the outer + // nodes (nodeB, groupNode) are saved and no longer in the active Map. + expect(manager.nodes.has(nodeA!.id)).toBe(true); + expect(manager.nodes.has(nodeB!.id)).toBe(false); + + state.exitGroupNode(); + + // After exit: outer nodes are restored + expect(manager.nodes.has(nodeB!.id)).toBe(true); + expect(manager.nodes.has(groupNode!.id)).toBe(true); + expect(manager.isInsideGroup).toBe(false); + }); + + it('isInsideGroup is false after exiting the only group level', () => { + const { manager, state } = createFixture(); + + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + assert.isDefined(nodeA); + const groupNode = manager.groupNodes([nodeA!.id]); + assert.isDefined(groupNode); + + state.activeNodeId = groupNode!.id; + state.enterGroupNode(); + expect(manager.isInsideGroup).toBe(true); + + state.exitGroupNode(); + expect(manager.isInsideGroup).toBe(false); + }); +}); + +describe('copyNodes / pasteNodes', () => { + it('copies the active node into the clipboard', () => { + const { manager, state } = createFixture(); + const node = manager.createNode({ type: 'test/node/output', position: [10, 20], props: {} }); + assert.isDefined(node); + + state.activeNodeId = node!.id; + state.mousePosition = [0, 0]; + state.copyNodes(); + + assert.isNotNull(state.clipboard); + expect(state.clipboard!.nodes.map(n => n.id)).toContain(node!.id); + }); + + it('includes edges between copied nodes', () => { + const { manager, state } = createFixture(); + const nodeA = manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + const nodeB = manager.createNode({ type: 'test/node/input', position: [100, 0], props: {} }); + assert.isDefined(nodeA); + assert.isDefined(nodeB); + + manager.createEdge(nodeA!, 0, nodeB!, 'value'); + + state.activeNodeId = nodeA!.id; + state.selectedNodes.add(nodeB!.id); + state.mousePosition = [0, 0]; + state.copyNodes(); + + assert.isNotNull(state.clipboard); + expect(state.clipboard!.edges.length).toBe(1); + }); + + it('pastes nodes and adds them to the graph', () => { + const { manager, state } = createFixture(); + const node = manager.createNode({ type: 'test/node/output', position: [10, 20], props: {} }); + assert.isDefined(node); + + state.activeNodeId = node!.id; + state.mousePosition = [0, 0]; + state.copyNodes(); + + const countBefore = manager.nodes.size; + state.mousePosition = [50, 50]; + state.pasteNodes(); + + expect(manager.nodes.size).toBe(countBefore + 1); + }); + + it('does nothing when clipboard is empty', () => { + const { manager, state } = createFixture(); + manager.createNode({ type: 'test/node/output', position: [0, 0], props: {} }); + const countBefore = manager.nodes.size; + state.pasteNodes(); + expect(manager.nodes.size).toBe(countBefore); + }); +}); -- 2.52.0 From 3ee074b11c9bc216ce7221f5611c8177cef9b313 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 14:11:52 +0200 Subject: [PATCH 17/44] feat(ui): make inputselect also handle value+label options --- .../graph-interface/graph-manager.svelte.ts | 69 +++++++++++---- .../graph-state.svelte.test.ts | 3 +- .../lib/graph-interface/graph-state.svelte.ts | 2 +- .../sidebar/panels/ActiveNodeSettings.svelte | 86 ++++++++++++++++++- packages/types/src/inputs.ts | 6 +- packages/ui/src/lib/inputs/InputSelect.svelte | 14 ++- packages/ui/src/routes/+page.svelte | 25 +++++- 7 files changed, 174 insertions(+), 31 deletions(-) diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index da0f928..7029192 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -152,6 +152,7 @@ export class GraphManager extends EventEmitter<{ return { id: group.id, + name: group.name, inputs: group.inputs, outputs: group.outputs, nodes: groupNodes, @@ -527,16 +528,25 @@ export class GraphManager extends EventEmitter<{ return; } - const inputs = { + const defaultInputs = { ...(node.state.type?.inputs || {}), - ...groupDefinition?.inputs, + ...groupDefinition?.inputs + }; + + // This is to make sure the the groupId is always first + delete defaultInputs['groupId']; + const inputs = { 'groupId': { type: 'select', label: '', value: node.props?.groupId, internal: true, - options: this.graph.groups.map(g => g.id) - } + options: this.graph.groups.map((g, i) => ({ + value: g.id, + label: g.name || `Group ${i + 1}` + })) + }, + ...defaultInputs }; const groupType = { @@ -658,6 +668,13 @@ export class GraphManager extends EventEmitter<{ return this.graph.groups.find(g => g.id === id); } + renameGroup(groupId: number, name: string) { + const group = this.getGroup(groupId); + if (!group) return; + group.name = name; + this.save(); + } + isInsideGroup = $state(false); enterGroup(nodeId: number, cameraPosition: [number, number, number]): boolean { @@ -845,35 +862,53 @@ export class GraphManager extends EventEmitter<{ groupPosition[0] /= nodes.length; groupPosition[1] /= nodes.length; + // Map from deduped edge source key → group input index, used for both + // internal edge wiring and external edge socket naming. + const inputIndexByEdgeKey = new Map(); + [...groupInputs.keys()].forEach((key, i) => inputIndexByEdgeKey.set(key, i)); + + // Allocate all needed IDs up front so sequential calls never collide. + const usedIds = new Set([ + ...this.nodes.keys(), + ...this.graph.groups.map(g => g.id), + ...this.graph.groups.flatMap(g => g.nodes.map(n => n.id)) + ]); + const nextId = () => { + let id = 0; + while (usedIds.has(id)) id++; + usedIds.add(id); + return id; + }; + const groupInputNode: NodeInstance = { - id: this.createNodeId(), + id: nextId(), type: '__internal/group/input', position: [bounds.minX - 50, (bounds.minY + bounds.maxY) / 2], state: {} }; const groupOutputNode: NodeInstance = { - id: this.createNodeId(), + id: nextId(), type: '__internal/group/output', position: [bounds.maxX + 25, (bounds.minY + bounds.maxY) / 2], state: {} }; - // Edges that are inside the group + // Edges that are inside the group, routed through boundary nodes at + // the correct input/output index for each unique external connection. const internalEdges = this.edges.filter((edge) => { return ids.has(edge[0].id) || ids.has(edge[2].id); }).map((edge) => { - // Going in from the group if (!ids.has(edge[0].id)) { - return [groupInputNode.id, 0, edge[2].id, edge[3]]; - // Going out to the group + const idx = inputIndexByEdgeKey.get(`${edge[0].id}-${edge[1]}`) ?? 0; + return [groupInputNode.id, idx, edge[2].id, edge[3]]; } else if (!ids.has(edge[2].id)) { return [edge[0].id, edge[1], groupOutputNode.id, 'out_0']; } return [edge[0].id, edge[1], edge[2].id, edge[3]]; }) as [number, number, number, string][]; - const groupId = this.createNodeId(); + const groupId = nextId(); const groupDefinition: GroupDefinition = { id: groupId, inputs: inputs, @@ -882,6 +917,9 @@ export class GraphManager extends EventEmitter<{ nodes: [groupInputNode, ...nodes, groupOutputNode] }; + // Push before createNode so createNodeId() inside sees the allocated IDs. + this.graph.groups.push(groupDefinition); + const groupNode = this.createNode({ type: '__internal/group/instance', position: [groupPosition[0], groupPosition[1]], @@ -892,20 +930,17 @@ export class GraphManager extends EventEmitter<{ if (!groupNode) throw new Error('Failed to create group node'); - // Update the edges that are now inside - // the group to be connected to that group node + // Rewire external edges to/from the group node using the correct input socket. const externalEdges = this.edges.map((edge) => { if (ids.has(edge[2].id)) { - // Edge going into the group - return [edge[0], edge[1], groupNode, 'input_0'] as Edge; + const idx = inputIndexByEdgeKey.get(`${edge[0].id}-${edge[1]}`) ?? 0; + return [edge[0], edge[1], groupNode, `input_${idx}`] as Edge; } else if (ids.has(edge[0].id)) { - // Edge going out of the group return [groupNode, 0, edge[2], edge[3]] as Edge; } return edge; }); - this.graph.groups.push(groupDefinition); this.nodes.set(groupNode.id, groupNode); this.edges = externalEdges; diff --git a/app/src/lib/graph-interface/graph-state.svelte.test.ts b/app/src/lib/graph-interface/graph-state.svelte.test.ts index 7e5f175..f5492ac 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.test.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.test.ts @@ -178,7 +178,8 @@ describe('exitGroupNode', () => { state.exitGroupNode(); - expect(state.activeNodeId).toBe(-1); + // Group instance node is re-selected on exit; internal selection is cleared + expect(state.activeNodeId).toBe(groupNode!.id); expect(state.selectedNodes.size).toBe(0); }); diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index fb24cc4..37e820b 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -376,7 +376,7 @@ export class GraphState { const result = this.graph.exitGroup(); if (!result) return; this.cameraPosition = result.camera; - this.activeNodeId = -1; + this.activeNodeId = result.nodeId; this.clearSelection(); } diff --git a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte index ba61908..df27f85 100644 --- a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte +++ b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte @@ -9,6 +9,21 @@ }; let { manager, node = $bindable() }: Props = $props(); + + const isGroupInstance = $derived(node?.type === '__internal/group/instance'); + const activeGroup = $derived( + isGroupInstance ? manager.getGroup(node!.props?.groupId as number) : undefined + ); + + let groupName = $state(''); + $effect(() => { + groupName = activeGroup?.name ?? ''; + }); + + function handleRename(e: Event) { + const name = (e.target as HTMLInputElement).value; + if (activeGroup) manager.renameGroup(activeGroup.id, name); + }
@@ -17,7 +32,18 @@ {#if node} {#key node.id} - {#if node} + {#if isGroupInstance && activeGroup} +
+ + +
+ {:else if node} {/if} {/key} @@ -26,7 +52,59 @@ {/if} {#if manager?.graph.groups.length} - +
+ +
{/if} + + diff --git a/packages/types/src/inputs.ts b/packages/types/src/inputs.ts index 4a09b6e..8ecd33d 100644 --- a/packages/types/src/inputs.ts +++ b/packages/types/src/inputs.ts @@ -61,8 +61,10 @@ export const NodeInputBooleanSchema = z.object({ export const NodeInputSelectSchema = z.object({ ...DefaultOptionsSchema.shape, type: z.literal('select'), - options: z.array(z.string()).optional(), - value: z.string().optional() + options: z.array( + z.union([z.string(), z.object({ value: z.number(), label: z.string() })]) + ).optional(), + value: z.union([z.string(), z.number()]).optional() }); export const NodeInputSeedSchema = z.object({ diff --git a/packages/ui/src/lib/inputs/InputSelect.svelte b/packages/ui/src/lib/inputs/InputSelect.svelte index faf7c43..3f0b084 100644 --- a/packages/ui/src/lib/inputs/InputSelect.svelte +++ b/packages/ui/src/lib/inputs/InputSelect.svelte @@ -1,16 +1,24 @@ diff --git a/packages/ui/src/routes/+page.svelte b/packages/ui/src/routes/+page.svelte index 12a91ec..be16114 100644 --- a/packages/ui/src/routes/+page.svelte +++ b/packages/ui/src/routes/+page.svelte @@ -21,7 +21,7 @@ let vecValue = $state([0.2, 0.3, 0.4]); const options = ['strawberry', 'raspberry', 'chickpeas']; let selectValue = $state(0); - const d = $derived(options[selectValue]); + let selectValue2 = $state(0); let checked = $state(false); let colorValue = $state<[number, number, number]>([59, 130, 246]); let mirrorShape = $state(true); @@ -82,9 +82,28 @@ -
- Select with simple values +
+

+ Select with simple values +
+ value={options[selectValue]} +

+
+
+

+ Select with {option: number, label: string}[] +
+ value={selectValue2} +

+
-- 2.52.0 From 6d5cac65e8acf013ac0a4a61baf3bbc423252d53 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 14:12:17 +0200 Subject: [PATCH 18/44] feat(ui): click-to-copy on node values in jsonviewer --- packages/ui/src/lib/JsonViewer.svelte | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/ui/src/lib/JsonViewer.svelte b/packages/ui/src/lib/JsonViewer.svelte index 7ee7f94..193ffc8 100644 --- a/packages/ui/src/lib/JsonViewer.svelte +++ b/packages/ui/src/lib/JsonViewer.svelte @@ -88,7 +88,11 @@ class:bg-layer-3={flashing} > {#if key !== undefined} - {key}: + : {/if} {#if isExpandable} -- 2.52.0 From 2a54fa7590c1834904a45fb0fc1fd0aa371f0120 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 14:12:30 +0200 Subject: [PATCH 19/44] feat: add name to groups --- packages/types/src/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 444dbcf..878f9b5 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -78,6 +78,7 @@ export type Edge = [NodeInstance, number, NodeInstance, string]; export const GroupSchema = z.object({ id: z.number(), + name: z.string().optional(), nodes: z.array(NodeSchema), edges: z.array(z.tuple([z.number(), z.number(), z.number(), z.string()])), inputs: z.record(z.string(), NodeInputSchema).optional(), -- 2.52.0 From e695c7649015b88d8ca6662bfee5dc0329dd89ac Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 14:50:11 +0200 Subject: [PATCH 20/44] chore: make eslint happy --- app/package.json | 2 +- .../graph-interface/graph-manager.svelte.ts | 34 +++++++++---------- .../graph-state.svelte.test.ts | 8 ++--- .../lib/graph-interface/graph/Graph.svelte | 23 ++++++------- .../lib/graph-interface/graph/Wrapper.svelte | 1 - .../graph-interface/helpers/nodeHelpers.ts | 2 +- .../graph-interface/node/NodeHeader.svelte | 2 +- app/src/lib/runtime/runtime-executor.ts | 26 +++++++------- .../sidebar/panels/ActiveNodeSettings.svelte | 5 +-- app/src/routes/+page.svelte | 2 +- packages/ui/src/lib/JsonViewer.svelte | 3 +- 11 files changed, 49 insertions(+), 59 deletions(-) diff --git a/app/package.json b/app/package.json index c509764..619c069 100644 --- a/app/package.json +++ b/app/package.json @@ -7,7 +7,7 @@ "dev": "vite dev", "predev": "rm static/CHANGELOG.md && ln -s ../../CHANGELOG.md static/CHANGELOG.md", "build": "svelte-kit sync && vite build", - "test:unit": "vitest", + "test:unit": "vitest --browser=false", "test": "npm run test:unit -- --run && npm run test:e2e", "test:e2e": "playwright test", "preview": "vite preview", diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 7029192..75dfb85 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -19,12 +19,12 @@ import EventEmitter from './helpers/EventEmitter'; import { HistoryManager } from './history-manager'; const logger = createLogger('graph-manager'); -// logger.mute(); +logger.mute(); const remoteRegistry = new RemoteNodeRegistry(''); -const clone = 'structuredClone' in self - ? self.structuredClone +const clone = 'structuredClone' in globalThis + ? globalThis.structuredClone : (args: unknown) => JSON.parse(JSON.stringify(args)); function areSocketsCompatible( @@ -104,7 +104,7 @@ export class GraphManager extends EventEmitter<{ history: HistoryManager = new HistoryManager(); - private serializeFullGraph(): Graph { + public serializeFullGraph(): Graph { if (this.graphStack.length === 0) return this.serialize(); let merged = this.serialize(); for (let i = this.graphStack.length - 1; i >= 0; i--) { @@ -538,7 +538,7 @@ export class GraphManager extends EventEmitter<{ const inputs = { 'groupId': { type: 'select', - label: '', + label: 'Group', value: node.props?.groupId, internal: true, options: this.graph.groups.map((g, i) => ({ @@ -551,6 +551,10 @@ export class GraphManager extends EventEmitter<{ const groupType = { ...node.state.type, + meta: { + title: 'Group', + ...node?.state?.type?.meta || {} + }, inputs, outputs: groupDefinition?.outputs?.map(o => o.type) } as NodeDefinition; @@ -620,7 +624,6 @@ export class GraphManager extends EventEmitter<{ } removeNode(node: NodeInstance, { restoreEdges = false } = {}) { - console.log('REMOVING NODE', $state.snapshot({ node })); const edgesToNode = this.edges.filter((edge) => edge[2].id === node.id); const edgesFromNode = this.edges.filter((edge) => edge[0].id === node.id); for (const edge of [...edgesToNode, ...edgesFromNode]) { @@ -686,7 +689,7 @@ export class GraphManager extends EventEmitter<{ this.graphStack.push({ rootGraph: this.serialize(), - savedNodes: new Map(this.nodes), + savedNodes: new SvelteMap(this.nodes), savedEdges: [...this.edges], outerGraph: this.graph, groupId, @@ -743,8 +746,6 @@ export class GraphManager extends EventEmitter<{ ...this.graph.groups.flatMap(g => g.nodes.map(n => n.id)) ]; - console.log('CREATE NODE ID', ids); - let id = 0; while (ids.includes(id)) { id++; @@ -796,7 +797,7 @@ export class GraphManager extends EventEmitter<{ } removeUnusedGroups() { - const usedGroups = new Set(this.getAllNodes().map(n => n.props?.groupId)); + const usedGroups = new SvelteSet(this.getAllNodes().map(n => n.props?.groupId)); const unusedGroupAmount = this.graph.groups.length - usedGroups.size; this.graph.groups = this.graph.groups.filter(g => usedGroups.has(g.id)); this.save(); @@ -808,14 +809,14 @@ export class GraphManager extends EventEmitter<{ this.removeUnusedGroups(); const nodes = [ - ...new Set(nodeIds).values().map(id => this.getNode(id)).filter(Boolean) + ...new SvelteSet(nodeIds).values().map(id => this.getNode(id)).filter(Boolean) ] as NodeInstance[]; if (!nodes.length) return; logger.log(`Grouping ${nodes.length} nodes`, { nodes }); - const ids = new Set(nodes.map(n => n.id)); + const ids = new SvelteSet(nodes.map(n => n.id)); // We use the map to dedupe when one external node is connected to multiple internal nodes // ┌──internal_a @@ -823,14 +824,14 @@ export class GraphManager extends EventEmitter<{ // └──internal_b // This should only result in one group input not two const incomingEdges = this.edges.filter((edge) => ids.has(edge[2].id) && !ids.has(edge[0].id)); - const groupInputs = new Map(); + const groupInputs = new SvelteMap(); for (const edge of incomingEdges) { groupInputs.set(`${edge[0].id}-${edge[1]}`, edge); } // And the same for the outputs const outgoingEdges = this.edges.filter((edge) => ids.has(edge[0].id) && !ids.has(edge[2].id)); - const groupOutputs = new Map(); + const groupOutputs = new SvelteMap(); for (const edge of outgoingEdges) { groupOutputs.set(`${edge[2].id}-${edge[3]}`, edge); } @@ -864,11 +865,11 @@ export class GraphManager extends EventEmitter<{ // Map from deduped edge source key → group input index, used for both // internal edge wiring and external edge socket naming. - const inputIndexByEdgeKey = new Map(); + const inputIndexByEdgeKey = new SvelteMap(); [...groupInputs.keys()].forEach((key, i) => inputIndexByEdgeKey.set(key, i)); // Allocate all needed IDs up front so sequential calls never collide. - const usedIds = new Set([ + const usedIds = new SvelteSet([ ...this.nodes.keys(), ...this.graph.groups.map(g => g.id), ...this.graph.groups.flatMap(g => g.nodes.map(n => n.id)) @@ -949,7 +950,6 @@ export class GraphManager extends EventEmitter<{ this.removeNode(node); } - console.log('FINISHED', this.serialize()); this.saveUndoGroup(); return groupNode; diff --git a/app/src/lib/graph-interface/graph-state.svelte.test.ts b/app/src/lib/graph-interface/graph-state.svelte.test.ts index f5492ac..a20a933 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.test.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.test.ts @@ -1,11 +1,7 @@ -import { assert, beforeEach, describe, expect, it } from 'vitest'; +import { assert, describe, expect, it } from 'vitest'; import { GraphManager } from './graph-manager.svelte'; import { GraphState } from './graph-state.svelte'; -import { - createMockNodeRegistry, - mockFloatInputNode, - mockFloatOutputNode -} from './test-utils'; +import { createMockNodeRegistry, mockFloatInputNode, mockFloatOutputNode } from './test-utils'; // GraphState constructor reads localStorage synchronously — mock before any instantiation Object.defineProperty(globalThis, 'localStorage', { diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index 6653166..e2e6744 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -136,6 +136,12 @@ /> + {#if graph.isInsideGroup} + + {/if} + - - - {/if} - {#if graphState.addMenuPosition} import { createKeyMap } from '$lib/helpers/createKeyMap'; import type { Graph, NodeInstance, NodeRegistry } from '@nodarium/types'; - import { onMount } from 'svelte'; import { GraphManager } from '../graph-manager.svelte'; import { GraphState, setGraphManager, setGraphState } from '../graph-state.svelte'; import { setupKeymaps } from '../keymaps'; diff --git a/app/src/lib/graph-interface/helpers/nodeHelpers.ts b/app/src/lib/graph-interface/helpers/nodeHelpers.ts index f4dd252..57bc166 100644 --- a/app/src/lib/graph-interface/helpers/nodeHelpers.ts +++ b/app/src/lib/graph-interface/helpers/nodeHelpers.ts @@ -1,4 +1,4 @@ -import type { NodeDefinition, NodeInstance } from '@nodarium/types'; +import type { NodeDefinition } from '@nodarium/types'; export function getParameterHeight(node: NodeDefinition, inputKey: string) { const input = node.inputs?.[inputKey]; diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte index c1b9d14..9bb56a2 100644 --- a/app/src/lib/graph-interface/node/NodeHeader.svelte +++ b/app/src/lib/graph-interface/node/NodeHeader.svelte @@ -71,7 +71,7 @@ {#if appSettings.value.debug.advancedMode} {node.id} {/if} - {node.type.split('/').pop()} + {nodeType?.meta?.title || node.type?.split('/').pop()}
node.type) .filter(t => !t.startsWith('__internal/')); - await this.registry.load(nonVirtualTypes as any); + await this.registry.load(nonVirtualTypes); const typeMap = new Map(); for (const node of graph.nodes) { diff --git a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte index df27f85..49d1da4 100644 --- a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte +++ b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte @@ -15,10 +15,7 @@ isGroupInstance ? manager.getGroup(node!.props?.groupId as number) : undefined ); - let groupName = $state(''); - $effect(() => { - groupName = activeGroup?.name ?? ''; - }); + const groupName = $derived(activeGroup?.name ?? ''); function handleRename(e: Event) { const name = (e.target as HTMLInputElement).value; diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index a442add..ccc4fb7 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -321,7 +321,7 @@ hidden={!appSettings.value.debug.advancedMode} icon="i-[tabler--code]" > - + - const cache = new Map>(); + import { SvelteMap } from 'svelte/reactivity'; + const cache = new SvelteMap>(); function getStore(root: string): Record { if (!cache.has(root)) { -- 2.52.0 From d4910aba8c5408fb9321b1a22d4c35eae8142309 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:00:40 +0200 Subject: [PATCH 21/44] chore: pnpm format --- app/src/lib/runtime/runtime-executor.test.ts | 40 ++++-- docs/LLM.md | 132 ++++++++++-------- packages/ui/src/lib/JsonViewer.svelte | 12 +- packages/ui/src/lib/inputs/InputSelect.svelte | 4 +- 4 files changed, 105 insertions(+), 83 deletions(-) diff --git a/app/src/lib/runtime/runtime-executor.test.ts b/app/src/lib/runtime/runtime-executor.test.ts index 7549e0a..6bfa647 100644 --- a/app/src/lib/runtime/runtime-executor.test.ts +++ b/app/src/lib/runtime/runtime-executor.test.ts @@ -1,13 +1,23 @@ +import type { Graph } from '@nodarium/types'; import { describe, expect, it } from 'vitest'; import { expandGroups } from './runtime-executor'; -import type { Graph } from '@nodarium/types'; // Helpers to build minimal serialized nodes/edges function node(id: number, type: string, props?: Record) { - return { id, type: type as Graph['nodes'][0]['type'], position: [0, 0] as [number, number], ...(props ? { props } : {}) }; + return { + id, + type: type as Graph['nodes'][0]['type'], + position: [0, 0] as [number, number], + ...(props ? { props } : {}) + }; } -function edge(from: number, fromSocket: number, to: number, toSocket: string): [number, number, number, string] { +function edge( + from: number, + fromSocket: number, + to: number, + toSocket: string +): [number, number, number, string] { return [from, fromSocket, to, toSocket]; } @@ -41,8 +51,8 @@ describe('expandGroups', () => { node(3, 'test/node/input') ], edges: [ - edge(1, 0, groupNodeId, 'input_0'), // A → group - edge(groupNodeId, 0, 3, 'value') // group → C + edge(1, 0, groupNodeId, 'input_0'), // A → group + edge(groupNodeId, 0, 3, 'value') // group → C ], groups: [{ id: groupId, @@ -52,8 +62,8 @@ describe('expandGroups', () => { node(7, '__internal/group/output') ], edges: [ - edge(6, 0, 2, 'input'), // inputBoundary → B - edge(2, 0, 7, 'Out') // B → outputBoundary + edge(6, 0, 2, 'input'), // inputBoundary → B + edge(2, 0, 7, 'Out') // B → outputBoundary ], inputs: { input_0: { type: 'float' } }, outputs: [{ type: 'float', label: 'Output 0' }] @@ -69,7 +79,7 @@ describe('expandGroups', () => { expect(ids).toContain(3); // C expect(result.nodes.length).toBe(3); // A, B(remapped), C - expect(result.edges).toContainEqual(edge(1, 0, remappedB, 'input')); // A → B + expect(result.edges).toContainEqual(edge(1, 0, remappedB, 'input')); // A → B expect(result.edges).toContainEqual(edge(remappedB, 0, 3, 'value')); // B → C expect(result.edges.length).toBe(2); }); @@ -96,14 +106,14 @@ describe('expandGroups', () => { id: groupId, nodes: [ node(3, '__internal/group/input'), - node(1, 'test/node/output'), // B - node(2, 'test/node/output'), // D + node(1, 'test/node/output'), // B + node(2, 'test/node/output'), // D node(4, '__internal/group/output') ], edges: [ - edge(3, 0, 1, 'input'), // inputBoundary → B - edge(1, 0, 2, 'input'), // B → D (internal) - edge(2, 0, 4, 'Out') // D → outputBoundary + edge(3, 0, 1, 'input'), // inputBoundary → B + edge(1, 0, 2, 'input'), // B → D (internal) + edge(2, 0, 4, 'Out') // D → outputBoundary ], inputs: { input_0: { type: 'float' } }, outputs: [{ type: 'float' }] @@ -116,9 +126,9 @@ describe('expandGroups', () => { expect(result.nodes.map(n => n.id)).toContain(remappedB); expect(result.nodes.map(n => n.id)).toContain(remappedD); - expect(result.edges).toContainEqual(edge(0, 0, remappedB, 'input')); // A → B + expect(result.edges).toContainEqual(edge(0, 0, remappedB, 'input')); // A → B expect(result.edges).toContainEqual(edge(remappedB, 0, remappedD, 'input')); // B → D (internal) - expect(result.edges).toContainEqual(edge(remappedD, 0, 9, 'value')); // D → C + expect(result.edges).toContainEqual(edge(remappedD, 0, 9, 'value')); // D → C expect(result.edges.length).toBe(3); }); diff --git a/docs/LLM.md b/docs/LLM.md index 983cd3d..48b1b83 100644 --- a/docs/LLM.md +++ b/docs/LLM.md @@ -47,6 +47,7 @@ User Interaction ``` **Event flow:** + 1. User edits graph → GraphManager mutates state 2. GraphManager emits `save` → ProjectManager persists to IndexDB 3. GraphManager emits `result` → Runtime executes graph → Viewer updates @@ -55,26 +56,26 @@ User Interaction ## Critical Files -| File | Role | -|------|------| -| `app/src/routes/+page.svelte` | Wires all systems; creates GraphManager, runtime, registry | -| `app/src/lib/graph-interface/graph-manager.svelte.ts` | Central graph logic: createNode, createEdge, serialize, load, history | -| `app/src/lib/graph-interface/graph-state.svelte.ts` | UI state: camera, selection, mouse, clipboard, groupSelectedNodes | -| `app/src/lib/graph-interface/graph/Graph.svelte` | Canvas renderer | -| `app/src/lib/graph-interface/node/Node.svelte` | 3D mesh node (Three.js shader) | -| `app/src/lib/graph-interface/node/NodeHTML.svelte` | HTML overlay: labels + parameters | -| `app/src/lib/graph-interface/node/NodeHeader.svelte` | Node title bar | -| `app/src/lib/graph-interface/keymaps.ts` | Keyboard shortcuts | -| `app/src/lib/graph-interface/helpers/nodeHelpers.ts` | Node height calculations | -| `app/src/lib/graph-interface/graph/colors.svelte.ts` | Socket type → color mapping | -| `app/src/lib/runtime/runtime-executor.ts` | Executes nodes in DAG order; expandGroups() | -| `app/src/lib/node-registry/index.ts` | RemoteNodeRegistry entry | -| `app/src/lib/node-registry/groupNode.ts` | Built-in group node definition | -| `app/src/lib/node-registry/debugNode.ts` | Built-in debug node | -| `app/src/lib/sidebar/panels/ActiveNodeSettings.svelte` | Per-node settings panel | -| `packages/types/src/types.ts` | Graph, NodeInstance, NodeDefinition, Edge, GroupDefinition | -| `packages/types/src/inputs.ts` | NodeInput union types (float, vec3, geometry, path, …) | -| `packages/utils/src/wasm.ts` | createWasmWrapper() — wraps WASM bytes into a NodeDefinition | +| File | Role | +| ------------------------------------------------------ | --------------------------------------------------------------------- | +| `app/src/routes/+page.svelte` | Wires all systems; creates GraphManager, runtime, registry | +| `app/src/lib/graph-interface/graph-manager.svelte.ts` | Central graph logic: createNode, createEdge, serialize, load, history | +| `app/src/lib/graph-interface/graph-state.svelte.ts` | UI state: camera, selection, mouse, clipboard, groupSelectedNodes | +| `app/src/lib/graph-interface/graph/Graph.svelte` | Canvas renderer | +| `app/src/lib/graph-interface/node/Node.svelte` | 3D mesh node (Three.js shader) | +| `app/src/lib/graph-interface/node/NodeHTML.svelte` | HTML overlay: labels + parameters | +| `app/src/lib/graph-interface/node/NodeHeader.svelte` | Node title bar | +| `app/src/lib/graph-interface/keymaps.ts` | Keyboard shortcuts | +| `app/src/lib/graph-interface/helpers/nodeHelpers.ts` | Node height calculations | +| `app/src/lib/graph-interface/graph/colors.svelte.ts` | Socket type → color mapping | +| `app/src/lib/runtime/runtime-executor.ts` | Executes nodes in DAG order; expandGroups() | +| `app/src/lib/node-registry/index.ts` | RemoteNodeRegistry entry | +| `app/src/lib/node-registry/groupNode.ts` | Built-in group node definition | +| `app/src/lib/node-registry/debugNode.ts` | Built-in debug node | +| `app/src/lib/sidebar/panels/ActiveNodeSettings.svelte` | Per-node settings panel | +| `packages/types/src/types.ts` | Graph, NodeInstance, NodeDefinition, Edge, GroupDefinition | +| `packages/types/src/inputs.ts` | NodeInput union types (float, vec3, geometry, path, …) | +| `packages/utils/src/wasm.ts` | createWasmWrapper() — wraps WASM bytes into a NodeDefinition | --- @@ -83,54 +84,56 @@ User Interaction ```typescript // packages/types/src/types.ts -type NodeId = `${string}/${string}/${string}` // e.g. "max/plantarium/stem" +type NodeId = `${string}/${string}/${string}`; // e.g. "max/plantarium/stem" type NodeInstance = { - id: number - type: NodeId - position: [number, number] - props?: Record // current parameter values - meta?: { title?: string; lastModified?: string } - state: NodeRuntimeState // runtime-only, NOT serialized -} + id: number; + type: NodeId; + position: [number, number]; + props?: Record; // current parameter values + meta?: { title?: string; lastModified?: string }; + state: NodeRuntimeState; // runtime-only, NOT serialized +}; type NodeRuntimeState = { - type?: NodeDefinition // resolved definition - parents?: NodeInstance[] - children?: NodeInstance[] - x?: number; y?: number // interpolated position - mesh?: Mesh // Three.js mesh reference - ref?: HTMLElement -} + type?: NodeDefinition; // resolved definition + parents?: NodeInstance[]; + children?: NodeInstance[]; + x?: number; + y?: number; // interpolated position + mesh?: Mesh; // Three.js mesh reference + ref?: HTMLElement; +}; type NodeDefinition = { - id: NodeId - inputs?: Record - outputs?: string[] // output type names - meta?: { title?: string; description?: string } - execute(input: Int32Array): Int32Array // WASM function -} + id: NodeId; + inputs?: Record; + outputs?: string[]; // output type names + meta?: { title?: string; description?: string }; + execute(input: Int32Array): Int32Array; // WASM function +}; // Edge: [fromNode, outputIndex, toNode, inputSocketName] -type Edge = [NodeInstance, number, NodeInstance, string] +type Edge = [NodeInstance, number, NodeInstance, string]; type Graph = { - nodes: NodeInstance[] - edges: [number, number, number, string][] // serialized (IDs, not refs) - settings: Record - groups: GroupDefinition[] -} + nodes: NodeInstance[]; + edges: [number, number, number, string][]; // serialized (IDs, not refs) + settings: Record; + groups: GroupDefinition[]; +}; type GroupDefinition = { - id: number - nodes: NodeInstance[] - edges: Edge[] - inputs?: Record - outputs?: string[] -} + id: number; + nodes: NodeInstance[]; + edges: Edge[]; + inputs?: Record; + outputs?: string[]; +}; ``` ### NodeInput socket types + `float` | `integer` | `boolean` | `select` | `seed` | `vec3` | `geometry` | `path` | `shape` | `color` | `*` (wildcard) Each input can have: `value` (default), `label`, `hidden`, `external`, `setting` (link to graph setting), `accepts` (extra compatible types). @@ -140,34 +143,43 @@ Each input can have: `value` (default), `label`, `hidden`, `external`, `setting` ## Patterns & Conventions ### Svelte 5 reactivity + The codebase uses Svelte 5 runes throughout — `$state`, `$derived`, `$effect`. Collections use `SvelteMap` and `SvelteSet` (from `svelte/reactivity`) instead of plain Map/Set so that mutations trigger reactive updates. ### Context API + `GraphManager` and `GraphState` are provided via Svelte context (`setContext` / `getContext`) inside `GraphInterface`. All child components (Node, Edge, etc.) consume them via context rather than props. ### Edge representation + In memory, edges are `[NodeInstance, outputIndex, NodeInstance, inputSocketName]` — direct object references for fast traversal. On serialization (`Graph.edges`), they become `[nodeId, outputIndex, nodeId, inputSocketName]` (plain IDs). ### Socket compatibility + ```typescript areSocketsCompatible(outputType: string, inputType: string | string[]): boolean // '*' wildcard matches any type; 'geometry' accepts ['geometry', 'instances'] ``` ### WASM execution interface + Every node exposes a single function: `execute(input: Int32Array): Int32Array`. Data encoding (Plantarium): + - `[0, stemDepth, ...x,y,z,thickness]` — path - `[1, vertexCount, faceCount, ...faces, ...vertices, ...normals]` — geometry - `[2, vertexCount, faceCount, instanceCount, stemDepth, ...]` — instances ### Event emitter + `GraphManager extends EventEmitter<{ save, result, settings }>`. Subscribe with `manager.on('result', cb)`. Used to decouple the editor UI from runtime execution and persistence. ### History + Every mutation goes through `HistoryManager`. Call `this.history.save(this.serialize())` before mutations; undo/redo replays jsondiffpatch deltas. ### Internal node IDs + Built-in nodes use the `__internal/` namespace: `__internal/group/instance`, `__internal/node/debug`. Virtual boundary nodes use `__virtual/`: `__virtual/group/input`, `__virtual/group/output`. --- @@ -178,13 +190,13 @@ Group selected nodes with **Ctrl+G**. A `GroupDefinition` is stored in `Graph.gr **Known gaps as of 2026-05-03:** -| Issue | Location | -|-------|----------| -| `createGroupNode()` called but not defined | `graph-state.svelte.ts:334` → missing in `graph-manager.svelte.ts` | -| Runtime expects `group.graph.nodes/edges`; schema has flat `nodes/edges` | `runtime-executor.ts` vs `types.ts` | -| Runtime expects `group.inputs` as array; schema defines it as `Record` | Same mismatch | -| `enterGroupNode()` is a stub — no group navigation | `graph-state.svelte.ts` | -| `serialize()` writes parent-graph edges into group instead of group-internal edges | `graph-manager.svelte.ts` | +| Issue | Location | +| ----------------------------------------------------------------------------------------- | ------------------------------------------------------------------ | +| `createGroupNode()` called but not defined | `graph-state.svelte.ts:334` → missing in `graph-manager.svelte.ts` | +| Runtime expects `group.graph.nodes/edges`; schema has flat `nodes/edges` | `runtime-executor.ts` vs `types.ts` | +| Runtime expects `group.inputs` as array; schema defines it as `Record` | Same mismatch | +| `enterGroupNode()` is a stub — no group navigation | `graph-state.svelte.ts` | +| `serialize()` writes parent-graph edges into group instead of group-internal edges | `graph-manager.svelte.ts` | --- diff --git a/packages/ui/src/lib/JsonViewer.svelte b/packages/ui/src/lib/JsonViewer.svelte index 804f109..1c3c5ec 100644 --- a/packages/ui/src/lib/JsonViewer.svelte +++ b/packages/ui/src/lib/JsonViewer.svelte @@ -1,4 +1,4 @@ - -- 2.52.0 From a6b9ca43155b5e9357570705b6f45ba4fc3490a8 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:12:51 +0200 Subject: [PATCH 22/44] feat: capture system stats in benchmark --- app/benchmark/index.ts | 144 ++++++++++++++++++++++++++++++++--- app/benchmark/systemStats.ts | 136 +++++++++++++++++++++++++++++++++ 2 files changed, 271 insertions(+), 9 deletions(-) create mode 100644 app/benchmark/systemStats.ts diff --git a/app/benchmark/index.ts b/app/benchmark/index.ts index e06c003..bd6070c 100644 --- a/app/benchmark/index.ts +++ b/app/benchmark/index.ts @@ -1,9 +1,21 @@ import type { Graph, Graph as GraphType, NodeId } from '@nodarium/types'; import { createLogger, createPerformanceStore, splitNestedArray } from '@nodarium/utils'; + import { mkdir, writeFile } from 'node:fs/promises'; +import { freemem, loadavg, totalmem } from 'node:os'; import { resolve } from 'node:path'; + import { MemoryRuntimeExecutor } from '../src/lib/runtime/runtime-executor.ts'; import { BenchmarkRegistry } from './benchmarkRegistry.ts'; + +import { + getMachineInfo, + measureCpuUsage, + readCgroupCpuStat, + readCpuSnapshot, + readProcMemInfo, + SystemSample +} from './systemStats.ts'; import defaultPlantTemplate from './templates/default.json' assert { type: 'json' }; import lottaFacesTemplate from './templates/lotta-faces.json' assert { type: 'json' }; import plantTemplate from './templates/plant.json' assert { type: 'json' }; @@ -14,23 +26,34 @@ const r = new MemoryRuntimeExecutor(registry); const log = createLogger('bench'); const templates: Record = { - 'plant': plantTemplate as unknown as GraphType, + plant: plantTemplate as unknown as GraphType, 'lotta-faces': lottaFacesTemplate as unknown as GraphType, - 'default': defaultPlantTemplate as unknown as GraphType + default: defaultPlantTemplate as unknown as GraphType }; -function countGeometry(result: Int32Array): { totalVertices: number; totalFaces: number } { +function average(values: number[]) { + if (values.length === 0) return 0; + return values.reduce((a, b) => a + b, 0) / values.length; +} + +function countGeometry(result: Int32Array): { + totalVertices: number; + totalFaces: number; +} { const parts = splitNestedArray(result); + let totalVertices = 0; let totalFaces = 0; + for (const part of parts) { const type = part[0]; - // Values are stored as uint32 in the wasm output but read as signed int32; - // >>> 0 reinterprets the bit pattern as unsigned. + const vertexCount = part[1] >>> 0; const faceCount = part[2] >>> 0; + if (type === 2) { const instanceCount = part[3] >>> 0; + totalVertices += vertexCount * instanceCount; totalFaces += faceCount * instanceCount; } else { @@ -38,41 +61,144 @@ function countGeometry(result: Int32Array): { totalVertices: number; totalFaces: totalFaces += faceCount; } } - return { totalVertices, totalFaces }; + + return { + totalVertices, + totalFaces + }; } async function run(g: GraphType, amount: number) { await registry.load(g.nodes.map(n => n.type) as NodeId[]); + log.log('loaded ' + g.nodes.length + ' nodes'); log.log('warming up'); + for (let index = 0; index < 10; index++) { await r.execute(g, { randomSeed: true }); } + const systemSamples: SystemSample[] = []; + + let previousCpuSnapshot = await readCpuSnapshot(); + + const sampler = setInterval(async () => { + try { + const cpu = await measureCpuUsage(previousCpuSnapshot); + + previousCpuSnapshot = cpu.snapshot; + + const [l1, l5, l15] = loadavg(); + + systemSamples.push({ + timestamp: Date.now(), + + cpuUsagePercent: cpu.usagePercent, + cpuStealPercent: cpu.stealPercent, + + load1: l1, + load5: l5, + load15: l15, + + freeMemory: freemem(), + totalMemory: totalmem() + }); + } catch (err) { + console.error(err); + } + }, 1000); + log.log('executing'); + const perfStore = createPerformanceStore(); + r.perf = perfStore; - let res; + + let res: Int32Array | undefined; + + const cgroupBefore = await readCgroupCpuStat(); + for (let i = 0; i < amount; i++) { r.perf?.startRun(); + res = await r.execute(g, { randomSeed: true }); + r.perf?.stopRun(); + const { totalVertices, totalFaces } = countGeometry(res!); + r.perf?.addToLastRun('total-vertices', totalVertices); r.perf?.addToLastRun('total-faces', totalFaces); } + + const cgroupAfter = await readCgroupCpuStat(); + + clearInterval(sampler); + log.log('finished'); - return r.perf.get(); + + return { + data: r.perf.get(), + metadata: { + timestamp: new Date().toISOString(), + + machine: getMachineInfo(), + + process: { + pid: process.pid, + uptime: process.uptime(), + + memoryUsage: process.memoryUsage() + }, + + system: { + averages: { + cpuUsagePercent: average( + systemSamples.map(s => s.cpuUsagePercent) + ), + + cpuStealPercent: average( + systemSamples.map(s => s.cpuStealPercent) + ), + + load1: average(systemSamples.map(s => s.load1)), + load5: average(systemSamples.map(s => s.load5)), + load15: average(systemSamples.map(s => s.load15)), + + freeMemory: average( + systemSamples.map(s => s.freeMemory) + ) + }, + + samples: systemSamples, + + meminfo: await readProcMemInfo() + }, + + cgroup: { + before: cgroupBefore, + after: cgroupAfter + } + } + }; } async function main() { const outPath = resolve('benchmark/out/'); + await mkdir(outPath, { recursive: true }); + for (const key in templates) { log.log('executing ' + key); + const perfData = await run(templates[key], 100); - await writeFile(resolve(outPath, key + '.json'), JSON.stringify(perfData)); + + await writeFile( + resolve(outPath, key + '.json'), + JSON.stringify(perfData, null, 2) + ); + await new Promise(res => setTimeout(res, 200)); } } diff --git a/app/benchmark/systemStats.ts b/app/benchmark/systemStats.ts new file mode 100644 index 0000000..f78bfad --- /dev/null +++ b/app/benchmark/systemStats.ts @@ -0,0 +1,136 @@ +import { readFile } from 'node:fs/promises'; +import { cpus, totalmem } from 'node:os'; + +export type CpuSnapshot = { + idle: number; + total: number; + steal: number; +}; + +export type SystemSample = { + timestamp: number; + cpuUsagePercent: number; + cpuStealPercent: number; + load1: number; + load5: number; + load15: number; + freeMemory: number; + totalMemory: number; +}; + +export async function readCpuSnapshot(): Promise { + const stat = await readFile('/proc/stat', 'utf8'); + const line = stat.split('\n')[0]; + + const parts = line + .trim() + .split(/\s+/) + .slice(1) + .map(v => Number(v)); + + const [ + user, + nice, + system, + idle, + iowait, + irq, + softirq, + steal + ] = parts; + + return { + idle: idle + iowait, + total: parts.reduce((a, b) => a + b, 0), + steal: steal ?? 0 + }; +} + +export async function measureCpuUsage( + previous: CpuSnapshot +): Promise<{ + snapshot: CpuSnapshot; + usagePercent: number; + stealPercent: number; +}> { + const current = await readCpuSnapshot(); + + const idle = current.idle - previous.idle; + const total = current.total - previous.total; + const steal = current.steal - previous.steal; + + return { + snapshot: current, + usagePercent: total === 0 ? 0 : 100 * (1 - idle / total), + stealPercent: total === 0 ? 0 : 100 * (steal / total) + }; +} + +export async function readCgroupCpuStat() { + const possiblePaths = [ + '/sys/fs/cgroup/cpu.stat', + '/sys/fs/cgroup/cpu/cpu.stat' + ]; + + for (const path of possiblePaths) { + try { + const txt = await readFile(path, 'utf8'); + + return Object.fromEntries( + txt + .trim() + .split('\n') + .map(line => { + const [k, v] = line.trim().split(/\s+/); + return [k, Number(v)]; + }) + ); + } catch { + // continue + } + } + + return null; +} + +export async function readProcMemInfo() { + try { + const txt = await readFile('/proc/meminfo', 'utf8'); + + const result: Record = {}; + + for (const line of txt.split('\n')) { + const match = line.match(/^(\w+):\s+(\d+)/); + + if (!match) continue; + + result[match[1]] = Number(match[2]); + } + + return result; + } catch { + return null; + } +} + +export function getMachineInfo() { + const cpuInfo = cpus(); + + return { + platform: process.platform, + arch: process.arch, + nodeVersion: process.version, + + cpuModel: cpuInfo[0]?.model ?? 'unknown', + cpuCount: cpuInfo.length, + + totalMemory: totalmem(), + + ci: { + githubActions: process.env.GITHUB_ACTIONS ?? false, + runnerName: process.env.RUNNER_NAME ?? null, + runnerOs: process.env.RUNNER_OS ?? null, + runnerArch: process.env.RUNNER_ARCH ?? null + } + }; +} -- 2.52.0 From db5ee8ba29812e6865706966ff690ef335ff5e4f Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:19:18 +0200 Subject: [PATCH 23/44] fix: make eslint happy --- app/benchmark/systemStats.ts | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) diff --git a/app/benchmark/systemStats.ts b/app/benchmark/systemStats.ts index f78bfad..e7bcc1f 100644 --- a/app/benchmark/systemStats.ts +++ b/app/benchmark/systemStats.ts @@ -22,22 +22,15 @@ export async function readCpuSnapshot(): Promise { const stat = await readFile('/proc/stat', 'utf8'); const line = stat.split('\n')[0]; - const parts = line + const parts: number[] = line .trim() .split(/\s+/) .slice(1) - .map(v => Number(v)); + .map((v: unknown) => Number(v)); - const [ - user, - nice, - system, - idle, - iowait, - irq, - softirq, - steal - ] = parts; + const idle = parts[3]; + const iowait = parts[4]; + const steal = parts[7]; return { idle: idle + iowait, @@ -74,7 +67,7 @@ export async function readCgroupCpuStat() { for (const path of possiblePaths) { try { - const txt = await readFile(path, 'utf8'); + const txt: string = await readFile(path, 'utf8'); return Object.fromEntries( txt -- 2.52.0 From 6c9cd1505d72c1c0600910f56ee158d07b7e4811 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:30:42 +0200 Subject: [PATCH 24/44] chore: sync sveltekit app before e2e --- .gitea/workflows/release.yaml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml index 12bf304..e0f5beb 100644 --- a/.gitea/workflows/release.yaml +++ b/.gitea/workflows/release.yaml @@ -65,6 +65,12 @@ jobs: - name: 🔧 Setup uses: ./.gitea/actions/setup + - name: 🔧 Make sure firefox is setup + # run: pnpm dlx playwright install --with-deps firefox + + - name: 🔧 Sync svelte-kit + run: pnpm --filter @nodarium/app exec svelte-kit sync + - name: 🧪 Run Tests run: xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" pnpm test:e2e -- 2.52.0 From cd7b51d86a1243e0714d9be73588db56c844086c Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:37:52 +0200 Subject: [PATCH 25/44] chore: sync sveltekit app before e2e --- .gitea/workflows/release.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml index e0f5beb..fc441e6 100644 --- a/.gitea/workflows/release.yaml +++ b/.gitea/workflows/release.yaml @@ -65,8 +65,8 @@ jobs: - name: 🔧 Setup uses: ./.gitea/actions/setup - - name: 🔧 Make sure firefox is setup - # run: pnpm dlx playwright install --with-deps firefox + # - name: 🔧 Make sure firefox is setup + # run: pnpm dlx playwright install --with-deps firefox - name: 🔧 Sync svelte-kit run: pnpm --filter @nodarium/app exec svelte-kit sync -- 2.52.0 From 8f60816c7841c845120e71590e1c4672d218703e Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:43:38 +0200 Subject: [PATCH 26/44] chore: sync sveltekit app before e2e --- .gitea/workflows/release.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml index fc441e6..8a77f71 100644 --- a/.gitea/workflows/release.yaml +++ b/.gitea/workflows/release.yaml @@ -69,7 +69,7 @@ jobs: # run: pnpm dlx playwright install --with-deps firefox - name: 🔧 Sync svelte-kit - run: pnpm --filter @nodarium/app exec svelte-kit sync + run: pnpm --filter @nodarium/app --filter @nodarium/ui exec svelte-kit sync - name: 🧪 Run Tests run: xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" pnpm test:e2e -- 2.52.0 From 733b0a2ceb3be6fac1eda5bbf856a4bd1f724e36 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 15:49:55 +0200 Subject: [PATCH 27/44] chore: sync sveltekit app before e2e --- .gitea/workflows/release.yaml | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/.gitea/workflows/release.yaml b/.gitea/workflows/release.yaml index 8a77f71..abf9f44 100644 --- a/.gitea/workflows/release.yaml +++ b/.gitea/workflows/release.yaml @@ -65,11 +65,8 @@ jobs: - name: 🔧 Setup uses: ./.gitea/actions/setup - # - name: 🔧 Make sure firefox is setup - # run: pnpm dlx playwright install --with-deps firefox - - - name: 🔧 Sync svelte-kit - run: pnpm --filter @nodarium/app --filter @nodarium/ui exec svelte-kit sync + - name: 🏗️ Build Web Assets + run: pnpm build - name: 🧪 Run Tests run: xvfb-run --auto-servernum --server-args="-screen 0 1280x1024x24" pnpm test:e2e -- 2.52.0 From 0ed22f20b913837b8e90d45aa1a4ada1a90a9313 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 16:01:21 +0200 Subject: [PATCH 28/44] chore: pnpm upgrade --- app/package.json | 58 +- package.json | 2 +- packages/planty/package.json | 32 +- packages/types/package.json | 4 +- packages/ui/package.json | 58 +- packages/utils/package.json | 6 +- pnpm-lock.yaml | 3061 ++++++++++++---------------------- pnpm-workspace.yaml | 7 +- 8 files changed, 1111 insertions(+), 2117 deletions(-) diff --git a/app/package.json b/app/package.json index 619c069..181f032 100644 --- a/app/package.json +++ b/app/package.json @@ -18,49 +18,49 @@ "bench": "tsx ./benchmark/index.ts" }, "dependencies": { + "@nodarium/planty": "workspace:*", "@nodarium/ui": "workspace:*", "@nodarium/utils": "workspace:*", - "@nodarium/planty": "workspace:*", - "@sveltejs/kit": "^2.50.2", - "@tailwindcss/vite": "^4.1.18", - "@threlte/core": "8.3.1", - "@threlte/extras": "9.7.1", + "@sveltejs/kit": "^2.59.0", + "@tailwindcss/vite": "^4.2.4", + "@threlte/core": "8.5.11", + "@threlte/extras": "9.15.1", "comlink": "^4.4.2", "file-saver": "^2.0.5", "idb": "^8.0.3", "jsondiffpatch": "^0.7.3", "micromark": "^4.0.2", - "tailwindcss": "^4.1.18", - "three": "^0.182.0" + "tailwindcss": "^4.2.4", + "three": "^0.184.0" }, "devDependencies": { - "@eslint/compat": "^2.0.2", - "@eslint/js": "^9.39.2", - "@iconify-json/tabler": "^1.2.26", - "@iconify/tailwind4": "^1.2.1", + "@eslint/compat": "^2.0.5", + "@eslint/js": "^10.0.1", + "@iconify-json/tabler": "^1.2.33", + "@iconify/tailwind4": "^1.2.3", "@nodarium/types": "workspace:^", - "@playwright/test": "^1.58.1", + "@playwright/test": "^1.59.1", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/vite-plugin-svelte": "^6.2.4", - "@tsconfig/svelte": "^5.0.7", + "@sveltejs/vite-plugin-svelte": "^7.0.0", + "@tsconfig/svelte": "^5.0.8", "@types/file-saver": "^2.0.7", - "@types/three": "^0.182.0", - "@vitest/browser-playwright": "^4.0.18", - "dprint": "^0.51.1", - "eslint": "^9.39.2", - "eslint-plugin-svelte": "^3.14.0", - "globals": "^17.3.0", - "svelte": "^5.49.2", - "svelte-check": "^4.3.6", + "@types/three": "^0.184.0", + "@vitest/browser-playwright": "^4.1.5", + "dprint": "^0.54.0", + "eslint": "^10.3.0", + "eslint-plugin-svelte": "^3.17.1", + "globals": "^17.6.0", + "svelte": "^5.55.5", + "svelte-check": "^4.4.7", "tslib": "^2.8.1", "tsx": "^4.21.0", - "typescript": "^5.9.3", - "typescript-eslint": "^8.54.0", - "vite": "^7.3.1", + "typescript": "^6.0.3", + "typescript-eslint": "^8.59.1", + "vite": "^8.0.10", "vite-plugin-comlink": "^5.3.0", - "vite-plugin-glsl": "^1.5.5", - "vite-plugin-wasm": "^3.5.0", - "vitest": "^4.0.18", - "vitest-browser-svelte": "^2.0.2" + "vite-plugin-glsl": "^1.6.0", + "vite-plugin-wasm": "^3.6.0", + "vitest": "^4.1.5", + "vitest-browser-svelte": "^2.1.1" } } diff --git a/package.json b/package.json index b18cc42..5553daa 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,6 @@ "packageManager": "pnpm@10.28.1+sha512.7d7dbbca9e99447b7c3bf7a73286afaaf6be99251eb9498baefa7d406892f67b879adb3a1d7e687fc4ccc1a388c7175fbaae567a26ab44d1067b54fcb0d6a316", "devDependencies": { "chokidar-cli": "catalog:", - "dprint": "^0.51.1" + "dprint": "^0.54.0" } } diff --git a/packages/planty/package.json b/packages/planty/package.json index c6dcdb0..a283448 100644 --- a/packages/planty/package.json +++ b/packages/planty/package.json @@ -34,29 +34,29 @@ "svelte": "^5.0.0" }, "devDependencies": { - "@nodarium/ui": "workspace:*", - "@eslint/compat": "^2.0.4", + "@eslint/compat": "^2.0.5", "@eslint/js": "^10.0.1", + "@nodarium/ui": "workspace:*", "@sveltejs/adapter-auto": "^7.0.1", - "@sveltejs/kit": "^2.57.0", + "@sveltejs/kit": "^2.59.0", "@sveltejs/package": "^2.5.7", "@sveltejs/vite-plugin-svelte": "^7.0.0", - "@tailwindcss/vite": "^4.2.2", - "@types/node": "^24", - "eslint": "^10.2.0", + "@tailwindcss/vite": "^4.2.4", + "@types/node": "^25.6.0", + "eslint": "^10.3.0", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-svelte": "^3.17.0", - "globals": "^17.4.0", - "prettier": "^3.8.1", + "eslint-plugin-svelte": "^3.17.1", + "globals": "^17.6.0", + "prettier": "^3.8.3", "prettier-plugin-svelte": "^3.5.1", - "prettier-plugin-tailwindcss": "^0.7.2", + "prettier-plugin-tailwindcss": "^0.8.0", "publint": "^0.3.18", - "svelte": "^5.55.2", - "svelte-check": "^4.4.6", - "tailwindcss": "^4.2.2", - "typescript": "^6.0.2", - "typescript-eslint": "^8.58.1", - "vite": "^8.0.7" + "svelte": "^5.55.5", + "svelte-check": "^4.4.7", + "tailwindcss": "^4.2.4", + "typescript": "^6.0.3", + "typescript-eslint": "^8.59.1", + "vite": "^8.0.10" }, "keywords": [ "svelte" diff --git a/packages/types/package.json b/packages/types/package.json index 65e8970..64809ff 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -18,9 +18,9 @@ "author": "", "license": "ISC", "dependencies": { - "zod": "^4.3.6" + "zod": "^4.4.3" }, "devDependencies": { - "dprint": "^0.51.1" + "dprint": "^0.54.0" } } diff --git a/packages/ui/package.json b/packages/ui/package.json index a8e70ef..bff81fc 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -30,46 +30,46 @@ "svelte": "^4.0.0" }, "devDependencies": { - "@eslint/compat": "^2.0.2", - "@eslint/eslintrc": "^3.3.3", - "@eslint/js": "^9.39.2", + "@eslint/compat": "^2.0.5", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "^10.0.1", "@nodarium/types": "workspace:^", - "@playwright/test": "^1.58.1", + "@playwright/test": "^1.59.1", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.50.2", + "@sveltejs/kit": "^2.59.0", "@sveltejs/package": "^2.5.7", - "@sveltejs/vite-plugin-svelte": "^6.2.4", + "@sveltejs/vite-plugin-svelte": "^7.0.0", "@testing-library/svelte": "^5.3.1", "@types/eslint": "^9.6.1", - "@types/three": "^0.182.0", - "@typescript-eslint/eslint-plugin": "^8.54.0", - "@typescript-eslint/parser": "^8.54.0", - "@vitest/browser-playwright": "^4.0.18", - "dprint": "^0.51.1", - "eslint": "^9.39.2", - "eslint-plugin-svelte": "^3.14.0", - "globals": "^17.3.0", - "publint": "^0.3.17", - "svelte": "^5.49.2", - "svelte-check": "^4.3.6", - "svelte-eslint-parser": "^1.4.1", + "@types/three": "^0.184.0", + "@typescript-eslint/eslint-plugin": "^8.59.1", + "@typescript-eslint/parser": "^8.59.1", + "@vitest/browser-playwright": "^4.1.5", + "dprint": "^0.54.0", + "eslint": "^10.3.0", + "eslint-plugin-svelte": "^3.17.1", + "globals": "^17.6.0", + "publint": "^0.3.18", + "svelte": "^5.55.5", + "svelte-check": "^4.4.7", + "svelte-eslint-parser": "^1.6.0", "tslib": "^2.8.1", - "typescript": "^5.9.3", - "typescript-eslint": "^8.54.0", - "vite": "^7.3.1", - "vitest": "^4.0.18", - "vitest-browser-svelte": "^2.0.2" + "typescript": "^6.0.3", + "typescript-eslint": "^8.59.1", + "vite": "^8.0.10", + "vitest": "^4.1.5", + "vitest-browser-svelte": "^2.1.1" }, "svelte": "./dist/index.js", "types": "./dist/index.d.ts", "type": "module", "dependencies": { + "@iconify-json/tabler": "^1.2.33", + "@iconify/tailwind4": "^1.2.3", "@nodarium/ui": "workspace:*", - "@iconify-json/tabler": "^1.2.26", - "@iconify/tailwind4": "^1.2.1", - "@tailwindcss/vite": "^4.1.18", - "@threlte/core": "^8.3.1", - "@threlte/extras": "^9.7.1", - "tailwindcss": "^4.1.18" + "@tailwindcss/vite": "^4.2.4", + "@threlte/core": "^8.5.11", + "@threlte/extras": "^9.15.1", + "tailwindcss": "^4.2.4" } } diff --git a/packages/utils/package.json b/packages/utils/package.json index 7809b75..ce8489c 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -16,8 +16,8 @@ "@nodarium/types": "workspace:^" }, "devDependencies": { - "dprint": "^0.51.1", - "vite": "^7.3.1", - "vitest": "^4.0.18" + "dprint": "^0.54.0", + "vite": "^8.0.10", + "vitest": "^4.1.5" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e3fd078..1e3a902 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,12 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +catalogs: + default: + chokidar-cli: + specifier: github:open-cli-tools/chokidar-cli#semver:v4.0.0 + version: 4.0.0 + importers: .: @@ -12,8 +18,8 @@ importers: specifier: 'catalog:' version: https://codeload.github.com/open-cli-tools/chokidar-cli/tar.gz/8dd8a1e8631d377de600f628d819a0cda46c102f dprint: - specifier: ^0.51.1 - version: 0.51.1 + specifier: ^0.54.0 + version: 0.54.0 app: dependencies: @@ -27,17 +33,17 @@ importers: specifier: workspace:* version: link:../packages/utils '@sveltejs/kit': - specifier: ^2.50.2 - version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^2.59.0 + version: 2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@tailwindcss/vite': - specifier: ^4.1.18 - version: 4.1.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^4.2.4 + version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@threlte/core': - specifier: 8.3.1 - version: 8.3.1(svelte@5.49.2)(three@0.182.0) + specifier: 8.5.11 + version: 8.5.11(svelte@5.55.5(@typescript-eslint/types@8.59.1))(three@0.184.0) '@threlte/extras': - specifier: 9.7.1 - version: 9.7.1(@types/three@0.182.0)(svelte@5.49.2)(three@0.182.0) + specifier: 9.15.1 + version: 9.15.1(@types/three@0.184.0)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(three@0.184.0) comlink: specifier: ^4.4.2 version: 4.4.2 @@ -54,66 +60,66 @@ importers: specifier: ^4.0.2 version: 4.0.2 tailwindcss: - specifier: ^4.1.18 - version: 4.1.18 + specifier: ^4.2.4 + version: 4.2.4 three: - specifier: ^0.182.0 - version: 0.182.0 + specifier: ^0.184.0 + version: 0.184.0 devDependencies: '@eslint/compat': - specifier: ^2.0.2 - version: 2.0.2(eslint@9.39.2(jiti@2.6.1)) + specifier: ^2.0.5 + version: 2.0.5(eslint@10.3.0(jiti@2.6.1)) '@eslint/js': - specifier: ^9.39.2 - version: 9.39.2 + specifier: ^10.0.1 + version: 10.0.1(eslint@10.3.0(jiti@2.6.1)) '@iconify-json/tabler': - specifier: ^1.2.26 - version: 1.2.26 + specifier: ^1.2.33 + version: 1.2.33 '@iconify/tailwind4': - specifier: ^1.2.1 - version: 1.2.1(tailwindcss@4.1.18) + specifier: ^1.2.3 + version: 1.2.3(tailwindcss@4.2.4) '@nodarium/types': specifier: workspace:^ version: link:../packages/types '@playwright/test': - specifier: ^1.58.1 - version: 1.58.1 + specifier: ^1.59.1 + version: 1.59.1 '@sveltejs/adapter-static': specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))) + version: 3.0.10(@sveltejs/kit@2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))) '@sveltejs/vite-plugin-svelte': - specifier: ^6.2.4 - version: 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^7.0.0 + version: 7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@tsconfig/svelte': - specifier: ^5.0.7 - version: 5.0.7 + specifier: ^5.0.8 + version: 5.0.8 '@types/file-saver': specifier: ^2.0.7 version: 2.0.7 '@types/three': - specifier: ^0.182.0 - version: 0.182.0 + specifier: ^0.184.0 + version: 0.184.0 '@vitest/browser-playwright': - specifier: ^4.0.18 - version: 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18) + specifier: ^4.1.5 + version: 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5) dprint: - specifier: ^0.51.1 - version: 0.51.1 + specifier: ^0.54.0 + version: 0.54.0 eslint: - specifier: ^9.39.2 - version: 9.39.2(jiti@2.6.1) + specifier: ^10.3.0 + version: 10.3.0(jiti@2.6.1) eslint-plugin-svelte: - specifier: ^3.14.0 - version: 3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.49.2)(ts-node@10.9.2(@types/node@24.12.2)(typescript@5.9.3)) + specifier: ^3.17.1 + version: 3.17.1(eslint@10.3.0(jiti@2.6.1))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) globals: - specifier: ^17.3.0 - version: 17.3.0 + specifier: ^17.6.0 + version: 17.6.0 svelte: - specifier: ^5.49.2 - version: 5.49.2 + specifier: ^5.55.5 + version: 5.55.5(@typescript-eslint/types@8.59.1) svelte-check: - specifier: ^4.3.6 - version: 4.3.6(picomatch@4.0.3)(svelte@5.49.2)(typescript@5.9.3) + specifier: ^4.4.7 + version: 4.4.7(picomatch@4.0.4)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3) tslib: specifier: ^2.8.1 version: 2.8.1 @@ -121,223 +127,223 @@ importers: specifier: ^4.21.0 version: 4.21.0 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 typescript-eslint: - specifier: ^8.54.0 - version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.59.1 + version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^8.0.10 + version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) vite-plugin-comlink: specifier: ^5.3.0 - version: 5.3.0(comlink@4.4.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + version: 5.3.0(comlink@4.4.2)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) vite-plugin-glsl: - specifier: ^1.5.5 - version: 1.5.5(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^1.6.0 + version: 1.6.0(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.7)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) vite-plugin-wasm: - specifier: ^3.5.0 - version: 3.5.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^3.6.0 + version: 3.6.0(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^4.1.5 + version: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) vitest-browser-svelte: - specifier: ^2.0.2 - version: 2.0.2(svelte@5.49.2)(vitest@4.0.18) + specifier: ^2.1.1 + version: 2.1.1(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vitest@4.1.5) packages/planty: devDependencies: '@eslint/compat': - specifier: ^2.0.4 - version: 2.0.5(eslint@10.2.1(jiti@2.6.1)) + specifier: ^2.0.5 + version: 2.0.5(eslint@10.3.0(jiti@2.6.1)) '@eslint/js': specifier: ^10.0.1 - version: 10.0.1(eslint@10.2.1(jiti@2.6.1)) + version: 10.0.1(eslint@10.3.0(jiti@2.6.1)) '@nodarium/ui': specifier: workspace:* version: link:../ui '@sveltejs/adapter-auto': specifier: ^7.0.1 - version: 7.0.1(@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))) + version: 7.0.1(@sveltejs/kit@2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))) '@sveltejs/kit': - specifier: ^2.57.0 - version: 2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^2.59.0 + version: 2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@sveltejs/package': specifier: ^2.5.7 - version: 2.5.7(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3) + version: 2.5.7(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3) '@sveltejs/vite-plugin-svelte': specifier: ^7.0.0 - version: 7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + version: 7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@tailwindcss/vite': - specifier: ^4.2.2 - version: 4.2.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^4.2.4 + version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@types/node': - specifier: ^24 - version: 24.12.2 + specifier: ^25.6.0 + version: 25.6.0 eslint: - specifier: ^10.2.0 - version: 10.2.1(jiti@2.6.1) + specifier: ^10.3.0 + version: 10.3.0(jiti@2.6.1) eslint-config-prettier: specifier: ^10.1.8 - version: 10.1.8(eslint@10.2.1(jiti@2.6.1)) + version: 10.1.8(eslint@10.3.0(jiti@2.6.1)) eslint-plugin-svelte: - specifier: ^3.17.0 - version: 3.17.0(eslint@10.2.1(jiti@2.6.1))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(ts-node@10.9.2(@types/node@24.12.2)(typescript@6.0.3)) + specifier: ^3.17.1 + version: 3.17.1(eslint@10.3.0(jiti@2.6.1))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) globals: - specifier: ^17.4.0 - version: 17.5.0 + specifier: ^17.6.0 + version: 17.6.0 prettier: - specifier: ^3.8.1 + specifier: ^3.8.3 version: 3.8.3 prettier-plugin-svelte: specifier: ^3.5.1 - version: 3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + version: 3.5.1(prettier@3.8.3)(svelte@5.55.5(@typescript-eslint/types@8.59.1)) prettier-plugin-tailwindcss: - specifier: ^0.7.2 - version: 0.7.2(prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)))(prettier@3.8.3) + specifier: ^0.8.0 + version: 0.8.0(prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.5(@typescript-eslint/types@8.59.1)))(prettier@3.8.3) publint: specifier: ^0.3.18 version: 0.3.18 svelte: - specifier: ^5.55.2 - version: 5.55.4(@typescript-eslint/types@8.58.2) + specifier: ^5.55.5 + version: 5.55.5(@typescript-eslint/types@8.59.1) svelte-check: - specifier: ^4.4.6 - version: 4.4.6(picomatch@4.0.4)(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3) + specifier: ^4.4.7 + version: 4.4.7(picomatch@4.0.4)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3) tailwindcss: - specifier: ^4.2.2 - version: 4.2.2 + specifier: ^4.2.4 + version: 4.2.4 typescript: - specifier: ^6.0.2 + specifier: ^6.0.3 version: 6.0.3 typescript-eslint: - specifier: ^8.58.1 - version: 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) + specifier: ^8.59.1 + version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) vite: - specifier: ^8.0.7 - version: 8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^8.0.10 + version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) packages/types: dependencies: zod: - specifier: ^4.3.6 - version: 4.3.6 + specifier: ^4.4.3 + version: 4.4.3 devDependencies: dprint: - specifier: ^0.51.1 - version: 0.51.1 + specifier: ^0.54.0 + version: 0.54.0 packages/ui: dependencies: '@iconify-json/tabler': - specifier: ^1.2.26 - version: 1.2.26 + specifier: ^1.2.33 + version: 1.2.33 '@iconify/tailwind4': - specifier: ^1.2.1 - version: 1.2.1(tailwindcss@4.1.18) + specifier: ^1.2.3 + version: 1.2.3(tailwindcss@4.2.4) '@nodarium/ui': specifier: workspace:* version: 'link:' '@tailwindcss/vite': - specifier: ^4.1.18 - version: 4.1.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^4.2.4 + version: 4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@threlte/core': - specifier: ^8.3.1 - version: 8.3.1(svelte@5.49.2)(three@0.182.0) + specifier: ^8.5.11 + version: 8.5.11(svelte@5.55.5(@typescript-eslint/types@8.59.1))(three@0.184.0) '@threlte/extras': - specifier: ^9.7.1 - version: 9.7.1(@types/three@0.182.0)(svelte@5.49.2)(three@0.182.0) + specifier: ^9.15.1 + version: 9.15.1(@types/three@0.184.0)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(three@0.184.0) tailwindcss: - specifier: ^4.1.18 - version: 4.1.18 + specifier: ^4.2.4 + version: 4.2.4 devDependencies: '@eslint/compat': - specifier: ^2.0.2 - version: 2.0.2(eslint@9.39.2(jiti@2.6.1)) + specifier: ^2.0.5 + version: 2.0.5(eslint@10.3.0(jiti@2.6.1)) '@eslint/eslintrc': - specifier: ^3.3.3 - version: 3.3.3 + specifier: ^3.3.5 + version: 3.3.5 '@eslint/js': - specifier: ^9.39.2 - version: 9.39.2 + specifier: ^10.0.1 + version: 10.0.1(eslint@10.3.0(jiti@2.6.1)) '@nodarium/types': specifier: workspace:^ version: link:../types '@playwright/test': - specifier: ^1.58.1 - version: 1.58.1 + specifier: ^1.59.1 + version: 1.59.1 '@sveltejs/adapter-static': specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))) + version: 3.0.10(@sveltejs/kit@2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))) '@sveltejs/kit': - specifier: ^2.50.2 - version: 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^2.59.0 + version: 2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@sveltejs/package': specifier: ^2.5.7 - version: 2.5.7(svelte@5.49.2)(typescript@5.9.3) + version: 2.5.7(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3) '@sveltejs/vite-plugin-svelte': - specifier: ^6.2.4 - version: 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + specifier: ^7.0.0 + version: 7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@testing-library/svelte': specifier: ^5.3.1 - version: 5.3.1(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18) + version: 5.3.1(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5) '@types/eslint': specifier: ^9.6.1 version: 9.6.1 '@types/three': - specifier: ^0.182.0 - version: 0.182.0 + specifier: ^0.184.0 + version: 0.184.0 '@typescript-eslint/eslint-plugin': - specifier: ^8.54.0 - version: 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.59.1 + version: 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@typescript-eslint/parser': - specifier: ^8.54.0 - version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.59.1 + version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) '@vitest/browser-playwright': - specifier: ^4.0.18 - version: 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18) + specifier: ^4.1.5 + version: 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5) dprint: - specifier: ^0.51.1 - version: 0.51.1 + specifier: ^0.54.0 + version: 0.54.0 eslint: - specifier: ^9.39.2 - version: 9.39.2(jiti@2.6.1) + specifier: ^10.3.0 + version: 10.3.0(jiti@2.6.1) eslint-plugin-svelte: - specifier: ^3.14.0 - version: 3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.49.2)(ts-node@10.9.2(@types/node@24.12.2)(typescript@5.9.3)) + specifier: ^3.17.1 + version: 3.17.1(eslint@10.3.0(jiti@2.6.1))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) globals: - specifier: ^17.3.0 - version: 17.3.0 + specifier: ^17.6.0 + version: 17.6.0 publint: - specifier: ^0.3.17 - version: 0.3.17 + specifier: ^0.3.18 + version: 0.3.18 svelte: - specifier: ^5.49.2 - version: 5.49.2 + specifier: ^5.55.5 + version: 5.55.5(@typescript-eslint/types@8.59.1) svelte-check: - specifier: ^4.3.6 - version: 4.3.6(picomatch@4.0.4)(svelte@5.49.2)(typescript@5.9.3) + specifier: ^4.4.7 + version: 4.4.7(picomatch@4.0.4)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3) svelte-eslint-parser: - specifier: ^1.4.1 - version: 1.4.1(svelte@5.49.2) + specifier: ^1.6.0 + version: 1.6.0(svelte@5.55.5(@typescript-eslint/types@8.59.1)) tslib: specifier: ^2.8.1 version: 2.8.1 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ^6.0.3 + version: 6.0.3 typescript-eslint: - specifier: ^8.54.0 - version: 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.59.1 + version: 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^8.0.10 + version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^4.1.5 + version: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) vitest-browser-svelte: - specifier: ^2.0.2 - version: 2.0.2(svelte@5.49.2)(vitest@4.0.18) + specifier: ^2.1.1 + version: 2.1.1(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vitest@4.1.5) packages/utils: dependencies: @@ -346,14 +352,14 @@ importers: version: link:../types devDependencies: dprint: - specifier: ^0.51.1 - version: 0.51.1 + specifier: ^0.54.0 + version: 0.54.0 vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^8.0.10 + version: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) vitest: - specifier: ^4.0.18 - version: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + specifier: ^4.1.5 + version: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) packages: @@ -371,10 +377,13 @@ packages: resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - '@babel/runtime@7.28.6': - resolution: {integrity: sha512-05WQkdpL9COIMz4LjTxGpPNCdlpyimKppYNoJ5Di5EUObifl8t4tuLuUBBZEpoLYOmfvIWrsp9fCl0HoPRVTdA==} + '@babel/runtime@7.29.2': + resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} engines: {node: '>=6.9.0'} + '@blazediff/core@1.9.1': + resolution: {integrity: sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==} + '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} @@ -407,8 +416,8 @@ packages: resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} engines: {node: '>=18'} - '@cyberalien/svg-utils@1.1.1': - resolution: {integrity: sha512-i05Cnpzeezf3eJAXLx7aFirTYYoq5D1XUItp1XsjqkerNJh//6BG9sOYHbiO7v0KYMvJAx3kosrZaRcNlQPdsA==} + '@cyberalien/svg-utils@1.2.15': + resolution: {integrity: sha512-ZbKU6npzW5PNocdoLVJYfKzaP+c/RpT6JUkoaKrW1DOcw6lyXub8XtcNpI3xok6FnyNjS6ZbsrrtjTnS9yeZAQ==} '@dimforge/rapier3d-compat@0.12.0': resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==} @@ -416,222 +425,222 @@ packages: '@dmsnell/diff-match-patch@1.1.0': resolution: {integrity: sha512-yejLPmM5pjsGvxS9gXablUSbInW7H976c/FJ4iQxWIm7/38xBySRemTPDe34lhg1gVLbJntX0+sH0jYfU+PN9A==} - '@dprint/darwin-arm64@0.51.1': - resolution: {integrity: sha512-C7fkaz0/NGf/X4G9Cq65izdJgerND5jWShOaPiOgGs4A0CyCMKMLRd45m3xKIttuO8x0IQiZVixD22qmVglXmQ==} + '@dprint/darwin-arm64@0.54.0': + resolution: {integrity: sha512-yqRI4enH+BDp+4+ZsPVdZM5h873JK1lN7li9l9A5u4C4cvh1oEsiBWAzEPccRkJ2ctF8LgaizBSxO38sqEVYbw==} cpu: [arm64] os: [darwin] - '@dprint/darwin-x64@0.51.1': - resolution: {integrity: sha512-/CESb4SJejshTWb/nO2gucrioKdLD/fK2gKB5Immi4XecAjhkV1HZpUMRLsIeVDQ6ha7xktKbnnvudJRI0maSg==} + '@dprint/darwin-x64@0.54.0': + resolution: {integrity: sha512-W9BARpgHypcQwatg5mnHaCpX6pLX5dBxxiv+tZKruhOmq8MKYOrAYDXlceMuHSowmWREfUF5yL4SRgXDGI6WQw==} cpu: [x64] os: [darwin] - '@dprint/linux-arm64-glibc@0.51.1': - resolution: {integrity: sha512-W+QD/4TkQKMPq02uz+ZIz/EI91YEtS2zHBu/Jihx2lfNh3HjUKgyY1KfqCTg2WGJVDkJtPc5KDw+M8yd4rI+Rg==} + '@dprint/linux-arm64-glibc@0.54.0': + resolution: {integrity: sha512-VhM7p70VFuNqxZMdiv1e+nMboPj/hMFlTIBWrRaX7+6VThs9mJr9+94wrUeXgfnfsyaEKSbRFa/dru1PINoSNw==} cpu: [arm64] os: [linux] - '@dprint/linux-arm64-musl@0.51.1': - resolution: {integrity: sha512-P4Cfn8wrdSvdoMoz0HtsC5zZpbh8Kk3OjRzgG4qs/gub5Ba3CCLcVaQvQmIOCvgPzdhPB41eSn5qAK87mh7vCQ==} + '@dprint/linux-arm64-musl@0.54.0': + resolution: {integrity: sha512-QS1A74Lv60/L9oemHCzbHgOLbV2smSJG5IxS5fjf8ZWetyUt918WDzIHBilz/+uiB+OlW2UVTsm952UG0YOrLw==} cpu: [arm64] os: [linux] - '@dprint/linux-loong64-glibc@0.51.1': - resolution: {integrity: sha512-dxDShELBrSGB9PktRqhYrm1UWCL+7N430rGuDTFg+i4d1wL4JD7EI5NDS/5IVbg3lrKJUu6gAJoY9NWF4sZ0mQ==} + '@dprint/linux-loong64-glibc@0.54.0': + resolution: {integrity: sha512-8Myka2/0KbhuZnEKL6jagPXTgDKVpd/tfXDRa0oibUBgaqOSku6iRMzHGa/PhqHL+s14Gcp+/cIHz0zU3Tkgug==} cpu: [loong64] os: [linux] - '@dprint/linux-loong64-musl@0.51.1': - resolution: {integrity: sha512-l+uNPzUBNxkywGN1HgvTV0CzUDpzXC+s6VEvjYRdVAEKl9TAsIfLMfZifS8rnlOi9hz/0sckmpny+wL40G6dhQ==} + '@dprint/linux-loong64-musl@0.54.0': + resolution: {integrity: sha512-/AN3xCuMhC4PK7Pbj7/4zBuhFGr4m0OHV/5uGTfzpkKX/3+AXoyKl7PbT2VlNMGXAK0kuRThfjtx23gIwlWk7Q==} cpu: [loong64] os: [linux] - '@dprint/linux-riscv64-glibc@0.51.1': - resolution: {integrity: sha512-YI6SemJRMsLUrtognhkAYOJ67j/AkiufHfx6+cPv/7qO6zBoBL6otR1e5yFYvAgEJOzRZD5g51EdqCcuK19B+g==} + '@dprint/linux-riscv64-glibc@0.54.0': + resolution: {integrity: sha512-Aw2vXzzwFDpPbXh6ajsSabVCkCc66C3hCyMKprR/IxYvFtjYX80nh1ox0c7iaw6c4HacHMRLGw7FUSXvomPaEQ==} cpu: [riscv64] os: [linux] - '@dprint/linux-x64-glibc@0.51.1': - resolution: {integrity: sha512-Hm9ntOWeclXU6/rZGYIN2XjuAhsRUZ77lRJC5EiM1rP6Ayh0J/YMsDdqlPAs+xZGdFFzt8ZeUpqJJJsbc54ZjQ==} + '@dprint/linux-x64-glibc@0.54.0': + resolution: {integrity: sha512-zZqj3wQELOX8n6QfT2uuWoMf64Wv0lMXNyam3btm+PKkg0P6a54TPL09Bs9XsViOdxgTcamsiQ7HlErt/LEjIA==} cpu: [x64] os: [linux] - '@dprint/linux-x64-musl@0.51.1': - resolution: {integrity: sha512-iUs/9Z4Ky6+2GAK+i1jF1ZwM27CSIGaqw3LxTXtmE8eBCRwyCW+opzn9bzaFtlT9REUAGMC5PXihAPmzP3ttWg==} + '@dprint/linux-x64-musl@0.54.0': + resolution: {integrity: sha512-it6Qdt06dyW2adbAXpOCb7/KQLxlm4i1UphUAWqWsZk4t3EYetyAza9J0g3Vu9itIWSEIo9MnccgANckQJ6+qw==} cpu: [x64] os: [linux] - '@dprint/win32-arm64@0.51.1': - resolution: {integrity: sha512-oXjEL7Blf/160/j7U8MapRzSOVQvLIdAKEZbslIHA4Fwj10fvoDizqpfVU/aVj/BVrlIcZ/+AH8kfSC9XAyjLw==} + '@dprint/win32-arm64@0.54.0': + resolution: {integrity: sha512-F5kjV/6I9YtNOTDWHUpTqM2HHHS510BPL7z4NJuU0nDnaVeks7GwNEltGr56CcsG8XQYhkiAsqZytPu6AhA2hQ==} cpu: [arm64] os: [win32] - '@dprint/win32-x64@0.51.1': - resolution: {integrity: sha512-RM9thb/+Jm6GkXJS+eW+0Pzmz2PNeDk8ZOWcjunE1jv2RabHgm+GbeGpS+WZPOM9W3LSntswv6f4wjzfUkWD0g==} + '@dprint/win32-x64@0.54.0': + resolution: {integrity: sha512-AAr2ye/DtgYXDplRoPS+5U++x7T6W4a3I9FvTFWFxziFmUptvAg5G2c4FcXoAduSruhYZJvjDZrLseR2c3IwXg==} cpu: [x64] os: [win32] - '@emnapi/core@1.9.2': - resolution: {integrity: sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==} + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} - '@emnapi/runtime@1.9.2': - resolution: {integrity: sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==} + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} '@emnapi/wasi-threads@1.2.1': resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} - '@esbuild/aix-ppc64@0.27.3': - resolution: {integrity: sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==} + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.3': - resolution: {integrity: sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==} + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.3': - resolution: {integrity: sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==} + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.3': - resolution: {integrity: sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==} + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.3': - resolution: {integrity: sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==} + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.3': - resolution: {integrity: sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==} + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.3': - resolution: {integrity: sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==} + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.3': - resolution: {integrity: sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==} + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.3': - resolution: {integrity: sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==} + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.3': - resolution: {integrity: sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==} + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.3': - resolution: {integrity: sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==} + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.3': - resolution: {integrity: sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==} + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.3': - resolution: {integrity: sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==} + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.3': - resolution: {integrity: sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==} + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.3': - resolution: {integrity: sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==} + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.3': - resolution: {integrity: sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==} + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.3': - resolution: {integrity: sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==} + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.3': - resolution: {integrity: sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==} + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.3': - resolution: {integrity: sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==} + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.3': - resolution: {integrity: sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==} + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.3': - resolution: {integrity: sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.3': - resolution: {integrity: sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==} + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.3': - resolution: {integrity: sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==} + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.3': - resolution: {integrity: sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==} + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.3': - resolution: {integrity: sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==} + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.3': - resolution: {integrity: sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==} + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -646,15 +655,6 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/compat@2.0.2': - resolution: {integrity: sha512-pR1DoD0h3HfF675QZx0xsyrsU8q70Z/plx7880NOhS02NuWLgBCOMDL787nUeQ7EWLkxv3bPQJaarjcPQb2Dwg==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - peerDependencies: - eslint: ^8.40 || 9 || 10 - peerDependenciesMeta: - eslint: - optional: true - '@eslint/compat@2.0.5': resolution: {integrity: sha512-IbHDbHJfkVNv6xjlET8AIVo/K1NQt7YT4Rp6ok/clyBGcpRx1l6gv0Rq3vBvYfPJIZt6ODf66Zq08FJNDpnzgg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} @@ -664,36 +664,20 @@ packages: eslint: optional: true - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-array@0.23.5': resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/config-helpers@0.5.5': resolution: {integrity: sha512-eIJYKTCECbP/nsKaaruF6LW967mtbQbsw4JTtSVkUQc9MneSkbrgPJAbKl9nWr0ZeowV8BfsarBmPpBzGelA2w==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@1.1.0': - resolution: {integrity: sha512-/nr9K9wkr3P1EzFTdFdMoLuo1PmIxjmwvPozwoSodjNBdefGujXQUF93u1DDZpEaTuDvMsIQddsd35BwtrW9Xw==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@1.2.1': resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/eslintrc@3.3.3': - resolution: {integrity: sha512-Kr+LPIUVKz2qkx1HAMH8q1q6azbqBAsXJUxBl/ODDuVPX45Z9DfwB8tPjTi6nNZ8BuM3nbJxC5zCAg5elnBUTQ==} + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} '@eslint/js@10.0.1': @@ -705,32 +689,24 @@ packages: eslint: optional: true - '@eslint/js@9.39.2': - resolution: {integrity: sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/object-schema@3.0.5': resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@eslint/plugin-kit@0.7.1': resolution: {integrity: sha512-rZAP3aVgB9ds9KOeUSL+zZ21hPmo8dh6fnIFwRQj5EAZl9gzR7wxYbYXYysAM8CTqGmUGyp2S4kUdV17MnGuWQ==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -741,22 +717,22 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@iconify-json/tabler@1.2.26': - resolution: {integrity: sha512-92G+ZD70AZgeJf07JfQzH+isnai6DwPcMBuF/qL1F+xAxdXCJzGd3w2RmsRvOmB+w1ImmWEEDms50QivQIjd6g==} + '@iconify-json/tabler@1.2.33': + resolution: {integrity: sha512-q9nUQfE/cjIrGh5bAKHTphitAZpT0kX9SxDgZo3Sx8ofeDTsaHVdRwrn+CfKiJ5vQ1b1btqVwizXzIgz9KEPjA==} - '@iconify/tailwind4@1.2.1': - resolution: {integrity: sha512-Hd7k8y7uzT3hk8ltw0jGku0r0wA8sc3d2iMvVTYv/9tMxBb+frZtWZGD9hDMU3EYuE+lMn58wi2lS8R2ZbwFcQ==} + '@iconify/tailwind4@1.2.3': + resolution: {integrity: sha512-z8SKiMHRASJKF/IY//87MF88lcB7ulxh8vlhQXXLWsBkNtOh6ese9R41MyGpQeqXdRvQVt+/fX2glQtHFjQ+MA==} peerDependencies: tailwindcss: '>= 4.0.0' - '@iconify/tools@5.0.3': - resolution: {integrity: sha512-W5nbH5fNv20TvU49Al19Foos/ViAnmppbCNV9ieGl6/dRMDRzxeFol6peXX/NAgaOytQwZZxTTJRq/Kxd4eWsA==} + '@iconify/tools@5.0.11': + resolution: {integrity: sha512-zur/06/zTSflUSoPARK5FfHNZQ9UYsoloPDQHLAZHbQqWhs0/tXS+KB70uOAt94dUB1F94JOkSqIOT2R4Deixg==} '@iconify/types@2.0.0': resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - '@iconify/utils@3.1.0': - resolution: {integrity: sha512-Zlzem1ZXhI1iHeeERabLNzBHdOa4VhQbqAcOQaMKuTuyZCpwKbC2R4Dd0Zo3g9EAc+Y4fiarO8HIHRAth7+skw==} + '@iconify/utils@3.1.1': + resolution: {integrity: sha512-MwzoDtw9rO1x+qfgLTV/IVXsHDBqeYZoMIQC8SfxfYSlaSUG+oWiAcoiB1yajAda6mqblm4/1/w2E8tRu7a7Tw==} '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -786,8 +762,8 @@ packages: '@emnapi/core': ^1.7.1 '@emnapi/runtime': ^1.7.1 - '@oxc-project/types@0.124.0': - resolution: {integrity: sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==} + '@oxc-project/types@0.127.0': + resolution: {integrity: sha512-aIYXQBo4lCbO4z0R3FHeucQHpF46l2LbMdxRvqvuRuW2OxdnSkcng5B8+K12spgLDj93rtN3+J2Vac/TIO+ciQ==} '@parcel/watcher-android-arm64@2.5.6': resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} @@ -871,8 +847,8 @@ packages: resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} engines: {node: '>= 10.0.0'} - '@playwright/test@1.58.1': - resolution: {integrity: sha512-6LdVIUERWxQMmUSSQi0I53GgCBYgM2RpGngCPY7hSeju+VrKjq3lvs7HpJoPbDiY5QM5EYRtRX5fvrinnMAz3w==} + '@playwright/test@1.59.1': + resolution: {integrity: sha512-PG6q63nQg5c9rIi4/Z5lR5IVF7yU5MqmKaPOe0HSc0O2cX1fPi96sUQu5j7eo4gKCkB2AnNGoWt7y4/Xx3Kcqg==} engines: {node: '>=18'} hasBin: true @@ -883,97 +859,97 @@ packages: resolution: {integrity: sha512-HDVTWq3H0uTXiU0eeSQntcVUTPP3GamzeXI41+x7uU9J65JgWQh3qWZHblR1i0npXfFtF+mxBiU2nJH8znxWnQ==} engines: {node: '>=18'} - '@rolldown/binding-android-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==} + '@rolldown/binding-android-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-s70pVGhw4zqGeFnXWvAzJDlvxhlRollagdCCKRgOsgUOH3N1l0LIxf83AtGzmb5SiVM4Hjl5HyarMRfdfj3DaQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==} + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-4ksWc9n0mhlZpZ9PMZgTGjeOPRu8MB1Z3Tz0Mo02eWfWCHMW1zN82Qz/pL/rC+yQa+8ZnutMF0JjJe7PjwasYw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-rc.15': - resolution: {integrity: sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==} + '@rolldown/binding-darwin-x64@1.0.0-rc.17': + resolution: {integrity: sha512-SUSDOI6WwUVNcWxd02QEBjLdY1VPHvlEkw6T/8nYG322iYWCTxRb1vzk4E+mWWYehTp7ERibq54LSJGjmouOsw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': - resolution: {integrity: sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==} + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': + resolution: {integrity: sha512-hwnz3nw9dbJ05EDO/PvcjaaewqqDy7Y1rn1UO81l8iIK1GjenME75dl16ajbvSSMfv66WXSRCYKIqfgq2KCfxw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': - resolution: {integrity: sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': + resolution: {integrity: sha512-IS+W7epTcwANmFSQFrS1SivEXHtl1JtuQA9wlxrZTcNi6mx+FDOYrakGevvvTwgj2JvWiK8B29/qD9BELZPyXQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==} + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-e6usGaHKW5BMNZOymS1UcEYGowQMWcgZ71Z17Sl/h2+ZziNJ1a9n3Zvcz6LdRyIW5572wBCTH/Z+bKuZouGk9Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==} + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-b/CgbwAJpmrRLp02RPfhbudf5tZnN9nsPWK82znefso832etkem8H7FSZwxrOI9djcdTP7U6YfNhbRnh7djErg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==} + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-4EII1iNGRUN5WwGbF/kOh/EIkoDN9HsupgLQoXfY+D1oyJm7/F4t5PYU5n8SWZgG0FEwakyM8pGgwcBYruGTlA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [ppc64] os: [linux] - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==} + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-AH8oq3XqQo4IibpVXvPeLDI5pzkpYn0WiZAfT05kFzoJ6tQNzwRdDYQ45M8I/gslbodRZwW8uxLhbSBbkv96rA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [s390x] os: [linux] - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': - resolution: {integrity: sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==} + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': + resolution: {integrity: sha512-cLnjV3xfo7KslbU41Z7z8BH/E1y5mzUYzAqih1d1MDaIGZRCMqTijqLv76/P7fyHuvUcfGsIpqCdddbxLLK9rA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': - resolution: {integrity: sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==} + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': + resolution: {integrity: sha512-0phclDw1spsL7dUB37sIARuis2tAgomCJXAHZlpt8PXZ4Ba0dRP1e+66lsRqrfhISeN9bEGNjQs+T/Fbd7oYGw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': - resolution: {integrity: sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==} + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': + resolution: {integrity: sha512-0ag/hEgXOwgw4t8QyQvUCxvEg+V0KBcA6YuOx9g0r02MprutRF5dyljgm3EmR02O292UX7UeS6HzWHAl6KgyhA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': - resolution: {integrity: sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': + resolution: {integrity: sha512-LEXei6vo0E5wTGwpkJ4KoT3OZJRnglwldt5ziLzOlc6qqb55z4tWNq2A+PFqCJuvWWdP53CVhG1Z9NtToDPJrA==} + engines: {node: ^20.19.0 || >=22.12.0} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==} + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-gUmyzBl3SPMa6hrqFUth9sVfcLBlYsbMzBx5PlexMroZStgzGqlZ26pYG89rBb45Mnia+oil6YAIFeEWGWhoZA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': - resolution: {integrity: sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==} + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': + resolution: {integrity: sha512-3hkiolcUAvPB9FLb3UZdfjVVNWherN1f/skkGWJP/fgSQhYUZpSIRr0/I8ZK9TkF3F7kxvJAk0+IcKvPHk9qQg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-rc.15': - resolution: {integrity: sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==} + '@rolldown/pluginutils@1.0.0-rc.17': + resolution: {integrity: sha512-n8iosDOt6Ig1UhJ2AYqoIhHWh/isz0xpicHTzpKBeotdVsTEcxsSA/i3EVM7gQAj0rU27OLAxCjzlj15IWY7bg==} '@rollup/pluginutils@5.1.4': resolution: {integrity: sha512-USm05zrsFxYLPdWWq+K3STlWiT/3ELn3RcV5hJMghpeAIhxfsUIg6mt12CBJBInWMV4VneoV7SfGv8xIwo2qNQ==} @@ -1112,8 +1088,8 @@ packages: '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - '@sveltejs/acorn-typescript@1.0.8': - resolution: {integrity: sha512-esgN+54+q0NjB0Y/4BomT9samII7jGwNy/2a3wNZbT2A2RpmXsXwUt24LvLhx6jUq2gVk4cWEvcRO6MFQbOfNA==} + '@sveltejs/acorn-typescript@1.0.9': + resolution: {integrity: sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==} peerDependencies: acorn: ^8.9.0 @@ -1127,24 +1103,8 @@ packages: peerDependencies: '@sveltejs/kit': ^2.0.0 - '@sveltejs/kit@2.50.2': - resolution: {integrity: sha512-875hTUkEbz+MyJIxWbQjfMaekqdmEKUUfR7JyKcpfMRZqcGyrO9Gd+iS1D/Dx8LpE5FEtutWGOtlAh4ReSAiOA==} - engines: {node: '>=18.13'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.0.0 - '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 - svelte: ^4.0.0 || ^5.0.0-next.0 - typescript: ^5.3.3 - vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - typescript: - optional: true - - '@sveltejs/kit@2.57.1': - resolution: {integrity: sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw==} + '@sveltejs/kit@2.59.0': + resolution: {integrity: sha512-WeJaGKvDf3uVQB4bnDHhM+BXCY34LC1v0HiPqnSpvNkjB54r8DAUP1rpk73s+5zprIirEKtUcVfgh6+fPODjzQ==} engines: {node: '>=18.13'} hasBin: true peerDependencies: @@ -1166,21 +1126,6 @@ packages: peerDependencies: svelte: ^3.44.0 || ^4.0.0 || ^5.0.0-next.1 - '@sveltejs/vite-plugin-svelte-inspector@5.0.2': - resolution: {integrity: sha512-TZzRTcEtZffICSAoZGkPSl6Etsj2torOVrx6Uw0KpXxrec9Gg6jFWQ60Q3+LmNGfZSxHRCZL7vXVZIWmuV50Ig==} - engines: {node: ^20.19 || ^22.12 || >=24} - peerDependencies: - '@sveltejs/vite-plugin-svelte': ^6.0.0-next.0 - svelte: ^5.0.0 - vite: ^6.3.0 || ^7.0.0 - - '@sveltejs/vite-plugin-svelte@6.2.4': - resolution: {integrity: sha512-ou/d51QSdTyN26D7h6dSpusAKaZkAiGM55/AKYi+9AGZw7q85hElbjK3kEyzXHhLSnRISHOYzVge6x0jRZ7DXA==} - engines: {node: ^20.19 || ^22.12 || >=24} - peerDependencies: - svelte: ^5.0.0 - vite: ^6.3.0 || ^7.0.0 - '@sveltejs/vite-plugin-svelte@7.0.0': resolution: {integrity: sha512-ILXmxC7HAsnkK2eslgPetrqqW1BKSL7LktsFgqzNj83MaivMGZzluWq32m25j2mDOjmSKX7GGWahePhuEs7P/g==} engines: {node: ^20.19 || ^22.12 || >=24} @@ -1188,122 +1133,65 @@ packages: svelte: ^5.46.4 vite: ^8.0.0-beta.7 || ^8.0.0 - '@tailwindcss/node@4.1.18': - resolution: {integrity: sha512-DoR7U1P7iYhw16qJ49fgXUlry1t4CpXeErJHnQ44JgTSKMaZUdf17cfn5mHchfJ4KRBZRFA/Coo+MUF5+gOaCQ==} + '@tailwindcss/node@4.2.4': + resolution: {integrity: sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==} - '@tailwindcss/node@4.2.2': - resolution: {integrity: sha512-pXS+wJ2gZpVXqFaUEjojq7jzMpTGf8rU6ipJz5ovJV6PUGmlJ+jvIwGrzdHdQ80Sg+wmQxUFuoW1UAAwHNEdFA==} - - '@tailwindcss/oxide-android-arm64@4.1.18': - resolution: {integrity: sha512-dJHz7+Ugr9U/diKJA0W6N/6/cjI+ZTAoxPf9Iz9BFRF2GzEX8IvXxFIi/dZBloVJX/MZGvRuFA9rqwdiIEZQ0Q==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] - - '@tailwindcss/oxide-android-arm64@4.2.2': - resolution: {integrity: sha512-dXGR1n+P3B6748jZO/SvHZq7qBOqqzQ+yFrXpoOWWALWndF9MoSKAT3Q0fYgAzYzGhxNYOoysRvYlpixRBBoDg==} + '@tailwindcss/oxide-android-arm64@4.2.4': + resolution: {integrity: sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==} engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.18': - resolution: {integrity: sha512-Gc2q4Qhs660bhjyBSKgq6BYvwDz4G+BuyJ5H1xfhmDR3D8HnHCmT/BSkvSL0vQLy/nkMLY20PQ2OoYMO15Jd0A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@tailwindcss/oxide-darwin-arm64@4.2.2': - resolution: {integrity: sha512-iq9Qjr6knfMpZHj55/37ouZeykwbDqF21gPFtfnhCCKGDcPI/21FKC9XdMO/XyBM7qKORx6UIhGgg6jLl7BZlg==} + '@tailwindcss/oxide-darwin-arm64@4.2.4': + resolution: {integrity: sha512-tSC/Kbqpz/5/o/C2sG7QvOxAKqyd10bq+ypZNf+9Fi2TvbVbv1zNpcEptcsU7DPROaSbVgUXmrzKhurFvo5eDg==} engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.18': - resolution: {integrity: sha512-FL5oxr2xQsFrc3X9o1fjHKBYBMD1QZNyc1Xzw/h5Qu4XnEBi3dZn96HcHm41c/euGV+GRiXFfh2hUCyKi/e+yw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@tailwindcss/oxide-darwin-x64@4.2.2': - resolution: {integrity: sha512-BlR+2c3nzc8f2G639LpL89YY4bdcIdUmiOOkv2GQv4/4M0vJlpXEa0JXNHhCHU7VWOKWT/CjqHdTP8aUuDJkuw==} + '@tailwindcss/oxide-darwin-x64@4.2.4': + resolution: {integrity: sha512-yPyUXn3yO/ufR6+Kzv0t4fCg2qNr90jxXc5QqBpjlPNd0NqyDXcmQb/6weunH/MEDXW5dhyEi+agTDiqa3WsGg==} engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.18': - resolution: {integrity: sha512-Fj+RHgu5bDodmV1dM9yAxlfJwkkWvLiRjbhuO2LEtwtlYlBgiAT4x/j5wQr1tC3SANAgD+0YcmWVrj8R9trVMA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] - - '@tailwindcss/oxide-freebsd-x64@4.2.2': - resolution: {integrity: sha512-YUqUgrGMSu2CDO82hzlQ5qSb5xmx3RUrke/QgnoEx7KvmRJHQuZHZmZTLSuuHwFf0DJPybFMXMYf+WJdxHy/nQ==} + '@tailwindcss/oxide-freebsd-x64@4.2.4': + resolution: {integrity: sha512-BoMIB4vMQtZsXdGLVc2z+P9DbETkiopogfWZKbWwM8b/1Vinbs4YcUwo+kM/KeLkX3Ygrf4/PsRndKaYhS8Eiw==} engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': - resolution: {integrity: sha512-Fp+Wzk/Ws4dZn+LV2Nqx3IilnhH51YZoRaYHQsVq3RQvEl+71VGKFpkfHrLM/Li+kt5c0DJe/bHXK1eHgDmdiA==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] - - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': - resolution: {integrity: sha512-FPdhvsW6g06T9BWT0qTwiVZYE2WIFo2dY5aCSpjG/S/u1tby+wXoslXS0kl3/KXnULlLr1E3NPRRw0g7t2kgaQ==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': + resolution: {integrity: sha512-7pIHBLTHYRAlS7V22JNuTh33yLH4VElwKtB3bwchK/UaKUPpQ0lPQiOWcbm4V3WP2I6fNIJ23vABIvoy2izdwA==} engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': - resolution: {integrity: sha512-S0n3jboLysNbh55Vrt7pk9wgpyTTPD0fdQeh7wQfMqLPM/Hrxi+dVsLsPrycQjGKEQk85Kgbx+6+QnYNiHalnw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': - resolution: {integrity: sha512-4og1V+ftEPXGttOO7eCmW7VICmzzJWgMx+QXAJRAhjrSjumCwWqMfkDrNu1LXEQzNAwz28NCUpucgQPrR4S2yw==} + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': + resolution: {integrity: sha512-+E4wxJ0ZGOzSH325reXTWB48l42i93kQqMvDyz5gqfRzRZ7faNhnmvlV4EPGJU3QJM/3Ab5jhJ5pCRUsKn6OQw==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - resolution: {integrity: sha512-1px92582HkPQlaaCkdRcio71p8bc8i/ap5807tPRDK/uw953cauQBT8c5tVGkOwrHMfc2Yh6UuxaH4vtTjGvHg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - resolution: {integrity: sha512-oCfG/mS+/+XRlwNjnsNLVwnMWYH7tn/kYPsNPh+JSOMlnt93mYNCKHYzylRhI51X+TbR+ufNhhKKzm6QkqX8ag==} + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': + resolution: {integrity: sha512-bBADEGAbo4ASnppIziaQJelekCxdMaxisrk+fB7Thit72IBnALp9K6ffA2G4ruj90G9XRS2VQ6q2bCKbfFV82g==} engines: {node: '>= 20'} cpu: [arm64] os: [linux] - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - resolution: {integrity: sha512-v3gyT0ivkfBLoZGF9LyHmts0Isc8jHZyVcbzio6Wpzifg/+5ZJpDiRiUhDLkcr7f/r38SWNe7ucxmGW3j3Kb/g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - resolution: {integrity: sha512-rTAGAkDgqbXHNp/xW0iugLVmX62wOp2PoE39BTCGKjv3Iocf6AFbRP/wZT/kuCxC9QBh9Pu8XPkv/zCZB2mcMg==} + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': + resolution: {integrity: sha512-7Mx25E4WTfnht0TVRTyC00j3i0M+EeFe7wguMDTlX4mRxafznw0CA8WJkFjWYH5BlgELd1kSjuU2JiPnNZbJDA==} engines: {node: '>= 20'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - resolution: {integrity: sha512-bhJ2y2OQNlcRwwgOAGMY0xTFStt4/wyU6pvI6LSuZpRgKQwxTec0/3Scu91O8ir7qCR3AuepQKLU/kX99FouqQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - resolution: {integrity: sha512-XW3t3qwbIwiSyRCggeO2zxe3KWaEbM0/kW9e8+0XpBgyKU4ATYzcVSMKteZJ1iukJ3HgHBjbg9P5YPRCVUxlnQ==} + '@tailwindcss/oxide-linux-x64-musl@4.2.4': + resolution: {integrity: sha512-2wwJRF7nyhOR0hhHoChc04xngV3iS+akccHTGtz965FwF0up4b2lOdo6kI1EbDaEXKgvcrFBYcYQQ/rrnWFVfA==} engines: {node: '>= 20'} cpu: [x64] os: [linux] - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - resolution: {integrity: sha512-LffYTvPjODiP6PT16oNeUQJzNVyJl1cjIebq/rWWBF+3eDst5JGEFSc5cWxyRCJ0Mxl+KyIkqRxk1XPEs9x8TA==} + '@tailwindcss/oxide-wasm32-wasi@4.2.4': + resolution: {integrity: sha512-FQsqApeor8Fo6gUEklzmaa9994orJZZDBAlQpK2Mq+DslRKFJeD6AjHpBQ0kZFQohVr8o85PPh8eOy86VlSCmw==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -1314,57 +1202,24 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - resolution: {integrity: sha512-eKSztKsmEsn1O5lJ4ZAfyn41NfG7vzCg496YiGtMDV86jz1q/irhms5O0VrY6ZwTUkFy/EKG3RfWgxSI3VbZ8Q==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - resolution: {integrity: sha512-HjSA7mr9HmC8fu6bdsZvZ+dhjyGCLdotjVOgLA2vEqxEBZaQo9YTX4kwgEvPCpRh8o4uWc4J/wEoFzhEmjvPbA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - resolution: {integrity: sha512-qPmaQM4iKu5mxpsrWZMOZRgZv1tOZpUm+zdhhQP0VhJfyGGO3aUKdbh3gDZc/dPLQwW4eSqWGrrcWNBZWUWaXQ==} + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': + resolution: {integrity: sha512-L9BXqxC4ToVgwMFqj3pmZRqyHEztulpUJzCxUtLjobMCzTPsGt1Fa9enKbOpY2iIyVtaHNeNvAK8ERP/64sqGQ==} engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - resolution: {integrity: sha512-bJWbyYpUlqamC8dpR7pfjA0I7vdF6t5VpUGMWRkXVE3AXgIZjYUYAK7II1GNaxR8J1SSrSrppRar8G++JekE3Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - resolution: {integrity: sha512-1T/37VvI7WyH66b+vqHj/cLwnCxt7Qt3WFu5Q8hk65aOvlwAhs7rAp1VkulBJw/N4tMirXjVnylTR72uI0HGcA==} + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': + resolution: {integrity: sha512-ESlKG0EpVJQwRjXDDa9rLvhEAh0mhP1sF7sap9dNZT0yyl9SAG6T7gdP09EH0vIv0UNTlo6jPWyujD6559fZvw==} engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.18': - resolution: {integrity: sha512-EgCR5tTS5bUSKQgzeMClT6iCY3ToqE1y+ZB0AKldj809QXk1Y+3jB0upOYZrn9aGIzPtUsP7sX4QQ4XtjBB95A==} - engines: {node: '>= 10'} - - '@tailwindcss/oxide@4.2.2': - resolution: {integrity: sha512-qEUA07+E5kehxYp9BVMpq9E8vnJuBHfJEC0vPC5e7iL/hw7HR61aDKoVoKzrG+QKp56vhNZe4qwkRmMC0zDLvg==} + '@tailwindcss/oxide@4.2.4': + resolution: {integrity: sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==} engines: {node: '>= 20'} - '@tailwindcss/vite@4.1.18': - resolution: {integrity: sha512-jVA+/UpKL1vRLg6Hkao5jldawNmRo7mQYrZtNHMIVpLfLhDml5nMRUo/8MwoX2vNXvnaXNNMedrMfMugAVX1nA==} - peerDependencies: - vite: ^5.2.0 || ^6 || ^7 - - '@tailwindcss/vite@4.2.2': - resolution: {integrity: sha512-mEiF5HO1QqCLXoNEfXVA1Tzo+cYsrqV7w9Juj2wdUFyW07JRenqMG225MvPwr3ZD9N1bFQj46X7r33iHxLUW0w==} + '@tailwindcss/vite@4.2.4': + resolution: {integrity: sha512-pCvohwOCspk3ZFn6eJzrrX3g4n2JY73H6MmYC87XfGPyTty4YsCjYTMArRZm/zOI8dIt3+EcrLHAFPe5A4bgtw==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 || ^8 @@ -1396,14 +1251,14 @@ packages: peerDependencies: three: '>=0.170.0' - '@threlte/core@8.3.1': - resolution: {integrity: sha512-qKjjNCQ+40hyeBcfOMh/8ef5x/j5PG5Wmo/L9Ye0aDCcdD6fCewWxfp7tV/J3CxPzX1dEp1JGK7sjyc7ntZSrg==} + '@threlte/core@8.5.11': + resolution: {integrity: sha512-2IyYlrXAWG0c6UnBLnE6lBzaVfiPPF5nsGte3HIc6domRna4w9gG4WIYDnJ1FH8wcSnaq7afztbrpF01Y9m5vg==} peerDependencies: svelte: '>=5' three: '>=0.160' - '@threlte/extras@9.7.1': - resolution: {integrity: sha512-SGm59HDCdHxADFHuweHfFDknwubkCPodyK0pbfsVtOWWOX26gE2xfK7aKolh6YFDiPAjWjGxN0jIgkNbbr1ohg==} + '@threlte/extras@9.15.1': + resolution: {integrity: sha512-+AhS+caKH9WIawwSWWYOlbqZzxPNW+kQ3PT9y4NyzzscCcVUPoFpZwd0izy8KEAIKM34J1uMs36cZff6U6LEjQ==} peerDependencies: svelte: '>=5' three: '>=0.160' @@ -1420,14 +1275,14 @@ packages: '@tsconfig/node16@1.0.4': resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - '@tsconfig/svelte@5.0.7': - resolution: {integrity: sha512-NOtJF9LQnV7k6bpzcXwL/rXdlFHvAT9e0imrftiMc6/+FUNBHRZ8UngDrM+jciA6ENzFYNoFs8rfwumuGF+Dhw==} + '@tsconfig/svelte@5.0.8': + resolution: {integrity: sha512-UkNnw1/oFEfecR8ypyHIQuWYdkPvHiwcQ78sh+ymIiYoF+uc5H1UBetbjyqT+vgGJ3qQN6nhucJviX6HesWtKQ==} '@tweenjs/tween.js@23.1.3': resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -1438,8 +1293,8 @@ packages: '@types/cookie@0.6.0': resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -1462,14 +1317,14 @@ packages: '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - '@types/node@24.12.2': - resolution: {integrity: sha512-A1sre26ke7HDIuY/M23nd9gfB+nrmhtYyMINbjI1zHJxYteKR6qSMX56FsmjMcDb3SMcjJg5BiRRgOCC/yBD0g==} + '@types/node@25.6.0': + resolution: {integrity: sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==} '@types/stats.js@0.17.4': resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} - '@types/three@0.182.0': - resolution: {integrity: sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==} + '@types/three@0.184.0': + resolution: {integrity: sha512-4mY2tZAu0y0B0567w7013BBXSpsP0+Z48NJvmNo4Y/Pf76yCyz6Jw4P3tUVs10WuYNXXZ+wmHyGWpCek3amJxA==} '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -1477,181 +1332,114 @@ packages: '@types/webxr@0.5.24': resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} - '@typescript-eslint/eslint-plugin@8.54.0': - resolution: {integrity: sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ==} + '@typescript-eslint/eslint-plugin@8.59.1': + resolution: {integrity: sha512-BOziFIfE+6osHO9FoJG4zjoHUcvI7fTNBSpdAwrNH0/TLvzjsk2oo8XSSOT2HhqUyhZPfHv4UOffoJ9oEEQ7Ag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.54.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/eslint-plugin@8.58.2': - resolution: {integrity: sha512-aC2qc5thQahutKjP+cl8cgN9DWe3ZUqVko30CMSZHnFEHyhOYoZSzkGtAI2mcwZ38xeImDucI4dnqsHiOYuuCw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.58.2 + '@typescript-eslint/parser': ^8.59.1 eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.54.0': - resolution: {integrity: sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/parser@8.58.2': - resolution: {integrity: sha512-/Zb/xaIDfxeJnvishjGdcR4jmr7S+bda8PKNhRGdljDM+elXhlvN0FyPSsMnLmJUrVG9aPO6dof80wjMawsASg==} + '@typescript-eslint/parser@8.59.1': + resolution: {integrity: sha512-HDQH9O/47Dxi1ceDhBXdaldtf/WV9yRYMjbjCuNk3qnaTD564qwv61Y7+gTxwxRKzSrgO5uhtw584igXVuuZkA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.54.0': - resolution: {integrity: sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/project-service@8.58.2': - resolution: {integrity: sha512-Cq6UfpZZk15+r87BkIh5rDpi38W4b+Sjnb8wQCPPDDweS/LRCFjCyViEbzHk5Ck3f2QDfgmlxqSa7S7clDtlfg==} + '@typescript-eslint/project-service@8.59.1': + resolution: {integrity: sha512-+MuHQlHiEr00Of/IQbE/MmEoi44znZHbR/Pz7Opq4HryUOlRi+/44dro9Ycy8Fyo+/024IWtw8m4JUMCGTYxDg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.54.0': - resolution: {integrity: sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg==} + '@typescript-eslint/scope-manager@8.59.1': + resolution: {integrity: sha512-LwuHQI4pDOYVKvmH2dkaJo6YZCSgouVgnS/z7yBPKBMvgtBvyLqiLy9Z6b7+m/TRcX1NFYUqZetI5Y+aT4GEfg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/scope-manager@8.58.2': - resolution: {integrity: sha512-SgmyvDPexWETQek+qzZnrG6844IaO02UVyOLhI4wpo82dpZJY9+6YZCKAMFzXb7qhx37mFK1QcPQ18tud+vo6Q==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.54.0': - resolution: {integrity: sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/tsconfig-utils@8.58.2': - resolution: {integrity: sha512-3SR+RukipDvkkKp/d0jP0dyzuls3DbGmwDpVEc5wqk5f38KFThakqAAO0XMirWAE+kT00oTauTbzMFGPoAzB0A==} + '@typescript-eslint/tsconfig-utils@8.59.1': + resolution: {integrity: sha512-/0nEyPbX7gRsk0Uwfe4ALwwgxuA66d/l2mhRDNlAvaj4U3juhUtJNq0DsY8M2AYwwb9rEq2hrC3IcIcEt++iJA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.54.0': - resolution: {integrity: sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.58.2': - resolution: {integrity: sha512-Z7EloNR/B389FvabdGeTo2XMs4W9TjtPiO9DAsmT0yom0bwlPyRjkJ1uCdW1DvrrrYP50AJZ9Xc3sByZA9+dcg==} + '@typescript-eslint/type-utils@8.59.1': + resolution: {integrity: sha512-klWPBR2ciQHS3f++ug/mVnWKPjBUo7icEL3FAO1lhAR1Z1i5NQYZ1EannMSRYcq5qCv5wNALlXr6fksRHyYl7w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.54.0': - resolution: {integrity: sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA==} + '@typescript-eslint/types@8.59.1': + resolution: {integrity: sha512-ZDCjgccSdYPw5Bxh+my4Z0lJU96ZDN7jbBzvmEn0FZx3RtU1C7VWl6NbDx94bwY3V5YsgwRzJPOgeY2Q/nLG8A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/types@8.58.2': - resolution: {integrity: sha512-9TukXyATBQf/Jq9AMQXfvurk+G5R2MwfqQGDR2GzGz28HvY/lXNKGhkY+6IOubwcquikWk5cjlgPvD2uAA7htQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.54.0': - resolution: {integrity: sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/typescript-estree@8.58.2': - resolution: {integrity: sha512-ELGuoofuhhoCvNbQjFFiobFcGgcDCEm0ThWdmO4Z0UzLqPXS3KFvnEZ+SHewwOYHjM09tkzOWXNTv9u6Gqtyuw==} + '@typescript-eslint/typescript-estree@8.59.1': + resolution: {integrity: sha512-OUd+vJS05sSkOip+BkZ/2NS8RMxrAAJemsC6vU3kmfLyeaJT0TftHkV9mcx2107MmsBVXXexhVu4F0TZXyMl4g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.54.0': - resolution: {integrity: sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.58.2': - resolution: {integrity: sha512-QZfjHNEzPY8+l0+fIXMvuQ2sJlplB4zgDZvA+NmvZsZv3EQwOcc1DuIU1VJUTWZ/RKouBMhDyNaBMx4sWvrzRA==} + '@typescript-eslint/utils@8.59.1': + resolution: {integrity: sha512-3pIeoXhCeYH9FSCBI8P3iNwJlGuzPlYKkTlen2O9T1DSeeg8UG8jstq6BLk+Mda0qup7mgk4z4XL4OzRaxZ8LA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.54.0': - resolution: {integrity: sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA==} + '@typescript-eslint/visitor-keys@8.59.1': + resolution: {integrity: sha512-LdDNl6C5iJExcM0Yh0PwAIBb9PrSiCsWamF/JyEZawm3kFDnRoaq3LGE4bpyRao/fWeGKKyw7icx0YxrLFC5Cg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/visitor-keys@8.58.2': - resolution: {integrity: sha512-f1WO2Lx8a9t8DARmcWAUPJbu0G20bJlj8L4z72K00TMeJAoyLr/tHhI/pzYBLrR4dXWkcxO1cWYZEOX8DKHTqA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@vitest/browser-playwright@4.0.18': - resolution: {integrity: sha512-gfajTHVCiwpxRj1qh0Sh/5bbGLG4F/ZH/V9xvFVoFddpITfMta9YGow0W6ZpTTORv2vdJuz9TnrNSmjKvpOf4g==} + '@vitest/browser-playwright@4.1.5': + resolution: {integrity: sha512-CWy0lBQJq97nionyJJdnaU4961IXTl43a7UCu5nHy51IoKxAt6PVIJLo+76rVl7KOOgcWHNkG4kbJu/pW7knvA==} peerDependencies: playwright: '*' - vitest: 4.0.18 + vitest: 4.1.5 - '@vitest/browser@4.0.18': - resolution: {integrity: sha512-gVQqh7paBz3gC+ZdcCmNSWJMk70IUjDeVqi+5m5vYpEHsIwRgw3Y545jljtajhkekIpIp5Gg8oK7bctgY0E2Ng==} + '@vitest/browser@4.1.5': + resolution: {integrity: sha512-iCDGI8c4yg+xmjUg2VsygdAUSIIB4x5Rht/P68OXy1hPELKXHDkzh87lkuTcdYmemRChDkEpB426MmDjzC0ziA==} peerDependencies: - vitest: 4.0.18 + vitest: 4.1.5 - '@vitest/expect@4.0.18': - resolution: {integrity: sha512-8sCWUyckXXYvx4opfzVY03EOiYVxyNrHS5QxX3DAIi5dpJAAkyJezHCP77VMX4HKA2LDT/Jpfo8i2r5BE3GnQQ==} + '@vitest/expect@4.1.5': + resolution: {integrity: sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==} - '@vitest/mocker@4.0.18': - resolution: {integrity: sha512-HhVd0MDnzzsgevnOWCBj5Otnzobjy5wLBe4EdeeFGv8luMsGcYqDuFRMcttKWZA5vVO8RFjexVovXvAM4JoJDQ==} + '@vitest/mocker@4.1.5': + resolution: {integrity: sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.18': - resolution: {integrity: sha512-P24GK3GulZWC5tz87ux0m8OADrQIUVDPIjjj65vBXYG17ZeU3qD7r+MNZ1RNv4l8CGU2vtTRqixrOi9fYk/yKw==} + '@vitest/pretty-format@4.1.5': + resolution: {integrity: sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==} - '@vitest/runner@4.0.18': - resolution: {integrity: sha512-rpk9y12PGa22Jg6g5M3UVVnTS7+zycIGk9ZNGN+m6tZHKQb7jrP7/77WfZy13Y/EUDd52NDsLRQhYKtv7XfPQw==} + '@vitest/runner@4.1.5': + resolution: {integrity: sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==} - '@vitest/snapshot@4.0.18': - resolution: {integrity: sha512-PCiV0rcl7jKQjbgYqjtakly6T1uwv/5BQ9SwBLekVg/EaYeQFPiXcgrC2Y7vDMA8dM1SUEAEV82kgSQIlXNMvA==} + '@vitest/snapshot@4.1.5': + resolution: {integrity: sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==} - '@vitest/spy@4.0.18': - resolution: {integrity: sha512-cbQt3PTSD7P2OARdVW3qWER5EGq7PHlvE+QfzSC0lbwO+xnt7+XH06ZzFjFRgzUX//JmpxrCu92VdwvEPlWSNw==} + '@vitest/spy@4.1.5': + resolution: {integrity: sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==} - '@vitest/utils@4.0.18': - resolution: {integrity: sha512-msMRKLMVLWygpK3u2Hybgi4MNjcYJvwTb0Ru09+fOyCXIgT5raYP041DRRdiJiI3k/2U6SEbAETB3YtBrUkCFA==} - - '@webgpu/types@0.1.69': - resolution: {integrity: sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==} + '@vitest/utils@4.1.5': + resolution: {integrity: sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==} acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - acorn-walk@8.3.4: - resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} engines: {node: '>=0.4.0'} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true - acorn@8.16.0: resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} engines: {node: '>=0.4.0'} @@ -1661,11 +1449,8 @@ packages: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -1675,10 +1460,6 @@ packages: resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} engines: {node: '>=12'} - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} @@ -1704,10 +1485,6 @@ packages: resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} engines: {node: '>= 0.4'} - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} - assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -1736,11 +1513,8 @@ packages: boolbase@1.0.0: resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@1.1.14: + resolution: {integrity: sha512-MWPGfDxnyzKU7rNOW9SP/c50vi3xrmrua/+6hfPbCS2ABNWfx24vPidzvC7krjU/RTo235sV776ymlsMtGKj8g==} brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} @@ -1771,10 +1545,6 @@ packages: resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} @@ -1804,13 +1574,6 @@ packages: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -1831,6 +1594,9 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} @@ -1852,8 +1618,8 @@ packages: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} css-what@6.2.2: @@ -1914,11 +1680,8 @@ packages: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - devalue@5.6.2: - resolution: {integrity: sha512-nPRkjWzzDQlsejL1WVifk5rvcFi/y1onBRxjaFMjZeR9mFpqu2gmAZ9xUB9/IEanEP/vBtGeGganC/GO1fmufg==} - - devalue@5.7.1: - resolution: {integrity: sha512-MUbZ586EgQqdRnC4yDrlod3BEdyvE4TapGYHMW2CiaW+KkkFmWEFqBUaLltEZCGi0iFXCEjRF0OjF0DV2QHjOA==} + devalue@5.8.0: + resolution: {integrity: sha512-2zA9pFEsnp7vWBZbXF5JAgAq0fsUIt/1XPbRiAmRV3lp/2C3upzH+sADiyy66aFCihoLEsrQHxNM5w1gIDfsBg==} devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} @@ -1946,8 +1709,8 @@ packages: domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dprint@0.51.1: - resolution: {integrity: sha512-CEx+wYARxLAe9o7RCZ77GKae6DF7qjn5Rd98xbWdA3hB4PFBr+kHwLANmNHscNumBAIrCg5ZJj/Kz+OYbJ+GBA==} + dprint@0.54.0: + resolution: {integrity: sha512-sIy25poR2gRP/tWPTgP0MPeJoJcpv0xzYDcsboapvthbEt1Qw3Al252CA0xFyIh2cYEGGKyBJtKokryv4ERlJw==} hasBin: true dunder-proto@1.0.1: @@ -1960,8 +1723,8 @@ packages: emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} - enhanced-resolve@5.19.0: - resolution: {integrity: sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==} + enhanced-resolve@5.21.0: + resolution: {integrity: sha512-otxSQPw4lkOZWkHpB3zaEQs6gWYEsmX4xQF68ElXC/TWvGxGMSGOvoNbaLXm6/cS/fSfHtsEdw90y20PCd+sCA==} engines: {node: '>=10.13.0'} entities@4.5.0: @@ -1984,8 +1747,8 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.1.0: + resolution: {integrity: sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==} es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} @@ -1995,8 +1758,8 @@ packages: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - esbuild@0.27.3: - resolution: {integrity: sha512-8VwMnyGCONIs6cWue2IdpHxHnAjzxnw2Zr7MkVxB2vjmQ2ivqGFb4LEG3SMnv0Gb2F/G/2yA8zUaiL1gywDCCg==} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -2014,18 +1777,8 @@ packages: peerDependencies: eslint: '>=7.0.0' - eslint-plugin-svelte@3.14.0: - resolution: {integrity: sha512-Isw0GvaMm0yHxAj71edAdGFh28ufYs+6rk2KlbbZphnqZAzrH3Se3t12IFh2H9+1F/jlDhBBL4oiOJmLqmYX0g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.1 || ^9.0.0 - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - svelte: - optional: true - - eslint-plugin-svelte@3.17.0: - resolution: {integrity: sha512-sF6wgd5FLS2P8CCaOy2HdYYYEcZ6TwL251dLHUkNmtLnWECk1Dwc+j6VeulmmnFxr7Xs0WNtjweOA+bJ0PnaFw==} + eslint-plugin-svelte@3.17.1: + resolution: {integrity: sha512-NyiXHtS3Ni7e532RBwS9OXlMKDIrENg3gY+/+ODjZzQx2xhU3NlJ+nIl1a93iUUQeiJL3lS8KLmY+W8hklzweQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 @@ -2054,8 +1807,8 @@ packages: resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - eslint@10.2.1: - resolution: {integrity: sha512-wiyGaKsDgqXvF40P8mDwiUp/KQjE1FdrIEJsM8PZ3XCiniTMXS3OHWWUe5FI5agoCnr8x4xPrTDZuxsBlNHl+Q==} + eslint@10.3.0: + resolution: {integrity: sha512-XbEXaRva5cF0ZQB8w6MluHA0kZZfV2DuCMJ3ozyEOHLwDpZX2Lmm/7Pp0xdJmI0GL1W05VH5VwIFHEm1Vcw2gw==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: @@ -2064,16 +1817,6 @@ packages: jiti: optional: true - eslint@9.39.2: - resolution: {integrity: sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - esm-env@1.2.2: resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} @@ -2089,9 +1832,6 @@ packages: resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} - esrap@2.2.2: - resolution: {integrity: sha512-zA6497ha+qKvoWIK+WM9NAh5ni17sKZKhbS5B3PoYbBvaYHZWoS33zmFybmyqpn07RLUxSmn+RCls2/XF+d0oQ==} - esrap@2.2.5: resolution: {integrity: sha512-/yLB1538mag+dn0wsePTe8C0rDIjUOaJpMs2McodSzmM2msWcZsBSdRtg6HOBt0A/r82BN+Md3pgwSc/uWt2Ig==} peerDependencies: @@ -2162,8 +1902,8 @@ packages: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} @@ -2186,8 +1926,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + get-east-asian-width@1.5.0: + resolution: {integrity: sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -2198,8 +1938,8 @@ packages: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.6: - resolution: {integrity: sha512-shZT/QMiSHc/YBLxxOkMtgSid5HFoauqCE3/exfsEcwg1WkeqjG+V40yBbBrsD+jW2HDXcs28xOfcbm2jI8Ddw==} + get-tsconfig@4.14.0: + resolution: {integrity: sha512-yTb+8DXzDREzgvYmh6s9vHsSVCHeC0G3PI5bEXNBHtmshPnO+S5O7qgLEOn0I5QvMy6kpZN8K1NKGyilLb93wA==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -2217,12 +1957,8 @@ packages: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} - globals@17.3.0: - resolution: {integrity: sha512-yMqGUQVVCkD4tqjOJf3TnrvaaHDMYp4VlUSObbkIiuCPe/ofdMBFIAcBbCSRFWOnos6qRiTVStDwqPLUclaxIw==} - engines: {node: '>=18'} - - globals@17.5.0: - resolution: {integrity: sha512-qoV+HK2yFl/366t2/Cb3+xxPUo5BuMynomoDmiaZBIdbs+0pYbjfZU+twLhGKp4uCZ/+NbtpVepH5bGCxRyy2g==} + globals@17.6.0: + resolution: {integrity: sha512-sepffkT8stwnIYbsMBpoCHJuJM5l98FUF2AnE07hfvE0m/qp3R586hw4jF4uadbhvg1ooIdzuu7CsfD2jzCaNA==} engines: {node: '>=18'} gopd@1.2.0: @@ -2232,10 +1968,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} @@ -2244,8 +1976,8 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + hasown@2.0.3: + resolution: {integrity: sha512-ej4AhfhfL2Q2zpMmLo7U1Uv9+PyhIZpgQLGT1F9miIGmiCJIoCgSmczFdrc97mWT4kVY72KA+WnnhJ5pghSvSg==} engines: {node: '>= 0.4'} html-encoding-sniffer@4.0.0: @@ -2280,8 +2012,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - immutable@4.3.7: - resolution: {integrity: sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw==} + immutable@4.3.8: + resolution: {integrity: sha512-d/Ld9aLbKpNwyl0KiM2CT1WYvkitQ1TSvmRtkcV8FKStiDoA7Slzgjmb/1G2yhKM1p0XeNOieaTbFZmU1d3Xuw==} import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} @@ -2377,142 +2109,72 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] - lightningcss-android-arm64@1.32.0: resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] - lightningcss-darwin-arm64@1.32.0: resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] - lightningcss-darwin-x64@1.32.0: resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] - lightningcss-freebsd-x64@1.32.0: resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] - lightningcss-linux-arm-gnueabihf@1.32.0: resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - lightningcss-linux-arm64-gnu@1.32.0: resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] - lightningcss-linux-arm64-musl@1.32.0: resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - lightningcss-linux-x64-gnu@1.32.0: resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] - lightningcss-linux-x64-musl@1.32.0: resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] - lightningcss-win32-arm64-msvc@1.32.0: resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] - lightningcss-win32-x64-msvc@1.32.0: resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} - engines: {node: '>= 12.0.0'} - lightningcss@1.32.0: resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} engines: {node: '>= 12.0.0'} @@ -2531,9 +2193,6 @@ packages: 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==} @@ -2570,11 +2229,11 @@ packages: mdn-data@2.0.28: resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - meshoptimizer@0.22.0: - resolution: {integrity: sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==} + meshoptimizer@1.1.1: + resolution: {integrity: sha512-oRFNWJRDA/WTrVj7NWvqa5HqE1t9MYDj2VaWirQCzCCrAd2GHrqR/sQezCxiWATPNlKTcRaPRHPJwIRoPBAp5g==} micromark-core-commonmark@2.0.3: resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} @@ -2653,21 +2312,14 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} - - modern-tar@0.7.3: - resolution: {integrity: sha512-4W79zekKGyYU4JXVmB78DOscMFaJth2gGhgfTl2alWE4rNe3nf4N2pqenQ0rEtIewrnD79M687Ouba3YGTLOvg==} + modern-tar@0.7.6: + resolution: {integrity: sha512-sweCIVXzx1aIGTCdzcMlSZt1h8k5Tmk08VNAuRk3IU28XamGiOH5ypi11g6De2CH7PhYqSSnGy2A/EFhbWnVKg==} engines: {node: '>=18.0.0'} mri@1.2.0: @@ -2681,16 +2333,16 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.12: + resolution: {integrity: sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - needle@3.3.1: - resolution: {integrity: sha512-6k0YULvhpw+RoLNiQCRKOl09Rv1dPLr8hHnVjHqdolKwDrdNyk+Hmrthi4lIGPPz3r39dLx0hsF5s40sZ3Us4Q==} + needle@3.5.0: + resolution: {integrity: sha512-jaQyPKKk2YokHrEg+vFDYxXIHTCBgiZwSHOoVx/8V3GIBS8/VN6NdVRmg8q1ERtPkMvmOvebsgga4sAj5hls/w==} engines: {node: '>= 4.4.x'} hasBin: true @@ -2750,14 +2402,10 @@ packages: picocolors@1.1.1: resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - picomatch@4.0.4: resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} engines: {node: '>=12'} @@ -2766,20 +2414,16 @@ packages: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} - pixelmatch@7.1.0: - resolution: {integrity: sha512-1wrVzJ2STrpmONHKBy228LM1b84msXDUoAzVEl0R8Mz4Ce6EPr+IVtxm8+yvrqLYMHswREkjYFaMxnyGnaY3Ng==} - hasBin: true - pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - playwright-core@1.58.1: - resolution: {integrity: sha512-bcWzOaTxcW+VOOGBCQgnaKToLJ65d6AqfLVKEWvexyS3AS6rbXl+xdpYRMGSRBClPvyj44njOWoxjNdL/H9UNg==} + playwright-core@1.59.1: + resolution: {integrity: sha512-HBV/RJg81z5BiiZ9yPzIiClYV/QMsDCKUyogwH9p3MCP6IYjUFu/MActgYAvK0oWyV9NlwM3GLBjADyWgydVyg==} engines: {node: '>=18'} hasBin: true - playwright@1.58.1: - resolution: {integrity: sha512-+2uTZHxSCcxjvGc5C891LrS1/NlxglGxzrC4seZiVjcYVQfUa87wBL6rTDqzGjuoWNjnBzRqKmF6zRYGMvQUaQ==} + playwright@1.59.1: + resolution: {integrity: sha512-C8oWjPR3F81yljW9o5OxcWzfh6avkVwDD2VYdwIGqTkl+OGFISgypqzfu7dOe4QNLL2aqcWBmI3PMtLIK233lw==} engines: {node: '>=18'} hasBin: true @@ -2815,12 +2459,8 @@ packages: resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} engines: {node: '>=4'} - postcss@8.5.10: - resolution: {integrity: sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==} - engines: {node: ^10 || ^12 || >=14} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + postcss@8.5.13: + resolution: {integrity: sha512-qif0+jGGZoLWdHey3UFHHWP0H7Gbmsk8T5VEqyYFbWqPr1XqvLGBbk/sl8V5exGmcYJklJOhOQq1pV9IcsiFag==} engines: {node: ^10 || ^12 || >=14} prelude-ls@1.2.1: @@ -2833,8 +2473,8 @@ packages: prettier: ^3.0.0 svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 - prettier-plugin-tailwindcss@0.7.2: - resolution: {integrity: sha512-LkphyK3Fw+q2HdMOoiEHWf93fNtYJwfamoKPl7UwtjFQdei/iIBoX11G6j706FzN3ymX9mPVi97qIY8328vdnA==} + prettier-plugin-tailwindcss@0.8.0: + resolution: {integrity: sha512-V8ITGH87yuBDF6JpEZTOVlUz/saAwqb8f3HRgUj8Lh+tGCcrmorhsLpYqzygwFwK0PE2Ib6Mv3M7T/uE2tZV1g==} engines: {node: '>=20.19'} peerDependencies: '@ianvs/prettier-plugin-sort-imports': '*' @@ -2900,11 +2540,6 @@ packages: prr@1.0.1: resolution: {integrity: sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==} - publint@0.3.17: - resolution: {integrity: sha512-Q3NLegA9XM6usW+dYQRG1g9uEHiYUzcCVBJDJ7yMcWRqVU9LYZUWdqbwMZfmTCFC5PZLQpLAmhvRcQRl3exqkw==} - engines: {node: '>=18'} - hasBin: true - publint@0.3.18: resolution: {integrity: sha512-JRJFeBTrfx4qLwEuGFPk+haJOJN97KnPuK01yj+4k/Wj5BgoOK5uNsivporiqBjk2JDaslg7qJOhGRnpltGeog==} engines: {node: '>=18'} @@ -2940,8 +2575,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - rolldown@1.0.0-rc.15: - resolution: {integrity: sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==} + rolldown@1.0.0-rc.17: + resolution: {integrity: sha512-ZrT53oAKrtA4+YtBWPQbtPOxIbVDbxT0orcYERKd63VJTF13zPcgXTvD4843L8pcsI7M6MErt8QtON6lrB9tyA==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true @@ -2968,8 +2603,8 @@ packages: engines: {node: '>=14.0.0'} hasBin: true - sax@1.4.4: - resolution: {integrity: sha512-1n3r/tGXO6b6VXMdFT54SHzT9ytu9yr7TaELowdYpMqY/Ao7EnlQGmAQ1+RatX7Tkkdm6hONI2owqNx2aZj5Sw==} + sax@1.6.0: + resolution: {integrity: sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==} engines: {node: '>=11.0.0'} saxes@6.0.0: @@ -2988,8 +2623,8 @@ packages: engines: {node: '>=10'} hasBin: true - set-cookie-parser@3.0.1: - resolution: {integrity: sha512-n7Z7dXZhJbwuAHhNzkTti6Aw9QDDjZtm3JTpTGATIdNzdQz5GuFs22w90BcvF4INfnrL5xrX3oGsuqO5Dx3A1Q==} + set-cookie-parser@3.1.0: + resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -3024,80 +2659,61 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.1.0: + resolution: {integrity: sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==} string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - svelte-check@4.3.6: - resolution: {integrity: sha512-uBkz96ElE3G4pt9E1Tw0xvBfIUQkeH794kDQZdAUk795UVMr+NJZpuFSS62vcmO/DuSalK83LyOwhgWq8YGU1Q==} + svelte-check@4.4.7: + resolution: {integrity: sha512-JRafFTRmaPUOqmri4u1WuIKgBLiHi6wIaB57i99pmHq5BAc3ioIpzdUN/RX32ij9GhI6ALMHKvnVxu68sFZlag==} engines: {node: '>= 18.0.0'} hasBin: true peerDependencies: svelte: ^4.0.0 || ^5.0.0-next.0 typescript: '>=5.0.0' - svelte-check@4.4.6: - resolution: {integrity: sha512-kP1zG81EWaFe9ZyTv4ZXv44Csi6Pkdpb7S3oj6m+K2ec/IcDg/a8LsFsnVLqm2nxtkSwsd5xPj/qFkTBgXHXjg==} - engines: {node: '>= 18.0.0'} - hasBin: true - peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.0 - typescript: '>=5.0.0' - - svelte-eslint-parser@1.4.1: - resolution: {integrity: sha512-1eqkfQ93goAhjAXxZiu1SaKI9+0/sxp4JIWQwUpsz7ybehRE5L8dNuz7Iry7K22R47p5/+s9EM+38nHV2OlgXA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.24.0} + svelte-eslint-parser@1.6.0: + resolution: {integrity: sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.30.3} peerDependencies: svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 peerDependenciesMeta: svelte: optional: true - svelte2tsx@0.7.47: - resolution: {integrity: sha512-1aw/MFKVPM96OBevJdC12do2an9t5Zwr3Va9amLgTLpJje36ibD1iIHpuqCYWUrdR9vw6g6btKGQPmsqE8ZYCw==} + svelte2tsx@0.7.54: + resolution: {integrity: sha512-2pzMA8FRPYBQCpJSMgODH2KTp3QpukfCHztWfbCZDyjozRWzezgBcDS1hhpQLxiUFjv1pkzFPdMQhmb2wSuN5A==} peerDependencies: svelte: ^3.55 || ^4.0.0-next.0 || ^4.0 || ^5.0.0-next.0 typescript: ^4.9.4 || ^5.0.0 - svelte@5.49.2: - resolution: {integrity: sha512-PYLwnngYzyhKzqDlGVlCH4z+NVI8mC0/bTv15vw25CcdOhxENsOHIbQ36oj5DIf3oBazM+STbCAvaskpxtBmWA==} + svelte@5.55.5: + resolution: {integrity: sha512-2uCs/LZ9us+AktdzYJM8OcxQ8qnPS1kpaO7syGT/MgO+6Qr1Ybl+TqPq+97u7PHqmmMlye5ZkoyXONy5mjjAbw==} engines: {node: '>=18'} - svelte@5.55.4: - resolution: {integrity: sha512-q8DFohk6vUswSng95IZb9nzWJnbINZsK7OiM1snAa3qCjJBL0ZQpvMyAaVXjUukdM75J/m8UE8xwqat8Ors/zQ==} - engines: {node: '>=18'} - - svgo@4.0.0: - resolution: {integrity: sha512-VvrHQ+9uniE+Mvx3+C9IEe/lWasXCU0nXMY2kZeLrHNICuRiC8uMPyM14UEaMOFA5mhyQqEkB02VoQ16n3DLaw==} + svgo@4.0.1: + resolution: {integrity: sha512-XDpWUOPC6FEibaLzjfe0ucaV0YrOjYotGJO1WpF0Zd+n6ZGEQUsSugaoLq9QkEZtAfQIxT42UChcssDVPP3+/w==} engines: {node: '>=16'} hasBin: true symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - tailwindcss@4.1.18: - resolution: {integrity: sha512-4+Z+0yiYyEtUVCScyfHCxOYP06L5Ne+JiHhY2IjR2KWMIWhJOYZKLSGZaP5HkZ8+bY0cxfzwDE5uOmzFXyIwxw==} + tailwindcss@4.2.4: + resolution: {integrity: sha512-HhKppgO81FQof5m6TEnuBWCZGgfRAWbaeOaGT00KOy/Pf/j6oUihdvBpA7ltCeAvZpFhW3j0PTclkxsd4IXYDA==} - tailwindcss@4.2.2: - resolution: {integrity: sha512-KWBIxs1Xb6NoLdMVqhbhgwZf2PGBpPEiwOqgI4pFIYbNTfBXiKYyWoTsXgBQ9WFg/OlhnvHaY+AEpW7wSmFo2Q==} - - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} terser@5.36.0: @@ -3110,8 +2726,8 @@ packages: peerDependencies: three: '>=0.125.0' - three-mesh-bvh@0.9.8: - resolution: {integrity: sha512-YphYvdXEZSXdz6iNdWJo1RB6qvSCRyiXPEVSvNU6xVWbLDOdSrfEIsJOpgFOnefdmVEvZ6M+sY0cjh9gl7MvdA==} + three-mesh-bvh@0.9.9: + resolution: {integrity: sha512-FJKitcjvbALmeQRK+Sc+nLGorCpkrZBrbgJZFzhdyWboak37DZikn46hvQkNqSbJPm227ahYmS6k3N/GXaAyXw==} peerDependencies: three: '>= 0.159.0' @@ -3125,22 +2741,22 @@ packages: peerDependencies: three: '>=0.162.0 <1.0.0' - three@0.182.0: - resolution: {integrity: sha512-GbHabT+Irv+ihI1/f5kIIsZ+Ef9Sl5A1Y7imvS5RQjWgtTPfPnZ43JmlYI7NtCRDK9zir20lQpfg8/9Yd02OvQ==} + three@0.184.0: + resolution: {integrity: sha512-wtTRjG92pM5eUg/KuUnHsqSAlPM296brTOcLgMRqEeylYTh/CdtvKUvCyyCQTzFuStieWxvZb8mVTMvdPyUpxg==} tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.1.2: + resolution: {integrity: sha512-dAqSqE/RabpBKI8+h26GfLq6Vb3JVXs30XYQjdMjaj/c2tS8IYYMbIzP599KtRj7c57/wYApb3QjgRgXmrCukA==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyglobby@0.2.16: + resolution: {integrity: sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==} engines: {node: '>=12.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.1.0: + resolution: {integrity: sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==} engines: {node: '>=14.0.0'} tldts-core@6.1.86: @@ -3179,12 +2795,6 @@ packages: troika-worker-utils@0.52.0: resolution: {integrity: sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==} - ts-api-utils@2.4.0: - resolution: {integrity: sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - ts-api-utils@2.5.0: resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} @@ -3220,35 +2830,23 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} - typescript-eslint@8.54.0: - resolution: {integrity: sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - typescript-eslint@8.58.2: - resolution: {integrity: sha512-V8iSng9mRbdZjl54VJ9NKr6ZB+dW0J3TzRXRGcSbLIej9jV86ZRtlYeTKDR/QLxXykocJ5icNzbsl2+5TzIvcQ==} + typescript-eslint@8.59.1: + resolution: {integrity: sha512-xqDcFVBmlrltH64lklOVp1wYxgJr6LVdg3NamBgH2OOQDLFdTKfIZXF5PfghrnXQKXZGTQs8tr1vL7fJvq8CTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 typescript: '>=4.8.4 <6.1.0' - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - typescript@6.0.3: resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.6.3: - resolution: {integrity: sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==} + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.19.2: + resolution: {integrity: sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==} uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} @@ -3265,8 +2863,8 @@ packages: comlink: ^4.3.1 vite: '>=2.9.6' - vite-plugin-glsl@1.5.5: - resolution: {integrity: sha512-6NM2P4JkM+1hNSqMhM4eagX03bmhEoTyrOrk68y3Q6KXfdF73QIuCb6BmRZvwLPgXTCOBM3Zc8gL1WxctYnrUQ==} + vite-plugin-glsl@1.6.0: + resolution: {integrity: sha512-3i3ZvIVb13LhTcAXEHGTOW+cNG2jbJ++XsDFyCWUpnoFN1NPXvdtC4j66pig+i0QjDnmusOK/YCpiDWizxBY0A==} engines: {node: '>= 20.17.0', npm: '>= 10.8.3'} peerDependencies: '@rollup/pluginutils': ^5.x @@ -3278,53 +2876,13 @@ packages: esbuild: optional: true - vite-plugin-wasm@3.5.0: - resolution: {integrity: sha512-X5VWgCnqiQEGb+omhlBVsvTfxikKtoOgAzQ95+BZ8gQ+VfMHIjSHr0wyvXFQCa0eKQ0fKyaL0kWcEnYqBac4lQ==} + vite-plugin-wasm@3.6.0: + resolution: {integrity: sha512-mL/QPziiIA4RAA6DkaZZzOstdwbW5jO4Vz7Zenj0wieKWBlNvIvX5L5ljum9lcUX0ShNfBgCNLKTjNkRVVqcsw==} peerDependencies: - vite: ^2 || ^3 || ^4 || ^5 || ^6 || ^7 + vite: ^2 || ^3 || ^4 || ^5 || ^6 || ^7 || ^8 - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - vite@8.0.8: - resolution: {integrity: sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==} + vite@8.0.10: + resolution: {integrity: sha512-rZuUu9j6J5uotLDs+cAA4O5H4K1SfPliUlQwqa6YEwSrWDZzP4rhm00oJR5snMewjxF5V/K3D4kctsUTsIU9Mw==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -3366,14 +2924,6 @@ packages: yaml: optional: true - vitefu@1.1.1: - resolution: {integrity: sha512-B/Fegf3i8zh0yFbpzZ21amWzHmuNlLlmJT6n7bu5e+pCHUKQIfXSYokrqOBGEMMe9UG2sostKQF9mml/vYaWJQ==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0-beta.0 - peerDependenciesMeta: - vite: - optional: true - vitefu@1.1.3: resolution: {integrity: sha512-ub4okH7Z5KLjb6hDyjqrGXqWtWvoYdU3IGm/NorpgHncKoLTCfRIbvlhBm7r0YstIaQRYlp4yEbFqDcKSzXSSg==} peerDependencies: @@ -3382,26 +2932,29 @@ packages: vite: optional: true - vitest-browser-svelte@2.0.2: - resolution: {integrity: sha512-OLJVYoIYflwToFIy3s41pZ9mVp6dwXfYd8IIsWoc57g8DyN3SxsNJ5GB1xWFPxLFlKM+1MPExjPxLaqdELrfRQ==} + vitest-browser-svelte@2.1.1: + resolution: {integrity: sha512-qbunYRSm+N92r9bfTkdDTpBZESLmp4QFz2SluV3n/x8U7ysosfeXYJZ4vXbJ0Y0LzoqqDnV5LHprmFgn4Eo+Ug==} peerDependencies: svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0 vitest: ^4.0.0 - vitest@4.0.18: - resolution: {integrity: sha512-hOQuK7h0FGKgBAas7v0mSAsnvrIgAvWmRFjmzpJ7SwFHH3g1k2u37JtYwOwmEKhK6ZO3v9ggDBBm0La1LCK4uQ==} + vitest@4.1.5: + resolution: {integrity: sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==} engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.18 - '@vitest/browser-preview': 4.0.18 - '@vitest/browser-webdriverio': 4.0.18 - '@vitest/ui': 4.0.18 + '@vitest/browser-playwright': 4.1.5 + '@vitest/browser-preview': 4.1.5 + '@vitest/browser-webdriverio': 4.1.5 + '@vitest/coverage-istanbul': 4.1.5 + '@vitest/coverage-v8': 4.1.5 + '@vitest/ui': 4.1.5 happy-dom: '*' jsdom: '*' + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true @@ -3415,6 +2968,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -3464,8 +3021,8 @@ packages: resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} engines: {node: '>=18'} - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -3487,8 +3044,8 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - yaml@1.10.2: - resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} + yaml@1.10.3: + resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} engines: {node: '>= 6'} yargs-parser@22.0.0: @@ -3510,15 +3067,15 @@ packages: zimmerframe@1.1.4: resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} - zod@4.3.6: - resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==} + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} snapshots: '@antfu/install-pkg@1.1.0': dependencies: package-manager-detector: 1.6.0 - tinyexec: 1.0.2 + tinyexec: 1.1.2 '@asamuzakjp/css-color@3.2.0': dependencies: @@ -3537,7 +3094,9 @@ snapshots: '@babel/helper-validator-identifier@7.28.5': {} - '@babel/runtime@7.28.6': {} + '@babel/runtime@7.29.2': {} + + '@blazediff/core@1.9.1': {} '@cspotcode/source-map-support@0.8.1': dependencies: @@ -3569,7 +3128,7 @@ snapshots: '@csstools/css-tokenizer@3.0.4': optional: true - '@cyberalien/svg-utils@1.1.1': + '@cyberalien/svg-utils@1.2.15': dependencies: '@iconify/types': 2.0.0 @@ -3577,46 +3136,46 @@ snapshots: '@dmsnell/diff-match-patch@1.1.0': {} - '@dprint/darwin-arm64@0.51.1': + '@dprint/darwin-arm64@0.54.0': optional: true - '@dprint/darwin-x64@0.51.1': + '@dprint/darwin-x64@0.54.0': optional: true - '@dprint/linux-arm64-glibc@0.51.1': + '@dprint/linux-arm64-glibc@0.54.0': optional: true - '@dprint/linux-arm64-musl@0.51.1': + '@dprint/linux-arm64-musl@0.54.0': optional: true - '@dprint/linux-loong64-glibc@0.51.1': + '@dprint/linux-loong64-glibc@0.54.0': optional: true - '@dprint/linux-loong64-musl@0.51.1': + '@dprint/linux-loong64-musl@0.54.0': optional: true - '@dprint/linux-riscv64-glibc@0.51.1': + '@dprint/linux-riscv64-glibc@0.54.0': optional: true - '@dprint/linux-x64-glibc@0.51.1': + '@dprint/linux-x64-glibc@0.54.0': optional: true - '@dprint/linux-x64-musl@0.51.1': + '@dprint/linux-x64-musl@0.54.0': optional: true - '@dprint/win32-arm64@0.51.1': + '@dprint/win32-arm64@0.54.0': optional: true - '@dprint/win32-x64@0.51.1': + '@dprint/win32-x64@0.54.0': optional: true - '@emnapi/core@1.9.2': + '@emnapi/core@1.10.0': dependencies: '@emnapi/wasi-threads': 1.2.1 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.9.2': + '@emnapi/runtime@1.10.0': dependencies: tslib: 2.8.1 optional: true @@ -3626,115 +3185,96 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.27.3': + '@esbuild/aix-ppc64@0.27.7': optional: true - '@esbuild/android-arm64@0.27.3': + '@esbuild/android-arm64@0.27.7': optional: true - '@esbuild/android-arm@0.27.3': + '@esbuild/android-arm@0.27.7': optional: true - '@esbuild/android-x64@0.27.3': + '@esbuild/android-x64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.27.3': + '@esbuild/darwin-arm64@0.27.7': optional: true - '@esbuild/darwin-x64@0.27.3': + '@esbuild/darwin-x64@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.27.3': + '@esbuild/freebsd-arm64@0.27.7': optional: true - '@esbuild/freebsd-x64@0.27.3': + '@esbuild/freebsd-x64@0.27.7': optional: true - '@esbuild/linux-arm64@0.27.3': + '@esbuild/linux-arm64@0.27.7': optional: true - '@esbuild/linux-arm@0.27.3': + '@esbuild/linux-arm@0.27.7': optional: true - '@esbuild/linux-ia32@0.27.3': + '@esbuild/linux-ia32@0.27.7': optional: true - '@esbuild/linux-loong64@0.27.3': + '@esbuild/linux-loong64@0.27.7': optional: true - '@esbuild/linux-mips64el@0.27.3': + '@esbuild/linux-mips64el@0.27.7': optional: true - '@esbuild/linux-ppc64@0.27.3': + '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.27.3': + '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/linux-s390x@0.27.3': + '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/linux-x64@0.27.3': + '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/netbsd-arm64@0.27.3': + '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.27.3': + '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/openbsd-arm64@0.27.3': + '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.27.3': + '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/openharmony-arm64@0.27.3': + '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/sunos-x64@0.27.3': + '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/win32-arm64@0.27.3': + '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/win32-ia32@0.27.3': + '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-x64@0.27.3': + '@esbuild/win32-x64@0.27.7': optional: true - '@eslint-community/eslint-utils@4.9.1(eslint@10.2.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.9.1(eslint@10.3.0(jiti@2.6.1))': dependencies: - eslint: 10.2.1(jiti@2.6.1) - eslint-visitor-keys: 3.4.3 - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.2(jiti@2.6.1))': - dependencies: - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.3.0(jiti@2.6.1) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/compat@2.0.2(eslint@9.39.2(jiti@2.6.1))': - dependencies: - '@eslint/core': 1.1.0 - optionalDependencies: - eslint: 9.39.2(jiti@2.6.1) - - '@eslint/compat@2.0.5(eslint@10.2.1(jiti@2.6.1))': + '@eslint/compat@2.0.5(eslint@10.3.0(jiti@2.6.1))': dependencies: '@eslint/core': 1.2.1 optionalDependencies: - eslint: 10.2.1(jiti@2.6.1) - - '@eslint/config-array@0.21.1': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color + eslint: 10.3.0(jiti@2.6.1) '@eslint/config-array@0.23.5': dependencies: @@ -3744,99 +3284,83 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - '@eslint/config-helpers@0.5.5': dependencies: '@eslint/core': 1.2.1 - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/core@1.1.0': - dependencies: - '@types/json-schema': 7.0.15 - '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.3': + '@eslint/eslintrc@3.3.5': dependencies: - ajv: 6.12.6 + ajv: 6.15.0 debug: 4.4.3 espree: 10.4.0 globals: 14.0.0 ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color - '@eslint/js@10.0.1(eslint@10.2.1(jiti@2.6.1))': + '@eslint/js@10.0.1(eslint@10.3.0(jiti@2.6.1))': optionalDependencies: - eslint: 10.2.1(jiti@2.6.1) - - '@eslint/js@9.39.2': {} - - '@eslint/object-schema@2.1.7': {} + eslint: 10.3.0(jiti@2.6.1) '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - '@eslint/plugin-kit@0.7.1': dependencies: '@eslint/core': 1.2.1 levn: 0.4.1 - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': + '@humanfs/core@0.19.2': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} - '@iconify-json/tabler@1.2.26': + '@iconify-json/tabler@1.2.33': dependencies: '@iconify/types': 2.0.0 - '@iconify/tailwind4@1.2.1(tailwindcss@4.1.18)': + '@iconify/tailwind4@1.2.3(tailwindcss@4.2.4)': dependencies: - '@iconify/tools': 5.0.3 + '@iconify/tools': 5.0.11 '@iconify/types': 2.0.0 - '@iconify/utils': 3.1.0 - tailwindcss: 4.1.18 + '@iconify/utils': 3.1.1 + tailwindcss: 4.2.4 - '@iconify/tools@5.0.3': + '@iconify/tools@5.0.11': dependencies: - '@cyberalien/svg-utils': 1.1.1 + '@cyberalien/svg-utils': 1.2.15 '@iconify/types': 2.0.0 - '@iconify/utils': 3.1.0 + '@iconify/utils': 3.1.1 fflate: 0.8.2 - modern-tar: 0.7.3 + modern-tar: 0.7.6 pathe: 2.0.3 - svgo: 4.0.0 + svgo: 4.0.1 '@iconify/types@2.0.0': {} - '@iconify/utils@3.1.0': + '@iconify/utils@3.1.1': dependencies: '@antfu/install-pkg': 1.1.0 '@iconify/types': 2.0.0 - mlly: 1.8.0 + mlly: 1.8.2 '@jridgewell/gen-mapping@0.3.13': dependencies: @@ -3869,14 +3393,14 @@ snapshots: '@jridgewell/sourcemap-codec': 1.5.5 optional: true - '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2)': + '@napi-rs/wasm-runtime@1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@tybys/wasm-util': 0.10.1 + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 optional: true - '@oxc-project/types@0.124.0': {} + '@oxc-project/types@0.127.0': {} '@parcel/watcher-android-arm64@2.5.6': optional: true @@ -3939,64 +3463,64 @@ snapshots: '@parcel/watcher-win32-x64': 2.5.6 optional: true - '@playwright/test@1.58.1': + '@playwright/test@1.59.1': dependencies: - playwright: 1.58.1 + playwright: 1.59.1 '@polka/url@1.0.0-next.29': {} '@publint/pack@0.1.4': {} - '@rolldown/binding-android-arm64@1.0.0-rc.15': + '@rolldown/binding-android-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-arm64@1.0.0-rc.15': + '@rolldown/binding-darwin-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-darwin-x64@1.0.0-rc.15': + '@rolldown/binding-darwin-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-rc.15': + '@rolldown/binding-freebsd-x64@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.15': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-arm64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-ppc64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-s390x-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-rc.15': + '@rolldown/binding-linux-x64-gnu@1.0.0-rc.17': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-rc.15': + '@rolldown/binding-linux-x64-musl@1.0.0-rc.17': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-rc.15': + '@rolldown/binding-openharmony-arm64@1.0.0-rc.17': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-rc.15': + '@rolldown/binding-wasm32-wasi@1.0.0-rc.17': dependencies: - '@emnapi/core': 1.9.2 - '@emnapi/runtime': 1.9.2 - '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.9.2)(@emnapi/runtime@1.9.2) + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-rc.15': + '@rolldown/binding-win32-x64-msvc@1.0.0-rc.17': optional: true - '@rolldown/pluginutils@1.0.0-rc.15': {} + '@rolldown/pluginutils@1.0.0-rc.17': {} '@rollup/pluginutils@5.1.4(rollup@4.57.1)': dependencies: @@ -4084,247 +3608,130 @@ snapshots: '@standard-schema/spec@1.1.0': {} - '@sveltejs/acorn-typescript@1.0.8(acorn@8.15.0)': + '@sveltejs/acorn-typescript@1.0.9(acorn@8.16.0)': dependencies: - acorn: 8.15.0 + acorn: 8.16.0 - '@sveltejs/adapter-auto@7.0.1(@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))': + '@sveltejs/adapter-auto@7.0.1(@sveltejs/kit@2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))': dependencies: - '@sveltejs/kit': 2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + '@sveltejs/kit': 2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))': + '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))': dependencies: - '@sveltejs/kit': 2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + '@sveltejs/kit': 2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@sveltejs/kit@2.50.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(typescript@5.9.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': + '@sveltejs/kit@2.59.0(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': dependencies: '@standard-schema/spec': 1.1.0 - '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) + '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) '@types/cookie': 0.6.0 - acorn: 8.15.0 + acorn: 8.16.0 cookie: 0.6.0 - devalue: 5.6.2 + devalue: 5.8.0 esm-env: 1.2.2 kleur: 4.1.5 magic-string: 0.30.21 mrmime: 2.0.1 - sade: 1.8.1 - set-cookie-parser: 3.0.1 + set-cookie-parser: 3.1.0 sirv: 3.0.2 - svelte: 5.49.2 - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - optionalDependencies: - typescript: 5.9.3 - - '@sveltejs/kit@2.57.1(@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': - dependencies: - '@standard-schema/spec': 1.1.0 - '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) - '@sveltejs/vite-plugin-svelte': 7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@types/cookie': 0.6.0 - acorn: 8.15.0 - cookie: 0.6.0 - devalue: 5.7.1 - esm-env: 1.2.2 - kleur: 4.1.5 - magic-string: 0.30.21 - mrmime: 2.0.1 - set-cookie-parser: 3.0.1 - sirv: 3.0.2 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) optionalDependencies: typescript: 6.0.3 - '@sveltejs/package@2.5.7(svelte@5.49.2)(typescript@5.9.3)': + '@sveltejs/package@2.5.7(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3)': dependencies: chokidar: 5.0.0 kleur: 4.1.5 sade: 1.8.1 semver: 7.7.4 - svelte: 5.49.2 - svelte2tsx: 0.7.47(svelte@5.49.2)(typescript@5.9.3) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) + svelte2tsx: 0.7.54(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3) transitivePeerDependencies: - typescript - '@sveltejs/package@2.5.7(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3)': - dependencies: - chokidar: 5.0.0 - kleur: 4.1.5 - sade: 1.8.1 - semver: 7.7.4 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - svelte2tsx: 0.7.47(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3) - transitivePeerDependencies: - - typescript - - '@sveltejs/vite-plugin-svelte-inspector@5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': - dependencies: - '@sveltejs/vite-plugin-svelte': 6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - obug: 2.1.1 - svelte: 5.49.2 - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - - '@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': - dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 5.0.2(@sveltejs/vite-plugin-svelte@6.2.4(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)))(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - deepmerge: 4.3.1 - magic-string: 0.30.21 - obug: 2.1.1 - svelte: 5.49.2 - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - vitefu: 1.1.1(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - - '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.4(@typescript-eslint/types@8.58.2))(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': + '@sveltejs/vite-plugin-svelte@7.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': dependencies: deepmerge: 4.3.1 magic-string: 0.30.21 obug: 2.1.1 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - vitefu: 1.1.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vitefu: 1.1.3(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@tailwindcss/node@4.1.18': + '@tailwindcss/node@4.2.4': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.19.0 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.18 - - '@tailwindcss/node@4.2.2': - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.19.0 + enhanced-resolve: 5.21.0 jiti: 2.6.1 lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.2.2 + tailwindcss: 4.2.4 - '@tailwindcss/oxide-android-arm64@4.1.18': + '@tailwindcss/oxide-android-arm64@4.2.4': optional: true - '@tailwindcss/oxide-android-arm64@4.2.2': + '@tailwindcss/oxide-darwin-arm64@4.2.4': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.18': + '@tailwindcss/oxide-darwin-x64@4.2.4': optional: true - '@tailwindcss/oxide-darwin-arm64@4.2.2': + '@tailwindcss/oxide-freebsd-x64@4.2.4': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.18': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.4': optional: true - '@tailwindcss/oxide-darwin-x64@4.2.2': + '@tailwindcss/oxide-linux-arm64-gnu@4.2.4': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.18': + '@tailwindcss/oxide-linux-arm64-musl@4.2.4': optional: true - '@tailwindcss/oxide-freebsd-x64@4.2.2': + '@tailwindcss/oxide-linux-x64-gnu@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.18': + '@tailwindcss/oxide-linux-x64-musl@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.2.2': + '@tailwindcss/oxide-wasm32-wasi@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.18': + '@tailwindcss/oxide-win32-arm64-msvc@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.2.2': + '@tailwindcss/oxide-win32-x64-msvc@4.2.4': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-arm64-musl@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-gnu@4.2.2': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.1.18': - optional: true - - '@tailwindcss/oxide-linux-x64-musl@4.2.2': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.1.18': - optional: true - - '@tailwindcss/oxide-wasm32-wasi@4.2.2': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-arm64-msvc@4.2.2': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.1.18': - optional: true - - '@tailwindcss/oxide-win32-x64-msvc@4.2.2': - optional: true - - '@tailwindcss/oxide@4.1.18': + '@tailwindcss/oxide@4.2.4': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-arm64': 4.1.18 - '@tailwindcss/oxide-darwin-x64': 4.1.18 - '@tailwindcss/oxide-freebsd-x64': 4.1.18 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.18 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.18 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.18 - '@tailwindcss/oxide-linux-x64-musl': 4.1.18 - '@tailwindcss/oxide-wasm32-wasi': 4.1.18 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.18 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.18 + '@tailwindcss/oxide-android-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-arm64': 4.2.4 + '@tailwindcss/oxide-darwin-x64': 4.2.4 + '@tailwindcss/oxide-freebsd-x64': 4.2.4 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.4 + '@tailwindcss/oxide-linux-arm64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-arm64-musl': 4.2.4 + '@tailwindcss/oxide-linux-x64-gnu': 4.2.4 + '@tailwindcss/oxide-linux-x64-musl': 4.2.4 + '@tailwindcss/oxide-wasm32-wasi': 4.2.4 + '@tailwindcss/oxide-win32-arm64-msvc': 4.2.4 + '@tailwindcss/oxide-win32-x64-msvc': 4.2.4 - '@tailwindcss/oxide@4.2.2': - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-arm64': 4.2.2 - '@tailwindcss/oxide-darwin-x64': 4.2.2 - '@tailwindcss/oxide-freebsd-x64': 4.2.2 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.2.2 - '@tailwindcss/oxide-linux-arm64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-arm64-musl': 4.2.2 - '@tailwindcss/oxide-linux-x64-gnu': 4.2.2 - '@tailwindcss/oxide-linux-x64-musl': 4.2.2 - '@tailwindcss/oxide-wasm32-wasi': 4.2.2 - '@tailwindcss/oxide-win32-arm64-msvc': 4.2.2 - '@tailwindcss/oxide-win32-x64-msvc': 4.2.2 - - '@tailwindcss/vite@4.1.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': + '@tailwindcss/vite@4.2.4(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': dependencies: - '@tailwindcss/node': 4.1.18 - '@tailwindcss/oxide': 4.1.18 - tailwindcss: 4.1.18 - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - - '@tailwindcss/vite@4.2.2(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': - dependencies: - '@tailwindcss/node': 4.2.2 - '@tailwindcss/oxide': 4.2.2 - tailwindcss: 4.2.2 - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + '@tailwindcss/node': 4.2.4 + '@tailwindcss/oxide': 4.2.4 + tailwindcss: 4.2.4 + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) '@testing-library/dom@10.4.1': dependencies: '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.28.6 + '@babel/runtime': 7.29.2 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -4332,46 +3739,45 @@ snapshots: picocolors: 1.1.1 pretty-format: 27.5.1 - '@testing-library/svelte-core@1.0.0(svelte@5.49.2)': + '@testing-library/svelte-core@1.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1))': dependencies: - svelte: 5.49.2 + svelte: 5.55.5(@typescript-eslint/types@8.59.1) - '@testing-library/svelte@5.3.1(svelte@5.49.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)': + '@testing-library/svelte@5.3.1(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5)': dependencies: '@testing-library/dom': 10.4.1 - '@testing-library/svelte-core': 1.0.0(svelte@5.49.2) - svelte: 5.49.2 + '@testing-library/svelte-core': 1.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1)) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) optionalDependencies: - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - vitest: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vitest: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@threejs-kit/instanced-sprite-mesh@2.5.1(@types/three@0.182.0)(three@0.182.0)': + '@threejs-kit/instanced-sprite-mesh@2.5.1(@types/three@0.184.0)(three@0.184.0)': dependencies: diet-sprite: 0.0.1 earcut: 2.2.4 - maath: 0.10.8(@types/three@0.182.0)(three@0.182.0) - three: 0.182.0 - three-instanced-uniforms-mesh: 0.52.4(three@0.182.0) - troika-three-utils: 0.52.4(three@0.182.0) + maath: 0.10.8(@types/three@0.184.0)(three@0.184.0) + three: 0.184.0 + three-instanced-uniforms-mesh: 0.52.4(three@0.184.0) + troika-three-utils: 0.52.4(three@0.184.0) transitivePeerDependencies: - '@types/three' - '@threlte/core@8.3.1(svelte@5.49.2)(three@0.182.0)': + '@threlte/core@8.5.11(svelte@5.55.5(@typescript-eslint/types@8.59.1))(three@0.184.0)': dependencies: - mitt: 3.0.1 - svelte: 5.49.2 - three: 0.182.0 + svelte: 5.55.5(@typescript-eslint/types@8.59.1) + three: 0.184.0 - '@threlte/extras@9.7.1(@types/three@0.182.0)(svelte@5.49.2)(three@0.182.0)': + '@threlte/extras@9.15.1(@types/three@0.184.0)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(three@0.184.0)': dependencies: - '@threejs-kit/instanced-sprite-mesh': 2.5.1(@types/three@0.182.0)(three@0.182.0) - camera-controls: 3.1.2(three@0.182.0) - svelte: 5.49.2 - three: 0.182.0 - three-mesh-bvh: 0.9.8(three@0.182.0) - three-perf: 1.0.11(three@0.182.0) - three-viewport-gizmo: 2.2.0(three@0.182.0) - troika-three-text: 0.52.4(three@0.182.0) + '@threejs-kit/instanced-sprite-mesh': 2.5.1(@types/three@0.184.0)(three@0.184.0) + camera-controls: 3.1.2(three@0.184.0) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) + three: 0.184.0 + three-mesh-bvh: 0.9.9(three@0.184.0) + three-perf: 1.0.11(three@0.184.0) + three-viewport-gizmo: 2.2.0(three@0.184.0) + troika-three-text: 0.52.4(three@0.184.0) transitivePeerDependencies: - '@types/three' @@ -4387,11 +3793,11 @@ snapshots: '@tsconfig/node16@1.0.4': optional: true - '@tsconfig/svelte@5.0.7': {} + '@tsconfig/svelte@5.0.8': {} '@tweenjs/tween.js@23.1.3': {} - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.2': dependencies: tslib: 2.8.1 optional: true @@ -4405,7 +3811,7 @@ snapshots: '@types/cookie@0.6.0': {} - '@types/debug@4.1.12': + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -4426,51 +3832,34 @@ snapshots: '@types/ms@2.1.0': {} - '@types/node@24.12.2': + '@types/node@25.6.0': dependencies: - undici-types: 7.16.0 + undici-types: 7.19.2 '@types/stats.js@0.17.4': {} - '@types/three@0.182.0': + '@types/three@0.184.0': dependencies: '@dimforge/rapier3d-compat': 0.12.0 '@tweenjs/tween.js': 23.1.3 '@types/stats.js': 0.17.4 '@types/webxr': 0.5.24 - '@webgpu/types': 0.1.69 fflate: 0.8.2 - meshoptimizer: 0.22.0 + meshoptimizer: 1.1.1 '@types/trusted-types@2.0.7': {} '@types/webxr@0.5.24': {} - '@typescript-eslint/eslint-plugin@8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/eslint-plugin@8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/type-utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 - eslint: 9.39.2(jiti@2.6.1) - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/eslint-plugin@8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/type-utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.58.2 - eslint: 10.2.1(jiti@2.6.1) + '@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/type-utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.59.1 + eslint: 10.3.0(jiti@2.6.1) ignore: 7.0.5 natural-compare: 1.4.0 ts-api-utils: 2.5.0(typescript@6.0.3) @@ -4478,255 +3867,167 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.54.0 + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.59.1 debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - '@typescript-eslint/visitor-keys': 8.58.2 - debug: 4.4.3 - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.3.0(jiti@2.6.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.54.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.59.1(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) - '@typescript-eslint/types': 8.54.0 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.58.2(typescript@6.0.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.3) - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@6.0.3) + '@typescript-eslint/types': 8.59.1 debug: 4.4.3 typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.54.0': + '@typescript-eslint/scope-manager@8.59.1': dependencies: - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/visitor-keys': 8.54.0 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/visitor-keys': 8.59.1 - '@typescript-eslint/scope-manager@8.58.2': - dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 - - '@typescript-eslint/tsconfig-utils@8.54.0(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/tsconfig-utils@8.58.2(typescript@6.0.3)': + '@typescript-eslint/tsconfig-utils@8.59.1(typescript@6.0.3)': dependencies: typescript: 6.0.3 - '@typescript-eslint/type-utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) debug: 4.4.3 - eslint: 9.39.2(jiti@2.6.1) - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/type-utils@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': - dependencies: - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - debug: 4.4.3 - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.3.0(jiti@2.6.1) ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.54.0': {} + '@typescript-eslint/types@8.59.1': {} - '@typescript-eslint/types@8.58.2': {} - - '@typescript-eslint/typescript-estree@8.54.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.59.1(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.54.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.54.0(typescript@5.9.3) - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/visitor-keys': 8.54.0 - debug: 4.4.3 - minimatch: 9.0.5 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.4.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/typescript-estree@8.58.2(typescript@6.0.3)': - dependencies: - '@typescript-eslint/project-service': 8.58.2(typescript@6.0.3) - '@typescript-eslint/tsconfig-utils': 8.58.2(typescript@6.0.3) - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/visitor-keys': 8.58.2 + '@typescript-eslint/project-service': 8.59.1(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.59.1(typescript@6.0.3) + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/visitor-keys': 8.59.1 debug: 4.4.3 minimatch: 10.2.5 semver: 7.7.4 - tinyglobby: 0.2.15 + tinyglobby: 0.2.16 ts-api-utils: 2.5.0(typescript@6.0.3) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.54.0 - '@typescript-eslint/types': 8.54.0 - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.58.2 - '@typescript-eslint/types': 8.58.2 - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - eslint: 10.2.1(jiti@2.6.1) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.59.1 + '@typescript-eslint/types': 8.59.1 + '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) + eslint: 10.3.0(jiti@2.6.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.54.0': + '@typescript-eslint/visitor-keys@8.59.1': dependencies: - '@typescript-eslint/types': 8.54.0 - eslint-visitor-keys: 4.2.1 - - '@typescript-eslint/visitor-keys@8.58.2': - dependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.1 eslint-visitor-keys: 5.0.1 - '@vitest/browser-playwright@4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)': + '@vitest/browser-playwright@4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5)': dependencies: - '@vitest/browser': 4.0.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18) - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - playwright: 1.58.1 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + '@vitest/browser': 4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5) + '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + playwright: 1.59.1 + tinyrainbow: 3.1.0 + vitest: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/browser@4.0.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18)': + '@vitest/browser@4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5)': dependencies: - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@vitest/utils': 4.0.18 + '@blazediff/core': 1.9.1 + '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + '@vitest/utils': 4.1.5 magic-string: 0.30.21 - pixelmatch: 7.1.0 pngjs: 7.0.0 sirv: 3.0.2 - tinyrainbow: 3.0.3 - vitest: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - ws: 8.19.0 + tinyrainbow: 3.1.0 + vitest: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + ws: 8.20.0 transitivePeerDependencies: - bufferutil - msw - utf-8-validate - vite - '@vitest/expect@4.0.18': + '@vitest/expect@4.1.5': dependencies: '@standard-schema/spec': 1.1.0 '@types/chai': 5.2.3 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 chai: 6.2.2 - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/mocker@4.0.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': + '@vitest/mocker@4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))': dependencies: - '@vitest/spy': 4.0.18 + '@vitest/spy': 4.1.5 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - '@vitest/pretty-format@4.0.18': + '@vitest/pretty-format@4.1.5': dependencies: - tinyrainbow: 3.0.3 + tinyrainbow: 3.1.0 - '@vitest/runner@4.0.18': + '@vitest/runner@4.1.5': dependencies: - '@vitest/utils': 4.0.18 + '@vitest/utils': 4.1.5 pathe: 2.0.3 - '@vitest/snapshot@4.0.18': + '@vitest/snapshot@4.1.5': dependencies: - '@vitest/pretty-format': 4.0.18 + '@vitest/pretty-format': 4.1.5 + '@vitest/utils': 4.1.5 magic-string: 0.30.21 pathe: 2.0.3 - '@vitest/spy@4.0.18': {} + '@vitest/spy@4.1.5': {} - '@vitest/utils@4.0.18': + '@vitest/utils@4.1.5': dependencies: - '@vitest/pretty-format': 4.0.18 - tinyrainbow: 3.0.3 - - '@webgpu/types@0.1.69': {} - - acorn-jsx@5.3.2(acorn@8.15.0): - dependencies: - acorn: 8.15.0 + '@vitest/pretty-format': 4.1.5 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.0 acorn-jsx@5.3.2(acorn@8.16.0): dependencies: acorn: 8.16.0 - acorn-walk@8.3.4: + acorn-walk@8.3.5: dependencies: acorn: 8.16.0 optional: true - acorn@8.15.0: {} - acorn@8.16.0: {} agent-base@7.1.4: optional: true - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ajv@6.14.0: + ajv@6.15.0: dependencies: fast-deep-equal: 3.1.3 fast-json-stable-stringify: 2.1.0 @@ -4737,10 +4038,6 @@ snapshots: ansi-regex@6.2.2: {} - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - ansi-styles@5.2.0: {} ansi-styles@6.2.3: {} @@ -4748,7 +4045,7 @@ snapshots: anymatch@3.1.3: dependencies: normalize-path: 3.0.0 - picomatch: 2.3.1 + picomatch: 2.3.2 arg@4.1.3: optional: true @@ -4761,8 +4058,6 @@ snapshots: aria-query@5.3.1: {} - aria-query@5.3.2: {} - assertion-error@2.0.1: {} asynckit@0.4.0: @@ -4782,15 +4077,11 @@ snapshots: boolbase@1.0.0: {} - brace-expansion@1.1.12: + brace-expansion@1.1.14: dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - brace-expansion@5.0.5: dependencies: balanced-match: 4.0.4 @@ -4810,17 +4101,12 @@ snapshots: callsites@3.1.0: {} - camera-controls@3.1.2(three@0.182.0): + camera-controls@3.1.2(three@0.184.0): dependencies: - three: 0.182.0 + three: 0.184.0 chai@6.2.2: {} - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - character-entities@2.0.2: {} chokidar-cli@https://codeload.github.com/open-cli-tools/chokidar-cli/tar.gz/8dd8a1e8631d377de600f628d819a0cda46c102f: @@ -4853,17 +4139,11 @@ snapshots: cliui@9.0.1: dependencies: string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 wrap-ansi: 9.0.2 clsx@2.1.1: {} - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.4: {} - combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -4880,6 +4160,8 @@ snapshots: confbox@0.1.8: {} + convert-source-map@2.0.0: {} + cookie@0.6.0: {} copy-anything@2.0.6: @@ -4909,9 +4191,9 @@ snapshots: mdn-data: 2.0.28 source-map-js: 1.2.1 - css-tree@3.1.0: + css-tree@3.2.1: dependencies: - mdn-data: 2.12.2 + mdn-data: 2.27.1 source-map-js: 1.2.1 css-what@6.2.2: {} @@ -4958,9 +4240,7 @@ snapshots: detect-libc@2.1.2: {} - devalue@5.6.2: {} - - devalue@5.7.1: {} + devalue@5.8.0: {} devlop@1.1.0: dependencies: @@ -4991,19 +4271,19 @@ snapshots: domelementtype: 2.3.0 domhandler: 5.0.3 - dprint@0.51.1: + dprint@0.54.0: optionalDependencies: - '@dprint/darwin-arm64': 0.51.1 - '@dprint/darwin-x64': 0.51.1 - '@dprint/linux-arm64-glibc': 0.51.1 - '@dprint/linux-arm64-musl': 0.51.1 - '@dprint/linux-loong64-glibc': 0.51.1 - '@dprint/linux-loong64-musl': 0.51.1 - '@dprint/linux-riscv64-glibc': 0.51.1 - '@dprint/linux-x64-glibc': 0.51.1 - '@dprint/linux-x64-musl': 0.51.1 - '@dprint/win32-arm64': 0.51.1 - '@dprint/win32-x64': 0.51.1 + '@dprint/darwin-arm64': 0.54.0 + '@dprint/darwin-x64': 0.54.0 + '@dprint/linux-arm64-glibc': 0.54.0 + '@dprint/linux-arm64-musl': 0.54.0 + '@dprint/linux-loong64-glibc': 0.54.0 + '@dprint/linux-loong64-musl': 0.54.0 + '@dprint/linux-riscv64-glibc': 0.54.0 + '@dprint/linux-x64-glibc': 0.54.0 + '@dprint/linux-x64-musl': 0.54.0 + '@dprint/win32-arm64': 0.54.0 + '@dprint/win32-x64': 0.54.0 dunder-proto@1.0.1: dependencies: @@ -5016,10 +4296,10 @@ snapshots: emoji-regex@10.6.0: {} - enhanced-resolve@5.19.0: + enhanced-resolve@5.21.0: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.3 entities@4.5.0: {} @@ -5037,7 +4317,7 @@ snapshots: es-errors@1.3.0: optional: true - es-module-lexer@1.7.0: {} + es-module-lexer@2.1.0: {} es-object-atoms@1.1.1: dependencies: @@ -5049,79 +4329,61 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.3 optional: true - esbuild@0.27.3: + esbuild@0.27.7: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.3 - '@esbuild/android-arm': 0.27.3 - '@esbuild/android-arm64': 0.27.3 - '@esbuild/android-x64': 0.27.3 - '@esbuild/darwin-arm64': 0.27.3 - '@esbuild/darwin-x64': 0.27.3 - '@esbuild/freebsd-arm64': 0.27.3 - '@esbuild/freebsd-x64': 0.27.3 - '@esbuild/linux-arm': 0.27.3 - '@esbuild/linux-arm64': 0.27.3 - '@esbuild/linux-ia32': 0.27.3 - '@esbuild/linux-loong64': 0.27.3 - '@esbuild/linux-mips64el': 0.27.3 - '@esbuild/linux-ppc64': 0.27.3 - '@esbuild/linux-riscv64': 0.27.3 - '@esbuild/linux-s390x': 0.27.3 - '@esbuild/linux-x64': 0.27.3 - '@esbuild/netbsd-arm64': 0.27.3 - '@esbuild/netbsd-x64': 0.27.3 - '@esbuild/openbsd-arm64': 0.27.3 - '@esbuild/openbsd-x64': 0.27.3 - '@esbuild/openharmony-arm64': 0.27.3 - '@esbuild/sunos-x64': 0.27.3 - '@esbuild/win32-arm64': 0.27.3 - '@esbuild/win32-ia32': 0.27.3 - '@esbuild/win32-x64': 0.27.3 + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 escalade@3.2.0: {} escape-string-regexp@4.0.0: {} - eslint-config-prettier@10.1.8(eslint@10.2.1(jiti@2.6.1)): + eslint-config-prettier@10.1.8(eslint@10.3.0(jiti@2.6.1)): dependencies: - eslint: 10.2.1(jiti@2.6.1) + eslint: 10.3.0(jiti@2.6.1) - eslint-plugin-svelte@3.14.0(eslint@9.39.2(jiti@2.6.1))(svelte@5.49.2)(ts-node@10.9.2(@types/node@24.12.2)(typescript@5.9.3)): + eslint-plugin-svelte@3.17.1(eslint@10.3.0(jiti@2.6.1))(svelte@5.55.5(@typescript-eslint/types@8.59.1))(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 9.39.2(jiti@2.6.1) + eslint: 10.3.0(jiti@2.6.1) esutils: 2.0.3 globals: 16.5.0 known-css-properties: 0.37.0 - postcss: 8.5.6 - postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.12.2)(typescript@5.9.3)) - postcss-safe-parser: 7.0.1(postcss@8.5.6) + postcss: 8.5.13 + postcss-load-config: 3.1.4(postcss@8.5.13)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)) + postcss-safe-parser: 7.0.1(postcss@8.5.13) semver: 7.7.4 - svelte-eslint-parser: 1.4.1(svelte@5.49.2) + svelte-eslint-parser: 1.6.0(svelte@5.55.5(@typescript-eslint/types@8.59.1)) optionalDependencies: - svelte: 5.49.2 - transitivePeerDependencies: - - ts-node - - eslint-plugin-svelte@3.17.0(eslint@10.2.1(jiti@2.6.1))(svelte@5.55.4(@typescript-eslint/types@8.58.2))(ts-node@10.9.2(@types/node@24.12.2)(typescript@6.0.3)): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) - '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 10.2.1(jiti@2.6.1) - esutils: 2.0.3 - globals: 16.5.0 - known-css-properties: 0.37.0 - postcss: 8.5.6 - postcss-load-config: 3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.12.2)(typescript@6.0.3)) - postcss-safe-parser: 7.0.1(postcss@8.5.6) - semver: 7.7.4 - svelte-eslint-parser: 1.4.1(svelte@5.55.4(@typescript-eslint/types@8.58.2)) - optionalDependencies: - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) transitivePeerDependencies: - ts-node @@ -5143,19 +4405,19 @@ snapshots: eslint-visitor-keys@5.0.1: {} - eslint@10.2.1(jiti@2.6.1): + eslint@10.3.0(jiti@2.6.1): dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@10.2.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.9.1(eslint@10.3.0(jiti@2.6.1)) '@eslint-community/regexpp': 4.12.2 '@eslint/config-array': 0.23.5 '@eslint/config-helpers': 0.5.5 '@eslint/core': 1.2.1 '@eslint/plugin-kit': 0.7.1 - '@humanfs/node': 0.16.7 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 '@types/estree': 1.0.8 - ajv: 6.14.0 + ajv: 6.15.0 cross-spawn: 7.0.6 debug: 4.4.3 escape-string-regexp: 4.0.0 @@ -5180,53 +4442,12 @@ snapshots: transitivePeerDependencies: - supports-color - eslint@9.39.2(jiti@2.6.1): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.2(jiti@2.6.1)) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.3 - '@eslint/js': 9.39.2 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - optionalDependencies: - jiti: 2.6.1 - transitivePeerDependencies: - - supports-color - esm-env@1.2.2: {} espree@10.4.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) + acorn: 8.16.0 + acorn-jsx: 5.3.2(acorn@8.16.0) eslint-visitor-keys: 4.2.1 espree@11.2.0: @@ -5239,15 +4460,11 @@ snapshots: dependencies: estraverse: 5.3.0 - esrap@2.2.2: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - esrap@2.2.5(@typescript-eslint/types@8.58.2): + esrap@2.2.5(@typescript-eslint/types@8.59.1): dependencies: '@jridgewell/sourcemap-codec': 1.5.5 optionalDependencies: - '@typescript-eslint/types': 8.58.2 + '@typescript-eslint/types': 8.59.1 esrecurse@4.3.0: dependencies: @@ -5272,10 +4489,6 @@ snapshots: fast-levenshtein@2.0.6: {} - fdir@6.5.0(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - fdir@6.5.0(picomatch@4.0.4): optionalDependencies: picomatch: 4.0.4 @@ -5299,17 +4512,17 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 - flatted@3.3.3: {} + flatted@3.4.2: {} form-data@4.0.5: dependencies: asynckit: 0.4.0 combined-stream: 1.0.8 es-set-tostringtag: 2.1.0 - hasown: 2.0.2 + hasown: 2.0.3 mime-types: 2.1.35 optional: true @@ -5324,7 +4537,7 @@ snapshots: get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} + get-east-asian-width@1.5.0: {} get-intrinsic@1.3.0: dependencies: @@ -5336,7 +4549,7 @@ snapshots: get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.3 math-intrinsics: 1.1.0 optional: true @@ -5346,7 +4559,7 @@ snapshots: es-object-atoms: 1.1.1 optional: true - get-tsconfig@4.13.6: + get-tsconfig@4.14.0: dependencies: resolve-pkg-maps: 1.0.0 @@ -5362,17 +4575,13 @@ snapshots: globals@16.5.0: {} - globals@17.3.0: {} - - globals@17.5.0: {} + globals@17.6.0: {} gopd@1.2.0: optional: true graceful-fs@4.2.11: {} - has-flag@4.0.0: {} - has-symbols@1.1.0: optional: true @@ -5381,7 +4590,7 @@ snapshots: has-symbols: 1.1.0 optional: true - hasown@2.0.2: + hasown@2.0.3: dependencies: function-bind: 1.1.2 optional: true @@ -5421,7 +4630,7 @@ snapshots: image-size@0.5.5: optional: true - immutable@4.3.7: + immutable@4.3.8: optional: true import-fresh@3.3.1: @@ -5484,7 +4693,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.19.0 + ws: 8.20.0 xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -5523,7 +4732,7 @@ snapshots: image-size: 0.5.5 make-dir: 2.1.0 mime: 1.6.0 - needle: 3.3.1 + needle: 3.5.0 source-map: 0.6.1 optional: true @@ -5532,88 +4741,39 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 - lightningcss-android-arm64@1.30.2: - optional: true - lightningcss-android-arm64@1.32.0: optional: true - lightningcss-darwin-arm64@1.30.2: - optional: true - lightningcss-darwin-arm64@1.32.0: optional: true - lightningcss-darwin-x64@1.30.2: - optional: true - lightningcss-darwin-x64@1.32.0: optional: true - lightningcss-freebsd-x64@1.30.2: - optional: true - lightningcss-freebsd-x64@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: - optional: true - lightningcss-linux-arm-gnueabihf@1.32.0: optional: true - lightningcss-linux-arm64-gnu@1.30.2: - optional: true - lightningcss-linux-arm64-gnu@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.30.2: - optional: true - lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-linux-x64-gnu@1.30.2: - optional: true - lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-x64-musl@1.30.2: - optional: true - lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-win32-arm64-msvc@1.30.2: - optional: true - lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.30.2: - optional: true - lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss@1.30.2: - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - lightningcss@1.32.0: dependencies: detect-libc: 2.1.2 @@ -5640,8 +4800,6 @@ snapshots: lodash.debounce@4.0.8: {} - lodash.merge@4.6.2: {} - lodash.throttle@4.1.1: {} lru-cache@10.4.3: @@ -5649,10 +4807,10 @@ snapshots: lz-string@1.5.0: {} - maath@0.10.8(@types/three@0.182.0)(three@0.182.0): + maath@0.10.8(@types/three@0.184.0)(three@0.184.0): dependencies: - '@types/three': 0.182.0 - three: 0.182.0 + '@types/three': 0.184.0 + three: 0.184.0 magic-string@0.30.17: dependencies: @@ -5676,9 +4834,9 @@ snapshots: mdn-data@2.0.28: {} - mdn-data@2.12.2: {} + mdn-data@2.27.1: {} - meshoptimizer@0.22.0: {} + meshoptimizer@1.1.1: {} micromark-core-commonmark@2.0.3: dependencies: @@ -5786,7 +4944,7 @@ snapshots: micromark@4.0.2: dependencies: - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3 decode-named-character-reference: 1.3.0 devlop: 1.1.0 @@ -5821,24 +4979,18 @@ snapshots: dependencies: brace-expansion: 5.0.5 - minimatch@3.1.2: + minimatch@3.1.5: dependencies: - brace-expansion: 1.1.12 + brace-expansion: 1.1.14 - minimatch@9.0.5: + mlly@1.8.2: dependencies: - brace-expansion: 2.0.2 - - mitt@3.0.1: {} - - mlly@1.8.0: - dependencies: - acorn: 8.15.0 + acorn: 8.16.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.3 + ufo: 1.6.4 - modern-tar@0.7.3: {} + modern-tar@0.7.6: {} mri@1.2.0: {} @@ -5846,14 +4998,14 @@ snapshots: ms@2.1.3: {} - nanoid@3.3.11: {} + nanoid@3.3.12: {} natural-compare@1.4.0: {} - needle@3.3.1: + needle@3.5.0: dependencies: iconv-lite: 0.6.3 - sax: 1.4.4 + sax: 1.6.0 optional: true node-addon-api@7.1.1: @@ -5909,88 +5061,68 @@ snapshots: picocolors@1.1.1: {} - picomatch@2.3.1: {} - - picomatch@4.0.3: {} + picomatch@2.3.2: {} picomatch@4.0.4: {} pify@4.0.1: optional: true - pixelmatch@7.1.0: - dependencies: - pngjs: 7.0.0 - pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.0 + mlly: 1.8.2 pathe: 2.0.3 - playwright-core@1.58.1: {} + playwright-core@1.59.1: {} - playwright@1.58.1: + playwright@1.59.1: dependencies: - playwright-core: 1.58.1 + playwright-core: 1.59.1 optionalDependencies: fsevents: 2.3.2 pngjs@7.0.0: {} - postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.12.2)(typescript@5.9.3)): + postcss-load-config@3.1.4(postcss@8.5.13)(ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3)): dependencies: lilconfig: 2.1.0 - yaml: 1.10.2 + yaml: 1.10.3 optionalDependencies: - postcss: 8.5.6 - ts-node: 10.9.2(@types/node@24.12.2)(typescript@5.9.3) + postcss: 8.5.13 + ts-node: 10.9.2(@types/node@25.6.0)(typescript@6.0.3) - postcss-load-config@3.1.4(postcss@8.5.6)(ts-node@10.9.2(@types/node@24.12.2)(typescript@6.0.3)): + postcss-safe-parser@7.0.1(postcss@8.5.13): dependencies: - lilconfig: 2.1.0 - yaml: 1.10.2 - optionalDependencies: - postcss: 8.5.6 - ts-node: 10.9.2(@types/node@24.12.2)(typescript@6.0.3) + postcss: 8.5.13 - postcss-safe-parser@7.0.1(postcss@8.5.6): + postcss-scss@4.0.9(postcss@8.5.13): dependencies: - postcss: 8.5.6 - - postcss-scss@4.0.9(postcss@8.5.6): - dependencies: - postcss: 8.5.6 + postcss: 8.5.13 postcss-selector-parser@7.1.1: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.5.10: + postcss@8.5.13: dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 + nanoid: 3.3.12 picocolors: 1.1.1 source-map-js: 1.2.1 prelude-ls@1.2.1: {} - prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)): + prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.5(@typescript-eslint/types@8.59.1)): dependencies: prettier: 3.8.3 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) - prettier-plugin-tailwindcss@0.7.2(prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)))(prettier@3.8.3): + prettier-plugin-tailwindcss@0.8.0(prettier-plugin-svelte@3.5.1(prettier@3.8.3)(svelte@5.55.5(@typescript-eslint/types@8.59.1)))(prettier@3.8.3): dependencies: prettier: 3.8.3 optionalDependencies: - prettier-plugin-svelte: 3.5.1(prettier@3.8.3)(svelte@5.55.4(@typescript-eslint/types@8.58.2)) + prettier-plugin-svelte: 3.5.1(prettier@3.8.3)(svelte@5.55.5(@typescript-eslint/types@8.59.1)) prettier@3.8.3: {} @@ -6003,13 +5135,6 @@ snapshots: prr@1.0.1: optional: true - publint@0.3.17: - dependencies: - '@publint/pack': 0.1.4 - package-manager-detector: 1.6.0 - picocolors: 1.1.1 - sade: 1.8.1 - publint@0.3.18: dependencies: '@publint/pack': 0.1.4 @@ -6023,7 +5148,7 @@ snapshots: readdirp@3.6.0: dependencies: - picomatch: 2.3.1 + picomatch: 2.3.2 readdirp@4.1.2: {} @@ -6035,26 +5160,26 @@ snapshots: resolve-pkg-maps@1.0.0: {} - rolldown@1.0.0-rc.15: + rolldown@1.0.0-rc.17: dependencies: - '@oxc-project/types': 0.124.0 - '@rolldown/pluginutils': 1.0.0-rc.15 + '@oxc-project/types': 0.127.0 + '@rolldown/pluginutils': 1.0.0-rc.17 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-arm64': 1.0.0-rc.15 - '@rolldown/binding-darwin-x64': 1.0.0-rc.15 - '@rolldown/binding-freebsd-x64': 1.0.0-rc.15 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.15 - '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.15 - '@rolldown/binding-linux-x64-musl': 1.0.0-rc.15 - '@rolldown/binding-openharmony-arm64': 1.0.0-rc.15 - '@rolldown/binding-wasm32-wasi': 1.0.0-rc.15 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.15 - '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.15 + '@rolldown/binding-android-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-arm64': 1.0.0-rc.17 + '@rolldown/binding-darwin-x64': 1.0.0-rc.17 + '@rolldown/binding-freebsd-x64': 1.0.0-rc.17 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-arm64-musl': 1.0.0-rc.17 + '@rolldown/binding-linux-ppc64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-s390x-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-gnu': 1.0.0-rc.17 + '@rolldown/binding-linux-x64-musl': 1.0.0-rc.17 + '@rolldown/binding-openharmony-arm64': 1.0.0-rc.17 + '@rolldown/binding-wasm32-wasi': 1.0.0-rc.17 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-rc.17 + '@rolldown/binding-win32-x64-msvc': 1.0.0-rc.17 rollup@4.57.1: dependencies: @@ -6086,6 +5211,7 @@ snapshots: '@rollup/rollup-win32-x64-gnu': 4.57.1 '@rollup/rollup-win32-x64-msvc': 4.57.1 fsevents: 2.3.3 + optional: true rrweb-cssom@0.7.1: optional: true @@ -6103,13 +5229,13 @@ snapshots: sass@1.80.6: dependencies: chokidar: 4.0.3 - immutable: 4.3.7 + immutable: 4.3.8 source-map-js: 1.2.1 optionalDependencies: '@parcel/watcher': 2.5.6 optional: true - sax@1.4.4: {} + sax@1.6.0: {} saxes@6.0.0: dependencies: @@ -6123,7 +5249,7 @@ snapshots: semver@7.7.4: {} - set-cookie-parser@3.0.1: {} + set-cookie-parser@3.1.0: {} shebang-command@2.0.0: dependencies: @@ -6154,128 +5280,65 @@ snapshots: stackback@0.0.2: {} - std-env@3.10.0: {} + std-env@4.1.0: {} string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 + get-east-asian-width: 1.5.0 + strip-ansi: 7.2.0 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: ansi-regex: 6.2.2 strip-json-comments@3.1.1: {} - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - svelte-check@4.3.6(picomatch@4.0.3)(svelte@5.49.2)(typescript@5.9.3): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - chokidar: 4.0.3 - fdir: 6.5.0(picomatch@4.0.3) - picocolors: 1.1.1 - sade: 1.8.1 - svelte: 5.49.2 - typescript: 5.9.3 - transitivePeerDependencies: - - picomatch - - svelte-check@4.3.6(picomatch@4.0.4)(svelte@5.49.2)(typescript@5.9.3): + svelte-check@4.4.7(picomatch@4.0.4)(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 chokidar: 4.0.3 fdir: 6.5.0(picomatch@4.0.4) picocolors: 1.1.1 sade: 1.8.1 - svelte: 5.49.2 - typescript: 5.9.3 - transitivePeerDependencies: - - picomatch - - svelte-check@4.4.6(picomatch@4.0.4)(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - chokidar: 4.0.3 - fdir: 6.5.0(picomatch@4.0.4) - picocolors: 1.1.1 - sade: 1.8.1 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) typescript: 6.0.3 transitivePeerDependencies: - picomatch - svelte-eslint-parser@1.4.1(svelte@5.49.2): + svelte-eslint-parser@1.6.0(svelte@5.55.5(@typescript-eslint/types@8.59.1)): dependencies: eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 espree: 10.4.0 - postcss: 8.5.6 - postcss-scss: 4.0.9(postcss@8.5.6) + postcss: 8.5.13 + postcss-scss: 4.0.9(postcss@8.5.13) postcss-selector-parser: 7.1.1 + semver: 7.7.4 optionalDependencies: - svelte: 5.49.2 + svelte: 5.55.5(@typescript-eslint/types@8.59.1) - svelte-eslint-parser@1.4.1(svelte@5.55.4(@typescript-eslint/types@8.58.2)): - dependencies: - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - postcss: 8.5.6 - postcss-scss: 4.0.9(postcss@8.5.6) - postcss-selector-parser: 7.1.1 - optionalDependencies: - svelte: 5.55.4(@typescript-eslint/types@8.58.2) - - svelte2tsx@0.7.47(svelte@5.49.2)(typescript@5.9.3): + svelte2tsx@0.7.54(svelte@5.55.5(@typescript-eslint/types@8.59.1))(typescript@6.0.3): dependencies: dedent-js: 1.0.1 scule: 1.3.0 - svelte: 5.49.2 - typescript: 5.9.3 - - svelte2tsx@0.7.47(svelte@5.55.4(@typescript-eslint/types@8.58.2))(typescript@6.0.3): - dependencies: - dedent-js: 1.0.1 - scule: 1.3.0 - svelte: 5.55.4(@typescript-eslint/types@8.58.2) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) typescript: 6.0.3 - svelte@5.49.2: + svelte@5.55.5(@typescript-eslint/types@8.59.1): dependencies: '@jridgewell/remapping': 2.3.5 '@jridgewell/sourcemap-codec': 1.5.5 - '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) - '@types/estree': 1.0.8 - acorn: 8.15.0 - aria-query: 5.3.2 - axobject-query: 4.1.0 - clsx: 2.1.1 - devalue: 5.6.2 - esm-env: 1.2.2 - esrap: 2.2.2 - is-reference: 3.0.3 - locate-character: 3.0.0 - magic-string: 0.30.21 - zimmerframe: 1.1.4 - - svelte@5.55.4(@typescript-eslint/types@8.58.2): - dependencies: - '@jridgewell/remapping': 2.3.5 - '@jridgewell/sourcemap-codec': 1.5.5 - '@sveltejs/acorn-typescript': 1.0.8(acorn@8.15.0) + '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) '@types/estree': 1.0.8 '@types/trusted-types': 2.0.7 - acorn: 8.15.0 + acorn: 8.16.0 aria-query: 5.3.1 axobject-query: 4.1.0 clsx: 2.1.1 - devalue: 5.7.1 + devalue: 5.8.0 esm-env: 1.2.2 - esrap: 2.2.5(@typescript-eslint/types@8.58.2) + esrap: 2.2.5(@typescript-eslint/types@8.59.1) is-reference: 3.0.3 locate-character: 3.0.0 magic-string: 0.30.21 @@ -6283,24 +5346,22 @@ snapshots: transitivePeerDependencies: - '@typescript-eslint/types' - svgo@4.0.0: + svgo@4.0.1: dependencies: commander: 11.1.0 css-select: 5.2.2 - css-tree: 3.1.0 + css-tree: 3.2.1 css-what: 6.2.2 csso: 5.0.5 picocolors: 1.1.1 - sax: 1.4.4 + sax: 1.6.0 symbol-tree@3.2.4: optional: true - tailwindcss@4.1.18: {} + tailwindcss@4.2.4: {} - tailwindcss@4.2.2: {} - - tapable@2.3.0: {} + tapable@2.3.3: {} terser@5.36.0: dependencies: @@ -6310,37 +5371,37 @@ snapshots: source-map-support: 0.5.21 optional: true - three-instanced-uniforms-mesh@0.52.4(three@0.182.0): + three-instanced-uniforms-mesh@0.52.4(three@0.184.0): dependencies: - three: 0.182.0 - troika-three-utils: 0.52.4(three@0.182.0) + three: 0.184.0 + troika-three-utils: 0.52.4(three@0.184.0) - three-mesh-bvh@0.9.8(three@0.182.0): + three-mesh-bvh@0.9.9(three@0.184.0): dependencies: - three: 0.182.0 + three: 0.184.0 - three-perf@1.0.11(three@0.182.0): + three-perf@1.0.11(three@0.184.0): dependencies: - three: 0.182.0 - troika-three-text: 0.52.4(three@0.182.0) + three: 0.184.0 + troika-three-text: 0.52.4(three@0.184.0) tweakpane: 3.1.10 - three-viewport-gizmo@2.2.0(three@0.182.0): + three-viewport-gizmo@2.2.0(three@0.184.0): dependencies: - three: 0.182.0 + three: 0.184.0 - three@0.182.0: {} + three@0.184.0: {} tinybench@2.9.0: {} - tinyexec@1.0.2: {} + tinyexec@1.1.2: {} - tinyglobby@0.2.15: + tinyglobby@0.2.16: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.0: {} tldts-core@6.1.86: optional: true @@ -6366,57 +5427,34 @@ snapshots: punycode: 2.3.1 optional: true - troika-three-text@0.52.4(three@0.182.0): + troika-three-text@0.52.4(three@0.184.0): dependencies: bidi-js: 1.0.3 - three: 0.182.0 - troika-three-utils: 0.52.4(three@0.182.0) + three: 0.184.0 + troika-three-utils: 0.52.4(three@0.184.0) troika-worker-utils: 0.52.0 webgl-sdf-generator: 1.1.1 - troika-three-utils@0.52.4(three@0.182.0): + troika-three-utils@0.52.4(three@0.184.0): dependencies: - three: 0.182.0 + three: 0.184.0 troika-worker-utils@0.52.0: {} - ts-api-utils@2.4.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - ts-api-utils@2.5.0(typescript@6.0.3): dependencies: typescript: 6.0.3 - ts-node@10.9.2(@types/node@24.12.2)(typescript@5.9.3): + ts-node@10.9.2(@types/node@25.6.0)(typescript@6.0.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.12 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 24.12.2 + '@types/node': 25.6.0 acorn: 8.16.0 - acorn-walk: 8.3.4 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.4 - make-error: 1.3.6 - typescript: 5.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - optional: true - - ts-node@10.9.2(@types/node@24.12.2)(typescript@6.0.3): - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.12 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.4 - '@types/node': 24.12.2 - acorn: 8.16.0 - acorn-walk: 8.3.4 + acorn-walk: 8.3.5 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.4 @@ -6430,8 +5468,8 @@ snapshots: tsx@4.21.0: dependencies: - esbuild: 0.27.3 - get-tsconfig: 4.13.6 + esbuild: 0.27.7 + get-tsconfig: 4.14.0 optionalDependencies: fsevents: 2.3.3 @@ -6441,35 +5479,22 @@ snapshots: dependencies: prelude-ls: 1.2.1 - typescript-eslint@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.54.0(@typescript-eslint/parser@8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.54.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.54.0(eslint@9.39.2(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.2(jiti@2.6.1) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript-eslint@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.58.2(@typescript-eslint/parser@8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3))(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/parser': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - '@typescript-eslint/typescript-estree': 8.58.2(typescript@6.0.3) - '@typescript-eslint/utils': 8.58.2(eslint@10.2.1(jiti@2.6.1))(typescript@6.0.3) - eslint: 10.2.1(jiti@2.6.1) + '@typescript-eslint/eslint-plugin': 8.59.1(@typescript-eslint/parser@8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3))(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/parser': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.59.1(typescript@6.0.3) + '@typescript-eslint/utils': 8.59.1(eslint@10.3.0(jiti@2.6.1))(typescript@6.0.3) + eslint: 10.3.0(jiti@2.6.1) typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript@5.9.3: {} - typescript@6.0.3: {} - ufo@1.6.3: {} + ufo@1.6.4: {} - undici-types@7.16.0: {} + undici-types@7.19.2: {} uri-js@4.4.1: dependencies: @@ -6480,53 +5505,35 @@ snapshots: v8-compile-cache-lib@3.0.1: optional: true - vite-plugin-comlink@5.3.0(comlink@4.4.2)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): + vite-plugin-comlink@5.3.0(comlink@4.4.2)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): dependencies: comlink: 4.4.2 json5: 2.2.3 magic-string: 0.30.17 source-map: 0.7.6 - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - vite-plugin-glsl@1.5.5(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.3)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): + vite-plugin-glsl@1.6.0(@rollup/pluginutils@5.1.4(rollup@4.57.1))(esbuild@0.27.7)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): dependencies: - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) optionalDependencies: '@rollup/pluginutils': 5.1.4(rollup@4.57.1) - esbuild: 0.27.3 + esbuild: 0.27.7 - vite-plugin-wasm@3.5.0(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): + vite-plugin-wasm@3.6.0(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): dependencies: - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0): - dependencies: - esbuild: 0.27.3 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.57.1 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.12.2 - fsevents: 2.3.3 - jiti: 2.6.1 - less: 4.2.0 - lightningcss: 1.32.0 - sass: 1.80.6 - terser: 5.36.0 - tsx: 4.21.0 - - vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0): + vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0): dependencies: lightningcss: 1.32.0 picomatch: 4.0.4 - postcss: 8.5.10 - rolldown: 1.0.0-rc.15 - tinyglobby: 0.2.15 + postcss: 8.5.13 + rolldown: 1.0.0-rc.17 + tinyglobby: 0.2.16 optionalDependencies: - '@types/node': 24.12.2 - esbuild: 0.27.3 + '@types/node': 25.6.0 + esbuild: 0.27.7 fsevents: 2.3.3 jiti: 2.6.1 less: 4.2.0 @@ -6534,58 +5541,44 @@ snapshots: terser: 5.36.0 tsx: 4.21.0 - vitefu@1.1.1(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): + vitefu@1.1.3(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): optionalDependencies: - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - vitefu@1.1.3(vite@8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): - optionalDependencies: - vite: 8.0.8(@types/node@24.12.2)(esbuild@0.27.3)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) - - vitest-browser-svelte@2.0.2(svelte@5.49.2)(vitest@4.0.18): + vitest-browser-svelte@2.1.1(svelte@5.55.5(@typescript-eslint/types@8.59.1))(vitest@4.1.5): dependencies: - '@testing-library/svelte-core': 1.0.0(svelte@5.49.2) - svelte: 5.49.2 - vitest: 4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + '@testing-library/svelte-core': 1.0.0(svelte@5.55.5(@typescript-eslint/types@8.59.1)) + svelte: 5.55.5(@typescript-eslint/types@8.59.1) + vitest: 4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - vitest@4.0.18(@types/node@24.12.2)(@vitest/browser-playwright@4.0.18)(jiti@2.6.1)(jsdom@25.0.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0): + vitest@4.1.5(@types/node@25.6.0)(@vitest/browser-playwright@4.1.5)(jsdom@25.0.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)): dependencies: - '@vitest/expect': 4.0.18 - '@vitest/mocker': 4.0.18(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) - '@vitest/pretty-format': 4.0.18 - '@vitest/runner': 4.0.18 - '@vitest/snapshot': 4.0.18 - '@vitest/spy': 4.0.18 - '@vitest/utils': 4.0.18 - es-module-lexer: 1.7.0 + '@vitest/expect': 4.1.5 + '@vitest/mocker': 4.1.5(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0)) + '@vitest/pretty-format': 4.1.5 + '@vitest/runner': 4.1.5 + '@vitest/snapshot': 4.1.5 + '@vitest/spy': 4.1.5 + '@vitest/utils': 4.1.5 + es-module-lexer: 2.1.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 + picomatch: 4.0.4 + std-env: 4.1.0 tinybench: 2.9.0 - tinyexec: 1.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: 7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) + tinyexec: 1.1.2 + tinyglobby: 0.2.16 + tinyrainbow: 3.1.0 + vite: 8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0) why-is-node-running: 2.3.0 optionalDependencies: - '@types/node': 24.12.2 - '@vitest/browser-playwright': 4.0.18(playwright@1.58.1)(vite@7.3.1(@types/node@24.12.2)(jiti@2.6.1)(less@4.2.0)(lightningcss@1.32.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.0.18) + '@types/node': 25.6.0 + '@vitest/browser-playwright': 4.1.5(playwright@1.59.1)(vite@8.0.10(@types/node@25.6.0)(esbuild@0.27.7)(jiti@2.6.1)(less@4.2.0)(sass@1.80.6)(terser@5.36.0)(tsx@4.21.0))(vitest@4.1.5) jsdom: 25.0.1 transitivePeerDependencies: - - jiti - - less - - lightningcss - msw - - sass - - sass-embedded - - stylus - - sugarss - - terser - - tsx - - yaml w3c-xmlserializer@5.0.0: dependencies: @@ -6626,9 +5619,9 @@ snapshots: dependencies: ansi-styles: 6.2.3 string-width: 7.2.0 - strip-ansi: 7.1.2 + strip-ansi: 7.2.0 - ws@8.19.0: {} + ws@8.20.0: {} xml-name-validator@5.0.0: optional: true @@ -6638,7 +5631,7 @@ snapshots: y18n@5.0.8: {} - yaml@1.10.2: {} + yaml@1.10.3: {} yargs-parser@22.0.0: {} @@ -6658,4 +5651,4 @@ snapshots: zimmerframe@1.1.4: {} - zod@4.3.6: {} + zod@4.4.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index bd46379..8494999 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,11 +2,12 @@ packages: - app - packages/* - nodes/** - - "!**/.template/**" - - "!**/pkg/**" + - '!**/.template/**' + - '!**/pkg/**' catalog: chokidar-cli: github:open-cli-tools/chokidar-cli#semver:v4.0.0 + onlyBuiltDependencies: - - "@tailwindcss/oxide" + - '@tailwindcss/oxide' - esbuild -- 2.52.0 From 703f531cd370c2d440a696a68413ea6d5f54019f Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 16:11:21 +0200 Subject: [PATCH 29/44] chore: make eslint and playwright happy --- .../main.test.ts-snapshots/test-1-linux.png | Bin 43588 -> 48205 bytes .../lib/graph-interface/graph/Wrapper.svelte | 1 + app/src/lib/result-viewer/geometryPool.ts | 1 - app/src/lib/sidebar/Sidebar.svelte | 1 + packages/ui/src/routes/ThemeSelector.svelte | 1 + 5 files changed, 3 insertions(+), 1 deletion(-) diff --git a/app/e2e/main.test.ts-snapshots/test-1-linux.png b/app/e2e/main.test.ts-snapshots/test-1-linux.png index bbafab1f3048215ab6d83dd60db4390a096aadea..bb17c17a4c2591bb267e9b8f176b1e5455d2a674 100644 GIT binary patch literal 48205 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 pBhz(N23 literal 43588 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 diff --git a/app/src/lib/graph-interface/graph/Wrapper.svelte b/app/src/lib/graph-interface/graph/Wrapper.svelte index 8b5fb7b..f56c481 100644 --- a/app/src/lib/graph-interface/graph/Wrapper.svelte +++ b/app/src/lib/graph-interface/graph/Wrapper.svelte @@ -28,6 +28,7 @@ graph, registry, safePadding, + // eslint-disable-next-line no-useless-assignment settings = $bindable(), activeNode = $bindable(), backgroundType = $bindable('grid'), diff --git a/app/src/lib/result-viewer/geometryPool.ts b/app/src/lib/result-viewer/geometryPool.ts index be22378..c2438f4 100644 --- a/app/src/lib/result-viewer/geometryPool.ts +++ b/app/src/lib/result-viewer/geometryPool.ts @@ -80,7 +80,6 @@ export function createGeometryPool(parentScene: Group, material: Material) { } const normals = new Float32Array(data.buffer, index * 4, vertexCount * 3); - index = index + vertexCount * 3; if ( geometry.userData?.faceCount !== faceCount diff --git a/app/src/lib/sidebar/Sidebar.svelte b/app/src/lib/sidebar/Sidebar.svelte index 1d5c2dd..b1cc1be 100644 --- a/app/src/lib/sidebar/Sidebar.svelte +++ b/app/src/lib/sidebar/Sidebar.svelte @@ -2,6 +2,7 @@ import { type Snippet } from 'svelte'; import { panelState as state } from './PanelState.svelte'; + // eslint-disable-next-line no-useless-assignment let { children, open = $bindable(false) } = $props<{ children?: Snippet; open?: boolean }>(); $effect(() => { diff --git a/packages/ui/src/routes/ThemeSelector.svelte b/packages/ui/src/routes/ThemeSelector.svelte index 85255b5..c01ac95 100644 --- a/packages/ui/src/routes/ThemeSelector.svelte +++ b/packages/ui/src/routes/ThemeSelector.svelte @@ -12,6 +12,7 @@ 'custom' ]; + // eslint-disable-next-line no-useless-assignment let { theme = $bindable() } = $props(); let themeIndex = $state(0); -- 2.52.0 From 1a56ba986d761be545c2cf0236f9c374222da6b1 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 16:14:20 +0200 Subject: [PATCH 30/44] damn dude --- pnpm-workspace.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index 8494999..5c0a872 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -2,12 +2,12 @@ packages: - app - packages/* - nodes/** - - '!**/.template/**' - - '!**/pkg/**' + - "!**/.template/**" + - "!**/pkg/**" catalog: chokidar-cli: github:open-cli-tools/chokidar-cli#semver:v4.0.0 onlyBuiltDependencies: - - '@tailwindcss/oxide' + - "@tailwindcss/oxide" - esbuild -- 2.52.0 From 106797de32f0d57059c481770e734b555900421d Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 19:11:52 +0200 Subject: [PATCH 31/44] feat: make group input/output node work --- .../graph-interface/graph-manager.svelte.ts | 30 ++++- .../lib/graph-interface/graph-state.svelte.ts | 7 + .../lib/graph-interface/graph/Graph.svelte | 45 +++++++ .../graph-interface/helpers/nodeHelpers.ts | 4 + .../graph-interface/node/NodeHeader.svelte | 21 +-- .../graph-interface/node/NodeParameter.svelte | 33 ++++- app/src/lib/node-registry/debugNode.ts | 3 + .../sidebar/panels/ActiveNodeSelected.svelte | 2 - .../sidebar/panels/ActiveNodeSettings.svelte | 94 +------------- .../lib/sidebar/panels/GroupSettings.svelte | 120 ++++++++++++++++++ app/src/routes/+page.svelte | 5 +- packages/ui/src/lib/JsonViewer.svelte | 4 +- 12 files changed, 255 insertions(+), 113 deletions(-) create mode 100644 app/src/lib/sidebar/panels/GroupSettings.svelte diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 75dfb85..9ec0566 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -69,7 +69,7 @@ export class GraphManager extends EventEmitter<{ status = $state<'loading' | 'idle' | 'error'>(); loaded = false; - graph: Graph = { id: 0, nodes: [], edges: [], groups: [] }; + graph: Graph = $state({ id: 0, nodes: [], edges: [], groups: [] }); id = $state(0); nodes = new SvelteMap(); @@ -495,9 +495,24 @@ export class GraphManager extends EventEmitter<{ const groupId = this.graphStack.at(-1)?.groupId; const group = groupId !== undefined ? this.getGroup(groupId) : undefined; if (!group) return node.state.type; + + const groupInputs: NodeDefinition['inputs'] = Object.fromEntries( + Object.values(group?.inputs || {}).map((o, i) => { + return [ + `in_${i}`, + { + ...o, + external: true + } + ]; + }) || [] + ); return { id: '__internal/group/input' as NodeId, - outputs: Object.values(group.inputs ?? {}).map(i => i.type), + meta: { + title: 'Group Input' + }, + inputs: groupInputs, execute: (x: Int32Array) => x } as NodeDefinition; } @@ -514,6 +529,9 @@ export class GraphManager extends EventEmitter<{ i ) => [`out_${i}`, { type: o.type, label: o.label, external: true }]) ), + meta: { + title: 'Group Output' + }, outputs: [], execute: (x: Int32Array) => x } as NodeDefinition; @@ -1007,7 +1025,9 @@ export class GraphManager extends EventEmitter<{ const toType = this.getNodeType(to); // check if socket types match - const fromSocketType = fromType?.outputs?.[fromSocket]; + const fromSocketType = from.type === '__internal/group/input' + ? fromType?.inputs?.[Object.keys(fromType?.inputs || {})[fromSocket]].type + : fromType?.outputs?.[fromSocket]; const toSocketType = [toType?.inputs?.[toSocket]?.type]; if (toType?.inputs?.[toSocket]?.accepts) { toSocketType.push(...(toType?.inputs?.[toSocket]?.accepts || [])); @@ -1179,7 +1199,9 @@ export class GraphManager extends EventEmitter<{ } }); - const ownType = nodeType.outputs?.[index]; + const ownType = node.type === '__internal/group/input' + ? nodeType.inputs?.[Object.keys(nodeType?.inputs || {})[index]].type + : nodeType.outputs?.[index]; for (const node of nodes) { const inputs = this.getNodeType(node)?.inputs; diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index 37e820b..1146e99 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -384,6 +384,13 @@ export class GraphState { node: NodeInstance, index: string | number ): [number, number] { + if (node.type === '__internal/group/input' && typeof index === 'number') { + return [ + (node?.state?.x ?? node.position[0]) + 20, + (node?.state?.y ?? node.position[1]) + 2.5 + 5 * index + 5 + ]; + } + if (typeof index === 'number') { return [ (node?.state?.x ?? node.position[0]) + 20, diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index e2e6744..352791c 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -100,8 +100,22 @@ if (typeof index === 'string') { return nodeType?.inputs?.[index].type || 'unknown'; } + + if (node.type === '__internal/group/input') { + const key = Object.keys(nodeType?.inputs || {})[index]; + return nodeType?.inputs?.[key].type || 'unknown'; + } + return nodeType?.outputs?.[index] || 'unknown'; } + + function getGroupName() { + const groupId = graph.graphStack.at(-1)?.groupId; + if (groupId !== undefined) { + const group = graph.getGroup(groupId); + return group?.name || `Group#${groupId}`; + } + } keymap.handleKeyboardEvent(ev)} onmousedown={(ev) => mouseEvents.handleMouseDown(ev)} oncontextmenu={(ev) => mouseEvents.handleContextMenu(ev)} {...fileDropEvents.getEventListenerProps()} > +
graphState.exitGroupNode()}> ↑ Exit Group +

+ Group {getGroupName()} +

{/if} @@ -250,6 +270,15 @@ height: 100%; } + .group-name { + position: absolute; + left: calc(50% - var(--padding-right) / 2); + transition: left 0.3s ease; + top: 12px; + transform: translateX(-50%); + z-index: 1000; + } + .exit-group { position: absolute; top: 12px; @@ -280,6 +309,22 @@ cursor: pointer; } + .shadow { + position: absolute; + top: -5px; + left: -5px; + right: calc(var(--padding-right) - 5px); + bottom: -5px; + z-index: 1; + transition: box-shadow 0.3s ease; + box-shadow: 0 0 0px 0px var(--color-layer-2) inset; + pointer-events: none; + } + + .is-inside-group .shadow { + box-shadow: 0 0 0px 8px var(--color-layer-2) inset; + } + .is-panning { cursor: grab; } diff --git a/app/src/lib/graph-interface/helpers/nodeHelpers.ts b/app/src/lib/graph-interface/helpers/nodeHelpers.ts index 57bc166..7e1c149 100644 --- a/app/src/lib/graph-interface/helpers/nodeHelpers.ts +++ b/app/src/lib/graph-interface/helpers/nodeHelpers.ts @@ -1,6 +1,10 @@ import type { NodeDefinition } from '@nodarium/types'; export function getParameterHeight(node: NodeDefinition, inputKey: string) { + if (node.id === '__internal/group/input') { + return 50; + } + const input = node.inputs?.[inputKey]; if (!input) { return 0; diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte index 9bb56a2..a292c74 100644 --- a/app/src/lib/graph-interface/node/NodeHeader.svelte +++ b/app/src/lib/graph-interface/node/NodeHeader.svelte @@ -23,7 +23,10 @@ const cornerTop = 10; const nodeType = $derived(graph.getNodeType(node)); - const rightBump = $derived(!!nodeType?.outputs?.length); + const rightBump = $derived( + !!nodeType?.outputs?.length && node.type !== '__internal/group/input' + ); + const aspectRatio = 0.25; const path = $derived( @@ -73,13 +76,15 @@ {/if} {nodeType?.meta?.title || node.type?.split('/').pop()}
-
-
+ {#if rightBump} +
+
+ {/if} key === id); + graphState.setDownSocket({ + node, + index: outputIndex, + position: graphState.getSocketPosition(node, outputIndex) + }); + } else { + graphState.setDownSocket({ + node, + index: id, + position: graphState.getSocketPosition(node, id) + }); + } } - const leftBump = $derived(nodeType.inputs?.[id].internal !== true); + const leftBump = $derived( + nodeType.inputs?.[id].internal !== true && node.type !== '__internal/group/input' + ); + const rightBump = $derived(node.type === '__internal/group/input'); const cornerBottom = $derived(isLast ? 5 : 0); const aspectRatio = 0.5; @@ -46,6 +59,7 @@ height: 2000 / height, y: 50.5, cornerBottom, + rightBump, leftBump, aspectRatio }) @@ -55,6 +69,7 @@ depth: 7, height: 2200 / height, y: 50.5, + rightBump, cornerBottom, leftBump, aspectRatio @@ -76,6 +91,7 @@
-{:else} -

Node has no settings

{/if} diff --git a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte index 49d1da4..e5ece84 100644 --- a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte +++ b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte @@ -11,97 +11,11 @@ let { manager, node = $bindable() }: Props = $props(); const isGroupInstance = $derived(node?.type === '__internal/group/instance'); - const activeGroup = $derived( - isGroupInstance ? manager.getGroup(node!.props?.groupId as number) : undefined - ); - - const groupName = $derived(activeGroup?.name ?? ''); - - function handleRename(e: Event) { - const name = (e.target as HTMLInputElement).value; - if (activeGroup) manager.renameGroup(activeGroup.id, name); - } -
-

Node Settings

-
- -{#if node} - {#key node.id} - {#if isGroupInstance && activeGroup} -
- - -
- {:else if node} - - {/if} - {/key} -{:else} -

No node selected

-{/if} - -{#if manager?.graph.groups.length} -
- +{#if node && !isGroupInstance} +
+

Node Settings

+ {/if} - - diff --git a/app/src/lib/sidebar/panels/GroupSettings.svelte b/app/src/lib/sidebar/panels/GroupSettings.svelte new file mode 100644 index 0000000..c285adb --- /dev/null +++ b/app/src/lib/sidebar/panels/GroupSettings.svelte @@ -0,0 +1,120 @@ + + +{#if activeGroup || hasUnusedGroups} +
+

Group Settings

+
+{/if} + +{#if activeGroup} + {#key activeGroup.id} +
+ + +
+ {/key} +{/if} + +{#if hasUnusedGroups} +
+ +
+{/if} + + diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index ccc4fb7..677b908 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -21,6 +21,7 @@ import Changelog from '$lib/sidebar/panels/Changelog.svelte'; import ExportSettings from '$lib/sidebar/panels/ExportSettings.svelte'; import GraphSource from '$lib/sidebar/panels/GraphSource.svelte'; + import GroupSettings from '$lib/sidebar/panels/GroupSettings.svelte'; import Keymap from '$lib/sidebar/panels/Keymap.svelte'; import { panelState } from '$lib/sidebar/PanelState.svelte'; import Sidebar from '$lib/sidebar/Sidebar.svelte'; @@ -258,7 +259,7 @@ graph={pm.graph} bind:this={graphInterface} registry={nodeRegistry} - safePadding={{ right: sidebarOpen ? 330 : undefined }} + safePadding={{ right: sidebarOpen ? 320 : undefined }} backgroundType={appSettings.value.nodeInterface.backgroundType} snapToGrid={appSettings.value.nodeInterface.snapToGrid} bind:activeNode @@ -336,12 +337,14 @@ title="Graph Settings" icon="i-[custom--graph] bg-blue-400" > + + - import { SvelteMap } from 'svelte/reactivity'; - const cache = new SvelteMap>(); + // eslint-disable-next-line svelte/prefer-svelte-reactivity + const cache = new Map>(); function getStore(root: string): Record { if (!cache.has(root)) { -- 2.52.0 From 83e0e47082ed0d9fbd60e67a6d6c9ed65a9f4f24 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 23:47:03 +0200 Subject: [PATCH 32/44] refactor: only show group/node panel when selected --- .../graph-interface/graph-manager.svelte.ts | 2 +- app/src/lib/node-registry/debugNode.ts | 3 +- .../sidebar/panels/ActiveNodeSelected.svelte | 99 ------------------- .../sidebar/panels/ActiveNodeSettings.svelte | 92 ++++++++++++++++- .../lib/sidebar/panels/GroupSettings.svelte | 2 - app/src/routes/+page.svelte | 6 +- 6 files changed, 94 insertions(+), 110 deletions(-) delete mode 100644 app/src/lib/sidebar/panels/ActiveNodeSelected.svelte diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 9ec0566..006f9a0 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -556,7 +556,7 @@ export class GraphManager extends EventEmitter<{ const inputs = { 'groupId': { type: 'select', - label: 'Group', + label: '', value: node.props?.groupId, internal: true, options: this.graph.groups.map((g, i) => ({ diff --git a/app/src/lib/node-registry/debugNode.ts b/app/src/lib/node-registry/debugNode.ts index 6ab2955..e2fcaf2 100644 --- a/app/src/lib/node-registry/debugNode.ts +++ b/app/src/lib/node-registry/debugNode.ts @@ -5,7 +5,8 @@ export const debugNode = { }, inputs: { input: { - type: '*' + type: '*', + label: '' } }, execute(_data: Int32Array): Int32Array { diff --git a/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte b/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte deleted file mode 100644 index 4f253b5..0000000 --- a/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte +++ /dev/null @@ -1,99 +0,0 @@ - - -{#if Object.keys(nodeDefinition).length} - -{/if} diff --git a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte index e5ece84..d32e847 100644 --- a/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte +++ b/app/src/lib/sidebar/panels/ActiveNodeSettings.svelte @@ -1,21 +1,103 @@ -{#if node && !isGroupInstance} +{#if !isGroupInstance && Object.keys(nodeDefinition).length}

Node Settings

- + {/if} diff --git a/app/src/lib/sidebar/panels/GroupSettings.svelte b/app/src/lib/sidebar/panels/GroupSettings.svelte index c285adb..1d5a7d1 100644 --- a/app/src/lib/sidebar/panels/GroupSettings.svelte +++ b/app/src/lib/sidebar/panels/GroupSettings.svelte @@ -10,10 +10,8 @@ const { manager, node = $bindable() }: Props = $props(); const activeGroup = $derived.by(() => { - console.log('isInsideGroup', manager?.isInsideGroup); if (manager?.isInsideGroup) { const activeGroupId = manager.graphStack?.at(-1)?.groupId; - console.log('activeGroupId', activeGroupId); if (activeGroupId !== undefined) { return manager.getGroup(activeGroupId); } diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 677b908..479b31b 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -343,8 +343,10 @@ type={graphSettingTypes} bind:value={graphSettings} /> - - + {#key activeNode} + + + {/key}
Date: Mon, 4 May 2026 23:47:29 +0200 Subject: [PATCH 33/44] fix: broken format command for @nodarium/planty --- packages/planty/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/planty/package.json b/packages/planty/package.json index a283448..e977d94 100644 --- a/packages/planty/package.json +++ b/packages/planty/package.json @@ -10,8 +10,8 @@ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", "lint": "eslint .", - "format": "dprint fmt -c '../.dprint.jsonc' .", - "format:check": "dprint check -c '../.dprint.jsonc' ." + "format": "dprint fmt -c '../../.dprint.jsonc' .", + "format:check": "dprint check -c '../../.dprint.jsonc' ." }, "files": [ "dist", -- 2.52.0 From 85e2fd1a7126aab4a544eea3d185cfc63754cb73 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Mon, 4 May 2026 23:54:43 +0200 Subject: [PATCH 34/44] fix: use correct id for debug node --- app/src/lib/node-registry/debugNode.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/lib/node-registry/debugNode.ts b/app/src/lib/node-registry/debugNode.ts index e2fcaf2..8292d44 100644 --- a/app/src/lib/node-registry/debugNode.ts +++ b/app/src/lib/node-registry/debugNode.ts @@ -1,5 +1,5 @@ export const debugNode = { - id: '__internal/debug/instance', + id: '__internal/node/debug', meta: { title: 'Debug' }, -- 2.52.0 From bff140a764ff0b6ed2c6e42814a088ca9e2ef1ee Mon Sep 17 00:00:00 2001 From: Max Richter Date: Tue, 5 May 2026 11:11:33 +0200 Subject: [PATCH 35/44] feat: show different ui when inside group --- .../lib/graph-interface/graph-manager.svelte.ts | 6 +++--- app/src/lib/graph-interface/graph/Graph.svelte | 13 ++++++------- app/src/lib/settings/NestedSettings.svelte | 7 +++++++ app/src/lib/sidebar/panels/GroupSettings.svelte | 17 +++++++++++++++++ app/src/routes/+page.svelte | 2 +- 5 files changed, 34 insertions(+), 11 deletions(-) diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 006f9a0..e588e7a 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -559,9 +559,9 @@ export class GraphManager extends EventEmitter<{ label: '', value: node.props?.groupId, internal: true, - options: this.graph.groups.map((g, i) => ({ + options: this.graph.groups.map((g) => ({ value: g.id, - label: g.name || `Group ${i + 1}` + label: g.name || `Group#${g.id}` })) }, ...defaultInputs @@ -863,7 +863,7 @@ export class GraphManager extends EventEmitter<{ inputs[`input_${i}`] = input as NodeInput; }); - const outputs = [...groupOutputs.values()].map((edge, i) => ({ + const outputs = [groupOutputs.values().next().value!].map((edge, i) => ({ label: `Output ${i}`, type: edge[2].state.type?.inputs?.[edge[3]].type || '*' })); diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index 352791c..d724edf 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -154,8 +154,11 @@ {#if graph.isInsideGroup} -

Group {getGroupName()} @@ -283,13 +286,9 @@ position: absolute; top: 12px; left: 12px; - z-index: 1000; - padding: 4px 12px; - background: var(--color-layer-2); + z-index: 10; border: 1px solid var(--stroke); border-radius: 4px; - color: inherit; - font-size: 0.85em; cursor: pointer; opacity: 0.85; } diff --git a/app/src/lib/settings/NestedSettings.svelte b/app/src/lib/settings/NestedSettings.svelte index af2aa3c..8e159e6 100644 --- a/app/src/lib/settings/NestedSettings.svelte +++ b/app/src/lib/settings/NestedSettings.svelte @@ -204,6 +204,13 @@ .input-boolean > label { order: 2; + font-size: 1em; + opacity: 0.9; + } + + label { + font-size: 0.8em; + opacity: 0.7; } .first-level.input { diff --git a/app/src/lib/sidebar/panels/GroupSettings.svelte b/app/src/lib/sidebar/panels/GroupSettings.svelte index 1d5a7d1..88f2182 100644 --- a/app/src/lib/sidebar/panels/GroupSettings.svelte +++ b/app/src/lib/sidebar/panels/GroupSettings.svelte @@ -1,6 +1,7 @@ + +

+ +{#if graph.isInsideGroup} +
+ + {#each graph.graphStack as group (group.groupId)} + + + {/each} +
+{/if} + + diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index e588e7a..b4b0713 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -1,3 +1,4 @@ +import { clone } from '$lib/helpers'; import throttle from '$lib/helpers/throttle'; import { RemoteNodeRegistry } from '$lib/node-registry/index'; import type { @@ -16,6 +17,12 @@ import { fastHashString } from '@nodarium/utils'; import { createLogger } from '@nodarium/utils'; import { SvelteMap, SvelteSet } from 'svelte/reactivity'; import EventEmitter from './helpers/EventEmitter'; +import { + areEdgesEqual, + areSocketsCompatible, + serializeEdge, + serializeNode +} from './helpers/nodeHelpers'; import { HistoryManager } from './history-manager'; const logger = createLogger('graph-manager'); @@ -23,41 +30,6 @@ logger.mute(); const remoteRegistry = new RemoteNodeRegistry(''); -const clone = 'structuredClone' in globalThis - ? globalThis.structuredClone - : (args: unknown) => JSON.parse(JSON.stringify(args)); - -function areSocketsCompatible( - output: string | undefined, - inputs: string | (string | undefined)[] | undefined -) { - if (output === '*') return true; - if (Array.isArray(inputs) && output) { - return inputs.includes('*') || inputs.includes(output); - } - return inputs === output; -} - -function areEdgesEqual(firstEdge: Edge, secondEdge: Edge) { - if (firstEdge[0].id !== secondEdge[0].id) { - return false; - } - - if (firstEdge[1] !== secondEdge[1]) { - return false; - } - - if (firstEdge[2].id !== secondEdge[2].id) { - return false; - } - - if (firstEdge[3] !== secondEdge[3]) { - return false; - } - - return true; -} - export class GraphManager extends EventEmitter<{ save: Graph; result: unknown; @@ -129,26 +101,11 @@ export class GraphManager extends EventEmitter<{ } serialize(): Graph { - const nodes = Array.from(this.nodes.values()).map((node) => ({ - id: node.id, - position: [...node.position], - type: node.type, - props: node.props - })) as NodeInstance[]; - const edges = this.edges.map((edge) => [ - edge[0].id, - edge[1], - edge[2].id, - edge[3] - ]) as Graph['edges']; + const nodes = Array.from(this.nodes.values()).map((node) => serializeNode(node)); + const edges = this.edges.map((edge) => serializeEdge(edge)); const groups = this.graph.groups?.map((group) => { - const groupNodes = group.nodes.map((node) => ({ - id: node.id, - position: [...node.position], - type: node.type, - props: node.props - })) as NodeInstance[]; + const groupNodes = group.nodes.map((node) => serializeNode(node)); return { id: group.id, @@ -814,12 +771,39 @@ export class GraphManager extends EventEmitter<{ return nodes; } + getUnusedGroups() { + const usedGroupIds = new SvelteSet(); + const queue: number[] = []; + + for (const node of this.nodes.values()) { + if (node.type === '__internal/group/instance' && node.props?.groupId !== undefined) { + queue.push(node.props.groupId as number); + } + } + + while (queue.length) { + const groupId = queue.pop()!; + if (usedGroupIds.has(groupId)) continue; + usedGroupIds.add(groupId); + const group = this.getGroup(groupId); + if (!group) continue; + for (const node of group.nodes) { + if (node.type === '__internal/group/instance' && node.props?.groupId !== undefined) { + const childId = node.props.groupId as number; + if (!usedGroupIds.has(childId)) queue.push(childId); + } + } + } + + return this.graph.groups.filter(g => !usedGroupIds.has(g.id)); + } + removeUnusedGroups() { - const usedGroups = new SvelteSet(this.getAllNodes().map(n => n.props?.groupId)); - const unusedGroupAmount = this.graph.groups.length - usedGroups.size; - this.graph.groups = this.graph.groups.filter(g => usedGroups.has(g.id)); + const unused = this.getUnusedGroups(); + const unusedIds = new SvelteSet(unused.map(g => g.id)); + this.graph.groups = this.graph.groups.filter(g => !unusedIds.has(g.id)); this.save(); - return unusedGroupAmount; + return unused.length; } groupNodes(nodeIds: number[]) { @@ -863,10 +847,14 @@ export class GraphManager extends EventEmitter<{ inputs[`input_${i}`] = input as NodeInput; }); - const outputs = [groupOutputs.values().next().value!].map((edge, i) => ({ - label: `Output ${i}`, - type: edge[2].state.type?.inputs?.[edge[3]].type || '*' - })); + const outputs = []; + if (groupOutputs.size) { + const edge = groupOutputs.values().next().value!; + outputs.push({ + label: `Output`, + type: edge[2].state.type?.inputs?.[edge[3]].type || '*' + }); + } const groupPosition = [0, 0] as [number, number]; const bounds: Box = { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity }; diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index d724edf..f66defd 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -7,6 +7,7 @@ import AddMenu from '../components/AddMenu.svelte'; import BoxSelection from '../components/BoxSelection.svelte'; import Camera from '../components/Camera.svelte'; + import GroupBreadcrumps from '../components/GroupBreadcrumps.svelte'; import HelpView from '../components/HelpView.svelte'; import Debug from '../debug/Debug.svelte'; import EdgeEl from '../edges/Edge.svelte'; @@ -109,13 +110,15 @@ return nodeType?.outputs?.[index] || 'unknown'; } - function getGroupName() { - const groupId = graph.graphStack.at(-1)?.groupId; - if (groupId !== undefined) { - const group = graph.getGroup(groupId); - return group?.name || `Group#${groupId}`; + let groupSize = 0; + $effect(() => { + if (graph.graph.groups.length > groupSize) { + groupSize = graph.graph.groups.length; } - } + if (graph.graph.groups.length < groupSize) { + console.error('We have lost a group!'); + } + }); mouseEvents.handleContextMenu(ev)} {...fileDropEvents.getEventListenerProps()} > -
- {#if graph.isInsideGroup} - -

- Group {getGroupName()} -

- {/if} + = {}; export function getNodeHeight(node: NodeDefinition) { if (!node || !('inputs' in node)) { @@ -45,3 +64,34 @@ export function getNodeHeight(node: NodeDefinition) { nodeHeightCache[node.id] = height; return height; } + +export function areSocketsCompatible( + output: string | undefined, + inputs: string | (string | undefined)[] | undefined +) { + if (output === '*') return true; + if (Array.isArray(inputs) && output) { + return inputs.includes('*') || inputs.includes(output); + } + return inputs === output; +} + +export function areEdgesEqual(firstEdge: Edge, secondEdge: Edge) { + if (firstEdge[0].id !== secondEdge[0].id) { + return false; + } + + if (firstEdge[1] !== secondEdge[1]) { + return false; + } + + if (firstEdge[2].id !== secondEdge[2].id) { + return false; + } + + if (firstEdge[3] !== secondEdge[3]) { + return false; + } + + return true; +} diff --git a/app/src/lib/sidebar/panels/GroupSettings.svelte b/app/src/lib/sidebar/panels/GroupSettings.svelte index 88f2182..5ffff60 100644 --- a/app/src/lib/sidebar/panels/GroupSettings.svelte +++ b/app/src/lib/sidebar/panels/GroupSettings.svelte @@ -2,6 +2,7 @@ import type { GraphManager } from '$lib/graph-interface/graph-manager.svelte'; import type { NodeInstance } from '@nodarium/types'; import InputSelect from '../../../../../packages/ui/src/lib/inputs/InputSelect.svelte'; + import UnusedGroupsPanel from './UnusedGroupsPanel.svelte'; type Props = { manager: GraphManager; @@ -28,18 +29,9 @@ const name = (e.target as HTMLInputElement).value; if (activeGroup) manager.renameGroup(activeGroup.id, name); } - - const hasUnusedGroups = $derived.by(() => { - if (!manager) return false; - if (manager.isInsideGroup) return false; - if (manager.graph.groups.length === 0) return false; - return manager.graph.groups.filter(g => { - return !manager.graph.nodes.find(n => n.props?.groupId === g.id); - }).length; - }); -{#if activeGroup || hasUnusedGroups} +{#if activeGroup}

Group Settings

@@ -76,12 +68,8 @@ {/key} {/if} -{#if hasUnusedGroups} -
- -
+{#if manager && !manager.isInsideGroup} + {/if} diff --git a/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte b/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte new file mode 100644 index 0000000..d2f2799 --- /dev/null +++ b/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte @@ -0,0 +1,134 @@ + + +{#if unusedTree.length} +
+
+ Unused groups + +
+ +
    + {#snippet treeNode(node: GroupNode)} +
  • + {node.group.name || `Group #${node.group.id}`} + {#if node.children.length} +
      + {#each node.children as child (child.group.id)} + {@render treeNode(child)} + {/each} +
    + {/if} +
  • + {/snippet} + {#each unusedTree as node (node.group.id)} + {@render treeNode(node)} + {/each} +
+
+{/if} + + diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts index 374cc5d..31cb6bb 100644 --- a/packages/types/src/index.ts +++ b/packages/types/src/index.ts @@ -8,6 +8,7 @@ export type { NodeDefinition, NodeId, NodeInstance, + SerializedEdge, SerializedNode, Socket } from './types'; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index 878f9b5..2a5f7fe 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -76,6 +76,10 @@ export type Socket = { export type Edge = [NodeInstance, number, NodeInstance, string]; +const SerializedEdgeSchema = z.tuple([z.number(), z.number(), z.number(), z.string()]); + +export type SerializedEdge = z.infer; + export const GroupSchema = z.object({ id: z.number(), name: z.string().optional(), @@ -100,7 +104,7 @@ export const GraphSchema = z.object({ .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(SerializedEdgeSchema), groups: z.array(GroupSchema) }); -- 2.52.0 From ed1119532750d47a1395ced92fe310a6aa5e070e Mon Sep 17 00:00:00 2001 From: Max Richter Date: Tue, 5 May 2026 18:45:54 +0200 Subject: [PATCH 37/44] chore: refactor graphStack to be simpler --- .../components/GroupBreadcrumps.svelte | 23 +- .../graph-interface/graph-manager.svelte.ts | 317 +++++++++--------- .../graph-state.svelte.test.ts | 8 +- .../lib/graph-interface/graph/Wrapper.svelte | 5 +- .../graph-interface/helpers/nodeHelpers.ts | 8 +- app/src/lib/runtime/runtime-executor.ts | 28 +- .../lib/sidebar/panels/GroupSettings.svelte | 10 +- app/src/routes/+page.svelte | 36 +- 8 files changed, 243 insertions(+), 192 deletions(-) diff --git a/app/src/lib/graph-interface/components/GroupBreadcrumps.svelte b/app/src/lib/graph-interface/components/GroupBreadcrumps.svelte index 8601bf2..3a2409f 100644 --- a/app/src/lib/graph-interface/components/GroupBreadcrumps.svelte +++ b/app/src/lib/graph-interface/components/GroupBreadcrumps.svelte @@ -7,11 +7,16 @@ return group?.name || `Group#${groupId}`; } - function exitToGroup(groupId?: number) { - while (graph.graphStack.length > 0 && graph.graphStack.at(-1)?.groupId !== groupId) { + function exitToGroup(targetId?: number) { + while (graph.currentGroupId !== (targetId ?? null)) { graph.exitGroup(); } } + + // Intermediate groups: parent stack entries that are groups (not the root graph). + const intermediateGroups = $derived( + graph.parentStack.filter(e => e.id !== graph.id) + );
@@ -24,15 +29,23 @@ > Root - {#each graph.graphStack as group (group.groupId)} + + {#each intermediateGroups as entry (entry.id)} {/each} + + +
{/if} diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index b4b0713..ea022f9 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -11,6 +11,8 @@ import type { NodeInput, NodeInstance, NodeRegistry, + SerializedEdge, + SerializedNode, Socket } from '@nodarium/types'; import { fastHashString } from '@nodarium/utils'; @@ -25,8 +27,8 @@ import { } from './helpers/nodeHelpers'; import { HistoryManager } from './history-manager'; -const logger = createLogger('graph-manager'); -logger.mute(); +const log = createLogger('graph-manager'); +log.mute(); const remoteRegistry = new RemoteNodeRegistry(''); @@ -42,24 +44,26 @@ export class GraphManager extends EventEmitter<{ loaded = false; graph: Graph = $state({ id: 0, nodes: [], edges: [], groups: [] }); - id = $state(0); - nodes = new SvelteMap(); - nodeArray = $derived(Array.from(this.nodes.values())); - - edges = $state([]); - - // Plain array — NOT $state. rootGraph items are plain-serialized (safe for structuredClone). - // savedNodes/savedEdges hold live reactive references so reactivity is preserved on exit. - graphStack: { - rootGraph: Graph; - savedNodes: Map; - savedEdges: Edge[]; - outerGraph: Graph; - groupId: number; - nodeId: number; + // Snapshots of parent levels we navigated away from. Empty at root. + // Entry i has the saved state of depth i (0 = root graph, 1 = first group, …). + parentStack: { + id: number; + nodes: SerializedNode[]; + edges: SerializedEdge[]; cameraPosition: [number, number, number]; - }[] = []; + }[] = $state([]); + + // ID of the currently active group, or null when at the root graph. + currentGroupId = $state(null); + + // Graph Data + id = $state(0); + nodes = new SvelteMap(); + edges = $state([]); + groups: GroupDefinition[] = $state([]); + + nodeArray = $derived(Array.from(this.nodes.values())); settingTypes: Record = {}; settings = $state>(); @@ -76,24 +80,9 @@ export class GraphManager extends EventEmitter<{ history: HistoryManager = new HistoryManager(); - public serializeFullGraph(): Graph { - if (this.graphStack.length === 0) return this.serialize(); - let merged = this.serialize(); - for (let i = this.graphStack.length - 1; i >= 0; i--) { - const { rootGraph, groupId } = this.graphStack[i]; - merged = { - ...rootGraph, - groups: rootGraph.groups.map(g => - g.id === groupId ? { ...g, nodes: merged.nodes, edges: merged.edges } : g - ) - }; - } - return merged; - } - execute = throttle(() => { if (this.loaded === false) return; - this.emit('result', this.serializeFullGraph()); + this.emit('result', this.serialize()); }, 10); constructor(public registry: NodeRegistry) { @@ -101,32 +90,44 @@ export class GraphManager extends EventEmitter<{ } serialize(): Graph { - const nodes = Array.from(this.nodes.values()).map((node) => serializeNode(node)); - const edges = this.edges.map((edge) => serializeEdge(edge)); - - const groups = this.graph.groups?.map((group) => { - const groupNodes = group.nodes.map((node) => serializeNode(node)); + const nodes = + (this.parentStack.length === 0 ? Array.from(this.nodes.values()) : this.parentStack[0].nodes) + .map(n => serializeNode(n)); + const edges = + (this.parentStack.length === 0 ? Array.from(this.edges.values()) : this.parentStack[0].edges) + .map(e => serializeEdge(e)); + const groups = this.groups?.map((group) => { + const isCurrentActive = this.currentGroupId === group.id; + const stackState = this.parentStack.find((s) => s.id === group.id); + const groupNodes = + (isCurrentActive ? [...this.nodes.values()] : stackState?.nodes ?? group.nodes).map( + n => serializeNode(n) + ); + const groupEdges = + (isCurrentActive ? [...this.edges.values()] : stackState?.edges ?? group.edges).map( + e => serializeEdge(e) + ); return { id: group.id, name: group.name, inputs: group.inputs, outputs: group.outputs, nodes: groupNodes, - edges: group.edges + edges: groupEdges }; }); - const serialized = { - id: this.graph.id, - settings: $state.snapshot(this.settings), - meta: $state.snapshot(this.graph.meta), + const serialized = $state.snapshot({ + id: this.id, + settings: this.settings, + meta: this.graph.meta, groups, nodes, edges - }; - logger.log('serializing graph', serialized); - return clone($state.snapshot(serialized)); + }); + log.log('serializing graph', serialized); + return clone(serialized); } private lastSettingsHash = 0; @@ -190,7 +191,7 @@ export class GraphManager extends EventEmitter<{ ); if (!bestInputEntry || bestOutputIdx === -1) { - logger.error('Could not find compatible sockets for drop'); + log.error('Could not find compatible sockets for drop'); return; } @@ -296,21 +297,22 @@ export class GraphManager extends EventEmitter<{ return edges; } - private _init(graph: Graph) { - const nodes = new SvelteMap( - graph.nodes.map((node) => { - const n = node as NodeInstance; - const registryType = this.registry.getNode(node.type); - n.state = registryType ? { type: registryType } : {}; - const resolvedType = this.getNodeType(n); - if (resolvedType) n.state = { type: resolvedType }; - return [node.id, n]; - }) - ); + private _init( + graph: { nodes: SerializedNode[]; edges: SerializedEdge[] } + ) { + this.nodes.clear(); + for (const node of graph.nodes) { + const n = $state(node) as NodeInstance; + const registryType = this.registry.getNode(node.type); + n.state = registryType ? { type: registryType } : {}; + const resolvedType = this.getNodeType(n); + if (resolvedType) n.state = { type: resolvedType }; + this.nodes.set(n.id, n); + } this.edges = graph.edges.map((edge) => { - const from = nodes.get(edge[0]); - const to = nodes.get(edge[2]); + const from = this.nodes.get(edge[0]); + const to = this.nodes.get(edge[2]); if (!from || !to) { throw new Error('Edge references non-existing node'); } @@ -321,11 +323,6 @@ export class GraphManager extends EventEmitter<{ return [from, edge[1], to, edge[3]] as Edge; }); - this.nodes.clear(); - for (const [id, node] of nodes) { - this.nodes.set(id, node); - } - this.execute(); } @@ -334,11 +331,12 @@ export class GraphManager extends EventEmitter<{ this.loaded = false; graph.groups ??= []; + this.groups = graph.groups; this.graph = graph; this.status = 'loading'; this.id = graph.id; - logger.info( + log.info( 'loading graph', { nodes: graph.nodes, edges: graph.edges, id: graph.id } ); @@ -353,8 +351,7 @@ export class GraphManager extends EventEmitter<{ .filter(n => n && 'type' in n) .map((n) => n.type) ) - ) - .filter(n => !n.startsWith('__internal/')); + ); await this.registry.load(nodeIds); @@ -374,20 +371,7 @@ export class GraphManager extends EventEmitter<{ }); } - logger.info('loaded node types', this.registry.getAllNodes()); - - for (const node of this.graph.nodes) { - const nodeType = this.registry.getNode(node.type); - if (!nodeType && !node.type.startsWith('__internal/')) { - logger.error(`Node type not found: ${node.type}`); - this.status = 'error'; - return; - } - // Turn into runtime node - const n = node as NodeInstance; - n.state = {}; - n.state.type = nodeType; - } + log.info('loaded node types', this.registry.getAllNodes()); // load settings const settingTypes: Record< @@ -418,18 +402,18 @@ export class GraphManager extends EventEmitter<{ } } + this.parentStack = []; + this.currentGroupId = null; + this.settings = settingValues; this.emit('settings', { types: settingTypes, values: settingValues }); this.history.reset(); - this._init(this.graph); - + this._init(graph); this.save(); - this.status = 'idle'; - this.loaded = true; - logger.log(`Graph loaded in ${performance.now() - a}ms`); + log.log(`Graph loaded in ${performance.now() - a}ms`); setTimeout(() => this.execute(), 100); } @@ -449,19 +433,15 @@ export class GraphManager extends EventEmitter<{ } if (node.type === '__internal/group/input') { - const groupId = this.graphStack.at(-1)?.groupId; - const group = groupId !== undefined ? this.getGroup(groupId) : undefined; + const group = this.currentGroupId !== null ? this.getGroup(this.currentGroupId) : undefined; if (!group) return node.state.type; const groupInputs: NodeDefinition['inputs'] = Object.fromEntries( Object.values(group?.inputs || {}).map((o, i) => { - return [ - `in_${i}`, - { - ...o, - external: true - } - ]; + return [`in_${i}`, { + ...o, + external: true + }]; }) || [] ); return { @@ -475,8 +455,7 @@ export class GraphManager extends EventEmitter<{ } if (node.type === '__internal/group/output') { - const groupId = this.graphStack.at(-1)?.groupId; - const group = groupId !== undefined ? this.getGroup(groupId) : undefined; + const group = this.currentGroupId !== null ? this.getGroup(this.currentGroupId) : undefined; if (!group) return node.state.type; return { id: '__internal/group/output' as NodeId, @@ -499,7 +478,7 @@ export class GraphManager extends EventEmitter<{ const groupDefinition = this.getGroup(node.props?.groupId as number); if (!groupDefinition) { - logger.error(`Group not found: ${node.props?.groupId}`); + log.error(`Group not found: ${node.props?.groupId}`); return; } @@ -508,18 +487,24 @@ export class GraphManager extends EventEmitter<{ ...groupDefinition?.inputs }; - // This is to make sure the the groupId is always first delete defaultInputs['groupId']; + const inputs = { 'groupId': { type: 'select', label: '', value: node.props?.groupId, internal: true, - options: this.graph.groups.map((g) => ({ + options: this.groups.map((g) => ({ value: g.id, label: g.name || `Group#${g.id}` - })) + })).filter((g) => { + const activeIds = new SvelteSet([ + ...this.parentStack.filter(e => e.id !== this.id).map(e => e.id), + ...(this.currentGroupId !== null ? [this.currentGroupId] : []) + ]); + return !activeIds.has(g.value); + }) }, ...defaultInputs }; @@ -599,6 +584,7 @@ export class GraphManager extends EventEmitter<{ } removeNode(node: NodeInstance, { restoreEdges = false } = {}) { + log.log('removing node', { id: node.id, type: node.type, restoreEdges }); const edgesToNode = this.edges.filter((edge) => edge[2].id === node.id); const edgesFromNode = this.edges.filter((edge) => edge[0].id === node.id); for (const edge of [...edgesToNode, ...edgesFromNode]) { @@ -643,82 +629,69 @@ export class GraphManager extends EventEmitter<{ } getGroup(id: number) { - return this.graph.groups.find(g => g.id === id); + return this.groups.find(g => g.id === id); } renameGroup(groupId: number, name: string) { + log.log('renaming group', { groupId, name }); const group = this.getGroup(groupId); if (!group) return; group.name = name; this.save(); } - isInsideGroup = $state(false); + isInsideGroup = $derived(this.currentGroupId !== null); enterGroup(nodeId: number, cameraPosition: [number, number, number]): boolean { const groupNode = this.getNode(nodeId); if (!groupNode || groupNode.type !== '__internal/group/instance') return false; + + log.log('entering group', { nodeId, cameraPosition }); + const groupId = groupNode.props?.groupId as number; const group = this.getGroup(groupId); if (!group) return false; - this.graphStack.push({ - rootGraph: this.serialize(), - savedNodes: new SvelteMap(this.nodes), - savedEdges: [...this.edges], - outerGraph: this.graph, - groupId, - nodeId, + // Snapshot current level and push it onto the parent stack. + this.parentStack.push({ + id: this.currentGroupId ?? this.id, + nodes: [...this.nodes.values()].map(n => serializeNode(n)), + edges: [...this.edges.values()].map(e => serializeEdge(e)), cameraPosition }); - this.graph = { ...this.graph, nodes: group.nodes, edges: group.edges }; - this._init(this.graph); + this.currentGroupId = groupId; + + log.log('entered group', { groupId, depth: this.parentStack.length }); this.history.reset(); - this.isInsideGroup = true; + this._init(group); return true; } - exitGroup(): { camera: [number, number, number]; nodeId: number } | false { - if (!this.graphStack.length) return false; - const { savedNodes, savedEdges, outerGraph, groupId, nodeId, cameraPosition } = this.graphStack - .pop()!; - const internalState = this.serialize(); + exitGroup() { + log.log('exiting group', { depth: this.parentStack.length }); + if (this.parentStack.length === 0) return; - // Clear stale DOM/mesh refs so the remounting components register fresh ones. - // The $effect guards in NodeHTML/Node only set these when undefined, so without - // this clear they'd keep pointing to the detached elements from before group entry. - for (const node of savedNodes.values()) { - node.state.ref = undefined; - node.state.mesh = undefined; + // Persist live edits back to the GroupDefinition. + const group = this.getGroup(this.currentGroupId!); + if (group) { + group.nodes = [...this.nodes.values()].map(n => serializeNode(n)); + group.edges = [...this.edges.values()].map(e => serializeEdge(e)); } - // Restore live reactive nodes and edges so drag-reactivity is preserved - this.nodes.clear(); - for (const [id, node] of savedNodes) { - this.nodes.set(id, node); - } - this.edges = savedEdges; - - // Patch the group definition with the edited internal graph - this.graph = { - ...outerGraph, - groups: (outerGraph.groups ?? []).map(g => - g.id === groupId ? { ...g, nodes: internalState.nodes, edges: internalState.edges } : g - ) - }; + const parent = this.parentStack.pop()!; + this.currentGroupId = this.parentStack.length === 0 ? null : parent.id; + this._init(parent); this.history.reset(); - this.isInsideGroup = this.graphStack.length > 0; this.execute(); this.save(); - return { camera: cameraPosition, nodeId }; } createNodeId() { const ids = [ ...this.nodes.keys(), - ...this.graph.groups.map(g => g.id), - ...this.graph.groups.flatMap(g => g.nodes.map(n => n.id)) + ...this.groups.map(g => g.id), + ...this.groups.flatMap(g => g.nodes.map(n => n.id)) ]; let id = 0; @@ -775,12 +748,32 @@ export class GraphManager extends EventEmitter<{ const usedGroupIds = new SvelteSet(); const queue: number[] = []; - for (const node of this.nodes.values()) { + // Seed from root-level nodes so outer groups aren't treated as unused when inside a group. + const rootNodes = this.parentStack.length > 0 + ? this.parentStack[0].nodes + : [...this.nodes.values()]; + + for (const node of rootNodes) { if (node.type === '__internal/group/instance' && node.props?.groupId !== undefined) { queue.push(node.props.groupId as number); } } + // Also seed from live nodes (may contain new group instances created inside a group). + if (this.currentGroupId !== null) { + for (const node of this.nodes.values()) { + if (node.type === '__internal/group/instance' && node.props?.groupId !== undefined) { + queue.push(node.props.groupId as number); + } + } + } + + // Every group on the navigation path is used by definition. + for (const entry of this.parentStack) { + if (entry.id !== this.id) usedGroupIds.add(entry.id); + } + if (this.currentGroupId !== null) usedGroupIds.add(this.currentGroupId); + while (queue.length) { const groupId = queue.pop()!; if (usedGroupIds.has(groupId)) continue; @@ -795,13 +788,13 @@ export class GraphManager extends EventEmitter<{ } } - return this.graph.groups.filter(g => !usedGroupIds.has(g.id)); + return this.groups.filter(g => !usedGroupIds.has(g.id)); } removeUnusedGroups() { const unused = this.getUnusedGroups(); const unusedIds = new SvelteSet(unused.map(g => g.id)); - this.graph.groups = this.graph.groups.filter(g => !unusedIds.has(g.id)); + this.groups = this.groups.filter(g => !unusedIds.has(g.id)); this.save(); return unused.length; } @@ -816,7 +809,7 @@ export class GraphManager extends EventEmitter<{ if (!nodes.length) return; - logger.log(`Grouping ${nodes.length} nodes`, { nodes }); + log.log(`Grouping ${nodes.length} nodes`, { nodes }); const ids = new SvelteSet(nodes.map(n => n.id)); @@ -877,8 +870,8 @@ export class GraphManager extends EventEmitter<{ // Allocate all needed IDs up front so sequential calls never collide. const usedIds = new SvelteSet([ ...this.nodes.keys(), - ...this.graph.groups.map(g => g.id), - ...this.graph.groups.flatMap(g => g.nodes.map(n => n.id)) + ...this.groups.map(g => g.id), + ...this.groups.flatMap(g => g.nodes.map(n => n.id)) ]); const nextId = () => { let id = 0; @@ -925,7 +918,7 @@ export class GraphManager extends EventEmitter<{ }; // Push before createNode so createNodeId() inside sees the allocated IDs. - this.graph.groups.push(groupDefinition); + this.groups.push(groupDefinition); const groupNode = this.createNode({ type: '__internal/group/instance', @@ -972,7 +965,7 @@ export class GraphManager extends EventEmitter<{ }) { const nodeType = this.registry.getNode(type); if (!nodeType && !type.startsWith('__internal/')) { - logger.error(`Node type not found: ${type}`); + log.error(`Node type not found: ${type}`); return; } @@ -984,6 +977,7 @@ export class GraphManager extends EventEmitter<{ props }); + log.log('creating node', { id: node.id, type, position, props }); this.nodes.set(node.id, node); this.save(); @@ -1005,7 +999,7 @@ export class GraphManager extends EventEmitter<{ (e) => e[0].id === from.id && e[1] === fromSocket && e[3] === toSocket ); if (existingEdge) { - logger.error('Edge already exists', existingEdge); + log.error('Edge already exists', existingEdge); return; } @@ -1022,7 +1016,7 @@ export class GraphManager extends EventEmitter<{ } if (!areSocketsCompatible(fromSocketType, toSocketType)) { - logger.error( + log.error( `Socket types do not match: ${fromSocketType} !== ${toSocketType}` ); return; @@ -1037,6 +1031,7 @@ export class GraphManager extends EventEmitter<{ const edge = [from, fromSocket, to, toSocket] as Edge; + log.log('creating edge', { from: from.id, fromSocket, to: to.id, toSocket }); this.edges.push(edge); from.state.children = from.state.children || []; @@ -1053,6 +1048,7 @@ export class GraphManager extends EventEmitter<{ } undo() { + log.log('undo'); const nextState = this.history.undo(); if (nextState) { this._init(nextState); @@ -1061,6 +1057,7 @@ export class GraphManager extends EventEmitter<{ } redo() { + log.log('redo'); const nextState = this.history.redo(); if (nextState) { this._init(nextState); @@ -1088,9 +1085,9 @@ export class GraphManager extends EventEmitter<{ return; } - const fullState = this.graphStack.length > 0 ? this.serializeFullGraph() : state; + const fullState = this.serialize(); this.emit('save', fullState); - logger.log('saving graphs', fullState); + log.log('saving graphs', fullState); } getParentsOfNode(node: NodeInstance) { @@ -1098,7 +1095,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'); + log.warn('Infinite loop detected'); break; } const parent = stack.pop(); @@ -1215,6 +1212,12 @@ export class GraphManager extends EventEmitter<{ edge: Edge, { applyDeletion = true }: { applyDeletion?: boolean } = {} ) { + log.log('removing edge', { + from: edge[0].id, + fromSocket: edge[1], + to: edge[2].id, + toSocket: edge[3] + }); const id0 = edge[0].id; const sid0 = edge[1]; const id2 = edge[2].id; diff --git a/app/src/lib/graph-interface/graph-state.svelte.test.ts b/app/src/lib/graph-interface/graph-state.svelte.test.ts index a20a933..cf2bd95 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.test.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.test.ts @@ -97,7 +97,7 @@ describe('enterGroupNode', () => { const { manager, state } = createFixture(); state.activeNodeId = -1; state.enterGroupNode(); - expect(manager.graphStack.length).toBe(0); + expect(manager.parentStack.length).toBe(0); }); it('does nothing when the active node is not a group instance', () => { @@ -106,7 +106,7 @@ describe('enterGroupNode', () => { assert.isDefined(node); state.activeNodeId = node!.id; state.enterGroupNode(); - expect(manager.graphStack.length).toBe(0); + expect(manager.parentStack.length).toBe(0); }); it('enters the group, pushes graphStack, and clears UI state', () => { @@ -123,7 +123,7 @@ describe('enterGroupNode', () => { state.enterGroupNode(); - expect(manager.graphStack.length).toBe(1); + expect(manager.parentStack.length).toBe(1); expect(state.activeNodeId).toBe(-1); expect(state.selectedNodes.size).toBe(0); expect(manager.isInsideGroup).toBe(true); @@ -135,7 +135,7 @@ describe('exitGroupNode', () => { const { manager, state } = createFixture(); const before = [...state.cameraPosition]; state.exitGroupNode(); - expect(manager.graphStack.length).toBe(0); + expect(manager.parentStack.length).toBe(0); expect(state.cameraPosition).toEqual(before); }); diff --git a/app/src/lib/graph-interface/graph/Wrapper.svelte b/app/src/lib/graph-interface/graph/Wrapper.svelte index f56c481..7b3de2e 100644 --- a/app/src/lib/graph-interface/graph/Wrapper.svelte +++ b/app/src/lib/graph-interface/graph/Wrapper.svelte @@ -1,6 +1,7 @@ {#if activeGroup} @@ -39,7 +80,7 @@ {#if activeGroup} {#key activeGroup.id} -
+
Group Inputs
- {#each Object.keys(activeGroup?.inputs ?? {}) as key (key)} -
- - - -
- {/each} + +
+ + +
+ +
{/key} @@ -77,10 +133,9 @@ display: flex; flex-direction: column; gap: 0.4em; - padding: 1em; } - .group-settings label { + label { font-size: 0.8em; opacity: 0.7; } diff --git a/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte b/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte index d2f2799..b217532 100644 --- a/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte +++ b/app/src/lib/sidebar/panels/UnusedGroupsPanel.svelte @@ -48,7 +48,7 @@ {#if unusedTree.length} -
+
Unused groups