diff --git a/app/package.json b/app/package.json
index d0e8204..411975d 100644
--- a/app/package.json
+++ b/app/package.json
@@ -18,6 +18,7 @@
"@types/three": "^0.164.0",
"@unocss/reset": "^0.59.4",
"comlink": "^4.4.1",
+ "file-saver": "^2.0.5",
"jsondiffpatch": "^0.6.0",
"three": "^0.164.1"
},
@@ -27,6 +28,7 @@
"@sveltejs/adapter-static": "^3.0.1",
"@sveltejs/vite-plugin-svelte": "next",
"@tsconfig/svelte": "^5.0.4",
+ "@types/file-saver": "^2.0.7",
"@unocss/preset-icons": "^0.59.4",
"svelte": "5.0.0-next.118",
"svelte-check": "^3.7.0",
diff --git a/app/src/lib/graph-interface/graph/Graph.svelte b/app/src/lib/graph-interface/graph/Graph.svelte
index 9291036..643b299 100644
--- a/app/src/lib/graph-interface/graph/Graph.svelte
+++ b/app/src/lib/graph-interface/graph/Graph.svelte
@@ -12,7 +12,7 @@
import Camera from "../Camera.svelte";
import GraphView from "./GraphView.svelte";
import type { Node, NodeId, Node as NodeType, Socket } from "@nodes/types";
- import { NodeDefinitionSchema } from "@nodes/types";
+ import { GraphSchema, NodeDefinitionSchema } from "@nodes/types";
import FloatingEdge from "../edges/FloatingEdge.svelte";
import {
activeNodeId,
@@ -28,6 +28,7 @@
import { createWasmWrapper } from "@nodes/utils";
import HelpView from "../HelpView.svelte";
+ import FileSaver from "file-saver";
export let manager: GraphManager;
@@ -612,6 +613,7 @@
keymap.addShortcut({
key: "a",
ctrl: true,
+ preventDefault: true,
description: "Select all nodes",
callback: () => {
if (!isBodyFocused()) return;
@@ -637,7 +639,6 @@
ctrl: true,
description: "Redo",
callback: () => {
- if (!isBodyFocused()) return;
manager.redo();
for (const node of $nodes.values()) {
updateNodePosition(node);
@@ -645,6 +646,20 @@
},
});
+ keymap.addShortcut({
+ key: "s",
+ ctrl: true,
+ description: "Save",
+ preventDefault: true,
+ callback: () => {
+ const state = manager.serialize();
+ const blob = new Blob([JSON.stringify(state)], {
+ type: "application/json;charset=utf-8",
+ });
+ FileSaver.saveAs(blob, "nodarium-graph.json");
+ },
+ });
+
keymap.addShortcut({
key: ["Delete", "Backspace", "x"],
description: "Delete selected nodes",
@@ -833,17 +848,31 @@
});
});
} else if (event.dataTransfer.files.length) {
- const files = event.dataTransfer.files;
- const reader = new FileReader();
- reader.onload = (e) => {
- const buffer = e.target?.result as Buffer;
- if (buffer) {
- const wrapper = createWasmWrapper(buffer);
- const definition = wrapper.get_definition();
- const res = NodeDefinitionSchema.parse(definition);
- }
- };
- reader.readAsArrayBuffer(files[0]);
+ const file = event.dataTransfer.files[0];
+
+ if (file.type === "application/wasm") {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const buffer = e.target?.result as Buffer;
+ if (buffer) {
+ const wrapper = createWasmWrapper(buffer);
+ const definition = wrapper.get_definition();
+ const res = NodeDefinitionSchema.parse(definition);
+ console.log(res);
+ }
+ };
+ reader.readAsArrayBuffer(file);
+ } else if (file.type === "application/json") {
+ const reader = new FileReader();
+ reader.onload = (e) => {
+ const buffer = e.target?.result as Buffer;
+ if (buffer) {
+ const state = GraphSchema.parse(JSON.parse(buffer.toString()));
+ manager.load(state);
+ }
+ };
+ reader.readAsText(file);
+ }
}
}
@@ -893,13 +922,13 @@
>
-
+
{#if showHelp}
diff --git a/app/src/lib/graph-templates/grid.ts b/app/src/lib/graph-templates/grid.ts
index 9e276df..996f5c6 100644
--- a/app/src/lib/graph-templates/grid.ts
+++ b/app/src/lib/graph-templates/grid.ts
@@ -20,7 +20,7 @@ export function grid(width: number, height: number) {
visible: false,
},
position: [x * 30, y * 40],
- props: i == 0 ? { value: 0 } : { op_type: 2, a: 2, b: 2 },
+ props: i == 0 ? { value: 0 } : { op_type: 0, a: 1, b: 0.05 },
type: i == 0 ? "max/plantarium/float" : "max/plantarium/math",
});
diff --git a/app/src/lib/graph-templates/index.ts b/app/src/lib/graph-templates/index.ts
index 662ed6e..129ff05 100644
--- a/app/src/lib/graph-templates/index.ts
+++ b/app/src/lib/graph-templates/index.ts
@@ -1,3 +1,7 @@
export { grid } from "./grid";
export { tree } from "./tree";
export { plant } from "./plant";
+export { default as lottaFaces } from "./lotta-faces.json";
+export { default as lottaNodes } from "./lotta-nodes.json";
+export { default as lottaNodesAndFaces } from "./lotta-nodes-and-faces.json";
+
diff --git a/app/src/lib/graph-templates/lotta-faces.json b/app/src/lib/graph-templates/lotta-faces.json
new file mode 100644
index 0000000..7ef1354
--- /dev/null
+++ b/app/src/lib/graph-templates/lotta-faces.json
@@ -0,0 +1 @@
+{"settings":{"resolution.circle":64,"resolution.curve":64,"randomSeed":false},"nodes":[{"id":9,"position":[260,0],"type":"max/plantarium/output","props":{}},{"id":18,"position":[185,0],"type":"max/plantarium/stem","props":{"amount":64,"length":12,"thickness":0.15}},{"id":19,"position":[210,0],"type":"max/plantarium/noise","props":{"scale":1.3,"strength":5.4}},{"id":20,"position":[235,0],"type":"max/plantarium/branch","props":{"length":0.8,"thickness":0.8,"amount":3}},{"id":21,"position":[160,0],"type":"max/plantarium/vec3","props":{"0":0.39,"1":0,"2":0.41}},{"id":22,"position":[130,0],"type":"max/plantarium/random","props":{"min":-2,"max":2}}],"edges":[[18,0,19,"plant"],[19,0,20,"plant"],[20,0,9,"input"],[21,0,18,"origin"],[22,0,21,"0"],[22,0,21,"2"]]}
diff --git a/app/src/lib/graph-templates/lotta-nodes-and-faces.json b/app/src/lib/graph-templates/lotta-nodes-and-faces.json
new file mode 100644
index 0000000..e45595c
--- /dev/null
+++ b/app/src/lib/graph-templates/lotta-nodes-and-faces.json
@@ -0,0 +1 @@
+{"id":96544,"settings":{"resolution.circle":64,"resolution.curve":64,"randomSeed":false},"nodes":[{"id":0,"position":[0,0],"type":"max/plantarium/float","props":{"value":0}},{"id":1,"position":[30,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":2,"position":[60,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":3,"position":[90,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":4,"position":[120,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":5,"position":[150,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":6,"position":[180,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":7,"position":[210,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":8,"position":[240,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":9,"position":[270,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":10,"position":[300,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":11,"position":[330,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":12,"position":[360,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":13,"position":[390,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":14,"position":[420,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":15,"position":[0,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":16,"position":[30,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":17,"position":[60,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":18,"position":[90,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":19,"position":[120,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":20,"position":[150,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":21,"position":[180,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":22,"position":[210,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":23,"position":[240,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":24,"position":[270,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":25,"position":[300,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":26,"position":[330,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":27,"position":[360,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":28,"position":[390,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":29,"position":[420,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":30,"position":[0,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":31,"position":[30,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":32,"position":[60,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":33,"position":[90,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":34,"position":[120,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":35,"position":[150,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":36,"position":[180,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":37,"position":[210,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":38,"position":[240,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":39,"position":[270,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":40,"position":[300,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":41,"position":[330,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":42,"position":[360,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":43,"position":[390,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":44,"position":[420,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":45,"position":[0,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":46,"position":[30,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":47,"position":[60,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":48,"position":[90,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":49,"position":[120,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":50,"position":[150,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":51,"position":[180,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":52,"position":[210,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":53,"position":[240,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":54,"position":[270,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":55,"position":[300,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":56,"position":[330,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":57,"position":[360,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":58,"position":[390,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":59,"position":[420,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":60,"position":[0,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":61,"position":[30,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":62,"position":[60,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":63,"position":[90,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":64,"position":[120,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":65,"position":[150,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":66,"position":[180,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":67,"position":[210,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":68,"position":[240,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":69,"position":[270,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":70,"position":[300,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":71,"position":[330,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":72,"position":[360,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":73,"position":[390,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":74,"position":[420,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":75,"position":[0,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":76,"position":[30,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":77,"position":[60,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":78,"position":[90,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":79,"position":[120,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":80,"position":[150,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":81,"position":[180,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":82,"position":[210,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":83,"position":[240,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":84,"position":[270,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":85,"position":[300,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":86,"position":[330,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":87,"position":[360,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":88,"position":[390,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":89,"position":[420,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":90,"position":[0,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":91,"position":[30,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":92,"position":[60,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":93,"position":[90,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":94,"position":[120,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":95,"position":[150,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":96,"position":[180,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":97,"position":[210,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":98,"position":[240,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":99,"position":[270,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":100,"position":[300,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":101,"position":[330,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":102,"position":[360,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":103,"position":[390,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":104,"position":[420,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":105,"position":[0,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":106,"position":[30,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":107,"position":[60,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":108,"position":[90,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":109,"position":[120,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":110,"position":[150,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":111,"position":[180,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":112,"position":[210,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":113,"position":[240,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":114,"position":[270,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":115,"position":[300,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":116,"position":[330,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":117,"position":[360,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":118,"position":[390,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":119,"position":[420,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":120,"position":[0,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":121,"position":[30,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":122,"position":[60,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":123,"position":[90,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":124,"position":[120,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":125,"position":[150,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":126,"position":[180,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":127,"position":[210,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":128,"position":[240,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":129,"position":[270,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":130,"position":[300,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":131,"position":[330,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":132,"position":[360,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":133,"position":[390,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":134,"position":[420,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":135,"position":[0,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":136,"position":[30,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":137,"position":[60,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":138,"position":[90,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":139,"position":[120,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":140,"position":[150,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":141,"position":[180,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":142,"position":[210,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":143,"position":[240,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":144,"position":[270,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":145,"position":[300,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":146,"position":[330,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":147,"position":[360,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":148,"position":[390,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":149,"position":[420,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":150,"position":[0,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":151,"position":[30,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":152,"position":[60,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":153,"position":[90,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":154,"position":[120,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":155,"position":[150,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":156,"position":[180,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":157,"position":[210,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":158,"position":[240,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":159,"position":[270,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":160,"position":[300,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":161,"position":[330,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":162,"position":[360,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":163,"position":[390,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":164,"position":[420,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":165,"position":[0,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":166,"position":[30,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":167,"position":[60,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":168,"position":[90,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":169,"position":[120,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":170,"position":[150,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":171,"position":[180,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":172,"position":[210,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":173,"position":[240,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":174,"position":[270,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":175,"position":[300,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":176,"position":[330,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":177,"position":[360,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":178,"position":[390,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":179,"position":[420,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":180,"position":[0,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":181,"position":[30,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":182,"position":[60,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":183,"position":[90,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":184,"position":[120,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":185,"position":[150,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":186,"position":[180,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":187,"position":[210,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":188,"position":[240,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":189,"position":[270,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":190,"position":[300,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":191,"position":[330,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":192,"position":[360,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":193,"position":[390,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":194,"position":[420,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":195,"position":[0,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":196,"position":[30,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":197,"position":[60,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":198,"position":[90,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":199,"position":[120,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":200,"position":[150,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":201,"position":[180,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":202,"position":[210,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":203,"position":[240,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":204,"position":[270,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":205,"position":[300,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":206,"position":[330,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":207,"position":[360,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":208,"position":[390,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":209,"position":[420,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":210,"position":[0,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":211,"position":[30,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":212,"position":[60,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":213,"position":[90,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":214,"position":[120,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":215,"position":[150,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":216,"position":[180,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":217,"position":[210,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":218,"position":[240,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":219,"position":[270,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":220,"position":[300,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":221,"position":[330,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":222,"position":[360,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":223,"position":[390,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":224,"position":[420,560],"type":"max/plantarium/math","props":{"op_type":1,"a":1,"b":0.075}},{"id":225,"position":[512.5,555],"type":"max/plantarium/output","props":{}},{"id":226,"position":[455,560],"type":"max/plantarium/stem","props":{"amount":126,"length":5,"thickness":1}},{"id":227,"position":[485,560],"type":"max/plantarium/noise","props":{"scale":3.3,"strength":5.3}}],"edges":[[0,0,1,"a"],[1,0,2,"a"],[2,0,3,"a"],[3,0,4,"a"],[4,0,5,"a"],[5,0,6,"a"],[6,0,7,"a"],[7,0,8,"a"],[8,0,9,"a"],[9,0,10,"a"],[10,0,11,"a"],[11,0,12,"a"],[12,0,13,"a"],[13,0,14,"a"],[14,0,15,"a"],[15,0,16,"a"],[16,0,17,"a"],[17,0,18,"a"],[18,0,19,"a"],[19,0,20,"a"],[20,0,21,"a"],[21,0,22,"a"],[22,0,23,"a"],[23,0,24,"a"],[24,0,25,"a"],[25,0,26,"a"],[26,0,27,"a"],[27,0,28,"a"],[28,0,29,"a"],[29,0,30,"a"],[30,0,31,"a"],[31,0,32,"a"],[32,0,33,"a"],[33,0,34,"a"],[34,0,35,"a"],[35,0,36,"a"],[36,0,37,"a"],[37,0,38,"a"],[38,0,39,"a"],[39,0,40,"a"],[40,0,41,"a"],[41,0,42,"a"],[42,0,43,"a"],[43,0,44,"a"],[44,0,45,"a"],[45,0,46,"a"],[46,0,47,"a"],[47,0,48,"a"],[48,0,49,"a"],[49,0,50,"a"],[50,0,51,"a"],[51,0,52,"a"],[52,0,53,"a"],[53,0,54,"a"],[54,0,55,"a"],[55,0,56,"a"],[56,0,57,"a"],[57,0,58,"a"],[58,0,59,"a"],[59,0,60,"a"],[60,0,61,"a"],[61,0,62,"a"],[62,0,63,"a"],[63,0,64,"a"],[64,0,65,"a"],[65,0,66,"a"],[66,0,67,"a"],[67,0,68,"a"],[68,0,69,"a"],[69,0,70,"a"],[70,0,71,"a"],[71,0,72,"a"],[72,0,73,"a"],[73,0,74,"a"],[74,0,75,"a"],[75,0,76,"a"],[76,0,77,"a"],[77,0,78,"a"],[78,0,79,"a"],[79,0,80,"a"],[80,0,81,"a"],[81,0,82,"a"],[82,0,83,"a"],[83,0,84,"a"],[84,0,85,"a"],[85,0,86,"a"],[86,0,87,"a"],[87,0,88,"a"],[88,0,89,"a"],[89,0,90,"a"],[90,0,91,"a"],[91,0,92,"a"],[92,0,93,"a"],[93,0,94,"a"],[94,0,95,"a"],[95,0,96,"a"],[96,0,97,"a"],[97,0,98,"a"],[98,0,99,"a"],[99,0,100,"a"],[100,0,101,"a"],[101,0,102,"a"],[102,0,103,"a"],[103,0,104,"a"],[104,0,105,"a"],[105,0,106,"a"],[106,0,107,"a"],[107,0,108,"a"],[108,0,109,"a"],[109,0,110,"a"],[110,0,111,"a"],[111,0,112,"a"],[112,0,113,"a"],[113,0,114,"a"],[114,0,115,"a"],[115,0,116,"a"],[116,0,117,"a"],[117,0,118,"a"],[118,0,119,"a"],[119,0,120,"a"],[120,0,121,"a"],[121,0,122,"a"],[122,0,123,"a"],[123,0,124,"a"],[124,0,125,"a"],[125,0,126,"a"],[126,0,127,"a"],[127,0,128,"a"],[128,0,129,"a"],[129,0,130,"a"],[130,0,131,"a"],[131,0,132,"a"],[132,0,133,"a"],[133,0,134,"a"],[134,0,135,"a"],[135,0,136,"a"],[136,0,137,"a"],[137,0,138,"a"],[138,0,139,"a"],[139,0,140,"a"],[140,0,141,"a"],[141,0,142,"a"],[142,0,143,"a"],[143,0,144,"a"],[144,0,145,"a"],[145,0,146,"a"],[146,0,147,"a"],[147,0,148,"a"],[148,0,149,"a"],[149,0,150,"a"],[150,0,151,"a"],[151,0,152,"a"],[152,0,153,"a"],[153,0,154,"a"],[154,0,155,"a"],[155,0,156,"a"],[156,0,157,"a"],[157,0,158,"a"],[158,0,159,"a"],[159,0,160,"a"],[160,0,161,"a"],[161,0,162,"a"],[162,0,163,"a"],[163,0,164,"a"],[164,0,165,"a"],[165,0,166,"a"],[166,0,167,"a"],[167,0,168,"a"],[168,0,169,"a"],[169,0,170,"a"],[170,0,171,"a"],[171,0,172,"a"],[172,0,173,"a"],[173,0,174,"a"],[174,0,175,"a"],[175,0,176,"a"],[176,0,177,"a"],[177,0,178,"a"],[178,0,179,"a"],[179,0,180,"a"],[180,0,181,"a"],[181,0,182,"a"],[182,0,183,"a"],[183,0,184,"a"],[184,0,185,"a"],[185,0,186,"a"],[186,0,187,"a"],[187,0,188,"a"],[188,0,189,"a"],[189,0,190,"a"],[190,0,191,"a"],[191,0,192,"a"],[192,0,193,"a"],[193,0,194,"a"],[194,0,195,"a"],[195,0,196,"a"],[196,0,197,"a"],[197,0,198,"a"],[198,0,199,"a"],[199,0,200,"a"],[200,0,201,"a"],[201,0,202,"a"],[202,0,203,"a"],[203,0,204,"a"],[204,0,205,"a"],[205,0,206,"a"],[206,0,207,"a"],[207,0,208,"a"],[208,0,209,"a"],[209,0,210,"a"],[210,0,211,"a"],[211,0,212,"a"],[212,0,213,"a"],[213,0,214,"a"],[214,0,215,"a"],[215,0,216,"a"],[216,0,217,"a"],[217,0,218,"a"],[218,0,219,"a"],[219,0,220,"a"],[220,0,221,"a"],[221,0,222,"a"],[222,0,223,"a"],[223,0,224,"a"],[224,0,226,"length"],[226,0,227,"plant"],[227,0,225,"input"]]}
diff --git a/app/src/lib/graph-templates/lotta-nodes.json b/app/src/lib/graph-templates/lotta-nodes.json
new file mode 100644
index 0000000..9c6c386
--- /dev/null
+++ b/app/src/lib/graph-templates/lotta-nodes.json
@@ -0,0 +1 @@
+{"id":96544,"settings":{"resolution.circle":32,"resolution.curve":32,"randomSeed":false},"nodes":[{"id":0,"position":[0,0],"type":"max/plantarium/float","props":{"value":0}},{"id":1,"position":[30,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":2,"position":[60,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":3,"position":[90,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":4,"position":[120,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":5,"position":[150,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":6,"position":[180,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":7,"position":[210,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":8,"position":[240,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":9,"position":[270,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":10,"position":[300,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":11,"position":[330,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":12,"position":[360,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":13,"position":[390,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":14,"position":[420,0],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":15,"position":[0,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":16,"position":[30,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":17,"position":[60,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":18,"position":[90,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":19,"position":[120,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":20,"position":[150,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":21,"position":[180,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":22,"position":[210,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":23,"position":[240,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":24,"position":[270,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":25,"position":[300,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":26,"position":[330,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":27,"position":[360,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":28,"position":[390,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":29,"position":[420,40],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":30,"position":[0,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":31,"position":[30,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":32,"position":[60,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":33,"position":[90,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":34,"position":[120,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":35,"position":[150,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":36,"position":[180,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":37,"position":[210,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":38,"position":[240,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":39,"position":[270,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":40,"position":[300,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":41,"position":[330,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":42,"position":[360,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":43,"position":[390,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":44,"position":[420,80],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":45,"position":[0,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":46,"position":[30,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":47,"position":[60,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":48,"position":[90,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":49,"position":[120,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":50,"position":[150,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":51,"position":[180,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":52,"position":[210,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":53,"position":[240,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":54,"position":[270,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":55,"position":[300,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":56,"position":[330,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":57,"position":[360,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":58,"position":[390,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":59,"position":[420,120],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":60,"position":[0,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":61,"position":[30,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":62,"position":[60,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":63,"position":[90,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":64,"position":[120,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":65,"position":[150,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":66,"position":[180,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":67,"position":[210,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":68,"position":[240,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":69,"position":[270,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":70,"position":[300,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":71,"position":[330,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":72,"position":[360,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":73,"position":[390,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":74,"position":[420,160],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":75,"position":[0,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":76,"position":[30,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":77,"position":[60,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":78,"position":[90,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":79,"position":[120,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":80,"position":[150,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":81,"position":[180,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":82,"position":[210,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":83,"position":[240,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":84,"position":[270,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":85,"position":[300,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":86,"position":[330,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":87,"position":[360,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":88,"position":[390,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":89,"position":[420,200],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":90,"position":[0,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":91,"position":[30,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":92,"position":[60,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":93,"position":[90,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":94,"position":[120,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":95,"position":[150,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":96,"position":[180,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":97,"position":[210,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":98,"position":[240,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":99,"position":[270,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":100,"position":[300,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":101,"position":[330,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":102,"position":[360,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":103,"position":[390,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":104,"position":[420,240],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":105,"position":[0,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":106,"position":[30,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":107,"position":[60,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":108,"position":[90,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":109,"position":[120,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":110,"position":[150,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":111,"position":[180,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":112,"position":[210,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":113,"position":[240,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":114,"position":[270,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":115,"position":[300,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":116,"position":[330,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":117,"position":[360,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":118,"position":[390,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":119,"position":[420,280],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":120,"position":[0,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":121,"position":[30,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":122,"position":[60,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":123,"position":[90,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":124,"position":[120,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":125,"position":[150,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":126,"position":[180,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":127,"position":[210,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":128,"position":[240,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":129,"position":[270,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":130,"position":[300,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":131,"position":[330,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":132,"position":[360,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":133,"position":[390,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":134,"position":[420,320],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":135,"position":[0,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":136,"position":[30,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":137,"position":[60,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":138,"position":[90,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":139,"position":[120,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":140,"position":[150,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":141,"position":[180,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":142,"position":[210,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":143,"position":[240,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":144,"position":[270,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":145,"position":[300,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":146,"position":[330,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":147,"position":[360,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":148,"position":[390,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":149,"position":[420,360],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":150,"position":[0,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":151,"position":[30,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":152,"position":[60,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":153,"position":[90,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":154,"position":[120,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":155,"position":[150,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":156,"position":[180,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":157,"position":[210,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":158,"position":[240,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":159,"position":[270,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":160,"position":[300,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":161,"position":[330,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":162,"position":[360,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":163,"position":[390,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":164,"position":[420,400],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":165,"position":[0,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":166,"position":[30,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":167,"position":[60,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":168,"position":[90,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":169,"position":[120,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":170,"position":[150,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":171,"position":[180,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":172,"position":[210,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":173,"position":[240,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":174,"position":[270,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":175,"position":[300,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":176,"position":[330,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":177,"position":[360,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":178,"position":[390,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":179,"position":[420,440],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":180,"position":[0,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":181,"position":[30,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":182,"position":[60,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":183,"position":[90,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":184,"position":[120,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":185,"position":[150,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":186,"position":[180,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":187,"position":[210,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":188,"position":[240,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":189,"position":[270,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":190,"position":[300,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":191,"position":[330,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":192,"position":[360,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":193,"position":[390,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":194,"position":[420,480],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":195,"position":[0,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":196,"position":[30,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":197,"position":[60,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":198,"position":[90,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":199,"position":[120,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":200,"position":[150,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":201,"position":[180,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":202,"position":[210,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":203,"position":[240,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":204,"position":[270,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":205,"position":[300,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":206,"position":[330,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":207,"position":[360,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":208,"position":[390,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":209,"position":[420,520],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":210,"position":[0,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":211,"position":[30,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":212,"position":[60,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":213,"position":[90,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":214,"position":[120,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":215,"position":[150,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":216,"position":[180,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":217,"position":[210,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":218,"position":[240,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":219,"position":[270,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":220,"position":[300,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":221,"position":[330,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":222,"position":[360,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":223,"position":[390,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.05}},{"id":224,"position":[420,560],"type":"max/plantarium/math","props":{"op_type":0,"a":1,"b":0.075}},{"id":225,"position":[485,560],"type":"max/plantarium/output","props":{}},{"id":226,"position":[455,560],"type":"max/plantarium/stem","props":{"amount":1,"length":5,"thickness":0.92}}],"edges":[[0,0,1,"a"],[1,0,2,"a"],[2,0,3,"a"],[3,0,4,"a"],[4,0,5,"a"],[5,0,6,"a"],[6,0,7,"a"],[7,0,8,"a"],[8,0,9,"a"],[9,0,10,"a"],[10,0,11,"a"],[11,0,12,"a"],[12,0,13,"a"],[13,0,14,"a"],[14,0,15,"a"],[15,0,16,"a"],[16,0,17,"a"],[17,0,18,"a"],[18,0,19,"a"],[19,0,20,"a"],[20,0,21,"a"],[21,0,22,"a"],[22,0,23,"a"],[23,0,24,"a"],[24,0,25,"a"],[25,0,26,"a"],[26,0,27,"a"],[27,0,28,"a"],[28,0,29,"a"],[29,0,30,"a"],[30,0,31,"a"],[31,0,32,"a"],[32,0,33,"a"],[33,0,34,"a"],[34,0,35,"a"],[35,0,36,"a"],[36,0,37,"a"],[37,0,38,"a"],[38,0,39,"a"],[39,0,40,"a"],[40,0,41,"a"],[41,0,42,"a"],[42,0,43,"a"],[43,0,44,"a"],[44,0,45,"a"],[45,0,46,"a"],[46,0,47,"a"],[47,0,48,"a"],[48,0,49,"a"],[49,0,50,"a"],[50,0,51,"a"],[51,0,52,"a"],[52,0,53,"a"],[53,0,54,"a"],[54,0,55,"a"],[55,0,56,"a"],[56,0,57,"a"],[57,0,58,"a"],[58,0,59,"a"],[59,0,60,"a"],[60,0,61,"a"],[61,0,62,"a"],[62,0,63,"a"],[63,0,64,"a"],[64,0,65,"a"],[65,0,66,"a"],[66,0,67,"a"],[67,0,68,"a"],[68,0,69,"a"],[69,0,70,"a"],[70,0,71,"a"],[71,0,72,"a"],[72,0,73,"a"],[73,0,74,"a"],[74,0,75,"a"],[75,0,76,"a"],[76,0,77,"a"],[77,0,78,"a"],[78,0,79,"a"],[79,0,80,"a"],[80,0,81,"a"],[81,0,82,"a"],[82,0,83,"a"],[83,0,84,"a"],[84,0,85,"a"],[85,0,86,"a"],[86,0,87,"a"],[87,0,88,"a"],[88,0,89,"a"],[89,0,90,"a"],[90,0,91,"a"],[91,0,92,"a"],[92,0,93,"a"],[93,0,94,"a"],[94,0,95,"a"],[95,0,96,"a"],[96,0,97,"a"],[97,0,98,"a"],[98,0,99,"a"],[99,0,100,"a"],[100,0,101,"a"],[101,0,102,"a"],[102,0,103,"a"],[103,0,104,"a"],[104,0,105,"a"],[105,0,106,"a"],[106,0,107,"a"],[107,0,108,"a"],[108,0,109,"a"],[109,0,110,"a"],[110,0,111,"a"],[111,0,112,"a"],[112,0,113,"a"],[113,0,114,"a"],[114,0,115,"a"],[115,0,116,"a"],[116,0,117,"a"],[117,0,118,"a"],[118,0,119,"a"],[119,0,120,"a"],[120,0,121,"a"],[121,0,122,"a"],[122,0,123,"a"],[123,0,124,"a"],[124,0,125,"a"],[125,0,126,"a"],[126,0,127,"a"],[127,0,128,"a"],[128,0,129,"a"],[129,0,130,"a"],[130,0,131,"a"],[131,0,132,"a"],[132,0,133,"a"],[133,0,134,"a"],[134,0,135,"a"],[135,0,136,"a"],[136,0,137,"a"],[137,0,138,"a"],[138,0,139,"a"],[139,0,140,"a"],[140,0,141,"a"],[141,0,142,"a"],[142,0,143,"a"],[143,0,144,"a"],[144,0,145,"a"],[145,0,146,"a"],[146,0,147,"a"],[147,0,148,"a"],[148,0,149,"a"],[149,0,150,"a"],[150,0,151,"a"],[151,0,152,"a"],[152,0,153,"a"],[153,0,154,"a"],[154,0,155,"a"],[155,0,156,"a"],[156,0,157,"a"],[157,0,158,"a"],[158,0,159,"a"],[159,0,160,"a"],[160,0,161,"a"],[161,0,162,"a"],[162,0,163,"a"],[163,0,164,"a"],[164,0,165,"a"],[165,0,166,"a"],[166,0,167,"a"],[167,0,168,"a"],[168,0,169,"a"],[169,0,170,"a"],[170,0,171,"a"],[171,0,172,"a"],[172,0,173,"a"],[173,0,174,"a"],[174,0,175,"a"],[175,0,176,"a"],[176,0,177,"a"],[177,0,178,"a"],[178,0,179,"a"],[179,0,180,"a"],[180,0,181,"a"],[181,0,182,"a"],[182,0,183,"a"],[183,0,184,"a"],[184,0,185,"a"],[185,0,186,"a"],[186,0,187,"a"],[187,0,188,"a"],[188,0,189,"a"],[189,0,190,"a"],[190,0,191,"a"],[191,0,192,"a"],[192,0,193,"a"],[193,0,194,"a"],[194,0,195,"a"],[195,0,196,"a"],[196,0,197,"a"],[197,0,198,"a"],[198,0,199,"a"],[199,0,200,"a"],[200,0,201,"a"],[201,0,202,"a"],[202,0,203,"a"],[203,0,204,"a"],[204,0,205,"a"],[205,0,206,"a"],[206,0,207,"a"],[207,0,208,"a"],[208,0,209,"a"],[209,0,210,"a"],[210,0,211,"a"],[211,0,212,"a"],[212,0,213,"a"],[213,0,214,"a"],[214,0,215,"a"],[215,0,216,"a"],[216,0,217,"a"],[217,0,218,"a"],[218,0,219,"a"],[219,0,220,"a"],[220,0,221,"a"],[221,0,222,"a"],[222,0,223,"a"],[223,0,224,"a"],[224,0,226,"length"],[226,0,225,"input"]]}
diff --git a/app/src/lib/helpers/createKeyMap.ts b/app/src/lib/helpers/createKeyMap.ts
index f9cc3c9..82aa7d6 100644
--- a/app/src/lib/helpers/createKeyMap.ts
+++ b/app/src/lib/helpers/createKeyMap.ts
@@ -5,6 +5,7 @@ type Shortcut = {
shift?: boolean,
ctrl?: boolean,
alt?: boolean,
+ preventDefault?: boolean,
description?: string,
callback: (event: KeyboardEvent) => void
}
@@ -17,8 +18,11 @@ export function createKeyMap(keys: Shortcut[]) {
const store = writable(new Map(keys.map(k => [getShortcutId(k), k])));
+
return {
handleKeyboardEvent: (event: KeyboardEvent) => {
+ const activeElement = document.activeElement as HTMLElement;
+ if (activeElement?.tagName === "INPUT" || activeElement?.tagName === "TEXTAREA") return;
const key = [...get(store).values()].find(k => {
if (Array.isArray(k.key) ? !k.key.includes(event.key) : k.key !== event.key) return false;
if ("shift" in k && k.shift !== event.shiftKey) return false;
@@ -26,6 +30,7 @@ export function createKeyMap(keys: Shortcut[]) {
if ("alt" in k && k.alt !== event.altKey) return false;
return true;
});
+ if (key && key.preventDefault) event.preventDefault();
key?.callback(event);
},
addShortcut: (shortcut: Shortcut) => {
diff --git a/app/src/lib/performance/BarSplit.svelte b/app/src/lib/performance/BarSplit.svelte
new file mode 100644
index 0000000..dd28ffd
--- /dev/null
+++ b/app/src/lib/performance/BarSplit.svelte
@@ -0,0 +1,48 @@
+
+
+
+
+ {#each values as value, i}
+
+ {Math.round(value)}ms
+
+ {/each}
+
+
+
+ {#each values as _label, i}
+
{labels[i]}
+ {/each}
+
+
+
+
+
+
diff --git a/app/src/lib/performance/PerformanceViewer.svelte b/app/src/lib/performance/PerformanceViewer.svelte
index 53a4553..5fcc674 100644
--- a/app/src/lib/performance/PerformanceViewer.svelte
+++ b/app/src/lib/performance/PerformanceViewer.svelte
@@ -4,6 +4,7 @@
import { Checkbox } from "@nodes/ui";
import localStore from "$lib/helpers/localStore";
import { type PerformanceData } from "./store";
+ import BarSplit from "./BarSplit.svelte";
export let data: PerformanceData;
@@ -42,7 +43,7 @@
}
function getLast(key: string) {
- return data.at(-1)?.[key][0] || 0;
+ return data.at(-1)?.[key]?.[0] || 0;
}
function getLasts() {
@@ -53,13 +54,13 @@
if (onlyLast) {
return (
getLast("runtime") +
- getLast("create-geometries") +
+ getLast("update-geometries") +
getLast("worker-transfer")
);
}
return (
getAverage("runtime") +
- getAverage("create-geometries") +
+ getAverage("update-geometries") +
getAverage("worker-transfer")
);
}
@@ -73,7 +74,7 @@
const viewerKeys = [
"total-vertices",
"total-faces",
- "create-geometries",
+ "update-geometries",
"split-result",
];
@@ -116,8 +117,8 @@
return data.map((run) => {
return (
run["runtime"].reduce((acc, v) => acc + v, 0) +
- run["create-geometries"].reduce((acc, v) => acc + v, 0) +
- run["worker-transfer"].reduce((acc, v) => acc + v, 0)
+ run["update-geometries"].reduce((acc, v) => acc + v, 0) +
+ (run["worker-transfer"]?.reduce((acc, v) => acc + v, 0) || 0)
);
});
}
@@ -125,8 +126,8 @@
return data.map((run) => {
return (
run["runtime"][0] +
- run["create-geometries"][0] +
- run["worker-transfer"][0]
+ run["update-geometries"][0] +
+ (run["worker-transfer"]?.[0] || 0)
);
});
}
@@ -147,6 +148,22 @@
});
}
+ function getSplitValues(): number[] {
+ if (showAverage) {
+ return [
+ getAverage("worker-transfer"),
+ getAverage("runtime"),
+ getAverage("update-geometries"),
+ ];
+ }
+
+ return [
+ getLast("worker-transfer"),
+ getLast("runtime"),
+ getLast("update-geometries"),
+ ];
+ }
+
function getTitle(t: string) {
if (t.includes("/")) {
return `Node ${t.split("/").slice(-1).join("/")}`;
@@ -159,7 +176,7 @@
}
-{#key $activeType && data}
+{#key $activeType}
{#if $activeType === "cache-hit"}
{/if}
-
-
-
-
-
-
- {#if data.length !== 0}
-
General
-
-
-
-
- {round(getTotalPerformance(!showAverage))}ms
- |
- ($activeType = "total")}
- >
- total({Math.floor(
- 1000 / getTotalPerformance(showAverage),
- )}fps)
- |
-
- {#each getPerformanceData(!showAverage) as [key, value]}
-
-
- {round(value)}ms
- |
- ($activeType = key)}
- >
- {key}
- |
-
- {/each}
-
-
- {data.length} |
- Samples |
-
-
-
-
-
- Nodes
- |
-
-
-
-
- {getCacheRatio(!showAverage)}% |
- ($activeType = "cache-hit")}>cache hits |
-
- {#each getNodePerformanceData(!showAverage) as [key, value]}
-
-
- {round(value)}ms
- |
-
- ($activeType = key)}
- >
- {key.split("/").slice(-1).join("/")}
- |
-
- {/each}
-
-
-
-
- Viewer
- |
-
-
-
-
- {humanizeNumber(getLast("total-vertices"))} |
- Vertices |
-
-
- {humanizeNumber(getLast("total-faces"))} |
- Faces |
-
- {#each getViewerPerformanceData(!showAverage) as [key, value]}
-
-
- {round(value)}ms
- |
- ($activeType = key)}
- >
- {key.split("/").slice(-1).join("/")}
- |
-
- {/each}
-
-
- {:else}
-
No runs available
- {/if}
-
{/key}
+
+
diff --git a/app/src/lib/settings/panels/ExportSettings.svelte b/app/src/lib/settings/panels/ExportSettings.svelte
new file mode 100644
index 0000000..2217ac1
--- /dev/null
+++ b/app/src/lib/settings/panels/ExportSettings.svelte
@@ -0,0 +1,53 @@
+
+
+
+
+
+
diff --git a/app/src/lib/settings/panels/Keymap.svelte b/app/src/lib/settings/panels/Keymap.svelte
index 32eb0df..28bf9ad 100644
--- a/app/src/lib/settings/panels/Keymap.svelte
+++ b/app/src/lib/settings/panels/Keymap.svelte
@@ -4,10 +4,11 @@
export let keymap: ReturnType;
const keys = keymap?.keys;
+ export let title = "Keymap";
-
Editor
+
{title}
{#each $keys as key}
diff --git a/app/src/lib/worker-runtime-executor-backend.ts b/app/src/lib/worker-runtime-executor-backend.ts
index a5d646e..55550d7 100644
--- a/app/src/lib/worker-runtime-executor-backend.ts
+++ b/app/src/lib/worker-runtime-executor-backend.ts
@@ -7,12 +7,15 @@ const cache = new MemoryRuntimeCache();
const nodeRegistry = new RemoteNodeRegistry("");
const executor = new MemoryRuntimeExecutor(nodeRegistry, cache);
-const performanceStore = createPerformanceStore();
+const performanceStore = createPerformanceStore("worker");
executor.perf = performanceStore;
export async function executeGraph(graph: Graph, settings: Record): Promise {
await nodeRegistry.load(graph.nodes.map((n) => n.type));
- return executor.execute(graph, settings);
+ performanceStore.startRun();
+ let res = await executor.execute(graph, settings);
+ performanceStore.stopRun();
+ return res;
}
export function getPerformanceData() {
diff --git a/app/src/routes/+page.svelte b/app/src/routes/+page.svelte
index f361ede..e817d3c 100644
--- a/app/src/routes/+page.svelte
+++ b/app/src/routes/+page.svelte
@@ -10,7 +10,7 @@
import { AppSettingTypes, AppSettings } from "$lib/settings/app-settings";
import { writable, type Writable } from "svelte/store";
import Keymap from "$lib/settings/panels/Keymap.svelte";
- import type { createKeyMap } from "$lib/helpers/createKeyMap";
+ import { createKeyMap } from "$lib/helpers/createKeyMap";
import NodeStore from "$lib/node-store/NodeStore.svelte";
import type { GraphManager } from "$lib/graph-interface/graph-manager";
import { setContext } from "svelte";
@@ -20,15 +20,28 @@
import GraphSettings from "$lib/settings/panels/GraphSettings.svelte";
import NestedSettings from "$lib/settings/panels/NestedSettings.svelte";
import { createPerformanceStore } from "$lib/performance";
+ import type { Scene } from "three";
+ import ExportSettings from "$lib/settings/panels/ExportSettings.svelte";
+ import {
+ MemoryRuntimeCache,
+ MemoryRuntimeExecutor,
+ } from "$lib/runtime-executor";
+ import { fastHashString } from "@nodes/utils";
+ import BenchmarkPanel from "$lib/settings/panels/BenchmarkPanel.svelte";
+
+ let performanceStore = createPerformanceStore("page");
const nodeRegistry = new RemoteNodeRegistry("");
const workerRuntime = new WorkerRuntimeExecutor();
+ const runtimeCache = new MemoryRuntimeCache();
+ const memoryRuntime = new MemoryRuntimeExecutor(nodeRegistry, runtimeCache);
+ memoryRuntime.perf = performanceStore;
- let performanceStore = createPerformanceStore();
+ $: runtime = $AppSettings.useWorker ? workerRuntime : memoryRuntime;
let activeNode: Node | undefined;
-
- let graphResult: Int32Array;
+ let scene: Scene;
+ let updateViewerResult: (result: Int32Array) => void;
let graph = localStorage.getItem("graph")
? JSON.parse(localStorage.getItem("graph")!)
@@ -36,11 +49,22 @@
let manager: GraphManager;
let managerStatus: Writable<"loading" | "error" | "idle">;
- $: if (manager) {
- setContext("graphManager", manager);
+
+ async function randomGenerate() {
+ const g = manager.serialize();
+ const s = { ...$graphSettings, randomSeed: true };
+ const res = await handleResult(g, s);
+ return res;
}
let keymap: ReturnType;
+ let applicationKeymap = createKeyMap([
+ {
+ key: "r",
+ description: "Regenerate the plant model",
+ callback: randomGenerate,
+ },
+ ]);
let graphSettings = writable>({});
let graphSettingTypes = {};
@@ -50,42 +74,59 @@
| {
graph: Graph;
settings: Record;
+ hash: number;
}
| undefined;
async function handleResult(_graph: Graph, _settings: Record) {
if (!_settings) return;
+ const inputHash = fastHashString(
+ JSON.stringify(_graph) + JSON.stringify(_settings),
+ );
if (isWorking) {
unfinished = {
graph: _graph,
settings: _settings,
+ hash: inputHash,
};
- return;
+ return false;
}
isWorking = true;
+ performanceStore.startRun();
try {
let a = performance.now();
- graphResult = await workerRuntime.execute(_graph, _settings);
+ const graphResult = await runtime.execute(_graph, _settings);
let b = performance.now();
- let perfData = await workerRuntime.getPerformanceData();
- let lastRun = perfData.at(-1);
- if (lastRun) {
- lastRun["worker-transfer"] = [b - a - lastRun.runtime[0]];
- performanceStore.mergeData(lastRun);
+
+ if ($AppSettings.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],
+ );
+ }
}
- isWorking = false;
+
+ updateViewerResult(graphResult);
} catch (error) {
console.log("errors", error);
+ } finally {
+ performanceStore.stopRun();
+ isWorking = false;
}
- performanceStore.stopRun();
- performanceStore.startRun();
-
- if (unfinished) {
+ if (unfinished && unfinished.hash === inputHash) {
let d = unfinished;
unfinished = undefined;
- handleResult(d.graph, d.settings);
+ await handleResult(d.graph, d.settings);
}
+
+ return true;
}
$: if (AppSettings) {
@@ -97,6 +138,18 @@
AppSettingTypes.debug.stressTest.loadTree.callback = () => {
graph = templates.tree($AppSettings.amount);
};
+ //@ts-ignore
+ AppSettingTypes.debug.stressTest.lottaFaces.callback = () => {
+ graph = templates.lottaFaces;
+ };
+ //@ts-ignore
+ AppSettingTypes.debug.stressTest.lottaNodes.callback = () => {
+ graph = templates.lottaNodes;
+ };
+ //@ts-ignore
+ AppSettingTypes.debug.stressTest.lottaNodesAndFaces.callback = () => {
+ graph = templates.lottaNodesAndFaces;
+ };
}
function handleSave(event: CustomEvent) {
@@ -104,13 +157,15 @@
}
+
@@ -143,10 +198,14 @@
title="Keyboard Shortcuts"
icon="i-tabler-keyboard"
>
+
{#if keymap}
-
+
{/if}
+
+
+
{/if}
+
+
+
-
-
diff --git a/packages/ui/src/lib/elements/Float.svelte b/packages/ui/src/lib/elements/Float.svelte
index d210ff2..b3dd594 100644
--- a/packages/ui/src/lib/elements/Float.svelte
+++ b/packages/ui/src/lib/elements/Float.svelte
@@ -1,11 +1,19 @@
- {#if typeof min !== "undefined" && typeof max !== "undefined"}
-
- {/if}
-
-
+ {#if typeof min !== 'undefined' && typeof max !== 'undefined'}
+
+ {/if}
+
+
-
+
diff --git a/packages/ui/src/lib/elements/Select.svelte b/packages/ui/src/lib/elements/Select.svelte
index ece13f2..6c09037 100644
--- a/packages/ui/src/lib/elements/Select.svelte
+++ b/packages/ui/src/lib/elements/Select.svelte
@@ -1,23 +1,25 @@
diff --git a/packages/ui/src/lib/elements/Vec3.svelte b/packages/ui/src/lib/elements/Vec3.svelte
index b2025fc..a0bba47 100644
--- a/packages/ui/src/lib/elements/Vec3.svelte
+++ b/packages/ui/src/lib/elements/Vec3.svelte
@@ -1,31 +1,29 @@
-
-
-
+
+
+
diff --git a/packages/ui/src/routes/+page.svelte b/packages/ui/src/routes/+page.svelte
index fed7354..c0a6057 100644
--- a/packages/ui/src/routes/+page.svelte
+++ b/packages/ui/src/routes/+page.svelte
@@ -1,7 +1,34 @@
-
+
+
+
+
+
+ Vec3 {JSON.stringify(vecValue)}
+
+
+
+
+
diff --git a/packages/utils/src/flatTree.ts b/packages/utils/src/flatTree.ts
index a42f101..e1cfca7 100644
--- a/packages/utils/src/flatTree.ts
+++ b/packages/utils/src/flatTree.ts
@@ -102,3 +102,47 @@ function decode_recursive(dense: number[] | Int32Array, index = 0) {
export function decodeNestedArray(dense: number[] | Int32Array) {
return decode_recursive(dense, 0)[0];
}
+
+
+export function splitNestedArray(input: Int32Array) {
+ let index = 0;
+ const length = input.length;
+ let res: Int32Array[] = [];
+
+ let nextBracketIndex = 0;
+ let argStartIndex = 0;
+ let depth = -1;
+
+ while (index < length) {
+ const value = input[index];
+
+ if (index === nextBracketIndex) {
+ nextBracketIndex = index + input[index + 1] + 1;
+ if (value === 0) {
+ depth++;
+ } else {
+ depth--;
+ }
+
+ if (depth === 1 && value === 0) {
+ // if opening bracket
+ argStartIndex = index + 2;
+ }
+
+ if (depth === 0 && value === 1) {
+ // if closing bracket
+ res.push(input.slice(argStartIndex, index));
+ argStartIndex = index + 2;
+ }
+
+ index = nextBracketIndex;
+ continue;
+ }
+
+ // we should not be here
+
+ index++;
+ }
+
+ return res;
+}
diff --git a/packages/utils/src/geometry/path_data.rs b/packages/utils/src/geometry/path_data.rs
index 2f1b99f..7050aef 100644
--- a/packages/utils/src/geometry/path_data.rs
+++ b/packages/utils/src/geometry/path_data.rs
@@ -11,12 +11,52 @@ pub struct PathDataMut<'a> {
pub points: &'a mut [f32],
}
+impl PathDataMut<'_> {
+ pub fn get_length(&self) -> f32 {
+ let mut l = 0.0;
+ for i in 0..(self.length - 1) {
+ let a = vec3(
+ self.points[i * 4],
+ self.points[i * 4 + 1],
+ self.points[i * 4 + 2],
+ );
+ let b = vec3(
+ self.points[(i + 1) * 4],
+ self.points[(i + 1) * 4 + 1],
+ self.points[(i + 1) * 4 + 2],
+ );
+ l += (b - a).length();
+ }
+ l
+ }
+}
+
pub struct PathData<'a> {
pub depth: i32,
pub length: usize,
pub points: &'a [f32],
}
+impl PathData<'_> {
+ pub fn get_length(&self) -> f32 {
+ let mut l = 0.0;
+ for i in 0..(self.length - 1) {
+ let a = vec3(
+ self.points[i * 4],
+ self.points[i * 4 + 1],
+ self.points[i * 4 + 2],
+ );
+ let b = vec3(
+ self.points[(i + 1) * 4],
+ self.points[(i + 1) * 4 + 1],
+ self.points[(i + 1) * 4 + 2],
+ );
+ l += (b - a).length();
+ }
+ l
+ }
+}
+
pub fn create_multiple_paths(amount: usize, point_amount: usize, depth: i32) -> Vec {
let output_size = amount * (point_amount * 4 + PATH_HEADER_SIZE + 4) + 4;
diff --git a/packages/utils/src/tree.rs b/packages/utils/src/tree.rs
index bc7c8db..6527ddd 100644
--- a/packages/utils/src/tree.rs
+++ b/packages/utils/src/tree.rs
@@ -162,7 +162,12 @@ pub fn evaluate_vec3(input_args: &[i32]) -> Vec {
}
pub fn evaluate_float(arg: &[i32]) -> f32 {
- decode_float(evaluate_int(arg))
+ let res = decode_float(evaluate_int(arg));
+ if res.is_nan() {
+ 0.0
+ } else {
+ res
+ }
}
pub fn evaluate_int(input_args: &[i32]) -> i32 {
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 80843e3..be1dacf 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -34,6 +34,9 @@ importers:
comlink:
specifier: ^4.4.1
version: 4.4.1
+ file-saver:
+ specifier: ^2.0.5
+ version: 2.0.5
jsondiffpatch:
specifier: ^0.6.0
version: 0.6.0
@@ -56,6 +59,9 @@ importers:
'@tsconfig/svelte':
specifier: ^5.0.4
version: 5.0.4
+ '@types/file-saver':
+ specifier: ^2.0.7
+ version: 2.0.7
'@unocss/preset-icons':
specifier: ^0.59.4
version: 0.59.4
@@ -747,6 +753,9 @@ packages:
'@types/estree@1.0.5':
resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==}
+ '@types/file-saver@2.0.7':
+ resolution: {integrity: sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==}
+
'@types/json-schema@7.0.15':
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
@@ -1314,6 +1323,9 @@ packages:
resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==}
engines: {node: ^10.12.0 || >=12.0.0}
+ file-saver@2.0.5:
+ resolution: {integrity: sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==}
+
fill-range@7.0.1:
resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==}
engines: {node: '>=8'}
@@ -3006,6 +3018,8 @@ snapshots:
'@types/estree@1.0.5': {}
+ '@types/file-saver@2.0.7': {}
+
'@types/json-schema@7.0.15': {}
'@types/node@20.12.7':
@@ -3735,6 +3749,8 @@ snapshots:
dependencies:
flat-cache: 3.2.0
+ file-saver@2.0.5: {}
+
fill-range@7.0.1:
dependencies:
to-regex-range: 5.0.1