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 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 | 12x 528x 216x 216x 216x 216x 216x 216x 216x 216x 528x 216x 216x 528x 216x 528x 216x 216x 528x | /**
* 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, { useEffect, useMemo } from "react";
import * as THREE from "three";
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]);
// Memoize shared skin material for all foot parts
const skinMaterial = useMemo(
() =>
new THREE.MeshPhysicalMaterial({
color: footColor,
metalness: 0,
roughness: 0.8,
clearcoat: 0.3,
clearcoatRoughness: 0.5,
// PBR skin properties
transmission: 0,
thickness: 0.1,
ior: 1.4, // Index of refraction for skin
sheen: 0.1, // Subtle skin sheen
sheenRoughness: 0.8,
// Subtle emissive for alive appearance
emissive: new THREE.Color(footColor),
emissiveIntensity: isHighlighted ? 0.3 : 0.02,
}),
[footColor, isHighlighted],
);
// Dispose skin material on unmount to prevent memory leaks
useEffect(() => {
return () => {
skinMaterial.dispose();
};
}, [skinMaterial]);
return (
<group name={`foot-3d-${side}`}>
{/* Ankle connector - larger sphere that bridges shin body surface to foot */}
<mesh
position={[0, 0, 0]}
castShadow
receiveShadow
name={`foot-ankle-bridge-${side}`}
>
<sphereGeometry args={[footDimensions.footHeight * 0.6, 10, 10]} />
<primitive object={skinMaterial} attach="material" />
</mesh>
{/* Ankle-to-heel transition cylinder */}
<mesh
position={[
0,
-footDimensions.footHeight * 0.2,
footDimensions.heelLength * 0.1,
]}
castShadow
receiveShadow
name={`foot-ankle-transition-${side}`}
>
<cylinderGeometry
args={[
footDimensions.footHeight * 0.5, // Top radius matches ankle sphere
footDimensions.footWidth * 0.45, // Bottom matches heel width
footDimensions.footHeight * 0.4,
8,
]}
/>
<primitive object={skinMaterial} attach="material" />
</mesh>
{/* Main heel/midfoot body - capsule for smooth organic shape */}
<mesh
position={[
0,
-footDimensions.footHeight * 0.4,
footDimensions.heelLength * 0.2,
]}
rotation={[Math.PI / 2, 0, 0]}
castShadow
receiveShadow
name={`foot-heel-${side}`}
>
<capsuleGeometry
args={[
footDimensions.footWidth * 0.45, // Radius
footDimensions.heelLength * 0.5, // Length (shorter than full heel - caps add length)
4,
8,
]}
/>
<primitive object={skinMaterial} attach="material" />
</mesh>
{/* Toe area - capsule for rounded toe shape */}
<mesh
position={[
0,
-footDimensions.footHeight * 0.35 + footDimensions.toeHeight * 0.2,
footDimensions.heelLength * 0.7 + footDimensions.toeLength / 2,
]}
rotation={[Math.PI / 2, 0, 0]}
castShadow
receiveShadow
name={`foot-toes-${side}`}
>
<capsuleGeometry
args={[
footDimensions.toeWidth * 0.35, // Narrower radius for tapered toes
footDimensions.toeLength * 0.4, // Shorter length
4,
8,
]}
/>
<primitive object={skinMaterial} attach="material" />
</mesh>
</group>
);
};
export default Foot3D;
|