Published
Edited
Sep 26, 2021
10 forks
Importers
68 stars
Insert cell
Insert cell
viewof gl = {
const height = width;
const canvas = document.createElement("canvas");
canvas.width = width * devicePixelRatio;
canvas.height = height * devicePixelRatio;
canvas.style = `width: ${width}px; height: ${height}px`;
const gl = canvas.value = canvas.getContext("webgl", {antialias: false, depth: false});
gl.getExtension("OES_texture_float");
return canvas;
}
Insert cell
a = -2.0 + Math.sin(now / 8000)
Insert cell
b = -2.0
Insert cell
c = -1.2
Insert cell
d = 2.0
Insert cell
n = Math.pow(2, 20)
Insert cell
setup = {
gl.viewport(0, 0, viewof gl.width, viewof gl.height);
gl.useProgram(program);
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.vertexAttribPointer(a_position, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(a_position);
}
Insert cell
draw = {
setup;
gl.uniform1f(u_a, a);
gl.uniform1f(u_b, b);
gl.uniform1f(u_c, c);
gl.uniform1f(u_d, d);
gl.drawArrays(gl.POINTS, 0, n);
}
Insert cell
fragmentShader = {
const shader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(shader, `
precision highp float;

varying float v_t;

const float PI = 3.14159265359;

vec3 cubehelix(float x, float y, float z) {
float a = y * z * (1.0 - z);
float c = cos(x + PI / 2.0);
float s = sin(x + PI / 2.0);
return vec3(
z + a * (1.78277 * s - 0.14861 * c),
z - a * (0.29227 * c + 0.90649 * s),
z + a * (1.97294 * c)
);
}

vec3 rainbow(float t) {
if (t < 0.0 || t > 1.0) t -= floor(t);
float ts = abs(t - 0.5);
return cubehelix(
(360.0 * t - 100.0) / 180.0 * PI,
1.5 - 1.5 * ts,
0.8 - 0.9 * ts
);
}

void main() {
gl_FragColor = vec4(rainbow(v_t / 4.0 + 0.25), 1.0);
}
`);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw gl.getShaderInfoLog(shader);
invalidation.then(() => gl.deleteShader(shader));
return shader;
}
Insert cell
vertexShader = {
const shader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(shader, `
precision highp float;

const float PI = 3.14159265359;

uniform float u_a;
uniform float u_b;
uniform float u_c;
uniform float u_d;

attribute vec2 a_position;

varying float v_t;

void main() {
float x1, x2 = a_position.x;
float y1, y2 = a_position.y;
for (int i = 0; i < 8; i++) {
x1 = x2, y1 = y2;
x2 = sin(u_a * y1) - cos(u_b * x1);
y2 = sin(u_c * x1) - cos(u_d * y1);
}
v_t = atan(a_position.y, a_position.x) / PI;
gl_Position = vec4(x2 / 2.0, y2 / 2.0, 0.0, 1.0);
gl_PointSize = 1.5;
}
`);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) throw gl.getShaderInfoLog(shader);
invalidation.then(() => gl.deleteShader(shader));
return shader;
}
Insert cell
vertexBuffer = {
const array = new Float32Array(n * 2).map(() => Math.random() * 2 - 1);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, array, gl.STATIC_DRAW);
invalidation.then(() => gl.deleteBuffer(buffer));
return buffer;
}
Insert cell
program = {
const program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) throw gl.getProgramInfoLog(program);
invalidation.then(() => gl.deleteProgram(program));
return program;
}
Insert cell
a_position = gl.getAttribLocation(program, "a_position")
Insert cell
u_a = gl.getUniformLocation(program, "u_a")
Insert cell
u_b = gl.getUniformLocation(program, "u_b")
Insert cell
u_c = gl.getUniformLocation(program, "u_c")
Insert cell
u_d = gl.getUniformLocation(program, "u_d")
Insert cell
height = width
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