Commit Graph
31 Commits
Author SHA1 Message Date
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
Sergey Matyunin f5c6d70b7c fix: stabilize cold 2.5D first frame
Issue: #654
User-Visible: yes
2026-09-26 09:05:20 +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 Matyunin 62d0f50593 feat(editor): перетаскивание кнопки настроек комнаты (#645)
Кнопка сохраняет положение в пределах комнаты только на время сессии редактора,
корректно отменяется при pinch/cancel и учитывается подписями Resize.

Issue: #645
User-Visible: yes
2026-09-25 08:33:07 +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
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
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
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 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
Matyshandclaude[bot] be5eeb41c3 fix: remove isometric overlay plates
Keep the raised overlay footprint as calculation-only geometry for collision, nudge and fit while removing its painted SVG surface and texture. Update Stage 3 contracts, smokes, golden harness rules and synchronized bundles.

Issue: #471
User-Visible: no
2026-09-06 11:23:51 +00:00
Sergey Matyunin ee7d486924 feat: implement isometric stage 3
Issue: #160
User-Visible: no
2026-09-06 07:06:54 +03:00
Sergey Matyunin 4aad9facdf feat: fit rooms from view
Issue: #152
User-Visible: yes
2026-09-04 10:24:25 +03:00
Sergey Matyuninandclaude[bot] dc95563d96 feat: add reusable custom decor images
Issue: #51
User-Visible: yes
2026-09-02 21:56:04 +00:00
Sergey Matyuninandclaude[bot] a0720e7584 fix: align support controls
Issue: #415
User-Visible: yes
2026-09-02 05:08:51 +00:00
Sergey Matyuninandclaude[bot] f5ba67d069 feat: add private help and feedback reports (#43)
Issue: #43
User-Visible: yes
2026-09-02 00:05:36 +00:00
Sergey Matyunin 686557c5cf feat: add smooth furniture transforms
Issue: #383
User-Visible: yes
2026-08-30 11:56:35 +03:00
Sergey Matyuninandclaude[bot] 5d37438e11 fix: make devices inert in the Background editor
Issue: #362
User-Visible: yes
2026-08-29 06:39:28 +00:00
Matysh fd762fa744 fix: restore reviewed furniture preview tree
The code-review worker published its report from a stale local snapshot and unintentionally reverted the already reviewed implementation artifacts. Restore every affected path exactly to the reviewed 84bdc7ef tree while retaining CODE-REVIEW-359-r1.md.

Issue: #359
User-Visible: no
2026-08-29 00:51:43 +03:00
claude[bot] bb2919f8c0 docs: review document for #359
Issue: #359
User-Visible: no
2026-08-28 21:49:12 +00:00
Matysh 8b66d67d3d feat: preview furniture placement
Issue: #359
User-Visible: yes
2026-08-29 00:34:06 +03:00
Matysh a66fb7ef53 feat: unify zero-thickness walls
Issue: #306
User-Visible: yes
2026-08-26 13:39:52 +03:00
Codex 0b782ee714 fix: host-gated groups belong to their owner surface; split mixed media wrappers (#266)
CI-шард смока поймал сдвиг каскада, невидимый golden-набору:
smoke_device_icon_design — alert-shell стал серым, dark-unavailable core
светлым. Причина: классификатор считал ведущий :host(...) владельцем
селектора и уносил гейтнутые группы устройств в base — ВПЕРЁД их поверхности,
меняя победителя при равной специфичности. Теперь :host-префикс — гейт, а не
владелец: владелец — первый значимый токен после него; смешанные @media
режутся на последовательные по-зонные копии обёртки (reduced-motion обёрток
стало 12 поверх тех же правил 10 исходных — юнит заякорен на факт, сверка
scope-ключом доказывает, что ни одно правило обёртку не потеряло). Два
мутантных якоря вернулись в devices.styles.ts; исключение юнита
непересечения опустело.

Гейты: refactor-proof diff пуст · golden 129/129 без переприёмки · смоки
device_icon_design, plan_snap_overlay, preloader OK · npm test 1318/0.

Issue: #266
User-Visible: no
2026-08-26 01:55:00 +03:00
Codex 55f7126afd refactor: extract the plan surface styles (#266 slice 4/5)
250 блоков сцены плана (stage, стены/оси/снап, декор, iso, resize ink) →
src/styles/plan.styles.ts, склейка [inline, plan, devices, chrome, dialogs].
Refactor-proof diff пуст; golden 129/129; обязательные смоки медиа-обёрток
(spec §7) smoke_plan_snap_overlay (forced-colors) и smoke_preloader
(reduced-motion) — OK; npm test 1315/0.

Issue: #266
User-Visible: no
2026-08-26 01:34:20 +03:00