Insert cell
Insert cell
Insert cell
Insert cell
commandUpdateAnts = regl({
frag: `
precision highp float;
uniform sampler2D space;
const int radius = ${radius};
const float invRadius = ${(1 / radius).toPrecision(5)};
varying vec2 uv;
varying vec2 cellPosition;
uniform sampler2D ants;
const int antCount = ${antCount};
void main() {
vec4 ant = texture2D(ants, uv);
gl_FragColor = vec4(ant.xy + invRadius, 0, 0);
}`,

vert: `
precision mediump float;
attribute vec2 position;
varying vec2 uv;
void main() {
uv = 0.5 * (position + 1.0);
gl_Position = vec4(position, 0, 1);
}`,
uniforms: {
space: (_, { space }) => space,
ants: (_, { ants }) => ants
},
framebuffer: (_, { antsNext }) => antsNext,
attributes: { position: [-3, -1, 3, -1, 0, 2] },
count: 3,
depth: { enable: false }
})
Insert cell
Insert cell
updateOnTick = 1
Insert cell
Insert cell
stateCount = 3
Insert cell
commandRender = regl({
frag: `
precision mediump float;
const vec2 size = vec2(${canvas.width}, ${canvas.height});
const vec2 invSize = vec2(
${(1 / canvas.width).toPrecision(5)},
${(1 / canvas.height).toPrecision(5)});

const int radius = ${radius};
const float invRadius = ${(1 / radius).toPrecision(5)};
uniform sampler2D space;
uniform sampler2D ants;
const int antCount = ${antCount};
varying vec2 uv;

void main() {
for (int i = 0; i < antCount; i++) {
vec4 ant = texture2D(ants, vec2(float(i) / float(antCount), 0));
}
gl_FragColor = vec4(texture2D(space, uv * size * invRadius).rgb, 1);
}`,

vert: `
precision mediump float;
attribute vec2 position;
varying vec2 uv;
uniform mat3 zoomMatrix;
void main() {
vec2 zoomedPosition = (zoomMatrix * vec3(position, 1)).xy;
uv = 0.5 * (zoomedPosition + 1.0);
gl_Position = vec4(position, 0, 1);
}`,
uniforms: {
space: (_, { space }) => space,
ants: (_, { ants }) => ants,
zoomMatrix: (_, { zoomMatrix }) => zoomMatrix
},
attributes: { position: [-3, -1, 3, -1, 0, 2] },
count: 3,
depth: { enable: false }
})
Insert cell
commandUpdate = regl({
frag: `
precision highp float;
uniform sampler2D space;
const int radius = ${radius};
const float invRadius = ${(1 / radius).toPrecision(5)};
varying vec2 uv;
varying vec2 cellPosition;
uniform sampler2D ants;
const int antCount = ${antCount};
void main() {
gl_FragColor =
texture2D(space, (cellPosition + vec2(-1.0, -1.0)) * invRadius) * 1.0
+ texture2D(space, (cellPosition + vec2(-1.0, 0.0)) * invRadius) * 2.0
+ texture2D(space, (cellPosition + vec2(-1.0, 1.0)) * invRadius) * 1.0
+ texture2D(space, (cellPosition + vec2(0.0, -1.0)) * invRadius) * 2.0
+ texture2D(space, (cellPosition + vec2(0.0, 0.0)) * invRadius) * 4.0
+ texture2D(space, (cellPosition + vec2(0.0, 1.0)) * invRadius) * 2.0
+ texture2D(space, (cellPosition + vec2(1.0, -1.0)) * invRadius) * 1.0
+ texture2D(space, (cellPosition + vec2(1.0, 0.0)) * invRadius) * 2.0
+ texture2D(space, (cellPosition + vec2(1.0, 1.0)) * invRadius) * 1.0;
gl_FragColor /= 16.0;
gl_FragColor *= 0.9;
for (int i = 0; i < antCount; i++) {
vec4 ant = texture2D(ants, vec2(float(i) / float(antCount), 0));
if (distance(ant.xy, uv) < invRadius) {
gl_FragColor += 1.0;
}
}
}`,

vert: `
precision mediump float;
const int radius = ${radius};
const float invRadius = ${(1 / radius).toPrecision(5)};
attribute vec2 position;
varying vec2 uv;
varying vec2 cellPosition;
void main() {
uv = 0.5 * (position + 1.0);
cellPosition = uv * float(radius);
gl_Position = vec4(position, 0, 1);
}`,
uniforms: {
space: (_, { space }) => space,
ants: (_, { ants }) => ants
},
framebuffer: (_, { nextSpace }) => nextSpace,
attributes: { position: [-3, -1, 3, -1, 0, 2] },
count: 3,
depth: { enable: false }
})
Insert cell
mutable state = {
reset;
const spaces = Array(2)
.fill()
.map(() =>
regl.framebuffer({
color: regl.texture({
radius,
data: initialSpace,
wrap: 'repeat',
type: 'half float'
}),
depth: false,
depthStencil: false
})
);
return {
space: spaces[0],
nextSpace: spaces[1],
ants: regl.framebuffer({
color: regl.texture({
width: antCount,
height: 1,
data: initialAnts,
wrap: 'clamp',
type: 'half float'
}),
depth: false,
depthStencil: false
}),
antsNext: regl.framebuffer({
color: regl.texture({
width: antCount,
height: 1,
data: initialAnts,
wrap: 'clamp',
type: 'half float'
}),
depth: false,
depthStencil: false
})
};
}
Insert cell
antCount = 300
Insert cell
initialAnts = Array(antCount * 4)
.fill(0)
.map(() => 0)
Insert cell
initialSpace = Array(radius * radius * 4)
.fill()
.map((_, i) =>
i % 4 == 0 ? (Math.random() > 0.8 ? 255 : 0) : i % 4 == 3 ? 255 : 0
)
Insert cell
Insert cell
updater = {
step;
if (typeof tick !== "undefined" && tick % updateOnTick != 0) {
return;
}
commandUpdateAnts(mutable state, () => {
regl.draw();
});
commandUpdate(mutable state, () => {
regl.draw();
mutable state = {
ants: mutable state.antsNext,
antsNext: mutable state.ants,
space: mutable state.nextSpace,
nextSpace: mutable state.space
};
});
}
Insert cell
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