diff --git a/docs/specs/231-decor-layer-order.md b/docs/specs/231-decor-layer-order.md new file mode 100644 index 00000000..94fd91db --- /dev/null +++ b/docs/specs/231-decor-layer-order.md @@ -0,0 +1,346 @@ +# Issue #231 — декоративный слой виден поверх заливок комнат + +- **Issue:** https://github.com/Matysh/houseplan-card/issues/231 +- **Связанные контракты:** `docs/DECOR-EDITOR.md`, `docs/BACKDROP.md`, + `docs/TOUCH-SUPPORT.md`, #19, #55 +- **Тип:** bug, обычный полный трек +- **Приоритет:** P1 +- **Пользовательское изменение:** да + +## 1. Сценарий и персона + +**Персона:** домашний администратор, который добавляет линии, фигуры, подписи +или мебель в редакторе подложки, а затем проверяет план в View; домочадец или +гость видит тот же план в View либо kiosk. + +**Сценарий:** декоративный объект целиком или частично расположен внутри комнаты +с непрозрачной либо полупрозрачной заливкой. В редакторе подложки объект создан и +остаётся в конфигурации, но текущий SVG-порядок рисует его до комнаты. Заливка +комнаты поэтому полностью скрывает декор либо смешивает его цвет со своим. + +## 2. Что человек увидит до и после + +До исправления декоративная линия, фигура, подпись или мебель может исчезнуть, +попав внутрь комнаты. После исправления весь декоративный слой одинаково виден +снаружи и внутри комнат: он лежит поверх пола и продолженного в проёмы пола, но +не перекрывает свет, стены, двери, окна, ворота и устройства. + +## 3. Проблема и подтверждённая причина + +В полном renderer карточки `_renderDecorLayer()` вызывается после backdrop, но +до рендера комнат. Позже в том же SVG рисуются: + +1. заливки и контуры комнат; +2. hover-заливка; +3. обычные тоннели проёмов; +4. Glow-base комнат; +5. Glow-base тоннелей; +6. Glow, солнце, стены и символы проёмов. + +SVG рисует более поздних соседей поверх ранних, поэтому заливка перекрывает +декор. Сами объекты не удаляются: дефект ограничен композицией полного плана. + +Статическая `houseplan-space-card` сейчас намеренно не рисует decor и не является +источником расхождения. + +## 4. Нормативные источники и приоритет + +При расхождении применяются: + +1. решения владельца в #231, включая принятое решение Q1; +2. это ТЗ после зелёного SPEC-REVIEW; +3. существующие контракты Glow, солнца, физических стен, проёмов и устройств; +4. `docs/DECOR-EDITOR.md`, `docs/BACKDROP.md` и `docs/TOUCH-SUPPORT.md`; +5. текущая реализация как compatibility baseline для явно не изменяемого + поведения. + +## 5. Цели + +1. Сделать decor видимым поверх любой эффективной заливки комнаты. +2. Не разрывать декор на тоннелях дверей, окон, ворот и открытых проёмов. +3. Сохранить свет, стены, символы проёмов и устройства выше decor. +4. Сохранить hide/editor/data contracts без новой настройки и миграции. +5. Защитить порядок структурным и визуальным тестом, который падает при возврате + старого расположения слоя. + +## 6. Scope + +В задачу входят: + +- перенос единственного вызова `_renderDecorLayer()` в общем SVG полного плана; +- единый порядок для линий, прямоугольников, эллипсов, текста, мебели и будущих + типов, которые выводятся тем же renderer; +- обычный View, kiosk и три редактора, использующие общий stage; +- обычные room fills, hover fill, обычные тоннели, Glow-base комнат и тоннелей; +- сохранение Glow pools, солнца, стен, opening symbols, устройств и room labels + выше decor; +- browser regression smoke, documented mutant и visual/golden evidence; +- актуализация канонического описания слоёв, testing docs и обоих changelog. + +## 7. Не входит в задачу + +- настройка или per-object флаг «под планом»; +- автоматическое изменение координат старого декора; +- изменение формы, размера, цвета, opacity, blend mode или hit area декора; +- изменение порядка backdrop либо room-shaped paper; +- изменение алгоритмов заливки, Glow, солнца, стен или проёмов; +- добавление decor в `houseplan-space-card`, экспорт «только планировка» или + другой статический renderer; +- новый UI, i18n-строки, persisted fields или migration; +- отдельный порядок для скрытой изометрии: она продолжает использовать общий + floor scene и не получает второго decor renderer; +- принятие golden baseline на Windows либо выпуск без команды владельца. + +## 8. Нормативный порядок слоёв + +### 8.1. Обязательная граница decor + +В полном plan SVG порядок снизу вверх должен быть эквивалентен: + +```text +scene background +room-shaped paper +plan image / backdrop +grid +room fills and their simple contours +room hover fill +opening tunnels: data fill +Glow-base rooms +opening tunnels: Glow-base +DECOR +live Glow pools +sun rays +physical/virtual wall presentation and editor overlays +opening symbols: door / window / gate / passage +devices and room labels +``` + +Дополнительные editor-only или hover-outline слои могут сохранять своё текущее +место, если не нарушают следующие инварианты: + +- любой `[data-hp="decor"]` следует в DOM после room fill, hover fill, обоих + видов тоннелей и Glow-base; +- он предшествует live Glow, sun, wall bodies и opening symbols; +- HTML-слои устройств и подписей комнат остаются выше SVG decor. + +Тоннель считается продолжением пола в проём, а не символом проёма. Поэтому линия +через порог не обрывается заливкой тоннеля; сама дверь, окно, ворота или открытый +проём остаются выше линии. + +### 8.2. Glow + +Glow-base является тёмной основой пола и располагается под decor. Live Glow pool +и солнечные лучи являются светом и располагаются над decor. Специальный blend, +компенсация цвета или отдельная opacity для decor не добавляются: свет визуально +воздействует на него тем же существующим способом, что и на прочее содержимое +пола. + +Если targeted fixture показывает иной фактический результат из-за CSS +isolation/compositing, реализация не должна молча переносить decor поверх live +Glow. Это расхождение возвращается владельцу как продуктовый вопрос. + +### 8.3. Существующий декор + +Решение владельца по Q1: + +- все старые и новые decor-объекты получают один порядок; +- новый compatibility-флаг не создаётся; +- объект, ранее заходивший под комнату в расчёте на ошибочное перекрытие, после + обновления может проявиться; пользователь при необходимости один раз правит + его геометрию. + +Открытие и сохранение плана без редактирования не переписывает decor и не +материализует новые поля. + +## 9. Hide, editor и interaction contract + +- `hide_decor: true` по-прежнему удаляет весь decor из View, kiosk, Plan editor + и Devices editor; +- Background editor показывает decor даже при `hide_decor: true`, чтобы слой + можно было редактировать; +- в Background editor decor остаётся интерактивным и визуально непрозрачным, а + архитектура сохраняет существующее de-emphasis; +- вне Background editor decor остаётся визуальным и инертным: он не получает + новое действие и не перехватывает tap/click у комнаты или устройства; +- backdrop остаётся ниже комнат и decor и сохраняет текущую editor-opacity. + +## 10. UX, accessibility и touch + +Новых элементов управления, focus targets, hover-правил и жестов нет. View и +kiosk на mouse, touch и pen используют один исправленный renderer. Target sizes, +pointer modality, pan, pinch, room hover и device actions не меняются. + +Touch editor остаётся best effort согласно `docs/TOUCH-SUPPORT.md`; safety floor +не затрагивается, потому что задача не меняет распознавание или запись жестов. + +## 11. Данные, migration, privacy и i18n + +Config, layout, backend schema, localStorage, import/export и сериализация не +меняются. Миграция не нужна. Новых пользовательских строк и i18n-ключей нет. +Fixture использует синтетические ids и не содержит пользовательских данных. + +## 12. Архитектура и зоны изменений + +Ожидаемая реализация сохраняет один renderer и один DOM-узел слоя: + +```text +existing space.decor[] + → existing _renderDecorLayer() + → the same .decorlayer group + → moved once between Glow-base tunnels and live Glow +``` + +Ожидаемые зоны: + +- `src/houseplan-card.ts` — порядок вызова слоя и поясняющий invariant comment; +- `demo/smoke_decor_layer_order.mjs` либо эквивалентный целевой smoke; +- синтетическая fixture/golden scenario с реальным пересечением слоёв; +- `scripts/mutation-gate.mjs` и registry test для documented mutant; +- `docs/BACKDROP.md`, при необходимости `docs/DECOR-EDITOR.md`; +- `docs/TESTING.md`, `docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`; +- docs screenshot artifacts, которые обязательный `check-docs` признает + изменившимися после правки `src/**`; +- три generated bundle copies после build. + +Нельзя создавать второй decor renderer, дублировать группу либо решать дефект +CSS `z-index`, который не определяет paint order внутри одного SVG. + +## 13. Performance и security + +- число decor nodes, render calls, SVG groups и вычислений на кадр не растёт; +- не добавляются observers, timers, event listeners, network calls, canvas или + offscreen compositing; +- move layer не меняет config write, service-call и permission paths; +- interaction/pointer security не ослабляется; +- targeted performance sanity подтверждает отсутствие второго `.decorlayer` и + прежнее число `[data-hp="decor"]` на fixture. + +## 14. Acceptance criteria + +1. **AC1 — decor поверх room fill.** На синтетическом плане с непрозрачной + custom-заливкой линия, прямоугольник, эллипс, текст и мебель, пересекающие + границу комнаты, остаются видимы и сохраняют заданные style values внутри и + снаружи комнаты. **Доказательство:** browser smoke + reviewed golden с + semantic pixel assertions; тест красный на коде до #231. +2. **AC2 — decor поверх пола проёма.** Decor следует в DOM и визуально лежит + после обычного тоннеля, Glow-base комнаты и Glow-base тоннеля; линия через + порог не разрывается. **Доказательство:** browser DOM-order + pixel smoke на + data-fill и no-fill/Glow fixtures. +3. **AC3 — верхние слои сохранены.** Live Glow и солнце следуют после decor; + wall bodies и door/window/gate/passage symbols перекрывают decor в точках + пересечения; устройства и room labels остаются выше. **Доказательство:** + browser DOM-order/pixel assertions и существующие Glow/sun/opening smokes. +4. **AC4 — hide/editor/backdrop parity.** `hide_decor` скрывает слой вне + Background editor, Background editor всё равно показывает и редактирует его, + backdrop остаётся ниже, а другие editors не получают новых действий. + **Доказательство:** targeted smoke + существующие `smoke_hide_layers`, + `smoke_decor` и `smoke_backdrop`. +5. **AC5 — mutant доказывает тест.** Documented mutant возвращает вызов decor до + room fills; целевой smoke либо его unit guard краснеет по AC1/AC2, а не только + по отсутствию узла. **Доказательство:** mutation registry check и целевой + mutant run. +6. **AC6 — compatibility и surfaces.** Persisted decor остаётся байт-в-байт + прежним, новых полей/i18n нет; общий full renderer даёт одинаковый порядок в + View/kiosk/editors и не создаёт второй слой в скрытой изометрии; статическая + карточка по-прежнему не рисует decor. **Доказательство:** unit/source review, + browser parity и existing static/isometric smokes. +7. **AC7 — performance/security.** Число групп и объектов не увеличено, нет + новых per-frame вычислений, listeners, service calls или pointer targets. + **Доказательство:** DOM count, source review и targeted performance sanity. +8. **AC8 — release artifacts.** Канонический порядок слоёв, testing contract, + оба changelog, docs screenshots и golden evidence актуальны. **Доказательство:** + docs diff, `check-docs`, reviewed Linux golden artifact перед beta. + +## 15. План автотестов + +### 15.1. Цикл реализации и код-ревью + +```bash +npx tsc --noEmit +npm test +npm run build +node scripts/check-docs.mjs --external +node scripts/mutation-gate.mjs --check +node demo/smoke_decor_layer_order.mjs +``` + +Сверяются три копии bundle. Ревьюер дополнительно выбирает затронутые существующие +smokes по изменённым функциям/полям; минимум проверяются контракты Glow blending, +opening tunnels, hide layers, decor и sun. Полный browser-smoke набор остаётся +предрелизным гейтом. + +### 15.2. Обязательная fixture + +Fixture содержит не декларации, а реальные пересечения: + +- opaque custom room fill и все поддерживаемые decor kinds; +- толстую стену с тоннелем, через который проходит контрастная decor line; +- вторую комнату без data fill, получающую Glow-base; +- включённый источник live Glow; +- окно с видимым солнечным лучом; +- physical wall, opening symbol, device и room label над decor; +- режимы `hide_decor` и Background editor. + +Для контрольных координат браузер считывает raster pixels либо эквивалентный +визуальный результат. Один `compareDocumentPosition` без пиксельного/поведенческого +assert не считается доказательством AC1–AC3. + +### 15.3. Golden + +До beta полный Linux artifact содержит минимум: + +- Light-сцену с opaque fill и decor, пересекающим комнату и проём; +- Dark/Glow-сцену с decor между Glow-base и live light; +- semantic assertions, краснеющие при возврате старого порядка. + +Windows capture диагностический. Baseline принимает отдельный reviewed +Linux-артефакт по процессу; реализация сама golden не принимает. + +## 16. Риски и меры + +| Риск | Последствие | Мера и доказательство | +|---|---|---| +| Decor поставить до второго Glow-base прохода | Линия снова разорвётся/потемнеет в тоннеле | DOM-order и два visual sample для room base и tunnel base | +| Decor поднять выше live Glow или солнца | Свет перестанет визуально воздействовать на подписи и фигуры | Явный верхний инвариант + Glow/sun smoke | +| Decor поднять выше стен или symbols | Линии перекроют архитектуру и дверь | Pixel intersections с wall body и opening symbol | +| Изменить hide/editor semantics | Скрытый слой появится в View либо станет нередактируемым | Existing hide/decor smoke + отдельная проверка режима | +| Golden содержит декор, но не пересекает заливку | Эталон останется зелёным при регрессии | Semantic sample строго внутри opaque room и mutant proof | +| Старый декор проявится там, где его намеренно прятали | Изменится вид существующего плана | Явно принято владельцем; без скрытой миграции и нового флага | +| Перестановка повлияет на скрытую 2.5D сцену | Decor окажется над объёмными стенами | Общий lower/upper invariant и existing isometric smoke без отдельного renderer | + +## 17. Откат + +Откат одного implementation commit возвращает прежний порядок и связанные test/ +docs artifacts. Данные не меняются, обратная миграция не нужна. Golden baseline +возвращается только из reviewed Linux artifact. Если до beta обнаружено, что +новая граница неверна именно для live Glow, issue возвращается в `S3-spec` за +продуктовым решением, а не получает молчаливую перестановку. + +## 18. Release-артефакты + +В user-visible implementation commit одновременно обновляются: + +- `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md` со ссылкой на #231; +- `docs/BACKDROP.md` и при необходимости `docs/DECOR-EDITOR.md`; +- `docs/TESTING.md` с layer-order/mutant contract; +- обязательные docs screenshots после `src/**` diff; +- browser fixture/smoke и golden scenario/semantic assertions. + +Release note: декор из редактора подложки больше не исчезает внутри комнат и в +проёмах; свет, стены, проёмы и устройства по-прежнему рисуются поверх него. +Сначала beta, stable — только по отдельной команде владельца. + +## 19. Принятые предположения + +1. Решение владельца по Q1 означает осознанное проявление любого старого decor, + который прежде перекрывался заливкой; автоматической compatibility-эвристики + нет. +2. Glow-base относится к полу, live Glow и солнце — к свету; поэтому decor + располагается между ними без специального blend. +3. Simple room contour остаётся вместе с room fill ниже decor; физическое тело + стены остаётся выше decor. +4. `houseplan-space-card` сохраняет текущий контракт без decor. +5. Для всех decor kinds используется одна `.decorlayer`; типоспецифичного + порядка нет. +6. Техническое имя нового smoke/mutant можно поменять без изменения AC, если + доказательства остаются эквивалентными. diff --git a/docs/specs/README.md b/docs/specs/README.md index 6b301023..1fa92626 100644 --- a/docs/specs/README.md +++ b/docs/specs/README.md @@ -68,6 +68,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным | [#224](https://github.com/Matysh/houseplan-card/issues/224) Канонические координаты на каждой записи | [224-config-coordinate-canonicalization.md](224-config-coordinate-canonicalization.md) | | [#228](https://github.com/Matysh/houseplan-card/issues/228) Надёжное рисование стен и операции с готовым контуром | [228-plan-drawing-problems.md](228-plan-drawing-problems.md) | | [#239](https://github.com/Matysh/houseplan-card/issues/239) Масштаб сетки не меняет внешний вид плана; default 1 см/1 дюйм | [239-grid-scale-invariance.md](239-grid-scale-invariance.md) | +| [#231](https://github.com/Matysh/houseplan-card/issues/231) Декоративный слой виден поверх заливок комнат | [231-decor-layer-order.md](231-decor-layer-order.md) | ## P2