Commit Graph
83 Commits
Author SHA1 Message Date
Claude 18c9f8e77c fix(stairs): View shows the link pointer over a stair, not the move cursor (#693)
The Plan editor rule `.hp-stair.input-enabled .hp-stair-hit { cursor: move }`
also matched the View layer, which sets input-enabled only to receive
clicks. The hit area sits over the outline, so the link's pointer on the
group was never visible and every stair in View showed a drag it cannot do.

- src/stairs-view.ts: View stairs carry `hp-stair-view`.
- plan.styles.ts: `move` applies only without it; in View the hit area
  keeps the group's cursor — pointer on a link, the stage's otherwise.
- demo/smoke_stairs.mjs: computed cursors in View (link, no target) and
  in the Plan editor; the two View checks are red on the old code.
- test/stairs.test.mjs: the cascade without Chromium; mutant
  view-stair-cursor-move-again.
- docs/STAIRS.md, changelogs.

Issue: #693
User-Visible: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-29 21:52:52 +03:00
Claude 600330e187 fix(daycycle): stage-sized plan layers without a frozen raster; revert #685 hatch
With the day/night background the plan went blurry after zooming from 100 %
(sharp when the page was opened at 800 %) and navigating a strongly zoomed
plan flashed the page white. Both came from #582's composition, not from the
wall hatch that #685 replaced:

- `.stage.daycycle.hp-safe-daycycle-outline .plan-svg` promoted the scene
  with `will-change: transform`; Chromium freezes the raster scale of such a
  layer, so the 100 % raster was shown stretched. The explicit layer #582
  needs is now `will-change: opacity` (re-rasters at the current scale).
- The filtered outline had `overflow: visible` and a gesture exposed every
  scene (#544) without bound, so the promoted layers grew with zoom squared
  (CDP LayerTree, ~460 %: plan-svg 15.9x, outline 13.2x the stage; 39x after
  navigating at 800 %). The full card clips its outline to its box and marks
  it data-hp-live-overflow="clip" (never exposed); the live viewport bounds
  every other exposure with an inline clip-path: inset(-25%) that leaves
  with it, so idle DOM stays byte-identical (#531).

Owner-verified in Chrome 152 (built-in browser, DPR 2): sharp after 100 ->
800 %, no white flashes after reloading at 800 %.

Owner decision: #685's analytic gradient is reverted (13af1d5e), the single
<pattern> is back at every zoom; its close-up golden scenes stay and check
the pattern, its terminal-frame smoke checks the pattern.

Witnesses: demo/smoke_daycycle_zoom_layers.mjs (800 % x DPR 2: layers vs
stage, the hint, reload path, button/wheel/pinch); #582/#532 smokes now pin
the opacity hint; test/live-viewport.test.mjs (bounded exposure, clipped
scene); test/daycycle-layers.test.mjs (cascade). Four Node-guarded mutants.

Issue: #689
User-Visible: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-28 17:51:06 +03:00
Matysh c04d0778ae fix(stairs): use one physical line weight (#688)
Issue: #688
User-Visible: yes
2026-09-28 14:58:33 +03:00
Claude 560849a1a7 feat(plan): device markers are landmarks in the Plan editor
The Plan editor hid every device marker (display: none), so walls,
openings and stairs were placed against devices from memory. It now
shows them exactly as the Background editor does (#362): the same
markers as View, at the Background editor's effective opacity, fully
pointer-inert. The fade is filter: opacity(0.35) on each marker, not
on .devlayer, because room labels and room settings buttons share that
layer and stay opaque and interactive; filter multiplies the marker's
own opacity (.unavail -> 0.35 x 0.35), as the Background layer does.
Marker handlers already fail closed outside View/Devices.

demo/smoke_plan_device_landmarks.mjs proves AC1/AC2: same markers as
View, per-marker alpha equal to Background, core and capsule fall
through, a real click on a marker reaches the Walls tool and a room
settings button below, cursor and target unchanged, handlers inert, no
tabindex. Three mutants guard hiding, opacity override and the pointer
boundary. UX-MODES, DECOR-EDITOR, USER-GUIDE.ru mode table, changelogs.

Issue: #687
User-Visible: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-28 09:38:26 +03:00
Claude c455e7c82d fix(stairs): лестница-переход без рамки фокуса (#686)
Решение владельца 2026-09-28: «убрать рамку фокуса полностью». Навигационная
лестница View — фокусируемый `<g role="link" tabindex="0">` (#676), а своих
стилей фокуса у `.hp-stair` не было, поэтому браузер рисовал чёрно-белое
кольцо по прямоугольнику символа. Теперь `.hp-stair:focus` и
`:focus-visible` — `outline: none`: ни кольца браузера, ни замены. Лестница
остаётся в порядке Tab, Enter/Пробел по-прежнему переходят; hover и
выделение в редакторе не тронуты.

Свидетель — `demo/smoke_stairs.mjs`: снимок области лестницы с запасом на
кольцо без фокуса и с клавиатурным фокусом (`:focus-visible`) обязан совпасть
байт в байт; Enter на сфокусированной лестнице переводит на целевой этаж.
Без правила смок красный (`focusedStairPaintsNoFrame`). STAIRS.md и оба
changelog.

Issue: #686
User-Visible: yes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-28 08:28:00 +03:00
Sergey Matyunin 5b5b808184 feat: настроить визуальный стиль лестниц (#683)
Issue: #683
User-Visible: yes
2026-09-27 23:04:28 +03:00
Claude 708ed850f3 docs(hygiene): снять чек-листы testing-notes и дизайн-материалы выпущенных задач (#681)
Волна 4 эпика #674.

docs/testing-notes/: восемь ручных чек-листов по поверхностям и индекс
удалены — ни одного отмеченного пункта, ручной фазы в PROCESS.md §2 нет.
Правило #650 (пустое совпадение --test-name-pattern) перенесено в
TESTING.md; пункты [manual] без автоматического свидетеля сведены в раздел
«Чего не проверяет автоматика» (реальный HA, сенсорное устройство, ресурсы
сервера, несколько клиентов, визуальная оценка, пользовательское
содержимое). В TESTING.md снят блок чек-листов v1.43–1.44 и приложения по
issue в разделе golden (#197/#249/#272/#275/#288/#261) — сцены объявлены в
demo/golden/matrix.mjs. Остался реестр браузерных гвардов #659
(mutation-browser-guards.md). test/testing-notes-index.test.mjs →
test/testing-doc.test.mjs: лимит 800 строк, правила #85, раздел ручных
проверок и живые ссылки TESTING.md; каталог testing-notes содержит только
реестр. Мутант testing-notes-index-drops-section (удалял строку индекса) →
testing-doc-drops-manual-section. golden-matrix: копия 67 id сцен #242/#250
в чек-листе снята, список и способ его измерения — в demo/golden/matrix.mjs.

docs/design/505-summary-panel удалён вместе с
demo/capture_summary_panel_505.mjs и маршрутом /reference/ фикстуры
диалога. docs/design/600-settings-dialogs: reference/, screenshots/,
pairs/, ARCHIVE-README, ISSUE-FORM, OPEN-POINTS удалены; SPEC,
IMPLEMENTATION-GUIDE, field-maps, ACCEPTANCE остаются; вывод
capture_design_pairs_600.mjs и verify_ha_form_shell_609.mjs --capture —
в artifacts/. docs/design: 68 файлов / 4,08 МБ → 13 / 0,70 МБ.
README-ha-dialog-505.md → README-ha-dialog.md (путь в release-review.yml);
demo/guard/README.md: запись гварда — в verify-guard.mjs, не в README.

docs/design/649-25d-stage6 не тронут — пункт после стабильного v1.78.0.

Issue: #681
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 21:27:57 +03:00
Claudeandclaude[bot] 5a258f3128 docs(hygiene): свести дубли документов подсистем и снять устаревшее (#679)
Волна 2 эпика #674 — у каждого правила один дом, остальные места ссылаются.

DECOR-EDITOR.md ← BACKDROP.md + LIVE-TEXT.md: один документ с нумерованными
разделами (§3 подложка, §5 текст с живыми значениями), на которые теперь
указывают комментарии кода вместо несуществовавших «BACKDROP §2/§3»;
исправлено утверждение, что space-card не рисует декор (он рисует подложку
и картинки декора, но не фигуры, мебель и текст). LIGHT.md ← матрица
настроек света (перевод, тест назван явно: test/devices.test.mjs «issues
84/88»). DEVICE-PRESENTATION.md ← правила «что показывает маркер» из
FILTERING.md (порядок cover → light sources → device role, шторы,
медиаплееры); «в одном pull request» → «в одном коммите». CANVAS.md: §9.5
«Оптимизировать планы» → CONFIG-COMPATIBILITY.md, overlay и планарные грани
Walls → WALL-THICKNESS.md §10–11, таблицы «было/стало» сняты. TESTING-DEMO.md
→ demo/stand/README.md: карта демо-дома и «чего на стенде нет», ручной
чек-лист снят (ручной фазы в процессе нет). ISOMETRIC.md — только текущее;
история Stage 2/4 — docs/adr/570-isometric-stage4-visual-handoff.md.
SUN.md: удалённый контракт фона снят, правило бумаги — в текущем разделе.
UX-MODES.md: декор над заливками, а не «под комнатами»; «hidden isometric»;
follow-up из #3 — все выпущены. Шапки VACUUM, WARM-REMOUNT («Выровнять всё
по сетке» → «Оптимизировать планы»), WALL-THICKNESS, STYLING-HOOKS,
CONFIG-COMPATIBILITY (#33), PDF-EXPORT — без устаревших статусов и планов.
README EN/RU: абзац про пересъёмку скриншотов → CONTRIBUTING.md, RADAR и
PDF-EXPORT в списке документации, RU догнал EN (2.5D, повторное
использование загруженного изображения, STAIRS). Один список канонических
документов подсистем в AGENTS.md и промпте ревьюера (_process.yml).
WALL-THICKNESS.md ссылается на ADR 282.

Правки src/** и validation.py — только пути документов в комментариях.

Issue: #679
User-Visible: no
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 18:07:37 +00:00
Claudeandclaude[bot] 93051edfc2 fix: переписать слой редактирования лестниц на box-контракт декора (#676)
Лестница рисуется протяжкой, как прямоугольник или эллипс декора: длинная
ось протяжки — ось подъёма, стрелка смотрит от нажатия к отпусканию, клик
ставит размер по умолчанию. Выделенная лестница получает рамку декора в
верхнем оверлее карточки — выше тел стен, с узлами постоянного экранного
размера и курсорами по мировому направлению узла; винтовая — четыре узла на
касательных. Ресайз идёт от противоположной стороны, не зеркалит и не
поворачивает; магнит работает по сторонам: в пределах 6 клеток и 5° сторона
ложится на видимую грань стены, при перемещении лестница доворачивается не
больше чем на 5°, при ресайзе и черновике — никогда. Грани перегородок и
колонн получают внешнюю сторону по обходу многоугольника.

Клик, синтезированный после жеста, глушится: под «Лестницей» больше не
появляется копия, под «Выбором» не пропадает выделение. Диалог свойств
считает в сантиметрах лестницы (30…10000), а не в конвертере толщины стены;
нетронутое поле хранит число бит в бит, «Сохранить» без изменений ничего не
пишет. В Просмотре наведение на лестницу с корректной целью показывает
«Переход на этаж …» — ровно при том же условии, что делает её ссылкой.

Чистые функции слоя — в stairs-editor-model.ts с юнитами; смок лестниц
покрывает протяжку, курсоры, рамку над стенами, клик после жеста, диалог и
пять состояний подсказки; реестр мутантов получил шесть свидетелей.

Issue: #676
User-Visible: yes
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-09-27 14:41:18 +00:00
Sergey Matyunin d03a68b88a feat: добавить лестницы между этажами (#663)
Прямые и винтовые лестницы получили отдельную модель, инструменты редактора, безопасную межэтажную навигацию, вычитание из чистой площади и плоское отображение в 2.5D.

Issue: #663
User-Visible: yes
2026-09-26 21:00:43 +03:00
Claude c93b3a90ef fix(2.5d): room metrics keep their distance from the name at every zoom (#665)
The raised room label in 2.5D View sized its own box to the 44 px touch
minimum (min-height + justify-content: center). The name therefore sat
centred in 44 px while the metrics row, placed absolutely from the label
bottom, hung (44 - name height) / 2 below it: 18.3 px at a 9 px name and
6.4 px at a 39 px one on the demo stand, against a constant 0.1 name
height on the flat plan.

The 44 x 44 px floor moves into an invisible ::before (the door-lock
pattern), z-index -1 inside the label stacking context; the label box is
sized by its text again.

demo/smoke_iso_room_label_metrics.mjs measures gap / name height at two
cameras (font x4) in Flat and 2.5D, and the 44 px floor and area-link hit
targets on labels no raised device covers. Mutant
iso-room-label-44-box-centres-name.

Screenshots: 11 frames pixel-identical, fingerprint only.

Issue: #665
User-Visible: yes
2026-09-26 15:16:14 +03:00
Claude 3bdd3c5163 fix(header): the active editor tab highlight covers its close X (#666)
The accent fill of the active Plan/Devices/Decor tab is now a pseudo-element
stretched over the 2 px group gap and the fixed 24 px X slot of #660, so
the X sits inside the highlighted zone without any box moving: the tab,
the slot, the X and the header keep their geometry. The X takes the tab
text colour, and the keyboard focus ring moves to the same pseudo-element
so it outlines the whole zone instead of cutting it at the tab edge.
.modes becomes its own stacking context so the z-index:-1 fill paints above
the group background. On a phone the mode tabs, and the fill, stay hidden.

smoke_toolbar_stable_width: painted-pixel probes for the gap, the slot edge
and top, and the first pixel after the slot, in every editor at every width
above 480 px; the X colour equals the tab colour. The existing geometry
and hit checks are unchanged and green. Mutant
toolbar-active-highlight-stops-at-tab.

Screenshots: 11 frames pixel-identical, fingerprint only.

Issue: #666
User-Visible: yes
2026-09-26 14:36:14 +03:00
Sergey Matyuninandclaude[bot] d3c88f06f9 feat: отполировать главную панель редакторов (#660)
Issue: #660
User-Visible: yes
2026-09-26 08:51:15 +00:00
Sergey Matyunin f5c6d70b7c fix: stabilize cold 2.5D first frame
Issue: #654
User-Visible: yes
2026-09-26 09:05:20 +03:00
Sergey Matyunin ec2b8c1522 fix(2.5D): preserve geometry on settings toggle
Проверка (CI) / Классификация изменённых файлов (push) Successful in 3m7s
Проверка (CI) / Предполёт: документация, провенанс, процесс (push) Failing after 6m52s
Проверка (CI) / Мутанты по диффу (1/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (2/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (3/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (4/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (5/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / Мутанты по диффу (6/6): затронутые свидетели краснеют (push) Skipped
Проверка (CI) / HACS: валидация репозитория (push) Failing after 29s
Проверка (CI) / Переиспользование: это дерево уже проверено (push) Successful in 57s
Проверка (CI) / Hassfest: манифест интеграции (push) Failing after 16s
Проверка (CI) / Фронтенд: типы, юниты, мутанты, синхрон бандла (push) Failing after 1m25s
Проверка (CI) / Смоки в браузере (шард 1 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 2 из 3) (push) Skipped
Проверка (CI) / Смоки в браузере (шард 3 из 3) (push) Skipped
Проверка (CI) / Смоки: все шарды зелёные (push) Skipped
Проверка (CI) / Golden-кадры против принятых эталонов (push) Skipped
Проверка (CI) / Перф-смок: бюджет времени кадра (push) Skipped
Проверка (CI) / Геометрия: TS/Python parity исполнена (push) Failing after 1m32s
Проверка (CI) / Бэкенд: pytest в Home Assistant (push) Failing after 5m6s
Проверка (CI) / Доказательство выполненных проверок (push) Failing after 18s
Issue: #649
User-Visible: no
2026-09-25 23:33:07 +03:00
Claude e5ab4659f6 feat: 2.5D stage 6 — public setting, raised tiles, soft sun, theme-free walls (#649)
- settings.volumetric_view (General settings › Display, third switch) replaces
  the alpha entry, the header projection toggle and the phone-menu item; one
  rule for card, sidebar page and kiosk; editors stay Flat; backend accepts
  only a boolean, support package copies it.
- Raised tiles in 2.5D View: no ring, rounded body min(0.275 D, 0.3 h), edge
  0.1 D with the lab filters, ×1.12 size also in layout/collision, lift
  0.075 D, one floor-shadow layer under all markers (theme × floor table),
  frames hugging tile and edge (Alert > Focus > Selected > Hover), forced
  colours without edge and shadow (src/iso-tiles.ts, styles/iso-tiles).
- Soft sun wash instead of projected Flat wedges (src/iso-sun.ts): same gates
  and windows as sun_rays, length from elevation, parallelogram along the sun,
  tone and streaks by floor lightness, sill line.
- Walls take the user's wall colour (top opaque, sides × .77/.68/.60); theme
  rules for walls/openings/labels removed; furniture uses the Flat stroke rule.
- Smokes smoke_iso_tiles/iso_sun/iso_theme_walls/volumetric_setting, 16 new
  mutants, acceptance scenes STAGE6_ACCEPTANCE_SCENARIOS (golden with their
  Linux CI baselines), ACCEPTANCE.md side by side.

Issue: #649
User-Visible: yes
2026-09-25 18:55:14 +03:00
Sergey Matyuninandclaude[bot] 2452c51d00 feat: вертикальный resize карточки в Sections (#648)
Issue: #648
User-Visible: yes
2026-09-25 13:11:44 +00:00
Claude 255330b9bc Шапка на телефоне: одна строка — вкладки, масштаб и шестерёнка с меню остального (#616)
На окне не шире 480 px шапка карточки и страницы бокового меню занимает одну
строку ≤ 56 px: вкладки пространств (без шестерёнок и «+», прокрутка вбок,
текущая вкладка докручивается в видимую область), масштаб, одна шестерёнка
«Действия и настройки» и у админа слот крестика #647. Заголовок скрыт.

Меню шестерёнки (src/header-menu.ts): редакторы, настройки и добавление
пространства, общие настройки, PDF, помощь, сводная панель и объёмный вид
(alpha) — в фиксированном порядке и с теми же условиями и действиями, что у
прежних кнопок. Пункт закрывает меню; Escape возвращает фокус на шестерёнку;
касание вне меню поглощается прозрачной подложкой. На > 480 px шапка прежняя,
в киоске меню нет.

- три кнопки шапки вынесены в renderHeaderActions — шапка карточки не растёт;
- сводная панель отдаёт свои пункты методом menuItems();
- i18n: title.header_menu (en/ru/de/fr);
- потолок initial View 291 000 → 292 600 (замер 291 635), база bundleBytes;
- смок smoke_mobile_view_header, юнит header-menu, 10 мутантов; смоки
  support_feedback, gear_tabs, modes, toolbar_stable_width переведены на
  меню на ≤ 480 px; подпись вкладки в span.tabtitle без pointer-events;
- USER-GUIDE.ru, UX-MODES, TOUCH-SUPPORT, STYLING-HOOKS, data-hp-contract,
  оба changelog.

Issue: #616
User-Visible: yes
2026-09-25 14:22:36 +03:00
Claudeandclaude[bot] f0ba7c5da9 Основная панель: без счётчика устройств, × редактора в своём слоте — ширина шапки не меняется (#647)
Счётчик «N устр.» и ключ count.devices удалены вместе с правилом
`.head .count` (скрывало счётчик на ≤1100 px). Крестик закрытия редактора
вынесен из активной кнопки режима в отдельный слот `.editor-close-slot`
сразу после группы кнопок режимов: 24 × 24 px (--hp-editor-close-size),
одинаковый в редакторе и вне его; вне редактора слот пуст, aria-hidden,
без фокуса и pointer-events. Кликабельная зона × — весь слот (≥24×24, #195),
глиф 13 px; × виден на любой ширине, где видны кнопки режимов.

Смок smoke_toolbar_stable_width (1400/1000/768/390 px, en/ru): ширина
шапки и отступы кнопок стабильны во всех переходах, × виден, попадание
в край зоны закрывает редактор, нет нового overflow. smoke_editor_tabs,
smoke_edge_cases, smoke_hidden_flag переведены на слот/список устройств.
6 мутантов. docs: UX-MODES.md, STYLING-HOOKS.md, data-hp-contract.json.

Issue: #647
User-Visible: yes
2026-09-25 08:35:57 +00:00
Sergey Matyunin 62d0f50593 feat(editor): перетаскивание кнопки настроек комнаты (#645)
Кнопка сохраняет положение в пределах комнаты только на время сессии редактора,
корректно отменяется при pinch/cancel и учитывается подписями Resize.

Issue: #645
User-Visible: yes
2026-09-25 08:33:07 +03:00
Claude d17bcc05fb feat(devices): пакетное «Скрыть/Показать выбранные» в каталоге устройств (#618)
На вкладках «На плане» и «Скрытые» — флажки строк, «Выбрать все (N)» по
всему отфильтрованному набору (включая строки за «Показать ещё»), панель
«Выбрано: K · Скрыть/Показать выбранные (K) · Снять выбор» в отдельном
контейнере .device-inbox-batch вне .device-inbox-filters.

- src/device-inbox.ts: чистые inboxVisibilityAllowed (один источник для
  canHide/canShow и выбора), selectableInboxRows, effectiveInboxSelection,
  applyInboxVisibility — свёртка одиночных действий; одиночное = пакет из
  одной строки.
- src/device-inbox-batch.ts (новый, lazy editor): выбор, панель, строка-
  флажок и writeInboxVisibility — одна запись houseplan/config/set с
  expected_rev на пакет, busy='__batch__' (inert), откат маркеров при отказе,
  выбор сохраняется и сужается. Одиночный _setInboxHidden рантайма — тонкая
  обёртка над той же записью; рантайм стал короче базы на 14 строк.
- сброс выбора при смене вкладки (клик и стрелка), поиска и «Только новые».
- i18n en/ru/de/fr: 9 ключей по ТЗ §8.
- смок demo/smoke_device_inbox_batch.mjs (AC1–AC8, AC10), юниты
  test/device-inbox.test.mjs (AC2, AC4), 4 мутанта в реестре.
- docs: USER-GUIDE ru/en, FILTERING.md, оба changelog.
- monolith-baseline: hostRefs 4948→4959, bundleBytes 2500387→2505569 —
  новая фича (состояние выбора и запись идут через порт хоста).
- bundle-budget: LAZY_EDITOR_GZIP_CEILING 245 400 → 246 600 (замер 245 610,
  +1 190 Б gzip от базы 244 420); initial View 289 449 → 289 765 (+316 Б,
  строки en-словаря), в пределах потолка.

Golden device-inbox-* изменятся ожидаемо — пересъёмка предрелизным гейтом
на Linux CI (§11.4).

Issue: #618
User-Visible: yes
2026-09-24 22:50:30 +03:00
Claude 4c9e013276 fix(dialog): align HA settings form shell (#609)
Use Home Assistant's public dialog tokens for the reviewed 560 px canvas, height cap, single scroller and mobile fullscreen layout. Keep generic dialogs and the native fallback unchanged, with authentic-HA evidence and mutation witnesses.

Issue: #609
User-Visible: yes
2026-09-23 03:18:37 +03:00
Claude 08a56953cc fix(settings): polish dialog colours and actions (#605)
Make colour tiles solid, readable and fully clickable; align Data actions and device icon field with the form kit. Cover narrow Windows layouts and both icon-picker branches with a focused browser smoke.

Issue: #605
User-Visible: yes
2026-09-21 13:13:50 +03:00
Claude 0a3e0674cc fix(dialogs): finish discard, switch and room polish (#603)
Issue: #603
User-Visible: yes
2026-09-21 08:53:05 +03:00
Claude 746147d0e0 fix(dialogs): polish settings layout and radar flow (#602)
Issue: #602
User-Visible: yes
2026-09-20 23:06:43 +03:00
Claude 8dc60aec6e fix(dialogs): находки код-ревью #600 r1 — сегмент без разрыва слов, радиус без блокировки Save, свидетель дефекта №5
M1. Подпись сегмента больше не рвётся посреди слова: колонка `.hpf-seg label`
не сжимается ниже самого длинного слова (`min-width: fit-content`, для
браузеров без него — прежний `0` строкой выше), слова переносятся только по
пробелам (`overflow-wrap: normal`), не поместившийся сегмент переносится на
вторую строку целыми кнопками (`flex-wrap`). Новый свидетель
demo/smoke_dialog_segments_i18n.mjs — четыре диалога × en/ru/de/fr: у каждой
подписи число строк (по Range текстового узла: span — flex-элемент, у блока
один прямоугольник даже при переносе) не больше числа слов, текст внутри
кнопки. На разметке r1 краснеет на en/ru/fr комнаты («Temperature» в 2
строки, «По температуре» в 3). Мутант form-kit-segment-breaks-words
возвращает прежние две строки CSS. ACCEPTANCE.md — строка про подписи
сегмента переписана.

M2. Glow radius — не условие Save: как на dev, нечисло или неположительное
значение при сохранении молча становится общим радиусом. Удалены
glowRadiusValid, MarkerProblem marker.error_glow_radius, ключ в четырёх
локалях словаря settings, aria-invalid у поля; смок device_settings_form
утверждает обратное прежнему (badRadiusDoesNotBlockSave,
zeroRadiusKeepsSaveEnabled) и проверяет «Review N fields» на привязке в
create-режиме. Changelog EN/RU и USER-GUIDE ru/en больше не называют радиус
среди ошибок; таблица устройства говорит про молчаливый общий радиус.

M3. Свидетель дефекта №5 (поповер «?» обрезается границей диалога комнаты):
demo/smoke_dialog_help_clipping.mjs — короткое окно 900×620, диалог комнаты
скроллится, «?» нижней карточки прижат к краю; подсказка выходит за край
скроллера и остаётся hit-test'ируемой во всех пяти точках (elementsFromPoint
сквозь теневые корни — обрезанная часть не hit-test'ится). Четыре ветки:
нативный <dialog> и ha-dialog × Popover API и портальный fallback; ветка
ha-dialog — заглушка с ловушками настоящей mwc-поверхности (transform +
overflow: hidden + собственный скроллер), portal вне поверхности проверен
явно. Настоящий ha-dialog (#505, загрузка колеса HA-frontend) — отдельная
диагностическая приёмка владельца; так и записано в ACCEPTANCE.md, где
появилась таблица AC8 «девять дефектов — свидетель на каждый».

M4. ACCEPTANCE.md: эталонов 13, а не 11 — одиннадцать из ТЗ (список AC10
унаследован от #598 без комнаты) плюс две room-temperature-dialog-*.

L1. USER-GUIDE.ru.md: испорченная строка таблицы настроек пространства
(хвост удалённой строки про декоративный слой) — убран; пояснение «в
редакторе подложки остаются видимыми» вернулось в строку «Видимые слои»;
строка про солнце говорит «слой Двери, окна и ворота выключен» вместо
«Скрыть проёмы включено».

Фикстуры листа диалогов набора пересняты (панель — байт в байт).

Бюджет: initial 289 852 / 290 900; lazy editor 242 989 / 243 900.

Гейты: typecheck, build, bundle:sync (три копии), npm test 2794 pass по
четырём частям, no-new-any, mutation-gate --check, check-inputs --coverage,
смоки: segments_i18n, help_clipping, четыре формы, config_parity,
help_affordance, room_settings, settings_dialog_cards.

Issue: #600
User-Visible: yes
2026-09-20 16:37:31 +03:00
Claude c3e64dc60a feat(dialogs): финал #600 — мёртвые стили, парные кадры, документация, потолки
Завершение четырёх серий по референсу docs/design/600-settings-dialogs/:

- из eager-листов dialogs.styles.ts и chrome.styles.ts сняты стили прежней
  разметки диалогов (.bindsel/.bindharow/.entcheck, .ctrlchip*, .markerhelp*,
  .helpfieldlabel, .markerradios, .markerlightdisabled, .markerbadgetechnical,
  .markerglowvalue, .fileupload, .descin, .pdfedit/.pdftag, .gsrow,
  .ripple-*row, .radaradditional, .togglehint, футеры marker/room) — 5,8 КБ
  исходника; с разметки сняты уже пустые классы;
- «Additional actions» карточки Details — подзаголовок и строка действий
  набора, без раскрывашки (radar-section.ts, только additional-placement);
- Q3 уточнён по кадру: hp-device-preview стоит без обёртки — у него свой
  заголовок «Display preview · Now», второй над ним удваивался; пустое
  состояние — блок на тинте;
- §6.1: «?» у комнаты стоит у поля Home Assistant area, а не у заголовка
  Basics; подписи сегмента заливки — None · Zigbee · Lights · Temperature ·
  Custom (два коротких ключа room.fill_seg_*), источники — «Average of the
  room’s sensors / Specific device or entity», режим свечения — «Colour and
  brightness» (тексты прежних ключей укорочены под сегменты);
- подпись поля с «?» и без стоят на одной линии в сетке (min-height 32 по
  кнопке hp-help); иконка внутри подсказки — inline;
- парные кадры: demo/capture_design_pairs_600.mjs снимает четыре диалога в
  двух темах на 560 в состояниях макетов → docs/design/…/pairs/ (8 PNG,
  палитра 256, ~0,5 МБ); ACCEPTANCE.md — статус по диалогам, расхождения с
  референсом по каждому со ссылкой на пункт SPEC и принятые адаптации (шапка
  hp-dialog по §3, тумблеры набора по К7, секции радара/пылесоса по §7.2);
- changelog EN/RU («Не выпущено»), USER-GUIDE ru/en: раздел «Как устроены
  диалоги настроек», таблица настроек пространства по новым карточкам,
  диалог комнаты, диалог устройства, ссылка «Как у пространства»;
- бюджет: стартовый граф 289 853 — потолок 291 600 → 290 900 (снятые стили);
  ленивый редакторский 243 149 — итоговый потолок 243 900 с разбором по
  сериям в bundle-budget.mjs.

Golden: 11 сцен диалогов (device-dialog-*, room-temperature-dialog-*,
toggle-entity-dialog-*, device-help-popover-light-ru,
general-color-popover-desktop-en, settings-help-zoom-200-*,
device-ripple-color-popover-mobile-ru, space-room-color-popover-desktop-ru)
прогнаны диагностически (capture, HP_ALLOW_FOREIGN_CAPTURE, только
artifacts/): харнесс проходит все пути без исключений, кадры «different» —
эталоны переснимаются на Linux CI / машине владельца по #455.
Скриншоты документации (06-device-editor, 06-device-display-preview и др.)
устарели по отпечатку — пересъёмка перед кандидатом беты (#479).

Гейты: typecheck, build, bundle:sync (три копии байт в байт), npm test
2793 pass по четырём частям, mutation-gate --check, check-inputs --coverage,
фокусные смоки четырёх форм и смоки диалога устройства.

Issue: #600
User-Visible: yes
2026-09-20 13:01:07 +03:00
Claude bf6602bbd8 feat(device): «Устройство на плане» по референсу — серия 4 из четырёх (#600)
§7 SPEC.md референса. Пять карточек #598 остались, менялось содержимое; все
ключи _markerDialog и все записи в них прежние (§7.2):

- Basics — баннеры привязки стали callout'ами; Name с подсказкой «Shown on
  the plan»; привязка — сегмент [Virtual | From the HA list] (те же радио
  bmode) и кнопка выбора #marker-binding с панелью в потоке (sourcePicker
  набора), чекбокс «Show entities» — внутри панели рядом с поиском (решение
  владельца Q8); Room селектом с подсказкой «по зоне / переопределяет»;
  секции радара и пылесоса — своими модулями без изменений;
- Tap action — селект с подсказкой Target/Now, «Ask for confirmation» —
  строка-тумблер только при toggle/run (Q8), Entity to toggle и What to run
  теми же условиями (список целей — панель набора), «Controls other light
  sources» — чипы набора и поиск с панелью в потоке;
- Light and glow — «Include the device temperature…» строкой-тумблером;
  роль — сегмент [Auto | Always | Never] с подсказкой результата Auto;
  Leading light entity по условиям; блок свечения (.hpf-block): подзаголовок
  с «?», сегмент [From source | Set colour | Colour and brightness] с
  отключёнными вариантами и aria-describedby на объяснение, плашка цвета
  вокруг прежнего hp-color-opacity (Q5), яркость и радиус строками с
  числом и единицей, при Never блок неактивен целиком (aria-disabled) с
  callout'ом причины;
- Appearance — поле иконки с превью, очисткой и ссылкой Pin в подсказке;
  Display селектом с подсказкой режима; пульс — плашка цвета и строка
  размера; Value source по условиям; подраздел Value badge — компактный
  тумблер, Value селектом с техническим идентификатором, Position сегментом
  [Above | Right | Below | Left]; предупреждения бейджа — заметки и
  callout'ы; Display preview — прежний hp-device-preview целиком в блоке на
  тинте с тегом Now (решение владельца Q3); «Icon size and rotation» —
  две строки range-line в сетке;
- Details — Model и Link в ряд, Description textarea набора, Manuals чипами
  и строкой действий Attach…, «Additional actions» подзаголовком набора.

Футер: Hide и Delete слева, статус, Cancel и Save справа. К10: снимок
черновика при _openMarkerDialog (marker-form-state.ts поверх
dialog-baseline; транзиентные ключи — раскрытие и фильтры списков, busy,
объявление подсказки, autoIcon, uploadId); в edit Save только при
изменениях, закрытие с изменениями спрашивает через _confirmDanger. Прежние
запреты Save (busy, калибровка радара, привязка не выбрана/не подтверждена)
остались; привязка и радиус свечения названы словами под полем
(marker.error_binding, marker.error_glow_radius), «Review N fields» ведёт к
полю. Тумблеры диалога — строки набора (нативный чекбокс, К7), а не
ha-switch; слайдеры — прежний _rangeInput (ha-slider в HA).

Набор: sourcePicker получил toolbar и disabled; сегмент — value у радио,
disabled и describedBy у варианта; callout — role note и id; unitInput —
describedBy; rangeLine — id; новые классы .hpf-block/.hpf-disabled,
.hpf-toolbar/.hpf-check, .hpf-iconfield/.hpf-iconpreview, .hpf-mono,
.hpf-note, .hpf-hint-line, textarea.hpf-input. settingsCopy вынесен в
editors/settings-copy.ts (общий для пространства, комнаты, устройства).

Смоки переписаны осознанно, с пометкой #600: binding_ui (#marker-binding,
.hpf-panel, #marker-show-entities), tap_run (панель набора, #marker-tap-
confirm), value_face_source (.hpf-cand.sel), static_icon (callout'ы),
climate_temp (#marker-use-climate-temp), help_affordance (#marker-name,
.hpf-block.hpf-disabled вместо fieldset[disabled]; второй Escape в грязном
диалоге спрашивает — К10), size_angle_parity (сетка Appearance),
color_picker_consumers (подписи полей), device_preview_parity (сегмент
стороны), ha_controls (тумблеры набора — нативные чекбоксы по К7, ha-slider
прежний). Golden-harness device — .hpf-field/.hpf-block, скроллер .content.
Новый фокусный свидетель demo/smoke_device_settings_form.mjs: пять карточек
без старой разметки, оболочка, привязка/панель/Show entities, Q8, сегменты и
блок свечения, плашки, иконка, бейдж, превью на тинте, размеры, Details,
цели 44, Save/dirty/вопрос при закрытии, create-режим, семь полос экранов.

Мутанты: marker-save-enabled-without-changes, marker-discard-without-asking,
marker-confirm-row-shown-for-do-nothing, marker-never-keeps-glow-block-live,
marker-badge-position-forgets-touch; якоря same-binding-click-resets-source,
state-callout-hidden-under-help, form-kit-segment-drops-radio-semantics
переставлены на новую разметку.

Контрактные тесты: color-picker (два поля набора вместо flex-строк),
native-select-contract (сторона бейджа — сегмент), i18n dead-keys (34 → 38
подсказок), German=English (marker.name_label). Словарь i18n/settings: 21
ключ marker.* на четыре локали; в основном каталоге marker.name_label
«Name», marker.size_label «Icon size and rotation», удалены мёртвые
marker.room_override, marker.light_role_always/never. Фикстуры листа
диалогов набора пересняты намеренно (панель — байт в байт, AC11).

Бюджет: стартовый граф 290 489 (потолок 291 600 без изменений); ленивый
редакторский 243 173 — потолок 240 100 → 243 900 с разбором в
bundle-budget.mjs; старые стили диалога устройства снимаются в финале.

Гейты: typecheck, build, bundle:sync (три копии байт в байт), npm test
2790+ pass по четырём частям, mutation-gate --check, 39 смоков диалога
устройства + новый + три формы серий 1–3.

Issue: #600
User-Visible: no
2026-09-20 12:18:12 +03:00
Claude e2c0c7ed81 feat(room): «Настройки комнаты» по референсу — серия 3 из четырёх (#600)
§6 SPEC.md референса. Четыре карточки #594 остались, менялось содержимое:

- Basics — Display name и Home Assistant area в одну строку из двух полей
  (#room-name, #room-area — контролы набора); подстановка имени из зоны при
  пустом имени прежняя;
- Fill — «Как у пространства» стала строкой-тумблером (#room-fill-inherit,
  решение владельца Q4): включена — подсказка «Следует за пространством:
  режим»; выключена — сегмент из пяти режимов, который стартует с
  действующего режима пространства, а не с «None». «Свой цвет» — плашка
  вокруг прежнего hp-color-opacity (Q5): свотч, hex, число прозрачности,
  Reset у своего цвета. Границы комфорта при эффективной «Температуре» —
  два поля с единицей °C (#room-temp-min/-max) с плейсхолдерами границ
  пространства, легендой Cold / Comfort / Hot, ошибкой под полями и ссылкой
  «Как у пространства». Модуль room-temperature-controls.ts удалён — его
  разметку заменили поля набора;
- Sensor sources — подзаголовки, прежний сегмент «среднее / конкретный», при
  конкретном — кнопка выбора в стиле селекта и панель с поиском в потоке
  карточки (sourcePicker набора, роль listbox/option; общая с диалогом
  устройства в серии 4). Кандидаты и запись прежние;
- Font sizes — две строки «слайдер + число % + Reset to 100%» с концами шкалы,
  подсказка про размер карточек пространства, образец карточки сохранён
  внутри .hpf-tint (решение владельца Q2).

Футер: Cancel | статус | Save; в create — Keep as walls слева. К10: снимок
черновика при _openRoomEdit (room-form-state.ts поверх dialog-baseline),
в edit Save только при изменениях, закрытие с изменениями спрашивает через
_confirmDanger; в create Save по прежнему условию (имя или зона), отмена без
вопроса — она и раньше значила «не создавать» и возвращала контур на план.
Ошибки черновика: имя (edit) / имя-или-зона (create), нечисло в границах —
подпись под полем, «Review N fields» в футере ведёт к первому полю.

Из eager-листа dialogs.styles.ts удалены .roomtemprange*, .roomdialog .srcrow
и .dropbtn; `overflow-x: hidden` у .body убран — скроллер один (К3).

Смоки переписаны осознанно, с пометкой #600: smoke_room_settings (тумблер
вместо радио, #room-name/#room-area, .hpf-panel .hpf-cand, старт сегмента с
режима пространства), smoke_room_temperature_thresholds (.hpf-temprange,
ссылка сброса). Golden-harness room-temperature — те же селекторы. Новый
фокусный свидетель demo/smoke_room_settings_form.mjs: четыре карточки без
старой разметки, имя и зона в одну строку, оболочка 560 и один скроллер,
тумблер/сегмент/плашка/границы/источники/размеры пишут в свои ключи, Save и
вопрос при закрытии, create-режим, семь полос экранов.

Мутанты: room-save-enabled-without-changes, room-discard-without-asking,
room-fill-segment-starts-at-none, room-temp-min-writes-max. Якорь
form-kit-writes-to-a-neighbour-key прежний. smoke-links: символ
roomTemperatureControls заменён на renderRoomSettingsDialog.

Словарь i18n/settings: девять ключей room.* на четыре локали; в основном
каталоге room.area_label без «(unassigned)». Фикстуры листа диалогов набора
пересняты намеренно (панель — байт в байт, AC11).

Бюджет: стартовый граф 290 575 — потолок ОПУЩЕН 292 200 → 291 600 (ушли CSS
диалога комнаты и модуль границ); ленивый редакторский 239 391 — потолок
238 600 → 240 100 с разбором в bundle-budget.mjs.

Гейты: typecheck, build, bundle:sync (три копии байт в байт), npm test
2790+ pass по четырём частям, mutation-gate --check, смоки: room_settings,
room_settings_form, room_temperature_thresholds, editor_tabs, font_scales,
resize_labels, room_autoclose, binding_ui, color_picker_consumers,
lazy_editor_chunk, space_settings_form, general_settings_form, ux_fixes,
settings_dialog_cards, dialog_footer_width.

Issue: #600
User-Visible: no
2026-09-20 11:39:46 +03:00
Claude de71bd7967 feat(general): «Общие настройки» по референсу — серия 2 из четырёх (#600)
§5 SPEC.md референса. Семь карточек #598 остались, менялось содержимое:

- Display — две полные строки с иконкой, подписью и тумблером справа; пояснение
  радара по §5.2 стало подписью строки (текст прежний, ключ переехал в ленивый
  словарь как gs.radar_show_live_hint, «?» у строки больше нет);
- Zigbee links — заголовок и «?» функции (topology.help) рисует карточка, а
  блок hp-zigbee-topology-settings получил режим embedded: строка-тумблер,
  callout «сохраните настройку», подзаголовки ZHA / Zigbee2MQTT, поле тем и
  строки действий контролами набора. Заголовок больше не удваивается
  (дефект 1). Лист набора вносится в теневой корень компонента; токены
  --hpf-* наследуются с хоста. Прежний render без embedded не тронут — его
  держит контракт #459;
- Room fill colors — три подзаголовка (Lights / Temperature / Zigbee signal,
  Q6) и плитки цвета по три в ряд: название на свотче, hex, число
  прозрачности; свотч — trigger прежнего hp-color-opacity (Q5);
- Light-source glow — две плитки и поле радиуса с единицей внутри рамки;
- Plan — плашка цвета стен, сегмент фона, при Static — плашка фона с Reset и
  подсказкой (тема / свой цвет);
- Sun — gs.sun_missing остаётся callout'ом (К5); север: поле градусов с «°»,
  ссылка Clear, «N» и компас 44 px справа — индикатор набора, но тянуть его
  по-прежнему можно (smoke_sun гоняет настоящий drag; старый 120-px SVG и его
  CSS в plan.styles.ts удалены); лучи — строка-тумблер с подписью; источник
  лучей — сегмент (sun-settings-view.ts переписан с <select> на segmented,
  логика та же);
- Data — подзаголовки с «?» и строки действий набора.

К10 (Q1): Save только при изменениях и без ошибок (радиус > 0, север 0–359),
статус в футере, вопрос при закрытии с изменениями; снимок при открытии —
editors/general-form-state.ts поверх общего editors/dialog-baseline.ts (на него
же переведён space-form-state.ts). _settingsDialog не получил новых ключей.

Удалено мёртвое: _renderColorRow (рантайм и карточка), .sunrow/.suncol,
ключи gs.wall_group, gs.bg_group, gs.bg_theme, gs.radar_show_live.help(.aria)
в четырёх локалях. Девять новых ключей — в i18n/settings.

Смоки переписаны осознанно, с пометкой #600: smoke_general_settings (инвентарь
по классам набора, подзаголовки .hpf-sub h4, пояснения под «?» и подписью,
ни одного .rhint), smoke_sun (сегмент источника лучей вместо select, поле
#gs-north, radius drag 18 px), smoke_backup_transfer (подзаголовок и строка
действий), smoke_settings_dialog_cards (callout вместо .rhint). Новый фокусный
свидетель demo/smoke_general_settings_form.mjs: семь карточек и отсутствие
старой разметки, один заголовок у Zigbee, десять плиток, компас 44, цели 44,
запись плиток/плашки/радиуса/севера/сегментов в свои ключи, Save/dirty/вопрос
при закрытии.

Мутанты: general-save-enabled-without-changes,
general-tile-opacity-writes-a-neighbour-key, general-north-clear-writes-zero,
topology-embedded-draws-its-own-heading; якоря state-callout-hidden-under-help
и dialog-card-loses-its-heading переставлены на новую разметку.

Контрактные тесты: houseplan-source.mjs приводит `host.` к `this.` и в телах
вынесенных диалогов; color-picker — три явных showOpacity=true (плитки, плашка
стены, цвет комнаты); счётчик производных .aria 35 → 34.

Бюджет: стартовый граф 290 711 — потолок ОПУЩЕН 292 500 → 292 200 (ушёл
120-px компас из eager-листа и мёртвые ключи); ленивый редакторский 237 929 —
потолок 236 300 → 238 600 с разбором в bundle-budget.mjs.

Гейты: typecheck, build, bundle:sync, npm test 2792 pass, mutation-gate
--check, семь смоков «Общих», smoke_color_picker_consumers без правок.

Issue: #600
User-Visible: no
2026-09-20 11:04:39 +03:00
Claude 91a008db9c feat(space): диалог «Пространство» по референсу — серия 1 из четырёх (#600)
§4 SPEC.md референса, четыре карточки: Basics (имя и масштаб в сетке 1fr/175,
подложка двумя choice-карточками, callout о пересчёте масштаба), Appearance
(строка-тумблер границ с иконкой и подписью, сегмент стиля стен с образцами
линии, плашка цвета с hex/прозрачностью/Reset, сегмент заливки с деталями
режима, компактный список «Видимые слои» с логикой «включено = видно» — К2),
Room cards (строка-тумблер названий, четыре плитки значений с отключением и
callout-ссылкой, слайдер размера с числом, концами и «Сбросить до 100%», образец
карточки внутри блока на тинте — Q2), Sun & light (сегмент фона, плашка цвета
фона, радио «свет через окна» в строку, север селектом с компасом 44 px и полем
градусов, строка-тумблер свечения).

Одна форма на два рантайма. `renderSpaceForm` в `editors/space-form.ts`
собирает тело и футер; редакторский вход (`space-settings-dialog.ts`) и
онбординг подают порт с тем, что у них различается, и сами рисуют
`<hp-dialog data-kind=…>` — контракт #489 требует литеральный kind. Копия
разметки онбординга на 300 строк удалена; локальные дубли CELL_CM_* и
strictNumber там же — тоже («одно число — один источник»).

К10 (решение владельца Q1): Save активен только при изменениях и без ошибок,
в футере «Есть несохранённые изменения» либо ссылка «Проверьте поля: N» к
первому ошибочному; «✕», Cancel и Escape с изменениями спрашивают через
`_confirmDanger`, без изменений закрывают сразу. Снимок делается при открытии
(`editors/space-form-state.ts`, WeakMap по хосту) — `SpaceDialogState` не
получил ни одного ключа. Валидация: имя, подложка без изображения, диапазон
температур, север 0–359 — с `aria-invalid` и текстом под полем.

Строки. 51 новый ключ живёт в ленивом словаре `i18n/settings` (приём
#423/#459), не в первом кадре: стартовый граф 291 260 при потолке 292 500.
Отдельный словарь, а не `support`, — иначе онбординг тянул бы весь словарь
редактора ради одной формы. 11 существующих ключей переименованы по Q6
(«Space name», «Appearance», «Room cards», «Draw it myself», «Zigbee signal
next to devices»…), 9 мёртвых удалены из четырёх локалей. `hp-color-opacity`
получил `hide-label`: подпись рисует плашка, `label` остаётся для title/aria и
`smoke_color_picker_consumers` проходит без правок (AC5).

Смоки. Переписаны осознанно (К6 снят), каждый — с пометкой #600 у правки:
smoke_hide_layers (компактные строки, инверсия К2 проверяется кликом),
smoke_ux_fixes (сегмент, строка-тумблер, поля °C, ширина 560 — Q7),
smoke_dialog_footer_width (560 для form-shell), smoke_temp_fill (два поля по
id), smoke_settings_dialog_cards (три сегмента), smoke_space_settings и
smoke_space_create_display_defaults и smoke_lazy_editor_chunk (choice-карточка
по смыслу, не по индексу — порядок §4.2 draw → file), smoke_space_scale_defaults
(поле с единицей). Новый фокусный свидетель demo/smoke_space_settings_form.mjs:
состав карточек и отсутствие старой разметки, оболочка 560 и один скроллер,
цели 44, запись каждого нового контрола в свой ключ, Save/dirty/вопрос при
закрытии, семь контрольных ширин (320…1920).

Мутанты: space-fill-segment-writes-a-neighbour-key,
space-save-enabled-without-changes, space-discard-without-asking,
space-layer-toggle-loses-inversion.

Контрактные тесты: `houseplan-source.mjs` дописывает общие модули диалогов к
логическому исходнику; коллектор i18n видит `help(...)` порта и `shelp(...)`
(заодно встал на учёт `radar.help`, проходивший мимо счётчика — 30 → 35).

Потолок ленивого редакторского графа 225 900 → 236 300 (замер 235 560) с
разбором в bundle-budget.mjs: словарь на четыре локали и подписи — большая
часть роста; промежуточно, итог в конце серий.

Гейты: typecheck, build, bundle:sync, npm test 2792 pass (красным был только
потолок — поднят с доводом), 10 смоков пространства зелёные,
smoke_color_picker_consumers без правок, mutation-gate --check.

Issue: #600
User-Visible: no
2026-09-20 10:28:51 +03:00
Claude 30da00403d feat(form-kit): набор контролов по референсу и оболочка диалогов настроек
Серия 0 из пяти по #600. Ничего из четырёх диалогов ещё не переложено — эта
серия даёт им инструменты и оболочку.

Набор (`form-kit.ts` + `form-kit.styles.ts`), числа из §3.1 SPEC.md референса,
цвета через переменные темы HA:
- полная строка настройки `toggleRow` — сетка 28/1fr/44: иконка, название +
  «?», подпись, тумблер справа; тумблер — нативный чекбокс, нарисованный CSS,
  как у редактора панели: один вид в HA, на стенде и в golden, и всё тот же
  `input[type=checkbox]` для смоков; компактный вариант для однотипных списков;
- `field`, `fieldGrid` (две колонки и 1fr/175), `subsection`, `unitInput`,
  `rangeLine`, `rangeEnds`, `radioRow`, `choiceCards`;
- `valueTiles` (4 колонки), плитки цвета в CSS; `colorField` — компактная
  плашка вокруг существующего `hp-color-opacity` (Q5): свотч открывает ту же
  панель, рядом hex, число прозрачности и Reset; нативного пикера нет;
- `callout` (К5: сообщения о состоянии остаются на виду), `compass` 44 px,
  `footerStatus`, `chip`, `tintBlock`, `textLink`, `divider`;
- `segmented` получил образцы линии, иконки и `disabled`; вид — как в
  референсе: контейнер на канве, активный сегмент на тинте.

Оболочка (`hp-dialog.ts`, атрибут `form-shell` у четырёх диалогов настроек):
ширина 560 через `--hp-dialog-wide-width`, которую `:host([wide])` уже читал;
высота min(940px, 100vh − 48); единственный скроллер — `.content`, тело формы
высотой не владеет (К6, дефект 7 из issue); «✕» 44 px; бейдж имени пространства
в заголовке (`badge`). Generic `wide` и остальные диалоги не тронуты (Q7).

`hp-dialog[form-shell] .body` — без max-height и overflow, канва 16 px.

Фикстуры листа диалогов `test/fixtures/form-kit-card-dialog*.css` пересняты
намеренно; лист панели совпал с замороженным побайтово (К9, AC11).

`editor.loading` → «Загрузка…» в четырёх локалях (дефект 9); aria-текст прежний.

Потолок ленивого редакторского графа 222 900 → 225 900 с доводом в
`bundle-budget.mjs`: рост — CSS-строки набора, не код; значение промежуточное,
серии 1–4 выкидывают старые правила, итог замеряется в конце.

Гейты: typecheck, build, bundle:sync, `npm test` (2791 pass; красными были
только потолок — поднят — и неотслеженные файлы манифеста — добавлены),
`smoke_settings_dialog_cards`, `smoke_room_settings`.

Issue: #600
User-Visible: no
2026-09-20 09:39:13 +03:00
Claudeandclaude[bot] b28907f63d refactor(styles): редактор панели переезжает на общий набор контролов
Набор контролов был поднят из редактора боковой панели в #594, но сама панель
осталась на своей копии тех же правил. Две копии расходятся молча: правка в
наборе не доедет до панели, и наоборот.

Просто вызвать `formKitCss` из панели нельзя. Общие правила в её листе не идут
подряд: между карточкой-группой и обводкой фокуса стоит сетка `.summary-general-grid`,
между фокусом и выключенным состоянием — `button { font: inherit }`, между ним и
рядом-переключателем — `svg`. Вставить один общий кусок значило бы переставить её
объявления, а перестановка правил равной специфичности — уже не подстановка:
проверять пришлось бы каждое правило по отдельности.

Поэтому генератор разрезан на пять именованных фрагментов — карточка-группа,
обводка фокуса, выключенное состояние, ряд-переключатель, подпись ряда, — и
панель подставляет каждый на своё место. `formKitCss` остаётся их композицией,
чтобы у диалогов не появилось пяти вызовов вместо одного.

Доказательство вместо обещания. У настроек панели нет ни одного golden-кадра: в
матрице нет сцены `dialog: 'summary'`, и «панель не изменилась» показать
пикселями нечем. Замена эталону — побайтовое сравнение собранного листа с
замороженным снимком с `origin/dev`:

    длина было 14585 стало 14585 — ПОБАЙТОВО СОВПАЛО

Две находки ревью ТЗ закрыты тестами, а не формулировками:

- проверка «копии не осталось» ловила один фрагмент из пяти (`min-height: 54px`
  встречается только в ряду-переключателе). Теперь цикл по всем пяти текстам;
  проба — фрагмент карточки-группы, оставленный в комментарии, — краснит именно
  этот цикл, а прежняя проверка была бы зелёной;
- «выход `formKitCss` остаётся байт в байт» опиралось на тесты, сравнивающие
  подстроки и счётчики. Добавлены две фикстуры с полным текстом обеих форм листа
  диалогов — с рядом-переключателем и без. Форма с переключателем сегодня не
  используется никем, и её расхождение не поймал бы никто до первого потребителя.

Три замороженные фикстуры — осознанный долг: они удаляются на том шаге эпика,
который законно меняет вид панели. Записано рядом с фикстурой.

Issue: #597
User-Visible: no
2026-09-19 14:19:54 +00:00
ClaudeandClaude 4344ede13a feat: общий набор контролов формы и диалог комнаты по нему (#594)
Шаг 1 эпика #591. Набор поднят из редактора боковой панели — он сделан по
макетам дизайнера и уже живёт в продукте, — а не собран заново по прототипу.

Стили набора выдаёт генератор, параметризованный именами: контейнер формы,
префикс классов, карточки, футер и токены цвета. Это не украшение архитектуры,
а условие переезда панели на общий источник: тест с замороженной фикстурой
показывает, что с параметрами панели генератор отдаёт её нынешние правила
дословно — карточку, обводку фокуса, выключенное состояние и ряд-переключатель.
После этого переезд станет подстановкой, а не редизайном, и пиксели панели не
дрогнут. Сама панель в этом коммите не тронута.

Диалог комнаты собран в четыре карточки: «Основное», «Заливка», «Источники»,
«Размеры шрифтов». Порядок полей прежний, записи прежние — те же ключи
черновика, те же условия «Сохранить», тот же `hp-color-opacity` с атомарной
записью цвета и прозрачности. Пояснения уехали под «?» у заголовков групп
(решение владельца 18.09), выбор источника стал сегментированным
переключателем — под капотом это по-прежнему радиогруппа, поэтому стрелки и
скринридер работают как раньше.

Два измерения определили форму решения, и оба стоило сделать до кода.

Первое: лист набора в синхронном графе дал +1459 Б gzip и пробил потолок
initial View на 415 Б. Диалоги — инструмент администратора, во View их не
открывают, поэтому лист уехал в ленивый редакторский граф и вносится в теневой
корень при открытии диалога — тем же способом, которым это делает боковая
панель. Потолок не поднимался.

Второе: `css` с интерполяцией запрещён минификатором сборки (он намеренно
падает, чтобы не зависеть от рантайма), поэтому лист собирается `unsafeCSS`.
Цена — несжатые пробелы генератора, замерено 59 Б gzip; копия литералом стоила
бы расхождения с генератором, то есть единого источника.

Оставшийся рост initial View — 291 356 → 291 872 Б (+516) — это четыре текста
подсказок в двух встроенных локалях. Тексты сокращены до одного предложения:
подсказка под «?» и должна быть короткой.

`_renderRoomSource` переехал в модуль комнаты вместе со стабом карточки: у него
остался ровно один потребитель.

Issue: #594
User-Visible: yes
2026-09-19 11:08:03 +03:00
Sergey Matyunin 5cae93501c fix: refine hidden 2.5D presentation (#583)
Issue: #583
User-Visible: no
2026-09-16 02:57:47 +03:00
Sergey Matyunin 54dc836dee fix: закрыть compositor-пути day-cycle (#582)
Issue: #582
User-Visible: no
2026-09-15 13:41:51 +03:00
Sergey Matyunin 2a8b5f1dcf fix: стабилизировать day-cycle при pinch в HA Companion (#582)
После первого движения камеры переносит фильтр контура на ограниченный размером viewport слой, сохраняя исходный статичный рендер без изменений.

Issue: #582
User-Visible: no
2026-09-15 12:20:44 +03:00
Sergey Matyunin a68e4c6b80 fix: ограничить дневной контур размером экрана (#582)
Issue: #582
User-Visible: yes
2026-09-15 12:17:27 +03:00
Sergey Matyunin 258896cb6f feat: refine hidden isometric Stage 4 (#570)
Issue: #570
User-Visible: no
2026-09-14 15:29:57 +03:00
Sergey Matyunin 6de854a03d fix: разрешить перекрытия целей маркеров (#564)
Issue: #564
User-Visible: yes
2026-09-14 02:57:50 +03:00
Codex 5afdb644c7 Смена пространства выбрасывает слой, а не сверяет его поэлементно
#525 увёл оба списка сцены с `map()` на `repeat(items, (item) => item.id, …)`,
чтобы Lit не переиспользовал узлы по позиции и не проигрывал анимацию двери,
которой не было. Правка верная, но на плане с двумя сотнями маркеров она
оказалась дорогой ровно там, где пользы не приносит: при смене пространства
ключи не пересекаются вовсе, и `repeat` строит две карты ключей и обходит оба
списка, чтобы затем всё равно выбросить всё и создать заново.

Бисект по медиане `switchCycleMs` на `large-house`: 871,2 перед #525 → 953,5
после. На раннере эти 80 мс распадаются на шесть-девять дополнительных длинных
задач, и `longTask.countP95` вышел за порог стабильного гейта.

Теперь оба списка рендерятся как `keyed(space.id, repeat(…))`. Внешний ключ
делает смену пространства: поддерево выбрасывается целиком, дифа нет. Внутренний
остаётся, потому что состав списков едет и внутри пространства — у маркеров от
призраков редактора и живого синка, у проёмов от записи с нерешённым хостом,
которая живёт только в режиме plan, — а переходы на `.device-shell-frame`,
`.op-leaf` и `.op-arc` никуда не делись.

Замер после правки: `switchCycleMs` 889,1 против 936,0 на `main` и 871,2 до
#525. Потолок карточки поднят на одну строку — на `import { keyed }`;
переносить нечего, сам рендер не вырос ни на символ.

Issue: #534
User-Visible: yes
2026-09-11 22:30:11 +03:00
Claudeandclaude[bot] ced9b41642 Keep the day-cycle outline on its own compositing layer
The "Follows the sun" background made the plan crawl in Firefox: 23 MB of
textures per frame, sixteen of about twenty picture-cache tiles thrown
away every frame, nine frames per second. The card's own JavaScript was
idle for 89 % of that.

The cost is the outer outline. It is a triple drop-shadow over the
grouped paper footprint, and although the group holds paper silhouettes
only and never changes on hover or pan, the filter lived in the plan's
own layer — so every repaint of the plan re-ran three blur passes over
the whole sheet. One hint moves the filtered paper into its own layer
and unhooks it from the plan's repaints.

Measured on a demo-stand pan (Chromium, CDP, summed RasterTask): 1456.6
ms against a static background's 96.7 ms before, 84.7 ms against 103.2
ms after. The new smoke measures that ratio and fails above two.

The picture does not change: the outline outside the plan matches byte
for byte and the frame's mean colour moves from 176.59 to 176.66 of 255.
Splitting the layer does move the remaining content onto a different
sub-pixel grid, so the diagonal wall hatch anti-aliases differently and
the four day-cycle baselines are re-taken on the beta candidate.

Issue: #532
User-Visible: yes
2026-09-11 17:01:04 +00:00
Codex b59e245e32 perf(markers): keep the CSS note short — comments ship to the browser
The long explanation inside the css`` template cost 518 gzipped bytes in
the initial chunk: the template minifier leaves comments in this file, so
every character of them is downloaded by every user. The reasoning now
lives in docs/DEVELOPMENT.md and in the commit above; the stylesheet
keeps one line and the issue number.

Measured: 300 577 B with the long notes, 300 111 B with the short ones,
300 059 B on dev before the fix.

Issue: #524
User-Visible: no
2026-09-11 08:33:18 +03:00
Codex 6b64801603 perf(markers): a marker's shadow no longer animates
The shadow of a device marker is sized from the marker, and the marker is
sized from the container: --device-shell-shadow is expressed in
--dev-size, which resolves to 2.5cqw. With box-shadow in the transition
list, every container-query re-evaluation — a tooltip, a scrollbar, a
rotation — produced a new computed value and restarted a 150 ms
non-composited transition on every marker at once.

The owner's Firefox profile shows what that costs: 244 box-shadow
transitions, all on span.device-shell-frame, all oncompositor:false, in
bursts of exactly 61 (the markers on screen), four bursts in two
seconds. During them the tab presented 103 frames in 11 seconds — 9.4
per second, CONTENT_FRAME_TIME median 149 ms and up to 320 — while the
refresh driver waited for paint 381 times. Our JavaScript in the worst
three seconds: 16 ms. Chromium starts the same transitions (measured:
one pixel of container width starts two per marker in both engines) and
merely pays less for them, which is why this hid there.

The shadow itself is unchanged; it simply applies at once. The core
keeps the same treatment, so the selection and focus rings appear
without a fade — an instant ring is ordinary feedback, a faded one costs
a full-frame repaint per marker. Hover still animates border-color.

Issue: #524
User-Visible: yes
2026-09-11 08:28:49 +03:00
Claudeandclaude[bot] 9edef041a9 fix: openings and markers keep their identity across a space switch (#525)
Lit reuses list nodes by position. The opening list and the device markers had
no keys, so on a space switch the leaf that held a slot kept its DOM node and
only changed values — and `.op-leaf` (transform) and `.op-arc`
(stroke-dashoffset) carry a 0.6 s transition, so the browser animated a door
that never moved: the new floor's leaf drove in from the previous floor's
opening angle. Measured on two spaces with a door in the same place and
opposite contact states: the node is reused, transform goes
`rotate(-90deg) → rotate(0deg)`, dash offset `0 → 125.66`, both transitions
`running`. The marker shell adds two more with its `box-shadow`.

Both lists are now rendered through `repeat(…, (item) => item.id, …)`, the
same lesson `glow-scene.ts` already learned for the Glow spots. The trap is
written where it starts — above the two transitions in `plan.styles.ts` —
because that is the file someone edits when adding the next animated property.
`houseplan-card.ts` is at its line ceiling, and the note would have cost the
budget a dozen lines for nothing: the swap itself is line-for-line.

The witness walks the shadow tree per element. `document.getAnimations()` is
empty here EVEN ON THE BROKEN CODE — the card lives in a shadow root and the
document-level call does not reach into it, and the issue proposed exactly
that call. The smoke also builds its own fixture: the demo home has no
openings at all, so two doors in two spaces are prepared in the smoke, and it
asserts the other half of the contract as well — a real contact change inside
one space still animates the leaf.

On `origin/dev` the smoke fails on five facts, naming the offenders:
`op-arc:stroke-dashoffset`, `op-leaf:transform`, `device-shell-frame:box-shadow`
twice. Mutants `openings-rendered-without-keys` and
`device-markers-rendered-without-keys` put each `map` back.

Perf, 7 samples against `19e421b3`: spaceSwitchMs 524.8 (limit 769.35, base
512.9), switchCycleMs 1293.9 (1696.28, 1256.5), firstStableRenderMs 2533.8
(3000, 2529.2), modelReadyMs 732.7 (944.97, 726.9), longTask.maxSingleMs 663
(910, 660) — `benchmark:compare` green in full.

The initial View graph grows 241 B gzip: `repeat` enters it for the first
time. The #438 ceiling is recentred 300 400 → 300 700 with the usual dated
note; measured 300 059 B keeps 641 B above and 1 359 B below the band. The
301 066 B budget is untouched, but only 366 B now separate the ceiling from
it — the #367 headroom debt has stopped being theoretical.

Issue: #525
User-Visible: yes
2026-09-11 01:42:46 +00:00
Matysh 3d2bfe9f6d Keep footer documentation out of the shipped CSS
Move the explanatory comment to TypeScript without changing styles; preserve the existing bundle-budget noise margin. Include independently accepted #498 in the release status.

Issue: #505
Issue: #498
User-Visible: no
2026-09-09 10:21:48 +03:00
Matysh 6fe01ecc1f Prepare v1.73.0-beta.8 and preserve dialog footer targets
Restore the shared footer minimum exposed by the #505 Linux screenshot gate; the focused browser assertion fails before the restoration and passes after it.

Issue: #505
Issue: #495
User-Visible: yes
2026-09-09 10:19:04 +03:00
Matysh d12488f40d fix: harden presence radar stage one
User-Visible: yes
Issue: #485
2026-09-09 03:52:23 +03:00
Matysh 58f5f18540 feat: add presence radar stage 1
User-Visible: yes
Issue: #485
2026-09-09 03:51:25 +03:00
Sergey Matyunin 96e07b9a02 feat: add configurable summary panel (#437)
Issue: #437
User-Visible: yes
2026-09-08 18:49:36 +03:00