feat: some moving around

This commit is contained in:
max_richter 2024-04-15 22:13:43 +02:00
parent 0254bc1ae5
commit dec205b234
86 changed files with 505 additions and 409 deletions

50
Cargo.lock generated
View File

@ -7,11 +7,13 @@ name = "array"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
@ -41,6 +43,7 @@ name = "float"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
@ -69,11 +72,21 @@ version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
[[package]]
name = "macros"
version = "0.1.0"
dependencies = [
"quote",
"serde_json",
"syn 1.0.109",
]
[[package]]
name = "math"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
@ -172,7 +185,7 @@ checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.59",
]
[[package]]
@ -187,15 +200,42 @@ dependencies = [
]
[[package]]
name = "sum"
name = "stem"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "sum"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"macros",
"serde",
"serde-wasm-bindgen",
"utils",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
]
[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]]
@ -258,7 +298,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
"syn",
"syn 2.0.59",
"wasm-bindgen-shared",
]
@ -292,7 +332,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.59",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@ -325,7 +365,7 @@ checksum = "b7f89739351a2e03cb94beb799d47fb2cac01759b40ec441f7de39b00cbf7ef0"
dependencies = [
"proc-macro2",
"quote",
"syn",
"syn 2.0.59",
]
[[package]]

View File

@ -1,6 +1,6 @@
[workspace]
resolver = "2"
members = ["nodes/max/plantarium/*", "packages/utils"]
members = ["nodes/max/plantarium/*", "packages/macros", "packages/utils"]
[profile.release]

View File

@ -1,9 +1,10 @@
import { writable, type Writable } from "svelte/store";
import { get, writable, type Writable } from "svelte/store";
import type { Graph, Node, Edge, Socket, NodeRegistry, } from "@nodes/types";
import { HistoryManager } from "./history-manager.js"
import EventEmitter from "./helpers/EventEmitter.js";
import throttle from "./helpers/throttle.js";
import { createLogger } from "./helpers/index.js";
import type { NodeInput } from "@nodes/types";
const logger = createLogger("graph-manager");
@ -17,6 +18,8 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
private _nodes: Map<number, Node> = new Map();
nodes: Writable<Map<number, Node>> = writable(new Map());
settingTypes: NodeInput[] = [];
settings: Writable<Record<string, any>> = writable({});
private _edges: Edge[] = [];
edges: Writable<Edge[]> = writable([]);
@ -51,7 +54,8 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
props: node.props,
})) as Node[];
const edges = this._edges.map(edge => [edge[0].id, edge[1], edge[2].id, edge[3]]) as Graph["edges"];
return { id: this.graph.id, nodes, edges };
const settings = get(this.settings);
return { id: this.graph.id, settings, nodes, edges };
}
execute() { }
@ -141,6 +145,12 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
this.status.set("loading");
this.id.set(graph.id);
if (graph.settings) {
this.settings.set(graph.settings);
} else {
this.settings.set({});
}
const nodeIds = Array.from(new Set([...graph.nodes.map(n => n.type)]));
await this.nodeRegistry.load(nodeIds);
@ -155,6 +165,20 @@ export class GraphManager extends EventEmitter<{ "save": Graph, "result": any }>
node.tmp.type = nodeType;
}
let settings: Record<string, NodeInput> = {};
const types = this.getNodeTypes();
for (const type of types) {
if (type.inputs) {
for (const key in type.inputs) {
let settingId = type.inputs[key].setting;
if (settingId) {
settings[settingId] = type.inputs[key];
}
}
}
}
console.log(settings);
this.history.reset();
this._init(this.graph);

View File

@ -106,7 +106,12 @@
if (!node?.inputs) {
return 5;
}
const height = 5 + 10 * Object.keys(node.inputs).filter((i) => i !== 'seed').length;
const height =
5 +
10 *
Object.keys(node.inputs)
.filter((i) => i !== 'seed')
.filter((p) => node?.inputs && !('setting' in node?.inputs?.[p])).length;
nodeHeightCache[nodeTypeId] = height;
return height;
}

View File

@ -22,7 +22,9 @@
const type = node?.tmp?.type;
const parameters = Object.entries(type?.inputs || {}).filter((p) => p[1].type !== 'seed');
const parameters = Object.entries(type?.inputs || {})
.filter((p) => p[1].type !== 'seed')
.filter((p) => !('setting' in p[1]));
let ref: HTMLDivElement;
let meshRef: Mesh;

View File

@ -0,0 +1,25 @@
<script lang="ts">
import type { Node, NodeInput } from "@nodes/types";
import { getGraphManager } from "../graph/context.js";
import { Input } from "@nodes/ui";
export let node: Node;
export let input: NodeInput;
export let id: string;
export let label: string | undefined;
const graph = getGraphManager();
let value = node?.props?.[id] ?? input.value;
let elementId = Math.random().toString(36).substring(7);
$: if (node?.props?.[id] !== value) {
node.props = { ...node.props, [id]: value };
graph.save();
graph.execute();
}
</script>
<label for="input-{elementId}">{label || id}</label>
<Input id="input-{elementId}" {input} bind:value />

View File

@ -0,0 +1,11 @@
import { test, expect } from 'vitest';
import fastHash from './fastHash';
test('Hashes dont clash', () => {
const hashA = fastHash('abcdef');
const hashB = fastHash('abcde');
const hashC = fastHash('abcde');
expect(hashA).not.toEqual(hashB);
expect(hashB).toEqual(hashC);
});

View File

@ -0,0 +1,14 @@
// Shamelessly copied from
// https://stackoverflow.com/a/8831937
export default function (input: string) {
if (input.length === 0) return 0;
let hash = 0;
for (let i = 0; i < input.length; i++) {
hash = (hash << 5) - hash + input.charCodeAt(i);
hash = hash & hash;
}
return hash;
}

View File

@ -1,12 +1,23 @@
import type { Graph, NodeRegistry, NodeType, RuntimeExecutor } from "@nodes/types";
import { encodeFloat } from "./helpers/encode";
import { concat_encoded, encode } from "./helpers/flat_tree";
import fastHash from "./helpers/fastHash";
async function hashIntArray(arr: Int32Array): Promise<string> {
const hashBuffer = await crypto.subtle.digest('SHA-256', arr.buffer);
const hashArray = Array.from(new Uint8Array(hashBuffer));
const hashHex = hashArray.map(byte => byte.toString(16).padStart(2, '0')).join('');
return hashHex;
}
export class MemoryRuntimeExecutor implements RuntimeExecutor {
private typeMap: Map<string, NodeType> = new Map();
private cache: Record<string, { eol: number, value: any }> = {};
constructor(private registry: NodeRegistry) { }
private getNodeTypes(graph: Graph) {
@ -111,6 +122,8 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
// here we store the intermediate results of the nodes
const results: Record<string, string | boolean | number> = {};
console.log(this.cache);
for (const node of sortedNodes) {
const node_type = this.typeMap.get(node.type)!;
@ -139,24 +152,65 @@ export class MemoryRuntimeExecutor implements RuntimeExecutor {
}
console.log(" ");
console.log("--> EXECUTING NODE " + node_type.id, node.id);
// execute the node and store the result
try {
const a0 = performance.now();
const node_inputs = Object.entries(inputs);
const cacheKey = `${node.id}/${fastHash(node_inputs.map(([_, value]: [string, any]) => {
if (value instanceof Int32Array) {
return hashIntArray(value);
}
console.log(value);
return `${value}`
}).join("/"))}`;
const a1 = performance.now();
console.log(`${a1 - a0}ms hashed inputs: ${node.id} -> ${cacheKey}`);
if (this.cache[cacheKey] && this.cache[cacheKey].eol > Date.now()) {
results[node.id] = this.cache[cacheKey].value;
console.log(`Using cached value`);
continue;
}
const transformed_inputs = node_inputs.map(([key, value]: [string, any]) => {
const input_type = node_type.inputs?.[key]!;
if (value instanceof Int32Array) {
return [...value.slice(0, value.length)];
let _v = new Array(value.length);
for (let i = 0; i < value.length; i++) {
_v[i] = value[i];
}
return _v;
}
if (input_type.type === "float") {
return encode(encodeFloat(value as number));
}
return value;
});
const a2 = performance.now();
console.log(`${a2 - a1}ms TRANSFORMED_INPUTS`);
const _inputs = concat_encoded(transformed_inputs);
// console.log(`Executing node ${node_type.id || node.id}`, { _inputs, inputs, node_type });
const a3 = performance.now();
results[node.id] = node_type.execute(_inputs) as number;
// console.log("--> result", results[node.id]);
const duration = performance.now() - a3;
if (duration > 5) {
this.cache[cacheKey] = { eol: Date.now() + 10_000, value: results[node.id] };
console.log(`Caching for 10 seconds`);
}
console.log(`${duration}ms Executed`);
const a4 = performance.now();
console.log(`${a4 - a0}ms e2e duration`);
} catch (e) {
console.error(`Error executing node ${node_type.id || node.id}`, e);
}

View File

@ -1,6 +1,6 @@
<script lang="ts">
import Grid from "$lib/grid";
import GraphInterface from "@nodes/graph-interface";
import GraphInterface from "$lib/graph-interface";
import { MemoryRuntimeExecutor } from "$lib/runtime-executor";
import { RemoteNodeRegistry } from "$lib/node-registry";
import * as templates from "$lib/graph-templates";
@ -25,7 +25,8 @@
let a = performance.now();
let _res: any = runtimeExecutor.execute(event.detail);
if (_res instanceof Int32Array) {
res = decodeFloat(_res[0], _res[1]);
const f = decodeFloat(_res[0], _res[1]);
res = Math.round(f * 100_000) / 100_000;
} else {
res = _res;
}

View File

@ -18,6 +18,8 @@ wasm-bindgen = "0.2.84"
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
utils = { version = "0.1.0", path = "../../../../packages/utils" }
macros = { version = "0.1.0", path = "../../../../packages/macros" }
web-sys = { version = "0.3.69", features = ["console"] }
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.4"
console_error_panic_hook = { version = "0.1.7", optional = true }

View File

@ -0,0 +1,10 @@
{
"value": {
"type": "float",
"value": 4.2
},
"amount": {
"type": "integer",
"value": 2
}
}

View File

@ -1,39 +1,33 @@
use macros::generate_input_types_file;
use utils::{evaluate_args, generate_outputs, get_args};
use wasm_bindgen::prelude::*;
// use web_sys::console;
// lifted from the `console_log` example
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
generate_outputs!(["float"]);
generate_input_types_file!("src/input.json");
#[wasm_bindgen]
pub fn get_outputs() -> Vec<String> {
vec!["float".to_string()]
}
pub fn execute(input: &[i32]) -> Vec<i32> {
utils::set_panic_hook();
#[wasm_bindgen]
pub fn get_input_types() -> String {
r#"{
"length": { "type": "float", "value": 2 }
}"#
.to_string()
}
let args = get_args(input);
#[rustfmt::skip]
#[wasm_bindgen]
pub fn execute(var_length: i32) -> Vec<f64> {
let value_encoded = evaluate_args(args[0]);
// let value = decode_float(value_encoded[0], value_encoded[1]);
let length = args[1];
let length = var_length;//evaluate_parameters(var_length);
// console::log_1(&format!("WASM(array_node): args {:?} ", args).into());
// console::log_1(&format!("WASM(array_node): value: {:?} length: {:?}", value, length).into());
// construct array of length
let mut res = Vec::new();
for _ in 0..length as usize {
res.push(2.0);
let mut res: Vec<i32> = Vec::with_capacity(length[0] as usize * 2 + 2);
res.push(0);
res.push((length[0]) * 2 + 2);
for _ in 0..length[0] as usize {
res.push(value_encoded[0]);
res.push(value_encoded[1])
}
log("executing array");
res
}

View File

@ -18,6 +18,7 @@ wasm-bindgen = "0.2.84"
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
utils = { version = "0.1.0", path = "../../../../packages/utils" }
macros = { version = "0.1.0", path = "../../../../packages/macros" }
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.4"
console_error_panic_hook = { version = "0.1.7", optional = true }

View File

@ -0,0 +1,7 @@
{
"value": {
"type": "float",
"value": 0.1,
"internal": true
}
}

View File

@ -1,17 +1,9 @@
use macros::generate_input_types_file;
use utils::generate_outputs;
use wasm_bindgen::prelude::*;
#[wasm_bindgen]
pub fn get_outputs() -> Vec<String> {
vec!["float".to_string()]
}
#[wasm_bindgen]
pub fn get_input_types() -> String {
r#"{
"value": { "type": "float", "value": 0.1, "internal": true }
}"#
.to_string()
}
generate_outputs!(["float"]);
generate_input_types_file!("src/input.json");
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {

View File

@ -16,6 +16,7 @@ serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.4"
console_error_panic_hook = { version = "0.1.7", optional = true }
utils = { version = "0.1.0", path = "../../../../packages/utils" }
macros = { version = "0.1.0", path = "../../../../packages/macros" }
web-sys = { version = "0.3.69", features = ["console"] }
[dev-dependencies]

View File

@ -0,0 +1,27 @@
{
"op_type": {
"label": "type",
"type": "select",
"labels": [
"add",
"subtract",
"multiply",
"divide"
],
"internal": true,
"value": 0
},
"a": {
"type": "float",
"value": 2
},
"b": {
"type": "float",
"value": 2
},
"clip": {
"type": "boolean",
"value": 0,
"setting": "math.clipping"
}
}

View File

@ -1,29 +1,13 @@
use macros::generate_input_types_file;
use utils::generate_outputs;
use wasm_bindgen::prelude::*;
// use web_sys::console;
#[wasm_bindgen]
pub fn get_outputs() -> Vec<String> {
vec!["float".to_string()]
}
generate_outputs!(["float"]);
#[wasm_bindgen]
pub fn get_input_types() -> String {
r#"{
"op_type": { "label": "type", "type": "select", "labels": ["add", "subtract", "multiply", "divide"], "internal": true, "value": 0 },
"a": { "type": "float", "value": 2 },
"b": { "type": "float", "value": 2 }
}"#.to_string()
}
generate_input_types_file!("src/input.json");
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {
// let d = args
// .iter()
// .map(|&num| num.to_string()) // Convert each integer to a String
// .collect::<Vec<String>>() // Collect all Strings into a Vec
// .join(","); // Join all Strings in the Vec with a dot
// console::log_1(&format!("Math: {:?}", d).into());
let mut result = Vec::with_capacity(args.len() + 3);
result.push(0); // encoding the [ bracket
result.push(args[1] + 1);
@ -31,6 +15,5 @@ pub fn execute(args: &[i32]) -> Vec<i32> {
result.extend_from_slice(&args[2..]);
result.push(1);
result.push(1); // closing bracket
result
}

View File

@ -17,7 +17,7 @@ pub fn get_input_types() -> String {
}
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {
// utils::set_panic_hook();
utils::set_panic_hook();
// console::log_1(&format!("WASM(output_node): input: {:?}", args).into());

6
nodes/max/plantarium/stem/.gitignore vendored Normal file
View File

@ -0,0 +1,6 @@
/target
**/*.rs.bk
Cargo.lock
bin/
pkg/
wasm-pack.log

View File

@ -0,0 +1,23 @@
[package]
name = "stem"
version = "0.1.0"
authors = ["Max Richter <jim-x@web.de>"]
edition = "2018"
[lib]
crate-type = ["cdylib", "rlib"]
[features]
default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.84"
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.4"
console_error_panic_hook = { version = "0.1.7", optional = true }
utils = { version = "0.1.0", path = "../../../../packages/utils" }
macros = { version = "0.1.0", path = "../../../../packages/macros" }
web-sys = { version = "0.3.69", features = ["console"] }
[dev-dependencies]
wasm-bindgen-test = "0.3.34"

View File

@ -0,0 +1,5 @@
{
"scripts": {
"build": "wasm-pack build --release --out-name index --no-default-features"
}
}

View File

@ -0,0 +1,27 @@
{
"op_type": {
"label": "type",
"type": "select",
"labels": [
"add",
"subtract",
"multiply",
"divide"
],
"internal": true,
"value": 0
},
"a": {
"type": "float",
"value": 2
},
"b": {
"type": "float",
"value": 2
},
"clip": {
"type": "boolean",
"value": 0,
"setting": "math.clipping"
}
}

View File

@ -0,0 +1,20 @@
use macros::generate_input_types_file;
use utils::generate_outputs;
use wasm_bindgen::prelude::*;
generate_outputs!(["stem"]);
generate_input_types_file!("src/input.json");
#[wasm_bindgen]
pub fn execute(args: &[i32]) -> Vec<i32> {
let mut result = Vec::with_capacity(args.len() + 3);
result.push(0); // encoding the [ bracket
result.push(args[1] + 1);
result.push(0); // adding the node-type, math: 0
result.extend_from_slice(&args[2..]);
result.push(1);
result.push(1); // closing bracket
result
}

View File

@ -0,0 +1,13 @@
//! Test suite for the Web and headless browsers.
#![cfg(target_arch = "wasm32")]
extern crate wasm_bindgen_test;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
#[wasm_bindgen_test]
fn pass() {
assert_eq!(1 + 1, 2);
}

View File

@ -21,6 +21,8 @@ utils = { version = "0.1.0", path = "../../../../packages/utils" }
serde = { version = "1.0", features = ["derive"] }
serde-wasm-bindgen = "0.4"
console_error_panic_hook = { version = "0.1.7", optional = true }
macros = { version = "0.1.0", path = "../../../../packages/macros" }
web-sys = { version = "0.3.69", features = ["console"] }
[dev-dependencies]
wasm-bindgen-test = "0.3.34"

View File

@ -0,0 +1,7 @@
{
"array": {
"type": "float",
"value": 2,
"external": true
}
}

View File

@ -1,29 +1,31 @@
use macros::generate_input_types_file;
use utils::{decode_float, encode_float, generate_outputs};
use wasm_bindgen::prelude::*;
// lifted from the `console_log` example
#[wasm_bindgen]
extern "C" {
#[wasm_bindgen(js_namespace = console)]
fn log(s: &str);
}
generate_outputs!(["float"]);
generate_input_types_file!("src/input.json");
#[wasm_bindgen]
pub fn get_outputs() -> Vec<String> {
vec!["float".to_string()]
}
pub fn execute(input: &[i32]) -> Vec<i32> {
utils::set_panic_hook();
#[wasm_bindgen]
pub fn get_input_types() -> String {
r#"{
"array": { "type": "float", "value": 2, "external": true }
}"#
.to_string()
}
let mut sum = 0.0;
#[rustfmt::skip]
#[wasm_bindgen]
pub fn execute(array: &[i32]) -> Vec<i32> {
let mut sum = 0;
array.iter().for_each(|x| sum += x);
vec![1, sum]
// console::log_1(&format!("WASM(sum_node): args: {:?}", input).into());
let length = (input.len() - 2) / 2;
(0..length).for_each(|i| {
let mantissa = input[2 + i * 2];
let exponent = input[2 + i * 2 + 1];
// console::log_1(&format!("WASM(sum_node): i: {} sum: {:?}", i, sum).into());
sum += decode_float(mantissa, exponent);
});
let encoded_sum = encode_float(sum);
// console::log_1(&format!("WASM(sum_node): result: {:?}", sum).into());
vec![0, 3, encoded_sum.0, encoded_sum.1]
}

View File

@ -1,13 +0,0 @@
.DS_Store
node_modules
/build
/.svelte-kit
/package
.env
.env.*
!.env.example
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View File

@ -1,31 +0,0 @@
/** @type { import("eslint").Linter.Config } */
module.exports = {
root: true,
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:svelte/recommended',
'prettier'
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
parserOptions: {
sourceType: 'module',
ecmaVersion: 2020,
extraFileExtensions: ['.svelte']
},
env: {
browser: true,
es2017: true,
node: true
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
]
};

View File

@ -1,11 +0,0 @@
.DS_Store
node_modules
/build
/dist
/.svelte-kit
/package
.env
.env.*
!.env.example
vite.config.js.timestamp-*
vite.config.ts.timestamp-*

View File

@ -1 +0,0 @@
engine-strict=true

View File

@ -1,4 +0,0 @@
# Ignore files for PNPM, NPM and YARN
pnpm-lock.yaml
package-lock.json
yarn.lock

View File

@ -1,8 +0,0 @@
{
"useTabs": true,
"singleQuote": true,
"trailingComma": "none",
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"overrides": [{ "files": "*.svelte", "options": { "parser": "svelte" } }]
}

View File

@ -1,58 +0,0 @@
# create-svelte
Everything you need to build a Svelte library, powered by [`create-svelte`](https://github.com/sveltejs/kit/tree/main/packages/create-svelte).
Read more about creating a library [in the docs](https://kit.svelte.dev/docs/packaging).
## Creating a project
If you're seeing this, you've probably already done this step. Congrats!
```bash
# create a new project in the current directory
npm create svelte@latest
# create a new project in my-app
npm create svelte@latest my-app
```
## Developing
Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server:
```bash
npm run dev
# or start the server and open the app in a new browser tab
npm run dev -- --open
```
Everything inside `src/lib` is part of your library, everything inside `src/routes` can be used as a showcase or preview app.
## Building
To build your library:
```bash
npm run package
```
To create a production version of your showcase app:
```bash
npm run build
```
You can preview the production build with `npm run preview`.
> To deploy your app, you may need to install an [adapter](https://kit.svelte.dev/docs/adapters) for your target environment.
## Publishing
Go into the `package.json` and give your package the desired name through the `"name"` option. Also consider adding a `"license"` field and point it to a `LICENSE` file which you can create from a template (one popular option is the [MIT license](https://opensource.org/license/mit/)).
To publish your library to [npm](https://www.npmjs.com):
```bash
npm publish
```

View File

@ -1,65 +0,0 @@
{
"name": "@nodes/graph-interface",
"version": "0.0.1",
"scripts": {
"dev": "svelte-package --watch",
"build": "vite build && npm run package",
"postbuild": "pnpm run package",
"preview": "vite preview",
"package": "svelte-kit sync && svelte-package && publint",
"prepublishOnly": "npm run package",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"lint": "prettier --check . && eslint .",
"format": "prettier --write ."
},
"exports": {
".": {
"types": "./dist/index.d.ts",
"svelte": "./dist/index.js"
}
},
"files": [
"dist",
"!dist/**/*.test.*",
"!dist/**/*.spec.*"
],
"dependencies": {
"@nodes/ui": "link:../ui",
"@nodes/types": "link:../types",
"@threlte/core": "^7.1.0",
"@threlte/extras": "^8.7.5",
"@threlte/flex": "^1.0.1",
"@types/three": "^0.159.0",
"jsondiffpatch": "^0.6.0",
"three": "^0.159.0",
"vite-plugin-glsl": "^1.2.1"
},
"peerDependencies": {
"svelte": "^4.0.0"
},
"devDependencies": {
"@histoire/plugin-svelte": "^0.17.9",
"@sveltejs/adapter-auto": "^3.0.0",
"@sveltejs/kit": "^2.0.0",
"@sveltejs/package": "^2.0.0",
"@sveltejs/vite-plugin-svelte": "^3.0.0",
"@types/eslint": "^8.56.0",
"@typescript-eslint/eslint-plugin": "^7.0.0",
"@typescript-eslint/parser": "^7.0.0",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.35.1",
"prettier": "^3.1.1",
"prettier-plugin-svelte": "^3.1.2",
"publint": "^0.1.9",
"svelte": "^4.2.7",
"svelte-check": "^3.6.0",
"tslib": "^2.4.1",
"typescript": "^5.0.0",
"vite": "^5.0.11"
},
"svelte": "./dist/index.js",
"types": "./dist/index.d.ts",
"type": "module"
}

View File

@ -1,13 +0,0 @@
// See https://kit.svelte.dev/docs/types#app
// for information about these interfaces
declare global {
namespace App {
// interface Error {}
// interface Locals {}
// interface PageData {}
// interface PageState {}
// interface Platform {}
}
}
export {};

View File

@ -1,12 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
%sveltekit.head%
</head>
<body data-sveltekit-preload-data="hover">
<div>%sveltekit.body%</div>
</body>
</html>

View File

@ -1,23 +0,0 @@
<script lang="ts">
import type { Node, NodeInput } from '@nodes/types';
import { getGraphManager } from '../graph/context.js';
import { Input } from '@nodes/ui';
export let node: Node;
export let input: NodeInput;
export let id: string;
export let label: string | undefined;
const graph = getGraphManager();
let value = node?.props?.[id] ?? input.value;
$: if (node?.props?.[id] !== value) {
node.props = { ...node.props, [id]: value };
graph.save();
graph.execute();
}
</script>
<label for="asd">{label || id}</label>
<Input {input} bind:value />

View File

@ -1,3 +0,0 @@
<h1>Welcome to your library project</h1>
<p>Create your package using @sveltejs/package and preview/showcase your work with SvelteKit</p>
<p>Visit <a href="https://kit.svelte.dev">kit.svelte.dev</a> to read the documentation</p>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@ -1,18 +0,0 @@
import adapter from '@sveltejs/adapter-auto';
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
/** @type {import('@sveltejs/kit').Config} */
const config = {
// Consult https://kit.svelte.dev/docs/integrations#preprocessors
// for more information about preprocessors
preprocess: vitePreprocess(),
kit: {
// adapter-auto only supports some environments, see https://kit.svelte.dev/docs/adapter-auto for a list.
// If your environment is not supported or you settled on a specific environment, switch out the adapter.
// See https://kit.svelte.dev/docs/adapters for more information about adapters.
adapter: adapter()
}
};
export default config;

View File

@ -1,18 +0,0 @@
{
"extends": "./.svelte-kit/tsconfig.json",
"compilerOptions": {
"allowJs": true,
"checkJs": true,
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"sourceMap": true,
"strict": true,
"module": "NodeNext",
"moduleResolution": "NodeNext",
"types": [
"vite-plugin-glsl/ext"
]
}
}

View File

@ -1,18 +0,0 @@
import { sveltekit } from '@sveltejs/kit/vite';
import glsl from "vite-plugin-glsl";
import { defineConfig } from 'vite';
import { exec } from 'child_process';
const dev = import.meta.env;
export default defineConfig({
plugins: [sveltekit(), glsl(), {
name: 'postbuild-commands', // the name of your custom plugin. Could be anything.
closeBundle: async () => {
return;
// run pnpm run package
exec('pnpm run package', (err, stdout, stderr) => {
console.log(stdout);
});
}
},]
});

View File

@ -0,0 +1,12 @@
[package]
name = "macros"
version = "0.1.0"
edition = "2021"
[lib]
proc-macro = true
[dependencies]
syn = { version = "1.0", features = ["full"] }
serde_json = "1.0"
quote = "1.0"

View File

@ -0,0 +1,65 @@
extern crate proc_macro;
use proc_macro::TokenStream;
use quote::quote;
use serde_json::Value;
use std::env;
use std::fs;
use std::path::Path;
use syn::{parse_macro_input, LitStr};
#[proc_macro]
pub fn generate_input_types(input: TokenStream) -> TokenStream {
let input_string = parse_macro_input!(input as LitStr).value();
// Validate JSON format
let json: Value = match serde_json::from_str(&input_string) {
Ok(json) => json,
Err(e) => panic!("Invalid JSON input: {}", e),
};
// Convert the validated JSON back to a pretty-printed string
let formatted_json = serde_json::to_string_pretty(&json).expect("Failed to serialize JSON");
// Generate the output function
let expanded = quote! {
#[wasm_bindgen]
pub fn get_input_types() -> String {
String::from(#formatted_json)
}
};
// Convert the generated code back to a TokenStream
TokenStream::from(expanded)
}
#[proc_macro]
pub fn generate_input_types_file(input: TokenStream) -> TokenStream {
let file_path = syn::parse_macro_input!(input as syn::LitStr).value();
// Retrieve the directory containing the Cargo.toml file
let project_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let full_path = Path::new(&project_dir).join(&file_path);
// Read the JSON file content
let json_content = fs::read_to_string(full_path).unwrap_or_else(|err| {
panic!(
"Failed to read JSON file at '{}/{}': {}",
project_dir, file_path, err
)
});
// Optionally, validate that the content is valid JSON
let _: Value = serde_json::from_str(&json_content)
.unwrap_or_else(|_| panic!("JSON file contains invalid JSON"));
// Generate the function that returns the JSON string
let expanded = quote! {
#[wasm_bindgen]
pub fn get_input_types() -> String {
String::from(#json_content)
}
};
// Convert the generated code back to a TokenStream
TokenStream::from(expanded)
}

View File

@ -8,7 +8,7 @@ export async function getNodeWrapper(id: `${string}/${string}/${string}`) {
let wrapperCode = await wrapperReponse.text();
wrapperCode = wrapperCode.replace("wasm = val;", `if(wasm) return;
wasm = val;`);
const wasmWrapper = await import(/*@vite-ignore*/`data:text/javascript;base64,${btoa(wrapperCode)}?id=${id}`);
const wasmWrapper = await import(/*@vite-ignore*/`data:text/javascript;base64,${btoa(wrapperCode)}#${id}${Math.random().toString().slice(2)}`);
return wasmWrapper;
}
@ -41,6 +41,7 @@ export async function getNode(id: `${string}/${string}/${string}`) {
const inputTypes = JSON.parse(rawInputs);
return { id, outputs, inputs: inputTypes }
} catch (e) {
console.log(rawInputs);
console.log("Failed to parse input types for node", { id, rawInputs });
}

View File

@ -89,6 +89,7 @@ export type Graph = {
title?: string;
lastModified?: string;
},
settings?: Record<string, any>,
nodes: Node[];
edges: [number, number, number, string][];
}

View File

@ -26,11 +26,13 @@ type NodeInputSelect = {
type NodeInputSeed = {
type: "seed"
value?: number;
}
type DefaultOptions = {
internal?: boolean;
external?: boolean;
setting?: string;
label?: string;
}

View File

@ -1,7 +0,0 @@
import { describe, it, expect } from 'vitest';
describe('sum test', () => {
it('adds 1 + 2 to equal 3', () => {
expect(1 + 2).toBe(3);
});
});

View File

@ -8,14 +8,15 @@
export let input: NodeInput;
export let value: any;
export let id: string;
</script>
{#if input.type === "float"}
<Float bind:value />
<Float {id} bind:value />
{:else if input.type === "integer"}
<Integer bind:value />
<Integer {id} bind:value />
{:else if input.type === "boolean"}
<Checkbox bind:value />
<Checkbox {id} bind:value />
{:else if input.type === "select"}
<Select bind:value labels={input.labels} />
<Select {id} bind:value labels={input.labels} />
{/if}

View File

@ -1,8 +1,10 @@
<script lang="ts">
export let value: boolean;
export let id: string;
</script>
<input type="checkbox" bind:checked={value} />
<input {id} type="checkbox" bind:checked={value} />
<style>
input[type="checkbox"] {

View File

@ -3,9 +3,10 @@
export let min = 0;
export let max = 10;
export let step = 0.1;
export let id: string;
</script>
<input type="number" bind:value {min} {max} {step} />
<input {id} type="number" bind:value {min} {max} {step} />
<style>
input {

View File

@ -3,9 +3,10 @@
export let min = 0;
export let max = 10;
export let step = 1;
export let id: string;
</script>
<input type="number" bind:value {min} {max} {step} />
<input {id} type="number" bind:value {min} {max} {step} />
<style>
input {

View File

@ -1,9 +1,10 @@
<script lang="ts">
export let labels: string[] = [];
export let value: number = 0;
export let id: string;
</script>
<select bind:value>
<select {id} bind:value>
{#each labels as label, i}
<option value={i}>{label}</option>
{/each}

View File

@ -16,3 +16,13 @@ pub fn set_panic_hook() {
#[cfg(feature = "console_error_panic_hook")]
console_error_panic_hook::set_once();
}
#[macro_export]
macro_rules! generate_outputs {
([$($item:expr),* $(,)?]) => {
#[wasm_bindgen]
pub fn get_outputs() -> Vec<String> {
vec![$($item.to_string()),*]
}
};
}

View File

@ -67,6 +67,10 @@ pub fn evaluate_node(input_args: &[i32]) -> (i32, i32) {
}
pub fn evaluate_args(input_args: &[i32]) -> Vec<i32> {
if input_args.len() == 4 && input_args[0] == 0 && input_args[1] == 3 {
return vec![input_args[2], input_args[3]];
}
let args = get_args(input_args);
let mut resolved: Vec<i32> = Vec::new();