Claude 3 で画像連携のクリエイティブコーディング

前回「Claude 3 で書くクリエイティブコーディング」という記事で、Three.jsを利用して、Claude 3 でコーディングを行う実験をリリースしましたが、今回もClaude 3を利用したコーディング実験。前回より、少し高度に外部の画像を読み込み処理させるプログラムを書いてみました。

生成したプログラム

粒子が集まり、指定した画像を形成し、さらにその後大きく拡散するというコードを書きました。何度か修正を行いましたが、数回のターンでここまでの表現が可能です。

実際のコード

<!DOCTYPE html>
<html>
<head>
  <title>Particle Image Animation with Three.js</title>
  <style>
    body { margin: 0; overflow: hidden; }
    canvas { width: 100%; height: 100%; }
  </style>
</head>
<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js"></script>
  <script>
    // シーンの作成
    const scene = new THREE.Scene();

    // カメラの設定
    const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.z = 500;

    // レンダラーの設定
    const renderer = new THREE.WebGLRenderer();
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    // 画像の読み込み
    const loader = new THREE.TextureLoader();
    const texture = loader.load('image.jpg', () => {
      const imageData = getImageData(texture.image);
      createParticles(imageData);
    });

    // 画像データの取得
    function getImageData(image) {
      const canvas = document.createElement('canvas');
      canvas.width = image.width;
      canvas.height = image.height;
      const context = canvas.getContext('2d');
      context.drawImage(image, 0, 0);
      return context.getImageData(0, 0, image.width, image.height);
    }

    let particles;
    let targetPositions;
    let initialPositions;
    let step = 0;
    const totalSteps = 200;
    let expanding = false;

    // 粒子の作成
    function createParticles(imageData) {
      const geometry = new THREE.BufferGeometry();
      const positions = new Float32Array(imageData.data.length / 4 * 3);
      const colors = new Float32Array(imageData.data.length / 4 * 3);

      for (let i = 0; i < imageData.data.length; i += 4) {
        const x = (i / 4) % imageData.width;
        const y = Math.floor((i / 4) / imageData.width);

        const r = imageData.data[i] / 255;
        const g = imageData.data[i + 1] / 255;
        const b = imageData.data[i + 2] / 255;

        const index = (i / 4) * 3;
        positions[index] = x - imageData.width / 2;
        positions[index + 1] = -y + imageData.height / 2;
        positions[index + 2] = 0;

        colors[index] = r;
        colors[index + 1] = g;
        colors[index + 2] = b;
      }

      geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
      geometry.setAttribute('color', new THREE.BufferAttribute(colors, 3));

      const material = new THREE.PointsMaterial({ size: 2, vertexColors: true });

      particles = new THREE.Points(geometry, material);
      scene.add(particles);

      // アニメーションの設定
      targetPositions = positions.slice();
      initialPositions = new Float32Array(positions.length);
      for (let i = 0; i < initialPositions.length; i += 3) {
        initialPositions[i] = Math.random() * 2000 - 1000;
        initialPositions[i + 1] = Math.random() * 2000 - 1000;
        initialPositions[i + 2] = Math.random() * 2000 - 1000;
      }

      // 初期位置の設定
      particles.geometry.attributes.position.array.set(initialPositions);
      particles.geometry.attributes.position.needsUpdate = true;

      animate();
    }

    function animate() {
      requestAnimationFrame(animate);

      const positions = particles.geometry.attributes.position.array;

      if (!expanding) {
        for (let i = 0; i < positions.length; i += 3) {
          positions[i] += (targetPositions[i] - positions[i]) * 0.05;
          positions[i + 1] += (targetPositions[i + 1] - positions[i + 1]) * 0.05;
          positions[i + 2] += (targetPositions[i + 2] - positions[i + 2]) * 0.05;
        }

        if (step < totalSteps) {
          step++;
        } else {
          expanding = true;
          step = 0;
        }
      } else {
        for (let i = 0; i < positions.length; i += 3) {
          positions[i] += (initialPositions[i] - positions[i]) * 0.01;
          positions[i + 1] += (initialPositions[i + 1] - positions[i + 1]) * 0.01;
          positions[i + 2] += (initialPositions[i + 2] - positions[i + 2]) * 0.01;
        }

        if (step < totalSteps) {
          step++;
        } else {
          expanding = false;
          step = 0;
        }
      }

      particles.geometry.attributes.position.needsUpdate = true;

      renderer.render(scene, camera);
    }

    // ウィンドウリサイズ時の処理
    window.addEventListener('resize', onWindowResize, false);

    function onWindowResize() {
      camera.aspect = window.innerWidth / window.innerHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(window.innerWidth, window.innerHeight);
    }
  </script>
</body>
</html>

動作デモ

実際の動作については以下をご覧ください。

https://taziku.co.jp/c-coding/c-anime02.html

外部データとの連携も指示可能

シンプルなサンプルコードを書くだけではなく、画像なども連携したコード出力にも対応しており、可能性を感じる実験結果になりました。さらに高度な実験も行っていきたいと思います。

※当サイトに掲載されている商標、一部画像、スクリ-ンショット、文章に置いては著作権侵害を目的に利用しておらず、第三十二条で定められる引用の範囲で使用しています。万が一問題があれば、お問い合わせからご連絡ください。即刻削除いたします。また、本ブログは業務の研究開発のためのものとなり、一部、弊社に関連性が無いものも掲載しております。

Related INSIGHTS

最新の知見をお届け

AI・クリエイティブに関する最新情報は
公式Xアカウントやnoteでも発信しています。

Follow @taziku_co note で読む