«Живая авиабаза» — UI/UX-ресёрч (AD-699, Ф0 эпика AD-698)
Статус: design-exploration, не решение о реализации. Документ готовит почву для
дешёвого статичного прототипа (см.living-airbase-prototype-concept.md) и промптов
генерации арта (см.living-airbase-art-prompts.md). Код продукта в рамках Ф0 не трогаем.
0. Что исследуем и зачем
Идея эпика: профиль-как-место — изометрическая «авиабаза» в перспективе ~30–40°, где
каждый раздел платформы это локация (Ангар, Мастерская, Полигон, Башня, Академия, Музей…).
Второй интерфейс рядом с обычным, а не вместо него. Сцена контент-зависимая: 0 бортов
→ голое поле, >10 → загруженный аэродром. База растёт от активности, не от доната.
Ключевой вопрос ресёрча: где спатиальная метафора даёт эмоцию и узнаваемость бренда, а где
ломает скорость и доступность — и как построить её так, чтобы «прикольно раз» не превратилось
в «потом медленно каждый день». Ниже — по каждому подвопросу тикета вывод и следствия для нас.
1. Спатиальная / игровая навигация в вебе
1.1. Когда работает
Спатиальные интерфейсы выигрывают, когда исходная предметная область сама пространственна
или когда пространство несёт смысл, который в плоском списке теряется. Аргумент Dark Blue Heaven:
«Люди — пространственные существа, мы переживаем жизнь в отношении к пространству»; примеры —
Sococo (план офиса: «просто смотришь на комнаты» — расписание понятно с одного взгляда), Figma
как случайный «hangout», Snapchat с направленной свайп-навигацией. Общий тезис balajis.com: spatial
UI уместен не только в играх, он «двигается во все вертикали, начиная с game-like социальных кейсов».
Для нас это важно: у авиабазы есть естественная пространственная семантика (ангар рядом с ВПП,
музей за забором, полигон в стороне) и есть эмоциональная нагрузка («захожу домой»). Это как раз
класс задач, где метафора уместна как дополнительный режим, а не как основная навигация.
1.2. Когда мешает скорости («прикольно раз — потом медленно»)
Фундаментальная плата спатиальности: движение стоит времени. Разбор game-навигации прямо
отмечает — «каждое перемещение занимает время независимо от того, насколько быстрой могла бы быть
вычислительная операция; это усиливает ощущение расстояния». Для иммерсии это плюс, для
повторяющейся рабочей задачи — чистый налог. Завсегдатай, который 20 раз в день идёт в «Мастерскую»,
не хочет каждый раз «идти через поле».
Это ровно риск из тикета: первое впечатление «вау» ≠ ежедневная эффективность. Эвристики
Nielsen/NN-g бьют по этому месту напрямую:
- Гибкость и эффективность (accelerators для опытных): у частых действий должен быть быстрый путь
в обход «мира».
- Узнаваемость вместо припоминания: игрок не должен вспоминать, где какая зона; но и не должен
учить карту — а спатиальный экран без подписей заставляет именно учить.
- Соответствие системы реальному миру — метафора помогает, но только если она однозначна.
- Контроль и свобода пользователя — обязательный «выход» из режима в один клик.
Baymard в исследованиях навигации показывает, куда сваливается спатиальный UI без дисциплины:
неоднозначные/образные ярлыки и иконки без подписей роняют находимость; в бенчмарке Baymard 2025
(по вторичным разборам) ~58% desktop и ~67% mobile сайтов имеют посредственную навигацию, а самая
частая ошибка — не подсвечен текущий раздел (не видно «где я»). Для «мира-как-интерфейса» это буквально
про нас: без явных подписей зон и индикации «вы здесь» красивая база = загадочная база.
1.3. Вывод по разделу 1
Спатиальная навигация для Skyforge оправдана как второй, опциональный режим-«витрина» и точка
эмоциональной идентичности, но не как замена быстрой навигации. Значит:
- Сайдбар/canonical-меню остаётся первичным и всегда доступным (это позиция и самого эпика).
- В game-режиме у каждой зоны — видимая подпись + понятная иконка (не только образ).
- Обязательны «accelerators»: клавиатура, прямые ссылки на разделы, deep-link в зону.
- Дефолт по контексту: новичок/«пришёл найти» → canonical; завсегдатай, который сам включил базу →
запоминаем выбор.
2. Изометрия / 2.5D в браузере: чем рисовать
2.1. Технологии и их профиль
| Технология | Сильные стороны | Слабые стороны | Где уместно у нас |
|---|---|---|---|
| SVG + CSS | Вектор, чёткое масштабирование, DOM-узлы = хитбоксы и a11y «из коробки», лёгкая интерактивность/hover, малый вес для сотен объектов | Деградирует на тысячах узлов (всё живёт в DOM/памяти) | Ф0–Ф1: статичная сцена, кликабельные зоны, подписи |
| Canvas 2D | Хорош для «нарисовать много спрайтов», проекция изометрии матрицей, дешёвая композиция слоёв | Нет DOM-семантики (a11y руками), ручной хит-тест | Ф2, если спрайтов/анимации станет много |
| WebGL | GPU, десятки тысяч полигонов в 60fps даже на мобиле, инстансинг | Тяжёлый старт, сложнее, a11y полностью руками, батарея при постоянном рендере | Только если позже понадобится «богатый» 3D-режим |
Практический консенсус (SVGGenie/Tapflare сравнения, O'Reilly «Making Isometric Social Games»,
melonJS): SVG хорош до ~сотен объектов, дальше выгоднее canvas/WebGL с батчингом. Наша сцена —
десяток зон плюс «репрезентативные» объекты (не 1:1!), поэтому на старте SVG/CSS с головой хватает.
2.2. Производительность и батарея (особенно мобилка)
Ключевой риск — не пиковый FPS, а постоянная анимация:
- Непрерывный requestAnimationFrame/анимация греет CPU/GPU и сажает батарею; iOS в low-power
режиме троттлит и rAF, и CSS-анимации.
- Анимации в фоновой вкладке жгут заряд впустую — их надо ставить на паузу через Page Visibility API.
- GPU-friendly свойства (transform/opacity) уходят в композитор без reflow/repaint — если анимировать,
то только их.
- Статичная картинка почти ничего не стоит — вся плата приходит с движением.
Отсюда прямой инженерный принцип для эпика: статика по умолчанию, движение — по возможности и
по желанию. Анимация (Ф2) включается только когда: устройство тянет, вкладка активна, у пользователя
не выставлен prefers-reduced-motion, и (на мобиле) он сам её не выключил.
2.3. Деградация / фолбэк (обязательно)
Лестница прогрессивного улучшения:
1. База (всегда работает): canonical-навигация — сайдбар/меню, обычные ссылки. Game-режим — надстройка.
2. Ф0/статик: одна изометрическая картинка (SVG или растровый спрайт) + прозрачные кликабельные
<a>/зоны сверху. Работает везде, грузится как обычная страница.
3. Ф1/состояния: та же сцена, но слои включаются по данным (пусто/мало/много).
4. Ф2/анимация: мягкие движения поверх — только при выполнении условий из 2.2; иначе тихо
откатываемся на статик.
- Мобилка: дефолт — статичная сцена или сразу canonical; анимацию не навязываем.
3. Контент-зависимые сцены без перерисовки арта
Требование: одна и та же авиабаза должна выглядеть по-разному — «0 бортов → грунтовка», «>10 →
загруженный аэродром», «пустой склад», «полный музей» — без того, чтобы художник рисовал каждое
состояние заново. Это классическая задача модульной композиции сцены.
3.1. Приёмы
- Параметризация зон через слои. Арт режется на слои: «базовая земля/грунт» → «застройка зоны»
→ «наполнение (объекты)» → «свет/огни» → «погода/небо». Состояние зоны = какие слои и с какой
«плотностью» включены. Пустой ангар — только каркас-слой; полный — каркас + слой с бортами. - Репрезентативные объекты и счётчики, не 1:1. Прямо из рамок эпика: не 50 самолётиков буквально.
Сцена показывает ступени («пусто / немного / много / очень много»), а точное число — бейджем на
зоне. Это снимает и перф-проблему, и проблему арта. - Спрайты / атлас / инстансинг. Повторяющиеся объекты (борт, ящик на складе, экспонат в музее) —
один спрайт, размещаемый N раз. Texture atlas/sprite-sheet сводит множество объектов к нескольким
draw-call; инстансный рендер (в WebGL) рисует «одинаковую геометрию, разная матрица» одним вызовом.
В SVG-варианте аналог —<use>одного символа с разными координатами. - Пороговые состояния (bucketing). Наполнение зоны считается не по «сколько нарисовать», а по
«в какой корзине число»:0/1–3/4–10/>10. Художник готовит 3–4 варианта плотности на
зону — этого достаточно для всех значений. - Слот-система. У зоны фиксированные «слоты» под объекты; данные лишь заполняют слоты сверху вниз.
Добавился борт — занялся следующий слот в ангаре; ничего не перерисовывается.
3.2. Как это ложится на наши данные
Источник состояний — статистика флота (AD-692): число бортов (в строю/в музее), моделей,
наличие треков/инвентаря и т.п. Каждой зоне сопоставляем правило «данные → корзина → набор слоёв».
Это ровно объём Ф1 и не требует нового арта после Ф0, если Ф0-арт сразу нарезан слоями (см. промпты).
4. Доступность (a11y) при спатиальном UI
Спатиальный/canvas-UI по умолчанию недоступен: <canvas> не читается скринридером, WebGL —
тем более; смысл «уносится» в пиксели. Поэтому a11y — не опция, а условие допуска game-режима.
Обязательный минимум:
- Canonical-текст-навигация всегда остаётся (сайдбар/меню с реальными ссылками) — это и есть
главный «текстовый эквивалент» всей сцены. Game-режим — сверху и опционально.
- Каждый хотспот — настоящий фокусируемый элемент (<a>/<button>), с видимым текстом-подписью,
aria-label, ролью и состоянием («вы здесь»). В SVG-варианте это достигается естественно; в
canvas/WebGL — параллельным «shadow DOM» из скрытых семантических элементов (приём для доступного canvas).
- Клавиатура (WCAG 2.1.1): весь режим проходится Tab/Shift+Tab + Enter/Space; фокус видим; ловушек
фокуса нет; порядок логичен. Никаких действий только по наведению/перетаскиванию.
- Движение: уважать prefers-reduced-motion — при reduce анимации выключены, показывается статик.
- Не полагаться на цвет/свечение как единственный сигнал (акцент #2D7BFF дублировать подписью/иконкой).
- Фолбэк обязателен: если game-режим не поддержан/выключен/недоступен — пользователь ничего не теряет,
вся функциональность достижима через canonical.
Формулировка для эпика: game-режим — это дополнение поверх полностью доступного canonical-UI, а не
его замена. Ни одна функция не должна существовать только в спатиальном режиме.
5. Прогрессивная / геймифицированная идентичность (база растёт от активности)
Цель: профиль-база растёт от вклада (проекты, статьи, помощь, испытания, достижения), а не от
доната — «зашёл к опытному, а у него огромная база: десятки бортов, музей, лаборатория, полигон».
5.1. Что реально растит вовлечённость (уроки индустрии)
- GitHub contribution graph — «вечная» публичная визуальная история активности (коммиты/PR/ревью)
- streak. Работает, потому что это побочный продукт настоящей работы, а не отдельная валюта:
граф нельзя «купить», он честно отражает вклад. Это идеальный образец для нашей базы: объекты сцены
= следствие реальных артефактов профиля. - Duolingo — streak + XP превращают долгую цель в ежедневное «да/нет»; streak freeze (защита
серии от одного пропуска) даёт +48% к средней длине серии. Урок: прощающие механики (не обнулять
за один плохой день) и явный «зачем вернуться завтра». - Habitica — RPG-персонаж, которого создаёшь под себя: IKEA-эффект (ценишь то, во что вложился).
Урок: дать пользователю обживать базу (именовать, расставлять) — привязанность растёт.
5.2. Что именно «растит» базу (маппинг вклада → сцена)
| Вклад пользователя (из данных профиля) | Как отражается на базе |
|---|---|
| Первый борт | Появляется ангар (из «голого поля с грунтовкой») |
| Много бортов (>N) | Ангаров больше / аэродром «загружен» |
| Завершённые/снятые проекты (AD-637) | Растёт Музей (достоинство, не потеря) |
| Статьи/мануалы (Академия) | Появляется/расширяется здание Академии |
| Помощь другим, разборы (Полигон) | Появляется полигон/лаборатория |
| Испытания, треки, налёт (AD-692) | Активность на ВПП/лётном поле |
| Долгая история/стаж | Общий «размер» и обжитость базы |
Принцип: сцена — это визуализация уже существующих данных профиля, а не отдельная игровая
экономика. Тогда «размер базы говорит больше, чем цифры» честно.
5.3. Анти-накрутка
Раз рост завязан на активность, появляется соблазн «фармить» ради красивой базы:
- Считать ценность результата, а не количество кликов. Не «сколько постов», а «есть завершённые
проекты / принятые разборы / реальные треки». Мусорный контент не должен растить базу.
- Пороги/корзины, а не линейный счётчик — от 3-го до 30-го борта прирост сцены небольшой; накрутка
ради «+1 объекта» бессмысленна.
- Отражать настоящие артефакты (как GitHub-граф): база меняется от того, что и так учитывается в
профиле — отдельной валюты для накрутки нет.
- Без прямого PvP-соревнования по числам — Trophy отмечает, что отсутствие явной конкуренции делает
среду дружелюбнее (важно для «хобби-аудитории всех уровней» из платформенного UX).
- Модерация/анти-абьюз — отдельная подсистема; это Ф3 и отдельный эпик, не Ф0.
6. Двойной интерфейс: canonical + game
Решение эпика: два интерфейса одновременно, оба поддерживаются.
- Переключение: явная кнопка/переключатель («Моя база» ↔ обычный вид). Не модальная ловушка —
выход в один клик (эвристика «контроль и свобода»). Deep-link:/baseоткрывает game-режим сразу. - Консистентность: одна модель данных, одна навигационная карта разделов — game-режим не должен
показывать/скрывать разделы иначе, чем canonical. Названия: в game-режиме допустимы образные имена
(Ангар/Мастерская/Полигон/Башня/Академия/Музей), но canonical-нейминг — отдельное IA/бренд-решение
(SEO/привычность/ссылки), в Ф0 не переименовываем продукт (это отмечено и в эпике). - Дефолт по контексту:
- Новый/неавторизованный/«пришёл найти» → canonical (быстро, знакомо, findable).
- Пользователь сам включил базу → запоминаем выбор (localStorage/профиль), уважаем его.
- Мобилка /
reduce-motion/ слабое устройство → дефолт canonical/статик. - «Вы здесь» и обратный путь сохраняются в обоих режимах (частая ошибка навигации по Baymard).
7. Вывод: рекомендованный подход
Строить «живую авиабазу» как опциональный второй режим-витрину поверх полностью работающего
canonical-UI, дёшево и послойно, с приоритетом статики и доступности.
Конкретно:
1. Технология старта — SVG/CSS изометрия, нарезанная слоями (земля → застройка → наполнение →
свет). Хитбоксы и подписи зон — обычные DOM-элементы (a11y и клики бесплатно). WebGL — не раньше,
чем появится реальная потребность в «богатом» 3D.
2. Статика по умолчанию, движение — прогрессивное улучшение (условия: устройство тянет, вкладка
активна, нет reduce-motion, пользователь не выключил).
3. Контент-зависимость через корзины + слоты + репрезентативные объекты, данные из AD-692 —
без перерисовки арта.
4. Canonical-навигация первична и всегда рядом; game-режим не эксклюзивен по функциям.
5. Рост от активности = визуализация реальных артефактов профиля (модель GitHub-графа), пороги
против накрутки; полноценная подсистема роста — отдельный эпик (Ф3+).
Фазовый план (совпадает с эпиком, уточнён)
- Ф0 — статичный прототип-концепт (этот тикет). UI/UX-ресёрч (готово) + промпты арта + статичная
кликабельная изометрия с подписанными зонами и фолбэком → валидация на людях (хотят ли, понятно ли,
быстро ли). Артефакты: этот файл,living-airbase-art-prompts.md,living-airbase-prototype-concept.md. - Ф1 — контент-зависимые состояния зон (пусто/мало/много) на данных AD-692. Без нового арта, если
Ф0-арт нарезан слоями. - Ф2 — анимация/ночь/подсветка как прогрессивное улучшение (rAF + Page Visibility + reduce-motion;
мобилка — статик). - Ф3 — рост базы от активности (отдельная подсистема + анти-накрутка) — свой эпик/дети.
- Ф4 — публичные/посещаемые чужие базы (приватность, производительность списков баз).
Ключевые риски и как их держим
| Риск | Митигирование |
|---|---|
| «Прикольно раз — потом медленно» | Режим опционален; canonical первичен; accelerators/deep-link; запоминаем выбор |
| Непонятно «где я» / загадочные зоны | Видимые подписи + иконки + индикатор «вы здесь» на каждой зоне |
| Батарея/перф на мобиле | Статик по умолчанию; анимация по условиям; Page Visibility; prefers-reduced-motion |
| Недоступность (скринридер/клавиатура) | Хотспоты = реальные фокусируемые элементы; canonical как текст-эквивалент; обязательный фолбэк |
| Дорогой арт под каждое состояние | Слои + корзины + репрезентативные объекты/спрайты (не 1:1) |
| Накрутка ради красивой базы | Считать результат, не действия; пороги; отражать реальные артефакты; без числового PvP |
| Расползание в отдельный продукт | Ф0 — только research+прототип; рост и публичные базы — отдельные эпики |
Sources
- Nielsen Norman Group — 10 Usability Heuristics for User Interface Design: https://www.nngroup.com/articles/ten-usability-heuristics/
- WICG — Spatial Navigation (спецификация): https://wicg.github.io/spatial-navigation/
- W3C — CSS Spatial Navigation Level 1: https://www.w3.org/TR/css-nav-1/
- David Bokan — Spatial Navigation on the Web: http://bokand.github.io/spatnav/spat-nav-on-the-web.html
- Dark Blue Heaven — Spatial Interfaces: https://darkblueheaven.com/spatialinterfaces/
- balajis.com — Spatial Interfaces: https://balajis.com/p/spatial-interfaces
- Baymard Institute — E-Commerce Homepage & Category Navigation: https://baymard.com/research/homepage-and-category-usability
- SVGGenie — SVG vs Canvas vs WebGL (2026 performance comparison): https://www.svggenie.com/blog/svg-vs-canvas-vs-webgl-performance-2025
- Tapflare — Comparing Web Graphics: Canvas, SVG, WebGL, CSS: https://tapflare.com/articles/web-graphics-comparison-canvas-svg-webgl
- O'Reilly — Making Isometric Social Real-Time Games with HTML5/CSS3/JS (гл. 1): https://www.oreilly.com/library/view/making-isometric-social/9781449309664/ch01.html
- melonJS — HTML5 game engine (WebGL tile rendering / 2.5D): https://melonjs.org/
- Wikipedia — Texture atlas: https://en.wikipedia.org/wiki/Texture_atlas
- LearnOpenGL — 2D Game, Final thoughts (instanced rendering): https://learnopengl.com/In-Practice/2D-Game/Final-thoughts
- Trophy — How GitHub Leverages Gamification: https://trophy.so/blog/github-gamification-case-study
- Trophy — Duolingo Gamification Strategy (case study): https://trophy.so/blog/duolingo-gamification-case-study
- Uladzislau Shauchenka — Duolingo/Gamification of Learning (Habitica IKEA-эффект): https://www.uladshauchenka.com/p/duolingo-case-study-the-gamification
- Paul J. Adam — HTML
<canvas>Accessibility: https://pauljadam.com/demos/canvas.html - W3C WAI — Understanding WCAG 2.1.1 Keyboard: https://www.w3.org/WAI/WCAG21/Understanding/keyboard.html
- MDN —
prefers-reduced-motion: https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-reduced-motion - web.dev — prefers-reduced-motion: https://web.dev/articles/prefers-reduced-motion
- Motion.dev — When browsers throttle requestAnimationFrame: https://motion.dev/blog/when-browsers-throttle-requestanimationframe
- MDN — Page Visibility API: https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API