Inktdruppel die zich in water uitspreidt New
Click or tap anywhere and a drop of ink falls into clear water: it blooms, sinks in tendrils and slowly dissolves, alternating black and orange. For the hero of a drawing studio, print shop, tattoo studio or art lending service, or as a calm background on a workshop page. Canvas 2D, pauses off screen; with reduced motion the stain appears at once.
Workshop inkt en water
Zaterdag 9 november · Haarlem · € 45
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.
<!-- Inktdruppel die zich in water uitspreidt · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie -->
<div class="jouw-container">
<div class="ikw">
<canvas class="ikw__cv" aria-hidden="true"></canvas>
<div class="ikw__txt"><p class="ikw__h">Workshop inkt en water</p><p class="ikw__p">Zaterdag 9 november · Haarlem · € 45</p></div>
<button class="ikw__btn" type="button">Laat een druppel vallen</button>
</div>
</div>/* Inktdruppel die zich in water uitspreidt · © 2026 NedDev BV · NedDev Lab-licentie (gratis gebruik, niet doorverkopen) · neddev.com/nl/lab/gebruik/#licentie */
.ikw{position:absolute;inset:0;background:linear-gradient(180deg,#fff 0%,#f4f3f1 100%);cursor:crosshair;font-family:Switzer,sans-serif;color:#0a0a0a;overflow:hidden}
.ikw__cv{position:absolute;inset:0;width:100%;height:100%;display:block}
.ikw__txt{position:absolute;left:16px;bottom:14px;right:16px;pointer-events:none}
.ikw__h{margin:0;font:600 18px/1.2 Switzer,sans-serif}
.ikw__p{margin:4px 0 0;font:400 14px/1.35 Switzer,sans-serif;color:#3a3a3a}
.ikw__btn{position:absolute;top:14px;right:14px}
.ikw__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}
.ikw__btn:hover{background:#F5480F;color:#0a0a0a}
.ikw__btn:focus-visible{outline:2px solid #F5480F;outline-offset:3px}
@media (prefers-reduced-motion: reduce){.ikw__btn{transition:none}}// Inktdruppel die zich in water uitspreidt · © 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('.ikw'), cv = w.querySelector('.ikw__cv'), ctx = cv.getContext('2d'), btn = w.querySelector('.ikw__btn');
var W = 1, H = 1, ps = [], n = 0, t = 0, MAX = 2200;
var cols = ['10,10,10', '245,72,15'];
fit(cv, ctx, function (a, b) { W = a; H = b; draw(); });
function drop(x, y) {
var c = cols[n++ % 2];
for (var i = 0; i < 46; i++) {
var a = Math.random() * 6.283, s = 15 + Math.random() * Math.random() * 90;
ps.push({ x: x, y: y, vx: Math.cos(a) * s, vy: Math.sin(a) * s * .5, r: 1.2 + Math.random() * 1.4, c: c, life: 0, max: 2.2 + Math.random() * 2.4, seed: Math.random() * 50, kid: 0, p: 1 });
}
ps.push({ x: x, y: y, vx: 0, vy: 4, r: 4, g: 6, a0: .26, c: c, life: 0, max: 6.5, p: 0 });
if (ps.length > MAX) ps.splice(0, ps.length - MAX);
if (reduce) { for (var k = 0; k < 75; k++) upd(1 / 30); draw(); }
}
function upd(dt) {
t += dt;
for (var i = ps.length - 1; i >= 0; i--) {
var p = ps[i]; p.life += dt;
if (p.life > p.max) { ps.splice(i, 1); continue; }
if (p.p) {
var k = Math.exp(-1.6 * dt); p.vx *= k; p.vy *= k; p.vy += 30 * dt;
var sw = Math.sin(p.y * .05 + t * .9 + p.seed) * 28, sv = Math.cos(p.x * .045 - t * .7 + p.seed) * 12;
p.x += (p.vx + sw) * dt; p.y += (p.vy + sv) * dt; p.kid -= dt;
if (p.kid <= 0) { p.kid = .055; ps.push({ x: p.x, y: p.y, vx: sw * .08, vy: 3 + Math.random() * 4, r: p.r, g: 2.5 + Math.random() * 4, a0: .085, life: 0, max: 3.5 + Math.random() * 2.5, c: p.c, p: 0 }); }
} else { p.x += p.vx * dt; p.y += p.vy * dt; p.r += p.g * dt * (1 - p.life / p.max); }
}
}
function draw() {
ctx.clearRect(0, 0, W, H);
for (var i = 0; i < ps.length; i++) {
var p = ps[i], f = 1 - p.life / p.max;
var a = p.p ? .45 * f : p.a0 * f * Math.min(1, p.life * 6);
if (a < .004) continue;
ctx.fillStyle = 'rgba(' + p.c + ',' + a.toFixed(3) + ')';
ctx.beginPath(); ctx.arc(p.x, p.y, p.r, 0, 6.283); ctx.fill();
}
}
w.addEventListener('pointerdown', function (e) {
if (e.target.closest('.ikw__btn')) return;
var r = w.getBoundingClientRect(); drop(e.clientX - r.left, e.clientY - r.top);
});
btn.addEventListener('click', function () { drop(W * (.25 + Math.random() * .5), H * (.2 + Math.random() * .25)); });
loop(w, function (dt) { if (reduce || !ps.length) return; upd(dt); draw(); });
setTimeout(function () { drop(W * .62, H * .28); }, 120);
setTimeout(function () { drop(W * .4, H * .22); }, 700);
}
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 →