Noisecraft - anyone heard of it?

Hey Steve,
That is good to know. Never used it.

So Gregorius could register a auto-layout action via a plugin, so we can call it that way. And if he wants to do auto-layout by injecting a message, he can simply do that with a function node (by executing that action via Js code). Or if he wants he can build a custom node that is dedicated to executing actions, e.g. that he can select an action from his config screen perhaps...

@gregorius: Perhaps if you create a new discussion about auto layouting, you might get some more feedback compared to a discussion about Noisecraft :yum:

3 Likes

I figure I should say thanks here @gregorius. You are really opening up some new ideas and challenging the status-quo. Good for all of us who've been around Node-RED for a long time. :grin:

We still might not always agree, but it is healthy to have the debate regardless.

3 Likes

Thank you all for helping :slight_smile: And above all, thank you all for making Node-RED such a joy to work with :+1:

Much appreciated :blush: and I hope I can continue to be a bit off-the-wall!

3 Likes

For those interested, this flow (new node at the top left) does layouting using elkjs - just a first attempt and the options need finetuning, but it demonstrates how it could be done ... or how it could be done better :slight_smile:

@BartButenaers can you try again please, I think I've found the encoding bug - it seems that the base64 node decodes to string('binary') and it should be string('utf8') (in my case) - the flows are now coming out properly.

@gregorius,
Thanks for the follow up of my issue!!
Unfortunately I still have the errors in my function node, when I import the flow from your previous post.
I see that the escaped characters are already available when I click "copy flow to clipboard" on FlowHub:

image

Or do you need to regenerate all the flows on FlowHub?

Perfect! I can reproduce that using Firefox & Opera ... ok, I'll have a look

Cheers!

1 Like

@BartButenaers thanks for the help, should be fixed with innerText instead of innerHTML - doh, bug was 40cm from screen!

Nice catch!! The flow now loads without syntax errors. Much better!

But none of the algorithms seem to work for me, i.e. the selected node(s) are not rearranged. Instead I see these errors in the Debug panel: ""Missing return node information""

And when I use the subflow to obtain elkjs configuration settings, I first get "timeout" messages and tthen again the ""Missing return node information"" message.

I thought I saw some error passing by in my developer tools, about the elk.js minified file that could not be loaded. But I forgot to make a screenshot, and now I don't get that error anymore.

My time is up for today...

The only thing I can think of is that you selected a group of nodes and not a single node. I noticed that through the grouping of groups of nodes - it's a lot of clicking to get to a node. I added a notification if that should be the case so it's clear that a node wasn't selected.

The timeout message still appears in the debug panel, that's because the link-call (the corresponding link-in never returns) times out when a notification is shown.

@gregorius,
After updating your introspection node, it worked. Not sure if that was the root cause. Perhaps something about my system, or me doing something stupid wrong.
Anyway you can forget about it!

1 Like

Some great discussion here about VPL :slight_smile: a minority of people deeply understand assembly while the majority of programmers only understand the text-based languages built on top of it. I think the same could be argued for text-based languages and VPL with programmers and non-technical users.

As has been said, it seems like VPL might not reach general purpose any time soon, but a common textual standard for representing applications could be interesting step in the right directionā€¦

Dunno what it is, must be because it's friday - found another two interesting products that should be here:

  • NoFlo Flow-Based Programming for JavaScript
  • and from them came flowhub.io

both of which I found via Flow Based Programming by J Paul Morrison - spoiler: we're doing nothing new here!

1 Like

Actually, Node-RED IS at least slightly different and is, in my opinionated opinion anyway :slight_smile: much easier to use than the other tools. And it is also fully open source which I don't think NoFlo is?

But no, Node-RED was far from being the first flow-based programming tool, that's for sure. But it is arguably one of the most successful. And certainly one of the most approachable ones.


OK, maybe NoFlow is now open, seems to have moved on a bit. But still a lot more complex than Node-RED - and I think they really need a UX designer to help them!

This is their example for a click counter:

I think that the equivalent in Node-RED would probably be a bit simpler. :wink:

This is an thought that's being going around my head in the last couple of weeks: every language is extremely flexible and can do anything. What all languages require are abstractions and reuse: libraries, functions, methods, objects ... whatever. If a language lets you build up your toolbox of abstractions, then you can do anything with very little effort, because you begin to use those abstractions.

I think Node-RED has nailed that by having subflows, flows and nodes as abstraction layers. We all start out building complex flows, then create subflows to simplify flows and eventually we create nodes to simplify subflows (if we look at it hierarchically). (another example is using function nodes where a switch or change node would do the same ...)

That NoFlo flow that you show may be complex however if it's quickly possible to abstract parts of that flow away, then NoFlo becomes useful. Remember, its difficult to create a general language that is always simple, that's why there are frameworks - abstractions for specific tasks.

Personally I have began creating flows that create flows and nodes - yet another level of abstraction. To prove the point:

[{"id":"6030f1e36ecbc405","type":"function","z":"73b4aedc.e9602","name":"generate nodes for 3d ticker wall","func":"/* How big should the display be? */\nconst nrCols = msg.nrCols;\nconst nrRows = msg.nrRows;\n\n/*\n  Matrial ids: these are taken from using \"Export Nodes\" and reading the json generated.\n*/\nvar materials = [\n    [\n        \"17350478e877bc09\", // red\n        \"e7298bcff0d93b16\", // white\n    ],\n    [\n        \"e7298bcff0d93b16\", // white\n        \"17350478e877bc09\", // red\n    ],\n]\n\nvar junctionToAll = {\n    \"id\": RED.util.generateId(),\n    \"type\": \"junction\",\n    \"x\": 0,\n    \"y\": 0,\n    \"wires\": [\n        [\n        ]\n    ]\n}\n\nvar colRouter = {\n    \"id\": RED.util.generateId(),\n    \"type\": \"switch\",\n    \"name\": \"col switch\",\n    \"property\": \"col\",\n    \"propertyType\": \"msg\",\n    \"rules\": Array.from({ length: nrCols }, () => { return { \"t\": \"eq\", \"v\": \"1\", \"vt\": \"num\" }}),\n    \"checkall\": \"false\",\n    \"repair\": false,\n    \"outputs\": nrCols,\n    \"x\": 0,\n    \"y\": -600,\n    \"wires\": Array.from({ length: nrCols }, () => { return []}),\n}\n\n// set correct values\ncolRouter.rules.forEach((i, d) => i.v = (d + 1).toString())\n\nvar rowRouters = [];\nfor ( var y = 0; y < nrCols; y++) {\n    var rowRouter = {\n        \"id\": RED.util.generateId(),\n        \"type\": \"switch\",\n        \"name\": \"row switch for col \" + (y+1),\n        \"property\": \"row\",\n        \"propertyType\": \"msg\",\n        \"rules\": Array.from({ length: nrRows }, () => { return { \"t\": \"eq\", \"v\": \"1\", \"vt\": \"num\" }}),\n        \"checkall\": \"false\",\n        \"repair\": false,\n        \"outputs\": nrRows,\n        \"x\": 200*y,\n        \"y\": -500,  \n        \"wires\": Array.from({ length: nrRows }, () => { return []})\n    }\n\n    colRouter.wires[y].push(rowRouter.id)\n    rowRouter.rules.forEach((i, d) => i.v = (d + 1).toString())\n    rowRouters.push(rowRouter)\n}\n\nvar valueScaler = {\n    \"id\": \"WILLBEPREPLACDE\",\n    \"type\": \"change\",\n    \"name\": \"Set Z scale\",\n    \"rules\": [\n        {\n            \"t\": \"set\",\n            \"p\": \"payload\",\n            \"pt\": \"msg\",\n            \"to\": \"{\\t    \\\"type\\\": \\\"scale\\\",\\t    \\\"relative\\\": false,\\t    \\\"values\\\": {\\t      \\\"x\\\":1,\\t      \\\"y\\\":1,\\t      \\\"z\\\":$$.payload\\t    },\\t    \\\"pivot\\\": {\\t        \\\"x\\\": null,\\t        \\\"y\\\": null,\\t        \\\"z\\\": null\\t    }\\t}\",\n            \"tot\": \"jsonata\"\n        }\n    ],\n    \"action\": \"\",\n    \"property\": \"\",\n    \"from\": \"\",\n    \"to\": \"\",\n    \"reg\": false,\n    \"x\": 0,\n    \"y\": 0,\n    \"wires\": [\n        [\n\n        ]\n    ]\n}\n\nvar baseNode = {\n    \"id\": \"WILLBEREPLACED\",\n    \"type\": \"box\",\n    \"scene\": \"c0d1433da002f3c6\",\n    \"material\": \"WILLBEREPLACED\",\n    \"name_conf_a\": \"WILLBEREPLACED\",\n    \"size_conf_n\": 1,\n    \"height_conf_n\": \"\",\n    \"width_conf_n\": \"\",\n    \"depth_conf_n\": \"\",\n    \"updatable_conf_b\": false,\n    \"sideOrientation_conf_a\": \"1\",\n    \"pos_x\": \"WILLBEREPLACED\",\n    \"pos_y\": \"WILLBEREPLACD\",\n    \"pos_z\": 0,\n    \"scale_x\": \"1\",\n    \"scale_y\": \"1\",\n    \"scale_z\": \"0.25\",\n    \"rot_x\": 0,\n    \"rot_y\": 0,\n    \"rot_z\": 0,\n    \"x\": 0,\n    \"y\": 0,\n    \"wires\": [\n        []\n    ]\n}\nvar nodes = []\n\nfor (var x = 1; x < (nrCols + 1); x++) {\n    for (var y = 1; y < (nrRows + 1); y++) {\n        var nde = { ...baseNode };\n        nde.x = 180 * x;\n        nde.y = (60 * nrRows) + (50 * y);\n        nde[\"name_conf_a\"] = \"pixel_\" + x + \"_x_\" + y\n        nde.pos_x = x;\n        nde.pos_y = y;\n        nde.material = materials[x % 2][y % 2]\n        nde.id = RED.util.generateId()\n\n        var scaler = { ...valueScaler }\n        scaler.id = RED.util.generateId()\n        scaler.x = 180 * x;\n        scaler.y = 50 * y;\n        scaler.wires = [[nde.id]]\n\n        rowRouters[x-1].wires[y-1].push(scaler.id)\n        junctionToAll.wires[0].push(nde.id)\n\n        nodes.push(scaler)\n        nodes.push(nde)\n    }\n}\n\nvar ary = [\n    junctionToAll,\n    colRouter\n];\n\n// @ts-ignore\nmsg.payload = nodes.concat(ary).concat(rowRouters);\n\nreturn msg;","outputs":1,"timeout":0,"noerr":0,"initialize":"","finalize":"","libs":[],"x":394.1426086425781,"y":138.57132053375244,"wires":[["e522af90c2ebba47","b9e6005780e0386f"]]},{"id":"3b6cf5336219131e","type":"inject","z":"73b4aedc.e9602","name":"number of: columns and rows","props":[{"p":"nrCols","v":"11","vt":"num"},{"p":"nrRows","v":"5","vt":"num"}],"repeat":"","crontab":"","once":false,"onceDelay":0.1,"topic":"","x":170.42828369140625,"y":86.71411323547363,"wires":[["6030f1e36ecbc405"]]},{"id":"e522af90c2ebba47","type":"debug","z":"73b4aedc.e9602","name":"debug 6","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":710.5711097717285,"y":77.99979782104492,"wires":[]},{"id":"b9e6005780e0386f","type":"json","z":"73b4aedc.e9602","name":"","property":"payload","action":"str","pretty":false,"x":625.8567047119141,"y":175.2856330871582,"wires":[["740780e56a0cf863"]]}]

This flow will create a bunch of nodes for creating a 3d ticker wall using babylonjs in Node-RED. With that flow, I say how many rows and how many columns, and the flow will give me a flows.json that I can import that will create the corresponding Node-RED nodes. It's like using eval in JS whereby the string being evaluated was generated by the same codebase doing the eval.

If a language can do that, then it's got the abstraction levels/layers just right :wink:

1 Like

I'm not sure if my understanding of "flow based language" is the orthodox one.

The first language that I heard described as flow based was SQL:
"SQL is a flow based language. Think of it as water flowing from a tap, your query sits in the flow and filters out the bits of data you seek. But importantly, you only get a single look at the data; once a particular droplet has flowed past the query, it has gone."

Of course Node-red is also a visual language and much more approachable than SQL but it still only has one chance to look at the data as it passes through.

By this definition AWK and Perl are flow based languages too, but not visual.

:rofl:

Great misuse of the term. SQL is a DECLARITIVE language. And that quote is clearly somewhat misleading though I get what it is trying to convey. It ignores great chunks of how SQL works and what it can do.

I believe the term "Flow-Based Language" actually came out of IBM in the 50's?

If looking at text-based languages rather than visual, PowerShell would be a better example since it uses a lot of flow-style concepts.

I would not deny that NoFlow is useful to some people and undoubtedly has features that Node-RED doesn't and they may fit better into the way that some people or processes think or work. But I'm an Architect - the asthetics and UX of something so user-focussed are important and I always struggled to get to grips with NoFlow on the few times I've tried to use it in anger (usually some time when I was frustrated with Node-RED!). And it looks so UGLY! :grinning:

Have a read of this Flow-based Programming which is basically what we're talking about however you're quite right in being confused since the Unix idea of pipes is clearly based on the ideas of FBP as described in that article.

But Yahoo!Pipes was inspired by Unix Pipes which were inspired by Flow Base Programming which in turn inspired Node-RED. So where does the flow come in? Pipes to direct the flow of data?

But in Node-RED the pipes are called wires, so where does the electricity come in?

It's all very confusing, I will stick to pipes ... put that in your pipe and smoke it! :wink:

Which reminds me of another thought, UML. Node-RED will never become a replacement for UML although it has more functionality than UML, i.e. it's far better. The reason for this is: UML is ugly and people who use UML like that ugliness! (sorry if I just offended someone!) Well ok, UML is not ugly but it uses shapes not colours to differentiate between stuff. Node-RED uses colours and not shapes to differentiate hence people who "get" UML, won't understand Node-RED.

I guess UML was invented in the days of monochrome monitors and black and white printers ... which ironically is true!

Oh, and I miss that - the only thing ever from Yahoo! that I miss!

It was THE tool for manipulating RSS/ATOM feeds. Nothing in Node-RED can do that right now I'm afraid and I've never managed to reproduce the calculated feeds I had in it in Node-RED.

Oh dear, you are determined to trigger me on a Friday afternoon aren't you!! Because now I have to mention ArchiMate modelling - :sigh: - talk about ugly!

Never really thought of it that way - interesting. Of course, if you are capable of understaning UML, you probably don't need a visual programming tool! :rofl: