diff --git a/docs/design/window-editor-vectorworks-study.md b/docs/design/window-editor-vectorworks-study.md
new file mode 100644
index 0000000..50fecd9
--- /dev/null
+++ b/docs/design/window-editor-vectorworks-study.md
@@ -0,0 +1,449 @@
+# Fenster-/Tür-Editor — Studie & Designdokument (Referenz: Vectorworks „Fenster bearbeiten")
+
+Status: Studie/Entwurf (KEIN Code). Ziel: den heute als „mega mager" empfundenen
+Fenster-/Tür-Editor zu einem eigenständigen, reichen **Einstellungs-Dialog** mit
+Kategorie-Sidebar, Live-Vorschau (2D + 3D) und **„Als Stil speichern"** ausbauen.
+Diese Datei ordnet die Vectorworks-Referenz dem bestehenden DOSSIER-Modell zu und
+schlägt einen realistischen, phasierten Plan vor.
+
+Konvention: Bezeichner englisch, UI-Text/Kommentare deutsch. Meter als Grundmaß.
+
+---
+
+## 1. Executive Summary
+
+**Was ein guter DOSSIER-Fenster-/Tür-Editor sein sollte.** Ein eigener modaler
+Dialog „Fenster-/Tür-Einstellungen" — nicht die heutige, in den Ressourcen-Manager
+eingebettete Formularspalte (`WindowStylesTab`/`DoorStylesTab` in
+`src/ui/ResourceManager.tsx`), die pro Feld nur eine `FieldRow` zeigt und keinerlei
+Vorschau bietet. Der neue Dialog hat drei Zonen (wie Vectorworks):
+
+1. **Kategorie-Sidebar** links (Basis, Größe/Position, Rahmen, Flügel/Sprossen,
+ Oberlicht/Unterlicht, Laibung/Bank, Sonnenschutz/Rollladen, Attribute/Darstellung,
+ Detaillierung).
+2. **Parameter-Panel** in der Mitte (die Controls der gewählten Kategorie).
+3. **Live-Vorschau** rechts: eine 2D-Plan-Vorschau (aus `generatePlan()`) und eine
+ 3D-Ansicht/Elevation (aus `projectToModel3d()`), beide sofort aktualisiert.
+
+**Die eine wichtigste strukturelle Änderung.** Der Editier-Primärort wandert vom
+Ressourcen-Tab in einen **dedizierten `OpeningEditorDialog`**, der TYP-Parameter
+(wiederverwendbarer Stil = `WindowType`/`DoorType`) und INSTANZ-Parameter (dieses
+`Opening`) im selben Fenster editiert und oben eine Stil-Leiste trägt:
+`Stil: [Dropdown]` · `Fenster speichern…` (aktuelle Konfiguration als neuen
+benannten `WindowType`/`DoorType` ablegen) · `Einstellungen zurücksetzen…`
+(auf den Stil zurückfallen). Das ⚙ in `ObjectInfoPanel.OpeningSection`
+(`src/panels/ObjectInfoPanel.tsx:731`) öffnet künftig DIESEN Dialog statt den
+Ressourcen-Manager-Tab.
+
+**Begriffsklärung.** Der Nutzer-Ausdruck „als **Wandstil** speichern" ist ein
+Versprecher — gemeint ist „als **Fensterstil/Türstil** (Bauteilstil) speichern",
+also ein neuer Eintrag in `project.windowTypes` bzw. `project.doorTypes`, analog
+`WallType`/`CeilingType`/`StairType`. Es entsteht KEIN neuer Wandtyp.
+
+**Warum das der Hebel ist.** Alle geplante Tiefe (mehrflügelig, Sprossenraster,
+Rollladen, Bank/Nische, Ober-/Unterlicht, Verglasungsanzahl) braucht (a) mehr
+Felder auf `WindowType`/`DoorType` und (b) eine UI, die sie ohne Formularwust
+zeigt und deren Wirkung sofort sichtbar macht. Ohne Live-Vorschau bleibt ein
+reicher Parametersatz unbenutzbar. Erst der Dialog macht die Tiefe zugänglich; die
+Modellfelder allein (Abschnitt 4) reichen nicht.
+
+---
+
+## 2. Vollständige Mapping-Tabelle (VW-Referenz → DOSSIER)
+
+Legende — Status: **✓** vorhanden · **~** teilweise (Feld existiert, Renderer liest
+es nicht ODER nur grob) · **✗** fehlt. Ebene: **T** = Typ (Stil, wiederverwendbar,
+auf `WindowType`/`DoorType`) · **I** = Instanz (auf `Opening`). Priorität P0
+(erste reiche Scheibe) … P3 (VW-Ballast). Aufwand grob in Personentagen (PT).
+
+Wichtiger Ist-Befund aus dem Code (Renderer-Konsum-Lücken):
+
+- `WindowType.glazing` (einfach/zweifach/dreifach) ist editierbar, wird aber von
+ KEINEM Renderer gelesen. 3D zeichnet stets EINE Scheibe (`glassPanesForOpening`
+ in `src/plan/toWalls3d.ts:1965` ignoriert `glazing`); 2D leitet die Glaslinien-
+ Anzahl allein aus `DetailLevel` ab (`addOpeningSymbol` in
+ `src/plan/generatePlan.ts:2214`, `glassCount = detail==="fein" ? 2 : 1`).
+- `WindowType.kind`/`DoorType.kind` (dreh/kipp/drehkipp/fest/schiebe …) schlagen
+ sich NICHT in 2D/3D-Geometrie nieder.
+- `DoorType.leafCount` (1/2), `leafStyle`/`glazingRatio` (außer `leafStyle==="glas"`
+ → 3D-Verglasung an) sind ungenutzt.
+- `WindowType.sillBoard` ungenutzt; `DoorType.threshold` → `hasSill` genutzt.
+- 3D-Mittelpfosten/Kämpfer und Sprossen werden nur bei `detail==="fein"` emittiert
+ (`frameMeshesForOpening` in `src/plan/toWalls3d.ts:1902`, ab :1938).
+
+### 2.1 Basiseinstellungen
+
+| VW-Control | Status | DOSSIER-Feld (Vorschlag) | 2D-Wirkung | 3D-Wirkung | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Fensterart („Für normale Wand") | ✗ | `WindowType.wallKind?: "normal"\|"eck"` (später) | — | — | T | P3 | 0.5 |
+| Öffnungsart (Dreh/Kipp/…) | ~ | `WindowType.kind` existiert, kein Render | Öffnungssymbol/Öffnungslinien | Öffnungslinien 3D | T | P1 | 2 |
+| Einfügepunkt längs (Mitte/…) | ✓ | `Opening.position` + Bezugspunkt in `ObjectInfoPanel` | Position im Plan | Position | I | — | — |
+| Einfügepunkt quer (Fensterseite außen/…) | ~ | `insetFromFace`/`insetFace` (T) | Band-Lage | Rahmen-Normalenlage (`resolveFrameNormalRange` :1803) | T | P1 | 0.5 |
+| Versatz im Fassadenmodul | ✗ | — (Fassadensystem fehlt in DOSSIER) | — | — | — | P3 | — |
+| Laibung (wählen) | ~ | `insetFromFace` deckt Teil ab | Laibungsstriche (fein) | Laibungstiefe | T | P2 | 1 |
+| Klasse | ~ | `Opening.categoryCode` (LayerCategory) | Farbe/Strich | — | I | — | — |
+| Darstellung höchste Detaillierung | ✓ | `Opening.detailLevel` + Ansichts-DetailLevel | Symbolstufe | Meshstufe | I | — | — |
+| Eigenes Symbol verwenden | ✗ | `WindowType.symbolId?` (Drawing2D-Ref) | Symbol-Override | — | T | P3 | 3 |
+
+### 2.2 Fenstergröße & Bemaßung
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Fensterbreite (Wert) | ✓ | `Opening.width` (+ `defaultWidth` T) | ✓ | ✓ | I/T | — | — |
+| Fensterhöhe (Wert) | ✓ | `Opening.height` (+ `defaultHeight` T) | ✓ | ✓ | I/T | — | — |
+| Bezug B1..B5 / H1..H7 (Roh-/Fertigmaß) | ✗ | `WindowType.dimRef?: {...}` | Bemaßungsschema | — | T | P3 | 3+ |
+| „Bemaßung automatisch" (außen/innen) | ✗ | — (DOSSIER hat noch keine parametrische Öffnungs-Bemaßung) | Maßketten | — | T | P3 | 5+ |
+
+Der ganze VW-Maßketten-/Bezugsapparat (B1..B5, H1..H7, Roh-/Fertigmaß-Umschaltung)
+ist **P3/„nicht bauen"** — siehe Abschnitt 5. DOSSIER trägt lichte Maße
+(`width`/`height`), das genügt.
+
+### 2.3 Höhe Brüstung/Sturz
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Position definieren durch (Brüstungshöhe/…) | ✓ | `Opening.sillHeight` (+ `defaultSillHeight` T) | — | vertikale Lage (`openingVerticalExtent`) | I | — | — |
+| Abstand Brüstungshöhe (Wert) | ✓ | `Opening.sillHeight` | — | ✓ | I | — | — |
+| „bezieht sich auf" (Wandaußenseite/…) | ✗ | — (immer Wand-UK-relativ) | — | — | — | P3 | — |
+| „auf Ebenenbasishöhe" | ~ | Wand-UK ergibt sich aus Geschoss (`baseElevation`) | — | ✓ | — | — | — |
+
+### 2.4 Rahmenwerte
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Rahmenbreiten (4 Kanten, asymmetrisch) | ~ | heute nur `frameWidth` (eine Zahl) → `WindowType.frameWidths?: {left,right,top,bottom}` | Rahmenkontur (`windowSymbol`/`addOpeningFrameBand`) | Rahmen-Boxen (`frameMeshesForOpening`) | T | P2 | 2 |
+| Symmetrisch-Toggle | ✗ | `WindowType.frameSymmetric?: boolean` | — | — | T | P2 | 0.5 |
+| Flügel mittig / Versatz | ✗ | `WindowType.sashOffset?: number` | Aufschlag-Linie | Flügel-Box-Lage | T | P2 | 1 |
+| Rahmenstärke quer zur Wand | ✓ | `frameThickness` / `frameDepth` (→ `resolveAcrossWallDepth` :1780) | — | Rahmentiefe | T | — | — |
+| Schnitt-/Außenansicht-Rahmenbreiten | ~ | von `frameWidth` mitgezeichnet | Bandbreite | — | T | P2 | 1 |
+
+### 2.5 Flügeleinteilung (KERN-Tiefe — höchster Wert)
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Flügeltabelle (Nr/Typ/Breite/Anschlag/…) | ~ | `wingCount` (Zahl) → **neu** `WindowType.sashes: SashDef[]` (siehe §4) | Pfostenlinien (`mullionLines`) heute nur gleichmäßig | Pfosten-Boxen nur gleichmäßig | T | **P0** | 4 |
+| Typ Flügel \| Pfosten | ✗ | `SashDef.kind: "fluegel"\|"pfosten"` | Pfostenlage frei | Pfosten frei | T | P0 | (inkl.) |
+| Aut. Breite / Flügelbreite | ~ | `SashDef.autoWidth`/`width` (heute nur gleichmäßig) | Teilungslage | Teilungslage | T | P1 | 1 |
+| Pfostenbreite / „alle gleich" | ~ | `SashDef.postWidth`, `WindowType.uniformPosts` | Pfostendicke | Pfostenbox-Breite | T | P1 | 1 |
+| Anschlag (Drehbar links/Drehkipp rechts) | ✗ | `SashDef.opening: OpeningKind`, `SashDef.hingeSide: "left"\|"right"` | Öffnungslinien/Pfeil je Flügel | Öffnungslinien 3D | T | **P0** | 2 |
+| Aufschlag (Abstand zu Rahmen) | ✗ | `SashDef.rebate?: number` | Aufschlag-Linie | — | T | P2 | 0.5 |
+| Winkel / 3D-Öffnung | ✗ | `SashDef.openAngle?: number` | — | Flügel gekippt/offen | T | P2 | 1.5 |
+| Griffart | ✗ | `SashDef.handle?: HandleKind` | — | Griff-Mesh (§2.7) | T | P2 | 1 |
+| Kämpfer-Zeilen (horizontale Teilung) | ~ | `mullionRows` existiert | Querlinien | Kämpfer-Boxen (fein) | T | P1 | — |
+
+Dies ist die **wertvollste Lücke**: VW modelliert je Flügel Typ, Breite,
+Öffnungsrichtung, Anschlag, Griff. DOSSIER hat nur eine gleichmäßige `wingCount`.
+Die `SashDef[]`-Tabelle (§4, Phase P0/P1) ist der zentrale Ausbau.
+
+### 2.6 Laibungsverkleidung · Form · Ober-/Unterlicht · Nische/Bank
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Laibungsverkleidung erstellen | ✗ | `WindowType.reveal?: {create, depth, thickness}` | Laibungsband | Laibungs-Boxen | T | P2 | 1.5 |
+| Form (Eckig/Schräg/Spitz/Rund) | ✗ | `WindowType.headShape?: HeadShape` + Eckmaße | Öffnungsumriss-Form | Bogen-/Schräg-Mesh | T | P2 | 4 |
+| Oberlicht erstellen + Höhe/Rahmen/Sprossen | ~ | `transomHeight` existiert (feste Scheibe) → `WindowType.transom?: {height, frame, grid}` | Kämpferlinie + Feld | zweite Scheibe (`glassPanesForOpening` :1988) | T | P1 | 2 |
+| Unterlicht (unteres festes Feld) | ✗ | `WindowType.underlight?: {height, frame, grid}` | Feld | Scheibe unten | T | P2 | 1.5 |
+| Sprossen (horiz./vert. im Feld) | ~ | `mullionRows` grob → `WindowType.muntins?: {rows, cols}` je Feld | Sprossengitter | Sprossen-Boxen (fein) | T | P1 | 2 |
+| Nische aussparen (außen/innen) | ✗ | `WindowType.niche?: {aussen, innen, ...}` | Nischenkontur | Nischen-Aussparung | T | P2 | 2 |
+| Fensterbank erstellen (außen/innen) | ~ | `sillBoard` existiert, ungenutzt → `WindowType.sill?: {aussen, innen, typ, masse}` | Bankkontur | Bank-Box | T | P1 | 2 |
+| Banktyp/Winkel/ΔZ/Endverkröpfung | ✗ | Unterfelder von `sill` | Detail | Detail-Mesh | T | P3 | 2 |
+
+### 2.7 Sonnenschutz · Beschlag · Geländer · Heizkörper · Eckfenster
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Sonnenschutz/Rollladen erstellen + Typ | ✗ | `WindowType.shading?: {create, kind: "raffstore"\|"rollladen"\|…, box, projection}` | Kasten-/Kastenlinien im Grundriss | Kastenbox + Auskragung | T | **P0/P1** | 2.5 |
+| Rollladenkasten-Maße | ✗ | `shading.box: {w,h,d}` | Rechteck | Box-Mesh | T | P0 | (inkl.) |
+| „Nische erzeugen"/„Kasten symm."/Lamellenwinkel | ✗ | `shading`-Unterfelder | — | Detail | T | P2 | 1 |
+| Beschlag (Griff/Knauf) Geometrie/Maße | ✗ | `SashDef.handle` + `WindowType.handleGeom?` | — | Griff-/Knauf-Mesh | T | P2 | 2 |
+| Geländer (Position/Höhe/Bauteile) | ✗ | `WindowType.railing?: {...}` | Geländerlinien | Geländer-Mesh | T | P3 | 3 |
+| Heizkörper | ✗ | — (eigenes Bauteil, nicht Fenster) | — | — | — | P3 | — |
+| Eckfenster | ✗ | eigener Sonderfall (zwei Wände) | — | — | T | P3 | 5+ |
+
+### 2.8 Attribute · Schnitte/Ansichten · Detaillierung · IFC/Energos
+
+| VW-Control | Status | DOSSIER-Feld | 2D | 3D | Ebene | Prio | Aufwand |
+|---|---|---|---|---|---|---|---|
+| Attribut-Tabelle je Bestandteil (Klasse/Material/Stift/Linie/…) | ~ | DOSSIER hat By-Layer/By-Object-Attribute (`foreground`/`background`/`hatchId`/`strokeWeight` an Wand/Decke, NICHT an `Opening`) → `Opening.foreground?` etc. + evtl. je Bestandteil | Farbe/Strich der Bestandteile | Material | I/T | P2 | 3 |
+| „Klassenattribute zuweisen/entfernen" | ~ | `AttributeSource` („layer"/„object") existiert für Wand/Decke | — | — | I | P2 | 1 |
+| Automatische 2D-Darstellungen (Horizontal/Ansicht/Querschnitt) | ~ | `generatePlan` erzeugt Grundriss; Schnitt/Ansicht sind Platzhalter (`DrawingLevelKind`) | — | — | — | P3 | — |
+| Sichtbarkeitsmatrix 3D-Objekte × Ansichten (Oben/Unten/…/Querschnitt) | ✗ | **nicht bauen** | — | — | — | P3 | — |
+| Detaillierung: Option × Kategorie × Detailstufe (Augen-Tabelle) | ~ | `DetailLevel` (grob/mittel/fein) fließt in 2D + 3D | Sichtbarkeit je Stufe | Meshstufe | I | P2 | 2 |
+| „Für 3D die Tiefe/Mittlere/Hohe Detaillierung verwenden" | ✓ | `Model3dOptions.detail` (`toWalls3d.ts:2145`) | — | Meshstufe | — | — | — |
+| Beschriftung | ✗ | eigenes Text/Tag-System | Label | — | — | P3 | — |
+| Infos/IFC-Daten/Infopalette/Energos | ✗ | **nicht bauen** | — | — | — | P3 | — |
+| „Mehrere ändern" | ~ | Multi-Selektion patcht bereits gemeinsame Felder | — | — | I | P2 | 1 |
+
+---
+
+## 3. Der dedizierte Dialog
+
+### 3.1 Komponente & Einbettung
+
+Neue Komponente **`src/ui/OpeningEditorDialog.tsx`** (Muster: die bestehenden
+`*Dialog.tsx` in `src/ui/`, z. B. `SettingsDialog.tsx`, `TextEditorDialog.tsx`,
+und das Overlay-Muster `res-overlay` + `role="dialog"` aus
+`ResourceManager.tsx:371`). Props (über `usePanelHost`/App-State geliefert):
+
+```
+open: boolean
+openingId: string // die editierte Instanz
+kind: "window" | "door" // steuert Sidebar-Sätze + welche Type-Liste
+project: Project // read (Typ-Listen, Bauteile, LayerCategories)
+onPatchOpening(patch) // Instanz-Felder
+onPatchType(typeId, patch) // Typ-Felder (aktueller Stil)
+onSaveAsStyle(name, snapshot)// „Fenster/Tür speichern…" → neuer WindowType/DoorType
+onResetToStyle() // „zurücksetzen…"
+onClose()
+```
+
+**Öffnen aus dem ⚙.** `ObjectInfoPanel.OpeningSection`
+(`src/panels/ObjectInfoPanel.tsx:731`, `onClick → host.onEditOpeningType(...)`)
+ruft künftig einen neuen Host-Handler `host.onOpenOpeningEditor(openingId)` statt
+`setResourcesTab(...) + setResourcesOpen(true)` (heutige Verdrahtung in
+`src/App.tsx:3130`). App hält `openingEditorId: string | null` als State und
+rendert ``. Der bisherige
+Ressourcen-Tab bleibt als Bibliotheks-/Massenpflege bestehen, ist aber nicht mehr
+der Primärort — das ⚙ landet direkt im reichen Dialog.
+
+### 3.2 Kategorie-Sidebar (realistischer Teilmenge)
+
+Reihenfolge und Sichtbarkeit je `kind`:
+
+1. **Basis** — Öffnungsart (`kind`), Einfügepunkt quer (`insetFace`/`insetFromFace`),
+ Klasse (`categoryCode`), Detaillierung (`detailLevel`).
+2. **Größe/Position** — `width`, `height`, `sillHeight`, `position` (I),
+ `defaultWidth/Height/SillHeight` (T).
+3. **Rahmen** — `frameThickness`, `frameDepth`, `frameWidth`/`frameWidths`,
+ `frameKind` (Tür), `sashOffset`.
+4. **Flügel/Sprossen** — die `SashDef[]`-Tabelle (Flügel/Pfosten einfügen,
+ Öffnungsrichtung/Anschlag je Flügel), Kämpfer-Zeilen, Sprossengitter.
+5. **Oberlicht/Unterlicht** — `transom`, `underlight` (je Feld: Höhe, Rahmen, Gitter).
+6. **Laibung/Bank** — `reveal`, `sill` (außen/innen), `niche`.
+7. **Sonnenschutz/Rollladen** — `shading` (Typ, Kastenmaße, Auskragung).
+8. **Attribute/Darstellung** — Bestandteil-Attribute (Farbe/Strich/Material).
+9. **Detaillierung** — welche Bestandteile bei grob/mittel/fein sichtbar sind.
+
+Sidebar-Sätze: bei `kind==="door"` entfallen Oberlicht/Unterlicht-Gitter-Details,
+Sonnenschutz und Bank; dafür Türblatt (`leafCount`, `leafStyle`, `threshold`,
+`swing`/`hinge`/`openingDir`/`swingAngle`).
+
+### 3.3 Live-Vorschau
+
+**2D (der billige, sofort machbare Teil).** DOSSIER hat den kompletten
+Plan→SVG-Pfad bereits: `generatePlan()` (`src/plan/generatePlan.ts:632`) →
+`toRenderScene.ts` (RScene) → `sceneToPrintSvg()` (`src/export/sceneToPrintSvg.ts:109`)
+bzw. `planToPrintSvg()` (`src/export/planToPrintSvg.ts:155`). Für die Vorschau ein
+**Mini-Projekt** bauen (eine kurze Wand + das editierte `Opening` mit den aktuellen
+Dialog-Werten), durch `generatePlan()` schicken und als SVG in ein Vorschau-`
`
+rendern — Grundriss oben, optional eine Elevations-Skizze. Reagiert auf jeden
+Patch reaktiv (React-State → neu generieren; günstig, da nur ein Element).
+
+**3D/Elevation.** Zwei Optionen, in aufsteigendem Aufwand:
+
+- **(A) günstig, empfohlen für den ersten Wurf:** eine reine 2D-**Ansicht/Elevation**
+ aus denselben Plan-Primitiven — VW's „Vorschau, schattiert" ist für uns nicht
+ nötig; eine saubere Frontalansicht (Rahmen/Flügel/Sprossen/Glas als SVG) zeigt
+ die Flügeleinteilung am aussagekräftigsten und nutzt exakt die neuen Felder.
+- **(B) echte 3D-Vorschau:** `projectToModel3d()` (`src/plan/toWalls3d.ts:2149`)
+ auf das Mini-Projekt anwenden und im wgpu-Viewport (`Wasm3DViewport.tsx`)
+ darstellen. Teurer (eigener Render-Kontext im Modal, WASM-Instanz) und laut
+ Projekt-Memo NICHT per Browser/Puppeteer verifizierbar — der Nutzer testet 3D
+ selbst in der Tauri-Dev-App. Deshalb 3D-Vorschau erst NACH der 2D-Vorschau, als
+ eigene Phase.
+
+Empfehlung: erste Scheibe nur **2D-Grundriss + 2D-Elevation**; echte wgpu-Vorschau
+später.
+
+### 3.4 „Als Stil speichern"-Flow
+
+Drei Aktionen in der Stil-Leiste:
+
+- **Fenster/Tür speichern… (`onSaveAsStyle`)** — nimmt einen Schnappschuss der
+ aktuellen (Typ-relevanten) Dialogwerte, fragt einen Namen ab (`PromptDialog.tsx`)
+ und legt einen NEUEN `WindowType`/`DoorType` in `project.windowTypes`/`doorTypes`
+ an (CRUD-Factories existieren: `addWindowType`/`addDoorType` in `src/App.tsx`
+ ab :2273/:2304). Das editierte `Opening.typeId` zeigt danach auf den neuen Stil.
+- **Update dieses Stils** — `patchWindowType`/`patchDoorType` (App :2319/:2287) auf
+ den aktuell referenzierten `typeId` anwenden (wirkt auf alle Instanzen des Stils).
+- **Einstellungen zurücksetzen… (`onResetToStyle`)** — die instanzseitigen
+ Overrides verwerfen und wieder die Typ-Defaults ziehen (Instanz-Felder auf
+ `undefined` setzen, sodass die Resolver `getWindowType`/`getDoorType`
+ (`src/model/types.ts:2060`/:2064) greifen).
+
+TYP-vs-INSTANZ-Regel im Dialog sichtbar machen: Typ-Felder tragen eine dezente
+„Stil"-Markierung; ein instanzseitig übersteuertes Feld zeigt einen „abweichend
+vom Stil"-Indikator + „zurücksetzen". Das ist genau VW's Stil-/Override-Logik.
+
+---
+
+## 4. Modell-Erweiterungsplan (phasiert)
+
+Alle Felder additiv/optional (Alt-Projekte laden unverändert — die bestehende
+Konvention der Datei, vgl. `wingCount?`, `sliceTermination` Default). Neue Felder
+auf `WindowType`/`DoorType` in `src/model/types.ts`.
+
+### P0 — die erste reiche Scheibe (Kern-Tiefe)
+
+```ts
+// Ein Flügel- oder Pfosten-Eintrag der Flügeleinteilung.
+type OpeningKind = "dreh" | "kipp" | "drehkipp" | "fest" | "schiebe";
+interface SashDef {
+ kind: "fluegel" | "pfosten";
+ autoWidth?: boolean; // gleichmäßig aufteilen (Default true)
+ width?: number; // feste Flügelbreite (m), wenn !autoWidth
+ postWidth?: number; // Pfostenbreite (m), nur kind="pfosten"
+ opening?: OpeningKind; // Öffnungsart DIESES Flügels
+ hingeSide?: "left" | "right"; // Anschlag
+}
+interface WindowType {
+ // … bestehend …
+ sashes?: SashDef[]; // ersetzt/erweitert wingCount; fehlt ⇒ aus wingCount abgeleitet
+ shading?: { // Rollladen/Sonnenschutz-Kasten (P0-Minimalfassung)
+ create: boolean;
+ kind: "rollladen" | "raffstore" | "markise";
+ box: { width: number; height: number; depth: number };
+ };
+ glazingPanes?: 1 | 2 | 3; // Verglasung endlich RENDER-wirksam (heute: glazing unbenutzt)
+}
+```
+
+Rationale/Render-Freischaltung:
+- `sashes` — schaltet echte, ungleichmäßige Flügel/Pfosten + Öffnungsrichtung je
+ Flügel frei; treibt neue Pfostenlinien in `windowSymbol`/`mullionLines`
+ (`src/geometry/opening.ts`) und Pfosten-Boxen in `frameMeshesForOpening`
+ (`src/plan/toWalls3d.ts:1938`). Höchster sichtbarer Mehrwert.
+- `shading` — der Rollladenkasten ist ein einzelnes Kästchen: eine 2D-Rechteckkontur
+ über der Öffnung (neuer Zeichenzweig in `addOpeningSymbol`) + eine Box in
+ `emitOpeningFrames`/eigener Emitter. Wenig Code, große „Reichhaltigkeit".
+- `glazingPanes` — `glassPanesForOpening` (:1965) liest die Scheibenzahl statt
+ konstant EINE Scheibe zu zeichnen; 2D-Glaslinien-Anzahl analog. Schließt die
+ auffälligste Konsum-Lücke.
+
+### P1 — Tiefe der Flügel/Felder
+
+```ts
+interface SashDef { /* + */ rebate?: number; openAngle?: number; handle?: "drueck"|"knauf"|"none"; }
+interface WindowType {
+ frameWidths?: { left: number; right: number; top: number; bottom: number };
+ frameSymmetric?: boolean;
+ uniformPosts?: boolean;
+ transom?: { height: number; frame?: number; muntins?: { rows: number; cols: number } };
+ sill?: { aussen?: SillDef; innen?: SillDef };
+ muntins?: { rows: number; cols: number }; // Sprossen im Hauptfeld
+}
+```
+
+Rationale: asymmetrische Rahmenbreiten, richtiges Oberlicht (statt nur feste Scheibe
+via `transomHeight`), Fensterbank (heute `sillBoard` ungenutzt), Sprossengitter.
+Alles hängt an vorhandenen Zeichen-/Mesh-Funktionen; nur Parameterausbau.
+
+### P2 — Detailbestandteile
+
+```ts
+interface WindowType {
+ reveal?: { create: boolean; depth: number; thickness: number }; // Laibungsverkleidung
+ underlight?: { height: number; frame?: number }; // Unterlicht
+ niche?: { aussen?: boolean; innen?: boolean; depth: number }; // Nische
+ headShape?: "eckig" | "schraeg_links" | "schraeg_rechts" | "spitz" | "rund";
+ handleGeom?: { kind: "quader" | "rund"; masse: Record };
+}
+interface Opening { foreground?: string; background?: string; strokeWeight?: number; } // Bestandteil-Attribute
+```
+
+Rationale: Form (Rundbogen/Schräge → neue Öffnungsumriss-Geometrie), Laibung/Nische,
+Beschlag-Geometrie, per-Instanz-Attribute (analog Wand/Decke, die es schon haben).
+
+### P3 — VW-Ballast (nur wenn je nachgefragt)
+
+Bemaßungs-Bezugsschemata (B1..B5/H1..H7), Sichtbarkeitsmatrix 3D×Ansichten,
+IFC/Energos, Geländer, Heizkörper, Eckfenster, eigenes Symbol, Fassadenmodul-Versatz.
+Siehe Abschnitt 5.
+
+**Höchster-Wert-Reihenfolge (verdichtet):** (1) `sashes` inkl. Öffnungsrichtung je
+Flügel, (2) mehrscheibige Verglasung, (3) Rollladenkasten, (4) Bank/Nische,
+(5) Sprossengitter, (6) Form (Rund/Spitz/Schräg), (7) Ober-/Unterlicht als eigene
+Felder.
+
+---
+
+## 5. Was NICHT bauen / Risiken
+
+**Nicht bauen (VW-Komplexität ohne DOSSIER-Nutzen):**
+
+- **Sichtbarkeitsmatrix „3D-Objekte × 9 Ansichten"** (Oben/Unten/Horizontalschnitt/
+ Vorne/Hinten/Frontalschnitt/Links/Rechts/Querschnitt). DOSSIER rendert heute
+ primär Grundriss; Schnitt/Ansicht sind `DrawingLevelKind`-Platzhalter. Eine
+ Matrix mit ~13×9 An/Aus-Zellen ist Pflegehölle ohne Zielrenderer. `DetailLevel`
+ (grob/mittel/fein) genügt als Sichtbarkeitsachse.
+- **Bemaßungs-Bezugssystem (Roh-/Fertigmaß, B1..B5/H1..H7).** DOSSIER trägt lichte
+ Maße; eine parametrische Öffnungs-Maßkette existiert nicht. Sehr teuer, geringer
+ Nutzen für ein CAAD-Werkzeug dieser Reife.
+- **IFC-Datenmapping-Tiefe, Energos, Infopalette.** Kein IFC-Export-Pfad vorhanden;
+ bewusst weglassen (kein Schein-Feature, vgl. die Modell-Doku-Konvention).
+- **Heizkörper, Geländer, Eckfenster** als Fenster-Unterobjekte — das sind eigene
+ Bauteile bzw. topologische Sonderfälle (zwei Wände). Nicht ins Fenster packen.
+- **Eigenes Symbol verwenden** (Drawing2D-Override je Stil) — erst wenn ein
+ Symbol-/Blocksystem existiert.
+
+**Risiken:**
+
+- **3D-Vorschau nicht als „korrekt" verkaufen.** Laut Projekt-Memo werden
+ `render3d`/`Wasm3DViewport`-Änderungen NICHT per Puppeteer/Browser verifiziert;
+ der Nutzer testet 3D selbst in der Tauri-Dev-App. Der Dialog darf 3D anzeigen,
+ aber diese Studie/Implementierung behauptet keine visuelle Korrektheit der
+ 3D-Vorschau — nur der 2D-Pfad (`generatePlan`→SVG) ist headless prüfbar.
+- **Typ-vs-Instanz-Verwirrung.** Ohne klaren „vom Stil abweichend"-Indikator wird
+ unklar, ob eine Änderung den Stil (alle Instanzen) oder nur dieses Fenster trifft.
+ Muss im UI explizit sein (§3.4).
+- **`sashes` vs. `wingCount` Migration.** `wingCount` bleibt als Fallback; `sashes`
+ hat Vorrang, wenn gesetzt. Resolver in `resolveOpeningFrame`
+ (`toWalls3d.ts:1845`) und `windowSymbol` müssen beide Wege beherrschen, sonst
+ brechen Alt-Projekte oder die `ObjectInfoPanel`-Flügelanzahl-Eingabe.
+- **Modal-Render-Kosten.** Live-Vorschau bei jedem Tastendruck neu generieren ist
+ ok für ein Mini-Projekt, aber Patches sollten (leicht) entprellt werden.
+
+---
+
+## 6. Empfohlene erste Scheibe (P0, konkret)
+
+Kleinstes End-to-End-Inkrement, das sich schon „reich" anfühlt:
+
+**Umfang:** Dialog-Shell + Live-2D-Vorschau + Flügeleinteilung (n Flügel mit
+Öffnungsrichtung je Flügel) + mehrscheibige Verglasung + Rollladenkasten +
+„Als Stil speichern".
+
+**Build-Reihenfolge:**
+
+1. **Modell (P0-Felder).** `SashDef`, `WindowType.sashes?`, `WindowType.shading?`,
+ `WindowType.glazingPanes?` in `src/model/types.ts` ergänzen (additiv). Resolver
+ `getWindowType` bleibt; `wingCount`→`sashes`-Ableitung als Helper.
+2. **Renderer-Konsum (2D zuerst, headless prüfbar).**
+ - `windowSymbol`/`mullionLines` (`src/geometry/opening.ts`) auf `sashes` umstellen
+ (ungleichmäßige Pfostenlagen + Öffnungsrichtung je Flügel als Öffnungslinien).
+ - `glassPanesForOpening`/2D-Glaslinien auf `glazingPanes` (statt konstant 1/detail).
+ - neuer Zeichenzweig in `addOpeningSymbol` (`src/plan/generatePlan.ts:2214`) für
+ die Rollladenkasten-Kontur; 3D-Box später.
+ - Unit-Tests gegen `generatePlan()`-Output (Primitive zählen) — das ist der
+ verifizierbare Beweis, nicht nur „grüne Typecheck".
+3. **Dialog-Shell.** `src/ui/OpeningEditorDialog.tsx` (Overlay `res-overlay` +
+ `role="dialog"`), Sidebar mit den Kategorien Basis / Größe/Position / Rahmen /
+ Flügel-Sprossen / Sonnenschutz. Nur diese fünf für P0.
+4. **Live-2D-Vorschau.** Mini-Projekt (kurze Wand + editiertes `Opening`) →
+ `generatePlan()` → `sceneToPrintSvg()`/`planToPrintSvg()` → `
`. Grundriss +
+ Elevations-SVG. Reaktiv auf Patches (leicht entprellt).
+5. **Flügel-Tabelle.** UI-Tabelle mit „Flügel einfügen / Pfosten einfügen / Löschen"
+ und je Zeile Öffnungsart + Anschlag (`SashDef`). Schreibt `WindowType.sashes`.
+6. **„Als Stil speichern".** Stil-Leiste + `onSaveAsStyle` → `addWindowType`
+ (`src/App.tsx:2304`) mit `PromptDialog`-Namensabfrage; „zurücksetzen" verwirft
+ Instanz-Overrides.
+7. **⚙-Verdrahtung.** `ObjectInfoPanel.OpeningSection` (:731) → neuer Host-Handler
+ `onOpenOpeningEditor(openingId)`; App-State `openingEditorId`. Ressourcen-Tab
+ bleibt als Bibliothek erhalten.
+
+**Definition of Done (P0):** Aus dem ⚙ öffnet sich der Dialog; man setzt 3 Flügel,
+davon einer Dreh-links / einer Dreh-rechts / einer fest, wählt Dreifachverglasung
+und einen Rollladenkasten; die 2D-Vorschau zeigt die Pfosten/Öffnungslinien/Kasten
+sofort; „Speichern…" legt einen benannten Fensterstil an, der im Typ-Dropdown der
+`OpeningSection` erscheint. Verifikation über `generatePlan()`-Primitiv-Tests
+(2D) — 3D-Box erst danach, vom Nutzer in der Tauri-App geprüft.
diff --git a/src/App.tsx b/src/App.tsx
index 5078cce..ea36938 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -69,6 +69,7 @@ import { exportIfcSpf } from "./export/exportIfc";
import { exportObj, exportStl } from "./export/exportMesh";
import type { ScheduleKind } from "./export/exportSchedule";
import { SettingsDialog } from "./ui/SettingsDialog";
+import { OpeningEditorDialog } from "./ui/OpeningEditorDialog";
import { ExportSaveDialog } from "./ui/ExportSaveDialog";
import type { ExportSaveFormat } from "./ui/ExportSaveDialog";
import { PromptDialog } from "./ui/PromptDialog";
@@ -414,6 +415,9 @@ export default function App() {
// Angeforderter Start-Tab des Ressourcen-Fensters (z. B. „doorStyles", wenn man
// von einer gewählten Tür in den Typeditor springt).
const [resourcesTab, setResourcesTab] = useState("components");
+ // Offener Fenster-/Tür-Einstellungsdialog (⚙ der OpeningSection) — ID der
+ // editierten Öffnung, oder null wenn geschlossen.
+ const [openingEditorId, setOpeningEditorId] = useState(null);
// Aktives Layout-Blatt im HAUPT-Viewport (DOSSIER A3, Phase 2b): Id des offenen
// Layouts oder null (= normale Modell-Ansicht). Transienter UI-State; das
@@ -2340,6 +2344,57 @@ export default function App() {
windowTypes: (p.windowTypes ?? []).filter((wt) => wt.id !== id),
};
});
+ // „Als Stil speichern": aktuellen Fenster-/Tür-Typ der Öffnung als NEUEN
+ // benannten Stil ablegen und der Öffnung zuweisen (VW „Fenster speichern…").
+ // Ohne Bezugstyp wird aus den Default-Feldern ein frischer Stil erzeugt.
+ const saveOpeningStyle = (openingId: string, name: string) =>
+ setProject((p) => {
+ const o = (p.openings ?? []).find((x) => x.id === openingId);
+ if (!o) return p;
+ if (o.kind === "door") {
+ const base = (p.doorTypes ?? []).find((d) => d.id === o.typeId);
+ const nt: DoorType = base
+ ? { ...base, id: `dt-${Date.now()}`, name }
+ : {
+ id: `dt-${Date.now()}`,
+ name,
+ kind: "dreh",
+ leafCount: 1,
+ leafStyle: "glatt",
+ frameThickness: 0.05,
+ defaultWidth: 0.9,
+ defaultHeight: 2.0,
+ };
+ return {
+ ...p,
+ doorTypes: [...(p.doorTypes ?? []), nt],
+ openings: (p.openings ?? []).map((x) =>
+ x.id === openingId ? { ...x, typeId: nt.id } : x,
+ ),
+ };
+ }
+ const base = (p.windowTypes ?? []).find((w) => w.id === o.typeId);
+ const nt: WindowType = base
+ ? { ...base, id: `ft-${Date.now()}`, name }
+ : {
+ id: `ft-${Date.now()}`,
+ name,
+ kind: "drehkipp",
+ wingCount: 1,
+ glazing: "zweifach",
+ frameThickness: 0.06,
+ defaultSillHeight: 0.9,
+ defaultWidth: 1.2,
+ defaultHeight: 1.4,
+ };
+ return {
+ ...p,
+ windowTypes: [...(p.windowTypes ?? []), nt],
+ openings: (p.openings ?? []).map((x) =>
+ x.id === openingId ? { ...x, typeId: nt.id } : x,
+ ),
+ };
+ });
const addStairType = () =>
setProject((p) => {
const st: StairType = {
@@ -3166,6 +3221,7 @@ export default function App() {
setResourcesTab(kind === "door" ? "doorStyles" : "windowStyles");
setResourcesOpen(true);
},
+ onOpenOpeningEditor: (id) => setOpeningEditorId(id),
// ── Dach-Attribute (nur bei selektiertem Dach) ─────────────────────────
onSetRoofPatch: (patch) => {
if (selection?.kind === "roof") updateRoof(selection.id, patch);
@@ -4959,6 +5015,20 @@ export default function App() {
/>
)}
+ {/* Reicher Fenster-/Tür-Einstellungsdialog (⚙ der OpeningSection). */}
+ {openingEditorId != null && (
+ updateOpening(openingEditorId, patch)}
+ onSetOpeningType={(typeId) => updateOpening(openingEditorId, { typeId: typeId || undefined })}
+ onSaveAsStyle={(name) => saveOpeningStyle(openingEditorId, name)}
+ onClose={() => setOpeningEditorId(null)}
+ />
+ )}
+
{/* Modaler Import-Dialog (DXF/DWG) — offen, sobald eine Datei gewählt/
fallengelassen wurde. Liefert eine strukturierte Entscheidung an
runImport (Ebene anlegen / Drawings anhängen / Meshes als Kontext). */}
diff --git a/src/i18n/de.ts b/src/i18n/de.ts
index dec9dac..777d937 100644
--- a/src/i18n/de.ts
+++ b/src/i18n/de.ts
@@ -362,7 +362,69 @@ export const de = {
// ── Öffnungs-Attribute (Object-Info-Panel) ──────────────────────────────
"objinfo.opening.section": "Öffnung",
"objinfo.opening.type": "Typ",
- "objinfo.opening.editType": "Typ bearbeiten (Ressourcen)",
+ "objinfo.opening.editType": "Einstellungen …",
+ // Fenster-/Tür-Einstellungsdialog (OpeningEditorDialog).
+ "oed.title.window": "Fenster-Einstellungen",
+ "oed.title.door": "Tür-Einstellungen",
+ "oed.style": "Stil",
+ "oed.saveStyle": "Als Stil speichern …",
+ "oed.saveStyle.hint": "Aktuelle Einstellungen als neuen, wiederverwendbaren Stil ablegen",
+ "oed.saveStyle.prompt": "Name des neuen Stils:",
+ "oed.saveStyle.copySuffix": "(Kopie)",
+ "oed.categories": "Kategorien",
+ "oed.noStyle": "Kein Stil zugewiesen — über die Stil-Leiste einen Stil wählen oder speichern.",
+ "oed.preview": "Ansicht",
+ "oed.cat.basis": "Basis",
+ "oed.cat.groesse": "Grösse/Position",
+ "oed.cat.rahmen": "Rahmen",
+ "oed.cat.fluegel": "Flügel/Sprossen",
+ "oed.cat.sonnenschutz": "Sonnenschutz",
+ "oed.cat.tuerblatt": "Türblatt",
+ "oed.f.kind": "Öffnungsart",
+ "oed.f.glazing": "Verglasung",
+ "oed.f.insetFace": "Schichteinzug ab",
+ "oed.f.insetFromFace": "Schichteinzug (m)",
+ "oed.f.width": "Breite (m)",
+ "oed.f.height": "Höhe (m)",
+ "oed.f.sillHeight": "Brüstungshöhe (m)",
+ "oed.f.position": "Position (m)",
+ "oed.f.frameThickness": "Rahmenstärke quer (m)",
+ "oed.f.frameDepth": "Rahmentiefe (m)",
+ "oed.f.frameWidth": "Rahmenbreite Ansicht (m)",
+ "oed.kind.dreh": "Dreh",
+ "oed.kind.kipp": "Kipp",
+ "oed.kind.drehkipp": "Dreh-Kipp",
+ "oed.kind.fest": "Fest",
+ "oed.kind.schiebe": "Schiebe",
+ "oed.glazing.1": "Einfach",
+ "oed.glazing.2": "Zweifach",
+ "oed.glazing.3": "Dreifach",
+ "oed.insetFace.aussen": "Aussenfläche",
+ "oed.insetFace.innen": "Innenfläche",
+ "oed.fluegel.hint": "Flügel und Pfosten von links nach rechts. Öffnungsart und Anschlag je Flügel.",
+ "oed.fluegel.col.kind": "Typ",
+ "oed.fluegel.col.opening": "Öffnung",
+ "oed.fluegel.col.hinge": "Anschlag",
+ "oed.fluegel.type.fluegel": "Flügel",
+ "oed.fluegel.type.pfosten": "Pfosten",
+ "oed.fluegel.remove": "Entfernen",
+ "oed.hinge.left": "Links",
+ "oed.hinge.right": "Rechts",
+ "oed.shading.create": "Rollladen-/Sonnenschutzkasten",
+ "oed.shading.kind": "Art",
+ "oed.shading.rollladen": "Rollladen",
+ "oed.shading.raffstore": "Raffstore",
+ "oed.shading.markise": "Markise",
+ "oed.shading.boxHeight": "Kastenhöhe (m)",
+ "oed.shading.boxDepth": "Kastentiefe (m)",
+ "oed.door.leafCount": "Türblätter",
+ "oed.door.leaf1": "Einflüglig",
+ "oed.door.leaf2": "Zweiflüglig",
+ "oed.door.leafStyle": "Blattart",
+ "oed.door.glatt": "Glatt",
+ "oed.door.kassette": "Kassette",
+ "oed.door.glas": "Glas",
+ "oed.door.wandoeffnung": "Wandöffnung",
"objinfo.stair.type": "Typ",
"objinfo.type.none": "(kein Typ)",
"objinfo.opening.kind": "Art",
diff --git a/src/i18n/en.ts b/src/i18n/en.ts
index 716d866..6d4de98 100644
--- a/src/i18n/en.ts
+++ b/src/i18n/en.ts
@@ -362,7 +362,69 @@ export const en: Record = {
// ── Opening attributes (object info panel) ──────────────────────────────
"objinfo.opening.section": "Opening",
"objinfo.opening.type": "Type",
- "objinfo.opening.editType": "Edit type (Resources)",
+ "objinfo.opening.editType": "Settings …",
+ // Window/door settings dialog (OpeningEditorDialog).
+ "oed.title.window": "Window settings",
+ "oed.title.door": "Door settings",
+ "oed.style": "Style",
+ "oed.saveStyle": "Save as style …",
+ "oed.saveStyle.hint": "Store the current settings as a new, reusable style",
+ "oed.saveStyle.prompt": "Name of the new style:",
+ "oed.saveStyle.copySuffix": "(copy)",
+ "oed.categories": "Categories",
+ "oed.noStyle": "No style assigned — choose or save one via the style bar.",
+ "oed.preview": "View",
+ "oed.cat.basis": "Basics",
+ "oed.cat.groesse": "Size/position",
+ "oed.cat.rahmen": "Frame",
+ "oed.cat.fluegel": "Sashes/muntins",
+ "oed.cat.sonnenschutz": "Shading",
+ "oed.cat.tuerblatt": "Leaf",
+ "oed.f.kind": "Opening type",
+ "oed.f.glazing": "Glazing",
+ "oed.f.insetFace": "Inset from",
+ "oed.f.insetFromFace": "Layer inset (m)",
+ "oed.f.width": "Width (m)",
+ "oed.f.height": "Height (m)",
+ "oed.f.sillHeight": "Sill height (m)",
+ "oed.f.position": "Position (m)",
+ "oed.f.frameThickness": "Frame depth across (m)",
+ "oed.f.frameDepth": "Frame depth (m)",
+ "oed.f.frameWidth": "Frame face width (m)",
+ "oed.kind.dreh": "Casement",
+ "oed.kind.kipp": "Tilt",
+ "oed.kind.drehkipp": "Turn-tilt",
+ "oed.kind.fest": "Fixed",
+ "oed.kind.schiebe": "Sliding",
+ "oed.glazing.1": "Single",
+ "oed.glazing.2": "Double",
+ "oed.glazing.3": "Triple",
+ "oed.insetFace.aussen": "Outer face",
+ "oed.insetFace.innen": "Inner face",
+ "oed.fluegel.hint": "Sashes and posts from left to right. Opening type and hinge per sash.",
+ "oed.fluegel.col.kind": "Type",
+ "oed.fluegel.col.opening": "Opening",
+ "oed.fluegel.col.hinge": "Hinge",
+ "oed.fluegel.type.fluegel": "Sash",
+ "oed.fluegel.type.pfosten": "Post",
+ "oed.fluegel.remove": "Remove",
+ "oed.hinge.left": "Left",
+ "oed.hinge.right": "Right",
+ "oed.shading.create": "Roller shutter / shading box",
+ "oed.shading.kind": "Kind",
+ "oed.shading.rollladen": "Roller shutter",
+ "oed.shading.raffstore": "Venetian blind",
+ "oed.shading.markise": "Awning",
+ "oed.shading.boxHeight": "Box height (m)",
+ "oed.shading.boxDepth": "Box depth (m)",
+ "oed.door.leafCount": "Door leaves",
+ "oed.door.leaf1": "Single leaf",
+ "oed.door.leaf2": "Double leaf",
+ "oed.door.leafStyle": "Leaf style",
+ "oed.door.glatt": "Flush",
+ "oed.door.kassette": "Panelled",
+ "oed.door.glas": "Glass",
+ "oed.door.wandoeffnung": "Wall opening",
"objinfo.stair.type": "Type",
"objinfo.type.none": "(no type)",
"objinfo.opening.kind": "Type",
diff --git a/src/panels/ObjectInfoPanel.tsx b/src/panels/ObjectInfoPanel.tsx
index c5cc154..dcd5b38 100644
--- a/src/panels/ObjectInfoPanel.tsx
+++ b/src/panels/ObjectInfoPanel.tsx
@@ -712,7 +712,7 @@ export function OpeningSection({
{t("objinfo.opening.section")}
{/* Tür-/Fenstertyp (Bibliothek) — je nach Art aus doorTypes bzw. windowTypes.
- Der ⚙-Knopf springt direkt in den Typeditor (Ressourcen-Fenster). */}
+ Der ⚙-Knopf öffnet den reichen Fenster-/Tür-Einstellungsdialog. */}