ASCII Halftone Hover
Image dissolves into ASCII glyphs, sharpens around the cursor.
How to use it
- Paste the HTML where the backgrounds & webgl should appear. Include the script tags at the top once per page.
- Add the CSS to your stylesheet. All classes are prefixed, so nothing clashes with your own styles.
- Add the JavaScript and call init() with the element that contains the HTML.
<!-- ASCII Halftone Hover · NedDev · eigen werk. -->
<!-- benodigd, één keer per pagina: -->
<script type="module">import * as OGL from "https://esm.sh/ogl@1.0.11"; window.OGL = OGL;</script>
<div class="jouw-container">
</div>/* ASCII Halftone Hover · NedDev · eigen werk. */
.ah-stage{position:relative;width:100%;height:100%;background:#0a0a0a;overflow:hidden;cursor:crosshair}.ah-stage canvas{position:absolute;inset:0;width:100%;height:100%;display:block}.ah-hint{position:absolute;bottom:10px;left:12px;font:700 10px/1 'JetBrains Mono',monospace;letter-spacing:.3em;color:#F5480F;pointer-events:none;z-index:2}// ASCII Halftone Hover · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root.classList.add('ah-stage');var reduce=matchMedia('(prefers-reduced-motion:reduce)').matches;var hint=document.createElement('div');hint.className='ah-hint';hint.textContent='HOVER';root.appendChild(hint);var c=document.createElement('canvas');root.appendChild(c);var ctx=c.getContext('2d');var chars=' .:-=+*#%@';var W=0,H=0,dpr=Math.min(devicePixelRatio||1,2),run=false,t=0,cell=12;
function size(){var r=root.getBoundingClientRect();W=r.width;H=r.height;c.width=W*dpr;c.height=H*dpr;ctx.setTransform(dpr,0,0,dpr,0,0);}new ResizeObserver(size).observe(root);size();
var mouse={x:-999,y:-999};root.addEventListener('pointermove',function(e){var r=root.getBoundingClientRect();mouse.x=e.clientX-r.left;mouse.y=e.clientY-r.top;});root.addEventListener('pointerleave',function(){mouse.x=mouse.y=-999;});
function draw(){if(!run)return;t+=reduce?0:.02;ctx.clearRect(0,0,W,H);ctx.font=cell+'px monospace';ctx.textBaseline='top';var cx=W/2,cy=H/2,maxd=Math.hypot(cx,cy);for(var y=0;y<H;y+=cell){for(var x=0;x<W;x+=cell){var dc=Math.hypot(x-cx,y-cy)/maxd;var lum=1-dc+Math.sin((x*.02)+(y*.02)+t)*.15;var dm=Math.hypot(x-mouse.x,y-mouse.y);var boost=Math.max(0,1-dm/160);lum=Math.min(1,lum*.6+boost*.9);var ci=Math.max(0,Math.min(chars.length-1,Math.floor(lum*(chars.length-1))));if(ci===0)continue;ctx.fillStyle=boost>.15?'rgba(245,72,15,'+(.5+boost*.5)+')':'rgba(255,255,255,'+(.25+lum*.45)+')';ctx.fillText(chars[ci],x,y);}}if(!reduce)requestAnimationFrame(draw);}
new IntersectionObserver(function(es){var v=es[0].isIntersecting;if(v&&!run){run=true;requestAnimationFrame(draw);}else if(!v)run=false;}).observe(root);if(reduce){run=true;draw();run=false;}
}
init(document.querySelector('.jouw-container'));
More backgrounds & webgl
Seen something you like?
Add it to your selection and send it over. We build your site around it, in your brand.
Get in touch →