mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-03 05:08:53 +00:00
@@ -0,0 +1,623 @@
|
||||
# Issue #122 — Isometric Stage 2: hidden visual polish
|
||||
|
||||
- **Issue:** https://github.com/Matysh/houseplan-card/issues/122
|
||||
- **Predecessor:** #89, normative Stage 1 contract
|
||||
[`089-isometric-view-stage1.md`](089-isometric-view-stage1.md)
|
||||
- **Owner decisions:**
|
||||
https://github.com/Matysh/houseplan-card/issues/122#issuecomment-5286229767
|
||||
- **Visual references:**
|
||||
https://github.com/Matysh/houseplan-card/issues/89#issuecomment-5279077001
|
||||
- **Type / priority:** feature / P2
|
||||
- **Assessment:** user value 7/10; development value 6/10; complexity and
|
||||
risk 9/10
|
||||
- **Revision:** first revision for independent spec review; task status is
|
||||
defined only by the issue labels
|
||||
- **Related:** #124 (existing Iso ↔ Flat performance debt), #82 (camera
|
||||
animation, explicitly out of scope)
|
||||
|
||||
## 1. Scenario and product context
|
||||
|
||||
**Persona:** a home administrator who deliberately enables the hidden `iso`
|
||||
Labs experiment to evaluate it on a real plan. Household members and guests do
|
||||
not discover or enable Stage 2 through the product UI.
|
||||
|
||||
**Surface and moment:** the administrator opens ordinary View or kiosk on a
|
||||
desktop, phone or wall tablet, activates the existing `iso` Labs flag and
|
||||
switches the current space from Flat to the volumetric presentation.
|
||||
|
||||
**Before → after, without implementation terms:** today the hidden volumetric
|
||||
view shows technically correct but schematic white/grey wall slabs and flat
|
||||
opening symbols; after Stage 2 the same live home has restrained material
|
||||
depth, vertical openings, a low outside floor edge and soft grounding shadows,
|
||||
without losing any state, action or existing floor effect.
|
||||
|
||||
The task serves:
|
||||
|
||||
- **J1:** the live whole-home view becomes easier to read spatially;
|
||||
- **J2:** opening, lock and alert state stays located on the same plan;
|
||||
- **J3:** existing safe actions remain available at the same projected anchors.
|
||||
|
||||
This remains inside the owner-approved narrow exception in `docs/SCOPE.md`:
|
||||
deterministic 2.5D presentation of the canonical plan, not a second model,
|
||||
photorealistic renderer, free camera or interior editor. View is still the
|
||||
product; the experiment being hidden does not relax the View/kiosk touch
|
||||
contract.
|
||||
|
||||
## 2. Problem
|
||||
|
||||
Stage 1 established the hard parts of the renderer: one fixed orthographic
|
||||
projection, canonical wall geometry, complete opening cuts, screen-facing
|
||||
overlays, live floor layers, fallback, warm-remount and bounded geometry cache.
|
||||
Its deliberate visual limits are now the gap:
|
||||
|
||||
- wall tops and sides are flat solid colours with minimal depth cues;
|
||||
- the floor has no visible outside edge and the plan does not feel grounded;
|
||||
- doors, windows and gates keep their old floor-plane symbols inside a
|
||||
volumetric wall gap;
|
||||
- there is no ambient, contact or leaf shadow;
|
||||
- owner references and the accepted pseudo-3D direction are not yet represented.
|
||||
|
||||
A literal copy of the references would be wrong. They omit labels, live fills,
|
||||
decor, furniture, columns, Glow, sunlight and vacuum data, and they imply
|
||||
concrete/wood semantics that House Plan does not store. Stage 2 must adopt the
|
||||
references' language of depth while retaining the user's canonical content and
|
||||
the semantic meaning of every live layer.
|
||||
|
||||
## 3. Accepted owner decisions
|
||||
|
||||
The owner accepted defaults Q0–Q6 on 13 August 2026.
|
||||
|
||||
1. Priority is P2; Stage 2 is valuable but hidden and does not displace public
|
||||
P1 defects.
|
||||
2. Stage 2 evolves the existing `iso` flag. There is no second flag, public
|
||||
setting or rollout surface; Flat remains the initial presentation.
|
||||
3. The references guide wall/opening/edge material and depth only. They do not
|
||||
replace the plan image, room fills, labels, decor/backdrop, furniture,
|
||||
Glow/spill, sun, vacuum or canonical columns, and do not add inferred
|
||||
concrete/wood/terrace materials.
|
||||
4. In Iso, doors use one vertical leaf, gates use their existing pair of short
|
||||
leaves and windows use a light vertical insert. The old floor symbol is not
|
||||
duplicated while the volumetric representation is active. Existing contact,
|
||||
inversion, hinge/side, live state, lock card/badge and actions remain.
|
||||
5. There is no new decorative window-light beam on the floor. Windows may have
|
||||
a local material highlight; directional window light remains the existing
|
||||
live sunlight and room light remains Glow.
|
||||
6. One low outside floor edge and restrained ambient/contact/leaf shadows are
|
||||
included. There are no per-room steps or new terrace/porch entities.
|
||||
7. Unsupported decorative filters may disappear without losing structural
|
||||
volume, openings, live layers or actions. Flat fallback remains reserved for
|
||||
structural projection/topology failure.
|
||||
|
||||
## 4. Scope
|
||||
|
||||
Stage 2 includes:
|
||||
|
||||
1. evolution of the existing hidden `iso` presentation under the same Labs
|
||||
activation and expiry contract;
|
||||
2. theme-aware matte material for wall tops and visible sides, with a stable
|
||||
distinction between top, side and outline in light and dark themes;
|
||||
3. one low outside floor edge for every connected exterior component of the
|
||||
canonical room footprint, with no edge at internal room boundaries;
|
||||
4. a restrained ambient shadow for the complete footprint, contact shadow at
|
||||
physical walls and soft shadow for visible vertical leaves;
|
||||
5. vertical Iso presentation of doors, windows and gates derived only from the
|
||||
existing opening model and live `openingAmount()` semantics;
|
||||
6. exact preservation of opening gaps, jamb faces, lock markers, room fills,
|
||||
hover, Glow/spill, sunlight, plan image, decor, furniture, vacuum and all
|
||||
device/room overlays;
|
||||
7. deterministic behaviour for `show_borders`, `hide_openings`, themes,
|
||||
forced colours and missing decorative-filter support;
|
||||
8. fit/pan/zoom/warm-remount/fallback bounds that include structural floor and
|
||||
opening volume without clipping;
|
||||
9. unit, targeted browser smoke, golden and exact-SHA performance evidence;
|
||||
10. internal architecture, Iso and status documentation.
|
||||
|
||||
## 5. Out of scope
|
||||
|
||||
- public activation, settings, onboarding, announcement or documentation of
|
||||
Iso; public rollout requires a separate owner-approved issue;
|
||||
- a second `iso2` flag or an A/B selector between Stage 1 and Stage 2;
|
||||
- free rotation, perspective, user tilt, camera presets or #82 animation;
|
||||
- new wall, floor, door or window material settings;
|
||||
- inferred room types, concrete, wood, terrace, porch or floor finish;
|
||||
- a constant decorative beam from each window or a second light model;
|
||||
- geometric occlusion of device markers, labels, cards or popovers by walls;
|
||||
- volumetric Plan/Devices/Background editors;
|
||||
- volumetric `houseplan-space-card`;
|
||||
- opening height/sill/frame fields, schema changes or compatibility aliases;
|
||||
- 3D furniture, ceiling, roof, external-object shadows or weather lighting;
|
||||
- WebGL, Three.js, CSS `preserve-3d`, raster textures or a runtime dependency;
|
||||
- fixing or weakening the independent performance defect/budget in #124;
|
||||
- backend, import/export, HA registry, service calls or lock security changes.
|
||||
|
||||
## 6. Behaviour contract
|
||||
|
||||
### 6.1 Labs and surface boundary
|
||||
|
||||
- `iso` remains the only Labs id. Query/hash/storage grammar, Flat default,
|
||||
per-space preference, kiosk preference and `-iso`/`off` rollback remain the
|
||||
Stage 1 contract.
|
||||
- Stage 2 is available only while that registry entry is live. Its existing
|
||||
exclusive expiry at `1.65.0` is not extended by this issue; a `1.65.0-beta.*`
|
||||
build must fail closed unless a separate reviewed graduation decision exists.
|
||||
- Editors and `houseplan-space-card` stay Flat. Entering an editor, returning
|
||||
to View, changing space and warm-remount preserve the existing logical centre
|
||||
and projection preference.
|
||||
- With Labs inactive, no Stage 2 geometry, definitions, filters, capability
|
||||
work or DOM is created. Existing Flat DOM and pixels remain the reference.
|
||||
|
||||
### 6.2 Material language
|
||||
|
||||
- Walls remain low, neutral and matte. Top faces are lighter than visible side
|
||||
faces in both themes; an outline keeps adjacent faces distinguishable.
|
||||
- Material uses deterministic CSS/SVG tokens. A subtle bounded gradient or
|
||||
reusable low-amplitude treatment is allowed, but no raster texture, random
|
||||
noise, glossy highlight or floor-material replacement is allowed.
|
||||
- Theme or colour-scheme changes update presentation only and do not rebuild
|
||||
topology or change cache keys.
|
||||
- User room/border colours retain their existing Flat/editor meaning. Stage 2
|
||||
does not reinterpret them as physical material.
|
||||
- Materials do not encode HA state. All live state remains in the existing
|
||||
room/device/opening layers.
|
||||
|
||||
### 6.3 Canonical floor edge
|
||||
|
||||
The Stage 2 floor footprint is computed from the union of room floor polygons
|
||||
and their derived exterior masonry. It deliberately excludes detached
|
||||
partitions, columns, decor, background images and far markers from deciding the
|
||||
slab perimeter.
|
||||
|
||||
- Each connected exterior component receives one low vertical edge below the
|
||||
current floor plane.
|
||||
- Shared room edges and other internal boundaries never form a step or seam.
|
||||
- Nested-room/internal holes do not create an additional decorative step.
|
||||
- Two genuinely detached room components may each have an outside edge; they
|
||||
are not bridged by a bounding box.
|
||||
- A space without room geometry has no inferred floor edge.
|
||||
- The existing floor nodes remain the top surface. Stage 2 must not paint a new
|
||||
opaque floor over plan images, fills, Glow, sunlight or decor.
|
||||
|
||||
### 6.4 Shadows
|
||||
|
||||
There are three decorative depth cues:
|
||||
|
||||
1. one ambient shadow for the complete connected plan footprint;
|
||||
2. a restrained contact shadow where physical masonry meets the floor;
|
||||
3. a soft shadow belonging to each visible door/gate leaf.
|
||||
|
||||
They are presentation only:
|
||||
|
||||
- no shadow changes light visibility, room state, hit testing or HA action;
|
||||
- shadow opacity is bounded so room fills, Glow and sunlight remain readable;
|
||||
- no per-edge SVG filter is created; filter/definition count is O(1) per card,
|
||||
while geometry remains O(E + O) for wall edges and openings;
|
||||
- theme, hover and an HA-only device update do not reconstruct shadow geometry;
|
||||
- shadows from roofs, neighbouring wings, furniture or outdoor objects are not
|
||||
modelled;
|
||||
- reduced/unsupported decoration removes the shadow rather than substituting a
|
||||
hard, misleading shape.
|
||||
|
||||
### 6.5 Vertical openings
|
||||
|
||||
All opening placement and live meaning continues to come from existing
|
||||
`OpeningCfg`, `OpeningWallIndex`, wall cuts and `openingAmount()`.
|
||||
|
||||
**Door**
|
||||
|
||||
- one thin vertical leaf is hinged exactly at the owning jamb;
|
||||
- closed state lies in the wall opening; open amount follows the same 0–1 path
|
||||
and opening side/hinge choices as the current floor symbol;
|
||||
- no handle, hinge hardware or decorative panel is added.
|
||||
|
||||
**Gate**
|
||||
|
||||
- two equal vertical leaves meet at the opening centre when closed;
|
||||
- live amount preserves the current 0–10° outward contract, including the
|
||||
static-open default when no contact exists;
|
||||
- gate lock semantics remain identical to a door.
|
||||
|
||||
**Window**
|
||||
|
||||
- a closed window is a light neutral insert in the wall opening;
|
||||
- open state uses the existing two-leaf/casement direction and amount rather
|
||||
than inventing a new sash type;
|
||||
- the insert may have a local highlight but emits no floor beam and does not
|
||||
replace the existing sun layer.
|
||||
|
||||
For every type:
|
||||
|
||||
- leaf/panel height and thickness are fixed presentation ratios to Stage 1 wall
|
||||
height; no persisted setting is introduced;
|
||||
- jamb attachment error is at most the existing geometric epsilon and the
|
||||
projected visual gap at the hinge is at most 1 CSS px;
|
||||
- panels do not fill the masonry cut or bridge the full-height opening with a
|
||||
wall strip;
|
||||
- panels and their shadows are `aria-hidden`/pointer-inert. Existing View
|
||||
inertness, lock badge, card and secure action boundary remain the only
|
||||
interaction contract;
|
||||
- a contact-state update changes only the live leaf projection and cannot
|
||||
rebuild wall union, floor footprint or opening-wall topology.
|
||||
|
||||
### 6.6 Display settings
|
||||
|
||||
- `hide_openings: true` hides vertical panels and leaf shadows, while the wall
|
||||
cut, contact/lock references, Glow passage and sunlight behaviour remain as
|
||||
today.
|
||||
- `show_borders: false` preserves the Stage 1 no-volume contract: Stage 2 wall
|
||||
material, vertical panels, floor edge and all new shadows are absent. The
|
||||
existing floor-plane opening symbol remains available under its current
|
||||
`hide_openings` rule so openings do not become invisible floating gaps.
|
||||
- With borders visible, the vertical panel replaces rather than duplicates the
|
||||
old floor-plane symbol in Iso.
|
||||
- Flat and every editor keep their current symbols and settings behaviour.
|
||||
|
||||
### 6.7 Existing live layers and actions
|
||||
|
||||
The following invariants are exact, not best effort:
|
||||
|
||||
- the same resolved rooms, sources, opening state, markers and vacuum data are
|
||||
consumed in Flat and Iso;
|
||||
- room fills/hover, Glow/spill, sun, backdrop/decor/furniture, vacuum and
|
||||
screen-facing overlays retain their existing node/state/action contract;
|
||||
- Stage 2 creates no new HA call, websocket request, fetch, storage write or
|
||||
network resource;
|
||||
- device actions, opening cards and the lock invariant from `docs/SCOPE.md`
|
||||
remain unchanged;
|
||||
- decorative shadow may modulate final pixels but may not remove, replace or
|
||||
reclassify any live effect;
|
||||
- there is no second window-light, Glow or sun layer.
|
||||
|
||||
### 6.8 Accessibility, touch and graceful degradation
|
||||
|
||||
- View and kiosk remain fully supported on desktop and touch: pan, pinch,
|
||||
swipe, double-tap reset, orientation resize, space change and long-press
|
||||
kiosk settings are unchanged.
|
||||
- New volume is non-interactive and cannot steal pointer, focus or assistive
|
||||
technology navigation. Existing HTML devices, room cards and lock badges
|
||||
stay screen-facing and above it.
|
||||
- New geometry has no animation timeline. Live opening state may update, but
|
||||
no decorative continuous motion is introduced; `prefers-reduced-motion`
|
||||
therefore retains the Stage 1 transition contract.
|
||||
- In forced-colours/high-contrast mode, structural faces and outlines remain
|
||||
distinguishable without relying only on a gradient; decorative shadows and
|
||||
material nuance may be absent.
|
||||
- A detected unsupported filter/paint capability degrades to solid material
|
||||
and no decorative shadows. Geometry, vertical openings, floor edge, live
|
||||
layers and actions remain.
|
||||
- Canonical supported browsers must render full Stage 2 and pass performance.
|
||||
Fallback may not be forced in the benchmark merely to make the budget green.
|
||||
- A structural projection/topology exception uses the existing latched Flat
|
||||
fallback for `space|fingerprint`. Decorative-filter failure alone never
|
||||
changes the selected presentation to Flat.
|
||||
|
||||
## 7. Rendering and architecture contract
|
||||
|
||||
Stage 1 projection and canonical wall decisions remain accepted. Stage 2 may
|
||||
extend their scene result, but must not create a second coordinate system or
|
||||
replace `wallBodiesGeometry()`.
|
||||
|
||||
Required boundaries:
|
||||
|
||||
1. One structural Stage 2 scene is keyed by the complete geometry fingerprint:
|
||||
rooms, canonical masonry, openings and flips, wall/camera/edge height and an
|
||||
algorithm revision. HA state, theme, hover, day/night and filter capability
|
||||
are excluded.
|
||||
2. Cached opening structure stores jamb/basis/topology only. Live
|
||||
`openingAmount()` is applied after the structural cache, O(O), without a
|
||||
boolean wall operation.
|
||||
3. Floor-edge geometry derives from canonical room/exterior geometry, not from
|
||||
SVG DOM measurement, a background image or duplicated room inference.
|
||||
4. Structural complexity remains O(E + O). A constant number of shared SVG
|
||||
gradients/filters is allowed; per-face filters and data URLs are forbidden.
|
||||
5. Render order is explicit and testable:
|
||||
|
||||
```text
|
||||
stage background
|
||||
→ optional ambient shadow
|
||||
→ exterior floor edge
|
||||
→ existing projected floor SVG and all live floor layers
|
||||
→ optional contact/leaf shadows
|
||||
→ canonical wall sides/top and vertical opening panels
|
||||
→ existing screen-facing HTML overlays
|
||||
```
|
||||
|
||||
6. If implementation uses more than one absolutely positioned SVG, they share
|
||||
the same `viewBox` snapshot and projection; no layer computes fit, pan or
|
||||
zoom independently.
|
||||
7. `projectedFrame()` or its Stage 2 successor includes wall tops, opening tops
|
||||
and structural floor edge. Filter blur may overflow safely but must not
|
||||
expand logical content bounds or change zoom when decoration degrades.
|
||||
8. Flat fallback is independent of the Stage 2 cache and can render even when
|
||||
Stage 2 construction throws.
|
||||
9. Existing LRU cap remains eight structural scenes per card and does not grow
|
||||
on HA updates, theme changes, view toggles or filter fallback.
|
||||
10. The implementation records its composition/cache/fallback decisions in a
|
||||
new `docs/adr/122-isometric-stage2-composition.md`; the historical Stage 1
|
||||
ADR is not rewritten as if it had decided Stage 2.
|
||||
|
||||
Likely implementation files, subject to code review:
|
||||
|
||||
- `src/iso-projection.ts` for Stage 2 structural bounds only if required;
|
||||
- `src/iso-walls.ts` or a new pure `src/iso-scene.ts` for cached walls and floor
|
||||
edge;
|
||||
- a pure `src/iso-openings.ts` (or equivalent) for live vertical-panel
|
||||
projection;
|
||||
- `src/houseplan-card.ts` for orchestration and exact layer order;
|
||||
- `src/styles.ts` for theme/capability/forced-colour material;
|
||||
- `src/labs.ts` only for traceability metadata, without changing id/lifetime;
|
||||
- unit, smoke, golden/performance harness and internal docs named in §11–§13.
|
||||
|
||||
## 8. Model data, compatibility and migration
|
||||
|
||||
No persisted model changes.
|
||||
|
||||
- `space.openings[]`, room/wall geometry and display settings retain their
|
||||
current schema;
|
||||
- there are no door/window height, sill, material or Stage 2 fields;
|
||||
- no config version, backend validation, import/export or compatibility-registry
|
||||
entry changes;
|
||||
- current `houseplan_card_labs_v1` and `houseplan_card_view_v1` values remain
|
||||
readable and unchanged;
|
||||
- merely rendering Stage 2 writes no config/layout and does not rewrite local
|
||||
storage beyond the existing Stage 1 Labs/preference operations;
|
||||
- downgrade to Stage 1 or Flat requires no migration and loses no user data.
|
||||
|
||||
The `iso` registry `since: 1.62.0` and exclusive `expires: 1.65.0` values are
|
||||
unchanged. The metadata issue/summary may point to #122 for current diagnostics,
|
||||
provided internal docs retain the #89 predecessor link.
|
||||
|
||||
## 9. UX and i18n
|
||||
|
||||
There is no new public control or text. The existing hidden projection button,
|
||||
its 44×44 target, labels “Volumetric view” / “Flat view” and per-space preference
|
||||
remain unchanged.
|
||||
|
||||
- no new i18n keys;
|
||||
- no public settings/YAML option;
|
||||
- no README, user-guide or HACS promise;
|
||||
- no change to editor wording or opening settings;
|
||||
- no new focusable node or interaction path.
|
||||
|
||||
`docs/USER-GUIDE.ru.md` remains deliberately silent about hidden Iso. The
|
||||
implementation must nevertheless preserve its normative contracts for View,
|
||||
kiosk, openings, Glow, sunlight and lock safety.
|
||||
|
||||
## 10. Dependency and Definition of Ready
|
||||
|
||||
#124 records a reproducible failure of the existing Stage 1
|
||||
`large-house-isometric-v1` view-toggle budget. Stage 2 must not absorb that bug,
|
||||
hide it with decorative fallback or weaken its budget.
|
||||
|
||||
This specification may be reviewed while #124 is open. After a green spec
|
||||
review, #122 may carry `S5-ready`, but it also receives `blocked` and may not be
|
||||
claimed into `S6-in-progress` until one of these is true:
|
||||
|
||||
1. #124 is resolved with a green exact-SHA Full Performance comparison using at
|
||||
least seven samples and unchanged budgets; or
|
||||
2. the owner records a separate explicit arbitration that #122 may start with
|
||||
the known baseline debt.
|
||||
|
||||
Stage 2's own implementation must then pass the same unchanged profile on its
|
||||
exact SHA. A coincidentally green single local sample is not a substitute.
|
||||
|
||||
## 11. Acceptance criteria
|
||||
|
||||
- **AC1 (`unit` + `smoke` + code review):** the same `iso` Labs id exposes Stage
|
||||
2 while live; Flat remains default, expiry remains exclusive at `1.65.0`, and
|
||||
there is no second flag, public setting or config key.
|
||||
- **AC2 (`unit` + existing flat smoke + existing flat golden):** with Labs
|
||||
inactive, Flat/editors/static card do not create Stage 2 geometry, filters or
|
||||
DOM and retain their existing state/action/pixel contract.
|
||||
- **AC3 (`unit` + `golden`):** light and dark Iso show deterministic matte wall
|
||||
top/side/outline separation without raster textures, random output, inferred
|
||||
room material or per-face filters.
|
||||
- **AC4 (`unit` + `golden`):** every connected room footprint receives one low
|
||||
outside edge; shared/internal room edges and nested holes create no steps,
|
||||
detached components are not bridged, and detached partitions/columns do not
|
||||
expand the slab.
|
||||
- **AC5 (`unit` + `smoke` + `golden`):** door, window and gate vertical geometry
|
||||
matches existing jamb, side, flip and `openingAmount()` semantics for
|
||||
closed/open/no-contact/unavailable/inverted states; projected hinge gap is
|
||||
≤1 CSS px and the masonry opening remains full-height.
|
||||
- **AC6 (`smoke` + code review):** vertical panels are pointer/focus/ARIA inert;
|
||||
the existing lock badge/card and safe action result are unchanged and no new
|
||||
service or network call exists.
|
||||
- **AC7 (`unit` + `smoke` + `golden`):** `hide_openings` hides panels/leaf shadows
|
||||
but not cuts/state/light; `show_borders:false` preserves the Stage 1
|
||||
no-volume scene and existing floor symbols without Stage 2 edge/shadows.
|
||||
- **AC8 (`smoke` + `golden`):** room fills/hover, Glow/spill, sun,
|
||||
backdrop/decor/furniture, vacuum, markers, labels/cards and opening locks keep
|
||||
the same resolved state, source count, action outcome and layer order; no
|
||||
second window-light/Glow/sun layer appears.
|
||||
- **AC9 (`unit` + `smoke`):** HA-only state changes do not rebuild wall/floor
|
||||
topology; an opening contact update changes only live leaf projection; theme,
|
||||
hover and filter fallback do not grow the structural cache.
|
||||
- **AC10 (`smoke` + `golden`):** desktop View, touch View and kiosk retain
|
||||
pan/pinch/tap/long-press/swipe/orientation/space/warm-remount behaviour, use one
|
||||
projection snapshot and never expose volumetric editors.
|
||||
- **AC11 (`unit` + `smoke` + code review):** unsupported decoration and forced
|
||||
colours retain solid readable structure with no decorative shadows; a
|
||||
decorative failure stays Iso, while a structural failure uses the existing
|
||||
latched Flat fallback and emits no personal data.
|
||||
- **AC12 (`unit` + `smoke`):** fit/home and projection toggle include wall,
|
||||
opening and floor-edge structural bounds without clipping, preserve scalar
|
||||
zoom/logical floor centre and do not change when blur is disabled.
|
||||
- **AC13 (`performance`):** after #124's precondition, exact-SHA Full Performance
|
||||
for `large-house-isometric-v1` is green with ≥7 samples and unchanged budgets;
|
||||
Flat remains inside noise, filter/definition count is bounded and
|
||||
`isoGeometry` cache cap/growth remain 8/0.
|
||||
- **AC14 (`unit` + smoke + code review):** plan/backend/import/export schema,
|
||||
local-storage keys, HA actions, network traffic and i18n keys are unchanged;
|
||||
render-only use does not write config or layout.
|
||||
- **AC15 (`golden` + documentation review):** reviewed Stage 2 Iso baselines show
|
||||
materials, openings, edge, shadows and live-layer parity; all Flat and
|
||||
`isometric-no-borders-dark` baselines remain unchanged; internal docs describe
|
||||
the hidden experiment without public rollout claims.
|
||||
- **AC16 (`typecheck` + `unit` + `build`):** implementation-loop gates are green
|
||||
and all three generated bundle copies are byte-identical.
|
||||
|
||||
## 12. Automated test plan
|
||||
|
||||
### 12.1 Unit
|
||||
|
||||
1. Extend pure Iso geometry coverage with room union/exterior floor-edge cases:
|
||||
one room, shared rooms, nested room, two detached components, detached
|
||||
partition/column and empty space.
|
||||
2. Prove floor-edge geometry has no segment on an internal shared boundary and
|
||||
remains stable under room order/winding changes.
|
||||
3. Add pure vertical-opening fixtures for door/window/gate across amount 0/1,
|
||||
no contact, unavailable, invert and both flips. Assert exact jamb anchors,
|
||||
leaf count, wall-height bounds and stable output order.
|
||||
4. Prove an HA amount change reuses the structural basis and cannot mutate or
|
||||
grow the wall/floor cache.
|
||||
5. Verify structural fingerprint includes opening geometry/flips, wall/edge
|
||||
height and algorithm revision, but excludes HA state, theme, hover and
|
||||
filter capability.
|
||||
6. Verify layer/capability resolution: full decoration, unsupported filter,
|
||||
forced colours, `hide_openings` and `show_borders:false`.
|
||||
7. Source-contract tests assert no new config key, dependency, network call,
|
||||
public control or second light layer.
|
||||
|
||||
Tests must be capable of failing independently: removing one exterior edge,
|
||||
moving a leaf off its jamb, including HA state in the cache key, duplicating a
|
||||
floor symbol or adding an extra light layer must make the relevant test red.
|
||||
|
||||
### 12.2 Targeted browser smoke
|
||||
|
||||
Extend or add a production-bundle scenario with:
|
||||
|
||||
1. light and dark Stage 2 activation under existing `iso`;
|
||||
2. door/window/gate with live contact and lock references, including state
|
||||
changes without topology rebuild;
|
||||
3. visible borders, `hide_openings`, `show_borders:false` and return to visible
|
||||
borders;
|
||||
4. room fill + two Glow sources + sunlight + decor + vacuum + room/device
|
||||
actions in the same frame;
|
||||
5. Flat ↔ Iso, editor round-trip, space switch, resize/orientation and warm
|
||||
remount;
|
||||
6. touch View and kiosk gestures with pointer-inert Stage 2 layers;
|
||||
7. forced/unsupported-decoration mode and structural-failure Flat fallback;
|
||||
8. assertions for one light model, stable cache counts and no config/layout/
|
||||
network write.
|
||||
|
||||
Per the implementation-loop policy, browser smoke is authored with the code but
|
||||
run in the full pre-beta gate, not on every local iteration.
|
||||
|
||||
### 12.3 Golden
|
||||
|
||||
The existing matrix remains the base. Expected work:
|
||||
|
||||
- update reviewed Stage 2 baselines for geometry light/dark, live layers,
|
||||
touch kiosk and large warm-remount;
|
||||
- keep every Flat baseline and `isometric-no-borders-dark` pixel-identical;
|
||||
- add a focused light-theme and dark-theme opening/material scenario containing
|
||||
door, window, gate, floor edge and shadows;
|
||||
- add a detached-footprint/internal-boundary scenario if existing geometry
|
||||
fixtures cannot prove AC4 visually;
|
||||
- inspect live-effect readability rather than accepting lower contrast merely
|
||||
because the diff is expected.
|
||||
|
||||
Baselines are accepted only through `npm run golden:accept -- --reviewed` from a
|
||||
complete reviewed Linux CI artifact with the required `Release:` and
|
||||
`Baseline-Reviewed:` trailers. Stage 2's spec approval is not baseline approval.
|
||||
|
||||
### 12.4 Performance
|
||||
|
||||
Use the existing `large-house-isometric-v1` runner and unchanged budget file:
|
||||
|
||||
- at least seven samples on the exact candidate SHA;
|
||||
- Flat baseline comparison and Iso candidate comparison;
|
||||
- view toggle, first stable render, state update, space switch, pan/zoom,
|
||||
long tasks, heap, cache caps and growth;
|
||||
- a DOM metric or smoke assertion bounding shared material/filter definitions
|
||||
and vertical opening count to O(1) definitions + O(O) geometry.
|
||||
|
||||
A local run is diagnostic only. #124's evidence and Stage 2's own exact-SHA
|
||||
comparison are separate required results.
|
||||
|
||||
### 12.5 Backend
|
||||
|
||||
Backend is unchanged. No new backend test is required. Existing Linux Validate
|
||||
still runs the full project gate before beta.
|
||||
|
||||
## 13. Documentation and release artefacts
|
||||
|
||||
Stage 2 remains hidden, so its implementation commits use
|
||||
`User-Visible: no`. They do **not** add public changelog, README, HACS or
|
||||
user-guide promises. Public documentation belongs to a separate rollout issue.
|
||||
|
||||
Update with the implementation:
|
||||
|
||||
- `docs/ISOMETRIC.md` — Stage 2 material/opening/edge/layer/fallback contract;
|
||||
- `docs/ARCHITECTURE.md` — one cached structural scene and live-opening split;
|
||||
- `docs/adr/122-isometric-stage2-composition.md` — accepted composition,
|
||||
caching and degradation decisions;
|
||||
- `docs/STATUS.md` — current hidden Labs stage and release-cycle state;
|
||||
- `AGENTS.md` only if Labs authoring/lifetime rules themselves change (not
|
||||
expected).
|
||||
|
||||
Visual release artefacts:
|
||||
|
||||
- reviewed golden set from §12.3;
|
||||
- exact-SHA Validate and Full Performance evidence from §12.4;
|
||||
- no public screenshot or announcement;
|
||||
- no separate security report because there are no inputs, services or data
|
||||
changes; code review explicitly confirms the negative security contract.
|
||||
|
||||
The feature/material change must pass through a published beta before stable,
|
||||
even though it remains hidden.
|
||||
|
||||
## 14. Risks and mitigation
|
||||
|
||||
| Risk | Probability / impact | Mitigation |
|
||||
|---|---|---|
|
||||
| Vertical panel drifts from jamb or crosses masonry | medium / high | pure opening basis, ≤1 px smoke, focused golden |
|
||||
| Floor edge follows room seams or bridges detached plans | medium / high | canonical exterior union, permutation units, detached golden |
|
||||
| Shadows obscure Glow/sun or alter live meaning | medium / high | bounded shared filters, combined live-layer golden, no new light model |
|
||||
| Per-face filters or live topology rebuild break performance | high / high | O(1) definitions, structural/live split, unchanged exact-SHA budget |
|
||||
| #124 debt is hidden by Stage 2 fallback | high / high | explicit DoR blocker and benchmark full decoration |
|
||||
| `show_borders:false` leaves floating panels | medium / medium | retain Stage 1 floor symbols in the no-volume branch |
|
||||
| Touch/kiosk layer steals gestures | low / high | pointer-inert geometry and targeted touch/kiosk smoke |
|
||||
| Dark/forced-colour material becomes unreadable | medium / medium | outline-based distinction and solid fallback |
|
||||
| Filter exception unnecessarily drops to Flat | medium / medium | separate decorative capability from structural latch |
|
||||
| New cache key includes HA state and grows every tick | medium / high | basis/live split and cache-growth unit/performance assertion |
|
||||
| Internal feature leaks into public docs | low / medium | internal artefact list, no changelog/user-guide/README |
|
||||
| Stage 2 misses Labs expiry | medium / medium | unchanged exclusive 1.65 expiry and separate graduation decision |
|
||||
|
||||
## 15. Rollback
|
||||
|
||||
Immediate tester rollback needs no build: `?hp-labs=-iso` or
|
||||
`?hp-labs=off` makes Flat effective, and warm state cannot resurrect Iso.
|
||||
|
||||
Code rollback reverts the Stage 2 behaviour/artefact commit while retaining the
|
||||
accepted Stage 1 renderer. There is no data or schema migration to reverse.
|
||||
Existing Labs and view-preference storage remain valid. If only decorative
|
||||
filters fail, the supported runtime fallback removes them without disabling
|
||||
structural Stage 2; if Flat itself changes or fails, beta publication is blocked.
|
||||
|
||||
## 16. Technical assumptions — may change without product review
|
||||
|
||||
1. Recommended fixed ratios are: floor edge roughly 10–16% of wall height,
|
||||
door/gate panels roughly 85–100% and window panels roughly 45–70% of wall
|
||||
height. Exact constants are selected by reviewed golden output and do not
|
||||
become user settings.
|
||||
2. A new pure `iso-openings.ts`/`iso-scene.ts` split is preferred, but names and
|
||||
file boundaries may change while the structural/live-cache contract holds.
|
||||
3. Gradients and shadows should use shared SVG defs/CSS variables. Exact tokens,
|
||||
blur radii and alpha may change in review within the restrained material
|
||||
contract and performance budget.
|
||||
4. `show_borders:false` uses the existing floor symbols rather than floating
|
||||
vertical panels; this is the deterministic consequence of the accepted
|
||||
no-volume setting, not a new public mode.
|
||||
5. The ambient shadow may be rendered in a dedicated shared-projection SVG
|
||||
beneath the existing floor SVG. The number of SVG roots is not a product
|
||||
contract; the one-snapshot/layer-order invariant is.
|
||||
6. The Labs registry diagnostic may change its issue metadata from #89 to #122,
|
||||
but id, storage key, since and expiry do not change.
|
||||
7. Capability detection may use CSS/forced-colour media queries or a cached
|
||||
per-Document probe. It must not classify performance from viewport width or
|
||||
coarse pointer alone.
|
||||
8. #124 is a process/technical prerequisite, not Stage 2 product scope. Its fix
|
||||
may change the renderer internals this spec builds upon without reopening
|
||||
owner decisions Q0–Q6.
|
||||
|
||||
@@ -77,6 +77,7 @@ GitHub Issues и GitHub Projects (v2) остаются единственным
|
||||
| [#90](https://github.com/Matysh/houseplan-card/issues/90) Управляемый бейдж со значением | [090-device-value-badge.md](090-device-value-badge.md) |
|
||||
| [#94](https://github.com/Matysh/houseplan-card/issues/94) Универсальное действие «Переключить состояние» | [094-universal-state-toggle.md](094-universal-state-toggle.md) |
|
||||
| [#101](https://github.com/Matysh/houseplan-card/issues/101) Плавный переход View ↔ редакторы | [101-view-editor-transition.md](101-view-editor-transition.md) |
|
||||
| [#122](https://github.com/Matysh/houseplan-card/issues/122) Изометрический режим Stage 2: скрытый режим и визуальная полировка | [122-isometric-stage2.md](122-isometric-stage2.md) |
|
||||
| [#123](https://github.com/Matysh/houseplan-card/issues/123) Split из вершины не меняет наружную геометрию стен | [123-corner-split-wall.md](123-corner-split-wall.md) |
|
||||
|
||||
## Правило актуализации
|
||||
|
||||
Reference in New Issue
Block a user