with-canvas
El trabajo con canvas falla de dos maneras diferentes: código visual bonito pero lento, y código optimizado pero inmantenible o inaccesible. Trata cada tarea como una decisión de arquitectura de renderizado antes de escribir llamadas de dibujo. Carga solo la referencia nombrada por la fase actual; no precargues todas las referencias.
Fase 1 - Clasificar el Trabajo con Canvas
Identifica la carga de trabajo dominante antes de elegir APIs:
- Rechazar canvas: prefiere DOM/CSS/SVG/video cuando la escena es principalmente texto, controles accesibles, diseño de documentos, iconografía simple, animación CSS, reproducción multimedia o un número pequeño de formas vectoriales escalables.
- Animación decorativa: ambiente no interactivo, partículas de fondo, estrellas, pájaros, bucles procedimentales.
- Renderizado de datos: gráficos, mapas, mapas de calor, grandes nubes de puntos, mediciones actualizadas con frecuencia.
- Arte generativo: dibujo aleatorio/semilla, bocetos creativos, sistemas procedimentales, imágenes exportables.
- Herramienta interactiva: entrada de puntero/teclado, selección, arrastre, objetos editables, detección de colisiones.
- Juego/simulación: bucle de actualización fijo, entidades dinámicas, colisión/física, escena por capas.
- Canvas WebGL/motor: Three.js/Babylon.js/otro renderizador que gestiona recursos GPU.
LECTURA OBLIGATORIA: si la carga de trabajo es animación decorativa o arte generativo, lee references/visual-quality.md — para esos dos trabajos, el objetivo es que se vea bien, y la higiene de rendimiento/accesibilidad por sí sola produce resultados genéricos. NO lo cargues para renderizado de datos, herramientas, juegos o canvas de motor.
Condición de salida: indica la carga de trabajo, por qué canvas es la primitiva adecuada, la frecuencia de imagen objetivo, el número esperado de objetos, el modelo de interacción, y si el canvas es decorativo o semánticamente significativo.
Fase 2 - Elegir el Modelo de Renderizado
Usa Canvas 2D sin formato cuando la escena es principalmente dibujo en modo inmediato, trabajo con píxeles, sprites, animación simple, o el tamaño del paquete importa.
Usa una biblioteca de modo retenido cuando la aplicación necesite objetos editables, selección, arrastrar y soltar, grafo de escena por capas, delegación de eventos o serialización.
Usa p5.js para bocetos, arte generativo, enseñanza/prototipado, o codificación creativa donde la ergonomía de setup/draw importa más que la integración con el framework.
Usa Paper.js para flujos de trabajo de edición vectorial: trazados, segmentos, geometría Bezier, detección de colisiones, importación/exportación SVG, documentos vectoriales por capas.
Usa Konva para interfaz de usuario sobre canvas: integraciones con React/Vue/Svelte, formas arrastrables, capas, formas en caché, controles de escucha de eventos.
Usa Pencil.js para abstracciones ligeras de escena/componentes cuando su modelo de componentes encaje y la frescura de las dependencias sea aceptable para el proyecto.
Usa Three.js/Babylon.js o WebGL directamente cuando el coste dominante sea el renderizado 3D/GPU, shaders, cámaras, materiales, o cargas de trabajo grandes de mallas/sprites.
LECTURA OBLIGATORIA: si eliges una biblioteca o revisas una elección de biblioteca, lee references/library-selection.md. NO cargues referencias de rendimiento o revisión a menos que la tarea llegue a esas fases.
Antes de instalar una biblioteca de canvas o escribir código no trivial de API de biblioteca, verifica la documentación actual con Context7 cuando esté disponible; de lo contrario, usa la documentación oficial. No te bases en APIs recordadas para p5.js, Paper.js, Pencil.js, Konva, ZIM, Three.js o Babylon.js.
Condición de salida: nombra el modelo y las alternativas rechazadas con razones de una línea.
Fase 3 - Diseñar el Bucle y el Estado
Separa el código de canvas en ciclo de vida, actualización de estado, renderizado, entrada, redimensionamiento y teardown. Para componentes de framework, mantén el motor de canvas imperativo detrás de un límite de montaje/inicialización.
Usa requestAnimationFrame para animación visible. Rastrea delta a partir de la marca de tiempo de RAF cuando la velocidad de simulación deba ser estable entre frecuencias de actualización. Cancela RAF al hacer teardown, pausa o reduce el trabajo cuando esté oculto, y respeta prefers-reduced-motion.
Elige una de estas estrategias de redibujado:
- Redibujado completo: aceptable para escenas pequeñas/decorativas donde la simplicidad gana.
- Rectángulos sucios: objetos en movimiento con cambios pequeños y acotados y fondo estable.
- Canvas por capas: fondo estático/lento, entidades dinámicas, superposición de interfaz/interacción.
- Sprite/caché de blits: formas costosas repetidas, texto, marcadores, imágenes escaladas, partículas.
- OffscreenCanvas con Worker: dibujo pesado o simulación que compite con la entrada/hilo principal.
LECTURA OBLIGATORIA: antes de optimizar animación, escenas grandes, partículas, gráficos, escalado de imágenes, salida de alta DPI o renderizado con workers, lee references/performance.md. NO cargues la selección de biblioteca a menos que estés añadiendo o reemplazando una biblioteca.
Condición de salida: escribe el pipeline de frames en orden: muestreo de entrada -> actualización -> estrategia de limpieza/redibujado -> dibujo -> programar el siguiente frame.
Fase 4 - Implementar Higiene de Canvas
Dimensiona el canvas por el almacenamiento de respaldo, no solo por CSS. Para una salida nítida, establece el tamaño CSS por separado, establece canvas.width/height = cssSize * devicePixelRatio, luego normaliza las transformaciones con ctx.setTransform(dpr, 0, 0, dpr, 0, 0). Reduce el DPR intencionadamente para escenas con mucho rendimiento.
Inicializa el contexto con opciones que coincidan con la escena. Usa { alpha: false } para canvas opacos. Usa willReadFrequently: true solo para lecturas frecuentes de getImageData, porque puede cambiar la estrategia de respaldo.
Para la entrada, convierte las coordenadas del puntero a través de getBoundingClientRect() y la escala del canvas. No confíes en clientX/clientY como coordenadas del canvas.
Para accesibilidad, los canvas decorativos reciben aria-hidden="true" y ningún controlador interactivo. Las interacciones significativas del canvas necesitan controles DOM, rutas de teclado, gestión de foco, etiquetas o una representación equivalente no basada en canvas.
Condición de salida: redimensionamiento, DPR, opciones de contexto, mapeo de coordenadas de eventos, preferencia de movimiento y teardown están todos explícitos.
Fase 5 - Revisar y Verificar
Revisa el código de canvas como un bucle caliente más un ciclo de vida de recursos. No te detengas en la corrección visual.
LECTURA OBLIGATORIA: al revisar código de canvas existente o antes de finalizar una nueva implementación, lee references/review-checklist.md. NO cargues la selección de biblioteca a menos que la revisión incluya la idoneidad de la dependencia.
Verifica con al menos una señal de tiempo de ejecución apropiada para la tarea: panel Rendimiento de Chrome, medidor de FPS, instantánea de memoria, latencia de interacción, ruta de movimiento reducido, comportamiento en pestaña oculta o limitación en dispositivos de gama baja/móvil.
Ejemplos
- El usuario pide "hacer un fondo de partículas": clasifica como animación decorativa, rechaza DOM/SVG solo si el número de partículas o el dibujo procedimental justifica el canvas, luego lee
references/visual-quality.mdpara el aspecto yreferences/performance.mdpara el bucle. - El usuario pide "construir formas arrastrables con selección": clasifica como herramienta interactiva, lee
references/library-selection.md, probablemente elige Konva/Paper.js/Canvas 2D sin formato según el modelo de objetos. - El usuario pide "revisar este bucle de canvas": clasifica la carga de trabajo existente, lee
references/review-checklist.md, y leereferences/performance.mdsolo si aparecen problemas de lentitud, alto número de objetos o ruta crítica. - El usuario pide "añadir un boceto p5": lee
references/library-selection.md, verifica los docs actuales de p5 antes del código de API, luego mantén los límites del ciclo de vida del framework explícitos.
NUNCA
-
NUNCA redimensiones solo con CSS para un canvas dibujado En su lugar: establece deliberadamente las dimensiones del almacenamiento de respaldo y las dimensiones CSS; aplica la transformación DPR una vez después del redimensionamiento. Por qué: el escalado solo con CSS difumina la salida y oculta un desajuste en el almacenamiento de respaldo que empeora en pantallas retina.
-
NUNCA inicies un bucle RAF sin una ruta de teardown En su lugar: almacena el id del frame, cancela al desmontar/eliminar, y protégete contra un doble inicio después de cambios de visibilidad o media query. Por qué: los bucles huérfanos siguen dibujando canvas desconectados y crean fugas de memoria/CPU que las instantáneas a menudo atribuyen incorrectamente a componentes internos del navegador.
-
NUNCA redibujes contenido estático costoso cada frame porque visualmente forma parte de la escena En su lugar: guárdalo en caché en un canvas fuera de pantalla, bitmap de imagen, canvas de capa, Path2D o caché de formas de biblioteca. Por qué: canvas es en modo inmediato; los visuales sin cambios siguen costando tiempo de dibujo completo a menos que se almacenen explícitamente en caché o por capas.
-
NUNCA uses una interacción solo de canvas como único control accesible En su lugar: proporciona controles/semántica DOM o un modelo de objetos retenido operable por teclado con etiquetas y comportamiento de foco. Por qué: los píxeles del canvas no exponen roles, nombres, estado o objetivos de interacción a la tecnología de asistencia.
-
NUNCA muevas el trabajo de canvas a OffscreenCanvas solo porque el rendimiento sea malo En su lugar: primero identifica si el cuello de botella son las llamadas de dibujo, la rotación de estado, el sobredibujado, el escalado de imágenes, las lecturas de píxeles o la simulación; usa workers cuando la contención del hilo principal sea el problema. Por qué: los workers añaden restricciones de transferencia, empaquetado y acceso al DOM; no arreglan una mala arquitectura de dibujo.
-
NUNCA trates las reglas de rendimiento de las bibliotecas de modo retenido como opcionales En su lugar: desactiva la escucha en capas inertes, guarda en caché las formas costosas, minimiza el número de capas y destruye nodos/escenarios a través del ciclo de vida de la biblioteca. Por qué: las bibliotecas añaden un grafo de escena y mecanismos de eventos; ignorar sus interruptores puede ser más lento que el canvas sin formato.