Sneeuwbol met winteractie Nieuw
Een sneeuwbol met de werkplaats van een fietsenmaker erin: sleep de bol heen en weer of gebruik de knop, de vlokken reageren op de versnelling van de bol, dwarrelen en blijven op de grond liggen. Na genoeg schudden verschijnt de actiecode. Voor een seizoensactie in de wintermaanden, zoals een banden- of onderhoudsweek bij een fietsenmaker of garage. Bij minder beweging ligt de sneeuw stil en toont de knop direct de code.
Winterklaar bij De Spaak
Fietsenmaker in Groningen. Schud voor je winteractie.
Zo gebruik je het
- Plak de HTML op de plek waar het onderdeel moet komen.
- Zet de CSS in je stylesheet. Alle klassen hebben een eigen voorvoegsel, dus niets botst met je eigen opmaak.
- Voeg de JavaScript toe en roep init() aan met het element waar de HTML in staat.
<!-- Sneeuwbol met winteractie · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="fys">
<div class="fys__staan"><div class="fys__bol" aria-hidden="true"><canvas class="fys__c"></canvas></div><span class="fys__voet" aria-hidden="true"></span></div>
<div class="fys__tekst">
<h3 class="fys__h">Winterklaar bij De Spaak</h3>
<p class="fys__p">Fietsenmaker in Groningen. Schud voor je winteractie.</p>
<button class="fys__knop" type="button">Schud de bol</button>
<p class="fys__code" aria-live="polite"></p>
</div>
</div>
</div>/* Sneeuwbol met winteractie · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.fys{position:absolute;inset:0;display:flex;align-items:center;gap:14px;padding:12px 16px;background:#f4f3f1;color:#0a0a0a;font-family:'Switzer',sans-serif;text-align:left;overflow:hidden}
.fys *{box-sizing:border-box}
.fys__staan{flex:0 0 auto;display:flex;flex-direction:column;align-items:center}
.fys__bol{position:relative;width:150px;height:150px;border-radius:50%;overflow:hidden;cursor:grab;touch-action:none;will-change:transform;box-shadow:inset 0 0 0 3px #0a0a0a}
.fys__bol:active{cursor:grabbing}
.fys__c{display:block;width:100%;height:100%}
.fys__voet{display:block;width:70%;height:22px;margin-top:-10px;background:#0a0a0a;clip-path:polygon(8% 0,92% 0,100% 100%,0 100%);border-radius:0 0 4px 4px}
.fys__tekst{flex:1;min-width:0;display:flex;flex-direction:column;align-items:flex-start;gap:6px}
.fys__h{margin:0;font:700 18px/1.15 'Switzer',sans-serif;letter-spacing:-.015em}
.fys__p{margin:0;font:400 13px/1.4 'Switzer',sans-serif;color:#3d3b37}
.fys__knop{margin-top:2px;padding:9px 13px;border:0;border-radius:4px;background:#0a0a0a;color:#fff;font:600 13px/1 'Switzer',sans-serif;cursor:pointer;transition:background-color .16s,color .16s}
.fys__knop:hover{background:#F5480F;color:#0a0a0a}
.fys__knop:focus-visible{outline:2px solid #F5480F;outline-offset:2px}
.fys__code{margin:0;min-height:18px;font:600 13px/1.35 'Switzer',sans-serif}// Sneeuwbol met winteractie · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie
// root = het element waarin de HTML staat
function init(root){
var el=root.querySelector('.fys');if(!el)return;
var RM=window.matchMedia&&window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var bol=el.querySelector('.fys__bol'),cv=el.querySelector('.fys__c'),ctx=cv.getContext('2d'),knop=el.querySelector('.fys__knop'),code=el.querySelector('.fys__code');
var D=140,R=70,dpr=1,F=[],NF=90,gx=0,gy=0,gvx=0,gvy=0,pgvx=0,pgvy=0,drag=false,sx=0,sy=0,raf=0,last=0,vis=true,energie=0,getoond=false,schud=[],stil=0;
function grond(x){return R*.52-Math.cos(x/R*1.3)*R*.06;}
function maat(){var r=el.getBoundingClientRect();if(!r.width)return false;D=Math.round(Math.max(110,Math.min(r.height*.66,r.width*.38)));R=D/2;bol.style.width=bol.style.height=D+'px';
dpr=Math.min(2,window.devicePixelRatio||1);cv.width=D*dpr;cv.height=D*dpr;ctx.setTransform(dpr,0,0,dpr,0,0);return true;}
function vlok(i){var a=Math.random()*Math.PI*2,rr=Math.sqrt(Math.random())*(R-6);return{x:Math.cos(a)*rr,y:Math.sin(a)*rr*.8-R*.15,vx:0,vy:0,r:.9+Math.random()*1.5,lig:false};}
function vul(){F=[];for(var i=0;i<NF;i++)F.push(vlok(i));if(RM)F.forEach(function(f,i){if(i%3){f.x=(Math.random()*2-1)*(R*.8);f.y=grond(f.x)-Math.random()*2;f.lig=true;}});}
function teken(){ctx.clearRect(0,0,D,D);ctx.save();ctx.translate(R,R);ctx.fillStyle='#16181a';ctx.beginPath();ctx.arc(0,0,R,0,Math.PI*2);ctx.fill();
ctx.fillStyle='#2b2e31';ctx.beginPath();ctx.moveTo(-R,R);for(var x=-R;x<=R;x+=4)ctx.lineTo(x,grond(x));ctx.lineTo(R,R);ctx.closePath();ctx.fill();
var hw=R*.5,hb=grond(0),hh=R*.36;ctx.fillStyle='#F5480F';ctx.beginPath();ctx.moveTo(-hw/2,hb);ctx.lineTo(-hw/2,hb-hh);ctx.lineTo(0,hb-hh-R*.22);ctx.lineTo(hw/2,hb-hh);ctx.lineTo(hw/2,hb);ctx.closePath();ctx.fill();
ctx.fillStyle='#0a0a0a';ctx.fillRect(-hw*.12,hb-hh*.55,hw*.24,hh*.55);ctx.fillStyle='#f4f3f1';ctx.fillRect(hw*.2,hb-hh*.78,hw*.16,hh*.22);ctx.fillRect(-hw*.36,hb-hh*.78,hw*.16,hh*.22);
ctx.strokeStyle='#f4f3f1';ctx.lineWidth=1.4;var wy=hb-5,wx=-R*.52;ctx.beginPath();ctx.arc(wx,wy,5,0,Math.PI*2);ctx.moveTo(wx+19,wy);ctx.arc(wx+14,wy,5,0,Math.PI*2);ctx.moveTo(wx,wy);ctx.lineTo(wx+7,wy-7);ctx.lineTo(wx+14,wy);ctx.stroke();
ctx.fillStyle='#fff';for(var i=0;i<F.length;i++){var f=F[i];ctx.globalAlpha=f.lig?.95:.85;ctx.beginPath();ctx.arc(f.x,f.y,f.r,0,Math.PI*2);ctx.fill();}ctx.globalAlpha=1;ctx.restore();}
function stap(dt){var ax=(gvx-pgvx)/dt,ay=(gvy-pgvy)/dt;pgvx=gvx;pgvy=gvy;var am=Math.hypot(ax,ay);
if(!drag){gvx+=(-gx*160-gvx*9)*dt;gvy+=(-gy*160-gvy*9)*dt;gx+=gvx*dt;gy+=gvy*dt;}
if(schud.length&&performance.now()>=schud[0].t){var s=schud.shift();gvx+=s.v;gvy+=s.v*.25;}
if(am>900)energie+=am*dt*.001;if(energie>2.2&&!getoond){getoond=true;toon();}
var lim=R-4,dr=Math.exp(-2.4*dt);
for(var i=0;i<F.length;i++){var f=F[i];
if(f.lig){if(am>1400&&Math.random()<.5){f.lig=false;f.vx=-ax*.03*(.5+Math.random());f.vy=-ay*.03*(.5+Math.random())-Math.random()*60;}else continue;}
f.vx+=(-ax*.016+Math.sin(f.y*.07+i)*6)*dt;f.vy+=(-ay*.016+22)*dt;f.vx*=dr;f.vy*=dr;f.x+=f.vx*dt;f.y+=f.vy*dt;
var d=Math.hypot(f.x,f.y);if(d>lim){var nx=f.x/d,ny=f.y/d;f.x=nx*lim;f.y=ny*lim;var vn=f.vx*nx+f.vy*ny;if(vn>0){f.vx-=1.3*vn*nx;f.vy-=1.3*vn*ny;}}
var gy2=grond(f.x)-f.r*.6;if(f.y>gy2){f.y=gy2;if(Math.abs(f.vx)+Math.abs(f.vy)<40){f.lig=true;f.vx=f.vy=0;}else{f.vy=-Math.abs(f.vy)*.2;}}}
bol.style.transform='translate('+gx.toFixed(1)+'px,'+gy.toFixed(1)+'px) rotate('+(gx*.35).toFixed(2)+'deg)';}
function tick(t){if(!vis){raf=0;return;}var dt=Math.min(.033,(t-last)/1000)||.016;last=t;stap(dt);teken();
var rust=!drag&&!schud.length&&Math.abs(gx)+Math.abs(gy)<.2&&F.every(function(f){return f.lig;});if(rust){if(++stil>30){raf=0;return;}}else stil=0;raf=requestAnimationFrame(tick);}
function kick(){if(RM||raf)return;stil=0;last=performance.now();raf=requestAnimationFrame(tick);}
function toon(){code.textContent='Code winter15: 15% op winterbanden, t/m 31 januari.';}
bol.addEventListener('pointerdown',function(e){if(RM||e.button>0)return;drag=true;sx=e.clientX-gx;sy=e.clientY-gy;try{bol.setPointerCapture(e.pointerId);}catch(_){}kick();});
bol.addEventListener('pointermove',function(e){if(!drag)return;var nx=Math.max(-22,Math.min(22,e.clientX-sx)),ny=Math.max(-14,Math.min(14,e.clientY-sy)),dt=1/60;gvx=(nx-gx)/dt;gvy=(ny-gy)/dt;gx=nx;gy=ny;});
function los(){drag=false;}bol.addEventListener('pointerup',los);bol.addEventListener('pointercancel',los);
knop.addEventListener('click',function(){if(RM){toon();return;}var t=performance.now();schud=[];[0,130,260,390,520].forEach(function(d,i){schud.push({t:t+d,v:(i%2?-1:1)*900});});kick();});
if(maat()){vul();teken();kick();}
if('ResizeObserver' in window)new ResizeObserver(function(){var o=D;if(maat()&&o!==D){vul();teken();}}).observe(el);
if('IntersectionObserver' in window)new IntersectionObserver(function(es){vis=es[0].isIntersecting;if(vis)kick();}).observe(el);
}
init(document.querySelector('.jouw-container'));
Meer uit componenten
Iets gezien dat je mooi vindt?
Zet het in je selectie en stuur hem op. Dan bouwen we je site eromheen, in jouw huisstijl.
Neem contact op →