# SEKTION 05 — OBERFLÄCHE (Node-Editor)

> Vorlage: Qwirbels `frontend/index.html` — **NUR LESEN, nicht ändern.**
> Dort arbeiten andere Chats parallel.

---

## 5.1 Grundsatz

**EINE Datei**, `oberflaeche/index.html`, React über UMD + Babel im Browser,
kein Build-Schritt. Ändern → F5. Genau wie Qwirbel.

Der Grund ist nicht Bequemlichkeit: der Nutzer ändert selbst daran, oft vom Handy
aus über einen Chat. Ein Build-Schritt bricht diesen Weg.

## 5.2 Das Aussehen kommt von Qwirbel

Übernehmen, nicht neu erfinden:

| Element | Aus Qwirbel |
|---|---|
| Farben | `--acc` · `--bg` · `--panel` · `--field` als CSS-Variablen |
| Karten | `.card` — dunkles Glas, Akzent-Rand beim Hover |
| Knöpfe | `.btn` · `.btn2` · `.chip` · `.iconbtn`, min. 36 px |
| Schwebende Panels | verschiebbar, fixierbar, **im Bild geklemmt beim ZIEHEN** |
| Menüs | Portal am `<body>` + Klick-Fang (`ChipMenue`-Muster) |
| Sprache | `t("deutsch","english")`, Standard Deutsch |

**Fallen, die dort teuer bezahlt wurden — nicht wiederholen:**

- In `t()`-Strings **nie ein gerades `"`** — beendet den JS-String, Babel
  bricht ab, die App mountet nicht, und zwar **ohne Fehlermeldung**.
  Deutsche Anführungszeichen `„…"` oder `\"`.
- Aus einem **Stacking-Context** (`zoom`, `transform`, `filter`,
  `backdrop-filter`) sticht **kein z-index heraus**. Aufklappmenüs gehören
  per Portal an `<body>`.
- Eine Komponente, die **im Rumpf** einer anderen definiert wird, ist bei
  jedem Rendern ein neuer Typ → kompletter Neuaufbau → Einblend-Animation
  läuft neu → sieht aus wie **Flackern**. Auf Modul-Ebene definieren.
- Ein Zähler, der eine Anzeige steuert, muss auf **jedem** Weg mitgenullt
  werden — sonst klemmt die Anzeige beim nächsten Mal.
- `[style*=…]`-Selektoren matchen die **serialisierte** Form (`rgb(…)`).

## 5.3 Der Node-Editor

**Leinwand:** Zoom, Verschieben, Auswahlrahmen, Raster mit Einrasten.
Nodes als Karten, Verbindungen als Bézier-Kurven, Ausgang → Eingang ziehen.

**Node-Karte:** Titel · Gruppen-Farbe · Ausgänge rechts · Eingänge links ·
Werte als Felder direkt in der Karte.

**Und der Teil, der Global UI ausmacht:**
Jede Node-Karte hat einen aufklappbaren Bereich **„Rechnen"** mit
`geraet` · `praezision` · `resident` · `verdraengen` · `bei_engpass`.

Zugeklappt sieht man eine Zeile: `gpu · bf16 · bleibt liegen`.
Weicht ein Node vom Standard ab, wird das **sichtbar markiert** — man soll
auf einen Blick sehen, wo jemand am Rechenverhalten gedreht hat.

Das ist keine Verstecken-Einstellung im Menü. Es steht am Node, weil es
zum Node gehört.

## 5.4 Der Speicher-Balken

Über der Leinwand, immer sichtbar: **was der Plan sagt, bevor man startet.**

```
VRAM 17,1 GB  [████████████░░░░░]  belegt 12,4 · frei 4,7
⚠ dec räumt clip — das kostet ~6 s pro Bild
```

Ein Klick auf die Warnung springt zum Knoten. Der Nutzer sieht **vorher**,
dass geschoben wird — statt sich hinterher zu wundern, warum es lahm ist.
Genau das fehlt bei ComfyUI komplett.

## 5.5 Fortschritt

Aus `WS /ereignisse`: laufender Knoten leuchtet, Sampler-Schritte als Balken,
**Räumungen erscheinen sichtbar** (nicht nur im Log), Fehler als Klartext
direkt am betroffenen Knoten.

## 5.6 ComfyUI-Workflows importieren

der Nutzer hat Workflows, die weiterlaufen müssen. Import bildet ComfyUI-Nodes auf
Global-UI-Nodes ab, setzt die Rechen-Eingänge auf sinnvolle Standards und
**meldet ehrlich, was nicht abbildbar war** — kein stiller Teil-Import.

Qwirbel hat für ComfyUIs UI→API-Format bereits einen Konverter
(`generation/_workflow_konverter.py`). **Nur lesen**, als Vorlage.

## 5.7 Checks für diese Sektion

- [ ] Babel-Parse-Check läuft (Muster: Qwirbels `babel_check.js`)
- [ ] Kein gerades `"` in `t()`-Strings
- [ ] Menüs sind klickbar und sitzen am Knopf — bei jeder UI-Größe gemessen
- [ ] Keine im Rumpf definierten Komponenten
- [ ] Der Speicher-Balken zeigt denselben Plan wie `/graf/plan`
- [ ] Ein importierter ComfyUI-Workflow läuft — oder sagt, warum nicht
