Skip to content

perf: Replay mit stabiler Skalierung und wiederverwendeten Pfaden/Fills (#366) - #367

Merged
S540d merged 1 commit into
testingfrom
perf/replay-fill-cache
Oct 22, 2026
Merged

S540d merged 1 commit into
testingfrom
perf/replay-fill-cache

Conversation

@S540d

@S540d S540d commented Oct 22, 2026

Copy link
Copy Markdown
Owner

Pull Request

Closes #366

Beschreibung

Die Replay-Animation hat in jedem Frame alle Flood-Fills neu berechnet: auf Web über getImageData/putImageData der ganzen Fläche, auf Android über computeNativeFillLayers. Ein Prefix-Cache war nicht möglich, weil die Skalierung im Replay aus den gerade sichtbaren Pfaden berechnet wurde und sich deshalb pro Frame änderte.

Änderung (wie in #366 abgestimmt: Ansatz 1 plus Prefix-Cache)

  1. Stabile Skalierung: DrawingCanvas (web und native) bekommt das Prop scaleReferencePaths. Bounding Box, scale und offset kommen aus diesem Array, Standard ist paths. ResultPhase übergibt drawingPaths, die Zeichnung erscheint im Replay also von Anfang an in Endgröße und wandert nicht mehr mit. Der Endzustand ist unverändert, er ist im echten Browser pixelidentisch zur statischen Ansicht.
  2. Web: Der gerenderte Stand aller Pfade außer dem letzten wird in einem Offscreen-Canvas gecacht. Solange die Pfade referenzgleich bleiben und sich Größe und Skalierung nicht ändern, wird dieser Stand wiederverwendet und nur der neue Teil gezeichnet. Der letzte Pfad gilt als „flüchtig“ (im Replay ist es der gerade wachsende Strich) und wird nie gecacht.
  3. Native: Neue Funktion computeNativeFillLayersIncremental (Cache aus Pixelpuffer und Layern, der flüchtige Pfad läuft auf einer Puffer-Kopie). Das Ergebnis ist identisch zu computeNativeFillLayers. Das gilt auch beim normalen Malen: Ein neuer Strich oder Fill bedeutet nur noch seine eigene Berechnung.

Wirkung: pro Frame höchstens 2 Flood-Fills statt N. Bei 10 Fills sind es im Replay 19 statt 55.

Art der Änderung

  • Bugfix
  • Neue Funktion
  • Breaking Change
  • Dokumentation Update
  • Performance. Sichtbare Änderung: Das Replay skaliert nicht mehr mit, die Zeichnung erscheint von Anfang an in Endgröße.

Cross-Platform Kompatibilität

Betrifft dieser PR plattformspezifischen Code? Ja: DrawingCanvas.web.tsx (Offscreen-Canvas, // platform-safe) und DrawingCanvas.native.tsx mit NativeFillLayerService.

Testing Checklist

  • Keine TypeScript Errors, keine ESLint Warnings, Prettier sauber
  • npm run test:ci: 468/468 grün
  • 6 neue Service-Tests: Äquivalenz zur Komplettberechnung für wachsende Präfixe, für das Replay (letzter Pfad als neues Objekt pro Frame), Neuaufbau bei Skalierungswechsel und bei Undo, Cache bleibt vom flüchtigen Pfad unberührt
  • 3 neue Web-Tests (Flood-Fill-Anzahl im Replay, stabile Skalierung, keine erneuten Striche). Alle drei schlagen gegen den alten Code fehl.
  • Im echten Browser (Playwright, volles Spiel bis zum Ergebnis-Screen) geprüft: Das Canvas nach dem Replay ist pixelidentisch zur statischen Ansicht, die Füllung erscheint mitten im Replay korrekt, und gegenüber dem alten Build bleibt die Zeichnung stabil.
  • Native (Android) manuell nicht getestet; abgedeckt nur durch die Service-Tests

Hinweis: separater, bereits vorhandener Fehler (nicht Teil dieses PRs)

Beim Test ist mir aufgefallen: Auf Web verschwinden Füllungen auf dem Ergebnis-Screen, wenn die Canvas-Breite nicht ganzzahlig ist (ResultPhase.imageSize = screenWidth * 0.44, z. B. 184,8 px bei 420 px Viewport). Bei ganzzahliger Breite (z. B. 176 px) erscheinen sie korrekt. Das reproduziert auch im Stand vor diesem PR. Vermutlich die Ursache: getImageData/floodFillPixels mit gebrochener Breite (derselbe Fehler, der im Native-Code bereits mit Math.floor umgangen wird). Wird separat behandelt.


Generated by Claude Code

…ls (#366)

Im Replay kam pro Frame ein neues paths-Array, und die Skalierung wurde aus
den gerade sichtbaren Pfaden berechnet (änderte sich pro Frame). Dadurch
liefen alle Flood-Fills in jedem Frame neu (web: getImageData/putImageData
über die Fläche, native: computeNativeFillLayers).

- DrawingCanvas (web + native): neues Prop scaleReferencePaths; Bounding Box
  und Skalierung kommen aus der gesamten Zeichnung. ResultPhase übergibt
  drawingPaths -> die Zeichnung erscheint von Anfang an in Endgröße
- web: gerenderter Stand aller Pfade außer dem letzten wird in einem
  Offscreen-Canvas gecacht und wiederverwendet, solange die Pfade
  referenzgleich und Größe/Skalierung unverändert sind
- native: computeNativeFillLayersIncremental (Cache aus Pixelpuffer + Layern,
  letzter Pfad auf einer Puffer-Kopie); Ergebnis identisch zur
  Komplettberechnung
- Tests: Service-Äquivalenz für wachsende Präfixe/Replay/Skalierungswechsel/
  Undo, Web-Tests für Flood-Fill-Anzahl und stabile Skalierung

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017fxbsNALrmwMj7LGMDPLw2
@github-actions

Copy link
Copy Markdown

🔀 Mergeability-Report

✅ Konfliktfrei mergebar (unstable).
✅ Ziel-Branch testing ist policy-konform.

CI-Checks: ✅ keine fehlgeschlagenen Checks

⏳ mergeability / mergeability
⏳ ⚙️ Workflow Linting / actionlint
⏳ 🔧 Platform Compatibility
⏳ 🔐 Docs Privacy Check
⏳ 🔑 Keystore & Credential Scan
⏳ 🔒 Security Audit
⏳ 🔍 Code Quality & Linting
⏳ Analyze (actions)
⏳ Analyze (javascript-typescript)

Merge-Checkliste

  • CI-Checks grün
  • Keine Merge-Konflikte
  • Ziel-Branch korrekt
  • (Optional) tiefes KI-Review via /review aus Claude Code (Pro-Abo, ohne API-Kosten)

Kostenlos generiert von reusable-mergeability.yml · keine API-Kosten · review-gate: success

@S540d
S540d merged commit f57102d into testing Oct 22, 2026
14 checks passed
@S540d
S540d deleted the perf/replay-fill-cache branch November 3, 2026 19:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants