ツンデレ授業「ダイヤモンドダストの夜」

WEBアプリは下記をクリック!

https://invisiblelagoon.com/lp/did/

👩‍🏫 先生: 今日は「ダイヤモンドダストの夜」のコード作成について説明してあげるわよ。コードの中身なんて、正直あんたにはあまり関係ないかもしれないけど、ちゃんと理解しておかないと後で困るんだからね!

👦 生徒: え、先生、コードの細かい説明は必要ないっす。とにかく動けばOKってことで、

ダイヤモンドダストをテーマに歌詞作成して

歌詞をテーマに画像生成して

歌詞と画像をテーマにあっと驚く最高クオリティのインタラクティブ性の強いjs htmlアニメーション作成

要はどんどん生成してくださいってAIに指示してたんすよね。

👩‍🏫 先生: そ、そんなに簡単に済ませるの?まったく、ツンデレだけど手抜きは許さないんだから!まずは、背景に設定したグラデーションやキャンバスのサイズ調整、ウィンドウリサイズに対応する部分を作ってるの。ここでちゃんとウィンドウの幅と高さを更新しておかないと、表示が乱れるでしょ?

👦 生徒: んー、なるほど。とにかくキャンバスが動くのは見たいです。詳しい説明はまた今度でいいです。

👩‍🏫 先生: ふん、あなたのために一つ一つ説明してあげるんだから感謝しなさい!次に、ダイヤモンドダストの粒子を管理するために Particle クラスを定義して、各粒子にランダムな動きや輝きを与えてるの。マウス操作で粒子が反発するのも、クリックした時にバーストエフェクトを生み出すための仕掛けなのよ。コードの一行一行に意味があるの、分かってる?

👦 生徒: まあ、実際に動くならそれでいいんすよ。あ、でも、歌詞の見た目よくするためにフォントサイズの変更はあったっすよね?最初は2emだったのを2/3にして、さらに80%に縮小したとか。

👩‍🏫 先生: そうよ!あなたのために、歌詞表示用のテキストのフォントサイズも調整してあるの。まず2emから1.33emに、そこからさらに80%にして約1.06emになったわ。細かい数値が気になるならメモしておきなさい、後で必要になるかもしれないからね!

👦 生徒: いや、そんな細かいのは俺には関係ないっす。コードが動いて、歌詞が表示されればそれで満足です。


Q&Aコーナー

Q1: このコードはどのようにしてインタラクティブなアニメーションを実現していますか?
A1: HTML5のCanvasとJavaScriptを利用し、requestAnimationFrame を用いて各フレームで粒子の位置を更新・描画することで、動的なアニメーションが実現されています。マウス操作やクリックイベントで粒子の挙動が変化するため、ユーザーとのインタラクションが生まれます。

Q2: 歌詞表示部分の改行はどのように行われていますか?
A2: 歌詞のテキスト中に含まれる半角・全角スペースを正規表現で検出し、<br> タグに置換することで、必ず改行して表示するようにしています。


👩‍🏫 先生: コードの中にある各機能、例えばマウス操作で粒子が反発する仕組みや、クリック時にバーストエフェクトが発生する部分も、全部ちゃんと作り込んであるの。理解しようとする姿勢があれば、私も教える気になるわよ。

👦 生徒: うーん、正直俺は見た目が動けば十分だから、細かいことはどうでもいいっす。とにかくこのコードを動かすことができればOKです!

👩‍🏫 先生: そ、そんなに適当な態度をとるなっての!でも…まぁ、動けばいいって言うなら、コードはちゃんと動くように設計されてるの。背景のグラデーション、キャンバスのリサイズ、そして歌詞のテキストアニメーションなど、どれも一見シンプルだけど、実は工夫が詰まってるのよ。

👦 生徒: なるほど、細かい仕組みはわかりませんが、実際に見たらキレイなアニメーションが動いてるんすね。

👩‍🏫 先生: その通り!このコードは、初心者でも手を加えやすいようにコメントも充実させてあるの。だから、あなたみたいにコードの中身に興味がない連中でも、動作確認だけなら十分楽しめるはず。…まあ、私がこんなに丁寧に教えてあげるんだから、感謝しなさいよね!


FAQコーナー

Q: コードが動かない場合の対処方法は?
A: ブラウザのコンソールにエラーメッセージが表示されるので、まずはエラー内容を確認してください。Canvasの設定や、イベントリスナーの登録部分など、細かいミスが原因の場合が多いです。また、最新のブラウザを使用することを推奨します。

Q: 粒子の数や速度を変更するにはどうすれば良いですか?
A: JavaScript内の maxParticlesParticle クラス内のプロパティを調整することで、粒子の数や動作速度をカスタマイズ可能です。自分好みにアレンジしてみてください。

Q: 歌詞のテキストを変更したいのですが、どこを編集すれば良いですか?
A: コード内の lyricsLines 配列に記述されている各文字列を編集することで、表示される歌詞を変更できます。改行の処理は正規表現で自動的に行われるため、スペースの挿入もそのままで問題ありません。


👩‍🏫 先生: どう、これでコードの作成過程が少しは理解できたかしら?あなたみたいな初心者でも、ちゃんと動けばそれでいいって思ってるなら、後は動作を楽しんでちょうだい。

👦 生徒: ありがとうございます、先生。正直、細かい説明はあまり理解できませんが、動くコードを見ると感動しますね。

👩‍🏫 先生: べ、別にあなたのために説明してあげたんだから、感謝しなさいよ!…まあ、次回も分からないことがあれば、また私が教えてあげるから覚悟しておきなさいね!

👦 生徒: はい、先生。またよろしくお願いします!

WEBアプリは下記をクリック!

https://invisiblelagoon.com/lp/did/
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>ダイヤモンドダストの夜</title>
  <style>
    /* 全画面表示と背景 */
    body {
      margin: 0;
      overflow: hidden;
      background: radial-gradient(ellipse at bottom, #1B2735 0%, #090A0F 100%);
    }
    canvas {
      display: block;
    }
    /* 歌詞テキストのスタイル(フォントサイズを前回の約80%に調整) */
    #lyrics {
      position: absolute;
      top: 50%;
      left: 50%;
      transform: translate(-50%, -50%);
      color: rgba(255,255,255,0.8);
      font-family: 'Georgia', serif;
      font-size: 1.06em; /* 1.33em の80%(約1.06em) */
      text-align: center;
      pointer-events: none;
      white-space: pre-wrap;
      transition: opacity 1s;
    }
  </style>
</head>
<body>
  <!-- 描画用のキャンバス -->
  <canvas id="canvas"></canvas>
  <!-- 歌詞表示用の要素 -->
  <div id="lyrics"></div>
  
  <script>
    /********** キャンバスのセットアップ **********/
    const canvas = document.getElementById('canvas');
    const ctx = canvas.getContext('2d');
    let W = canvas.width = window.innerWidth;
    let H = canvas.height = window.innerHeight;
    
    // ウィンドウリサイズ時にキャンバスサイズを調整
    window.addEventListener('resize', function() {
      W = canvas.width = window.innerWidth;
      H = canvas.height = window.innerHeight;
    });
    
    /********** マウスインタラクション用 **********/
    let mouseX = -1000, mouseY = -1000;
    canvas.addEventListener('mousemove', function(e) {
      const rect = canvas.getBoundingClientRect();
      mouseX = e.clientX - rect.left;
      mouseY = e.clientY - rect.top;
    });
    canvas.addEventListener('mouseleave', function(){
      mouseX = -1000;
      mouseY = -1000;
    });
    
    /********** Particle クラス:ダイヤモンドダストの粒子 **********/
    class Particle {
      constructor(x, y, isBurst = false) {
        this.x = x;
        this.y = y;
        this.radius = Math.random() * 1.5 + 0.5;
        // 通常の粒子はゆったりと降下
        this.speedY = Math.random() * 0.7 + 0.5;
        this.speedX = (Math.random() - 0.5) * 0.5;
        this.alpha = Math.random() * 0.5 + 0.5;
        this.isBurst = isBurst;
        if(isBurst) {
          // クリック時の爆発エフェクト用にランダムな方向と速さを設定
          const angle = Math.random() * 2 * Math.PI;
          const speed = Math.random() * 3 + 1;
          this.speedX = Math.cos(angle) * speed;
          this.speedY = Math.sin(angle) * speed;
          this.life = 100; // フレーム数で減少
        }
      }
      update() {
        if(this.isBurst) {
          this.x += this.speedX;
          this.y += this.speedY;
          this.life--;
          this.alpha = this.life / 100;
        } else {
          // マウスが近い場合、軽く反発する効果
          const dx = this.x - mouseX;
          const dy = this.y - mouseY;
          const dist = Math.sqrt(dx * dx + dy * dy);
          if(dist < 80) {
            const angle = Math.atan2(dy, dx);
            this.x += Math.cos(angle) * 2;
            this.y += Math.sin(angle) * 2;
          }
          this.x += this.speedX;
          this.y += this.speedY;
          // 下まで到達したら上部にリサイクル
          if(this.y > H) {
            this.y = 0;
            this.x = Math.random() * W;
          }
          // 横方向のラップアラウンド
          if(this.x > W) this.x = 0;
          if(this.x < 0) this.x = W;
        }
      }
      draw(ctx) {
        ctx.save();
        ctx.globalAlpha = this.alpha;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        // 中心から外側に向けたグラデーションで輝きを表現
        const gradient = ctx.createRadialGradient(this.x, this.y, 0, this.x, this.y, this.radius);
        gradient.addColorStop(0, 'rgba(255,255,255,1)');
        gradient.addColorStop(1, 'rgba(200,200,255,0)');
        ctx.fillStyle = gradient;
        ctx.fill();
        ctx.restore();
      }
    }
    
    /********** 粒子の生成 **********/
    let particles = [];
    const maxParticles = 300;
    for(let i = 0; i < maxParticles; i++){
      particles.push(new Particle(Math.random() * W, Math.random() * H));
    }
    
    /********** アニメーションループ **********/
    function animate() {
      ctx.clearRect(0, 0, W, H);
      particles.forEach((p, index) => {
        p.update();
        p.draw(ctx);
        // 爆発エフェクトの粒子は寿命が尽きたら配列から削除
        if(p.isBurst && p.life <= 0){
          particles.splice(index, 1);
        }
      });
      requestAnimationFrame(animate);
    }
    animate();
    
    /********** クリックでバーストエフェクトを追加 **********/
    canvas.addEventListener('click', function(e) {
      const rect = canvas.getBoundingClientRect();
      const clickX = e.clientX - rect.left;
      const clickY = e.clientY - rect.top;
      for(let i = 0; i < 30; i++){
        particles.push(new Particle(clickX, clickY, true));
      }
    });
    
    /********** 歌詞テキストのアニメーション **********/
    const lyricsDiv = document.getElementById('lyrics');
    const lyricsLines = [
      "凍てつく空にひそやかに",
      "光の粒が舞い降りる",
      "透明な奇跡 冬の息吹",
      "君への想い 煌めく記憶",
      "ダイヤモンドダスト 夜空に散らばる",
      "一瞬の光 心を照らす",
      "儚くも美しい 奇跡の軌跡",
      "永遠を夢見て 僕らは歩む"
    ];
    let currentLine = 0;
    
    function showNextLyric() {
      lyricsDiv.style.opacity = 0;
      setTimeout(() => {
        // 空白(半角・全角)があれば必ず改行して表示する
        const formatted = lyricsLines[currentLine].replace(/[  ]/g, "<br>");
        lyricsDiv.innerHTML = formatted;
        lyricsDiv.style.opacity = 1;
        currentLine = (currentLine + 1) % lyricsLines.length;
      }, 1000);
    }
    // 初期表示
    lyricsDiv.innerHTML = lyricsLines[currentLine].replace(/[  ]/g, "<br>");
    currentLine++;
    // 6秒ごとに次の歌詞へ
    setInterval(showNextLyric, 6000);
    
  </script>
</body>
</html>
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

コメント

コメントする

目次