mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-08 07:29:13 +00:00
feat: добавить лестницы между этажами (#663)
Прямые и винтовые лестницы получили отдельную модель, инструменты редактора, безопасную межэтажную навигацию, вычитание из чистой площади и плоское отображение в 2.5D. Issue: #663 User-Visible: yes
This commit is contained in:
+29
-2
@@ -26,6 +26,11 @@ houseplan-card/
|
||||
│ ├─ houseplan-panel.ts # HA sidebar/app-bar host for the same full card
|
||||
│ ├─ editor-runtime-loader.ts # lazy loader: dedupe, retry and build handshake
|
||||
│ ├─ houseplan-editor-runtime.ts # Plan/Devices/Background composition root
|
||||
│ ├─ stairs-view.ts # eager read-only stair symbols, links and gesture guards
|
||||
│ ├─ stairs-editor.ts # lazy Plan stair tools, transforms and properties
|
||||
│ ├─ stairs-editor-model.ts # pure editor transforms, snapping and target-state helpers
|
||||
│ ├─ stairs.ts # stair model, render geometry and area math
|
||||
│ ├─ clean-floor.ts # shared room-floor subtraction including stair footprints
|
||||
│ ├─ decor-image-editor.ts # lazy Background/Furniture image palette, upload and properties controller
|
||||
│ ├─ houseplan-onboarding-runtime.ts # first-space/import dialogs, independent of editor
|
||||
│ ├─ iso-scene-render.ts # lazy 2.5D scene/runtime boundary (settings.volumetric_view, #649)
|
||||
@@ -656,7 +661,7 @@ not be added to an individual sink.
|
||||
"rooms":[{"id","name","area","poly|x/y/w/h","wall_ids":[…],"settings"}],
|
||||
"wall_segments":[{"id","a","b","cm","owners":[…]}],
|
||||
"partitions":[…], "wall_columns":[…],
|
||||
"openings":[…], "decor":[…], "settings":{…} }],
|
||||
"openings":[…], "decor":[…], "stairs":[…], "settings":{…} }],
|
||||
"markers": [{ "id","binding":"device:<id>|entity:<eid>|virtual","hidden","removed",
|
||||
"name","icon","display","controls","is_light","glow_color","tap_action",
|
||||
"room_id","pdfs",… }],
|
||||
@@ -940,7 +945,7 @@ designer handoff are attached to issue #570.
|
||||
## Markup editor (v1.4.0+)
|
||||
|
||||
State inside the card: `_markup` (mode), `_tool` (draw/column/merge/split/resize/opening/
|
||||
wallthick/delroom), `_path` (the current outline,
|
||||
stairs/wallthick/delroom), `_path` (the current outline,
|
||||
vertices on the GRID_N=240 grid). Clicks on the stage → `_svgPoint`→`_snap`. The outline is closed
|
||||
= a click on the first vertex → area select (hass.areas) + name → room {poly}. Polygon rooms and
|
||||
rectangles are rendered uniformly (hit-test: point-in-polygon / rect).
|
||||
@@ -1125,6 +1130,28 @@ While drawing, the length of the current segment follows the cursor (`_fmtLen`
|
||||
per-space `cell_cm` — canonical centimetres represented by one grid cell; new
|
||||
spaces use 1 cm or 2.54 cm/1 inch, while missing legacy values fall back to 5 cm.
|
||||
|
||||
### Stairs (#663)
|
||||
|
||||
Stairs are a separate Plan entity, not decor. The lazy `StairEditorRuntime`
|
||||
owns the straight/spiral tool group, selection, continuous
|
||||
move/resize/rotation, wall/stair magnet and properties. The eager
|
||||
`StairViewRuntime` owns only read-only symbols, guarded navigation and gesture
|
||||
suppression, so opening a plan does not load the editor graph. The root card
|
||||
owns lifecycle composition, shared Plan history/persistence and stage pointer
|
||||
terminals. `stairs.ts` is the pure boundary for the discriminated model, exact
|
||||
30 cm tread geometry, cached render projection and footprint containment;
|
||||
`stairs-editor-model.ts` contains the pure transform, target-state and
|
||||
footprint-to-footprint snapping helpers used by the editor.
|
||||
|
||||
`spaces[].stairs[]` is optional and capped at 250 records. A record exists on
|
||||
one space only; `target_space_id` is a one-way navigation reference and never
|
||||
creates target geometry. Straight footprints are rotated rectangles; spiral
|
||||
footprints are circles. `clean-floor.ts` subtracts their geometric overlap
|
||||
from the same clean-area result used by room cards and summary metrics, without
|
||||
cutting the painted floor or changing walls/light/vacuum. PDF and full/static
|
||||
renderers consume the same stair geometry. The 2.5D scene keeps the SVG object
|
||||
on its floor plane with no height or shadow. See `docs/STAIRS.md`.
|
||||
|
||||
## Editor chrome and contextual controls
|
||||
|
||||
Every editor uses one stable primary `.editbar`. Its `.editbar-tools` contains
|
||||
|
||||
+21
-9
@@ -16,7 +16,7 @@ coordinate system.
|
||||
|
||||
## Principle
|
||||
|
||||
1. **Coordinates keep their meaning.** Rooms, openings, decor and
|
||||
1. **Coordinates keep their meaning.** Rooms, openings, decor, stairs and
|
||||
device positions are still stored normalised. `1.0` is still the
|
||||
same distance it always was; `cell_cm` still ties a grid cell to
|
||||
real centimetres. **No data migration.** An existing plan opens as
|
||||
@@ -56,8 +56,10 @@ Negative zero becomes positive zero.
|
||||
|
||||
The lattice allow-list covers room outlines/extents, exact wall endpoints,
|
||||
opening `x/y`, decor origins/sizes/endpoints, drafts, partitions, columns, open
|
||||
spans and layout `x/y`. Angles, opening length/host `t`, decor scale and
|
||||
backdrop transforms retain the nine-decimal scalar contract. The traversal
|
||||
spans and layout `x/y`. Angles, opening length/host `t`, decor scale, backdrop
|
||||
transforms and every stair transform field retain the nine-decimal scalar
|
||||
contract. Stairs are deliberately excluded even when a value is near a grid
|
||||
node: their continuous wall-face magnet position is authored data. The traversal
|
||||
deliberately excludes `cell_cm`, `plan_aspect`, `view_box`,
|
||||
physical centimetre fields, colours/opacities/live values, presentation scales
|
||||
and vacuum affine calibration. Unknown/future numeric fields round-trip
|
||||
@@ -113,6 +115,7 @@ the exact target atomically without exposing a default-fit frame.
|
||||
| `_GEOM` (room x/y, poly points, opening x/y, `view_box` origin) | `-4 .. 4` | `-5000 .. 5000` | coordinate |
|
||||
| `_EXTENT` (room w/h, `view_box` w/h) | `0.001 .. 4` | `0.001 .. 5000` | size — strictly positive |
|
||||
| `_NORM` (decor x/y/w/h) | `-1 .. 2` | `-5000 .. 5000` | coordinate |
|
||||
| stair `x/y`, `length/width/radius` | — | `-5000 .. 5000`; sizes positive | continuous transform |
|
||||
| opening `length` | `0.001 .. 1` | `0.001 .. 5000` | size — strictly positive |
|
||||
|
||||
`+/-5000` is **garbage insurance, not a frame**. At the historical compatibility
|
||||
@@ -132,6 +135,7 @@ tested. Input is a list of **items**, one per drawn/placed object:
|
||||
* the backdrop image rectangle, when the space has one;
|
||||
* every opening (door/window/gate) end-to-end segment;
|
||||
* every decor shape;
|
||||
* every stair, using its complete rotated rectangle or circular footprint;
|
||||
* every device the layout actually places in this space **and that the card
|
||||
actually draws** — a HIDDEN device (docs/FILTERING.md) is not content: the
|
||||
frame is presentation, and an object nobody can see must not decide what the
|
||||
@@ -276,7 +280,7 @@ produce a zero-sized SVG `viewBox`.
|
||||
in the decision — `_clampView` alone says how far you may walk.
|
||||
* **Who owns the pointer.** A drag pans only when it starts on empty
|
||||
scene: the room-resize handles, device badges, openings, room labels
|
||||
and the decor shapes take the pointer first (`_stagePointerDown`
|
||||
stairs and the decor shapes take the pointer first (`_stagePointerDown`
|
||||
bails out on them), and a drawing tool that consumes the press —
|
||||
decor line/rect/ellipse/text — bails out too. Two fingers are always
|
||||
a pinch, never a pan. On a **kiosk** screen at swipe zoom (`≤ 1`,
|
||||
@@ -526,10 +530,18 @@ exception to positional quantisation: it is continuous in both modes, with
|
||||
Shift selecting independent axes, while Shift on its rotation handle snaps to
|
||||
45°. Furniture placement and movement remain grid-bound.
|
||||
|
||||
Stairs use the continuous branch of this contract for their complete
|
||||
transform. Move and resize stay off-grid when authored there; Shift snaps only
|
||||
rotation to 45°. Wall magnet resolves the visible physical face (including
|
||||
half-thickness) and stair magnet resolves outer footprint-to-footprint contact.
|
||||
Neither save/load nor Optimize may replace that contact with a nearby lattice
|
||||
node.
|
||||
|
||||
### 9.5 «Оптимизировать планы» — explicit whole-plan maintenance
|
||||
|
||||
Existing and imported plans may still hold coordinates between the
|
||||
nodes. New editor operations cannot create more. General settings contain
|
||||
Existing and imported plans may still hold grid-bound coordinates between the
|
||||
nodes. Ordinary grid-bound editor operations do not create more; explicitly
|
||||
continuous objects are exempt. General settings contain
|
||||
a **Plan maintenance** group whose action previews and then repairs old
|
||||
data through all current passes: model upgrades, mandatory grid
|
||||
alignment, exact open-span canonicalisation and wall-interval compaction.
|
||||
@@ -585,9 +597,9 @@ either store changes, commits both revisions, and retains one snapshot.
|
||||
has changed since the optimization. A crash between store writes is
|
||||
completed from the intent on the next integration setup.
|
||||
|
||||
The grid pass deliberately excludes the complete transform of `furniture` and
|
||||
uploaded `image` decor. Their position, size and rotation are continuously
|
||||
authored values (#383), so changing even one of those fields would make
|
||||
The grid pass deliberately excludes the complete transform of `furniture`,
|
||||
uploaded `image` decor and `spaces[].stairs[]`. Their position, size and
|
||||
rotation are continuously authored values (#383, #663), so changing even one of those fields would make
|
||||
Optimize create debt from a normal editor operation. Other decor kinds and
|
||||
storage-level numeric canonicalization keep their existing grid contract
|
||||
(#477).
|
||||
|
||||
+10
-1
@@ -2,6 +2,16 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
- The Plan editor can now place straight and one-turn spiral stair objects with
|
||||
physical sizes, automatic 30 cm treads and an ascent arrow. Stairs move,
|
||||
resize, rotate and snap continuously to wall faces or each other; their
|
||||
footprint is deducted from clean room area without cutting the visible
|
||||
floor. An optional one-way target turns a stair into safe floor navigation
|
||||
in View, while gestures, broken targets and fixed-floor cards remain inert.
|
||||
The target floor is never changed automatically, and the first 2.5D version
|
||||
stays flat on the floor plane
|
||||
([#663](https://github.com/Matysh/houseplan-card/issues/663)).
|
||||
|
||||
## v1.78.0-beta.5 — 2026-09-26
|
||||
|
||||
- In the 2.5D plan the metrics row under a room name (temperature, humidity,
|
||||
@@ -22,7 +32,6 @@
|
||||
footer button as the only clickable control. The regression came with the
|
||||
overlapping-marker fix in v1.76.0-beta.2
|
||||
([#664](https://github.com/Matysh/houseplan-card/issues/664)).
|
||||
|
||||
## v1.78.0-beta.4 — 2026-09-26
|
||||
|
||||
- The main toolbar is steadier and more compact: its editor close **×** now
|
||||
|
||||
+11
-1
@@ -8,6 +8,17 @@
|
||||
|
||||
## Не выпущено
|
||||
|
||||
- В редакторе плана появились отдельные прямые и винтовые лестницы с физическими
|
||||
размерами, автоматическим шагом ступеней 30 см и стрелкой подъёма. Лестницу
|
||||
можно плавно перемещать, менять её размер, поворачивать и магнитить к грани
|
||||
стены или другой лестнице; её габарит вычитается из чистой площади комнаты,
|
||||
но не вырезает видимый пол. Необязательная односторонняя ссылка безопасно
|
||||
переводит на выбранный этаж в Просмотре, а после жеста, при битой ссылке и в
|
||||
карточке с закреплённым этажом переход не срабатывает. Целевой этаж
|
||||
автоматически не меняется; в первой версии 2.5D лестница остаётся плоской
|
||||
на полу
|
||||
([#663](https://github.com/Matysh/houseplan-card/issues/663)).
|
||||
|
||||
## v1.78.0-beta.5 — 2026-09-26
|
||||
|
||||
- На объёмном плане (2.5D) строка показателей под названием комнаты
|
||||
@@ -28,7 +39,6 @@
|
||||
единственный кликабельный элемент — кнопка в подвале. Регрессия пришла с
|
||||
исправлением перекрытий маркеров в v1.76.0-beta.2
|
||||
([#664](https://github.com/Matysh/houseplan-card/issues/664)).
|
||||
|
||||
## v1.78.0-beta.4 — 2026-09-26
|
||||
|
||||
- Основная панель стала компактнее и перестала дёргаться: крестик **×**
|
||||
|
||||
@@ -112,6 +112,28 @@ An older frontend ignores the field and shows Flat. An older backend preserves
|
||||
it through the unknown-settings policy. Full backup/import carries `settings`
|
||||
whole, so the value survives.
|
||||
|
||||
## Stairs (#663)
|
||||
|
||||
`spaces[].stairs[]` is an optional bounded (250 records per space)
|
||||
discriminated collection. `kind: "straight"` stores positive `length` and
|
||||
`width` plus `direction: "forward" | "backward"`; `kind: "spiral"` stores a
|
||||
positive `radius` plus `direction: "clockwise" | "counterclockwise"`. Both
|
||||
variants carry stable `id`, continuous normalized centre `x/y`, scalar
|
||||
`angle`, and an optional nullable `target_space_id`.
|
||||
|
||||
Stair transforms follow furniture's continuous contract. Config writes apply
|
||||
only the nine-decimal scalar cleanup to position, size and angle; they do not
|
||||
use near-lattice snapping, and Optimize does not move them. Full backup,
|
||||
support data and diagnostics retain the bounded records. Full import remaps a
|
||||
known target space id and clears a target that was not imported; single-space
|
||||
transfer cannot invent a link to an external floor. Deleting a target space
|
||||
clears incoming links without deleting the source stair.
|
||||
|
||||
The collection is additive and requires no model/store version migration. A
|
||||
current frontend renders and edits it; a legacy frontend ignores the objects.
|
||||
The current backend preserves valid records through unrelated writes, while a
|
||||
backend predating the field must not be used to edit a newer configuration.
|
||||
|
||||
## Sun-ray window face (#577)
|
||||
|
||||
`settings.sun_ray_origin` is an optional global enum: `inner` or `outer`.
|
||||
|
||||
+2
-2
@@ -92,7 +92,7 @@ Composition remains SVG-first:
|
||||
3. screen-facing HTML overlays.
|
||||
|
||||
The floor keeps the same nodes and order for paper/backdrop, room fills/hover,
|
||||
Glow/spill, sun, decor/furniture, opening symbols and vacuum path/outline. Stage
|
||||
Glow/spill, sun, decor/furniture, flat stair symbols, opening symbols and vacuum path/outline. Stage
|
||||
1 does not add a second light source/layer. Markers and room cards intentionally
|
||||
remain above walls without geometric occlusion.
|
||||
|
||||
@@ -248,7 +248,7 @@ search. There is no painted plate, long tether, ground dot or per-marker
|
||||
shadow. The original screen-facing HTML root remains the only hit, focus,
|
||||
tooltip and action target, and selection/hover cannot invalidate the placement
|
||||
cache. Vacuum, Glow/spill, SUN, room fills/hover, arbitrary decor,
|
||||
furniture/backdrop and every persisted coordinate remain on `z=0`.
|
||||
furniture/backdrop, stairs and every persisted coordinate remain on `z=0`.
|
||||
|
||||
Room names remain screen-facing and lose stroke, text shadow, drop shadow and
|
||||
halo. Iso uses `#303936` on a light presentation and `#f2f0e8` on a dark one;
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
| [Полное руководство пользователя](USER-GUIDE.ru.md) | Пользователи и администраторы Home Assistant | Установка, первая настройка, пространства, комнаты, стены, проёмы, устройства, визуальные состояния, заливки, подложка, солнце, пылесосы, киоск, обслуживание и диагностика |
|
||||
| [Радары присутствия](RADAR.md) | Пользователи, администраторы и интеграторы | Поддерживаемые профили, привязка источников, установка и калибровка, статусы данных, приватность и диагностика |
|
||||
| [Редактор подложки и декора](DECOR-EDITOR.md) | Пользователи, тестировщики и разработчики | Инструменты, единое выделение и трансформации, физические размеры, магнит, Undo/Redo, поведение картинки-подложки и совместимость старых полей |
|
||||
| [Лестницы и переходы между этажами](STAIRS.md) | Пользователи, тестировщики и разработчики | Прямые и винтовые лестницы, размеры, направление подъёма, магнит, связь этажей, площадь и ограничения 2.5D |
|
||||
| [GitHub Issues](https://github.com/Matysh/houseplan-card/issues) и [Project v2](https://github.com/users/Matysh/projects/1) | Владелец, разработчики и контрибьюторы | Единственный актуальный backlog: задачи, приоритеты, решения и статусы выполнения |
|
||||
|
||||
Старые тематические документы в этом каталоге остаются инженерными спецификациями и историей решений. При расхождении пользовательского описания с интерфейсом текущей версии приоритет имеет новое руководство, а при расхождении с фактическим поведением — код текущей версии.
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
# 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.
|
||||
A click places the chosen default; the object remains selected. Drag moves it,
|
||||
the visible handles resize it, and the upper handle rotates it. Straight stairs
|
||||
have corner and one-axis edge handles. A spiral stair remains a circle and has
|
||||
one radial resize handle. 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, transform and delete.
|
||||
|
||||
Double click opens properties. A straight stair stores positive length and
|
||||
width; a spiral stair stores a positive radius. The dialog also selects the
|
||||
rise direction, rotation and an optional target space. 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 an ordinary multi-space card, a clean click/tap or keyboard activation on a
|
||||
valid stair switches to the target tab and restores that floor's remembered
|
||||
camera. Pan, pinch, long press, swipe and pointer cancellation do not navigate.
|
||||
In a card configured with `floor`, stairs are visible but inert. The target
|
||||
floor receives no automatic stair, highlight or camera centring.
|
||||
|
||||
## Geometry and drawing
|
||||
|
||||
Both variants use the same continuous transform contract as furniture: their
|
||||
authored position, size and angle are not grid-quantised on save or by
|
||||
**Optimize plans**. A stair near a wall snaps to the visible physical wall face;
|
||||
a straight stair also becomes parallel to that face. Any straight/circular pair
|
||||
of stairs can snap footprint-to-footprint. The other stair is never modified or
|
||||
linked by the magnet.
|
||||
|
||||
Straight tread lines are perpendicular to the rise axis and start at the lower
|
||||
edge every 30 cm. A remainder shorter than 30 cm stays at the upper edge.
|
||||
Spiral stairs make one full turn; radial treads use the same 30 cm physical step
|
||||
measured on the travel line at two thirds of the radius. Their direction is
|
||||
clockwise or counter-clockwise when viewed from above. The arrow always means
|
||||
physical ascent, not the direction of navigation between named tabs.
|
||||
|
||||
The footprint overlap is removed from clean room floor area exactly once. It
|
||||
does not cut the visible floor, change room or wall geometry, create a light
|
||||
occluder, affect Glow/sun/vacuum, or participate in Optimize. In 2.5D the first
|
||||
version remains a flat symbol projected with the floor/decor plane; it has no
|
||||
height, risers, railings or shadows.
|
||||
|
||||
## Persisted model
|
||||
|
||||
Each space may contain `stairs: []`, bounded to 250 valid records:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "stair-main",
|
||||
"kind": "straight",
|
||||
"x": 0.42,
|
||||
"y": 0.55,
|
||||
"angle": 90,
|
||||
"length": 0.24,
|
||||
"width": 0.10,
|
||||
"direction": "forward",
|
||||
"target_space_id": "floor-2"
|
||||
}
|
||||
```
|
||||
|
||||
`kind:"spiral"` replaces `length`/`width` with `radius` and uses direction
|
||||
`clockwise` or `counterclockwise`. Coordinates and sizes use the normalized
|
||||
plan coordinate system; physical labels are derived through `cell_cm`.
|
||||
`target_space_id` is nullable. Unknown sibling fields survive validation and
|
||||
round trips for forward compatibility. Full backup/import/export, one-space
|
||||
transfer, plan-only transfer, diagnostics and support packages preserve the
|
||||
same records. When a complete backup removes a target space its incoming stair
|
||||
links are cleared; a one-space transfer cannot invent an external target.
|
||||
|
||||
## Implementation boundary
|
||||
|
||||
- `src/stairs.ts` owns validation, drawing geometry and area-subtraction
|
||||
primitives.
|
||||
- `src/stairs-view.ts` is the eager read-only boundary for symbols, guarded
|
||||
navigation and touch/pointer gesture suppression.
|
||||
- `src/stairs-editor-model.ts` owns pure Plan transforms, target state and
|
||||
stair-to-stair magnet math; `src/stairs-editor.ts` owns the lazy Plan UI and
|
||||
properties.
|
||||
- `src/clean-floor.ts` and `src/summary-panel-metrics.ts` consume the same
|
||||
footprint subtraction for room cards and summary totals; PDF rendering uses
|
||||
the same stair outline/tread geometry without changing the room floor paint.
|
||||
- Backend schemas and transfer/support surfaces treat `stairs` as a bounded,
|
||||
additive space collection. Old configs without it remain unchanged.
|
||||
@@ -98,6 +98,7 @@ Everything in this table is **public API**.
|
||||
| Wall body (thickness) | `path` (SVG) | `wall` | `data-id` = segment key, `data-kind` = `shared` \| `outer` | `.wallbody` |
|
||||
| Independent partition | `path` (SVG editor hit target) | `partition` | `data-id` = partition id, `data-kind` = `partition` | `.physical-hit` |
|
||||
| Wall column | `path` / `circle` (SVG editor hit target) | `wall-column` | `data-id` = column id, `data-kind` = `square` \| `circle` | `.physical-hit` |
|
||||
| Stair | `g` (SVG) | `stair` | `data-id` = stair id, `data-kind` = `straight` \| `spiral`, `data-target-state` = `active` \| `missing` \| `self` \| `deleted` \| `fixed` | `.hp-stair` |
|
||||
| Decor shape | `line` / `rect` / `ellipse` / `text` (SVG) | `decor` | `data-id` = shape id, `data-kind` = `line` \| `rect` \| `ellipse` \| `text` | `.dshape` (`.dtext` on text); persisted colour/alpha are inline SVG attributes and therefore win over weak CSS selectors |
|
||||
| Furniture | `path` (SVG) | `decor` | `data-id` = shape id, `data-kind` = `furniture`, `data-symbol` = the symbol id (`sofa`, `toilet`, …) | `.dshape .dfurn` |
|
||||
| Floor / space tab | `button` (HTML, header) | `space-tab` | `data-id` = space id | `.tab` |
|
||||
|
||||
@@ -37,6 +37,8 @@ On phones, tablets, wall panels and HA Companion apps, the ordinary View must:
|
||||
tabs, zoom and one gear whose menu holds every other header action, each
|
||||
item a 44 px target (#616);
|
||||
- support convenient pan, pinch zoom and space switching;
|
||||
- treat a linked stair as a floor-navigation target only after a clean tap;
|
||||
pan, pinch, long press, swipe and cancellation tails must stay inert;
|
||||
- fit the whole plan after two clean taps on free scene background, while one
|
||||
tap on a room keeps the immediate room-fit action;
|
||||
- provide a touch path for essential information that desktop exposes through
|
||||
@@ -158,6 +160,11 @@ Desktop `Shift` bypasses that offer and constrains drawing to an exact 45° ray;
|
||||
touch has no separate modifier gesture. A pan, pinch, cancellation or second
|
||||
pointer never accepts a face, applies a small-gap repair or creates a room.
|
||||
|
||||
Stair placement and transforms remain best-effort editor interactions on
|
||||
touch, but the safety floor is strict: cancellation and navigation gestures do
|
||||
not create, move, save or follow a stair. A long press in View does not activate
|
||||
its target floor, and the next deliberate tap is re-armed immediately.
|
||||
|
||||
During a View/editor visual transition the moving stage is inert while the
|
||||
header tabs remain available. A pinch, cancelled pointer or synthetic click
|
||||
cannot operate stale geometry; leaving the editor is always a single safe
|
||||
|
||||
@@ -594,6 +594,7 @@ shape change it is retained only while it remains inside the room.
|
||||
| Walls | Continuous wall chain; offers rooms when it closes faces and finishes open chains as independent walls | Only a confirmed room has area | Positive thickness blocks light; zero thickness follows the space's dashed/solid policy | Partial room overlap is rejected; there is no separate Partition or Boundary drawing tool |
|
||||
| Column | Square or circular support | Does not change area | Blocks light inside its shape | One shape/size/rotation; not a wall or room |
|
||||
| Opening | Door, window or gate | Does not change area | Door/gate passage follows state; window may cast sun | Must fit completely on a suitable wall segment |
|
||||
| Stairs | Straight flight or one-turn spiral with automatic 30 cm treads and an ascent arrow | Subtracts only its footprint overlap from clean area | No effect on Glow, sun or walls | Lives on this floor only; a valid optional target makes it a View link |
|
||||
|
||||
Other operations edit existing geometry:
|
||||
|
||||
@@ -605,6 +606,16 @@ Other operations edit existing geometry:
|
||||
| Thickness | Changes one span or every wall of a room, including zero-thickness walls |
|
||||
| Delete room | Deletes the room after choosing whether its exclusive physical walls remain; shared walls always remain |
|
||||
|
||||
Choose **Stairs → Straight** or **Stairs → Spiral**, then click the plan. A
|
||||
selected stair moves and resizes smoothly like furniture; `Shift` snaps its
|
||||
rotation to 45°. It snaps to the visible physical face of a wall or flush to
|
||||
another stair, and **Optimize plans** preserves that exact continuous
|
||||
transform. Double click opens size, direction, angle and target-floor
|
||||
properties. In View a clean activation switches to the valid target and
|
||||
restores that floor's saved view; gesture tails, broken links and fixed-floor
|
||||
cards do nothing. The target floor is never changed automatically. In 2.5D the
|
||||
symbol is flat on the floor. See [Stairs](STAIRS.md).
|
||||
|
||||

|
||||
|
||||
Deleting a room also clears that exact room from direct device assignments and
|
||||
|
||||
@@ -779,6 +779,7 @@ Undo оптимизации.
|
||||
| Стены | Непрерывную цепочку стен; при замыкании предлагает комнаты, при выходе сохраняет независимые стены | Площадь появляется только у подтверждённой комнаты | Положительная толщина блокирует свет; нулевая следует настройке пространства | Частичное перекрытие комнат запрещено; отдельных инструментов «Перегородка» и «Граница» нет |
|
||||
| Колонна | Квадратную или круглую опору | Не меняет площадь комнаты | Блокирует свет внутри своей формы | Имеет одну форму/размер/поворот, но не является стеной или комнатой |
|
||||
| Проём | Дверь, окно, открытый проём или ворота на стене комнаты либо законченном независимом отрезке | Не меняет площадь | Дверь/ворота пропускают свет между полами, открытый проём — всегда; только наружное окно комнаты может давать солнечный луч | Должен целиком помещаться на одном подходящем отрезке стены |
|
||||
| Лестница | Прямой марш или один оборот винтовой лестницы с автоматическим шагом ступеней 30 см и стрелкой подъёма | Вычитает из чистой площади только пересечение своего габарита | Не влияет на Glow, солнце и стены | Существует только на этом этаже; необязательная корректная цель превращает её в ссылку в Просмотре |
|
||||
|
||||
Остальные операции меняют уже созданную геометрию:
|
||||
|
||||
@@ -790,6 +791,17 @@ Undo оптимизации.
|
||||
| Толщина | Задаёт толщину 0–100 см выбранному участку или всем стенам комнаты |
|
||||
| Удалить комнату | Открывает выбор: удалить комнату и оставить её физические стены либо удалить комнату вместе с ними; общие стены остаются всегда |
|
||||
|
||||
Выберите **Лестница → Прямая** или **Лестница → Винтовая**, затем кликните по
|
||||
плану. Выбранная лестница перемещается и меняет размер плавно, как мебель;
|
||||
`Shift` привязывает поворот к 45°. Магнит ставит её к видимой физической грани
|
||||
стены или вплотную к другой лестнице, а **Оптимизировать планы** сохраняет этот
|
||||
continuous-transform без привязки к сетке. Двойной клик открывает размеры,
|
||||
направление подъёма, угол и целевой этаж. В Просмотре чистый клик переходит на
|
||||
корректную цель и восстанавливает сохранённый вид этажа; хвост жеста, битая
|
||||
ссылка и карточка с закреплённым этажом ничего не делают. На целевом этаже
|
||||
объект автоматически не создаётся. В 2.5D символ остаётся плоским на полу.
|
||||
Подробный контракт — в [документе о лестницах](STAIRS.md).
|
||||
|
||||
При варианте **«Удалить комнату, оставить стены»** эксклюзивные участки
|
||||
положительной толщины становятся обычными независимыми перегородками с той же
|
||||
толщиной, а их двери/окна перепривязываются к ним. Нулевые участки сохраняются
|
||||
|
||||
@@ -269,6 +269,11 @@ layer you cannot see is a layer you cannot edit.
|
||||
- Door, window, gate and passage may be hosted by one finished independent wall
|
||||
segment. Drafts and columns are never opening targets. Missing hosts fail
|
||||
dark and expose a rebind action only in Plan.
|
||||
- **Stairs** places a straight flight or a one-turn spiral as a separate Plan
|
||||
object. It uses furniture-like continuous move/resize/rotation and physical
|
||||
wall/stair magnet rather than the grid-bound wall contract. Its optional
|
||||
one-way target is edited in properties; in View only a clean activation of a
|
||||
valid target switches floors. The target floor is never modified.
|
||||
- **Select** is the only mode in which these objects intercept input. It offers
|
||||
rigid grid-bound drag, double-click/tap properties, Delete, and a rotate
|
||||
handle for square columns (5° steps; Shift is free). Draft Delete removes the
|
||||
|
||||
@@ -43,6 +43,7 @@
|
||||
"rules",
|
||||
"settings",
|
||||
"space",
|
||||
"stairs",
|
||||
"summary",
|
||||
"support",
|
||||
"vacuum"
|
||||
@@ -156,6 +157,11 @@
|
||||
"since": "1.59.0-beta.3",
|
||||
"audience": ["styling", "test"]
|
||||
},
|
||||
"stair": {
|
||||
"elements": ["g"],
|
||||
"since": "1.78.0-beta.5",
|
||||
"audience": ["styling", "test"]
|
||||
},
|
||||
"support": {
|
||||
"elements": ["button"],
|
||||
"since": "1.73.0-beta.7",
|
||||
@@ -193,6 +199,7 @@
|
||||
"resize",
|
||||
"select",
|
||||
"split",
|
||||
"stairs",
|
||||
"text",
|
||||
"wall-thickness"
|
||||
]
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"fixture": "synthetic-only",
|
||||
"chromium": "151.0.7922.34",
|
||||
"oxipng": null,
|
||||
"sourceFingerprint": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceFingerprint": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"captureScriptSha256": "e2d14d89de793011615662af7c83c433768d4761f6cec7f0b3860c797494299e",
|
||||
"command": "npm run build && node demo/docs/capture.mjs",
|
||||
"scenarios": {
|
||||
@@ -15,7 +15,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "1bde1bff8d4ab5f197320b54ef57186b3c07cf2121d5414ada63ce357826bfa8"
|
||||
},
|
||||
"view-touch": {
|
||||
@@ -26,7 +26,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "f9dd5b54f86b814c00bc84149af84485f052b103cdcc9263b5c50bf5d32c69d6"
|
||||
},
|
||||
"space-create": {
|
||||
@@ -37,7 +37,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "aab4811bba3afa6cc849cb9d3989d126b8c327b69a2f8f853e55fc077e0e9a1b"
|
||||
},
|
||||
"room-contour-close": {
|
||||
@@ -48,7 +48,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "e106ff9db6c96adb08beba12cc299a88ac5fa47c079be316f185e5657bc656f0"
|
||||
},
|
||||
"plan-context-tray": {
|
||||
@@ -59,7 +59,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "9b0db923fa7c8aff783b5c7050ee5b410b1b04df81a9e48bbc8111a7d0d47e76"
|
||||
},
|
||||
"device-editor": {
|
||||
@@ -70,7 +70,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "198c084c0a45aa3afdf79181b80d8bb0347c95f3248b4fac9e05d69eb8a35f8f"
|
||||
},
|
||||
"device-display-preview": {
|
||||
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "e9b88d65dca74133646aa849d47bc09ad85eb8b16a168c4df6930e8f5856b5f5"
|
||||
},
|
||||
"background-editor": {
|
||||
@@ -92,7 +92,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "44beadd61365ac1730c1efde846e528bfe92d8935fd167f1b6bf3bbad6af8f33"
|
||||
},
|
||||
"room-card": {
|
||||
@@ -103,7 +103,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "d47988b03e6a078508b27b5612b6eafe8ecc33c891b589ddda1cc7c71f43b7c8"
|
||||
},
|
||||
"device-info": {
|
||||
@@ -114,7 +114,7 @@
|
||||
},
|
||||
"theme": "dark",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "4ec8c6df671742b90ca55222917076c47c5035a6df0587282e60873c0ce5f64e"
|
||||
},
|
||||
"pdf-export": {
|
||||
@@ -125,7 +125,7 @@
|
||||
},
|
||||
"theme": "light",
|
||||
"language": "en",
|
||||
"sourceSha256": "25eae6908d0b7e5b154910505e483bc772e2f0406fed852c21b6ee910808a383",
|
||||
"sourceSha256": "fcc2617295be1d37facbd00dea5df81fc5d3d11605b97f23da563a25df22425e",
|
||||
"imageSha256": "ad3d735135b180ce015c9cda07fdcec08d7c8707abe0665734ef7b450a8a7093"
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user