Files
DOSSIER-STANDALONE/docs/design/tauri-architecture.md
T
karim 8fd8987b70 2D-Plan-Renderer auf WebGL2 (GPU) + akkumulierter Funktionsstand
Neuer GPU-Renderer fuer den Grundriss (src/plan/glPlan/): Earcut-Tessellierung
(konkav-faehig), gehrte Linienzuege (Miter), echte Papier-mm-Strichbreiten im
Massstab (repliziert den SVG-printStrokeVb-Pfad), Hybrid mit scharfem SVG-Text-
Overlay. GPU ist der Standardpfad; der SVG-Renderer bleibt automatischer Fallback,
falls WebGL2/Shader nicht verfuegbar sind. Imperativer Pan (rAF + CSS-transform)
fuer fluessige Interaktion ohne React-Re-Render je Frame.

Enthaelt zudem den bisher nicht committeten Arbeitsstand des Browser-BIM
(Oeffnungen, Treppen, Raeume, Decken, DXF-Export, Materialbibliothek, Kontext-
Import, Tauri-Compute-Boundary-PoC).
2026-07-02 00:12:39 +02:00

9.0 KiB
Raw Blame History

Architektur-Pivot: Tauri + Rust-Backend (2026-07-01)

Entscheidung

Alte Welt: Browser-CAD (React/Vite + WebGL/three.js)
Neue Welt: Desktop Tauri-App (React/Vite Frontend + Rust-Backend + wgpu 3D-Rendering)

Grund: Komplexe Möbel mit vielen Polygonen (100k+) + mehrere parallele rechenintensive Ops → WebGL/three.js wird zum Bottleneck. wgpu (low-level GPU-API auf Vulkan/Metal/DX12) + Rust-Compute skaliert native.

Scope: Desktop-only Release (Milestone 1). WASM-Fallback für Browser später wenn gebraucht.


Post-Migration Stack

Frontend (React/Vite — Komponenten + State, unverändert)

src/
  App.tsx                    ← Shell-Komponente
  compute/index.ts           ← Compute-Boundary (neu)
  model/types.ts             ← Semantisches Modell
  commands/                  ← Befehlssystem
  panels/                    ← UI-Panels
  plan/PlanView.tsx          ← 2D-SVG-Rendering
  viewport/Viewport3D.tsx    ← three.js 3D-Display
  ui/                        ← Topbar, Dialogs, etc.
  state/                     ← Redux-Slices (project, selection, view, layout)
  ...

Rolle: User-Input-Handling, 2D/3D-Darstellung (Display-Layer), State-Management.

Backend (Rust/Tauri — neu)

src-tauri/
  src/
    main.rs                  ← Tauri window + invoke-handler registration
    geometry.rs              ← compute_joins(), kernel2d(), etc.
    parsers/
      dwg.rs                 ← DXF/DWG-Geometrie-Parsing
      dxf.rs
    sia/
      room_detection.rs      ← detectRooms() (SIA-416)
    ...
  Cargo.toml                 ← Dependencies (serde, tauri, …)

Rolle: Rechenintensive Ops, Geometrie-Kernel, Parsing, SIA-Raumerkennung.

IPC: Tauri invoke (async, serde)

// Frontend ruft Rust auf
const result = await invoke<JoinInfo[]>('compute_joins', { walls, joints });

// Rust bearbeitet + serialisiert Ergebnis
#[tauri::command]
async fn compute_joins(input: JoinInput) -> Result<JoinOutput, String> {
  geometry::compute_joins(input).map_err(|e| e.to_string())
}

Compute-Boundary (Key Design)

Neue Datei: src/compute/index.ts — einziger Eingang für rechenintensive Ops.

// Beispiel-Schnittstellen
export async function computeJoins(walls: Wall[], joints: Array<[number, number]>): Promise<JoinInfo[]> {  }
export async function computeKernel2D(op: 'offset'|'trim', geom: Polyline, ): Promise<Polyline[]> {  }
export async function detectRooms(): Promise<Room[]> {  }
export async function parseShapeFromDwg(): Promise<DwgGeometry> {  }

Hinter der Boundary:

  1. Versuche Tauri invoke zu Rust (#[tauri::command])
  2. Fallback auf lokale TS-Impl wenn Rust nicht verfügbar (während Migration)

Effekt: Aufrufort im Code bleibt stabil; Caller sieht nicht, ob Op schon in Rust ist oder noch TS.

Migrationsfluss:

1. TS-Impl existiert (z.B. src/model/joins.ts)
2. Neue Op in Compute-Boundary mit Invoke+Fallback
3. Parallel: Rust-Impl in src-tauri/src/geometry.rs
4. Tests: Rust-Output == TS-Output (Parität)
5. TS-Impl bleibt (Fallback, wird nicht entfernt bis Rust stable)
6. Eventuell: TS-Impl löschen wenn Rust bewährt

Dev-Workflow (post-Tauri)

Development

# Terminal 1: Vite dev-server
npm run dev  # localhost:5173

# Terminal 2: Tauri dev
npm run tauri:dev  # öffnet Tauri-Fenster, zeigt auf localhost:5173
                    # Rust hot-reload + TS hot-reload gleichzeitig

Voraussetzungen:

  • Node.js + npm (wie heute)
  • Rust + Cargo (neu)
  • Tauri CLI: npm install -D @tauri-apps/cli

Build

# Single command
npm run tauri:build

# Erzeugt: 
# - Windows: src-tauri/target/release/cad.exe
# - macOS: src-tauri/target/release/bundle/macos/cad.app
# - Linux: src-tauri/target/release/bundle/deb/cad_*.deb (oder Flatpak)

Testing

# Rust-Unit-Tests
cargo test  # in src-tauri/

# TS-Tests (unverändert)
npm run test

# Integration-Test: App starten + Aktion prüfen
npm run tauri:dev  # manuell testen oder Puppeteer-Probe erweitern

GPU-Strategy (für später)

Milestone 1 (jetzt): CPU-Ops in Rust (kernel2d, joins, parsing, SIA).

Milestone 2 (später): GPU-Compute via wgpu

  • Tauri + wgpu Renderer (optional, nicht erforderlich)
  • ODER drei.js bleibt, Rust handelt CPU-Ops, three.js handelt Display
  • GPU-Heavy-Ops (z.B. große Boolean-Operationen) können in wgpu laufen, aber MVP braucht das nicht

Aktueller Plan: three.js bleibt für 3D-Display (skaliert ausreichend für Möbel-Geometrie mit Instancing + LOD).


Migration Strategy: Ops nach Priorisierung

Phase 1 (aktuell — Tauri-Shell + Proof-of-Concept):

  • computeJoins (Wand-Eckverbindungen) → Rust
    • Gründe: klein, häufig, zeigt invoke-Flow

Phase 2 (nächst):

  • kernel2d (Offset/Trim/Extend/Fillet) → Rust
    • Gründe: Rechenlast , Frequenz hoch
  • DXF/DWG-Parser → Rust (Geometrie-Extraktion)
    • Gründe: Rechenlast , Frequenz mittel (Import-Dialog)

Phase 3 (später):

  • detectRooms (SIA-416 Raumerkennung) → Rust
    • Gründe: Rechenlast , async-freundlich
  • booleanOps (Union/Differenz/Schnitt) → Rust
    • Gründe: Rechenlast , Frequenz gering (ad-hoc)

Folgen für bestehenden Code

Was ändert sich NICHT

  • src/model/types.ts — semantisches Modell bleibt in TS (Frontend kennt es)
  • src/state/ — Redux-Store unverändert
  • src/ui/ — Komponenten unverändert
  • src/plan/PlanView.tsx — SVG-Rendering unverändert
  • src/viewport/Viewport3D.tsx — three.js-Rendering unverändert
  • src/commands/ — Befehlssystem unverändert

Was ändert sich

  • Neue src/compute/index.ts — alle rechenintensiven Ops laufen durch hier
  • Neue src-tauri/ — Rust-Backend
  • Vite-Config: Tauri plugin hinzufügen
  • Package.json: tauri scripts hinzufügen
  • Build-Prozess: npm run tauri:build statt npm run build

Was wird migriert (schrittweise)

  • src/model/joins.tssrc-tauri/src/geometry.rs (Phase 1)
  • src/geometry/kernel2d.tssrc-tauri/src/geometry.rs (Phase 2)
  • src/io/{dxfParser, dwgParser}.tssrc-tauri/src/parsers/ (Phase 2)
  • src/geometry/{roomArea, roomBoundary}.tssrc-tauri/src/sia/room_detection.rs (Phase 3)
  • src/editors/booleanOps.tssrc-tauri/src/geometry.rs (Phase 3)

Wichtig: TS-Versionen bleiben als Fallback (nicht gelöscht).


Distribution (später)

Desktop Binaries (post-Tauri)

  • Windows: .exe (standalone executable)
  • macOS: .app bundle (code-signed)
  • Linux: .deb package ODER Flatpak (preferred)
    • Flatpak = moderne WebKitGTK6 immer dabei, unabhängig von Distro-Alter

Browser (wenn gebraucht)

  • WASM-Fallback für src/compute/ Ops (Rust → WASM via wasm-bindgen)
  • Later-phase feature, nicht Milestone 1

Technische Details

Serialisierung (TS ↔ Rust)

serde + serde_json für Geometrie-Typen:

// Rust
#[derive(Serialize, Deserialize)]
pub struct Vec2 { pub x: f64, pub y: f64 }

#[derive(Serialize, Deserialize)]
pub struct Wall {
    pub id: String,
    pub start: Vec2,
    pub end: Vec2,
    // …
}
// TS (type-safe invoke)
interface Vec2 { x: number; y: number }
interface Wall { id: string; start: Vec2; end: Vec2; /* … */ }

await invoke<JoinInfo[]>('compute_joins', { walls: Wall[] })

Tauri Security (default)

  • Invoke-Handler sind Rust-side validiert
  • Whitelist-Makro (#[tauri::command]) registered nur explizit erlaubte Functions
  • CORS/CSP Policy default secure
  • Keine arbitrary-Script-Execution (native app)

Abhängigkeiten (neu post-Tauri)

Frontend (npm)

  • Bestehende: react, vite, three.js, redux, etc.
  • Neu: @tauri-apps/api (JS-SDK für invoke)
  • Optional später: @tauri-apps/cli dev-dependency (bereits in package.json)

Backend (Cargo)

[dependencies]
tauri = { version = "2", features = ["webkit2gtk-6.0"] }  # GTK4
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
# später: wgpu, delaunator, opencascade-sys, etc.

System

  • Rust 1.70+
  • GTK4 dev libraries (Linux only, auto-handled by Tauri)
  • Xcode Command Line Tools (macOS, auto-checked)

Next Steps (Koordination)

Aufgabe für nächste Phase: → Siehe docs/design/tauri-migration-plan.md (Schritt-für-Schritt, vier parallele Agents)

HANDOVER.md: wird aktualisiert nach Tauri-Shell stabil.


FAQ

Q: Läuft die App noch im Browser?
A: Nein (Milestone 1). Desktop-only. WASM-Fallback für Browser später wenn gebraucht.

Q: Was passiert mit dem existing TS-Code?
A: Bleibt unverändert (außer neue Compute-Boundary). TS-Implementierungen = Fallback bis Rust stabil.

Q: Muss ich Rust können um das Projekt zu verstehen?
A: Nein. Frontend bleibt React/TS. Rust ist "blackbox" hinter invoke. Aber bei Rust-Bugs muss man rein.

Q: Wann ist Tauri-Shell fertig?
A: Nach den vier Agents (Schritt 14 in tauri-migration-plan.md), ~12 Wochen.

Q: Kann ich lokal testen?
A: Ja, npm run tauri:dev öffnet lokale App. Alles wie heute, nur Rust hinten dran.