万華鏡ジェネレーター
CSSとJavaScriptで、Canvasを使用し幾何学模様が中心から対称に広がり色鮮やかに変化する万華鏡のような背景アニメーションを生成します。
プレビュー
<!-- 万華鏡背景を描画するCanvas要素 -->
<canvas class="kaleidoscope-canvas"></canvas>
/* Canvasを親コンテナ全体にフィットさせるスタイル */
.kaleidoscope-canvas {
display: block;
width: 100%;
height: 400px;
background-color: {{bg_color}};
}
(() => {
const canvas = document.querySelector('.kaleidoscope-canvas');
if (!canvas) return;
const ctx = canvas.getContext('2d');
// 高解像度対応とサイズ調整 (ResizeObserverを使用してメモリリークを防止)
const resizeObserver = new ResizeObserver(() => {
canvas.width = canvas.offsetWidth;
canvas.height = canvas.offsetHeight;
});
resizeObserver.observe(canvas);
// 設定値のバインド
const symmetry = {{symmetry}};
const speed = {{speed}};
const lineWidth = {{line_width}};
const particleCount = {{particle_count}};
const colorScheme = '{{color_scheme}}';
const bgColor = '{{bg_color}}';
const zoom = {{zoom}};
const fadeSpeed = {{fade_speed}} / 100; // 残像(透明度)
// パーティクルクラス定義
class Particle {
constructor() {
this.reset();
}
reset() {
// 中心からの距離と角度
this.r = Math.random() * 200 + 20;
this.angle = Math.random() * Math.PI * 2;
this.size = Math.random() * 5 + 2;
// 速度
this.vr = (Math.random() - 0.5) * speed;
this.vangle = (Math.random() - 0.5) * 0.02 * speed;
// 色生成
this.color = this.getColor();
}
getColor() {
const hue = Math.random() * 360;
switch(colorScheme) {
case 'rainbow':
return `hsl(${hue}, 100%, 60%)`;
case 'neon':
const neonColors = ['#ff007f', '#00f6ff', '#39ff14', '#ffff00'];
return neonColors[Math.floor(Math.random() * neonColors.length)];
case 'warm':
return `hsl(${Math.random() * 60}, 100%, 50%)`;
case 'cool':
return `hsl(${Math.random() * 120 + 180}, 100%, 50%)`;
case 'monochrome':
return `hsl(0, 0%, ${Math.random() * 100}%)`;
default:
return `hsl(${hue}, 100%, 60%)`;
}
}
update() {
this.r += this.vr;
this.angle += this.vangle;
// 画面端にいったら反射
const maxR = Math.min(canvas.width, canvas.height) * 0.5 * zoom;
if (this.r > maxR || this.r < 10) {
this.vr = -this.vr;
}
}
}
const particles = Array.from({ length: particleCount }, () => new Particle());
// 描画処理関数
const draw = () => {
// 背景色に透明度を混ぜてフェードアウト(残像)
ctx.fillStyle = hexToRgba(bgColor, fadeSpeed);
ctx.fillRect(0, 0, canvas.width, canvas.height);
const cx = canvas.width / 2;
const cy = canvas.height / 2;
// パーティクルの更新
particles.forEach(p => p.update());
// 対称描画のループ
for (let i = 0; i < symmetry; i++) {
// 表側の描画
ctx.save();
ctx.translate(cx, cy);
ctx.rotate((Math.PI * 2 / symmetry) * i);
drawSector();
ctx.restore();
// 鏡像(反射)の描画
ctx.save();
ctx.translate(cx, cy);
ctx.scale(1, -1);
ctx.rotate((Math.PI * 2 / symmetry) * i);
drawSector();
ctx.restore();
}
};
// 扇形セクション内の描画ロジック
const drawSector = () => {
ctx.lineWidth = lineWidth;
ctx.lineCap = 'round';
ctx.lineJoin = 'round';
// パーティクル同士を線で結ぶ(幾何学模様)
for (let j = 0; j < particles.length; j++) {
const p1 = particles[j];
const x1 = Math.cos(p1.angle) * p1.r * zoom;
const y1 = Math.sin(p1.angle) * p1.r * zoom;
ctx.beginPath();
ctx.fillStyle = p1.color;
ctx.arc(x1, y1, p1.size, 0, Math.PI * 2);
ctx.fill();
// 近いパーティクル同士を繋ぐ
for (let k = j + 1; k < particles.length; k++) {
const p2 = particles[k];
const x2 = Math.cos(p2.angle) * p2.r * zoom;
const y2 = Math.sin(p2.angle) * p2.r * zoom;
const dist = Math.hypot(x2 - x1, y2 - y1);
if (dist < 100 * zoom) {
ctx.beginPath();
ctx.strokeStyle = p1.color;
ctx.globalAlpha = (1 - dist / (100 * zoom)) * 0.4;
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
}
}
ctx.globalAlpha = 1.0;
};
// 16進数カラーコードをRGBAに変換するヘルパー関数
function hexToRgba(hex, alpha) {
const r = parseInt(hex.slice(1, 3), 16);
const g = parseInt(hex.slice(3, 5), 16);
const b = parseInt(hex.slice(5, 7), 16);
return `rgba(${r}, ${g}, ${b}, ${alpha})`;
}
const animate = () => {
draw();
requestAnimationFrame(animate);
};
animate();
})();
機能、使い方
- HTML5
canvasを使用して、幾何学模様が中心から対称に広がる美しい万華鏡エフェクトを表現します。 - 対称軸の数(分割数)、移動速度、線の太さ、オブジェクトの複雑さ(パーティクル数)、ズーム倍率をリアルタイムに変更できます。
- 背景色と色彩パターン(レインボー、ネオン、ウォーム、クール、モノクロ)を自在にカスタマイズできます。
- 残像の長さを調整することで、くっきりとした幾何学模様から、滑らかで幻想的な光の軌跡まで様々な表現が可能です。
コードの説明
getContext('2d') を使用し、Canvas API による高度な描画操作を行っています。
ctx.rotate() を用いた座標系の回転と、ctx.scale(1, -1) による鏡像反射を組み合わせることで、万華鏡ならではの対称的な幾何学模様を完璧に表現しています。
アニメーションループには requestAnimationFrame を採用し、ブラウザの描画タイミングに同期させた滑らかで高パフォーマンスな処理を行っています。