Crafting generative art with javascript generators
Tags: javascript, frontend, es6, art
Published: 2022-09-28 12:53:44

---
title: Crafting generative art with javascript generators
published: true
description: 
tags: javascript, frontend, es6, art
# cover_image: https://direct_url_to_image.jpg
# Use a ratio of 100:42 for best results.
---
Apart from career programming and management tasks, I spend my free time doing creative coding. Most of it is [programming music with SuperCollider](https://bohdanstupak.bandcamp.com/) but recently I was also involved in some visual art.

## Initial project structure
The idea behind the project is to study the relation between colors by randomly morphing them into each other. The program which does this is the array of program frames which are the color and number of frame executions. In the initial iteration, the capacity of the array is 5.
```javascript
function generateProgram() {
    var numberOfFrames = 500;
    var numberOfIterations = 5000;
    var previousIteration = 0;
    var program = [];
    for (var i = 0; i < numberOfFrames; i++) {
        var currentIteration = randomInt(numberOfIterations) + previousIteration;
        program[i] = {
            color: randomHsl(),
            latestIteration: currentIteration
        }
        previousIteration = currentIteration;
    }
    return program;
}
```
We're generating colors in HSL format since random colors in RGB look pretty similar and the result wouldn't be as pleasing aesthetically.

Program execution is the infinite loop that selects a couple of random points on the canvas and blends them with the color of the current program frame. Once we've reached the target number of iterations we switch to the next program frame.
```javascript
function executeProgram(program) {
    var points = getInitialCanvas(program);
    drawOnCanvas(points);
    var iteration = 0;
    var currentProgramFrameIndex = 0;
    var currentProgramFrame = program[currentProgramFrameIndex];
    function run() {
        setTimeout(function() {
            for (var k = 0; k < 10; k++) {
                window.requestAnimationFrame(run);
                iteration++;
                var i = randomInt(height)-1;
                var j = randomInt(width)-1;
                points[i][j] = blendColors(points[i][j], currentProgramFrame.color);
                if (iteration == currentProgramFrame.latestIteration
                        && currentProgramFrameIndex !== program.length - 1) {
                    currentProgramFrameIndex++;
                    currentProgramFrame = program[currentProgramFrameIndex];
                }
                drawPointOnCanvas(i, j, points[i][j]);
            }
        }, 1);
    }
    run();
}
```
We can observe that we're instructing the browser to schedule animation using [window.requestAnimationFrame](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) method. This method accepts a callback which will be executed when it is time to paint the animation. So by calling `run` method as the callback we're effectively creating the infinite loop.

In order for our infinite loop not to block repainting of the canvas, we call each iteration inside the `setTimeout` function.

## Using generators
The obvious downside of this approach is that we have a limited amount of frames. Instead, we want our animation to last forever. One of the possible ways is to provide each new program frame via [generators](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Generator)

Changes are pretty straightforward. Instead of generating the program as an array of frames, we define a generator function that will return a new frame when requested.
```javascript
function* generateProgram()  {
	while (true) {
		var numberOfIterations = 5000;
		var program = [];
		var currentIteration = randomInt(numberOfIterations)
		program = {
			color: randomHsl(),
			latestIteration: currentIteration
		}
		previousIteration = currentIteration;
		yield program;
	}
}
```

To request the frame we instantiate the generator object by calling the function and then calling `next` method.
```javascript
var programGenerator = generateProgram()
var program = programGenerator.next().value;
```

Now we can request each program frame, once the previous is completed.
```javascript
function executeProgram(program) {
    var points = getInitialCanvas(program);
    drawOnCanvas(points);
    var iteration = 0;
    function run() {
        setTimeout(function() {
            for (var k = 0; k < 10; k++) {
                window.requestAnimationFrame(run);
                iteration++;
                var i = randomInt(height)-1;
                var j = randomInt(width)-1;
                points[i][j] = blendColors(points[i][j], program.color);
                if (iteration == program.latestIteration) {
                    program = programGenerator.next().value
                }
                drawPointOnCanvas(i, j, points[i][j]);
            }
        }, 1);
    }
    run();

}
```

### Sidenote: Fixing the memory leak
When you pay attention to this program long enough you might notice that it starts consuming more and more memory.

Upon examining memory profile in my Firefox devtools I can notice that the primary source of allocation is `setTimeout` function.


![Memory profile](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/v1lswuzee00qg44eps17.PNG)



Turns out that calls to `requestAnimationFrame` are stacked to [map of animation frame callbacks](https://html.spec.whatwg.org/multipage/imagebitmap-and-animations.html#list-of-animation-frame-callbacks). And if the browser is not keeping up with the growth of callback's map it's starts growing up in size consuming more and more memory.

So the fix is as simple as increasing timeout duration.