Skip to content

Commit 8f86127

Browse files
committed
feat(3d): Dashboard 深海世界新增 LeviathanShadow 远景巨影
- 蝠鲼剪影 60~90s 周期水平弧线缓慢滑过,深海雾中若隐若现 - 克制含蓄:透明度 0.1~0.15,单网格+平移单 draw call,low 档关闭
1 parent dd812b9 commit 8f86127

1 file changed

Lines changed: 71 additions & 0 deletions

File tree

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
/**
2+
* LeviathanShadow — 远洋巨影:对未知知识的敬畏
3+
* 远景蝠鲼剪影,60~90 秒周期水平弧线缓慢滑过,深海雾中若隐若现
4+
* 克制含蓄:透明度 0.1~0.15,单网格 + 平移,1 draw call
5+
*
6+
* @ai-context: 3D 场景对象:LeviathanShadow(DeepSeaWorld 增强层)。
7+
* 宪法第四条:high 透明度 0.15 / medium 0.1 / low 关闭。
8+
*/
9+
import { useMemo, useRef } from 'react';
10+
import { useFrame } from '@react-three/fiber';
11+
import * as THREE from 'three';
12+
import { useEffectiveTier } from '@/lib/performance/usePerformanceMode';
13+
14+
/** 蝠鲼剪影轮廓(俯视 Shape):头部圆润、双翼展开、尾部细长 */
15+
function createMantaShape(): THREE.Shape {
16+
const s = new THREE.Shape();
17+
s.moveTo(0, 0.7); // 头部
18+
s.quadraticCurveTo(2.4, 0.55, 3.2, 0); // 右翼展开
19+
s.quadraticCurveTo(2.4, -0.55, 0.6, -0.3); // 右下回收
20+
s.quadraticCurveTo(0.3, -0.75, 0, -0.85); // 尾基
21+
s.quadraticCurveTo(-0.3, -0.75, -0.6, -0.3); // 左下
22+
s.quadraticCurveTo(-2.4, -0.55, -3.2, 0); // 左翼展开
23+
s.quadraticCurveTo(-2.4, 0.55, 0, 0.7); // 左上回收
24+
return s;
25+
}
26+
27+
/** 远洋巨影:远景剪影周期滑过 */
28+
export function LeviathanShadow() {
29+
const tier = useEffectiveTier();
30+
const meshRef = useRef<THREE.Mesh>(null);
31+
const timeRef = useRef(0);
32+
33+
// 剪影几何:蝠鲼平面(单面,只从前方可见)
34+
const geometry = useMemo(() => new THREE.ShapeGeometry(createMantaShape(), 12), []);
35+
36+
const opacity = tier === 'low' ? 0 : tier === 'medium' ? 0.1 : 0.15;
37+
// 周期:每只巨影一个 60~90 秒滑过周期
38+
const cycle = useMemo(() => 60 + Math.random() * 30, []);
39+
// 滑过路径(弧线)
40+
const path = useMemo(() => ({
41+
startX: -18 + Math.random() * 4,
42+
endX: 18 + Math.random() * 4,
43+
z: -20 - Math.random() * 10,
44+
y: 1 + Math.random() * 3,
45+
}), []);
46+
47+
useFrame((_, delta) => {
48+
if (tier === 'low') return;
49+
if (!meshRef.current) return;
50+
const safeDelta = Math.min(delta, 0.1);
51+
timeRef.current += safeDelta;
52+
const u = (timeRef.current % cycle) / cycle; // 0→1 循环
53+
54+
// 水平弧线滑过 + 上下起伏 + 缓慢拍翼
55+
meshRef.current.position.x = path.startX + (path.endX - path.startX) * u;
56+
meshRef.current.position.y = path.y + Math.sin(u * Math.PI * 2) * 0.8;
57+
meshRef.current.rotation.y = Math.sin(u * Math.PI) * 0.3;
58+
meshRef.current.rotation.z = Math.sin(u * Math.PI * 4) * 0.08; // 拍翼
59+
});
60+
61+
if (tier === 'low') return null;
62+
63+
return (
64+
<mesh ref={meshRef} geometry={geometry} position={[path.startX, path.y, path.z]} scale={[8, 8, 8]}>
65+
<meshBasicMaterial
66+
color="#1E3A5F" transparent opacity={opacity}
67+
side={THREE.DoubleSide} depthWrite={false}
68+
/>
69+
</mesh>
70+
);
71+
}

0 commit comments

Comments
 (0)