Snap and Roll: Geometric Elegance Through the Node Garden

Creative coding examples.


Exploring Dynamic Geometric Forms through Creative Coding

This generative animation was developed in Processing, utilizing a refined "Node Garden" technique to create evolving geometric structures.

The project began with a simple polar equation: abs(sin(3 * theta)). Originally intended to draw a standard floral shape, the concept evolved through experimentation.

Flower with sin().

I discovered that by significantly reducing the number of points and drawing connections between them, I could create a sophisticated, web-like structure. By modulating the sine values over time, these static connections transformed into a fluid, mesmerizing animation.

 

Implementation in Processing

The following script generates a series of high-resolution frames. And it does not display any images on the screen.
These frames can be compiled into a seamless animation, showcasing the rhythmic movement of the network.

This code is provided under the GPL license. Feel free to experiment with it—I would be honored to see any works inspired by this approach.

/**
 * Snap and Roll.
 * Node garden without nodes.
 * 
 * @author @deconbatch
 * @version 0.1
 * Processing 3.2.1
 * 2019.03.12
 */

/* ---------------------------------------------------------------------- */

void setup() {

  size(720, 720);
  colorMode(HSB, 360, 100, 100, 100);
  rectMode(CENTER);
  smooth();
  noLoop();

}

void draw() {

  int   frameCntMax = 24 * 6;
  int   nodeCntMax  = floor(random(9.0, 13)) * 2;
  int   cornerCnt   = floor(random(2.0, 9.0));
  float limitMin    = 50.0;
  float limitMax    = 200.0;
  float baseHue     = random(360.0);

  StepEasing se = new StepEasing(3);
  EasingCalc ec = new InOutCubic();
  Node [] nodes = new Node[nodeCntMax];
  for (int i = 0; i < nodeCntMax; ++i) {
    nodes[i] = new Node(baseHue + (i % 3) * 30.0);
  }

  translate(width * 0.5, height * 0.5);
  
  for (int frameCnt = 0; frameCnt < frameCntMax; ++frameCnt) {

    background(0, 0, 90, 100);
    float easeRatio = se.calculate(ec, map(frameCnt, 0, frameCntMax, 0.0, 1.0));

    // set nodes
    for (int nodeCnt = 0; nodeCnt < nodeCntMax; ++nodeCnt) {
      float radian = TWO_PI * map(nodeCnt, 0, nodeCntMax, 0.0, 1.0);
      float radius = abs(sin(radian * cornerCnt + PI * easeRatio)) * width * 0.4;
      float eX = radius * cos(radian);
      float eY = radius * sin(radian);
      nodes[nodeCnt].setNode(eX, eY);
    }

    // draw lines in a sequence
    for (int i = 0; i < nodeCntMax - 1; i++) {
      for (int j = i + 1; j < nodeCntMax; j++) {
        nodes[i].drawLine(nodes[j], limitMin, limitMax);
      }
    }

    casing();
    saveFrame("frames/" + String.format("%04d", frameCnt) + ".png");

  }
  exit();
}


/**
 * casing : draw fancy casing
 */
private void casing() {
  blendMode(BLEND);
  fill(0.0, 0.0, 0.0, 0.0);
  strokeWeight(45.0);
  stroke(0.0, 0.0, 0.0, 100.0);
  rect(0.0, 0.0, width, height);
  strokeWeight(40.0);
  stroke(0.0, 0.0, 100.0, 100.0);
  rect(0.0, 0.0, width, height);
  noStroke();
  noFill();
}

/**
 * Keeping node information. Drawint polka dot and line between nodes.
 * @param  baseHue 0.0 - 360.0 : draw points color.
 */
private class Node {

  private float nX, nY;
  private float nHue;

  Node(float baseHue) {
    nX    = 0.0;
    nY    = 0.0;
    nHue  = baseHue % 360.0;
  }

  public void setNode(float pX, float pY) {
    nX = pX;
    nY = pY;
  }

  public float getNodeX() {
    return nX;
  }

  public float getNodeY() {
    return nY;
  }

  public void drawLine(Node toNode, float limitMin, float limitMax) {
  
    float distance = dist(nX, nY, toNode.getNodeX(), toNode.getNodeY());

    if (distance < limitMax && distance > limitMin) {
      strokeWeight(sin(PI * map(distance, limitMin, limitMax, 0.0, 1.0)) * 2.0);
      stroke(nHue, 40.0, 60.0, 100.0);
      line(nX, nY, toNode.getNodeX(), toNode.getNodeY());
    }
  
  }
}

/**
 * StepEasing : calculate easing value with step landing. It just has one easing function yet.
 * @param  _landingCount : 1 - any int value : landing number.
 */
private class StepEasing {

  private float landingPoint;
  private float easePrev;
  private float easeRatio;
  
  StepEasing(int _landingCount) {
    landingPoint = 1.0 / (_landingCount + 1);
    reset();
  }

  StepEasing() {
    landingPoint = 1.0;
    reset();
  }

  private void reset() {
    easePrev  = 0.0;
    easeRatio = 0.0;
  }
  
  /**
   * calculate : calculate easing value with step landing.
   * @param  _t    0.0 - 1.0 : linear value.
   * @return float 0.0 - 1.0 : eased value with step landing.
   */
  public float calculate(EasingCalc _calc, float _t) {
    float easeCurr = _calc.calculate(map(_t % landingPoint, 0.0, landingPoint, 0.0, 1.0));
    easeRatio += constrain((easeCurr - easePrev) * landingPoint, 0.0, 1.0);
    easePrev = easeCurr;

    return easeRatio;
  }

}

/**
 * easeInOutCubic easing function.
 * @param  _t    : 0.0 - 1.0 : linear value.
 * @return float : 0.0 - 1.0 : eased value.
 */
interface EasingCalc {
  float calculate(float _t);
}

private class InOutCubic implements EasingCalc {
  public float calculate(float _t) {
    _t *= 2.0;
    if (_t < 1.0) {
      return pow(_t, 3) / 2.0;
    }
    _t -= 2.0;
    return (pow(_t, 3) + 2.0) / 2.0;
  }
}

/*
Copyright (C) 2019- deconbatch

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>
*/


 

Gallery: Further Iterations

Here are a few additional examples exploring different parameters within the Node Garden system.

Creative coding examples.


 

Next Post Previous Post
No Comment
Add Comment
comment url