thats-me/frontend/dev/IMPROVEMENTS-floating-lines.md
2026-04-30 14:54:39 +02:00

200 lines
8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Verbesserungsvorschläge: floating-lines.js
Analyse von `floating-lines.js` (Dev-Klasse) im Vergleich zur produktiven `FloatingLines.vue`.
**Stand: April 2026 — alle wesentlichen Punkte umgesetzt.**
---
## Was der Code macht (Kurzübersicht)
Ein WebGL-Fullscreen-Shader via Three.js mit drei visuellen Schichten:
- **Top/Bottom**: Einfache Sinus-Wellen mit Rotation (`wave()`)
- **Middle**: Bézier-Kurven zwischen Kontrollpunkten mit animierten Fächer-Linien (`waveFocal()`) + Kreise an den Punkten
- **Hintergrund**: Radialer Verlauf von Mitte → Rand (oder Horizont-Split bei Modus „Trennung")
---
## Fehler / Bugs
### 1. Totes Uniform `bgColor` ✅ Umgesetzt
**Datei:** `floating-lines.js`, Zeile 508
Das tote `bgColor`-Uniform wurde entfernt. Der Shader nutzt ausschließlich `bgColorCenter` + `bgColorEdge`.
```js
// Entfernt:
bgColor: { value: new Vector3(0, 0, 0) },
```
### 2. Konstruktor-Parameter `middleWavePosition` wird ignoriert ✅ Umgesetzt
Der ungenutzte Parameter wurde aus der Konstruktorsignatur entfernt.
### 3. Kein Konstruktor-Interface für `bgColorCenter` / `bgColorEdge` ✅ Umgesetzt
Beide Uniforms sind jetzt als Konstruktor-Parameter verfügbar und werden korrekt initialisiert:
```js
constructor({ ..., bgColorCenter = '#0a0514', bgColorEdge = '#000000', ... })
```
Die Uniforms werden beim Konstruktoraufruf aus den Hex-Strings in `Vector3`-Werte konvertiert.
---
## Performance-Problem
### 4. `bezierClosestT` wird pro Linie neu berechnet (kritisch) ✅ Umgesetzt
`bezierClosestT` wird jetzt **einmal pro Segment** berechnet. Die Ergebnisse (`bt`, `bPos`, `bNorm`) werden als Parameter an `waveFocal()` übergeben:
```glsl
// Neue waveFocal()-Signatur (precomputed values):
float waveFocal(vec2 uv, float fi, float totalLines, float t, vec2 bPos, vec2 bNorm)
// Im Segment-Loop (einmal pro Segment, nicht pro Linie):
float bt = bezierClosestT(baseUv, sp, pc, ep);
vec2 bPos = bmt*bmt*sp + 2.0*bmt*bt*pc + bt*bt*ep;
vec2 bTang = normalize(2.0*bmt*(pc - sp) + 2.0*bt*(ep - pc));
vec2 bNorm = vec2(-bTang.y, bTang.x);
// → alle middleLineCount Aufrufe nutzen dieselben Werte
```
Reduktion von O(Segmente × Linien) auf O(Segmente) `bezierClosestT`-Aufrufe pro Pixel.
---
## Fehlende Features (in `.vue` vorhanden, in `.js` nicht)
### 5. `lineBrightness` Uniform fehlt ✅ Umgesetzt
`lineBrightness` ist jetzt als Konstruktor-Parameter und Uniform vorhanden. Im Shader:
```glsl
col *= lineBrightness; // vor Background-Composite
```
### 6. Kein Pause bei verstecktem Tab ✅ Umgesetzt
Der `requestAnimationFrame`-Loop pausiert jetzt bei `document.hidden`:
```js
this._handleVisibility = () => {
if (document.hidden) {
cancelAnimationFrame(this.raf)
this.raf = 0
} else if (!this.raf) {
renderLoop()
}
}
document.addEventListener('visibilitychange', this._handleVisibility)
// destroy() ruft removeEventListener auf
```
### 7. Kein adaptives DPR ⏭️ Offen / Optional
Die Vue-Version misst FPS live und reduziert `devicePixelRatio` bei schlechter Performance (vor allem Mobile). Die Dev-Klasse ist ein Test-Tool und nicht für Mobile ausgelegt — diese Komplexität lohnt sich hier nicht.
---
## Code-Qualität
### 8. Legacy-Code: `background_color()`, `BLACK`, `PINK`, `BLUE` ✅ Umgesetzt
Die Shader-Konstanten `BLACK`, `PINK`, `BLUE` und die Funktion `background_color()` wurden entfernt. Der Hintergrund wird immer über `bgColorCenter`/`bgColorEdge` gesteuert.
### 9. Redundante `enabledWaves.includes()` Checks ✅ Umgesetzt
Die doppelten Prüfungen in den Hilfsfunktionen wurden entfernt. Die äußere Prüfung im Aufrufer ist die einzige Guard.
### 10. Hardcoded `* 0.5` in `getLineColor()` ✅ Umgesetzt
Der feste `* 0.5`-Faktor wurde entfernt. `getLineColor()` gibt jetzt die volle Gradient-Farbe zurück. Die Kompensation mit `* 2.5` an den Kreisen wurde auf `* 1.5` angepasst. Die Helligkeit wird über das `lineBrightness`-Uniform gesteuert (→ Punkt 5).
---
## Optionale Verbesserungen / Ideen
### 11. Glättere Kreise bei höherem DPR ⏭️ Offen / Optional
Der AA-Radius passt sich durch `iResolution` (physische Pixel bei gesetztem DPR) bereits implizit an. Keine Änderung nötig.
### 12. `pointSpacingX` + `pointsOffsetX` vs. explizite X-Koordinaten ⏭️ Offen / Optional
Die Dev-Klasse behält das Auto-Spacing-Modell für einfache Testzwecke. Die Vue-Komponente nutzt explizite X-Koordinaten für die Lebenszeitlinie. Beide Ansätze sind intentional verschieden.
### 13. GLSL `precision highp` → `mediump` ✅ Umgesetzt
Fragment-Shader nutzt jetzt `precision mediump float` — ausreichend für diese Visualisierung, effizienter auf Mobile/Low-End.
---
## Neue Punkte (nachträglich ergänzt)
### 14. Resize-Bug: Kreise und Linien desynchronisieren sich ✅ Umgesetzt
**Betrifft:** `LifeWaveLayout.vue`
**Ursache:** `layoutResizeObserver` aktualisierte `layoutWidth/Height` sofort, während `TimelineView`s `@view-update` (mit den neuen CSS-Event-Positionen) erst im nächsten Frame kam — führte zu 1-Frame UV-Desync.
**Fix:** `requestAnimationFrame`-Wrapper im Callback:
```js
layoutResizeObserver = new ResizeObserver(() => {
requestAnimationFrame(() => {
if (!layoutRef.value) return
layoutWidth.value = layoutRef.value.clientWidth
layoutHeight.value = layoutRef.value.clientHeight
})
})
```
### 15. Feature: Horizont ✅ Umgesetzt (erweitert)
Statt einer einzelnen Linie wurden **drei wählbare Horizont-Modi** implementiert:
| Modus | Wert | Beschreibung |
|-------|------|--------------|
| Aus | `'off'` | Kein Horizont-Effekt |
| Nebel | `'fog'` | Leuchtender Band-Effekt auf Y=0, Farbe aus Gradient |
| Trennung | `'split'` | Hintergrund wird vertikal geteilt: `bgColorCenter` oben, `bgColorEdge` unten — mit einstellbarer Blend-Breite |
| Glow | `'glow'` | Weiches + hartes Leuchten auf dem Horizont, Farbe aus Gradient |
**Shader (alle Modi):**
```glsl
uniform int horizonMode; // 0=off 1=fog 2=split 3=glow
uniform float horizonOpacity;
uniform float horizonBlend;
if (horizonMode == 1) {
float band = exp(-baseUv.y * baseUv.y * 5.0);
vec3 fogColor = getLineColor(0.5, bg) * 2.0;
col += fogColor * band * horizonOpacity;
} else if (horizonMode == 2) {
float blendW = max(horizonBlend * 0.7, 0.001);
float t = smoothstep(-blendW, blendW, baseUv.y);
bg = mix(bgColorEdge, bgColorCenter, t);
} else if (horizonMode == 3) {
float d2 = baseUv.y * baseUv.y;
float softGlow = exp(-d2 * 10.0);
float coreGlow = exp(-d2 * 70.0) * 0.7;
vec3 glowColor = getLineColor(0.5, bg) * 3.0;
col += glowColor * (softGlow + coreGlow) * horizonOpacity;
}
```
**Umgesetzt in:**
- `floating-lines.js` — Shader + Konstruktor-Parameter + Uniforms
- `FloatingLines.vue` — Shader (mit `gradientMid()` Hilfsfunktion) + Props + Uniforms + Watches
- `settings.js``horizonMode: 'off'`, `horizonOpacity: 0.5`, `horizonBlend: 0.2`
- `LifeWaveSettings.vue` — Segmented Control + bedingte Slider (Deckkraft / Übergang)
- `LifeWaveLayout.vue` — Props weitergeleitet
- `init-fl.html` — 4 Modus-Buttons + bedingte Slider-Sichtbarkeit
---
## Zusammenfassung Prioritäten
| # | Typ | Priorität | Aufwand | Status |
|---|-----|-----------|---------|--------|
| 4 | Performance: `bezierClosestT` Hoisting | **Hoch** | Mittel | ✅ |
| 14 | Bug: Resize-Desync (LifeWaveLayout) | **Hoch** | Minimal | ✅ |
| 1 | Bug: totes `bgColor` Uniform | Mittel | Minimal | ✅ |
| 3 | Bug: `bgColorCenter/Edge` nicht setzbar | Mittel | Klein | ✅ |
| 5 | Feature: `lineBrightness` | Mittel | Klein | ✅ |
| 10 | Qualität: hardcoded `* 0.5` | Mittel | Klein | ✅ |
| 15 | Feature: Horizont (3 Modi) | Mittel | Mittel | ✅ |
| 8 | Qualität: Legacy-Code entfernen | Niedrig | Klein | ✅ |
| 6 | Feature: Tab-Pause | Niedrig | Klein | ✅ |
| 2 | Bug: ignorierter Parameter | Niedrig | Minimal | ✅ |
| 9 | Qualität: redundante Checks | Niedrig | Minimal | ✅ |
| 13 | Perf: `mediump` Precision | Optional | Minimal | ✅ |
| 7 | Feature: adaptives DPR | Optional | Groß | ⏭️ |
| 11 | Qualität: AA-Radius explizit | Optional | Minimal | ⏭️ |
| 12 | API: explizite X-Koordinaten | Optional | Mittel | ⏭️ |