Gras dat wegbuigt voor je muis New
A strip of grass with the odd orange flower sways in the wind and bends aside where your mouse or finger passes, then springs back. For the hero or quote button of a landscaper, lawnmower shop, campsite, petting farm or sports park. Canvas 2D with a few hundred blades, vertical scrolling on a phone keeps working; with reduced motion the grass stands still.
How to use it
- Paste the HTML where the backgrounds & webgl should appear.
- 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.
<!-- Gras dat wegbuigt voor je muis · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="grb">
<canvas class="grb__cv" aria-hidden="true"></canvas>
<div class="grb__txt"><p class="grb__h">Hoveniersbedrijf Groenvast, Apeldoorn</p><p class="grb__p">Nieuw gazon aanleggen vanaf € 18 per m²</p><a class="grb__btn" href="#">Vraag een offerte</a></div>
</div>
</div>/* Gras dat wegbuigt voor je muis · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.grb{position:absolute;inset:0;background:#f4f3f1;font-family:Switzer,sans-serif;color:#0a0a0a;overflow:hidden}
.grb__cv{position:absolute;inset:0;width:100%;height:100%;display:block;touch-action:pan-y}
.grb__txt{position:absolute;left:16px;top:14px;right:16px;pointer-events:none}
.grb__h{margin:0;font:600 18px/1.2 Switzer,sans-serif}
.grb__p{margin:4px 0 10px;font:400 14px/1.35 Switzer,sans-serif;color:#3a3a3a}
.grb__btn{pointer-events:auto}
.grb__btn{display:inline-flex;align-items:center;min-height:36px;padding:0 14px;border:0;border-radius:4px;font:600 14px/1 Switzer,sans-serif;cursor:pointer;text-decoration:none;background:#0a0a0a;color:#fff;transition:background-color .18s,color .18s}
.grb__btn:hover{background:#F5480F;color:#0a0a0a}
.grb__btn:focus-visible{outline:2px solid #F5480F;outline-offset:3px}
@media (prefers-reduced-motion: reduce){.grb__btn{transition:none}}// Gras dat wegbuigt voor je muis · © 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 reduce=!!(window.matchMedia&&matchMedia('(prefers-reduced-motion: reduce)').matches);
function fit(cv,ctx,cb){var dpr=Math.min(window.devicePixelRatio||1,2);function f(){var r=cv.getBoundingClientRect();var w=Math.max(1,Math.round(r.width)),h=Math.max(1,Math.round(r.height));if(cv.width===Math.round(w*dpr)&&cv.height===Math.round(h*dpr))return;cv.width=Math.round(w*dpr);cv.height=Math.round(h*dpr);if(ctx)ctx.setTransform(dpr,0,0,dpr,0,0);if(cb)cb(w,h,dpr);}if(window.ResizeObserver)new ResizeObserver(f).observe(cv);f();}
function loop(el,step){var on=false,raf=0,last=0;function fr(t){raf=requestAnimationFrame(fr);var dt=last?Math.min(.05,(t-last)/1000):.016;last=t;step(dt,t/1000);}function go(v){if(v&&!on){on=true;last=0;raf=requestAnimationFrame(fr);}else if(!v&&on){on=false;cancelAnimationFrame(raf);}}if(window.IntersectionObserver)new IntersectionObserver(function(es){go(es[0].isIntersecting);}).observe(el);else go(true);}
var w = root.querySelector('.grb'), cv = w.querySelector('.grb__cv'), ctx = cv.getContext('2d');
var W = 1, H = 1, bl = [], t = 0, mx = -999, my = -999;
var COL = ['#9dbb6e', '#6f9a48', '#4f7f33', '#3a6526'];
function make() {
bl = []; var fh = H * .42;
for (var row = 0; row < 2; row++) {
var n = Math.round(W / (row ? 2.6 : 3.6));
for (var i = 0; i < n; i++) {
var h = fh * (row ? .55 + Math.random() * .45 : .4 + Math.random() * .35);
bl.push({ x: Math.random() * W, h: h, wb: 1.4 + Math.random() * 2.2, c: row ? 1 + Math.floor(Math.random() * 3) : Math.floor(Math.random() * 2), a: 0, v: 0, ph: Math.random() * 6.283, fl: row && Math.random() < .03 });
}
}
bl.sort(function (a, b) { return a.c - b.c; });
}
function draw() {
ctx.clearRect(0, 0, W, H);
var flowers = [];
for (var c = 0; c < COL.length; c++) {
ctx.fillStyle = COL[c]; ctx.beginPath();
for (var i = 0; i < bl.length; i++) {
var b = bl[i]; if (b.c !== c) continue;
var tx = b.x + Math.sin(b.a) * b.h, ty = H - Math.cos(b.a) * b.h, cx = b.x + Math.sin(b.a * .5) * b.h * .5, cy = H - b.h * .55;
ctx.moveTo(b.x - b.wb, H); ctx.quadraticCurveTo(cx - b.wb * .4, cy, tx, ty); ctx.quadraticCurveTo(cx + b.wb * .4, cy, b.x + b.wb, H); ctx.closePath();
if (b.fl) flowers.push(tx, ty);
}
ctx.fill();
}
ctx.fillStyle = '#F5480F';
for (var k = 0; k < flowers.length; k += 2) { ctx.beginPath(); ctx.arc(flowers[k], flowers[k + 1], 3.6, 0, 6.283); ctx.fill(); }
}
fit(cv, ctx, function (a, b) { W = a; H = b; make(); draw(); });
cv.addEventListener('pointermove', function (e) { var r = cv.getBoundingClientRect(); mx = e.clientX - r.left; my = e.clientY - r.top; });
cv.addEventListener('pointerleave', function () { mx = my = -999; });
w.querySelector('.grb__btn').addEventListener('click', function (e) { e.preventDefault(); });
loop(w, function (dt) {
if (reduce) return; t += dt;
var gust = Math.max(0, Math.sin(t * .45)) * .12;
for (var i = 0; i < bl.length; i++) {
var b = bl[i], tgt = Math.sin(t * 1.5 + b.x * .015 + b.ph * .2) * .09 + gust * Math.sin(t * .9 + b.x * .004);
var dx = b.x - mx;
if (Math.abs(dx) < 80 && my > H - b.h - 40) tgt += (dx > 0 ? 1 : -1) * (1 - Math.abs(dx) / 80) * .95;
b.v += (tgt - b.a) * 34 * dt; b.v *= Math.exp(-6 * dt); b.a += b.v * dt;
}
draw();
});
}
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 →