mirror of
https://github.com/Matysh/houseplan-card
synced 2026-09-30 19:58:50 +00:00
@@ -0,0 +1,534 @@
|
||||
# Issue #179 — новый визуальный язык маркеров устройств
|
||||
|
||||
- **Статус:** готово к ревью ТЗ
|
||||
- **Issue:** https://github.com/Matysh/houseplan-card/issues/179
|
||||
- **Приоритет:** P1
|
||||
- **Тип:** feature / polish / accessibility
|
||||
- **Область:** frontend, общий renderer маркера, preview, статическая карточка,
|
||||
документация и visual QA
|
||||
- **Нормативный дизайн-пакет:** `House Plan Icons — Developer Package`,
|
||||
версия 1.1.1, экспорт 2026-08-18
|
||||
- **Архив:** https://github.com/user-attachments/files/31235094/House.plan.Icons.-.Developer.Package.2026-08-19.zip
|
||||
- **SHA-256 архива:**
|
||||
`63670C73E25D1E59DDAF1BE236F3D7F2FAC827B9B5D6DD4B77125EA9BC012025`
|
||||
- **Figma frames:** Light `99:1290`, Dark `104:1539`
|
||||
|
||||
## 1. Пользовательский сценарий и персона
|
||||
|
||||
**Персона:** пользователь House Plan, который одновременно контролирует
|
||||
устройства разных доменов, читает значения датчиков и оценивает состояние
|
||||
связи на светлой либо тёмной теме Home Assistant.
|
||||
|
||||
**Сценарий:** пользователь открывает план и за один взгляд различает обычное,
|
||||
активное, тревожное, заблокированное, разблокированное, виртуальное и
|
||||
недоступное устройство; видит полное значение и Zigbee LQI; получает тот же
|
||||
результат в полном плане, preview редактора и статической карточке пространства.
|
||||
|
||||
## 2. Проблема и результат
|
||||
|
||||
### До реализации
|
||||
|
||||
- plate маркера является одним заполненным rounded-square без общего внешнего
|
||||
shell из дизайн-пакета;
|
||||
- hover применяется и к unavailable-маркеру;
|
||||
- selected обозначается amber-цветом и конфликтует с семантикой активности;
|
||||
- value и legacy secondary value рисуются отдельными спутниками, длинные
|
||||
значения обрезаются ellipsis;
|
||||
- LQI использует непрерывный HSL-gradient, а не три читаемых диапазона;
|
||||
- ordinary continuous pulse длится 2,4 с и по умолчанию разрастается до 3×;
|
||||
- маркер не является клавиатурной целью и не активируется Enter/Space;
|
||||
- light/dark, focus и semantic states не образуют единой дизайн-системы.
|
||||
|
||||
### После реализации
|
||||
|
||||
Все поверхности используют один runtime-renderer нового shell/core,
|
||||
компоновок Text/Double, LQI и motion из пакета. Семантика устройств и действий
|
||||
остаётся прежней; меняется её единое визуальное и доступное представление.
|
||||
|
||||
## 3. Нормативный источник и порядок разрешения расхождений
|
||||
|
||||
Единственный дизайн-источник этой задачи — архив #179. Нормативны его
|
||||
`README.md`, `SPECIFICATION.md`, `ACTIVE_ANIMATION_SPEC.md`,
|
||||
`DEVELOPER_HANDOFF.md`, `PACKAGE_ANNOTATION.txt`, `manifest.json` и SVG-примеры.
|
||||
|
||||
Порядок приоритета:
|
||||
|
||||
1. решения владельца в §4;
|
||||
2. текстовые документы архива;
|
||||
3. SVG-примеры архива;
|
||||
4. текущая реализация House Plan — только для поведения, которое пакет не
|
||||
переопределяет.
|
||||
|
||||
Статические SVG являются эталонами геометрии и состояний, а не готовыми
|
||||
production-иконками: runtime продолжает использовать динамические MDI glyphs,
|
||||
HA-значения и локализованный текст.
|
||||
|
||||
## 4. Принятые решения владельца
|
||||
|
||||
1. **Unavailable.** Визуальный hover и motion отсутствуют. Click/tap остаётся
|
||||
доступен и выполняет текущее действие поверхности (More Info либо открытие
|
||||
настроек).
|
||||
2. **Пользовательские pulse-настройки.** Если `ripple_color` или `ripple_size`
|
||||
явно сохранены, они сохраняют приоритет. При отсутствии поля используются
|
||||
геометрия и цвет пакета.
|
||||
3. **Zigbee LQI.** `0…40` — red, `41…179` — amber, `180+` — green.
|
||||
4. **Клавиатура.** Интерактивный маркер получает focus; Enter и Space выполняют
|
||||
то же действие, что click на этой поверхности.
|
||||
5. Специальная кнопка либо новый action для клавиатуры не вводятся.
|
||||
|
||||
## 5. Цели
|
||||
|
||||
1. Реализовать shell/core, цвета, состояния, focus и motion пакета #179.
|
||||
2. Сохранить единую проекцию на полном плане, в editor preview и static card.
|
||||
3. Показывать полное динамическое значение без ellipsis в Text/Double layout.
|
||||
4. Сделать маркер читаемым в light/dark и на цветном фоне плана.
|
||||
5. Обеспечить минимум 44×44 CSS px для интерактивной цели и keyboard parity.
|
||||
6. Сохранить существующую HA-семантику, пользовательские настройки, координаты
|
||||
и безопасный pipeline действий.
|
||||
|
||||
## 6. Не входит в задачу
|
||||
|
||||
- новые правила определения `on`, `working`, `open`, alarm и activity;
|
||||
- новые HA service calls, actions или обход secure confirmation;
|
||||
- новые display modes и новые пользовательские настройки дизайна;
|
||||
- смена MDI-иконок либо поставка собственного icon font;
|
||||
- настройка порогов LQI пользователем;
|
||||
- автоматическое устранение пересечений соседних маркеров;
|
||||
- изменение комнатной LQI-заливки, Glow, света, комнатных fills или isometry;
|
||||
- миграция сохранённых координат и marker config;
|
||||
- перенос каждого example SVG из архива в production bundle.
|
||||
|
||||
## 7. Визуальная система
|
||||
|
||||
### 7.1. Геометрия
|
||||
|
||||
Маркер состоит из независимых слоёв:
|
||||
|
||||
1. прозрачная hit area минимум 44×44 CSS px;
|
||||
2. внешний shell: прозрачный fill, stroke и внешние shadows;
|
||||
3. внутренний core с MDI glyph либо динамическим значением;
|
||||
4. semantic/focus/selection decoration;
|
||||
5. pulse layer с `pointer-events: none`;
|
||||
6. LQI и дополнительные секции, если включены.
|
||||
|
||||
Для Icon-эталона shell имеет диаметр `101.5/127` viewBox, core — `80/127`;
|
||||
отношение core/shell равно `0.788` с допустимым расхождением не более 0,5 CSS
|
||||
px на QA-размерах 32, 56 и 96 px. Координата сохранённого маркера остаётся
|
||||
центром icon core, поэтому включение Text/Double и смена стороны не двигает
|
||||
устройство на плане.
|
||||
|
||||
Light shell: stroke `#BCBCBC`; core по умолчанию white. У light-варианта
|
||||
запрещены backdrop blur и inner shadows. Внешние shadows масштабируются от
|
||||
референса 56 px: `0 1px 2px rgb(0 0 0 / 12%)` и
|
||||
`0 4px 8px -1.07px rgb(0 0 0 / 18%)`.
|
||||
|
||||
Dark использует неизменённую dark-ревизию пакета, включая core `#252525` и её
|
||||
эталонные эффекты. Тема берётся из актуальных HA theme tokens; переключение
|
||||
темы не требует remount и не меняет semantic state.
|
||||
|
||||
### 7.2. Цвета
|
||||
|
||||
Нормативные semantic colors:
|
||||
|
||||
| Смысл | Цвет |
|
||||
|---|---|
|
||||
| hover / focus / neutral activity | `#0C82F0` |
|
||||
| active / working / unlocked | `#F0A00C` |
|
||||
| alert / low LQI | `#F0410C` |
|
||||
| unavailable core | `#B5BAC1` |
|
||||
| locked glyph | black |
|
||||
| high LQI | `#1DC21D` |
|
||||
|
||||
Тема не подменяет semantic colors. Контраст glyph/core и читаемость текста
|
||||
проверяются в light/dark и на светлом, тёмном и насыщенном фоне плана.
|
||||
|
||||
### 7.3. Состояния и приоритет
|
||||
|
||||
Нормативный визуальный приоритет:
|
||||
|
||||
```text
|
||||
Alert > Focus > Selected > Hover > semantic state > Default
|
||||
```
|
||||
|
||||
- **Default:** theme-default shell/core и обычный glyph.
|
||||
- **Hover:** blue decoration пакета; не меняет semantic state и не
|
||||
перезапускает pulse.
|
||||
- **Focus:** blue keyboard-focus decoration, видимая без hover.
|
||||
- **Selected:** отдельная selection decoration пакета, не amber semantic fill.
|
||||
- **Active/working:** amber.
|
||||
- **Lock:** locked glyph black; **Unlock:** unlocked glyph amber.
|
||||
- **Alert:** red и всегда выше остальных состояний.
|
||||
- **Unavailable:** gray core/glyph по текущему правилу прозрачности; без
|
||||
визуальной реакции на hover и без motion.
|
||||
- **Virtual:** пунктирный внешний shell. У обычного virtual default/hover
|
||||
меняется только цвет оформления. Реальная HA unavailable и active pulse для
|
||||
HA-less virtual device не синтезируются.
|
||||
|
||||
Текущая semantic-модель `neutral/open/working/alarm`, activity resolver и
|
||||
domain-specific HA rules сохраняются. Для lock presentation дополнительно
|
||||
различает locked/unlocked, не меняя secure action. Generic physical `open`
|
||||
для cover/contact/valve не переименовывается в lock state и продолжает
|
||||
существующую отдельную semantic-проекцию.
|
||||
|
||||
`display: static_icon` получает новую theme-default shell/core геометрию, но
|
||||
остаётся нереактивным к HA state, values и pulse. На интерактивной поверхности
|
||||
он сохраняет разрешённые hover/focus/click; unavailable hover запрещён.
|
||||
|
||||
## 8. Text, Double и дополнительные секции
|
||||
|
||||
### 8.1. Text
|
||||
|
||||
В `display: value` динамический текст находится внутри общего shell. Полная
|
||||
строка всегда доступна визуально: CSS ellipsis, clipping и скрытие хвоста
|
||||
запрещены. Сначала шрифт равномерно уменьшается до `0.25 × marker size`
|
||||
(8 CSS px при размере 32); если этого недостаточно, text section расширяет
|
||||
shell. Измерение выполняется детерминированно и кэшируемо, без layout-loop и
|
||||
ResizeObserver на каждый маркер.
|
||||
|
||||
### 8.2. Double
|
||||
|
||||
Иконка и value badge входят в один общий shell. Поддерживаются сохранённые
|
||||
позиции `right`, `bottom`, `left`, `top`; icon core остаётся anchor. Высота
|
||||
внутренней value-секции равна `0.7875 × icon core`, как в референсе.
|
||||
|
||||
Если у нетронутой legacy-конфигурации одновременно разрешены два значения,
|
||||
второе становится третьей секцией того же shell, а не отдельным спутником.
|
||||
Новая пользовательская модель второго бейджа не вводится.
|
||||
|
||||
Длинное значение проходит тот же auto-fit, что Text: полная строка без
|
||||
ellipsis, а shell при необходимости расширяется. Динамический текст остаётся
|
||||
текстом DOM, а не SVG path; шрифт — HA/system Roboto с weight 600 и безопасным
|
||||
system fallback.
|
||||
|
||||
## 9. Zigbee LQI
|
||||
|
||||
Числовое LQI располагается под shell по геометрии пакета и окрашивается
|
||||
категориально:
|
||||
|
||||
- `<= 40` — `#F0410C`;
|
||||
- `41…179` — `#F0A00C`;
|
||||
- `>= 180` — `#1DC21D`.
|
||||
|
||||
Границы применяются к текущему resolved average LQI без изменения источника,
|
||||
агрегации, форматирования и флагов `show_signal`. Значение `0` валидно. Для
|
||||
missing/unavailable LQI сохраняется текущая политика отсутствия подписи.
|
||||
|
||||
Категориальная функция применяется только к marker LQI. Непрерывный
|
||||
HSL-gradient комнатной LQI-заливки остаётся неизменным.
|
||||
|
||||
В `Light/Zigbee LQI Low.svg` архива low ошибочно окрашен amber. Текстовая
|
||||
спецификация архива и решение владельца имеют приоритет: production low — red.
|
||||
|
||||
## 10. Motion
|
||||
|
||||
### 10.1. Continuous
|
||||
|
||||
- одно кольцо;
|
||||
- duration `3.6s`, infinite;
|
||||
- easing `cubic-bezier(.45,.05,.55,.95)`;
|
||||
- scale `1 → 1.5`, opacity `.55 → 0`;
|
||||
- цвет соответствует resolved ordinary activity.
|
||||
|
||||
### 10.2. Short
|
||||
|
||||
- три кольца;
|
||||
- каждое длится `1.1s`;
|
||||
- delays `0`, `1.1s`, `2.2s`;
|
||||
- общий цикл `3.3s`;
|
||||
- новое событие перезапускает цикл через существующий generation/runtime.
|
||||
|
||||
### 10.3. Alert
|
||||
|
||||
- red независимо от custom pulse color;
|
||||
- wave stroke 3 reference units;
|
||||
- scale до `1.5`;
|
||||
- два wave-starts с интервалом `1.2s`, цикл `2.4s`;
|
||||
- alert имеет приоритет над ordinary short/continuous.
|
||||
|
||||
### 10.4. Пользовательские настройки и fallback
|
||||
|
||||
Явно сохранённые `ripple_color` и `ripple_size` сохраняются без миграции.
|
||||
Отсутствующий `ripple_size` использует package scale `1.5`, отсутствующий
|
||||
`ripple_color` разрешается в порядке:
|
||||
|
||||
1. валидный live RGB контролируемого light, если он уже является текущим
|
||||
источником pulse color;
|
||||
2. semantic amber для working/open/unlocked;
|
||||
3. package blue для neutral activity.
|
||||
|
||||
UI-default размера меняется на `1.5`, но Open → Save не материализует поле и
|
||||
не переписывает существующее явно сохранённое значение. Backend допустимый
|
||||
диапазон и import/export round-trip не меняются.
|
||||
|
||||
### 10.5. Reduced motion
|
||||
|
||||
При `prefers-reduced-motion: reduce` animated rings отсутствуют. Ordinary
|
||||
activity обозначается статической semantic point из существующего единого
|
||||
pulse renderer; alert остаётся красным статическим состоянием. Marker не
|
||||
создаёт собственную media-query subscription: используется одна подписка на
|
||||
surface/card host.
|
||||
|
||||
## 11. Интерактивность и доступность
|
||||
|
||||
- Интерактивные маркеры в View/kiosk и Device editor получают `tabindex="0"`
|
||||
и button semantics.
|
||||
- Enter/Space вызывают тот же существующий click handler текущей поверхности:
|
||||
action/More Info в View и открытие настроек в Device editor.
|
||||
- Space предотвращает прокрутку только когда активирует marker.
|
||||
- Pointer/touch поведение, long-press/context action и drag в редакторе не
|
||||
меняются; keyboard path не создаёт прямой HA service call.
|
||||
- Background/Plan, read-only static card и неинтерактивный preview не входят в
|
||||
tab order и не получают ложный button role.
|
||||
- Minimum hit area 44×44 CSS px центрирована по icon core и не влияет на
|
||||
visual bounds, координату, pulse либо collision geometry.
|
||||
- `aria-label` включает локализованное имя, semantic state, activity/alert и,
|
||||
если LQI показан, число и понятный диапазон «низкий/средний/высокий».
|
||||
- Цвет и motion не являются единственным носителем alert, availability, lock
|
||||
или LQI band.
|
||||
- Focus после закрытия открытого marker dialog возвращается на исходный
|
||||
marker по существующему dialog contract.
|
||||
|
||||
Secure lock/cover/valve actions продолжают проходить через текущий action
|
||||
resolver и confirmation policy. Новый DOM-shell и keyboard handler не имеют
|
||||
отдельного пути обхода подтверждения.
|
||||
|
||||
## 12. Совместимость и данные
|
||||
|
||||
- config schema version не меняется;
|
||||
- `display`, `value_badge`, `value_badge_position`, `ripple_color`,
|
||||
`ripple_size`, `show_signal` и legacy fields сохраняют формат и round-trip;
|
||||
- существующие координаты относятся к icon core и не мигрируют;
|
||||
- явно сохранённые pulse color/size воспроизводятся как раньше, кроме нового
|
||||
shell и motion geometry;
|
||||
- отсутствующие поля не материализуются при Open → Save;
|
||||
- старые версии карточки читают тот же config; downgrade меняет только
|
||||
внешний вид;
|
||||
- runtime не зависит от наличия в bundle статических SVG-примеров;
|
||||
- ru/en i18n parity обязательна.
|
||||
|
||||
## 13. Архитектурный контракт
|
||||
|
||||
```text
|
||||
HA/device registry + marker config
|
||||
→ existing semantic/activity resolvers
|
||||
→ resolveDevicePresentation
|
||||
→ resolveDevicePulse
|
||||
→ renderDeviceFace (shell/core/text/LQI/motion)
|
||||
→ full plan | editor preview | static space card
|
||||
```
|
||||
|
||||
Один resolved presentation и один `renderDeviceFace()` остаются источником
|
||||
истины всех поверхностей. Surface передаёт только interaction/theme context и
|
||||
не вычисляет semantic state повторно.
|
||||
|
||||
Рекомендуемые зоны изменений:
|
||||
|
||||
- `src/device-visual.ts` — lock presentation facet без смены action semantics;
|
||||
- `src/device-presentation.ts` — theme/semantic projection, marker-only LQI
|
||||
band, defaults pulse;
|
||||
- `src/device-pulse.ts` — package timings/scale/reduced motion;
|
||||
- `src/device-face.ts` — единый shell и Text/Double/third section DOM;
|
||||
- `src/styles.ts` — tokens, geometry, states, focus, auto-fit и motion;
|
||||
- `src/houseplan-card.ts` и общие surface adapters — role/tabindex/keydown;
|
||||
- i18n, unit, smoke, golden fixtures и документация.
|
||||
|
||||
Нельзя вводить surface-specific копию state mapping, formatter либо motion
|
||||
runtime. Text auto-fit не должен читать layout на каждом render/animation
|
||||
frame. Pulse использует transform/opacity и не меняет layout.
|
||||
|
||||
## 14. Эдж-кейсы
|
||||
|
||||
- light/dark hot switch во время continuous/short pulse;
|
||||
- colored room background и минимальный marker size 32;
|
||||
- marker sizes 32/56/96, user scale 0.5…3 и explicit ripple size 1…20;
|
||||
- alarm во время hover/focus/selected и снятие alarm;
|
||||
- unavailable во время active pulse, затем reconnect baseline без false short;
|
||||
- locked, unlocked, locking и unlocking с secure action;
|
||||
- virtual default/hover без HA entity и linked virtual with resolved controller;
|
||||
- `static_icon` при реальном alarm/working/unavailable;
|
||||
- `0`, `false`, very long localized string, unit symbol и third legacy value;
|
||||
- Double на четырёх сторонах вместе с LQI;
|
||||
- LQI exactly `0`, `40`, `41`, `179`, `180`, missing;
|
||||
- rapid short retrigger, short поверх continuous, reduced-motion hot switch;
|
||||
- keyboard activation после drag, click confirmation и dialog focus return;
|
||||
- несколько cards одного плана с независимыми runtime и theme context;
|
||||
- hidden/HA-disabled/orphaned marker и read-only static card.
|
||||
|
||||
## 15. Acceptance criteria
|
||||
|
||||
- [ ] **AC1 — shell/theme.** Icon, Text и Double используют package shell/core
|
||||
geometry и Light/Dark tokens; light не содержит blur/inner shadow.
|
||||
**Доказательство:** unit token assertions + reviewed golden 32/56/96.
|
||||
- [ ] **AC2 — states.** Default, Hover, Focus, Selected, Active, Lock, Unlock,
|
||||
Alert, Virtual и Unavailable соблюдают §7.3 и нормативный приоритет.
|
||||
**Доказательство:** presentation unit matrix + light/dark state-table
|
||||
golden.
|
||||
- [ ] **AC3 — unavailable.** Unavailable не получает visual hover/motion, но
|
||||
click/tap по-прежнему открывает текущее действие поверхности.
|
||||
**Доказательство:** unit + browser smoke.
|
||||
- [ ] **AC4 — secure locks.** Locked black, unlocked amber, locking/unlocking
|
||||
continuous; pointer и keyboard проходят один action/confirmation path.
|
||||
**Доказательство:** unit + secure-action smoke.
|
||||
- [ ] **AC5 — virtual/static.** Virtual имеет dashed shell; HA-less virtual не
|
||||
синтезирует unavailable/activity. `static_icon` использует theme-default
|
||||
shell и не реагирует на live state/value/pulse.
|
||||
**Доказательство:** unit + existing static-icon smoke.
|
||||
- [ ] **AC6 — Text/Double.** Полные строки видимы без ellipsis; четыре стороны,
|
||||
anchor, auto-fit и третья legacy section соответствуют §8.
|
||||
**Доказательство:** unit layout facts + browser smoke + long-value golden.
|
||||
- [ ] **AC7 — LQI.** Marker LQI использует red/amber/green thresholds на
|
||||
границах, а room fill сохраняет continuous gradient.
|
||||
**Доказательство:** boundary unit tests + room-fill regression test.
|
||||
- [ ] **AC8 — motion.** Continuous/short/alert timings, ring counts, retrigger,
|
||||
scale и colors соответствуют §10; explicit color/size сохраняются.
|
||||
**Доказательство:** pure resolver tests + DOM/style smoke.
|
||||
- [ ] **AC9 — reduced motion.** Rings отсутствуют, ordinary point и static red
|
||||
alert остаются; одна subscription на host.
|
||||
**Доказательство:** unit + reduced-motion browser smoke.
|
||||
- [ ] **AC10 — keyboard/a11y.** Только интерактивные surfaces получают focus;
|
||||
Enter/Space эквивалентны click, hit area >=44×44, aria-label содержит
|
||||
state/LQI, focus возвращается после dialog.
|
||||
**Доказательство:** keyboard/touch/browser smoke.
|
||||
- [ ] **AC11 — parity.** Full plan, editor preview и static card используют
|
||||
один presentation/face renderer и дают одинаковую read-only projection.
|
||||
**Доказательство:** existing preview/static parity smokes.
|
||||
- [ ] **AC12 — совместимость.** Schema и saved config не мигрируют; Open → Save
|
||||
не материализует defaults; explicit pulse settings round-trip.
|
||||
**Доказательство:** frontend/backend config tests.
|
||||
- [ ] **AC13 — производительность.** Нет per-frame JS, per-marker media query,
|
||||
ResizeObserver/layout loop или SVG example assets в production bundle;
|
||||
transform/opacity motion не вызывает layout.
|
||||
**Доказательство:** code assertion + `performance_smoke.mjs` перед beta.
|
||||
- [ ] **AC14 — release artifacts.** ru/en copy, guides, architecture/testing
|
||||
docs, changelogs, targeted smokes и golden review актуальны.
|
||||
|
||||
## 16. Тестирование
|
||||
|
||||
### 16.1. Цикл реализации
|
||||
|
||||
После каждого логического блока:
|
||||
|
||||
```bash
|
||||
npm run typecheck
|
||||
npm test
|
||||
npm run build
|
||||
```
|
||||
|
||||
Unit coverage:
|
||||
|
||||
- полная state/priority/theme/display matrix;
|
||||
- lock/unlock и generic open не смешиваются;
|
||||
- LQI boundaries и неизменность room gradient;
|
||||
- pulse kinds, timings, fallback/explicit settings и reduced motion;
|
||||
- Text/Double/third section facts, long values и anchor;
|
||||
- keyboard surface policy и accessible labels;
|
||||
- config/default/round-trip compatibility.
|
||||
|
||||
### 16.2. Targeted browser smoke перед S7
|
||||
|
||||
Добавить `demo/smoke_device_icon_design.mjs` и прогнать его вместе с:
|
||||
|
||||
- `demo/smoke_device_preview_parity.mjs`;
|
||||
- `demo/smoke_static_icon.mjs`;
|
||||
- `demo/smoke_state_value.mjs`;
|
||||
- `demo/smoke_disabled_device.mjs`;
|
||||
- релевантным secure-action/keyboard smoke из существующего набора.
|
||||
|
||||
Новый smoke проверяет light/dark, все состояния, Text/Double, четыре позиции,
|
||||
long value, LQI boundaries, unavailable click, 44×44 hit area, keyboard и
|
||||
reduced motion.
|
||||
|
||||
### 16.3. Mutation gates
|
||||
|
||||
Зарегистрировать targeted mutants, которые обязаны быть пойманы тестами:
|
||||
|
||||
1. generic hover снова применяется к `.unavail`;
|
||||
2. LQI `40/180` уходит в соседний диапазон либо меняет room gradient;
|
||||
3. Text/Double снова получает ellipsis;
|
||||
4. keyboard activation вызывает отдельный action path.
|
||||
|
||||
### 16.4. Golden и pre-beta
|
||||
|
||||
Golden matrix: desktop/mobile, light/dark, neutral/hover/focus/selected,
|
||||
active/lock/unlock/alert/virtual/unavailable, Text, четыре Double, third section,
|
||||
LQI low/mid/high, reduced motion, sizes 32/56/96 и цветной фон.
|
||||
|
||||
Golden принимается только по Linux CI artifact согласно HP-QA-01. Перед beta
|
||||
запускаются полный golden, smoke и performance наборы по release runbook;
|
||||
Windows не является каноном полного HA harness из-за `fcntl`.
|
||||
|
||||
## 17. Риски и откат
|
||||
|
||||
### Риски
|
||||
|
||||
- рост shell у длинных значений может чаще пересекаться с соседями;
|
||||
- old explicit ripple size 3+ визуально заметно больше package default;
|
||||
- dark package намеренно отличается от light по blur/shadow;
|
||||
- новый focus/tab order увеличивает число клавиатурных остановок на больших
|
||||
планах;
|
||||
- ошибочная привязка общего `lqiColor()` изменит комнатную заливку;
|
||||
- новый DOM может изменить snapshot/golden fingerprint всех поверхностей.
|
||||
|
||||
### Митигации
|
||||
|
||||
- центр icon core и saved coordinates неизменны;
|
||||
- explicit settings не переписываются скрыто;
|
||||
- marker-only LQI helper отделён и покрыт regression test;
|
||||
- интерактивность добавляется только существующим actionable surfaces;
|
||||
- один renderer и одна token table исключают drift;
|
||||
- targeted golden содержит контрастные backgrounds и dense layout.
|
||||
|
||||
### Откат
|
||||
|
||||
Откат выполняется одним revert implementation commit. Миграции данных нет,
|
||||
поэтому rollback возвращает старый renderer без преобразования config. ТЗ и
|
||||
архив остаются диагностическим контрактом.
|
||||
|
||||
## 18. Release-артефакты
|
||||
|
||||
В том же user-visible implementation commit обновить:
|
||||
|
||||
- `docs/CHANGELOG.md` и `docs/CHANGELOG.ru.md` со ссылкой на #179;
|
||||
- `docs/USER-GUIDE.md` и `docs/USER-GUIDE.ru.md`: состояния, Text/Double,
|
||||
LQI, keyboard и static mode;
|
||||
- `docs/ARCHITECTURE.md`: общий presentation/face pipeline и theme context;
|
||||
- `docs/TESTING.md`: новый smoke, mutation и golden matrix;
|
||||
- ru/en i18n для доступных state/LQI descriptions и изменённого static hint;
|
||||
- screenshot/golden fingerprints и review manifest по HP-QA-01.
|
||||
|
||||
Release note: единая новая визуальная система устройств на светлой и тёмной
|
||||
теме, полные значения, читаемый LQI и клавиатурное управление. Поставка сначала
|
||||
в beta; stable — только после release gates.
|
||||
|
||||
## 19. План реализации
|
||||
|
||||
1. Зафиксировать package tokens и pure projection facts unit-тестами.
|
||||
2. Расширить presentation lock/LQI/theme facts без изменения semantic/action
|
||||
resolvers.
|
||||
3. Перевести `renderDeviceFace()` на shell/core и общие Text/Double sections.
|
||||
4. Реализовать package states, focus, unavailable и light/dark CSS.
|
||||
5. Обновить pulse timings/defaults/reduced motion.
|
||||
6. Подключить keyboard/hit area/accessibility к интерактивным surfaces.
|
||||
7. Обновить preview/static parity, settings default и i18n/docs.
|
||||
8. Добавить unit, mutation, targeted smoke и golden fixtures.
|
||||
9. Прогнать typecheck, unit, build и named smokes; отправить в S7.
|
||||
10. Перед beta выполнить полный golden/smoke/performance gate в Linux CI.
|
||||
|
||||
## 20. Принятые технические предположения
|
||||
|
||||
1. Package SVGs — visual reference; runtime DOM/SVG строится из тех же ratios и
|
||||
tokens, потому что MDI glyph, HA text и theme динамические.
|
||||
2. `Light/Zigbee LQI Low.svg` содержит ошибочный amber; red из textual spec и
|
||||
решения владельца нормативен.
|
||||
3. Package не задаёт minimum font size для бесконечно длинного значения:
|
||||
используется floor `0.25 × marker size`, затем расширяется shell.
|
||||
4. Generic physical `open` сохраняет текущую отдельную semantic-проекцию;
|
||||
специальные black/amber Lock/Unlock применяются только к lock domain.
|
||||
5. `static_icon` остаётся нереактивным, но default plate становится
|
||||
theme-aware, потому что package задаёт разные Light/Dark defaults.
|
||||
6. Отсутствующий pulse color сохраняет существующий validated live-light RGB
|
||||
раньше semantic fallback; это единственный package-compatible способ не
|
||||
потерять текущий пользовательский light-color effect.
|
||||
7. Marker LQI меняет только цвет подписи; room LQI fill остаётся непрерывным.
|
||||
8. Preview и static card показывают новый дизайн, но не получают ложную
|
||||
интерактивность либо tab stop.
|
||||
@@ -1,6 +1,6 @@
|
||||
# Спецификации задач
|
||||
|
||||
Актуально на 2026-08-17.
|
||||
Актуально на 2026-08-19.
|
||||
|
||||
GitHub Issues и GitHub Projects (v2) остаются единственным каноническим backlog проекта. Этот каталог содержит развёрнутые ТЗ: каждое ТЗ ссылается на issue, а issue — на соответствующий файл. Статус, приоритет и факт завершения меняются только в GitHub.
|
||||
|
||||
@@ -53,6 +53,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
|
||||
| [#166](https://github.com/Matysh/houseplan-card/issues/166) Солнечные лучи зеркально учитывают направление севера | [166-sun-north-rotation.md](166-sun-north-rotation.md) |
|
||||
| [#167](https://github.com/Matysh/houseplan-card/issues/167) Экспорт «только планировка» | [167-plan-only-export.md](167-plan-only-export.md) |
|
||||
| [#170](https://github.com/Matysh/houseplan-card/issues/170) HA-устройство не привязывается к комнате без HA-зоны | [170-room-without-area.md](170-room-without-area.md) |
|
||||
| [#179](https://github.com/Matysh/houseplan-card/issues/179) Новый визуальный язык маркеров устройств | [179-device-icons-redesign.md](179-device-icons-redesign.md) |
|
||||
| [#205](https://github.com/Matysh/houseplan-card/issues/205) Продолжение следа после короткой остановки пылесоса | [205-vacuum-trail-resume-grace.md](205-vacuum-trail-resume-grace.md) |
|
||||
|
||||
## P2
|
||||
|
||||
Reference in New Issue
Block a user