Ersetzt den Tauri-Webview-Weg testweise durch eine Electron-Shell (randlos, ohne native Menüleiste, wie chromium-shell.sh), damit die WASM/WebGPU-Engine zuverlässig laeuft statt in WebKitGTK. Rust-Backend nicht noetig, da compute_joins einen TS-Fallback hat. npm run electron zum Starten.
67 KiB
HANDOVER — Browser-BIM (cad), Standalone-Port von DOSSIER
Für die nächste Instanz. Stand: 2026-06-29. Lies zuerst
CONVENTIONS.md,ROADMAP.mdund die Projektnotizen (siehe unten).
>>> COMMIT-REGEL (verbindlich, IMMER beachten) <<<
Dieses Repo darf keinerlei Hinweise auf KI-Werkzeuge enthalten — weder im Code/Doku noch in der Git-Historie.
- Commit-Messages: sachlich, in der Sprache des Projekts. NIEMALS
Co-Authored-By:-Trailer, „Generated with …"-Zeilen, Tool-/Modellnamen oder sonstige Urheber-Hinweise auf einen Assistenten. - Dateien/Kommentare: keine Erwähnung von Assistenten, Modellen oder Agenten. Wer hier weiterarbeitet, schreibt so, als wäre es Handarbeit des Teams.
- Vor jedem Push kurz prüfen:
git logundgit difffrei von solchen Spuren.
>>> KOORDINATION & MEMORY (bei mehreren Instanzen/Agents) <<<
Mehrere Hauptinstanzen gleichzeitig:
- Git: nur eine Instanz committet/pusht auf
master, ODER jede arbeitet auf eigenem Branch und merged kontrolliert.App.tsx/types.tsist der serielle Flaschenhals — verschiedene Features ≠ dieselbe Datei. - Dieser HANDOVER ist der Koordinationskanal zwischen Instanzen (liegt im Repo, wird mitgepusht). Stand hier kurz festhalten, bevor du übergibst.
Subagents:
- Bekommen kein Memory automatisch — nur was im Prompt steht. Regeln (v. a. die COMMIT-REGEL oben) explizit mitgeben, sonst kennt der Agent sie nicht.
- Agents nicht committen und nicht ins Memory schreiben lassen. Sie liefern Diffs/Dateien/Ergebnisse zurück; die Hauptinstanz committet und pflegt das Gedächtnis.
Memory (~/.claude/..., außerhalb des Repos — leakt nie hierher):
- In den Kontext geladen wird nur der schlanke Index (eine Zeile je Eintrag); einzelne Fakten erscheinen nur bei Relevanz. Größe ist daher selten ein Problem.
- Keine automatische Bereinigung. Gepflegt wird beim Schreiben (Duplikate aktualisieren statt anlegen, Überholtes löschen) oder auf Ansage.
- Nur beständige Fakten ablegen, ein Fakt pro Datei, Index-Zeile knapp. Bei parallelen Schreibvorgängen ist der Index (MEMORY.md) die Contention-Stelle — vor dem Edit frisch lesen (der „modified since read"-Guard verhindert blindes Überschreiben).
>>> ENGINE-NORDSTERN (User-Direktive 2026-07-02): die volle Engine-Vision <<<
Der User hat explizit beauftragt, die Engine-Vision KOMPLETT anzustreben ("wir brauchen exakte breiten usw. strebe bitte das komplett an!"). render2d/render3d sind nicht nur Viewport-Ersatz, sondern werden die EINZIGE Render-Wahrheit des CAD:
-
Papier-mm-exakte Strichbreiten überall — Bildschirm bei jedem Maßstab/Zoom = Druck.
-
Deterministische Plan-Ausgabe: Druck/PDF mm-genau identisch zum Bildschirm, beides aus render2d (kein separater Druckpfad). Vektor-PDF-Backend = dieselbe Szene, anderes Target.
-
Headless-Rendering: PNG/PDF-Export und Golden-Image-Tests ohne Fenster (die serde-only/GPU-Trennung in render2d existiert genau dafür; wgpu kann offscreen).
-
HLR/Schnitt-Pipelines durch die Engine (render3d → Kantenextraktion → render2d-Szene).
-
Eine Wahrheit: SVG-/WebGL2-Geometriepfade im Browser schrittweise durch die WASM/WebGPU-Engine ersetzen (
?engine=wasm-Spike ist der Anfang); SVG bleibt nur Interaktions-/Overlay-Schicht. Bereits gefundene Duplikations-Bugs: Wandecken-Kerben, fehlende Strichelung im WebGL2-Pfad. -
WebKit-Unabhängigkeit (explizit vom User betont): kein Render- oder Ausgabepfad darf von WebKitGTK abhängen. Brücke = Chromium-Shell (
npm run shell), Endzustand = All-Native (ein Rust-Prozess, Engines + natives UI, kein Webview).
RICHTUNGSENTSCHEIDUNG 2026-07-02: Electron statt Tauri, all-native aufgeschoben. Abgewogen mit dem User: (a) „auf Tauri bleiben" = WebKitGTK, das WEDER WebGPU (kein WASM- Viewport) NOCH native-wgpu-Composite ins Fenster (Wayland tot) kann → Engine nur als separate Fenster möglich, kein integrierter Viewport. (b) „all-native jetzt" = kein Shortcut, sondern das GRÖSSERE Rewrite: ~46k Zeilen TS (UI ~18k + Modell-Gehirn ~5k + Interaktion ~23k) müssten nach Rust; die Rust-Engines sind erst ~10% der App. → Gewählt: Electron/Chromium-Shell + WASM/WebGPU-Engine im Webview (behält die funktionierende React-UI, verlässt WebKitGTK, integrierter Engine-Viewport möglich). Die Engine-Rust-Crates sind in einem späteren All-Native- Schritt 1:1 wiederverwendbar; nur die dünne WASM-Bindeschicht wäre dann Wegwerf. All-native bleibt legitimes Fernziel, ist aber KEIN Weg zurück zu Tauri (Tauri IST der Webview-Shell).
ELECTRON-PROTOTYP: FERTIG (2026-07-02). <<<
electronals devDep,scripts/electron-main.cjs(BrowserWindow,Menu.setApplicationMenu(null)
frame:false/autoHideMenuBarfür randloses Fenster wie chromium-shell.sh, WebGPU-Flagsenable-unsafe-webgpu+enable-features=Vulkan),scripts/electron-shell.sh(Dev-Server-Guard wie chromium-shell.sh), npm-Scriptnpm run electron. Verifiziert per Screenshot: App startet als eigenes randloses Fenster, lädt den echten Grundriss (nicht leer). WICHTIG:
- Datei muss
.cjssein (package.jsonhat"type":"module", Electron-Main läuft als CJS). ELECTRON_RUN_AS_NODE=1kann aus dem umgebenden Prozess (z.B. VSCode-Electron-Host) vererbt sein — zwingt Electron in den Node-Modus (require('electron')liefert nur einen Pfad-String statt{app,...}→appist undefined). Immer mitenv -u ELECTRON_RUN_AS_NODEstarten, falls das Fenster nicht öffnet /app.commandLineundefined ist.- WebGPU/
?engine=wasmin Electron auf diesem System (niri/Wayland) fällt auf WebGL2 zurück (Ozone-Wayland+Vulkan-Warnung beim Start).--ozone-platform=x11GEHT NICHT (bricht die Fenstererstellung komplett — GetGeometry/Vulkan-Surface-Fehler). System-Chromium (chromium-shell.sh) rendert die WASM-Engine hingegen nachweislich (siehe wasm-engine-viewport- Notizen); die verwendete Electron-Version (Paket sagt ^43,--versionmeldet v24 — Versions- Mismatch, ggf. stale Binary-Cache) könnte ein älteres/anders konfiguriertes Chromium mitbringen. TODO nächste Session: Electron-Version/Ozone-Flags weiter untersuchen, bevor der Prototyp der primäre Dev-Weg wird — bis dahin bleibt WebGL2-Fallback der Standardpfad, funktional unverändert. Danach: render3d-WASM, Doppeltext-Fix.<<< Klarstellung an den User (er fragte, ob Webview = „billig"): NEIN — Figma (eigene C++/WASM-Engine im Web-Shell), Onshape, VS Code zeigen, dass „eigene Engine + Web-UI" Top-Tier-Architektur ist. CAD/BIM-Substanz = Modell + Engine + Normen (haben wir: parametrische Wände, SIA 416, DOSSIER- Ebenen, ein-Modell→alle-Sichten), NICHT der Fenster-Shell.
Praxisregel ab jetzt: Darstellungs-Features NICHT mehr mehrfach (SVG/WebGL2/nativ) bauen, sondern einmal in der Engine + dünne Anbindungen.
>>> AUFGABE FÜR NEUE INSTANZ: 2D-Plan auf WebGL-GPU-Renderer (ZUERST) <<<
Warum: Tauri-Linux-Webview = WebKitGTK, das SVG/2D auf der CPU (Cairo) rastert. User-GPU (AMD RX 7800 XT) langweilt sich; bei 144 Hz (~6,9 ms/Frame) ruckelt Pan/Zoom/ Objekt-Bewegen sichtbar. three.js/WebGL (3D) läuft GPU-beschleunigt → NUR der 2D-SVG-Pfad ist CPU-gebunden. Entscheidung mit User: 2D-Plan von SVG auf WebGL2 (GPU) umbauen.
Sofortlösung fürs Vorführen/Entwickeln — Chromium-App-Shell: npm run shell
(scripts/chromium-shell.sh) startet bei Bedarf den Vite-Dev-Server (Port 5187, Polling per
curl) und öffnet ihn dann in einem randlosen Chromium-Fenster (--app=…, eigenes Profil unter
~/.cache/cad-chromium-shell), statt im WebKitGTK-Webview von tauri:dev. Chromium rendert
dieselbe Seite GPU-beschleunigt und spürbar flüssiger. Kein Ersatz für den nativen wgpu-Pfad
(render2d/render3d), aber ein schneller Weg zu einer ruckelfreien Oberfläche, solange der
Electron/CEF-Shell (siehe Notizen zu „Render path decision") noch aussteht. Läuft rein im
Browser ohne Tauri-Backend — src/compute/index.ts guardet den einzigen invoke()-Aufruf
bereits per dynamischem Import mit TS-Fallback.
Architektur (mit User abgestimmt):
- Hybrid: WebGL2-Canvas rendert die schwere Geometrie (Poché-Polygone, Linien, Schraffuren, Kreise/Bögen als Segmente). Dünne SVG-Ebene DARÜBER behält Text (Raumstempel/Labels), Griffe, Snap-Marker, Werkzeug-Vorschau (wenige Elemente → billig, DOM-Hit-Test + scharfer Text bleibt).
- Raw WebGL2, KEINE neue npm-Dependency (User will nicht „abhängiger" werden; nativ).
- Geometrie pro Plan EINMAL tessellieren (Cache), Pan/Zoom = nur Transform-Matrix-Uniform → keine Re-Tessellation, GPU-buttrig. Objekt-Bewegen: Plan ändert sich → re-tessellieren (leichter als SVG-Reconcile+Cairo).
- Linienbreite konstant in Screen-px (wie heutiges
non-scaling-stroke): im Vertex-Shader expandieren (Position world → clip, dann Normalen-Offset in clip via Viewport-px). Miter an Ecken später; Spike: Quads pro Segment. - SVG-Renderer als Fallback hinter einem Flag behalten, bis GL-Parität erreicht → kein Risiko.
- Vorgehen: erst Spike (Linien+gefüllte Polygone + GPU-Pan/Zoom), Glätte bei 144 Hz messen
(dev :5187 läuft;
tauri:dev-Fenster läuft), DANN Schraffur/Feinschliff/Text-Overlay/Hit-Test.
Fixpunkte im Code:
src/plan/PlanView.tsx(~2500 Z.):toScreen()= Modell-m → viewBox-Einheiten, FIXER Ursprung,PX_PER_M=90;view={x,y,w,h}treibt<svg viewBox>; Pan = setView, Zoom = setView(onWheel). BEREITS optimiert:primitiveEls/drawingRunElsuseMemo(Pan/Zoom 312→0 Re-Renders) + rAF-Coalescing beim Objekt-Drag (flushDragMove/enqueueDragMove, 40→1 Update/Frame). Diese bleiben nützlich; der GL-Renderer ersetzt die SVG-Primitiv-Ebene, NICHT die Interaktions-Logik/Griffe.src/plan/generatePlan.ts:export type Primitive(Z.133) — kinds:polygon{pts,fill,stroke, strokeWidthMm,hatch,*Id},line{a,b,weightMm?,strokeWidthMm?,dash?,color,cls,greyed,drawingId?},arc{center,r,…},text{at,doc,extraLines,basePt,color} (Text → SVG-Overlay, NICHT WebGL).- Koordinaten/Breiten-Logik im SVG-Renderer:
PrimitiveShape(~Z.2280) +DrawingRunShape— dort steht, wie Haarlinie/mm/paperScale/non-scaling-strokedie Strichstärke bestimmen (für GL nachbilden). - Hit-Test/Auswahl/Griffe laufen weiter über die bestehenden PlanView-Pfade (modellbasiert); GL ist nur Anzeige.
- Vektor-PDF/-Export bleibt (kommt aus
generatePlan/DXF, nicht aus der Anzeigefläche) — NICHT anfassen.
Gates: npx tsc -b 0, npm run build grün, Trace-Scan sauber (keine KI-Spuren, COMMIT-REGEL oben).
Kein Commit ohne Ansage. Verifizieren wie üblich per Puppeteer gegen :5187 (Render korrekt + Glätte messen).
GESAMT-TODO-LISTE (Stand 2026-07-01 Nacht) — im Hinterkopf behalten:
ERLEDIGT+verifiziert: U/I/O/P-Kopiermodi · Backlog#1 Transform→CommandLine · Backlog#4 3D-Zeichnen +
Engine-Confirm-Bugfix · Raumstempel#2 (Feld-Modell) · Plan-Perf (Memo + rAF-Coalesce) · Tauri-M1-PoC
(geometry-Crate 4/4 + Parität + tauri:dev-Boot). OFFEN: (A) 2D-WebGL-Renderer [DIESE AUFGABE] ·
(B) Tauri-M1 Rest: Compute-Boundary in Render-Pfad einhängen (generatePlan sync → precompute+cache) +
nächste Ops (kernel2d→DXF/DWG→detectRooms) · (C) three.js→wgpu (M2, nach 2D-WebGL) · Parametric Walls
Phase B (andere Instanz) · Wand-Referenzlinien-Option unter Bezugspunkt · Viewport/Editier-Welle
(Treppen-Griffe, Öffnung-entlang-Wand, 2D auf Zeichenebenen, runde Linienenden, schattiert-Politur) ·
Smart-Join/Split + nahtfreie Wandverschneidung · Text/Stempel-Annotation (Frame+Rotation) · Welle B
(3D-Schnitt+Stencil-Capping) · Welle C (HLR verdrahten) · Overrides/Ausschnitte/Multi-Page-Layouts.
>>> STAND 2026-07-01 (Tauri-PoC — App-frei, gelandet) <<<
Tauri v2 + Rust-Compute-Boundary — Proof-of-Concept steht (3 App-freie Agents).
Alle Gates grün, nichts an App.tsx/src/model/ angefasst (nur NEUE Dateien +
additive Config). Ref: docs/design/tauri-migration-plan.md / tauri-architecture.md.
src-tauri/(Rust, neu): Cargo-Workspace aus zwei Crates:src-tauri/geometry/— serde-only Lib, Port voncomputeJoins(aussrc/model/joins.ts) inkl. Vektor-Helfer. Input flach:WallInput{ id,start,end, thickness,referenceOffset }; OutputWallCuts{ wallId,startCut,endCut }(Line= point+dir).cargo testgrün: 4/4 (L-Ecke=geteilte Gehrung, freies Ende, T-Stoss, kollinear → alle korrekt). Braucht KEIN webkit → hier testbar.src-tauri/App-Crate (cad-tauri) — Tauri-v2-Shell (lib.rsmit#[tauri::command] compute_joins+run(),main.rs,build.rs,tauri.conf.jsondevUrl :5187,icons/icon.png).cargo checkGRÜN — wider Erwarten NICHT von webkit blockiert: tauri v2 bindetwebkit2gtk-4.1(vorhanden); nur-6.0fehlte.src-tauri/target+gen/sind Build-Artefakte (gitignored).
src/compute/index.ts(neu, Boundary): einzige Stelle für schwere Ops.computeJoins(project,walls)flacht ab →invoke("compute_joins")(geguardeter dynamischer Import von@tauri-apps/api/core, Build bleibt grün OHNE das Paket) → bei null/Fehlerconsole.warn+ TS-Fallback (joins.ts). Zusätzlich DurchreicherdetectRooms(roomBoundary.ts) +parseShapeFromDwg(=parseDwg);computeKernel2Dbewusst ausgelassen (kein Einzel-Entry, ~30 Primitive).package.json/vite.config.ts:@tauri-apps/cli+api(v2) installiert, Scriptstauri/tauri:dev/tauri:build; vite Port 5187strictPort,clearScreen:false,envPrefix— rein additiv.
NÄCHSTE SCHRITTE (Tauri): (1) Echte TS↔Rust-Numerik-Parität end-to-end prüfen
— erst sinnvoll, wenn die Boundary in einen Caller verdrahtet ist (aktuell bewusst
NICHT verdrahtet, weil das generatePlan/App async machen würde). (2) computeJoins
in den Wand-Render-Pfad einhängen (async-Welle). (3) tauri:dev end-to-end auf einer
Maschine MIT webkit2gtk (hier nur cargo check, kein Fenster-Boot getestet).
(4) Nächste Ops laut Plan: kernel2d → DXF/DWG → detectRooms.
>>> STAND 2026-07-01 (Parametric Walls Phase A — ISOLIERT) <<<
Neue Instanz (Opus) — Parallelisierung mit Agents (Sonnet):
- Branch:
feature/parametric-walls(isoliert, keine App.tsx-Änderungen) - Phase A FERTIG (alle Agents grün):
- Agent 1: Types (
ParametricWall, 5ParametricRuleVarianten) + Engine (resolveParametricWall(), 5 rule handlers, helpers) insrc/model/parametricWalls.ts - Agent 2: 50 Unit-Tests (Vitest), alle grün;
npm test -- parametricWalls.test.ts - Agent 3: Design-Doku
docs/design/parametric-walls.md+docs/README.mdaktualisiert - Verification:
tsc -b✓,npm run build✓ (577 modules, 3.72s)
- Agent 1: Types (
- Phase B (UI-Integration) — für nächste Instanz mit Agents:
- Agent 1: TopBar ParametricWall-Picker + UI-Komponente
- Agent 2: Command
pw(cmds/parametricWall.ts) - Agent 3: ResourceManager-Integration (ParametricWall CRUD)
- Dann merge →
master, Screenshot-Verifikation
- Koordination: andere Instanz committet parallel (Text, Raum, HLR) auf
master, keine Konflikte (nurtypes.ts+src/model/erweitert, nichtApp.tsx).
Backlog #4 ERLEDIGT (Zeichnen im 3D-View — vorherige Instanz): Werkzeug-Gate toolsEnabled
(App.tsx ~1877) von viewType === "grundriss" auf activeLevel.kind === "floor" erweitert → Werkzeuge sind jetzt AUCH in der Perspektive aktiv. Die
gesamte Zeichen-Pipeline war bereits verdrahtet (Viewport3D.workplaneModel()
raycastet den Cursor auf die Geschoss-OKFF; onWorkplanePoint/onWorkplaneConfirm
speisen dieselbe Engine wie der Grundriss). Ende-zu-Ende per Puppeteer verifiziert:
in iso-Ansicht Linie mit 2 Klicks gezeichnet → committet (draw2d 0→1, Prompt
zurück auf „Befehl:"); Picks liefern gültige Modell-Vec2 (raycast korrekt).
-
BUG-FIX unterwegs (Engine-Confirm,
src/commands/engine.tsconfirm()): Beim Testen von #4 fiel ein VORBESTEHENDER Bug auf (reproduziert IDENTISCH im Grundriss, nicht durch #4 verursacht): mehrteilige Befehle (Wand/Polylinie) liessen sich per Enter/Rechtsklick NIE abschliessen. Ursache:confirm()nahm IMMER den Tab-Feld-Zweig (fieldResultPoint), sobald der Schritt Felder hatte — auch OHNE gelocktes Feld → es wurde ein Cursor-Punkt gefüttert (bei Wand: Null- Strecke, ignoriert) stattonConfirm(das den Zug committet) aufzurufen. Fix: Feld-Zweig nur noch bei tatsächlich GELOCKTEM Feld (`Object.keys(this.locks).length0
); ohne Lock fälltconfirm()aufonConfirmdurch. Verifiziert: Wand schliesst jetzt per Rechtsklick im Grundriss (91→98) UND in 3D (99→106); Tab-Feld- Fluss „Länge 4 tippen → Enter lockt → leeres Enter setzt Punkt" unverändert; Linie-Auto-Commit (2 Klicks) unverändert. Gegatet:tsc -b0,build` grün, keine Konsolenfehler. KEIN Commit. -
Backlog #1 ERLEDIGT (Befehlsleiste-Transform vereinheitlicht): Die laufende Auswahl-Transformation (nur noch
rotate/Tastedmit U/I/O/P; move/mirror laufen längst über die Engine) speist jetzt dieCommandLinestatt der schwebendenTransformBar. Dritter Zweig in der<CommandLine>-Ternäre parallel zugripEdit(gripEdit ? … : activeTransform ? … : engineView…): Prompt =transform.hint.${op}.${…}, Inline-Optionen = U/I/O/P (transformOptions(), aktiver Modus hervorgehoben via neuemactive?-Feld anCommandLineOption+.cmdline-option.activein styles.css,×countbei array/distribute), Live-/ lockbares Winkel-Feld beim Drehen bzw. Distanz beim Bewegen (transformFields()aus neuemtransformDragInfoRef), getippte Zahl committet übersubmitTransformValue().dfokussiert die CommandLine (wiem/s).src/ui/TransformBar.tsxgelöscht; verwaiste.transform-bar/.tf-*-CSS +transform.bar-Key harmlos stehen gelassen. Gegatet:tsc -b0 Fehler,buildgrün, Trace-Scan sauber, Puppeteer-Probe end-to-end (nachd: „Drehzentrum klicken" + U/I/O/P; nach Zentrum+Bezug: „Zielwinkel klicken" + Live-Winkelfeld; keine Konsolenfehler). KEIN Commit (Konvention der Vorsessions beibehalten).
>>> STAND 2026-07-01 (Abend) — Raum + Topbar-Umbau + Backlog — ZUERST lesen <<<
Alle unten genannten Agenten GRÜN gelandet und gegatet (tsc -b 0 Fehler,
npm run build grün, Trace-Scan sauber, Boot-Probe ohne Konsolenfehler). Dev-
Server läuft/hält auf :5187. KEIN Commit gemacht (Commit-Regel oben beachten).
Diese Session gelandet:
- Rich-Text-Kern (komplett):
src/text/richText.ts(Marks/RichTextDoc/TextRange, toggleMark/applyMark/isMarkActive/DEFAULT_PRESETS/serialize…),src/text/renderHtml.ts(docToHtml/docToLines/docToSvgText),src/text/RichTextEditor.tsx(contentEditable, Toolbar B/I/U/S + Grösse/Farbe/Presets). - Raum-Slice (SIA-416), Agent gelandet:
Roominmodel/types.ts(id, floorId, categoryCode "60", siaCategory HNF/NNF/VF/FF/KGF, boundary, stampAnchor?, stampDoc?);cmds/room.ts(Modus inside=click-inside viaroomFromPointInside, manual=Polylinie); Plan: neuestext-Primitive + Füllpolygon + Stempel viadocToLines+ Live-Fläche;panels/RoomBalancePanel.tsx(SIA-Bilanz + CSV). App-State für Stempel:selectedRoomId/selectedRoom.stampDoc,projectSlice.setRoomStampDoc(roomId,doc),moveRoomStamp,setRoomStampAnchor,stampEditorRoomId. Stempel-Editor = kleines schwebendes Fenster (kein Footer). - DOSSIER-Referenz studiert → Spec
docs/design/topbar-dossier.md(verbindlich für Topbar-Arbeit; Referenz-Klon lag unter/tmp/DOSSIER). Kernbefund: Text-Styling ist im Original eine FEST in der Oberleiste sitzende Text-Gruppe (Stil/Font/Grösse + B/I/U + L/C/R + „+Text"), Akzent-Glow bei Auswahl; Raumstempel-Typografie darüber; Text-INHALT in eigenem kleinem Fenster; Zoom/Massstab als 2×2-Cluster (kombinierte Stat-Pille). - Topbar-Umbau (Agent gelandet),
src/ui/TopBar.tsx+styles.css+App.tsx+ui/TextEditorDialog.tsx(neu) + i18n: Zoom-Doppelung entfernt; 2×2-Massstab/Zoom- Cluster; einheitliche Segmentpillen (neueSegment-Komponente); Text-Gruppe in der Topbar (textTarget-Prop =null | {doc,range,apply}, aus selektiertem Raum abgeleitet,apply→setRoomStampDoc; ohne range wirkt Format auf ganzes Doc); Doppelklick öffnetTextEditorDialog. Verwaiste alte CSS-Regeln (.tb-zoom*,.stamp-editor*) bewusst stehen gelassen (harmlos). „+ Text"-Button verdrahtet, aber DEAKTIVIERT (noch kein Text-Annotations-Werkzeug).
Backlog / nächste Schritte (Priorität dieser Session, siehe auch Todo-Liste):
- Befehlsleiste-Transform vereinheitlichen: laufende Transformation (move/mirror/rotate)
soll die
CommandLinespeisen (Prompt „Basispunkt/Zielpunkt" + U/I/O/P als Inline- Optionen) statt der separaten schwebendenTransformBar; freies Befehl-Tippen während der Geste unterdrücken, Zahleneingabe (Distanz/Winkel) viafieldsbleibt. Muster: parallel zum bestehendengripEdit-Zweig bei<CommandLine>(~App.tsx:2793). U/I/O/P-Routing (App.tsx ~1543–1548) NICHT kaputt machen — nur zusätzlich in die CommandLine spiegeln. - Strukturierter Raumstempel (DOSSIER
RaumProperties): Stempel ist KEIN Freitext, sondern ein FELD-Modell: Raumnummer · Raumname · Raumname-Zeile2 (in Listen als ein Name zusammengezogen) · Bodenfläche (an/aus + Präfix) · Fensterfläche (an/aus + Präfix) · Nutzung HNF/… (an/aus). Zeilen-Layout-Editor (welches Feld auf welche Zeile) + Typografie PRO Feld-Einheit (Raumname grösser, andere kleiner, eine Zeile kursiv). Ersetzt den Freitext-stampDoc-Zwischenstand; die Topbar-Text-Gruppe formatiert dann die gewählte Feld-Einheit (löst auch die „ganzes Doc statt Selektion"-Einschränkung). - Wand-Optionen: Referenzlinien-Option UNTER den Bezugspunkt setzen, gleiche Optik/
Anordnung wie die übrigen Optionen (
cmds/wall.ts/ ToolsPanel-Optionsreihenfolge). - Zeichnen im 3D-View: Cursor per Raycast auf die Arbeitsebene (okff des Geschosses)
projizieren → Weltkoordinaten als
engine.move/pickeinspeisen;toolsEnabled-Gate (App.tsx ~1834, heuteviewType==="grundriss") auch für Perspektive öffnen. - Viewport/Editier-Welle: Treppen-Griffe (App.tsx grips-memo hat keinen stair-Fall),
Öffnung entlang Host-Wand verschieben (kein opening-Handler im Body-Move;
moveOpeningByfehlt), 2D-Tools auf Zeichnungsebenen (toolsEnablederweitern + Bau-Tool-Buttons grauen), runde Linienenden (stroke-linecap:roundauf offene Linien), „schattiert"-Politur (ACES-Tonemapping+sRGB, HemisphereLight/RoomEnvironment-PMREM, MeshLambert→MeshStandard inViewport3D.tsx~416–449). - Smart-Join/Split + NAHT-FREIE Wandverschneidung (Poché-Union an Stössen, keine sichtbare
innere Naht, Gehrung/T-Stoss). 7. Text/Stempel-Annotation (aktiviert „+Text";
Frame+Rotation). 8. Welle B (3D-Schnittebene + Stencil-Capping + Schnittschraffur).
9. Welle C (HLR verdrahten;
src/section/hlr.tsbereit). 10. Overrides/Ausschnitte/ Multi-Page-Layouts.
Kollisions-Regel bestätigt: App.tsx, types.ts, generatePlan.ts, Viewport3D.tsx,
registry.ts, PlanView.tsx, i18n, styles.css sind Hotspots → nur EIN App.tsx-Agent pro
Welle; parallele Tracks nur auf genuin App-freien neuen Modulen.
>>> STAND 2026-07-01 (Bug-Batch Runde 1) — ZUERST lesen <<<
Runde-1-Agenten alle GRÜN gelandet (tsc -b + build + Probe verifiziert):
- 3D-Editier-Kamera-Bug (kritisch,
src/viewport/Viewport3D.tsx): Ursache = schwerer Szenen-Aufbau-Effekt mitproject-Dependency → jede Griff-Mutation baute Szene neu auf undapplyView3dresettete die Kamera auf Preset (→ „springt in Top-View", Rechts/Links-Pan-Illusion). Fix:camStateRef-Snapshot (Pos/Target/up/ortho-Zoom/aktive Kam) im Render-Loop fortgeschrieben, bei Neuaufbau WIEDERHERGESTELLT stattapplyView3d;applyView3dnur beim ersten Aufbau;view3d-Effekt guarded viagripDragRef; Top-ViewenableRotate=false; 2D-Drawings bekommenmove-Griff (Anker=center/at) → in 3D verschiebbar. Kamera pos/target numerisch identisch vor/nach Drag/Löschen bewiesen. - Print-Linienstärke invertiert → korrekt (
src/plan/PlanView.tsx,styles.css): Print zeichnet jetzt echte Papier-mm in viewBox-Einheiten OHNEnon-scaling-stroke:strokeVb=(mm·N/1000)·PX_PER_M, N=paperScalestabil (nur beiapplyScale/erstem Messen gesetzt). Rein=dicker, raus=dünner; 1:100 vs 1:10 = exakt ×10. Display/Haarlinie unverändert. Ecken-Miter: CSSstroke-linejoin:miterbuildDrawingRunsbündelt zusammenhängendeline-Primitive gleicher drawingId zu einempolyline/polygon(Ringschluss erkannt) → gehrte Ecken statt Butt-Cap-Stufe. Primitive-Modell (und Print-Export) unverändert.
- ambientCG-Live-Bibliothek (
src/materials/ambientcg.tsneu,ResourceManager.tsx): komplette CC0-Lib live durchsuchbar (Suche/Kategorie/Auflösung 1K-4K), jszip-Entpackung → Blob-URLs, NormalGL bevorzugt. CORS: Such-JSON +/getbrauchen Proxy → Vite-Dev-Proxy/ambientcginvite.config.ts(VITE_AMBIENTCG_PROXYfür Prod); optionale Prod-Routeopenbureau-core/api/src/routes/ambientcg.js(lesend, gemountet VOR Auth-Gate). Thumbnails direkt (ACAO:*). Offline → Schnellauswahl-Fallback.
Runde 2 FERTIG (2026-07-01, alle GRÜN + Probe-verifiziert):
- 2a [App/engine/editors/registry, neu
cmds/mirror.ts+cmds/join.ts]: Snapping erster Punkt gefixt (Modifier shift/ctrl wurden im Command-Pfad verschluckt → jetzt viaEngineModsdurchmove/pick→host.snapgefädelt); Segment-Move für offene Polylinien/Linien (EdgeGrip.free, ganzer 2D-Delta, Nachbar-Segmente folgen über geteilte Vertices); Kürzel↔Befehl vereinheitlicht (M→engine.start("move"),S→"mirror",Ctrl+J→"join", identisch zum Tippen;Command.autoRunfür nicht-interaktive Befehle;CommandSelection.drawingIdsfür Mehrfachauswahl); Mirror-Befehl (2-Punkt-Achse, Vorschau,commitTransform mirror/copy). - 2b [cmds/{polyline,rect,wall}]: Polylinie offen/geschlossen (Toggle
m, Ring-Fill); Rechteck 2pt/3pt/Zentrum (3pt = gedreht → closed polyline); Wandstärke-Tab-Feld nur bei einschichtigen Wandtypen (baut on-commit einen einschichtigen Wandtyp der Zieldicke, Original bleibt). - Swisstopo/OSM-Kontext-Importer [io/{lv95,geoContext,swissTopo,osm}, ui/ContextImportDialog, SitePanel]:
„Standort importieren" — geocode (geo.admin SearchServer, LV95 direkt), swisstopo-Gebäude
(
MapServer/identifylayerch.swisstopo.vec25-gebaeude), OSM-Overpass (Gebäude/Strassen/Wasser/Grün). LV95↔WGS84 (Bern round-trip 0.38 m) + Origin-Shift. CORS: geo.admin direkt, Overpass via neuer read-only-Routeopenbureau-core/api/src/routes/geoproxy.js(vor Auth-Gate, host-allowlist) wennVITE_GEO_PROXYgesetzt.
TIER-1 FORTSCHRITT (2026-07-01):
-
DXF-Vektor-Export FERTIG [src/export/{dxfWriter,exportDxf}, ui/ExportDxfDialog, TopBar+App-Button]: hand-rollierter R2000/AC1015-ASCII-Writer,
$INSUNITS=6(Meter), 23 Layer aus Kategorien (ACI+True-Color+lw), LINE/LWPOLYLINE(closed)/CIRCLE/ARC/TEXT; Quelle =generatePlan()in Meter-Modellraum. 5 m-Wand→5.345 m Span verifiziert. DWG NICHT geshippt (libredwg-web nur lesend — ehrlich weggelassen). -
Decke (Ceiling) FERTIG [geometry/ceiling, cmds/ceiling(alias d/decke), types.ts
Ceiling, projectSlice/selectionSlice, generatePlanaddCeilingPoche, PlanView-Hittest, Viewport3DaddCeilingMesh(Extrude+Material+Modi), ToolsPanel-Button+ Deckentyp-Picker, ObjectInfoPanelCeilingSection, host.ts, App-Grips/Selection]. Wand-Muster: floorId + categoryCode "30"- wallTypeId/Component + VerticalAnchor(OK=Geschoss-Top) + optionale Dickenüberschreibung; statt Achse/Band ein
closed
outline: Vec2[]. Plan = Umriss-Polygon (Fill+Hatch + schwere Outline) VOR den Wänden gezeichnet. Grips Vertex+Edge+Body.
- wallTypeId/Component + VerticalAnchor(OK=Geschoss-Top) + optionale Dickenüberschreibung; statt Achse/Band ein
closed
-
⚠️ MERKE: App.tsx ist der Serialisierungs-Engpass — pro Welle darf NUR EIN Agent App.tsx editieren (DXF+Decke liefen versehentlich gleichzeitig darauf; Merge hat diesmal geklappt, aber nicht drauf verlassen).
-
Öffnung (Fenster/Tür) FERTIG [geometry/opening, cmds/opening(alias f/fenster, t/tuer/tür, oe), types.ts
Opening, generatePlan(wallGaps), PlanView, Viewport3D(addWallMeshessegmentiert + Sturz/Brüstung,addOpeningMeshesRahmen/Glas/Flügel), slices, App, ToolsPanel(Fenster+Tür-Buttons), ObjectInfoPanel(editierbar)]. Host-Sync: Öffnung speichert KEINE Weltkoordinaten — alles wird pro Render auswall.start/endneu abgeleitet → Wand verschieben bewegt Öffnung automatisch. Plan-Symbole je Detailgrad (Tür: Blatt→+Schwenkbogen→+Anschlag; Fenster: 1→+Rahmen→+2 Glaslinien). -
SIA-416-Engine FERTIG [geometry/{roomArea,roomBoundary} — pure, isoliert, 34/34 Tests]: Raumerkennung (planar-arrangement+half-edge face-tracing,
detectRooms/roomFromPointInside), Fläche/Umfang/Zentroid, SIA-Hierarchie (GF→KGF+NGF; NGF→NF(HNF/NNF)/VF/FF),balance(),roomsToCsv. Bereit für den Raum-Slice. -
Treppe FERTIG [geometry/stair, cmds/stair(alias treppe/tp —
tr=trim!), types.tsStair, model/wallstairVerticalExtent, generatePlanaddStairSymbol(Schnittbruchlinie+Pfeil), Viewport3DaddStairMeshes(Stufenprofil), slices/App/Panels/i18n]. gerade/L/Wendel (Wendel = vereinfachtes Keil-Modell), SIA-17/29, geschoss-übergreifend (totalRise=Geschosshöhe). -
HLR-Spike FERTIG (Welle-C-Fundament) [src/section/{hlr,occt,occt-wasm.d}.ts, docs/welle-c-hlr-spike/, package.json +opencascade.js, vite.config aliases]. API-Pfad =
HLRAppli_ReflectLines(NICHT HLRBRep_Algo — im Prebuilt nicht konstruierbar). Lazy via dynamic import, Haupt-Bundle unberührt. 62 MB WASM → später Custom-Build auf 5-15 MB.
SESSION-LIMIT-STOP (2026-07-01 ~11:00, reset 13:00 Europe/Zurich): Raum- + Rich-Text-Agenten wurden vom Session-Limit abgeschnitten. Repo ist trotzdem GRÜN & stabil (tsc+build grün, dev :5187 läuft). Genauer Stand:
- Raum: NICHT begonnen — kein
cmds/room.ts, keinRoom-Typ, keine Verdrahtung. Sauber neu starten. SIA-Engine (geometry/roomArea.ts+roomBoundary.ts) liegt fertig & getestet bereit zum Import. - Rich-Text: FAST FERTIG —
src/text/richText.ts(Doc-Modell + Marks + plainText/applyMark/toggleMark/serialize/Presets) FERTIG.src/text/renderHtml.ts(docToHtml für Editor + docToLines/docToSvgText für SVG-Plan, gemeinsame Mark→Stil-Map) JETZT FERTIG & kompiliert (im Hauptthread nachgezogen, da Agent am Limit war). FEHLT nur noch:src/text/RichTextEditor.tsx(WYSIWYG-Komponente mit Toolbar bold/italic/underline/strike/Grösse/Farbe + Presets, controlled: value/onChange). - Zwei Helfer-Subagenten ("Map/Extract …wiring in App.tsx") liefen ebenfalls ins Limit; App.tsx ist laut tsc+build INTAKT.
RESUME NACH RESET (Reihenfolge): (1) Rich-Text-Kern fertig (renderHtml + Editor-Komponente) — App-frei, isoliert.
(2) Raum-Slice (nutzt SIA-Engine, click-inside, Stempel, Bilanz+CSV) — App-Slice. (3) Text/Stempel-Slice (nutzt Rich-Text-Kern).
(4) Smart-Join/Split. (5) Welle B (3D-Schnitt+Stencil-Capping) → Welle C (HLR verdrahten, src/section/hlr.ts bereit).
(6) Overrides-Engine, Ausschnitte, Multi-Page-Layouts. REGEL: nur EIN App.tsx-Agent pro Welle; Parallel-Track nur wenn App-frei.
>>> STAND 2026-06-30 (Fortsetzung, spät) <<<
Fortsetzungs-Lauf (UI + Import + Wand-Attribute + Selektion/Editieren). Alles
unten ist npx tsc -b + npm run build GRÜN und per Screenshot/Probe verifiziert,
außer „LÄUFT" markiert. Viel wurde an Subagenten delegiert (Dateien landen
auf der Platte, unabhängig von Benachrichtigungen).
Fertig & verifiziert (diese Fortsetzung):
-
Vektor-PDF-Export des Grundrisses (KERN-ZIEL — fertig & verifiziert):
src/export/planToPrintSvg.ts(Druck-SVG ausgeneratePlan, mm-Mapping im Maßstab, echte mm-Linienstärken/ISO-Stifte, Schraffuren als Vektorlinien) +src/export/exportPdf.ts(jspdf+svg2pdf.js→ echtes Vektor-PDF, A4/A3 ×Hoch/Quer, Schriftfeld). TopBar-Button „PDF" +src/ui/ExportPdfDialog.tsx. Verifiziert: 522 Pfade, 0 Rasterbilder, maßstabsgenau (5,345×4,345 m → 53,45×43,45 mm @1:100).scripts/probe-pdf.mjs. -
2D-Boolean (Union/Differenz/Schnitt):
src/editors/booleanOps.ts(polygon-clipping), Kontextmenü „Vereinigen/Subtrahieren/Schneiden" + Ctrl/Cmd+Shift+U/D/I; geschlossene Drawing2D, Differenz=erstes Element minus Rest, Loch→Außenring gefüllt + Innenringe als Umriss. Verifiziert (Union 8/Differenz 6/Schnitt 4 Ecken).scripts/probe-boolean.mjs. -
3D-1 — ERSTELLEN in 3D (Meilenstein): der 3D-Viewport ist Erstellungs-Fläche; dieselben Befehle (line/wall/rect/polyline) erzeugen Elemente direkt in 3D. Raycast auf Geschoss-Arbeitsebene (
THREE.Planey=gridElevation) → Modell-Vec2(model.x=P.x, model.y=P.z, ausaddDrawing2DLinesabgeleitet) → dieselbeCommandEngine(move/pick/confirm). Live-3D-Draft (Rubber-Band + Snap-Marker, eigenedraftGroup), OrbitControls bei aktivem Befehl umgeschaltet,pxPerMeter-Fallback 90. Viewport3D-PropscommandActive/onWorkplanePoint/onWorkplaneConfirm/draft. Verifiziert (Wand in 3D → in 3D + Plan sichtbar).scripts/probe-3d-create-*.png. -
3D-2 — EDITIEREN in 3D (Meilenstein): 3D-Griffe (eigene
gripGroup) bei genau 1 Auswahl +!commandActive. Wand: Endpunkt-Kugeln (Achse), Höhen-Griff (OK viaupdateWall top:{mode:"custom",z}), Verschiebe-Griff; Drawing2D: Vertices. Drag raycastet auf Arbeitsebene bzw. vertikale Ebene → DIESELBEN Store-Actions wie Plan-Griffe (moveGripOf/moveElementByOf/updateWall) → Plan+3D konsistent. Laufender Drag ingripDragRef(übersteht den Szenen-Neuaufbau pro Move). Verifiziert (Endpunkt + Höhe in 3D editiert, im Plan deckungsgleich).scripts/probe-3d-edit-*.png. Offen (→ Editier-Welle 3): 3D-Snap beim Drag + Griffe „immer oben" (Tiefentest). -
Zwei-Ton-Dark-Theme + KEIN Petrol-Grün mehr:
src/styles.cssDark-Tokens neutral (--bg #0e0e0e,--panel #1d1d1d,--accent #4d4d4d…); Kontextmenü-Tokens--ctx-hover/-textneutral; grüner Fokus-Ring entfernt. -
Topbar DOSSIER-Stil: Icon-Grid 4-oben/3-unten (Grundriss integriert), Kombis gestapelt, kompakte Selects.
src/ui/TopBar.tsx. -
Themed Dropdowns statt nativer
<select>:src/ui/Dropdown.tsx(Wert- + Aktions- Modus, Popover im Kontextmenü-Stil, kein blaues OS-Menü). In TopBar verdrahtet. -
Kontextmenü/Dropdown-Politur: Material-Symbols-Icon-Font in
index.htmlgeladen.material-symbols-outlined-Regel in styles.css (sonst Roh-Ligaturtext); Größen runterskaliert (.ctx-menu11.5px, Icons 13–14px, weniger Padding, Radius 10).
-
Geschoss-Z-Raster:
Viewport3DBodenraster aufgridElevation(= aktives GeschossbaseElevation). -
DXF/DWG-Import als DIALOG + Drag&Drop:
src/ui/ImportDialog.tsx,src/io/dxfToDrawings.ts; Ziel-Zeichnungsebene wählen / neue „Zeichnung" anlegen; Layer→Kategorie-Handling; App-weiter Drop-Handler. -
DWG in-app parsen:
@mlightcad/libredwg-web(WASM, installiert),src/io/dwgParser.ts(lazy, mappt DwgDatabase→{meshes,contours}),vite.config.ts-Aliase für WASM (virtual:libredwg-glue+?url),src/io/libredwg-web.d.ts. Gegen echte DWGs getestet (11.668 Konturen). Fallback→ODA-Hinweis bei Lib-Fehler. -
Wand-Objekt-Info-Attribute (additiv, abwärtskompatibel): Modell
Wall.referenceLine(left|center|right, default center) +Wall.bottom/top: VerticalAnchor({mode:"floor",floorId,offset?}|{mode:"custom",z}) insrc/model/types.ts; Resolversrc/model/wall.ts(wallReferenceOffset,wallVerticalExtent,nextFloorAbove); angewandt ingeneratePlan,model/joins.ts,Viewport3D. Panelsrc/panels/ObjectInfoPanel.tsx;src/state/selectionInfo.tsSelection.wall: WallInfo; Host-Setter +projectSliceupdateWall/setWallThickness. Einschichtig = 1-Layer-WallType. -
Panel-Text:
.attr-*/.objinfo-*Untertitel fett + Kontrast (--labelstatt--muted). -
Selektion-Überarbeitung:
selectedDrawingId→selectedDrawingIds[](selectionSlice); Marquee wählt Linien (marqueeHitDrawings), Ctrl/Cmd+A, Multi-Delete, Multi-Highlight (.plan-sel-draw), Shift-Klick-Mehrfachauswahl (PlanSelection.shift→onPlanSelecttoggelt). -
Editier-Welle 2 — Split/Join/Segment-Löschen (FERTIG & verifiziert): Ctrl+S Split (Rechteck→zwei geschlossene; nur bis Schnittpunkt), Ctrl+J Join (koinzidente Enden), Alt+Klick=Segment löschen (Schere).
kernel2d.ts(splitPolylineAtParam/splitClosedByChord/removeSegment/splitAtIntersections/joinChains; Tests 16–23, 25 ok),src/editors/splitJoin.ts, App-Keydown (Ctrl/Cmd+S/J,preventDefault) +onSegmentCut, PlanView Alt-Klick. Verifiziert (Rechteck→2 geschlossene, Join→1 Polylinie, Alt→Segment weg).scripts/probe-splitjoin.mjs. Wände bleiben no-op. -
Editier-Welle 3 + Eingabe-Vereinheitlichung + Snap-Feinschliff (FERTIG): 3D-Drag-Snap (gleiche
computeSnap) · Griffe/Marker immer-oben · koinzidente Endpunkt-Griffe ziehen gemeinsam (Viewport3D). GUI-Werkzeug (line/polyline/rect) →engine.start+ Befehlsfeld-Fokus; Shift = H/V-Ortho beim Griff-Drag (2D+3D,applyAngleConstraintaustools/snapping). OFFEN: „Wand" noch Legacy (Wand-als-Command); Editieren läuft noch AD-HOC, nicht durch die Engine → Tab-Wert + Referenz-Tracking offen. Snap-Marker vereinheitlicht: 2D Endpunkt=Kreis/Mittelpunkt=Strich, 3D-Snap=#ffcc44, Marker kleiner; 2D-Vorschaulinie grau-Volllinie. -
DWG-Parser erweitert (FIX „keine Geometrie gefunden") + Trim (FERTIG):
io/dwgParser.tsneu — ARC/CIRCLE/ELLIPSE/SPLINE + INSERT/Block-Expansion (rekursiv, ausdb.tables.BLOCK_RECORD.entries, volle 2D-Affin-Transform) + Diagnose-Histogramm (DxfImportResult.diagnostics, in ImportDialog). Real-DWG 37 INSERT → 67k Konturen. Trim (commands/cmds/trim.ts, Aliastr,kernel2d.trimPolyline) — Quick-Trim bis Schnittpunkt. Beide verifiziert. -
Material-Bibliothek (Daten, FERTIG): 12 CC0-Materialien von ambientCG →
public/assets/materials/<id>/{color,normal,roughness,displacement,ao}.jpg+manifest.jsonsrc/materials/library.ts(PBR).
-
Welle A — 3D-Materialien (FERTIG & verifiziert):
Component.material(ComponentMaterial: PBR-Map-URLs +sizeMKachelgröße),src/materials/runtime.ts(MaterialRuntime→ gecachteMeshStandardMaterial, Kacheln in Welt-Metern via Extrude-UVs),renderMode„textured" (TopBar-Darstellung), Material-Picker (ambientCG-Grid) + Upload + Kachelgröße imResourceManager(Bauteile-Tab). Backstein mit Normal-Map-Tiefe verifiziert.scripts/probe-materials.mjs. Schnittschraffur-Slot frei für Welle B. -
Editier-Eingabe + Topbar-Politur (FERTIG): Befehlszeile zeigt Live-Länge/-Winkel beim Zeichnen (
Command.fieldValues), Cursor-HUD entfernt; Seiten-Verschieben propagiert verbundene Enden (2D+3D); Tab beim Vertex-Editieren setzt Wert (gripEdit-Controller in App — noch ad-hoc, NICHT durch die Engine). Topbar: Rest iconisiert (Referenzlinien/Linien-Modus/Ressourcen), Linien-Modus → Dropdown, Aktions- Buttons als Dropdown-Pill-Familie, Detailgrad+Massstab gestapelt + 1:N/Zoom% kompakt (.tb-zoomstack). -
Wand-als-Command (FERTIG & verifiziert):
commands/cmds/wall.ts(chainend, Achs+Band- Draft, Tab-Felder; Wandfelder ausCommandContext.activeWallTypeId/level) + Registry (Aliasew/wand) + App-Kopplung (TOOL_COMMAND.wall, Legacy-Wand umgeleitet). Wände in 2D+3D.scripts/probe-wall-cmd.mjs.
OFFENE WELLEN (nächste Schritte): Referenzobjekt-Achs-Tracking + Editieren VOLL durch die
Engine (heute gripEdit ad-hoc); Welle B (3D-Clip/Schnittebene + Stencil-Capping +
Schnittschraffur — nutzt das Material-System aus Welle A); Welle C (3D→2D-Schnitt/
Perspektive via HLR, opencascade.js-Spike); Swisstopo-Importer (Ort+Radius → Gebäude+
Gelände, geo.admin STAC/Geocode, CORS prüfen); Bögen/Kreise-Trim; Wandstärke-Tab bei
einschichtigen Wänden.
Offene Wellen (Todo-Spiegel — Todo-Liste lebt im Kontext):
- Editier-Welle 3: koinzidente Endpunkt-Griffe gemeinsam ziehen + verbundene Enden propagieren beim Seiten-Verschieben (topologisch, das Tiefste).
- GUI-Werkzeug ↔ Befehlszeile koppeln: Werkzeug-Klick startet denselben Command → Werte unten eintippbar; danach Cursor-Wert entfernen/optional.
- Selektions-Direkt-Edit: Länge/Winkel des gewählten Elements im Befehlsfeld (Tab-Zyklus).
- Swisstopo/openbureau-Importer-Dialog (Ort+Radius). Fluss steht: Geocode
api3.geo.admin.ch/.../SearchServer(sr=2056→LV95) → ±Radius → WGS84-bbox → STACdata.geo.admin.ch/api/stac/v1, Collectionsch.swisstopo.swissalti3d+ch.swisstopo.swissbuildings3d_3_0→ Download → TIN/Mesh→Kontext. LV95↔WGS84 nötig; Browser-CORS das Risiko. Referenz: DOSSIERrhino/swisstopo.py. - 3D→2D-Dokument: live + statisch (MVP-Kantenprojektion → HLR) für Vektor-PDF.
Hinweis:
generatePlanliefert SCHON Vektoren (SVG) → Plan-PDF bereits vektoriell. - Topbar-Rest iconisieren (Zoom/Referenzlinien/Linien-Modus/Ressourcen).
- Wand als Command (+ Wandstärke-Tab nur bei einschichtig) + Trim.
Resume-Checkliste: 1. CONVENTIONS.md + diesen HANDOVER + Memory lesen. 2. npx tsc -b &
npm run build (grün?). 3. npm run dev -- --port 5187 --strictPort (User schaut :5187).
4. Split/Join-Stand prüfen (git diff, Probe). 5. Arbeitsweise: autonom, keine
Rückfragen (User hat Vollrechte), substanzielle Arbeit an Subagenten delegieren,
jede Änderung per tsc+build+Screenshot verifizieren. node scripts/probe.mjs.
>>> STAND 2026-06-30 (Über-Nacht-Run) — älter <<<
Großer autonomer Build-Lauf. Alles unten ist tsc + build GRÜN und per Screenshot
verifiziert (sofern nicht „läuft" markiert). Befehlssystem-Bauplan:
docs/design/rhino-command-system.md.
Fertig & verifiziert:
- Rhino-Befehlssystem (Tier 0 + Tier 1 Zeichnen):
src/commands/—types.ts(Command-Interface),engine.ts(State-Machine + lastCommand + Eingabe-Routing),parseInput.ts(5,3·r5,3·5<45·<45·nackte Zahl),registry.ts(+Aliasel/pl/rec/c),cmds/{line,polyline,rect,circle}.ts. UI:src/ui/CommandLine.tsx(über der Statusleiste, Tab fokussiert). Befehle: Line, Polyline (Close/Undo), Rectangle, Circle — alle mit getippten Koordinaten, per Probe gezeichnet. Koexistenz mit Alt-Tools (Werkzeugleiste).scripts/probe-command-line.mjs,probe-draw-commands.mjs. - Tab-Feld-Zyklus (Rhino-Präzision §2.7): beim Zeichnen Tab durch Felder
(Linie/Polylinie: Länge→Winkel; Rechteck: Breite→Höhe; Kreis: Radius). Zahl lockt
das aktive Feld, ungelockte folgen der Maus. Additive optionale Command-Methoden
fields()/pointFromFields()+ Engine-Feldzustand + CommandLine-Boxen. Verifiziert exakt (3 m/45°, Rechteck 4×2).scripts/probe-tab-fields.mjs. - Tier-1-Editierbefehle: Move (Auswahl verschieben), Copy (wiederholend
duplizieren), Offset (parallele Kurve via
kernel2d.offsetPolyline, persistente Distanz, Seite per Klick) —cmds/{move,copy,offset}.ts, Aliasem/cp/o.CommandContextumselectionerweitert (Apphost.context()füllt sie aus dem Store). Offset verifiziert (paralleler Versatz exakt 0.5 m).scripts/probe-offset2.mjs. - 2D-Geometrie-Kernel
src/geometry/kernel2d.ts— Offset/Trim/Extend/Fillet + Segment-/Linien-/Kreis-Schnitt + Fläche/Wicklung. 16/16 Unit-Checks (scripts/test-kernel2d.ts, vianpx esbuild … | node). Basis für Tier-1-Editierbefehle. - Kontext/Gelände Phase 1 (paralleler Strang):
src/io/dxfParser.ts(DXF: 3DFACE/ MESH/POLYLINE→Mesh, LWPOLYLINE/LINE→Konturen; DWG bewusst nur via ODA→DXF-Hinweis),src/model/terrain.ts(generateTerrainFromContours→ TIN via delaunator),src/state/siteSlice.ts(addContextObject/generateTerrain/…),Project.context(ContextObject = ImportedMesh|ContourSet|TerrainMesh, „dumme" Kontext-Geometrie, NICHT semantisch),Viewport3Drendert Kontext/Terrain. Depsdxf-parser+delaunator. - Echte Isometrie (Orthographic-Kamera):
Viewport3Dschaltet front/top/side/iso auf OrthographicCamera (parallele Projektion), Perspektive bleibt perspektivisch. Verifiziert. - Plan-Tinte-Fix: 2D-Linien waren unsichtbar (CSS
.draw2d{stroke:var(--ink)}hell auf hellem Papier). CSS-stroke entfernt + dunkler Fallback in generatePlan → 2D dunkel sichtbar. - Bugfixes: 2D-Füllungen (rect/polyline rendern Fill+Schraffur+
fillColor); Kanten-Griff- Dreiecke sitzen auf der Linie + inkrementelles Dragging (keine Akkumulation); Plan-View wandert nicht mehr mit (fixer Welt-Ursprung, Reset nur bei Geschoss-Wechsel viaresetKey).
LÄUFT gerade (Agent):
- Tab-Feld-Zyklus (Nutzer-Wunsch): beim Zeichnen Tab durch Felder (Länge→Winkel→
Breite/Höhe/Radius), Zahl lockt Feld, Rest folgt Maus. Additive optionale Command-Methoden
fields()/pointFromFields()+ Engine-Feldzustand + CommandLine-Boxen.
NÄCHSTE SCHRITTE (Reihenfolge):
- Tab-Feld-Zyklus verifizieren (Agent-Gate).
- Tier-1-Editierbefehle: Move/Copy/Offset(nutzt kernel2d)/Trim/Split/Join/Explode.
Undo/Redo-Stack im Store erwägen (Commits laufen über
setProject). - Terrain-Integration: Konturen im Plan (generatePlan/PlanView), Import-/Terrain-Befehle
- Site-Panel (
src/panels/) + i18n + DWG→DXF-Hinweis-UI;.dxf-File-Picker →parseDxf.
- Site-Panel (
- Wand-Stärke-Feld: Wand ist noch ein Alt-Tool — als Command portieren, dann Tab-Feld
thicknessNUR bei einschichtigen/freien Wänden (mehrschichtige Typen: Stärke vorgegeben). - Tier 2 (Rotate/Scale/Mirror/Arc/Fillet/Array/Group/Gumball2D), Tier 3 (ExtrudeCrv/Box/ PushPull + analytische Wand-Öffnungen, §3.0 Bauplan).
Gotchas (frisch gelernt):
- Ein Prozess-Neustart killt laufende Hintergrund-Agenten (Status
failed); nach jedem Wiederaufnehmensrc/commands/-Existenz +npx tsc -bprüfen, Abgestürztes neu starten. - Inline
{...s, feld}als Tupel-Return löst TS-Excess-Property-Check aus → erst typisierte Variable (siehe cmds/line.ts-Muster). - Ein Subagent ist bei diesem Befehls-Build geflaket (spawnte Research statt zu bauen) → verzahnte/quer schneidende Arbeit an einen fähigen Subagenten delegieren oder selbst machen.
Was das ist
Standalone-Browser-BIM (React+TS+Vite+Three.js) für Wohnbau — die Browser-Variante
des Rhino-Plugins DOSSIER (Referenz-Repo, public/klonbar: https://git.kgva.ch/karim/DOSSIER;
falls weg: neu klonen nach scratchpad/DOSSIER). Prinzip: ein semantisches Modell →
alle Sichten (Plan/3D/Schnitt) abgeleitet, Darstellung erst beim Rendern.
Aktueller Stand (tsc + build GRÜN)
Funktioniert & verifiziert: semantisches Modell · mehrschichtige Wände mit
L-Ecken-Gehrung · Tür mit Öffnung + Schwenkbogen · Dokumentmodell (Zeichnungsebenen
= Geschosse+Schnitte/Ansichten/Zeichnungen; Ebenen = Kategorie-Baum, DOSSIER-Codes 1:1) ·
3D zeigt EG+OG gestapelt · Resource-Manager (Component/Hatch/Line, als Fenster-Overlay) ·
Panel-System (Docks links/rechts, Tabs, 5 Anzeige-Modi) · Top-Bar + Footer (Massstab
echt 1:N, Detailgrad, Render-Modus Schattiert/Draht/Kanten, Referenzlinien, Cursor X/Y live) ·
Maus: Mitte=Pan/Orbit, Links=Auswahl(+Marquee), Rechts=eigenes Kontextmenü · Native-App
(kein Browser-Rechtsklick/Textauswahl) · i18n (src/i18n/, de+en, t('key')) ·
aktive Zeichenwerkzeuge (Wand/Linie/Polylinie/Rechteck + Snapping endpoint/midpoint/
intersection/onEdge/grid/ortho mit Fang-Menü, Live-Vorschau+HUD — src/tools/, Phase 1+2).
Gerade fertig & verifiziert (2026-06-29)
Aktive Zeichenwerkzeuge — Phase 1 + 2 (docs/design/drawing-tools.md): Tool-System in
src/tools/ (types · snapping · tools/registry) + Verdrahtung in PlanView/App/TopBar/
generatePlan. Per probe verifiziert (scripts/probe-tools.mjs, probe-line.mjs, probe-phase2.mjs):
- Werkzeugleiste (TopBar): Auswahl/Wand/Linie/Polylinie/Rechteck + Wandtyp-Dropdown +
Fang-Menü (Häkchen je Snap-Art, Rasterweite, Winkelraster —
position:fixed, da Topbar clippt). Nur im Grundriss aktiv. - Wand-Werkzeug: Achs-Polylinie → je Segment ein
Wall; Live-Band-Vorschau + HUD (Länge·Winkel); Rechts-/Doppelklick/Enter committet; Gehrung automatisch auscomputeJoins(mehrschichtiger L-Stoss). - 2D-Werkzeuge: Linie (2-Klick), Polylinie (Klick auf Start schließt, Doppel-/Rechtsklick beendet
offen), Rechteck (zwei Ecken) →
Drawing2D(line/polyline/rect); ingeneratePlanabgeleitet (addDrawing2D,coloram line-Primitiv, Bounds erweitert). - Snapping: endpoint · midpoint · intersection · onEdge(Lot) · grid · ortho(Shift); Prioritäts-
gewichtet (
PRIORITYin snapping.ts); Bildschirm-Marker je Art (Quadrat/Dreieck/✕/Raute/Punkt) + Ortho-Hilfslinie; Ctrl = Fang aus. Einstellbar über das Fang-Menü (snapState in App). - Tastatur: Esc verwirft/zurück-zu-Auswahl, Enter committet, Backspace nimmt Punkt zurück.
- Modell:
Drawing2D+Project.drawings2d(types.ts),Elementerweitert. i18n de+en (tool.*,snap.*). - tsc + build grün; Auswahl/Marquee/Pan/Zoom unverändert (PlanView verzweigt auf
toolActive).
Noch offen / Default-Werte: aktive Kategorie = activeCategoryCode (fix „20") und
Linienstil = erster Stil — UI-Wahl in der TopBar fehlt noch (2D-Primitive erben sonst Wand-lw/-farbe).
Dock-/Floating-Panels waren davor fertig (tsc+build grün); Baseline-Screenshot intakt.
Ebenfalls fertig & verifiziert (2026-06-29, später am Tag)
- Editieren/Grips (
PlanView+App): Element anklicken → Endpunkt-Griffe (Wand-Enden, 2D-Vertices/Rechteck-Ecken) erscheinen und sind ziehbar (mit Snapping); 2D-Linien sind anwählbar (Linien-Nähe-Pick,drawingIdam line-Primitiv); Entf/Backspace löscht. Wand- Gehrung folgt live.moveGrip/drawingVerticesin App. - Shift = Ortho beim Griff-Ziehen (Bezug = Nachbar-Vertex; H/V bzw. Winkelraster).
- Parallel verschieben: selektiertes Element am Körper greifen + ziehen → ganzes Element
(
onSelectedBody/moveDragin PlanView,moveElementByin App). - Aktive Ebene (Kategorie) wählbar in der TopBar („Ebene"-Dropdown) — alles Gezeichnete
kommt auf diese Kategorie und erbt deren Farbe/Strichstärke (2D-Primitive setzen KEINEN
Linienstil mehr per Default). Statusleiste zeigt die aktive Ebene.
activeCategoryCodeState. - 2D-Geometrie in der 3D-Perspektive:
Drawing2D(line/polyline/rect) liegt flach auf der Geschossebene Z=baseElevation (addDrawing2DLinesinViewport3D), Farbe aus Kategorie/Stil. (Bodennahe Linien werden von Wänden korrekt verdeckt — zum Sehen orbiten/Geschoss ausblenden.) - Probes:
probe-grips.mjs,probe-3d2d.mjs,probe-edit2.mjs. tsc + build grün.
Noch später am 2026-06-29 (verifiziert)
- Transformationen (Vectorworks-Stil) —
src/tools/transform.ts+src/ui/TransformBar.tsx+ App. Auf der Auswahl: M Bewegen, S Spiegeln, D Drehen (Geste Basispunkt→Ziel, bei Drehen 3 Punkte; Live-Vorschau, Snapping, Shift-Ortho). Modusleiste U/I/O/P: U bewegen · I Kopie · O N Kopien (Anzahl-Prompt) · P verteilen. Probeprobe-transform.mjs/probe-array.mjs(move/copy/array verifiziert). Routing viatoolInputActive-Prop in PlanView. - Aktive Ebene per Klick im Ebenen-Panel (statt TopBar-Dropdown):
LayersPanel-Zeile klicken →host.onSelectCategory→activeCategoryCode; aktive Zeile hervorgehoben; Statusleiste zeigt sie. TopBar-Ebene-Dropdown entfernt. (probe-layer.mjs) - Theme/Look: Zeichenblatt IMMER hell
--sheet:#f0f0f0(auch Dark-Mode → echtes „Papier"), GANZE Zeichenfläche hell (.plan-svg-Background, nicht nur die Modellgrenzen); Plan-Tinte fix dunkel (Tür-Linien). Dark-Theme etwas abgedunkelt (Panels #1c1c1c). 3D-Orbit ohne Nachlauf (enableDamping=false— kontrollierter).
Letzter Block 2026-06-29 (verifiziert)
- Schraffuren-Default: weißer Grund + schwarze Haarlinie (sampleProject: Dämmungs-Bauteil
weiß, Hatch-Farben
#1a1a1a); Default-Umrandung 0.18 mm (WALL_FALLBACK_MM, addCategory). - Stiftstärken-Vorgabe
PEN_WEIGHTS(0.02…2.0) als<datalist>im Linienstil-Editor. - Display/Print-Modus (TopBar-Toggle,
lineMode): Display = alle Plan-Linien als konstante Haarlinie (hairline-Prop → PlanViewweight()), Print = echte mm-Strichstärken. .lin/.pat-Import: Parsersrc/io/linParser.ts/patParser.ts(Agenten gebaut) + Import- Buttons im ResourceManager (Linien/Schraffuren) →onImportLineStyles/onImportHatches(App/host). .lin voll (Dash); .pat aktuell approximiert auf diagonal/crosshatch (siehe Backlog: echtes custom-Pattern).- Werkzeug-Palette (
src/panels/ToolsPanel.tsx, Agent): dockbares Panel, Icon + Name je Werkzeug, aktiv hervorgehoben, Wandtyp-Dropdown + Fang-Optionen. Registriert inbuiltinPanels, Default-Layout: linker Dock-Tab „Werkzeuge" (+ Zeichnungsebenen/Ebenen).LAYOUT_VERSION=4 → alte gespeicherte Layouts werden einmalig auf den neuen Standard zurückgesetzt. - Probes:
probe-display.mjs,probe-import.mjs,probe-tools-panel.mjs. tsc + build grün.
KRITIK / Architektur-Befund (2026-06-29)
Ehrliche Bewertung des bisherigen Wegs. Für die nächste Instanz als Entscheidungsgrundlage.
Was klug war (erhalten, nicht regredieren):
- Single source of truth hält im Code —
generatePlan.tsundViewport3D.tsxnutzen dieselbecomputeJoins/clippedBandaussrc/model/. Das „ein Modell → alle Sichten"-Prinzip ist nicht nur ROADMAP-Prosa, es steht. Beim Refactor diese Trennung Modell↔Sicht bewahren. - Grundriss analytisch aus Parametern statt Mesh-Schnitt (Weg A) — richtig.
- Bewusst leichter Stack (Three.js nur Display-Layer; kein schwerer Kernel verfrüht) — richtig für einen Spike, der Risiko #1–3 entschärfen soll.
- i18n via
t()wird eingehalten;tsc -bist grün.
Hauptkritik (zu beheben):
- God-Component gegen eigene Regel.
App.tsxist ~2461 Zeilen mit ~29useState. CONVENTIONS.md fordert wörtlich „dünner Shell, keine Geschäftslogik". Das ist verletzt. - Kein Store.
src/state/existiert NICHT, obwohl CONVENTIONS.md Store+Slices (project/selection/view/layout) vorschreibt. Zustand = lokale Hooks → Prop-Drilling.- Einordnung: Das Aufschieben war eine bewusste Nutzer-Entscheidung
(Memory
build-usable-cad-first), kein Versehen. Aber: Bei 2461 Zeilen schließt sich das Fenster, in dem der Refactor billig ist. Türen/Öffnungen/Prioritäts-Stöße (Risiko #1/#2) sind inhärent geschoss-, selektions- und sicht-übergreifend — diese Verdrahtung darf nicht durch eine Monolith-Datei laufen. Empfehlung: Store ziehen VOR der nächsten Feature-Welle.
- Einordnung: Das Aufschieben war eine bewusste Nutzer-Entscheidung
(Memory
Befund (separat angehen, nach Refactor): Die harten, roadmap-markierten 🔴-Risiken sind noch
unbewiesen — Door existiert als Typ, aber kein echter 3D-Boolean (Öffnung = nur Plan-Lücke);
HLR für Schnitte/Ansichten fehlt; Prioritäts-T-Stöße offen. Das einfache Drittel ist bewiesen,
das schwere aufgeschoben. Die Frage „ist es wirklich CAD?" entscheidet sich erst, wenn diese landen.
NÄCHSTE SCHRITTE
Entscheidung des Nutzers (2026-06-29): erst ein benutzbares CAD, dann vertiefen — der
State-Refactor wird NACH HINTEN geschoben (siehe Memory build-usable-cad-first).
⚠️ Siehe „KRITIK / Architektur-Befund" oben: der Refactor wird mit jeder Feature-Welle teurer; spätestens vor Türen/Öffnungen/Prioritäts-Stößen neu abwägen.
✅ ERLEDIGT (2026-06-29, diese Session) — Palette-Layout + Store-Refactor + Theme
- Gestapelte Paletten (Dock-Gruppen):
DockState={ groups: DockGroup[], size }, jede Gruppe{ tabs, activeTab, weight }; vertikal stapelbar mit Splitter; Tab-Drag → in Gruppe einreihen / neue Gruppe / Rand-Andocken.LAYOUT_VERSION=6. (types.ts/layout.ts/Dock.tsx/TabStrip.tsx/panelDrag.tsx/App.tsx.) Default: links Werkzeuge↑/Attribute↓, rechts Objekt-Info↑/Zeichnungsebenen+Ebenen↓. - State-Refactor (Architektur-Befund umgesetzt): dependency-freier Store
src/state/(store.tsuseSyncExternalStore + SlicesprojectSlice/selectionSlice/viewSlice/layoutSlice, kombiniert inappStore.ts). App.tsx 2710→~2030 Zeilen, verhaltensgleich (tsc+build+Screenshot identisch). Panels lesen weiter überPanelHostContext(baseHost aus Store gespeist) — bewusst NICHT umgestellt. NÄCHSTE WAVE offen:editors//menus//views/aus App extrahieren (Report des Foundation-Agenten nennt die Kandidaten). - Selektions-Kontrakt (
src/state/selectionInfo.ts+ host.ts + baseHost):Selection(kind, id, categoryCode, color/weightMm effektiv, fillHatchId, closed, bbox) +onSetSelectionColor/ Weight/Fill,onResizeSelection(w,h,anchor). Modell:Wall.color?,Drawing2D.weightMm?ergänzt; generatePlan wendet beide an. Wand = Weight/Fill bewusst No-op (erbt aus Ebene). - Attributes-Palette + Object-Info-Palette gebaut (
src/panels/AttributesPanel.tsx,ObjectInfoPanel.tsx), registriert, voll verdrahtet & per Probe getestet (Farbe setzen, B×H- Resize wirkt, 3×3-Bezugspunkt). Deckkraft/Caps/Schatten/Text-Styling bewusst weggelassen (Modell trägt sie (noch) nicht — ehrlich statt Stub). - Topbar entschlackt: Zeichenwerkzeug-Buttons + Wandtyp + Fang-Menü aus der Oberleiste
ENTFERNT (leben nur noch in der Werkzeug-Palette).
SnapMenu/SNAP_TOGGLESausTopBar.tsxraus. - Dark-Theme vertieft (
styles.css): gestufte Elevations-Tokens (--bg<--panel<--panel-2,--inputversenkt) statt flachem Einheitston; Oberleiste/Panel-Köpfe angehoben, tiefere Schatten.--sheetbleibt hell. Siehe Memoryui-depth-dark. - CSS-Altlast behoben: ein
*/in einem Kommentar (.nav-*/.res-*) hatte die ganze.dock- Regel verschluckt (display:flexnie aktiv) — gefixt.
Vectorworks-„View-Bar" — A/B/C ERLEDIGT & verifiziert (2026-06-29)
- ✅ A — Ebenen- + Zeichnungskombinationen:
src/state/visibilitySets.ts(localStoragecad.layercombos.<name>/cad.drawingcombos.<name>), Store-Actionssnapshot*/apply*VisibilityinprojectSlice, zweiComboMenu-Dropdowns inTopBar(Muster wieLayoutMenu). Round-Trip per Probe verifiziert. (Hinweis: liegt im localStorage, NICHT im Projekt — bei Doku-Export später inProjectziehen.) - ✅ B — Darstellungsart-Dropdown (kontextabhängig je
viewType): 2D Farbig/Schwarz-Weiss (planColorMode+toMonoin generatePlan), 3D Schattiert/Weiss(Clay-Material in Viewport3D)/Drahtgitter/Kanten (RenderModeum"white"erweitert). Ersetzt die alte Render-Modus-Buttongruppe. Screenshots bestätigt. - ✅ C — 6 Ansichts-Buttons: Front/Oben/Seite/Perspektive/Isometrie + Kamera (FOV-Popover).
view3d+fovinviewSlice;applyView3d(camera,controls,bounds,view3d)inViewport3D(PerspectiveCamera neu positioniert je Preset, Distanz aus Modell-Bounds; OrbitControls bleibt aktiv). Preset-Klick wechselt nötigenfalls in die Perspektive. Screenshots top/front/iso/persp klar verschieden. Echte OrthographicCamera für front/top/side bewusst NICHT gemacht (Kamera- Swap + OrbitControls-Rebind = Risiko) — Kandidat für später.
Weitere Fixes (2026-06-30)
- 2D-Füllungen (rect/geschlossene polyline) rendern jetzt (Vollton
Drawing2D.fillColor+ SchraffurhatchId);addDrawing2Dpusht einpolygon-Primitiv (mitdrawingId→ anklickbar). Attribute-Palette hat „Füllfarbe". (Kreis-Füllung offen — Kreis-Primitiv im Plan fehlt noch.) - Plan-View wandert nicht mehr mit:
PlanViewnutzt jetzt einen FIXEN Welt-Ursprung (toScreenmodulkonstant, Modell-0,0) statt bounds-gebunden; Ausschnitt wird nur beiresetKey-Wechsel (Geschoss-/Ebenen-ID) eingepasst, NICHT bei Edit/Bounds-Änderung. Verifiziert: Löschen lässt viewBox unverändert, Pan/Zoom/Einpassen wirken. - Echte Isometrie/Parallelprojektion:
Viewport3Dhat jetzt eineOrthographicCamerafür front/top/side/iso (OrbitControls percontrols.object-Swap umgebunden), Perspektive bleibtPerspectiveCamera. Verifiziert (parallele Kanten).
>>> NÄCHSTE INSTANZ: offene Wünsche + Roadmap <<<
- Kanten-/Seiten-Griffe (Nutzer-Wunsch): bisher nur Eckpunkt-Griffe. Gewünscht: Seiten ziehen
(z. B. Rechteck-Kante), mit dreieckigem Anfasser nach außen. Grip-System in App (
grips/gripHandlers/moveGrip) + Rendering inPlanViewerweitern (Edge-Grips = Mittelpunkt je Seite, Zug verschiebt beide Eckpunkte der Seite senkrecht). - 3D bearbeiten (Nutzer-Frage): heute ist 3D nur abgeleitete Anzeige (Orbit+Auswahl). Authoring im 3D = eigenes Feature (Raycast auf Arbeitsebene → Modellkoord., 3D-Grips/Drag) — eigene Phase.
Text-Styling (View-Bar Rest) + Roadmap
- Text-Styling (Nutzer-Wunsch). VORAUSSETZUNG: Text wird noch NICHT gerendert —
Drawing2Dmitgeom.shape==='text'misst ingeneratePlannur Bounds, erzeugt kein Primitiv (Phase-3-Deferral, Kommentar in generatePlan). Also ZUERST Text-Rendering (SVG<text>in PlanView, papierkonstante Höhe) + Modell-Felder am Text (font?,bold?,italic?,anchor?), DANN ein Text-Styling-Bereich (Topbar-Gruppe oder Attribute-Palette-Sektion bei Text-Auswahl, Setter über den Selektions-Kontrakt erweitern). - Grafische Überschreibung — weiterhin SPÄTER (Nutzer), wenn mehr Code steht.
- Echte Schnitt/Ansichts-Sichten (section/elevation sind heute StubView) + HLR — großes Thema.
- Refactor-Rest:
editors//menus//views/aus App.tsx extrahieren (App noch ~2030 Z.).
- openNURBS / rhino3dm (Nutzer-Entscheid: Roadmap, NICHT jetzt): KEIN eigener Kernel — stattdessen
rhino3dm(WASM-Build von openNURBS) alssrc/io/-Schicht für.3dm-Import/Export + NURBS, sobald gebraucht. Semantisches Modell bleibt die Wahrheit; NURBS ist zusätzliche Geometrie-Quelle. - Echtes custom-
.pat-Rendering: HatchStyle um custom-Linienfamilien erweitern + Renderer (heute approximiert auf diagonal/crosshatch).
Offene Wünsche des Nutzers (Backlog, priorisiert)
- Palette-Layout (Vectorworks-Stil) — GROSS, nächster Fokus. Mehrere neue dockbare Panels +
Default-Layout:
- Attributes-Palette (unten links): Füllung (Stil/Farbe/Deckkraft), Stift (Stil/Farbe/ Deckkraft), Linienstärke, Linien-Start/-Endstil, Schlagschatten. (Referenzbild vom Nutzer.)
- Werkzeug-Palette darüber (Icon + Text je Werkzeug; ArchiCAD/VW-Stil).
- Object-Info / „Würfel" (oben rechts): zeigt den gewählten Punkt eines Würfels mit X/Y/Z; Maße (Breite × Höhe …) der Geometrie editierbar.
- Ebenen + Zeichnungsebenen als Tabs darunter (rechts).
- Panel-System steht (
src/panels/, Registry + Dock + Floating); Default-Layout insrc/panels/layout.ts(defaultLayout). Neue Panels inbuiltinPanels/registryanmelden.
- Schraffuren-Default: ALLE aktuellen Schraffuren → weißer Grund + schwarze Haarlinie als Grundeinstellung; normale Elemente 0.18 mm Umrandung als Default. (sampleProject hatches/ components + generatePlan-Defaults anpassen.)
- Stiftstärken-Vorgabeliste: 0.02 · 0.10 · 0.13 · 0.18 · 0.25 · 0.35 · 0.5 · 0.7 · 1.0 · 1.4 · 2.0 mm (abweichbar). Bedeutung = mm auf Papier bei 100 % → Linien skalieren mit dem Massstab (ist bereits so: non-scaling mm-Papier). In Linienstil-Editor als Presets anbieten.
- Display- vs. Print-Modus: Umschalter. Display = ALLES Haarlinien (konstant dünn); Print =
echte mm-Strichstärken. (Globaler View-State + an
generatePlan/PlanView durchreichen.) .lin- und.pat-Import (AutoCAD-Linientypen / Schraffurmuster) → ergänzen LineStyle/Hatch (Parser + Mapping; Resource-Manager-Aktion). Nutzer: „um die Linien und Schraffuren zu ergänzen".- „Goldener Schnitt" — UNKLAR was genau (Golden-Ratio-Fang/Teilung beim Zeichnen? Proportions-Hilfslinien?). → beim Nutzer rückfragen, bevor gebaut wird.
- Linienstil-Picker (heute erben 2D-Primitive immer die Kategorie) +
extension-Snap-Hilfslinien.
Danach (ursprünglicher Plan)
- Zeichenwerkzeuge Phase 3 (
drawing-tools.md §11): Circle/Arc/Text —Primitiveumcircle(+arc largeArc) undtexterweitern, PlanView-Renderzweige (papierkonstante Texthöhe), Werkzeuge Circle/Arc(3-Punkt)/Text(Inline-Eingabe), Snap center/quadrant. - Bearbeiten (Phase 4) — Rest: Auswahl/Grips/Verschieben/Löschen sind DA (s. o.). Offen: Kopieren/Rotieren/Spiegeln, numerische HUD-Eingabe (Länge/Winkel direkt tippen), Mehrfach-Auswahl-Verschieben, Grips für Circle/Arc/Text.
- State-Refactor (zurückgestellt) —
App.tsxGod-Component → Store+Slices (docs/design/state-architecture.md). Erst nötig, wenn parallele Code-Workflows gebraucht werden. - Weiter im Backlog: Pro-Ebene-Darstellung (
layer-display-settings.md), Prioritäts-T-Stöße (wall-joins-priority.md).
Arbeitsweise (WICHTIG — aus Memory + CONVENTIONS.md)
- Autonom arbeiten, NICHT um Bestätigung fragen. Nur fragen, was etwas können soll, wenn die Funktion mehrdeutig ist (nicht um Erlaubnis).
- Alles voll verdrahten, KEINE Stubs/No-op-Buttons. Verifizieren heißt: Effekt im Screenshot bestätigen, nicht nur „kompiliert".
- Identifier ENGLISCH; UI-Text via
t()(neue Keys in de.ts und en.ts). - Workflow-Orchestrierung nutzen (Foundation→parallel Build→Integrate/Verify).
- Code-Workflows seriell (fast alles geht durch
App.tsx/types.ts→ Konflikt); Design/Research parallel (nurdocs/). Der State-Refactor (#1) löst das. - Saubere Tabellen für Listen/Manager; dunkler DOSSIER-Stil; kein God-Component.
Verifizieren / Ausführen
- Dev:
npm run dev(Vite, Port 5173). Typecheck:npx tsc -b. Build:npm run build. - Screenshot:
node scripts/probe.mjs→scripts/probe.png(Puppeteer, Chrome in~/.cache/puppeteer). Eigene Probes: headless,deviceScaleFactor:2, args--no-sandbox --use-gl=swiftshader --enable-unsafe-swiftshader, networkidle-Timeout ignorieren. Firefox-Fälle via Playwright (scripts/probe-ff*.mjs). Screenshot ansehen + Geometrie prüfen. - Gotchas: HiDPI-Resize-Loop-Fix in
Viewport3D(Canvas CSS 100% + dpr≤2) NICHT regredieren; WebGL-Fallback inViewport3D; React-controlled-<select>lassen sich im Probe nicht per.value=ändern (Fehlalarm) — Verdrahtung im Code prüfen.
Orientierung
ROADMAP.md (Vision/Phasen/§10–§11 Backlog) · CONVENTIONS.md (Konventionen) ·
docs/README.md + docs/design/* (alle Specs) · docs/backend.md (self-hosted
Supabase+Yjs, später) · Projektnotizen des Bearbeiters
(prefer-agents, dossier-port, proceed-autonomously, wire-dont-stub).