Skip to content

feat(dashboard): Live-3D-Linie (Anlagen-Synoptik 3D, Platzhalter-zuerst) - #54

Merged
patricznr1 merged 3 commits into
mainfrom
feat/synoptik-3d
Jun 25, 2026
Merged

feat(dashboard): Live-3D-Linie (Anlagen-Synoptik 3D, Platzhalter-zuerst)#54
patricznr1 merged 3 commits into
mainfrom
feat/synoptik-3d

Conversation

@patricznr1

@patricznr1 patricznr1 commented Jun 25, 2026

Copy link
Copy Markdown
Owner

Was

Neue datengetriebene FE-Sektion Anlagen-Synoptik 3D (/synoptik): eine interaktive Three.js-Liniensicht der Montagelinie 1 — 12 Maschinen in kanonischer Sequenz (Fördern → Pressen → Handling → Bestücken → Endkontrolle), Live-Status, klickbar → kanonische Maschinenkarte.

Gebaut gegen saubere Platzhalter-Geometrie (wie beauftragt). Der Realismus kommt später aus den GLB-Modellen — die datengetriebene Mechanik steht jetzt und ist getestet. GLB-Tausch = Asset-Swap über ein Manifest, kein Renderer-Umbau.

Verortung (Entscheidung mit Patric)

  • Sub-Ansicht der Sektion A (Cockpit)/overview ist exakt für manager/shift_lead autorisiert, deckungsgleich mit Sektion A.
  • Einstieg über einen Ansichts-Umschalter im Cockpit (Heatmap ⇆ 3D-Linie) — kein achter Nav-Eintrag (Designstudie §3.3, ≤ 7), kein neuer SectionId.
  • Reuse des bestehenden overview-WS-Topics (gleiche Quelle wie Cockpit/Stream-Kachel).

Architektur

  • Reine, render-agnostische Logik (lib/synoptic3d/, voll Vitest-getestet): layout.ts (Sequenz aus geteiltem STAGE_ORDER), manifest.ts (Swap-Naht), status-color.ts (Status→FCSM-Token, eine Quelle wie Cockpit), placeholder-proportions.ts (Silhouetten je Klasse).
  • Three.js-Renderer (raw, kein react-three-fiber — konsistent zum minimalistischen FE-Ethos): EINE geteilte neutrale Beleuchtung + IBL + ACESFilmic (der Render-Kohärenz-Hebel), OrbitControls, dezenter Hallenboden, Live-Recolor in-place, ehrliche WebGL-Degradation.
  • GLB-Pipeline eingerichtet (GLTFLoader + Draco/meshopt + KTX2), heute ruhend (Manifest = nur Platzhalter). GLB-Vertrag dokumentiert: Meter-Maßstab, Y-up, Pivot am Boden-Zentrum.
  • Barrierefreie Maschinen-Leiste (Tastatur-Zugang + Fallback ohne WebGL + Klick-Vertrag-Testfläche).
  • Verfassungslinie gewahrt: Sim-Vorbehalt sichtbar (digitaler Zwilling), die Ansicht navigiert nur, steuert nicht; kein erfundenes Signal auf gesunden Maschinen — die kranke Maschine sticht räumlich zwischen ihren gesunden Schwestern heraus (datengetrieben aus /overview).

Abnahmekriterien

Kriterium Status
Szene lädt, 12 Maschinen angeordnet ✅ (Layout-Test + Build)
Status-Farben aus /overview ✅ (FCSM-Token, geteilte Quelle)
WS-Update färbt live um ✅ (View-Test mit FakeTransport)
Klick → Karte/Detail ✅ (machineHref, loser Vertrag)
Swap-Manifest greift (Dummy-GLB-Test)
60 fps mit 12 Platzhaltern ⏳ visuell in der Laufumgebung zu bestätigen (12 Low-Poly-Gruppen, geteilte Umgebung, keine Per-Frame-Allokation)

Gates grün: tsc --noEmit 0 · eslint 0 · vitest 708 (+29) · tokens:check synchron · next build ok (three nur auf der /synoptik-Route gebündelt: 196 kB).

Adversarialer Review (Multi-Agent)

8 Findings bestätigt, 6 verworfen. 5 jetzt gefixt: Touch-Mindesthöhe der Maschinenliste (§5.4), RoomEnvironment-Dispose-Leck, Fremdklassen-Verschmelzung im Layout, Fokusring-Token, internes Akronym „HITL" aus dem sichtbaren UI.

3 bewusst in die GLB-Swap-Phase verschoben (betreffen nur den ruhenden GLB-Pfad — heute kein Impact, vom Verifier bestätigt; als TODO am Seam + im GLB-Vertrag dokumentiert): GLB-Dispose/Unmount-Race, GLB-Raycast-Registrierung (Klick-Vertrag), Beacon/Ring-Reposition auf echte GLB-Höhe.

Nächste Phase

Die optimierten GLBs liegen bereits unter docs/FOREMAN-3D/models (feeder/servo_press/servo_axis/robot/vision, inkl. KTX2-Varianten). Der Swap (Assets nach public/, Manifest-Einträge + Transforms, die 3 offenen Renderer-Punkte, visuelle Maßstab-/Pivot-Kalibrierung) folgt als eigener, visuell verifizierter PR.

CC merged nie selbst — bitte nach Review mergen.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Neue Features
    • Synoptik-3D-Ansicht ergänzt: Maschinenliste, Status-Legende, Interaktion per Auswahl sowie Live-Status-Updates.
    • Cockpit-Sichtumschalter hinzugefügt (Heatmap ↔ 3D-Linie) mit klarer Fokus-/Aktiv-Ansicht.
    • Neue Kanäle für Synoptik: serverseitiges Laden eines Start-Snapshots und Sicherung des Zugriffs.
  • Bug Fixes
    • Robusteres Laden des Übersichts-Startzustands; konsistente Zustandsdarstellung mit CSS-gestützten 3D-Farben.
  • Tests
    • Umfangreiche Tests für Navigation, 3D-Layout, Statusfarben und Fallback-Verhalten ergänzt.

Neue Sektion-A-Sub-Ansicht /synoptik: Three.js-Liniensicht der Montagelinie 1,
12 Maschinen in kanonischer Sequenz (Fördern→Pressen→Handling→Bestücken→
Endkontrolle), Live-Status aus /overview über das WS-Thema "overview", Klick/
Hover → kanonische Maschinenkarte (machineHref, loser Vertrag machine_id→Karte).

- Reine, render-agnostische Logik (lib/synoptic3d): Layout, Swap-Manifest,
  Status-Farbe, Platzhalter-Proportionen — voll Vitest-getestet.
- Three.js-Renderer (raw, kein R3F): EINE geteilte neutrale Beleuchtung + IBL +
  ACESFilmic (Render-Kohärenz-Hebel), OrbitControls, proportionale Blockouts je
  Klasse, Live-Recolor in-place, ehrliche WebGL-Degradation.
- GLB-Swap-Naht verdrahtet (GLTFLoader + Draco/meshopt + KTX2), heute ruhend
  (Manifest = nur Platzhalter); GLB-Vertrag dokumentiert (Meter/Y-up/Boden-Pivot).
- Einstieg über Ansichts-Umschalter im Cockpit (Heatmap/3D-Linie); kein achter
  Nav-Eintrag (Designstudie §3.3, ≤7). Sim-Vorbehalt sichtbar; Ansicht navigiert nur.
- Barrierefreie Maschinen-Leiste (Tastatur + Fallback ohne WebGL).

three@^0.171.0 nur auf der /synoptik-Route gebündelt. Gates grün: tsc 0,
eslint 0, vitest 708, tokens synchron, next build ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Review was skipped due to path filters

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json

CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including **/dist/** will override the default block on the dist directory, by removing the pattern from both the lists.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: f250eb12-9e70-4c04-ad2f-e87520fb8084

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Die PR extrahiert den gemeinsamen Overview-Snapshot-Fetch, ergänzt eine neue Synoptik-Route und baut dafür Layout-, Scene-, View- und Navigationsbausteine für die 3D-Anzeige sowie begleitende Tests und three-Abhängigkeiten ein.

Changes

Synoptik 3D-Grundlagen

Layer / File(s) Summary
Datenmodelle und Lookup-Helper
frontend/lib/machine/grouping.ts, frontend/lib/synoptic3d/manifest.ts, frontend/lib/synoptic3d/placeholder-proportions.ts, frontend/lib/synoptic3d/status-color.ts, frontend/lib/synoptic3d/manifest.test.ts, frontend/lib/synoptic3d/placeholder-proportions.test.ts, frontend/lib/synoptic3d/status-color.test.ts
Exportierte Stufenreihenfolge, Placeholder-Proportionen, Modellquellen und Status-Farbwerte werden definiert und mit Lookup-Tests abgesichert.
Layout und Fixtures
frontend/lib/synoptic3d/layout.ts, frontend/lib/synoptic3d/testing/fixtures.ts, frontend/lib/synoptic3d/layout.test.ts
buildLineLayout ordnet Maschinen deterministisch an; Fixtures und Tests prüfen Reihenfolge, Abstände, Zentrierung und Randfälle.
Three.js Support-Module
frontend/components/synoptik/scene/*, frontend/package.json
Statusfarben, Boden, Beleuchtung, Loader und Placeholder-Builder werden als wiederverwendbare Three.js-Bausteine eingeführt, und three wird als Laufzeitabhängigkeit ergänzt.
SynoptikScene-Laufzeit
frontend/components/synoptik/synoptik-scene.tsx, frontend/components/synoptik/synoptik-scene.test.tsx
SynoptikScene baut die 3D-Szene auf, verarbeitet Raycasts, Hover, Klicks, Live-Statusänderungen und Cleanup; ein Test prüft das WebGL-Fallback und das gerenderte Bild.
SynoptikView und Navigation
frontend/components/synoptik/synoptik-view.tsx, frontend/components/synoptik/synoptik-view.test.tsx, frontend/components/synoptik/synoptik-legend.tsx, frontend/components/synoptik/synoptik-legend.test.tsx, frontend/components/synoptik/synoptik-machine-list.tsx, frontend/components/synoptik/synoptik-machine-list.test.tsx, frontend/components/cockpit/cockpit-view-switch.tsx, frontend/components/cockpit/cockpit-view-switch.test.tsx, frontend/components/cockpit/cockpit-view.tsx
SynoptikView kombiniert Realtime-Overview, Legende, Maschinenliste und Cockpit-Ansichtswechsel; Tests prüfen Rendering, Navigation und Live-Updates.
Snapshot und Routen
frontend/lib/api/overview-snapshot.ts, frontend/app/(app)/overview/page.tsx, frontend/app/(app)/synoptik/page.tsx
Der Overview-Snapshot-Fetcher wird gemeinsam genutzt; die Overview-Route importiert ihn neu, und die Synoptik-Route lädt Initialdaten serverseitig.

Sequence Diagram(s)

sequenceDiagram
  participant SynoptikPage
  participant fetchOverviewSnapshot
  participant SynoptikView
  SynoptikPage->>fetchOverviewSnapshot: fetchOverviewSnapshot()
  fetchOverviewSnapshot-->>SynoptikPage: FleetOverviewOut | undefined
  SynoptikPage->>SynoptikView: user + initialData
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • patricznr1/foreman#29: Führt ebenfalls den SSR-Snapshot für /overview bzw. die initiale Cockpit-Ansicht ein.
  • patricznr1/foreman#49: Teilt den FleetOverviewOut-//api/v1/overview-Pfad und erweitert verwandte Dashboard-Komponenten um Live-Datenbezug.

Poem

Ich hoppelte durch Daten, leicht und fein,
die 3D-Linie darf nun sichtbar sein. 🐇
Ein Snapshot glänzt, der Hase nickt,
und jede Maschine wird korrekt geklickt.
Mampf, mampf — die Farben laufen rund!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 69.23% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Der Titel beschreibt die neue Live-3D-Linie für die Anlagen-Synoptik und den Platzhalter-Ansatz passend zum Changeset.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/synoptik-3d

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🧹 Nitpick comments (2)
frontend/lib/synoptic3d/placeholder-proportions.test.ts (1)

12-18: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

mixing_unit fehlt in der Testabdeckung der bekannten Klassen.

In frontend/lib/synoptic3d/placeholder-proportions.ts ist mixing_unit ebenfalls Teil der bekannten Tabelle, aber hier wird weder seine Shape-Zuordnung noch sein Dimensionsvertrag geprüft. Ein Regression dort würde aktuell grün bleiben.

Vorgeschlagene Ergänzung
   it("gibt jeder bekannten Klasse ihre eigene Silhouette", () => {
     expect(proportionsFor("feeder").shape).toBe("conveyor");
     expect(proportionsFor("servo_press").shape).toBe("press");
     expect(proportionsFor("servo_axis").shape).toBe("axis");
     expect(proportionsFor("robot").shape).toBe("robot");
     expect(proportionsFor("vision").shape).toBe("vision");
+    expect(proportionsFor("mixing_unit").shape).toBe("generic");
   });
@@
-    for (const c of ["feeder", "servo_press", "servo_axis", "robot", "vision", null]) {
+    for (const c of ["feeder", "servo_press", "servo_axis", "robot", "vision", "mixing_unit", null]) {
       const p = proportionsFor(c);
       expect(p.width).toBeGreaterThan(0);
       expect(p.height).toBeGreaterThan(0);
       expect(p.depth).toBeGreaterThan(0);
     }

Also applies to: 37-44

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/lib/synoptic3d/placeholder-proportions.test.ts` around lines 12 -
18, The known-classes coverage in the `proportionsFor` test is missing
`mixing_unit`, so add assertions for that entry alongside the existing shape
checks. Extend the `placeholder-proportions.test.ts` suite to verify
`proportionsFor("mixing_unit")` returns the expected `shape` and also covers its
dimension contract, matching the other known class cases.
frontend/components/synoptik/synoptik-view.tsx (1)

46-48: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: SSR-Snapshot-Überbrückung als Helper extrahieren.

Die Logik live.kind === "loading" && initialData ? { kind: "cached", data } : live ist identisch zu CockpitView (cockpit-view.tsx, Zeile 60-61). Ein gemeinsamer Helper (z. B. bridgeWithSnapshot(live, initialData)) hält das Verhalten zwischen beiden Ansichten konsistent, falls sich die Übergangslogik später ändert.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/components/synoptik/synoptik-view.tsx` around lines 46 - 48, The SSR
snapshot bridging logic in synoptik-view should be extracted into a shared
helper to match CockpitView and keep both views consistent. Move the `live.kind
=== "loading" && initialData ? { kind: "cached", data: initialData } : live`
pattern into a reusable function such as `bridgeWithSnapshot(live,
initialData)`, then call that helper from `SynoptikView` and `CockpitView` so
any future changes to the transition behavior happen in one place.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@frontend/components/synoptik/scene/lighting.ts`:
- Around line 31-42: The PMREM cleanup in lighting.ts is only disposing the
texture, but PMREMGenerator.fromScene returns a WebGLRenderTarget that must be
released separately. Update the code around the PMREMGenerator/fromScene setup
to store the returned target (for example alongside envTexture), and in the
returned dispose() implementation free that target explicitly before disposing
the PMREMGenerator and room resources.

In `@frontend/components/synoptik/scene/placeholders.ts`:
- Around line 99-105: The status ring is rendered in the placeholder mesh setup
but never registered as an interaction target, so hover/click never reaches it.
Update the placeholder creation logic in the ring mesh path (the ring generation
in the scene placeholders helper) to expose the ring as a pickable target, and
then add that ring mesh to the interaction target list consumed by
synoptik-scene’s handle.pickTargets so the existing picking logic can detect it.

In `@frontend/components/synoptik/synoptik-scene.tsx`:
- Around line 202-210: The handleClick logic in synoptik-scene.tsx is treating
every mouse up as a selection, which can trigger onSelectMachine after an
OrbitControls drag. Update handleClick to distinguish a real click from a camera
drag by tracking whether the pointer interaction moved/dragged (likely via
updatePointer and related pointer state in SynoptikScene), and only call
pickMachineId/onSelectMachine when the interaction was not a drag.

In `@frontend/lib/api/overview-snapshot.ts`:
- Around line 19-30: The SSR fetch in the overview snapshot helper can hang
indefinitely because it has no timeout. Update the fetch call inside the
overview snapshot function to use AbortSignal.timeout(...) with a reasonable
limit (for example 5_000 ms), and keep the existing error handling so timeouts
still return undefined. Use the overview snapshot fetch logic in
overview-snapshot.ts and the backendUrl() / fetch() call site to locate the
change.

In `@frontend/lib/synoptic3d/testing/fixtures.ts`:
- Around line 35-48: Align the PARK fixture in fixtures.ts with the scenario
described by the comment: currently only the PARK entries with
machineClass/status combinations in the PARK array are inconsistent with the
stated drift set. Update either the comment or the ParkSpec statuses so that
only the intended machines are marked drift_active and PR-02/VS-01 remain
open_warning; use the PARK constant and its ParkSpec entries to verify the
scenario stays consistent.

---

Nitpick comments:
In `@frontend/components/synoptik/synoptik-view.tsx`:
- Around line 46-48: The SSR snapshot bridging logic in synoptik-view should be
extracted into a shared helper to match CockpitView and keep both views
consistent. Move the `live.kind === "loading" && initialData ? { kind: "cached",
data: initialData } : live` pattern into a reusable function such as
`bridgeWithSnapshot(live, initialData)`, then call that helper from
`SynoptikView` and `CockpitView` so any future changes to the transition
behavior happen in one place.

In `@frontend/lib/synoptic3d/placeholder-proportions.test.ts`:
- Around line 12-18: The known-classes coverage in the `proportionsFor` test is
missing `mixing_unit`, so add assertions for that entry alongside the existing
shape checks. Extend the `placeholder-proportions.test.ts` suite to verify
`proportionsFor("mixing_unit")` returns the expected `shape` and also covers its
dimension contract, matching the other known class cases.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ff36f704-8a7b-4af8-aa98-533722d001c4

📥 Commits

Reviewing files that changed from the base of the PR and between 3dfb62a and aa08660.

⛔ Files ignored due to path filters (1)
  • frontend/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (31)
  • frontend/app/(app)/overview/page.tsx
  • frontend/app/(app)/synoptik/page.tsx
  • frontend/components/cockpit/cockpit-view-switch.test.tsx
  • frontend/components/cockpit/cockpit-view-switch.tsx
  • frontend/components/cockpit/cockpit-view.tsx
  • frontend/components/synoptik/scene/colors.ts
  • frontend/components/synoptik/scene/floor.ts
  • frontend/components/synoptik/scene/lighting.ts
  • frontend/components/synoptik/scene/loaders.ts
  • frontend/components/synoptik/scene/placeholders.ts
  • frontend/components/synoptik/synoptik-legend.test.tsx
  • frontend/components/synoptik/synoptik-legend.tsx
  • frontend/components/synoptik/synoptik-machine-list.test.tsx
  • frontend/components/synoptik/synoptik-machine-list.tsx
  • frontend/components/synoptik/synoptik-scene.test.tsx
  • frontend/components/synoptik/synoptik-scene.tsx
  • frontend/components/synoptik/synoptik-view.test.tsx
  • frontend/components/synoptik/synoptik-view.tsx
  • frontend/lib/api/overview-snapshot.ts
  • frontend/lib/machine/grouping.ts
  • frontend/lib/synoptic3d/layout.test.ts
  • frontend/lib/synoptic3d/layout.ts
  • frontend/lib/synoptic3d/manifest.test.ts
  • frontend/lib/synoptic3d/manifest.ts
  • frontend/lib/synoptic3d/placeholder-proportions.test.ts
  • frontend/lib/synoptic3d/placeholder-proportions.ts
  • frontend/lib/synoptic3d/status-color.test.ts
  • frontend/lib/synoptic3d/status-color.ts
  • frontend/lib/synoptic3d/testing/fixtures.ts
  • frontend/lib/synoptic3d/types.ts
  • frontend/package.json

Comment thread frontend/components/synoptik/scene/lighting.ts
Comment thread frontend/components/synoptik/scene/placeholders.ts
Comment thread frontend/components/synoptik/synoptik-scene.tsx
Comment thread frontend/lib/api/overview-snapshot.ts
Comment thread frontend/lib/synoptic3d/testing/fixtures.ts Outdated
…Pick, Timeout)

- lighting.ts: PMREM-Render-Target (nicht nur .texture) freigeben — sonst bleiben
  Framebuffer/Renderbuffer des WebGLRenderTarget liegen.
- synoptik-scene.tsx: Klick von Kamera-Drag trennen (Distanz-Schwelle zwischen
  pointerdown und click) — eine OrbitControls-Rotation löst kein onSelectMachine
  mehr aus.
- placeholders.ts: den sichtbaren Status-Ring als Pick-Ziel registrieren, damit
  Klick/Hover genau auf der Statusfläche greifen.
- overview-snapshot.ts: SSR-Fetch mit AbortSignal.timeout(5s) absichern — ein
  hängendes Backend blockiert das Rendering nicht mehr (Node ≥ 20).
- fixtures.ts: Kommentar an die tatsächlichen Statuswerte angeglichen
  (drift_active vs. open_warning).

Gates grün: tsc 0, eslint 0, vitest 708, tokens synchron, next build ok.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@patricznr1

Copy link
Copy Markdown
Owner Author

CodeRabbit-Findings abgearbeitet (Commit f70b167)

Alle 5 Findings geprüft und gefixt:

Finding Datei Fix
🟠 PMREM-Render-Target-Leck scene/lighting.ts fromScene()-Target gehalten und envTarget.dispose() statt nur .texture — gibt Framebuffer/Renderbuffer mit frei
🟠 Klick vs. Kamera-Drag synoptik-scene.tsx Distanz-Schwelle (6 px) zwischen pointerdown und click → eine OrbitControls-Rotation löst kein onSelectMachine mehr aus
🟡 Status-Ring nicht pickbar scene/placeholders.ts Ring in pickTargets registriert (klick-/hoverbar)
🟠 SSR-Fetch ohne Timeout lib/api/overview-snapshot.ts AbortSignal.timeout(5_000) — hängendes Backend blockiert das Rendering nicht mehr
🟡 Kommentar/Daten-Mismatch lib/synoptic3d/testing/fixtures.ts Kommentar an die tatsächlichen Statuswerte (drift_active vs. open_warning) angeglichen

Gates grün: tsc 0 · eslint 0 · vitest 708 · next build ok.

…änzt

three (0 Dependencies) + @types/three samt Leaf-Deps in den unveränderten,
CI-grünen main-Lock eingefügt; der @emnapi/wasm-Optional-Baum bleibt byte-identisch
zu main. Vermeidet die npm-Versions-/Plattform-Diskrepanz, die beim vollständigen
Neu-Auflösen auf Windows @emnapi/wasi-threads bumpte (npm ci out of sync auf Linux).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@patricznr1
patricznr1 merged commit 2e1fd3e into main Jun 25, 2026
3 checks passed
@patricznr1
patricznr1 deleted the feat/synoptik-3d branch June 25, 2026 20:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant