Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 | 5x 71x 71x 5x 142x 142x 142x 142x 142x 142x | /**
* StanceAura - 3D visual effect for trigram stance
*
* Renders a pulsing, color-coded aura around the player based on their
* current trigram stance and Ki energy level.
*
* @module components/three/StanceAura
* @category 3D Components
* @korean 자세오라
*/
import { useFrame } from "@react-three/fiber";
import React, { useRef, useMemo } from "react";
import * as THREE from "three";
import { TrigramStance } from "../../types/common";
import { KOREAN_COLORS } from "../../types/constants";
import type { StanceAuraProps } from "../../types/player-visual";
/**
* Get color for each trigram stance
* Maps 8 trigrams to Korean cyberpunk color palette
*
* @param stance - Current trigram stance
* @returns Hex color number
* @korean 자세색상가져오기
*/
const getStanceColor = (stance: TrigramStance): number => {
const stanceColors = {
[TrigramStance.GEON]: KOREAN_COLORS.TRIGRAM_GEON_PRIMARY,
[TrigramStance.TAE]: KOREAN_COLORS.TRIGRAM_TAE_PRIMARY,
[TrigramStance.LI]: KOREAN_COLORS.TRIGRAM_LI_PRIMARY,
[TrigramStance.JIN]: KOREAN_COLORS.TRIGRAM_JIN_PRIMARY,
[TrigramStance.SON]: KOREAN_COLORS.TRIGRAM_SON_PRIMARY,
[TrigramStance.GAM]: KOREAN_COLORS.TRIGRAM_GAM_PRIMARY,
[TrigramStance.GAN]: KOREAN_COLORS.TRIGRAM_GAN_PRIMARY,
[TrigramStance.GON]: KOREAN_COLORS.TRIGRAM_GON_PRIMARY,
};
return stanceColors[stance] ?? KOREAN_COLORS.PRIMARY_CYAN;
};
/**
* StanceAura Component
*
* Renders an animated 3D aura effect that pulses and glows based on
* the player's stance and Ki energy level.
*
* @example
* ```tsx
* <StanceAura
* stance={TrigramStance.GEON}
* intensity={0.8}
* animated={true}
* />
* ```
*
* @korean 자세오라컴포넌트
*/
export const StanceAura: React.FC<StanceAuraProps> = ({
stance,
intensity,
animated = true,
}) => {
const innerAuraRef = useRef<THREE.Mesh>(null);
const outerAuraRef = useRef<THREE.Mesh>(null);
// Get stance-specific color
const stanceColor = useMemo(() => getStanceColor(stance), [stance]);
// Animation loop for pulsing effect
useFrame((state) => {
if (!animated) return;
const time = state.clock.elapsedTime;
// Inner aura: fast pulse
if (innerAuraRef.current) {
const innerPulse = Math.sin(time * 3) * 0.1 + 1;
innerAuraRef.current.scale.setScalar(innerPulse * intensity);
innerAuraRef.current.rotation.y = time * 0.5;
}
// Outer aura: slow pulse
if (outerAuraRef.current) {
const outerPulse = Math.sin(time * 1.5) * 0.15 + 1;
outerAuraRef.current.scale.setScalar(outerPulse * intensity * 1.3);
outerAuraRef.current.rotation.y = -time * 0.3;
}
});
// Only render if intensity is above threshold
Iif (intensity < 0.1) return null;
return (
<group>
{/* Inner aura - solid sphere */}
<mesh ref={innerAuraRef} position={[0, 1, 0]}>
<sphereGeometry args={[0.6, 16, 16]} />
<meshBasicMaterial
color={stanceColor}
transparent
opacity={0.2 * intensity}
wireframe={false}
/>
</mesh>
{/* Outer aura - wireframe sphere */}
<mesh ref={outerAuraRef} position={[0, 1, 0]}>
<sphereGeometry args={[0.8, 16, 16]} />
<meshBasicMaterial
color={stanceColor}
transparent
opacity={0.15 * intensity}
wireframe
/>
</mesh>
{/* Stance ring on ground */}
<mesh position={[0, 0.02, 0]} rotation={[-Math.PI / 2, 0, 0]}>
<ringGeometry args={[0.45, 0.5, 32]} />
<meshBasicMaterial
color={stanceColor}
transparent
opacity={0.7 * intensity}
side={THREE.DoubleSide}
/>
</mesh>
</group>
);
};
export default StanceAura;
|