diff --git a/app/src/lib/graph-interface/AddMenu.svelte b/app/src/lib/graph-interface/AddMenu.svelte index 2b6b645..87470e0 100644 --- a/app/src/lib/graph-interface/AddMenu.svelte +++ b/app/src/lib/graph-interface/AddMenu.svelte @@ -52,7 +52,7 @@ if (event.key === "Enter") { if (activeNodeId && position) { - graph.createNode({ type: activeNodeId, position }); + graph.createNode({ type: activeNodeId, position, props: {} }); position = null; } return; diff --git a/app/src/lib/graph-interface/background/Background.story.svelte b/app/src/lib/graph-interface/background/Background.story.svelte deleted file mode 100644 index dc09cd6..0000000 --- a/app/src/lib/graph-interface/background/Background.story.svelte +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - diff --git a/app/src/lib/graph-interface/graph-manager.svelte.ts b/app/src/lib/graph-interface/graph-manager.svelte.ts index 1bbb5b8..158301b 100644 --- a/app/src/lib/graph-interface/graph-manager.svelte.ts +++ b/app/src/lib/graph-interface/graph-manager.svelte.ts @@ -11,7 +11,7 @@ import { fastHashString } from "@nodes/utils"; import { SvelteMap } from "svelte/reactivity"; import EventEmitter from "./helpers/EventEmitter"; import { createLogger } from "./helpers/index"; -import throttle from "./helpers/throttle"; +import throttle from "$lib/helpers/throttle"; import { HistoryManager } from "./history-manager"; const logger = createLogger("graph-manager"); @@ -24,7 +24,7 @@ const clone = function areSocketsCompatible( output: string | undefined, - inputs: string | string[] | undefined, + inputs: string | (string | undefined)[] | undefined, ) { if (Array.isArray(inputs) && output) { return inputs.includes(output); @@ -99,7 +99,6 @@ export class GraphManager extends EventEmitter<{ private lastSettingsHash = 0; setSettings(settings: Record) { - console.log("GraphManager.setSettings", settings); let hash = fastHashString(JSON.stringify(settings)); if (hash === this.lastSettingsHash) return; this.lastSettingsHash = hash; @@ -154,7 +153,7 @@ export class GraphManager extends EventEmitter<{ private _init(graph: Graph) { const nodes = new Map( - graph.nodes.map((node) => { + graph.nodes.map((node: Node) => { const nodeType = this.registry.getNode(node.type); if (nodeType) { node.tmp = { diff --git a/app/src/lib/graph-interface/graph/GraphView.svelte b/app/src/lib/graph-interface/graph/GraphView.svelte index 076767d..345f4f0 100644 --- a/app/src/lib/graph-interface/graph/GraphView.svelte +++ b/app/src/lib/graph-interface/graph/GraphView.svelte @@ -23,8 +23,6 @@ invalidate(); }); - $effect(() => console.log({ nodes })); - const graphState = getGraphState(); const isNodeInView = getContext<(n: NodeType) => boolean>("isNodeInView"); @@ -50,8 +48,6 @@ }), ); - const nodeArray = $derived(Array.from(nodes.values())); - onMount(() => { for (const node of nodes.values()) { if (node?.tmp?.ref) { @@ -86,9 +82,9 @@ style:transform={`scale(${cameraPosition[2] * 0.1})`} class:hovering-sockets={graphState.activeSocket} > - {#each nodeArray as node, i (node.id)} + {#each nodes.values() as node (node.id)} diff --git a/app/src/lib/graph-interface/helpers/EventEmitter.ts b/app/src/lib/graph-interface/helpers/EventEmitter.ts index a10a55e..023c09b 100644 --- a/app/src/lib/graph-interface/helpers/EventEmitter.ts +++ b/app/src/lib/graph-interface/helpers/EventEmitter.ts @@ -1,15 +1,15 @@ -import throttle from './throttle.js'; +import throttle from "$lib/helpers/throttle"; type EventMap = Record; type EventKey = string & keyof T; type EventReceiver = (params: T, stuff?: Record) => unknown; - -export default class EventEmitter { +export default class EventEmitter< + T extends EventMap = { [key: string]: unknown }, +> { index = 0; public eventMap: T = {} as T; - constructor() { - } + constructor() {} private cbs: { [key: string]: ((data?: unknown) => unknown)[] } = {}; private cbsOnce: { [key: string]: ((data?: unknown) => unknown)[] } = {}; @@ -29,7 +29,11 @@ export default class EventEmitter>(event: K, cb: EventReceiver, throttleTimer = 0) { + public on>( + event: K, + cb: EventReceiver, + throttleTimer = 0, + ) { if (throttleTimer > 0) cb = throttle(cb, throttleTimer); const cbs = Object.assign(this.cbs, { [event]: [...(this.cbs[event] || []), cb], @@ -38,7 +42,7 @@ export default class EventEmitter { - cbs[event]?.splice(cbs[event].indexOf(cb), 1); + this.cbs[event]?.splice(cbs[event].indexOf(cb), 1); }; } @@ -48,10 +52,17 @@ export default class EventEmitter>(event: K, cb: EventReceiver): () => void { - this.cbsOnce[event] = [...(this.cbsOnce[event] || []), cb]; + public once>( + event: K, + cb: EventReceiver, + ): () => void { + const cbsOnce = Object.assign(this.cbsOnce, { + [event]: [...(this.cbsOnce[event] || []), cb], + }); + this.cbsOnce = cbsOnce; + return () => { - this.cbsOnce[event].splice(this.cbsOnce[event].indexOf(cb), 1); + cbsOnce[event]?.splice(cbsOnce[event].indexOf(cb), 1); }; } diff --git a/app/src/lib/graph-interface/helpers/throttle.ts b/app/src/lib/graph-interface/helpers/throttle.ts deleted file mode 100644 index 9dcb09c..0000000 --- a/app/src/lib/graph-interface/helpers/throttle.ts +++ /dev/null @@ -1,20 +0,0 @@ -export default ( - fn: (...args: A) => R, - delay: number -): ((...args: A) => R) => { - let wait = false; - - return (...args: A) => { - if (wait) return undefined; - - const val = fn(...args); - - wait = true; - - setTimeout(() => { - wait = false; - }, delay); - - return val; - } -}; diff --git a/app/src/lib/graph-interface/history-manager.ts b/app/src/lib/graph-interface/history-manager.ts index f485c4f..8509e6d 100644 --- a/app/src/lib/graph-interface/history-manager.ts +++ b/app/src/lib/graph-interface/history-manager.ts @@ -2,23 +2,22 @@ import { create, type Delta } from "jsondiffpatch"; import type { Graph } from "@nodes/types"; import { createLogger, clone } from "./helpers/index.js"; - const diff = create({ objectHash: function (obj, index) { if (obj === null) return obj; - if ("id" in obj) return obj.id; + if ("id" in obj) return obj.id as string; + if ("_id" in obj) return obj._id as string; if (Array.isArray(obj)) { - return obj.join("-") + return obj.join("-"); } - return obj?.id || obj._id || '$$index:' + index; - } -}) + return "$$index:" + index; + }, +}); -const log = createLogger("history") +const log = createLogger("history"); log.mute(); export class HistoryManager { - index: number = -1; history: Delta[] = []; private initialState: Graph | undefined; @@ -27,26 +26,25 @@ export class HistoryManager { private opts = { debounce: 400, maxHistory: 100, - } + }; constructor({ maxHistory = 100, debounce = 100 } = {}) { this.history = []; this.index = -1; this.opts.debounce = debounce; this.opts.maxHistory = maxHistory; - globalThis["_history"] = this; } save(state: Graph) { if (!this.state) { this.state = clone(state); this.initialState = this.state; - log.log("initial state saved") + log.log("initial state saved"); } else { const newState = state; const delta = diff.diff(this.state, newState); if (delta) { - log.log("saving state") + log.log("saving state"); // Add the delta to history if (this.index < this.history.length - 1) { // Clear the history after the current index if new changes are made @@ -62,7 +60,7 @@ export class HistoryManager { } this.state = newState; } else { - log.log("no changes") + log.log("no changes"); } } } @@ -76,7 +74,7 @@ export class HistoryManager { undo() { if (this.index === -1 && this.initialState) { - log.log("reached start, loading initial state") + log.log("reached start, loading initial state"); return clone(this.initialState); } else { const delta = this.history[this.index]; @@ -96,7 +94,7 @@ export class HistoryManager { this.state = nextState; return clone(nextState); } else { - log.log("reached end") + log.log("reached end"); } } } diff --git a/app/src/lib/graph-interface/node/Node.svelte b/app/src/lib/graph-interface/node/Node.svelte index ae5effd..5ec7e71 100644 --- a/app/src/lib/graph-interface/node/Node.svelte +++ b/app/src/lib/graph-interface/node/Node.svelte @@ -41,6 +41,7 @@ const height = getNodeHeight?.(node.type); $effect(() => { + if (!node?.tmp) node.tmp = {}; node.tmp.mesh = meshRef; }); diff --git a/app/src/lib/graph-interface/node/NodeHTML.svelte b/app/src/lib/graph-interface/node/NodeHTML.svelte index 1754c45..73af6e2 100644 --- a/app/src/lib/graph-interface/node/NodeHTML.svelte +++ b/app/src/lib/graph-interface/node/NodeHTML.svelte @@ -27,9 +27,7 @@ const zOffset = (node.tmp?.random || 0) * 0.5; const zLimit = 2 - zOffset; - const type = node?.tmp?.type; - - const parameters = Object.entries(type?.inputs || {}).filter( + const parameters = Object.entries(node?.tmp?.type?.inputs || {}).filter( (p) => p[1].type !== "seed" && !("setting" in p[1]) && p[1]?.hidden !== true, ); diff --git a/app/src/lib/graph-interface/node/NodeInput.svelte b/app/src/lib/graph-interface/node/NodeInput.svelte index 2e67d0d..7a09d5e 100644 --- a/app/src/lib/graph-interface/node/NodeInput.svelte +++ b/app/src/lib/graph-interface/node/NodeInput.svelte @@ -11,7 +11,7 @@ }; const { - node, + node = $bindable(), input, id, elementId = `input-${Math.random().toString(36).substring(7)}`, diff --git a/app/src/lib/graph-interface/node/NodeParameter.svelte b/app/src/lib/graph-interface/node/NodeParameter.svelte index 126666f..badac93 100644 --- a/app/src/lib/graph-interface/node/NodeParameter.svelte +++ b/app/src/lib/graph-interface/node/NodeParameter.svelte @@ -82,7 +82,7 @@ class:disabled={!graphState?.possibleSocketIds.has(socketId)} > {#key id && graphId} - + {#if inputType.label !== ""} {input.label || id} {/if} diff --git a/app/src/lib/grid/Row.svelte b/app/src/lib/grid/Row.svelte index 438b123..d54696d 100644 --- a/app/src/lib/grid/Row.svelte +++ b/app/src/lib/grid/Row.svelte @@ -7,8 +7,6 @@ const { children } = $props(); - console.log("RowChildren", children); - let registerIndex = 0; setContext("registerCell", function () { let index = registerIndex; diff --git a/app/src/lib/helpers/throttle.ts b/app/src/lib/helpers/throttle.ts index 9dcb09c..f209c9e 100644 --- a/app/src/lib/helpers/throttle.ts +++ b/app/src/lib/helpers/throttle.ts @@ -1,20 +1,19 @@ -export default ( - fn: (...args: A) => R, - delay: number -): ((...args: A) => R) => { - let wait = false; +export default ( + callback: (...args: T) => void, + delay: number, +) => { + let isWaiting = false; - return (...args: A) => { - if (wait) return undefined; + return (...args: T) => { + if (isWaiting) { + return; + } - const val = fn(...args); - - wait = true; + callback(...args); + isWaiting = true; setTimeout(() => { - wait = false; + isWaiting = false; }, delay); - - return val; - } + }; }; diff --git a/app/src/lib/node-registry.ts b/app/src/lib/node-registry.ts index 7977f2d..b21cc84 100644 --- a/app/src/lib/node-registry.ts +++ b/app/src/lib/node-registry.ts @@ -1,6 +1,6 @@ -import { createWasmWrapper } from "@nodes/utils" -import fs from "fs/promises" -import path from "path" +import { createWasmWrapper } from "@nodes/utils"; +import fs from "fs/promises"; +import path from "path"; export async function getWasm(id: `${string}/${string}/${string}`) { const filePath = path.resolve(`../nodes/${id}/pkg/index_bg.wasm`); @@ -8,17 +8,15 @@ export async function getWasm(id: `${string}/${string}/${string}`) { try { await fs.access(filePath); } catch (e) { - return null + return null; } const file = await fs.readFile(filePath); return new Uint8Array(file); - } export async function getNodeWasm(id: `${string}/${string}/${string}`) { - const wasmBytes = await getWasm(id); if (!wasmBytes) return null; @@ -27,9 +25,7 @@ export async function getNodeWasm(id: `${string}/${string}/${string}`) { return wrapper; } - export async function getNode(id: `${string}/${string}/${string}`) { - const wrapper = await getNodeWasm(id); const definition = wrapper?.get_definition?.(); @@ -37,18 +33,17 @@ export async function getNode(id: `${string}/${string}/${string}`) { if (!definition) return null; return definition; - } export async function getCollectionNodes(userId: `${string}/${string}`) { const nodes = await fs.readdir(path.resolve(`../nodes/${userId}`)); return nodes - .filter(n => n !== "pkg" && n !== ".template") - .map(n => { + .filter((n) => n !== "pkg" && n !== ".template") + .map((n) => { return { id: `${userId}/${n}`, - } - }) + }; + }); } export async function getCollection(userId: `${string}/${string}`) { @@ -56,36 +51,40 @@ export async function getCollection(userId: `${string}/${string}`) { return { id: userId, nodes, - } + }; } export async function getUserCollections(userId: string) { const collections = await fs.readdir(path.resolve(`../nodes/${userId}`)); - return Promise.all(collections.map(async n => { - const nodes = await getCollectionNodes(`${userId}/${n}`); - return { - id: `${userId}/${n}`, - nodes, - } - })); + return Promise.all( + collections.map(async (n) => { + const nodes = await getCollectionNodes(`${userId}/${n}`); + return { + id: `${userId}/${n}`, + nodes, + }; + }), + ); } export async function getUser(userId: string) { const collections = await getUserCollections(userId); return { id: userId, - collections - } + collections, + }; } export async function getUsers() { const nodes = await fs.readdir(path.resolve("../nodes")); - const users = await Promise.all(nodes.map(async n => { - const collections = await getUserCollections(n); - return { - id: n, - collections - } - })) + const users = await Promise.all( + nodes.map(async (n) => { + const collections = await getUserCollections(n); + return { + id: n, + collections, + }; + }), + ); return users; } diff --git a/app/src/lib/performance/Monitor.svelte b/app/src/lib/performance/Monitor.svelte index c942f0c..6e94f9c 100644 --- a/app/src/lib/performance/Monitor.svelte +++ b/app/src/lib/performance/Monitor.svelte @@ -27,10 +27,12 @@ function constructPath() { max = max !== undefined ? max : Math.max(...points); min = min !== undefined ? min : Math.min(...points); + const mi = min as number; + const ma = max as number; return points .map((point, i) => { const x = (i / (points.length - 1)) * 100; - const y = 100 - ((point - min) / (max - min)) * 100; + const y = 100 - ((point - mi) / (ma - mi)) * 100; return `${x},${y}`; }) .join(" "); diff --git a/app/src/lib/result-viewer/Scene.svelte b/app/src/lib/result-viewer/Scene.svelte index ed63acb..94f279b 100644 --- a/app/src/lib/result-viewer/Scene.svelte +++ b/app/src/lib/result-viewer/Scene.svelte @@ -42,11 +42,9 @@ export const invalidate = function () { if (scene) { geometries = scene.children - .filter( - (child) => "geometry" in child && child.isObject3D && child.geometry, - ) + .filter((child) => "geometry" in child && child.isObject3D) .map((child) => { - return child.geometry; + return (child as Mesh).geometry; }); } diff --git a/app/src/lib/result-viewer/geometryPool.ts b/app/src/lib/result-viewer/geometryPool.ts index f4a9297..295a4c2 100644 --- a/app/src/lib/result-viewer/geometryPool.ts +++ b/app/src/lib/result-viewer/geometryPool.ts @@ -1,20 +1,27 @@ import { fastHashArrayBuffer } from "@nodes/utils"; -import { BufferAttribute, BufferGeometry, Float32BufferAttribute, Group, InstancedMesh, Material, Matrix4, Mesh } from "three"; +import { + BufferAttribute, + BufferGeometry, + Float32BufferAttribute, + Group, + InstancedMesh, + Material, + Matrix4, + Mesh, +} from "three"; -function fastArrayHash(arr: ArrayBuffer) { - let ints = new Uint8Array(arr); +function fastArrayHash(arr: Int32Array) { + const sampleDistance = Math.max(Math.floor(arr.length / 100), 1); + const sampleCount = Math.floor(arr.length / sampleDistance); - const sampleDistance = Math.max(Math.floor(ints.length / 100), 1); - const sampleCount = Math.floor(ints.length / sampleDistance); - - let hash = new Uint8Array(sampleCount); + let hash = new Int32Array(sampleCount); for (let i = 0; i < sampleCount; i++) { const index = i * sampleDistance; - hash[i] = ints[index]; + hash[i] = arr[index]; } - return fastHashArrayBuffer(hash.buffer); + return fastHashArrayBuffer(hash); } export function createGeometryPool(parentScene: Group, material: Material) { @@ -26,8 +33,10 @@ export function createGeometryPool(parentScene: Group, material: Material) { let totalVertices = 0; let totalFaces = 0; - function updateSingleGeometry(data: Int32Array, existingMesh: Mesh | null = null) { - + function updateSingleGeometry( + data: Int32Array, + existingMesh: Mesh | null = null, + ) { let hash = fastArrayHash(data); let geometry = existingMesh ? existingMesh.geometry : new BufferGeometry(); @@ -50,11 +59,7 @@ export function createGeometryPool(parentScene: Group, material: Material) { index = indicesEnd; // Vertices - const vertices = new Float32Array( - data.buffer, - index * 4, - vertexCount * 3, - ); + const vertices = new Float32Array(data.buffer, index * 4, vertexCount * 3); index = index + vertexCount * 3; let posAttribute = geometry.getAttribute( @@ -71,11 +76,7 @@ export function createGeometryPool(parentScene: Group, material: Material) { ); } - const normals = new Float32Array( - data.buffer, - index * 4, - vertexCount * 3, - ); + const normals = new Float32Array(data.buffer, index * 4, vertexCount * 3); index = index + vertexCount * 3; if ( @@ -109,11 +110,8 @@ export function createGeometryPool(parentScene: Group, material: Material) { } } - return { - update( - newData: Int32Array[], - ) { + update(newData: Int32Array[]) { totalVertices = 0; totalFaces = 0; for (let i = 0; i < Math.max(newData.length, meshes.length); i++) { @@ -127,11 +125,14 @@ export function createGeometryPool(parentScene: Group, material: Material) { } } return { totalVertices, totalFaces }; - } - } + }, + }; } -export function createInstancedGeometryPool(parentScene: Group, material: Material) { +export function createInstancedGeometryPool( + parentScene: Group, + material: Material, +) { const scene = new Group(); parentScene.add(scene); @@ -139,19 +140,25 @@ export function createInstancedGeometryPool(parentScene: Group, material: Materi let totalVertices = 0; let totalFaces = 0; - function updateSingleInstance(data: Int32Array, existingInstance: InstancedMesh | null = null) { - + function updateSingleInstance( + data: Int32Array, + existingInstance: InstancedMesh | null = null, + ) { let hash = fastArrayHash(data); - let geometry = existingInstance ? existingInstance.geometry : new BufferGeometry(); + let geometry = existingInstance + ? existingInstance.geometry + : new BufferGeometry(); // Extract data from the encoded array let index = 0; - const geometryType = data[index++]; + // const geometryType = data[index++]; + index++; const vertexCount = data[index++]; const faceCount = data[index++]; const instanceCount = data[index++]; - const stemDepth = data[index++]; + // const stemDepth = data[index++]; + index++; totalVertices += vertexCount * instanceCount; totalFaces += faceCount * instanceCount; @@ -168,11 +175,7 @@ export function createInstancedGeometryPool(parentScene: Group, material: Materi } // Vertices - const vertices = new Float32Array( - data.buffer, - index * 4, - vertexCount * 3, - ); + const vertices = new Float32Array(data.buffer, index * 4, vertexCount * 3); index = index + vertexCount * 3; let posAttribute = geometry.getAttribute( "position", @@ -187,11 +190,7 @@ export function createInstancedGeometryPool(parentScene: Group, material: Materi ); } - const normals = new Float32Array( - data.buffer, - index * 4, - vertexCount * 3, - ); + const normals = new Float32Array(data.buffer, index * 4, vertexCount * 3); index = index + vertexCount * 3; const normalsAttribute = geometry.getAttribute( "normal", @@ -203,20 +202,23 @@ export function createInstancedGeometryPool(parentScene: Group, material: Materi geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3)); } - if (existingInstance && instanceCount > existingInstance.geometry.userData.count) { - console.log("recreating instance") + if ( + existingInstance && + instanceCount > existingInstance.geometry.userData.count + ) { + console.log("recreating instance"); scene.remove(existingInstance); instances.splice(instances.indexOf(existingInstance), 1); existingInstance = new InstancedMesh(geometry, material, instanceCount); - scene.add(existingInstance) - instances.push(existingInstance) + scene.add(existingInstance); + instances.push(existingInstance); } else if (!existingInstance) { - console.log("creating instance") + console.log("creating instance"); existingInstance = new InstancedMesh(geometry, material, instanceCount); - scene.add(existingInstance) - instances.push(existingInstance) + scene.add(existingInstance); + instances.push(existingInstance); } else { - console.log("updating instance") + console.log("updating instance"); existingInstance.count = instanceCount; } @@ -225,28 +227,31 @@ export function createInstancedGeometryPool(parentScene: Group, material: Materi const matrices = new Float32Array( data.buffer, index * 4, - instanceCount * 16); + instanceCount * 16, + ); for (let i = 0; i < instanceCount; i++) { - const matrix = new Matrix4().fromArray(matrices.subarray(i * 16, i * 16 + 16)); + const matrix = new Matrix4().fromArray( + matrices.subarray(i * 16, i * 16 + 16), + ); existingInstance.setMatrixAt(i, matrix); } geometry.userData = { vertexCount, faceCount, - count: Math.max(instanceCount, existingInstance.geometry.userData.count || 0), + count: Math.max( + instanceCount, + existingInstance.geometry.userData.count || 0, + ), hash, }; existingInstance.instanceMatrix.needsUpdate = true; - } return { - update( - newData: Int32Array[], - ) { + update(newData: Int32Array[]) { totalVertices = 0; totalFaces = 0; for (let i = 0; i < Math.max(newData.length, instances.length); i++) { @@ -260,6 +265,6 @@ export function createInstancedGeometryPool(parentScene: Group, material: Materi } } return { totalVertices, totalFaces }; - } - } + }, + }; } diff --git a/app/src/lib/runtime/runtime-executor.ts b/app/src/lib/runtime/runtime-executor.ts index 8c3e9c0..d4ee625 100644 --- a/app/src/lib/runtime/runtime-executor.ts +++ b/app/src/lib/runtime/runtime-executor.ts @@ -1,12 +1,26 @@ -import type { Graph, NodeDefinition, NodeInput, NodeRegistry, RuntimeExecutor, SyncCache } from "@nodes/types"; -import { concatEncodedArrays, createLogger, encodeFloat, fastHashArrayBuffer, type PerformanceStore } from "@nodes/utils"; +import type { + Graph, + Node, + NodeDefinition, + NodeInput, + NodeRegistry, + RuntimeExecutor, + SyncCache, +} from "@nodes/types"; +import { + concatEncodedArrays, + createLogger, + encodeFloat, + fastHashArrayBuffer, + type PerformanceStore, +} from "@nodes/utils"; const log = createLogger("runtime-executor"); -log.mute() +log.mute(); function getValue(input: NodeInput, value?: unknown) { if (value === undefined && "value" in input) { - value = input.value + value = input.value; } if (input.type === "float") { @@ -15,7 +29,13 @@ function getValue(input: NodeInput, value?: unknown) { if (Array.isArray(value)) { if (input.type === "vec3") { - return [0, value.length + 1, ...value.map(v => encodeFloat(v)), 1, 1] as number[]; + return [ + 0, + value.length + 1, + ...value.map((v) => encodeFloat(v)), + 1, + 1, + ] as number[]; } return [0, value.length + 1, ...value, 1, 1] as number[]; } @@ -36,22 +56,23 @@ function getValue(input: NodeInput, value?: unknown) { } export class MemoryRuntimeExecutor implements RuntimeExecutor { - private definitionMap: Map = new Map(); private randomSeed = Math.floor(Math.random() * 100000000); perf?: PerformanceStore; - constructor(private registry: NodeRegistry, private cache?: SyncCache) { } + constructor( + private registry: NodeRegistry, + private cache?: SyncCache, + ) {} private async getNodeDefinitions(graph: Graph) { - if (this.registry.status !== "ready") { throw new Error("Node registry is not ready"); } - await this.registry.load(graph.nodes.map(node => node.type)); + await this.registry.load(graph.nodes.map((node) => node.type)); const typeMap = new Map(); for (const node of graph.nodes) { @@ -66,18 +87,22 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { } private async addMetaData(graph: Graph) { - // First, lets check if all nodes have a definition this.definitionMap = await this.getNodeDefinitions(graph); - const outputNode = graph.nodes.find(node => node.type.endsWith("/output")); + const outputNode = graph.nodes.find((node) => + node.type.endsWith("/output"), + ) as Node; if (!outputNode) { throw new Error("No output node found"); } + outputNode.tmp = outputNode.tmp || {}; outputNode.tmp.depth = 0; - const nodeMap = new Map(graph.nodes.map(node => [node.id, node])); + const nodeMap = new Map( + graph.nodes.map((node) => [node.id, node]), + ); // loop through all edges and assign the parent and child nodes to each node for (const edge of graph.edges) { @@ -96,7 +121,7 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { } } - const nodes = [] + const nodes = []; // loop through all the nodes and assign each nodes its depth const stack = [outputNode]; @@ -125,7 +150,6 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { } async execute(graph: Graph, settings: Record) { - this.perf?.addPoint("runtime"); let a = performance.now(); @@ -137,71 +161,74 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { this.perf?.addPoint("collect-metadata", b - a); /* - * Here we sort the nodes into buckets, which we then execute one by one - * +-b2-+-b1-+---b0---+ - * | | | | - * | n3 | n2 | Output | - * | n6 | n4 | Level | - * | | n5 | | - * | | | | - * +----+----+--------+ - */ + * Here we sort the nodes into buckets, which we then execute one by one + * +-b2-+-b1-+---b0---+ + * | | | | + * | n3 | n2 | Output | + * | n6 | n4 | Level | + * | | n5 | | + * | | | | + * +----+----+--------+ + */ // we execute the nodes from the bottom up - const sortedNodes = nodes.sort((a, b) => (b.tmp?.depth || 0) - (a.tmp?.depth || 0)); + const sortedNodes = nodes.sort( + (a, b) => (b.tmp?.depth || 0) - (a.tmp?.depth || 0), + ); // here we store the intermediate results of the nodes const results: Record = {}; for (const node of sortedNodes) { - const node_type = this.definitionMap.get(node.type)!; if (!node_type || !node.tmp || !node_type.execute) { log.warn(`Node ${node.id} has no definition`); continue; - }; + } a = performance.now(); // Collect the inputs for the node - const inputs = Object.entries(node_type.inputs || {}).map(([key, input]) => { - - if (input.type === "seed") { - if (settings["randomSeed"] === true) { - return Math.floor(Math.random() * 100000000) - } else { - return this.randomSeed + const inputs = Object.entries(node_type.inputs || {}).map( + ([key, input]) => { + if (input.type === "seed") { + if (settings["randomSeed"] === true) { + return Math.floor(Math.random() * 100000000); + } else { + return this.randomSeed; + } } - } - // If the input is linked to a setting, we use that value - if (input.setting) { - return getValue(input, settings[input.setting]); - } - - // check if the input is connected to another node - const inputNode = node.tmp?.inputNodes?.[key]; - if (inputNode) { - if (results[inputNode.id] === undefined) { - throw new Error(`Node ${node.type} is missing input from node ${inputNode.type}`); + // If the input is linked to a setting, we use that value + if (input.setting) { + return getValue(input, settings[input.setting]); } - return results[inputNode.id]; - } - // If the value is stored in the node itself, we use that value - if (node.props?.[key] !== undefined) { - return getValue(input, node.props[key]); - } + // check if the input is connected to another node + const inputNode = node.tmp?.inputNodes?.[key]; + if (inputNode) { + if (results[inputNode.id] === undefined) { + throw new Error( + `Node ${node.type} is missing input from node ${inputNode.type}`, + ); + } + return results[inputNode.id]; + } - return getValue(input); - }); + // If the value is stored in the node itself, we use that value + if (node.props?.[key] !== undefined) { + return getValue(input, node.props[key]); + } + + return getValue(input); + }, + ); b = performance.now(); this.perf?.addPoint("collected-inputs", b - a); try { - a = performance.now(); const encoded_inputs = concatEncodedArrays(inputs); b = performance.now(); @@ -234,13 +261,10 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { this.perf?.addPoint("node/" + node_type.id, b - a); log.log("Result:", results[node.id]); log.groupEnd(); - } catch (e) { log.groupEnd(); log.error(`Error executing node ${node_type.id || node.id}`, e); } - - } // return the result of the parent of the output node @@ -253,11 +277,9 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor { this.perf?.endPoint("runtime"); return res as unknown as Int32Array; - } getPerformanceData() { return this.perf?.get(); } - } diff --git a/app/src/lib/runtime/worker-runtime-executor-backend.ts b/app/src/lib/runtime/worker-runtime-executor-backend.ts index 650323a..46b59aa 100644 --- a/app/src/lib/runtime/worker-runtime-executor-backend.ts +++ b/app/src/lib/runtime/worker-runtime-executor-backend.ts @@ -6,14 +6,16 @@ import { MemoryRuntimeCache } from "./runtime-executor-cache"; const cache = new MemoryRuntimeCache(); const indexDbCache = new IndexDBCache("node-registry"); -const nodeRegistry = new RemoteNodeRegistry(""); -nodeRegistry.cache = indexDbCache; +const nodeRegistry = new RemoteNodeRegistry("", indexDbCache); const executor = new MemoryRuntimeExecutor(nodeRegistry, cache); const performanceStore = createPerformanceStore(); executor.perf = performanceStore; -export async function executeGraph(graph: Graph, settings: Record): Promise { +export async function executeGraph( + graph: Graph, + settings: Record, +): Promise { await nodeRegistry.load(graph.nodes.map((n) => n.type)); performanceStore.startRun(); let res = await executor.execute(graph, settings); diff --git a/app/src/lib/settings/NestedSettings.svelte b/app/src/lib/settings/NestedSettings.svelte index aa9141a..853e62d 100644 --- a/app/src/lib/settings/NestedSettings.svelte +++ b/app/src/lib/settings/NestedSettings.svelte @@ -1,7 +1,3 @@ - - {#if key && isNodeInput(type?.[key])} + {#if type[key].type === "button"} console.log(type[key])}> @@ -94,7 +119,8 @@ {/if} {:else if depth === 0} - {#each Object.keys(type ?? {}).filter((key) => key !== "title") as childKey} + + {#each Object.keys(type ?? {}).filter((k) => k !== "title") as childKey} {:else if key && type?.[key]} + {#if depth > 0} {/if} - {type[key]?.title || key} + {(type[key] as SettingsGroup).title || key} - {#each Object.keys(type[key]).filter((key) => key !== "title") as childKey} + {#each Object.keys(type[key] as SettingsGroup).filter((k) => k !== "title") as childKey} {/each} @@ -156,6 +183,7 @@ flex-direction: row; align-items: center; } + .input-boolean > label { order: 2; } diff --git a/app/src/lib/settings/app-settings.svelte.ts b/app/src/lib/settings/app-settings.svelte.ts index c90a64f..ca9863f 100644 --- a/app/src/lib/settings/app-settings.svelte.ts +++ b/app/src/lib/settings/app-settings.svelte.ts @@ -1,5 +1,6 @@ import { localState } from "$lib/helpers/localState.svelte"; import type { NodeInput } from "@nodes/types"; +import type { SettingsType } from "."; const themes = [ "dark", @@ -118,7 +119,7 @@ export const AppSettingTypes = { }, }, }, -} as const; +} as const satisfies SettingsType; type IsInputDefinition = T extends NodeInput ? T : never; type HasTitle = { title: string }; diff --git a/app/src/lib/settings/index.ts b/app/src/lib/settings/index.ts index 7f1959b..28b4cc1 100644 --- a/app/src/lib/settings/index.ts +++ b/app/src/lib/settings/index.ts @@ -2,12 +2,26 @@ import type { NodeInput } from "@nodes/types"; type Button = { type: "button"; label?: string }; +export type SettingsStore = { + [key: string]: SettingsStore | string | number | boolean; +}; + type InputType = NodeInput | Button; -export interface SettingsType { - [key: string]: (SettingsType & { title?: string }) | InputType; +type SettingsNode = InputType | SettingsGroup; + +export interface SettingsGroup { + title?: string; + [key: string]: SettingsNode | string | number | undefined; } -export type SettingsStore = { - [key: string]: SettingsStore | string | number | boolean -}; +export type SettingsType = Record; + +export type SettingsValue = Record< + string, + Record | string | number | boolean | number[] +>; + +export function isNodeInput(v: SettingsNode | undefined): v is InputType { + return !!v && "type" in v; +} diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte index e7997b9..6c59582 100644 --- a/app/src/routes/+page.svelte +++ b/app/src/routes/+page.svelte @@ -26,6 +26,7 @@ import { IndexDBCache, RemoteNodeRegistry } from "@nodes/registry"; import { createPerformanceStore } from "@nodes/utils"; import BenchmarkPanel from "$lib/sidebar/panels/BenchmarkPanel.svelte"; + import { debounceAsyncFunction } from "$lib/helpers"; let performanceStore = createPerformanceStore(); @@ -79,40 +80,39 @@ }); let runIndex = 0; - const handleUpdate = async ( - g: Graph, - s: Record = graphSettings, - ) => { - runIndex++; - performanceStore.startRun(); - try { - let a = performance.now(); - const graphResult = await runtime.execute( - $state.snapshot(g), - $state.snapshot(s), - ); - let b = performance.now(); + const handleUpdate = debounceAsyncFunction( + async (g: Graph, s: Record = graphSettings) => { + runIndex++; + performanceStore.startRun(); + try { + let a = performance.now(); + const graphResult = await runtime.execute( + $state.snapshot(g), + $state.snapshot(s), + ); + let b = performance.now(); - if (appSettings.debug.useWorker) { - let perfData = await runtime.getPerformanceData(); - let lastRun = perfData?.at(-1); - if (lastRun?.total) { - lastRun.runtime = lastRun.total; - delete lastRun.total; - performanceStore.mergeData(lastRun); - performanceStore.addPoint( - "worker-transfer", - b - a - lastRun.runtime[0], - ); + if (appSettings.debug.useWorker) { + let perfData = await runtime.getPerformanceData(); + let lastRun = perfData?.at(-1); + if (lastRun?.total) { + lastRun.runtime = lastRun.total; + delete lastRun.total; + performanceStore.mergeData(lastRun); + performanceStore.addPoint( + "worker-transfer", + b - a - lastRun.runtime[0], + ); + } } + viewerComponent?.update(graphResult); + } catch (error) { + console.log("errors", error); + } finally { + performanceStore.stopRun(); } - viewerComponent?.update(graphResult); - } catch (error) { - console.log("errors", error); - } finally { - performanceStore.stopRun(); - } - }; + }, + ); $effect(() => { //@ts-ignore diff --git a/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts b/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts index 6acc01f..dfb6cfe 100644 --- a/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts +++ b/app/src/routes/nodes/[user]/[collection]/[node].wasm/+server.ts @@ -1,27 +1,36 @@ -import type { RequestHandler } from "./$types"; +import type { EntryGenerator, RequestHandler } from "./$types"; import * as registry from "$lib/node-registry"; -import type { EntryGenerator } from "../$types"; export const prerender = true; export const entries: EntryGenerator = async () => { const users = await registry.getUsers(); - return users.map(user => { - return user.collections.map(collection => { - return collection.nodes.map(node => { - return { user: user.id, collection: collection.id.split("/")[1], node: node.id.split("/")[2] } + return users + .map((user) => { + return user.collections.map((collection) => { + return collection.nodes.map((node) => { + return { + user: user.id, + collection: collection.id.split("/")[1], + node: node.id.split("/")[2], + }; + }); }); }) - }).flat(2); -} + .flat(2); +}; export const GET: RequestHandler = async function GET({ params }) { - - const wasm = await registry.getWasm(`${params.user}/${params.collection}/${params.node}`); + const wasm = await registry.getWasm( + `${params.user}/${params.collection}/${params.node}`, + ); if (!wasm) { return new Response("Not found", { status: 404 }); } - return new Response(wasm, { status: 200, headers: { "Content-Type": "application/wasm" } }); -} + return new Response(wasm, { + status: 200, + headers: { "Content-Type": "application/wasm" }, + }); +}; diff --git a/packages/types/src/components.ts b/packages/types/src/components.ts index df4c7cf..d2b67f1 100644 --- a/packages/types/src/components.ts +++ b/packages/types/src/components.ts @@ -1,4 +1,4 @@ -import { Graph, NodeDefinition, NodeType } from "./types"; +import type { Graph, NodeDefinition, NodeType } from "./types"; export interface NodeRegistry { /** diff --git a/packages/types/src/inputs.ts b/packages/types/src/inputs.ts index b07f5eb..a26877d 100644 --- a/packages/types/src/inputs.ts +++ b/packages/types/src/inputs.ts @@ -6,11 +6,23 @@ const DefaultOptionsSchema = z.object({ setting: z.string().optional(), label: z.string().optional(), description: z.string().optional(), - accepts: z.array(z.string()).optional(), + accepts: z + .array( + z.union([ + z.literal("float"), + z.literal("integer"), + z.literal("boolean"), + z.literal("select"), + z.literal("seed"), + z.literal("vec3"), + z.literal("geometry"), + z.literal("path"), + ]), + ) + .optional(), hidden: z.boolean().optional(), }); - export const NodeInputFloatSchema = z.object({ ...DefaultOptionsSchema.shape, type: z.literal("float"), @@ -40,7 +52,7 @@ export const NodeInputSelectSchema = z.object({ ...DefaultOptionsSchema.shape, type: z.literal("select"), options: z.array(z.string()).optional(), - value: z.number().optional(), + value: z.string().optional(), }); export const NodeInputSeedSchema = z.object({ @@ -74,7 +86,7 @@ export const NodeInputSchema = z.union([ NodeInputSeedSchema, NodeInputVec3Schema, NodeInputGeometrySchema, - NodeInputPathSchema + NodeInputPathSchema, ]); export type NodeInput = z.infer; diff --git a/packages/types/src/types.ts b/packages/types/src/types.ts index b33c9d7..9d1434f 100644 --- a/packages/types/src/types.ts +++ b/packages/types/src/types.ts @@ -8,22 +8,6 @@ export const NodeTypeSchema = z export type NodeType = z.infer; -export const NodeSchema = z.object({ - id: z.number(), - type: NodeTypeSchema, - tmp: z.any().optional(), - props: z - .record(z.string(), z.union([z.number(), z.array(z.number())])) - .optional(), - meta: z - .object({ - title: z.string().optional(), - lastModified: z.string().optional(), - }) - .optional(), - position: z.tuple([z.number(), z.number()]), -}); - export type Node = { tmp?: { depth?: number; @@ -55,6 +39,21 @@ export const NodeDefinitionSchema = z.object({ .optional(), }); +export const NodeSchema = z.object({ + id: z.number(), + type: NodeTypeSchema, + props: z + .record(z.string(), z.union([z.number(), z.array(z.number())])) + .optional(), + meta: z + .object({ + title: z.string().optional(), + lastModified: z.string().optional(), + }) + .optional(), + position: z.tuple([z.number(), z.number()]), +}); + export type NodeDefinition = z.infer & { execute(input: Int32Array): Int32Array; }; diff --git a/packages/ui/src/lib/Details.svelte b/packages/ui/src/lib/Details.svelte index 5c21148..c1b2049 100644 --- a/packages/ui/src/lib/Details.svelte +++ b/packages/ui/src/lib/Details.svelte @@ -3,12 +3,13 @@ title?: string; transparent?: boolean; children?: import('svelte').Snippet; + open?: boolean; } - let { title = "Details", transparent = false, children }: Props = $props(); + let { title = "Details", transparent = false, children, open = $bindable(false) }: Props = $props(); - + {title} {@render children?.()} @@ -33,7 +34,4 @@ outline: none; } - .content { - /* padding-left: 12px; */ - } diff --git a/packages/utils/src/fastHash.ts b/packages/utils/src/fastHash.ts index 6019522..8feba27 100644 --- a/packages/utils/src/fastHash.ts +++ b/packages/utils/src/fastHash.ts @@ -1,47 +1,84 @@ - // https://github.com/6502/sha256/blob/main/sha256.js -function sha256(data?: string | Uint8Array) { - let h0 = 0x6a09e667, h1 = 0xbb67ae85, h2 = 0x3c6ef372, h3 = 0xa54ff53a, - h4 = 0x510e527f, h5 = 0x9b05688c, h6 = 0x1f83d9ab, h7 = 0x5be0cd19, - tsz = 0, bp = 0; - const k = [0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, - 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, - 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, - 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, - 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, - 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, - 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, - 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2], - rrot = (x, n) => (x >>> n) | (x << (32 - n)), +function sha256(data?: string | Int32Array) { + let h0 = 0x6a09e667, + h1 = 0xbb67ae85, + h2 = 0x3c6ef372, + h3 = 0xa54ff53a, + h4 = 0x510e527f, + h5 = 0x9b05688c, + h6 = 0x1f83d9ab, + h7 = 0x5be0cd19, + tsz = 0, + bp = 0; + const k = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, + 0x923f82a4, 0xab1c5ed5, 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, 0xe49b69c1, 0xefbe4786, + 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, + 0x06ca6351, 0x14292967, 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, 0xa2bfe8a1, 0xa81a664b, + 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, + 0x5b9cca4f, 0x682e6ff3, 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, + ], + rrot = (x: number, n: number) => (x >>> n) | (x << (32 - n)), w = new Uint32Array(64), buf = new Uint8Array(64), process = () => { for (let j = 0, r = 0; j < 16; j++, r += 4) { - w[j] = (buf[r] << 24) | (buf[r + 1] << 16) | (buf[r + 2] << 8) | buf[r + 3]; + w[j] = + (buf[r] << 24) | (buf[r + 1] << 16) | (buf[r + 2] << 8) | buf[r + 3]; } for (let j = 16; j < 64; j++) { let s0 = rrot(w[j - 15], 7) ^ rrot(w[j - 15], 18) ^ (w[j - 15] >>> 3); let s1 = rrot(w[j - 2], 17) ^ rrot(w[j - 2], 19) ^ (w[j - 2] >>> 10); w[j] = (w[j - 16] + s0 + w[j - 7] + s1) | 0; } - let a = h0, b = h1, c = h2, d = h3, e = h4, f = h5, g = h6, h = h7; + let a = h0, + b = h1, + c = h2, + d = h3, + e = h4, + f = h5, + g = h6, + h = h7; for (let j = 0; j < 64; j++) { let S1 = rrot(e, 6) ^ rrot(e, 11) ^ rrot(e, 25), - ch = (e & f) ^ ((~e) & g), + ch = (e & f) ^ (~e & g), t1 = (h + S1 + ch + k[j] + w[j]) | 0, S0 = rrot(a, 2) ^ rrot(a, 13) ^ rrot(a, 22), maj = (a & b) ^ (a & c) ^ (b & c), t2 = (S0 + maj) | 0; - h = g; g = f; f = e; e = (d + t1) | 0; d = c; c = b; b = a; a = (t1 + t2) | 0; + h = g; + g = f; + f = e; + e = (d + t1) | 0; + d = c; + c = b; + b = a; + a = (t1 + t2) | 0; } - h0 = (h0 + a) | 0; h1 = (h1 + b) | 0; h2 = (h2 + c) | 0; h3 = (h3 + d) | 0; - h4 = (h4 + e) | 0; h5 = (h5 + f) | 0; h6 = (h6 + g) | 0; h7 = (h7 + h) | 0; + h0 = (h0 + a) | 0; + h1 = (h1 + b) | 0; + h2 = (h2 + c) | 0; + h3 = (h3 + d) | 0; + h4 = (h4 + e) | 0; + h5 = (h5 + f) | 0; + h6 = (h6 + g) | 0; + h7 = (h7 + h) | 0; bp = 0; }, - add = data => { - if (typeof data === "string") { - data = typeof TextEncoder === "undefined" ? Buffer.from(data) : (new TextEncoder).encode(data); - } + add = (input: string | Int32Array) => { + const data = + typeof input === "string" + ? typeof TextEncoder === "undefined" + ? //@ts-ignore + Buffer.from(input) + : new TextEncoder().encode(input) + : input; + for (let i = 0; i < data.length; i++) { buf[bp++] = data[i]; if (bp === 64) process(); @@ -49,7 +86,8 @@ function sha256(data?: string | Uint8Array) { tsz += data.length; }, digest = () => { - buf[bp++] = 0x80; if (bp == 64) process(); + buf[bp++] = 0x80; + if (bp == 64) process(); if (bp + 8 > 64) { while (bp < 64) buf[bp++] = 0x00; process(); @@ -57,24 +95,48 @@ function sha256(data?: string | Uint8Array) { while (bp < 58) buf[bp++] = 0x00; // Max number of bytes is 35,184,372,088,831 let L = tsz * 8; - buf[bp++] = (L / 1099511627776.) & 255; - buf[bp++] = (L / 4294967296.) & 255; + buf[bp++] = (L / 1099511627776) & 255; + buf[bp++] = (L / 4294967296) & 255; buf[bp++] = L >>> 24; buf[bp++] = (L >>> 16) & 255; buf[bp++] = (L >>> 8) & 255; buf[bp++] = L & 255; process(); let reply = new Uint8Array(32); - reply[0] = h0 >>> 24; reply[1] = (h0 >>> 16) & 255; reply[2] = (h0 >>> 8) & 255; reply[3] = h0 & 255; - reply[4] = h1 >>> 24; reply[5] = (h1 >>> 16) & 255; reply[6] = (h1 >>> 8) & 255; reply[7] = h1 & 255; - reply[8] = h2 >>> 24; reply[9] = (h2 >>> 16) & 255; reply[10] = (h2 >>> 8) & 255; reply[11] = h2 & 255; - reply[12] = h3 >>> 24; reply[13] = (h3 >>> 16) & 255; reply[14] = (h3 >>> 8) & 255; reply[15] = h3 & 255; - reply[16] = h4 >>> 24; reply[17] = (h4 >>> 16) & 255; reply[18] = (h4 >>> 8) & 255; reply[19] = h4 & 255; - reply[20] = h5 >>> 24; reply[21] = (h5 >>> 16) & 255; reply[22] = (h5 >>> 8) & 255; reply[23] = h5 & 255; - reply[24] = h6 >>> 24; reply[25] = (h6 >>> 16) & 255; reply[26] = (h6 >>> 8) & 255; reply[27] = h6 & 255; - reply[28] = h7 >>> 24; reply[29] = (h7 >>> 16) & 255; reply[30] = (h7 >>> 8) & 255; reply[31] = h7 & 255; + reply[0] = h0 >>> 24; + reply[1] = (h0 >>> 16) & 255; + reply[2] = (h0 >>> 8) & 255; + reply[3] = h0 & 255; + reply[4] = h1 >>> 24; + reply[5] = (h1 >>> 16) & 255; + reply[6] = (h1 >>> 8) & 255; + reply[7] = h1 & 255; + reply[8] = h2 >>> 24; + reply[9] = (h2 >>> 16) & 255; + reply[10] = (h2 >>> 8) & 255; + reply[11] = h2 & 255; + reply[12] = h3 >>> 24; + reply[13] = (h3 >>> 16) & 255; + reply[14] = (h3 >>> 8) & 255; + reply[15] = h3 & 255; + reply[16] = h4 >>> 24; + reply[17] = (h4 >>> 16) & 255; + reply[18] = (h4 >>> 8) & 255; + reply[19] = h4 & 255; + reply[20] = h5 >>> 24; + reply[21] = (h5 >>> 16) & 255; + reply[22] = (h5 >>> 8) & 255; + reply[23] = h5 & 255; + reply[24] = h6 >>> 24; + reply[25] = (h6 >>> 16) & 255; + reply[26] = (h6 >>> 8) & 255; + reply[27] = h6 & 255; + reply[28] = h7 >>> 24; + reply[29] = (h7 >>> 16) & 255; + reply[30] = (h7 >>> 8) & 255; + reply[31] = h7 & 255; let res = ""; - reply.forEach(x => res += ("0" + x.toString(16)).slice(-2)); + reply.forEach((x) => (res += ("0" + x.toString(16)).slice(-2))); return res; }; @@ -83,8 +145,8 @@ function sha256(data?: string | Uint8Array) { return { add, digest }; } -export function fastHashArrayBuffer(buffer: ArrayBuffer): string { - return sha256(new Uint8Array(buffer)).digest(); +export function fastHashArrayBuffer(buffer: string | Int32Array): string { + return sha256(buffer).digest(); } // Shamelessly copied from @@ -101,22 +163,19 @@ export function fastHashString(input: string) { return hash; } - export function fastHash(input: (string | Int32Array | number)[]) { - const s = sha256(); for (let i = 0; i < input.length; i++) { - const v = input[i] + const v = input[i]; if (typeof v === "string") { s.add(v); } else if (v instanceof Int32Array) { - s.add(new Uint8Array(v.buffer)); + s.add(v); } else { s.add(v.toString()); } } - return s.digest() - + return s.digest(); } diff --git a/packages/utils/src/flatTree.ts b/packages/utils/src/flatTree.ts index e1cfca7..ac47194 100644 --- a/packages/utils/src/flatTree.ts +++ b/packages/utils/src/flatTree.ts @@ -1,7 +1,8 @@ type SparseArray = (T | T[] | SparseArray)[]; -export function concatEncodedArrays(input: (number | number[] | Int32Array)[]): Int32Array { - +export function concatEncodedArrays( + input: (number | number[] | Int32Array)[], +): Int32Array { let totalLength = 4; for (let i = 0; i < input.length; i++) { const item = input[i]; @@ -36,7 +37,7 @@ export function concatEncodedArrays(input: (number | number[] | Int32Array)[]): result[totalLength - 2] = 1; result[totalLength - 1] = 1; - return result + return result; } // Encodes a nested array into a flat array with bracket and distance notation @@ -68,12 +69,11 @@ export function encodeNestedArray(array: SparseArray): number[] { } return [...encoded, 1, 1]; -}; +} function decode_recursive(dense: number[] | Int32Array, index = 0) { - if (dense instanceof Int32Array) { - dense = Array.from(dense) + dense = Array.from(dense); } const decoded: (number | number[])[] = []; @@ -82,12 +82,17 @@ function decode_recursive(dense: number[] | Int32Array, index = 0) { index += 2; // Skip the initial bracket notation while (index < dense.length) { if (index === nextBracketIndex) { - if (dense[index] === 0) { // Opening bracket detected - const [p, nextIndex, _nextBracketIndex] = decode_recursive(dense, index); - decoded.push(p); + if (dense[index] === 0) { + // Opening bracket detected + const [p, nextIndex, _nextBracketIndex] = decode_recursive( + dense, + index, + ); + decoded.push(...p); index = nextIndex + 1; nextBracketIndex = _nextBracketIndex; - } else { // Closing bracket detected + } else { + // Closing bracket detected nextBracketIndex = dense[index + 1] + index + 1; return [decoded, index, nextBracketIndex] as const; } @@ -103,7 +108,6 @@ export function decodeNestedArray(dense: number[] | Int32Array) { return decode_recursive(dense, 0)[0]; } - export function splitNestedArray(input: Int32Array) { let index = 0; const length = input.length; diff --git a/packages/utils/src/wasm-wrapper.ts b/packages/utils/src/wasm-wrapper.ts index 8c71e4f..60e4b3a 100644 --- a/packages/utils/src/wasm-wrapper.ts +++ b/packages/utils/src/wasm-wrapper.ts @@ -1,21 +1,25 @@ +//@ts-nocheck import { NodeDefinition } from "@nodes/types"; -const cachedTextDecoder = new TextDecoder('utf-8', { ignoreBOM: true, fatal: true }); +const cachedTextDecoder = new TextDecoder("utf-8", { + ignoreBOM: true, + fatal: true, +}); const cachedTextEncoder = new TextEncoder(); - -const encodeString = (typeof cachedTextEncoder.encodeInto === 'function' - ? function (arg, view) { - return cachedTextEncoder.encodeInto(arg, view); - } - : function (arg, view) { - const buf = cachedTextEncoder.encode(arg); - view.set(buf); - return { - read: arg.length, - written: buf.length - }; - }); +const encodeString = + typeof cachedTextEncoder.encodeInto === "function" + ? function (arg, view) { + return cachedTextEncoder.encodeInto(arg, view); + } + : function (arg, view) { + const buf = cachedTextEncoder.encode(arg); + view.set(buf); + return { + read: arg.length, + written: buf.length, + }; + }; function createWrapper() { let wasm: any; @@ -53,7 +57,9 @@ function createWrapper() { return cachedTextDecoder.decode(getUint8Memory0().subarray(ptr, ptr + len)); } - function getObject(idx: number) { return heap[idx]; } + function getObject(idx: number) { + return heap[idx]; + } function addHeapObject(obj: any) { if (heap_next === heap.length) heap.push(heap.length + 1); @@ -63,9 +69,11 @@ function createWrapper() { return idx; } - let WASM_VECTOR_LEN = 0; - function passArray32ToWasm0(arg: ArrayLike, malloc: (arg0: number, arg1: number) => number) { + function passArray32ToWasm0( + arg: ArrayLike, + malloc: (arg0: number, arg1: number) => number, + ) { const ptr = malloc(arg.length * 4, 4) >>> 0; getUint32Memory0().set(arg, ptr / 4); WASM_VECTOR_LEN = arg.length; @@ -89,21 +97,10 @@ function createWrapper() { return ret; } - function getArrayJsValueFromWasm0(ptr: number, len: number) { - ptr = ptr >>> 0; - const mem = getUint32Memory0(); - const slice = mem.subarray(ptr / 4, ptr / 4 + len); - const result = []; - for (let i = 0; i < slice.length; i++) { - result.push(takeObject(slice[i])); - } - return result; - } - function __wbindgen_string_new(arg0: number, arg1: number) { const ret = getStringFromWasm0(arg0, arg1); return addHeapObject(ret); - }; + } // Additional methods and their internal helpers can also be refactored in a similar manner. function get_definition() { @@ -124,7 +121,6 @@ function createWrapper() { } } - function execute(args: Int32Array) { try { const retptr = wasm.__wbindgen_add_to_stack_pointer(-16); @@ -141,12 +137,19 @@ function createWrapper() { } } - function passStringToWasm0(arg: string, malloc: (arg0: any, arg1: number) => number, realloc: ((arg0: number, arg1: any, arg2: number, arg3: number) => number) | undefined) { - + function passStringToWasm0( + arg: string, + malloc: (arg0: any, arg1: number) => number, + realloc: + | ((arg0: number, arg1: any, arg2: number, arg3: number) => number) + | undefined, + ) { if (realloc === undefined) { const buf = cachedTextEncoder.encode(arg); const ptr = malloc(buf.length, 1) >>> 0; - getUint8Memory0().subarray(ptr, ptr + buf.length).set(buf); + getUint8Memory0() + .subarray(ptr, ptr + buf.length) + .set(buf); WASM_VECTOR_LEN = buf.length; return ptr; } @@ -160,7 +163,7 @@ function createWrapper() { for (; offset < len; offset++) { const code = arg.charCodeAt(offset); - if (code > 0x7F) break; + if (code > 0x7f) break; mem[ptr + offset] = code; } @@ -168,7 +171,7 @@ function createWrapper() { if (offset !== 0) { arg = arg.slice(offset); } - ptr = realloc(ptr, len, len = offset + arg.length * 3, 1) >>> 0; + ptr = realloc(ptr, len, (len = offset + arg.length * 3), 1) >>> 0; const view = getUint8Memory0().subarray(ptr + offset, ptr + len); const ret = encodeString(arg, view); @@ -183,15 +186,19 @@ function createWrapper() { function __wbg_new_abda76e883ba8a5f() { const ret = new Error(); return addHeapObject(ret); - }; + } function __wbg_stack_658279fe44541cf6(arg0, arg1) { const ret = getObject(arg1).stack; - const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc); + const ptr1 = passStringToWasm0( + ret, + wasm.__wbindgen_malloc, + wasm.__wbindgen_realloc, + ); const len1 = WASM_VECTOR_LEN; getInt32Memory0()[arg0 / 4 + 1] = len1; getInt32Memory0()[arg0 / 4 + 0] = ptr1; - }; + } function __wbg_error_f851667af71bcfc6(arg0, arg1) { let deferred0_0; @@ -203,27 +210,25 @@ function createWrapper() { } finally { wasm.__wbindgen_free(deferred0_0, deferred0_1, 1); } - }; - + } function __wbindgen_object_drop_ref(arg0) { takeObject(arg0); - }; + } function __wbg_log_5bb5f88f245d7762(arg0) { console.log(getObject(arg0)); - }; + } function __wbindgen_throw(arg0, arg1) { throw new Error(getStringFromWasm0(arg0, arg1)); - }; + } return { setInstance(instance: WebAssembly.Instance) { wasm = instance.exports; }, - exports: { // Expose other methods that interact with the wasm instance execute, @@ -240,11 +245,12 @@ function createWrapper() { }; } - -export function createWasmWrapper(wasmBuffer: ArrayBuffer) { +export function createWasmWrapper(wasmBuffer: ArrayBuffer | Uint8Array) { const wrapper = createWrapper(); const module = new WebAssembly.Module(wasmBuffer); - const instance = new WebAssembly.Instance(module, { ["./index_bg.js"]: wrapper }); + const instance = new WebAssembly.Instance(module, { + ["./index_bg.js"]: wrapper, + }); wrapper.setInstance(instance); return wrapper.exports; }
{type[key]?.title || key}
{(type[key] as SettingsGroup).title || key}