Tips & Tricks

Optimisation Canvas/WebGL avec Claude Code

Découvrez l'optimisation Canvas/WebGL avec Claude Code. Conseils pratiques et exemples de code inclus.

L’attrait et les défis du développement Canvas/WebGL

Canvas peut être utilisé pour une grande variété d’applications : jeux, visualisation de données, édition d’images, art interactif, etc. Cependant, l’API étant de bas niveau, le volume de code tend à être important. Avec Claude Code, vous pouvez générer rapidement la logique de rendu et le code des shaders, améliorant considérablement la vitesse de développement.

Système de rendu Canvas 2D de base

> Crée une classe qui gère le rendu Canvas 2D.
> Inclus une boucle d'animation, la gestion du redimensionnement et l'affichage des FPS.
class CanvasApp {
  private canvas: HTMLCanvasElement;
  private ctx: CanvasRenderingContext2D;
  private animationId: number = 0;
  private lastTime: number = 0;
  private fps: number = 0;
  private frameCount: number = 0;
  private fpsTime: number = 0;

  constructor(container: HTMLElement) {
    this.canvas = document.createElement('canvas');
    this.ctx = this.canvas.getContext('2d')!;
    container.appendChild(this.canvas);
    this.resize();
    window.addEventListener('resize', () => this.resize());
  }

  private resize() {
    const dpr = window.devicePixelRatio || 1;
    const rect = this.canvas.parentElement!.getBoundingClientRect();
    this.canvas.width = rect.width * dpr;
    this.canvas.height = rect.height * dpr;
    this.canvas.style.width = `${rect.width}px`;
    this.canvas.style.height = `${rect.height}px`;
    this.ctx.scale(dpr, dpr);
  }

  start(renderFn: (ctx: CanvasRenderingContext2D, dt: number) => void) {
    const loop = (time: number) => {
      const dt = (time - this.lastTime) / 1000;
      this.lastTime = time;

      // Calcul des FPS
      this.frameCount++;
      if (time - this.fpsTime >= 1000) {
        this.fps = this.frameCount;
        this.frameCount = 0;
        this.fpsTime = time;
      }

      const { width, height } = this.canvas.getBoundingClientRect();
      this.ctx.clearRect(0, 0, width, height);

      renderFn(this.ctx, dt);

      // Affichage des FPS
      this.ctx.fillStyle = '#0f0';
      this.ctx.font = '12px monospace';
      this.ctx.fillText(`FPS: ${this.fps}`, 10, 20);

      this.animationId = requestAnimationFrame(loop);
    };

    this.animationId = requestAnimationFrame(loop);
  }

  stop() {
    cancelAnimationFrame(this.animationId);
  }
}

Système de particules

> Implémente un effet de particules. Crée des particules qui suivent la souris.
interface Particle {
  x: number; y: number;
  vx: number; vy: number;
  life: number; maxLife: number;
  size: number;
  color: string;
}

class ParticleSystem {
  private particles: Particle[] = [];
  private maxParticles = 500;

  emit(x: number, y: number, count: number = 5) {
    for (let i = 0; i < count; i++) {
      if (this.particles.length >= this.maxParticles) break;

      const angle = Math.random() * Math.PI * 2;
      const speed = Math.random() * 3 + 1;
      const hue = Math.random() * 60 + 200; // bleu à violet

      this.particles.push({
        x, y,
        vx: Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        life: 1,
        maxLife: Math.random() * 1 + 0.5,
        size: Math.random() * 4 + 2,
        color: `hsl(${hue}, 80%, 60%)`,
      });
    }
  }

  update(dt: number) {
    this.particles = this.particles.filter((p) => {
      p.x += p.vx;
      p.y += p.vy;
      p.vy += 0.5 * dt; // gravité
      p.life -= dt / p.maxLife;
      return p.life > 0;
    });
  }

  draw(ctx: CanvasRenderingContext2D) {
    this.particles.forEach((p) => {
      ctx.globalAlpha = p.life;
      ctx.fillStyle = p.color;
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2);
      ctx.fill();
    });
    ctx.globalAlpha = 1;
  }
}

Shaders WebGL

> Crée un shader de dégradé simple avec WebGL.
function createShaderProgram(gl: WebGLRenderingContext) {
  const vertexShaderSource = `
    attribute vec2 a_position;
    varying vec2 v_uv;

    void main() {
      v_uv = a_position * 0.5 + 0.5;
      gl_Position = vec4(a_position, 0.0, 1.0);
    }
  `;

  const fragmentShaderSource = `
    precision mediump float;
    varying vec2 v_uv;
    uniform float u_time;

    void main() {
      vec3 color1 = vec3(0.1, 0.3, 0.8);
      vec3 color2 = vec3(0.8, 0.2, 0.5);
      float t = sin(v_uv.x * 3.0 + u_time) * 0.5 + 0.5;
      vec3 color = mix(color1, color2, t * v_uv.y);
      gl_FragColor = vec4(color, 1.0);
    }
  `;

  const vertexShader = compileShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
  const fragmentShader = compileShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

  const program = gl.createProgram()!;
  gl.attachShader(program, vertexShader);
  gl.attachShader(program, fragmentShader);
  gl.linkProgram(program);

  return program;
}

function compileShader(gl: WebGLRenderingContext, type: number, source: string) {
  const shader = gl.createShader(type)!;
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    throw new Error(gl.getShaderInfoLog(shader) || 'Erreur de compilation du shader');
  }
  return shader;
}

Intégration avec React

function CanvasComponent() {
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (!containerRef.current) return;

    const app = new CanvasApp(containerRef.current);
    const particles = new ParticleSystem();

    containerRef.current.addEventListener('mousemove', (e) => {
      const rect = containerRef.current!.getBoundingClientRect();
      particles.emit(e.clientX - rect.left, e.clientY - rect.top);
    });

    app.start((ctx, dt) => {
      particles.update(dt);
      particles.draw(ctx);
    });

    return () => app.stop();
  }, []);

  return <div ref={containerRef} className="w-full h-96 bg-gray-900 rounded-lg" />;
}

Résumé

Avec Claude Code, vous pouvez développer efficacement du système de rendu Canvas 2D aux effets de particules et shaders WebGL. Pour l’intégration avec l’audio, consultez Web Audio API, et pour la visualisation de données, consultez l’article sur la visualisation de données.

Pour plus de détails sur l’API Canvas, consultez MDN Web Docs - Canvas API, et pour WebGL, consultez WebGL Fundamentals.

#Claude Code #Canvas #WebGL #graphiques #TypeScript