docs: specify removal of isometric overlay plates

Issue: #471
User-Visible: no
This commit is contained in:
Matysh
2026-09-06 11:23:51 +00:00
committed by claude[bot]
parent 90b185f603
commit 5d6c1992e4
2 changed files with 395 additions and 0 deletions
@@ -0,0 +1,394 @@
# #471 — Убрать видимые raised plates вокруг элементов изометрического View
- **Issue:** https://github.com/Matysh/houseplan-card/issues/471
- **Тип / приоритет:** bug + polish / P1
- **Трек:** полный; задача отменяет явно принятый UX-контракт Stage 3 из #160,
поэтому не проходит критерий лёгкого трека «нет нового или изменённого
UX-контракта»
- **Оценка:** пользовательская ценность 8/10; ценность для архитектуры 7/10;
сложность 4/10; риск 4/10
- **Связано:** #89, #122, #160; `docs/ISOMETRIC.md`,
`docs/adr/160-isometric-stage3-overlays.md`
## 1. Сценарий
Персона — Home admin из `docs/SCOPE.md`, который тестирует скрытый
изометрический режим в полном House Plan View на desktop, wall tablet либо
телефоне. Момент — план со множеством устройств и подписей комнат целиком
вписан в доступную область, поэтому белые подложки поднятых элементов занимают
заметную долю изображения и перекрывают архитектуру.
## 2. Что человек увидит до и после
**До:** вокруг маркеров видны дополнительные белые квадраты, а под длинными
названиями комнат — широкие белые полосы, пересекающие пол и стены.
**После:** остаются сами маркеры с их штатными компактными подложками и обычный
текст комнаты; дополнительного прямоугольного фона вокруг полного габарита
элемента нет.
## 3. Подтверждённая причина и заменяемый контракт
Артефакт является намеренной частью Stage 3, а не браузерной ошибкой:
- `ISO_RAISED_FOOTPRINT` и `isoRaisedOverlayHalfSize()` в
`src/iso-scene-render.ts` вычисляют консервативный габарит для device,
room-label и opening-lock;
- `resolveIsoOverlayPlacement()` в `src/iso-overlays.ts` проецирует этот габарит
и использует его для wall collision, nudge и tether policy;
- `renderIsoRaisedOverlays()` рисует тот же габарит как SVG polygon;
- `.iso-overlay-plate` в `src/styles/plan.styles.ts` имеет почти непрозрачную
светлую заливку `rgba(248, 249, 247, 0.9)`;
- room footprint резервирует worst-case ширину всех включённых метрик, а device
footprint — auxiliary extent, даже если фактическое содержимое короче;
- golden `demo/golden/baselines/isometric-stage3-overlays-light.png` и
contract/smoke тесты сейчас закрепляют наличие видимого polygon.
Первый коммит с поведением — `ee7d4869` из #160. D3 и AC4 исходного ТЗ #160,
ADR и текущий `docs/ISOMETRIC.md` называют эту поверхность raised plate.
#471 заменяет только визуальную часть этого решения: консервативная геометрия
остаётся невидимым collision/fit footprint, но больше не является декоративной
поверхностью. Сам raised plane, координаты и интерактивность не отменяются.
## 4. Решение владельца
В изометрическом View ни у одного поднятого overlay нет отдельной видимой
floor-parallel подложки по его общему прямоугольному габариту.
Единое правило применяется к:
1. device marker целиком;
2. room name и room metrics card;
3. opening lock marker.
Штатные собственные поверхности содержимого не относятся к удаляемой plate:
- shell/core маркера устройства;
- value badge, LQI и прочие satellite badges;
- компактная поверхность lock marker;
- focus/selection/hover affordance, определённые самим интерактивным root.
Grounding shadow и tether остаются. Консервативный footprint остаётся
невидимой расчётной геометрией для collision, nudge, fit/home и room fit.
## 5. Скоуп
1. Прекратить вывод видимых SVG plate и plate texture для всех трёх raised
overlay kinds.
2. Сохранить footprint и все потребляющие его placement/bounds алгоритмы без
числового изменения результата.
3. Развести в именовании и документации невидимый footprint и удалённую
декоративную plate, чтобы safety envelope нельзя было снова принять за
пользовательскую поверхность.
4. Удалить ставшие неиспользуемыми plate styles и overlay texture definition;
grounding shadow definition сохранить.
5. Переписать contract/unit/browser доказательства, которые сейчас требуют
видимый polygon.
6. Переснять затронутые изометрические golden только через независимое Linux
acceptance по общему процессу.
7. Актуализировать текущие внутренние документы Stage 3.
## 6. Не входит
- изменение высоты raised plane, камеры `4°/20°`, wall height или visual offset;
- изменение размеров консервативного footprint;
- новое измерение фактического DOM, `ResizeObserver` либо layout read-loop;
- изменение wall collision, owner selection, nudge direction/cap или tether
visibility rules;
- удаление grounding shadow либо tether;
- новый фон, text shadow, blur, outline или другая замена белой plate;
- редизайн shell/core, badge, room typography либо opening lock;
- изменение z-order, Zigbee topology, Glow, sunlight, vacuum и opening volume;
- новые настройки, schema/config/layout/storage поля, миграция либо i18n;
- публичное включение изометрического режима;
- изменение Flat, редакторов или `houseplan-space-card`.
Если читаемость конкретного текста без общей подложки окажется недостаточной,
альтернативный локальный text treatment требует отдельного продуктового
решения и не добавляется в #471 попутно.
## 7. Контракт невидимого footprint
Для каждого raised overlay по-прежнему вычисляются:
1. неизменная логическая floor-точка;
2. projected floor point;
3. raised point до nudge;
4. консервативный screen-facing footprint на raised plane;
5. конечный visual point и тот же footprint после nudge;
6. grounding и tether geometry.
Footprint не попадает в SVG/HTML как закрашенная или обведённая поверхность и
не создаёт собственный stacking/paint artifact. Он остаётся входом для:
- пересечения с canonical wall silhouettes и safety gap;
- bounded inward nudge;
- `nearWallBefore` / `nearWallAfter` и tether visibility;
- `isoOverlaySceneBounds()`;
- стабильного `resolveIsoOverlayFitEnvelope()` для fit/home и room fit.
Удаление декора не должно менять ни одну координату либо boolean/status
placement result на одинаковом входе. Переименование внутренних полей
`plate*` в `footprint*` предпочтительно и не является изменением модели данных.
## 8. Контракт рендера и композиции
`iso-overlays-svg` сохраняется как inert слой для grounding и tether. В нём не
должно быть `.iso-overlay-plate`, `.iso-overlay-plate-texture` либо эквивалентной
залитой/обведённой геометрии footprint.
Порядок остаётся прежним:
1. floor/live content;
2. structural walls/openings;
3. grounding/tether cues;
4. screen-facing HTML markers/labels/locks;
5. системные tooltip/dialog/chrome.
HTML roots продолжают получать один и тот же `visualScene`. Их role, tabindex,
accessible name, pointer/keyboard handlers, hit target и CSS собственных
элементов не меняются.
`layers.materialNuance` больше не создаёт overlay texture pattern, потому что
допустимой поверхности для него нет. `layers.shadows` продолжает управлять
только grounding shadow. Ошибка decorative capability не должна переводить
сцену в Flat.
## 9. Режимы, состояния и graceful degradation
- Light/dark theme используют одно правило «без plate».
- Forced colors не возвращает `fill: Canvas` вокруг overlay; собственные
нативные поверхности marker/lock продолжают существующий forced-colors
контракт.
- No-filter скрывает grounding nuance как раньше, но не меняет наличие
содержимого.
- Reduced motion ничего не меняет в конечном кадре; новой анимации нет.
- Kiosk и coarse pointer показывают тот же результат, сохраняя минимум 44×44 px
у интерактивного HTML root.
- `show_borders:false` по-прежнему полностью отключает raised placement,
grounding и tether и возвращает overlays к floor anchor.
- Flat, Plan/Devices/Background editors и static card не получают изменений DOM
либо CSS.
## 10. UX и доступность
Новых контролов, жестов, подсказок и текстов нет. Изменение только убирает
визуальный шум. Room fit/Area link, device click/context action и opening-lock
semantics остаются действующими.
Invisible footprint, grounding и tether не получают role, accessible name,
tab stop или pointer events. Focus ring принадлежит исходному HTML root и не
зависит от удалённой plate.
## 11. Модель данных, совместимость и i18n
Config, layout, backend stores, schema version, export/import и localStorage не
меняются. Миграции и downgrade converter отсутствуют.
Внутреннее переименование поля placement не сериализуется и не является
compatibility surface. Старый frontend после downgrade прочитает те же данные
и снова покажет прежнюю plate.
Новых или изменённых строк нет; словари EN/RU/DE/FR не меняются.
## 12. Производительность и lifecycle
- Structural fingerprint, LRU cap 8 и cache invalidation остаются прежними.
- HA state, hover/focus, pan/zoom и opening update не начинают перестраивать
structural scene либо читать layout.
- Удаляются до двух SVG polygon на raised overlay и один неиспользуемый shared
texture pattern; DOM/paint объём может только уменьшиться.
- Footprint/nudge computation сохраняет прежнюю сложность и кэширование.
- Initial Flat graph и alpha lazy boundary не меняются.
- Новый performance profile не нужен; существующие Stage 3 counts,
`bundle:budget` и точечный isometric smoke не должны регрессировать.
## 13. Security и privacy
Новых API, URL, persistence, HA service call или пользовательского HTML нет.
Удаляемая геометрия уже pointer/ARIA-inert; после исправления существующие
interactive roots остаются единственными владельцами действий.
## 14. Критерии приёмки
### AC1 — видимый результат (browser raster + reviewed golden)
В light и dark изометрическом View отсутствует дополнительный прямоугольный
или квадратный фон вокруг device, room label/card и opening lock. Длинное имя
комнаты при fit/home и минимальном масштабе не создаёт белую полосу через стены.
Штатные shell/core/badges/lock surfaces остаются.
### AC2 — отсутствие скрытых визуальных fallback (contract + smoke)
Raised SVG не содержит `.iso-overlay-plate`, plate texture либо эквивалентной
painted footprint geometry при material nuance on/off, forced colors и
unsupported filter. Возврат одного непрозрачного polygon делает защитный тест
красным.
### AC3 — placement parity (unit exact matrix)
На одинаковых fixtures до/после исправления совпадают floor/raised/visual
anchors, footprint points, nudge vector/distance, near-wall flags, status,
reason, tether и grounding для device, room-label и opening-lock.
### AC4 — fit и границы (unit + browser smoke)
`isoOverlaySceneBounds`, fit/home и room fit продолжают учитывать невидимый
footprint и полный screen-facing root. Конечный viewBox и позиция элементов не
меняются только из-за удаления декора; длинные/короткие имена и 0/часть/все
room metrics не клипуются.
### AC5 — interaction и touch (browser smoke)
Device hover/focus/click/context action, room click/Area link, lock action и
44×44 px target работают по прежним roots. Ground/tether/footprint не
перехватывают pointer. Kiosk/coarse pointer сохраняют View safety floor.
### AC6 — режимы и соседние слои (contract + browser smoke)
`show_borders:false` возвращает floor placement без raised subtree; Flat,
редакторы и static card не меняются. Zigbee topology endpoints продолжают
совпадать с фактическими поднятыми marker positions.
### AC7 — data/performance contract (unit + source contract)
Нет новых config/layout/storage/i18n/network/service полей. Structural
fingerprint/build count и LRU не меняются; overlay material definition count и
polygon count уменьшаются, а bundle остаётся в действующем бюджете.
### AC8 — документация и артефакты (review)
`docs/ISOMETRIC.md`, ADR #160 и исходное ТЗ #160 явно отмечают superseding
решение #471: plate как видимая поверхность удалена, footprint как расчётная
геометрия сохранён. Затронутые golden приняты независимым reviewer из полного
Linux artifact.
## 15. План автотестов и red witnesses
### Unit/contract
1. Обновить `test/iso-overlays.test.mjs`: footprint остаётся четырёхугольником,
а все placement outputs для free/near-wall/nudged/degraded/no-borders
fixtures сохраняются.
2. Обновить `test/iso-scene-render.test.mjs`: footprint по-прежнему учитывает
device auxiliaries и room metrics; scene/fit bounds используют его без
видимого renderer.
3. Обновить `test/isometric-contract.test.mjs`: запретить plate selectors,
polygons и overlay texture definition; сохранить raised root, grounding,
tether, forced-colors и 44 px contracts.
4. Проверить material definition count без orphan `hp-iso-overlay-texture`.
### Browser smoke
Расширить `demo/smoke_isometric_contract.mjs` и при необходимости
`demo/smoke_isometric_live_touch.mjs`:
- dense device set и room label с 0/частью/всеми метриками;
- отсутствие painted footprint в обычном, dark, forced-colors и no-filter;
- неизменные centres/nudge/tether/bounds;
- fit/home и room fit без клиппинга;
- pointer/keyboard/coarse-pointer actions и 44 px target;
- topology endpoint следует фактическому marker root.
### Golden
Переснять только действительно изменённые Iso Stage 3 кадры. Flat baselines
должны остаться byte/pixel unchanged. Обязателен плотный общий кадр с длинными
названиями и несколькими типами marker; возвращённая непрозрачная plate должна
создавать заметный diff.
Golden acceptance выполняет только независимый reviewer через
`npm run golden:accept -- --reviewed` на полном Linux CI artifact с provenance.
### Red witnesses
| Witness | Искусственная поломка | Обязательный красный тест |
|---|---|---|
| W1 | Вернуть один painted footprint polygon | DOM/raster smoke и Iso golden |
| W2 | Удалить footprint из wall collision | near-wall/nudge unit |
| W3 | Удалить footprint из fit bounds | long-room-label fit smoke |
| W4 | Удалить 44 px target вместе с plate | coarse-pointer smoke |
| W5 | Вернуть `fill: Canvas` plate в forced colors | forced-colors contract/smoke |
| W6 | Оставить orphan overlay texture pattern | definition-count contract |
Каждый witness запускается на минимальном тесте и полностью откатывается до
финального зелёного состояния.
## 16. Ожидаемые файлы реализации
Продукт и тесты:
- `src/iso-overlays.ts`;
- `src/iso-scene-render.ts`;
- `src/styles/plan.styles.ts`;
- `test/iso-overlays.test.mjs`;
- `test/iso-scene-render.test.mjs`;
- `test/isometric-contract.test.mjs`;
- `demo/smoke_isometric_contract.mjs`;
- при необходимости `demo/smoke_isometric_live_touch.mjs`;
- затронутые Iso golden после независимого принятия.
Документация:
- `docs/ISOMETRIC.md`;
- `docs/ARCHITECTURE.md`;
- `docs/adr/160-isometric-stage3-overlays.md`;
- `docs/specs/160-isometric-stage3.md`;
- `docs/TESTING.md` и `docs/STATUS.md` только в части действующего Stage 3
контракта/доказательств;
- этот документ и индекс `docs/specs/README.md`.
Backend, schema, translations и `src/space-card.ts` не меняются.
## 17. Release-артефакты
Изометрический Stage 3 остаётся скрытым за `hp_alpha`, поэтому по действующему
решению #160 реализация имеет `User-Visible: no` и не получает публичную запись
в `docs/CHANGELOG.md`, `docs/CHANGELOG.ru.md`, README, User Guide, HACS или
release body.
Обязательны:
- синхронные manifest-driven bundles через `npm run bundle:sync`;
- адресные unit/contract/browser tests;
- `golden:verify` с ожидаемым Iso diff и отсутствием Flat diff;
- independently reviewed Linux golden acceptance;
- `check-docs` и штатные exact-SHA beta gates;
- обновление внутренних Stage 3 документов в том же product commit.
## 18. Риски и меры
| Риск | Мера |
|---|---|
| Вместе с декором удаляется collision geometry | Отдельное имя footprint и exact placement unit matrix |
| Fit начинает клиповать длинные подписи | Footprint остаётся в scene/fit bounds; browser fit smoke |
| Исчезает штатная shell маркера | AC1 отдельно различает native surface и raised plate |
| Forced colors возвращает белые квадраты | Negative selector + forced-colors smoke |
| Tether/grounding исчезают из-за удаления всего subtree | Отдельные DOM assertions и golden |
| Golden снова закрепляет случайный фон | W1 и обязательный dense reviewed frame |
| Переименование внутреннего поля задевает cache | Structural fingerprint/build-count assertions |
| Улучшение скрытой alpha попадает в публичные notes | Явный `User-Visible: no` и отрицательный список артефактов |
## 19. Откат
Кодовый откат одного product commit возвращает декоративные polygons и styles.
Config/layout/store не меняются, поэтому миграция, восстановление данных и
действия пользователя не нужны. Немедленный пользовательский workaround —
переключиться в Flat либо отключить `hp_alpha`.
## 20. Принятые технические предположения — можно менять на ревью
1. Внутренние `plate`, `plateHalfSize`, `buildIsoPlatePolygon` и
`plateNearSilhouette` переименовываются в `footprint*`; это снижает риск снова
отрисовать safety envelope. Допустимо сохранить старые имена, если tests/docs
столь же однозначно запрещают видимую поверхность.
2. `renderIsoRaisedOverlays()` может сохранить имя и выводить только tethers;
DOM topology функции не является публичным контрактом.
3. Fit/home намеренно сохраняет прежний envelope, даже если после удаления
plate визуально можно было бы вписать план плотнее. Изменение framing — другая
UX-задача.
4. Opening-lock включён в единое правило, потому использует тот же общий
renderer; оставшийся квадрат был бы тем же артефактом.
5. Grounding shadow остаётся допустимой непрямоугольной подсказкой связи с
floor anchor и не считается заменой plate.
+1
View File
@@ -28,6 +28,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
| Issue | ТЗ |
|---|---|
| [#471](https://github.com/Matysh/houseplan-card/issues/471) Убрать белые raised plates вокруг маркеров и названий комнат | [471-isometric-overlay-white-plates.md](471-isometric-overlay-white-plates.md) |
| [#6](https://github.com/Matysh/houseplan-card/issues/6) Vacuum XCME path segments | [006-vacuum-xcme-path.md](006-vacuum-xcme-path.md) |
| [#7](https://github.com/Matysh/houseplan-card/issues/7) Valetudo room outlines | [007-vacuum-valetudo-room-outlines.md](007-vacuum-valetudo-room-outlines.md) |
| [#8](https://github.com/Matysh/houseplan-card/issues/8) Vacuum support docs and XCME hint | [008-vacuum-support-docs-xcme-hint.md](008-vacuum-support-docs-xcme-hint.md) |