Cursorspoor dat tekent New
The cursor leaves a thin orange line that follows like a pencil stroke and fades after just over a second; without a mouse the area slowly draws a loop by itself. Canvas with smoothed motion, pauses off-screen. For the hero of a design studio, architect or illustrator. With reduced motion a single static line is shown.
Elk interieur begint met een lijn op papier.
Studio Wiersma, interieurarchitectuur in Groningen
Bekijk ons werkHow to use it
- Paste the HTML where the components 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.
<!-- Cursorspoor dat tekent · NedDev · eigen werk. -->
<div class="jouw-container">
<div class="cst">
<canvas class="cst__c" aria-hidden="true"></canvas>
<div class="cst__txt"><h3 class="cst__h">Elk interieur begint met een lijn op papier.</h3><p class="cst__p">Studio Wiersma, interieurarchitectuur in Groningen</p><a class="cst__btn" href="#cursorspoor-tekent">Bekijk ons werk</a></div>
</div>
</div>/* Cursorspoor dat tekent · NedDev · eigen werk. */
.cst{position:absolute;inset:0;overflow:hidden;font-family:'Switzer',system-ui,sans-serif;color:#0a0a0a;background:#f4f3f1;text-align:left;touch-action:pan-y}
.cst__c{position:absolute;inset:0;width:100%;height:100%;display:block}
.cst__txt{position:absolute;left:18px;right:18px;bottom:16px;pointer-events:none}
.cst__h{margin:0;max-width:16em;font-size:clamp(18px,5.4cqi,26px);line-height:1.08;font-weight:700;letter-spacing:-.025em}
.cst{container-type:inline-size}
.cst__p{margin:6px 0 0;font-size:12.5px;color:#4a4a4a}
.cst__btn{pointer-events:auto;display:inline-flex;align-items:center;min-height:34px;margin-top:10px;padding:0 13px;background:#0a0a0a;color:#fff;border-radius:4px;font-size:12.5px;font-weight:600;text-decoration:none;transition:background-color .15s,color .15s}
.cst__btn:hover{background:#F5480F;color:#0a0a0a}
.cst__btn:focus-visible{outline:2px solid #F5480F;outline-offset:2px}// Cursorspoor dat tekent · NedDev · eigen werk.
// root = het element waarin de HTML staat
function init(root){
var w = root.querySelector('.cst'), c = w.querySelector('.cst__c'), ctx = c.getContext('2d');
var rm = matchMedia('(prefers-reduced-motion: reduce)').matches;
var W = 0, H = 0, dpr = 1, pts = [], LIFE = 1300, tx = 0, ty = 0, x = 0, y = 0, auto = true, idleT = 0, raf = 0, vis = true, t0 = performance.now();
w.querySelector('.cst__btn').addEventListener('click', function (e) { e.preventDefault(); });
function size() {
dpr = Math.min(2, window.devicePixelRatio || 1); W = w.clientWidth; H = w.clientHeight;
c.width = W * dpr; c.height = H * dpr; ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
if (rm) still();
}
function lus(t) { return [W * .62 + W * .26 * Math.sin(t / 1500), H * .36 + H * .2 * Math.sin(t / 950) * Math.cos(t / 2600)]; }
function still() {
ctx.clearRect(0, 0, W, H); ctx.strokeStyle = '#F5480F'; ctx.lineWidth = 1.8; ctx.lineCap = 'round'; ctx.beginPath();
for (var t = 0; t < 5200; t += 40) { var p = lus(t); if (t) ctx.lineTo(p[0], p[1]); else ctx.moveTo(p[0], p[1]); }
ctx.stroke();
}
function draw(now) {
raf = 0;
if (auto) { var p = lus(now - t0); tx = p[0]; ty = p[1]; }
var nx = x + (tx - x) * .2, ny = y + (ty - y) * .2;
if (Math.abs(nx - x) + Math.abs(ny - y) > .4 || !pts.length) pts.push({ x: nx, y: ny, t: now });
x = nx; y = ny;
while (pts.length && now - pts[0].t > LIFE) pts.shift();
ctx.clearRect(0, 0, W, H); ctx.lineCap = 'round'; ctx.lineJoin = 'round';
for (var i = 2; i < pts.length; i++) {
var a = pts[i - 2], b = pts[i - 1], q = pts[i], f = 1 - (now - q.t) / LIFE;
ctx.strokeStyle = 'rgba(245,72,15,' + f.toFixed(3) + ')'; ctx.lineWidth = .8 + 1.6 * f;
ctx.beginPath(); ctx.moveTo((a.x + b.x) / 2, (a.y + b.y) / 2); ctx.quadraticCurveTo(b.x, b.y, (b.x + q.x) / 2, (b.y + q.y) / 2); ctx.stroke();
}
if (vis && !document.hidden && (auto || pts.length > 1)) raf = requestAnimationFrame(draw);
}
function kick() { if (!raf && !rm) raf = requestAnimationFrame(draw); }
size();
if ('ResizeObserver' in window) new ResizeObserver(size).observe(w);
if (rm) return;
var p0 = lus(0); x = tx = p0[0]; y = ty = p0[1];
w.addEventListener('pointermove', function (e) {
var r = w.getBoundingClientRect(); tx = e.clientX - r.left; ty = e.clientY - r.top;
if (auto) { auto = false; x = tx; y = ty; pts = []; }
clearTimeout(idleT); idleT = setTimeout(function () { auto = true; t0 = performance.now() - 0; var p = lus(0); tx = p[0]; ty = p[1]; kick(); }, 3500);
kick();
});
if ('IntersectionObserver' in window) new IntersectionObserver(function (e) { vis = e[0].isIntersecting; if (vis) kick(); }).observe(w);
document.addEventListener('visibilitychange', kick);
kick();
}
init(document.querySelector('.jouw-container'));
More components
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 →