A WebGL fragment shader that rebuilds any photograph out of horizontal and vertical rules. Tone is sampled once per grid cell, then built up by interleaving lines between the ones already there, so the marks stay on a square lattice and read as constructed rather than photographic. Interactive: the cursor tightens the lattice until the photo resolves, and pools amber into the ink.
The preview above and any production embed use the same custom element. Tune, click Copy embed code, paste. Attributes stream through attributeChangedCallback, so you can also bind them from any framework.
<!-- paste into any HTML/JSX -->
<cross-hatch
src="/handshake.jpg"
grid="32"
levels="4"
weight="0.22"
contrast="1.05"
exposure="0.16"
bleed="0.85"
focus="0.5"
angle="0"
ink="#0A0A0A"
paper="#EFEBDD"
accent="#DF8E2A"
style="display:block; width:100%; aspect-ratio:32/9;"
></cross-hatch>
<script src="/cross-hatch.js" defer></script>Ship cross-hatch.js from your public assets (~5KB gzipped, zero dependencies). Works in React 19, Vue, Svelte, or plain HTML. The component pauses rAF when off-screen, stops the loop when mouse easing settles, and respects prefers-reduced-motion.