Particle Constellation
Floating nodes linked by lines that light up 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.
<!-- Particle Constellation · 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>/* Particle Constellation · NedDev · eigen werk. */
.pc-stage{position:relative;width:100%;height:100%;background:radial-gradient(120% 120% at 70% 10%,#141414,#0a0a0a);overflow:hidden}.pc-stage canvas{position:absolute;inset:0;width:100%;height:100%;display:block}// Particle Constellation · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
root.classList.add('pc-stage');var reduce=matchMedia('(prefers-reduced-motion:reduce)').matches;var c=document.createElement('canvas');root.appendChild(c);var ctx=c.getContext('2d');var dpr=Math.min(devicePixelRatio||1,2),W=0,H=0,parts=[],run=false;var mouse={x:-999,y:-999};
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);var n=Math.min(70,Math.round(W*H/12000));parts=[];for(var i=0;i<n;i++)parts.push({x:Math.random()*W,y:Math.random()*H,vx:(Math.random()-.5)*.25,vy:(Math.random()-.5)*.25});}
new ResizeObserver(size).observe(root);size();
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 step(){if(!run)return;ctx.clearRect(0,0,W,H);for(var k=0;k<parts.length;k++){var p=parts[k];if(!reduce){p.x+=p.vx;p.y+=p.vy;}if(p.x<0||p.x>W)p.vx*=-1;if(p.y<0||p.y>H)p.vy*=-1;var dm=Math.hypot(p.x-mouse.x,p.y-mouse.y);var near=dm<140;ctx.beginPath();ctx.arc(p.x,p.y,near?2.6:1.6,0,7);ctx.fillStyle=near?'#F5480F':'rgba(255,255,255,.55)';ctx.fill();}
for(var i=0;i<parts.length;i++)for(var j=i+1;j<parts.length;j++){var a=parts[i],b=parts[j];var d=Math.hypot(a.x-b.x,a.y-b.y);if(d<110){var md=Math.hypot((a.x+b.x)/2-mouse.x,(a.y+b.y)/2-mouse.y);var hot=md<150;ctx.beginPath();ctx.moveTo(a.x,a.y);ctx.lineTo(b.x,b.y);ctx.strokeStyle=hot?'rgba(245,72,15,'+(.5*(1-d/110))+')':'rgba(255,255,255,'+(.14*(1-d/110))+')';ctx.lineWidth=hot?1.1:.6;ctx.stroke();}}
if(!reduce)requestAnimationFrame(step);}
new IntersectionObserver(function(es){var v=es[0].isIntersecting;if(v&&!run){run=true;requestAnimationFrame(step);}else if(!v)run=false;}).observe(root);if(reduce){run=true;step();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 →