200 lines
8 KiB
Markdown
200 lines
8 KiB
Markdown
# 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 | ⏭️ |
|