From 024d554a4ba8816d239a663f0a1c3167d07d0d64 Mon Sep 17 00:00:00 2001 From: Wassim SAMAD Date: Fri, 14 Aug 2026 10:15:21 +0200 Subject: [PATCH 1/2] fix(editor): drop the stale 6 m caps left over from the 20 m storey raise MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `#642` raised the room-envelope caps from 6 m to 20 m but missed two sliders, so a tall storey is still unusable in practice: - ceiling panel's non-level-parent fallback stayed at 6 m while `definition.ts` uses `POSITIVE_INFINITY` for the same case — the panel and the 3D drag handle disagreed on the same bound. - slab elevation (Surface/Floor and Base/Rim) stayed at 6 m, so a slab could not be raised past 6 m inside a 20 m level. `clampSlabElevation` in the write path is the real bound; the slider was just a UI ceiling. Co-Authored-By: Claude Opus 5 (1M context) --- packages/nodes/src/ceiling/panel.tsx | 2 +- packages/nodes/src/slab/panel.tsx | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nodes/src/ceiling/panel.tsx b/packages/nodes/src/ceiling/panel.tsx index 210976f8c3..7a5124d34d 100644 --- a/packages/nodes/src/ceiling/panel.tsx +++ b/packages/nodes/src/ceiling/panel.tsx @@ -55,7 +55,7 @@ export function CeilingPanel() { const parent = node?.parentId ? s.nodes[node.parentId as AnyNode['id']] : undefined return parent?.type === 'level' ? getCeilingClampBound(parent.id, s.nodes, node?.polygon ?? []) - : 6 + : Number.POSITIVE_INFINITY }) // Effective height: the stored custom height, or — for follows-mode diff --git a/packages/nodes/src/slab/panel.tsx b/packages/nodes/src/slab/panel.tsx index 07e88ade22..b582b3ca97 100644 --- a/packages/nodes/src/slab/panel.tsx +++ b/packages/nodes/src/slab/panel.tsx @@ -279,9 +279,11 @@ export function SlabPanel() { width={320} > + {/* Range mirrors the 20 m storey cap; `clampSlabElevation` in the + write path stays the real bound against the level. */} Date: Fri, 14 Aug 2026 10:23:01 +0200 Subject: [PATCH 2/2] fix(editor): make the ceiling's level constraint visible instead of silent MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A ceiling's cap is the storey plane (`getCeilingClampBound`), so on a stock 2.5 m level it is 2.49 m — which means the "Standard (2.5m)" and "High (3.0m)" presets clamped silently and read as dead buttons, with nothing pointing at the level height as the real gate. Presets taller than the level are now disabled with the available height in their tooltip, and the Height section names the bound. The clamp itself is unchanged: a ceiling still never pokes through its own storey. Co-Authored-By: Claude Opus 5 (1M context) --- packages/nodes/src/ceiling/panel.tsx | 34 +++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/packages/nodes/src/ceiling/panel.tsx b/packages/nodes/src/ceiling/panel.tsx index 7a5124d34d..c3cb2cb809 100644 --- a/packages/nodes/src/ceiling/panel.tsx +++ b/packages/nodes/src/ceiling/panel.tsx @@ -271,16 +271,34 @@ export function CeilingPanel() { )} {/* Presets write an explicit height (clamped to the bound), so - clicking one on a follows-mode ceiling switches it to custom. */} + clicking one on a follows-mode ceiling switches it to custom. + A preset taller than the storey would clamp silently and look + like a dead button — disable it and name the real gate instead. */}
- {heightPresets.map((preset) => ( - handleHeightChange(preset.height)} - /> - ))} + {heightPresets.map((preset) => { + const fits = preset.height <= maxHeight + return ( + handleHeightChange(preset.height)} + title={ + fits + ? undefined + : `Taller than this level (${formatLinearMeasurement(maxHeight, unit, metricNotation)} available). Raise the level height first.` + } + /> + ) + })}
+ {Number.isFinite(maxHeight) && ( +
+ Limited by the level to {formatLinearMeasurement(maxHeight, unit, metricNotation)} — + raise the level height for a taller ceiling. +
+ )}