Nodysseus: a node-based editor for the web with three.js bindings

Hey everyone,

I’d like to introduce you all to Nodysseus (https://nodysseus.io), a node-based editor for the web. It’s got three.js bindings integrated into the editor both for regular three.js and three.js’ exciting new node system. You can also use regular javascript methods as nodes, or drop a @js.script node to have a more traditional text editor.

Why another node-based editor? The VFX industry has Houdini, live shows - TouchDesigner/Notch, and video games Unity/Unreal. All of those are desktop apps and the web was lacking a node-based editor for javascript that had both high-level wrappers for non-programmers and exposed low-level scripting for devs who need it. There were also no good solutions for programming on a mobile device, and few options for procedural modeling on them too.

So, over the past couple years, I built Nodysseus. It’s for javascript in general, but recently I’ve been focusing on the three.js bindings. Some features that set Nodysseus apart from other node-based editors:

  • it’s vanilla javascript, batteries not included: most additional functionality, including the three.js bindings, is done with dynamic imports and in-editor graphs that can be inspected and edited by the user. New functionality is added by making and using graphs, including custom html elements per-node.

  • local first, optional sync: everything is saved to the local browser cache for use offline, can be synced through a passthrough websocket connection with another device or collaborators, or exported in plain json

  • automatic layout: each node has many inputs but only one output so the graph is automatically laid out. There’s no dragging nodes or wires, and a page refresh gets you a clean layout if things get too messy

  • multithreaded: the three.js library has an @three.worker which makes it easy to background any three.js rendering, and there’s jsupport for the WebGPU compute nodes

  • cross-device: it works with touchscreens on phones, tablets, or laptops and is almost on par with the desktop experience (the only thing missing is chrome dev tools). I built most of the standard library on my commute from my phone.

And there are some that are more commonly claimed:

  • fast: an efficient graph walk algorithm (inspired by compiler AST walkers) makes the core library relatively quick. For performance-critical code, like per-point attribute manipulation, there is @js.create_fn which compiles a subset of nodes down to javascript.

  • simple: each node just has a reference graph (either built-in or user created in-app), some data, and inputs

  • shader editing: the three.js nodes implementation is exposed with @three.node and features autocomplete and compatibility with Nodysseus nodes like @html.slider

  • procedural: @three.modify_attribute modifies vertex data directly, or higher level nodes can be used to manipulate and transform meshes

Give it a shot, and let me know what you think! Here are some videos and links to get started:

three.js node example video tutorial: https://youtu.be/VGzW1lnVLbA
UI overview (a bit outdated now): Nodysseus UI Overview - YouTube

Basic example: Nodysseus
Node example: Nodysseus
Attribute manipulation example: Nodysseus
Compute example: Nodysseus

Code: Ulysses Popple / nodysseus · GitLab

Demo at halfstack 2022: HalfStack Shore(ditch) 2022: Ulysses Popple - YouTube

Looking forward to hearing from anyone who’s interested in using Nodysseus, or if you have a killer feature or idea that could make it a part of your everyday dev toolkit.

Cheers,
Ulysses

1 Like

Thanks for sharing your work. I like the minimalistic style.

I’m not quite a fan of blocks (as in Scratch), so my comments might be general to node-based editors. I decided to act as a complete noob, so I did not check in advance any documentation or tutorial. As a result, some of my observations could be trivial or even stupid.

  • The automatic layout of nodes and their labels sometimes overlaps them
    image

  • I was unable to understand the purpose of undefined nodes

  • How do you define an array of values, like data=[0,1,0,0,1,1,0,0,0,0,1,0,1,0,0,1,1,1]? Maybe with a script node, because the other way is rather impractical

  • How to select a group of nodes and copy and paste them in another branch? (I see copy and paste, but somehow did not manage to copy and paste)

  • Is is possible to collapse a branch of the tree showing only its root?

  • Although it will break the tree-concept, it might be useful to have easier identification of same entities in different areas of the graph. In the following snapshot is the cube on the far right the same cube as in the far left?

  • While playing with the graph I manage to break it (deleted a few nodes, the cube disappeared and an error message is shown in the top left). Reloading the page does not help, as long as the tree is saved locally and reloading just pulls it from the local storage. What is the preferred way to reset (besides clearing browser’s data)?

  • Is it possible to export a tree as source code (I think you should have some form of source code generator)? And the opposite – is it possible to import source code and see it transformed into nodes?

  • I was glad that errors also indicate the node with different color), this makes it easier to fix bugs.

  • How to write and test a program with pointer events? (or how to indicate that a mouse click event is for the program and not for the editor)

Thanks for trying it out! You’ve got some good feedback in there - it’s really useful hearing it as though you’re a complete noob. I’ll try and address the feedback

  • Yup, the layout can be difficult sometimes - I’ll go back to the drawing board and see what I can do to avoid overlaps

  • undefined is just that - like a variable with the name of the edge and not set yet

  • The value of a node is parsed as JSON, so you can put any valid JSON in there - [0, 1, 0, 1, …] would return an array

  • Copying a node copies all of the inputs to that node as well so you can copy chunks of the graph. You make a good point about selecting groups of nodes, I just still haven’t figured out how to do selection in a way that works on both pcs and mobile devices

  • It is! If you drop a node with its graph set to node it will have a “collapse” action. It’s essentially making a javascript function, and if there’s an input labeled “args” to the return node, when you collapse it it will keep those nodes out of the collapsed graph
    Here it is non-collapsed


  • Yes, the cube is the same. In javascript it would be something like setupThreejs([cube], (cube) => cube.rotation.x += 0.2) where the second argument is an update function.

  • Oh no! I’m glad that the saving function is working at least… Usually I start editing a graph by renaming it in the bottom node. The new name for the graph means that it gets saved separately. You can also use any graph you make in the graph field of any node.

  • At the moment only a small number of nodes can be compiled directly into javascript primarily for functions that need to be fast (like a function for iterating over all points in a mesh). I have been expanding the number of nodes that are compatible with transpiling to javascript, and great idea having a javascript → tree generator

  • How to distinguish between pointer events for a program and not the editor is a great question. For the most part I’ve been making html displays for the nodes, and anything inside of those isn’t handled by the editor.

For example, this HTML slider is entirely controlled by the @html.slider node. Another one that I have is an <svg> element which has a curve to remap a 0-1 value.

Is there anything else you’d like to see graph-wise? I could cook something up for a demo.