1. Mechanisme — kopieer 1-op-1, geen styling-keuzes
// Mechanisme: footer-noise-bg-brutalist
// Hard-stepped grayscale noise (4 levels) — Canvas2D, rAF.
// Fallback: SVG <feTurbulence> data-uri op de container.
(()=>{const reduce=window.matchMedia('(prefers-reduced-motion: reduce)').matches;
const cv=document.querySelector('.noise-canvas-brut');if(!cv)return;
const ctx=cv.getContext('2d');const dpr=Math.min(window.devicePixelRatio||1,2);
const fit=()=>{cv.width=cv.offsetWidth*dpr;cv.height=cv.offsetHeight*dpr;};fit();
const STEPS=[0,85,170,255];const draw=()=>{const d=ctx.createImageData(cv.width,cv.height);
for(let i=0;i<d.data.length;i+=4){const v=STEPS[Math.random()*4|0];d.data[i]=d.data[i+1]=d.data[i+2]=v;d.data[i+3]=255;}ctx.putImageData(d,0,0);};
if(reduce){draw();return;}let raf=0;const tick=()=>{draw();raf=requestAnimationFrame(tick);};raf=requestAnimationFrame(tick);
window.addEventListener('resize',()=>{cancelAnimationFrame(raf);fit();raf=requestAnimationFrame(tick);});})(); 2. Skeleton — DOM + class-namen, mag herschikken
<!-- Skeleton: footer-noise-bg-brutalist -->
<footer class="ft-brut">
<div class="ft-brut-noise" aria-hidden="true">
<canvas class="noise-canvas-brut"></canvas>
</div>
<div class="ft-brut-marquee"><span>BLURR · MOTION · LAB · </span><span>BLURR · MOTION · LAB · </span></div>
<div class="ft-brut-meta">2026 / NO COOKIES / NO BS</div>
</footer> 3. Styling-template — verplicht eigen invulling per merk
/* Styling: footer-noise-bg-brutalist */
:root { --brut-bg:#0A0A0A; --brut-fg:#F2F2F2; --brut-accent:#FF4500; }