feat: refactor how frontend was structured
Some checks failed
Deploy to GitHub Pages / build_site (push) Failing after 1m16s
Some checks failed
Deploy to GitHub Pages / build_site (push) Failing after 1m16s
This commit is contained in:
parent
f51f61df17
commit
c28ef550a9
@ -27,6 +27,8 @@
|
|||||||
export let showGrid = false;
|
export let showGrid = false;
|
||||||
export let snapToGrid = false;
|
export let snapToGrid = false;
|
||||||
|
|
||||||
|
export let settingTypes = {};
|
||||||
|
|
||||||
const updateSettings = debounce((s) => {
|
const updateSettings = debounce((s) => {
|
||||||
manager.setSettings(s);
|
manager.setSettings(s);
|
||||||
}, 200);
|
}, 200);
|
||||||
@ -36,7 +38,8 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
manager.on("settings", (settings) => {
|
manager.on("settings", (settings) => {
|
||||||
dispatch("settings", settings);
|
settingTypes = settings.types;
|
||||||
|
$settings = settings.values;
|
||||||
});
|
});
|
||||||
|
|
||||||
manager.on("result", (result) => {
|
manager.on("result", (result) => {
|
||||||
|
@ -3,6 +3,8 @@ import { createWasmWrapper } from "@nodes/utils";
|
|||||||
import { createLogger } from "./helpers";
|
import { createLogger } from "./helpers";
|
||||||
|
|
||||||
const log = createLogger("node-registry");
|
const log = createLogger("node-registry");
|
||||||
|
log.mute();
|
||||||
|
|
||||||
export class RemoteNodeRegistry implements NodeRegistry {
|
export class RemoteNodeRegistry implements NodeRegistry {
|
||||||
|
|
||||||
status: "loading" | "ready" | "error" = "loading";
|
status: "loading" | "ready" | "error" = "loading";
|
||||||
@ -10,9 +12,6 @@ export class RemoteNodeRegistry implements NodeRegistry {
|
|||||||
|
|
||||||
constructor(private url: string) { }
|
constructor(private url: string) { }
|
||||||
|
|
||||||
async loadNode(id: `${string}/${string}/${string}`) {
|
|
||||||
}
|
|
||||||
|
|
||||||
async fetchUsers() {
|
async fetchUsers() {
|
||||||
const response = await fetch(`${this.url}/nodes/users.json`);
|
const response = await fetch(`${this.url}/nodes/users.json`);
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -58,6 +57,10 @@ export class RemoteNodeRegistry implements NodeRegistry {
|
|||||||
|
|
||||||
const nodes = await Promise.all(nodeIds.map(async id => {
|
const nodes = await Promise.all(nodeIds.map(async id => {
|
||||||
|
|
||||||
|
if (this.nodes.has(id)) {
|
||||||
|
return this.nodes.get(id);
|
||||||
|
}
|
||||||
|
|
||||||
const wasmResponse = await this.fetchNode(id);
|
const wasmResponse = await this.fetchNode(id);
|
||||||
|
|
||||||
const wrapper = createWasmWrapper(wasmResponse);
|
const wrapper = createWasmWrapper(wasmResponse);
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
import BreadCrumbs from "./BreadCrumbs.svelte";
|
import BreadCrumbs from "./BreadCrumbs.svelte";
|
||||||
import DraggableNode from "./DraggableNode.svelte";
|
import DraggableNode from "./DraggableNode.svelte";
|
||||||
|
|
||||||
export let nodeRegistry: RemoteNodeRegistry;
|
export let registry: RemoteNodeRegistry;
|
||||||
|
|
||||||
const activeId = localStore<
|
const activeId = localStore<
|
||||||
`${string}` | `${string}/${string}` | `${string}/${string}/${string}`
|
`${string}` | `${string}/${string}` | `${string}/${string}/${string}`
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<div class="header">
|
<div class="header">
|
||||||
<h3>Users</h3>
|
<h3>Users</h3>
|
||||||
</div>
|
</div>
|
||||||
{#await nodeRegistry.fetchUsers()}
|
{#await registry.fetchUsers()}
|
||||||
<div>Loading...</div>
|
<div>Loading...</div>
|
||||||
{:then users}
|
{:then users}
|
||||||
{#each users as user}
|
{#each users as user}
|
||||||
@ -34,7 +34,7 @@
|
|||||||
<div>{error.message}</div>
|
<div>{error.message}</div>
|
||||||
{/await}
|
{/await}
|
||||||
{:else if !activeCollection}
|
{:else if !activeCollection}
|
||||||
{#await nodeRegistry.fetchUser(activeUser)}
|
{#await registry.fetchUser(activeUser)}
|
||||||
<div>Loading...</div>
|
<div>Loading...</div>
|
||||||
{:then user}
|
{:then user}
|
||||||
<div class="header">
|
<div class="header">
|
||||||
@ -68,11 +68,11 @@
|
|||||||
></button>
|
></button>
|
||||||
<h3>Nodes</h3>
|
<h3>Nodes</h3>
|
||||||
</div>
|
</div>
|
||||||
{#await nodeRegistry.fetchCollection(`${activeUser}/${activeCollection}`)}
|
{#await registry.fetchCollection(`${activeUser}/${activeCollection}`)}
|
||||||
<div>Loading...</div>
|
<div>Loading...</div>
|
||||||
{:then collection}
|
{:then collection}
|
||||||
{#each collection.nodes as node}
|
{#each collection.nodes as node}
|
||||||
{#await nodeRegistry.fetchNodeDefinition(node.id)}
|
{#await registry.fetchNodeDefinition(node.id)}
|
||||||
<div>Loading...</div>
|
<div>Loading...</div>
|
||||||
{:then node}
|
{:then node}
|
||||||
<DraggableNode {node} />
|
<DraggableNode {node} />
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { PerformanceStore } from ".";
|
import type { PerformanceData } from ".";
|
||||||
|
|
||||||
export let store: PerformanceStore;
|
export let data: PerformanceData;
|
||||||
|
|
||||||
function getPerformanceData() {
|
function getPerformanceData() {
|
||||||
return Object.entries($store.total).sort((a, b) => b[1] - a[1]);
|
return Object.entries(data.total).sort((a, b) => b[1] - a[1]);
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $store.runs.length !== 0}
|
{#if data.runs.length !== 0}
|
||||||
{#each getPerformanceData() as [key, value]}
|
{#each getPerformanceData() as [key, value]}
|
||||||
<p>{key}: {Math.floor(value * 100) / 100}ms</p>
|
<p>{key}: {Math.floor(value * 100) / 100}ms</p>
|
||||||
{/each}
|
{/each}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { readable, type Readable } from "svelte/store";
|
import { readable, type Readable } from "svelte/store";
|
||||||
|
|
||||||
type PerformanceData = {
|
export type PerformanceData = {
|
||||||
total: Record<string, number>;
|
total: Record<string, number>;
|
||||||
runs: Record<string, number[]>[];
|
runs: Record<string, number[]>[];
|
||||||
}
|
}
|
||||||
@ -8,6 +8,7 @@ export interface PerformanceStore extends Readable<PerformanceData> {
|
|||||||
startRun(): void;
|
startRun(): void;
|
||||||
stopRun(): void;
|
stopRun(): void;
|
||||||
addPoint(name: string, value?: number): void;
|
addPoint(name: string, value?: number): void;
|
||||||
|
get: () => PerformanceData;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createPerformanceStore(): PerformanceStore {
|
export function createPerformanceStore(): PerformanceStore {
|
||||||
@ -41,7 +42,7 @@ export function createPerformanceStore(): PerformanceStore {
|
|||||||
|
|
||||||
data.runs.push(currentRun);
|
data.runs.push(currentRun);
|
||||||
currentRun = undefined;
|
currentRun = undefined;
|
||||||
set(data);
|
if (set) set(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,11 +52,16 @@ export function createPerformanceStore(): PerformanceStore {
|
|||||||
currentRun[name].push(value);
|
currentRun[name].push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function get() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
subscribe,
|
subscribe,
|
||||||
startRun,
|
startRun,
|
||||||
stopRun,
|
stopRun,
|
||||||
addPoint,
|
addPoint,
|
||||||
|
get
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Canvas } from "@threlte/core";
|
import { Canvas } from "@threlte/core";
|
||||||
import Scene from "./Scene.svelte";
|
import Scene from "./Scene.svelte";
|
||||||
import { Inspector } from "three-inspect";
|
|
||||||
import {
|
import {
|
||||||
BufferGeometry,
|
BufferGeometry,
|
||||||
Float32BufferAttribute,
|
Float32BufferAttribute,
|
||||||
@ -13,9 +12,10 @@
|
|||||||
|
|
||||||
export let result: Int32Array;
|
export let result: Int32Array;
|
||||||
|
|
||||||
export let camera: PerspectiveCamera;
|
let camera: PerspectiveCamera;
|
||||||
export let controls: OrbitControls;
|
let controls: OrbitControls;
|
||||||
export let center: Vector3;
|
let center: Vector3;
|
||||||
|
export let centerCamera: boolean = true;
|
||||||
|
|
||||||
let geometries: BufferGeometry[] = [];
|
let geometries: BufferGeometry[] = [];
|
||||||
let lines: Vector3[][] = [];
|
let lines: Vector3[][] = [];
|
||||||
|
39
app/src/lib/settings/Panel.svelte
Normal file
39
app/src/lib/settings/Panel.svelte
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import { getContext } from "svelte";
|
||||||
|
import type { Readable } from "svelte/store";
|
||||||
|
|
||||||
|
export let id: string;
|
||||||
|
export let icon: string = "";
|
||||||
|
export let title = "";
|
||||||
|
|
||||||
|
const registerPanel =
|
||||||
|
getContext<(id: string, icon: string) => Readable<boolean>>(
|
||||||
|
"registerPanel",
|
||||||
|
);
|
||||||
|
|
||||||
|
let visible = registerPanel(id, icon);
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $visible}
|
||||||
|
<div class="wrapper">
|
||||||
|
{#if title}
|
||||||
|
<header>
|
||||||
|
<h3>{title}</h3>
|
||||||
|
</header>
|
||||||
|
{/if}
|
||||||
|
<slot />
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
header {
|
||||||
|
border-bottom: solid thin var(--outline);
|
||||||
|
height: 69px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding-left: 1em;
|
||||||
|
}
|
||||||
|
h3 {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,33 +1,34 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { NodeInput } from "@nodes/types";
|
|
||||||
import type { Writable } from "svelte/store";
|
|
||||||
import localStore from "$lib/helpers/localStore";
|
import localStore from "$lib/helpers/localStore";
|
||||||
import type { SvelteComponent } from "svelte";
|
import { setContext } from "svelte";
|
||||||
import NestedSettings from "./NestedSettings.svelte";
|
import { derived } from "svelte/store";
|
||||||
|
|
||||||
export let panels: Record<
|
let panels: Record<
|
||||||
string,
|
string,
|
||||||
{
|
{
|
||||||
icon: string;
|
icon: string;
|
||||||
id: string;
|
id: string;
|
||||||
hidden?: boolean;
|
|
||||||
props?: Record<string, unknown>;
|
|
||||||
component?: typeof SvelteComponent<{}, {}, {}>;
|
|
||||||
definition: Record<string, NodeInput>;
|
|
||||||
settings: Writable<Record<string, unknown>>;
|
|
||||||
}
|
}
|
||||||
>;
|
> = {};
|
||||||
|
|
||||||
const activePanel = localStore<keyof typeof panels | false>(
|
const activePanel = localStore<keyof typeof panels | false>(
|
||||||
"nodes.settings.activePanel",
|
"nodes.settings.activePanel",
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
|
|
||||||
$: keys = panels
|
$: keys = panels
|
||||||
? (Object.keys(panels) as unknown as (keyof typeof panels)[]).filter(
|
? (Object.keys(panels) as unknown as (keyof typeof panels)[]).filter(
|
||||||
(key) => !!panels[key]?.id && panels[key]?.hidden !== true,
|
(key) => !!panels[key]?.id,
|
||||||
)
|
)
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
|
setContext("registerPanel", (id: string, icon: string) => {
|
||||||
|
panels[id] = { id, icon };
|
||||||
|
return derived(activePanel, ($activePanel) => {
|
||||||
|
return $activePanel === id;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
function setActivePanel(panel: keyof typeof panels | false) {
|
function setActivePanel(panel: keyof typeof panels | false) {
|
||||||
if (panel === $activePanel) {
|
if (panel === $activePanel) {
|
||||||
$activePanel = false;
|
$activePanel = false;
|
||||||
@ -37,28 +38,6 @@
|
|||||||
$activePanel = false;
|
$activePanel = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Nested {
|
|
||||||
[key: string]: NodeInput | Nested;
|
|
||||||
}
|
|
||||||
|
|
||||||
function constructNested(panel: (typeof panels)[keyof typeof panels]) {
|
|
||||||
const nested: Nested = {};
|
|
||||||
|
|
||||||
for (const key in panel.definition) {
|
|
||||||
const parts = key.split(".");
|
|
||||||
let current = nested;
|
|
||||||
for (let i = 0; i < parts.length; i++) {
|
|
||||||
if (i === parts.length - 1) {
|
|
||||||
current[parts[i]] = panel.definition[key];
|
|
||||||
} else {
|
|
||||||
current[parts[i]] = current[parts[i]] || {};
|
|
||||||
current = current[parts[i]] as Nested;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nested;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper" class:visible={$activePanel}>
|
<div class="wrapper" class:visible={$activePanel}>
|
||||||
@ -81,25 +60,7 @@
|
|||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
{#if $activePanel && panels[$activePanel] && panels[$activePanel].hidden !== true}
|
<slot />
|
||||||
<h1 class="m-0 p-4">{panels[$activePanel].id}</h1>
|
|
||||||
{#key $activePanel}
|
|
||||||
{#if panels[$activePanel]?.component}
|
|
||||||
<svelte:component
|
|
||||||
this={panels[$activePanel].component}
|
|
||||||
{...panels[$activePanel]?.props}
|
|
||||||
/>
|
|
||||||
{:else}
|
|
||||||
<div class="flex flex-col">
|
|
||||||
<NestedSettings
|
|
||||||
id={$activePanel}
|
|
||||||
settings={constructNested(panels[$activePanel])}
|
|
||||||
store={panels[$activePanel].settings}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
{/if}
|
|
||||||
{/key}
|
|
||||||
{/if}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -10,6 +10,7 @@ export const AppSettings = localStore("node-settings", {
|
|||||||
showVertices: false,
|
showVertices: false,
|
||||||
centerCamera: true,
|
centerCamera: true,
|
||||||
showStemLines: false,
|
showStemLines: false,
|
||||||
|
amount: 5
|
||||||
});
|
});
|
||||||
|
|
||||||
const themes = ["dark", "light", "catppuccin", "solarized", "high-contrast", "nord", "dracula"];
|
const themes = ["dark", "light", "catppuccin", "solarized", "high-contrast", "nord", "dracula"];
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Node, NodeInput } from "@nodes/types";
|
import type { Node, NodeInput } from "@nodes/types";
|
||||||
import NestedSettings from "../NestedSettings.svelte";
|
import NestedSettings from "./NestedSettings.svelte";
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import type { GraphManager } from "$lib/graph-interface/graph-manager";
|
import type { GraphManager } from "$lib/graph-interface/graph-manager";
|
||||||
|
|
||||||
@ -28,7 +28,7 @@
|
|||||||
|
|
||||||
export let manager: GraphManager;
|
export let manager: GraphManager;
|
||||||
|
|
||||||
export let node: Node;
|
export let node: Node | undefined;
|
||||||
let nodeDefinition: Record<string, NodeInput> | undefined;
|
let nodeDefinition: Record<string, NodeInput> | undefined;
|
||||||
$: nodeDefinition = node?.tmp?.type
|
$: nodeDefinition = node?.tmp?.type
|
||||||
? filterInputs(node.tmp.type.inputs)
|
? filterInputs(node.tmp.type.inputs)
|
40
app/src/lib/settings/panels/GraphSettings.svelte
Normal file
40
app/src/lib/settings/panels/GraphSettings.svelte
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<script lang="ts">
|
||||||
|
import type { NodeInput } from "@nodes/types";
|
||||||
|
import NestedSettings from "./NestedSettings.svelte";
|
||||||
|
import type { Writable } from "svelte/store";
|
||||||
|
|
||||||
|
interface Nested {
|
||||||
|
[key: string]: NodeInput | Nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
export let type: Record<string, NodeInput>;
|
||||||
|
|
||||||
|
export let store: Writable<Record<string, any>>;
|
||||||
|
|
||||||
|
function constructNested(type: Record<string, NodeInput>) {
|
||||||
|
const nested: Nested = {};
|
||||||
|
|
||||||
|
for (const key in type) {
|
||||||
|
const parts = key.split(".");
|
||||||
|
let current = nested;
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
if (i === parts.length - 1) {
|
||||||
|
current[parts[i]] = type[key];
|
||||||
|
} else {
|
||||||
|
current[parts[i]] = current[parts[i]] || {};
|
||||||
|
current = current[parts[i]] as Nested;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nested;
|
||||||
|
}
|
||||||
|
|
||||||
|
$: settings = constructNested({
|
||||||
|
randomSeed: { type: "boolean", value: false },
|
||||||
|
...type,
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#key settings}
|
||||||
|
<NestedSettings id="graph-settings" {settings} {store} />
|
||||||
|
{/key}
|
@ -3,7 +3,7 @@
|
|||||||
import { ShortCut } from "@nodes/ui";
|
import { ShortCut } from "@nodes/ui";
|
||||||
|
|
||||||
export let keymap: ReturnType<typeof createKeyMap>;
|
export let keymap: ReturnType<typeof createKeyMap>;
|
||||||
const keys = keymap.keys;
|
const keys = keymap?.keys;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper">
|
<div class="wrapper">
|
||||||
@ -13,7 +13,12 @@
|
|||||||
{#each $keys as key}
|
{#each $keys as key}
|
||||||
{#if key.description}
|
{#if key.description}
|
||||||
<div class="command-wrapper">
|
<div class="command-wrapper">
|
||||||
<ShortCut {...key} />
|
<ShortCut
|
||||||
|
alt={key.alt}
|
||||||
|
ctrl={key.ctrl}
|
||||||
|
shift={key.shift}
|
||||||
|
key={key.key}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<p>{key.description}</p>
|
<p>{key.description}</p>
|
||||||
{/if}
|
{/if}
|
||||||
|
@ -4,8 +4,12 @@
|
|||||||
import Input from "@nodes/ui";
|
import Input from "@nodes/ui";
|
||||||
import type { Writable } from "svelte/store";
|
import type { Writable } from "svelte/store";
|
||||||
|
|
||||||
|
type Button = { type: "button"; label?: string; callback: () => void };
|
||||||
|
|
||||||
|
type Input = NodeInput | Button;
|
||||||
|
|
||||||
interface Nested {
|
interface Nested {
|
||||||
[key: string]: Nested | NodeInput;
|
[key: string]: (Nested & { __title?: string }) | Input;
|
||||||
}
|
}
|
||||||
|
|
||||||
export let id: string;
|
export let id: string;
|
||||||
@ -20,22 +24,23 @@
|
|||||||
export let depth = 0;
|
export let depth = 0;
|
||||||
|
|
||||||
const keys = Object.keys(settings).filter((key) => key !== "__title");
|
const keys = Object.keys(settings).filter((key) => key !== "__title");
|
||||||
function isNodeInput(v: NodeInput | Nested): v is NodeInput {
|
function isNodeInput(v: Input | Nested): v is Input {
|
||||||
return v && "type" in v;
|
return v && "type" in v;
|
||||||
}
|
}
|
||||||
|
console.log({ settings, store });
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if store}
|
{#if $store}
|
||||||
{#each keys as key}
|
{#each keys as key}
|
||||||
{@const value = settings[key]}
|
{@const value = settings[key]}
|
||||||
<div class="wrapper" class:first-level={depth === 0}>
|
<div class="wrapper" class:first-level={depth === 0}>
|
||||||
{#if isNodeInput(value)}
|
{#if value !== undefined && isNodeInput(value)}
|
||||||
<div class="input input-{settings[key].type}">
|
<div class="input input-{settings[key].type}">
|
||||||
{#if settings[key].type === "button"}
|
{#if value.type === "button"}
|
||||||
<button on:click={() => settings[key]?.callback?.()}
|
<button on:click={() => value?.callback?.()}
|
||||||
>{settings[key].label || key}</button
|
>{value.label || key}</button
|
||||||
>
|
>
|
||||||
{:else if "setting" in value}
|
{:else if "setting" in value && value.setting !== undefined}
|
||||||
<label for={key}>{settings[key].label || key}</label>
|
<label for={key}>{settings[key].label || key}</label>
|
||||||
<Input id={key} input={value} bind:value={$store[value?.setting]} />
|
<Input id={key} input={value} bind:value={$store[value?.setting]} />
|
||||||
{:else}
|
{:else}
|
19
app/src/lib/worker-runtime-executor-backend.ts
Normal file
19
app/src/lib/worker-runtime-executor-backend.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { MemoryRuntimeExecutor } from "./runtime-executor";
|
||||||
|
import { RemoteNodeRegistry } from "./node-registry-client";
|
||||||
|
import type { Graph } from "@nodes/types";
|
||||||
|
import { createPerformanceStore } from "./performance";
|
||||||
|
|
||||||
|
const nodeRegistry = new RemoteNodeRegistry("");
|
||||||
|
const executor = new MemoryRuntimeExecutor(nodeRegistry);
|
||||||
|
|
||||||
|
const performanceStore = createPerformanceStore();
|
||||||
|
executor.perf = performanceStore;
|
||||||
|
|
||||||
|
export async function executeGraph(graph: Graph, settings: Record<string, unknown>): Promise<Int32Array> {
|
||||||
|
await nodeRegistry.load(graph.nodes.map((n) => n.type));
|
||||||
|
return executor.execute(graph, settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getPerformanceData() {
|
||||||
|
return performanceStore.get();
|
||||||
|
}
|
16
app/src/lib/worker-runtime-executor.ts
Normal file
16
app/src/lib/worker-runtime-executor.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
/// <reference types="vite-plugin-comlink/client" />
|
||||||
|
|
||||||
|
import type { Graph, RuntimeExecutor } from "@nodes/types";
|
||||||
|
|
||||||
|
export class WorkerRuntimeExecutor implements RuntimeExecutor {
|
||||||
|
private worker = new ComlinkWorker<typeof import('./worker-runtime-executor-backend.ts')>(new URL("./worker-runtime-executor-backend.ts", import.meta.url));
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
async execute(graph: Graph, settings: Record<string, unknown>) {
|
||||||
|
return this.worker.executeGraph(graph, settings);
|
||||||
|
}
|
||||||
|
async getPerformanceData() {
|
||||||
|
return this.worker.getPerformanceData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,17 +1,14 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import Grid from "$lib/grid";
|
import Grid from "$lib/grid";
|
||||||
import GraphInterface from "$lib/graph-interface";
|
import GraphInterface from "$lib/graph-interface";
|
||||||
import {
|
import { WorkerRuntimeExecutor } from "$lib/worker-runtime-executor";
|
||||||
MemoryRuntimeExecutor,
|
|
||||||
MemoryRuntimeCache,
|
|
||||||
} from "$lib/runtime-executor";
|
|
||||||
import { RemoteNodeRegistry } from "$lib/node-registry-client";
|
import { RemoteNodeRegistry } from "$lib/node-registry-client";
|
||||||
import * as templates from "$lib/graph-templates";
|
import * as templates from "$lib/graph-templates";
|
||||||
import type { Graph, Node } from "@nodes/types";
|
import type { Graph, Node } from "@nodes/types";
|
||||||
import Viewer from "$lib/result-viewer/Viewer.svelte";
|
import Viewer from "$lib/result-viewer/Viewer.svelte";
|
||||||
import Settings from "$lib/settings/Settings.svelte";
|
import Settings from "$lib/settings/Settings.svelte";
|
||||||
import { AppSettings, AppSettingTypes } from "$lib/settings/app-settings";
|
import { AppSettingTypes, AppSettings } from "$lib/settings/app-settings";
|
||||||
import { get, writable, type Writable } from "svelte/store";
|
import { writable, type Writable } from "svelte/store";
|
||||||
import Keymap from "$lib/settings/panels/Keymap.svelte";
|
import Keymap from "$lib/settings/panels/Keymap.svelte";
|
||||||
import type { createKeyMap } from "$lib/helpers/createKeyMap";
|
import type { createKeyMap } from "$lib/helpers/createKeyMap";
|
||||||
import NodeStore from "$lib/node-store/NodeStore.svelte";
|
import NodeStore from "$lib/node-store/NodeStore.svelte";
|
||||||
@ -22,27 +19,22 @@
|
|||||||
decodeNestedArray,
|
decodeNestedArray,
|
||||||
encodeNestedArray,
|
encodeNestedArray,
|
||||||
} from "@nodes/utils";
|
} from "@nodes/utils";
|
||||||
import type { PerspectiveCamera, Vector3 } from "three";
|
import ActiveNodeSettings from "$lib/settings/panels/ActiveNodeSettings.svelte";
|
||||||
import type { OrbitControls } from "three/examples/jsm/Addons.js";
|
|
||||||
import ActiveNode from "$lib/settings/panels/ActiveNode.svelte";
|
|
||||||
import { createPerformanceStore } from "$lib/performance";
|
|
||||||
import PerformanceViewer from "$lib/performance/PerformanceViewer.svelte";
|
import PerformanceViewer from "$lib/performance/PerformanceViewer.svelte";
|
||||||
|
import Panel from "$lib/settings/Panel.svelte";
|
||||||
|
import GraphSettings from "$lib/settings/panels/GraphSettings.svelte";
|
||||||
|
import NestedSettings from "$lib/settings/panels/NestedSettings.svelte";
|
||||||
|
|
||||||
const nodePerformance = createPerformanceStore();
|
|
||||||
|
|
||||||
const runtimeCache = new MemoryRuntimeCache();
|
|
||||||
const nodeRegistry = new RemoteNodeRegistry("");
|
const nodeRegistry = new RemoteNodeRegistry("");
|
||||||
const runtimeExecutor = new MemoryRuntimeExecutor(nodeRegistry, runtimeCache);
|
const workerRuntime = new WorkerRuntimeExecutor();
|
||||||
runtimeExecutor.perf = nodePerformance;
|
|
||||||
|
let performanceData: PerformanceData;
|
||||||
|
|
||||||
globalThis.decode = decodeNestedArray;
|
globalThis.decode = decodeNestedArray;
|
||||||
globalThis.encode = encodeNestedArray;
|
globalThis.encode = encodeNestedArray;
|
||||||
globalThis.decodeFloat = decodeFloat;
|
globalThis.decodeFloat = decodeFloat;
|
||||||
|
|
||||||
let res: Int32Array;
|
let res: Int32Array;
|
||||||
let viewerCamera: PerspectiveCamera;
|
|
||||||
let viewerControls: OrbitControls;
|
|
||||||
let viewerCenter: Vector3;
|
|
||||||
let activeNode: Node | undefined;
|
let activeNode: Node | undefined;
|
||||||
|
|
||||||
let graph = localStorage.getItem("graph")
|
let graph = localStorage.getItem("graph")
|
||||||
@ -56,154 +48,103 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
let keymap: ReturnType<typeof createKeyMap>;
|
let keymap: ReturnType<typeof createKeyMap>;
|
||||||
|
let graphSettings = writable<Record<string, any>>({});
|
||||||
|
let graphSettingTypes = {};
|
||||||
|
|
||||||
function handleResult(event: CustomEvent<Graph>) {
|
async function handleResult(event: CustomEvent<Graph>) {
|
||||||
|
const settings = $graphSettings;
|
||||||
|
if (!settings) return;
|
||||||
try {
|
try {
|
||||||
res = runtimeExecutor.execute(
|
res = await workerRuntime.execute(event.detail, settings);
|
||||||
event.detail,
|
performanceData = await workerRuntime.getPerformanceData();
|
||||||
get(settingPanels?.graph?.settings),
|
|
||||||
);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.log("errors", error);
|
console.log("errors", error);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($AppSettings.centerCamera && viewerCamera && viewerCenter) {
|
$: if (AppSettings) {
|
||||||
if (
|
//@ts-ignore
|
||||||
Number.isNaN(viewerCenter.x) ||
|
AppSettingTypes.debug.stressTest.loadGrid.callback = () => {
|
||||||
Number.isNaN(viewerCenter.y) ||
|
graph = templates.grid($AppSettings.amount, $AppSettings.amount);
|
||||||
Number.isNaN(viewerCenter.z)
|
};
|
||||||
) {
|
//@ts-ignore
|
||||||
// viewerCenter.set(0, 0, 0);
|
AppSettingTypes.debug.stressTest.loadTree.callback = () => {
|
||||||
} else {
|
graph = templates.tree($AppSettings.amount, $AppSettings.amount);
|
||||||
viewerControls.target.copy(viewerCenter);
|
};
|
||||||
}
|
|
||||||
viewerControls.update();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleSave(event: CustomEvent<Graph>) {
|
function handleSave(event: CustomEvent<Graph>) {
|
||||||
localStorage.setItem("graph", JSON.stringify(event.detail));
|
localStorage.setItem("graph", JSON.stringify(event.detail));
|
||||||
}
|
}
|
||||||
|
|
||||||
let settingPanels: Record<string, any> = {
|
|
||||||
general: {
|
|
||||||
id: "general",
|
|
||||||
icon: "i-tabler-settings",
|
|
||||||
settings: AppSettings,
|
|
||||||
definition: AppSettingTypes,
|
|
||||||
},
|
|
||||||
shortcuts: {},
|
|
||||||
nodeStore: {},
|
|
||||||
graph: {
|
|
||||||
id: "graph",
|
|
||||||
icon: "i-tabler-git-fork",
|
|
||||||
definition: {
|
|
||||||
randomSeed: {
|
|
||||||
type: "boolean",
|
|
||||||
label: "Random Seed",
|
|
||||||
value: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
performance: {
|
|
||||||
id: "performance",
|
|
||||||
icon: "i-tabler-brand-speedtest",
|
|
||||||
props: { store: nodePerformance, title: "Runtime Performance" },
|
|
||||||
component: PerformanceViewer,
|
|
||||||
},
|
|
||||||
activeNode: {
|
|
||||||
id: "Active Node",
|
|
||||||
icon: "i-tabler-adjustments",
|
|
||||||
props: { node: undefined, manager: undefined },
|
|
||||||
component: ActiveNode,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
$: if (keymap) {
|
|
||||||
settingPanels.shortcuts = {
|
|
||||||
id: "shortcuts",
|
|
||||||
icon: "i-tabler-keyboard",
|
|
||||||
props: { keymap },
|
|
||||||
component: Keymap,
|
|
||||||
};
|
|
||||||
|
|
||||||
settingPanels = settingPanels;
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (manager) {
|
|
||||||
settingPanels.activeNode.props.manager = manager;
|
|
||||||
settingPanels.nodeStore = {
|
|
||||||
id: "Node Store",
|
|
||||||
icon: "i-tabler-database",
|
|
||||||
props: { nodeRegistry, manager },
|
|
||||||
component: NodeStore,
|
|
||||||
};
|
|
||||||
settingPanels = settingPanels;
|
|
||||||
}
|
|
||||||
|
|
||||||
$: if (activeNode) {
|
|
||||||
settingPanels.activeNode.props.node = activeNode;
|
|
||||||
settingPanels = settingPanels;
|
|
||||||
} else {
|
|
||||||
settingPanels.activeNode.props.node = undefined;
|
|
||||||
settingPanels = settingPanels;
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleSettings(
|
|
||||||
ev: CustomEvent<{
|
|
||||||
values: Record<string, unknown>;
|
|
||||||
types: Record<string, unknown>;
|
|
||||||
}>,
|
|
||||||
) {
|
|
||||||
settingPanels.general.definition.debug.stressTest.loadGrid.callback =
|
|
||||||
function () {
|
|
||||||
const store = get(settingPanels.general.settings);
|
|
||||||
graph = templates.grid(store.amount, store.amount);
|
|
||||||
};
|
|
||||||
|
|
||||||
settingPanels.general.definition.debug.stressTest.loadTree.callback =
|
|
||||||
function () {
|
|
||||||
const store = get(settingPanels.general.settings);
|
|
||||||
graph = templates.tree(store.amount);
|
|
||||||
};
|
|
||||||
|
|
||||||
settingPanels.graph.settings = writable(ev.detail.values);
|
|
||||||
settingPanels.graph.definition = {
|
|
||||||
...settingPanels.graph.definition,
|
|
||||||
...ev.detail.types,
|
|
||||||
};
|
|
||||||
|
|
||||||
settingPanels = settingPanels;
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<div class="wrapper manager-{$managerStatus}">
|
<div class="wrapper manager-{$managerStatus}">
|
||||||
<header></header>
|
<header></header>
|
||||||
<Grid.Row>
|
<Grid.Row>
|
||||||
<Grid.Cell>
|
<Grid.Cell>
|
||||||
<Viewer
|
<Viewer centerCamera={$AppSettings.centerCamera} result={res} />
|
||||||
bind:controls={viewerControls}
|
|
||||||
bind:center={viewerCenter}
|
|
||||||
bind:camera={viewerCamera}
|
|
||||||
result={res}
|
|
||||||
/>
|
|
||||||
</Grid.Cell>
|
</Grid.Cell>
|
||||||
<Grid.Cell>
|
<Grid.Cell>
|
||||||
{#key graph}
|
{#key graph}
|
||||||
<GraphInterface
|
<GraphInterface
|
||||||
|
{graph}
|
||||||
|
registry={nodeRegistry}
|
||||||
bind:manager
|
bind:manager
|
||||||
bind:activeNode
|
bind:activeNode
|
||||||
registry={nodeRegistry}
|
|
||||||
{graph}
|
|
||||||
bind:keymap
|
bind:keymap
|
||||||
showGrid={$AppSettings?.showNodeGrid}
|
showGrid={$AppSettings?.showNodeGrid}
|
||||||
snapToGrid={$AppSettings?.snapToGrid}
|
snapToGrid={$AppSettings?.snapToGrid}
|
||||||
settings={settingPanels?.graph?.settings}
|
bind:settings={graphSettings}
|
||||||
on:settings={handleSettings}
|
bind:settingTypes={graphSettingTypes}
|
||||||
on:result={handleResult}
|
on:result={handleResult}
|
||||||
on:save={handleSave}
|
on:save={handleSave}
|
||||||
/>
|
/>
|
||||||
<Settings panels={settingPanels}></Settings>
|
<Settings>
|
||||||
|
<Panel id="general" title="General" icon="i-tabler-settings">
|
||||||
|
<NestedSettings
|
||||||
|
id="general"
|
||||||
|
store={AppSettings}
|
||||||
|
settings={AppSettingTypes}
|
||||||
|
/>
|
||||||
|
</Panel>
|
||||||
|
<Panel id="node-store" title="Node Store" icon="i-tabler-database">
|
||||||
|
<NodeStore registry={nodeRegistry} />
|
||||||
|
</Panel>
|
||||||
|
<Panel
|
||||||
|
id="performance"
|
||||||
|
title="Performance"
|
||||||
|
icon="i-tabler-brand-speedtest"
|
||||||
|
>
|
||||||
|
{#if performanceData}
|
||||||
|
<PerformanceViewer data={performanceData} />
|
||||||
|
{/if}
|
||||||
|
</Panel>
|
||||||
|
<Panel
|
||||||
|
id="shortcuts"
|
||||||
|
title="Keyboard Shortcuts"
|
||||||
|
icon="i-tabler-keyboard"
|
||||||
|
>
|
||||||
|
{#if keymap}
|
||||||
|
<Keymap {keymap} />
|
||||||
|
{/if}
|
||||||
|
</Panel>
|
||||||
|
<Panel
|
||||||
|
id="graph-settings"
|
||||||
|
title="Graph Settings"
|
||||||
|
icon="i-tabler-brand-git"
|
||||||
|
>
|
||||||
|
{#if Object.keys(graphSettingTypes).length > 0}
|
||||||
|
<GraphSettings type={graphSettingTypes} store={graphSettings} />
|
||||||
|
{/if}
|
||||||
|
</Panel>
|
||||||
|
<Panel
|
||||||
|
id="active-node"
|
||||||
|
title="Node Settings"
|
||||||
|
icon="i-tabler-adjustments"
|
||||||
|
>
|
||||||
|
<ActiveNodeSettings {manager} node={activeNode} />
|
||||||
|
</Panel>
|
||||||
|
</Settings>
|
||||||
{/key}
|
{/key}
|
||||||
</Grid.Cell>
|
</Grid.Cell>
|
||||||
</Grid.Row>
|
</Grid.Row>
|
||||||
|
@ -10,18 +10,18 @@
|
|||||||
"scale": {
|
"scale": {
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"min": 0.1,
|
"min": 0.1,
|
||||||
"max": 100
|
"max": 10
|
||||||
},
|
},
|
||||||
"strength": {
|
"strength": {
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"min": 0.1,
|
"min": 0.1,
|
||||||
"max": 100
|
"max": 10
|
||||||
},
|
},
|
||||||
"fixBottom": {
|
"fixBottom": {
|
||||||
"type": "float",
|
"type": "float",
|
||||||
"label": "Fixate bottom of plant",
|
"label": "Fixate bottom of plant",
|
||||||
"hidden": true,
|
"hidden": true,
|
||||||
"value": 0,
|
"value": 1,
|
||||||
"min": 0,
|
"min": 0,
|
||||||
"max": 1
|
"max": 1
|
||||||
},
|
},
|
||||||
|
@ -33,7 +33,7 @@ export interface RuntimeExecutor {
|
|||||||
* @param graph - The graph to execute
|
* @param graph - The graph to execute
|
||||||
* @returns The result of the execution
|
* @returns The result of the execution
|
||||||
*/
|
*/
|
||||||
execute: (graph: Graph, settings: Record<string, unknown>) => unknown;
|
execute: (graph: Graph, settings: Record<string, unknown>) => Int32Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface RuntimeCache {
|
export interface RuntimeCache {
|
||||||
|
Loading…
Reference in New Issue
Block a user