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
外部データとの連携も指示可能
シンプルなサンプルコードを書くだけではなく、画像なども連携したコード出力にも対応しており、可能性を感じる実験結果になりました。さらに高度な実験も行っていきたいと思います。