From c42bc93174d42dec719f61cbf6021cc8a3167fe6 Mon Sep 17 00:00:00 2001 From: Max Richter Date: Fri, 24 Apr 2026 21:45:56 +0200 Subject: [PATCH] feat: make it work --- .../graph-interface/graph-manager.svelte.ts | 12 ++--- .../lib/graph-interface/graph/Wrapper.svelte | 18 +++---- .../graph-interface/helpers/nodeHelpers.ts | 14 ++++++ app/src/lib/graph-interface/keymaps.ts | 12 ++--- .../lib/graph-interface/node/NodeHTML.svelte | 1 + .../graph-interface/node/NodeHeader.svelte | 18 +++---- .../graph-interface/node/NodeParameter.svelte | 47 +++++++++++++++++-- 7 files changed, 90 insertions(+), 32 deletions(-) diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 08d6419..4b5692c 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -94,7 +94,7 @@ export class GraphManager extends EventEmitter<{ groups = new SvelteMap(); groupNodeDefinitions: Map = new Map(); currentGroupContext: string | null = null; - graphStack: { rootGraph: Graph; groupId: string; cameraPosition: [number, number, number] }[] = $state([]); + graphStack: { rootGraph: Graph; groupId: string; nodeId: number; cameraPosition: [number, number, number] }[] = $state([]); inputSockets = $derived.by(() => { const s = new SvelteSet(); @@ -115,7 +115,7 @@ export class GraphManager extends EventEmitter<{ const { rootGraph, groupId } = $state.snapshot(this.graphStack[i]); // Prefer the live definition (may have been updated via addGroupSocket/rename) // over the snapshot taken when we entered the group. - const currentDef = (this.graph.groups ?? rootGraph.groups)?.[groupId]; + const currentDef = $state.snapshot((this.graph.groups ?? rootGraph.groups)?.[groupId]); merged = { ...rootGraph, groups: { @@ -563,7 +563,7 @@ export class GraphManager extends EventEmitter<{ if (!group) return false; const currentSerialized = this.serialize(); - this.graphStack.push({ rootGraph: currentSerialized, groupId, cameraPosition }); + this.graphStack.push({ rootGraph: currentSerialized, groupId, nodeId, cameraPosition }); this.currentGroupContext = groupId; @@ -581,10 +581,10 @@ export class GraphManager extends EventEmitter<{ return true; } - exitGroup(): [number, number, number] | false { + exitGroup(): { camera: [number, number, number]; nodeId: number } | false { if (this.graphStack.length === 0) return false; - const { rootGraph, groupId, cameraPosition } = this.graphStack[this.graphStack.length - 1]; + const { rootGraph, groupId, nodeId, cameraPosition } = this.graphStack[this.graphStack.length - 1]; this.graphStack.pop(); // Serialize current internal graph state @@ -614,7 +614,7 @@ export class GraphManager extends EventEmitter<{ this.history.reset(); this.save(); - return cameraPosition; + return { camera: cameraPosition, nodeId }; } get isInsideGroup(): boolean { diff --git a/app/src/lib/graph-interface/graph/Wrapper.svelte b/app/src/lib/graph-interface/graph/Wrapper.svelte index 8d0d84d..a043470 100644 --- a/app/src/lib/graph-interface/graph/Wrapper.svelte +++ b/app/src/lib/graph-interface/graph/Wrapper.svelte @@ -91,21 +91,23 @@ function navigateToBreadcrumb(index: number) { const crumbs = manager.breadcrumbs; const depth = crumbs.length - 1 - index; - let restoredCamera: [number, number, number] | false = false; + let result: { camera: [number, number, number]; nodeId: number } | false = false; for (let i = 0; i < depth; i++) { const groupId = manager.currentGroupContext; if (groupId) { state.groupCameras.set(groupId, [...state.cameraPosition] as [number, number, number]); } - restoredCamera = manager.exitGroup(); + result = manager.exitGroup(); } - state.activeNodeId = -1; - state.clearSelection(); - if (restoredCamera !== false) { - state.cameraPosition[0] = restoredCamera[0]; - state.cameraPosition[1] = restoredCamera[1]; - state.cameraPosition[2] = restoredCamera[2]; + if (result !== false) { + state.activeNodeId = result.nodeId; + state.clearSelection(); + state.cameraPosition[0] = result.camera[0]; + state.cameraPosition[1] = result.camera[1]; + state.cameraPosition[2] = result.camera[2]; } else { + state.activeNodeId = -1; + state.clearSelection(); state.centerNode(); } } diff --git a/app/src/lib/graph-interface/helpers/nodeHelpers.ts b/app/src/lib/graph-interface/helpers/nodeHelpers.ts index 9c08998..df73fba 100644 --- a/app/src/lib/graph-interface/helpers/nodeHelpers.ts +++ b/app/src/lib/graph-interface/helpers/nodeHelpers.ts @@ -31,6 +31,20 @@ export function getSocketPosition( index: string | number ): [number, number] { if (typeof index === 'number') { + if (node.type === '__virtual/group/input') { + const nodeType = node.state.type; + const keys = Object.keys(nodeType?.inputs || {}); + let height = 5; + for (let i = 0; i < keys.length; i++) { + const h = getParameterHeight(nodeType!, keys[i]) / 10; + if (i === index) { height += h / 2; break; } + height += h; + } + return [ + (node?.state?.x ?? node.position[0]) + 20, + (node?.state?.y ?? node.position[1]) + height + ]; + } return [ (node?.state?.x ?? node.position[0]) + 20, (node?.state?.y ?? node.position[1]) + 2.5 + 10 * index diff --git a/app/src/lib/graph-interface/keymaps.ts b/app/src/lib/graph-interface/keymaps.ts index 1440a92..d86f6f7 100644 --- a/app/src/lib/graph-interface/keymaps.ts +++ b/app/src/lib/graph-interface/keymaps.ts @@ -55,13 +55,13 @@ export function setupKeymaps(keymap: Keymap, graph: GraphManager, graphState: Gr [...graphState.cameraPosition] as [number, number, number] ); } - const savedCamera = graph.exitGroup(); - if (savedCamera !== false) { - graphState.activeNodeId = -1; + const result = graph.exitGroup(); + if (result !== false) { + graphState.activeNodeId = result.nodeId; graphState.clearSelection(); - graphState.cameraPosition[0] = savedCamera[0]; - graphState.cameraPosition[1] = savedCamera[1]; - graphState.cameraPosition[2] = savedCamera[2]; + graphState.cameraPosition[0] = result.camera[0]; + graphState.cameraPosition[1] = result.camera[1]; + graphState.cameraPosition[2] = result.camera[2]; return; } } diff --git a/app/src/lib/graph-interface/node/NodeHTML.svelte b/app/src/lib/graph-interface/node/NodeHTML.svelte index 6c5a329..0d41160 100644 --- a/app/src/lib/graph-interface/node/NodeHTML.svelte +++ b/app/src/lib/graph-interface/node/NodeHTML.svelte @@ -128,6 +128,7 @@ id={key} input={value} isLast={i == parameters.length - 1} + outputIndex={node.type === '__virtual/group/input' ? i : undefined} /> {/each} diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte index a10da57..441525e 100644 --- a/app/src/lib/graph-interface/node/NodeHeader.svelte +++ b/app/src/lib/graph-interface/node/NodeHeader.svelte @@ -22,7 +22,7 @@ } const cornerTop = 10; - const rightBump = $derived(!!node?.state?.type?.outputs?.length); + const rightBump = $derived(!!node?.state?.type?.outputs?.length && node.type !== '__virtual/group/input'); const aspectRatio = 0.25; const path = $derived( @@ -72,13 +72,15 @@ {/if} {node.state?.type?.meta?.title ?? node.type.split('/').pop()} -
-
+ {#if node.type !== '__virtual/group/input'} +
+
+ {/if} {#key id && graphId}
@@ -91,7 +109,7 @@ {/if}
- {#if node?.state?.type?.inputs?.[id]?.internal !== true} + {#if outputIndex === undefined && node?.state?.type?.inputs?.[id]?.internal !== true}
+
+ {/if} +