Skip to content

Commit 7071149

Browse files
committed
style(3d): tooltip 边框靛蓝换品牌令牌色
1 parent 3130477 commit 7071149

2 files changed

Lines changed: 93 additions & 16 deletions

File tree

‎client/src/lib/3d/objects/AuroraModuleEntity.tsx‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ const PLANET_CONFIGS: Record<ModuleId, PlanetConfig> = {
3939
inspiration: { radius: 0.4, color: '#F472B6', emissive: '#EC4899', label: '萤火海沟' },
4040
classroom: { radius: 0.55, color: '#14B8A6', emissive: '#0D9488', label: '回声定位' },
4141
constellation: { radius: 0.5, color: '#FBBF24', emissive: '#F59E0B', label: '星座' },
42+
sop: { radius: 0.45, color: '#A3E635', emissive: '#65A30D', label: '标准作业' },
4243
};
4344

4445
/** 轨道位置最大距离约束(兜底),超出则等比缩放回安全范围 */
@@ -192,7 +193,7 @@ export function AuroraModuleEntity({
192193
position={[0, config.radius + 0.6, 0]}
193194
style={{ pointerEvents: 'none' }}
194195
>
195-
<div className="rounded-lg bg-slate-900/80 px-3 py-1.5 text-sm font-medium text-white backdrop-blur-sm whitespace-nowrap border border-indigo-500/30">
196+
<div className="rounded-lg bg-slate-900/80 px-3 py-1.5 text-sm font-medium text-white backdrop-blur-sm whitespace-nowrap border border-brand-400/30">
196197
{config.label}
197198
{/* 常驻功能副标题:隐喻名旁附直白功能名 */}
198199
{subtitle && (

‎client/src/lib/3d/objects/ModuleEntity.tsx‎

Lines changed: 91 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
* 宪法第一条接入:glowScale 映射学习数据(掌握度=亮度),域 0.6–1.15。
77
* 宪法第四条:三级性能降级嵌入(high/medium/low)。
88
*/
9-
import { useRef, useMemo, useEffect } from 'react';
9+
import { useRef, useMemo } from 'react';
1010
import { useFrame } from '@react-three/fiber';
1111
import * as THREE from 'three';
1212
import { Float, Html } from '@react-three/drei';
@@ -50,18 +50,80 @@ function ModuleGeometry({ geometry }: { geometry: GeometryType }) {
5050
}
5151
}
5252

53-
/** 闪卡专用 */
54-
function FlashcardGeometry({ textures }: { textures?: { mapA?: THREE.CanvasTexture; mapB?: THREE.CanvasTexture } | null }) {
53+
/**
54+
* 闪卡专用:保留平面卡片造型,与其他模块一致的交互表现
55+
* 矩形辉光线框(透明度逻辑同 WireframeGlow)+ 自转 + 悬停/激活缩放与发光增强
56+
*/
57+
function FlashcardGeometry({ textures, emissiveColor, isActive, isHovered }: {
58+
textures?: { mapA?: THREE.CanvasTexture; mapB?: THREE.CanvasTexture } | null;
59+
emissiveColor: string;
60+
isActive: boolean;
61+
isHovered: boolean;
62+
}) {
63+
const groupRef = useRef<THREE.Group>(null);
64+
const frontRef = useRef<THREE.Mesh>(null);
65+
const backRef = useRef<THREE.Mesh>(null);
66+
const frontLineRef = useRef<THREE.LineSegments>(null);
67+
const backLineRef = useRef<THREE.LineSegments>(null);
68+
69+
// 卡片矩形边框几何体(平面四边,与卡片同尺寸)
70+
const edgesGeom = useMemo(() => {
71+
const plane = new THREE.PlaneGeometry(0.9, 1.2);
72+
const edges = new THREE.EdgesGeometry(plane);
73+
plane.dispose();
74+
return edges;
75+
}, []);
76+
77+
// 与其他模块主体一致的自转配置
78+
const rotationConfig = useRef({
79+
axis: new THREE.Vector3(
80+
Math.random() - 0.5, Math.random() - 0.5, Math.random() - 0.5,
81+
).normalize(),
82+
speed: 0.2 + Math.random() * 0.3,
83+
}).current;
84+
85+
const targetScale = isActive ? 1.3 : isHovered ? 1.15 : 1.0;
86+
const targetEmissive = isActive ? 1.2 : isHovered ? 0.8 : 0.3;
87+
88+
useFrame((_, delta) => {
89+
const safeDelta = Math.min(delta, 0.1);
90+
// 自转 + 交互缩放(与其他模块一致)
91+
if (groupRef.current) {
92+
groupRef.current.rotateOnAxis(rotationConfig.axis, safeDelta * rotationConfig.speed);
93+
const cs = groupRef.current.scale.x;
94+
groupRef.current.scale.setScalar(THREE.MathUtils.lerp(cs, targetScale, safeDelta * 4));
95+
}
96+
// 卡片发光增强(与其他模块一致)
97+
[frontRef, backRef].forEach((ref) => {
98+
const mat = ref.current?.material as THREE.MeshStandardMaterial | undefined;
99+
if (mat) mat.emissiveIntensity = THREE.MathUtils.lerp(mat.emissiveIntensity, targetEmissive, safeDelta * 4);
100+
});
101+
// 线框透明度(与 WireframeGlow 相同逻辑:基线 0.25,悬停 0.6,激活 0.85)
102+
const targetLine = isActive ? 0.85 : isHovered ? 0.6 : 0.25;
103+
[frontLineRef, backLineRef].forEach((ref) => {
104+
const mat = ref.current?.material as THREE.LineBasicMaterial | undefined;
105+
if (mat) mat.opacity = THREE.MathUtils.lerp(mat.opacity, targetLine, safeDelta * 3);
106+
});
107+
});
108+
55109
return (
56-
<group>
57-
<mesh position={[0, 0, 0.05]} rotation={[0, 0, 0.05]}>
110+
<group ref={groupRef}>
111+
{/* 正面卡片 + 矩形辉光线框 */}
112+
<mesh ref={frontRef} position={[0, 0, 0.05]} rotation={[0, 0, 0.05]}>
58113
<planeGeometry args={[0.9, 1.2]} />
59114
<meshStandardMaterial color="#3B82F6" emissive="#3B82F6" emissiveIntensity={0.3} map={textures?.mapA} side={THREE.DoubleSide} />
60115
</mesh>
61-
<mesh position={[0, 0, -0.05]} rotation={[0, 0, -0.05]}>
116+
<lineSegments ref={frontLineRef} geometry={edgesGeom} position={[0, 0, 0.05]} rotation={[0, 0, 0.05]} scale={[1.06, 1.06, 1.06]}>
117+
<lineBasicMaterial color={emissiveColor} transparent opacity={0.25} blending={THREE.AdditiveBlending} />
118+
</lineSegments>
119+
{/* 背面卡片 + 矩形辉光线框 */}
120+
<mesh ref={backRef} position={[0, 0, -0.05]} rotation={[0, 0, -0.05]}>
62121
<planeGeometry args={[0.9, 1.2]} />
63122
<meshStandardMaterial color="#6366F1" emissive="#6366F1" emissiveIntensity={0.3} map={textures?.mapB} side={THREE.DoubleSide} />
64123
</mesh>
124+
<lineSegments ref={backLineRef} geometry={edgesGeom} position={[0, 0, -0.05]} rotation={[0, 0, -0.05]} scale={[1.06, 1.06, 1.06]}>
125+
<lineBasicMaterial color={emissiveColor} transparent opacity={0.25} blending={THREE.AdditiveBlending} />
126+
</lineSegments>
65127
</group>
66128
);
67129
}
@@ -100,6 +162,7 @@ function FresnelGlow({ color, isActive, isHovered, geometry }: {
100162
}
101163

102164
// ─── 细节层 2:辉光线框(EdgesGeometry) ────────────
165+
// 常驻显示:默认透明度 0.4 持续可见,悬停/选中时进一步增强
103166
function WireframeGlow({ color, isActive, isHovered, geometry }: {
104167
color: string; isActive: boolean; isHovered: boolean; geometry: GeometryType;
105168
}) {
@@ -123,13 +186,14 @@ function WireframeGlow({ color, isActive, isHovered, geometry }: {
123186
useFrame((_, delta) => {
124187
if (!lineRef.current) return;
125188
const mat = lineRef.current.material as THREE.LineBasicMaterial;
126-
const target = isActive ? 0.8 : isHovered ? 0.5 : 0.15;
189+
// 常驻可见基线 0.4,交互时平滑增强(悬停 0.6 / 激活 0.85)
190+
const target = isActive ? 0.85 : isHovered ? 0.6 : 0.4;
127191
mat.opacity = THREE.MathUtils.lerp(mat.opacity, target, Math.min(delta * 3, 1));
128192
});
129193

130194
return (
131195
<lineSegments ref={lineRef} geometry={edgesGeom} scale={[1.06, 1.06, 1.06]}>
132-
<lineBasicMaterial color={color} transparent opacity={0.15} blending={THREE.AdditiveBlending} />
196+
<lineBasicMaterial color={color} transparent opacity={0.25} blending={THREE.AdditiveBlending} />
133197
</lineSegments>
134198
);
135199
}
@@ -263,7 +327,6 @@ export function ModuleEntity({
263327
const subtitle = getModuleSubtitle(id);
264328
const tier = useEffectiveTier();
265329
const isLowTier = tier === 'low';
266-
const isMidTier = tier === 'medium';
267330

268331
const rotationConfig = useRef({
269332
axis: new THREE.Vector3(
@@ -321,7 +384,22 @@ export function ModuleEntity({
321384
onClick={onClick} onPointerOver={onPointerOver} onPointerOut={onPointerOut}
322385
>
323386
{isFlashcard ? (
324-
<FlashcardGeometry textures={flashcardTextures} />
387+
<>
388+
{/* 核心呼吸光(与其他模块一致) */}
389+
{!isLowTier && <CoreBreath color={emissiveColor} isActive={isActive} isHovered={isHovered} />}
390+
<FlashcardGeometry
391+
textures={flashcardTextures}
392+
emissiveColor={emissiveColor}
393+
isActive={isActive}
394+
isHovered={isHovered}
395+
/>
396+
{/* 轨道粒子环(与其他模块一致) */}
397+
{!isLowTier && (isActive || isHovered) && (
398+
<OrbitalRing isActive={isActive} isHovered={isHovered} color={emissiveColor} />
399+
)}
400+
{/* 地面辉光(与其他模块一致) */}
401+
{!isLowTier && <GroundGlow color={emissiveColor} isActive={isActive} />}
402+
</>
325403
) : (
326404
<>
327405
{/* 核心呼吸光 */}
@@ -353,10 +431,8 @@ export function ModuleEntity({
353431
<FresnelGlow color={emissiveColor} isActive={isActive} isHovered={isHovered} geometry={geometry} />
354432
)}
355433

356-
{/* 辉光线框 */}
357-
{!isMidTier && !isLowTier && (
358-
<WireframeGlow color={emissiveColor} isActive={isActive} isHovered={isHovered} geometry={geometry} />
359-
)}
434+
{/* 辉光线框(全档位常驻显示:性能降级也不关闭) */}
435+
<WireframeGlow color={emissiveColor} isActive={isActive} isHovered={isHovered} geometry={geometry} />
360436

361437
{/* 轨道粒子环 */}
362438
{!isLowTier && (isActive || isHovered) && (
@@ -371,7 +447,7 @@ export function ModuleEntity({
371447
{/* 标签 */}
372448
{(showLabel || isHovered) && (
373449
<Html center distanceFactor={8} position={[0, 1.3, 0]} style={{ pointerEvents: 'none' }}>
374-
<div className="rounded-lg bg-slate-900/80 px-3 py-1.5 text-sm font-medium text-white backdrop-blur-sm whitespace-nowrap border border-indigo-500/30">
450+
<div className="rounded-lg bg-slate-900/80 px-3 py-1.5 text-sm font-medium text-white backdrop-blur-sm whitespace-nowrap border border-brand-400/30">
375451
{label}
376452
{subtitle && <span className="ml-1.5 text-xs text-white/50">· {subtitle}</span>}
377453
</div>

0 commit comments

Comments
 (0)