Notes / Quiet
A surface that whispers rather than shouts. The grain is barely there — under one percent ink — present only when the eye searches for it. Otherwise it sits behind the words like a held breath.
Houdini paint worklets let the browser draw this texture procedurally, without an image asset, without a network request. The fallback is an SVG data-uri, also weightless, also quiet.
Negative space does the rest of the work.
// Mechanisme: content-houdini-paint-quiet // Houdini paint worklet (technique #42) — subtle dot/cross hatch, sub-1% opacity ink. // Loaded via Blob URL to avoid extra HTTP. SVG data-uri fallback when Houdini unsupported. import gsap from 'https://esm.sh/[email protected]'; import{ScrollTrigger}from 'https://esm.sh/[email protected]/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger); const workletCode = `registerPaint('quiet-grain',class{static get inputProperties(){return['--grain-ink','--grain-step']}paint(ctx,geom,props){const ink=(props.get('--grain-ink').toString()||'rgba(10,10,10,.06)').trim();const step=parseFloat(props.get('--grain-step').toString())||14;ctx.fillStyle=ink;for(let y=0;y<geom.height;y+=step){for(let x=0;x<geom.width;x+=step){ctx.fillRect(x,y,1,1);ctx.fillRect(x+step/2,y+step/2,1,1)}}}});`; if(window.CSS&&CSS.paintWorklet){ const url=URL.createObjectURL(new Blob([workletCode],{type:'text/javascript'})); CSS.paintWorklet.addModule(url).catch(()=>{}); }else{ // SVG dot-pattern data-uri fallback const svg='data:image/svg+xml;utf8,'+encodeURIComponent('<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14"><circle cx="1" cy="1" r="0.6" fill="rgba(10,10,10,0.06)"/><circle cx="8" cy="8" r="0.6" fill="rgba(10,10,10,0.06)"/></svg>'); document.querySelectorAll('.quiet-paint').forEach(el=>{el.style.backgroundImage='url("'+svg+'")';el.style.backgroundRepeat='repeat';}); } if(!window.matchMedia('(prefers-reduced-motion: reduce)').matches){ ScrollTrigger.batch('.quiet-reveal',{ onEnter:b=>gsap.fromTo(b,{autoAlpha:0,y:18},{autoAlpha:1,y:0,duration:1.6,ease:'power1.out',stagger:0.1}), start:'top 88%',once:true }); }
<!-- Skeleton: content-houdini-paint-quiet -->
<section class="quiet-paint">
<div class="col">
<p class="eyebrow">Eyebrow</p>
<h2 class="quiet-reveal">Headline in serif</h2>
<p class="quiet-reveal">Body paragraph...</p>
<p class="quiet-reveal">Body paragraph...</p>
</div>
</section> /* Styling: content-houdini-paint-quiet */
:root {
--block-bg: #F4F1EB;
--block-fg: #0A0A0A;
--block-accent: rgba(10,10,10,.06);
--grain-ink: rgba(10,10,10,.06);
--grain-step: 14;
}
.quiet-paint {
background: paint(quiet-grain), #F4F1EB;
background-color: #F4F1EB;
}