Files
DOSSIER-STANDALONE/HANDOVER.md
T
karim ca859c4aa4 Browser-BIM (cad): semantisches Modell, abgeleitete 2D/3D-Sichten, Zeichenwerkzeuge
Standalone-Browser-Port von DOSSIER. Enthaelt das semantische Modell mit
Plan-/3D-Ableitung, Zeichen- und Editierwerkzeuge, Rhino-artiges Befehlssystem,
dockbares Panel-System, Resource-Manager, DXF/.lin/.pat-Import, i18n (de/en)
sowie Projektdokumentation und Probe-Harness.
2026-06-30 20:52:27 +02:00

31 KiB
Raw Blame History

HANDOVER — Browser-BIM (cad), Standalone-Port von DOSSIER

Für die nächste Instanz. Stand: 2026-06-29. Lies zuerst CONVENTIONS.md, ROADMAP.md und 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 log und git diff frei von solchen Spuren.

>>> STAND 2026-06-30 (Fortsetzung, spät) — ZUERST lesen <<<

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):

  • Zwei-Ton-Dark-Theme + KEIN Petrol-Grün mehr: src/styles.css Dark-Tokens neutral (--bg #0e0e0e, --panel #1d1d1d, --accent #4d4d4d …); Kontextmenü-Tokens --ctx-hover/-text neutral; 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.html geladen
    • .material-symbols-outlined-Regel in styles.css (sonst Roh-Ligaturtext); Größen runterskaliert (.ctx-menu 11.5px, Icons 1314px, weniger Padding, Radius 10).
  • Geschoss-Z-Raster: Viewport3D Bodenraster auf gridElevation (= aktives Geschoss baseElevation).
  • 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}) in src/model/types.ts; Resolver src/model/wall.ts (wallReferenceOffset, wallVerticalExtent, nextFloorAbove); angewandt in generatePlan, model/joins.ts, Viewport3D. Panel src/panels/ObjectInfoPanel.tsx; src/state/selectionInfo.ts Selection.wall: WallInfo; Host-Setter + projectSlice updateWall/setWallThickness. Einschichtig = 1-Layer-WallType.
  • Panel-Text: .attr-*/.objinfo-* Untertitel fett + Kontrast (--label statt --muted).
  • Selektion-Überarbeitung: selectedDrawingIdselectedDrawingIds[] (selectionSlice); Marquee wählt Linien (marqueeHitDrawings), Ctrl/Cmd+A, Multi-Delete, Multi-Highlight (.plan-sel-draw), Shift-Klick-Mehrfachauswahl (PlanSelection.shiftonPlanSelect toggelt).

LÄUFT bei Übergabe (auf Resume verifizieren, NICHT doppelt bauen):

  • Editier-Welle 2 — Split/Join/Segment (Agent): Ctrl+S Split (Rechteck→zwei geschlossene; nur bis Schnittpunkt), Ctrl+J Join, Alt+Klick=Segment löschen. Berührt App.tsx, PlanView.tsx, kernel2d.ts (splitPolylineAtParam/splitClosedByChord/ removeSegment/splitAtIntersections/joinChains), projectSlice.ts, ggf. src/editors/splitJoin.ts. Resume: git diff --stat, npx tsc -b, npm run build, node scripts/probe-splitjoin.mjs.

Offene Wellen (Todo-Spiegel — Todo-Liste lebt im Kontext):

  1. Editier-Welle 3: koinzidente Endpunkt-Griffe gemeinsam ziehen + verbundene Enden propagieren beim Seiten-Verschieben (topologisch, das Tiefste).
  2. GUI-Werkzeug ↔ Befehlszeile koppeln: Werkzeug-Klick startet denselben Command → Werte unten eintippbar; danach Cursor-Wert entfernen/optional.
  3. Selektions-Direkt-Edit: Länge/Winkel des gewählten Elements im Befehlsfeld (Tab-Zyklus).
  4. Swisstopo/openbureau-Importer-Dialog (Ort+Radius). Fluss steht: Geocode api3.geo.admin.ch/.../SearchServer (sr=2056→LV95) → ±Radius → WGS84-bbox → STAC data.geo.admin.ch/api/stac/v1, Collections ch.swisstopo.swissalti3d + ch.swisstopo.swissbuildings3d_3_0 → Download → TIN/Mesh→Kontext. LV95↔WGS84 nötig; Browser-CORS das Risiko. Referenz: DOSSIER rhino/swisstopo.py.
  5. 3D→2D-Dokument: live + statisch (MVP-Kantenprojektion → HLR) für Vektor-PDF. Hinweis: generatePlan liefert SCHON Vektoren (SVG) → Plan-PDF bereits vektoriell.
  6. Topbar-Rest iconisieren (Zoom/Referenzlinien/Linien-Modus/Ressourcen).
  7. 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 (+Aliase l/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, Aliase m/cp/o. CommandContext um selection erweitert (App host.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, via npx 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), Viewport3D rendert Kontext/Terrain. Deps dxf-parser+delaunator.
  • Echte Isometrie (Orthographic-Kamera): Viewport3D schaltet 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 via resetKey).

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):

  1. Tab-Feld-Zyklus verifizieren (Agent-Gate).
  2. Tier-1-Editierbefehle: Move/Copy/Offset(nutzt kernel2d)/Trim/Split/Join/Explode. Undo/Redo-Stack im Store erwägen (Commits laufen über setProject).
  3. Terrain-Integration: Konturen im Plan (generatePlan/PlanView), Import-/Terrain-Befehle
    • Site-Panel (src/panels/) + i18n + DWG→DXF-Hinweis-UI; .dxf-File-Picker → parseDxf.
  4. Wand-Stärke-Feld: Wand ist noch ein Alt-Tool — als Command portieren, dann Tab-Feld thickness NUR bei einschichtigen/freien Wänden (mehrschichtige Typen: Stärke vorgegeben).
  5. 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 Wiederaufnehmen src/commands/-Existenz + npx tsc -b prü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 aus computeJoins (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); in generatePlan abgeleitet (addDrawing2D, color am line-Primitiv, Bounds erweitert).
  • Snapping: endpoint · midpoint · intersection · onEdge(Lot) · grid · ortho(Shift); Prioritäts- gewichtet (PRIORITY in snapping.ts); Bildschirm-Marker je Art (Quadrat/Dreieck/✕/Raute/Punkt) + Ortho-Hilfslinie; Ctrl = Fang aus. Einstellbar über das Fang-Menü (snap State in App).
  • Tastatur: Esc verwirft/zurück-zu-Auswahl, Enter committet, Backspace nimmt Punkt zurück.
  • Modell: Drawing2D + Project.drawings2d (types.ts), Element erweitert. 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, drawingId am line-Primitiv); Entf/Backspace löscht. Wand- Gehrung folgt live. moveGrip/drawingVertices in 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/moveDrag in PlanView, moveElementBy in 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. activeCategoryCode State.
  • 2D-Geometrie in der 3D-Perspektive: Drawing2D (line/polyline/rect) liegt flach auf der Geschossebene Z=baseElevation (addDrawing2DLines in Viewport3D), 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. Probe probe-transform.mjs/probe-array.mjs (move/copy/array verifiziert). Routing via toolInputActive-Prop in PlanView.
  • Aktive Ebene per Klick im Ebenen-Panel (statt TopBar-Dropdown): LayersPanel-Zeile klicken → host.onSelectCategoryactiveCategoryCode; 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 → PlanView weight()), Print = echte mm-Strichstärken.
  • .lin/.pat-Import: Parser src/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 in builtinPanels, 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 CodegeneratePlan.ts und Viewport3D.tsx nutzen dieselbe computeJoins/clippedBand aus src/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 #13 entschärfen soll.
  • i18n via t() wird eingehalten; tsc -b ist grün.

Hauptkritik (zu beheben):

  1. God-Component gegen eigene Regel. App.tsx ist ~2461 Zeilen mit ~29 useState. CONVENTIONS.md fordert wörtlich „dünner Shell, keine Geschäftslogik". Das ist verletzt.
  2. 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.

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.ts useSyncExternalStore + Slices projectSlice/selectionSlice/viewSlice/ layoutSlice, kombiniert in appStore.ts). App.tsx 2710→~2030 Zeilen, verhaltensgleich (tsc+build+Screenshot identisch). Panels lesen weiter über PanelHostContext (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_TOGGLES aus TopBar.tsx raus.
  • Dark-Theme vertieft (styles.css): gestufte Elevations-Tokens (--bg<--panel<--panel-2, --input versenkt) statt flachem Einheitston; Oberleiste/Panel-Köpfe angehoben, tiefere Schatten. --sheet bleibt hell. Siehe Memory ui-depth-dark.
  • CSS-Altlast behoben: ein */ in einem Kommentar (.nav-*/.res-*) hatte die ganze .dock- Regel verschluckt (display:flex nie aktiv) — gefixt.

Vectorworks-„View-Bar" — A/B/C ERLEDIGT & verifiziert (2026-06-29)

  • A — Ebenen- + Zeichnungskombinationen: src/state/visibilitySets.ts (localStorage cad.layercombos.<name> / cad.drawingcombos.<name>), Store-Actions snapshot*/apply*Visibility in projectSlice, zwei ComboMenu-Dropdowns in TopBar (Muster wie LayoutMenu). Round-Trip per Probe verifiziert. (Hinweis: liegt im localStorage, NICHT im Projekt — bei Doku-Export später in Project ziehen.)
  • B — Darstellungsart-Dropdown (kontextabhängig je viewType): 2D Farbig/Schwarz-Weiss (planColorMode + toMono in generatePlan), 3D Schattiert/Weiss(Clay-Material in Viewport3D)/Drahtgitter/Kanten (RenderMode um "white" erweitert). Ersetzt die alte Render-Modus-Buttongruppe. Screenshots bestätigt.
  • C — 6 Ansichts-Buttons: Front/Oben/Seite/Perspektive/Isometrie + Kamera (FOV-Popover). view3d+fov in viewSlice; applyView3d(camera,controls,bounds,view3d) in Viewport3D (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 + Schraffur hatchId); addDrawing2D pusht ein polygon-Primitiv (mit drawingId → anklickbar). Attribute-Palette hat „Füllfarbe". (Kreis-Füllung offen — Kreis-Primitiv im Plan fehlt noch.)
  • Plan-View wandert nicht mehr mit: PlanView nutzt jetzt einen FIXEN Welt-Ursprung (toScreen modulkonstant, Modell-0,0) statt bounds-gebunden; Ausschnitt wird nur bei resetKey-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: Viewport3D hat jetzt eine OrthographicCamera für front/top/side/iso (OrbitControls per controls.object-Swap umgebunden), Perspektive bleibt PerspectiveCamera. 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 in PlanView erweitern (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

  1. Text-Styling (Nutzer-Wunsch). VORAUSSETZUNG: Text wird noch NICHT gerendertDrawing2D mit geom.shape==='text' misst in generatePlan nur 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).
  2. Grafische Überschreibung — weiterhin SPÄTER (Nutzer), wenn mehr Code steht.
  3. Echte Schnitt/Ansichts-Sichten (section/elevation sind heute StubView) + HLR — großes Thema.
  4. 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) als src/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)

  1. 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 in src/panels/layout.ts (defaultLayout). Neue Panels in builtinPanels/registry anmelden.
  2. 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.)
  3. 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.
  4. Display- vs. Print-Modus: Umschalter. Display = ALLES Haarlinien (konstant dünn); Print = echte mm-Strichstärken. (Globaler View-State + an generatePlan/PlanView durchreichen.)
  5. .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".
  6. „Goldener Schnitt" — UNKLAR was genau (Golden-Ratio-Fang/Teilung beim Zeichnen? Proportions-Hilfslinien?). → beim Nutzer rückfragen, bevor gebaut wird.
  7. Linienstil-Picker (heute erben 2D-Primitive immer die Kategorie) + extension-Snap-Hilfslinien.

Danach (ursprünglicher Plan)

  1. Zeichenwerkzeuge Phase 3 (drawing-tools.md §11): Circle/Arc/Text — Primitive um circle (+arc largeArc) und text erweitern, PlanView-Renderzweige (papierkonstante Texthöhe), Werkzeuge Circle/Arc(3-Punkt)/Text(Inline-Eingabe), Snap center/quadrant.
  2. 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.
  3. State-Refactor (zurückgestellt) — App.tsx God-Component → Store+Slices (docs/design/state-architecture.md). Erst nötig, wenn parallele Code-Workflows gebraucht werden.
  4. 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 (nur docs/). 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.mjsscripts/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 in Viewport3D; 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).