with-canvas
O trabalho com canvas falha de duas maneiras diferentes: código visual bonito, mas instável, e código otimizado, mas inmantível ou inacessível. Trate cada tarefa como uma decisão de arquitetura de renderização antes de escrever chamadas de desenho. Carregue apenas a referência nomeada pela fase atual; não pré-carregue todas as referências.
Fase 1 – Classificar o Trabalho de Canvas
Identifique a carga de trabalho dominante antes de escolher APIs:
- Rejeitar canvas: prefira DOM/CSS/SVG/vídeo quando a cena é principalmente texto, controles acessíveis, layout de documento, iconografia simples, animação CSS, reprodução de mídia ou um pequeno número de formas vetoriais escaláveis.
- Animação decorativa: ambiente não interativo, partículas de fundo, estrelas, pássaros, loops processuais.
- Renderização de dados: gráficos, mapas, mapas de calor, grandes nuvens de pontos, medições atualizadas com frequência.
- Arte generativa: desenho com semente/aleatório, esboços criativos, sistemas processuais, imagens exportáveis.
- Ferramenta interativa: entrada de ponteiro/teclado, seleção, arrastar, objetos editáveis, teste de colisão.
- Jogo/simulação: loop de atualização fixo, entidades dinâmicas, colisão/física, cena em camadas.
- Canvas WebGL/mecanismo: Three.js/Babylon.js/outro renderizador que possui recursos de GPU.
LEITURA OBRIGATÓRIA: se a carga de trabalho for animação decorativa ou arte generativa, leia references/visual-quality.md — para esses dois trabalhos, parecer bom é a tarefa, e apenas práticas de desempenho/acessibilidade geram resultados genéricos. NÃO carregue para renderização de dados, ferramentas, jogos ou canvas de mecanismo.
Condição de saída: declare a carga de trabalho, por que o canvas é a primitiva correta, taxa de quadros alvo, contagem esperada de objetos, modelo de interação e se o canvas é decorativo ou semanticamente significativo.
Fase 2 – Escolher o Modelo de Renderização
Use Canvas 2D puro quando a cena é principalmente desenho em modo imediato, trabalho com pixels, sprites, animação simples ou o tamanho do pacote é importante.
Use uma biblioteca de modo retido quando o aplicativo precisa de objetos editáveis, seleção, arrastar/soltar, grafo de cena em camadas, delegação de eventos ou serialização.
Use p5.js para esboços, arte generativa, ensino/prototipagem ou codificação criativa onde a ergonomia de setup/draw importa mais do que a integração com o framework.
Use Paper.js para fluxos de trabalho de edição vetorial: caminhos, segmentos, geometria bezier, teste de colisão, exportação/importação SVG, documentos vetoriais em camadas.
Use Konva para UI de aplicativo em canvas: integrações React/Vue/Svelte, formas arrastáveis, camadas, formas em cache, controles de escuta de eventos.
Use Pencil.js para abstrações leves de cena/componente quando seu modelo de componente se encaixa e a atualidade das dependências é aceitável para o projeto.
Use Three.js/Babylon.js ou WebGL diretamente quando o custo dominante é renderização 3D/GPU, shaders, câmeras, materiais ou cargas de trabalho grandes de malhas/sprites.
LEITURA OBRIGATÓRIA: se estiver escolhendo uma biblioteca ou revisando uma escolha de biblioteca, leia references/library-selection.md. NÃO carregue referências de desempenho ou revisão a menos que a tarefa atinja essas fases.
Antes de instalar uma biblioteca de canvas ou escrever código não trivial de API de biblioteca, verifique a documentação atual com Context7 quando disponível; caso contrário, use a documentação oficial. Não confie em APIs lembradas para p5.js, Paper.js, Pencil.js, Konva, ZIM, Three.js ou Babylon.js.
Condição de saída: nomeie o modelo e as alternativas rejeitadas com razões de uma linha.
Fase 3 – Projetar o Loop e o Estado
Separe o código de canvas em ciclo de vida, atualização de estado, renderização, entrada, redimensionamento e desmontagem. Para componentes de framework, mantenha o mecanismo de canvas imperativo atrás de um limite de montagem/inicialização.
Use requestAnimationFrame para animação visível. Rastreie delta a partir do timestamp do RAF quando a velocidade da simulação precisar ser estável entre taxas de atualização. Cancele RAF na desmontagem, pause ou reduza o trabalho quando oculto e respeite prefers-reduced-motion.
Escolha uma destas estratégias de redesenho:
- Redesenho completo: aceitável para cenas pequenas/decorativas onde a simplicidade vence.
- Retângulos sujos: objetos em movimento com pequenas alterações limitadas e fundo estável.
- Canvas em camadas: fundo estático/lento, entidades dinâmicas, sobreposição de interface/interação.
- Blits de sprite/cache: formas caras repetidas, texto, marcadores, imagens redimensionadas, partículas.
- OffscreenCanvas em Worker: desenho pesado ou simulação que compete com entrada/thread principal.
LEITURA OBRIGATÓRIA: antes de otimizar animação, cenas grandes, partículas, gráficos, redimensionamento de imagens, saída de alta DPI ou renderização em worker, leia references/performance.md. NÃO carregue library-selection a menos que esteja adicionando/substituindo uma biblioteca.
Condição de saída: escreva o pipeline de quadros em ordem: amostragem de entrada -> atualização -> estratégia de limpeza/redesenho -> desenho -> agendar próximo quadro.
Fase 4 – Implementar Higiene de Canvas
Dimensione o canvas pelo armazenamento de apoio, não apenas pelo CSS. Para saída nítida, defina o tamanho CSS separadamente, defina canvas.width/height = cssSize * devicePixelRatio, depois normalize transformações com ctx.setTransform(dpr, 0, 0, dpr, 0, 0). Reduza o DPR intencionalmente para cenas com alto custo de desempenho.
Inicialize o contexto com opções que correspondam à cena. Use { alpha: false } para canvas opacos. Use willReadFrequently: true apenas para leituras frequentes de getImageData, pois pode alterar a estratégia de armazenamento de apoio.
Para entrada, converta coordenadas do ponteiro através de getBoundingClientRect() e da escala do canvas. Não confie em clientX/clientY como coordenadas do canvas.
Para acessibilidade, canvas decorativos recebem aria-hidden="true" e nenhum manipulador interativo. Interações significativas de canvas precisam de controles DOM, caminhos de teclado, gerenciamento de foco, rótulos ou uma representação equivalente não-canvas.
Condição de saída: redimensionamento, DPR, opções de contexto, mapeamento de coordenadas de evento, preferência de movimento e desmontagem estão todos explícitos.
Fase 5 – Revisar e Verificar
Revise o código de canvas como um loop quente mais um ciclo de vida de recursos. Não pare na correção visual.
LEITURA OBRIGATÓRIA: ao revisar código de canvas existente ou antes de finalizar uma nova implementação, leia references/review-checklist.md. NÃO carregue library-selection a menos que a revisão inclua adequação de dependência.
Verifique com pelo menos um sinal de tempo de execução apropriado para a tarefa: painel Performance do Chrome, medidor de FPS, snapshot de memória, latência de interação, caminho de movimento reduzido, comportamento de aba oculta ou limitação de baixo desempenho/mobile.
Exemplos
- Usuário pede "fazer um fundo de partículas": classifique como animação decorativa, rejeite DOM/SVG apenas se a contagem de partículas ou desenho processual justificar canvas, depois leia
references/visual-quality.mdpara a aparência ereferences/performance.mdpara o loop. - Usuário pede "construir formas arrastáveis com seleção": classifique como ferramenta interativa, leia
references/library-selection.md, provavelmente escolha Konva/Paper.js/Canvas 2D puro com base no modelo de objetos. - Usuário pede "revisar este loop de canvas": classifique a carga de trabalho existente, leia
references/review-checklist.md, e leiareferences/performance.mdapenas se problemas de instabilidade, alta contagem de objetos ou caminho crítico aparecerem. - Usuário pede "adicionar esboço p5": leia
references/library-selection.md, verifique a documentação atual do p5 antes do código de API, depois mantenha os limites do ciclo de vida do framework explícitos.
NUNCA
-
NUNCA redimensione apenas com CSS para um canvas desenhado Em vez disso: defina as dimensões do armazenamento de apoio e as dimensões CSS deliberadamente; aplique a transformação DPR uma vez após o redimensionamento. Por quê: o escalonamento apenas com CSS desfoca a saída e esconde uma incompatibilidade de armazenamento de apoio que piora em telas retina.
-
NUNCA inicie um loop RAF sem um caminho de desmontagem Em vez disso: armazene o id do quadro, cancele na desmontagem/liberação e proteja contra dupla inicialização após mudanças de visibilidade ou media-query. Por quê: loops órfãos continuam desenhando canvas destacados e criam vazamentos de memória/CPU que snapshots frequentemente atribuem erroneamente a componentes internos do navegador.
-
NUNCA redesenhe conteúdo estático caro a cada quadro porque ele faz parte visualmente da cena Em vez disso: armazene em cache em um canvas offscreen, bitmap de imagem, canvas de camada, Path2D ou cache de formas da biblioteca. Por quê: canvas é modo imediato; visuais inalterados ainda custam tempo de desenho completo a menos que explicitamente armazenados em cache ou em camadas.
-
NUNCA use uma interação exclusiva de canvas como o único controle acessível Em vez disso: forneça controles/semântica DOM ou um modelo de objeto retido operável por teclado com rótulos e comportamento de foco. Por quê: pixels de canvas não expõem funções, nomes, estados ou alvos de clique para tecnologia assistiva.
-
NUNCA mova trabalho de canvas para OffscreenCanvas apenas porque o desempenho é ruim Em vez disso: primeiro identifique se o gargalo são chamadas de desenho, oscilação de estado, sobreposição de desenho, redimensionamento de imagem, leituras de pixels ou simulação; use workers quando a contenção da thread principal for o problema. Por quê: workers adicionam restrições de transferência, empacotamento e acesso DOM; eles não corrigem arquitetura de desenho ruim.
-
NUNCA trate regras de desempenho de bibliotecas de modo retido como opcionais Em vez disso: desabilite a escuta em camadas inertes, armazene formas caras em cache, minimize o número de camadas e destrua nós/cenas através do ciclo de vida da biblioteca. Por quê: bibliotecas adicionam grafo de cena e maquinário de eventos; ignorar suas opções pode ser mais lento do que canvas puro.