24 KiB
#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 подложки по его общему прямоугольному габариту.
Единое правило применяется к:
- device marker целиком;
- room name и room metrics card;
- 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. Скоуп
- Прекратить вывод видимых SVG plate и plate texture для всех трёх raised overlay kinds.
- Сохранить footprint и все потребляющие его placement/bounds алгоритмы без числового изменения результата.
- Развести в именовании и документации невидимый footprint и удалённую декоративную plate, чтобы safety envelope нельзя было снова принять за пользовательскую поверхность.
- Удалить ставшие неиспользуемыми plate styles и overlay texture definition; grounding shadow definition сохранить.
- Переписать contract/unit/browser доказательства, которые сейчас требуют видимый polygon.
- Переснять затронутые изометрические golden только через независимое Linux acceptance по общему процессу.
- Актуализировать текущие внутренние документы 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 по-прежнему вычисляются:
- неизменная логическая floor-точка;
- projected floor point;
- raised point до nudge;
- консервативный screen-facing footprint на raised plane;
- конечный visual point и тот же footprint после nudge;
- 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.
Порядок остаётся прежним:
- floor/live content;
- structural walls/openings;
- grounding/tether cues;
- screen-facing HTML markers/labels/locks;
- системные 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
- Обновить
test/iso-overlays.test.mjs: footprint остаётся четырёхугольником, а все placement outputs для free/near-wall/nudged/degraded/no-borders fixtures сохраняются. - Обновить
test/iso-scene-render.test.mjs: footprint по-прежнему учитывает device auxiliaries и room metrics; scene/fit bounds используют его без видимого renderer. - Обновить
test/isometric-contract.test.mjs: запретить plate selectors, polygons и overlay texture definition; сохранить raised root, grounding, tether, forced-colors и 44 px contracts. - Проверить 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. Принятые технические предположения — можно менять на ревью
- Внутренние
plate,plateHalfSize,buildIsoPlatePolygonиplateNearSilhouetteпереименовываются вfootprint*; это снижает риск снова отрисовать safety envelope. Допустимо сохранить старые имена, если tests/docs столь же однозначно запрещают видимую поверхность. renderIsoRaisedOverlays()может сохранить имя и выводить только tethers; DOM topology функции не является публичным контрактом.- Fit/home намеренно сохраняет прежний envelope, даже если после удаления plate визуально можно было бы вписать план плотнее. Изменение framing — другая UX-задача.
- Opening-lock включён в единое правило, потому использует тот же общий renderer; оставшийся квадрат был бы тем же артефактом.
- Grounding shadow остаётся допустимой непрямоугольной подсказкой связи с floor anchor и не считается заменой plate.