mirror of
https://github.com/Matysh/houseplan-card
synced 2026-10-01 12:18:51 +00:00
Встроенная библиотека мебели была смешанной: 44 предмета рисовал дизайнер, а 12 — код, прямоугольниками и эллипсами в unit box. Они выбивались из стиля, и три категории меню (`computer`, `hood`, `oven`) вообще не открывались, потому что вида сверху для них не было. Пакет 0.4.0 перерисовывает все 56 существующих публичных ID и добавляет четыре новых: `computer`, `hood`, `oven`, `cactus`. Каталог становится равен поставке: 60 символов, 32 непустые категории. Совместимость. Ни один сохранённый план не мигрирует: положение, размер, поворот, отражение, цвет, прозрачность и толщина линии не трогаются, а default-размеры всех 56 прежних ID совпадают со старыми до числа — таблица зашита в `test/furniture.test.mjs`, чтобы сдвиг было видно тестом, а не глазами. Ловушка, ради которой примитивы удалены целиком. Библиотека собиралась союзом каталога и `LEGACY_FURNITURE`, и обе половины несли ОДНИ И ТЕ ЖЕ публичные ID. `BY_ID` — это `Map`, она оставляет последнюю запись, поэтому примитив молча побеждал дизайнерский рисунок, который его заменял: задача выглядит выполненной, 12 предметов не обновились, ни один существующий тест этого не видит. Поэтому `LEGACY_FURNITURE`, `RETAINED_IDS`, тип `Prim`, `box()` и `primitivePathD` удалены, а на дубликаты в каталоге стоит тест и мутант. Два продуктовых решения владельца (#593): - `cactus` живёт в категории `plant`, а не `exercise`, как предлагал пакет: плитка «Тренажёр» рисует тренажёр, и открывать её на кактус — врать о содержимом палитры. `exercise` остаётся скрытой пустой категорией, непустых становится 32, а не 33; - при отказе ленивого чанка с рисунками не рисуется НИЧЕГО. Прежде 12 примитивов рисовались всегда, и `docs/FURNITURE.md` это обещал; обещание снято. Это единственное место, где задача ухудшает наблюдаемое поведение, и оно проверяется смоком, а не словом. Бюджеты. Ревью ТЗ показало, что «бюджет ленивого графа защищён» было заявлением без гейта: размеры печатались в отчёт и ни с чем не сравнивались. Добавлены `lazyGraphCeilingViolation` и два настоящих потолка со своим мутантом. Стартовый граф ушёл ниже полосы, поэтому `INITIAL_VIEW_GZIP_CEILING` опущен 292 400 → 291 400 — вторая половина храповика, без которой выигрыш отыграется. Провенанс. Документ пакета воссоздан под 0.4.0: грант владельца, имя архива и его SHA-256. Это единственная исполнимая защита от повторения истории #159, и она не ослаблена — число проверок в тесте не уменьшилось, а мутант подменяет хеш и обязан её покраснить. Свидетели: пять новых мутантов, новая golden-сцена `furniture-new-symbols-light` для четырёх новых ID, матрица 63 → 64. Шестой мутант правится, а не добавляется: `furniture-placement-needs-art` ссылался на удалённое поле `g` и переставал компилироваться — раннер честно отличал это от «пойман» и отчитывался setup-failure. Ложь мутанта осталась прежней по смыслу, убрана только ветка про примитив. i18n: 7 ключей × 4 локали. `furn.cat_exercise` не добавлен — категория скрыта. Issue: #593 User-Visible: yes
1176 lines
68 KiB
JavaScript
1176 lines
68 KiB
JavaScript
import { fixtureWallKey } from '../fixtures/visual-matrix.mjs';
|
|
|
|
/** Data-only HP-QA-01 capture matrix. Bump when framing or scenarios change. */
|
|
export const GOLDEN_MATRIX_VERSION = 64;
|
|
|
|
const stage = { capture: 'stage', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.0005 } };
|
|
const page = { capture: 'page', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.0008 } };
|
|
const sunWindow = { capture: 'sun-window', threshold: { maxChannelDelta: 10, maxDiffRatio: 0.001 } };
|
|
const openingRoomContract = {
|
|
kind: 'room', wallCm: 30, surface: 'flat',
|
|
openings: [
|
|
{ id: 'golden-centred-door', type: 'door', at: 0.25, length: 0.10,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-centred-window', type: 'window', at: 0.50, length: 0.10,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-centred-gate', type: 'gate', at: 0.75, length: 0.10,
|
|
flipV: false, offset: 'center' },
|
|
],
|
|
};
|
|
|
|
const openingPartitionContract = {
|
|
kind: 'partition', wallCm: 30, surface: 'flat',
|
|
a: [0.14, 0.22], b: [0.86, 0.78],
|
|
openings: [
|
|
{ id: 'golden-diagonal-door', type: 'door', at: 0.22, length: 0.09,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-diagonal-window', type: 'window', at: 0.50, length: 0.09,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-diagonal-gate', type: 'gate', at: 0.78, length: 0.09,
|
|
flipV: false, offset: 'center' },
|
|
],
|
|
};
|
|
|
|
const openingFlipContract = {
|
|
kind: 'room', wallCm: 30, surface: 'flat',
|
|
openings: [
|
|
{ id: 'golden-door-default', type: 'door', at: 0.16, length: 0.08,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-door-flipped', type: 'door', at: 0.30, length: 0.08,
|
|
flipV: true, offset: 'center' },
|
|
{ id: 'golden-window-default', type: 'window', at: 0.44, length: 0.08,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-window-flipped', type: 'window', at: 0.58, length: 0.08,
|
|
flipV: true, offset: 'center' },
|
|
{ id: 'golden-gate-default', type: 'gate', at: 0.72, length: 0.08,
|
|
flipV: false, offset: 'center', turnPair: 'golden-gate-turn' },
|
|
{ id: 'golden-gate-flipped', type: 'gate', at: 0.86, length: 0.08,
|
|
flipV: true, offset: 'center', turnPair: 'golden-gate-turn' },
|
|
],
|
|
};
|
|
|
|
const openingIsoContract = {
|
|
kind: 'room', wallCm: 30, surface: 'iso',
|
|
openings: [
|
|
{ id: 'golden-iso-door', type: 'door', at: 0.20, length: 0.09,
|
|
flipV: false, offset: 'selected-face' },
|
|
{ id: 'golden-iso-window', type: 'window', at: 0.40, length: 0.09,
|
|
flipV: false, offset: 'center' },
|
|
{ id: 'golden-iso-gate-default', type: 'gate', at: 0.62, length: 0.09,
|
|
flipV: false, offset: 'selected-face', turnPair: 'golden-iso-gate-turn' },
|
|
{ id: 'golden-iso-gate-flipped', type: 'gate', at: 0.82, length: 0.09,
|
|
flipV: true, offset: 'selected-face', turnPair: 'golden-iso-gate-turn' },
|
|
],
|
|
};
|
|
|
|
const stage3DenseMarkers = [
|
|
{ id: 'golden-light-one', binding: 'device:golden-light-one', value_badge: {
|
|
enabled: true,
|
|
source: { kind: 'entity_state', entity_id: 'light.golden_light_one' },
|
|
position: 'right',
|
|
} },
|
|
{ id: 'golden-light-two', binding: 'device:golden-light-two' },
|
|
{ id: 'golden-presence', binding: 'device:golden-presence', display: 'icon_ripple' },
|
|
{ id: 'golden-climate', binding: 'device:golden-climate', value_badge: {
|
|
enabled: true,
|
|
source: {
|
|
kind: 'entity_attribute', entity_id: 'climate.golden_climate',
|
|
attribute: 'current_temperature',
|
|
},
|
|
position: 'top',
|
|
} },
|
|
{ id: 'golden-left-linkquality', binding: 'device:golden-left-linkquality', value_badge: {
|
|
enabled: true,
|
|
source: { kind: 'entity_state', entity_id: 'sensor.golden_left_linkquality' },
|
|
position: 'bottom',
|
|
} },
|
|
{ id: 'golden-right-linkquality', binding: 'device:golden-right-linkquality' },
|
|
];
|
|
|
|
const stage3DenseLayout = {
|
|
'golden-light-one': { s: 'golden-lighting', x: 0.487, y: 0.22 },
|
|
'golden-light-two': { s: 'golden-lighting', x: 0.43, y: 0.76 },
|
|
'golden-presence': { s: 'golden-lighting', x: 0.513, y: 0.22 },
|
|
'golden-climate': { s: 'golden-lighting', x: 0.56, y: 0.64 },
|
|
'golden-left-linkquality': { s: 'golden-lighting', x: 0.487, y: 0.43 },
|
|
'golden-right-linkquality': { s: 'golden-lighting', x: 0.513, y: 0.76 },
|
|
};
|
|
|
|
const stage3VacuumTrail = {
|
|
maxDeviationCm: 17.5,
|
|
current: [
|
|
[[180, 220], [360, 220], [360, 420], [520, 420]],
|
|
[[650, 240], [780, 240], [780, 500], [650, 620], [850, 760]],
|
|
],
|
|
previous: [[160, 760], [300, 650], [420, 740], [560, 600]],
|
|
};
|
|
|
|
const stage3RequiredOverlays = ['device', 'room-label', 'opening-lock'];
|
|
|
|
/** Exact existing baseline impact measured against origin/dev with the same
|
|
* Chromium build. Keep this list reviewable: shared visual fixtures make an
|
|
* opening-only change visible in editor/dialog captures too. */
|
|
export const OPENING_SYMBOL_EXISTING_GOLDEN_IMPACT = Object.freeze([
|
|
'isometric-geometry-view-dark',
|
|
'isometric-geometry-view-light',
|
|
'isometric-live-layers-dark',
|
|
'isometric-no-borders-dark',
|
|
'isometric-touch-kiosk-dark',
|
|
'isometric-large-warm-remount-dark',
|
|
'geometry-view-dark-fit',
|
|
'geometry-view-light-fit',
|
|
'room-label-parity-view-dark',
|
|
'room-label-parity-plan-dark',
|
|
'room-label-parity-view-light',
|
|
'room-label-parity-plan-light',
|
|
'day-cycle-dawn-dark',
|
|
'day-cycle-day-dark',
|
|
'day-cycle-dusk-dark',
|
|
'day-cycle-night-dark',
|
|
'geometry-plan-editor-dark',
|
|
'space-tab-drop-before-light',
|
|
'space-tab-drop-after-dark',
|
|
'plan-snap-endpoint-light',
|
|
'plan-snap-line-gaps-dark',
|
|
'junction-patch-resilience-plan-dark',
|
|
'opening-placement-door-thick-wall-dark',
|
|
'opening-placement-passage-thick-wall-dark',
|
|
'opening-placement-passage-thick-wall-light',
|
|
'geometry-devices-editor-dark',
|
|
'geometry-decor-editor-dark',
|
|
'tray-wide-selection-en',
|
|
'tray-wide-tool-ru',
|
|
'tray-medium-group-en',
|
|
'tray-medium-selection-ru',
|
|
'tray-narrow-palette-en',
|
|
'tray-narrow-tool-ru',
|
|
'geometry-diagonal-45-opening-dark',
|
|
'openings-thick-wall-dark',
|
|
'lighting-glow-sun-dark',
|
|
'device-value-badge-positions-dark',
|
|
'device-icon-state-table-light',
|
|
'device-icon-state-table-dark',
|
|
'device-text-shell-long-light',
|
|
'device-text-shell-long-dark',
|
|
'lighting-sun-window-state-only-dark',
|
|
'lighting-fill-light-axis-split-dark',
|
|
'lighting-fill-temp-axis-split-dark',
|
|
'lighting-fill-lqi-axis-split-dark',
|
|
'lighting-temp-glow-dark',
|
|
'lighting-temp-glow-light',
|
|
'lighting-custom-glow-dark',
|
|
'lighting-opaque-glow-two-doorways-dark',
|
|
'lighting-custom-glow-light',
|
|
'lighting-temp-glow-no-sources-dark',
|
|
'lighting-temp-glow-room-override-dark',
|
|
'lighting-manual-auto-spill-overlap-dark',
|
|
'hover-over-glow-dark',
|
|
'hover-nested-room-dark',
|
|
'large-house-zoom-040-dark',
|
|
'large-house-zoom-250-dark',
|
|
'large-house-warm-remount-dark',
|
|
'device-dialog-desktop-en',
|
|
'device-help-popover-light-ru',
|
|
'decor-color-popover-desktop-en',
|
|
'general-color-popover-desktop-en',
|
|
'space-room-color-popover-desktop-ru',
|
|
'backup-full-preview-desktop-en',
|
|
'backup-plan-only-export-desktop-en',
|
|
'optimize-preflight-dialog-dark-en',
|
|
'optimize-preflight-dialog-light-ru',
|
|
]);
|
|
|
|
const decorLayerFixture = [
|
|
{ id: 'golden-decor-axis', kind: 'line', x1: 0.10, y1: 0.54, x2: 0.90, y2: 0.54,
|
|
color: '#ff0033', opacity: 1, width_cm: 8 },
|
|
{ id: 'golden-decor-rect', kind: 'rect', x: 0.15, y: 0.28, w: 0.16, h: 0.12,
|
|
color: '#ff0033', opacity: 1, width_cm: 2, fill: true,
|
|
fill_color: '#ff6680', fill_opacity: 1 },
|
|
{ id: 'golden-decor-ellipse', kind: 'ellipse', x: 0.69, y: 0.28, w: 0.16, h: 0.12,
|
|
color: '#ff0033', opacity: 1, width_cm: 2, fill: true,
|
|
fill_color: '#ff6680', fill_opacity: 1 },
|
|
{ id: 'golden-decor-text', kind: 'text', x: 0.24, y: 0.72, text: 'DECOR',
|
|
color: '#ff0033', opacity: 1, size_cm: 14 },
|
|
{ id: 'golden-decor-sofa', kind: 'furniture', symbol: 'sofa',
|
|
x: 0.68, y: 0.66, w: 0.18, h: 0.13, color: '#ff0033', opacity: 1, width_cm: 2 },
|
|
];
|
|
const decorLayerProbes = {
|
|
color: '#ff0033', radius: 2, minMatchingFraction: 0.6,
|
|
points: [
|
|
{ id: 'left-room', x: 0.25, y: 0.54 },
|
|
{ id: 'opening-tunnel', x: 0.50, y: 0.54 },
|
|
{ id: 'right-room', x: 0.75, y: 0.54 },
|
|
],
|
|
};
|
|
|
|
export const GOLDEN_SCENARIOS = Object.freeze([
|
|
// #486 AC7: the custom HA panel owns the full viewport. These three focused
|
|
// frames pin its populated View, its Plan-editor chrome and the deliberately
|
|
// inert read-only first-run state without duplicating the card matrix below.
|
|
{ id: 'panel-wide-view-light-en', fixture: 'visual', space: 'golden-geometry',
|
|
panelHost: true, mode: 'view', language: 'en', theme: 'light',
|
|
viewport: { width: 1280, height: 800 }, ...page },
|
|
{ id: 'panel-wide-plan-editor-dark-en', fixture: 'visual', space: 'golden-geometry',
|
|
panelHost: true, mode: 'plan', language: 'en', theme: 'dark',
|
|
viewport: { width: 1280, height: 800 }, ...page },
|
|
{ id: 'panel-narrow-read-only-empty-light-en', fixture: 'visual',
|
|
panelHost: true, narrow: true, emptyPlan: true, canWrite: false, userIsAdmin: false,
|
|
preloadEditorRuntime: false, mode: 'view', language: 'en', theme: 'light',
|
|
viewport: { width: 320, height: 720 }, ...page },
|
|
// #462 AC12: the card-level version recovery notice must stay compact,
|
|
// readable and outside layout/fit flow on desktop, narrow touch and the
|
|
// manual-only kiosk state after this tab already attempted the target.
|
|
{ id: 'version-mismatch-desktop-dark-en', fixture: 'visual', space: 'golden-geometry',
|
|
mode: 'view', integrationVersion: '0.0.0-golden-backend',
|
|
language: 'en', theme: 'dark', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'version-mismatch-touch-light-ru', fixture: 'visual', space: 'golden-geometry',
|
|
mode: 'view', integrationVersion: '0.0.0-golden-backend', touchViewport: true,
|
|
language: 'ru', theme: 'light', viewport: { width: 390, height: 760 }, ...page },
|
|
{ id: 'version-mismatch-kiosk-attempted-dark-de', fixture: 'visual', space: 'golden-geometry',
|
|
mode: 'view', integrationVersion: '0.0.0-golden-backend',
|
|
versionRecoveryAttempted: true, kiosk: true,
|
|
language: 'de', theme: 'dark', viewport: { width: 820, height: 760 }, ...page },
|
|
{ id: 'hidden-wall-diagnostics-plan-light', fixture: 'visual',
|
|
space: 'golden-coincident-partition', coincidentPartition: 'before',
|
|
hiddenWallDiagnostics: true, mode: 'plan', theme: 'light',
|
|
viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'hidden-wall-diagnostics-plan-dark', fixture: 'visual',
|
|
space: 'golden-coincident-partition', coincidentPartition: 'before',
|
|
hiddenWallDiagnostics: true, mode: 'plan', theme: 'dark',
|
|
viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'coincident-partition-before-dark', fixture: 'visual',
|
|
space: 'golden-coincident-partition', coincidentPartition: 'before',
|
|
mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'coincident-partition-thin-dark', fixture: 'visual',
|
|
space: 'golden-coincident-partition', coincidentPartition: 'thin',
|
|
mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'coincident-partition-thick-dark', fixture: 'visual',
|
|
space: 'golden-coincident-partition', coincidentPartition: 'thick',
|
|
mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'coincident-partition-virtual-dark', fixture: 'visual',
|
|
space: 'golden-coincident-partition', coincidentPartition: 'virtual',
|
|
mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
// #316 §3.1: a legacy span over a wall with a door — after the migration the
|
|
// door keeps its carrying atom while the border is zero on both sides.
|
|
{ id: 'span-over-door-migrated-dark', fixture: 'visual',
|
|
space: 'golden-span-over-door', spanOverDoor: true,
|
|
mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'split-corner-wall-before-dark', fixture: 'visual', space: 'golden-corner-split',
|
|
cornerSplitWall: 'before', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'split-corner-wall-thin-dark', fixture: 'visual', space: 'golden-corner-split',
|
|
cornerSplitWall: 'thin', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'split-corner-wall-thick-dark', fixture: 'visual', space: 'golden-corner-split',
|
|
cornerSplitWall: 'thick', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'split-zero-divider-taper-dark', fixture: 'visual', space: 'golden-zero-divider',
|
|
cornerSplitWall: 'zero-taper', mode: 'view', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-geometry-view-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
// Stage 2 material/floor-edge plus door, window, gate and nested-room coverage.
|
|
alpha: true, projection: 'iso',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-geometry-view-light', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
alpha: true, projection: 'iso',
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-live-layers-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
alpha: true, projection: 'iso',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-no-borders-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
alpha: true, projection: 'iso', showBorders: false, fillMode: 'custom',
|
|
customFill: { c: '#486a8f', a: 0.42 }, glowEnabled: true,
|
|
stage3Golden: { noBorders: true },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-touch-kiosk-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
alpha: true, projection: 'iso', kiosk: true,
|
|
theme: 'dark', viewport: { width: 390, height: 760 }, ...stage },
|
|
{ id: 'isometric-large-warm-remount-dark', fixture: 'large', space: 'perf-floor-2', mode: 'view',
|
|
alpha: true, projection: 'iso', warmRemount: true,
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...stage },
|
|
...['light', 'dark'].map((theme) => ({
|
|
id: `isometric-stage3-overlays-${theme}`, fixture: 'visual',
|
|
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
|
|
stage3Fixture: {
|
|
roomMetrics: true, lockOpening: 'light-door', lockState: 'locked',
|
|
newDevice: 'golden-presence',
|
|
},
|
|
stage3Golden: {
|
|
requiredKinds: stage3RequiredOverlays, requireNudged: true,
|
|
requireMaterialDefs: true, maxMaterialDefs: 12,
|
|
requireVacuumFloor: theme === 'dark',
|
|
requireDenseFacets: true,
|
|
requireNoTetherCues: true,
|
|
requireNoGrounding: true,
|
|
requireLiveLayers: theme === 'dark',
|
|
},
|
|
markerOverrides: stage3DenseMarkers,
|
|
markerAreaSnapshot: {
|
|
'golden-light-one': { binding: 'device:golden-light-one', area: 'golden_light_left' },
|
|
'golden-light-two': { binding: 'device:golden-light-two', area: 'golden_light_left' },
|
|
'golden-presence': { binding: 'device:golden-presence', area: 'golden_light_right' },
|
|
'golden-climate': { binding: 'device:golden-climate', area: 'golden_light_right' },
|
|
'golden-left-linkquality': {
|
|
binding: 'device:golden-left-linkquality', area: 'golden_light_left',
|
|
},
|
|
'golden-right-linkquality': {
|
|
binding: 'device:golden-right-linkquality', area: 'golden_light_right',
|
|
},
|
|
},
|
|
stateOverrides: {
|
|
'light.golden_light_one': { attributes: { lqi: 40 } },
|
|
'light.golden_light_two': { attributes: { lqi: 120 } },
|
|
'sensor.golden_right_linkquality': { state: '210' },
|
|
...(theme === 'dark' ? {
|
|
'sun.sun': { attributes: { azimuth: 270, elevation: 24 } },
|
|
} : {}),
|
|
},
|
|
layoutOverrides: stage3DenseLayout,
|
|
...(theme === 'dark' ? {
|
|
vacuumTrail: stage3VacuumTrail,
|
|
fillMode: 'custom', customFill: { c: '#486a8f', a: 0.42 },
|
|
hoverRoom: 'light-left', decorOverride: decorLayerFixture,
|
|
glowEnabled: true, sunRays: true, northDeg: 90,
|
|
} : {}),
|
|
theme, viewport: { width: 1000, height: 900 }, ...stage,
|
|
})),
|
|
{ id: 'isometric-stage3-openings-dark', fixture: 'visual',
|
|
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
|
|
showNames: false, glowEnabled: false, sunRays: false,
|
|
stage3Fixture: { lockOpening: 'light-door', lockState: 'unlocked' },
|
|
extraOpenings: [{
|
|
id: 'stage3-passage', type: 'passage', x: 0.50, y: 0.30,
|
|
angle: 90, length: 0.12,
|
|
}],
|
|
stage3Golden: {
|
|
requiredKinds: ['device', 'opening-lock'],
|
|
requireMaterialDefs: true, maxMaterialDefs: 12,
|
|
openingKinds: ['door', 'window', 'gate'], requirePassage: true,
|
|
},
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-stage3-forced-colors-dark', fixture: 'visual',
|
|
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
|
|
forcedColors: true,
|
|
stage3Fixture: { roomMetrics: true, lockOpening: 'light-door', lockState: 'locked' },
|
|
stage3Golden: {
|
|
requiredKinds: stage3RequiredOverlays, requireNudged: true,
|
|
requireNoMaterialDefs: true, requireNoTetherCues: true, requireNoGrounding: true,
|
|
},
|
|
layoutOverrides: stage3DenseLayout,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-stage3-no-filter-dark', fixture: 'visual',
|
|
space: 'golden-lighting', mode: 'view', alpha: true, projection: 'iso',
|
|
disableIsoFilters: true,
|
|
stage3Fixture: { roomMetrics: true, lockOpening: 'light-door', lockState: 'locked' },
|
|
stage3Golden: {
|
|
requiredKinds: stage3RequiredOverlays, requireNudged: true,
|
|
requireNoMaterialDefs: true, requireNoTetherCues: true, requireNoGrounding: true,
|
|
},
|
|
layoutOverrides: stage3DenseLayout,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'geometry-view-dark-fit', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'geometry-view-light-fit', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'pdf-export-geometry-light', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
pdfExport: true, theme: 'light', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'pdf-export-polish-light', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
pdfExport: true, northDeg: 90,
|
|
// One almost-zero seam exercises duplicate collapse in the complete PDF
|
|
// pipeline; the zero-thickness bottom edge keeps that material contract in
|
|
// the reviewed frame without growing a second fixture family.
|
|
wallReplacements: [
|
|
{
|
|
match: { a: [0.06, 0.08], b: [0.48, 0.08] },
|
|
segments: [
|
|
{ key: fixtureWallKey([0.06, 0.08], [0.479999, 0.08]),
|
|
a: [0.06, 0.08], b: [0.479999, 0.08], cm: 10 },
|
|
{ key: fixtureWallKey([0.479999, 0.08], [0.48, 0.08]),
|
|
a: [0.479999, 0.08], b: [0.48, 0.08], cm: 10 },
|
|
],
|
|
},
|
|
{
|
|
match: { a: [0.06, 0.92], b: [0.48, 0.92] },
|
|
segments: [{ key: fixtureWallKey([0.06, 0.92], [0.48, 0.92]),
|
|
a: [0.06, 0.92], b: [0.48, 0.92], cm: 0 }],
|
|
},
|
|
],
|
|
pdfSemantic: {
|
|
minSceneInkPixels: 2_000,
|
|
minSceneCoverage: 0.20,
|
|
maxCenterOffsetMm: 3,
|
|
minSceneClearanceMm: 0.1,
|
|
minWallGrayPixels: 600,
|
|
maxWallGrayOutsideFieldRatio: 0.02,
|
|
minInteriorHatchPixels: 30,
|
|
opening: {
|
|
xFraction: (0.26 - 0.06) / (0.94 - 0.06),
|
|
controlOffsetFraction: 0.16,
|
|
halfWidthFraction: 0.025,
|
|
maxGrayRatio: 0.65,
|
|
minWhiteFraction: 0.40,
|
|
},
|
|
minCompassInkPixels: 60,
|
|
maxDimensionAxisErrorDeg: 0.5,
|
|
minRepeatedDimensionLabels: 1,
|
|
forbiddenText: ['wall', 'partition', 'door', 'window', 'gate'],
|
|
},
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'pdf-export-stepped-dimensions-light', fixture: 'visual',
|
|
space: 'golden-pdf-stepped', mode: 'view', pdfExport: true, pdfSteppedExterior: true,
|
|
pdfSemantic: {
|
|
minSceneInkPixels: 1_000,
|
|
minSceneCoverage: 0.15,
|
|
maxCenterOffsetMm: 3,
|
|
minSceneClearanceMm: 0.1,
|
|
minWallGrayPixels: 400,
|
|
maxWallGrayOutsideFieldRatio: 0.02,
|
|
minInteriorHatchPixels: 20,
|
|
minCompassInkPixels: 60,
|
|
maxDimensionAxisErrorDeg: 0.5,
|
|
minRepeatedDimensionLabels: 0,
|
|
requiredDimensionLabels: ['1.20 m', '2.40 m', '3.60 m', '3.75 m', '7.35 m', '9.75 m'],
|
|
forbiddenText: ['wall', 'partition', 'door', 'window', 'gate'],
|
|
},
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'vacuum-trail-smoothing-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
vacuumTrail: {
|
|
maxDeviationCm: 17.5,
|
|
current: [
|
|
[[180, 220], [360, 220], [360, 420], [520, 420]],
|
|
[[650, 240], [780, 240], [780, 500], [650, 620], [850, 760]],
|
|
],
|
|
previous: [[160, 760], [300, 650], [420, 740], [560, 600]],
|
|
},
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'room-label-parity-view-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
roomLabelParity: true, theme: 'dark', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'room-label-parity-plan-dark', fixture: 'visual', space: 'golden-lighting', mode: 'plan',
|
|
roomLabelParity: true, theme: 'dark', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'room-label-parity-view-light', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
roomLabelParity: true, theme: 'light', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'room-label-parity-plan-light', fixture: 'visual', space: 'golden-lighting', mode: 'plan',
|
|
roomLabelParity: true, theme: 'light', viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'washer-active-cycle-dark', fixture: 'visual', applianceLifecycle: true,
|
|
space: 'golden-appliance', mode: 'view',
|
|
stateOverrides: { 'sensor.golden_washer_status': { state: 'start' } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'washer-idle-cycle-dark', fixture: 'visual', applianceLifecycle: true,
|
|
space: 'golden-appliance', mode: 'view',
|
|
stateOverrides: { 'sensor.golden_washer_status': { state: 'done' } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'day-cycle-dawn-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
bgMode: 'daynight', dayCycle: { phase: 'dawn', top: '#aabdd1' },
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 95, elevation: -2, rising: true } } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'day-cycle-day-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
bgMode: 'daynight', dayCycle: { phase: 'day', top: '#dce9ef' },
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 180, elevation: 42, rising: false } } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'day-cycle-dusk-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
bgMode: 'daynight', dayCycle: { phase: 'dusk', top: '#48536c' },
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 265, elevation: -2, rising: false } } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'day-cycle-night-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
bgMode: 'daynight', dayCycle: { phase: 'night', top: '#111a27' },
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 0, elevation: -12, rising: false } } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'geometry-plan-editor-dark', fixture: 'visual', space: 'golden-geometry', mode: 'plan',
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'safe-resize-handles-clamp-light', fixture: 'visual', space: 'golden-safe-resize',
|
|
safeResizeFixture: true, safeResizePreview: true, iconSize: 0.8, mode: 'plan',
|
|
theme: 'light', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'safe-resize-handles-clamp-dark', fixture: 'visual', space: 'golden-safe-resize',
|
|
safeResizeFixture: true, safeResizePreview: true, iconSize: 0.8, mode: 'plan',
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'space-tab-drop-before-light', fixture: 'visual', applianceLifecycle: true,
|
|
space: 'golden-geometry', mode: 'plan', tabDrag: 'before',
|
|
theme: 'light', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'space-tab-drop-after-dark', fixture: 'visual', applianceLifecycle: true,
|
|
space: 'golden-geometry', mode: 'plan', tabDrag: 'after',
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'plan-snap-endpoint-light', fixture: 'visual', space: 'golden-geometry', mode: 'plan',
|
|
planSnap: { tool: 'draw', pointer: [0.48, 0.48], expectedKind: 'endpoint' },
|
|
theme: 'light', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'plan-snap-line-gaps-dark', fixture: 'visual', space: 'golden-geometry', mode: 'plan',
|
|
planSnap: {
|
|
tool: 'draw', anchor: [0.70, 0.455], pointer: [0.482, 0.455], expectedKind: 'line',
|
|
},
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'wall-junctions-plan-preview-light', fixture: 'visual',
|
|
space: 'golden-wall-junctions', wallJunctions: true, mode: 'plan',
|
|
wallJunctionPreview: {
|
|
path: [[0.16, 0.15], [0.38, 0.15]], pointer: [0.38, 0.25], cms: [12], cm: 24,
|
|
},
|
|
theme: 'light', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'wall-junctions-plan-t-dark', fixture: 'visual',
|
|
space: 'golden-wall-junctions', wallJunctions: true, mode: 'plan',
|
|
wallJunctionPreview: {
|
|
path: [[0.50, 0.54]], pointer: [0.50, 0.70], cms: [], cm: 24,
|
|
},
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'wall-junctions-view-dark', fixture: 'visual',
|
|
space: 'golden-wall-junctions', wallJunctions: true, mode: 'view',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'junction-patch-resilience-plan-dark', fixture: 'visual',
|
|
space: 'golden-junction-patch-resilience', junctionPatchResilience: true, mode: 'plan',
|
|
retainedWedgeProbe: [0.8955, 0.556],
|
|
absentWallProbes: [[0.420833333, 0.37625], [0.92, 0.348]],
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'junction-patch-resilience-view-dark', fixture: 'visual',
|
|
space: 'golden-junction-patch-resilience', junctionPatchResilience: true, mode: 'view',
|
|
retainedWedgeProbe: [0.8955, 0.556],
|
|
absentWallProbes: [[0.420833333, 0.37625], [0.92, 0.348]],
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'wall-union-isolation-view-light', fixture: 'visual',
|
|
space: 'golden-wall-union-isolation', wallUnionIsolation: true, mode: 'view',
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'wall-union-isolation-view-dark', fixture: 'visual',
|
|
space: 'golden-wall-union-isolation', wallUnionIsolation: true, mode: 'view',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'multiwall-junction-bevel-view-dark', fixture: 'visual',
|
|
space: 'golden-multiwall-junction', mode: 'view',
|
|
multiWallJunction: {
|
|
node: [0.329166667, 0.141666667], rays: 3,
|
|
// #302: the chamfer is strip-safe — this point sits in the overlap of
|
|
// two incident strips and must stay FILLED (it used to be discarded by
|
|
// the old subtractive bevel, which is exactly the hole class fixed).
|
|
retainedOverlapProbe: [0.3303808442725, 0.1488560107825],
|
|
// Product contract (#272): a bounded exterior bevel is allowed, but no
|
|
// empty component may remain trapped inside the continuous masonry.
|
|
enclosedHoles: 0,
|
|
},
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'orthogonal-strip-cell-5-view-dark', fixture: 'visual',
|
|
space: 'golden-orthogonal-strip-cell-5', mode: 'view',
|
|
orthogonalStripContainment: { caseId: 'cell-5-mixed-depth-t', minSamples: 300 },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'orthogonal-strip-cell-1-view-dark', fixture: 'visual',
|
|
space: 'golden-orthogonal-strip-cell-1', mode: 'view',
|
|
orthogonalStripContainment: { caseId: 'cell-1-thick-crossbar-t', minSamples: 300 },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'wall-key-roundtrip-view-dark', fixture: 'visual',
|
|
space: 'golden-wall-key-roundtrip', mode: 'view',
|
|
wallKeyRoundtrip: {
|
|
variant: 'affected',
|
|
node: [0.8875, 0.345833333],
|
|
incidentArm: [0.8875, 0.333833333],
|
|
},
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-wall-junctions-dark', fixture: 'visual',
|
|
space: 'golden-wall-junctions', wallJunctions: true, mode: 'view',
|
|
alpha: true, projection: 'iso',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'opening-placement-door-thick-wall-dark', fixture: 'visual', space: 'golden-geometry',
|
|
// The shared centre edge is a long 25 cm physical wall. It can contain the
|
|
// complete 90 cm door preset while still proving rotation, centreline
|
|
// placement and ruler geometry on a thick wall.
|
|
mode: 'plan', openingPreview: { type: 'door', pointer: [0.48, 0.65] },
|
|
openingPreviewPixels: { minPixels: 150, minInsideWallPixels: 8, minChannelDelta: 4 },
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'opening-placement-passage-thick-wall-dark', fixture: 'visual', space: 'golden-geometry',
|
|
mode: 'plan', openingPreview: { type: 'passage', pointer: [0.48, 0.65] },
|
|
openingPreviewPixels: { minPixels: 150, minInsideWallPixels: 8, minChannelDelta: 4 },
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'opening-placement-passage-thick-wall-light', fixture: 'visual', space: 'golden-geometry',
|
|
mode: 'plan', openingPreview: { type: 'passage', pointer: [0.48, 0.65] },
|
|
openingPreviewPixels: { minPixels: 150, minInsideWallPixels: 8, minChannelDelta: 4 },
|
|
theme: 'light', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'opening-symbol-room-wall-light', fixture: 'visual', space: 'golden-opening-symbols',
|
|
mode: 'view', openingSymbolContract: openingRoomContract,
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'opening-symbol-diagonal-partition-dark', fixture: 'visual', space: 'golden-opening-symbols',
|
|
mode: 'view', openingSymbolContract: openingPartitionContract,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'opening-symbol-flip-pairs-light', fixture: 'visual', space: 'golden-opening-symbols',
|
|
mode: 'view', openingSymbolContract: openingFlipContract,
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'isometric-opening-symbol-parity-dark', fixture: 'visual', space: 'golden-opening-symbols',
|
|
mode: 'view', alpha: true, projection: 'iso',
|
|
openingSymbolContract: openingIsoContract,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'geometry-devices-editor-dark', fixture: 'visual', space: 'golden-geometry', mode: 'devices',
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'device-inbox-desktop-en-light', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device-inbox', language: 'en', theme: 'light',
|
|
viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'device-inbox-desktop-ru-dark', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device-inbox', language: 'ru', theme: 'dark',
|
|
viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'device-inbox-narrow-ru-dark', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device-inbox', deviceInboxTab: 'hidden',
|
|
markerOverrides: [{ id: 'golden-light-two', binding: 'device:golden-light-two', hidden: true }],
|
|
language: 'ru', theme: 'dark', viewport: { width: 390, height: 900 }, ...page },
|
|
{ id: 'geometry-decor-editor-dark', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
theme: 'dark', viewport: { width: 1180, height: 900 }, ...page },
|
|
// HP-UX-11 visual contract: every adaptive width is captured in both
|
|
// languages while the six materially different tray contents are open.
|
|
{ id: 'tray-wide-selection-en', fixture: 'visual', space: 'golden-geometry', mode: 'plan',
|
|
editorTray: 'plan-selection', language: 'en', theme: 'dark',
|
|
viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'tray-wide-tool-ru', fixture: 'visual', space: 'golden-geometry', mode: 'plan',
|
|
editorTray: 'plan-tool', language: 'ru', theme: 'dark',
|
|
viewport: { width: 1180, height: 900 }, ...page },
|
|
{ id: 'tray-medium-group-en', fixture: 'visual', space: 'golden-geometry', mode: 'plan',
|
|
editorTray: 'group', language: 'en', theme: 'dark',
|
|
viewport: { width: 760, height: 820 }, ...page },
|
|
{ id: 'tray-medium-selection-ru', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
editorTray: 'decor-selection', language: 'ru', theme: 'dark',
|
|
viewport: { width: 760, height: 820 }, ...page },
|
|
{ id: 'tray-narrow-palette-en', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
editorTray: 'furniture-palette', furniturePalette: 'categories', language: 'en', theme: 'dark',
|
|
viewport: { width: 390, height: 760 }, ...page },
|
|
{ id: 'furniture-categories-light', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
furniturePalette: 'categories', language: 'ru', theme: 'light',
|
|
viewport: { width: 900, height: 820 }, ...page },
|
|
{ id: 'furniture-variants-dark', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
furniturePalette: 'variants', furnitureCategory: 'sofa', language: 'en', theme: 'dark',
|
|
viewport: { width: 900, height: 820 }, ...page },
|
|
{ id: 'furniture-variants-light', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
furniturePalette: 'variants', furnitureCategory: 'coffee_table', language: 'ru', theme: 'light',
|
|
viewport: { width: 900, height: 820 }, ...page },
|
|
{ id: 'furniture-placement-preview-light', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
furniturePlacementPreview: { symbol: 'sofa', widthCm: 180, depthCm: 90, pointer: [0.35, 0.90] },
|
|
language: 'ru', theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'furniture-plan-art-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
decorOverride: [
|
|
...decorLayerFixture.filter((shape) => shape.kind !== 'furniture'),
|
|
{ id: 'furn-replaced', kind: 'furniture', symbol: 'sofa', x: 0.16, y: 0.18,
|
|
w: 0.18, h: 0.09, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-retained', kind: 'furniture', symbol: 'fridge', x: 0.43, y: 0.18,
|
|
w: 0.06, h: 0.065, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-new', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.58, y: 0.18,
|
|
w: 0.26, h: 0.17, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
],
|
|
language: 'en', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
// #593 AC7: четыре ID, которых до пакета 0.4.0 не существовало. Кадр — их
|
|
// единственное доказательство «видно на плане»: остальные мебельные сцены
|
|
// сняты на символах, которые были и раньше.
|
|
{ id: 'furniture-new-symbols-light', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
decorOverride: [
|
|
...decorLayerFixture.filter((shape) => shape.kind !== 'furniture'),
|
|
{ id: 'furn-computer', kind: 'furniture', symbol: 'computer', x: 0.14, y: 0.18,
|
|
w: 0.12, h: 0.06, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-hood', kind: 'furniture', symbol: 'hood', x: 0.32, y: 0.18,
|
|
w: 0.06, h: 0.05, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-oven', kind: 'furniture', symbol: 'oven', x: 0.44, y: 0.18,
|
|
w: 0.06, h: 0.06, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-cactus', kind: 'furniture', symbol: 'cactus', x: 0.58, y: 0.18,
|
|
w: 0.07, h: 0.12, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
],
|
|
language: 'ru', theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'furniture-transform-light', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
decorOverride: [
|
|
...decorLayerFixture.filter((shape) => shape.kind !== 'furniture'),
|
|
{ id: 'furn-normal', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.08, y: 0.16,
|
|
w: 0.18, h: 0.12, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-flip-h', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.30, y: 0.16,
|
|
w: 0.18, h: 0.12, flip_h: true, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-flip-v', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.52, y: 0.16,
|
|
w: 0.18, h: 0.12, flip_v: true, color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-flip-hv', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.74, y: 0.16,
|
|
w: 0.18, h: 0.12, flip_h: true, flip_v: true,
|
|
color: '#141832', opacity: 1, width_cm: 1.2 },
|
|
],
|
|
decorSelection: 'furn-flip-hv', language: 'ru', theme: 'light',
|
|
viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'furniture-transform-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
decorOverride: [
|
|
...decorLayerFixture.filter((shape) => shape.kind !== 'furniture'),
|
|
{ id: 'furn-normal', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.08, y: 0.16,
|
|
w: 0.18, h: 0.12, angle: 30, color: '#d8def0', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-flip-h', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.30, y: 0.16,
|
|
w: 0.18, h: 0.12, angle: 30, flip_h: true,
|
|
color: '#d8def0', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-flip-v', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.52, y: 0.16,
|
|
w: 0.18, h: 0.12, angle: 30, flip_v: true,
|
|
color: '#d8def0', opacity: 1, width_cm: 1.2 },
|
|
{ id: 'furn-flip-hv', kind: 'furniture', symbol: 'sofa_corner_right', x: 0.74, y: 0.16,
|
|
w: 0.18, h: 0.12, angle: 30, flip_h: true, flip_v: true,
|
|
color: '#d8def0', opacity: 1, width_cm: 1.2 },
|
|
],
|
|
language: 'en', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'tray-narrow-tool-ru', fixture: 'visual', space: 'golden-geometry', mode: 'decor',
|
|
editorTray: 'decor-tool', language: 'ru', theme: 'dark',
|
|
viewport: { width: 390, height: 760 }, ...page },
|
|
{ id: 'geometry-diagonal-45-opening-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
openingGeometry: { id: 'geo-diagonal-window', type: 'window', angle: 45 },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'openings-thick-wall-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'none', glowEnabled: false, theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'openings-filled-tunnel-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'custom', customFill: { c: '#66717c', a: 0.55 }, glowEnabled: false,
|
|
hideOpenings: true,
|
|
wallReplacements: [{
|
|
match: { a: [0.5, 0.1], b: [0.5, 0.88] },
|
|
segments: [
|
|
{ key: fixtureWallKey([0.5, 0.1], [0.5, 0.5]), a: [0.5, 0.1], b: [0.5, 0.5], cm: 18 },
|
|
{ key: fixtureWallKey([0.5, 0.5], [0.5, 0.88]), a: [0.5, 0.5], b: [0.5, 0.88], cm: 32 },
|
|
],
|
|
}],
|
|
tunnelContinuity: { openingId: 'light-door', insetPx: 2, maxChannelJump: 3, dpr2: true },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'decor-over-opaque-hover-light', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'custom', customFill: { c: '#2255cc', a: 1 }, glowEnabled: false,
|
|
sunRays: false, showBorders: false, showNames: false, hideOpenings: true,
|
|
hoverRoom: 'light-left', decorOverride: decorLayerFixture,
|
|
decorPixelProbes: decorLayerProbes,
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'decor-over-glow-base-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'glow', glowEnabled: true, allLightsOff: true,
|
|
sunRays: false, showBorders: false, showNames: false, hideOpenings: true,
|
|
decorOverride: decorLayerFixture, decorPixelProbes: decorLayerProbes,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'openings-hidden-view-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'none', glowEnabled: false, hideOpenings: true, theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-glow-sun-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'device-value-badge-positions-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
glowEnabled: false, sunRays: false,
|
|
markerOverrides: [
|
|
{ id: 'golden-light-one', binding: 'device:golden-light-one', value_badge: {
|
|
enabled: true, source: { kind: 'entity_state', entity_id: 'light.golden_light_one' }, position: 'right',
|
|
} },
|
|
{ id: 'golden-light-two', binding: 'device:golden-light-two', value_badge: {
|
|
enabled: true, source: { kind: 'entity_state', entity_id: 'light.golden_light_two' }, position: 'left',
|
|
} },
|
|
{ id: 'golden-presence', binding: 'device:golden-presence', value_badge: {
|
|
enabled: true, source: { kind: 'entity_state', entity_id: 'binary_sensor.golden_presence' }, position: 'top',
|
|
} },
|
|
{ id: 'golden-climate', binding: 'device:golden-climate', value_badge: {
|
|
enabled: true,
|
|
source: { kind: 'entity_attribute', entity_id: 'climate.golden_climate', attribute: 'current_temperature' },
|
|
position: 'bottom',
|
|
} },
|
|
],
|
|
stateOverrides: { 'climate.golden_climate': { attributes: { lqi: 190 } } },
|
|
layoutOverrides: {
|
|
'golden-light-one': { s: 'golden-lighting', x: 0.20, y: 0.32 },
|
|
'golden-light-two': { s: 'golden-lighting', x: 0.20, y: 0.72 },
|
|
'golden-presence': { s: 'golden-lighting', x: 0.80, y: 0.68 },
|
|
'golden-climate': { s: 'golden-lighting', x: 0.80, y: 0.28 },
|
|
},
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'device-value-face-cover-source-dark', fixture: 'visual',
|
|
space: 'golden-lighting', mode: 'view', glowEnabled: false, sunRays: false,
|
|
showNames: false,
|
|
markerOverrides: [{
|
|
id: 'golden-left-linkquality', binding: 'entity:cover.golden_door_half',
|
|
display: 'value', size: 3,
|
|
value_source: {
|
|
kind: 'entity_attribute', entity_id: 'cover.golden_door_half',
|
|
attribute: 'current_position',
|
|
},
|
|
}],
|
|
stateOverrides: {
|
|
'cover.golden_door_half': { attributes: { current_position: 42 } },
|
|
},
|
|
layoutOverrides: {
|
|
'golden-left-linkquality': { s: 'golden-lighting', x: 0.50, y: 0.50 },
|
|
},
|
|
deviceOnly: 'golden-left-linkquality',
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
...['light', 'dark'].map((theme) => ({
|
|
id: `device-icon-state-table-${theme}`, fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
glowEnabled: false, sunRays: false,
|
|
markerOverrides: [
|
|
// #588: пятый режим показан там же, где живут остальные четыре. Источник
|
|
// выбран цветной (включённая RGB-лампа) намеренно: на нейтральном кадр
|
|
// совпал бы с прежним, и эталон не доказывал бы ничего.
|
|
{ id: 'golden-light-one', binding: 'device:golden-light-one',
|
|
display: 'value_static_icon' },
|
|
{ id: 'golden-light-two', binding: 'device:golden-light-two' },
|
|
{ id: 'golden-light-three', binding: 'device:golden-light-three' },
|
|
{ id: 'golden-presence', binding: 'device:golden-presence' },
|
|
{ id: 'golden-climate', binding: 'device:golden-climate' },
|
|
{ id: 'golden-left-temperature', binding: 'device:golden-left-temperature', display: 'value' },
|
|
{ id: 'golden-right-temperature', binding: 'device:golden-right-temperature', display: 'static_icon' },
|
|
{ id: 'golden-left-linkquality', binding: 'device:golden-left-linkquality',
|
|
tap_action: 'toggle', controls: ['light.golden_light_three'], value_badge: {
|
|
enabled: true,
|
|
source: { kind: 'entity_state', entity_id: 'sensor.golden_left_linkquality' },
|
|
position: 'right',
|
|
} },
|
|
{ id: 'golden-right-linkquality', binding: 'device:golden-right-linkquality', value_badge: {
|
|
enabled: true,
|
|
source: { kind: 'entity_state', entity_id: 'sensor.golden_right_linkquality' },
|
|
position: 'bottom',
|
|
} },
|
|
],
|
|
// This scenario deliberately places two devices outside their HA rooms to
|
|
// exercise icon states at fixed coordinates. Seed the Area-following
|
|
// provenance so #126 does not reinterpret that test-only layout as stale
|
|
// legacy placement and turn an unrelated visual matrix into a relocation
|
|
// scenario.
|
|
markerAreaSnapshot: {
|
|
'golden-light-one': { binding: 'device:golden-light-one', area: 'golden_light_left' },
|
|
'golden-light-two': { binding: 'device:golden-light-two', area: 'golden_light_left' },
|
|
'golden-light-three': { binding: 'device:golden-light-three', area: 'golden_light_right' },
|
|
'golden-presence': { binding: 'device:golden-presence', area: 'golden_light_right' },
|
|
'golden-climate': { binding: 'device:golden-climate', area: 'golden_light_right' },
|
|
'golden-left-temperature': {
|
|
binding: 'device:golden-left-temperature', area: 'golden_light_left',
|
|
},
|
|
'golden-right-temperature': {
|
|
binding: 'device:golden-right-temperature', area: 'golden_light_right',
|
|
},
|
|
'golden-left-linkquality': {
|
|
binding: 'device:golden-left-linkquality', area: 'golden_light_left',
|
|
},
|
|
'golden-right-linkquality': {
|
|
binding: 'device:golden-right-linkquality', area: 'golden_light_right',
|
|
},
|
|
},
|
|
stateOverrides: {
|
|
'light.golden_light_one': { attributes: { lqi: 40 } },
|
|
'light.golden_light_two': { attributes: { lqi: 41 } },
|
|
'light.golden_light_three': { state: 'unavailable', attributes: { lqi: 180 } },
|
|
'sensor.golden_left_temperature': { state: 'Complete long localized state' },
|
|
'sensor.golden_right_temperature': { state: 'unavailable' },
|
|
},
|
|
layoutOverrides: {
|
|
'golden-light-one': { s: 'golden-lighting', x: 0.16, y: 0.25 },
|
|
'golden-light-two': { s: 'golden-lighting', x: 0.34, y: 0.25 },
|
|
'golden-light-three': { s: 'golden-lighting', x: 0.66, y: 0.25 },
|
|
'golden-presence': { s: 'golden-lighting', x: 0.84, y: 0.25 },
|
|
'golden-climate': { s: 'golden-lighting', x: 0.16, y: 0.72 },
|
|
'golden-left-temperature': { s: 'golden-lighting', x: 0.34, y: 0.72 },
|
|
'golden-right-temperature': { s: 'golden-lighting', x: 0.66, y: 0.72 },
|
|
'golden-left-linkquality': { s: 'golden-lighting', x: 0.77, y: 0.55 },
|
|
'golden-right-linkquality': { s: 'golden-lighting', x: 0.84, y: 0.72 },
|
|
},
|
|
deviceClassOverrides: {
|
|
'golden-light-two': ['lock-locked'],
|
|
'golden-light-three': ['lock-unlocked'],
|
|
'golden-presence': ['virtual'],
|
|
'golden-climate': ['alarm', 'sel'],
|
|
'golden-right-linkquality': ['open'],
|
|
},
|
|
focusDevice: 'golden-climate',
|
|
hoverDevice: 'golden-presence',
|
|
hideHoverTooltip: true,
|
|
theme, viewport: { width: 1000, height: 900 }, ...stage,
|
|
})),
|
|
...['light', 'dark'].map((theme) => ({
|
|
id: `device-text-shell-long-${theme}`, fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
glowEnabled: false, sunRays: false, showNames: false,
|
|
markerOverrides: [{
|
|
id: 'golden-left-linkquality', binding: 'device:golden-left-linkquality',
|
|
display: 'value', size: 3,
|
|
}],
|
|
stateOverrides: {
|
|
'sensor.golden_left_linkquality': {
|
|
state: '498', attributes: { unit_of_measurement: 'ppm' },
|
|
},
|
|
},
|
|
layoutOverrides: {
|
|
'golden-left-linkquality': { s: 'golden-lighting', x: 0.50, y: 0.50 },
|
|
},
|
|
deviceOnly: 'golden-left-linkquality',
|
|
theme, viewport: { width: 1000, height: 900 }, ...stage,
|
|
})),
|
|
{ id: 'lighting-sun-window-state-only-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
// The golden screenshot is backed by a second, sun-layer-hidden capture.
|
|
// A real painted ray must account for enough changed pixels; DOM-only
|
|
// presence or an accidentally accepted empty baseline is not sufficient.
|
|
glowEnabled: false, allLightsOff: true, northDeg: 90,
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 270, elevation: 24 } } },
|
|
sunRayPixels: { minPixels: 500, minChannelDelta: 4 },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...sunWindow },
|
|
{ id: 'lighting-sun-window-outer-thick-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
// The matching inner scene above is not enough for #577: this frame pins
|
|
// the exterior source edge, the physical 15 cm tunnel and its seam with
|
|
// the clean room floor on a real rendered wall.
|
|
glowEnabled: false, allLightsOff: true, northDeg: 90, sunRayOrigin: 'outer',
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 270, elevation: 24 } } },
|
|
sunRayPixels: { minPixels: 500, minChannelDelta: 4 },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...sunWindow },
|
|
...[1, 2].map((deviceScaleFactor) => ({
|
|
id: `lighting-sun-window-outer-occluded-dpr${deviceScaleFactor}-dark`,
|
|
fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
// #580: diagonal light through the real 15 cm tunnel must narrow at the
|
|
// inner jamb instead of continuing through solid wall. Pin both raster
|
|
// scales because the tunnel/room seam is exactly where subpixels differ.
|
|
glowEnabled: false, allLightsOff: true, northDeg: 90, sunRayOrigin: 'outer',
|
|
stateOverrides: { 'sun.sun': { attributes: { azimuth: 240, elevation: 24 } } },
|
|
sunRayPixels: { minPixels: 400, minChannelDelta: 4 }, deviceScaleFactor,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...sunWindow,
|
|
})),
|
|
{ id: 'lighting-fill-light-axis-split-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'light', glowEnabled: false, theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-fill-temp-axis-split-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'temp', glowEnabled: false, theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-fill-lqi-axis-split-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'lqi', glowEnabled: false, theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-temp-glow-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'temp', glowEnabled: true, theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-temp-glow-light', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'temp', glowEnabled: true, theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-custom-glow-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'custom', customFill: { c: '#486a8f', a: 0.42 }, glowEnabled: true,
|
|
roomCustomFill: { 'light-right': { c: '#8f5f48', a: 0.56 } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-opaque-glow-two-doorways-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'custom', customFill: { c: '#3f4854', a: 1 }, glowEnabled: true, sunRays: false,
|
|
allLightsOff: true,
|
|
stateOverrides: {
|
|
'light.golden_light_one': { state: 'on', attributes: { rgb_color: [255, 196, 112], brightness: 255 } },
|
|
},
|
|
extraOpenings: [
|
|
{
|
|
id: 'light-door-second', type: 'door', x: 0.50, y: 0.30,
|
|
angle: 90, length: 0.13, contact: 'cover.golden_door_closed',
|
|
},
|
|
{
|
|
id: 'light-door-third', type: 'door', x: 0.50, y: 0.76,
|
|
angle: 90, length: 0.13, contact: 'cover.golden_door_half',
|
|
},
|
|
],
|
|
layoutOverrides: { 'golden-light-one': { s: 'golden-lighting', x: 0.40, y: 0.48 } },
|
|
// One frame contains the complete #20 matrix: the original unbound door is
|
|
// fully open, the upper bound door is closed and the lower positional door
|
|
// exposes 50%. Protection is meaningful only if the receiving half also
|
|
// contains rendered light; a data-only check once let an empty baseline pass.
|
|
warmPixelRegion: { x: 0.5, y: 0, w: 0.5, h: 1, minPixels: 2500, minRedBlueDelta: 25 },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-custom-glow-light', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'custom', customFill: { c: '#486a8f', a: 0.42 }, glowEnabled: true,
|
|
roomCustomFill: { 'light-right': { c: '#8f5f48', a: 0.56 } },
|
|
theme: 'light', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-temp-glow-no-sources-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'temp', glowEnabled: true, allLightsOff: true,
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-temp-glow-room-override-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'temp', glowEnabled: true, roomGlow: { 'light-left': true, 'light-right': false },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'lighting-manual-auto-spill-overlap-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
fillMode: 'temp', glowEnabled: true,
|
|
markerOverrides: [{
|
|
id: 'golden-light-two', binding: 'device:golden-light-two',
|
|
glow_color: { c: '#3a8fff', bri: 0.35 }, glow_radius_cm: 420,
|
|
}],
|
|
layoutOverrides: { 'golden-light-two': { s: 'golden-lighting', x: 0.39, y: 0.57 } },
|
|
theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'hover-over-glow-dark', fixture: 'visual', space: 'golden-lighting', mode: 'view',
|
|
hoverRoom: 'light-right', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
{ id: 'hover-nested-room-dark', fixture: 'visual', space: 'golden-geometry', mode: 'view',
|
|
hoverRoom: 'geo-nested', theme: 'dark', viewport: { width: 1000, height: 900 }, ...stage },
|
|
// --- #302: junction close-ups. One node per scene, the node fills the
|
|
// frame; the same scenes carry the objective no-holes detector in tests.
|
|
...[
|
|
['junction-t-90-equal15-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 15 }, { deg: 180, cm: 15 }] }],
|
|
['junction-t-90-bar50-leg15-dark', { arms: [
|
|
{ deg: 0, cm: 50 }, { deg: 90, cm: 15 }, { deg: 180, cm: 50 }] }],
|
|
['junction-t-90-bar70-leg15-dark', { arms: [
|
|
{ deg: 0, cm: 70 }, { deg: 90, cm: 15 }, { deg: 180, cm: 70 }] }],
|
|
['junction-x-90-equal15-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 15 }, { deg: 180, cm: 15 },
|
|
{ deg: 270, cm: 15 }] }],
|
|
['junction-x-90-mixed-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 50 }, { deg: 180, cm: 15 },
|
|
{ deg: 270, cm: 70 }] }],
|
|
['junction-x-45-alternating-dark', { arms: [
|
|
{ deg: 45, cm: 15 }, { deg: 135, cm: 50 }, { deg: 225, cm: 15 },
|
|
{ deg: 315, cm: 50 }] }],
|
|
['junction-star5-equal15-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 72, cm: 15 }, { deg: 144, cm: 15 },
|
|
{ deg: 216, cm: 15 }, { deg: 288, cm: 15 }] }],
|
|
['junction-y-60-equal50-dark', { arms: [
|
|
{ deg: 0, cm: 50 }, { deg: 60, cm: 50 }, { deg: 120, cm: 50 }] }],
|
|
['junction-acute30-mixed-dark', { arms: [
|
|
{ deg: 0, cm: 50 }, { deg: 30, cm: 70 }, { deg: 180, cm: 15 }] }],
|
|
['junction-acute15-equal50-dark', { arms: [
|
|
{ deg: 0, cm: 50 }, { deg: 15, cm: 50 }, { deg: 180, cm: 50 }] }],
|
|
['junction-splay10-170-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 10, cm: 15 }, { deg: 180, cm: 50 }] }],
|
|
['junction-t-virtual-arm-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 15, virtual: true },
|
|
{ deg: 180, cm: 15 }] }],
|
|
['junction-x-virtual-through-dark', { arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 15, virtual: true },
|
|
{ deg: 180, cm: 15 }, { deg: 270, cm: 15, virtual: true }] }],
|
|
['junction-column-node-dark', { column: true, arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 15 }, { deg: 180, cm: 15 }] }],
|
|
['junction-draft-end-node-dark', { draft: true, arms: [
|
|
{ deg: 0, cm: 15 }, { deg: 90, cm: 15 }, { deg: 180, cm: 15 }] }],
|
|
].map(([id, junctionNode]) => ({
|
|
id, fixture: 'visual', space: `golden-${id}`, mode: 'view', junctionNode,
|
|
zoom: 4, theme: 'dark', viewport: { width: 900, height: 900 }, ...stage,
|
|
})),
|
|
...[
|
|
['junction-309-step-dark', 8, [808.33, 1233.33]],
|
|
['junction-309-spike-dark', 8, [2220.83, 1350]],
|
|
['junction-309-hump-dark', 6, [1758.33, 1612.5]],
|
|
].map(([id, zoom, zoomCenter]) => ({
|
|
id, fixture: 'visual', space: `golden-${id}`, mode: 'view', junctionTeeth: true,
|
|
zoom, zoomCenter, theme: 'dark', viewport: { width: 900, height: 900 }, ...stage,
|
|
})),
|
|
{ id: 'sharp-apex-legacy-dark', fixture: 'visual',
|
|
space: 'golden-sharp-apex', mode: 'view', sharpApex: true,
|
|
theme: 'dark',
|
|
viewport: { width: 900, height: 900 }, ...stage },
|
|
{ id: 'junction-owner-repro-dark', fixture: 'visual',
|
|
space: 'golden-junction-owner-repro', mode: 'view', junctionArtifacts: true,
|
|
zoom: 6, zoomCenter: [329.17, 141.67], theme: 'dark',
|
|
viewport: { width: 900, height: 900 }, ...stage },
|
|
{ id: 'large-house-zoom-040-dark', fixture: 'large', space: 'perf-floor-1', mode: 'view',
|
|
zoom: 0.4, theme: 'dark', viewport: { width: 1180, height: 900 }, ...stage },
|
|
{ id: 'large-house-zoom-250-dark', fixture: 'large', space: 'perf-floor-1', mode: 'view',
|
|
zoom: 2.5, theme: 'dark', viewport: { width: 1180, height: 900 }, ...stage },
|
|
{ id: 'large-house-warm-remount-dark', fixture: 'large', space: 'perf-floor-2', mode: 'view',
|
|
warmRemount: true, theme: 'dark', viewport: { width: 1180, height: 900 }, ...stage },
|
|
{ id: 'device-dialog-desktop-en', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device', deviceId: 'golden-light-two', deviceLightControls: true,
|
|
deviceName: 'Living room light controller with an intentionally long title',
|
|
openHelp: 'marker.glow_mode.help', helpTextRegion: { key: 'marker.glow_mode.help', minPixels: 30 },
|
|
focusDialogClose: true, language: 'en', theme: 'dark', viewport: { width: 1180, height: 1200 }, ...page },
|
|
{ id: 'device-dialog-mobile-ru', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device', deviceId: 'golden-light-two', deviceLightControls: true,
|
|
deviceName: 'Контроллер освещения гостиной с намеренно очень длинным названием',
|
|
language: 'ru', theme: 'dark', viewport: { width: 390, height: 1000 }, ...page },
|
|
{ id: 'device-dialog-desktop-de', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device', deviceId: 'golden-light-two', deviceLightControls: true,
|
|
deviceName: 'Wohnzimmer-Lichtsteuerung mit absichtlich sehr langem Namen',
|
|
language: 'de', theme: 'light', viewport: { width: 1180, height: 1200 }, ...page },
|
|
{ id: 'room-temperature-dialog-desktop-en', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'room-temperature', roomTemperature: { min: 18, max: 22 },
|
|
language: 'en', theme: 'light', viewport: { width: 900, height: 900 }, ...page },
|
|
{ id: 'room-temperature-dialog-mobile-ru', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'room-temperature', roomTemperature: { min: 18, max: null },
|
|
language: 'ru', theme: 'dark', viewport: { width: 390, height: 820 }, ...page },
|
|
{ id: 'german-view-mobile-light', fixture: 'visual', space: 'golden-geometry',
|
|
mode: 'view', language: 'de', theme: 'light',
|
|
viewport: { width: 390, height: 900 }, ...page },
|
|
{ id: 'toggle-entity-dialog-desktop-en', fixture: 'visual', applianceLifecycle: true,
|
|
space: 'golden-appliance', dialog: 'device', deviceId: 'golden-washer',
|
|
deviceToggleEntity: 'selected', markerOverrides: [{
|
|
id: 'golden-washer', binding: 'device:golden-washer', tap_action: 'toggle',
|
|
toggle_entity: 'switch.golden_washer_child_lock',
|
|
}],
|
|
language: 'en', theme: 'light', viewport: { width: 1180, height: 1100 }, ...page },
|
|
{ id: 'toggle-entity-dialog-mobile-ru', fixture: 'visual', applianceLifecycle: true,
|
|
space: 'golden-appliance', dialog: 'device', deviceId: 'golden-washer',
|
|
deviceToggleEntity: 'stale', markerOverrides: [{
|
|
id: 'golden-washer', binding: 'device:golden-washer', tap_action: 'toggle',
|
|
toggle_entity: 'switch.golden_washer_removed',
|
|
}],
|
|
language: 'ru', theme: 'dark', viewport: { width: 390, height: 1000 }, ...page },
|
|
{ id: 'device-help-popover-light-ru', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device', deviceId: 'golden-light-two', deviceLightControls: true,
|
|
openHelp: 'marker.glow_mode.help', helpTextRegion: { key: 'marker.glow_mode.help', minPixels: 30 },
|
|
language: 'ru', theme: 'light', viewport: { width: 760, height: 900 }, ...page },
|
|
{ id: 'decor-color-popover-mobile-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'decor-color', language: 'ru', theme: 'dark',
|
|
viewport: { width: 390, height: 760 }, ...page },
|
|
{ id: 'decor-color-popover-desktop-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'decor-color', language: 'en', theme: 'light',
|
|
viewport: { width: 760, height: 820 }, ...page },
|
|
{ id: 'general-color-popover-desktop-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'general-color', language: 'en', theme: 'light',
|
|
viewport: { width: 900, height: 900 }, ...page },
|
|
// #86 AC7: renderer-level 200% browser zoom is 390 CSS px at DPR 2
|
|
// (780 physical px). Keep both themes reviewed because help placement and
|
|
// contrast are part of the visual contract, not just a DOM assertion.
|
|
{ id: 'settings-help-zoom-200-en-light', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'general-help', openHelp: 'gs.bg_mode.help', deviceScaleFactor: 2,
|
|
helpTextRegion: { key: 'gs.bg_mode.help', minPixels: 30 },
|
|
language: 'en', theme: 'light', viewport: { width: 390, height: 900 }, ...page },
|
|
{ id: 'settings-help-zoom-200-ru-dark', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'general-help', openHelp: 'gs.bg_mode.help', deviceScaleFactor: 2,
|
|
helpTextRegion: { key: 'gs.bg_mode.help', minPixels: 30 },
|
|
language: 'ru', theme: 'dark', viewport: { width: 390, height: 900 }, ...page },
|
|
// #43 AC14: the support dialog owns reviewed desktop, phone and tablet
|
|
// states. The six scenes deliberately cover both themes while keeping the
|
|
// individual states named in the specification independently reviewable.
|
|
{ id: 'support-desktop-empty-light-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'support', supportState: 'empty', language: 'en', theme: 'light',
|
|
viewport: { width: 1000, height: 980 }, ...page },
|
|
{ id: 'support-desktop-preview-dark-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'support', supportState: 'preview', language: 'en', theme: 'dark',
|
|
viewport: { width: 1000, height: 980 }, ...page },
|
|
{ id: 'support-phone-validation-light-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'support', supportState: 'validation', language: 'ru', theme: 'light',
|
|
viewport: { width: 320, height: 760 }, ...page },
|
|
{ id: 'support-phone-success-dark-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'support', supportState: 'success', language: 'en', theme: 'dark',
|
|
viewport: { width: 390, height: 820 }, ...page },
|
|
{ id: 'support-relay-error-light-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'support', supportState: 'relay-error', language: 'en', theme: 'light',
|
|
viewport: { width: 900, height: 900 }, ...page },
|
|
{ id: 'support-tablet-preview-dark-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'support', supportState: 'preview', language: 'ru', theme: 'dark',
|
|
viewport: { width: 768, height: 900 }, ...page },
|
|
{ id: 'device-ripple-color-popover-mobile-ru', fixture: 'visual', space: 'golden-lighting',
|
|
dialog: 'device-ripple-color', deviceId: 'golden-light-two',
|
|
language: 'ru', theme: 'dark', viewport: { width: 390, height: 1000 }, ...page },
|
|
{ id: 'space-room-color-popover-desktop-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'space-room-color', language: 'ru', theme: 'dark',
|
|
viewport: { width: 900, height: 1000 }, ...page },
|
|
{ id: 'backup-full-preview-desktop-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'backup-full', language: 'en', theme: 'dark',
|
|
viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'backup-plan-only-export-desktop-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'backup-export-plan-only', language: 'en', theme: 'dark',
|
|
viewport: { width: 1000, height: 900 }, ...page },
|
|
{ id: 'backup-space-preview-mobile-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'backup-space', language: 'ru', theme: 'light',
|
|
viewport: { width: 390, height: 820 }, ...page },
|
|
{ id: 'optimize-preflight-dialog-dark-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'optimize-preflight', language: 'en', theme: 'dark',
|
|
viewport: { width: 900, height: 760 }, ...page },
|
|
{ id: 'optimize-preflight-dialog-light-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'optimize-preflight', language: 'ru', theme: 'light',
|
|
viewport: { width: 900, height: 760 }, ...page },
|
|
{ id: 'optimize-orphan-references-dark-en', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'optimize-orphan-references', language: 'en', theme: 'dark',
|
|
markerOverrides: [{
|
|
id: 'golden-light-two', binding: 'virtual', space: 'removed-floor',
|
|
room_id: 'removed-room', icon: 'mdi:lightbulb', name: 'Living-room lamp',
|
|
}, {
|
|
id: 'golden-light-one', binding: 'virtual', name: 'Hall lamp',
|
|
}, {
|
|
id: 'golden-presence', binding: 'virtual', removed: true,
|
|
space: 'removed-floor', name: 'Retired marker',
|
|
}],
|
|
// The orphan-reference fixture intentionally reuses ids of live registry
|
|
// devices. Pin their pre-#126 provenance so the lifecycle synchronizer
|
|
// cannot consume the deliberately orphaned positions before Optimize
|
|
// inspects them.
|
|
markerAreaSnapshot: {
|
|
'golden-light-one': { binding: 'device:golden-light-one', area: 'golden_light_left' },
|
|
'golden-light-two': { binding: 'device:golden-light-two', area: 'golden_light_left' },
|
|
'golden-presence': { binding: 'device:golden-presence', area: 'golden_light_right' },
|
|
},
|
|
layoutOverrides: {
|
|
'golden-light-two': { s: 'removed-floor', x: 0.35, y: 0.72 },
|
|
'golden-light-one': { s: 'unresolved-floor', x: 0.20, y: 0.34 },
|
|
'golden-presence': { s: 'removed-floor', x: 0.45, y: 0.64 },
|
|
},
|
|
viewport: { width: 900, height: 760 }, ...page },
|
|
{ id: 'optimize-orphan-references-light-ru', fixture: 'visual', space: 'golden-geometry',
|
|
dialog: 'optimize-orphan-references', language: 'ru', theme: 'light',
|
|
markerOverrides: [{
|
|
id: 'golden-light-two', binding: 'virtual', space: 'removed-floor',
|
|
room_id: 'removed-room', icon: 'mdi:lightbulb', name: 'Лампа в гостиной',
|
|
}, {
|
|
id: 'golden-light-one', binding: 'virtual', name: 'Лампа в холле',
|
|
}, {
|
|
id: 'golden-presence', binding: 'virtual', removed: true,
|
|
space: 'removed-floor', name: 'Старый маркер',
|
|
}],
|
|
markerAreaSnapshot: {
|
|
'golden-light-one': { binding: 'device:golden-light-one', area: 'golden_light_left' },
|
|
'golden-light-two': { binding: 'device:golden-light-two', area: 'golden_light_left' },
|
|
'golden-presence': { binding: 'device:golden-presence', area: 'golden_light_right' },
|
|
},
|
|
layoutOverrides: {
|
|
'golden-light-two': { s: 'removed-floor', x: 0.35, y: 0.72 },
|
|
'golden-light-one': { s: 'unresolved-floor', x: 0.20, y: 0.34 },
|
|
'golden-presence': { s: 'removed-floor', x: 0.45, y: 0.64 },
|
|
},
|
|
viewport: { width: 900, height: 880 }, ...page },
|
|
{ id: 'card-editor-invalid-default-floor-light-en', fixture: 'visual',
|
|
cardEditorInvalidDefaultFloor: 'removed-floor', language: 'en', theme: 'light',
|
|
viewport: { width: 900, height: 760 }, ...page },
|
|
{ id: 'card-editor-invalid-default-floor-dark-ru', fixture: 'visual',
|
|
cardEditorInvalidDefaultFloor: 'removed-floor', language: 'ru', theme: 'dark',
|
|
viewport: { width: 900, height: 760 }, ...page },
|
|
]);
|