Alex's notes

Gridtoy

Gridtoy is a lightweight tool for writing “ping-pong” feedback shaders. The following principles guide the development of Gridtoy:

  1. Tool for learning first
  2. Easy to export your work from Gridtoy and share / tinker / use in different contexts
  3. Low level code is possible (for learning), but high level convenience functions available
  4. Minimal boilerplate (like Processing)

Language brainstorming

Here is the WebGL GLSL code for Conway’s Game of Life:

#version 100
precision mediump float;

uniform vec2 size;
uniform float time;
uniform sampler2D previous;

void main() {
  vec2 position = (gl_FragCoord.xy / size.xy);
  vec2 pixel = 1./size;
  vec4 me = texture2D(previous, position);
  float sum = 0.;

  sum += texture2D(previous, position + pixel * vec2(-1., -1.)).x;
  sum += texture2D(previous, position + pixel * vec2(0., -1.)).x;
  sum += texture2D(previous, position + pixel * vec2(1., -1.)).x;
  sum += texture2D(previous, position + pixel * vec2(-1., 0.)).x;
  sum += texture2D(previous, position + pixel * vec2(1., 0.)).x;
  sum += texture2D(previous, position + pixel * vec2(-1., 1.)).x;
  sum += texture2D(previous, position + pixel * vec2(0., 1.)).x;
  sum += texture2D(previous, position + pixel * vec2(1., 1.)).x;

  if (me.x == 1.) {
    if (sum == 2. || sum == 3.) {
      gl_FragColor = vec4(1., 1., 1., 1.);
    } else {
      gl_FragColor = vec4(0., 0., 0., 1.);
    }
  } else {
    if (sum == 3.) {
      gl_FragColor = vec4(1., 1., 1., 1.);
    } else {
      gl_FragColor = vec4(0., 0., 0., 1.);
    }
  }
}

Not to mention all the setup code. I won’t copy that here, but it includes initializing textures of the appropriate size, filling texture with an initial random state, passing information into the shaders (time, previous frame, mouse state), and resizing the output to fill the screen.

Here are some ideas for how this program could be represented in grid.play:

void main() {
	float sum = 0;

  sum += neighbor(-1, 1);    // or neighborhood.get(-1, 1)
  sum += neighbor(0, -1);
  sum += neighbor(1, -1);
  sum += neighbor(-1, 0);
  sum += neighbor(1, 0);
  sum += neighbor(-1, 1);
  sum += neighbor(0, 1);
  sum += neighbor(1, 1);

  if (me == 1) {
    if (sum == 2 || sum == 3) {
      return 1;
    } else {
      return 0;
    }
  } else {
    if (sum == 3) {
			return 1;
    } else {
			return 0;
    }
  }
}

More compact:

void main() {
	window square = square(1);
	int sum = sum(square(neighborhood))

  if (me == 1) {
    if (sum == 2 || sum == 3) {
      return 1;
    } else {
      return 0;
    }
  } else {
    if (sum == 3) {
			return 1;
    } else {
			return 0;
    }
  }
}

How should setup configuration happen?

setup() function

void setup() {
	size(100, 100);
	frameRate(20);
}

Pros:

Cons:

JSON blob

{
	size: [100, 100],
	frameRate: 60
}

Pros:

Cons:

GLSL comments

// config:size 100 100
// config:frameRate 60

Pros:

Cons:

Freestyle ideas

.gridtoy file which can be run automatically by gridtoy library:

function setup() {
  renderSize(200, 200);
  gridSize(100, 100);
  fillRandom(0.1);
}

function draw(neighborhood) {
  return neighborhood(0, 0);
}

.js file:

gridtoy.renderSize(200, 200);
gridtoy.gridSize(100, 100);
gridtoy.fillRandom(0.1);
gridtoy.update((neighborhood) => {
  return neighborhood(0, 0);
});

// requestAnimationFrame:
gridtoy.run();

p5.js integration? three.js integration? standalone minified export?

Outstanding questions

?
| | \| | . | \ | \ | \ \| / \| - --- |--- |/| / . \|/|/ | | - \ | | . \|/ \|/| /|/| | . | |/ | |/ | \ / \| \| | /\|/ \---| - | || |/ | \ \|/| -| ||\| | - | |/ |\|| | / \ \|/| |/| \| / - | \ | |- |/ \ . | ./\|/ \| @ | --- \ | - /| /| / / \ \|/|/ |\-- | /|/ \ / | | / - \|/ | -- \|/| - \ | / . \ |\|/ |\|/|./ \ | | - | | |/ - \ | | |\|\|\| - \|/- \|/|\| | | | \ | \|| | |/ / \| @ - | |/\ \| / | \ \| | - |/ / \ | / \| --- . - - | - |/ | - \ |/ \|/ | \|/ \| | | | |/ | | | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^