From f4853821d42ba9535523945682f0c6103891793e Mon Sep 17 00:00:00 2001 From: Max Richter Date: Sun, 5 May 2024 13:47:08 +0200 Subject: [PATCH] feat: add some documentation --- DEVELOPING_NODES.md | 1 - README.md | 4 +- ARCHITECTURE.md => docs/ARCHITECTURE.md | 24 ++++ docs/DEVELOPING_NODES.md | 128 +++++++++++++++++++++ docs/NODE_DEFINITION.md | 38 ++++++ nodes/max/plantarium/branch/src/input.json | 5 +- 6 files changed, 194 insertions(+), 6 deletions(-) delete mode 100644 DEVELOPING_NODES.md rename ARCHITECTURE.md => docs/ARCHITECTURE.md (50%) create mode 100644 docs/DEVELOPING_NODES.md create mode 100644 docs/NODE_DEFINITION.md diff --git a/DEVELOPING_NODES.md b/DEVELOPING_NODES.md deleted file mode 100644 index a4465f8..0000000 --- a/DEVELOPING_NODES.md +++ /dev/null @@ -1 +0,0 @@ -# Developing Nodes diff --git a/README.md b/README.md index 3792888..c369e5e 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Nodarium # Table of contents -- [Architecture](./ARCHITECTURE.md) +- [Architecture](./docs/ARCHITECTURE.md) - [Developing](#developing) - [Roadmap](#roadmap) @@ -45,6 +45,6 @@ cd app pnpm dev ``` -### [Now you can create your first node 🤓](./DEVELOPING_NODES.md) +### [Now you can create your first node 🤓](./docs/DEVELOPING_NODES.md) # Roadmap diff --git a/ARCHITECTURE.md b/docs/ARCHITECTURE.md similarity index 50% rename from ARCHITECTURE.md rename to docs/ARCHITECTURE.md index f60019b..0213bd8 100644 --- a/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -16,6 +16,30 @@ type Node = { } ``` +## How are the arguments defined? +To define which arguments a nodes accepts we use JSON. This json is embeded into the `.wasm` file of our node. An example `definition.json` file could look like this: + +```json +{ + "id": "my-name/my-namespace/zylinder-node", + "outputs": [ + "geometry" + ], + "inputs": { + "height": { + "type": "float", + "value": 2 + }, + "radius": { + "type": "float", + "value": 0.5 + } + } +} +``` + +For a more in-depth explanation have a look at [./NODE_DEFINITION.md](NODE_DEFINITION.md). + ## How are the nodes executed? ## How are the nodes stored? diff --git a/docs/DEVELOPING_NODES.md b/docs/DEVELOPING_NODES.md new file mode 100644 index 0000000..45a6f15 --- /dev/null +++ b/docs/DEVELOPING_NODES.md @@ -0,0 +1,128 @@ +# Developing Nodes + +This guide will help you developing your first Nodarium Node written in Rust. As an example we will implement a `cylinder` node, which generates a 3D model of a cylinder. + +## Prerequesites + +You need to have [Rust](https://www.rust-lang.org/tools/install) and [wasm-pack](https://rustwasm.github.io/wasm-pack/book/) installed. Rust is the language we are going to develop our node in and wasm-pack helps us compile our rust code into a webassembly file. + +```bash +# install rust +curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh +# install wasm-pack +cargo install wasm-pack +``` + +## Clone Template + +```bash +wasm-pack new my-new-node --template https://github.com/jim-fx/nodarium_template +cd my-new-node +``` + +## Setup Definition + +Now we create the definition file of the node. +Here we define what kind of inputs our node will expect and what kind of output it produces. If you want to dive deeper into this topic, have a look at [NODE_DEFINITION.md](./NODE_DEFINITION.md). + +`src/definition.json` +```json +{ + "id": "my-name/my-namespace/zylinder-node", + "outputs": [ + "geometry" + ], + "inputs": { + "height": { + "type": "float", + "value": 2, + }, + "radius": { + "type": "float", + "value": 0.4 + } + } +} +``` +If we take a look at the `src/lib.rs` file we see that `src/definition.json` is included with the following line: + +```rust +include_definition_file!("src/definition.json"); +``` + +This procedural rust macro loads the definition.json, validates its content and embeds it in our output file. + +## Implement Node + +This is the hardest part when developing a node, for now you can copy the following content into the `src/lib.rs` file: + +```rust +use glam::Vec2; +use wasm_bindgen::prelude::*; + +nodarium_macros::include_definition_file!("src/definition.json"); + +#[wasm_bindgen] +pub fn execute(input: &[i32]) -> Vec { + let arguments = nodarium_utils::split_args(input); + + let height = nodarium_utils::evaluate_float(arguments[0]); + let radius = nodarium_utils::evaluate_float(arguments[1]); + + let mut geometry_data = nodarium_utils::geometry::create_geometry_data(16, 16); + + let geometry = nodarium_utils::geometry::wrap_geometry_data(&mut geometry_data); + + // bottom circle + for i in 0..8 { + let x = radius * (2.0 * std::f32::consts::PI * i as f32 / 8.0).cos(); + let y = radius * (2.0 * std::f32::consts::PI * i as f32 / 8.0).sin(); + + let vec = Vec2::new(x, y).normalize(); + + // bottom circle + geometry.positions[i * 3 + 0] = x; + geometry.positions[i * 3 + 1] = 0.0; + geometry.positions[i * 3 + 2] = y; + + geometry.normals[i * 3 + 0] = vec[0]; + geometry.normals[i * 3 + 1] = 0.0; + geometry.normals[i * 3 + 2] = vec[1]; + + // top circle + geometry.positions[24 + i * 3 + 0] = x; + geometry.positions[24 + i * 3 + 1] = height; + geometry.positions[24 + i * 3 + 2] = y; + + geometry.normals[24 + i * 3 + 0] = vec[0]; + geometry.normals[24 + i * 3 + 1] = 0.0; + geometry.normals[24 + i * 3 + 2] = vec[1]; + + geometry.faces[i * 6 + 0] = (i + 8) as i32; + geometry.faces[i * 6 + 1] = (i as i32 + 1) % 8; + geometry.faces[i * 6 + 2] = (i) as i32; + + geometry.faces[i * 6 + 3] = 8 + (i % 8) as i32; + geometry.faces[i * 6 + 4] = 8 + (i as i32 + 1) % 8; + geometry.faces[i * 6 + 5] = (i as i32 + 1) % 8; + } + + nodarium_utils::concat_arg_vecs(vec![geometry_data]) +} +``` + +As you can see we import `glam` on the first line. Glam is a fantastic math library. Install it with the following command: + +```bash +cargo add glam +``` + +## Build time + +We compile our node by running the following command: + +```bash +wasm-pack build --release +``` + +This will produce a `.wasm` file in the `pkg/` directory of our node. To check if the node works, we can drag it onto the node-graph on https://nodes.max-richter.dev and see if it loads. diff --git a/docs/NODE_DEFINITION.md b/docs/NODE_DEFINITION.md new file mode 100644 index 0000000..a639ff5 --- /dev/null +++ b/docs/NODE_DEFINITION.md @@ -0,0 +1,38 @@ +# Node Definition + +Which arguments a node expects is defined in a single `.json` file that is embedded into our node. It consists of three main fields: + +## id + +`user-name/namespace/node-id` + +## outputs + +```json +"outputs": [ + "geometry" +] +``` + +## inputs + +```json +"inputs": { + "height": { + "type": "float", + "value": 2 + }, + "radius": { + "type": "float", + "value": 0.5 + } +} +``` + +## meta (optional) + +The meta object is optional and can contain two other fields: + +`title` + +`description` diff --git a/nodes/max/plantarium/branch/src/input.json b/nodes/max/plantarium/branch/src/input.json index 181a94c..5136079 100644 --- a/nodes/max/plantarium/branch/src/input.json +++ b/nodes/max/plantarium/branch/src/input.json @@ -30,12 +30,11 @@ }, "offsetSingle": { "type": "float", + "hidden": true, "description": "Used to offset every second branch", "min": 0, - "hidden": true, "max": 1, - "step": 0.01, - "value": 0.5 + "value": 0 }, "lowestBranch": { "type": "float",