# Design — Ressourcen & Grafik > Teil der Standalone-Architektur — siehe [../../ARCHITECTURE.md](../../ARCHITECTURE.md). > Bauteile: [elements.md](elements.md). Output/Pläne: [plans-output.md](plans-output.md). Die **Stil-Schicht**: verwaltete Ressourcen-Bibliotheken (Vectorworks-Stil), regelbasierte Overrides, Symbol-/Text-Bibliotheken und Detailgrad-Steuerung. Sie wird **beim Rendern angewandt, nie in die Geometrie eingebacken** (ROADMAP §2b). Dieses Dokument übersetzt DOSSIERs `styles.py`/`gestaltung.py`, `mass_style.py`, `overrides.py`, `library.py`, `text_create.py`. Bezeichner englisch, Prosa deutsch. --- ## 1. Resource Manager — verwaltete Bibliotheken Drei Bibliotheken im `Project.resources`-Block; **alles verweist per id**, zentral änderbar (ROADMAP §2d). Verweis-Kette: 2D-Objekte/Ebenen → LineStyle/Hatch; Hatch → LineStyle; Component → Hatch (+3D-Material). ```ts interface Resources { lineStyles: LineStyle[]; hatches: Hatch[]; components: Component[]; } interface LineStyle { // Line Manager id; name; weight: number; // Strichstärke in mm (≙ Rhino PlotWeight) color: string; // hex dash: number[]; // Strichmuster in mm ([] = durchgezogen) } interface Hatch { // Hatch Manager id; name; pattern: PatternId; // "solid" | "diagonal" | "insulation" | "concrete" | ... scale: number; // Grundmaßstab des Musters angle: number; // Grad lineStyleId: string; // Linien der Schraffur → Line Manager } interface Component { // Component Manager (= DOSSIER-Material, erweitert) id; name; hatchId: string; // Schnitt-Schraffur → Hatch Manager color3d: string; // 3D-Diffusfarbe texture3d?: TextureRef; // optionale PBR-Textur (Phase 3) pbr?: { roughness; metalness; opacity; ior }; // Material-Bibliothek (ROADMAP §11) joinPriority: number; // Verschneidungs-Rang (DOSSIER _MATERIAL_PRIO als Daten) } ``` **Migration vom heutigen Stand:** Der Spike hat `Material { color, planFill, hatch }` und `Layer { materialId, thickness, priority }`. Ziel: `Material → Component` (`color→color3d`, `planFill→` Fill aus `hatch.pattern==solid`+Farbe, `hatch`-Enum → `hatchId`), `Layer.priority → Component.joinPriority` (Priorität wandert vom Layer zum Component, damit man sie nur einmal pflegt — siehe elements.md §1.3). ### 1.1 Manager-UI `managers/ComponentManager.tsx`, `HatchManager.tsx`, `LineManager.tsx` — je eine Liste mit CRUD + Vorschau (Three-Sphere für Component-3D, SVG-Swatch für Hatch/Line). **Seeds** beim ersten Projekt (DOSSIER-Defaults): - LineStyles: 0.13 / 0.18 / 0.25 / 0.35 / 0.50 mm (aus `DEFAULT_LAYER_SCHEMA`-lw). - Hatches: `solid`, `diagonal`, `concrete`, `insulation` (Dämmung). - Components: Stahlbeton (prio 800), Beton (800), Mauerwerk (600), Ziegel (550), Holzständer (400), Dämmung (200), Putz (100) — exakt DOSSIER `_MATERIAL_PRIO` (elements.md §1.3). Plus Glas (transparent), Holz-Türblatt (DOSSIER `_OEFF_PIECE_DEFS`). ### 1.2 Render-Anwendung - **3D:** Component → `MeshStandardMaterial` (`color3d`/`pbr`), pro `componentId` gecacht (`viewport/scene.ts`). - **Plan/Schnitt:** geschnittene Schicht → Polygon mit `fill` (Component-Farbe) + `` aus `hatchId`. Pattern als SVG `` mit `patternTransform` für Massstab (plans-output.md §3.2). Der Hatch nutzt seinen `lineStyleId` für die Musterlinien. --- ## 2. Mehrschichtige Aufbauten ↔ Ressourcen `WallType.layers[].componentId` / `SlabType.layers[].componentId` verweisen auf Components. 3D und Plan lesen dieselben Schichten (elements.md §1). Die **Prioritäts-Verschneidung** (Risiko #1) liest `Component.joinPriority`: höhere Priorität läuft am Stoß durch (Backbone), niedrigere stößt seitlich an — Algorithmus in elements.md §1.3 (Port DOSSIER `_t_junction_layer_overrides`). --- ## 3. Stile & Element-Override (Selektions-Attribute) DOSSIERs GESTALTUNG-Panel (`styles.py`) setzt Farbe/Lineweight/Linetype/Hatch auf die *Selektion*. Browser-Äquivalent — zwei Ebenen, in Render-Reihenfolge: ``` ByLayer (Ebenen-Default) → Element-Style (styleId) → Override-Regeln → gerendert ``` ```ts // Effektiver Stil eines Elements (resolve beim Rendern, nie persistiert) interface EffectiveStyle { color; lineStyleId; hatchId?; } function resolveStyle(project, el, doc): EffectiveStyle { // 1) Default aus LayerCategory(categoryCode) // 2) überschrieben durch el.styleId (Element-Override, optional) // 3) überschrieben durch passende Override-Regeln (§4) } ``` - **Wall-/Opening-Stil-Kataloge** (Presets, ROADMAP §11): benannte Sätze von Default-Werten (Wandtyp + Farbe + lw; Öffnung mit Rahmen/Sims/…). 1-Klick- Anwendung, globaler Stilwechsel. Speicherung: pro Projekt + cross-Projekt (LocalStorage), Seed wie DOSSIER `_OEFF_DEFAULT_STYLES` (elements.md §2.1). - **LoD-bewusste Stil-UI** (DOSSIER ROADMAP §11): das Stil-Panel zeigt nur passende Controls je Geometrietyp (keine Füll-Optionen bei einer 3D-/Linien- Auswahl). `panels/StylePanel.tsx` schaltet Felder nach `selection`-Typ. - **Pipette:** Stil/Typ von einem Element auf ein anderes übernehmen (DOSSIER `cmd/pipette`). --- ## 4. Regelbasierte Overrides (Engine) Port `overrides.py` (ArchiCAD Graphical Overrides / Vectorworks Datenvisualisierung). Im Browser **viel einfacher**, weil Overrides reine **Render-Transformationen** sind — kein UserString-Backup/Restore nötig (DOSSIER musste Originalwerte sichern, weil es echte Rhino-Objekte mutierte; wir mutieren nichts). ```ts interface OverrideConfig { enabled: boolean; rules: OverrideRule[]; activePresetId?: string; } interface OverrideRule { id; name; enabled: boolean; conditions: Condition[]; conditionsLogic: "and" | "or"; actions: { color?: string; lineWeight?: number; lineStyleId?: string; hatchId?: string; hatchScale?: number }; } interface Condition { type: "category" | "userField" | "name" | "elementType"; // ≙ layer_name/user_string/object_name operator: "equals"|"notEquals"|"contains"|"startsWith"|"endsWith"; value: string; key?: string; // nur für userField (z.B. "sia") } ``` **Auswertung** (Port `_compose_overrides`): ```ts function composeOverrides(el, project, cfg): Partial { // additive: Actions aller matchenden, aktiven Regeln kombinieren; // bei Konflikt für dieselbe Property gewinnt die Regel WEITER OBEN (kleinerer Index). } ``` - **Anwendung:** `resolveStyle` (§3) ruft `composeOverrides` — Override liegt über Element-Style. Reines Read beim Rendern → kein `apply_all`/`restore_all`, kein Backup, **keine reversibilität nötig**. Toggle `enabled` rendert neu. - **Live:** Da abgeleitet, schlägt jede Modell-/Regel-Änderung sofort durch (kein `install_listeners`/`AddRhinoObject`-Hook wie DOSSIER). - **Presets & Templates** (cross-Projekt): Preset = Satz Regeln, Template = einzelne Regel; LocalStorage statt `~/Library/.../override_presets.json` (`save_preset`/`load_preset`/`list_rule_templates` → `resources/overridePresets.ts`). - **SIA-416-Preset** (elements.md §7): vier Regeln `userField sia == HNF|NNF|VF|FF` → Farbe + Solid-Hatch, Port `_build_sia_preset_rules`. Aktivieren = Preset `activePresetId` setzen. ```ts // resources/overrides.ts function composeOverrides(el, project, cfg): Partial function setActivePreset(project, presetId): Project // immutabel const PRESETS_NS = "cad.presets.overrides"; // LocalStorage ``` --- ## 5. Symbol-Bibliothek Port `library.py` + `cmd/symbol`. Wiederverwendbare 2D-Symbole (Möbel, Sanitär, Bäume, Nordpfeil, Pflanzen) für den Plan. ```ts interface Symbol { id; name; category: string; // "furniture" | "sanitary" | "vegetation" | "annotation" svgPath: string; // Pfad-/Gruppen-Markup im Symbol-Koordinatensystem (m) defaultScale: number; } interface SymbolInstance extends ElementBase { // type:"draw2d", subtype:"symbol" symbolId: string; at: Vec2; scale: number; angle: number; } ``` - **Speicherung:** mitgelieferte Symbole als statische Assets (SVG); Nutzer- Symbole im Projekt + cross-Projekt (LocalStorage). DOSSIER nutzt Block- Definitionen; bei uns SVG-Definition + Instanz-Transform (``-artig). - **Picker:** `panels/SymbolPicker.tsx` (≙ DOSSIER `SymbolPicker.jsx`) — Grid mit Vorschau, Drag in den Plan; Instanz auf Ebene `60 Plangrafik` (bzw. `22 Möbel`). - **Render:** `Primitive{ kind:"symbol", ... }` → SVG `` mit dem Symbol-Markup (plans-output.md §9). --- ## 6. Text & Rich-Text-Annotationen Port `text_create.py` + `text_editor.py`. Formatierte Beschriftungen auf Canvas. ```ts interface TextElement extends ElementBase { // type:"draw2d", subtype:"text" at: Vec2; runs: RichRun[]; heightMm: number; // Paper-mm (rendern × Massstab) ODER Modell-m heightMode: "paper" | "model"; // DOSSIER raum_txt_modus fix|masstab font: string; align: "left"|"mid"|"right"; angle: number; mask?: boolean; // Hintergrund-Maskierung (verdeckt Linien darunter) frame?: boolean; // Rahmen um den Text } interface RichRun { text: string; bold?; italic?; super?; sub?; // Hoch-/Tiefstellung (Maß-Indizes) } interface TextStyle { id; name; font; heightMm; bold; italic; } // Text-Presets ``` - **Render:** `` mit `` pro Run; `super/sub` via `baseline-shift` + kleinerer `font-size`; `mask` via weißem `` darunter; `frame` via ``. - **Editor:** Inline-Rich-Text-Editor (contentEditable oder leichter Custom-Editor) → `RichRun[]`. Fonts aus einer kuratierten Web-Font-Liste + System-Fonts (DOSSIER `_list_system_fonts` mit Preferred-Liste DM Mono/Krungthep/…); im Browser via `document.fonts` / `queryLocalFonts()` (wo verfügbar) + gebündelte Web-Fonts. - **Massstabsbezug:** `heightMode:"paper"` → Texthöhe in mm, gerendert × Massstab (plans-output.md §3) — Beschriftung bleibt bei jedem Massstab lesbar. --- ## 7. Detailgrad (Level of Detail) Querschnittsthema (ROADMAP §2b „Modelldarstellungen"). Drei Stufen, Dokument-/ Snapshot-weiter Override mit Per-Element-Ausnahme — DOSSIER `darstellung`/`aktive_darstellung`. ```ts type DetailLevel = "coarse" | "medium" | "fine"; // einfach | standard | detail // Auflösung (Port _resolve_oeff_darstellung): function resolveDetail(el, doc): DetailLevel { const v = el.detailLevel ?? "auto"; return v === "auto" ? doc.detailLevel : v; // doc-Level hat IMMER konkreten Wert } ``` - **Dokument-Ebene:** `Project.detailLevel` (Default `coarse`/einfach = 1:100, DOSSIER `_DARSTELLUNG_DEFAULT_GLOBAL`). In der TopBar global umschaltbar; ein ViewSnapshot kann ihn pro Ansicht überschreiben (plans-output.md §5). - **Wirkung:** jedes Bauteil-`generatePlan`/`build3d` liest den aufgelösten LoD und zeichnet entsprechend (elements.md: Tür coarse=Lücke, fine=Glas/Schwenkbogen/ Sims). Kritisch für Mixed-Scale-Pläne (1:50 Detail neben 1:200 Übersicht). - **Schnitt-Schraffur** koppelt an LoD: grob ggf. nur Umriss, fein voll schraffiert. --- ## 8. Section-Style (3D-Schnittflächen) Port DOSSIER `_apply_section_style` (`layer_builder.py`). Wo die Schnittebene ein Bauteil durchschneidet: Schnittfläche bekommt die **Component-Schraffur**, die Schnittkante einen dicken Rand, optional eine Silhouette. ```ts interface SectionStyle { // pro Component (oder Ebene) ableitbar hatchId?: string; hatchScale; hatchAngle; boundaryShow: boolean; boundaryLineStyleId; boundaryWidthScale; fillBackground: boolean; } ``` - **3D-Viewport:** Three.js hat keinen nativen „Schnittflächen-Cap". Cap-Geometrie selbst erzeugen: Schnittpolygon der Cut-Plane mit den Breps → Fläche mit Hatch-Material (oder Stencil-Cap-Technik). Phase 4. - **2D-Schnitt (SVG):** `generateSection` (plans-output.md §4) liefert `cutFaces` → mit `SectionStyle.hatchId` füllen. Das ist der Hauptweg; der 3D-Cap ist Bonus. --- ## 9. Was Browser hier einfacher macht (vs. DOSSIER) | DOSSIER-Aufwand | entfällt im Browser, weil … | |---|---| | UserString-Backup/Restore bei Overrides (`_backup_original`/`_restore_original`) | Overrides sind reine Render-Reads — nichts wird mutiert | | Hatch-Curve-Link über Sticky (`gestaltung_curve_hatch`, Pending-TTL) | Schraffur ist eine Eigenschaft des Polygons, kein separates Objekt | | Plotweight-Welt↔Bildschirm-Rescaling (`write/read_plotweight`) | Strichstärke ist in mm im SVG-Paper-Space (plans-output.md §3.2) | | `install_listeners` für Live-Override-Reapply | reaktiver Store re-rendert automatisch | | SectionStyle-API-Reflection über Rhino-Versionen | wir definieren das Rendering selbst (SVG/Three) | | Cross-doc Presets als Dateien im User-Home | LocalStorage + Export/Import | --- ## 10. Umsetzungs-Reihenfolge (verweist auf ROADMAP-Phasen) 1. **Phase 1:** Component/Hatch/Line-Manager (§1) + `resolveStyle` (§3) + LoD-Grundgerüst (§7) + LoD-bewusste Stil-UI. 2. **Phase 2:** Stil-Kataloge (Wände/Öffnungen), Material-Seeds mit `joinPriority`. 3. **Phase 3:** Overrides-Engine + SIA-Preset (§4), Symbol-Bibliothek (§5), Rich-Text (§6), PBR-Material-Bibliothek; massstabsabhängige Hatch-/Linetype- Skalierung (plans-output.md §3.2). 4. **Phase 4:** Section-Style 3D-Cap (§8).