27 KiB
#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 не подходит, потому что:
- Геометрия Houseplan динамическая: смешанная толщина, T/X-стыки, перегородки, круглые и квадратные колонны, двери, окна и ворота.
- В карточке есть тяжёлые динамические слои: Glow, spill через проёмы, солнечные лучи, hover, vacuum overlays и HTML-маркеры.
- 20–32 копии сложных wall paths заметно увеличат DOM, raster/compositing cost и вероятность швов.
- CSS 3D-контекст разрушается или уплощается рядом свойств, уже используемых карточкой:
filter, opacity на предках,clip-path, mask и часть blend/compositing-сценариев. - Сейчас day/night использует
filter: brightness(...)на.zoomwrap, а Glow —mix-blend-mode: screen; слепое помещение существующего дерева в CSS 3D создаёт высокий риск регрессий. - Координаты устройств и 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 должны покрыть:
- Выпуклые и вогнутые комнаты, отверстия и несколько несвязанных контуров.
- Смешанную толщину стен, короткие сегменты, T/X-стыки и сложные объединения.
- Проём у угла, несколько соседних проёмов, дверь/окно/ворота шире толщины стены.
- Перегородку, примыкающую к стене без визуального шва.
- Квадратную повёрнутую и круглую колонну.
- Виртуальную стену между двумя толстыми стенами.
- Комнату без физических стен и старую конфигурацию без thickness.
- Glow с несколькими источниками, spill через открытые проёмы и hover комнаты.
- Day/night brightness, непрозрачные/полупрозрачные заливки и additive blending.
- Большую подложку, decor, текст, пунктирные линии и мебель.
- Скрытые/удалённые/недоступные устройства и все режимы device presentation.
- Touch: pinch не вызывает click, long press не оставляет phantom pan.
- Возврат на вкладку: сцена не мигает и не пересобирается из пустого состояния.
- Очень широкий/высокий план, detached terrace/porch и несколько пространств.
- Светлая/тёмная тема, 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 пользовательской версии
- Пользователь может переключить текущий план между плоским и объёмным видом без изменения данных.
- Существующие планы открываются плоскими и не требуют миграции.
- В объёмном виде физические стены, перегородки и колонны имеют непрерывные top/side faces; виртуальные стены не экструдируются.
- Двери, окна и ворота образуют реальные разрывы объёма, без тонких швов и торцов внутри проёма.
- Glow, spill, sunlight, room fill и hover сохраняют текущую семантику и не мигают.
- Device markers, room controls, tooltips и dialogs остаются кликабельными, читаемыми и доступными с клавиатуры.
- Открытие редактора показывает плоский вид; выход восстанавливает предыдущий просмотр.
- Zoom/pan/fit работают без скачка, phantom click и изменения сохранённой геометрии.
- При ошибке объёмного renderer доступен безопасный плоский fallback.
- Пройдены unit tests проекции/side faces, smoke interactions, golden matrix и performance comparison на детерминированных fixtures.
- Обновлены
README.md,docs/USER-GUIDE.ru.md, RU/EN changelog и release screenshots.
15. Рекомендуемая поставка
Фичу лучше вести отдельным релизным циклом:
- внутренняя beta/spike без публичного toggle;
- beta с фиксированным объёмным видом и полным fallback;
- beta с doors/windows/markers polish и performance fixes;
- stable только после golden review на реальных больших планах и проверки мобильного просмотра.
Главный критерий успеха — не максимальная «трёхмерность», а визуально сильный вид без потери надёжности Houseplan как интерактивной HA-карточки.