From 8237bbc1ccd08214f3d858cbf1855a1c8c8d29e2 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <209825114+claude[bot]@users.noreply.github.com> Date: Fri, 2 Oct 2026 11:29:25 +0300 Subject: [PATCH] feat(card): LED strips in the 2.5D View (#780) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Stage 3c of #780 (ТЗ §7). In the volumetric View the stripe is raised like a device tile: body lifted by ISO_TILE.lift (0.075 D), the edge swept ISO_TILE.depth (0.1 D) below it in isoEdgeColor, an inert blurred floor shadow from isoTileShadow for the current theme and floor; D takes the shared ISO_ICON_SCALE. The field stays on the floor plane, the hit path moves with the raised body, everything is in plan units so zoom cannot detach it. Editors and the static card keep Flat. Issue: #780 User-Visible: no --- src/led-strip-runtime.ts | 48 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/led-strip-runtime.ts b/src/led-strip-runtime.ts index 0075cbf1..4de28c22 100755 --- a/src/led-strip-runtime.ts +++ b/src/led-strip-runtime.ts @@ -22,6 +22,8 @@ import { } from './glow-scene'; import { NORM_W, iconUnit } from './space-geometry'; import { roomGlowOf, roomPoly } from './logic'; +import { ISO_ICON_SCALE, ISO_TILE, isoEdgeColor, isoTileShadow } from './iso-tiles'; +import { deviceThemeClass } from './device-face'; import type { VirtualLightSnapshot } from './virtual-light-state'; import { geometryAllRings, pointInOpaquePlanBody } from './physical-geometry'; import { @@ -131,8 +133,19 @@ export interface LedHandlers { label: (d: DevItem) => string; } +/** 2.5D View (ТЗ §7): the stripe raised like a tile, its edge and floor shadow. */ +export interface LedIsoStyle { + /** Raise of the stripe, plan units: ISO_TILE.lift × D (0.075 D). */ + lift: number; + /** Visible edge below the raised stripe: ISO_TILE.depth × D (0.1 D). */ + depth: number; + edge: string; + shadow: { dx: number; dy: number; sigma: number; opacity: number }; +} + export interface LedStripeInput { views: readonly LedStripView[]; + iso?: LedIsoStyle | null; /** Base device diameter D in plan units (icon_size of this card × iconUnit). */ d: number; faces: FaceContext | null; @@ -183,7 +196,12 @@ export function renderLedStripes(input: LedStripeInput): TemplateResult { const h = input.handlers; // Smaller ids last: an exact overlap of hit paths resolves to the stable id. const ordered = [...input.views].sort((a, b) => (a.strip.id < b.strip.id ? 1 : a.strip.id > b.strip.id ? -1 : 0)); - return svg` + const iso = input.iso; + return svg` + ${iso ? svg` + ` : nothing}