Published
Edited
Jun 25, 2022
1 fork
Importers
3 stars
Insert cell
Insert cell
Insert cell
toy(demoShader, demoOptions)
Insert cell
Insert cell
demoOptions = ({
width: 640,
height: 480,
extra_uniforms: {
u_radius: `Inputs.range([0.1,1], {label:"radius", step:0.01, value:0.5})`
}
})
Insert cell
Insert cell
Insert cell
toy = function (shader, options = {}) {
let div = html`<div>`;
let {
width = 512,
height = 512,
render = "continuous",
extra_uniforms = {}
} = options;
let canvas = DOM.canvas(width, height);
let gl = canvas.getContext("webgl", {
antialias: true
});
let regl = createRegl(gl);
let now = Date.now();
let uniforms = {
iResolution: [width, height, 1],
iFrame: 0,
iMouse: [0, 0, 0, 0],
iTime: 0
};
let inputs = {};
for (const key of Object.keys(extra_uniforms)) {
uniforms[key] = 0;
if (typeof extra_uniforms[key] == "string") {
inputs[key] = parseInput(extra_uniforms[key]);
div.append(inputs[key]);
}
}
let uniform_props = {};
for (const key of Object.keys(uniforms)) {
uniform_props[key] = regl.prop(key);
}
let draw;
let oldlog = console.log;
let error = "";
console.log = function (...args) {
error += args[0];
};
try {
draw = regl({
frag:
`
precision mediump float;
uniform vec3 iResolution;
uniform int iFrame;
uniform float iTime;
uniform vec4 iMouse;
` +
[...Object.keys(extra_uniforms)]
.map((key) => `uniform float ${key};`)
.join("\n") +
"\n" +
shader,

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

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

uniforms: uniform_props,

count: 6
});
} catch (e) {
error += e;
}
console.log = oldlog;
if (error != "") throw error;

let requestId = null;
function renderFrame() {
uniforms.iFrame++;
uniforms.iTime = (Date.now() - now) / 1000;
for (let key of Object.keys(extra_uniforms)) {
if (inputs[key]) {
uniforms[key] = inputs[key].value;
} else {
uniforms[key] = extra_uniforms[key]();
}
}
draw(uniforms);
}
canvas.onmousedown = canvas.onmouseup = (e) => {
uniforms.iMouse = [e.offsetX, height - e.offsetY, e.buttons, 0];
if (render != "single") renderFrame();
};
canvas.onmousemove = (e) => {
uniforms.iMouse = [e.offsetX, height - e.offsetY, e.buttons, 0];
if (render != "single" || e.buttons != 0) renderFrame();
};

invalidation.then(() => {
if (requestId) cancelAnimationFrame(requestId);
});
canvas.value = shader;

if (render == "continuous") {
function animationRender() {
renderFrame();
requestId = requestAnimationFrame(animationRender);
}
animationRender();
} else {
renderFrame();
}

div.append(canvas);
return div;
}
Insert cell
function parseInput(inputSpec) {
let regex = /(?<type>(\w|\.)+)\s*\((?<args>.*)\)\s*$/;
let match = inputSpec.match(regex);
let inputs = [
Inputs.range,
Inputs.radio,
Inputs.select,
Inputs.toggle,
Toggle,
Radio,
Range,
Select
];
let inputNames = [
"Inputs.range",
"Inputs.radio",
"Inputs.select",
"Inputs.toggle",
"Toggle",
"Radio",
"Range",
"Select"
];
let func = inputs[inputNames.indexOf(match.groups.type)];
let args = eval(`[${match.groups.args}]`);
return func(...args);
}
Insert cell
Insert cell
createRegl = require('regl@1.4.2/dist/regl.js')
Insert cell
import {
Button,
Checkbox,
Toggle,
Radio,
Range,
Select,
Text,
Textarea,
Search,
Table
} from "@observablehq/inputs"
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