Nutzer-Report nach der Umstellung auf Inline-Editing: beides funktionierte
nicht — "Text" liess sich kein Ankerpunkt setzen, "Textspalte" sollte ein
Rechteck statt nur eine Breite sein.
Root Cause für "Text": `.planview-inline-text` bekam ohne Spaltenbreite
`width: undefined` — bei position:fixed ohne rechten Rand greift shrink-to-
fit-Sizing, das für ein LEERES contentEditable auf ~0px kollabiert. Der Klick
erzeugte tatsächlich ein Element + öffnete den Editor, beides war nur
unsichtbar (eine 0px-Box lässt sich nicht anklicken/fokussieren). Fix: neue
Klasse .planview-inline-text-free (kein wrapWidth) erzwingt `width:
max-content` + `white-space: pre` auf Editor/Surface (Box wächst mit dem
Inhalt statt umzubrechen — "Text" bleibt einzeilig bis Enter, wie gewünscht)
plus eine CSS-Mindestbreite (160px) für den leeren Startzustand.
"Textspalte" (textbox.ts) zeichnet jetzt ein RECHTECK (zwei diagonale Ecken,
beliebige Zugrichtung) statt nur eine horizontale Breitenlinie — die
aufgezogene Höhe wird nicht im Modell gespeichert (das Textformat kennt nur
`width` für den Wortumbruch, keine feste Rahmenhöhe), sondern als
Editor-MINDESThöhe durchgereicht: CommandResult/EngineHost.focusDrawing um
`focusMinHeightM` erweitert (Passthrough wie focusDrawingId), App.tsx hält
sie in einem neuen editTextMinHeightM-State (useContextMenuState.ts),
PlanView nutzt sie als CSS-min-height des Editors — der Rahmen wächst bei
mehr Text darüber hinaus, schrumpft aber nicht darunter (InDesign-Verhalten).
Beim Doppelklick-Editieren bestehender Elemente wird die Mindesthöhe
zurückgesetzt (kein Nachwirken einer vorigen Textspalten-Erstellung).
textbox.test.ts an die neue Rechteck-Geste angepasst (+ Test für beliebige
Zugrichtung). tsc -b / vitest run (919/919) / npm run build grün. Die
eigentliche Sichtbarkeits-Vermutung (CSS-Kollaps) konnte ich nicht
interaktiv im Browser verifizieren (kein Browser-Tool verfügbar) — Nutzer
prüft erneut in der laufenden App.
Nutzer-Report: Textfelder waren nicht mehrzeilig. Ursache: die Text-/
Textspalte-Werkzeuge holten ihre Eingabe über die Befehlszeile
(CommandLine.tsx) — ein einzeiliges <input>, Enter committet sofort, kein
Zeilenumbruch möglich. Das betraf auch "Textspalte", obwohl die explizit für
mehrzeiligen Wortumbruch gedacht ist.
Lösung (Nutzer-Vorgabe: kein Dialog, direktes Editieren auf der Fläche wie
im Layout-System): text.ts/textbox.ts committen nach dem Platzieren (Anker
bzw. Anker+Breite) sofort ein LEERES Text-Element und melden
`focusDrawingId` — dafür CommandResult/EngineHost um einen Passthrough
erweitert (engine.ts applyResult ruft host.focusDrawing(id)). App.tsx setzt
darauf Auswahl + editTextId (dieselbe State-Variable wie beim bisherigen
Doppelklick-Editieren). PlanView rendert bei gesetztem editTextId jetzt
einen RichTextEditor-Overlay direkt über dem Element (position:fixed via
vbToClient/toScreen, eigene Mini-Toolbar erscheint darüber) statt des
bisherigen TextEditorDialog-Modals — Prinzip 1:1 vom Layout-Blatt-Inline-
Editor (LayoutSheet.tsx) übernommen. Die neuen Props (editTextId/
onCommitTextEdit/onCloseTextEdit) laufen durch Content/LevelPlanView/
SectionPlanView (viewportContent.tsx) bis zu PlanView durch.
Verhalten der beiden Werkzeuge (Nutzer-Vorgabe): "text" bleibt ohne
Wortumbruch (kein `width`) — Enter erzeugt weitere Zeilen, aber keine
automatische Breite. "textbox" setzt `width` und verhält sich damit wie ein
InDesign-Textrahmen (echter Wortumbruch live beim Tippen, kein reines
Render-Detail mehr).
commitTextEdit (useMouseSelectionHandlers.ts) schreibt jetzt bei JEDEM
Tastendruck (kein Guard mehr gegen leeren Text — nötig, damit Löschen bis
auf null Zeichen sich sofort spiegelt); neues closeTextEdit räumt ein beim
Schliessen noch leeres Element auf (verhindert Leichen bei abgebrochener
Neuerstellung).
4 neue Tests (text/textbox: sofortiger Commit + focusDrawingId). tsc -b /
vitest run (918/918) / npm run build grün. Rendering/Positionierung des
Overlays selbst nicht automatisiert testbar — Nutzer prüft visuell in der
Tauri-App.
Neuer Befehl multiline.ts, baut auf derselben Offset-Geometrie auf wie der
bestehende offset-Befehl (offsetSegment) — erzeugt aber alle Kopien auf
einmal statt einzeln nacheinander offsetten zu müssen. Deckt gerade
Basislinien ab (häufigster Fall: Grenzlinie+Abstand, Leitungspaar,
Randlinien), keine mehrsegmentige Variante.
Ablauf: Start-/Endpunkt (Tab-Felder Länge/Winkel wie line.ts), dann Abstand
per Maus-Klick (Seite bestimmt Vorzeichen, wie bei offset.ts) oder getippt;
die Anzahl (Default 3, Bereich 2-6) zyklt über eine Inline-Option und bleibt
wie Abstand/Seite über Aufrufe hinweg persistent.
In Registry/Aliase (ml/parallel), ToolsPanel (COMMANDS_EDIT neben Offset),
CommandIcon, i18n de/en aufgenommen.
2 neue Tests. tsc -b / vitest run (916/916) / npm run build grün.
Anders als Fillet/Extend existierte hierfür noch gar keine Geometrie —
chamferCorner (src/geometry/kernel2d.ts) ist neu: gleicher Abstand vom Eck
auf beiden Schenkeln, gerade verbunden (klassischer Gleichabstands-Chamfer,
analog zu filletCorner, nur ohne Bogen — daher exakt statt tesselliert).
commands/cmds/chamfer.ts wortwörtlich nach dem fillet.ts-Muster: Ecke wählen,
Distanz per Maus oder getippt (Tab-Feld). In Registry/Aliase
(ch/fasen), ToolsPanel (COMMANDS_EDIT neben Fillet), CommandIcon, i18n
de/en aufgenommen.
3 neue Tests (Fasung, Fehltreffer, Distanz-zu-gross-No-op). tsc -b /
vitest run (914/914) / npm run build grün.
filletCorner (Eckpunkt-Verrundung) und extendSegment (Gegenstück zu Trim)
existierten fertig implementiert und getestet im Kernel (kernel2d.ts), hatten
aber keinen einzigen Aufrufer — kein Command, kein Werkzeug-Knopf, für den
Nutzer nicht erreichbar. Reine Verdrahtungsarbeit, kein neues Geometrie-
Problem:
- fillet.ts: Ecke einer polyline/rect wählen (nächstgelegener Eckpunkt mit
zwei Nachbarn), Radius per Maus oder getippt (Tab-Feld wie bei circle.ts).
Da Polylinien im Modell keine Bogen-Segmente kennen (kein "Bulge" —
bekannte, separate Lücke), wird die Verrundung als kurze Punktfolge
tessselliert statt als echtes Arc-Objekt gespeichert; ein rect wird beim
ersten Fillet zu einer polyline. Ehrlich im Kopfkommentar dokumentiert.
- extend.ts: offene Kurve (line/offene polyline) nahe einem Ende anklicken,
dieses Ende wird bis zur nächsten anderen Kurve verlängert (implizite
Cutter wie bei Trim). Kein Treffer → No-op, Befehl bleibt aktiv.
Beide in COMMANDS/ALIASES registriert (fi/verrunden, ext/verlaengern),
i18n de/en ergänzt, in ToolsPanel COMMANDS_EDIT neben Trim/Join aufgenommen,
eigene Icons in CommandIcon.tsx (bisher: unbekannter Name → kein Icon).
Rotate NICHT angefasst: der ursprüngliche Befund „Rotate ist keine getippte
Kommandozeilen-Aktion, nur ein UI-Button" war unvollständig — App.tsx routet
sowohl den Ribbon-Button als auch das getippte Wort „rotate"/„drehen" ganz
bewusst an startTransformOp() (den reicheren U/I/O/P-Move/Copy/Array/
Verteilen-Fluss), nicht an die generische Befehls-Engine (Kommentar dort
erklärt das explizit). Ein zuerst geschriebener, einfacher rotateCommand
(nur „move"-Modus) wäre über diese Sonderfälle nie erreicht worden UND hätte
über neue Aliase wie „ro" einen inkonsistenten Zweit-Pfad geöffnet (voller
Funktionsumfang bei „rotate", abgespeckter bei „ro") — verworfen, bevor
committet.
6 neue Tests (fillet: Verrundung + Fehltreffer; extend: Verlängerung +
Kein-Cutter-No-op). tsc -b / vitest run (911/911) / npm run build grün.
Shortcut-Map, obwohl beide Befehle längst fertig implementiert waren.
Zusätzlich musste man nach jedem gesetzten Punkt Esc drücken, bevor eine
Zifferntaste das nächste Werkzeug wählte — der Fokus blieb im Befehlsfeld
hängen (dort wird nach Abschluss nicht mehr geblurred) und die globale
Kürzel-Prüfung ignorierte jede Eingabe im Feld pauschal. Jetzt gibt die
Engine den Fokus frei, sobald ein Befehl fertig ist (Commit/Abbruch), und
eine Zifferntaste wählt direkt das nächste Werkzeug (Vectorworks-Stil) —
aber nur, wenn das Feld leer ist UND der aktuelle Schritt weder Tab-Felder
noch Freitext erwartet (Textlabel-Eingabe wie „Raum 101" bleibt geschützt).
Nach einem Standort-Import landet die Kontext-Geometrie dort, wo der gesuchte
Ort war — das kann weit vom bisherigen Modell-Ursprung liegen. Neuer Befehl
"georef" (Button in SitePanel) verschiebt das GESAMTE Projekt per Klick so,
dass der gewählte Punkt zum neuen Ursprung wird; geoAnchor wandert automatisch
mit, der reale LV95-Bezug bleibt exakt erhalten (rekonstruierbar, auch beim
späteren Export). Bewusst nur Translation, keine Rotation — mehrere Felder
(Roof.ridgeAxis, Column.rotation, Text-/Bild-Rotation) sind achsen-/winkel-
gebunden und bräuchten bei einer Drehung eigene Sorgfalt.
VW-Feinschliff (Nutzer-Screenshots):
- Rechteck (2-Punkt + Zentrum) zeigt Δx/Δy vorzeichenbehaftet statt
Diagonale+Winkel (deltaHud; Zentrum = volle Rechteckmasse). Die
width/height-Tab-Felder erscheinen im HUD als Δx/Δy.
- Führungslinie des Winkelrasters läuft jetzt weit über den Cursor hinaus
(quer über den Ausschnitt statt 40 px).
- Winkelbogen ergänzt: gestrichelter Bogen von der horizontalen 0°-Referenz
(dezentes Lachsrot, VW-Anlehnung) zur Strahlrichtung, Badge sitzt am
halben Winkel aussen am Bogen.
737/737 grün; headless verifiziert (Linie 45° + Rechteck-Δ).
Beim Zeichnen erscheinen Länge + Winkel direkt am Cursor (L:/W:-Kästchen),
gängige Winkel (15°-Vielfache) rasten weich ein — mit Winkel-Badge und
gestrichelter Führungslinie. Vorrang: Objekt-Snap > Shift/Ortho > Winkelraster
> Raster. Toggle + Toleranz in der Fang-Leiste. Konflikt tools/types.ts:
erweitertes hud-Feld + measure-Feld koexistieren.
# Conflicts:
# src/tools/types.ts
Alle punktbasierten Zeichenbefehle setzen den Cursor-HUD jetzt einheitlich
über den gemeinsamen segmentHud()-Helper statt eigener Text-Formatierung:
- line/polyline/wall: L/W-Kästchen für das lebende Segment ab dem letzten
Punkt.
- rect: 2-Punkt/Zentrum-Methode zeigt die Diagonale als L/W; die 3-Punkt-
Methode zeigt die Basiskante als L/W bzw. Basisbreite+Höhe im Rise-Schritt.
- circle/arc (Radius-Schritt): Radius als „R: …m"-Label statt L/W (kein
Winkel sinnvoll); arc zeigt im Spannwinkel-Schritt Radius als L und
Spannwinkel als W.
Alle Werte jetzt mit 3 Nachkommastellen (vorher 2 bzw. 0), konsistent mit
der VW-Konvention der Statusleiste.
Tests: line.test.ts/wall.test.ts prüfen hud.length/angleDeg im onMove-Draft
(inkl. negativer Winkel im Bereich (−180,180] und Segment-Wechsel bei
mehrteiligen Wandzügen).
Beim Zeichnen erscheint jetzt direkt am Cursor ein blau umrandetes
Massband-Kästchen mit Länge/Winkel (L: 3.118m W: 60.000°, Winkel im
Bereich (−180,180]) statt nur in der Befehlszeile. Zusätzlich rastet
der Zugwinkel weich auf gängige Winkel (15°-Vielfache, Toleranz per
Default 2.5°) ein, sobald kein Objekt-Snap greift — mit gelblichem
Winkel-Badge und einer über den Cursor hinaus verlängerten, gestrichelten
Führungslinie (Vectorworks-Vorbild).
- tools/types.ts: ToolDraft.hud um length/angleDeg erweitert (text bleibt
für Befehle ohne L/W-Paar), neuer segmentHud()-Helper.
- tools/snapping.ts: neue reine Funktion snapCommonAngle() + Einbindung in
computeSnap (Objekt-Snap > harter Ortho-Zwang > weiches Winkelraster >
Raster). Neues SnapSettings-Feld commonAngles + commonAngleTolerance,
neuer SnapKind "angle".
- ui/StatusBar.tsx: Toggle + Toleranz-Eingabe in der Fang-Popover.
- plan/PlanView.tsx: DraftHud- und AngleGuide-Overlay (screen-space,
zoomunabhängige Größe); die Winkel-Info reitet auf draft.snap mit.
- i18n: snap.commonAngles / snap.commonAngleTolerance (de/en).
- snapping.test.ts: snapCommonAngle-Fälle (exakt/Toleranz/Bereich/
15°-Raster/Projektion) + Objekt-Snap-Vorrang vor dem Winkelraster.
Zwei Klicks (Start -> Ende) legen die Grundriss-Schnitt-/Ansichtslinie einer
DrawingLevel fest. Ziel: genau eine Platzhalter-Ebene ohne Linie wird belegt,
sonst neue Ebene (Schnitt B/C ...). Live-Vorschau mit Richtungspfeil, Art
(Schnitt/Ansicht) als Inline-Option umschaltbar. Registry-Aliase schnittlinie/
ansichtslinie, Ribbon-Gruppe 'Schnitte' im BIM-Tab, i18n de/en, Datenpfad-Tests.
Zwei Klicks (Ecke → Gegenecke, Live-Vorschau + Mass-HUD); die Aussparung wird
der Decke des aktiven Geschosses hinzugefügt, die das Rechteck vollständig
enthält (alle 4 Ecken im Umriss), sonst No-op. Aliase 'deckenloch'/
'aussparung', BIM-Ribbon-Eintrag mit eigenem Icon. Komplettiert die Decken-
Aussparungen (b290120) um den Zeichenweg. 684/684 grün.
Frisch mit dem Fenster-/Tür-Werkzeug platzierte Öffnungen erhielten keinen
typeId → resolveOpeningFrame lieferte null → weder 2D-Rahmenband noch
3D-Rahmen/Laibung wurden gezeichnet (nur Loch + flache Scheibe). Das war
der Grund, warum die vertiefte Fenster-/Tür-Darstellung „im 3D gar nicht
so aussah". Fix: appendOpening weist den ersten Fenster-/Türtyp der
Bibliothek zu (Fenster→windowTypes[0], Tür→doorTypes[0]); ohne Bibliothek
bleibt das typlose Inline-Verhalten.
Das Mess-Werkzeug wird von der reinen Strecke zum Polygonzug:
- Jeder Klick setzt einen weiteren Stützpunkt; angezeigt werden letztes
Segment (Länge · Winkel), aufsummierte Pfadlänge und — ab 3 Ecken —
die umschlossene Fläche (Gauss).
- Die Messwerte erscheinen dauerhaft im Objekt-Info-Panel (neuer
Abschnitt „Messung"), nicht nur flüchtig am Cursor-HUD. Kanal:
ToolDraft.measure → PanelHost.measurement → ObjectInfoPanel.
- Rechtsklick/Enter beendet den aktuellen Pfad und armiert sofort einen
neuen (mehrere Messungen nacheinander); Rechtsklick auf leerem Pfad
bzw. Esc beendet das Werkzeug.
+4 Tests (Segment/Winkel, Summe/Fläche, Ketten-Verhalten). tsc sauber.
Neuer GPU-Renderer fuer den Grundriss (src/plan/glPlan/): Earcut-Tessellierung
(konkav-faehig), gehrte Linienzuege (Miter), echte Papier-mm-Strichbreiten im
Massstab (repliziert den SVG-printStrokeVb-Pfad), Hybrid mit scharfem SVG-Text-
Overlay. GPU ist der Standardpfad; der SVG-Renderer bleibt automatischer Fallback,
falls WebGL2/Shader nicht verfuegbar sind. Imperativer Pan (rAF + CSS-transform)
fuer fluessige Interaktion ohne React-Re-Render je Frame.
Enthaelt zudem den bisher nicht committeten Arbeitsstand des Browser-BIM
(Oeffnungen, Treppen, Raeume, Decken, DXF-Export, Materialbibliothek, Kontext-
Import, Tauri-Compute-Boundary-PoC).
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.