Files
houseplan-card/docs/specs/089-isometric-view.md
T

27 KiB
Raw Blame History

#89 — Опциональный объёмный 2.5D/изометрический вид плана

Статус: исследование завершено; черновик продуктового и технического решения Дата: 2026-08-11 Приоритет: P1 — высокая продуктовая ценность, высокая стоимость реализации Область: режим просмотра и киоск; редакторы в первую версию не входят Исходные референсы: предоставленные владельцем проекта isometric-plan-demo.zip и изображение photo_2026-08-11_18-30-38.jpg

1. Краткое решение

Добавить в Houseplan опциональный «Объёмный вид» — стилизованное 2.5D-представление существующего плана с приподнятыми стенами, видимыми боковыми гранями, мягкой тенью и изометрической камерой.

Это не отдельный редактор и не новая модель плана. Комнаты, стены, проёмы, перегородки, колонны, устройства, Glow и все состояния продолжают использовать текущие данные. Меняется только способ их проекции и визуализации.

Рекомендуемая первая пользовательская версия:

  • переключаемый плоский/объёмный вид;
  • только режим просмотра и киоск;
  • фиксированный проверенный ракурс без свободного вращения камеры;
  • редакторы всегда открываются в обычном плоском виде;
  • без WebGL/Three.js и без 32 копий всего SVG;
  • стены строятся из канонической геометрии Houseplan, проёмы действительно вырезаются из объёма;
  • Glow, солнечные лучи, заливки и hover остаются функционально теми же эффектами на плоскости пола;
  • диалоги и tooltips остаются обычным экранным UI и не наклоняются вместе с планом.

2. Пользовательская ценность

Ценность оценивается как очень высокая:

  • план превращается из утилитарной схемы в визуально сильный центр dashboard;
  • различия стен, комнат, проёмов и внешних зон считываются быстрее;
  • скриншоты и демонстрации продукта становятся существенно убедительнее;
  • Houseplan получает заметное визуальное отличие от обычных floorplan-карточек;
  • существующая модель данных уже содержит большую часть необходимой геометрии — пользователь не строит второй план.

При этом объёмный вид не должен становиться обязательным. Плоский вид точнее для редактирования, плотных планов и слабых устройств и остаётся полностью поддерживаемым.

3. Что показало исследование демо

Переданный demo — удачный визуальный proof of concept, но не готовая архитектура для Houseplan.

Он использует:

  • один SVG с вручную заданной геометрией;
  • CSS perspective, rotateX, rotateZ и preserve-3d;
  • 32 копии одного контура стен, поднятые последовательными translateZ, чтобы имитировать толщину по высоте;
  • отдельный верхний контур стен;
  • статические подписи и устройства внутри наклонённой плоскости;
  • drag для вращения и wheel для масштаба.

Для маленькой статической сцены это работает и хорошо показывает продуктовый эффект. Прямой перенос подхода в Houseplan не подходит, потому что:

  1. Геометрия Houseplan динамическая: смешанная толщина, T/X-стыки, перегородки, круглые и квадратные колонны, двери, окна и ворота.
  2. В карточке есть тяжёлые динамические слои: Glow, spill через проёмы, солнечные лучи, hover, vacuum overlays и HTML-маркеры.
  3. 20–32 копии сложных wall paths заметно увеличат DOM, raster/compositing cost и вероятность швов.
  4. CSS 3D-контекст разрушается или уплощается рядом свойств, уже используемых карточкой: filter, opacity на предках, clip-path, mask и часть blend/compositing-сценариев.
  5. Сейчас day/night использует filter: brightness(...) на .zoomwrap, а Glow — mix-blend-mode: screen; слепое помещение существующего дерева в CSS 3D создаёт высокий риск регрессий.
  6. Координаты устройств и room labels сейчас считаются для плоского viewBox и выводятся HTML-слоем. Их нужно проецировать тем же каноническим преобразованием, иначе они разойдутся с планом.

Вывод: demo подтверждает реализуемость и ценность визуального направления, но production-рендерер нужно строить на геометрии Houseplan.

4. Рекомендуемая архитектура

4.1. Не полноценный 3D, а детерминированная 2.5D-проекция

Для первой версии рекомендуется обычный SVG с явной 2D-проекцией, а не CSS-стопка и не WebGL:

  • floor/decor/room/glow-слои помещаются в SVG-группу с одной аффинной изометрической матрицей;
  • верх стены — каноническое объединённое тело стены, спроецированное и сдвинутое на визуальную высоту;
  • боковые грани — четырёхугольники, построенные из граничных рёбер wall body и вектора высоты;
  • видимые боковые грани фильтруются по направлению камеры и сортируются по глубине;
  • HTML-маркеры получают экранные координаты через ту же чистую функцию проекции;
  • tooltips, dialogs и системные controls остаются вне проецируемой сцены.

Это позволяет сохранить обычный SVG compositor, mask/blend-поведение Glow и предсказуемую деградацию, а число элементов растёт по числу реальных граней, а не умножается на 20–32 слоя.

4.2. Канонические источники геометрии

Нельзя создавать вторую независимую модель стен. Рендерер обязан использовать:

  • wallBodiesGeometry() / объединённые wall bodies из src/wall-thickness.ts;
  • текущие opening cuts/tunnel geometry;
  • существующую модель перегородок и колонн;
  • текущие room polygons и decor geometry;
  • текущий канонический light resolver и описанную в docs/LIGHT.md семантику.

Возможные новые модули:

  • src/render/isometric-projection.ts — чистая математика проекции и обратного hit mapping;
  • src/render/isometric-walls.ts — top/side faces и depth ordering;
  • src/render/isometric-scene.ts — композиция слоёв;
  • детерминированные fixtures/golden matrix отдельно от основной карточки.

Кэш геометрии строится по содержательному fingerprint геометрии, а не только по _cfgEpoch.

4.3. Высота стен

В модели сейчас нет полноценной высоты помещений/стен. В первой версии высота — визуальный параметр представления, а не архитектурный размер:

  • единое безопасное значение по умолчанию;
  • один общий параметр для карточки/пространства, если настройка вообще выводится пользователю;
  • одинаковая высота у обычных стен, перегородок и колонн;
  • виртуальные стены остаются линиями пола и не получают объём.

Не следует выводить высоту в сантиметрах: это создаст ложное обещание настоящей 3D-модели.

5. UX первой версии

5.1. Переключение

  • В режиме просмотра появляется компактная кнопка с mdi:cube-outline и accessible name «Объёмный вид».
  • Повторное нажатие возвращает «Плоский вид».
  • Переключение не изменяет геометрию и не создаёт запись в command stack.
  • Предпочтение вида хранится отдельно от модели плана; оно не должно создавать конфликтов совместного редактирования.
  • В киоске используется настроенный вид по умолчанию; скрытая панель не должна делать возврат в плоский вид невозможным из настроек.
  • Вход в любой редактор временно показывает плоский вид. После выхода восстанавливается предыдущий режим просмотра.

Плоский вид остаётся значением по умолчанию для существующих установок и fallback при ошибке/неподдерживаемом окружении.

5.2. Камера и навигация

MVP использует один тщательно подобранный ракурс либо 2–3 пресета. Свободное вращение и изменение tilt не входят в первую версию.

Причины:

  • свободное вращение конфликтует с pan, pinch zoom, long press и кликами устройств;
  • оно требует динамической сортировки граней на каждом кадре;
  • маркетинговый эффект достигается фиксированным хорошим ракурсом;
  • фиксированный ракурс детерминирован для golden image и поддержки.

Обычный zoom/pan сохраняется. Изменение масштаба должно быть совместимо с #82 и не менять фокус плана скачком при переключении вида.

5.3. Устройства и подписи

Для первой версии рекомендуется:

  • позиция marker/room label проецируется вместе с планом;
  • сама интерактивная карточка устройства остаётся достаточно читаемой и получает мягкую объёмную тень;
  • tooltip/dialog всегда экранные и не наклоняются;
  • touch target не уменьшается из-за визуального наклона;
  • tab order и accessible name совпадают с плоским режимом.

Полностью «лежащие на полу» подписи красивее, но хуже читаются. Допустим компромисс: лёгкое согласование с ракурсом для подложки и screen-facing содержимое. Точный вариант выбирается по прототипу и a11y-проверке.

6. Поведение слоёв

Слой/объект Поведение в объёмном виде
Пол/заливка комнаты Лежит на нижней плоскости, текущая семантика цвета сохраняется
Room hover Затемняет заливку и подсвечивает внутренние границы без вспышки Glow
Физические стены Верхняя поверхность + видимые боковые грани
Перегородки Как физические стены; комнату автоматически не делят
Квадратные/круглые колонны Экструдируются из своей текущей геометрии
Виртуальные стены Пунктир на плоскости пола, без высоты
Дверь Проём реально разрывает стену; символ состояния сохраняется. Вертикальная створка — polish-этап
Окно Разрыв объёма с отдельным стилизованным оконным элементом; без моделирования реальной высоты подоконника
Ворота Разрыв объёма; две наружные створки сохраняются
Opening tunnel fill Цвет комнаты на полу, без швов; семантика Glow не меняется
Glow и spill На плоскости пола, стеновые барьеры и проёмы работают по docs/LIGHT.md
Солнечные лучи На плоскости пола, геометрия и настройки остаются текущими
Decor/backdrop Лежит на floor plane; не создаёт объём автоматически
Vacuum path/outline На floor plane; robot marker остаётся интерактивным
Device markers Проецированная позиция, безопасный z-order и неизменная логика состояний
Tooltips/dialogs Экранный overlay поверх сцены
show_borders: false Невидимые стены остаются невидимыми, но продолжают влиять на площадь и свет

7. Обязательные edge cases

Реализация и fixtures должны покрыть:

  1. Выпуклые и вогнутые комнаты, отверстия и несколько несвязанных контуров.
  2. Смешанную толщину стен, короткие сегменты, T/X-стыки и сложные объединения.
  3. Проём у угла, несколько соседних проёмов, дверь/окно/ворота шире толщины стены.
  4. Перегородку, примыкающую к стене без визуального шва.
  5. Квадратную повёрнутую и круглую колонну.
  6. Виртуальную стену между двумя толстыми стенами.
  7. Комнату без физических стен и старую конфигурацию без thickness.
  8. Glow с несколькими источниками, spill через открытые проёмы и hover комнаты.
  9. Day/night brightness, непрозрачные/полупрозрачные заливки и additive blending.
  10. Большую подложку, decor, текст, пунктирные линии и мебель.
  11. Скрытые/удалённые/недоступные устройства и все режимы device presentation.
  12. Touch: pinch не вызывает click, long press не оставляет phantom pan.
  13. Возврат на вкладку: сцена не мигает и не пересобирается из пустого состояния.
  14. Очень широкий/высокий план, detached terrace/porch и несколько пространств.
  15. Светлая/тёмная тема, kiosk, reduced motion и high zoom.

8. Производительность и технические ограничения

  • Не клонировать весь SVG или wall body десятки раз.
  • Число side faces должно быть O(числу граничных рёбер), а не O(рёбра × визуальная высота).
  • Pan/zoom не пересчитывает модельную геометрию; меняется только transform/viewBox.
  • Геометрия стен пересчитывается только при изменении содержательного fingerprint.
  • Цель на детерминированном большом fixture: плавный pan/zoom на desktop и не более 20% регрессии frame time относительно плоского вида.
  • Переключение вида не должно показывать пустой/чёрный промежуточный кадр.
  • При нехватке возможностей или исключении renderer карточка безопасно возвращается в плоский вид и сообщает диагностируемую причину в dev log.
  • Новая тяжёлая runtime-зависимость и WebGL не допускаются без отдельного архитектурного решения.

9. Доступность

  • «Объёмный вид» — визуальная альтернатива, не отдельный набор функций.
  • Все устройства, комнаты и действия доступны с клавиатуры так же, как в плоском виде.
  • Focus ring виден и не обрезается стеной/контейнером.
  • Screen reader получает те же имена и состояния.
  • prefers-reduced-motion отключает переход между проекциями, но не сам режим.
  • Минимальные touch targets сохраняются в экранных координатах.
  • Плоский вид остаётся fallback для пользователей, которым перспектива мешает чтению.

10. План реализации

Этап 0 — технический spike, 2–4 рабочих дня

  • детерминированный fixture со стенами, mixed thickness, проёмами, колонной, Glow и устройствами;
  • два прототипа: CSS wall slices и явные side faces;
  • замеры Chrome/Edge, Firefox и Safari/WebKit;
  • проверка Glow/mask/blend, day/night и HTML overlays;
  • ADR с окончательным выбором renderer.

Spike не включается пользователям и не считается завершением issue.

Этап 1 — ship-ready фиксированный объёмный вид, 8–15 рабочих дней

  • чистая математика проекции;
  • floor plane, wall top и side faces;
  • проёмы, перегородки и колонны;
  • проекция markers/labels и pointer mapping;
  • переключение view/editor/kiosk;
  • кэш, fallback, unit/integration/golden/performance gates;
  • RU/EN документация и changelog.

Этап 2 — визуальный polish уровня референса, ещё 8–15 рабочих дней

  • улучшенные двери, окна и ворота;
  • мягкие тени/ambient depth без дорогого dynamic lighting;
  • аккуратные floor/platform edges;
  • доводка markers/labels и occlusion;
  • дополнительные пресеты камеры и качества.

Отдельный будущий этап — свободная камера, ещё 5–10+ рабочих дней

Свободное вращение/tilt, gesture arbitration и динамический depth sort не входят в базовый scope. Их ценность ниже, а риск заметно выше.

11. Оценка сложности

Вариант Срок Риск Оценка
Демонстрационный CSS stack на одном fixture 2–4 дня Средний Хорош для spike, не для релиза
Production MVP с фиксированным ракурсом 8–15 дней Высокий Рекомендуемый первый релиз
Визуально отполированный вариант уровня референса 16–30 дней суммарно Высокий Реалистичная конечная цель
Свободная камера поверх polished renderer +5–10 дней Высокий Позже, только по подтверждённой ценности
Настоящий WebGL/Three.js 3D renderer 1–2+ месяца Очень высокий Не рекомендуется для этой цели

Общая оценка: L/XL, высокий архитектурный и визуальный риск, но очень высокая продуктовая отдача. Сам эффект дешёв в статичном demo; дорого стоит сохранение всей существующей интерактивности и световой модели без регрессий.

12. Риски и меры

Риск Вероятность/влияние Мера
Glow/blend/filter ломает CSS 3D Высокие Обычная SVG 2.5D-проекция вместо вложенного preserve-3d
Неверные T/X-стыки и проёмы Высокие Только канонические union bodies + geometry fixtures
Маркеры расходятся с планом Высокие Одна pure projection для SVG и HTML overlays
Падение FPS на больших планах Средние/высокие Side faces вместо десятков slices, кэш и perf gate
Нечитаемые подписи Средние Screen-facing/гибридный marker prototype и a11y review
Touch misclick при навигации Средние/высокие В MVP нет свободной камеры; существующие pan/pinch правила сохраняются
Режим превращается в второй renderer со своей логикой Высокие Общие resolvers/geometry; новый слой отвечает только за projection/presentation
Референс обещает больше, чем модель умеет Средние Называть «Объёмный вид», не «полноценный 3D»; явно ограничить высоту и окна

13. Не входит в первую версию

  • редактирование геометрии в перспективе;
  • пользовательская высота каждой стены/комнаты;
  • 3D-мебель и импорт моделей;
  • настоящая физика света и динамические тени;
  • свободный orbit camera;
  • WebGL/Three.js;
  • автоматическое превращение растровой подложки в 3D;
  • изменение формата существующих room/wall/opening данных.

14. Acceptance criteria пользовательской версии

  1. Пользователь может переключить текущий план между плоским и объёмным видом без изменения данных.
  2. Существующие планы открываются плоскими и не требуют миграции.
  3. В объёмном виде физические стены, перегородки и колонны имеют непрерывные top/side faces; виртуальные стены не экструдируются.
  4. Двери, окна и ворота образуют реальные разрывы объёма, без тонких швов и торцов внутри проёма.
  5. Glow, spill, sunlight, room fill и hover сохраняют текущую семантику и не мигают.
  6. Device markers, room controls, tooltips и dialogs остаются кликабельными, читаемыми и доступными с клавиатуры.
  7. Открытие редактора показывает плоский вид; выход восстанавливает предыдущий просмотр.
  8. Zoom/pan/fit работают без скачка, phantom click и изменения сохранённой геометрии.
  9. При ошибке объёмного renderer доступен безопасный плоский fallback.
  10. Пройдены unit tests проекции/side faces, smoke interactions, golden matrix и performance comparison на детерминированных fixtures.
  11. Обновлены README.md, docs/USER-GUIDE.ru.md, RU/EN changelog и release screenshots.

15. Рекомендуемая поставка

Фичу лучше вести отдельным релизным циклом:

  1. внутренняя beta/spike без публичного toggle;
  2. beta с фиксированным объёмным видом и полным fallback;
  3. beta с doors/windows/markers polish и performance fixes;
  4. stable только после golden review на реальных больших планах и проверки мобильного просмотра.

Главный критерий успеха — не максимальная «трёхмерность», а визуально сильный вид без потери надёжности Houseplan как интерактивной HA-карточки.