feat(perception): qualify inline temporal stability

This commit is contained in:
DCCONSTRUCTIONS
2026-07-24 09:10:07 +03:00
parent cfc7b062da
commit 23181c867b
16 changed files with 2250 additions and 218 deletions
+53 -35
View File
@@ -13,11 +13,10 @@
display: flex;
min-width: 0;
align-items: center;
justify-content: space-between;
justify-content: flex-start;
gap: 1rem;
}
.spatial-toolbar__mode,
.spatial-toolbar__actions {
display: flex;
min-width: 0;
@@ -39,39 +38,6 @@
border-radius: 999px;
}
.spatial-toolbar__perception-status,
.spatial-toolbar__perception-retry {
display: inline-flex;
min-width: 0;
align-items: center;
gap: 0.4rem;
border: 1px solid rgb(255 255 255 / 0.07);
border-radius: 999px;
background: rgb(255 255 255 / 0.035);
padding: 0.42rem 0.62rem;
color: var(--nodedc-text-muted);
font: inherit;
font-size: 0.58rem;
white-space: nowrap;
}
.spatial-toolbar__perception-status .busy-indicator {
width: 0.72rem;
height: 0.72rem;
flex-basis: 0.72rem;
}
.spatial-toolbar__perception-retry {
color: var(--nodedc-text-primary);
cursor: pointer;
}
.spatial-toolbar__perception-retry:hover,
.spatial-toolbar__perception-retry:focus-visible {
background: rgb(255 255 255 / 0.09);
outline: none;
}
.spatial-viewport-shell {
position: relative;
min-width: 0;
@@ -369,6 +335,58 @@
.scene-selection small { color: var(--nodedc-text-muted); font-size: 0.55rem; }
.scene-selection strong { overflow: hidden; font-size: 0.66rem; text-overflow: ellipsis; white-space: nowrap; }
.scene-operation-status-stack {
position: absolute;
z-index: 11;
right: 0.85rem;
bottom: 7.15rem;
display: grid;
justify-items: end;
gap: 0.3rem;
}
.scene-operation-status {
display: inline-flex;
max-width: min(24rem, calc(100% - 1.7rem));
align-items: center;
gap: 0.42rem;
border: 1px solid rgb(255 255 255 / 0.07);
border-radius: 999px;
background: rgb(9 10 13 / 0.7);
color: var(--nodedc-text-muted);
padding: 0.42rem 0.65rem;
font: inherit;
font-size: 0.52rem;
font-weight: 680;
line-height: 1;
white-space: nowrap;
backdrop-filter: blur(14px);
}
.scene-operation-status .busy-indicator {
width: 0.66rem;
height: 0.66rem;
flex-basis: 0.66rem;
border-width: 1px;
}
.scene-operation-status--action {
color: var(--nodedc-text-secondary);
cursor: pointer;
}
.scene-operation-status--action:hover,
.scene-operation-status--action:focus-visible {
border-color: rgb(255 255 255 / 0.14);
background: rgb(20 21 25 / 0.82);
color: var(--nodedc-text-primary);
outline: none;
}
.scene-operation-status--error {
color: rgb(var(--nodedc-danger-rgb));
}
.scene-timeline {
right: 0.75rem;
bottom: 0.75rem;
@@ -536,9 +536,6 @@ function SpatialWorkspace({
data-focused={pointCloudFocused || floatingSourceMaximized ? "true" : undefined}
>
<div className="spatial-toolbar" data-viewer-controls="v1">
<div className="spatial-toolbar__mode">
<span className="section-eyebrow">СЦЕНА 3D · RERUN</span>
</div>
<div className="spatial-toolbar__actions">
{recordedPerceptionSupported || livePerceptionAvailable ? (
<div className="spatial-toolbar__view-switch" role="group" aria-label="Слои распознавания сцены">
@@ -598,33 +595,6 @@ function SpatialWorkspace({
</Button>
</div>
) : null}
{recordedSource && perceptionLoad.phase === "loading" ? (
<div className="spatial-toolbar__perception-status" role="status">
<span className="busy-indicator" aria-hidden="true" />
<span>{perceptionLoad.message || "Готовим AI-слои."}</span>
</div>
) : null}
{recordedSource && perceptionLoad.phase === "error" ? (
<button
type="button"
className="spatial-toolbar__perception-retry"
onClick={() => setPerceptionRetryGeneration((generation) => generation + 1)}
>
<Icon name="refresh" size={14} />
Повторить AI
</button>
) : null}
{recordedSource && pointColorLoad.phase === "loading" ? (
<div className="spatial-toolbar__perception-status" role="status">
<span className="busy-indicator" aria-hidden="true" />
<span>{pointColorLoad.message}</span>
</div>
) : null}
{recordedSource && pointColorLoad.phase === "error" ? (
<div className="spatial-toolbar__perception-status" role="status">
<span>{pointColorLoad.message}</span>
</div>
) : null}
{recordedSource && presentedViewerStatus === "ready" ? (
<Button
size="compact"
@@ -804,6 +774,43 @@ function SpatialWorkspace({
</div>
) : null}
{!floatingSourceMaximized && recordedSource && (
perceptionLoad.phase === "loading" ||
perceptionLoad.phase === "error" ||
pointColorLoad.phase === "loading" ||
pointColorLoad.phase === "error"
) ? (
<div className="scene-operation-status-stack">
{perceptionLoad.phase === "loading" ? (
<div className="scene-operation-status" role="status">
<span className="busy-indicator" aria-hidden="true" />
<span>{perceptionLoad.message || "Готовим AI-слои."}</span>
</div>
) : null}
{perceptionLoad.phase === "error" ? (
<button
type="button"
className="scene-operation-status scene-operation-status--action"
onClick={() => setPerceptionRetryGeneration((generation) => generation + 1)}
>
<Icon name="refresh" size={12} />
<span>Повторить AI</span>
</button>
) : null}
{pointColorLoad.phase === "loading" ? (
<div className="scene-operation-status" role="status">
<span className="busy-indicator" aria-hidden="true" />
<span>{pointColorLoad.message}</span>
</div>
) : null}
{pointColorLoad.phase === "error" ? (
<div className="scene-operation-status scene-operation-status--error" role="status">
<span>{pointColorLoad.message}</span>
</div>
) : null}
</div>
) : null}
{presentedViewerStatus === "ready" && !floatingSourceMaximized ? (
<div className="scene-navigation-hint" aria-label="Навигация по 3D-сцене">
<span>Колесо · зум к курсору</span>