// Mechanisme: content-houdini-paint-brutalist
// Houdini Paint Worklet — registreer via blob-URL (geen extern bestand nodig).
const workletCode = `
registerPaint('brutal-grid', class {
static get inputProperties() { return ['--grid-bg','--grid-fg','--grid-density','--grid-seed']; }
paint(ctx, size, props) {
const bg = (props.get('--grid-bg').toString() || '#F4F1EB').trim();
const fg = (props.get('--grid-fg').toString() || '#0A0A0A').trim();
const density = parseInt(props.get('--grid-density').toString()) || 14;
let seed = parseInt(props.get('--grid-seed').toString()) || 7;
const rand = () => { seed = (seed * 9301 + 49297) % 233280; return seed / 233280; };
ctx.fillStyle = bg; ctx.fillRect(0, 0, size.width, size.height);
ctx.fillStyle = fg;
for (let i = 0; i < density; i++) {
const w = Math.floor(rand() * size.width * 0.5) + 40;
const h = Math.floor(rand() * size.height * 0.4) + 30;
const x = Math.floor(rand() * size.width) - w/2;
const y = Math.floor(rand() * size.height) - h/2;
ctx.fillRect(x, y, w, h);
}
}
});`;
if ('paintWorklet' in CSS) {
const blob = new Blob([workletCode], { type: 'text/javascript' });
CSS.paintWorklet.addModule(URL.createObjectURL(blob));
}
// Tekst-reveal (brutal & instant): stagger 0.03, duration 0.5, power4.out.
import gsap from 'https://esm.sh/gsap@3.12.5';
import { ScrollTrigger } from 'https://esm.sh/gsap@3.12.5/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
if (!window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
gsap.fromTo('.brutal-line', { yPercent: 110, autoAlpha: 0 },
{ yPercent: 0, autoAlpha: 1, duration: 0.55, stagger: 0.03, ease: 'power4.out',
scrollTrigger: { trigger: '.brutal-stage', start: 'top 80%', once: true } });
} <!-- Skeleton: content-houdini-paint-brutalist -->
<section class="brutal-stage">
<div class="brutal-paint"></div>
<div class="brutal-content">
<p class="brutal-meta">// content / houdini paint / brutalist</p>
<h2><span class="brutal-line">RAW</span><span class="brutal-line">SYSTEM</span><span class="brutal-line">NO APOLOGIES.</span></h2>
<p class="brutal-body">Hard edges. No gradients. No softness. The grid is the message.</p>
</div>
</section> /* Styling: content-houdini-paint-brutalist */
:root {
--block-bg: #F4F1EB;
--block-fg: #0A0A0A;
--block-accent: #0A0A0A;
}
.brutal-stage { position: relative; min-height: 80vh; isolation: isolate; }
.brutal-paint {
position: absolute; inset: 0; z-index: 0;
--grid-bg: #F4F1EB; --grid-fg: #0A0A0A;
--grid-density: 16; --grid-seed: 7;
background: paint(brutal-grid);
/* Fallback: brutal repeating bands wanneer Houdini ontbreekt */
background:
repeating-linear-gradient(90deg, #0A0A0A 0 14vw, transparent 14vw 22vw),
repeating-linear-gradient(0deg, #0A0A0A 0 9vw, transparent 9vw 18vw),
#F4F1EB;
}
@supports (background: paint(brutal-grid)) {
.brutal-paint { background: paint(brutal-grid); }
}
@media (prefers-reduced-motion: reduce) {
.brutal-line { transform: none !important; opacity: 1 !important; }
}