生成AI+スマホで作成「WordPress(ブログ)で使えるJavaScript」 砂字

コードエディター 本文

// canvasサイズ
<div id="sand-container" style="width: 320px; height: 90px; background: #1a1a1a; position: relative; overflow: hidden;">
    </div>

カスタムJavaScript

(function() {
    // --- 設定項目 ---
    const containerId = 'sand-container'; // 砂を表示させるDIVのID
    const textList = ["東海の", "小島の磯の", "白砂に","われ泣きぬれて","蟹とたはむる","- 石川啄木"]; // 表示する文字列
    const particleCount = 4000; // 砂の粒の数
    const sandColor = '#D8CEBA'; // 砂の色
    
    const container = document.getElementById(containerId);
    if (!container) return;

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    
    // 枠内にフィットさせるためのスタイル
    canvas.style.position = 'absolute';
    canvas.style.top = '0';
    canvas.style.left = '0';
    canvas.style.width = '100%';
    canvas.style.height = '100%';
        let width, height, particles = [];
    let textIndex = 0;

    class Particle {
        constructor() {
            this.init();
        }
        init() {
            this.x = Math.random() * width;
            this.y = Math.random() * height;
            this.destX = this.x;
            this.destY = this.y;
            this.vx = 0;
            this.vy = 0;
            this.accel = 0.02 + Math.random() * 0.04;
            this.friction = 0.85 + Math.random() * 0.1;
        }
        update() {
            // 目的地に向かう物理演算
            let dx = this.destX - this.x;
            let dy = this.destY - this.y;
            
            this.vx += dx * this.accel;
            this.vy += dy * this.accel;
            this.vx *= this.friction;
            this.vy *= this.friction;
            
            this.x += this.vx;
            this.y += this.vy;
        }
        draw() {
            ctx.fillStyle = sandColor;
            ctx.globalAlpha = 0.8; // 少し透けさせて質感を出す
            ctx.fillRect(this.x, this.y, 1.2, 1.2);
        }
    }

    function resize() {
        // 親要素のサイズを取得
        width = canvas.width = container.offsetWidth;
        height = canvas.height = container.offsetHeight;
    }

    function getTextPoints(text) {
        const tempCanvas = document.createElement('canvas');
        const tempCtx = tempCanvas.getContext('2d');
        tempCanvas.width = width;
        tempCanvas.height = height;
        
        const fontSize = 40; // 好きなピクセル数に変更(フォントサイズ)

        tempCtx.textAlign = 'center';
        tempCtx.textBaseline = 'middle';
        // フォントの書体
        tempCtx.font = `bold ${fontSize}px "Yu Mincho", "YuMincho", "MS PMincho", serif`;
        tempCtx.fillText(text, width / 2, height / 2);

        const imageData = tempCtx.getImageData(0, 0, width, height).data;
        const points = [];
        const step = 1; // 密度調整

        for (let y = 0; y < height; y += step) {
            for (let x = 0; x < width; x += step) {
                if (imageData[(y * width + x) * 4 + 3] > 128) {
                    points.push({x, y});
                }
            }
        }
        return points;
    }

    function updateText() {
        const points = getTextPoints(textList[textIndex]);
        // 砂に新しい目的地を割り当てる
        for (let i = 0; i < particles.length; i++) {
            const p = particles[i];
            if (i < points.length) {
                // 文字の形へ
                p.destX = points[i].x + (Math.random() - 0.5) * 3;
                p.destY = points[i].y + (Math.random() - 0.5) * 3;
            } else {
                // 溢れた砂は下に溜まるように(重力演出)
                p.destX = Math.random() * width;
                p.destY = height + Math.random() * 50;
            }
        }
        textIndex = (textIndex + 1) % textList.length;
    }

    function animate() {
        ctx.clearRect(0, 0, width, height);
        particles.forEach(p => {
            p.update();
            p.draw();
        });
        requestAnimationFrame(animate);
    }

    // 初期起動
    window.addEventListener('resize', () => {
        resize();
        updateText();
    });
    
    resize();
    for (let i = 0; i < particleCount; i++) {
        particles.push(new Particle());
    }
    
    animate();
    setInterval(updateText, 4000); // 4秒ごとに切り替え
    setTimeout(updateText, 500); // 初回実行
})();

カスタムCSS