Public
Edited
Oct 27, 2022
17 stars
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
fragmentShader = `
uniform sampler2D u_texture;
uniform vec2 u_size;
uniform float u_time;

int state_from_color(vec3 col) {
${col_arr_str}
for (int i = 0; i < ${number_of_states}; i++) {
float d = distance(colors[i] / 255.0, col);
if (d < 0.0001) return i;
}
return -1;
}

vec3 color_from_state(const int state) {
${col_arr_str}
// this is an ugly hack. Can't index with state as it is not constant
for (int i = 0; i < ${number_of_states}; i++) {
if (i == state) return colors[i] / 255.0;
}
}

void main() {
vec2 position = gl_FragCoord.xy;
vec4 c = texture2D(u_texture, position / u_size);
int c_state = state_from_color(c.xyz);

int opp_state = c_state + 1;
if (opp_state >= ${number_of_states}) opp_state -= ${number_of_states};

int counter = 0;
for (int dx = -int(${size_of_neighborhood / 2}); dx <= int(${
size_of_neighborhood / 2
}); ++dx) {
for (int dy = -int(${size_of_neighborhood / 2}); dy <= int(${
size_of_neighborhood / 2
}); ++dy) {
if (dx == 0 && dy == 0) continue;
vec4 n = texture2D(u_texture, (position + vec2(dx,dy)) / u_size);
int n_state = state_from_color(n.xyz);

if (n_state == opp_state) {
counter++;
}
}
}

vec4 next_col = c;
if (counter >= ${n}) {
vec3 val = color_from_state(opp_state).xyz;
next_col = vec4(val, 1.0);
}

gl_FragColor = next_col;
}
`
Insert cell
Insert cell
seed = {
const seed = new Float32Array(4 * width * height);

for (let i = 0; i < 4 * width * height; i += 4) {
let r = Math.random();
for (let j = 1; j <= number_of_states; ++j) {
if ((j - 1) / number_of_states < r && r < j / number_of_states) {
const [r, g, b] = getColor((j - 1) / number_of_states);
seed[i + 0] = r / 255;
seed[i + 1] = g / 255;
seed[i + 2] = b / 255;
}
}
seed[i + 3] = 1;
}

return seed;
}
Insert cell
function getColor(t) {
if (colormap === "magma") {
return hexToRgb(d3.interpolateMagma(t));
}
if (colormap === "virdis") {
return hexToRgb(d3.interpolateViridis(t));
}
if (colormap === "plasma") {
return hexToRgb(d3.interpolatePlasma(t));
}
if (colormap === "inferno") {
return hexToRgb(d3.interpolateInferno(t));
}
if (colormap === "turbo") {
return rgbToRgb(d3.interpolateTurbo(t));
}
if (colormap === "warm") {
return rgbToRgb(d3.interpolateWarm(t));
}
if (colormap === "cool") {
return rgbToRgb(d3.interpolateCool(t));
}
if (colormap === "rainbow") {
return rgbToRgb(d3.interpolateRainbow(t));
}
if (colormap === "sinebow") {
return rgbToRgb(d3.interpolateSinebow(t));
}
}
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell
Insert cell

Purpose-built for displays of data

Observable is your go-to platform for exploring data and creating expressive data visualizations. Use reactive JavaScript notebooks for prototyping and a collaborative canvas for visual data exploration and dashboard creation.
Learn more