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).
9.0 KiB
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:
- Versuche Tauri invoke zu Rust (
#[tauri::command]) - 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ändertsrc/ui/— Komponenten unverändertsrc/plan/PlanView.tsx— SVG-Rendering unverändertsrc/viewport/Viewport3D.tsx— three.js-Rendering unverändertsrc/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:buildstattnpm run build
Was wird migriert (schrittweise)
src/model/joins.ts→src-tauri/src/geometry.rs(Phase 1)src/geometry/kernel2d.ts→src-tauri/src/geometry.rs(Phase 2)src/io/{dxfParser, dwgParser}.ts→src-tauri/src/parsers/(Phase 2)src/geometry/{roomArea, roomBoundary}.ts→src-tauri/src/sia/room_detection.rs(Phase 3)src/editors/booleanOps.ts→src-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:
.appbundle (code-signed) - Linux:
.debpackage 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/clidev-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 1–4 in tauri-migration-plan.md), ~1–2 Wochen.
Q: Kann ich lokal testen?
A: Ja, npm run tauri:dev öffnet lokale App. Alles wie heute, nur Rust hinten dran.