Files
houseplan-card/docs/STAIRS.md
T
Claudeandclaude[bot] d709ea110d perf(stairs): draw all treads of a stair as one path (#740)
A floor with stairs pays for them on every switch to it: the stair layer
is emptied on other floors, so Lit recreates every symbol on each return
and the browser lays out and paints it again. With 250 stairs (the
large-house fixture, the per-floor limit) that was 2,875 SVG elements and
about 40 ms per entry locally; each stair carried 3-7 separate tread lines
with four bound coordinates each.

The treads of one stair are now a single <path class="hp-stair-tread">
with one `M a L b` subpath per tread, in geometry order and with the
numbers the lines carried. Treads of one stair never overlap (straight:
parallel, >= 20 cm apart; spiral: inner ends >= 6.7 cm apart at the
3.6 cm stroke), so the path paints the same pixels at any opacity. The
outline points and the tread data are built once per cached geometry
object (cachedStairMarkup, weak keys), not on every render. The View and
plan-editor layers share the strings; outline, hit polygon, trapezoid,
arrow, attributes and handlers are unchanged. Floor 1 of the fixture
drops from 4,210 to 2,960 elements.

Witnesses: the unit test for the path data and its cache, and the
smoke_stairs markup checks in View and in the plan editor, are red on
dev. The stairs-view-tread-lines mutant restores the View lines.

Issue: #740
User-Visible: no
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018qZfe7YS4rqEMKoVeS3GKd
2026-10-01 18:27:53 +00:00

9.3 KiB
Raw Blame History

Stairs

Stairs are plan-level navigation objects. They show the physical place and direction of an ascent on one space and can link that space to one other House Plan space. The link is deliberately one-way: adding or editing a stair never creates or changes anything on the target floor.

User contract

The Plan editor has one Stairs group with Straight and Spiral tools. Stairs are drawn like decor shapes (#676): press on the plan, drag and release. The dominant drag axis is the rise axis, the ascent points from the press to the release ("draw from the bottom up"), the sizes are the drawn extents (never below one 30 cm tread) and the angle is 0°, 90°, 180° or 270°; equal extents prefer the horizontal. A spiral stair takes the square of the drag, anchored at the press. A drag shorter than one grid cell is a click and places the default size (240 × 100 cm straight, R 90 cm spiral) at the press. The new stair stays selected and the tool remains armed; Esc during the drag discards the draft.

The selected stair shows the same frame as furniture in the decor editor, painted above wall bodies: a dashed outline, four corner and four side handles (a spiral stair has four handles on its axis tangents), a stem with the rotation handle above the local top side. Handle hit areas are finger-sized on screen at every zoom. The cursor over a handle follows the handle's world direction — ew/ns when it moves along an axis, a diagonal arrow otherwise — and the rotation handle shows the circular cursor. Drag the body to move, a handle to resize about the opposite side or corner (sizes stop at 30 cm and a pointer dragged past the anchor never mirrors the stair; Shift keeps the proportions), and the upper handle to rotate. Resizing never changes the angle. Rotation is continuous; holding Shift snaps to the nearest multiple of 45 degrees. Esc cancels an active transform or clears the selection; Delete/Backspace removes the selected stair; the ordinary Plan Undo/Redo history covers create, edit, move, resize, rotate and delete. The click a browser synthesizes after a gesture never reaches the plan tool: it places no copy under Stairs and keeps the selection under Select. Under any other plan tool the frame is not rendered at all.

Double click opens properties. A straight stair stores positive length and width; a spiral stair stores a positive radius. The fields accept 30–10000 cm (inches when Home Assistant is imperial); a field left untouched keeps the stored number bit for bit, and saving without changes writes nothing. The dialog also selects the rise direction, rotation, two colour/opacity pairs (all linework; full-footprint fill) and an optional target space. A new stair snapshots the current main decor colour for its outline, treads, trapezoid and arrow; its full rectangle/circle fill starts completely transparent. The colours then belong to that stair and do not follow later default-decor changes. For a straight stair the choices are Up and Down. They flip only the 100%/80% trapezoid; the arrow always points along the canonical local axis, so turn the whole stair to point the arrow elsewhere. A target cannot be the current space. A missing, self or deleted target leaves the stair visible and editable but shows a repair warning and makes View activation a no-op.

In View, hovering a stair with a mouse shows the card tooltip "Go to floor