Components / KATAYABURI / Goo Cursor
Goo Cursor beta
A slime that follows the cursor: blobs with surface tension, courtesy of an SVG goo filter.
Move through the stage. It follows like it means it.
<div class="k-goo" data-goo role="img" aria-label="A gooey slime that follows the cursor"> <div class="k-goo-field"></div> <p>Move through the stage. It follows like it means it.</p> </div>
/* KATA Goo Cursor — KATAYABURI. Surface tension as a service. */
.k-goo{position:relative;width:100%;background:var(--k-zinc-950);border-radius:14px;overflow:hidden;height:250px;font-family:var(--k-font)}
.k-goo-field{position:absolute;inset:0}
.k-goo-b{position:absolute;border-radius:50%;background:var(--k-accent);transform:translate(-50%,-50%);pointer-events:none}
.k-goo p{position:relative;z-index:2;text-align:center;padding-top:104px;font-size:13px;color:var(--k-zinc-400);pointer-events:none}
// KATA Goo Cursor — a chain of lazy blobs under a goo filter.
document.querySelectorAll('[data-goo]').forEach(function (stage) {
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
var svgNS = 'http://www.w3.org/2000/svg';
var svg = document.createElementNS(svgNS, 'svg');
svg.setAttribute('width', '0'); svg.setAttribute('height', '0');
svg.style.position = 'absolute';
var filter = document.createElementNS(svgNS, 'filter');
filter.setAttribute('id', 'k-goo-filter');
var blur = document.createElementNS(svgNS, 'feGaussianBlur');
blur.setAttribute('in', 'SourceGraphic'); blur.setAttribute('stdDeviation', '9');
var matrix = document.createElementNS(svgNS, 'feColorMatrix');
matrix.setAttribute('values', '1 0 0 0 0 0 1 0 0 0 0 0 1 0 0 0 0 0 22 -11');
filter.appendChild(blur); filter.appendChild(matrix);
svg.appendChild(filter);
stage.appendChild(svg);
var field = stage.querySelector('.k-goo-field');
field.style.filter = 'url(#k-goo-filter)';
var SIZES = [44, 34, 27, 21, 16, 12];
var blobs = SIZES.map(function (s, i) {
var el = document.createElement('span');
el.className = 'k-goo-b';
el.style.width = s + 'px'; el.style.height = s + 'px';
field.appendChild(el);
return { el: el, x: stage.clientWidth / 2, y: stage.clientHeight / 2, ease: .34 - i * .045 };
});
var mouse = { x: stage.clientWidth / 2, y: stage.clientHeight / 2 };
stage.addEventListener('pointermove', function (e) {
var r = stage.getBoundingClientRect();
mouse.x = e.clientX - r.left; mouse.y = e.clientY - r.top;
});
(function frame() {
var tx = mouse.x, ty = mouse.y;
blobs.forEach(function (b) {
b.x += (tx - b.x) * b.ease;
b.y += (ty - b.y) * b.ease;
b.el.style.left = b.x + 'px';
b.el.style.top = b.y + 'px';
tx = b.x; ty = b.y;
});
requestAnimationFrame(frame);
})();
});
Installation
CLI
node kata-ui.mjs add goo-cursor
Writes the part’s CSS and JS into your project. New to the CLI? See the CLI doc.
Manual
- Load
tokens.cssonce, before any part. - Copy the CSS tab into your stylesheet.
- Copy the HTML where it belongs. The part has a script — include it after the markup; it initializes itself.
Usage
Six blobs chase the pointer in a chain, each lazier than the last, and a blur-and-contrast filter fuses them into one creature with surface tension. It serves no purpose a meeting could survive. It is also the first thing everyone touches — some parts are for the hands, not the roadmap.
Accessibility
Pointer theatre in its purest form: invisible to assistive technology, absent on touch, and fully still under prefers-reduced-motion. The stage beneath it must carry its own meaning, because the goo carries none.
Anatomy
The public surface of this part, read from its own source. Class names are the API — the CSS tab above is the full contract.
.k-goo | class |
.k-goo-field | class |
.k-goo-b | class |
data-goo | data hook |
aria-label | ARIA |
Related parts
Bounce Letters beta
A headline whose letters hop when touched — and do the wave when you click.
Carousel Ring beta
A merry-go-round of cards in real 3D: eight panels riding a ring that never stops turning.
Confetti Cannon beta
A button that fires confetti out of both corners of its stage. You already pressed it twice.
Fireworks beta
Click the night and it blooms: rockets, bursts and falling sparks on one canvas.