All files / components/three StanceAura.tsx

47.82% Statements 11/23
27.27% Branches 3/11
75% Functions 3/4
50% Lines 10/20

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;