Tips & Tricks

Optimasi Canvas/WebGL dengan Claude Code

Pelajari tentang optimasi Canvas/WebGL menggunakan Claude Code. Tips praktis dan contoh kode disertakan.

Daya Tarik dan Tantangan Pengembangan Canvas/WebGL

Canvas bisa digunakan untuk berbagai keperluan seperti game, visualisasi data, pengeditan gambar, dan seni interaktif. Namun karena API-nya low-level, kode cenderung menjadi banyak. Dengan Claude Code, logika gambar dan kode shader bisa di-generate dengan cepat sehingga kecepatan pengembangan meningkat secara signifikan.

Sistem Gambar Dasar Canvas 2D

> Buat class yang mengelola gambar Canvas 2D.
> Sertakan loop animasi, dukungan resize, dan tampilan 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;

      // Kalkulasi 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);

      // Tampilan 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);
  }
}

Sistem Partikel

> Implementasikan efek partikel. Buat partikel yang mengikuti mouse.
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; // Biru ke ungu

      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; // Gravitasi
      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;
  }
}

Shader WebGL

> Buat shader gradien sederhana dengan 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) || 'Error kompilasi shader');
  }
  return shader;
}

Integrasi dengan 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" />;
}

Summary

Dengan Claude Code, pengembangan mulai dari sistem gambar Canvas 2D hingga efek partikel dan shader WebGL bisa dilakukan secara efisien. Untuk integrasi audio, lihat Web Audio API, dan untuk visualisasi data, lihat Visualisasi Data.

Untuk detail Canvas API, lihat MDN Web Docs - Canvas API, dan untuk WebGL, lihat WebGL Fundamentals.

#Claude Code #Canvas #WebGL #graphics #TypeScript