Live preview
Попробуйте механику
02
Что показывает эта механика
Отделяет коммерческие сигналы от шума и объясняет ценность релевантного трафика.
Где использовать
Лидогенерация, B2B, продуктовые страницы. Для коммерческого проекта меняются правила, визуальный язык, тексты, аналитические события и действие после завершения.
Технологии
Семантический HTML, адаптивный CSS, Canvas API, Pointer Events и requestAnimationFrame. Внешние библиотеки и графические ассеты не требуются.
Полный исходный код / 13 строк
<!doctype html><html lang="ru"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"><meta name="theme-color" content="#f3f0e9"><meta name="robots" content="noindex, nofollow"><title>Магнит лидов — Lavrushin Interactive</title><style>
:root{--bg:#f3f0e9;--ink:#111;--accent:#ff5a1f;--muted:#6f6b64;--line:rgba(17,17,17,.16)}
*{box-sizing:border-box}html,body{margin:0;min-height:100%;background:var(--bg);color:var(--ink);font-family:Arial,Helvetica,sans-serif;-webkit-text-size-adjust:100%}
body{padding:env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left)}main{width:100%;max-width:760px;margin:0 auto;padding:14px}.card{border:1px solid var(--ink);overflow:hidden;background:var(--bg)}
.head{position:relative;padding:20px 18px 16px;border-bottom:1px solid var(--ink)}.kicker{margin:0 0 10px;font-size:10px;letter-spacing:.16em;text-transform:uppercase}.num{position:absolute;right:16px;top:16px;font-size:58px;line-height:.8;font-weight:900;color:var(--accent);opacity:.17;letter-spacing:-.08em}
h1{margin:0;max-width:82%;font-size:clamp(36px,11vw,64px);line-height:.9;letter-spacing:-.055em}.copy{margin:14px 0 0;max-width:620px;font-size:14px;line-height:1.5;color:#34312d}.stage{padding:12px}.canvas-wrap{position:relative;border:1px solid var(--ink);overflow:hidden;background:#fff9}
canvas{display:block;width:100%;height:clamp(360px,58svh,500px);touch-action:none;-webkit-user-select:none;user-select:none}.hud{position:absolute;left:10px;right:10px;top:10px;display:flex;justify-content:space-between;gap:8px;pointer-events:none}.chip{background:var(--bg);border:1px solid var(--ink);padding:7px 9px;font-size:9px;letter-spacing:.08em;text-transform:uppercase;font-weight:800}.status{min-height:62px;padding:13px 2px 8px;font-size:14px;line-height:1.45}.actions{display:grid;grid-template-columns:1fr 1fr;gap:8px}.actions .wide{grid-column:1/-1}
button,a.btn{min-height:46px;border:1px solid var(--ink);border-radius:0;background:var(--ink);color:var(--bg);padding:12px 14px;font:800 11px/1 Arial,sans-serif;letter-spacing:.07em;text-transform:uppercase;text-decoration:none;display:flex;align-items:center;justify-content:center;-webkit-tap-highlight-color:transparent}button.secondary{background:transparent;color:var(--ink)}.help{padding:13px 18px;border-top:1px solid var(--ink);font-size:11px;line-height:1.45;color:var(--muted)}.help strong{color:var(--ink)}
@media(min-width:700px){main{padding:24px}.head{padding:24px}.stage{padding:18px}.actions{display:flex;justify-content:flex-end}.actions .wide{grid-column:auto}.status{min-height:48px}}@media(prefers-reduced-motion:reduce){*{scroll-behavior:auto!important}}
</style></head><body><main><section class="card" aria-labelledby="title"><header class="head"><p class="kicker">Interactive demo / Lead attraction</p><h1 id="title">Магнит лидов</h1><div class="num" aria-hidden="true">05</div><p class="copy">Притягивайте не любой трафик, а сигналы с коммерческим намерением. Магнитом здесь работает релевантный контент.</p></header><div class="stage"><div class="canvas-wrap"><canvas id="game" aria-label="Игра Магнит лидов"></canvas><div class="hud"><span class="chip" id="leads">Лиды 0</span><span class="chip" id="time">30 сек</span></div></div><div class="status" id="status" aria-live="polite">Ведите магнит пальцем или мышью. Притягивайте целевые сигналы и избегайте ботов, спама и случайного трафика.</div><div class="actions"><button id="start">Начать</button><button class="secondary" id="reset">Сбросить</button><a class="btn wide" href="https://t.me/DMITRIY_LAVRUSHIN" target="_blank" rel="noopener">Обсудить сайт</a></div></div><footer class="help"><strong>Mobile-first:</strong> touch, Pointer Events, safe-area. Без библиотек и внешних ассетов.</footer></section></main><script>(()=>{'use strict';const c=document.getElementById('game'),x=c.getContext('2d'),leadsEl=document.getElementById('leads'),timeEl=document.getElementById('time'),status=document.getElementById('status');let W=320,H=420,dpr=1,raf=0,last=0,running=false,mag={x:160,y:320},objs=[],leads=0,noise=0,time=30,spawn=0;const good=['BRIEF','B2B','SEO','CATALOG','API','LEAD'],bad=['BOT','SPAM','FAKE','NOISE'];
function track(action,d={}){const p={event:'interactive_game',game:'magnet',action,...d};window.dataLayer=window.dataLayer||[];window.dataLayer.push(p)}function fit(){const r=c.getBoundingClientRect();W=Math.max(280,Math.round(r.width));H=Math.max(340,Math.round(r.height));dpr=Math.min(2,devicePixelRatio||1);c.width=W*dpr;c.height=H*dpr;x.setTransform(dpr,0,0,dpr,0,0);mag.x=W/2;mag.y=H*.76;draw()}function spawnObj(){const ok=Math.random()>.34;objs.push({x:20+Math.random()*(W-40),y:40+Math.random()*H*.42,vx:(Math.random()-.5)*20,vy:(Math.random()-.5)*20,r:13,ok,label:(ok?good:bad)[Math.floor(Math.random()*(ok?good.length:bad.length))]})}
function loop(t){const dt=Math.min(.032,(t-last)/1000||.016);last=t;if(running){time-=dt;spawn-=dt;if(spawn<=0){spawn=.38+Math.random()*.35;spawnObj()}for(const o of objs){const dx=mag.x-o.x,dy=mag.y-o.y,d=Math.max(18,Math.hypot(dx,dy));if(d<150){const f=(1-d/150)*(o.ok?150:70);o.vx+=dx/d*f*dt;o.vy+=dy/d*f*dt}o.x+=o.vx*dt;o.y+=o.vy*dt;o.vx*=.99;o.vy*=.99;if(o.x<o.r||o.x>W-o.r)o.vx*=-1;if(o.y<o.r||o.y>H-o.r)o.vy*=-1}for(let n=objs.length-1;n>=0;n--){const o=objs[n];if(Math.hypot(o.x-mag.x,o.y-mag.y)<31){if(o.ok){leads++;track('collect',{label:o.label})}else{noise++;track('noise',{label:o.label})}objs.splice(n,1)}}leadsEl.textContent='Лиды '+leads+' / шум '+noise;timeEl.textContent=Math.max(0,Math.ceil(time))+' сек';if(time<=0){running=false;status.innerHTML='<strong>'+(leads>noise*2?'Чистый поток.':'Слишком много шума.')+'</strong> Целевых сигналов: '+leads+', случайных: '+noise+'.';track('complete',{leads,noise})}}draw();raf=requestAnimationFrame(loop)}
function draw(){x.clearRect(0,0,W,H);x.fillStyle='#f7f4ed';x.fillRect(0,0,W,H);x.strokeStyle='rgba(17,17,17,.08)';for(let q=0;q<W;q+=32){x.beginPath();x.moveTo(q,0);x.lineTo(q,H);x.stroke()}for(const o of objs){x.fillStyle=o.ok?'#111':'#bbb4aa';x.beginPath();x.arc(o.x,o.y,o.r,0,Math.PI*2);x.fill();x.fillStyle=o.ok?'#f3f0e9':'#111';x.font='800 7px Arial';x.textAlign='center';x.fillText(o.label,o.x,o.y+2)}x.strokeStyle='#ff5a1f';x.lineWidth=8;x.beginPath();x.arc(mag.x,mag.y,25,.15*Math.PI,.85*Math.PI);x.stroke();x.strokeStyle='#111';x.beginPath();x.moveTo(mag.x-22,mag.y+18);x.lineTo(mag.x-22,mag.y+33);x.moveTo(mag.x+22,mag.y+18);x.lineTo(mag.x+22,mag.y+33);x.stroke();if(!running){x.fillStyle='rgba(17,17,17,.82)';x.fillRect(12,H/2-38,W-24,76);x.fillStyle='#f3f0e9';x.font='800 18px Arial';x.textAlign='center';x.fillText('ПРИТЯГИВАЙТЕ ЦЕЛЕВЫХ',W/2,H/2+6)}}function move(e){const r=c.getBoundingClientRect();mag.x=Math.max(28,Math.min(W-28,e.clientX-r.left));mag.y=Math.max(28,Math.min(H-28,e.clientY-r.top))}c.addEventListener('pointerdown',e=>{e.preventDefault();c.setPointerCapture?.(e.pointerId);move(e)},{passive:false});c.addEventListener('pointermove',e=>{if(e.buttons||e.pointerType==='touch'){e.preventDefault();move(e)}},{passive:false});document.getElementById('start').onclick=()=>{running=true;time=30;leads=0;noise=0;objs=[];spawn=0;track('start')};document.getElementById('reset').onclick=()=>{running=false;time=30;leads=0;noise=0;objs=[];leadsEl.textContent='Лиды 0';timeEl.textContent='30 сек';status.textContent='Ведите магнит пальцем или мышью. Притягивайте целевые сигналы и избегайте ботов, спама и случайного трафика.';track('reset')};if('ResizeObserver'in window)new ResizeObserver(fit).observe(c);else addEventListener('resize',fit);requestAnimationFrame(fit);last=performance.now();raf=requestAnimationFrame(loop)})();</script></body></html>