All files / components/shared/three/anatomy Foot3D.tsx

93.33% Statements 14/15
80% Branches 4/5
100% Functions 3/3
93.33% Lines 14/15

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 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183                                                                                                                                                      10x               284x   142x 142x 142x     142x 142x 142x     142x   142x                       284x 142x     142x     284x                                                                                                                                    
/**
 * Foot3D component with anatomically accurate foot geometry
 *
 * Renders detailed 3D foot with proper dimensions for martial arts stances
 * and kicks. Supports left/right feet with Korean skin tone coloring.
 *
 * Implements anatomically correct foot proportions:
 * - Length: ~26-29cm (varies by archetype)
 * - Width: ~10cm at widest point
 * - Height: ~8cm at ankle
 *
 * @module components/three/Foot3D
 * @category 3D Components
 * @korean 발3D컴포넌트
 */
 
import React, { useMemo } from "react";
import { KOREAN_COLORS } from "../../../../types/constants";
 
/**
 * Props for Foot3D component
 *
 * @public
 * @korean 발3D속성
 */
export interface Foot3DProps {
  /**
   * Foot side (left or right)
   * @korean 발쪽
   */
  readonly side: "left" | "right";
 
  /**
   * Base skin color
   * @korean 피부색
   */
  readonly skinColor?: number;
 
  /**
   * Scale multiplier (based on archetype physical attributes)
   * @korean 크기배율
   */
  readonly scale?: number;
 
  /**
   * Whether foot is highlighted (e.g., during kicks)
   * @korean 표시여부
   */
  readonly isHighlighted?: boolean;
}
 
/**
 * Foot3D Component
 *
 * Complete foot geometry with anatomically correct dimensions suitable
 * for Korean martial arts stance visualization and kick animations.
 *
 * Design notes:
 * - Main foot body is box-shaped with rounded edges
 * - Toe area is slightly elevated and separated
 * - Heel is wider than toe area for stability
 * - Dimensions scale with archetype (Amsalja: smaller, Jojik: larger)
 *
 * @example
 * ```tsx
 * <Foot3D
 *   side="right"
 *   skinColor={0xffdbac}
 *   scale={1.0}
 *   isHighlighted={false}
 * />
 * ```
 *
 * @korean 발3D컴포넌트
 */
export const Foot3D: React.FC<Foot3DProps> = ({
  side,
  skinColor = 0xffdbac,
  scale = 1.0,
  isHighlighted = false,
}) => {
  // Anatomically correct foot dimensions for average male (180cm height)
  // These scale with archetype physical attributes
  const footDimensions = useMemo(() => {
    // Average male foot: 26-29cm length, ~10cm width, ~8cm height
    const footLength = 0.26 * scale; // 26cm base length
    const footWidth = 0.1 * scale; // 10cm width
    const footHeight = 0.08 * scale; // 8cm height at ankle
 
    // Toe area dimensions (front 30% of foot)
    const toeLength = footLength * 0.3;
    const toeWidth = footWidth * 0.9; // Slightly narrower than heel
    const toeHeight = footHeight * 0.6; // Lower profile
 
    // Heel area dimensions (back 70% of foot)
    const heelLength = footLength * 0.7;
 
    return {
      footLength,
      footWidth,
      footHeight,
      toeLength,
      toeWidth,
      toeHeight,
      heelLength,
    };
  }, [scale]);
 
  // Foot color (highlight during kicks with brighter color)
  const footColor = useMemo(() => {
    Iif (isHighlighted) {
      return KOREAN_COLORS.ACCENT_GOLD;
    }
    return skinColor;
  }, [isHighlighted, skinColor]);
 
  return (
    <group name={`foot-3d-${side}`}>
      {/* Main heel/midfoot body */}
      <mesh
        position={[0, -footDimensions.footHeight / 2, 0]}
        castShadow
        receiveShadow
        name={`foot-heel-${side}`}
      >
        <boxGeometry
          args={[
            footDimensions.footWidth,
            footDimensions.footHeight,
            footDimensions.heelLength,
          ]}
        />
        <meshStandardMaterial
          color={footColor}
          metalness={0.1}
          roughness={0.9}
        />
      </mesh>
 
      {/* Toe area (slightly raised and forward) */}
      <mesh
        position={[
          0,
          -footDimensions.footHeight / 2 + footDimensions.toeHeight * 0.2,
          footDimensions.heelLength / 2 + footDimensions.toeLength / 2,
        ]}
        castShadow
        receiveShadow
        name={`foot-toes-${side}`}
      >
        <boxGeometry
          args={[
            footDimensions.toeWidth,
            footDimensions.toeHeight,
            footDimensions.toeLength,
          ]}
        />
        <meshStandardMaterial
          color={footColor}
          metalness={0.1}
          roughness={0.9}
        />
      </mesh>
 
      {/* Ankle connection point indicator (small sphere for visual continuity) */}
      <mesh
        position={[0, 0, -footDimensions.heelLength * 0.3]}
        castShadow
        name={`foot-ankle-${side}`}
      >
        <sphereGeometry args={[footDimensions.footHeight * 0.4, 8, 8]} />
        <meshStandardMaterial
          color={footColor}
          metalness={0.1}
          roughness={0.9}
        />
      </mesh>
    </group>
  );
};
 
export default Foot3D;