生成AI+スマホで作成「WordPress(ブログ)で使えるJavaScript」 ミニ水槽

コードエディター 本文

<div class="aquarium-container">
    <canvas id="aquarium"></canvas>
</div>

カスタムJavaScript

    const canvas = document.getElementById('aquarium');
    const ctx = canvas.getContext('2d');

    let width, height;
    const fishes = [];
    const bubbles = [];
    const FISH_COUNT = 5;
    const BUBBLE_COUNT = 8;

    function resize() {
        width = canvas.width = canvas.parentElement.clientWidth;
        height = canvas.height = 100; // 高さを100pxに固定
    }

    // 魚のクラス
    class Fish {
        constructor() {
            this.x = Math.random() * width;
            this.y = Math.random() * height;
            this.size = 5; // さらに小さく
            this.speedX = (Math.random() - 0.5) * 1.2;
            this.speedY = (Math.random() - 0.5) * 0.3;
            this.color = `hsl(${Math.random() * 30 + 15}, 100%, 60%)`; // 鮮やかなオレンジ
        }
        update() {
            this.x += this.speedX;
            this.y += this.speedY;
            if (this.x < 5 || this.x > width - 5) this.speedX *= -1;
            if (this.y < 5 || this.y > height - 5) this.speedY *= -1;
        }
        draw() {
            ctx.save();
            ctx.translate(this.x, this.y);
            if (this.speedX < 0) ctx.scale(-1, 1);
            ctx.fillStyle = this.color;
            // 胴体
            ctx.beginPath();
            ctx.ellipse(0, 0, this.size, this.size/2.5, 0, 0, Math.PI * 2);
            ctx.fill();
            // 尾びれ
            ctx.beginPath();
            ctx.moveTo(-this.size + 1, 0);
            ctx.lineTo(-this.size - 3, -3);
            ctx.lineTo(-this.size - 3, 3);
            ctx.fill();
            ctx.restore();
        }
    }

    // 泡のクラス
    class Bubble {
        constructor() {
            this.init();
        }
        init() {
            this.x = Math.random() * width;
            this.y = height + Math.random() * 20;
            this.r = Math.random() * 2 + 1;
            this.speedY = Math.random() * 0.5 + 0.2;
            this.opacity = Math.random() * 0.5;
        }
        update() {
            this.y -= this.speedY;
            if (this.y < -10) this.init();
        }
        draw() {
            ctx.beginPath();
            ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
            ctx.strokeStyle = `rgba(255, 255, 255, ${this.opacity})`;
            ctx.stroke();
        }
    }

    function setup() {
        resize();
        for (let i = 0; i < FISH_COUNT; i++) fishes.push(new Fish());
        for (let i = 0; i < BUBBLE_COUNT; i++) bubbles.push(new Bubble());
        animate();
    }

    function animate() {
        ctx.clearRect(0, 0, width, height);
        
        // 泡の描画
        bubbles.forEach(b => { b.update(); b.draw(); });
        // 魚の描画
        fishes.forEach(f => { f.update(); f.draw(); });

        requestAnimationFrame(animate);
    }

    window.addEventListener('resize', resize);
    setup();

カスタムCSS

        /* 水槽の設定:高さ100px */
        .aquarium-container {
            width: 95%;
            max-width: 450px;
            height: 100px;
            border-radius: 8px;
            overflow: hidden;
            position: relative;
            border: 2px solid #555;
            /* 背景画像の設定(グラデーションと模様で水槽を表現) */
            background: 
                linear-gradient(rgba(0, 100, 200, 0.4), rgba(0, 50, 100, 0.7)),
                url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100" viewBox="0 0 100 100"><path d="M10 100 Q 20 50 10 0 M30 100 Q 40 60 30 10 M80 100 Q 70 40 80 0" stroke="green" stroke-width="2" fill="none" opacity="0.3"/></svg>');
            background-size: cover;
        }
        canvas { display: block; }