Shader Reveal Nieuw
Klik en het tweede beeldvlak verschijnt via een ruis- of strepenovergang met een gloeiende rand. Handig voor dag/nacht, voor/na of twee collecties.
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- Shader Reveal · Bron: SmoothUI · licentie MIT. Laat deze vermelding staan bij hergebruik. -->
<div class="jouw-container">
<div class="shr"><div class="shr__fb"><div class="shr__a"></div><div class="shr__b"></div></div><canvas class="shr__gl" aria-hidden="true"></canvas><button class="shr__go" type="button">Toon nacht</button><div class="shr__ctl" role="group" aria-label="Overgang"><button type="button" class="is-on" data-m="0">Ruis</button><button type="button" data-m="1">Strepen</button></div></div>
</div>/* Shader Reveal · Bron: SmoothUI · licentie MIT. Laat deze vermelding staan bij hergebruik. */
.shr{position:absolute;inset:0;overflow:hidden;background:#f4f3f1;font-family:'Switzer',system-ui,sans-serif}
.shr__gl,.shr__fb,.shr__fb canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.shr.is-nogl .shr__gl{display:none}
.shr__tag{position:absolute;left:12px;bottom:12px;z-index:3;font:500 10px/1 'JetBrains Mono',monospace;letter-spacing:.14em;text-transform:uppercase;background:#0a0a0a;color:#fff;padding:6px 8px;border-radius:3px}
.shr__ctl{position:absolute;right:12px;bottom:12px;z-index:3;display:flex;align-items:center;gap:8px;background:#fff;border:1px solid rgba(10,10,10,.14);border-radius:4px;padding:6px 9px;font:500 10px/1 'JetBrains Mono',monospace;letter-spacing:.1em;text-transform:uppercase;color:#0a0a0a}
.shr__ctl input{width:84px;accent-color:#F5480F;margin:0}
.shr.is-nogl .shr__ctl{display:none}
.shr__a,.shr__b,.shr__a canvas,.shr__b canvas{position:absolute;inset:0;width:100%;height:100%;display:block}
.shr__b{clip-path:inset(0 100% 0 0);transition:clip-path .9s cubic-bezier(.7,0,.2,1)}
.shr.is-b .shr__b{clip-path:inset(0 0 0 0)}
.shr__go{position:absolute;left:12px;bottom:12px;z-index:3;font:600 12px/1 'Switzer',system-ui,sans-serif;background:#F5480F;color:#fff;border:0;border-radius:999px;padding:10px 16px;cursor:pointer}
.shr.is-b .shr__go{background:#fff;color:#0a0a0a}
.shr__go:focus-visible,.shr__ctl button:focus-visible{outline:2px solid #0a0a0a;outline-offset:2px}
.shr__ctl{padding:3px;gap:2px}
.shr__ctl button{font:inherit;letter-spacing:inherit;text-transform:inherit;background:none;border:0;border-radius:3px;padding:5px 7px;color:#0a0a0a;cursor:pointer}
.shr__ctl button.is-on{background:#0a0a0a;color:#fff}
@media(prefers-reduced-motion:reduce){.shr__b{transition:none}}// Shader Reveal · Bron: SmoothUI · licentie MIT. Laat deze vermelding staan bij hergebruik.
// root = het element waarin de HTML staat
function init(root){
function mkGL(cv, frag) {
var gl = null;
try { gl = cv.getContext('webgl', { antialias: false, premultipliedAlpha: false }) || cv.getContext('experimental-webgl'); } catch (e) { gl = null; }
if (!gl) return null;
function sh(t, s) { var o = gl.createShader(t); gl.shaderSource(o, s); gl.compileShader(o); if (!gl.getShaderParameter(o, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(o) || 'shader'); return o; }
var pr = gl.createProgram();
try {
gl.attachShader(pr, sh(gl.VERTEX_SHADER, 'attribute vec2 p;varying vec2 vUv;void main(){vUv=p*.5+.5;gl_Position=vec4(p,0.,1.);}'));
gl.attachShader(pr, sh(gl.FRAGMENT_SHADER, 'precision highp float;varying vec2 vUv;' + frag));
gl.linkProgram(pr);
if (!gl.getProgramParameter(pr, gl.LINK_STATUS)) throw new Error('link');
} catch (e) { console.warn('lab webgl', e); return null; }
gl.useProgram(pr);
var buf = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buf);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
var loc = gl.getAttribLocation(pr, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
var U = {};
var api = {
gl: gl,
u: function (n) { if (!(n in U)) U[n] = gl.getUniformLocation(pr, n); return U[n]; },
upd: function (t, src, unit) {
gl.activeTexture(gl.TEXTURE0 + unit); gl.bindTexture(gl.TEXTURE_2D, t);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, src);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
},
tex: function (src, unit, name) { var t = gl.createTexture(); api.upd(t, src, unit); gl.uniform1i(api.u(name), unit); return t; },
fit: function () {
var d = Math.min(window.devicePixelRatio || 1, 2), w = Math.max(1, Math.round(cv.clientWidth * d)), h = Math.max(1, Math.round(cv.clientHeight * d));
if (cv.width !== w || cv.height !== h) { cv.width = w; cv.height = h; }
gl.viewport(0, 0, w, h); gl.uniform2f(api.u('uRes'), w, h); return d;
},
draw: function () { gl.drawArrays(gl.TRIANGLES, 0, 3); }
};
return api;
}
function runLoop(el, frame, still) {
var reduce = matchMedia('(prefers-reduced-motion:reduce)').matches, vis = true, raf = 0, t0 = performance.now();
function tick(now) { raf = 0; frame((now - t0) / 1000); if (!reduce && !still && vis) raf = requestAnimationFrame(tick); }
if ('IntersectionObserver' in window) new IntersectionObserver(function (es) { vis = es[0].isIntersecting; if (vis && !raf) raf = requestAnimationFrame(tick); }).observe(el);
raf = requestAnimationFrame(tick);
return { reduce: reduce, kick: function () { if (!raf) raf = requestAnimationFrame(tick); } };
}
function paintScene(c, v) {
var x = c.getContext('2d'), W = c.width, H = c.height, night = v === 1;
var bg = x.createLinearGradient(0, 0, 0, H);
if (night) { bg.addColorStop(0, '#0a0a0a'); bg.addColorStop(1, '#2b1b12'); } else { bg.addColorStop(0, '#f4f3f1'); bg.addColorStop(1, '#ddd5c9'); }
x.fillStyle = bg; x.fillRect(0, 0, W, H);
var sx = W * .68, sy = H * .44, sr = H * .27;
var sg = x.createRadialGradient(sx - sr * .35, sy - sr * .35, sr * .1, sx, sy, sr);
if (night) { sg.addColorStop(0, '#ffffff'); sg.addColorStop(1, '#cfc8bd'); } else { sg.addColorStop(0, '#ffa071'); sg.addColorStop(1, '#F5480F'); }
x.fillStyle = sg; x.beginPath(); x.arc(sx, sy, sr, 0, 7); x.fill();
x.fillStyle = night ? '#7a2a0c' : '#6b645d';
x.beginPath(); x.moveTo(0, H * .72); x.bezierCurveTo(W * .25, H * .58, W * .45, H * .78, W * .7, H * .66); x.bezierCurveTo(W * .85, H * .6, W * .95, H * .66, W, H * .64); x.lineTo(W, H); x.lineTo(0, H); x.fill();
x.fillStyle = night ? '#F5480F' : '#0a0a0a';
x.beginPath(); x.moveTo(0, H * .84); x.bezierCurveTo(W * .3, H * .74, W * .6, H * .92, W, H * .8); x.lineTo(W, H); x.lineTo(0, H); x.fill();
x.strokeStyle = night ? '#f4f3f1' : '#0a0a0a'; x.lineWidth = H * .012;
x.beginPath(); x.moveTo(W * .2, H * .8); x.lineTo(W * .2, H * .34); x.lineTo(W * .44, H * .34); x.moveTo(W * .16, H * .34); x.lineTo(W * .2, H * .34); x.moveTo(W * .4, H * .34); x.lineTo(W * .4, H * .5); x.stroke();
x.fillStyle = night ? '#f4f3f1' : '#0a0a0a';
x.fillRect(W * .385, H * .5, W * .03, H * .05);
x.textBaseline = 'top';
x.font = '400 ' + Math.round(H * .08) + "px Boldonse, Switzer, sans-serif"; x.fillText('HAVENKADE', W * .06, H * .08);
x.font = '500 ' + Math.round(H * .034) + "px 'JetBrains Mono', monospace"; x.fillText(night ? 'NACHTVERSIE · ROTTERDAM' : 'DAGVERSIE · ROTTERDAM', W * .06, H * .22);
}
function fontsThen(cb) {
if (!document.fonts || !document.fonts.load) return;
Promise.all(['400 40px Boldonse', "500 20px 'JetBrains Mono'", '600 20px Switzer'].map(function (f) { return document.fonts.load(f).catch(function () {}); })).then(cb);
}
var NOISE="float hash(vec2 p){p=fract(p*vec2(123.34,456.21));p+=dot(p,p+45.32);return fract(p.x*p.y);}float vnoise(vec2 p){vec2 i=floor(p),f=fract(p);f=f*f*(3.-2.*f);return mix(mix(hash(i),hash(i+vec2(1.,0.)),f.x),mix(hash(i+vec2(0.,1.)),hash(i+vec2(1.,1.)),f.x),f.y);}float fbm(vec2 p){float v=0.,a=.5;for(int i=0;i<5;i++){v+=a*vnoise(p);p*=2.03;a*=.5;}return v;}";
var w = root.querySelector('.shr'); if (!w) return;
var cv = w.querySelector('.shr__gl'), go = w.querySelector('.shr__go'), mb = w.querySelectorAll('.shr__ctl button');
var a = document.createElement('canvas'), b = document.createElement('canvas');
a.width = b.width = 960; a.height = b.height = 600; paintScene(a, 0); paintScene(b, 1);
w.querySelector('.shr__a').appendChild(a); w.querySelector('.shr__b').appendChild(b);
var target = 0, pr = 0, mode = 0, L = null, g;
function setLabel() { go.textContent = target ? 'Toon dag' : 'Toon nacht'; }
go.addEventListener('click', function () { target = target ? 0 : 1; w.classList.toggle('is-b', !!target); setLabel(); if (L) L.kick(); });
mb.forEach(function (bt) { bt.addEventListener('click', function () { mode = +bt.dataset.m; mb.forEach(function (o) { o.classList.toggle('is-on', o === bt); }); if (L) L.kick(); }); });
g = mkGL(cv, NOISE + `uniform sampler2D uA,uB;uniform float uP,uMode;
void main(){
vec2 uv=vUv;
float n=uMode<.5?fbm(uv*vec2(5.,3.2)):clamp((1.-uv.y)*.55+hash(vec2(floor(uv.x*12.),3.))*.4,0.,1.);
float w=.07;float t=uP*(1.+2.*w)-w;
float m=smoothstep(t-w,t+w,n);
float band=1.-abs(m-.5)*2.;
vec2 off=vec2(0.,band*.03);
vec3 ca=texture2D(uA,uv+off).rgb,cb=texture2D(uB,uv-off).rgb;
vec3 col=mix(cb,ca,m)+vec3(.961,.282,.059)*pow(band,2.)*1.1;
gl_FragColor=vec4(col,1.);
}`);
if (!g) { w.classList.add('is-nogl'); return; }
var ta = g.tex(a, 0, 'uA'), tb = g.tex(b, 1, 'uB'), last = 0;
L = runLoop(w, function (t) {
var dt = Math.min(.05, t - last); last = t;
if (L && L.reduce) pr = target; else pr += Math.sign(target - pr) * Math.min(Math.abs(target - pr), dt / 1.1);
var e = pr * pr * (3 - 2 * pr);
g.fit(); g.gl.uniform1f(g.u('uP'), e); g.gl.uniform1f(g.u('uMode'), mode); g.draw();
});
fontsThen(function () { paintScene(a, 0); paintScene(b, 1); g.upd(ta, a, 0); g.upd(tb, b, 1); L.kick(); });
}
init(document.querySelector('.jouw-container'));
Meer uit achtergronden & webgl
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →