with-canvas
Canvas-Arbeit schlägt auf zwei Arten fehl: durch hübsche, aber ruckeligen visuellen Code und durch optimierten, aber unwartbaren oder unzugänglichen Code. Behandle jede Aufgabe als Entscheidung über die Rendering-Architektur, bevor du Draw-Calls schreibst. Lade nur die Referenz, die von der aktuellen Phase benannt wird; lade nicht alle Referenzen vorab.
Phase 1 – Die Canvas-Aufgabe klassifizieren
Identifiziere die dominante Arbeitslast, bevor du APIs auswählst:
- Canvas ablehnen: Bevorzuge DOM/CSS/SVG/Video, wenn die Szene hauptsächlich aus Text, zugänglichen Steuerelementen, Dokumentlayout, einfacher Ikonografie, CSS-Animation, Medienwiedergabe oder einer kleinen Anzahl skalierbarer Vektorformen besteht.
- Dekorative Animation: Nicht interaktive Atmosphäre, Hintergrundpartikel, Sterne, Vögel, prozedurale Schleifen.
- Datenrendering: Diagramme, Karten, Heatmaps, große Punktwolken, häufig aktualisierte Messwerte.
- Generative Kunst: Gesäte/zufällige Zeichnungen, kreative Skizzen, prozedurale Systeme, exportierbare Bilder.
- Interaktives Werkzeug: Zeiger-/Tastatureingabe, Auswahl, Ziehen, bearbeitbare Objekte, Treffertests.
- Spiel/Simulation: Feste Update-Schleife, dynamische Entitäten, Kollision/Physik, geschichtete Szene.
- WebGL/Engine-Canvas: Three.js/Babylon.js/anderer Renderer, der GPU-Ressourcen besitzt.
PFLICHTLEKTÜRE: Wenn die Arbeitslast dekorative Animation oder generative Kunst ist, lies references/visual-quality.md – für diese beiden Aufgaben ist das Aussehen die Aufgabe, und nur Performanz-/A11y-Hygiene liefert generische Ausgabe. Lade es NICHT für Datenrendering, Werkzeuge, Spiele oder Engine-Canvas.
Exit-Bedingung: Gib die Arbeitslast an, warum Canvas das richtige Primitiv ist, die angestrebte Bildrate, die erwartete Objektanzahl, das Interaktionsmodell und ob die Canvas dekorativ oder semantisch bedeutsam ist.
Phase 2 – Das Rendering-Modell auswählen
Verwende rohes Canvas 2D, wenn die Szene hauptsächlich aus Immediate-Mode-Zeichnung, Pixelarbeit, Sprites, einfacher Animation oder einer begrenzten Paketgröße besteht.
Verwende eine Retained-Mode-Bibliothek, wenn die App bearbeitbare Objekte, Auswahl, Ziehen/ablegen, geschichtete Szenengraphen, Event-Delegation oder Serialisierung benötigt.
Verwende p5.js für Skizzen, generative Kunst, Lehre/Prototyping oder kreatives Coding, bei dem die Ergonomie von setup/draw wichtiger ist als die Framework-Integration.
Verwende Paper.js für Vektorbearbeitungs-Workflows: Pfade, Segmente, Bézier-Geometrie, Treffertests, SVG-Import/Export, geschichtete Vektordokumente.
Verwende Konva für App-UI auf Canvas: React/Vue/Svelte-Integrationen, ziehbare Formen, Ebenen, gecachte Formen, ereignisgesteuerte Steuerelemente.
Verwende Pencil.js für leichte Szenen-/Komponentenabstraktionen, wenn sein Komponentenmodell passt und die Abhängigkeitsaktualität für das Projekt akzeptabel ist.
Verwende Three.js/Babylon.js oder direkt WebGL, wenn die dominanten Kosten 3D/GPU-Rendering, Shader, Kameras, Materialien oder große Mesh-/Sprite-Workloads sind.
PFLICHTLEKTÜRE: Wenn du eine Bibliothek auswählst oder eine Bibliothekswahl überprüfst, lies references/library-selection.md. Lade keine Performance- oder Review-Referenzen, es sei denn, die Aufgabe erreicht diese Phasen.
Überprüfe vor der Installation einer Canvas-Bibliothek oder dem Schreiben von nicht-trivialem Bibliotheks-API-Code die aktuellen Dokumente mit Context7, falls verfügbar; andernfalls verwende die offiziellen Dokumente. Verlasse dich nicht auf erinnerte APIs für p5.js, Paper.js, Pencil.js, Konva, ZIM, Three.js oder Babylon.js.
Exit-Bedingung: Nenne das Modell und die abgelehnten Alternativen mit einzeiligen Begründungen.
Phase 3 – Die Schleife und den Zustand entwerfen
Trenne Canvas-Code in Lifecycle, Zustandsaktualisierung, Rendern, Eingabe, Größenänderung und Bereinigung. Halte bei Framework-Komponenten die imperative Canvas-Engine hinter einer Mount/Init-Grenze.
Verwende requestAnimationFrame für sichtbare Animation. Verfolge delta aus dem RAF-Zeitstempel, wenn die Simulationsgeschwindigkeit über verschiedene Bildwiederholraten stabil sein muss. Breche RAF bei der Bereinigung ab, pausiere oder reduziere die Arbeit, wenn die Seite verborgen ist, und respektiere prefers-reduced-motion.
Wähle eine dieser Neuzeichnungsstrategien:
- Vollständige Neuzeichnung: Akzeptabel für kleine/dekorative Szenen, bei denen Einfachheit gewinnt.
- Dirty Rectangles: Bewegte Objekte mit kleinen begrenzten Änderungen und stabilem Hintergrund.
- Geschichtete Canvas: Statischer/langsamer Hintergrund, dynamische Entitäten, UI/Interaktionsüberlagerung.
- Sprite/Cache-Blits: Wiederholte teure Formen, Text, Markierungen, skalierte Bilder, Partikel.
- Worker OffscreenCanvas: Schweres Zeichnen oder Simulation, das mit Eingabe/Hauptthread konkurriert.
PFLICHTLEKTÜRE: Bevor du Animationen, große Szenen, Partikel, Diagramme, Bildskalierung, High-DPI-Ausgabe oder Worker-Rendering optimierst, lies references/performance.md. Lade NICHT library-selection, es sei denn, du fügst eine Bibliothek hinzu oder ersetzt sie.
Exit-Bedingung: Schreibe die Frame-Pipeline in der Reihenfolge: Eingabeabtastung -> Aktualisierung -> Clear/Redraw-Strategie -> Zeichnen -> Nächsten Frame planen.
Phase 4 – Canvas-Hygiene implementieren
Skaliere die Canvas über das Backing Store, nicht allein über CSS. Setze für eine scharfe Ausgabe die CSS-Größe separat, setze canvas.width/height = cssSize * devicePixelRatio und normalisiere dann Transformationen mit ctx.setTransform(dpr, 0, 0, dpr, 0, 0). Verringere DPR absichtlich für leistungsintensive Szenen.
Initialisiere den Kontext mit Optionen, die zur Szene passen. Verwende { alpha: false } für undurchsichtige Canvas. Verwende willReadFrequently: true nur für häufige getImageData-Lesevorgänge, da dies die Backing-Strategie ändern kann.
Konvertiere für Eingaben Zeigerkoordinaten über getBoundingClientRect() und den Canvas-Maßstab. Vertraue nicht auf clientX/clientY als Canvas-Koordinaten.
Für Barrierefreiheit erhalten dekorative Canvas aria-hidden="true" und keine interaktiven Handler. Sinnvolle Canvas-Interaktionen benötigen DOM-Steuerelemente, Tastaturpfade, Fokusverwaltung, Beschriftungen oder eine äquivalente Nicht-Canvas-Darstellung.
Exit-Bedingung: Größenänderung, DPR, Kontextoptionen, Ereigniskoordinaten-Zuordnung, Bewegungspräferenz und Bereinigung sind alle explizit.
Phase 5 – Überprüfen und Verifizieren
Überprüfe Canvas-Code als heiße Schleife plus Ressourcen-Lebenszyklus. Höre nicht bei visueller Korrektheit auf.
PFLICHTLEKTÜRE: Wenn du vorhandenen Canvas-Code überprüfst oder bevor du eine neue Implementierung abschließt, lies references/review-checklist.md. Lade NICHT library-selection, es sei denn, die Überprüfung umfasst die Passung der Abhängigkeit.
Verifiziere mit mindestens einem Laufzeitsignal, das zur Aufgabe passt: Chrome Performance Panel, FPS-Meter, Speicher-Snapshot, Interaktionslatenz, Reduced-Motion-Pfad, verstecktes Tab-Verhalten oder Low-End-/Mobile-Drosselung.
Beispiele
- Der Benutzer fragt: „Erstelle einen Partikel-Hintergrund“: Klassifiziere als dekorative Animation, lehne DOM/SVG nur ab, wenn die Partikelanzahl oder das prozedurale Zeichnen Canvas rechtfertigt, lies dann
references/visual-quality.mdfür das Aussehen undreferences/performance.mdfür die Schleife. - Der Benutzer fragt: „Baue ziehbare Formen mit Auswahl“: Klassifiziere als interaktives Werkzeug, lies
references/library-selection.md, wähle wahrscheinlich Konva/Paper.js/rohes Canvas 2D basierend auf dem Objektmodell. - Der Benutzer fragt: „Überprüfe diese Canvas-Schleife“: Klassifiziere die vorhandene Arbeitslast, lies
references/review-checklist.md, und liesreferences/performance.mdnur, wenn Ruckeln, eine hohe Objektanzahl oder Hot-Path-Probleme auftreten. - Der Benutzer fragt: „Füge eine p5-Skizze hinzu“: Lies
references/library-selection.md, überprüfe die aktuellen p5-Dokumente, bevor du API-Code schreibst, und halte dann die Framework-Lebenszyklusgrenzen explizit.
NIE
-
NIE nur mit CSS für eine gezeichnete Canvas skalieren Stattdessen: Setze die Backing-Store-Dimensionen und CSS-Dimensionen bewusst; wende den DPR-Transform einmal nach der Größenänderung an. Warum: Nur CSS-Skalierung macht die Ausgabe unscharf und versteckt eine Backing-Store-Diskrepanz, die auf Retina-Displays schlimmer wird.
-
NIE eine RAF-Schleife ohne Bereinigungspfad starten Stattdessen: Speichere die Frame-ID, breche sie beim Unmount/Dispose ab und schütze gegen doppeltes Starten nach Sichtbarkeits- oder Media-Query-Änderungen. Warum: Verwaiste Schleifen zeichnen weiterhin auf losgelöste Canvas und erzeugen Speicher-/CPU-Lecks, die Snapshots oft fälschlicherweise Browser-Interna zuschreiben.
-
NIE teure statische Inhalte in jedem Frame neu zeichnen, weil sie visuell Teil der Szene sind Stattdessen: Cache sie in einer Offscreen-Canvas, einem Image-Bitmap, einer Layer-Canvas, einem Path2D oder einem Bibliotheks-Shape-Cache. Warum: Canvas ist Immediate-Mode; unveränderte Bilder kosten immer noch die volle Zeichenzeit, sofern sie nicht explizit gecacht oder geschichtet werden.
-
NIE eine reine Canvas-Interaktion als einzige zugängliche Steuerung verwenden Stattdessen: Stelle DOM-Steuerungen/Semantik oder ein tastaturbedienbares Retained-Objektmodell mit Beschriftungen und Fokusverhalten bereit. Warum: Canvas-Pixel legen Rollen, Namen, Zustände oder Trefferziele für assistive Technologien nicht offen.
-
NIE Canvas-Arbeit nur wegen schlechter Leistung auf OffscreenCanvas verschieben Stattdessen: Identifiziere zuerst, ob der Engpass Draw-Calls, Zustandsänderungen, Überzeichnung, Bildskalierung, Pixel-Lesevorgänge oder Simulation ist; verwende Worker, wenn der Hauptthread die Konkurrenz darstellt. Warum: Worker fügen Transfer-, Bündelungs- und DOM-Zugriffsbeschränkungen hinzu; sie beheben keine schlechte Zeichenarchitektur.
-
NIE die Leistungsregeln von Retained-Mode-Bibliotheken als optional behandeln Stattdessen: Deaktiviere das Lauschen auf inaktiven Ebenen, cache teure Formen, minimiere die Ebenenanzahl und zerstöre Knoten/Stadien durch den Bibliotheks-Lebenszyklus. Warum: Bibliotheken fügen Szenengraph- und Ereignismechanismen hinzu; das Ignorieren ihrer Schalter kann langsamer sein als rohes Canvas.