← Back to Desktop app developers

Skill · Version 1.0.0

Interactive Canvas graphics

Builds responsive custom Canvas visuals with correct pixel density, stable animation timing and usable alternatives to bitmap-only interaction.

canvas-interactive-graphics

Team members using this skill

See how it helps

When is it useful?

Use it when an interactive diagram or animation needs precise drawing without excluding keyboard or assistive-technology users.

What does it help you do?

  • Matches drawing resolution to display pixel density.
  • Uses elapsed time and pauses rendering when offscreen.
  • Maps pointer hits and supplies accessible HTML controls.

Try asking this

Build an interactive node canvas with keyboard alternatives and reduced motion. Select a node by keyboard and pointer, then move the canvas offscreen. Both inputs should identify the same node, and hidden rendering should pause.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

Canvas & Interactive Graphics

Reach for HTML5 <canvas> when a scene animates hundreds of simultaneous elements (particle fields, live node-link topologies, waveform visualizers, spatial grids) where individual DOM/SVG nodes would bottleneck layout and style recalculation.

Crisp High-DPI (devicePixelRatio) Setup & Resize

A raw <canvas width="800" height="600"> looks blurry on Retina/high-DPI screens. Always decouple logical CSS coordinates from physical backing-store pixels:

function syncCanvasSize(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D, cssWidth: number, cssHeight: number) {
  const dpr = Math.min(window.devicePixelRatio || 1, 2); // Cap at 2x to protect fill-rate on 3x/4x mobile screens
  canvas.width = Math.round(cssWidth * dpr);
  canvas.height = Math.round(cssHeight * dpr);
  canvas.style.width = `${cssWidth}px`;
  canvas.style.height = `${cssHeight}px`;
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0); // Draw in logical CSS pixels everywhere else
}
  • Observe the container with ResizeObserver and re-run syncCanvasSize + an immediate render pass when dimensions change (because changing canvas.width clears the canvas buffer).

Frame-Rate Independent Loop & Offscreen Pausing

  1. Delta-time (dt) integration:
    • Never advance positions by a fixed pixel step per requestAnimationFrame tick (x += 2), which runs twice as fast on 120Hz displays as on 60Hz displays.
    • Compute elapsed seconds const dt = Math.min((now - lastTime) / 1000, 0.05); and use frame-rate independent exponential damping for smooth pointer/camera follow: $$\text{value} = \text{lerp}(\text{value}, \text{target}, 1 - e^{-\lambda \cdot dt})$$
  2. Zero-allocation render loop:
    • Never allocate new Path2D(), objects, arrays, or gradient instances inside the per-frame render() loop—GC pauses cause visible frame drops. Pre-allocate typed arrays or object pools during setup.
    • Cache static background grids or complex vector stamps onto an offscreen canvas (OffscreenCanvas or hidden <canvas>) and composite via ctx.drawImage().
  3. Sleep when idle or offscreen:
    • Stop the requestAnimationFrame loop when all springs/particles have settled within $\epsilon$ of rest, and restart it on pointer/scroll/state events.
    • Pause rendering whenever IntersectionObserver reports the canvas is outside the viewport or document.hidden is true.

Pointer Interaction & Accessibility Overlay

  • Coordinate mapping: Convert client pointer events (PointerEvent) to logical canvas coordinates via const rect = canvas.getBoundingClientRect(); const x = e.clientX - rect.left; const y = e.clientY - rect.top;.
  • Accessible DOM twin: Because <canvas> is a single opaque bitmap to assistive tech, never draw interactive buttons or essential text solely inside Canvas. Overlay semantic, keyboard-focusable HTML buttons/controls positioned over the canvas (or provide a synchronized accessible list/table inside the container) and honor prefers-reduced-motion: reduce by rendering a calm static or step-driven frame.

Included files 1

  • SKILL.md