Skip to content
Deasy Corporation
Logos
Theos
Work
Deasy Corporation
2026 AD
Games
Motion Trail Afterimage POC
Back to Gaming Concepts
A moving dot leaves a smooth fading trail behind it to prove readable motion direction and speed
<html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width,initial-scale=1"> <title>POC — Motion Trail (Correct)</title> <style> html, body { margin:0; width:100%; height:100%; overflow:hidden; background:#000; } canvas { display:block; outline:none; } .hint { position:absolute; left:12px; bottom:12px; color:#aaa; font:14px system-ui; user-select:none; } </style> </head> <body> <canvas id="c" width="1500" height="1500" tabindex="0"></canvas> <div class="hint">Click canvas to focus • Arrows move • Trail fades + grid stays stable</div> <script> const c = document.getElementById("c"); const x = c.getContext("2d"); const W = 1500, H = 1500; // Prevent scroll on arrows const k = {}; function isArrow(key){ return key.startsWith("Arrow"); } addEventListener("keydown", e => { if (isArrow(e.key)) e.preventDefault(); k[e.key]=true; }, {passive:false}); addEventListener("keyup", e => { if (isArrow(e.key)) e.preventDefault(); k[e.key]=false; }, {passive:false}); c.focus(); c.addEventListener("pointerdown", () => c.focus()); // Player const p = { x: W/2, y: H/2, vx: 0, vy: 0 }; const ACCEL = 0.55, DRAG = 0.92, MAX = 16; // Trail settings const FADE_ALPHA = 0.10; // higher fades faster (0.10–0.20 is usable) const DOT_R = 10; // Pre-render grid as TRANSPARENT lines only const grid = document.createElement("canvas"); grid.width = W; grid.height = H; const gx = grid.getContext("2d"); gx.clearRect(0,0,W,H); gx.strokeStyle = "rgba(255,255,255,0.06)"; gx.lineWidth = 1; for (let i=0;i<=W;i+=150){ gx.beginPath(); gx.moveTo(i,0); gx.lineTo(i,H); gx.stroke(); } for (let j=0;j<=H;j+=150){ gx.beginPath(); gx.moveTo(0,j); gx.lineTo(W,j); gx.stroke(); } function clamp(v,a,b){ return Math.max(a, Math.min(b, v)); } function update(){ if (k.ArrowUp) p.vy -= ACCEL; if (k.ArrowDown) p.vy += ACCEL; if (k.ArrowLeft) p.vx -= ACCEL; if (k.ArrowRight) p.vx += ACCEL; p.vx *= DRAG; p.vy *= DRAG; const sp = Math.hypot(p.vx, p.vy); if (sp > MAX){ p.vx = (p.vx/sp)*MAX; p.vy = (p.vy/sp)*MAX; } p.x = clamp(p.x + p.vx, 0, W); p.y = clamp(p.y + p.vy, 0, H); } // init: solid black once x.fillStyle = "#000"; x.fillRect(0,0,W,H); (function loop(){ update(); // 1) fade ONLY (this creates trail) x.fillStyle = `rgba(0,0,0,${FADE_ALPHA})`; x.fillRect(0,0,W,H); // 2) draw stable grid (transparent lines) x.drawImage(grid, 0, 0); // 3) draw dot x.fillStyle = "#fff"; x.beginPath(); x.arc(p.x, p.y, DOT_R, 0, Math.PI*2); x.fill(); requestAnimationFrame(loop); })(); </script> </body> </html> '></iframe> </div>