杨帆 发表于 2025-6-18 22:34

影子《最辛苦的是咱爸》- 学习马老师帖《ThreeJS 直管道》

本帖最后由 杨帆 于 2025-6-19 17:45 编辑 <br /><br /><style>
      #papa { --size: 15vw; margin: 30px 0; left: calc(50% - 110px); transform: translateX(-50%); width: clamp(600px, 90vw, 1400px); min-height: 80vh; aspect-ratio: 16/9; background: #333 url('') 0 0/100% 105%; box-shadow: 3px 3px 6px 6px gray; user-select: none; position: relative; overflow: hidden; z-index: 1; }
#dt { position: absolute; width: 100%; height: 100%; top: 0%; left: 0%; mix-blend-mode: screen; z-index: -1; }
#dt img { width: 100%; height: 100%; }
#bt { position: absolute; width: 100%; height: 100%; top: 0%; left: 0%; mix-blend-mode: screen; z-index: -1; }
#bt img { width: 100%; height: 100%; }
#papa>canvas { position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: block; }
#btnFs { left: 2%; bottom: 20px; color: #eee; }
#pa { position: absolute; top: 2%; left: 92%; width: 35%; height: auto; opacity: 0; cursor: pointer; overflow: hidden; z-index: 10; }
#papa:hover #pa { opacity: .8; color: #fff; font-size: 20px; font-family: 华文中宋; filter: drop-shadow(0 0 80px Gold); }
.lrc { position: absolute; top: 42%; left: 5%; width: 540px; height: 250px; overflow: hidden; }
.lrc #ul { width: 100%; padding: 0; list-style: none; transition: 0.3s all ease; margin: 0; }
.lrc #ul li { color: #fff; font-size: 35px; font-family: 华文行楷; transition: .3s all ease; list-style-type: none; text-align: center; display: block; padding: 0 10px; height: 50px; line-height: 50px; margin: 0 auto; text-shadow: 0 0 3px rgba(0, 0, 0, 0.7); }
.lrc #ul li.active { transform: scale(1.2); color: #FFD700; font-weight: 650; text-shadow: 0 0 10px #EE1111; }
#vid2 { width: 100%; height: 100%; position: absolute; top: 0%; left: 0%; object-fit: cover; z-index: -2; opacity: .98; pointer-events: none; }
#nhzer { color: #99ff00; position: absolute; left: 10%; top: 6%; font-size: 40px; font-family: 华文行楷; z-index: 1; animation: yd 20s linear infinite var(--state); filter: drop-shadow(#ffffff 1px 0 0) drop-shadow(#ffffff 0 1px 0) drop-shadow(#ffffff -1px 0 0) drop-shadow(#ffffff 0 -1px 0); }
#nhzer span { transition: color 0.3s ease, text-shadow 0.3s ease; text-shadow: 0 0 5px rgba(0, 255, 255, 0.5); }

@keyframes rot { to { transform: rotate(360deg); } }
@keyframes yd {
    0% { opacity: 0.8; left: 10%; }
    50% { opacity: 1; left: 60%; }
    100% { opacity: 0.8; left: 10%; }
}
    </style>
    <div id="papa">
      <div id="nhzer"></div>
      <div id="dt"><img src="https://pic1.imgdb.cn/item/67564aedd0e0a243d4e015f5.gif" id="Img" style="mix-blend-mode: screen"
                alt=" " /></div>
      <div id="bt"><img src="https://pic1.imgdb.cn/item/684b6ce058cb8da5c848da8b.gif" id="IMG"
                style="mix-blend-mode: screen" alt=" " /></div>
      <video id="vid2" src="https://cccimg.com/view.php/c5ccfecbbe8ed24c5469ebb96883573c.mp4" loop muted autoplay="">
      </video>
      <div id="pa" title="播放/暂停">播放/暂停</div>
      <div id="dhgc" class="lrc"><ul id="ul"></ul></div>
    </div>
    <audio id="audio" src="https://cccimg.com/view.php/ee2cec2853c8aa3f0f987e40c793673b.mp3" loop autoplay></audio>

    <script type="module">
      import * as THREE from 'https://638183.freep.cn/638183/3dev/build/three.module.min.js';

      const papa = document.getElementById('papa');
      const width = papa.offsetWidth;
      const height = papa.offsetHeight;

      const scene = new THREE.Scene();
      const clock = new THREE.Clock(false);
      const camera = new THREE.PerspectiveCamera(75, width / height, 0.1, 1000);
      camera.position.z = 5;

      const renderer = new THREE.WebGLRenderer({ alpha: true });
      renderer.setSize(width, height);
      papa.appendChild(renderer.domElement);

      // 直管道
      const path = new THREE.LineCurve3(new THREE.Vector3(-0.35, 0, 0), new THREE.Vector3(0.35, 0, 0));
      const geometry = new THREE.TubeGeometry(path, 36, 1.2, 6, false);
      const material = new THREE.MeshNormalMaterial({ side: THREE.DoubleSide });
      const mesh = new THREE.Mesh(geometry, material);
      mesh.rotateZ(Math.PI / 2.2);
      mesh.rotateY(Math.PI / 1.01);
      mesh.position.set(0, 1.3 ,0);

      scene.add(mesh);

      // 动画
      const animate = () => {
            if (clock.running) {
                requestAnimationFrame(animate);
                const delta = clock.getDelta();
                mesh.rotation.y += delta;
                renderer.render(scene, camera);
            }
      };

      window.onresize = () => {
            const width = papa.offsetWidth;
            const height = papa.offsetHeight;
            camera.aspect = width / height;
            camera.updateProjectionMatrix();
            renderer.setSize(width, height);
      };

      const audio = document.getElementById('audio');
      const pa = document.getElementById('pa');

      pa.addEventListener('click', () => {
            if (audio.paused) {
                audio.play();
                clock.start();
                animate();
            } else {
                audio.pause();
                clock.stop();
            }
            const videos = document.querySelectorAll('video');
            const Img = document.getElementById('Img');
            const nhzer = document.getElementById('nhzer');
            const IMG = document.getElementById('IMG');

            if (audio.paused) {
                videos.forEach(v => v.pause());
                Img.style.opacity = '0';
                IMG.style.opacity = '0';
                nhzer.style.setProperty('--state', 'paused');
            } else {
                videos.forEach(v => v.play());
                Img.style.opacity = '0.9';
                IMG.style.opacity = '0.9';
                nhzer.style.setProperty('--state', 'running');
            }
      });

      audio.addEventListener('play', () => {
            clock.start();
            animate();
      });

      audio.addEventListener('pause', () => {
            clock.stop();
      });

      audio.addEventListener('ended', () => {
            clock.stop();
      });
    </script>
    <script>
      var lrc = `

`;

      let lrcArr = lrc.split('\n');
      let result = [];
      doms = {
            audio: document.querySelector("#audio"),
            ul: document.querySelector("#ul"),
            container: document.querySelector(".lrc")
      }

      for (let i = 0; i < lrcArr.length; i++) {
            let line = lrcArr.trim();
            if (!line) continue;

            let separatorIndex = line.indexOf(']');
            if (separatorIndex === -1) continue;

            let timePart = line.substring(1, separatorIndex);
            let lyric = line.substring(separatorIndex + 1) || '';

            result.push({
                time: parseTime(timePart),
                word: lyric.trim() || ' '
            });
      }

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

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

      function createElements() {
            let frag = document.createDocumentFragment();
            for (let i = 0; i < result.length; i++) {
                let li = document.createElement("li");
                li.innerText = result.word;
                frag.appendChild(li);
            }
            doms.ul.appendChild(frag);
      }
      createElements();
      let containerHeight = doms.container.clientHeight;
      let liHeight = doms.ul.children.clientHeight;
      let minOffset = 0;
      let maxOffset = doms.ul.clientHeight - containerHeight;
      function setOffset() {
            let index = getIndex();
            let offset = liHeight * index - containerHeight / 2 + liHeight / 2;
            if (offset < minOffset) {
                offset = minOffset;
            };
            if (offset > maxOffset) {
                offset = maxOffset;
            };
            doms.ul.style.transform = `translateY(-${offset}px)`;

            let li = doms.ul.querySelector(".active")
            if (li) {
                li.classList.remove("active");
            }

            li = doms.ul.children;
            if (li) {
                li.classList.add("active");
            }
      };

      doms.audio.addEventListener("timeupdate", setOffset);
      function createElements() {
            let frag = document.createDocumentFragment();
            for (let i = 0; i < result.length; i++) {
                let li = document.createElement("li");
                li.innerText = result.word || ' ';
                frag.appendChild(li);
            }
            doms.ul.appendChild(frag);
      }

      const audio = doms.audio;
      const nhzer = document.getElementById('nhzer');
      const message = "最辛苦的是咱爸 - 影子";
      const flashSpeed = 150;
      const baseColor = "#00ffff";
      const highlightColor = "#00ff00";
      let currentIndex = 0;
      let flashingTimer = null;
      const textSpans = [];

      function initNeonText() {
            nhzer.innerHTML = '';
            textSpans.length = 0;
            message.split('').forEach((char) => {
                const span = document.createElement('span');
                span.textContent = char;
                span.style.color = baseColor;
                textSpans.push(span);
                nhzer.appendChild(span);
            });
      }

      function animateNeon() {
            textSpans.forEach(span => {
                span.style.color = baseColor;
                span.style.textShadow = `0 0 5px rgba(0, 255, 255, 0.5)`;
            });

            if (textSpans) {
                textSpans.style.color = highlightColor;
                textSpans.style.textShadow = `
                0 0 10px ${highlightColor},
                0 0 20px ${highlightColor},
                0 0 30px ${highlightColor}
            `;
            }

            currentIndex = (currentIndex + 1) % textSpans.length;
      }

      audio.addEventListener('play', () => {
            if (!flashingTimer) {
                currentIndex = 0;
                animateNeon();
                flashingTimer = setInterval(animateNeon, flashSpeed);
                nhzer.style.setProperty('--state', 'running');
            }
      });

      audio.addEventListener('pause', () => {
            if (flashingTimer) {
                clearInterval(flashingTimer);
                flashingTimer = null;
            }
            textSpans.forEach(span => {
                span.style.color = baseColor;
                span.style.textShadow = `0 0 5px rgba(0, 255, 255, 0.5)`;
            });
            nhzer.style.setProperty('--state', 'paused');
      });

      audio.addEventListener('ended', () => {
            if (flashingTimer) {
                clearInterval(flashingTimer);
                flashingTimer = null;
            }
            currentIndex = 0;
            textSpans.forEach(span => {
                span.style.color = baseColor;
                span.style.textShadow = `0 0 5px rgba(0, 255, 255, 0.5)`;
            });
            nhzer.style.setProperty('--state', 'paused');
      });

      initNeonText();
    </script>
</body>
</html>


梦江南 发表于 2025-6-19 07:58

早上问好,欣赏精彩制作,真厉害!{:4_178:}

红影 发表于 2025-6-19 11:01

视频轮播很漂亮,这直管道用得也好。这播放器按钮还是另外设的呢。{:4_187:}

红影 发表于 2025-6-19 11:01

欣赏杨帆好帖{:4_187:}

杨帆 发表于 2025-6-19 17:48

梦江南 发表于 2025-6-19 07:58
早上问好,欣赏精彩制作,真厉害!

问好江南,谢谢鼓励,祝开心{:4_204:}

杨帆 发表于 2025-6-19 17:50

本帖最后由 杨帆 于 2025-6-19 21:52 编辑

红影 发表于 2025-6-19 11:01
视频轮播很漂亮,这直管道用得也好。这播放器按钮还是另外设的呢。
呵呵,影子当然欣赏影子了

问好影子,谢谢鼓励,祝开心{:4_204:}

梦油 发表于 2025-6-19 21:21

影子唱歌真好。我很早就想听影子唱歌了。

杨帆 发表于 2025-6-19 21:51

梦油 发表于 2025-6-19 21:21
影子唱歌真好。我很早就想听影子唱歌了。

好呀,欢迎梦油超版多听听,祝开心{:4_191:}

红影 发表于 2025-6-19 22:05

杨帆 发表于 2025-6-19 17:50
呵呵,影子当然欣赏影子了

问好影子,谢谢鼓励,祝开心

呵呵,居然还有这样的重名,也挺开心的{:4_173:}

杨帆 发表于 2025-6-19 22:07

红影 发表于 2025-6-19 22:05
呵呵,居然还有这样的重名,也挺开心的

对,开心天天是必须滴{:4_187:}

红影 发表于 2025-6-19 22:20

杨帆 发表于 2025-6-19 22:07
对,开心天天是必须滴

谢谢,也祝你时时开心快乐{:4_187:}

杨帆 发表于 2025-6-19 22:37

红影 发表于 2025-6-19 22:20
谢谢,也祝你时时开心快乐

谢谢!健康是第一,开心是目的{:4_204:}

红影 发表于 2025-6-20 09:35

杨帆 发表于 2025-6-19 22:37
谢谢!健康是第一,开心是目的

其实健康也包含心理健康,而开心就是心理健康的重要课题之一{:4_173:}

杨帆 发表于 2025-6-20 12:11

红影 发表于 2025-6-20 09:35
其实健康也包含心理健康,而开心就是心理健康的重要课题之一

对,身心健康,开心快乐,丰富体验,淬炼灵魂,光大人生{:4_204:}

红影 发表于 2025-6-20 20:14

杨帆 发表于 2025-6-20 12:11
对,身心健康,开心快乐,丰富体验,淬炼灵魂,光大人生

杨帆说的这些词汇都是正能量的呢{:4_187:}
页: [1]
查看完整版本: 影子《最辛苦的是咱爸》- 学习马老师帖《ThreeJS 直管道》