← Blurr Motion testimonial-shader-bg-kinetic
Categorie testimonials Tier 2 Techniek #34 Deps webgl
// CLIENT VOICE
"It hit live in seven days. The ROI took the rest of the month to catch up."
1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: testimonial-shader-bg-kinetic
const reduce = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const canvas = document.querySelector('.kshd-canvas');
if (canvas) {
  const gl = canvas.getContext('webgl2') || canvas.getContext('webgl');
  if (!gl) { canvas.style.background = 'linear-gradient(135deg,#0A0A0A,#FF5C3A,#C8FF00)'; }
  else {
    const vs = '#version 300 es\nin vec2 p;void main(){gl_Position=vec4(p,0.,1.);}';
    const fs = '#version 300 es\nprecision highp float;uniform vec2 R;uniform float T;out vec4 o;'+
      'vec3 mixc(float t){vec3 a=vec3(0.04);vec3 b=vec3(0.78,0.36,0.23);vec3 c=vec3(0.78,1.0,0.0);'+
      'float k=fract(t*0.5);if(k<.33){return mix(a,b,k/.33);}else if(k<.66){return mix(b,c,(k-.33)/.33);}else{return mix(c,a,(k-.66)/.34);}}'+
      'void main(){vec2 u=(gl_FragCoord.xy*2.-R)/min(R.x,R.y);'+
      'float d=length(u);float w=sin(d*4.-T*1.2)*.5+.5;'+
      'vec3 col=mixc(T*.15+w*.6);col+=0.06*sin(u.x*8.+T)*sin(u.y*8.-T);'+
      'o=vec4(col,1.);}';
    const isWebgl2 = !!gl.createVertexArray;
    const v = gl.createShader(gl.VERTEX_SHADER); gl.shaderSource(v, isWebgl2?vs:vs.replace('#version 300 es','').replace('in ','attribute ')); gl.compileShader(v);
    const f = gl.createShader(gl.FRAGMENT_SHADER); gl.shaderSource(f, isWebgl2?fs:fs.replace('#version 300 es','').replace('out vec4 o;','').replace('o=','gl_FragColor=')); gl.compileShader(f);
    const pr = gl.createProgram(); gl.attachShader(pr, v); gl.attachShader(pr, f); gl.linkProgram(pr); gl.useProgram(pr);
    const 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);
    const loc = gl.getAttribLocation(pr, 'p'); gl.enableVertexAttribArray(loc); gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
    const uR = gl.getUniformLocation(pr, 'R'); const uT = gl.getUniformLocation(pr, 'T');
    const resize = () => { canvas.width = canvas.clientWidth*devicePixelRatio; canvas.height = canvas.clientHeight*devicePixelRatio; gl.viewport(0,0,canvas.width,canvas.height); gl.uniform2f(uR, canvas.width, canvas.height); };
    resize(); addEventListener('resize', resize);
    const t0 = performance.now();
    const draw = () => { gl.uniform1f(uT, (performance.now()-t0)/1000); gl.drawArrays(gl.TRIANGLES,0,3); if (!reduce) requestAnimationFrame(draw); };
    draw();
  }
}
2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: testimonial-shader-bg-kinetic -->
<section class="kshd-wrap">
  <canvas class="kshd-canvas"></canvas>
  <div class="kshd-card">
    <span class="kshd-tag">// CLIENT VOICE</span>
    <blockquote class="kshd-q">"It hit live in seven days. The ROI took the rest of the month to catch up."</blockquote>
    <footer class="kshd-foot"><strong>L. VAN DIJK</strong><span>Founder, Northrun</span></footer>
  </div>
</section>
3. Styling-template — verplicht eigen invulling per merk
/* Styling: testimonial-shader-bg-kinetic — kinetic */
.kshd-wrap { position:relative; background:#0A0A0A; color:#fff; min-height:100vh; display:grid; place-items:center; padding:6rem 6vw; font-family:'Archivo',sans-serif; overflow:hidden; }
.kshd-canvas { position:absolute; inset:0; width:100%; height:100%; display:block; }
.kshd-card { position:relative; max-width:54rem; }
.kshd-tag { font-family:'JetBrains Mono',monospace; font-size:.78rem; letter-spacing:.18em; color:#C8FF00; }
.kshd-q { font-family:'Archivo Black','Archivo',sans-serif; font-weight:900; font-size:clamp(2rem,5vw,4.4rem); line-height:1; letter-spacing:-.03em; margin:1.2rem 0 1.4rem; text-transform:uppercase; mix-blend-mode:difference; color:#fff; }
.kshd-foot { display:flex; gap:1.2rem; align-items:baseline; font-family:'JetBrains Mono',monospace; font-size:.85rem; letter-spacing:.14em; text-transform:uppercase; }
.kshd-foot strong { color:#FF5C3A; }
.kshd-foot span { color:rgba(255,255,255,.7); }