杨帆 发表于 2025-6-24 19:42

拥有的回忆 - 学习马老师帖《三亩地·寻》

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>《拥有的回忆》-影子</title>
</head>
<body>
<style>
#tz { margin: 30px 0; left: calc(50% - 81px); transform: translateX(-50%);width: clamp(600px, 90vw, 1400px); height: auto;aspect-ratio: 16/9; background: url('https://638183.freep.cn/638183/t24/4/self0.jpg') no-repeat center/cover; box-shadow: 2px 2px 8px #000; display: grid; place-items: center; z-index: 1;user-select: none;position: relative; overflow: hidden;}
#tz>canvas { position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: block; }
#pa { width: 45%; height: 45%; top: -35%; left: 38%; cursor: pointer; position: absolute; overflow: hidden; z-index: 1; }
#pa:hover { transform: scale(1.05); filter: drop-shadow(0 0 80px Gold); }
#vid { position: absolute; width: 100%; height: 100%; object-fit: cover; opacity: .2; mask: linear-gradient(to bottom, red 30%,transparent 80%,transparent); -webkit-mask: linear-gradient(to bottom, red 30%,transparent 80%,transparent); }
#btnFs { top: 5%; left: 3%; color: #eee; }
#player { position: absolute; left: -1000px; }
.lrc { z-index: 1; position: absolute; top: 45%; left: 60%; width: 740px; height: 350px; overflow: hidden; }
.lrc #ul { width: 100%; padding: 0; list-style: none; transition: 0.3s all ease; margin: 0; }
.lrc #ul li { color: #fff; font: normal 28px 'YouYuan', sans-serif; transition: .3s all ease; list-style-type: none; text-align: center; display: block; padding: 0 10px; height: 50px; line-height: 50px; margin: 0 auto; cursor: pointer; }
.lrc #ul li.active { transform: scale(1.2); color: #FFD700; font-weight: 650; text-shadow: 0 0 10px #EE1111; }
#dt { position: absolute; width: 100%; height: 100%; top: 0%; left: 0%; mix-blend-mode: screen; z-index: -1; }
#dt img { width: 100%; height: 100%; }
</style>
    <div id="tz">
      <div id="pa"></div>
      <audio id="aud" src="https://cccimg.com/view.php/27830924892abb12eec28b068f9b6599.mp3" autoplay loop></audio>
      <video id="vid" src="https://cccimg.com/view.php/1f070b939d57467dcc4bd6717d6421eb.mp4"
            autoplay loop muted></video>
      <div id="player"></div>
      <div class="lrc">
            <ul id="ul"></ul>
      </div>
      <div id="dt">
            <img src="https://pic1.imgdb.cn/item/67564aedd0e0a243d4e015f5.gif" id="Img" style="mix-blend-mode: screen"
                alt=" " />
      </div>
    </div>
<script type="module">
    import { THREE, scene, camera, renderer, clock, basic3, click3 } from 'https://638183.freep.cn/638183/3dev/3/3basic.js';
    import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';

    FS(pa, player);
    basic3(pa);

    const group = new THREE.Group(), sGroup = new THREE.Group;
    const tt = 40, poses = [ , [-2, 0, 0], , , ];
    // 圆环
    for (let i = 0; i < tt; i ++) {
      const ellipse = drawEllipse(1.2, 0.8);
      ellipse.rotateY(THREE.MathUtils.degToRad(360 / tt * i));
      group.add(ellipse);
    }
    // 球
    poses.forEach( (pos, key) => {
      const texture = new THREE.TextureLoader().load('https://638183.freep.cn/638183/small/texture/wdrop.jpg');
      texture.colorSpace = THREE.SRGBColorSpace;
      const mesh = new THREE.Mesh(
            new THREE.SphereGeometry(0.25),
            new THREE.MeshBasicMaterial({ map: texture })
      );
      mesh.position.set(pos, pos, pos);
      if (key === 0) mesh.scale.set(2, 2, 2);
      sGroup.add(mesh);
    });

    sGroup.rotateX(-0.15);
    group.add(sGroup);

    scene.add(group);
    animate();

    const audio = document.getElementById('aud');
      const video = document.getElementById('vid');
      const Img = document.getElementById('Img');

      pa.onclick = (e) => {
            if (click3(group, e)) {
                if (audio.paused) {
                  audio.play();
                  video.play();
                  clock.start();
                  Img.style.opacity = '0.9';
                } else {
                  audio.pause();
                  video.pause();
                  clock.stop();
                  Img.style.opacity = '0';
                }
            }
      };

    pa.onmousemove = (e) => {
      pa.title = click3(group, e) ? '播放/暂停' : '';
      pa.style.cursor = click3(group, e) ? 'pointer' : 'default';
    }

    // 绘制圆环函数
    function drawEllipse(r1, r2) {
      const curve = new THREE.EllipseCurve(0, 0, r1, r2, 0, 2 * Math.PI, false, 0);
      const arc = new THREE.Line(
            new THREE.BufferGeometry().setFromPoints( curve.getPoints(50) ),
            new THREE.LineDashedMaterial( { color: 0xffffff * Math.random(), dashSize: 0.02, gapSize: 0.02 } )
      );
      arc.computeLineDistances(); // 显示虚线必须计算线距
      return arc;
    }

    function animate() {
      requestAnimationFrame(animate);
      const delta = clock.getDelta();
      group.rotation.y += delta / 5;
      sGroup.children.forEach(child => child.rotation.y += delta);
      renderer.render(scene, camera);
    }   
</script> <script>
      let lrc = `
拥有的回忆 - 影子
词:谢世超
曲:谢世超
编曲:张浩
录混:鲁晓锋
和声:雪无影
统筹:张文兵
监制:黄第宏
宣发:马嘉璐
制作人:梁乃文
出品人:李彦桦
发行公司:涌纳文化

那个熟悉的街头
想起曾经的拥有
你的离去为何让我一个人走
你走了以后谁来问候
痛苦的我多想把你挽留
那个熟悉的名字
永远不会忘记你
我会一直把你藏在我的心底
忧伤的旋律把你唱起
以后以后慢慢变成回忆
为何让我把你苦苦厮守
你说过爱我会到白头
一日如三秋我心里好难受
你的身影一直伴我在左右
为何让我把你苦苦厮守
那么狠心丢下独自漂流
花开花落不见你回头
孤独的我不知还要等多久
那个熟悉的名字
永远不会忘记你
我会一直把你藏在我的心底
忧伤的旋律把你唱起
以后以后慢慢变成回忆
为何让我把你苦苦厮守
你说过爱我会到白头
一日如三秋我心里好难受
你的身影一直伴我在左右
为何让我把你苦苦厮守
那么狠心丢下独自漂流
花开花落不见你回头
孤独的我不知还要等多久
孤独的我不知还要等多久

`;
      let lrcArr = lrc.split('\n');
      let result = [];
      var audio = document.querySelector("#aud");
      var ul = document.querySelector("#ul");
      var container = document.querySelector(".lrc");

      for (let i = 0; i < lrcArr.length; i++) {
            var lrcData = lrcArr.split(']');
            if (lrcData.length < 2) continue;
            var lrcTime = lrcData.substring(1);
            var obj = {
                time: parseTime(lrcTime),
                word: lrcData.trim()
            }
            result.push(obj);
      }

      function parseTime(lrcTime) {
            let lrcTimeArr = lrcTime.split(":");
            return +lrcTimeArr * 60 + parseFloat(lrcTimeArr);
      }

      function getIndex() {
            let time = audio.currentTime;
            for (let i = 0; i < result.length; i++) {
                if (result.time > time) {
                  return i - 1;
                }
            }
            return result.length - 1;
      }

      function createElements() {
            let fragment = document.createDocumentFragment();

            for (let i = 0; i < result.length; i++) {
                let li = document.createElement("li");
                li.innerText = result.word;

                li.addEventListener("click", function () {
                  audio.currentTime = result.time;
                  setOffset();
                });

                fragment.appendChild(li);
            }

            ul.appendChild(fragment);
      }

      createElements();
      let containerHeight = container.clientHeight;
      let liHeight = ul.children?.clientHeight || 50;
      let minOffset = 0;
      let maxOffset = ul.clientHeight - containerHeight;

      function setOffset() {
            const index = getIndex();
            if (index < 0) return;

            const liHeight = ul.children?.clientHeight || 50;
            let offset = liHeight * index - containerHeight / 2 + liHeight / 2;

            offset = Math.max(minOffset, Math.min(offset, maxOffset));

            ul.style.transform = `translateY(${-offset}px)`;

            ul.querySelectorAll('.active').forEach(li => li.classList.remove('active'));
            if (index < ul.children.length) {
                ul.children.classList.add('active');
            }
      }

      audio.addEventListener("timeupdate", setOffset);
    </script><script type="module">
      import * as THREE from 'https://638183.freep.cn/638183/3dev/build/three.module.min.js';
      import { FS } from 'https://638183.freep.cn/638183/web/ku/FS.js';

      const scene = new THREE.Scene();
      const camera = new THREE.PerspectiveCamera(45, tz.offsetWidth/tz.offsetHeight, 0.1, 1000);
      camera.position.z = 10;
      const renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true });
      renderer.setClearAlpha(0.0);
      renderer.setSize(tz.offsetWidth, tz.offsetHeight);
      const clock = new THREE.Clock();
      tz.appendChild(renderer.domElement);

      const texture = new THREE.TextureLoader().load('https://638183.freep.cn/638183/small/rose.jpg');

      const mesh = new THREE.Mesh(
                new THREE.SphereGeometry(1, 64, 64),
                new THREE.MeshBasicMaterial({ map: texture })
      );
      mesh.position.set(-1000, -2, 0);
      scene.add(mesh);

      const particleContainer = new THREE.Object3D(); // 粒子容器
      const total = 1000;

      for (let i = 0; i < total; i++) {
                const faces = Math.floor(Math.random() * 3 + 1);
                const geometry = new THREE.SphereGeometry(0.4);
                const material = new THREE.MeshBasicMaterial({
                        color: new THREE.Color(Math.random(), Math.random(), Math.random()),
                        map: texture
                });
                const particle = new THREE.Mesh(geometry, material);
                particle.position.set(
                        Math.random() * 100 - 50,
                        Math.random() * 100 - 50,
                        Math.random() * 300 - 150
                );
                particleContainer.add(particle);
      }
      scene.add(particleContainer);

      const isMess = (event) => {
                const raycaster = new THREE.Raycaster();
                const pointer = new THREE.Vector2();
                let intersects = [];
                pointer.x = (event.offsetX / tz.offsetWidth) * 2 - 1;
                pointer.y = -(event.offsetY / tz.offsetHeight) * 2 + 1;
                raycaster.setFromCamera(pointer, camera);
                intersects = raycaster.intersectObjects(, true);
                return intersects.length > 0;
      }   

      const animate = () => {
                requestAnimationFrame(animate);
                const delta = clock.getDelta();
                mesh.rotation.x += delta;
                mesh.rotation.y -= delta;
                particleContainer.rotation.x += delta / 5;
                particleContainer.rotation.y -= delta / 5;
                renderer.render(scene, camera);
      };

      window.onresize = () => {
                camera.aspect = tz.offsetWidth / tz.offsetHeight;
                camera.updateProjectionMatrix();
                renderer.setSize(tz.offsetWidth, tz.offsetHeight);
      };

      aud.onplaying = aud.onpause = () => aud.paused ? clock.stop() : clock.start();

      animate();
      FS(tz, player);
</script>
</body>
</html>


红影 发表于 2025-6-24 21:03

这个把球体播放器放到旁边也很不错呢。淡淡的视频也有着回忆感。
这个制作真漂亮{:4_187:}

红影 发表于 2025-6-24 21:03

这里面内容真不少。
欣赏杨帆好帖{:4_199:}

杨帆 发表于 2025-6-24 21:25

红影 发表于 2025-6-24 21:03
这里面内容真不少。
欣赏杨帆好帖

谢谢影子鼓励,这是影子的又一首广为流传的歌呦{:4_173:}

红影 发表于 2025-6-24 22:41

杨帆 发表于 2025-6-24 21:25
谢谢影子鼓励,这是影子的又一首广为流传的歌呦

嗯嗯,很好听呢{:4_187:}

梦江南 发表于 2025-6-25 08:57

就知道,您会鼓捣。真的又快又漂亮!真赞!{:4_187:}

梦江南 发表于 2025-6-25 08:59

图图很有意境,歌曲有点伤感。整体效果特棒!{:4_199:}。

杨帆 发表于 2025-6-25 11:19

梦江南 发表于 2025-6-25 08:59
图图很有意境,歌曲有点伤感。整体效果特棒!。

问好江南,谢谢鼓励,祝开心{:4_204:}
页: [1]
查看完整版本: 拥有的回忆 - 学习马老师帖《三亩地·寻》