Gridtoy
Gridtoy is a lightweight tool for writing “ping-pong” feedback shaders. The following principles guide the development of Gridtoy:
- Tool for learning first
- Easy to export your work from Gridtoy and share / tinker / use in different contexts
- Low level code is possible (for learning), but high level convenience functions available
- 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:
- looks like processing
- implies turing complete environment to write setup code (i.e. if (blah) { frameRate(60) })
Cons:
- implies that you can call size/framerate/other setup functions from within the draw() function, when in fact you cannot
JSON blob
{
size: [100, 100],
frameRate: 60
}
Pros:
- possibly could extend the ISF interface
Cons:
- static configuration only, not turing complete
GLSL comments
// config:size 100 100
// config:frameRate 60
Pros:
- lightweight, doesn’t pop you out of GLSL too much
Cons:
- less structured than JSON
- again, not turing complete
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?
#size 200 200
#fps 60
uniform ...
void init() {
pixel = random() < 0.5 ? WHITE : BLACK;
}
void update() {
}
void render() {
}
Outstanding questions
- how to handle color
- how to handle other inputs
- mouse
- keyboard
- custom user stuff
- idea: allow lots of different signatures for update/draw functions, and then call the one that matches. how to differentiate between:
function draw(neighborhood, mouse)
vsfunction draw(neighborhood, key)
?
- one common interface for a lot of different contexts:
- educational online editor
- advanced standalone code (write your own wrapper around the library)
- export from online editor to minified standalone version
- plug-and-play with p5.js
- plug-and-play with three.js