Preserve onboard preview recordings across backpressure and share the complete spatial scene

This commit is contained in:
DCCONSTRUCTIONS
2026-09-07 17:47:10 +03:00
parent 9b6534287a
commit 9bba44f7c4
30 changed files with 957 additions and 494 deletions
@@ -0,0 +1,8 @@
import {Icon} from '@nodedc/ui-react';
export function EmptySpatialStage({settings, title='Визуальный источник не назначен', detail='Область сцены не подставляет демонстрационные точки. Назначьте RRD или Rerun gRPC, чтобы открыть реальные данные.'}: {settings:{showGrid:boolean};title?:string;detail?:string}) {
return <div className="empty-spatial-stage" data-grid={settings.showGrid?'true':undefined}>
<div className="empty-spatial-stage__grid" aria-hidden="true"/>
<div className="spatial-axis" aria-hidden="true"><span data-axis="x">X</span><span data-axis="z">Z</span></div>
<div className="empty-spatial-stage__message"><span className="empty-spatial-stage__icon"><Icon name="globe" size={20}/></span><strong>{title}</strong><p>{detail}</p></div>
</div>;
}
+32
View File
@@ -0,0 +1,32 @@
import type {ReactNode, RefObject} from 'react';
import {StatusBadge} from '@nodedc/ui-react';
/** The existing scene composition. Hosts supply transport/renderers and authority. */
export function SpatialScene({viewportRef, focused, primaryFocused, mediaMaximized, toolbar,
renderer, deviceControls, sourceControls, status, metrics, timeline, media, overlays, footer,
navigationReady=false}: {
viewportRef: RefObject<HTMLDivElement|null>; focused?:boolean; primaryFocused?:boolean;
mediaMaximized?:boolean; toolbar:ReactNode; renderer:ReactNode; deviceControls?:ReactNode;
sourceControls?:ReactNode; status:{label:string;tone:'neutral'|'success'|'warning'|'danger';message?:string};
metrics:ReactNode; timeline?:ReactNode; media?:ReactNode; overlays?:ReactNode; footer?:ReactNode;
navigationReady?:boolean;
}) {
return <div className="spatial-workspace" data-focused={focused?'true':undefined}>
<div className="spatial-toolbar" data-viewer-controls="v1"><div className="spatial-toolbar__actions">{toolbar}</div></div>
<div ref={viewportRef} className="spatial-viewport-shell" data-primary-focused={primaryFocused?'true':undefined} data-media-maximized={mediaMaximized?'true':undefined}>
{renderer}
{deviceControls&&<div className="scene-device-controls">{deviceControls}</div>}
{sourceControls}
<div className="scene-status scene-status--top-left" aria-hidden={primaryFocused||mediaMaximized}>
<span className="section-eyebrow">ВИЗУАЛЬНЫЙ ДВИЖОК</span>
<StatusBadge tone={status.tone}>{status.label}</StatusBadge>
{status.message?<small>{status.message}</small>:null}
</div>
<div className="scene-metrics" aria-label="Метрики пространственной сцены" aria-hidden={primaryFocused||mediaMaximized}>{metrics}</div>
{overlays}
{navigationReady&&!mediaMaximized&&<div className="scene-navigation-hint" aria-label="Навигация по 3D-сцене"><span>Колесо · зум к курсору</span><span>WASD · свободный проход</span></div>}
{timeline}{media}
</div>
{footer}
</div>;
}
+2
View File
@@ -8,3 +8,5 @@ export * from './FloatingMediaWindow';
export * from './ObservationTimeline';
export * from './sceneSettings';
export * from './ObservationSourcePicker';
export * from './SpatialScene';
export * from './EmptySpatialStage';