## Expressing the rhythm and density in a creative coding animation.

I tried to express the rhythm and density in a creative coding animation.
I've been reading Paul Klee's book. It's an exercise that will help me to understand this book well.

At first, I drew a still image that expresses density.

And I added some deviation to it.

I drew still images that express rhythm also.

Then, I combined these and added some deviations.

And I added express of 'weight' and some structure instead of a simple rectangle.

## An example source code of Processing.

This code does not display any images on the screen but generates image files in frames directory.
You can make an animation with these files.

Please feel free to use this example code.
To see other works based on my code is my pleasure. And my honor.

``````
/**
* White Room.
* Expressing the rhythm and density in a creative coding animation.
*
* @author @deconbatch
* @version 0.1
* Processing 3.5.3
* 2020.10.25
*/

void setup() {
size(720, 720);
colorMode(HSB, 360.0, 100.0, 100.0, 100.0);
noLoop();
}

void draw() {
int   rhythm   = 3;
int   virtMax  = 6;
int   horiMax  = 6;
int   frmMorph = 24 * 5;            // morphing duration frames
int   cycles   = 3;                 // animation cycle no.
int   frmMax   = frmMorph * cycles; // whole frames
float margin   = 20.0;
float baseBri  = 800.0 * (virtMax + horiMax);
float rndHue   = random(360.0);

// set whole nodes
ArrayList<ArrayList<Node>> nodes = new ArrayList<ArrayList<Node>>();
for (int i = 0; i < cycles; i++) {
}
ArrayList<Node> nodesFrom = new ArrayList<Node>();
ArrayList<Node> nodesTo   = new ArrayList<Node>();

for (int frmCnt = 0; frmCnt < frmMax; frmCnt++) {

// nodes for morphing animation. loops cyclic.
if (frmCnt % frmMorph == 0) {
nodesFrom = nodes.get(frmCnt / frmMorph);
nodesTo   = nodes.get((frmCnt / frmMorph + 1) % cycles);
}

background(0.0, 0.0, 100.0, 100.0);
stroke(0.0, 0.0, 30.0, 100.0);

float toRatio = InFourthPow(map(frmCnt % frmMorph, 0, frmMorph - 1, 0.0, 1.0));
float frRatio = 1.0 - toRatio;
for (int i = 0; i < nodesTo.size(); i++) {
// morphing calculations
float nB = nodesFrom.get(i).bri * frRatio + nodesTo.get(i).bri * toRatio;
float nX = nodesFrom.get(i).x * frRatio + nodesTo.get(i).x * toRatio;
float nY = nodesFrom.get(i).y * frRatio + nodesTo.get(i).y * toRatio;
float nW = nodesFrom.get(i).w * frRatio + nodesTo.get(i).w * toRatio;
float nH = nodesFrom.get(i).h * frRatio + nodesTo.get(i).h * toRatio;
float eX = nodesFrom.get(i).ex * frRatio + nodesTo.get(i).ex * toRatio;
float eY = nodesFrom.get(i).ey * frRatio + nodesTo.get(i).ey * toRatio;
float eR = nodesFrom.get(i).er * frRatio + nodesTo.get(i).er * toRatio;

// draw base matrix
strokeWeight(5);
fill(0.0, 0.0, nB, 100.0);
rect(nX, nY, nW, nH);

// draw some construction
strokeWeight(1);
pushMatrix();
translate(nX, nY);
for (int j = 0; j < 10; j++) {
rect(0.0, 0.0, nW - j * 10, nH - j * 10, eR * 0.25);
translate(5, 5);
}
popMatrix();

// draw light/heavy objects
float eRatio = (nH * eR) / (height * 15.0 / horiMax);
strokeWeight(constrain(eRatio, 0.0, 3.0));
if (eRatio > 0.5 && eRatio < 2.0) {
if (nB > 67.0) {
// heavy
line(eX, eY, eX, nY);
fill(0.0, 0.0, 100.0 - nB * 0.5, 100.0);
ellipse(eX, eY, eR, eR);
fill(0.0, 0.0, nB, 100.0);
ellipse(eX, eY, eR * 0.5, eR * 0.5);
} else {
// light
line(eX, eY, eX, nY + nH);
fill(0.0, 0.0, 100.0 - nB * 0.5, 100.0);
ellipse(eX, eY, eR, eR);
}
}
}

// draw casing
strokeWeight(10);
stroke(0.0, 0.0, 30.0, 100.0);
noFill();
rect(margin, margin, width - margin * 2.0, height - margin * 2.0);

saveFrame("frames/" + String.format("%04d", frmCnt) + ".png");
}
exit();
}

/**
* Node : holds node informations.
*/
class Node {
public float x, y, w, h; // rectangle
public float ex, ey, er; // ellipse (navel)
public float bri;        // brightness

Node(float _x, float _y, float _w, float _h, float _ex, float _ey, float _bri) {
x = _x;
y = _y;
w = _w;
h = _h;
ex = _ex;
ey = _ey;
bri = _bri;
er = 0.0;
}

void setNavel() {
er = (w + h) * 0.07;
}
}

/**
* setNodes : calculate the nodes location and size.
* @param  _xs, _ys : divided ratios of canvas.
* @param  _margin  : canvas margin.
* @param  _rhythm  : rhythm number.
* @param  _baseBri : base brightness.
* @return : array of nodes.
*/
ArrayList<Node> setNodes(ArrayList<Float> _xs, ArrayList<Float> _ys, float _margin, int _rhythm, float _baseBri) {

ArrayList<Node> ns = new ArrayList<Node>();

float w = width  - _margin * 2.0;
float h = height - _margin * 2.0;

int   xCnt = 0;
float xSum = 0.0;
for (float x : _xs) {

int   yCnt = 0;
float ySum = 0.0;
for (float y : _ys) {

float rW = x * w;
float rH = y * h;
float pX = xSum * w + _margin;
float pY = ySum * h + _margin;
float eX = pX + rW * 0.5;
float eY = pY + rH * 0.5;

float rVal = (1.0 + (xCnt + yCnt) % _rhythm) / _rhythm;
float rBri = constrain((x * y * _baseBri * rVal), 0.0, 100.0);

// brightness deviation
if (random(1.0) < 0.4) {
rBri = rVal * 90.0;
}

// size deviation
if (random(1.0) < 0.2) {
rW = x * w * random(0.5, 2.5);
rW = (pX + rW >= w + _margin) ? rW - (rW - _margin) : rW;
rH = y * h * random(0.5, 2.5);
rH = (pY + rH >= h + _margin) ? rH - (rH - _margin) : rH;
}

Node n = new Node(pX, pY, rW, rH, eX, eY, rBri);

if (xCnt % (_rhythm) == 0 || yCnt % (_rhythm - 1) == 0) {
if (random(1.0) < 0.5) {
n.setNavel();
}
}

yCnt++;
ySum += y;
}

xCnt++;
xSum += x;
}
return ns;
}

/**
* divide : divide the canvas randomly and returns ratios of divided spaces.
* @param  _div : divide number.
* @return : ratios(0.0 - 1.0) of divided spaces per canvas.
*/
ArrayList<Float> divide(int _div) {
ArrayList<Float> ratios = new ArrayList<Float>();
float rndPhase = random(TWO_PI);
float rndCycle = random(0.5, 2.5);
float rndMulti = random(0.5, 1.0);
float lenSum = 0.0;
for (int i = 0; i < _div; i++) {
float len = 2.0 + sin(map(i, 0, _div, 0.0, TWO_PI) * rndCycle + rndPhase) * rndMulti;
lenSum += len;
}
for (int i = 0; i < _div; i++) {
ratios.set(i, ratios.get(i) / lenSum); // normalize
}
return ratios;
}

/**
* InFourthPow : easing function.
* @param  _t    0.0 - 1.0 : linear value.
* @return       0.0 - 1.0 : eased value.
*/
private float InFourthPow(float _t) {
return 1.0 - pow(1.0 - _t, 4);
}

/*

This program is free software: you can redistribute it and/or modify