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 8a06ff7..7be9fee 100644 Binary files a/app/e2e/main.test.ts-snapshots/test-1-linux.png and b/app/e2e/main.test.ts-snapshots/test-1-linux.png differ diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 6d33fd2..1a8907f 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -29,8 +29,9 @@ function areSocketsCompatible( output: string | undefined, inputs: string | (string | undefined)[] | undefined ) { + if (output === '*') return true; if (Array.isArray(inputs) && output) { - return inputs.includes(output); + return inputs.includes('*') || inputs.includes(output); } return inputs === output; } diff --git a/app/src/lib/graph-interface/graph-state.svelte.ts b/app/src/lib/graph-interface/graph-state.svelte.ts index 512fe39..a62fac5 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,54 +160,27 @@ 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; + 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; } - height += 10; } - this.nodeHeightCache[nodeTypeId] = height; - return height; + const debugNode = this.graph.createNode({ + type: 'max/plantarium/debug', + position: [node.position[0] + 30, node.position[1]], + props: {} + }); + + if (debugNode) { + this.graph.createEdge(node, 0, debugNode, 'input'); + } } copyNodes() { @@ -266,7 +240,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 +260,7 @@ export class GraphState { return { node, index, - position: this.getSocketPosition(node, index) + position: getSocketPosition(node, index) }; }); } @@ -323,7 +297,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 +309,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..48a9304 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]]; } @@ -208,7 +209,6 @@ {/each} diff --git a/app/src/lib/graph-interface/graph/mouse.events.ts b/app/src/lib/graph-interface/graph/mouse.events.ts index e7c32c0..336fd1f 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'; @@ -188,6 +189,10 @@ export class MouseEventManager { // if we clicked on a node if (clickedNodeId !== -1) { + if (event.ctrlKey && event.shiftKey) { + this.state.tryConnectToDebugNode(clickedNodeId); + return; + } if (this.state.activeNodeId === -1) { this.state.activeNodeId = clickedNodeId; // if the selected node is the same as the clicked node @@ -289,7 +294,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..1058780 --- /dev/null +++ b/app/src/lib/graph-interface/helpers/nodeHelpers.ts @@ -0,0 +1,71 @@ +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; + const nodeType = node.state.type!; + 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 + ]; + } +} + +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; + + 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.frag b/app/src/lib/graph-interface/node/Node.frag index 997ace1..46a6151 100644 --- a/app/src/lib/graph-interface/node/Node.frag +++ b/app/src/lib/graph-interface/node/Node.frag @@ -1,56 +1,88 @@ - varying vec2 vUv; uniform float uWidth; uniform float uHeight; +uniform float uZoom; uniform vec3 uColorDark; uniform vec3 uColorBright; - uniform vec3 uStrokeColor; -uniform float uStrokeWidth; + +const float uHeaderHeight = 5.0; +uniform float uSectionHeights[16]; +uniform int uNumSections; float msign(in float x) { return (x < 0.0) ? -1.0 : 1.0; } +float sdCircle(vec2 p, float r) { return length(p) - r; } vec4 roundedBoxSDF( in vec2 p, in vec2 b, in float r, in float s) { vec2 q = abs(p) - b + r; float l = b.x + b.y + 1.570796 * r; - float k1 = min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r; float k2 = ((q.x > 0.0) ? atan(q.y, q.x) : 1.570796); float k3 = 3.0 + 2.0 * msign(min(p.x, -p.y)) - msign(p.x); float k4 = msign(p.x * p.y); float k5 = r * k2 + max(-q.x, 0.0); - float ra = s * round(k1 / s); float l2 = l + 1.570796 * ra; - return vec4(k1 - ra, k3 * l2 + k4 * (b.y + ((q.y > 0.0) ? k5 + k2 * ra : q.y)), 4.0 * l2, k1); } void main(){ + float strokeWidth = mix(2.0, 0.5, uZoom); + + float borderRadius = 0.5; + float dentRadius = 0.8; - float y = (1.0-vUv.y) * uHeight; + float y = (1.0 - vUv.y) * uHeight; float x = vUv.x * uWidth; - vec2 size = vec2(uWidth, uHeight); - vec2 uv = (vUv - 0.5) * 2.0; + vec2 uvCenter = (vUv - 0.5) * 2.0; - float u_border_radius = 0.4; - vec4 distance = roundedBoxSDF(uv * size, size, u_border_radius*2.0, 0.0); + vec4 boxData = roundedBoxSDF(uvCenter * size, size, borderRadius * 2.0, 0.0); + float sceneSDF = boxData.w; - if (distance.w > 0.0 ) { - // outside - gl_FragColor = vec4(0.0,0.0,0.0, 0.0); - }else{ - if (distance.w > -uStrokeWidth || mod(y+5.0, 10.0) < uStrokeWidth/2.0) { - // draw the outer stroke - gl_FragColor = vec4(uStrokeColor, 1.0); - }else if (y<5.0){ - // draw the header - gl_FragColor = vec4(uColorBright, 1.0); - }else{ - gl_FragColor = vec4(uColorDark, 1.0); - } + vec2 headerDentPos = vec2(uWidth, uHeaderHeight * 0.5); + float headerDentDist = sdCircle(vec2(x, y) - headerDentPos, dentRadius); + sceneSDF = max(sceneSDF, -headerDentDist*2.0); + + float currentYBoundary = uHeaderHeight; + float previousYBoundary = uHeaderHeight; + + for (int i = 0; i < 16; i++) { + if (i >= uNumSections) break; + + float sectionHeight = uSectionHeights[i]; + currentYBoundary += sectionHeight; + + float centerY = previousYBoundary + (sectionHeight * 0.5); + vec2 circlePos = vec2(0.0, centerY); + float circleDist = sdCircle(vec2(x, y) - circlePos, dentRadius); + + sceneSDF = max(sceneSDF, -circleDist*2.0); + previousYBoundary = currentYBoundary; + } + + if (sceneSDF > 0.05) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); + return; + } + + vec3 finalColor = (y < uHeaderHeight) ? uColorBright : uColorDark; + bool isDivider = false; + + float dividerY = uHeaderHeight; + if (abs(y - dividerY) < strokeWidth * 0.25) isDivider = true; + + for (int i = 0; i < 16; i++) { + if (i >= uNumSections - 1) break; + dividerY += uSectionHeights[i]; + if (abs(y - dividerY) < strokeWidth * 0.25) isDivider = true; + } + + if (sceneSDF > -strokeWidth || isDivider) { + gl_FragColor = vec4(uStrokeColor, 1.0); + } else { + gl_FragColor = vec4(finalColor, 1.0); } } diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index 0e72475..cba7fd7 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, getParameterHeight } from '../helpers/nodeHelpers'; import NodeFrag from './Node.frag'; import NodeVert from './Node.vert'; import NodeHtml from './NodeHTML.svelte'; @@ -14,9 +15,10 @@ type Props = { node: NodeInstance; inView: boolean; - z: number; }; - let { node = $bindable(), inView, z }: Props = $props(); + let { node = $bindable(), inView }: Props = $props(); + + const nodeType = $derived(node.state.type!); const isActive = $derived(graphState.activeNodeId === node.id); const isSelected = $derived(graphState.selectedNodes.has(node.id)); @@ -29,9 +31,18 @@ : colors.outline) ); + const sectionHeights = $derived( + Object + .keys(nodeType.inputs || {}) + .map(key => getParameterHeight(nodeType, key) / 10) + .filter(b => !!b) + ); + let meshRef: Mesh | undefined = $state(); - const height = graphState.getNodeHeight(node.type); + const height = getNodeHeight(node.state.type!); + + const zoom = $derived(graphState.cameraPosition[2]); $effect(() => { if (meshRef && !node.state?.mesh) { @@ -39,6 +50,10 @@ graphState.updateNodePosition(node); } }); + const zoomValue = $derived( + (Math.log(graphState.cameraPosition[2]) - Math.log(1)) / (Math.log(40) - Math.log(1)) + ); + // const zoomValue = (graphState.cameraPosition[2] - 1) / 39; - + 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 @@ + + diff --git a/app/src/lib/result-viewer/Scene.svelte b/app/src/lib/result-viewer/Scene.svelte index cf3736b..e68af5a 100644 --- a/app/src/lib/result-viewer/Scene.svelte +++ b/app/src/lib/result-viewer/Scene.svelte @@ -1,33 +1,26 @@ + + {#if appSettings.value.showGrid} {/if} - - - {#if geometries} - {#each geometries as geo (geo.id)} - {#if appSettings.value.debug.showIndices} - {#each geo.attributes.position.array, i (i)} - {#if i % 3 === 0} - - {/if} - {/each} - {/if} - - {#if appSettings.value.debug.showVertices} - - - - - {/if} - {/each} - {/if} - - - - -{#if appSettings.value.debug.showStemLines && lines} - {#each lines as line (line[0].x + '-' + line[0].y + '-' + '' + line[0].z)} - - - - - {/each} -{/if} + diff --git a/app/src/lib/result-viewer/Viewer.svelte b/app/src/lib/result-viewer/Viewer.svelte index 9f9c451..c7a370d 100644 --- a/app/src/lib/result-viewer/Viewer.svelte +++ b/app/src/lib/result-viewer/Viewer.svelte @@ -1,10 +1,10 @@ -{#if appSettings.value.debug.showPerformancePanel} +{#if appSettings.value.debug.advancedMode} {/if} @@ -97,8 +70,8 @@ diff --git a/app/src/lib/result-viewer/debug.ts b/app/src/lib/result-viewer/debug.ts new file mode 100644 index 0000000..ea40319 --- /dev/null +++ b/app/src/lib/result-viewer/debug.ts @@ -0,0 +1,90 @@ +import { splitNestedArray } from '@nodarium/utils'; +import { + BufferGeometry, + type Group, + InstancedMesh, + Line, + LineBasicMaterial, + Matrix4, + MeshBasicMaterial, + SphereGeometry, + Vector3 +} from 'three'; + +function writePath(scene: Group, data: Int32Array): Vector3[] { + const positions: Vector3[] = []; + const f32 = new Float32Array(data.buffer); + + for (let i = 2; i + 2 < f32.length; i += 4) { + const vec = new Vector3(f32[i], f32[i + 1], f32[i + 2]); + positions.push(vec); + } + + // Path line + if (positions.length >= 2) { + const geometry = new BufferGeometry().setFromPoints(positions); + const line = new Line( + geometry, + new LineBasicMaterial({ color: 0xff0000, depthTest: false }) + ); + scene.add(line); + } + + // Instanced spheres at points + if (positions.length > 0) { + const sphereGeometry = new SphereGeometry(0.05, 8, 8); // keep low-poly + const sphereMaterial = new MeshBasicMaterial({ + color: 0xff0000, + depthTest: false + }); + + const spheres = new InstancedMesh( + sphereGeometry, + sphereMaterial, + positions.length + ); + + const matrix = new Matrix4(); + for (let i = 0; i < positions.length; i++) { + matrix.makeTranslation( + positions[i].x, + positions[i].y, + positions[i].z + ); + spheres.setMatrixAt(i, matrix); + } + + spheres.instanceMatrix.needsUpdate = true; + scene.add(spheres); + } + + return positions; +} + +function clearGroup(group: Group) { + for (let i = group.children.length - 1; i >= 0; i--) { + const child = group.children[i]; + group.remove(child); + // optional but correct: free GPU memory + // @ts-expect-error three.js runtime fields + child.geometry?.dispose?.(); + // @ts-expect-error three.js runtime fields + child.material?.dispose?.(); + } +} + +export function updateDebugScene( + group: Group, + data: Record +) { + clearGroup(group); + return Object.entries(data || {}).map(([, d]) => { + switch (d.type) { + case 'path': + splitNestedArray(d.data) + .forEach(p => writePath(group, p)); + } + // eslint-disable-next-line @typescript-eslint/no-unused-vars + return (_g: Group) => {}; + }).flat(); +} diff --git a/app/src/lib/runtime/runtime-executor.ts b/app/src/lib/runtime/runtime-executor.ts index 0248f25..bf9d3bc 100644 --- a/app/src/lib/runtime/runtime-executor.ts +++ b/app/src/lib/runtime/runtime-executor.ts @@ -59,6 +59,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { private definitionMap: Map = new Map(); private seed = Math.floor(Math.random() * 100000000); + private debugData: Record = {}; perf?: PerformanceStore; @@ -124,10 +125,10 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { } } - const nodes = []; + const nodes = new Map(); // loop through all the nodes and assign each nodes its depth - const stack = [outputNode]; + const stack = [outputNode, ...graphNodes.filter(n => n.type.endsWith('/debug'))]; while (stack.length) { const node = stack.pop(); if (!node) continue; @@ -136,16 +137,31 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { parent.state.depth = node.state.depth + 1; stack.push(parent); } - nodes.push(node); + nodes.set(node.id, node); } - return [outputNode, nodes] as const; + for (const node of graphNodes) { + if (node.type.endsWith('/debug')) { + node.state = node.state || {}; + const parent = node.state.parents[0]; + if (parent) { + node.state.depth = parent.state.depth - 1; + parent.state.debugNode = true; + } + nodes.set(node.id, node); + } + } + + const _nodes = [...nodes.values()]; + + return [outputNode, _nodes] as const; } async execute(graph: Graph, settings: Record) { this.perf?.addPoint('runtime'); let a = performance.now(); + this.debugData = {}; // Then we add some metadata to the graph const [outputNode, nodes] = await this.addMetaData(graph); @@ -237,6 +253,12 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { log.log(`Using cached value for ${node_type.id || node.id}`); this.perf?.addPoint('cache-hit', 1); results[node.id] = cachedValue as Int32Array; + if (node.state.debugNode && node_type.outputs) { + this.debugData[node.id] = { + type: node_type.outputs[0], + data: cachedValue + }; + } continue; } this.perf?.addPoint('cache-hit', 0); @@ -245,6 +267,12 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { log.log(`Inputs:`, inputs); a = performance.now(); results[node.id] = node_type.execute(encoded_inputs); + if (node.state.debugNode && node_type.outputs) { + this.debugData[node.id] = { + type: node_type.outputs[0], + data: results[node.id] + }; + } log.log('Executed', node.type, node.id); b = performance.now(); @@ -273,6 +301,10 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { return res as unknown as Int32Array; } + getDebugData() { + return this.debugData; + } + getPerformanceData() { return this.perf?.get(); } diff --git a/app/src/lib/runtime/types.ts b/app/src/lib/runtime/types.ts index 8786862..1b91e7c 100644 --- a/app/src/lib/runtime/types.ts +++ b/app/src/lib/runtime/types.ts @@ -5,6 +5,7 @@ type RuntimeState = { parents: RuntimeNode[]; children: RuntimeNode[]; inputNodes: Record; + debugNode?: boolean; }; export type RuntimeNode = SerializedNode & { state: RuntimeState }; diff --git a/app/src/lib/runtime/worker-runtime-executor-backend.ts b/app/src/lib/runtime/worker-runtime-executor-backend.ts index 1e7f581..2def545 100644 --- a/app/src/lib/runtime/worker-runtime-executor-backend.ts +++ b/app/src/lib/runtime/worker-runtime-executor-backend.ts @@ -1,3 +1,4 @@ +import { debugNode } from '$lib/node-registry/debugNode'; import { IndexDBCache, RemoteNodeRegistry } from '$lib/node-registry/index'; import type { Graph } from '@nodarium/types'; import { createPerformanceStore } from '@nodarium/utils'; @@ -5,7 +6,7 @@ import { MemoryRuntimeExecutor } from './runtime-executor'; import { MemoryRuntimeCache } from './runtime-executor-cache'; const indexDbCache = new IndexDBCache('node-registry'); -const nodeRegistry = new RemoteNodeRegistry('', indexDbCache); +const nodeRegistry = new RemoteNodeRegistry('', indexDbCache, [debugNode]); const cache = new MemoryRuntimeCache(); const executor = new MemoryRuntimeExecutor(nodeRegistry, cache); @@ -43,3 +44,7 @@ export async function executeGraph( export function getPerformanceData() { return performanceStore.get(); } + +export function getDebugData() { + return executor.getDebugData(); +} diff --git a/app/src/lib/runtime/worker-runtime-executor.ts b/app/src/lib/runtime/worker-runtime-executor.ts index 2b9a56b..6aba5b1 100644 --- a/app/src/lib/runtime/worker-runtime-executor.ts +++ b/app/src/lib/runtime/worker-runtime-executor.ts @@ -6,12 +6,15 @@ export class WorkerRuntimeExecutor implements RuntimeExecutor { new URL(`./worker-runtime-executor-backend.ts`, import.meta.url) ); - async execute(graph: Graph, settings: Record) { + execute(graph: Graph, settings: Record) { return this.worker.executeGraph(graph, settings); } - async getPerformanceData() { + getPerformanceData() { return this.worker.getPerformanceData(); } + getDebugData() { + return this.worker.getDebugData(); + } set useRuntimeCache(useCache: boolean) { this.worker.setUseRuntimeCache(useCache); } diff --git a/app/src/lib/settings/app-settings.svelte.ts b/app/src/lib/settings/app-settings.svelte.ts index 3c17bf4..d9ff323 100644 --- a/app/src/lib/settings/app-settings.svelte.ts +++ b/app/src/lib/settings/app-settings.svelte.ts @@ -59,34 +59,9 @@ export const AppSettingTypes = { label: 'Execute in WebWorker', value: true }, - showIndices: { + advancedMode: { type: 'boolean', - label: 'Show Indices', - value: false - }, - showPerformancePanel: { - type: 'boolean', - label: 'Show Performance Panel', - value: false - }, - showBenchmarkPanel: { - type: 'boolean', - label: 'Show Benchmark Panel', - value: false - }, - showVertices: { - type: 'boolean', - label: 'Show Vertices', - value: false - }, - showStemLines: { - type: 'boolean', - label: 'Show Stem Lines', - value: false - }, - showGraphJson: { - type: 'boolean', - label: 'Show Graph Source', + label: 'Advanced Mode', value: false }, cache: { diff --git a/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte b/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte index ac53556..2993c6e 100644 --- a/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte +++ b/app/src/lib/sidebar/panels/ActiveNodeSelected.svelte @@ -42,11 +42,13 @@ const store: Store = {}; Object.keys(inputs).forEach((key) => { if (props) { - const value = props[key] || inputs[key].value; + const value = props[key] !== undefined ? props[key] : inputs[key].value; if (Array.isArray(value) || typeof value === 'number') { store[key] = value; + } else if (typeof value === 'boolean') { + store[key] = value ? 1 : 0; } else { - console.error('Wrong error'); + console.error('Wrong error', { value }); } } }); diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index 4cb7dd3..515dd8e 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -4,6 +4,7 @@ import Grid from '$lib/grid'; import { debounceAsyncFunction } from '$lib/helpers'; import { createKeyMap } from '$lib/helpers/createKeyMap'; + import { debugNode } from '$lib/node-registry/debugNode.js'; import { IndexDBCache, RemoteNodeRegistry } from '$lib/node-registry/index'; import NodeStore from '$lib/node-store/NodeStore.svelte'; import PerformanceViewer from '$lib/performance/PerformanceViewer.svelte'; @@ -32,7 +33,8 @@ const { data } = $props(); const registryCache = new IndexDBCache('node-registry'); - const nodeRegistry = new RemoteNodeRegistry('', registryCache); + + const nodeRegistry = new RemoteNodeRegistry('', registryCache, [debugNode]); const workerRuntime = new WorkerRuntimeExecutor(); const runtimeCache = new MemoryRuntimeCache(); const memoryRuntime = new MemoryRuntimeExecutor(nodeRegistry, runtimeCache); @@ -66,6 +68,7 @@ let sidebarOpen = $state(false); let graphInterface = $state>(null!); let viewerComponent = $state>(); + let debugData = $state>(); const manager = $derived(graphInterface?.manager); async function randomGenerate() { @@ -105,6 +108,7 @@ if (appSettings.value.debug.useWorker) { let perfData = await runtime.getPerformanceData(); + debugData = await runtime.getDebugData(); let lastRun = perfData?.at(-1); if (lastRun?.total) { lastRun.runtime = lastRun.total; @@ -163,6 +167,7 @@ bind:scene bind:this={viewerComponent} perf={performanceStore} + debugData={debugData} centerCamera={appSettings.value.centerCamera} /> @@ -216,7 +221,7 @@