# Changelog ## Unreleased ## v1.64.0-beta.1 — 2026-08-14 - Read-only View and kiosk cards now paint a complete first frame even when Home Assistant refuses live-sync event subscriptions. The selected space, room fills, decor, walls, Glow and device values no longer require clicking the already active space tab ([#131](https://github.com/Matysh/houseplan-card/issues/131)). - Virtual markers configured as **Light source → Always** with **Toggle state** can now be switched directly without an HA helper. Their shared state survives reloads/restarts and stays consistent across Glow, room light presentation, full cards and static space cards, including markers that retain saved outgoing controls ([#107](https://github.com/Matysh/houseplan-card/issues/107)). - Small fixes and improvements. ## v1.63.0 — 2026-08-13 - Preserved explicit door, window and gate bindings when their standalone sensor or lock marker is removed, and fixed the supported empty state after deleting the last space ([#104](https://github.com/Matysh/houseplan-card/issues/104), [#111](https://github.com/Matysh/houseplan-card/issues/111)). - Splitting a room from an existing corner no longer deforms the exterior facade, including with thick dividers. Flat, static and hidden isometric rendering use the same preserved wall geometry ([#123](https://github.com/Matysh/houseplan-card/issues/123)). - Small fixes and improvements. ## v1.63.0-beta.2 — 2026-08-13 - Splitting a room from an existing corner no longer deforms the exterior wall or pulls a thick internal divider through the facade. Plan, View, kiosk, static cards, hidden isometric rendering and light obstacles now use the same preserved exterior geometry, including already saved plans ([#123](https://github.com/Matysh/houseplan-card/issues/123)). - Small fixes and improvements. ## v1.63.0-beta.1 — 2026-08-13 - Deleting a standalone sensor or lock marker no longer breaks its explicit door, window or gate binding: the entity stays available in opening settings and continues to drive its state without restoring the marker on the plan ([#104](https://github.com/Matysh/houseplan-card/issues/104)). - Fixed a crash after deleting the last space: the supported empty state now stays usable so a new space can be added ([#111](https://github.com/Matysh/houseplan-card/issues/111)). - Small fixes and improvements. ## v1.62.0 — 2026-08-13 - Added portable full-plan and single-space backups with server-validated preview, safe import and one-step undo, plus reusable contextual help for complex settings ([#50](https://github.com/Matysh/houseplan-card/issues/50), [#68](https://github.com/Matysh/houseplan-card/issues/68)). - Added passive light markers, explicit leading-entity selection and user-controlled value badges, while unifying device actions and activity presentation across the plan, preview and static cards ([#84](https://github.com/Matysh/houseplan-card/issues/84), [#88](https://github.com/Matysh/houseplan-card/issues/88), [#90](https://github.com/Matysh/houseplan-card/issues/90), [#94](https://github.com/Matysh/houseplan-card/issues/94), [#98](https://github.com/Matysh/houseplan-card/issues/98)). - Reworked opening placement with a Window / Door / Gate submenu and a full-symbol preview on thick walls. Fixed room Split wall thickness, opening tunnel seams and Glow sources embedded in walls or exterior openings ([#75](https://github.com/Matysh/houseplan-card/issues/75), [#76](https://github.com/Matysh/houseplan-card/issues/76), [#81](https://github.com/Matysh/houseplan-card/issues/81), [#91](https://github.com/Matysh/houseplan-card/issues/91), [#92](https://github.com/Matysh/houseplan-card/issues/92)). - Added coherent transitions between View and editors, restored reliable window sun rays, and hardened editor lifecycle, composite-device selection, previews and regression coverage ([#93](https://github.com/Matysh/houseplan-card/issues/93), [#95](https://github.com/Matysh/houseplan-card/issues/95), [#101](https://github.com/Matysh/houseplan-card/issues/101), [#102](https://github.com/Matysh/houseplan-card/issues/102)). - Small fixes and improvements. ## v1.62.0-rc.1 — 2026-08-13 - Republished the reviewed beta.10 candidate under an RC identifier so HACS discovers it after beta.9; the application code and user-visible behaviour are unchanged. ## v1.62.0-beta.10 — 2026-08-13 - Fixed composite device presentation and actions after the beta review: an explicitly selected light entity now remains the tap target, a primary cover keeps the cover face, and registry-backed state selection is identical in the full plan, preview and static card. Strengthened Split, Glow, contextual-help and opening-preview regression coverage. - A light source placed inside a physical wall, window tunnel or exterior door/gate opening intentionally produces no Glow; move its marker onto the room floor to restore illumination ([#92](https://github.com/Matysh/houseplan-card/issues/92)). - Small fixes and improvements ([#108](https://github.com/Matysh/houseplan-card/issues/108)). ## v1.62.0-beta.9 — 2026-08-12 - Fixed post-review inconsistencies between device state and tap behaviour: exact bindings no longer toggle a sibling entity, a passive relay controls its leading entity, and incidental cover or humidity entities no longer take over a composite device's presentation. - Hardened opening placement with shared defaults, a stable geometry cache, correct centre snapping and a stricter visual preview gate. Restored the public activity and preview-dot CSS hooks, improved help accessibility and strengthened internal process checks. - Small fixes and improvements ([#108](https://github.com/Matysh/houseplan-card/issues/108)). ## v1.62.0-beta.8 — 2026-08-12 - Reworked opening placement in the Plan editor. **Opening** now opens a compact Window / Door / Gate sub-menu; choosing a type arms its 120 / 90 / 300 cm preset and shows the complete future architectural symbol at 50% opacity on top of physical walls. Thick-wall targeting, junction selection, click without prior hover and repeated placement are now deterministic, while the persisted opening model remains unchanged ([#75](https://github.com/Matysh/houseplan-card/issues/75), [#76](https://github.com/Matysh/houseplan-card/issues/76)). - Hardened the beta after the full review: editor close/navigation can no longer be swallowed by an active transition or context tray; device taps, passive light state and value badges now use the same resolved sources on every surface; legacy temperature/humidity satellites are preserved; help, paired import/export and split-wall geometry gained the missing guards and regression coverage. Small fixes and internal improvements ([#50](https://github.com/Matysh/houseplan-card/issues/50), [#68](https://github.com/Matysh/houseplan-card/issues/68), [#84](https://github.com/Matysh/houseplan-card/issues/84), [#90](https://github.com/Matysh/houseplan-card/issues/90), [#91](https://github.com/Matysh/houseplan-card/issues/91), [#92](https://github.com/Matysh/houseplan-card/issues/92), [#94](https://github.com/Matysh/houseplan-card/issues/94), [#95](https://github.com/Matysh/houseplan-card/issues/95), [#98](https://github.com/Matysh/houseplan-card/issues/98), [#101](https://github.com/Matysh/houseplan-card/issues/101)). ## v1.62.0-beta.7 — 2026-08-12 - Fixed the first opening of device settings: **Display**, **Room** and **Leading light entity** now immediately show the value that is actually persisted instead of the first option. The form and its preview can no longer report different settings. - Added a shared native-select contract and browser checks that reopen a device with non-first persisted choices. Future selectors can no longer silently reintroduce the unsafe binding pattern. ## v1.62.0-beta.6 — 2026-08-12 - Fixed the remaining cause of invisible window sun rays in real Home Assistant installations. Core/runtime entities such as `sun.sun` may have a live state without an Entity Registry row; House Plan now preserves that state while continuing to exclude explicitly disabled entities and devices ([#102](https://github.com/Matysh/houseplan-card/issues/102)). - Added a deterministic visual regression crop of an exterior window and its ray. The browser now compares the reviewed image with the same frame after hiding only the sun layer and fails unless the ray paints a material number of pixels, so an empty screenshot cannot be accepted as success. ## v1.62.0-beta.5 — 2026-08-12 - Unified all device activity around one predictable pulse system. Alerts use the red alarm pulse, witnessed events use three finite waves, and ongoing work, movement or presence uses one continuous pulse. Static rings are gone; reduced-motion users get a compact dot for ordinary activity. The full plan, device preview and static space card now share the same resolver and renderer ([#98](https://github.com/Matysh/houseplan-card/issues/98)). - Made transitions between View and all three editors coherent. Toolbar height, usable plan area, camera, background and editor presentation now move on one short timeline; editor-to-editor switches fade their incoming controls, rapid choices retarget from the visible frame, and reduced motion remains atomic ([#101](https://github.com/Matysh/houseplan-card/issues/101)). - Fixed the device editor's **Value** selector visually showing its first row instead of the source that was actually saved and rendered on the plan. Saved source and position are now selected explicitly when the dialog opens, including temporarily missing sources ([#100](https://github.com/Matysh/houseplan-card/issues/100)). - Fixed contextual help temporarily adding a vertical scrollbar to its owning dialog. The accessibility-only description no longer participates in the dialog's scroll geometry in either native Popover or fallback mode ([#99](https://github.com/Matysh/houseplan-card/issues/99)). - Fixed a transition regression that could leave window sun rays invisible in View. The ray layer again owns its lifecycle independently from editor transitions, without changing sun position, window geometry or the existing threshold fade ([#102](https://github.com/Matysh/houseplan-card/issues/102)). ## v1.62.0-beta.4 — 2026-08-12 - Fixed contextual help showing a dead icon when its explanation was absent. Incomplete help content is now omitted entirely, and the plain `?` glyph was replaced with the consistent outlined circled-question icon ([#68](https://github.com/Matysh/houseplan-card/issues/68)). - Hardened universal **Toggle state** after the beta code review. Climate, water-heater, siren, camera, media-player and legacy-vacuum actions now require the exact HA entity capability bits as well as a live service; clicks resolve current controls instead of a retained visual frame, and a disabled legacy cover keeps its original, explainable target ([#94](https://github.com/Matysh/houseplan-card/issues/94)). - Fixed the device editor showing **Device card** for a lamp whose effective default action is **Toggle state**. Untouched actions now follow the current preview entity in real time, while explicit choices and lossless legacy storage remain unchanged ([#97](https://github.com/Matysh/houseplan-card/issues/97)). - Fixed **Device card** taps doing nothing on compound curtain/cover devices. The local House Plan card now opens independently of a momentary HA registry revalidation, while HA more-info and service actions retain their safety gate ([#96](https://github.com/Matysh/houseplan-card/issues/96)). - Fixed an editor-close race after a same-route technical remount. A visible editor now closes on the first press even while write permission is still resolving; the late server response can no longer reopen it ([#95](https://github.com/Matysh/houseplan-card/issues/95)). ## v1.62.0-beta.3 — 2026-08-12 - Replaced the separate Toggle and cover actions with one universal **Toggle state** action. The device editor now shows the exact target, current/next effect and any skipped or unsupported entities; covers and valves retain open/close/stop behaviour, secure devices remain no-op, and configured no-target actions never fall back to an info card. Existing `cover` records remain lossless until deliberately edited ([#94](https://github.com/Matysh/houseplan-card/issues/94)). - Returning to House Plan now restores only the last space and always opens View. Editor mode and dialogs no longer survive page reloads or navigation through other Home Assistant pages; same-route technical remounts still protect unfinished work ([#93](https://github.com/Matysh/houseplan-card/issues/93)). - Fixed Glow starting from inside a thick wall or an exterior opening and lighting one half of an exterior door or gate tunnel. Sources embedded in the final opaque masonry geometry now produce no Glow at all, while real interior passages remain transparent ([#92](https://github.com/Matysh/houseplan-card/issues/92)). ## v1.62.0-beta.2 — 2026-08-11 - Added a user-controlled value badge beside each device. Users can select the exact reading and place it on the right, bottom, left or top; preview, the main plan and the static space card consume one resolver, while untouched legacy markers retain their previous automatic behaviour ([#90](https://github.com/Matysh/houseplan-card/issues/90)). - Fixed room Split losing the thickness of adjoining walls. Split now materializes exact intervals from the legacy wall profile before changing geometry, so the new thickness applies only to the divider ([#91](https://github.com/Matysh/houseplan-card/issues/91)). - Hardened portable backups: full import retains the model version, write endpoints and preview tokens have negative coverage, and the test harness clears temporary plans and attachments. - Removed the contextual-help scroll-listener leak and made the plan-wide light graph resolve once per frame instead of once for every marker. - Strengthened golden, smoke and repository gates: the seam scenario now crosses a stepped wall, baseline inventory is exact, and temporary-file plus browser-quiescence flakes are eliminated. ## v1.62.0-beta.1 — 2026-08-11 - Fixed layout maintenance silently discarding the one-deep Optimize/Import undo snapshot. Explicit geometry repair and its undo now preserve all store metadata and keep the plan snapshot valid for the resulting layout revision ([#87](https://github.com/Matysh/houseplan-card/issues/87)). - Added passive plan light sources and explicit leading-entity selection. A virtual dumb lamp can now own its Glow position, colour, brightness and radius while following a smart relay; multiple controllers use OR, and `marker:*` links are validated without ever reaching Home Assistant as entity IDs. Multi-channel Always sources can select the meaningful `light.*` or `switch.*` instead of silently using registry order ([#84](https://github.com/Matysh/houseplan-card/issues/84), [#88](https://github.com/Matysh/houseplan-card/issues/88)). - Added portable House Plan backups: editors can export the complete model or one space, inspect a server-validated JSON import before any write, safely handle duplicate HA bindings and undo a full replacement until the next plan edit. Internal plans and attachments remain local references rather than being silently copied between Home Assistant instances ([#50](https://github.com/Matysh/houseplan-card/issues/50)). - Fixed recurring one-pixel SVG seams in room-coloured door, window and gate tunnels. Equal and stepped wall profiles now render as continuous contours without translucent overlaps or gaps at fractional zoom ([#81](https://github.com/Matysh/houseplan-card/issues/81)). - Added reusable localized help buttons for complex settings. They work with mouse, keyboard and touch, stay inside the viewport, and share the dialog's Escape and focus lifecycle ([#68](https://github.com/Matysh/houseplan-card/issues/68)). ## v1.61.0 — 2026-08-11 - Expanded robot-vacuum integration coverage with deterministic source selection, explicit capability and health diagnostics, gap-preserving trails, safer map arbitration and stricter calibration checks. - Reworked room colour and lighting controls. Glow is an independent additive overlay, room fills keep their exact configured colour, and each source can use automatic, always-on or disabled behaviour with manual colour, brightness and radius where applicable. - Light propagation now follows the same physical wall bodies drawn on the plan, including wall thickness, jambs, partitions and columns. Doorways and virtual boundaries transmit light without seams, while walls and corners cast stable clipped shadows. - Returning to a tab, reconnecting Home Assistant or remounting the card keeps the last coherent plan frame. Devices, rooms, Glow, sun, openings, vacuums and live decorative text update atomically instead of flashing partial state. - Small fixes and improvements to dialogs, room hover, device markers, editor stability, validation and release tooling. ## v1.61.0-beta.8 — 2026-08-11 - Plan recovery now has one bounded two-second barrier: a stalled signature or protected-backdrop decode can no longer leave an already complete plan below an opaque layer forever. The card retains its last coherent frame, while a cold failure exposes an explicit retryable error. - Added an immutable per-frame data snapshot. Devices, positions, room fills, Glow, sun, openings, vacuums and HA variables in decorative text now update together instead of mixing old and new state during reconnect. - Connection readiness is treated as recovery only after a confirmed loss; ordinary HA ticks no longer alter the structural frame fingerprint. Forced config refreshes, signed-URL caching and late image load events are now protected from their respective races. - Strengthened deterministic continuity, protected-backdrop and screencast coverage. The browser scenario now exercises the production visibility listener while checking geometry, devices, Glow, sun and decor together. ## v1.61.0-beta.7 — 2026-08-11 - Fixed rare but severe Glow geometry failures: a clipping exception can no longer paint outside the house, a grid-snapped source on a wall stays dark, and the angular seam no longer cuts a wedge from an otherwise valid pool. Light barriers now invalidate for every changed body point, wall endpoint, scale or space. - Delete/Cancel/Save in opening and space dialogs now use the same responsive grouped footer as physical-object properties, keeping localized actions inside narrow dialogs. - Returning to a dashboard no longer hides or rebuilds an already complete plan. Full and compact cards keep the last coherent frame through tab sleep, reconnect, remount and transient resize; identical config/layout echoes are adopted without geometry churn, and protected backdrops share a bounded loaded cache. A localized recovery layer is reserved for the rare case where no complete frame can be retained. ([#73](https://github.com/Matysh/houseplan-card/issues/73)) - Restored the room-hover contract without bringing back the Glow flash: a neutral clean-floor wash now darkens the resolved room fill while its late outline remains above walls; Glow, sun, openings and devices stay visually independent. ([#79](https://github.com/Matysh/houseplan-card/issues/79)) - Working device markers keep their yellow resting plate with the ordinary neutral elevation shadow, use the same hover as other interactive markers, and no longer add an unrelated yellow outer glow. ([#80](https://github.com/Matysh/houseplan-card/issues/80)) ## v1.61.0-beta.6 — 2026-08-11 - Fixed shared dialog layout for localized content: multi-line titles now grow the Home Assistant header instead of being clipped, and physical-object footers keep Delete inside the left inset while Cancel/Save wrap together on narrow dialogs. ([#77](https://github.com/Matysh/houseplan-card/issues/77), [#78](https://github.com/Matysh/houseplan-card/issues/78)) - Light now works one way, everywhere: a lamp lights the floor it can see. Walls block it with their real thickness — the same bodies the plan draws — as do columns and free-standing partitions; doorways, gates and virtual boundaries simply are not walls, so light crosses them, and a thick wall's jambs narrow the beam exactly as they would in the house. Everything else follows from that single rule — a doorway carries one continuous light instead of an unlit bar and a detached blob, a beam ends where the receiving room's own walls end, a column and a wall corner cast crisp shadows (also when they belong to a room further away), and shadow edges are lines with a hairline penumbra rather than smears. A window and an outside door stay solid for light — there is no floor behind a front door to light, so it no longer glows halfway. Pools also fade over their whole radius instead of holding a flat plateau to 70%, so distant floor is faint because it is distant. As a side effect the light layer became a single clipped circle per source. Cold geometry calculation on a complex plan became dramatically faster; the warm render path remains broadly comparable with beta.5 and is tracked separately. ([#71](https://github.com/Matysh/houseplan-card/issues/71)) - Fixed a one-frame Glow brightness flash when hovering any room. Room hover now uses a plain SVG wash and double outline without compositor filters. ([#72](https://github.com/Matysh/houseplan-card/issues/72)) - Prerelease publishing now accepts an intentionally skipped announcement job, so recovery after a partial workflow run no longer rejects a valid release. ## v1.61.0-beta.5 — 2026-08-10 - Device settings now offer Auto / Always / Never light-source roles. Per-source Glow can follow Home Assistant, use a custom colour with live brightness, or fix both colour and brightness; dim lights remain visibly readable through a perceptual intensity curve. ([#65](https://github.com/Matysh/houseplan-card/issues/65), [#66](https://github.com/Matysh/houseplan-card/issues/66), [#67](https://github.com/Matysh/houseplan-card/issues/67)) - Compatibility note: an explicitly stored `is_light: false` now means Never, rather than behaving like Auto. UI-authored historical configs normally used `null`, so this primarily affects hand-written YAML. - Prerelease validation now uses a short candidate-only 60-source Glow performance smoke. The expensive same-runner baseline comparison remains mandatory for stable releases and runs on `main`, weekly and on demand. ([#69](https://github.com/Matysh/houseplan-card/issues/69)) - Telegram release announcements are now sent only for stable releases; betas and release candidates publish silently. ([#70](https://github.com/Matysh/houseplan-card/issues/70)) ## v1.61.0-beta.4 — 2026-08-10 - Performance comparison now keeps newly introduced private members optional for older supported baselines while validating every present field's runtime type. Rewritten-push baselines prefer the candidate parent and emit a warning instead of silently jumping to an older release. ([#15](https://github.com/Matysh/houseplan-card/issues/15), [#16](https://github.com/Matysh/houseplan-card/issues/16)) - In Glow spaces, LQI/Light/Temperature modes without usable HA data now fall back to the dark room base instead of exposing a bright unfilled paper hole. A genuinely resolved data or custom fill still keeps its exact color and opacity. ([#61](https://github.com/Matysh/houseplan-card/issues/61)) - In space settings, Custom color is now the ordinary first room-fill mode and replaces the separate None choice. Historical spaces with `fill_mode: none` open as a zero-opacity custom color, preserving the same floor and Glow appearance through Preview and Save. New spaces also start at zero opacity, so replacing the choice does not change their previous initial appearance. An individual room can still suppress an inherited dynamic fill. ([#64](https://github.com/Matysh/houseplan-card/issues/64)) - Prerelease publication can now be completed with one fail-closed local command or a manual GitHub Actions run. Version files, bilingual release notes, the exact-SHA Validate result, annotated tag, both release assets and HACS discovery are checked before completion. Downloaded JS/ZIP contents are bound to the candidate hash and manifest version; per-tag concurrency rejects parallel publication. ZIP inspection is portable across Windows and Linux without a system `tar`, while standalone JS and hashes come from exact Git blobs rather than CRLF-sensitive worktree bytes; stale assets are repaired automatically and handled interruptions release the local lock. The public release is staged as a draft first and partial failures are safe to retry. Existing release workflows remain available as a fallback. ([#63](https://github.com/Matysh/houseplan-card/issues/63)) ## v1.61.0-beta.3 — 2026-08-10 - Performance tooling now fails before measurement when a candidate/base card no longer exposes a private API consumed by the benchmark, documents the safe two-revision rename path, and falls back from an unreachable force-push comparison SHA to the latest reachable release. The bilingual release-body headings now have one explicit canonical template. ([#15](https://github.com/Matysh/houseplan-card/issues/15), [#16](https://github.com/Matysh/houseplan-card/issues/16), [#17](https://github.com/Matysh/houseplan-card/issues/17)) - Rooms and spaces can now use a persistent custom fill color and opacity, independently of border/name color and Home Assistant state. Room overrides inherit safely from the space and can be reset. ([#56](https://github.com/Matysh/houseplan-card/issues/56)) - Glow no longer darkens or tints LQI, light, temperature, or custom room fills: those colors stay exact while live radial light pools remain visible. ([#61](https://github.com/Matysh/houseplan-card/issues/61)) - The global Glow radius now sits with the other Glow settings. Small code review cleanups also remove an unreachable legacy branch and empty static SVG layers. ([#60](https://github.com/Matysh/houseplan-card/issues/60)) ## v1.61.0-beta.2 — 2026-08-10 - Light-source Glow is now an independent overlay that can be combined with temperature, Zigbee signal, light-state or no room fill. Existing plans that used the legacy Glow fill keep the same effective appearance and migrate losslessly on a normal save or Optimize Plans. - Overlapping light pools now blend additively, producing brighter mixed-colour intersections. The card verifies real SVG support at runtime and falls back safely to the previous normal composition on unsupported engines. - Closing a device card opened by mouse long-press no longer leaves the plan attached to the cursor or reopens the dialog from a stale gesture. ## v1.61.0-beta.1 — 2026-08-09 - Stored plan colours now use one strict `#RRGGBB` contract at both API and render boundaries. Malformed legacy/imported values safely fall back instead of being able to add CSS declarations; Home Assistant RGB light colours stay supported through a separately generated numeric form. - Vacuum integration coverage is now explicit and diagnosable. One sticky, order-independent source resolver supports same-device discovery and a lazy picker for registry-less map cameras, distinguishes missing, disabled, unavailable and limited-permission states, and never leaks stale disabled telemetry onto the plan. - Xiaomi Cloud Map Extractor multi-subpath trails retain real gaps; path arbitration, point budgets and map IDs are deterministic across frontend and backend. Room calibration uses area centroids on both sides, keeps bbox-only integration dialects through a final bbox-centre fallback, and a physical error above 40 cm now requires Apply or manual fitting before config changes. - Server trail health reports one deduplicated warning per missing/disabled source incident and records recovery. Documentation now states the verified Dreame/XCME/Valetudo capability matrix; Roomba remains Stage 2. ## v1.60.3 — 2026-08-09 - Editor toolbars now keep their working area stable: selection actions, transient tool settings and the furniture palette open in one accessible context tray over the stage, while Close remains pinned. Adaptive wide, medium and narrow layouts are covered by deterministic golden scenarios. - Returning to a browser tab no longer causes the plan to flash or briefly reset its zoom/day state. Two-finger gestures cannot activate an underlying marker, and vacuum-map fitting isolates its own gesture surface. - Thick-wall openings use one wall association for their symbol, cut and room-coloured tunnel. Detached/T-junction walls no longer steal a side, overlapping openings do not compound opacity, and adjacent atomic tunnel strips no longer expose thin SVG seams. - Furniture previews stay inside their palette buttons, the editor Close icon is centred, and dismissing an unarmed palette no longer leaves click suppression behind. - Maintenance improvements include deterministic golden-image coverage, same-runner performance gates and migration of the active backlog to GitHub Issues + Project v2. - Small fixes and improvements. ## v1.60.3-beta.2 — 2026-08-09 - Editor toolbars now keep a stable height while selecting objects or changing active-tool context. Properties, Delete, drawing parameters, operation hints and the furniture palette use one translucent tray over the stage, so the plan no longer shrinks/refits and Close stays pinned. The same accessible surface is prepared for future explicitly designed tool groups without grouping any current buttons automatically. - Two-finger gestures no longer activate an interactive plan item when a pinch starts over it, and robot-map calibration no longer zooms the plan underneath its overlay. Furniture palettes and future tool groups now dismiss reliably outside the card without swallowing an unrelated following click. - Small fixes and improvements: reduced-motion navigation is respected again, stale contextual actions are rejected immediately after local edits, and the editor/performance regression checks now exercise their real UI and state. ## v1.60.3-beta.1 — 2026-08-08 - Returning to a briefly backgrounded browser tab no longer forces a one-frame day/night/hover reset that could make the whole plan flash. Long suspended tabs keep the protected settle and immediate sun catch-up. - Thick-wall openings now use one cached wall association for their symbol, wall cut and room-coloured tunnel. Nearby detached walls and perpendicular T-junction arms can no longer steal a tunnel side, while overlapping openings no longer darken the room fill twice. A legacy opening whose saved angle or offset no longer actually aligns with a wall is no longer allowed to cut or shift that wall; re-snap the opening in the Plan editor to restore it. - Expanded always-static device coverage now verifies RGB suppression, size/rotation, lifecycle priority, mode round trips, plan/preview/static-card parity and live-vacuum overlay removal. - Maintenance groundwork adds an offline compatibility-field registry/config audit, a schema-valid large-house performance baseline with stale-bundle and precise-memory guards, deterministic golden-image capture/review infrastructure and the first render-only extraction from the root card. These changes do not alter saved data or the plan's SVG/interaction contract. ## v1.60.2 — 2026-08-08 - Door, window and gate tunnels in thick walls now continue the effective room fill instead of exposing a white paper strip. An exterior opening uses its room colour through the full wall depth; a shared opening splits cleanly on the wall centreline when its rooms use different fills. Glow, window sun rays and opening symbols keep their existing behaviour. - Device display now has an **Always static icon** option. It keeps the normal dark icon unchanged by work, open, alarm, unavailable, RGB, values or sensor badges, and hides live vacuum puck/trail overlays. Hover, actions, controls and the device's separate contribution to room light remain unchanged. The former **Icon** option is now named **Icon + dynamic plate**. - A controller no longer becomes a physical Glow origin merely because it has managed light targets. `controls` still drives group toggling, room light state and statistics, while the actual lamp marker owns the light pool. A marker's own legacy `switch.*` self-control is no longer inferred as a light; relay-driven fixtures require the explicit “This device is a light source” flag. ## v1.60.2-beta.3 — 2026-08-08 - Saved devices disabled in Home Assistant are now forced off the plan and all plan calculations until re-enabled, while the Device editor keeps a labelled service ghost. Registry refresh now also recovers from unavailable update subscriptions, and preview/static-card status hooks and explanations stay in sync. Small accessibility, routing and preview-parity fixes are included. - Openings now include Gate. It keeps the same contact, lock, wall cut and Glow behaviour as a door, but defaults to 300 cm and uses two half-width leaves opening only 10° outwards, without a plan-obscuring full swing arc. - Sunlight through windows no longer depends on a weather entity: clouds, rain and snow cannot dim or hide geometrically valid rays. The obsolete weather selector is removed; legacy stored values are safely ignored. - Device settings now include a live display preview with the actual current state, effective source entities, the providing Home Assistant integration, an explanation of the resulting marker, and a safe local activity demo. The full plan, preview and read-only space card now share one presentation resolver and one marker-face renderer. - Existing `Value instead of icon` markers can now show localized text states, not only numeric measurements. Long valid values are ellipsized without changing the marker hit area, while their full text remains accessible. - When several equally valid visual sources exist, `Value instead of icon` no longer picks the first registry entity arbitrarily: it falls back to the device icon and the preview explains the ambiguity. - Decorative lines can now be switched between Solid and Dashed in the properties dialog opened by double-clicking a finished line. Existing and newly drawn lines stay solid by default, and dashed gaps retain a comfortable selection target in the Background editor. - The Plan editor now has one contextual Boundary tool instead of separate Virtual wall and Physical wall buttons. Two points on a solid shared wall open a virtual stretch; one click on a dashed stretch restores its complete physical body with the inherited thickness previewed before the click. Screen-space hit zones stay usable at every zoom, ambiguous junctions and independent masonry block unsafe edits, and an unfinished first point is cancelled by Esc, Undo/Redo, navigation, reconnect or multi-touch. - The shared `hp-dialog` now wraps long translated titles and device names instead of clipping them horizontally. Numeric angle fields across editors display at most three decimal places without rounding stored geometry. ## v1.60.2-beta.2 — 2026-08-08 - Composite switch-only devices now use one representative lifecycle entity instead of treating every uncategorised feature toggle as whole-device activity. A dedicated Power switch is selected from generic Home Assistant metadata: powered-on appliances stay neutral, while off/unavailable ones use the existing faded presentation. Standalone relays retain their normal yellow working state. - Device information uses the wide responsive dialog shell and a wrapping footer which keeps Edit, Open in HA and Close aligned on narrow screens. - New Room has one save path: choosing “No area” in the area list and entering a name enables the regular Save action and stores `area: null`; the duplicate “No area” footer button has been removed. - Erase in the Background editor gives thin lines and outlined shapes an invisible 16 px screen-space target without changing their appearance. The target remains usable at every zoom level. ## v1.60.2-beta.1 — 2026-08-07 - The final review follow-up makes geometry cache invalidation root-safe and LRU-bounded, keeps pan/pinch available over saved outline hit targets, rejects partially numeric editor values, preserves absent column angles in Optimize Plans and gives rotation handles a full 24 px touch target. Boolean geometry now has a lossless sequential fallback, and draft joining plus editor-to-editor height animation are covered by realistic browser smokes. - The Plan editor now supports persistent unfinished room outlines, room-independent partitions and square/circular columns. They stay on the grid, participate in clean floor area, Glow and window-ray occlusion, and share the geometry Undo/Redo stack. Select provides drag, properties and a rotation handle for square columns; saved outlines can be resumed or joined endpoint-to-endpoint. Client and backend limits are aligned and invalid thicknesses are rejected visibly instead of being silently clamped. - Audit hardening adds cached clean-floor/light geometry, complete blocking for a light embedded in masonry, leak-free point shadows behind long partitions, strict column validation, reconnect gesture cancellation and browser smoke coverage for the new physical objects. - While drawing a room outline, Shift now locks the new segment to the nearest 45° direction. The preview and committed vertex match, and the endpoint remains strictly grid-bound. - The Plan editor toolbar now uses the compact labels Merge, Virtual wall, Physical wall and Thickness. Undo and Redo are icon-only while retaining localized tooltips and accessible names. - The Background editor now de-emphasizes physical, thick and dashed virtual walls to the same 35% opacity as every other non-decor plan layer. - Switching between editors on the same space now visibly fades in the new toolbar and interpolates its measured height. Different wrapping and tool composition no longer make the plan jump; rapid switches continue smoothly from the current intermediate height. - Audit hardening makes editor history unambiguous on QWERTZ/AZERTY and non-Latin layouts, gives SVG text an atomic Gecko/WebKit hit-test fallback, and fully resets or disables hidden navigation/editor chrome after lifecycle changes. Exact header sizing no longer leaves a stale viewport. - Opening and saving a marker no longer drops ordered, duplicate or temporarily unknown external controls. Climate recognizes preheating/defrosting and ignores vendor pseudo-actions before using its documented mode fallback; Optimize Plans repairs zero, null and negative grid scales to the 5 cm default. ## v1.60.1-beta.1 — 2026-08-07 - Climate markers whose integrations omit `hvac_action` now fall back to the current non-off HA mode advertised in `hvac_modes`, so enabled air conditioners regain their yellow working plate. A present action remains authoritative, therefore `hvac_action: idle` stays neutral. - Room settings now opens at the medium dialog width. Long radio labels and source names wrap or ellipsize within the content area, eliminating the horizontal scrollbar while retaining responsive mobile sizing. - Erase now treats a text label as one atomic decor object across its full bounding box. Clicking between glyphs or on its selection glow can no longer remove only the apparent outline; an empty-canvas miss is a true no-op. - Space tabs, View/editor changes and switches between editors now use one short, subtle transition. Editor controls expand and collapse smoothly, and reduced-motion preferences still disable all navigation motion. - While drawing a room outline, Ctrl/Cmd+click now closes the last point back to the first without adding another vertex. Closure requires at least two existing edges and refuses degenerate or self-intersecting contours. - Editor Undo/Redo shortcuts now use layout-independent keyboard codes, so Ctrl/Cmd+Z, Ctrl/Cmd+Shift+Z and Ctrl/Cmd+Y work with non-Latin layouts too. Focused text and number fields retain their native browser history. - Closed the v1.60.0 follow-up audit: reconnecting during resume settle can no longer strand the plan veil; legacy self-controlled switches retain their light-source intent and migrate to `is_light`; colour/opacity pickers use the browser top layer and flip/clamp inside small dialogs; Optimize repairs out-of-range `cell_cm` while preserving unknown/duplicate control targets; entity-bound legacy relays discard only their exact self-control and keep explicitly added sibling light targets; wall SVG fallbacks now use valid literal colours. ## v1.60.0 — 2026-08-07 - **Audit hardening.** Deleting one virtual marker no longer removes its neighbours; real `v_*` ids remain positionable; deletion tombstones are hidden for old clients and binding-scoped for entity members of live HA devices. Runtime-filtered controls are no longer destructively saved. Trail deletion is transactional. Optimisation clamps migrated physical styles, validates `cell_cm`, preserves invalid legacy transforms for manual repair and reports model-version bookkeeping honestly. Flat shapes are rejected, furniture selectors initialise reliably, rotated resize keeps its fixed corner, mode switches cancel live transforms, and the demo bundle is rebuilt from the same source as production. English device names containing `thermometer` now resolve as temperature sensors instead of matching the broader meter rule. - Auto icons now update immediately after rebinding and can be explicitly pinned; imperial stroke-field bounds use inches; decor magnet geometry is memoised; Undo and Redo share the same live-gesture boundary. - A marker can no longer list its own bound entity (or an entity of its bound device) as an external light control. Legacy self-controls are ignored immediately; marker Save removes them, and plan optimisation also cleans a directly bound entity self-reference. The explicit `is_light` switch remains the only way to classify that bound relay as a light source. Active fans/hoods still use the yellow working-state plate without entering Glow, Light fill or room light statistics. - **The Background editor now has one coherent transform and style system.** Every decor kind can be selected, moved, resized proportionally (Shift for independent axes), rotated and edited numerically; lines expose endpoint handles. Stroke/text and fill have independent colour/opacity; stroke width and text size are canonical physical cm/in values. Rectangle drafts show area and ovals show radii. Drawing magnetises only to decor and room geometry. Decor and the plan image keep both dimensions on the grid even during proportional resize and use the named 50-step Undo/Redo stack. The image has an exclusive tool, fades to 0.5 elsewhere in this editor, supports independent axes/rotation and remains fully opaque outside it. Legacy styles/transforms remain visually stable and migrate only via explicit plan optimisation. - **Devices can now be deleted from the plan, not merely hidden.** Delete sits beside Hide/Show and requires confirmation. A deleted HA binding is excluded from rendering, Show-hidden ghosts, LQI, climate, room sources, light resolution/Glow/statistics, controls, openings and live text, while remaining available in Add. Re-adding replaces its minimal discovery tombstone and starts with a fresh position. Virtual markers are removed outright; layout, attachments, activity runtime and vacuum trails are cleaned, and stale-tab drag updates cannot resurrect the old position. - **Device-dialog footer spans the dialog again.** The shared `hp-dialog` footer is now a full-width slot item instead of exposing its action row as a shrink-to-fit flex child. The divider no longer starts halfway across the modal, Hide stays at bottom-left, and Cancel/Save stay at bottom-right. - **Auto device icons keep their label in the editor.** When a marker has no explicit icon override, the HA icon picker now receives the effective auto-derived icon as its display value, so the field shows both the glyph and `mdi:*` name instead of a nameless glyph. The stored override remains empty until the user actually selects an icon. - **Media-player power is no longer mistaken for work.** `media_player` markers now stay neutral for `on`, `idle`, `playing`, `paused` and other transport states; an explicit `off` uses the same faded presentation as `unknown` / `unavailable`. This is a domain-level rule for TVs, receivers, speakers and soundbars, not a model exception. Mixed media entities fade only when none of them is currently available and powered. - **Returning to a long-suspended View is stable.** In normal View (not kiosk), transient zero/partial ResizeObserver boxes no longer overwrite the saved viewport. After a genuinely long background sleep the plan is revealed only after the stage size is measurable and quiet, then zoom and centre are applied in one frame. Critical wall fill/stroke attributes also live directly on the SVG paths, so a warm Lovelace re-mount cannot show the browser's black default paint while component styles are being restored. Editors, kiosk and quick tab switches keep their existing immediate behaviour. - **Device-info actions stay inside narrow dialogs.** The Edit, Open in HA and Close actions now wrap as complete buttons when the small HA dialog cannot fit one row; reduced mobile padding preserves useful width. The leading Edit action can no longer be pushed beyond the left edge of the modal. ## v1.59.2 — 2026-08-07 - **A11Y-02: one accessible dialog shell.** Every House Plan modal now uses `hp-dialog`: Home Assistant supplies the modal surface and focus trap through `ha-dialog`, while the standalone demo uses a native `` fallback. Dialogs have an announced title, deterministic initial focus, Escape handling, contained Tab navigation and focus restoration to the control that opened the modal, including nested and dialog-to-dialog flows. ## v1.59.1 — 2026-08-06 This maintenance release makes device status and every light-related view use shared semantic resolvers, softens Glow, and fixes the last compacted-wall T-junction artifact. - **Systemic device-state resolver instead of a “first entity”.** HA devices have no single state, so House Plan now excludes `config`/`diagnostic` entities first, resolves the device's functional role, then semantic binary signals, and uses generic switches only as a fallback. Passive readings are aggregated, so one unavailable entity no longer makes the whole marker unavailable. The same rule fixes X50/Customized Cleaning, presence/Anti interference, TRV service switches and equivalent integration mistakes. A real cover now also outranks its reverse-direction option, while a mixed lamp+cover remains a lamp unless the cover action is explicitly selected. - **UX-12: one resolved light-source set.** Glow, Light fill, room light stats, marker indication and group controls now consume `resolvedLightSources(room)`. Its precedence is `controls` -> an explicit `is_light` source -> automatic `light.*`; hidden markers are excluded, entity ids are de-duplicated, and an explicit `room_id` outranks an HA area. Relays and controlled groups therefore mean the same thing in every light presentation. - **Softer source glow.** The complete glow layer now renders at `0.7` opacity; room darkness and the yellow working-state plate are unchanged. - **Clean real/virtual T-junctions after wall compaction.** A maximal real wall may cross several shorter collinear room sides. Exact endpoint containment now restores its thickness on every covered side even when the compacted wall's midpoint lies outside that room. Room hover therefore stays on the inner face and the adjoining real wall no longer exposes a false end cap at a virtual continuation. ## v1.59.0 — 2026-08-06 Stable 1.59 turns House Plan into a substantially more complete floor-plan editor while keeping the card's live Home Assistant view coherent. It includes every beta/RC change below and closes the line with clean-floor hover geometry and robust wall unions. - **Real walls, virtual boundaries and openings form one geometry system.** A room can mix wall thicknesses, a wall can contain real and virtual stretches, adjacent equal fragments compact again, and Resize preserves exact interval endpoints. Partial openings, virtual T-junctions, thick-wall door tunnels and sunlight from the inner corners of windows are handled consistently. - **Plan edits are explicit and reversible.** Room outline, Split, Close boundary, Merge rooms, Delete room, Resize, wall thickness and opening edits have one result each and share a named 50-command Undo/Redo stack. Delete removes only the selected object. - **One mandatory grid invariant.** Rooms, openings, markers, decor, furniture and backdrops always land on the grid or stay quantised along their wall. Optimize plans previews and applies all current lossless migrations, repairs legacy/off-grid data and compacts wall fragments with a safe one-step undo. - **Editors gained production workflows.** Background objects open their properties on double click; furniture has real dimensions and wall snapping; live labels accept arbitrary text mixed with manually typed or picker-inserted Home Assistant tokens; layer and object visibility controls are explicit. - **Device feedback uses one semantic language.** Yellow means actual work, orange means open/unlocked, alarms remain dominant, unavailable devices are muted, motion is a short event and presence lasts while detected. The marker plate, pulse/activity effect and source-light room fill now agree, including covers, climate, fans, relays, media players and other working devices. - **Rooms explain themselves in View.** Glow and toasts are pointer-transparent; room hover and tooltips work through light pools, the tooltip reports clean floor area, and device dialogs expose an explicit Hide/Show action. The hover accent now follows the same inner wall faces used for area; nested-room walls use the face exposed to the parent floor, while doors, windows and virtual spans remain gaps. - **Final wall-body correction.** Wall bodies are formed as the union of each room's own outset-minus-inset ring. A parent clean-floor contour can no longer erase half of a nested 15 cm wall or leave a white sliver at a complex multi-wall crossing. - **Documentation was rebuilt from the product.** The complete Russian user guide, setting/device behaviour tables and improvement plan describe the shipped code; obsolete audits and one-off debug material live under `legacy/`. ## v1.59.0-rc.2 — 2026-08-06 The second release candidate makes plan editing predictable and reversible, enforces one grid invariant, and completes the documentation refresh. - **One tool — one result.** Closing a virtual boundary, merging rooms and deleting a room are now three separate Plan actions. Delete removes only the room that was explicitly clicked; the opening tool no longer closes an existing dashed stretch. The drawing action is renamed Room outline to state that it creates a closed room rather than a free wall. - **One named geometry history.** Create, Split, Merge, Resize, room deletion, wall thickness, virtual-boundary edits and door/window add/edit/move/delete all share a 50-command Undo/Redo stack. Toolbar buttons and Ctrl+Z, Ctrl+Shift+Z/Ctrl+Y expose the same named steps; a new branch clears Redo. Echoes of the card's own server writes keep the history, while a genuinely newer external revision safely resets it. - **The grid is mandatory.** Shift can no longer place rooms, markers, labels, decor, furniture, backdrops or openings between grid positions. Free points land on nodes; wall-bound objects stay projected and quantised along their wall. Shift remains only for explicitly angular controls. Optimize plans repairs old/imported off-grid data. - **Clearer interaction feedback.** Glow is pointer-transparent, so room hover and tooltips work through a light pool. The View hover overlay follows the complete physical perimeter, including shared thick walls. Existing device dialogs now expose an explicit bottom-left Hide/Show action. The static space-card editor no longer offers the unused `aspect_ratio` setting. Toasts are pointer-transparent and cannot block a tool handle underneath them. - **Documentation and repository hygiene.** A new Russian user guide and a code-grounded product audit/roadmap document current behaviour, setting and device matrices. Obsolete audits, rejected design notes and one-off debug scripts moved under `legacy/`; active docs and automated scenarios now match the grid, Undo and split-action contracts. ## v1.59.0-rc.1 — 2026-08-06 First release candidate of the 1.59 line: safe whole-plan optimization, clearer object editing and room feedback, plus the beta.10 audit follow-ups. - **Whole-plan optimizer with safe undo.** The former Align-to-grid action is now Optimize plans. One preview runs every current lossless model migration, aligns grid- and wall-bound geometry, materialises legacy open boundaries, merges touching virtual pieces and compacts equal-thickness real-wall fragments. Config and layout are committed through a durable two-store intent; one undo remains available until the next plan edit. Backdrop calibration, saved views, unattached layout entries and user files are left alone. Interrupted optimization/undo completes on the next integration setup. - **Background-object properties on double click.** In the Background editor's Select mode, double-clicking any object now opens its properties: labels keep their text form, while lines, rectangles, ellipses and furniture get a compact colour / line-width dialog (plus fill for closed shapes). The new dialog is included in warm-remount draft recovery. - **Rooms identify themselves in View.** Hover now highlights the room under the pointer, including rooms with no configured fill or HA area. The room tooltip also shows its formatted clean-floor area; thick walls use the same inner contour as room labels and resize measurements. - **Yellow working state remains universal in source-light fill.** A device that is semantically on/working keeps its yellow marker plate when the space uses the per-source glow fill. The light pool supplements the marker state instead of replacing it. - **beta.10 audit fixes.** The first real device transition after load is no longer consumed while rebuilding the registry, and changing a marker's effective source synchronously clears an old source's short effect. Editing a legacy live label preserves an explicit unit or a non-representable attribute instead of silently dropping it; the old `attr: state` selector migrates to a bare state token instead of a nonexistent attribute. Wall thickness fragments now persist exact normalised endpoints (legacy midpoint keys still read), survive resize, and compact into maximal equal-thickness solid runs after virtual pieces are closed. Virtual-wall dashes remain visible in all editors even with borders hidden. Release CI now reports GitHub/HACS prerelease-order trouble instead of silently publishing a beta that HACS cannot discover. ## v1.59.0-beta.10 — 2026-08-05 Tenth pre-release of the 1.59 line: one coherent device-state language and a focused set of wall, doorway-light and background-label refinements. - **One device-state language.** Marker plates and effects now come from one semantic resolver: yellow means actual work, orange means open/unlocked, unavailable is faded, and alarms are always red. The display list is reduced to Icon, Icon + activity and Value; the removed Ripple-only value migrates to Icon + activity on the next save. Activity distinguishes short events, persistent presence, mechanical travel and actual running, with reduced-motion fallbacks and no false event on first load or reconnect. Short effects also reset when a marker's effective source changes, while a cover's real opening/closing state takes precedence over the tap fallback. - **Clearer wall-drawing toolbar.** The Plan editor's former “Add” tool is now labelled “Walls”, and its new-wall thickness field sits immediately to the right of that button instead of after the rest of the toolbar. - **View-mode virtual walls sit behind thick wall bodies.** Their stored geometry still reaches the physical centreline, but in View the hatch masks the dash ends inside adjoining thick walls. All three editors keep saved dashes and live previews above the wall body so the complete span remains visible while editing. - **Door light respects thick-wall reveals.** Light now crosses a doorway only through the clear width of its physical wall tunnel. The near and far inner face spans jointly clip the spill, so the two jamb returns cast the expected cut-offs for an off-centre source; zero-thickness walls retain the previous doorway sector. - **Inline HA variables in decor text.** A label can now mix ordinary copy and multiple `{entity}` / `{entity:attribute}` references. Choosing a state or attribute inserts its token at the textarea caret. The separate unit field, one-slot hint, and preview are removed; old linked labels remain readable and migrate to inline tokens when edited. - **Canonical wall fragments.** Touching or overlapping virtual stretches on the same boundary and room pair now collapse into one `open_span`; Split pieces belonging to different room pairs remain separate. When removing the last virtual stretches leaves an original wall solid and uniformly thick, its atomic thickness entries collapse back to one whole-wall key. ## v1.59.0-beta.9 — 2026-08-05 Ninth pre-release of the 1.59 line: mixed virtual/thick resize integrity and clean, visible virtual T-junctions. - **Resize keeps mixed virtual/thick walls intact.** A live edge drag now moves `open_spans` and whole/atomic thickness keys together with the room polygons; commit no longer drops the thickness of the solid remainders, and Undo restores the complete transaction. - **Clean virtual T-junctions.** Real wall arms owned by different room contours receive the missing mitre at an open-span endpoint instead of a stepped corner. Virtual dashes and the two-click drawing preview paint above real wall bodies, so they stay visible right up to the junction centreline. ## v1.59.0-beta.8 — 2026-08-05 Eighth pre-release of the 1.59 line: beta.7 audit follow-ups, a fail-closed release path, full/static wall-render parity, and sunlight anchored to the room-side corners of thick window openings. - **Sun rays start at the inner window corners.** With wall thickness, the wedge's full source span now sits on the room-side face of the opening, so both crisp side edges begin at its two inner corners even at an oblique sun angle. The clean-floor contour still clips the light at the wall body. - **Beta.7 audit follow-up.** A Split crossing one `open_span` now keeps every valid room-pair piece and derives `open_to` for both children instead of silently turning one half back into a solid wall (`AUD-159B7-01`). - **Release safety.** `release.yml` resolves the published tag to its exact commit and waits for all matching Validate runs to finish green; missing, failed, cancelled or timed-out validation withholds the asset (`AUD-159B7-02`). The same fail-closed policy has automated negative tests. - **Test/render parity.** General-settings smoke includes the Walls group, inventory counts class-based and trail backend tests, and the static space card uses the same 3 px thin-wall hatch fallback as the full card (`AUD-159B7-03`, `AUD-159B7-04`). ## v1.59.0-beta.7 — 2026-08-05 Seventh pre-release of the 1.59 line: audit fixes for partial-wall geometry and lifecycle, plus wall fill colour under the hatch. - **Wall fill + hatch.** General setting `fill_colors.wall_fill` (default opaque white) paints under the diagonal hatch; the hatch stays. Thin-on-screen bodies keep the solid fill alone so the hatch does not collapse into noise. - **Atomic wall intervals (AUD-159B6-01).** Thickness and open cuts follow shared-boundary / open-span endpoints, not whole polygon edges — a partial shared stretch no longer leaks thickness onto the outer remainder, and an open span away from the edge midpoint clears only its own piece. - **Open-span geometry transaction (AUD-159B6-02).** `open_spans` ride in the resize snapshot/Undo; Split / Merge / Delete rekey, clip and sync `open_to` in one step without resurrecting a legacy stretch mid-mutation. - **Backend `open_spans` schema (AUD-159B6-03)** with cap / finite points / dedupe; frontend fail-soft sanitises malformed entries. - **Warm owner vs pending nav (AUD-159B6-04):** adopting a warm viewport clears the global LS pending mode so a neighbour card cannot overwrite the owner's editor and draft. - **Smoke / inventory hygiene (AUD-159B6-06):** two-click openwall fixtures, island-by-id, render-perf hook on `_openPairs` / `_buildModel`, inventory counts `test` and `it`. ## v1.59.0-beta.6 — 2026-08-05 Sixth pre-release of the 1.59 line: partial open-wall spans and wall-centric Delete. - **Partial open (virtual) wall spans** (`space.open_spans`): two-click openwall (anchor → second point on a shared wall, clamped to nearest corners); crosshair cursor; openings on virtual stretches are removed and cannot be placed; thickness clears on open and restores from neighbour / 15 cm on close. Legacy `open_to` still expands to the full shared boundary on read. - **Wall-centric Delete**: virtual → solid; shared solid → confirm merge (whole shared boundary); outer wall or click inside room → confirm delete room. ## v1.59.0-beta.5 — 2026-08-05 Fifth pre-release of the 1.59 line: wall-thickness redesign (seamless ±½ rings, inner floor/area/sun), draw-with-thickness, new-space opens the plan editor, and audit hygiene from the beta.4 recheck. - **Draw with wall thickness.** The Plan Draw toolbar has a thickness field (default 15 cm / HA inches). New rooms get that thickness on commit; shared walls keep the neighbour's value; empty clears. Live thick preview while drawing. - **New space opens the plan editor.** Saving a newly created space switches to Plan with the draw tool armed, so an empty floor is not left in View with nothing to look at (same as the first-space onboard path). - **Wall thickness redesign (docs/WALL-THICKNESS.md).** Walls grow ±½ from the centreline (outer and shared); bodies are outset−inset rings unioned into one hatch (seamless L/T as in the reference plan); fills/glow/sun clip to the inner contour; displayed m² is the clean floor; sun wedges narrow through the opening tunnel. Resize/undo/scale keep and re-key `walls`; openings resolve by wall angle; plan-editor mode restores after `can_write`. Hatch colour matches the wall outline. ## v1.59.0-beta.4 — 2026-08-05 Fourth pre-release of the 1.59 line: wall thickness in the plan editor, and a fix so editors keep a white drawing sheet under the grid even when a backdrop image is loaded. - **Wall thickness in the plan editor (docs/WALL-THICKNESS.md).** A wall carries one thickness (`space.walls: [{ key, cm }]`), entered in cm or inches from HA's unit system. Shared walls grow half into each room; outer walls grow inward; open boundaries refuse thickness. Hatched bodies follow `show_borders` (always visible in the plan editor); openings cut the slab full-depth and door swings start at the inner face. Area, glow and sun stay on the polygon. The static space card draws the same bodies. Unit + smoke: `test/wall-thickness.test.mjs`, `demo/smoke_wall_thickness.mjs`. - **Editors keep a white sheet under the grid with a backdrop.** With an uploaded plan image, the plan / devices / decor editors used the theme card colour under the grid instead of the white drawing sheet of a hand-drawn plan. They now stay white; View is unchanged (theme under an image, white without one). ## v1.59.0-beta.3 — 2026-08-05 The third pre-release of the 1.59 line: you can furnish the plan with top-view symbols at real size, hide the decor layer or the openings from View without losing them, aim card-mod at stable `data-*` hooks, and let Home Assistant format entity values the way its own more-info does. A handful of editor polish lands with it — bead-sized corner handles, the backdrop editor opening on its own tool, virtual walls following the room-border switch — plus the audit follow-ups (write policy, README differentiation, tighter validation). Wall thickness is approved as a written spec only (docs/WALL-THICKNESS.md); it is not coded yet. - **Two new switches in a space's settings: «Hide the decorative layer» and «Hide doors and windows».** Both only hide. The shapes, labels, furniture and openings stay in your config, and each stays visible in the editor that owns it — the backdrop editor always draws decor, the plan editor always draws openings — because a layer you cannot see is a layer you cannot edit. What an opening *means* is untouched either way: light still spills through it, the sun still comes in at a window, a contact sensor still opens it; only the symbol is gone. Both are off by default and store nothing when off, so every existing plan reads back unchanged. - **A space that does not draw room borders no longer draws virtual walls.** With «Always show room borders» off, the dashed stretches of an open boundary used to survive on their own, leaving a plan with no walls except a few floating dashes. They now follow the same switch. The plan editor still shows them — the Open-boundary tool has to show what it edits. - **The backdrop editor opens on the tool it is named after.** With a picture in the space, «Backdrop image» is armed the moment the editor opens, so dragging the picture works straight away instead of after finding the tool. The frame was already drawn on open, which promised a draggable picture; the promise is now kept. Select is still one click away and still leaves the picture's body to the one-finger pan. - **Corner handles are beads again, not blobs.** Every corner handle in the card — the backdrop frame, the room-resize frame and the robot-map fit — paints a circle a **quarter** of its old radius while its clickable area is unchanged, matching the text block's handles. A handle the size of a room hides the thing it is there to adjust. - **You can furnish the plan (docs/FURNITURE.md).** The background editor gains a seventh tool, **Furniture**: a grouped palette of ~30 top-view symbols — furniture, appliances, plumbing and a few odds like stairs and a rug — that are placed at their **real size**. Pick a sofa, correct the 2.2 × 0.9 m in the two fields if your sofa is a different one, click the plan, and 2.2 m of *your* plan is what it takes, because the size goes through the space's `cell_cm` like every other length in this card. While you place or drag it, the nearest wall within ~30 cm claims it: the piece's back lands flat on that wall and turns to it, so "put the bed against that wall" is one click. Shift suspends the magnet, as Shift suspends every snap here. A placed piece is selected in the **Select** tool and wears the text block's frame — the corner handles now set **width and depth independently** (a bed is not made deeper by being made wider), with live badges showing both in metres or feet, and the handle above it turns the piece in 5° steps. The symbols are **drawn by us, in code**: an icon set draws a sofa seen from the front in a 24 × 24 square, and stretching that into a 2.2 × 0.9 m rectangle gives an icon lying on the floor rather than a plan. That also settles the licence question outright — nothing third-party ships in the bundle. Every piece carries `data-kind="furniture"` and `data-symbol`, so card-mod can colour all the plumbing in one rule. New kind, nothing migrated: a plan written before this reads back byte-for-byte. - **The plan has stable hooks for card-mod (docs/STYLING-HOOKS.md).** Every object the plan draws now carries the same identity — `data-hp` says what it is (`device`, `room`, `room-label`, `opening`, `decor`, `space-tab`), `data-id` is its id in your config, and where it applies `data-entity`, `data-area` and `data-kind` (door/window, line/rect/ellipse/text) come with it. That is all this is: we do not ship a CSS field, do not add a theme editor and do not support user stylesheets — we simply stop getting in the way of a power user who has already installed card-mod and only needed something stable to aim at. The names are a contract now: renaming one is a breaking change. Everything NOT in that table — editor chrome, boot classes, layer wrappers, dialog markup — is explicitly not the contract. The doc carries the table, three worked examples, the shadow-DOM limits (you can style an `ha-icon` host, never its insides) and a plain disclaimer that card-mod is not ours to support. - **Values are formatted by Home Assistant, not by us.** Wherever the card prints one entity's state — the value badge of a «value instead of icon» marker, a live decor label, the device info card — it now goes through `hass.formatEntityState` (and `hass.formatEntityAttributeValue` for an attribute), the same call HA's own more-info makes. So a sensor's `display_precision` is honoured, the decimal separator is the one your locale uses, and `on` finally reads as *Включено* instead of `on`. The unit lands exactly once — the formatter usually appends it, and where it does not we still do — and your own unit on a decor label replaces the entity's rather than piling on after it. An older Home Assistant without those methods behaves exactly as before. The small °/% plates next to an icon keep their own compact form on purpose: they are a derived reading (an average over the area's sensors, a climate device's `current_temperature`), not an entity state, and the plan reads as one instrument panel because they all look alike. - **The text block's handles are a quarter of the size** (owner's request). The corner circles and the rotate handle above a selected label are now ink the size of a bead instead of a button, so the frame stops covering the very words it frames. The area you can grab is unchanged — an invisible finger-sized circle still owns the gesture at the old 1.8 % of the visible view, exactly the split the wall-resize handles use. - **Wall thickness — the approved spec (docs/WALL-THICKNESS.md).** Not implemented yet; the document captures the model (thickness on a wall, not a room edge), segment keys that survive resize, hatching that does not affect area, and how openings render in a thick wall. Audit follow-ups from `legacy/docs/audit-v1.58.0/AUDIT-RECOMMENDATIONS.md` (2026-08-05): - **Write policy aligned (P0-4).** `admin_only` now defaults to **on** for new installs and when the option key is missing; `houseplan/config/get` returns `can_write` from `may_write`, and the card's editor chrome follows that flag. Missing `hass.user` no longer fails open into the editors. - **README differentiation (P0-3).** Comparison table now positions House Plan against both YAML/SVG incumbents and GUI draw cards (e.g. easy-floorplan): shared `.storage` map + area-bound rooms, not furniture CAD. - **Validation tighten (P3-4).** Marker `binding` must be `device:…` / `entity:…` / `virtual`; `ripple_color` is `#rrggbb`; decor rect/ellipse extents are strictly positive; space `id` matches `SPACE_ID_RE`. - **Hygiene (P3-5).** `quality_scale.yaml` points at the real config-flow test file; card-level `tap_action` documented as deprecated/ignored. ## v1.59.0-beta.2 — 2026-08-04 The second pre-release of the 1.59 line, and it is about the words you put on the plan. A decor label can now read a live value off an entity, so a caption becomes a readout without becoming a template language. The text block itself lost the choice between three font sizes: it is scaled by its corners and turned by its handle, like every other object on the plan, and it may have more than one line. Under that, the three findings of the beta.1 audit are closed — two identical cards no longer share one warm memo, a rapid double re-mount no longer eats the draft, and an expired dialog no longer holds a plan file in memory. - **A decor label can show a live value (docs/LIVE-TEXT.md).** A text shape gains three optional fields — `entity`, `attr`, `unit` — and its `text` becomes a template whose `{}` is where the value lands: `Бак {}` reads *Бак 68 %*. Without a placeholder the value is appended; without an entity the label is byte-for-byte the static one it always was. The unit comes from the entity unless you type your own; a dead, unknown or missing entity shows an em dash instead of quietly vanishing. Nothing is rounded or reformatted — the value is what Home Assistant reports, because rounding belongs to the sensor's `display_precision`. Not a template language: one value, one place, no syntax to get wrong. - **The text dialog gained an entity picker, an attribute picker and a live preview.** The attribute list is the chosen entity's own attributes, the unit field shows the entity's unit as its placeholder, and the preview is rendered through the very same substitution the plan uses. - **A text block is sized by its corners and turned by its handle.** The choice between three font sizes is gone: select a label and pull a corner to scale it, or use the handle above it to rotate in 5° steps (Shift for any angle) — the same mechanics as the backdrop frame. Labels drawn with the old Small/Medium/Large come back at exactly their old size, and the first drag replaces that setting with the scale it meant. - **A label can have more than one line.** The text field is a textarea now: your line breaks are stored and drawn as line breaks, centred, with the block growing around its anchor. Nothing wraps by itself — a caption that reflows on a state change is a caption that jumps around the plan. - **The text tool edits the label you press on.** Drawing tools own the canvas (a new line must be able to start on the end of an old one), and that stays true — with one exception: pressing an existing label with the text tool opens ITS form instead of starting a second label on top of it. Empty canvas and non-text shapes still create a new label. - **Two identical cards on one page no longer share a warm memo (AUD-159B1-01).** The memo key was the window size and the card config, which cannot tell two placements of the same config apart: the newer of them was the last writer, and a card re-created in the OTHER placement woke up with its neighbour's floor, editor mode and zoom — while the draft of its real predecessor was eaten by the mode guard. The memo now keeps one entry per card PLACEMENT: `location.pathname` (the dashboard view) joins the key, and inside a key the entry is claimed by DOM slot — the parent element and the index in it — with a live neighbour's entry never adoptable. When two placements are genuinely indistinguishable only the settled header height is adopted (it is the same for both), never the viewport and never the dialog. - **A rapid double re-mount no longer destroys the draft (AUD-159B1-02).** `disconnectedCallback()` cleared the «I still owe my predecessor a dialog» flag BEFORE taking its snapshot, so a middle instance in an A→B→C rebuild wrote `dlg: null` over a draft it had not yet restored, and the third instance got nothing. The snapshot now runs while the flag is still set: an unsaved dialog simply travels down the chain until one instance lives long enough to reopen it. - **An expired dialog no longer holds its payload (AUD-159B1-03).** The 10-second revive TTL was only a rule checked at revive time; the entry itself kept the dialog — for a space dialog that is a whole plan file as base64 — until the page reloaded. Detaching now arms a guarded eviction that frees the payload the moment it stops being revivable (and drops the stale slot, so the next claim is unambiguous again). ## v1.59.0-beta.1 — 2026-08-04 Minor pre-release: the card survives a Lovelace re-mount bit-for-bit — your pan, your zoom and even the dialog you had open come back with it — sun rays get a hairline edge so they read on white paper, the «+» that adds a space leaves the Plan editor for the tab row, and the list of plans already uploaded to the server stops collapsing into a stripe. - **The card no longer twitches — and no longer loses your open dialog — when you come back to the tab (docs/WARM-REMOUNT.md).** Lovelace re-creates the card element on a websocket reconnect; v1.58.0 removed the preloader flash, but the new instance still had to guess what the dead one had been looking at. Measured: the PAN never left the instance (a view parked in a corner came back re-centred: x=50 → x=250 at zoom 2.2), and the EDITOR zoom is deliberately not persisted while the editor MODE is — so a re-mount inside an editor came back at 1.0 instead of 3.0. The warm memo now carries the whole viewport (space, mode, zoom, the `_view` rect itself, the view-mode snapshot, the «show far objects» frame, the selected tool and selection, the local «show hidden» toggle), so the restore is the same RECTANGLE, not the same zoom number — bit-for-bit, verified frame by frame. - **An open dialog survives the re-creation with its draft.** The memo is module state and is never serialised, so the live draft object — a half-filled device dialog with its uploaded PDFs included — moves over for free. The rule is «revive the draft, never revive the decision»: the confirmations for «Align everything to the grid» and for a room merge are deliberately NOT restored (a modal whose whole content is «press OK to rewrite your plan» must not greet a returning user), nor is a tap confirmation (it closes over the dead instance), nor the floor import wizard (it reopens itself), nor any dialog with a save in flight. Revival requires the same space and the same mode, happens at most once (the snapshot is consumed), and only if the previous instance died within the last 10 s. A dialog closed on purpose — Esc, Cancel or Save — writes `null` into the memo on the very next render, so it can never come back (smoke_warm_dialogs). - **Sun rays get an edge (docs/SUN.md, «The rim»).** On a white plan a wedge of light was nearly invisible, and no amount of opacity could fix it: painting light means adding luminance, and white paper has none left to give. Every lit wedge now carries a 1 px black hairline along its two SIDE edges — the ones running inward from the ends of the window. It fades to nothing on exactly the same axis, the same curve and the same 85 % threshold as the fill (a second gradient built on the fill's own stops), stays one screen pixel at any zoom (`non-scaling-stroke`), is cut by the room like the wedge itself, and lives in the same layer — so the 3° threshold, the two-second fade, cloud cover, night and the editors govern it without a line of extra logic. Peak opacity 0.42, picked against a white sheet and the dark glow canvas alike. The «shade instead of light» model of legacy/docs/SUN-CONTRAST.md was rejected in favour of this; that file now records the decision and keeps the analysis behind it. - **The «+» that adds a space is not an editor tool.** The button next to the floor names only existed inside the Plan editor, so adding a second floor meant first opening an editor you did not want. Adding a space is navigation, not markup: the «+» now sits in the tab row in every mode — View and all three editors — exactly where the per-space gear already lives, and under the same admin rule. The kiosk is a shop window: the button is not rendered there at all (its header is `display:none`, and a hidden-but-present node is still clickable from script). The tab row wraps as before at 390 px (smoke_gear_tabs measures the overflow). - **«Already uploaded» shows the plans again.** In both space dialogs (new space and space settings) the list of plans stored on the server collapsed into a thin rounded stripe: the rows were rendered, the box itself was 14 px tall. A scrolling box is a flex item whose automatic minimum size is zero, and the dialog body is a flex column with a 66 vh cap — so the picker was the one child that could be squeezed to nothing. It no longer shrinks and keeps a floor of its own; up to five thumbnails are visible at once and the rest scroll. The empty and loading states stay readable instead of clipping their own text (smoke_plan_picker measures the heights — the old smoke only counted DOM nodes and passed). ## v1.58.0 — 2026-08-04 Minor release: the backdrop picture becomes a movable, scalable object, the opaque plan sheet is redefined as the room contours, the decor drawing tools stop stealing clicks, and «Align everything to the grid» tells the truth about what it is going to do. ### The backdrop picture can be moved and scaled (docs/BACKDROP.md) - **The plan image is no longer nailed down.** In the Background editor the picture gets a transform frame: drag it by its body to move it, pull a corner to resize it evenly (proportions kept, the opposite corner stays put). A live badge states the picture's real size in metres (or feet) while you drag, through the space's `cell_cm`. Position and size land on the grid; Shift steps off it. Nothing else moves — rooms, doors, devices and decor stay put — and there is no rotation. - Three new optional space fields: `plan_x`, `plan_y`, `plan_scale`. Their absence is exactly the old behaviour, so **existing plans render bit-identically and nothing is migrated**. «Вернуть картинку» in the toolbar clears them. - **The opaque plan sheet is now always the room contours.** It used to be the image rectangle whenever a picture was attached; now the picture is drawn ON the sheet — above it, below the walls. The scene colour (`bg_color`, the `daynight` sky) therefore reaches the exterior walls on an image plan too. Consequence, deliberate: a transparent picture over a space with no rooms drawn shows the scene background through itself. - «Вписать всё» counts the moved and scaled picture, so it can no longer be left off screen. ### Drawing tools no longer grab the shape under the cursor - **A drawing tool owns the canvas.** With Line, Rectangle, Oval or Text picked in the decor editor, clicking on an existing figure now starts a NEW figure instead of selecting the old one — so a line can begin exactly on the end of another line, and a rectangle can be drawn on top of a filled one. Double-clicking a text under a drawing tool no longer opens it for editing either. The same inertness applies in the «Картинка-подложка» tool, where a decor shape lying over the plan must not block the picture's own drag. - «Выбрать» and «Стереть» are unchanged: shapes stay clickable there, which is where selecting and deleting belong. ### «Align everything to the grid» keeps its promise (AUD-158B1-01) The action has no undo, so its confirmation dialog is the only safety there is — and it was understating the damage. - **The maximum shift is measured on the geometry that is actually written**, not on an intermediate one. A rect was measured by its origin and its far corner only — so the minimum-size correction that widens a too-thin box afterwards went unmeasured, and the two corners that carry the X error of one side together with the Y error of the other were never looked at at all. An ordinary box could move √2 times further than promised; a box thinner than one grid step, much further. - **Each space is converted through its own `cell_cm`.** The dialog used to take one normalised maximum and multiply it by the cell size of the FIRST space: a plan whose ground floor is drawn at 5 cm per cell and whose attic is at 100 cm promised 2.5 cm for a vertex that moved 50 cm. The report now carries the maximum in centimetres and the space it belongs to, and the dialog names that space when there is more than one. - The last tenth of a centimetre is rounded **up**: the promise can never be smaller than the deed. ### An opening whose only error is its angle can now be fixed (AUD-158B1-02) - A window sitting exactly on its wall but holding a wrong `angle` used to come back as `changed: false` — the dialog said there was nothing to move and offered no button, while the returned plan differed from the one given. Such openings could never be aligned. The angle is part of the diff now; the dialog counts them separately, and the displacement is measured on the opening's ENDS, so turning it in place is not free in the report either. Turning an opening end over end (180°) is still counted as a correction but displaces nothing. ## v1.57.0 — 2026-08-04 Minor release: the canvas becomes infinite — no more "plan size", no more edge to run past — plus a tap action for curtains and blinds, a polish pass over the sun, live rulers while placing openings, and a warm re-mount that no longer flashes. ### The infinite canvas (docs/CANVAS.md) The idea of a "grid size" or "plan size" is gone. The canvas is conceptually unbounded — any coordinate is legal, with a `+/-5000` limit kept only as garbage insurance (about 60 km of plan at the card's own scale). - **If your plan ran off the edge, it now just works.** Some plans grew past the old square and devices simply could not be placed outside it; the only workaround was to redraw everything. That limit no longer exists: draw, drag and place devices anywhere, and nothing needs to be redrawn. Your stored plan is untouched — the coordinates mean exactly what they always meant, and there is no migration. - **Existing plans open exactly as before.** Verified on a real three-floor config: the opening frames come out bit-for-bit identical to v1.56.0. - **The opening view is derived from what is actually drawn.** `view_box` is now an optional hint for the very first frame only; after that the starting view is always computed from the real content, with outliers rejected so one stray room cannot shrink the whole plan. - **Pan at any zoom, in every editor.** Dragging the plan used to work only above 100% zoom; now it works at any zoom and in all editing modes, with one screen of slack around the content. - **Zoom out to 3x the content**, so you can see the whole plan and the space around it. - **"Fit everything" button** — one tap frames all the content again. - **A "home is that way" arrow** appears when you have panned away from the plan, pointing back to it. - **An adaptive grid.** The grid picks its step from the zoom (1 / 2 / 5 / 10 ... 1000) instead of a fixed cell, and the dots stay a muted hint rather than a pattern that competes with the plan. ### Curtains and blinds - **New "Open/close" tap action for covers.** Closed opens, open closes, and a cover in motion stops. Offered only for the unprotected device classes — garage doors, doors and gates stay on the info dialog, on purpose. - **The icon itself tells you the state**: it morphs between the open and closed shape (a table of cover classes, plus aliases resolved from the base icon), and pulses with a soft ring while the cover is travelling. - **A curtain never wears a coloured plate.** No state fill behind a cover marker, ever. - **The cover is found among all of the marker's entities**, not just the primary one — which is the common case for Aqara and zigbee2mqtt devices — and an explicit "Open/close" choice always wins the indication. ### Sun polish - **Brighter, shorter rays.** Opacity up to 0.30, length down 30%, with crisp sides again. - **Light fades only along the ray**, and is guaranteed to reach zero before the wedge ends — the wedge is now clipped by distance along the ray, so the "bright rim" that appeared with a low, oblique sun is gone. - **A hard 3 degree threshold.** The rays appear and disappear at 3 degrees of solar elevation over a two-second fade, instead of creeping in. - **The day/night sky catches up with the sun** when you come back to the tab: a gap of more than 3 degrees is repainted at once, while normal movement keeps breathing smoothly. ### Everything else - **Live rulers and the centre magnet while PLACING an opening**, not only while dragging one — with the distances measured along the owning room's own edge. - **A warm re-mount.** When Lovelace recreates the card on reconnect there is no preloader and no flash of the plan any more, and a dropped WebSocket never blanks a plan that is already on screen. - **Room borders and names default to dark grey `#55606c`** instead of the accent blue. If you picked a colour explicitly, nothing changes. - **An "About" block at the end of the general settings** — card version, GitHub and Telegram links. - **The icon angle now steps by 5 degrees.** - Audit fixes: the sun-ray cache survives local edits, hidden devices no longer stretch the frame, the editor's grown frame does not leak into view mode, an outlier room no longer inflates icon sizes, and a kiosk pan stays a pan instead of flipping to the next floor. ## v1.56.0 — 2026-08-03 Minor release: the sun comes to the floor plan — a compass, a day/night backdrop and real sunlight through the windows — plus room temperature from climate devices, a design-token pass over the UI, live rulers for opening drags, and a sun-cache fix. - **The sun on your floor plan** (docs/SUN.md). Tell the plan where north is — a compass dial in the general settings, with a per-space override — and the card starts living by Home Assistant's own `sun.sun`: - *Day/night backdrop* (`bg_mode: daynight`): the scene behind the plan follows the sun's elevation — white at full day, warm gold through the golden hour, cooling dusk, deep night. The plan itself dims only ~10% at night, so the rooms stay readable. - *Light through the windows* (`sun_rays`): every window on an exterior wall casts a soft wedge of light into its room — clipped by the room's own contour, warmer near the horizon, stretching long at sunrise and sunset, short at noon, gone after dark. - *Clouds, if you want them* (`weather_entity`): point at a weather entity and an overcast sky mutes the wedges; rain or snow puts them out. A dead sensor never kills the sun. - The plan now sits on an *opaque sheet of paper* traced along the room contours: the scene background — `bg_color` or the daynight sky — is visible only around the walls and never bleeds through the rooms; in day/night mode the sheet casts a soft shadow. - The whole feature is silent until the compass is set; without `sun.sun` the settings dialog explains why. - **Room temperature from climate devices.** A new checkbox in the device dialog puts the AC's or thermostat's `current_temperature` on the badge next to its icon and into the room's average temperature. - **UI modernization.** A design-token pass over `styles.ts` — 209 hard-coded values unified into spacing/radius/font/shadow scales — and native `ha-switch` / `ha-slider` controls in the dialogs, with a hard fallback to the old plain inputs where HA components are unavailable. - **Live rulers for opening drags.** Dragging a door or window now shows the live distances to both ends of its wall, measured along the owning room's edge; a dashed guide and a soft magnet snap the opening to the wall's center (hold Shift to disable the magnet). - **Fix DEV-B701-01** — the sun-ray cache is now invalidated by local geometry edits too, so a wedge can no longer go stale after you move a wall locally before the server confirms the change. ## v1.55.3 — 2026-08-02 Patch release: two fixes for the v1.55.2 first-open veil, found by an adversarial lifecycle audit (AUD-1552-01/02). - **A dashboard rebuild during the first open can no longer leave the plan hidden forever** (AUD-1552-01). Disconnecting the card while the boot veil was up (Lovelace recreates its DOM, a view switch remounts the card) killed the settle timers but kept their ids, so nothing ever lifted the veil again. The veil lifecycle now restarts from every reconnect — with a fresh clock and an unconditional hard cap — and the fade-out also survives a mid-fade remount. - **The veil no longer opens early, right before a late panel lands** (AUD-1552-02). Two equal height reads at 200/400 ms used to reveal the plan at ~400 ms, so Home Assistant chrome arriving at 450+ ms jumped on a visible plan — exactly what the veil was meant to prevent. The veil now holds for a full protective window with trailing quiescence (height changes near the cap extend the wait), and for a short grace after the reveal any later shift glides via a height transition instead of snapping. Deliberate height changes (entering an editor) still apply instantly. ## v1.55.2 — 2026-08-02 Patch release: a calmer first open — no zoom flash and no layout jumps while Home Assistant is still settling — plus a new background color setting and two bits of editor polish. - **Opening a plan no longer flashes the default view before your saved zoom** (HP-1551). The saved zoom used to be applied a beat after the first render, so the card painted the default fit for a frame and then snapped to your position. It is now applied synchronously, before the first paint — the plan appears exactly where you left it. - **A first-open veil hides the plan until the layout settles** (HP-1552). While Home Assistant is still loading its side panels, the stage height can change several times, and the plan visibly jumped along with it. The card now waits under a dark veil with a pulsing house outline until the height stops moving, then reveals the plan already in place. Kiosk mode skips the veil entirely. - **New setting: background color around the plan** (HP-1554). The area around the plan can now be any color — set it in general settings for the whole card, or override it per space. The backend validates the value as a #rrggbb hex color. - **Round caps and joins on background-editor lines** (HP-1553). Strokes used to end and meet in square cuts; line ends and corners are rounded now, so traced walls and outlines look clean. - **The Resize tool's wall handles now look the part.** They are half the previous size, show a wall-with-arrows glyph that rotates to follow the wall, and use the grab cursor — while the hit area stays exactly as large as before. ## v1.55.1 — 2026-08-01 Patch release: the four findings of the v1.55.0 audit, all in the new Room resize tool (HP-1550-01..04). - **A pending save can no longer leak a live drag to the server** (HP-1550-01). The resize preview used to be written straight into the shared config object, and a debounced save still queued from a previous edit could snapshot it mid-drag — so a resize you then cancelled with Esc quietly survived on the server and came back after a reload. The live geometry now stays in a separate overlay that only the renderer sees; it reaches the config exactly once, when the handle is released. - **An interrupted drag is cancelled, not committed** (HP-1550-03). When the system cuts a drag short — switching apps, palm rejection on a tablet — the tool used to treat it as a release and save the half-finished geometry. Such interruptions now take the same path as Esc: the original geometry comes back, no undo step, no save. - **A door in the middle of a wall no longer blocks resizing it** (HP-1550-04). The door's invisible hit area used to sit on top of the wall handle, making such a wall ungrabbable for both rooms. In the resize tool the handles now own the hit test (openings are not editable there anyway — they simply travel with the wall), while all other editor tools keep openings clickable exactly as before. - **The ~30 cm minimum size now holds for any room shape** (HP-1550-02). The old check only measured parallel opposite walls, so a triangular room could be squeezed into a sliver, and a rotated room could scale its real short side below the floor unnoticed. Both measures are orientation-independent now: wall drags respect every obstacle in the wall's path (a triangle's apex, a slanted wall), and the scale frame uses the room's true minimum width. Rooms already thinner than the floor may still be improved, never made worse. ## v1.55.0 — 2026-08-01 Minor release: rooms are no longer set in stone — a dedicated Resize tool in the plan editor changes their size by dragging walls; plus the two findings of the v1.54.3 audit (HP-1543-01/02). - **Room resize — a new «Размер» tool in the plan editor** (spec: docs/RESIZE.md). Every wall gets a handle at its midpoint; drag it and the whole wall moves, staying parallel to itself, with grid snap. Works for polygons (L-shapes included) and for legacy rectangles alike. - **Shared walls always move together.** If the dragged wall coincides with a neighbour's boundary, the neighbour follows: your room grows, the neighbour shrinks — gaps and overlaps cannot appear by construction. At T-junctions only the coinciding stretch follows, inserting new corners into the neighbour's outline where needed. - **Live numbers while you drag.** The dragged wall and its two adjacent walls show their lengths in real meters/feet, and the room area in m² updates live at the room centre — for a shared wall, the areas of both rooms. - **The wall stops where it must.** Rooms cannot get thinner than ~30 cm (neither yours nor the neighbour's), an outline never crosses itself, a growing wall stops at foreign rooms and island rooms, and doors and windows are anchors: an opening travels with its wall, and a wall carrying openings can never get too short for them. - **A scale frame for the whole room.** Click a room in the resize tool to select it: dragging a corner of the dashed frame scales the outline proportionally, with the same stops applied. - **Esc and Ctrl+Z.** Esc cancels the current drag and puts the original geometry back; one released drag is one undo step, and Ctrl+Z walks back up to 30 of them while the tool is active. - **Fix: room overlap detection missed equal-height rectangles slid over each other.** Found while building the resize stops; the slide-over case now counts as an overlap everywhere the check is consulted, including the draw tool. - **Fix (HP-1543-01): editor zoom stayed on screen after a floor switch made inside the editor.** Exiting an editor on a different floor than the one you started on skipped the viewport restore and left the editor working zoom in view mode. Such an exit now falls back to the current floor's saved view zoom. - **Fix (HP-1543-02): a motion sensor re-tripped mid-flash stayed invisible.** A rapid off→on before the current flash ended kept the old CSS animation timeline, so the second detection played nothing. Every witnessed trip now gets a fresh animation identity and the flash restarts; under reduced motion the static ring stays, as before. ## v1.54.3 — 2026-08-01 Patch release: three quality-of-life rounds — icon satellites now follow the per-device size multiplier, editor zoom stopped leaking into view mode, and motion sensors got a visual language of their own. - **The per-device size multiplier now scales the icon's satellites too.** Reported by an owner with a screenshot: shrinking a device left the value badge, the temperature/humidity plates, the LQI label, the «new» dot and the alarm ring at full size, towering over the tiny icon. Every satellite now follows the multiplier along with the icon. - **Editor zoom is a working tool, not a saved setting.** Zooming to 500% to place a marker precisely and then closing the editor used to drop you into a 500% view mode. Leaving any editor now restores the viewport you had in view mode before you started editing. - **Fix: editor zoom could still resurrect when switching floors.** The editor viewport raced the per-floor viewport store and won: switch floors while editing and the 500% was written down as that floor's saved view, greeting you on the next visit (steps to reproduce came from the owner). Editor zoom is never written to the store anymore. - **Tripped motion and presence sensors signal with a yellow ring.** The rule stays «fill = on»: motion is a one-shot flash — three pulses at the moment of detection, with no pulsing during the cool-down tail — while occupancy/presence hold a static ring for as long as they report someone present. - Stand only: a `services.yaml` for the demo stand's `demo_guard` to keep hassfest green; nothing of it ships in the integration. ## v1.54.2 — 2026-07-31 Patch release: the one remaining finding of the v1.54.1 re-audit (HP-1541-01), pinned by regression tests on both sides of the contract. - **Fix: a vacuum whose own `selected_map` is `0` split calibration and trail between two map ids.** The v1.54.1 map-id contract («the first value that exists wins, and zero is a value») was applied to the source entity but not to the card's fallback on the vacuum's `selected_map`: the frontend still judged it by truthiness and turned `0` into `default`, while the server recorder stored the run under `0`. Calibration was saved under a key the recorder never used, and the recorded trail never rendered after a reload. The fallback now follows the same not-nullish rule on both sides (`vacMapIdWithFallback` in the card, `resolve_map_id` on the server), with cross-runtime regressions for `selected_map` = `0`, `"0"` and `""`. ## v1.54.1 — 2026-07-31 Patch release: everything the adversarial audit of v1.54.0 found (HP-1540-01..06), each fix pinned by a regression test that fails on the old code. - **Fix: the first calibration of a freshly discovered vacuum silently did nothing.** Until the device dialog was saved once, the robot had no config marker — yet the «Живая позиция» section was fully interactive, and every handler quietly bailed out while auto-calibration still announced success. Any vacuum edit now materialises the marker itself, and the success toast only appears after the matrix has verifiably landed in the config. - **Fix: a robot whose first map is `map_index: 0` lost its server-side trail.** The backend picked the map id by truthiness and dropped the zero, so the recorded run was stored under a key the card never looked up. Both sides now share one explicit rule — the first value that exists wins, and zero is a value. - **Fix: one robot on two floors recorded history for the last floor only.** The recorder kept a single marker per source entity, so the second placement silently evicted the first. Every marker fed by a source now gets its own copy of the run. - **Fix: auto-calibration ignored plans drawn with rectangle rooms.** The room matcher only accepted polygon outlines and then blamed the room names. Legacy rectangles count like everywhere else in the card. - **Fix: overlapping recorder refreshes leaked state subscriptions.** Two config saves racing each other could both subscribe and strand one callback until restart; refreshes are serialised now and teardown wins over any refresh still in flight. - The «no rooms» / «no match» toasts and docs/VACUUM.md no longer send you to the three-point calibration that no longer exists — they point at «Подогнать вручную», which does. ## v1.54.0 — 2026-07-31 ### Live robot vacuums The plan now shows the robot while it works. The device marker stays where you put it — that is the dock — and a round puck drives the plan in real time, pouring its path out from under itself. Everything is display only: the card never commands the robot. - **Calibration without arithmetic.** «Настроить автоматически» matches the robot's room list against your rooms by name and solves the transform in one click. When names do not match, the fit panel lays the robot's rooms over the plan as a dashed ghost: drag it into place, stretch it by the corner handles, quarter-turn and mirror with two buttons. Mirror is on by default — every robot map we have measured flips Y versus the screen. One calibration per robot map, so two floors stay independent. - **The path is recorded server-side.** The integration watches the robot itself, so the trail records with no card open, survives page reloads, and every screen sees the same line. The current run and one previous run are kept — cleaned versus not-yet-cleaned at a glance. - **«Показывать путь робота»**: never / while cleaning (default) / always. Only the last mode also draws the previous run, faded. - The trail never runs ahead of the icon: drawn segments lag one point and the growing tip is glued to the puck's animated centre every frame. It is drawn as a dark halo under a light core, so it stays readable over any room fill. The puck teleports instead of gliding when the view changes — zoom, floor switch or a return to the browser tab. - Adapters: Xiaomi Cloud Map Extractor, dreame-vacuum (Tasshack), Valetudo. Verified against a live Dreame X50 Master. ### Also - **«Свет по источникам» is the default fill for new spaces** and leads the options list. Existing plans are untouched: a space whose owner never chose a fill still renders as before. - **Fixed: the "what to run" search showed no results.** The list is a scrollable box and, as a flex item, collapsed into a 1px sliver — the matches were there, rendered into nothing. ## v1.53.1 — 2026-07-30 - **Fix: the "what to run" search showed no results.** The results were there — the list is a scrollable box, and as a flex item inside the dialog body it collapsed into a 1px sliver, so 26 matching automations rendered into nothing visible. Reported within minutes of v1.53.0 by the owner. The list keeps its height now; the smoke measures that height instead of merely counting DOM rows, which is why it passed the broken build. ## v1.53.0 — 2026-07-30 **A tap can run your automation** (owner's spec) - **New tap action: "Run automation/script/scene".** We cannot know every exotic device, but you know what a tap on it should do: pick any automation, script or scene from a searchable list, and the tap runs it — `automation.trigger`, `script.turn_on` or `scene.turn_on` per kind, with a "Started" toast. A script is the idiomatic HA "action", so all three runnable kinds are offered — no trigger-less dummy automations needed. Saving refuses a run action without a target; a target deleted later warns in the dialog and toasts safely on tap. - **"Ask for confirmation" checkbox** — the accidental-tap guard, available for any state-changing action: toggle and run alike, wall-switch markers with bound targets included. The dialog is the card's own (Esc, backdrop or Cancel = nothing happens), so it works on a wall tablet. - **Curtains toggle natively:** covers and valves joined the card-wide toggle domains — with one deliberate exception: garage doors, doors and gates (cover device classes garage/door/gate) stay OUT of the default toggle, an accidental tap must not open the driveway. An explicit per-device toggle remains the owner's conscious choice, and locks/alarm panels stay untouchable from the plan, as always. ## v1.52.2 — 2026-07-29 **From the v1.52.1 review** (no runtime changes — test and wording quality) - The plan-editor regression check now targets THE lamp (HP-1521-01): the old assertion accepted any yellow badge, and the lit socket in the same fixture would have satisfied it with the lamp fix removed. Verified by mutation: reverting the v1.52.1 gate makes the smoke fail. - The one remaining "yellow in every fill mode" wording — the checklist entry and the _stateClass comment — now states the actual contract: the lit-source state is computed by the glow-pool condition, and the yellow badge shows only where the glow spot is not drawn (HP-1521-02). ## v1.52.1 — 2026-07-29 **From the v1.52.0 review** - **A lit lamp always has exactly one indicator (HP-1520-01).** The glow layer is hidden in the plan editor, but the yellow suppression still applied there — a lit lamp showed neither the spot nor the badge. The suppression gate now equals the layer's actual visibility: wherever the spot is not drawn, the yellow badge returns. - **The static card honours a marker's size and rotation (HP-1513-01).** The same stored marker rendered at base size, unrotated, on the read-only card. It now mirrors the full card's --dev-scale and angle — geometry only, still a schematic. - Documentation caught up with the v1.52.0 colour contract (HP-1520-02): the RGB-tint expectations in TESTING/UX-MODES and a stale inline comment. ## v1.52.0 — 2026-07-29 **One look for light sources, whatever flipped them** (owner's rule) - **A lamp's colour lives only in its glow.** The RGB tint of the icon, border and shadow is gone: depending on whether the state carried colour data, the same lamp used to land in the "coloured icon on a dark badge" or the "plain yellow badge" branch — turning one lamp off by tap and the rest by the wall switch produced visibly different results. The branch is gone. - **In glow fill the indicator IS the glow spot.** A light source's badge stays standard, lit or not — the pool of light around it says everything. A lit socket, fan or kettle keeps its yellow even in glow fill: they cast no light, the rule is for sources only. - **In every other fill a lit source is plain yellow**, like a heating radiator valve — RGB and white lamps alike. - Icon morphing (the shining-bulb outline) stays in every mode, and the ripple colour still falls back to the lamp's light colour. ## v1.51.3 — 2026-07-29 - **The icon size multiplier scales the glyph, not just the badge.** Changing a device's size grew the badge, the ripple and the value badges but left the icon itself at its default size — a big empty box around a small glyph (user report). The glyph now derives from the same per-device size as everything else and keeps its proportion at any multiplier and zoom. ## v1.51.2 — 2026-07-29 **From the v1.51.1 review** - **The auto grid is the same on both cards (HP-1511-01).** The full card reserves grid cells for hidden devices (their ghosts keep a place in the device editor); the static card compacted the grid over visible ones only, so a freshly discovered marker with no saved position landed in different spots on the two cards. The static card now feeds the full roster to the same grid and still draws only the visible. - **A ripple-display ghost keeps its base icon (HP-1511-02).** Hidden markers with the "ripple" presentation rendered as an icon-less inactive pulse — unrecognisable in the editor. A ghost now drops the display dressing entirely: base icon and name, whatever the display mode. ## v1.51.1 — 2026-07-29 **From the v1.51.0 review** - **The static card counts hidden devices in room LQI again (HP-1510-01).** Its visibility filter had quietly become the aggregation filter: the same room showed different Zigbee health on the two cards. Aggregation and rendering use separate lists now — hidden devices count toward signal on both cards, are drawn on neither, and still cast no light. - **A ghost shows no live numbers (HP-1510-02).** A hidden device in "Show hidden" suppressed the state colors but still painted its value text, temperature, humidity, LQI badge and state-morphed icon. All of that is gone: the ghost keeps only the base icon and name — enough to recognise it and open the dialog. ## v1.51.0 — 2026-07-29 **Hiding is an explicit flag now** (docs/FILTERING.md) - **Every device dialog — virtual ones included — has a "Hide device from plan" checkbox.** The old on-the-fly filter survives only as the SEEDER of those flags: on first load by an editing client the config is materialised once — non-physical devices (bridges, scenes, service integrations, lamps folded into a light group) get the flag, and from then on the flag belongs to you. Unticking it is final: the seeder never revisits a device you have decided about. New non-physical devices hide silently; physical ones keep the red-dot flow. - **"Show all" became "Show hidden"** — a local tool of the device editor (nothing flips on the wall tablets), showing hidden devices as translucent BLUE dashed ghosts: clearly apart from a grey unavailable icon, and with no live-state paint at all — a ghost is configuration, not status. Click one to untick the box. "Remove from plan" is gone for bound devices (the checkbox is the way); a virtual device's Delete still deletes. - Hidden devices still count toward the room's Zigbee signal, but cast no glow and no light fill — an invisible device casts no visible light. Room climate is unchanged. Old configs behave exactly as before until an editing client materialises them. **Yellow means working right now** - One principle for the glowing icon: a light is shining, a socket is powering, a fan is spinning, media is playing, a vacuum is cleaning — or a radiator valve is ACTUALLY heating (hvac_action), not merely enabled for the winter. Previously a TRV could glow yellow because its anti-scaling service switch was on while the actually-heating one stayed dark: the primary-entity search let a vendor's config switch outrank the visible climate entity. Fixed — a service entity never beats the device's visible main function (this also fixes tap-toggle and icon morphing on such devices). - The glow pool and the icon color now ask the same question: a lit light yellows its icon in every fill mode, by exactly the condition that lights its glow spot. The README (en+ru) documents the color language. **The editors, on a phone** - Pinch zoom and pan gestures now work in every editor: drawing is click-based, so the two coexist — a moving finger pans, two fingers pinch, releasing after a gesture never draws a point, a clean tap still does. **The room settings button** - Detached from the (movable) room name: it sits at the VISUAL centre of the room — the centre of the largest inscribed circle with a pull toward the area centroid, so an elongated room centres it on both axes and an L-shaped one keeps it in the middle of its widest part, never down a thin limb. - Half its former size, sized from the device icon (70% of the icon box) and zooming WITH the plan instead of keeping a constant screen size. - The small metric rows under the room name (temperature, humidity, signal, lights) now show in the plan editor too, and the name renders in exactly the same spot in view mode and in the editor. ## v1.50.4 — 2026-07-29 **From the v1.50.3 review** - **Both cards build their model with the same code now (HP-1503-01).** The full card carried a hand-copied twin of the shared model builder, and the twin missed the legacy-store fallbacks v1.50.3 added — the same broken store rendered fine in the static card and as a blank `viewBox="0 0 0 0"` in the main one. The duplicate is gone: the full card calls the shared builder and only swaps in the raw plan url its signing flow needs. A new smoke runs the audit's exact legacy vector through both models and both DOM trees and asserts parity. ## v1.50.3 — 2026-07-29 **From the v1.50.2 review** - **A size is not a coordinate (HP-1502-01).** The ±4 bound from v1.50.2 treated all four view_box elements and room w/h alike, so `[0, 0, 0, 0]` and negative sizes still passed — and a zero axis serialises into `viewBox="0 0 0 0"`, a blank plan on every client, with the static card computing `aspect-ratio: 0 / 0` on top. Sizes now get their own validator: strictly positive, floored at one thousandth of the canvas; coordinates may still be negative, because a crop origin legitimately sits past the edge. And since a store may already hold a broken viewport from before, both cards fall back to the whole canvas instead of a blank screen, and a legacy rectangle with a negative size is read as the same rectangle drawn from the other corner. **Also in this release** - The room settings button moved to the bottom of the room card, and the room name renders in exactly the same spot in view mode and in the plan editor — the button and the metrics no longer take part in the label's centring. ## v1.50.2 — 2026-07-29 **From the v1.50.1 review** - **Geometry magnitudes are bounded on both layers (HP-1501-01).** v1.50.1 bounded layout positions, but room rectangles, polygon vertices, view_box and opening coordinates still took any finite float — one schema-valid 1e100 vertex framed the space so wide the plan was a dot, for every client, and the server stored it as a perfectly good configuration. The config schema now bounds geometry to ±4 (angles to ±360°), and the content frame applies the same canvas envelope to room vertices it already applied to device positions — so a store that already holds an absurd coordinate from before this door existed still renders: the point draws wherever it is, it just no longer commands the frame. A vertex a bit past the canvas edge keeps working. - **A no-op repair no longer eats the undo backup (HP-1501-02).** A typo'd space id "succeeded" with moved: 0 — and its empty result replaced the one-deep backup, destroying the only way back exactly when it was needed most: right after repairing the wrong space. Matching nothing is an error now (`nothing_to_repair`); nothing is written, the revision does not move, and the previous repair stays undoable. ## v1.50.1 — 2026-07-29 **From the v1.50.0 review** - **A card below other dashboard content gets its stage back (HP-1500-02).** The v1.50.0 height measurement used the absolute document coordinate, so a tall card before this one was billed as "header" and the stage collapsed to zero. The card now measures only its own chrome plus a bounded allowance for what the dashboard keeps above it, and re-measures on window resize; the listener is removed on teardown. - **The content frame can no longer be degenerate or absurd (HP-1500-03).** A lone marker in an empty space produced a zero-area viewBox — a blank scene; a single stored coordinate like 1e100 (any finite float passed validation) stretched the frame until the plan was a dot, for every viewer of the space. A near-zero axis now opens up to a floor of canvas around the marker, points far outside the canvas envelope no longer command the frame (they still render where they are), and the server refuses layout coordinates outside ±4 — generous slack for an icon dragged past an edge, not an envelope for absurdity. A real thin room keeps its tight frame, and the gate sensor slightly past the edge still counts. - **A repair path for installs stranded by the v1.48 migration window (HP-1500-01).** If the old migration crashed between its two writes, the markers of a space are left in the old coordinates with nothing in the data able to prove it — and re-transforming a correct layout would corrupt it, so nothing automatic is safe. `houseplan/geometry/repair {space_id, aspect}` is the explicit answer: `dry_run` previews the exact moves, the previous positions ride the same store write as a one-deep backup, `undo` restores them, and routine drags no longer erase that backup. The v1.50.0 `geom_pending` protocol already protects every future migration; this covers the installs it was too late for. ## v1.50.0 — 2026-07-28 **Owner's batch** - **The default zoom counts devices as content.** They are allowed to stand outside every room — a gate sensor by the fence, a camera on a pole — and the opening view now includes them, even on a space with no rooms at all. - **Entering an editor no longer shifts the plan.** The stage height assumed a fixed 118px of header, and the editor header is taller: the scene slid down by the difference and its bottom went below the fold. The card measures where the stage actually starts and gives it the rest of the viewport. - **The zoom goes out as well as in.** Down to 0.4×, and zoomed out the plan floats centred instead of being pinned to a corner. **From the v1.49.0 review** - **The square-canvas migration survives a crash between its two writes (HP-1490-01).** Config and layout live in separate stores, written one after the other, and the first write deleted the very fields the second needed — a failure between them stranded markers in the old coordinates for good. The migration intent is durable now, saved before anything moves and cleared by the layout write itself; whichever half is missing after a crash, the next start finishes exactly that half, once. - **Parallel uploads cannot slip past the store quota together (HP-1490-02).** N uploads all measured the store before any of them wrote, and all passed a limit only one of them fit under. The measure-and-write pair is one atomic step under its own lock — separate from the config lock, so a slow directory scan does not stall saves. - **The editors see the whole canvas again (HP-1490-03).** The content frame also bounded pan, zoom and pointer maths, so after the first room there was nowhere left to draw the second one. Edit modes now measure from the full square; the view keeps its content fit, and switching modes refits instead of carrying a view clamped against the wrong base. - **Save waits for the proportions of a picked plan (HP-1490-04).** Saving before the image had answered used to ship the PREVIOUS file's ratio, and the new plan kept the old shape for good. Picking a plan clears the old ratio at once, and Save awaits the bounded read; if it fails, "unknown" is stored — a square fallback is honest, an inherited ratio is not. - Release hygiene from §5: package-lock.json caught up with the package version, and a duplicated comment in space-geometry.ts is gone. ## v1.49.0 — 2026-07-28 **The canvas is square** (see v1.48.0, released together with this one). - **Zoom opens on what is drawn, not on the whole canvas.** A space without a background image now fits its rooms with a 5% margin, so a small plan on a big canvas fills the screen instead of sitting in the middle of it as a speck. With a background image nothing changes: the image is the plan, and cropping to the rooms would hide the parts nobody has outlined yet. - **Switching spaces by swipe, or on the kiosk carousel, slides.** The plan leaves the way the finger went and the next one arrives from the other side. Respects "reduce motion". - The room settings button says "Room settings" rather than just "Room", and lightens slightly under the cursor. - "Curation" is called filtering everywhere — the interface, the documentation and the code. **From the v1.47.0 review** - **A plan you have just picked can no longer be deleted from the same dialog (HP-1470-02).** It was not saved yet, so the server correctly considered it free — and the save then stored a url with no file behind it. The button is disabled now, and, because two clients can do the same in either order, the server checks every internal plan url a configuration adds against the disk and refuses a new reference that is already broken. A url the stored configuration already carries is let through — a file can vanish from outside Home Assistant, and refusing then would block the very edit that detaches it. Urls that are not ours are left alone. - **Uploads are bounded (HP-1470-01).** Nothing is deleted for being old — that cost real plans twice — so the limit sits where a decision is being made anyway: an upload is refused if the store would pass 256 MB or 200 plans (1 GB / 1000 for attachments), or if the disk would drop below 512 MB free. The plan list is capped at the 60 newest and its thumbnails load lazily. - **Picking a saved plan reads its real proportions (HP-1470-03).** The card waited for nothing and, when the signature for the protected url had not arrived yet, saved a fallback ratio — a square plan came out stretched. It now waits for the signature, ties the result to the dialog that asked, and the preview in the dialog is signed like everything else. ## v1.48.0 — 2026-07-28 (the canvas is always square) - **A space no longer has proportions of its own.** The drawing area is a square; a plan image keeps its own shape and is centred inside it, so a wide plan gets margins above and below and a tall one gets them at the sides. There is nothing left to choose — the canvas orientation setting for hand-drawn spaces is gone with it. - **Existing plans are migrated once, on upgrade.** Nothing about a drawing changes: the box is padded out to a square and every coordinate is re-expressed against it — rooms, doors and windows, decor, marker positions and the saved viewport. Angles, room proportions and relative positions are preserved exactly. For a tall plan the scale in centimetres per grid cell is adjusted along with it, because the grid is tied to the width; without that a wall would silently measure less than it does. ## v1.47.0 — 2026-07-28 (pick a plan you already uploaded) - **The space dialog can now show the plans stored on the server.** Detaching a plan keeps the image on disk — that has been the rule since v1.46.4, but until now the only way back was to find the original file on your computer and upload it again. "Already uploaded" lists what is there, with a thumbnail, the file size and which space uses it. One click attaches it; the aspect ratio is read from the image, exactly as on upload. - **And it is where you delete one.** A plan file is never removed automatically — not for being detached, not for being old — which is only a sensible policy if you can see what is being kept and get rid of it deliberately. The trash button does that, and refuses while a space still uses the plan: the answer to "may this go" comes from the stored configuration, not from the browser. - Documentation caught up with the code: several comments still described the age-based collection that v1.46.6 removed. ## v1.46.6 — 2026-07-28 (the detach promise, actually kept this time) - **Switching a space to "draw" no longer deletes its image.** v1.46.4 and v1.46.5 said it did not, and the scheduled cleanup indeed left detached plans alone — but the save itself deleted the file the moment the reference was cleared, before any of those guards were reached. The cause: a file that left the configuration was called "superseded", and from that difference alone replacing a plan, detaching one and deleting its space are indistinguishable. Only the first is a deletion anybody asked for. The transition is now classified by the space that owned the file, and the same distinction applies to attachments: dropping one from a device that still exists removes it, deleting the device keeps its manuals. - **A plan whose space was deleted is kept**, rather than the thirty days v1.46.5 promised — thirty days measured from the file's age is meaningless anyway, since it was usually uploaded months earlier. - **Nothing is deleted for being old any more**, except a per-dialog staging folder. The rule that aged out "rejected uploads" turned out to race a retry: the cleanup removed the file from a failed save while the next attempt was committing a reference to it. A rule that can delete a file somebody is about to point at is not worth the disk it reclaims. Files therefore go when an action says so, and otherwise stay. ## v1.46.5 — 2026-07-28 (audit of every automatic deletion) - **A detached plan is never deleted, at any age.** v1.46.4 gave it a month; this makes it permanent and writes the reason down where the next change will see it. The rule, now in docs/SCOPE.md: the component may delete a file only when a user action says so — replacing a plan, removing an attachment, deleting a device. "Nothing points at this any more" is not such an action. The errors are not symmetrical: wasted disk is visible, cheap and reversible; a deleted file is none of those. - **`houseplan/files/cleanup` no longer takes a folder on the client's word.** After a device is rebound its files are copied to the new id and the old folder is dropped — with `rmtree`, on whatever id the card sent. Two ways that ends badly: a partial copy leaves some urls still pointing into that folder (the migration deliberately does not rewrite those, so they were live links to files being deleted), and a wrong or stale id from any client would destroy a live device's manuals. The server now checks the stored configuration itself, under the config lock, and removes only files nothing references. - **A plan of a space that was deleted waits thirty days instead of an hour.** Deleting a space is deliberate, but an hour is a short window in which to notice it was a misclick. ## v1.46.4 — 2026-07-28 (data loss: detached plans were collected as garbage) - **A plan you detach is no longer deleted an hour later.** Switching a space to "draw" clears the reference and, as the editor has always said, leaves the image on disk so you can put it back. The collection added in v1.46.0 did not make that distinction: it treated "nothing points at this right now" as abandoned and applied a one-hour rule. On the author's own instance the scheduled pass then removed two floor plans that had been detached weeks earlier, with no way to get them back. If you have detached a plan since v1.46.0 and your instance restarted or ran for a day, check `config/houseplan/plans/` before updating anything else — and please report it in the Telegram chat if a file is missing. The rule now: **a commit still removes exactly what it replaced**, because that it knows for certain. Beyond that the question is whether "unreferenced" means "abandoned", and the answer depends on the case. A space with no plan at all has had one detached and may want it back — its files are never collected. A space that does have a plan can only be holding rejected uploads of its own, so those still go after an hour. Attachments outside a per-dialog staging folder wait a month; a staging folder, which by construction only ever holds an upload from a dialog that was never saved, keeps the one-hour rule. ## v1.46.3 — 2026-07-28 (re-check of v1.46.2: HP-1462-01) - **The cleanup at startup now actually cleans up.** It looked its own runtime data up by domain, and during startup Home Assistant does not yet consider the integration loaded — so the lookup came back empty and the pass quietly degraded to removing half-finished transfers, leaving the real work to a timer 24 hours away. Restart more often than that and it never ran at all. It uses the object it was given at startup now. - **The test that was supposed to prove this was passing for the wrong reason.** It created the stray files *before* saving the configuration — and saving collects too, so everything was already gone by the time the restart happened. Rewritten to seed after the save, plus a second test that fires the scheduled timer on its own, and a third that runs a restart and a save at the same time and asserts the accepted configuration never points at a file the cleanup removed. ## v1.46.2 — 2026-07-28 (re-check of v1.46.1: HP-1461-01, -02) - **A file nobody ended up using is now cleaned up even if nothing is ever saved again (HP-1461-01).** Collection is tied to a configuration write, which is right for what a write supersedes but leaves a gap: cancel a dialog after the file has already uploaded, lose the connection just after, or call the upload API directly, and nothing references the file and no future write notices it. The daily sweep added in v1.46.1 only removed half-finished transfers, so the promise that a cancelled attachment disappears after an hour did not hold on an instance nobody edits. The sweep now compares against the stored configuration — under the same lock a write uses — and collects aged unreferenced attachments and plans as well. - **A drag is no longer undone by someone else's move (HP-1461-02).** When the full card learned to follow position changes in v1.46.1, it protected the positions you had moved but not yet sent — except it read that list *after* flushing the pending write, and flushing empties it first. In a real drag, where a write is already scheduled, the list was therefore empty and the server's older position was painted over your move. The card now takes the snapshot before flushing and also holds on to positions that are sent but not yet acknowledged: until the server confirms a position, the card that moved it is the authority on it. - Two tests grew up to their docstrings: the upload test now actually cancels the request task instead of only exercising error paths, and the position-sync smoke schedules a real debounced write and delays it, which is the ordering that lost the drag. ## v1.46.1 — 2026-07-28 (re-check of v1.46.0: HP-1460-01 … -03) - **Two uploads of the same file name can no longer collide (HP-1460-01).** v1.46.0 stopped overwriting attachments, but choosing a free name and taking it were two steps: two uploads racing between them agreed on the same name, both reported success, and one set of bytes replaced the other. The name is now claimed atomically as it is chosen — twenty simultaneous uploads of `manual.pdf` produce twenty files. The same helper is used when rebinding moves files, which had the same gap. Also fixed there: a name at the length limit lost its extension, and the collision suffix pushed it past the limit, so the attachment was stored under a name the server would not serve back — a permanent 404 on a file the UI reported as attached. - **An interrupted upload no longer leaves a temporary file forever (HP-1460-02).** Cleanup ran in an `except Exception`, which a cancelled request walks straight past, and the collector only ever looks inside marker folders — so an aborted transfer left a `.upload-*` in place with nothing able to remove it. Every exit path now cleans up, a request carrying two files is refused outright, and abandoned temporaries are swept at startup and daily. Uploads also write in 1 MB batches instead of one disk task per 64 KB. - **Two full cards side by side keep the same positions (HP-1460-03).** v1.46.0 taught the static card to follow position changes and left the full one behind, so dragging an icon in one window did not move it in another until a reload. It follows now, without disturbing a drag of its own: a revision arriving mid-drag is merged rather than applied over the top, and a card does not re-read what it just wrote itself. ## v1.46.0 — 2026-07-28 (full external audit of v1.45.4: HP-1454-01 … -10) **Security** - **An uploaded SVG plan is no longer a live document of your Home Assistant origin (HP-1454-01, high — release blocker).** Inside the card a plan is referenced by ``, where scripts never run; but the same url opened directly became a top-level document of HA's own origin, and a `