From ddc3b4ce357ef1c1e8066c0a52151713d0b6ed95 Mon Sep 17 00:00:00 2001 From: release-bot Date: Thu, 12 Feb 2026 16:16:24 +0100 Subject: [PATCH] feat: allow variable height node parameters --- .../lib/graph-interface/graph-state.svelte.ts | 65 ++--------------- .../lib/graph-interface/graph/Graph.svelte | 5 +- .../lib/graph-interface/graph/mouse.events.ts | 3 +- app/src/lib/graph-interface/helpers/index.ts | 7 +- .../graph-interface/helpers/nodeHelpers.ts | 73 +++++++++++++++++++ app/src/lib/graph-interface/node/Node.svelte | 3 +- .../graph-interface/node/NodeHeader.svelte | 7 +- .../graph-interface/node/NodeParameter.svelte | 28 +++---- 8 files changed, 109 insertions(+), 82 deletions(-) create mode 100644 app/src/lib/graph-interface/helpers/nodeHelpers.ts diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index 512fe39..223d741 100644 --- a/app/src/lib/graph-interface/graph-state.svelte.ts +++ b/app/src/lib/graph-interface/graph-state.svelte.ts @@ -3,6 +3,7 @@ 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 { getNodeHeight, getSocketPosition } from './helpers/nodeHelpers'; const graphStateKey = Symbol('graph-state'); export function getGraphState() { @@ -159,56 +160,6 @@ export class GraphState { return 1; } - 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 { - const _index = Object.keys(node.state?.type?.inputs || {}).indexOf(index); - return [ - node?.state?.x ?? node.position[0], - (node?.state?.y ?? node.position[1]) + 10 + 10 * _index - ]; - } - } - - private nodeHeightCache: Record = {}; - getNodeHeight(nodeTypeId: string) { - if (nodeTypeId in this.nodeHeightCache) { - return this.nodeHeightCache[nodeTypeId]; - } - const node = this.graph.getNodeType(nodeTypeId); - if (!node?.inputs) { - return 5; - } - let height = 5; - - for (const key of Object.keys(node.inputs)) { - if (key === 'seed') continue; - if (!node.inputs) continue; - if (node?.inputs?.[key] === undefined) continue; - if ('setting' in node.inputs[key]) continue; - if (node.inputs[key].hidden) continue; - if ( - node.inputs[key].type === 'shape' - && node.inputs[key].external !== true - && node.inputs[key].internal !== false - ) { - height += 20; - continue; - } - height += 10; - } - - this.nodeHeightCache[nodeTypeId] = height; - return height; - } - copyNodes() { if (this.activeNodeId === -1 && !this.selectedNodes?.size) { return; @@ -266,7 +217,7 @@ export class GraphState { if (edge[3] === index) { node = edge[0]; index = edge[1]; - position = this.getSocketPosition(node, index); + position = getSocketPosition(node, index); this.graph.removeEdge(edge); break; } @@ -286,7 +237,7 @@ export class GraphState { return { node, index, - position: this.getSocketPosition(node, index) + position: getSocketPosition(node, index) }; }); } @@ -323,7 +274,7 @@ export class GraphState { for (const node of this.graph.nodes.values()) { const x = node.position[0]; const y = node.position[1]; - const height = this.getNodeHeight(node.type); + const height = getNodeHeight(node.state.type!); if (downX > x && downX < x + 20 && downY > y && downY < y + height) { clickedNodeId = node.id; break; @@ -335,14 +286,12 @@ export class GraphState { } isNodeInView(node: NodeInstance) { - const height = this.getNodeHeight(node.type); + const height = getNodeHeight(node.state.type!); const width = 20; - return ( - node.position[0] > this.cameraBounds[0] - width + return node.position[0] > this.cameraBounds[0] - width && node.position[0] < this.cameraBounds[1] && node.position[1] > this.cameraBounds[2] - height - && node.position[1] < this.cameraBounds[3] - ); + && node.position[1] < this.cameraBounds[3]; } openNodePalette() { diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte index 3bc90c8..a68a7fd 100644 --- a/app/src/lib/graph-interface/graph/Graph.svelte +++ b/app/src/lib/graph-interface/graph/Graph.svelte @@ -11,6 +11,7 @@ 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'; @@ -38,8 +39,8 @@ return [0, 0, 0, 0]; } - const pos1 = graphState.getSocketPosition(fromNode, edge[1]); - const pos2 = graphState.getSocketPosition(toNode, edge[3]); + const pos1 = getSocketPosition(fromNode, edge[1]); + const pos2 = getSocketPosition(toNode, edge[3]); return [pos1[0], pos1[1], pos2[0], pos2[1]]; } diff --git a/app/src/lib/graph-interface/graph/mouse.events.ts b/app/src/lib/graph-interface/graph/mouse.events.ts index e7c32c0..184dc65 100644 --- a/app/src/lib/graph-interface/graph/mouse.events.ts +++ b/app/src/lib/graph-interface/graph/mouse.events.ts @@ -3,6 +3,7 @@ import { type NodeInstance } from '@nodarium/types'; import type { GraphManager } from '../graph-manager.svelte'; import { type GraphState } from '../graph-state.svelte'; import { snapToGrid as snapPointToGrid } from '../helpers'; +import { getNodeHeight } from '../helpers/nodeHelpers'; import { maxZoom, minZoom, zoomSpeed } from './constants'; import { EdgeInteractionManager } from './edge.events'; @@ -289,7 +290,7 @@ export class MouseEventManager { if (!node?.state) continue; const x = node.position[0]; const y = node.position[1]; - const height = this.state.getNodeHeight(node.type); + const height = getNodeHeight(node.state.type!); if (x > x1 - 20 && x < x2 && y > y1 - height && y < y2) { this.state.selectedNodes?.add(node.id); } else { diff --git a/app/src/lib/graph-interface/helpers/index.ts b/app/src/lib/graph-interface/helpers/index.ts index e165bdd..448ed0e 100644 --- a/app/src/lib/graph-interface/helpers/index.ts +++ b/app/src/lib/graph-interface/helpers/index.ts @@ -35,6 +35,9 @@ export function createNodePath({ rightBump = false, aspectRatio = 1 } = {}) { + const leftBumpTopY = y + height / 2; + const leftBumpBottomY = y - height / 2; + return `M0,${cornerTop} ${ cornerTop @@ -64,9 +67,7 @@ export function createNodePath({ } ${ leftBump - ? ` V${y + height / 2} C${depth},${y + height / 2} ${depth},${y - height / 2} 0,${ - y - height / 2 - }` + ? ` V${leftBumpTopY} C${depth},${leftBumpTopY} ${depth},${leftBumpBottomY} 0,${leftBumpBottomY}` : ` H0` } Z`.replace(/\s+/g, ' '); diff --git a/app/src/lib/graph-interface/helpers/nodeHelpers.ts b/app/src/lib/graph-interface/helpers/nodeHelpers.ts new file mode 100644 index 0000000..c214314 --- /dev/null +++ b/app/src/lib/graph-interface/helpers/nodeHelpers.ts @@ -0,0 +1,73 @@ +import type { NodeDefinition, NodeInstance } from '@nodarium/types'; + +export function getParameterHeight(node: NodeDefinition, inputKey: string) { + const input = node.inputs?.[inputKey]; + if (!input) { + return 0; + } + + if (inputKey === 'seed') return 0; + if (!node.inputs) return 0; + if ('setting' in input) return 0; + if (input.hidden) return 0; + + if (input.type === 'shape' && input.external !== true) { + return 200; + } + if ( + input?.label !== '' && !input.external && input.type !== 'path' + && input.type !== 'geometry' + ) { + return 100; + } + return 50; +} + +export function 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; + let nodeType = node.state.type!; + const inputs = nodeType.inputs || {}; + for (const inputKey in inputs) { + const h = getParameterHeight(nodeType, inputKey) / 10; + console.log({ inputKey, h }); + if (inputKey === index) { + height += h / 2; + break; + } + height += h; + } + return [ + node?.state?.x ?? node.position[0], + (node?.state?.y ?? node.position[1]) + height + ]; + } +} + +const nodeHeightCache: Record = {}; +export function getNodeHeight(node: NodeDefinition) { + if (node.id in nodeHeightCache) { + return nodeHeightCache[node.id]; + } + if (!node?.inputs) { + return 5; + } + let height = 5; + console.log('Get Node Height', node.id); + + for (const key in node.inputs) { + const h = getParameterHeight(node, key) / 10; + height += h; + } + + nodeHeightCache[node.id] = height; + return height; +} diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index 0e72475..81cfdfc 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -5,6 +5,7 @@ import { type Mesh } from 'three'; import { getGraphState } from '../graph-state.svelte'; import { colors } from '../graph/colors.svelte'; + import { getNodeHeight } from '../helpers/nodeHelpers'; import NodeFrag from './Node.frag'; import NodeVert from './Node.vert'; import NodeHtml from './NodeHTML.svelte'; @@ -31,7 +32,7 @@ let meshRef: Mesh | undefined = $state(); - const height = graphState.getNodeHeight(node.type); + const height = getNodeHeight(node.state.type!); $effect(() => { if (meshRef && !node.state?.mesh) { diff --git a/app/src/lib/graph-interface/node/NodeHeader.svelte b/app/src/lib/graph-interface/node/NodeHeader.svelte index a3bdb11..dae3399 100644 --- a/app/src/lib/graph-interface/node/NodeHeader.svelte +++ b/app/src/lib/graph-interface/node/NodeHeader.svelte @@ -1,7 +1,9 @@