Mastering the Node Garden: A Beginner’s Guide to Generative Networks

The "Node Garden" is a staple technique in creative coding. It allows you to create sophisticated, interconnected visuals—resembling neural networks or constellations—with surprisingly simple logic.


In this article, I will walk you through the basics and provide a hands-on guide to building your first node garden using p5.js.

[Japanese version / 日本語版はこちら]

 

Getting Started with p5.js

For this tutorial, we will use p5.js. If you are new to the environment, I recommend using OpenProcessing or the p5.js Web Editor. These platforms allow you to write and run code directly in your browser without any local setup.

We won't dive deep into JavaScript syntax here. Instead, I encourage you to learn by doing—running the code first and analyzing the mechanics afterward is often the fastest way to master creative coding.

 

The Core Logic: Distribute and Connect

Creating a node garden is fundamentally about two operations:

  • Instantiate: Randomly place points (nodes) across the canvas.
  • Connect: Draw lines between those nodes to form a network.

That's it!

Instantiate


Connect

By simply iterating through every pair of points and drawing a line, a scattered set of nodes transforms into an intricate geometric web.


You can try various expressions by thinking out how to place nodes and the conditions when drawing the lines.

 

Implementation: Building Your First Garden

Here is a concise p5.js implementation. This script sets up a fixed number of nodes and connects every possible pair.

 

p5.js Example Code


/*
 * Node Garden basics section.
 */

const w = 640;
const h = 480;
const nodeNum = 10;
const nodes = new Array();

function setup() {
  // canvas setting
  createCanvas(w, h);
  background(240);
  noFill();
  stroke(100);

  // 1. Distribute nodes randomly
  for (let i = 0; i < nodeNum; i++) {
    let x = random(w);
    let y = random(h);
    ellipse(x, y, 10, 10);
    nodes.push(createVector(x, y));
  }

  // 2. Connect every node pair using a nested loop
  for (let i = 0; i < nodeNum - 1; i++) {
    let n = nodes[i];
    for (let j = i + 1; j < nodeNum; j++) {
      let m = nodes[j];
      line(n.x, n.y, m.x, m.y);
    }
  }
}

 

Breaking Down the Logic

※You can skip the part that you don't get.

Initializing


const w = 640;
const h = 480;
const nodeNum = 10;
const nodes = new Array();

Define the canvas dimensions. Here, the width is set to 640 pixels and the height to 480 pixels.
We define nodeNum as 10 and initialize an empty array, nodes, to store the positions of each node.

 

Canvas Settings


  // canvas setting
  createCanvas(w, h);
  background(240);
  noFill();
  stroke(100);

Set the background color 240 (almost white), line color 100 (grey).

 

Placing Nodes


  // 1. Distribute nodes randomly
  for (let i = 0; i < nodeNum; i++) {
    let x = random(w);
    let y = random(h);
    ellipse(x, y, 10, 10);
    nodes.push(createVector(x, y));
  }

This loop distributes nodeNum points randomly across the canvas. Each node is drawn as a 10-pixel circle and its coordinates are stored as a P5.Vector in the nodes array.

 

Draw the Lines


  // 2. Connect every node pair using a nested loop
  for (let i = 0; i < nodeNum - 1; i++) {
    let n = nodes[i];
    for (let j = i + 1; j < nodeNum; j++) {
      let m = nodes[j];
      line(n.x, n.y, m.x, m.y);
    }
  }

Draw line with line() with picking the node from array one by one. Do it with every node.

The Nested Loop: Notice how the inner loop starts at i + 1. This is crucial for performance and accuracy; it ensures we don't draw a line from a node to itself, and we don't draw the same line twice (e.g., from Node A to B, and then B to A).


You'll see the result like this.


 

Refining Connections: Proximity-Based Linking

Connecting every node pair works for small counts, but can quickly become chaotic. To achieve a more organic and "web-like" appearance, we can add a distance condition: only draw a line if the nodes are close to each other.


      if (dist(n.x, n.y, m.x, m.y) < 100) {
        line(n.x, n.y, m.x, m.y);
      }

Using the dist() function, we can limit connections to only those nodes within 100 pixels of each other.
You'll see the result like this.


This looks a bit sparse.
By increasing the node count (e.g., nodeNum = 100) while restricting connections by distance, you create a much more complex and visually pleasing structure.


const nodeNum = 100;


 

Visual Polish: Aesthetics and Styling

In the initial example, nodes are drawn before the lines, causing the lines to overlap the points.


  // put nodes
  for (let i = 0; i < nodeNum; i++) {
    let x = random(w);
    let y = random(h);
    ellipse(x, y, 10, 10);      // draw the nodes here
    nodes.push(createVector(x, y));
  }
  
  // draw lines
  for (let i = 0; i < nodeNum - 1; i++) {
    let n = nodes[i];
    for (let j = i + 1; j < nodeNum; j++) {
      let m = nodes[j];
      line(n.x, n.y, m.x, m.y); // draw the lines here
    }
  }

A simple yet effective trick in generative art is to pay attention to layering. By drawing the lines first and then rendering the nodes on top (filled with the background color), you hide the messy intersections where lines meet the points. This creates a much "cleaner" look.


  fill(240);
  for (let i = 0; i < nodeNum; i++) {
    let n = nodes[i];
    ellipse(n.x, n.y, 10, 10);
  }


Paint the node with fill(240) the same color of background color. This is the key to the code. If you lost the key, you'll see the result like this.


 

Don't stop at circles—experiment with strokeWeight, rotation, or even replacing nodes with squares to create a mechanical, gear-like aesthetic. The possibilities are endless once you master the connection logic.

It will be interesting changing the boldness of the lines.


  strokeWeight(10);


 

You can make gear nodes with squares.


rectMode(CENTER);
for (let i = 0; i < nodeNum; i++) {
  let n = nodes[i];
  for (let r = 0; r < TWO_PI; r += TWO_PI / 3) {
    push();
    translate(n.x, n.y);
    rotate(r);
    rect(0, 0, 50, 50);
    pop();
  }
}


The rectangles, not squares look interesting also.


 

Inspiration: Moving Beyond Static Gardens

The true power of the Node Garden technique is revealed when you add motion. Here are two examples of my work where I've animated the nodes using Processing:

Linear Motion: Nodes traversing straight paths.

Geometric Harmony: Advanced animation with node-garden logic.

 

Start Building!

I hope this introduction inspires you to experiment with your own node gardens. Take the sample code, tweak the parameters, and find your own unique style.

Enjoy the process!

 

Dynamic Systems: Animation, Attractors, and Image Processing in the Node Garden

 

Next Post Previous Post
No Comment
Add Comment
comment url