Published
Edited
May 22, 2022
4 forks
2 stars
Insert cell
Insert cell
{
// The drawing canvas
const canvas = html`<canvas width=500 height=500 style="border:1px solid gray" />`;
yield canvas;

// The regl objects
let { regl, drawCircle } = circleRenderProgram(canvas);

// Click callback (pause)
let run = true;
canvas.onmousedown = () => {
run = !run;
};

// A set of lights
let circles = [new circleLight()];
const maxCircles = 30;
const minCircles = 5;
const createProbability = 0.01;

// The animation
for (let frame = 0; ; frame++) {
if (run) {
regl.clear({
color: [0, 0, 0, 1]
});
for (let circle of circles) {
drawCircle(circle);
circle.animate();
}
circles = circles.filter((c) => !c.terminated);
if (
circles.length < maxCircles &&
(circles.length < minCircles || Math.random() < createProbability)
)
circles.push(new circleLight());
}
yield canvas;
}
}
Insert cell
palette = d3.schemeAccent.map((c) => {
let color = d3.color(c);
return [color.r / 255, color.g / 255, color.b / 255, 1];
})
Insert cell
class circleLight {
constructor(aspect = 1) {
this.pos = [(Math.random() * 2 - 1) * aspect, Math.random() * 2 - 1];
this.r = 0.01;
this.maxR = Math.random() * 0.8 + 0.2;
this.color = palette[~~(Math.random() * palette.length)];
this.increment = 0.001;
}
get terminated() {
return this.r < 0;
}
animate() {
if (!this.terminated) {
this.r += this.increment;
}
if (this.r > this.maxR) this.increment = -this.increment;
}
}
Insert cell
function circleRenderProgram(canvas) {
const regl = createRegl(canvas);

const drawCircle = regl({
frag: `
precision mediump float;
uniform vec4 color;
uniform vec2 pos;
uniform float r;
uniform vec2 resolution;


float sdCircle ( in vec2 p, in vec2 pos, in float r )
{
return length (p-pos) - r;
}

void main () {
vec2 p = (2.0*gl_FragCoord.xy-resolution)/resolution.y;
float d = sdCircle(p, pos, r);
if (d >= 0. && d <= 1.) {
float t = smoothstep(0.,0.005,d)-smoothstep(0.005,0.01,d);
gl_FragColor = vec4(color.xyz,(t+0.8*pow((1.-d),5.))*smoothstep(0.,0.1,r));
}
else discard;
}`,

vert: `
attribute vec2 position;
void main () {
gl_Position = vec4(position, 0., 1.);
}`,

attributes: {
position: [
[-1, -1],
[1, -1],
[1, 1],
[-1, 1]
]
},

depth: {
enable: false
},

primitive: "triangle fan",

blend: {
enable: true,
func: {
srcRGB: "src alpha",
srcAlpha: 1,
dstRGB: "one minus src alpha",
dstAlpha: 1
}
},

count: 4,

uniforms: {
resolution: [canvas.width, canvas.height],
r: regl.prop("r"),
pos: regl.prop("pos"),
color: regl.prop("color")
}
});

return { regl, drawCircle };
}
Insert cell
Insert cell
Insert cell
Insert cell

One platform to build and deploy the best data apps

Experiment and prototype by building visualizations in live JavaScript notebooks. Collaborate with your team and decide which concepts to build out.
Use Observable Framework to build data apps locally. Use data loaders to build in any language or library, including Python, SQL, and R.
Seamlessly deploy to Observable. Test before you ship, use automatic deploy-on-commit, and ensure your projects are always up-to-date.
Learn more