Live preview
Попробуйте механику
02
Что показывает эта механика
Объясняет, почему SEO, содержание, дизайн, скорость и аналитика должны работать одновременно.
Где использовать
Стратегия, аудит, образовательный контент. Для коммерческого проекта меняются правила, визуальный язык, тексты, аналитические события и действие после завершения.
Технологии
Семантический HTML, адаптивный CSS, Canvas API, Pointer Events и requestAnimationFrame. Внешние библиотеки и графические ассеты не требуются.
Полный исходный код / 20 строк
<!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 / System balance</p><h1 id="title">Баланс сайта</h1><div class="num" aria-hidden="true">01</div><p class="copy">Разложите SEO, контент, дизайн, скорость и аналитику так, чтобы система не перевесила в одну сторону.</p></header><div class="stage"><div class="canvas-wrap"><canvas id="game" aria-label="Игра Баланс сайта"></canvas><div class="hud"><span class="chip" id="next">Следующий: SEO</span><span class="chip" id="bal">Баланс 100%</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'),next=document.getElementById('next'),bal=document.getElementById('bal'),status=document.getElementById('status');
const items=[['SEO',18],['КОНТЕНТ',16],['ДИЗАЙН',15],['СКОРОСТЬ',18],['HTML',12],['АНАЛИТИКА',11],['API',9],['LINKS',10]];let W=320,H=420,dpr=1,blocks=[],i=0,tilt=0,running=false;
function track(action,d={}){const p={event:'interactive_game',game:'balance',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);draw()}
function moment(){let m=0,w=0;for(const b of blocks){m+=(b.cx-W/2)*b.weight;w+=b.weight}tilt=w?Math.max(-.38,Math.min(.38,m/(w*W*.40))):0;return Math.abs(tilt)}
function draw(){x.clearRect(0,0,W,H);x.fillStyle='#f7f4ed';x.fillRect(0,0,W,H);x.strokeStyle='rgba(17,17,17,.10)';for(let y=0;y<H;y+=32){x.beginPath();x.moveTo(0,y);x.lineTo(W,y);x.stroke()}const py=H*.72;x.save();x.translate(W/2,py);x.rotate(tilt);x.fillStyle='#111';x.fillRect(-W*.38,-7,W*.76,14);for(let n=0;n<blocks.length;n++){const b=blocks[n],yy=-42-Math.floor(n/2)*38;x.fillStyle=n===blocks.length-1?'#ff5a1f':'#111';x.fillRect(b.cx-W/2-b.w/2,yy,b.w,30);x.fillStyle='#f3f0e9';x.font='800 9px Arial';x.textAlign='center';x.textBaseline='middle';x.fillText(b.label,b.cx-W/2,yy+15)}x.restore();x.fillStyle='#ff5a1f';x.beginPath();x.moveTo(W/2-18,py+10);x.lineTo(W/2+18,py+10);x.lineTo(W/2,py+48);x.closePath();x.fill()}
function hud(){next.textContent='Следующий: '+(items[i]?.[0]||'ГОТОВО');bal.textContent='Баланс '+Math.max(0,Math.round((1-Math.abs(tilt)/.38)*100))+'%'}
function place(e){if(!running||i>=items.length)return;e.preventDefault();const r=c.getBoundingClientRect(),cx=Math.max(W*.12,Math.min(W*.88,e.clientX-r.left)),[label,weight]=items[i];blocks.push({cx,label,weight,w:Math.max(62,weight*4)});i++;const t=moment();hud();draw();track('place',{label,tilt:t});if(t>.30){running=false;status.innerHTML='<strong>Система перевешена.</strong> Хорошие элементы не спасают, если архитектура собрана без баланса.';track('fail',{count:i})}else if(i===items.length){running=false;status.innerHTML='<strong>Баланс собран.</strong> SEO, контент, дизайн, скорость и аналитика удерживают одну систему.';track('complete',{score:Math.round((1-t/.38)*100)})}}
function reset(start=false){blocks=[];i=0;tilt=0;running=start;status.textContent=start?'Ставьте блоки на платформу.':'Тапните по платформе, чтобы поставить следующий блок. Чем тяжелее элемент, тем ближе его лучше ставить к центру.';hud();draw();if(start)track('start')}
c.addEventListener('pointerdown',place,{passive:false});document.getElementById('start').onclick=()=>reset(true);document.getElementById('reset').onclick=()=>reset(false);if('ResizeObserver'in window)new ResizeObserver(fit).observe(c);else addEventListener('resize',fit);requestAnimationFrame(fit);hud();})();</script></body></html>