"+"-Buttons für Bauteile/Schraffuren/Linienstile/Wand-/Decken-/Dachstile
waren direkt als onClick={onAddX} verdrahtet — React reicht dabei das
Klick-Event als Argument durch. Im In-App-Overlay harmlos (Store-
Funktionen ignorieren Extra-Argumente), aber im nativen Ressourcen-
Fenster läuft jeder Aufruf über die Tauri-Event-Brücke (emitTo), die den
Aufruf als JSON serialisiert — ein React-Event mit zirkulären DOM-
Referenzen lässt sich nicht serialisieren, der Aufruf scheiterte lautlos.
Fix: alle betroffenen Buttons rufen den Handler jetzt explizit ohne
Argument auf. Zusätzlich die bisher stillschweigend verschluckten Fehler
in der Fenster-Sync-Brücke sichtbar gemacht (console.error statt leerem
catch), fürs nächste Mal.
Neues Project.geoAnchor: verbindet EINEN Modell-Punkt mit seiner realen
LV95-Koordinate. Bisher berechnete jeder Standort-Import (Gebäude/Terrain/
OSM) unabhängig einen neuen Bezug aus der jeweils gesuchten Adresse — bei
mehreren Importen mit leicht unterschiedlichen Suchbegriffen landete
importierter Kontext lagefalsch zueinander.
Der erste Import in einem Projekt setzt den Bezug automatisch (Modell-(0,0)
= gesuchter Ort) und speichert ihn; alle weiteren Importe verwenden densel-
ben Bezug, unabhängig vom neu gesuchten Ort (der bestimmt nur noch WOVON
Daten geladen werden, nicht mehr WOHIN sie im Modell platziert werden).
UI: Anzeige des aktiven Bezugs im Import-Dialog mit Zurücksetzen-Option.
Löst das strukturelle Problem noch nicht vollständig (der Bezug sitzt immer
bei Modell-(0,0) — passt nur, wenn das eigene Gebäude dort gezeichnet ist),
aber behebt die akute Inkonsistenz zwischen mehreren Importen.
Nutzer-Report „funktioniert nicht": Der Import stürzte mit einem harten
RangeError ab, sobald eine STAC-Kachel entpackt die maximale JS-String-Länge
überschritt (DXF komprimiert stark — eine Kachel unter dem 150-MB-Limit kann
trotzdem >700 MB unkomprimierten Text ergeben, real reproduziert für ein
dicht bebautes Stadtzentrum). downloadAssetText prüft jetzt zusätzlich die
JSZip-interne unkomprimierte Grössenschätzung VOR dem Entpacken und fängt
verbleibende Fehler (Netzwerk/ZIP/String-Länge) sicher ab, statt zu werfen.
Zu grosse/fehlgeschlagene Kacheln wurden bisher stumm übersprungen (0 Gebäude,
keine Erklärung — sah wie ein Bug aus). fetchBuildings3d liefert jetzt
skippedTiles mit; der Dialog zeigt „X Kachel(n) übersprungen, zu gross" statt
eines wortlosen Leer-Ergebnisses.
Neuer RenderStyle::ShadedEdges in render3d: wie "shaded" (echte Bauteilfarben,
beleuchtet), zusätzlich dunkle Modell-Kanten obenauf wie bei "hidden" — der
typische Revit/ArchiCAD-Look, der bisher fehlte (nur reines Weiss+Kanten via
"hidden" oder reine Bauteilfarben ohne Kanten via "shaded" waren möglich).
Nutzt dieselbe tiefengebiaste Flächen-Pipeline wie "hidden", damit die Kanten
sauber obenauf liegen (kein Z-Fighting). +6 Rust-Tests (--features render,
83/83 grün). Als neue Option "shaded-edges" in beiden Darstellungsart-
Dropdowns der 3D-Oberleiste; Three.js-Fallback ignoriert den Wert graceful
(fällt auf shaded zurück, bekommt bewusst keine neuen Features).
ColorHexField stellte Swatch UND natives <input type="color"> sichtbar
nebeneinander dar (zusätzlich zum separaten Hex-Textfeld) — wirkte wie zwei
Farbfelder pro Zeile. Hex-Textfeld entfernt, natives Color-Input liegt jetzt
unsichtbar über dem Swatch (öffnet die native Palette beim Klick auf das
einzige sichtbare Quadrat). Betrifft alle Attribute-Farbfelder in der App,
nicht nur die neuen Fenster-Linien-Felder.
Ersatz für die entfernte pauschale Brüstungslinie: wählbar aussen/innen/beide
Flächen + Blickrichtung Auf-/Untersicht (Aufsicht dünn gepunktet, Untersicht
gestrichelt wie die übrigen Überkopf-Projektionen), an der tatsächlichen
Rahmenkante statt der Wandachse. Default aus (kein Feld gesetzt = keine Linie).
UI-Feld im Fenstertyp-Editor.
Ersetzt die stark vereinfachte Box-Extrusion (vec25-Footprint + Pauschalhöhe
9m) durch echte Gebäudegeometrie aus den swissBUILDINGS3D-STAC-Kacheln (Wahl
zwischen Generation 2.0 stabil und 3.0 Beta, DXF-Kacheln über den bestehenden
dxfParser als Mesh eingelesen). Gelände kommt neu aus echten swissALTI3D-XYZ-
Rastern (0.5m/2m wählbare Punktdichte) statt der groben profile.json-Näherung.
Gemeinsames STAC-Client-Modul (stacApi.ts) für beide Quellen.
Vertikale Sprossenteilung im Glasfeld (mullionCols−1 Spalten), spiegelbildlich
zur bestehenden mullionRows-Logik: 3D-Rahmen-Riegel, Ansichts-Trennlinien +
Glasscheiben als echtes rows×cols-Raster, Eingabefeld im Fenstertyp-Editor und
im ResourceManager.
VW-Verhalten vervollständigt: das Cursor-Kästchen spiegelt jetzt den Feld-
Status der Befehlszeile (Tab-Feld-Zyklus) — der getippte Wert erscheint
SOFORT im aktiven Feld oben am Cursor UND unten im Befehl; gelockte Werte
fett/dunkel, das aktive Tab-Ziel als blaue Pille mit weissem Text. Tab
wechselt Länge ↔ Winkel (global, auch ohne Fokus), und eine Ziffer (oder
. , -) beim Zeichnen startet die Werteingabe direkt (beginTyping fokussiert
die Befehlszeile mit dem ersten Zeichen — kein Klick nötig).
- PlanView: HudFieldsState + Segment-HUD (aktiv/gelockt/getippt je Feld)
- CommandLine: onTextChange (Live-Echo) + Handle beginTyping(seed)
- App: cmdTyped-State, hudFields an alle PlanView-Pfade, globaler
Ziffern-Handler vor dem Tab-Zyklus
737/737 grün.
toElevation.ts: Painter-Projektion des 3D-Modells auf die Ansichtsebene
(Fassaden-/Deckenflächen fern→nah, Rückseiten-Culling, Fenster/Türen als
Rahmen+Glas, Bodenlinie) + klassischer 45°-Schlagschatten auskragender
Bauteile (Sutherland–Hodgman auf die Empfängerfläche geclippt). Schatten-
Umschalter in der Ansichts-Leiste (DrawingLevel.shadows), App rendert
elevation-Ebenen über den neuen Generator (synchron, ohne WASM).
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
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.
App: kind "elevation" nutzt generateElevationPlan (synchron, ohne WASM)
statt der Schnitt-Pipeline; Fallback-Hinweis bleibt bei fehlender Linie.
Oberleiste (ViewRibbonTab): Umschalter "Schatten", nur bei aktiver Ansicht
sichtbar, schreibt DrawingLevel.shadows. i18n-Keys in de/en.
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 (cdbef99) um den Zeichenweg. 684/684 grün.
Dachaufbauten sind jetzt im Ressourcen-Manager anleg-/editier-/löschbar
(RoofStylesTab auf dem LayeredStylesTab-Rumpf, Ressource roofTypes):
Schichtliste mit Bauteil/Dicke/Fugen-Linienstil, Löschen geschützt solange
ein Dach den Typ referenziert. Host-/App-Handler (patch/add/deleteRoofType)
+ i18n de/en. Vervollständigt die Dach-Schichtlogik (3a986ec) um die UI.
Zwei vom Renderer bereits konsumierte Felder im Flügel/Sprossen-Panel
zugänglich gemacht + in der Live-Ansicht dargestellt:
- transomHeight (Oberlicht): 2D-Kämpferlinie im Grundriss + 3D-Oberlichtscheibe
waren schon da; Kämpferlinie jetzt auch in der Dialog-Vorschau
- mullionRows (Kämpfer-/Sprossenzeilen): 3D-Kämpfer bei 'fein'; waagrechte
Teiler in der Vorschau
Kein Renderer-Aufwand — reine UI-/Vorschau-Freischaltung. 659/659 grün.
Das ⚙ der Öffnungs-Sektion öffnet neu einen dedizierten Dialog (VW-Studie §3)
statt in den Ressourcen-Tab zu springen. Drei Zonen: Kategorie-Sidebar,
Parameter-Panel, Live-2D-Frontalansicht (aus den aktuellen Werten gezeichnet:
Rahmen/Flügel/Öffnungslinien/Verglasung/Rollladenkasten).
- OpeningEditorDialog.tsx: Kategorien Basis/Grösse/Rahmen/Flügel/Sonnenschutz
(Fenster) bzw. Türblatt (Tür); Flügeltabelle (Flügel/Pfosten + Öffnungsart +
Anschlag je Zeile); Stil-Leiste mit Stilwahl + 'Als Stil speichern …'
- App: openingEditorId-State, Dialog-Render, saveOpeningStyle (klont aktuellen
Typ als neuen benannten WindowType/DoorType und weist ihn zu)
- host.onOpenOpeningEditor + OpeningInfo.id für den ⚙-Sprung
- Studie docs/design/window-editor-vectorworks-study.md
- Dialog-CSS (.oed-*) + i18n (de/en)
Renderer-Konsum der neuen Felder (sashes/glazingPanes/shading in 2D/3D) folgt separat.
Discoverability für die vertieften Bauteil-Typen: neben dem Typ-Dropdown
einer gewählten Öffnung öffnet ein ⚙-Knopf das Ressourcen-Fenster direkt
beim passenden Typeditor-Tab (Tür→doorStyles, Fenster→windowStyles).
- ResourceManager: initialTab-Prop (springt auch bei bereits offenem
Fenster auf den angeforderten Tab).
- host.onEditOpeningType(kind) + App-Wiring (resourcesTab-State).
tsc + vitest 620 grün.
Der WebGL2<->Nordstern-Umschalter wandert aus der Statusleiste in den
Settings-Dialog. Default ist jetzt Nordstern (WASM), sofern WebGPU
verfuegbar ist; WebGL2 nur noch als expliziter Fallback. So sieht man
nicht mehr versehentlich die Darstellungsfehler des WebGL2-Viewers.
styles.css: .sb-renderer-toggle align-self:flex-start, damit das Pill
im Settings-Dialog nicht auf volle Breite zieht.
Neuer Datei-Menü-Eintrag „Bauteilliste (CSV)": eine Zeile je Wand/Decke
(Typ, ID, Bauteil, Geschoss, Länge, Höhe, Dicke, Fläche) plus Aggregat
je Bauteil-Typ, als CSV-Download. Kennwerte aus dem Modell abgeleitet
(Wandlänge aus Achse, wallTypeThickness, polygonArea), RFC-4180-Escaping.
- "+ Text"-Knopf entfernt (war ohnehin immer deaktiviert, kein Werkzeug
dahinter — Text wird ein eigenständiges Zeichenwerkzeug, AUDIT B1).
An seiner Stelle ein Zeilenhöhe-Regler (Stepper, Vielfaches der
Schriftgrösse) — neues Paragraph.lineHeight, durchgereicht bis in
HTML-Vorschau (line-height) und SVG-Render (kumulierte Zeilen-
Vorschübe statt festem lineGap).
- Linienstil im Attribute-Panel war rein informativ (kein Setter im
Host-Kontrakt). onSetSelectionLineStyle ergänzt (nur Drawing2D),
jetzt echtes Dropdown statt "—"-Anzeige.
- docs/design/dossier-feature-audit.md: der ausführliche A1-A6/B1-B4/
C1-C3/D1-D3/E-Auditbericht aus einer alten Session gesichert (lag
bisher nur im Transkript, nicht im Repo) — Quelle der HANDOVER.md-
AUDIT-Kürzel.
Text-Werkzeug nutzte bisher OS-abhängige Systemfonts (Helvetica/Arial/
Times/Georgia/Courier) — Darstellung und PDF-Export waren damit nicht
plattformunabhängig deterministisch. Jetzt 15 kuratierte SIL-OFL-
Schriften lokal als WOFF2 gebündelt (je mit OFL.txt-Lizenz):
Inter, Work Sans, IBM Plex Sans/Mono, Source Sans 3, Space Grotesk,
Manrope, Outfit, DM Sans, Public Sans, Karla, Rubik, Jost, Archivo,
Source Serif 4. Ein späterer Einstellungen-Dialog kann weitere
Schriften nachladen.
ColorHexField (neu, geteilt) trennt die zwei Klickziele: Swatch/
natives Farb-Input öffnet weiter den Picker, der Hex-Text daneben ist
jetzt ein eigenes Eingabefeld (Enter übernimmt, Esc verwirft, ungültige
Eingabe fällt auf den letzten gültigen Wert zurück). Ersetzt die
bisherige reine Text-Anzeige in SettingsDialog + AttributesPanel.
- Marke (DOSSIER-Wortmarke) + Ressourcen-Icon ganz links, wie im
Rhino-Plugin; Settings-Icon folgt über den neuen Einstellungs-Dialog.
- Massstab/Zoom-Cluster bereinigt: doppelte Massstab-Dropdown entfernt,
Zoom-Aktionen unter dem Massstab-Dropdown gestapelt (gleiche Breite),
Ring bei "am Massstab" statt Flächen-Aufhellung.
- PDF/DXF-Export aus der Leiste raus, zusammen mit Speichern/Öffnen/
Import in einem neuen Datei-Burger-Menü ganz rechts. Speichern/Öffnen
sind echte JSON-Download/-Upload-Handler fürs ganze Projekt.
- Einstellungs-Fenster (neu): Accent-Palette, Auswahlrahmen-/Snap-Farbe
editierbar (freier Picker + Presets), Projekt-Referenzhöhe (m ü. M.)
als Feld.
- LayoutMenu auf die eigene Dropdown-Komponente umgestellt (war noch
natives <select>).
- Custom Fenstersteuerung (_/□/X) für die randlose Electron-Shell via
Preload+IPC, eigener Look statt OS-Chrome; Oberleiste als Drag-Region.
- Dark-Theme ist jetzt fester Standard (vorher an OS-Präferenz
gekoppelt, zeigte je nach Umgebung fälschlich Light) — Light bleibt
als Opt-in (`[data-theme="light"]`) für einen künftigen Umschalter.
Alle Oberleisten-Pillen (Dropdown-Trigger, Segmente, Icon-Knöpfe,
Ansichts-Icons) auf dieselbe dunkle Fläche wie das Kontextmenü
vereinheitlicht. Panel-Köpfe nicht mehr separat aufgehellt, feste
Höhe (40px) unabhängig von optionalem Darstellungsmodus-Dropdown.
- 2D-Zoom-Grenzen deutlich erweitert (20000x/0.005x statt 50x/0.2x).
Mehrere Stellen (ResourceManager SelectField + Material-Browser,
ImportDialog, AttributesPanel, SitePanel, ToolsPanel,
DisplayModeSelect, RichTextEditor) nutzten noch native <select>, deren
Optionsliste vom Betriebssystem gerendert wird und optisch nicht zur
eigenen Dropdown-Komponente (dunkles Kontextmenü-Popover) passt. Jetzt
durchgaengig dieselbe Optik.
Wie bei Schraffuren/Linien/Wandstile: Liste links, Detail-Panel rechts.
Vorarbeit vor der eigentlichen Bauteil-Logik. Alte Tabellen-Bausteine
(ResTable/ResRow/ResCell/AddButton) entfernt, da nicht mehr genutzt.
Wand- und Deckenstile bekommen dasselbe Master-Detail wie Schraffuren/Linien:
Liste links mit Querschnitt-Thumbnail + Name, Detail rechts mit grossem
Querschnitt und Aufbau-Editor (Schichten: Bauteil/Dicke/Fugenlinie,
hinzufuegen/entfernen/umordnen), Inline-Rename, Trash-Delete, Neu anlegen.
Neuer WallTypeSwatch (hatchPreview) zeichnet die geschichtete Wand/Decke als
proportionale Baender mit den Bauteil-Schnittschraffuren. Add/Delete-Handler
(addWallType/deleteWallType/addCeilingType/deleteCeilingType, In-Use-Schutz)
in App.tsx + host ergaenzt.
Gebaeude-Footprints (swisstopo vec25) werden jetzt zu Volumen extrudiert
(z=0 bis Hoehe; Hoehe aus OSM height/building:levels, sonst 9 m; Deckel/
Boden via Delaunay, konkave Grundrisse) und als importedMesh gerendert — der
flache Footprint-contourSet bleibt fuer den 2D-Plan erhalten. Neuer
Terrain-Abruf (swissALTI3D ueber den CORS-faehigen profile.json-Dienst,
zeilenweise parallel) liefert ein N-Raster, das terrainMeshFromGrid
trianguliert; Hoehen aufs Zentrum bezogen, lagerichtig zu den Gebaeuden.
Neue Quelle 'Swisstopo-Gelaende' im Import-Dialog. Viewport3D unveraendert
(bestehender importedMesh/terrainMesh-Pfad). 8 neue Tests.
Der Ressourcen-Editor ist von einem blockierenden Modal (dunkler Backdrop,
Canvas gesperrt) zu einem frei schwebenden Fenster geworden: verschiebbar
ueber die Kopfzeile (Pointer-Capture-Drag), unten rechts resizable, KEIN
Backdrop — der Plan bleibt bedienbar, sodass Schraffur-/Linien-Aenderungen
live am Modell sichtbar sind. Der Ressourcen-Button bleibt Toggle, Esc
schliesst weiter. FloatingPanel-Bausteine wiederverwendet; die interne
Tab-/Master-Detail-Struktur unveraendert.
Der Linien-Editor ist modular: eine Linie ist eine geordnete, loopende Folge
aus Segmenten Strich (Laenge), Punkt (Dot) und Luecke (Laenge) — beliebige
Sequenzen (Volllinie/Strichlinie/Punktlinie/Strich-Punkt als Presets, plus
frei), die Schluss-Luecke ist die letzte Luecke. Datenbasis bleibt
LineStyle.dash (mm, alternierend); ein Punkt ist ein 0-Laengen-AN-Segment.
Enthaelt dash eine 0, wird die Linie mit runder Kappe gezeichnet, damit
Punkte als Dots erscheinen (Live + Print; GL/DXF Folgearbeit). Neue reine
Segment-Logik in ui/lineSegments.ts. LineSwatch zeigt den ersten Loop dunkel
und 2 weitere grau (Loop-Kontext). 14 neue Tests, 127 gruen.