杨帆 发表于 2025-9-3 22:14

马头琴之灵魂之曲:万马奔腾 — 学习马老师帖代码

本帖最后由 杨帆 于 2025-9-4 09:17 编辑 <br /><br /><style>
#tz { margin: 30px auto; left: calc(50% - 81px); transform: translateX(-50%); width: 1400px; height: 750px;background:var(--bg1), var(--bg2);overflow: hidden; box-shadow: 2px 2px 6px #333; display: grid; place-items: center; z-index: 1; position: relative; --bg1:url('https://www.helloimg.com/i/2025/09/02/68b6e86716956.gif') no-repeat center/cover;--bg2:url('https://www.helloimg.com/i/2025/09/02/68b6e879a5399.gif') no-repeat center/cover; --opacity: .8;--ma-size:10%;--state:running; animation: multiColorShift 20s infinite ease-in-out var(--state);}
#player2 { position: absolute;background:var(--bg3); width:var(--ma-size);height: auto;border-radius: 50%;right:5px;bottom:10px;cursor: pointer; transition: .6s; opacity: .8; animation: rot 8s linear infinite var(--state);--bg3:url('https://pic1.imgdb.cn/item/6866a84758cb8da5c88e215d.gif') no-repeat center/45% 45%; }
#player2:hover{filter: brightness(2);}
#msvg { position: absolute; border: none; pointer-events: none; transition: 1.2s; }
@keyframes rot { to { transform: rotate(1turn); } }
#player1 { position: absolute; left: 20px; top: 20px; z-index: 5;transition: filter .7s; cursor: pointer;width:var(--ma-size); transform-origin: 50% 100%; animation: swear 1s infinite alternate linear var(--state); display: var(--display);--display:block;transition: .8s;}
#player1:hover { filter: hue-rotate(120deg); }
#btnFs { right: 30px; top: 30px; color: #eee; }
#btnFs:hover { color: red; }
@keyframes swear {30% { transform: rotate(-6deg); } 80% { transform: rotate(6deg); } }
@keyframes multiColorShift {0% {filter: hue-rotate(0deg) saturate(1.2);}16% {filter: hue-rotate(60deg) saturate(1.3); }32% { filter: hue-rotate(120deg) saturate(1.2);} 48% { filter: hue-rotate(180deg) saturate(1.4);} 64% { filter: hue-rotate(240deg) saturate(1.2); }80% {filter: hue-rotate(300deg) saturate(1.3); } 100% { filter: hue-rotate(360deg) saturate(1.2);}}
.title-text {font: bold 45px 'Microsoft YaHei', sans-serif; color: #eee;letter-spacing: 2px; text-shadow: 0 0 1px #000, 2px 2px 6px #333; user-select: none; position: absolute;}
.rotate {animation: rotate 1s linear var(--state);}
@keyframes rotate {from {transform: rotate(0);}to {transform: rotate(360deg);}}
.ani { animation: flash 1s linear alternate var(--state), rotate 1s linear var(--state); }
    @keyframes flash { to { color: red; opacity: .7; } }
</style>
<div id="tz">
         <audio id="aud" src="https://upfile.mp3.wf/view.php/6db439492a45285ae68773e1ef9b14ff.mp3" autoplay loop></audio>
      <img id="player1" src="https://638183.freep.cn/638183/small/260.webp"title="播放/暂停" />
      <img id="player2"src="https://pic1.imgdb.cn/item/6722130ed29ded1a8c52391c.png"   alt="" title="播放/暂停" />
      <img id="msvg" src="https://638183.freep.cn/638183/web/svg/hexagon.svg" width="100%" height="100%">
</div>
<script>
var players = document.querySelectorAll('#player1');
var players = document.querySelectorAll('#player2');
var msvgs = document.querySelectorAll('#msvg');
mState = () => {
      tz.style.setProperty('--state', aud.paused ? 'paused' : 'running');
      tz.style.setProperty('--bg1', aud.paused ? 'none' : '');
      tz.style.setProperty('--bg2', aud.paused ? '' : 'none');
      player2.style.setProperty('--bg3', aud.paused ? 'none' : '' );
      player1.style.setProperty('--display', aud.paused ? 'none' : 'block' );
      msvg.style.setProperty('opacity', aud.paused ? '0' : '.8');
      player1.title = aud.paused ? '播放' : '暂停';
      player2.title = aud.paused ? '播放' : '暂停';
};
aud.onplaying = aud.onpause = () => mState();
player1.onclick = player2.onclick = () => aud.paused ? aud.play() : aud.pause();
</script>
<script type="importmap">
{
"imports": {
    "three": "https://esm.sh/three@0.176.0?target=es2022",
    "three/addons/": "https://esm.sh/three@0.176.0/addons/"
}
}
</script>
<script type="module">
import * as THREE from 'three';
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { FS } from 'https://638183.freep.cn/638183/web/js/fullscreen.js';
let camera, scene, renderer, mesh, mixer, dummy;
const offset = 5000;
const timeOffsets = new Float32Array( 1024 );
for (let x = 0; x < 1024; x ++) {
      timeOffsets = Math.random() * 3;
}
const clock = new THREE.Clock(true);
init();
function init() {
      camera = new THREE.PerspectiveCamera(60, tz.offsetWidth / tz.offsetHeight, 100, 10000);
      scene = new THREE.Scene();
      scene.background = new THREE.Color(0x99DDFF);
      scene.fog = new THREE.Fog(0x99DDFF, 5000, 10000);
      const light = new THREE.DirectionalLight(0xffffff, 1);
      light.position.set(200, 1000, 50);
      light.castShadow = true;
      light.shadow.camera.left = - 5000;
      light.shadow.camera.right = 5000;
      light.shadow.camera.top = 5000;
      light.shadow.camera.bottom = - 5000;
      light.shadow.camera.far = 2000;
      light.shadow.bias = - 0.01;
      light.shadow.camera.updateProjectionMatrix();
      scene.add(light);
      const hemi = new THREE.HemisphereLight(0x99DDFF, 0x669933, 1 / 3);
      scene.add(hemi);
      const ground = new THREE.Mesh(
                new THREE.PlaneGeometry(1000000, 1000000),
                new THREE.MeshStandardMaterial({color: 0x669933, depthWrite: true})
      );
      ground.rotation.x = - Math.PI / 2;
      ground.receiveShadow = true;
      scene.add(ground);
      const loader = new GLTFLoader();
      loader.load('https://638183.freep.cn/638183/web/3models/Horse.glb', function (glb) {
                dummy = glb.scene.children;
                mesh = new THREE.InstancedMesh(dummy.geometry, dummy.material, 1024);
                mesh.castShadow = true;
                for (let x = 0, i = 0; x < 32; x ++) {
                        for (let y = 0; y < 32; y ++) {
                              dummy.position.set(offset - 300 * x + 200 * Math.random(), 0, offset - 300 * y);
                              dummy.updateMatrix();
                              mesh.setMatrixAt(i, dummy.matrix);
                              mesh.setColorAt(i, new THREE.Color( `hsl(${Math.random() * 360}, 50%, 66%)`));
                              i ++;
                        }
                }
                scene.add(mesh);
                mixer = new THREE.AnimationMixer(glb.scene);
                const action = mixer.clipAction(glb.animations);
                action.play();         
      });
      renderer = new THREE.WebGLRenderer({antialias: true,alpha: true });
      renderer.setPixelRatio(window.devicePixelRatio);
      renderer.setSize(tz.offsetWidth, tz.offsetHeight);
      renderer.setAnimationLoop(animate);
      tz.appendChild(renderer.domElement);
      renderer.shadowMap.enabled = true;
      renderer.shadowMap.type = THREE.VSMShadowMap;
      window.addEventListener('resize', onWindowResize);
}
function onWindowResize() {
      camera.aspect = tz.offsetWidth / tz.offsetHeight;
      camera.updateProjectionMatrix();
      renderer.setSize(tz.offsetWidth, tz.offsetHeight);
}
function animate() {
      if (aud.paused) return; //动画停
      render();
}
function render() {
      const time = clock.getElapsedTime();
      const r = 3000;
      camera.position.set(Math.sin(time / 10) * r, 1500 + 1000 * Math.cos(time / 5), Math.cos(time / 10) * r);
      camera.lookAt(0, 0, 0);
      if (mesh) {
                for (let x = 0; x < 1024; x ++) {
                        mixer.setTime(time + timeOffsets);
                        mesh.setMorphAt(x, dummy);
                }
                mesh.morphTexture.needsUpdate = true;
      }
      renderer.render(scene, camera);
}
FS(tz, player1,player2);
const txtAr = '万马奔腾'.split('');
    let spans = [];
    txtAr.forEach( (t,k) => {
      const s = document.createElement('span');
      s.textContent = t;
      s.className = k === 0 ? 'title-text rotate' : 'title-text';
      s.style.cssText += `left: 50px; top: ${k * 80 + 350}px;`;
      spans.push(s);
      s.onanimationend = () => {
            s.classList.remove('rotate');
            spans[(k+1) % txtAr.length].classList.add('rotate');
s.classList.remove('ani');
            spans[(k + 1) % txtAr.length].classList.add('ani');
      };
       tz.appendChild(s);
    });
</script>

红影 发表于 2025-9-3 23:06

这个又是好多效果的结合呢,如转钟的文字,左上和右下的两个按钮都能操控暂停呢,暂停的时候中间的动态效果会消失。最奇妙的是这些奔腾的战马,而且背景还是变色的{:4_187:}

红影 发表于 2025-9-3 23:07

这个好像在某个时刻露出后面的场景了呢。
欣赏杨帆好帖{:4_199:}

杨帆 发表于 2025-9-3 23:39

红影 发表于 2025-9-3 23:06
这个又是好多效果的结合呢,如转钟的文字,左上和右下的两个按钮都能操控暂停呢,暂停的时候中间的动态效果 ...

谢谢影子鼓励,鼓捣着玩呢{:4_173:}

杨帆 发表于 2025-9-3 23:53

红影 发表于 2025-9-3 23:07
这个好像在某个时刻露出后面的场景了呢。
欣赏杨帆好帖

是,也可不显示

梦江南 发表于 2025-9-4 09:49

万马奔腾开场,气势磅礴,变色的背景,吸引眼球。左上角的小姑娘很可爱。

梦江南 发表于 2025-9-4 09:50

欣赏杨帆带来的精彩。{:4_187:}

杨帆 发表于 2025-9-4 09:59

梦江南 发表于 2025-9-4 09:49
万马奔腾开场,气势磅礴,变色的背景,吸引眼球。左上角的小姑娘很可爱。

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

樵歌 发表于 2025-9-4 11:31

万马奔腾气势磅礴!{:4_199:}

杨帆 发表于 2025-9-4 12:00

本帖最后由 杨帆 于 2025-9-4 12:06 编辑

樵歌 发表于 2025-9-4 11:31
万马奔腾气势磅礴!
恢复挺快呀,身心休整再出发~

谢谢樵歌管理员鼓励{:4_190:}

红影 发表于 2025-9-4 13:30

杨帆 发表于 2025-9-3 23:39
谢谢影子鼓励,鼓捣着玩呢

这个非常不容易,杨帆厉害了{:4_199:}

红影 发表于 2025-9-4 13:31

杨帆 发表于 2025-9-3 23:53
是,也可不显示

哦,那最好就不显示,否则有些奇怪呢。

杨帆 发表于 2025-9-4 13:41

红影 发表于 2025-9-4 13:31
哦,那最好就不显示,否则有些奇怪呢。

已改了呀{:4_173:}

红影 发表于 2025-9-4 14:43

杨帆 发表于 2025-9-4 13:41
已改了呀

厉害,辛苦了{:4_187:}

梦江南 发表于 2025-9-4 18:58

再欣赏马头琴之灵魂之曲:万马奔腾 。一点小姑娘马上隐去了,一点下面的按钮小姑娘就出现了。这设计得巧妙。

杨帆 发表于 2025-9-4 19:11

红影 发表于 2025-9-4 14:43
厉害,辛苦了

鼓捣着玩呢,谢谢影子鼓励{:4_204:}

杨帆 发表于 2025-9-4 19:12

梦江南 发表于 2025-9-4 18:58
再欣赏马头琴之灵魂之曲:万马奔腾 。一点小姑娘马上隐去了,一点下面的按钮小姑娘就出现了。这设计得巧妙 ...

问好江南,鼓捣着玩呢,谢谢鼓励{:4_204:}

梦江南 发表于 2025-9-4 19:19

杨帆 发表于 2025-9-4 19:12
问好江南,鼓捣着玩呢,谢谢鼓励

也只有你会鼓捣。{:5_116:}

红影 发表于 2025-9-4 21:27

杨帆 发表于 2025-9-4 19:11
鼓捣着玩呢,谢谢影子鼓励

杨帆谦虚了,这个制作十分美妙{:4_187:}

杨帆 发表于 2025-9-4 21:45

梦江南 发表于 2025-9-4 19:19
也只有你会鼓捣。

只要你鼓捣多了,也一样会{:4_171:}
页: [1] 2
查看完整版本: 马头琴之灵魂之曲:万马奔腾 — 学习马老师帖代码