a(href='//www.twitter.com/ycwhk' target='_blank') hello
View Compiled
@import url('https://fonts.googleapis.com/css?family=Lora&display=swap');
body {
display:grid;
justify-content:center;
align-content:center;
height:100vh;
font:5vh Lora;
}
a {
color:#222a;
text-decoration:#2224 wavy underline;
transition:all 0.3s;
&:hover {
color:#2223;
text-shadow:0 0 100px #333;
}
}
canvas {
position:fixed;
z-index:-1;
}
View Compiled
console.clear();
const canvas = document.createElement('canvas');
document.body.append(canvas);
canvas.style.display = 'block';
canvas.style.width = '100vw';
canvas.style.height = '100vh';
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
const gl = canvas.getContext('webgl2');
if (!gl) {
alert('require webgl 2.0, bye')
}
const vss = `#version 300 es
in vec2 p;
void main() {
gl_Position = vec4(p, 0.0, 1.0);
}
`;
const fss = `#version 300 es
precision mediump float;
out vec4 o;
uniform vec4 c;
void main() {
o = c;
}
`;
// Create shader program
// # should query both shader logs and program logs
// # only if program link's status is false.
//
// Here's the antipattern .. keep for ref
//
const vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, vss);
gl.compileShader(vs);
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(vs));
throw 1;
}
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, fss);
gl.compileShader(fs);
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) {
console.error(gl.getShaderInfoLog(fs));
throw 2;
}
const prg = gl.createProgram();
gl.attachShader(prg, vs);
gl.attachShader(prg, fs);
gl.linkProgram(prg);
if (!gl.getProgramParameter(prg, gl.LINK_STATUS)) {
console.error(gl.getProgramInfoLog(prg));
throw 3;
}
gl.detachShader(prg, vs);
gl.deleteShader(vs);
gl.detachShader(prg, fs);
gl.deleteShader(fs);
// ---- End of antipattern ----
const $p = gl.getAttribLocation(prg, 'p');
const $c = gl.getUniformLocation(prg, 'c');
const va = gl.createVertexArray();
gl.bindVertexArray(va);
const N = 300; // n triangles
let ps;
{
ps = new Float32Array(2 + N * 2 * 2);
ps[0] = 0; // clip space center
ps[1] = 0;
let j = 2;
for (let i = 0; i < N; ++i) {
ps[j++] = Math.random() * 2 - 1; //x
ps[j++] = Math.random() * 2 - 1; //y
ps[j++] = Math.random() * 2 - 1; //x
ps[j++] = Math.random() * 2 - 1; //y
}
}
const buf = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, ps, gl.DYNAMIC_DRAW);
gl.enableVertexAttribArray($p);
gl.vertexAttribPointer(
$p,
2, gl.FLOAT, // two 32b-float (8bytes)
false,
0, // skip n byte to fetch next
0 // skip n byte to fetch first
);
let idxs;
{
idxs = new Uint16Array(3 * N);
let j = 0;
for (let i = 0; i < N; ++i) {
idxs[j++] = 0;
idxs[j++] = 1 + i * 2;
idxs[j++] = 2 + i * 2;
}
}
const ibuf = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, ibuf);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, idxs, gl.STATIC_DRAW);
gl.bindVertexArray(null);
//----- render
gl.viewport(0, 0, gl.canvas.width, gl.canvas.height);
gl.clearColor(0.1, 0.1, 0.1, 1);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
gl.enable(gl.BLEND);
gl.disable(gl.CULL_FACE);
gl.useProgram(prg);
gl.bindVertexArray(va);
function f() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.uniform4fv($c, [0.2, 0.2, 0.2, 0.02]);
gl.drawElements(
gl.TRIANGLES,
idxs.length, // n indices
gl.UNSIGNED_SHORT, // ui16
0 // skip n bytes to fetch first
);
}
f();
// ---
gl.bindBuffer(gl.ARRAY_BUFFER, buf);
document.body.onmousemove = (e) => {
ps[0] = e.clientX / window.innerWidth * 2 - 1;
ps[1] = -1 * (e.clientY / window.innerHeight * 2 - 1);
gl.bufferSubData(gl.ARRAY_BUFFER, 0, ps.slice(0, 2)); // that's why DYNAMIC_DRAW
f();
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.