项目展示

🔈也可通过博客顶部 菜单栏->歌单->近日最喜欢 进行访问~

值得一提的是,该页面当前展示的这首歌曲由SunoAi生成,名字叫《老头环》,小郭非常喜欢,已经无脑循环很久了😆
Ai生成的音乐是什么样子的呢,你是否好奇,这首《老头环》会让你失望吗,快来听听吧!

源代码

该页面部分使用了github开源项目WebGL-Fluid-Simulation

该项目致力于使用javascript模拟出任意种流体的动画

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="Cache-Control" content="no-cache" />

    <meta
      name="viewport"
      content="width=device-width, initial-scale=1.0, user-scalable=no"
    />
    <meta
      name="apple-mobile-web-app-status-bar-style"
      content="black-translucent"
    />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="mobile-web-app-capable" content="yes" />

    <link rel="apple-touch-icon" href="logo.png" />
    <link rel="icon" href="logo.png" />

    <title>近日最喜欢的音乐 | 郭同学的笔记本</title>
    <!-- 设置网站icon -->
    <link
      rel="icon"
      href="https://lovexl-oss.oss-cn-beijing.aliyuncs.com/bed/%E5%A4%B4%E5%83%8F%E5%8E%BB%E8%83%8C%E6%99%AF.png"
      type="image/x-icon"
    />

    <meta property="og:type" content="website" />
    <meta property="og:title" content="Webgl Fluid Simulation" />
    <meta
      property="og:description"
      content="A WebGL fluid simulation that works in mobile browsers."
    />

    <script type="text/javascript" src="dat.gui.min.js"></script>
    <style>
      /* 设置使用的字体为Comic Sans MS */
      body {
        /* 设置英文字体为Comic Sans MS */
        font-family: "Comic Sans MS", cursive, sans-serif;
        color: #ffffff;
        /* 文字抗锯齿 */
        -webkit-font-smoothing: antialiased;
      }

      /* 以下样式为互动背景样式 */
      @font-face {
        font-family: "iconfont";
        src: url("iconfont.ttf") format("truetype");
      }

      * {
        user-select: none;
      }

      html,
      body {
        overflow: hidden;
        background-color: #000;
      }

      body {
        margin: 0;
        position: fixed;
        width: 100%;
        height: 100%;
      }

      canvas {
        width: 100%;
        height: 100%;
      }

      .dg {
        opacity: 0.9;
      }

      .dg .property-name {
        overflow: visible;
      }

      .bigFont {
        font-size: 150%;
        color: #8c8c8c;
      }

      .cr.function.appBigFont {
        font-size: 150%;
        line-height: 27px;
        color: #a5f8d3;
        background-color: #023c40;
      }

      .cr.function.appBigFont .property-name {
        float: none;
      }

      .cr.function.appBigFont .icon {
        position: sticky;
        bottom: 27px;
      }

      .icon {
        font-family: "iconfont";
        font-size: 130%;
        float: right;
      }

      .twitter:before {
        content: "a";
      }

      .github:before {
        content: "b";
      }

      .app:before {
        content: "c";
      }

      .discord:before {
        content: "d";
      }

      .promo {
        display: none;
        /* display: table; */
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
        z-index: 1;
        overflow: auto;
        color: lightblue;
        background-color: rgba(0, 0, 0, 0.4);
        animation: promo-appear-animation 0.35s ease-out;
      }

      .promo-middle {
        display: table-cell;
        vertical-align: middle;
      }

      .promo-content {
        width: 80vw;
        height: 80vh;
        max-width: 80vh;
        max-height: 80vw;
        margin: auto;
        padding: 0;
        font-size: 2.8vmax;
        font-family: Futura, "Trebuchet MS", Arial, sans-serif;
        text-align: center;
        background-image: url("promo_back.png");
        background-position: center;
        background-repeat: no-repeat;
        background-size: cover;
        border-radius: 15px;
        box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2),
          0 6px 20px 0 rgba(0, 0, 0, 0.19);
      }

      .promo-header {
        height: 10%;
        padding: 2px 16px;
      }

      .promo-close {
        width: 10%;
        height: 100%;
        text-align: left;
        float: left;
        font-size: 1.3em;
        /* transition: 0.2s; */
      }

      .promo-close:hover {
        /* transform: scale(1.25); */
        cursor: pointer;
      }

      .promo-body {
        padding: 8px 16px 16px 16px;
        margin: auto;
      }

      .promo-body p {
        margin-top: 0;
        mix-blend-mode: color-dodge;
      }

      .link {
        width: 100%;
        display: inline-block;
      }

      .link img {
        width: 100%;
      }

      @keyframes promo-appear-animation {
        0% {
          transform: scale(2);
          opacity: 0;
        }
        100% {
          transform: scale(1);
          opacity: 1;
        }
      }

      /* 以下样式为自设样式 */
      .top {
        position: fixed;
        top: 25px;
        right: 0;
        z-index: 9999;
        font-size: 1.5rem;
        font-weight: 600;
        color: aliceblue;
        /* 背景反转色 */
        mix-blend-mode: difference;

        span {
          margin-left: 13px;
          margin-right: 13px;
          cursor: pointer;
        }

        a {
          /* 取消下划线 */
          text-decoration: none;
          margin-left: 13px;
          margin-right: 13px;
          cursor: pointer;
          color: aliceblue;
        }
      }

      .middle {
        position: fixed;
        top: 40%;
        left: 50%;
        transform: translate(-50%, -50%);
        color: aliceblue;
        /* 不影响下层元素的点击 */
        pointer-events: none;
        /* 文字不换行 */
        white-space: nowrap;
        /* 背景反转色 */
        mix-blend-mode: difference;

        .middle-one {
          font-size: 50px;
          font-weight: 800;
          margin-bottom: 32px;
        }

        .middle-two {
          font-size: 2rem;
          /* 居中 */
          text-align: center;
          /* 透明度设为0 */
          opacity: 0;
          /* 过渡效果 */
          transition: opacity 1s;
        }

        .middle-three {
          margin-top: 32px;
          /* 播放器居中 */
          display: flex;
          justify-content: center;
          /* 可选中 */
          pointer-events: auto;
          /* 透明度设为0 */
          opacity: 0;
          /* 过渡效果 */
          transition: opacity 2s;
        }

        .middle-four {
          margin-top: 10px;
          /* 居中 */
          text-align: center;
          /* 透明度设为0 */
          opacity: 0;
          /* 过渡效果 */
          transition: opacity 3s;
        }
      }

      .bottom {
        /* 置底居中 */
        position: fixed;
        bottom: 0;
        left: 50%;
        transform: translate(-50%, 0);
        z-index: 9999;
        font-size: 18px;
        margin-bottom: 15px;
        font-weight: 400;
        /* 背景反转色 */
        mix-blend-mode: difference;

        /* 不换行 */
        white-space: nowrap;
        /* 取消a标签下划线 */
        a {
          text-decoration: none;
          color: rgb(147, 147, 147);
          /* 设置字体为微软雅黑 */
          font-family: "Microsoft YaHei";
          font-weight: 600;
        }

        .huibiao {
          width: 20px;
          height: 20px;
          margin: 0 5px;
        }
      }

      @keyframes blink {
        0% {
          opacity: 1;
        }
        50% {
          opacity: 0.4;
        }
        100% {
          opacity: 1;
        }
      }

      /* 弹窗提示点击屏幕试试 */
      .tanchuang {
        position: fixed;
        top: 40%;
        left: 50%;
        transform: translate(-50%, -50%);
        z-index: 9999;
        font-size: 1.5rem;
        font-weight: 600;
        color: aliceblue;
        /* 背景反转色 */
        mix-blend-mode: difference;
        /* 所有动画1s */
        transition: all 1s;
      }
    </style>
    <script>
      window.ga =
        window.ga ||
        function () {
          (ga.q = ga.q || []).push(arguments);
        };
      ga.l = +new Date();
      ga("create", "UA-105392568-1", "auto");
      ga("send", "pageview");
    </script>
    <script async src="https://www.google-analytics.com/analytics.js"></script>
  </head>
  <body>
    <div class="tanchuang">Tip:点击屏幕试试~</div>
    <!-- 顶部状态栏 -->
    <div class="top">
      <span id="back" onclick="goBack()">Back</span>
      <a href="http://lovexl.top/" target="_blank">Home</a>
      <a href="http://lovexl.top/about" target="_blank">About</a>
      <a href="http://lovexl.top/music">MoreMusci..</a>
    </div>
    <!-- 可互动背景 -->
    <canvas></canvas>
    <!-- 中间文字部分 -->
    <div class="middle">
      <div class="middle-one"><span id="typed"></span></div>
      <div class="middle-two">Recent-favorite music</div>
      <div class="middle-three">
        <!-- 播放一个音频,自动播放 -->
        <audio
          controls
          autoplay
          src="http://lovexl.top/upload/%E8%80%81%E5%A4%B4%E7%8E%AF-suno.mp3"
        ></audio>
      </div>
      <div class="middle-four">
        This song is generated by SunoAi and is deeply loved by Xiao Guo
      </div>
    </div>
    <!-- 底部备案信息 -->
    <div class="bottom">
      <span
        ><a href="https://beian.miit.gov.cn/" target="_blank"
          >晋ICP备2024031692号</a
        ></span
      >
      <img
        src="https://lovexl-oss.oss-cn-beijing.aliyuncs.com/bed/202404031851756.png"
        alt="公安徽标"
        class="huibiao"
      />
      <span
        ><a
          href="https://beian.gov.cn/portal/registerSystemInfo?recordcode=11010802000001"
          target="_blank"
          >晋公网安备4090202000509号</a
        ></span
      >
    </div>

    <!-- 默认内容 -->
    <div class="promo">
      <div class="promo-middle">
        <div class="promo-content">
          <div class="promo-header">
            <span class="promo-close">&times;</span>
          </div>
          <div class="promo-body">
            <p>Try Fluid Simulation app!</p>
            <div class="links-container">
              <a class="link" id="apple_link" target="_blank">
                <img
                  class="link-img"
                  alt="Download on the App Store"
                  src="app_badge.png"
                />
              </a>
              <a class="link" id="google_link" target="_blank">
                <img
                  class="link-img"
                  alt="Get it on Google Play"
                  src="gp_badge.png"
                />
              </a>
            </div>
          </div>
        </div>
      </div>
    </div>

    <script src="./script.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/typed.js@2.0.12"></script>
    <script>
      // 识别只能在电脑端访问,手机端访问提示不可访问并跳回首页
      if (
        navigator.userAgent.match(
          /Android|webOS|iPhone|iPod|BlackBerry|IEMobile|Opera Mini/i
        )
      ) {
        alert("手机端不可访问,请使用电脑端");
        window.location.href = "http://lovexl.top/";
      }

      // 打字机效果
      new Typed("#typed", {
        strings: ["BlogMusic ©️XiaoGuo"],
        contentType: "html", // 使用html作为内容类型,以支持解析HTML标签
        typeSpeed: 80, // 打字速度
        loop: false, // 是否循环
        showCursor: true, // 是否显示光标
        cursorChar: "|", // 光标字符
        onComplete: function (self) {
          // 打字完成后的回调
          self.cursor.remove(); // 移除光标
          // moddle-one开始闪烁blink
          document.querySelector(".middle-one").style.animation =
            "blink 3s infinite";
          // 显示middle-two,透明度渐变为1
          document.querySelector(".middle-two").style.opacity = 1;
          // 显示middle-three,透明度渐变为1
          document.querySelector(".middle-three").style.opacity = 1;
          // 显示middle-four,透明度渐变为1
          document.querySelector(".middle-four").style.opacity = 1;
          // tanchuang消失
          document.querySelector(".tanchuang").style.display = "none";
        },
      });

      const typed = new Typed("#typed", options);

      // 顶部状态栏back添加返回上一个网页
      function goBack() {
        window.history.back();
      }
    </script>
  </body>
</html>

script.js

仅为部分展示,文末提供完整下载

const canvas = document.getElementsByTagName('canvas')[0];
resizeCanvas();

let config = {
    SIM_RESOLUTION: 128,
    DYE_RESOLUTION: 1024,
    CAPTURE_RESOLUTION: 512,
    DENSITY_DISSIPATION: 1,
    VELOCITY_DISSIPATION: 0.2,
    PRESSURE: 0.8,
    PRESSURE_ITERATIONS: 20,
    CURL: 30,
    SPLAT_RADIUS: 0.25,
    SPLAT_FORCE: 6000,
    SHADING: true,
    COLORFUL: true,
    COLOR_UPDATE_SPEED: 10,
    PAUSED: false,
    BACK_COLOR: { r: 0, g: 0, b: 0 },
    TRANSPARENT: false,
    BLOOM: true,
    BLOOM_ITERATIONS: 8,
    BLOOM_RESOLUTION: 256,
    BLOOM_INTENSITY: 0.8,
    BLOOM_THRESHOLD: 0.6,
    BLOOM_SOFT_KNEE: 0.7,
    SUNRAYS: true,
    SUNRAYS_RESOLUTION: 196,
    SUNRAYS_WEIGHT: 1.0,
}

function pointerPrototype () {
    this.id = -1;
    this.texcoordX = 0;
    this.texcoordY = 0;
    this.prevTexcoordX = 0;
    this.prevTexcoordY = 0;
    this.deltaX = 0;
    this.deltaY = 0;
    this.down = false;
    this.moved = false;
    this.color = [30, 0, 300];
}

let pointers = [];
let splatStack = [];
pointers.push(new pointerPrototype());

const { gl, ext } = getWebGLContext(canvas);

if (isMobile()) {
    config.DYE_RESOLUTION = 512;
}
if (!ext.supportLinearFiltering) {
    config.DYE_RESOLUTION = 512;
    config.SHADING = false;
    config.BLOOM = false;
    config.SUNRAYS = false;
}

// startGUI();

function getWebGLContext (canvas) {
    const params = { alpha: true, depth: false, stencil: false, antialias: false, preserveDrawingBuffer: false };

    let gl = canvas.getContext('webgl2', params);
    const isWebGL2 = !!gl;
    if (!isWebGL2)
        gl = canvas.getContext('webgl', params) || canvas.getContext('experimental-webgl', params);

    let halfFloat;
    let supportLinearFiltering;
    if (isWebGL2) {
        gl.getExtension('EXT_color_buffer_float');
        supportLinearFiltering = gl.getExtension('OES_texture_float_linear');
    } else {
        halfFloat = gl.getExtension('OES_texture_half_float');
        supportLinearFiltering = gl.getExtension('OES_texture_half_float_linear');
    }

    gl.clearColor(0.0, 0.0, 0.0, 1.0);

    const halfFloatTexType = isWebGL2 ? gl.HALF_FLOAT : halfFloat.HALF_FLOAT_OES;
    let formatRGBA;
    let formatRG;
    let formatR;

    if (isWebGL2)
    {
        formatRGBA = getSupportedFormat(gl, gl.RGBA16F, gl.RGBA, halfFloatTexType);
        formatRG = getSupportedFormat(gl, gl.RG16F, gl.RG, halfFloatTexType);
        formatR = getSupportedFormat(gl, gl.R16F, gl.RED, halfFloatTexType);
    }
    else
    {
        formatRGBA = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
        formatRG = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
        formatR = getSupportedFormat(gl, gl.RGBA, gl.RGBA, halfFloatTexType);
    }

    ga('send', 'event', isWebGL2 ? 'webgl2' : 'webgl', formatRGBA == null ? 'not supported' : 'supported');

    return {
        gl,
        ext: {
            formatRGBA,
            formatRG,
            formatR,
            halfFloatTexType,
            supportLinearFiltering
        }
    };
}

dat.gui.min.js

仅为部分展示,文末提供完整下载

/**
 * dat-gui JavaScript Controller Library
 * http://code.google.com/p/dat-gui
 *
 * Copyright 2011 Data Arts Team, Google Creative Lab
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 */

{完整代码包下载, https://lovexl-oss.oss-cn-beijing.aliyuncs.com/bed/musci_home_page.zip, haofont hao-icon-book}