Files
houseplan-card/legacy/docs/089-isometric-view-draft.md
T
Matysh 8eb4bab7c6 docs: file reviews where reviews live, retire the #89 draft, honest markers
Three review documents sat in the repository root, committed before the pipeline
existed and before docs/reviews/ did. The directory exists now and the pipeline
writes into it, so they move there and the root stops being a second place to
look.

The #89 spec had a twin: the research draft next to the normative stage1
document, two files for one issue. The draft goes to legacy — it fed the
decisions and is worth keeping, but nothing should read it as current.

ROADMAP.md carried a live link to the Project v2 board that was dropped
yesterday; missed then because the sweep grepped for status-canon wording, not
for every link. And docs/README.ru.md said "verified against v1.60.0" as if
that were fresh — the line is now an explicit warning naming what to trust
instead: USER-GUIDE.ru.md and the changelogs.

Issue: #142
User-Visible: no
2026-08-14 11:40:26 +03:00

302 lines
27 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# #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-карточки.