JSFiddle - React, Tailwind, and code Playground
by Oski Krawczyk
HTML
<canvas id="glCanvas"></canvas>
<div id="controls">
<label for="animationSpeed">Animation Speed:</label>
<input type="range" id="animationSpeed" min="0.01" max="55.0" step="0.01" value="1.0">
<span id="speedValue">1.00x</span>
<label for="verticalOffset">Vertical Offset:</label>
<input type="range" id="verticalOffset" min="-2.0" max="2.0" step="0.01" value="0.0">
<span id="offsetValue">0.00</span>
<label for="patternZoom">Pattern Zoom:</label>
<input type="range" id="patternZoom" min="0.1" max="2.0" step="0.01" value="0.5">
<span id="zoomValue">0.50</span>
</div>
JavaScript
// main.js
const canvas = document.getElementById('glCanvas');
const gl = canvas.getContext('webgl2'); // Use webgl2 for GLSL ES 3.00
if (!gl) {
alert('Unable to initialize WebGL. Your browser or machine may not support it.');
}
// Vertex shader source
const vsSource = `#version 300 es
in vec4 a_position;
out vec2 v_uv;
void main() {
gl_Position = a_position;
// Map clip space (-1 to 1) to UV space (0 to 1)
v_uv = (a_position.xy * 0.5) + 0.5;
}
`;
// Fragment shader source (translated from Swift Metal)
const fsSource = `#version 300 es
precision highp float;
in vec2 v_uv;
out vec4 fragColor;
uniform float u_time;
uniform float u_tapValue;
uniform vec2 u_resolution;
uniform float u_aspectRatio;
uniform float u_verticalOffset;
uniform float u_patternZoom; // NEW: Pattern Zoom uniform
// Helper functions
float hash(float n) {
return fract(sin(n) * 753.5453123);
}
float noise(vec2 x) {
vec2 p = floor(x);
vec2 f = fract(x);
f = f * f * (3.0 - 2.0 * f);
float n = p.x + p.y * 157.0;
return mix(
mix(hash(n + 0.0), hash(n + 1.0), f.x),
mix(hash(n + 157.0), hash(n + 158.0), f.x),
f.y
);
}
float fbm(vec2 p, vec3 a) {
float v = 0.0;
v += noise(p * a.x) * 0.50 ;
v += noise(p * a.y) * 1.50 ;
v += noise(p * a.z) * 0.125 * 0.1; // variable
return v;
}
vec3 drawLines(
vec2 uv,
vec3 fbmOffset,
vec3 color1,
vec3 colorSet[4], // GLSL requires size for arrays in parameters
float secs
) {
float timeVal = secs * 0.1;
vec3 finalColor = vec3(0.0);
for (int i = 0; i < 4; ++i) {
float indexAsFloat = float(i);
float amp = 80.0 + (indexAsFloat * 0.0);
float period...