mesh.rs berechnet die Ecken-Verschneidung jetzt selbst (portiert aus dem
Web-Kern computeJoins/clippedBand): Wandenden werden per Rundungs-Key
gruppiert, ueber Hoehen-Ueberlappung geclustert (gestapelte Geschosse mit
gleichem Grundriss verschneiden sich NICHT), und Zweier-Cluster ueber die
gemeinsame Gehrungslinie geschnitten. T-/X-Stoesse und freie Enden bleiben
stumpf, wie im Web-Kern. Endkappen-Normalen geometrisch aus dem Kreuzprodukt.
WallInput bekommt optional layers (WallLayer{thickness,color}, serde-default,
rueckwaertskompatibel): jede Schicht wird als eigenes Band ueber dieselbe
gehrte Grundflaeche extrudiert und materialgefaerbt. toWalls3d.ts loest die
WallType-Schichten je Wand auf (hexToRgb) und reicht sie durch.
39/39 Rust-Tests (7 neue: Gehrung, T-Stoss, freies Ende, Schichten, Kombi).
Die alte Eigenschaften-Leiste (Geschosshoehe/Schnitthoehe/OKFF) weicht einer
Tab-Leiste 'Zeichnungen': ein Tab je Geschoss-Grundriss, Klick wechselt die
aktive Zeichnungsebene. Bindet an activeLevelId/setActiveLevelId — dieselbe
Store-Quelle wie das Panel 'Zeichnungsebenen', beide bleiben synchron.
Geschosshoehe/Schnitthoehe werden in den Geschoss-Einstellungen gepflegt.
Der Drawing-Typ (kind: 'plan') und der switch beim Aktivieren lassen spaeter
Schnitt-/Layout-Tabs zu, ohne die Leiste umzubauen.
Jede Stempelzeile (Name, Name-2, Bodenflaeche, Nutzung) hat jetzt eine
eigene Ausrichtung links/mitte/rechts, im Stempel-Editor pro Zeile
waehlbar und in SVG- wie nativer Darstellung honoriert (text-anchor bzw.
align). Bodenflaeche/Nutzung fallen auf mitte zurueck (bisheriges Bild).
Der Stempel-Anker (stampAnchor bzw. Schwerpunkt) meldet sich zusaetzlich
als Endpunkt-Snapkandidat an — gefiltert nach Geschoss und sichtbarer
Kategorie; der ziehbare Griff war bereits verdrahtet.
Die Kamera-Presets liefen zuvor als Viewport-Overlay mit eigenen JS-yaw/pitch-
Winkeln, rein perspektivisch (Iso falsch, keine Parallelprojektion). Jetzt
haengt der Engine-Viewport am app-weiten view3d-State (TopBar-CameraMenu, wie
three.js) und nutzt die vorhandene Rust-preset_camera:
- web.rs: set_view_preset(preset) + model_bounds/fit; Front/Top/Side echt
orthografisch, Iso/Perspektive perspektivisch - wie das native Fenster.
default_fov() pub(crate), damit Fit denselben FOV nutzt.
- useWasm3dRenderer: applyViewPreset; render(null) ueberschreibt die
Preset-Kamera nicht.
- Wasm3DViewport: konsumiert view3d/renderMode als Props (Overlay + lokaler
Umschalter entfernt, wasm3dOverlay.css geloescht); Orbit bleibt frei
(Preset = Sprung, kein Lock), three.js-Verhalten gespiegelt.
- Viewport3D-Switcher reicht view3d/renderMode an den Engine-Viewport durch
(kein three.js-Szenencode angefasst).
- Sample-Raum R1: boundary auf die echte Innenkante der Aussenwaende
(Achse +/- halbe Wanddicke 0.1725 bei Wandtyp aw 0.345 m) statt 0.1-Inset -
der Umriss lag bisher ~7 cm im Wandkoerper.
- Raumfarbe #5a7a9a -> neutrales Grau #6b7280 (Umriss + Stempel).
- ROOM_FILL_ALPHA 33 -> 00: keine transluzente Farbfuellung mehr
(Plandarstellung schwarz/grau); das Polygon bleibt fuer die Auswahl
erhalten (Hit-Test laeuft ueber pointInPolygon, nicht ueber die Fuellung).
Offen: automatische Ableitung der Raum-Boundary aus den Wand-Innenflaechen
fuer spaeter gezeichnete Raeume.
Der Engine-3D-Viewport (render3d/wgpu) war reines Ansehen (Orbit/Zoom). Jetzt:
- Kamera-Presets als Overlay: Top/Unten/Vorne/Hinten/Links/Rechts/Iso.
Richtungen exakt wie der three.js-Pfad (applyView3d); framen die aktuelle
Modell-Bounding-Box (fitTargetDist) und springen auf den Preset-Winkel,
danach Orbit/Pan/Zoom weiter frei. Rein JS.
- Render-Modus Schattiert/Weiss: mode-Uniform in Globals (WGSL/Rust),
Weiss = beleuchtetes Clay-Grau; wasm-Binding set_render_mode_white,
durchgereicht via useWasm3dRenderer.
- Overlay-CSS self-contained (wasm3dOverlay.css), Theme-aware.
three.js unangetastet. Auswahl/Grips/Zeichnen + Wireframe/HLR bewusst noch
offen (naechste Scheibe).
Mehrschichtige Waende zeichnen die Trennlinie an jeder Materialfuge jetzt mit
einem pro Fuge waehlbaren LineStyle statt einer festen Haarlinie.
- Layer.jointLineStyleId (optional): LineStyle der Fuge an der Innenkante
dieser Schicht; fehlt er, gilt die Default-Haarlinie (0.02) in Wandfarbe.
- generatePlan: Schicht-Baender tragen nur noch Fuellung + Schraffur (kein
Band-Umriss); jede innere Fuge wird als eigene Linie mit ihrem LineStyle
(Gewicht/Farbe/Dash, x Detailfaktor) gezeichnet. Wand-Umriss (0.35) und
grob-Pfad unveraendert.
- ResourceManager: neue Abteilung "Wandstile" - je Wandtyp die Schichten
mit Fugen-LineStyle-Dropdown.
- Sample: LineStyle "Schichtfuge 0.13"; der Daemmung-Backstein-Fuge (massiv/
massiv) zugewiesen, Putzfugen bleiben Haarlinie.
- 2 Joint-Tests ergaenzt.
Boegen (Tuer-Schwenkbogen) wurden mit fester Segmentzahl (16/90 Grad) beim
Kompilieren tesselliert und beim Zoom nur per Matrix neu gezeichnet - beim
Reinzoomen daher sichtbare Facetten. Jetzt skaliert die Segmentzahl mit der
Bildschirmgroesse des Bogens: Sagitta < 0.5 px (segs = clamp(ceil(|dPhi|/theta),
8, 2048)), theta = 2*acos(1 - 0.5/rPx). Weit weg wenige Segmente (Perf),
nah rund.
Anti-Thrash per LOD-Bucket round(log2(pxPerMeter)): Neu-Tessellierung nur
bei Bucket-Wechsel, sonst bleibt Zoom/Pan reiner Matrix-Update. Bogen laeuft
weiter durch strokePolyline - runde Caps/Joins bleiben erhalten.
Plandarstellung ist schwarz/grau; Farbe bleibt spaeteren Schemaelementen
vorbehalten.
- Tuerblatt, Schwenkbogen, Fensterscheibe und Anschlagstriche: einheitlich
#1a1a1a statt blau (#2b3039/#4a86c7/#6b7280), im render2d/PDF-Pfad
(CLS_STROKE) und im SVG-CSS.
- Schwenkbogen als Volllinie (Strichelung entfernt).
- Tuer-/Fenstersymbol-Linien auf Haarlinie 0.02 mm (SYMBOL_HAIRLINE_MM).
- Decken-Poche: Schraffur auf weissem Grund wie mehrschichtige Waende
(pocheFill), solid schwarz - nicht mehr die Bauteil-Fuellfarbe.
quantizePen hob bisher jede Breite <= 0.13 mm auf die unterste Stift-Stufe
(0.13 mm) an. Dadurch druckte die 0.02-mm-Schraffur/Schichtfuge im PDF und
im SVG-Print-Modus als 0.13 mm - im Viewport duenn, im Export dick.
Breiten unter MIN_PEN_MM gelten jetzt als bewusste Haarlinien und werden
exakt (unquantelt) durchgereicht; ab 0.13 mm rundet die Leiter wie gehabt.
Der Linien-Modus (Display/Print) wandert aus der Oberleiste und die
Fang-Optionen aus der Werkzeug-Palette in die Statusleiste unten:
- StatusBar: segmentierter Display/Print-Umschalter (Stil wie der
Renderer-Umschalter) plus Fang-Pill mit nach oben öffnendem Popover
(Master-Schalter + Endpunkt/Mittelpunkt/Schnittpunkt/Kante/Raster/
Ortho + Rastermass).
- TopBar: Linien-Modus-Gruppe entfernt.
- ToolsPanel: Fang-Abschnitt entfernt.
- App reicht lineMode/snap an die StatusBar durch.
Schraffurlinien verlassen den screenPx-Sonderpfad und laufen wie jede
andere Linie durch die Papier-mm-Pipeline (glPlan, SVG, PDF): im Display
konstante Haarlinie (paperScaleForGl-Kehrwert von meet), im Print echte
0.02 mm - deckungsgleich mit den Schichtfugen in beiden Modi.
- POCHE_STROKE #2b3039 -> #1a1a1a: kein Blaustich mehr, gleicher
Neutralton wie die Schraffur (Wände/Öffnungen/Decken/Treppen).
- Schichtfuge LAYER_LINE_MM 0.13 -> 0.02 (Haarlinie).
- Schraffur-Stift hatch-hair/hatch-dash 0.05 -> 0.02.
- Wand-Umriss Kategorie 20 lw 0.5 -> 0.35 (Standard-Aussenlinie war zu dick).
- SVG-Schraffur nutzt HAIRLINE_PX/printStrokeVb statt hatchStrokePx;
PDF-Export echte mm statt widthScreen.
WASM_ENGINE_ACTIVE nimmt die Engine, sofern nicht explizit WebGL2 gewählt ist
(?engine=webgl2 bzw. localStorage cad.rendererMode==="webgl2") oder WebGPU
fehlt. three.js bleibt der stille Fallback. Der Engine-3D-Viewport ist vorerst
nur Ansehen (Orbit/Zoom); Auswahl/Griffe/Zeichnen folgen.
- HatchStyle.relativeToWall: der Wandwinkel (aus wall.start/end) wird in
addWallPoche und resolveWallSectionStyle auf hatch.angle addiert (Vorzeichen
zur SVG-CW-Konvention passend), sodass die Schraffur der Wandachse folgt.
- sampleProject: sia-concrete (crosshatch 45° absolut), sia-brick (diagonal
wandrelativ), sia-insulation (diagonal 90° wandrelativ, solide Haarlinie);
Komponenten Beton/Backstein/Dämmung darauf umgehängt. Dichte Muster (scale
0.5/0.5/0.45), hairline (Strichgewicht 0.05 → 0.6px-Boden).
- Poché-Hinterlegung: mehrschichtige Wände (und einschichtige) weiss, solid
schwarz (Fill + Schraffurfarbe), konsistent in SVG- und glPlan-Fill; Mono
behält Schwarz für solid. Gilt auch für den Schnitt-Cut.
- ResourceManager: Wandbezug-Schalter im Hatch-Manager. exportDxf: Dash-
Splitting für gestrichelte Schraffuren.
- Runde Enden und Ecken statt Butt-Caps/Miter: jedes Segment als eigenes
Quad, an Innenecken ein Dreiecks-Fächer über den Aussenwinkel (addRoundJoin),
an offenen Enden ein Halbkreis-Fächer (addRoundCap). Gilt für Wandumrisse,
Linien, Bögen und Schraffurläufe — Look wie das Vektor-PDF. Keine Shader-
Änderung nötig (Radius weiterhin zur Render-Zeit aus strokePx*strokeScale).
- Schraffur-Dicke-Bug behoben: glPlan schickte die Schraffur-mm durch die
Papier-mm-Pipeline (strokeMm*mmToDevicePx); im Display-Modus ist der darin
steckende paperScaleN ein zoom-abgeleiteter, nicht auf 0.13/mm kalibrierter
Wert → Breite explodierte. Jetzt hatchStrokeVb = max(0.6, hatchMm/0.13) als
screenPx-Batch (skaliert nur mit meet/Zoom) — byte-genau wie SVG-<pattern>
und der PDF-Export (widthScreen). Wandumrisse unverändert (echte mm).
appendStroke rechnete widthScreen-Schraffurbreiten über mmPerM=1000/
scaleDenominator um → die gedruckte mm-Breite hing vom Export-Massstab ab
(0.25mm bei 1:50 vs 0.13mm bei 1:200 für dieselbe Quellbreite). Jetzt
widthMm * HATCH_DENSITY_MM (0.13) — der exakte Kehrwert von toRenderScene
hatchPx = max(0.6, hatchMm/0.13) → identische Papier-mm bei jedem Massstab,
deckungsgleich zur Bildschirmvorschau. Ungenutzten mmPerM-Parameter entfernt.
buildPlanPdf ruft planToRenderScene(plan, opts.scaleDenominator) statt des
Default 1:100 → der Stempel-Zeilenabstand mehrzeiliger Texte ist jetzt auch im
PDF bei Nicht-1:100-Massstab papier-mm-genau (identischer Nenner wie an
sceneToPrintSvg). Schliesst den in der vorigen Änderung offen gelassenen
Aufrufer-Punkt.
planToRenderScene(plan, paperScaleN=100) leitet den Zeilenabstand mehrzeiliger
Stempeltexte jetzt aus dem tatsächlichen Massstab-Nenner ab (mmToM = paperScaleN
/1000) statt aus der bisher fest verdrahteten 1:100-Konstante. Deckt sich mit dem
nRef der SVG-Text-Formel in PlanView. Viewport/WASM-Aufrufer behalten den Default
100 (deren Referenzmassstab). Der PDF-Export reicht den echten Massstab im
Folgeschritt durch.
Die SVG-Print-Vorschau reichte rohe mm-Breiten in printStrokeVb, während der
PDF-Export jede Breite via quantizePen() auf die Stiftleiter (0.13/0.18/0.25/…)
rundete → Vorschau ≠ Druck. quantizePen ist jetzt aus sceneToPrintSvg.ts
exportiert und wird in den zwei Print-Zweigen von PlanView (DrawingRunShape,
renderPrimitive-weight) verwendet. Nur EINE Leiter, keine Kopie. Haarlinien-Pfad
und Dash-Arrays unangetastet (das PDF quantisiert Dashes ebenfalls nicht).
Die geschnittenen Flächen erhielten bisher die rohe Albedo-Farbe der Engine plus
eine generische Diagonalschraffur. Jetzt löst attachCutStyles() jede Cut-Fläche
über den index-parallelen ComponentRef auf ihr Quell-Bauteil auf:
- toSection.ts: wallSegmentOwners()/slabSegmentOwners() bilden die exakte
Segment-Zerlegung aus projectToModel3d nach (gleiche EPS-/Öffnungs-Logik) und
liefern je emittiertem Segment das Quell-Wall/Ceiling — index-gleich zur
WASM-Elementreihenfolge (per Test bewiesen: W1,W1,W1,W2).
- generatePlan.ts: resolveWallSectionStyle/resolveCeilingSectionStyle wählen die
Komponente mit höchster joinPriority (wie die Grundriss-Poché) bzw. die erste
Deckenschicht und liefern fill+HatchRender über resolveHatch. generateSectionPlan
nutzt diese, im Mono-Modus weiss/SECTION_INK. Fallback bei fehlendem Bauteil =
bisheriges Verhalten (Albedo + generische Schraffur).
Gates: tsc -b 0, build grün.
paperScaleForGl nutzt im hairline-Modus den live aus dem Ausschnitt abgeleiteten
scaleFromView(v) statt des stabilen paperScale. Der GL-Term mm_to_device_px =
N/1000·PX_PER_M·meet wuchs bisher über meet mit dem Zoom, obwohl Display/Haarlinie
konstante Strichbreiten verspricht. scaleFromView ist der exakte Kehrwert von meet
→ N·meet kürzt sich, die Breite in Geräte-px bleibt zoom-unabhängig (dieselbe
Wirkung wie non-scaling-stroke im SVG-Pfad). Print-Modus unverändert.
Restlücke (separat, bräuchte Shader-Änderung): noch nicht wörtlich uniform 1px wie
der SVG-Haarlinienpfad — Breiten bleiben gewichts-proportional, aber zoom-konstant.
- render3d/web.rs: GPU-freies WASM-Binding cut_section_json(model_json, p, n)
→ JSON {cutPolygons, visibleEdges, hiddenEdges} in (u,v)-Metern.
- src/plan/toSection.ts (neu): SectionOutput-Typen, sectionPlaneFromLevel()
leitet die Schnittebene aus linePoints/directionSign ab, computeSection()
flacht über projectToModel3d ab und ruft das Binding.
- src/engine/engine3d.ts (neu): geteilter memoisierter pkg3d-Loader, damit
3D-Viewport und Schnittpfad EINE mod.default()-Init teilen.
- generatePlan.ts: generateSectionPlan() übersetzt SectionOutput in
bestehende Primitive (Cut = polygon mit Poché-Schraffur, sichtbare Kante =
line solid, verdeckte Kante = line dashed) — keine neue Primitive-Art nötig.
- App.tsx: SectionPlanView ersetzt den Stub für Ebenen vom Typ Schnitt/Ansicht;
rendert dasselbe PlanView, mit lokalisierten Hinweisen (lädt/keine Linie/Fehler).
- i18n de/en: section.*-Schlüssel.
- Öffnungen erscheinen korrekt (Brüstung/Sturz-Teilrechtecke) über die
projectToModel3d-Teilkörper-Zerlegung.
Gates: tsc -b 0, build grün (WASM = eigener Lazy-Chunk), render3d cargo test 29/29,
wasm32 --features web check grün.
glyphon 0.11 ist die neueste zu wgpu 29 passende Version (wgpu 30 existiert
bereits, glyphon pinnt aber ^29). Das 22er-Limit maxInterStageShaderComponents
wird von 29 nicht mehr in requiredLimits gesendet — src/engine/requestDeviceShim.ts
komplett entfernt, beide Hook-Importstellen (useWasmPlanRenderer, useWasm3dRenderer)
angepasst. pollster 0.3→0.4, naga 22→29 mitgezogen. Alle Draw-/Text-Pfade
(draw_sequence, glyphon ColorMode::Web, widthScreen-Polylinien, Headless/Golden)
unverändert funktionsfähig.
Verifiziert: cargo check nativ (render2d/render3d/src-tauri) grün, cargo test
render2d 17/17 + Golden bit-exakt, render3d 29/29, wasm32 --features web für
beide grün, npx tsc -b + npm run build grün.
exportPdf baut jetzt planToRenderScene(plan) — identischer Aufruf wie der
Engine-Viewport — und serialisiert über den neuen sceneToPrintSvg nach
Papier-mm: z-stabile Reihenfolge wie compile_scene, PEN_STEPS-Quantisierung
wie bisher, widthScreen-Schraffurbreiten via (widthPx/PX_PER_M)*(1000/N)
in mm umgerechnet, Texte neu als echte Vektor-Texte (alter Pfad liess sie
weg). planToPrintSvg bleibt als Referenz, im Kopf als abgeloest markiert.
probe-pdf.mjs: Icon-Button-Selektor nachgezogen, neue Assertions (Schraffur-
Polylinien vorhanden, alle stroke-widths auf PEN_STEPS). Messung: 3666
Vektor-Pfadoperatoren, 7 Text-Operatoren, 0 Rasterbilder; Inhalt per
pdftoppm 53.51x43.69 mm vs. erwartet 53.45x43.45 bei 1:100.
Feature web (wasm-bindgen) + cdylib analog render2d; WebModelRenderer
mit Canvas-Surface, set_model (walls/slabs wie der native Push) und
set_camera. Projektion liefert bereits [0,1]-Clip-Z, math.rs unveraendert.
wgpu-22-requestDevice-Shim in src/engine/requestDeviceShim.ts geteilt.
Neuer Hook useWasm3dRenderer + Wasm3DViewport (Orbit/Pan/Zoom wie three.js-
Sicht); Viewport3D dispatcht per ?engine=wasm bzw. localStorage, three.js
bleibt Default. Build-Script build:engine3d (wasm-pack, src/engine/pkg3d).
Verifiziert headful per scripts/probe-engine3d.mjs (37 % Geometrie-Pixel);
headless praesentiert Chromium keine WebGPU-Frames (auch bei render2d).
Geteilter Offscreen-three.js-Renderer (ein Kontext, serielle Queue, Cache
per Map-Signatur) rendert 128px-Kugeln lazy via IntersectionObserver.
Kategorie-Chips aus der Bibliothek abgeleitet, uneinheitliche Manifest-
Schreibweisen normalisiert; Suche und Kategorie kombinierbar. Kachel-Klick
markiert aktiv (gleiche Sprache wie MaterialPicker). Puppeteer-Probe
scripts/probe-material-tiles.mjs prüft Grid, Lazy-Render und Filter.
Integrations-Spike: die native 2D-Engine (src-tauri/render2d) laeuft jetzt als
WASM/WebGPU-Canvas in der App-UI, mit derselben Szene (planToRenderScene) und
ViewBox wie der WebGL2-Pfad; das SVG-Overlay (Text/Griffe/Auswahl) bleibt drueber.
- render2d: neues Feature "web" (wasm-bindgen/web-sys), Fassade WebPlanRenderer
(new/set_scene/set_view_box/set_paper_scale/resize/render) auf Canvas-Surface.
Geteilte GPU-Schicht (gpu.rs), native Fensterschicht (winit) unberuehrt.
- Font: cosmic-text findet auf wasm keine Systemfonts -> Inter-Bytes eingebettet
(assets/Inter.ttf), Renderer.load_font + text_family aus der geladenen Familie.
- Frontend: useWasmPlanRenderer (gleiche Schnittstelle wie useGlPlanRenderer);
PlanView waehlt die Engine per ?engine=wasm + navigator.gpu, sonst WebGL2/SVG.
- Build: npm-Script build:engine (wasm-pack, target web -> src/engine/pkg,
gitignored). chromium-shell.sh mit WebGPU-Flags (--enable-unsafe-webgpu/Vulkan).
- Kompat-Shim: wgpu 22 sendet das spec-entfernte Limit maxInterStageShaderComponents,
das neuere Chromium ablehnen -> im Hook vor requestDevice entfernt.
Verifiziert: cargo test -p render2d gruen (18), tsc gruen, wasm-Build gruen;
Headless-Chromium (?engine=wasm) zeichnet den Grundriss (Waende/Schraffur/
Tuerschwenk/Treppe/Raumtext) im WASM-Viewport, Fallback ohne Flag unveraendert.
Bögen im nativen 2D-wgpu-Renderer werden nicht mehr zoomabhängig in Segmente
zerlegt, sondern per SDF-Fragment-Shader (ARC_WGSL) mathematisch exakt rund
gerendert — bei jeder Zoomstufe ein echter Kreis, kein Vieleck, ohne
Neu-Tessellierung.
- compile_scene sammelt je Bogen EINE analytische Instanz (ArcInstanceData,
Bildschirm-Raum-Parameter + Dash in Modell-Metern), zoom-invariant.
- Eigene Arc-Pipeline (ein Frame-Uniform, Quad je Instanz aus vertex_index):
radiale Kante, Butt-Cap-Winkelclamp (beide Sweep-Vorzeichen) und Dash
(Bogenlänge modulo Muster) analytisch antialiased; Strichbreite mit derselben
mm->px-Formel wie die Linien.
- tessellate_arc + Zoom-Retessellierungs-Cache (last_scene/arc_px_per_m/
maybe_retessellate) entfernt; upload_scene ohne px_per_m.
- Tests auf die neue Semantik umgeschrieben (Winkel-Parität, Bounding-Box,
Dash-Mapping), ARC_WGSL per naga validiert.
Papier-mm-Strichmuster (dash) wurden bisher komplett ignoriert und immer
durchgezogen gerendert — im nativen 2D-Fenster gab es dafür bislang gar keinen
Mechanismus. `split_dash` portiert den bereits für Schraffuren bewährten
`applyDashRuns`-Algorithmus (glPlanHatch.ts) nach Rust und zerlegt einen
Linienzug in seine "an"-Teilstücke; die Phase läuft dabei über bereits
verkettete Zeichnungszüge UND über die neu adaptiv tessellierten Bögen
hinweg durch, sodass z. B. der gestrichelte Türschwenk-Bogen gleichmäßig
gestrichelt bleibt statt an jedem Segment neu anzusetzen.
Bögen (Türschwenke) wurden bisher einmalig in JS in eine feste Facettenzahl
zerlegt; beim Hineinzoomen wurden die Facetten sichtbar. Die Zerlegung
(`tessellate_arc`) wandert nach Rust und läuft jetzt zoomabhängig anhand einer
Sehnenabweichungs-Toleranz (Sagitta ≤0.3 Geräte-px), Segmentzahl auf 8..512
geklemmt. Die native GPU-Szene bekommt dafür einen eigenen `Arc`-Primitiv-Typ
(unvortessellliert); der Renderer merkt sich die zuletzt hochgeladene Szene und
tessellliert Bögen automatisch neu, sobald sich der Zoom seit dem letzten
Upload um mehr als Faktor 1.3 verändert hat.
Deckenplatten (SlabInput) werden im render3d aus dem Grundriss-Umriss per
Ear-Clipping trianguliert und über die Deckendicke extrudiert (Deckel/Boden/
Mantel mit robust nach außen orientierten Normalen). Payload erweitert auf
{ walls, slabs } — blanke Wand-Arrays bleiben kompatibel. Beleuchtung auf
hemisphärisches Ambient (Himmel/Boden) + Directional-Sonne umgestellt, dezente
Kantenbetonung, hellerer Hintergrund (#f5f5f5). Beispiel-Geschossdecke im EG.
Viewport3D nutzt jetzt ACESFilmicToneMapping + sRGB-Ausgabe (weiche
Lichter statt hartem Clipping) und eine neutrale Raum-Umgebung
(PMREMGenerator + RoomEnvironment) als IBL-Quelle für plausible
Reflexionen. Wände/Decken/Öffnungsrahmen/Glas/Türblatt/Treppen und das
Auswahl-Highlight laufen von MeshLambertMaterial auf MeshStandardMaterial
um (Rauigkeit/Metallizität je Bauteilart, moderate envMapIntensity);
direktes Licht entsprechend zurückgenommen, da die Umgebung nun mit-
trägt. Hintergrundfarbe, Hidden-Line- und Clay-Modus unverändert.
Raumstempel-Text rendert jetzt im nativen wgpu-Fenster mit echten
TrueType-Glyphen (Inter, Systemfonts via cosmic-text) ueber einen
GPU-Glyphen-Atlas — im selben 4x-MSAA-Pass nach der Geometrie.
Schriftgroesse in Papier-mm (gleiche Formel wie Strichbreiten, skaliert
mit dem Zoom); die Bridge flacht Rich-Text-Stempel + Zusatzzeilen
zeilenweise auf serde-kompatible texts ab (Layout wie der SVG-Pfad).
Die nativen wgpu-Fenster spiegeln jetzt das LIVE-Modell statt des
eingefrorenen JSON-Snapshots: die Webview schiebt bei jeder Aenderung
(debounced 200 ms) den sichtbaren Plan (planToRenderScene) bzw. die
Projekt-Waende (projectToWalls3d) per push_native_scene/push_native_walls
an einen EventLoopProxy<UserEvent> der winit-Loop. Ansicht wird nur neu
eingepasst, solange im Fenster noch nicht gepannt/gezoomt/orbitiert
wurde; die JSON-Assets bleiben Start-Fallback. Ohne Tauri: No-op.
Eine Einstrich-Vektorschrift sieht neben dem echten Browser-Font schlecht aus;
Text bleibt dem Browser-/Overlay-Pfad ueberlassen. strokeFont.ts entfernt,
toRenderScene ueberspringt Text-Primitive wieder. Schraffuren/Poche/Ecken bleiben.
Neues strokeFont.ts (kompakte Einstrich-Schrift: A-Z, 0-9, Symbole inkl. ²/·).
toRenderScene wickelt Text-Primitive (Doc-Zeilen + Live-Zusatzzeilen) zu Glyph-
Polylinien in Modell-Metern ab (vertikal um den Anker zentriert, Ausrichtung je
Absatz) und speist sie wie die Schraffuren in die render2d-Szene. Erste Fassung
in Versalien; render2d bleibt textrenderer-frei. Damit zeigt der native Grundriss
den Raumstempel (Name/Fläche/SIA) analog zum Browser.
- native.rs: EINE winit-EventLoop hostet 2D- und 3D-Fenster (winit erlaubt nur
eine Loop pro Prozess) — loest den RecreationAttempt-Panic zweier Loops; ersetzt
native2d.rs/native3d.rs. Feature-gegated (native2d/native3d, einzeln oder zusammen).
- render2d/render3d laden das ECHTE Modell aus assets/native2d_scene.json bzw.
native3d_walls.json (Demo-Szene als Fallback); initialer Ausschnitt/Kamera aus
den Modell-Grenzen gerahmt, initialer Redraw + gesetzte Fenstergroesse.
- TS-Konverter toRenderScene/toWalls3d + scripts/dump-native-scene erzeugen die
JSON aus sampleProject/generatePlan (npm run dump:native).
- render2d: Scene.polylines fuer zusammenhaengende Umriss-/Zeichnungslaeufe →
Gehrung statt Stumpfkappen an Wandecken/2D-Geometrien; MITER_LIMIT 4→8
(deckungsgleich mit SVG stroke-miterlimit:8 und WebGL2).
- native3d-Feature + render3d-Pfad-Dep in der Tauri-Crate.
Wandecken (generatePlan/glPlanCompile/PlanView): die diagonale Miter-Stirnkante
am L-Stoss wurde als Umriss gestrokt -> Barb-Ueberstand am Aussenapex + 45deg-
Naht zwischen gleichen Schichten. Fix: interne Join-Stirnkanten per neuem
noStrokeEdges vom Umriss ausnehmen (Fuellung bleibt volle Flaeche, laengs
laufende Materialfugen bleiben). Ecke = sauberer Miter ohne Ueberstand, gleiche
Schichten verschmelzen nahtlos ueber die Ecke. GPU- und SVG-Pfad teilen sich
noStrokeEdges.
Dämmschraffur (glPlanHatch): die Sinuswelle wurde pro Segment einzeln aufs
Polygon geclippt und mit Butt-Caps gestrokt -> fransige Fragmente an jeder
Wellenbiegung. Fix: kontinuierliche Punkt-Laeufe (clipPolylineToPolygon) als EIN
gehrter Streifen; Dash laeuft ueber die Laeufe. STEPS 12->22. Gerade Scharen
(diagonal/crosshatch) unveraendert.
Muster in Modell-Metern erzeugt (massstabstreu wie SVG-<pattern>), konkav-
faehig auf das Fuellpolygon geclippt (even-odd-Scanline, halb-offene Kanten-
Konvention). Strichbreite in Papier-mm; Dash geometrisch aufgeloest. Emittiert
nach der Fuellung, vor dem Umriss (Stapelreihenfolge wie SVG). 12 Unit-Tests.
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.