# #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-карточки.