見出し画像

連続投稿100日!感謝の気持ちを込めて!ちょっとした矛盾の贈り物!

先ほどの投稿で気付いたのですが、連続投稿が100日に到達していました!

アカウント登録直後からログインしたことがないまま眠っていたnote。

日記、あるいは作業記録のような気持ちで、ちょっと書いてみようかなと思ったとき、そういえばnoteってアカウント作ってあるけど、使えるんじゃないかと思い出し、書き始めました。

すぐに、あれ?これは読む方が楽しいよね、などと思ったり。
仲良くしてくださる方ができて来ると、いやいや、読んで書くから楽しいんだと思い直したり。

たった100日。されど100日。
出会いもあり別れもあり。

とても濃密な時間を過ごさせて頂いています。

特に、元々苦手意識の強い書くことを継続というのは、応援し支えてくださる皆様、スキをくださる皆様、読んでくださる皆様がいなければ絶対にできないことです。

こんなことやったら面白いかも?
あんなこと書いたら少しは役に立つかも?

なんてやっているうちに、気づいたら100日が過ぎていました。

全ての皆様に、ここまで支えてくださり、本当にありがとうございます!
今後とも引き続き、よろしくお願いします!


感謝の気持ちを込めて何か作ろう、などと思ったのですが、感謝とは全く接点のない代物を作ってしまいました💦

ですが、実はこんなものが出来上がってしまったことにはほんの少しの意図があり。

あれやこれやと記事を書いている中、何か、ほんの少しでも誰かの役に立つようなことを書けないだろうか?という気持ちが少しずつ強くなりました。

きっと多くの方が思うことなんじゃないかと思います。

そんな中、プログラミングに関する基本的な知識や発想での土台を整えようと模索している方々が思いの外多いことに気付きました。

AIが大部分を容易に作ってくれるからこそ、そのような土台があるのかどうかは、より大きなものになっていると感じています。

それなら、知識と経験をAIに食わせていくようなこととか、そこから生み出される何か、さらには知識と経験そのものも、そういった方々の糧になるのかもしれません。

そのように考えたとき、AIを使って古い知識やノウハウの再利用をし遊んでみたものを、ソースコードを含めて公開する、なんてことも、もしかしたら感謝の気持ちをあらわすということに繋がるのではないか?

プログラミングなんて関係ない、という方にも、AIを使わないでもこんなことができるという驚きや楽しさをお届けできるのではないか?

それを簡単に、AIを使って作ってもらうなんて一見矛盾するようなことをお見せすると「明言しながら」やってみるのも楽しいのではないか?

これを視覚的に、直感的に表現できるものはないか?

などと考えた結果、何か「動画(アニメーション)」でも作ってみたらいいんじゃないか、などということに辿り着きました。


Geminiさんに作ってもらった、AIではない動画!
録画したものがこちら。
文字が出るでもなく、単にふよふよと登っていくくらげさんです!

以下はこの動画そのものです。

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Deep Sea Fluid Animation</title>
    <style>
        body, html {
            margin: 0;
            padding: 0;
            width: 100%;
            height: 100%;
            overflow: hidden;
            background-color: #010512;
        }
        canvas {
            display: block;
            width: 100vw;
            height: 100vh;
        }
    </style>
</head>
<body>

<canvas id="fluidCanvas"></canvas>

<script>
const canvas = document.getElementById('fluidCanvas');
const ctx = canvas.getContext('2d');

function resize() {
    canvas.width = window.innerWidth * window.devicePixelRatio;
    canvas.height = window.innerHeight * window.devicePixelRatio;
    ctx.scale(window.devicePixelRatio, window.devicePixelRatio);
}
window.addEventListener('resize', resize);
resize();

// --- 生物(流体型)クラスの定義 ---
class JellyCreature {
    constructor(x, y, scale) {
        this.x = x;
        this.y = y;
        this.scale = scale;
        this.baseSpeedY = -(Math.random() * 0.4 + 0.3); // 上昇速度
        this.time = Math.random() * 100;
        this.pulseSpeed = Math.random() * 0.02 + 0.02; // 伸縮のテンポ
        
        // 触手の本数とそれぞれの固有の波のズレ
        this.tentacleCount = 6;
        this.tentacleOffsets = [];
        for(let i=0; i<this.tentacleCount; i++) {
            this.tentacleOffsets.push(Math.random() * Math.PI);
        }
    }

    update() {
        this.time += this.pulseSpeed;
        
        // 傘の収縮に合わせて推進力を変化させる(生物らしい移動)
        const pulseFactor = Math.max(0, Math.sin(this.time)); 
        this.y += this.baseSpeedY * (1 + pulseFactor * 1.5);
        this.x += Math.sin(this.time * 0.5) * 0.15;

        // 画面上部に消えたら下からリスポーン
        if (this.y < -120 * this.scale) {
            this.y = window.innerHeight + 120 * this.scale;
            this.x = Math.random() * window.innerWidth;
        }
    }

    draw() {
        this.update();

        // パルス運動による伸縮変形量の計算
        const capWobble = Math.sin(this.time) * 12;   // 横の広がり
        const capStretch = Math.cos(this.time) * 8;   // 縦の縮み

        ctx.save();
        ctx.translate(this.x, this.y);
        ctx.scale(this.scale, this.scale);
        
        // 幻想的な発光(グロー)エフェクト
        ctx.shadowBlur = 25;
        ctx.shadowColor = '#00a2ff';

        // ―― 1. 触手(一本ずつ数式で滑らかにしならせる) ――
        for (let i = 0; i < this.tentacleCount; i++) {
            // 触手の付け根の座標
            const startX = -40 + (i * 16);
            const startY = 20 + capStretch;
            
            ctx.beginPath();
            ctx.moveTo(startX, startY);
            
            let currentX = startX;
            let currentY = startY;

            // 5つの関節(セグメント)に分けて波を先端へ伝える
            for (let j = 1; j <= 5; j++) {
                const nextY = startY + (j * 25);
                // 上から下に向かって波のタイムラグを作ることで「しなり」を生む
                const waveAngle = this.time * 2.2 - (j * 0.7) + this.tentacleOffsets[i];
                const nextX = startX + Math.sin(waveAngle) * (j * 4.5); // 先端ほど大きく揺れる
                
                // ベジエ曲線で滑らかに接続
                ctx.bezierCurveTo(
                    currentX, currentY + 12,
                    nextX, nextY - 12,
                    nextX, nextY
                );
                
                currentX = nextX;
                currentY = nextY;
            }
            
            // 外側から内側にかけて徐々に細く、透明にする
            ctx.strokeStyle = '#00d2ff';
            ctx.lineWidth = 2 * ((this.tentacleCount - i) / this.tentacleCount);
            ctx.globalAlpha = 0.3 + (Math.sin(this.time) * 0.2);
            ctx.stroke();
        }

        // ―― 2. 傘頭部(リアルタイム計算で伸縮するメインボディ) ――
        const topY = -40 + capStretch;
        const leftX = -60 - capWobble;
        const rightX = 60 + capWobble;
        const bottomY = 20 + capStretch;

        // グラデーションの作成
        const jellyGrad = ctx.createLinearGradient(0, topY, 0, bottomY + 20);
        jellyGrad.addColorStop(0, 'rgba(0, 240, 255, 0.7)');
        jellyGrad.addColorStop(0.5, 'rgba(0, 102, 255, 0.3)');
        jellyGrad.addColorStop(1, 'rgba(0, 17, 68, 0)');

        // 本体(塗りつぶし)
        ctx.beginPath();
        ctx.moveTo(leftX, bottomY);
        ctx.bezierCurveTo(leftX - 10, topY + 20, -40, topY, 0, topY);
        ctx.bezierCurveTo(40, topY, rightX + 10, topY + 20, rightX, bottomY);
        ctx.bezierCurveTo(30, bottomY - 8, -30, bottomY - 8, leftX, bottomY);
        ctx.closePath();
        ctx.fillStyle = jellyGrad;
        ctx.globalAlpha = 1.0;
        ctx.fill();

        // クッキリ輝く外郭のライン
        ctx.beginPath();
        ctx.moveTo(leftX, bottomY);
        ctx.bezierCurveTo(leftX - 10, topY + 20, -40, topY, 0, topY);
        ctx.bezierCurveTo(40, topY, rightX + 10, topY + 20, rightX, bottomY);
        ctx.strokeStyle = '#00f5ff';
        ctx.lineWidth = 2;
        ctx.stroke();

        ctx.restore();
    }
}

// --- 群れの生成 ---
const creatures = [];
for (let i = 0; i < 8; i++) {
    creatures.push(new JellyCreature(
        Math.random() * window.innerWidth,
        Math.random() * window.innerHeight,
        Math.random() * 0.5 + 0.4
    ));
}

// 浮遊する極小の光の胞子
const spores = [];
for (let i = 0; i < 40; i++) {
    spores.push({ 
        x: Math.random() * window.innerWidth, 
        y: Math.random() * window.innerHeight, 
        r: Math.random() * 1.5 + 0.5, 
        speed: Math.random() * 0.2 + 0.1, 
        t: Math.random() * 10 
    });
}

// --- メインアニメーションループ ---
function animate() {
    // 海の透明度と残像エフェクト
    ctx.fillStyle = 'rgba(1, 5, 18, 0.08)';
    ctx.fillRect(0, 0, window.innerWidth, window.innerHeight);

    // 1. 背景の胞子を描画
    for (let s of spores) {
        s.t += 0.02;
        s.y -= s.speed;
        s.x += Math.sin(s.t) * 0.1;
        
        ctx.beginPath();
        ctx.fillStyle = `rgba(0, 240, 255, ${0.2 + Math.abs(Math.sin(s.t)) * 0.4})`;
        ctx.arc(s.x, s.y, s.r, 0, Math.PI * 2);
        ctx.fill();

        if (s.y < -10) { 
            s.y = window.innerHeight + 10; 
            s.x = Math.random() * window.innerWidth; 
        }
    }

    // 2. 各生物の変形&描画の実行
    ctx.shadowBlur = 0; // 一度リセット
    for (let creature of creatures) {
        creature.draw();
    }

    requestAnimationFrame(animate);
}

// 起動
animate();
</script>

</body>
</html>

何でもどうぞ!答えられるものは全て答えます!

設置はお済みですか?図らずも人の庭でnote質問箱を試す!|へろん


メンバーシップ始めました!
まだ手探りですが、ご要望/無茶振り/質問、可能な限りお受けします!


有料記事、今回は問題提起と警告!

note生活1ヶ月の総括記事を書きました!大事な部分は全て無料公開中!
何を考え何をしてきたのか、500人記念のワンコインで公開します!


記事作成のお供に!お役立ちツール!

その他、こんなことやってみてます!


気に入ったらスキ、フォローよろしくお願いします!
note外から見にきてくださったかたも、もしよければハートマーク押して頂けたら励みになります😊

いいなと思ったら応援しよう!