blacktrigram 0.7.39 → 0.7.41

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (354) hide show
  1. package/lib/App2.js.map +1 -1
  2. package/lib/audio/AudioAssetLoader.js.map +1 -1
  3. package/lib/audio/AudioAssetRegistry.js.map +1 -1
  4. package/lib/audio/AudioCache.js.map +1 -1
  5. package/lib/audio/AudioManager.js.map +1 -1
  6. package/lib/audio/AudioMonitor.js.map +1 -1
  7. package/lib/audio/AudioPool.js.map +1 -1
  8. package/lib/audio/AudioProvider.js.map +1 -1
  9. package/lib/audio/AudioUtils.js.map +1 -1
  10. package/lib/audio/BoneImpactAudioMap.js.map +1 -1
  11. package/lib/audio/VariantSelector.js.map +1 -1
  12. package/lib/audio/types.js.map +1 -1
  13. package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
  14. package/lib/components/screens/combat/components/controls/CombatButtons.js.map +1 -1
  15. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
  16. package/lib/components/screens/combat/components/controls/ControlsGuide.js.map +1 -1
  17. package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
  18. package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
  19. package/lib/components/screens/combat/components/controls/PauseMenuButton.js.map +1 -1
  20. package/lib/components/screens/combat/components/controls/QuickSettings.js.map +1 -1
  21. package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
  22. package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
  23. package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
  24. package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
  25. package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
  26. package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
  27. package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
  28. package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
  29. package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
  30. package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
  31. package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
  32. package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
  33. package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js.map +1 -1
  34. package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
  35. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
  36. package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
  37. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
  38. package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
  39. package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
  40. package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
  41. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  42. package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
  43. package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
  44. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  45. package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
  46. package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
  47. package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
  48. package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
  49. package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
  50. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  51. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  52. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  53. package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
  54. package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
  55. package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
  56. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  57. package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
  58. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  59. package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
  60. package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
  61. package/lib/components/screens/controls/components/Key3D.js.map +1 -1
  62. package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
  63. package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
  64. package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
  65. package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
  66. package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
  67. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  68. package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
  69. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  70. package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
  71. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  72. package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
  73. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  74. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  75. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  76. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  77. package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
  78. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  79. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  80. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  81. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  82. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  83. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  84. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  85. package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
  86. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  87. package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
  88. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  89. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  90. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  91. package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
  92. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  93. package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
  94. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  95. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  96. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  97. package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
  98. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
  99. package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
  100. package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
  101. package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
  102. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  103. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  104. package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
  105. package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
  106. package/lib/components/shared/base/BaseButton.js.map +1 -1
  107. package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
  108. package/lib/components/shared/base/BasePanel.js.map +1 -1
  109. package/lib/components/shared/base/BaseText.js.map +1 -1
  110. package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
  111. package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
  112. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  113. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  114. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  115. package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
  116. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  117. package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
  118. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  119. package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
  120. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  121. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  122. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  123. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  124. package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
  125. package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
  126. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  127. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  128. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  129. package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
  130. package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
  131. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  132. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  133. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  134. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  135. package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
  136. package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
  137. package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
  138. package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
  139. package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
  140. package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
  141. package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
  142. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  143. package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
  144. package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
  145. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  146. package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
  147. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  148. package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
  149. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  150. package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
  151. package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
  152. package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
  153. package/lib/components/shared/three/ui/MenuList.js.map +1 -1
  154. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  155. package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
  156. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  157. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  158. package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
  159. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  160. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  161. package/lib/components/shared/ui/BackButton.js.map +1 -1
  162. package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
  163. package/lib/components/shared/ui/CombatTimer.js.map +1 -1
  164. package/lib/components/shared/ui/ErrorModal.js.map +1 -1
  165. package/lib/components/shared/ui/LoadingState.js.map +1 -1
  166. package/lib/components/shared/ui/SplashScreen.js +2 -2
  167. package/lib/components/shared/ui/SplashScreen.js.map +1 -1
  168. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  169. package/lib/components/shared/ui/VolumeControl.js.map +1 -1
  170. package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
  171. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  172. package/lib/constants/bodyDimensions.js.map +1 -1
  173. package/lib/constants/bodyRenderingConstants.js.map +1 -1
  174. package/lib/data/archetypeClothing.js.map +1 -1
  175. package/lib/data/archetypePhysicalAttributes.js.map +1 -1
  176. package/lib/data/techniqueMappings.js.map +1 -1
  177. package/lib/data/techniques.js.map +1 -1
  178. package/lib/hooks/useActionFeedback.js.map +1 -1
  179. package/lib/hooks/useBalanceAnimations.js.map +1 -1
  180. package/lib/hooks/useCombatTimer.js.map +1 -1
  181. package/lib/hooks/useDebounce.js.map +1 -1
  182. package/lib/hooks/useHUDLayout.js.map +1 -1
  183. package/lib/hooks/useHandPoseTransitions.js.map +1 -1
  184. package/lib/hooks/useKeyboardControls.js.map +1 -1
  185. package/lib/hooks/useMatchCountdown.js.map +1 -1
  186. package/lib/hooks/useMuscleActivation.js.map +1 -1
  187. package/lib/hooks/usePauseMenu.js.map +1 -1
  188. package/lib/hooks/usePlayerAnimation.js.map +1 -1
  189. package/lib/hooks/useResponsiveLayout.js.map +1 -1
  190. package/lib/hooks/useRoundTransition.js.map +1 -1
  191. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  192. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  193. package/lib/hooks/useThrottle.js.map +1 -1
  194. package/lib/hooks/useTouchControls.js.map +1 -1
  195. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  196. package/lib/hooks/useWindowSize.js.map +1 -1
  197. package/lib/systems/CombatSystem.js.map +1 -1
  198. package/lib/systems/EffectCalculator.js.map +1 -1
  199. package/lib/systems/LayoutSystem.js.map +1 -1
  200. package/lib/systems/PlayerEffectManager.js.map +1 -1
  201. package/lib/systems/ResponsiveScaling.js.map +1 -1
  202. package/lib/systems/TrigramSystem.js.map +1 -1
  203. package/lib/systems/VitalPointSystem.js.map +1 -1
  204. package/lib/systems/ai/AIPersonality.js.map +1 -1
  205. package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
  206. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  207. package/lib/systems/ai/ComboSystem.js.map +1 -1
  208. package/lib/systems/ai/DecisionTree.js.map +1 -1
  209. package/lib/systems/ai/TrainingAI.js.map +1 -1
  210. package/lib/systems/ai/types.js.map +1 -1
  211. package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
  212. package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
  213. package/lib/systems/animation/builders/HandPoses.js.map +1 -1
  214. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  215. package/lib/systems/animation/builders/KeyframeInterpolation.js +3 -90
  216. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  217. package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
  218. package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
  219. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  220. package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
  221. package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
  222. package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
  223. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  224. package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
  225. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  226. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  227. package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
  228. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  229. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  230. package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
  231. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  232. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  233. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  234. package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
  235. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  236. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  237. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  238. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  239. package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
  240. package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
  241. package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
  242. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  243. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  244. package/lib/systems/animation/core/types.js.map +1 -1
  245. package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
  246. package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
  247. package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
  248. package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
  249. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  250. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  251. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  252. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  253. package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
  254. package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
  255. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  256. package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
  257. package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
  258. package/lib/systems/bodypart/types.js.map +1 -1
  259. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  260. package/lib/systems/breathing/feedback.js.map +1 -1
  261. package/lib/systems/breathing/integration.js.map +1 -1
  262. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  263. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  264. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  265. package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
  266. package/lib/systems/combat/FallIntegration.js.map +1 -1
  267. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  268. package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
  269. package/lib/systems/combat/PainResponseSystem.js.map +1 -1
  270. package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
  271. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  272. package/lib/systems/combat/typeGuards.js.map +1 -1
  273. package/lib/systems/effects.js.map +1 -1
  274. package/lib/systems/game.js.map +1 -1
  275. package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
  276. package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
  277. package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
  278. package/lib/systems/movement/integration.js.map +1 -1
  279. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  280. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  281. package/lib/systems/physics/CoordinateMapper.js.map +1 -1
  282. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  283. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  284. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  285. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  286. package/lib/systems/trigram/KoreanCulture.js.map +1 -1
  287. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  288. package/lib/systems/trigram/StanceManager.js.map +1 -1
  289. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  290. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  291. package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
  292. package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
  293. package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
  294. package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
  295. package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
  296. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  297. package/lib/systems/trigram/techniques/index.js.map +1 -1
  298. package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
  299. package/lib/systems/trigram/types.js.map +1 -1
  300. package/lib/systems/types.js.map +1 -1
  301. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  302. package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
  303. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  304. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  305. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  306. package/lib/types/AccessibilityTypes.js.map +1 -1
  307. package/lib/types/PhysicsTypes.js.map +1 -1
  308. package/lib/types/common.js.map +1 -1
  309. package/lib/types/constants/colors.js.map +1 -1
  310. package/lib/types/constants/designSystem.js.map +1 -1
  311. package/lib/types/constants/layout.js.map +1 -1
  312. package/lib/types/constants/performance.js.map +1 -1
  313. package/lib/types/constants/typography.js.map +1 -1
  314. package/lib/types/facial.js.map +1 -1
  315. package/lib/types/hand-animation.js.map +1 -1
  316. package/lib/types/injury.js.map +1 -1
  317. package/lib/types/physics.js.map +1 -1
  318. package/lib/types/skeletal.js.map +1 -1
  319. package/lib/types/techniqueId.js.map +1 -1
  320. package/lib/utils/accessibility.js.map +1 -1
  321. package/lib/utils/arenaWorldDimensions.js.map +1 -1
  322. package/lib/utils/assetConfig.js.map +1 -1
  323. package/lib/utils/characterScaling.js.map +1 -1
  324. package/lib/utils/colorHelpers.js.map +1 -1
  325. package/lib/utils/colorUtils.js.map +1 -1
  326. package/lib/utils/combatReadiness.js.map +1 -1
  327. package/lib/utils/controlMapping.js.map +1 -1
  328. package/lib/utils/deviceDetection.js.map +1 -1
  329. package/lib/utils/effectUtils.js.map +1 -1
  330. package/lib/utils/fabricTextures.js.map +1 -1
  331. package/lib/utils/hapticFeedback.js.map +1 -1
  332. package/lib/utils/haptics.js.map +1 -1
  333. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  334. package/lib/utils/inputSystem.js.map +1 -1
  335. package/lib/utils/koreanThemeHelpers.js.map +1 -1
  336. package/lib/utils/math.js.map +1 -1
  337. package/lib/utils/mobileLayoutHelpers.js.map +1 -1
  338. package/lib/utils/mobileUIUtils.js.map +1 -1
  339. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  340. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  341. package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
  342. package/lib/utils/performanceOptimization.js.map +1 -1
  343. package/lib/utils/player3DHelpers.js.map +1 -1
  344. package/lib/utils/playerUtils.js.map +1 -1
  345. package/lib/utils/responsiveLayout.js.map +1 -1
  346. package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
  347. package/lib/utils/responsiveOrientationConstants.js.map +1 -1
  348. package/lib/utils/safeAreaUtils.js.map +1 -1
  349. package/lib/utils/sharedPhysicsConfig.js.map +1 -1
  350. package/lib/utils/skeletonScaling.js.map +1 -1
  351. package/lib/utils/stanceHelpers.js.map +1 -1
  352. package/lib/utils/threeObjectPool.js.map +1 -1
  353. package/lib/utils/visualEffects.js.map +1 -1
  354. package/package.json +8 -8
@@ -1 +1 @@
1
- {"version":3,"file":"TrainingAI.js","names":[],"sources":["../../../src/systems/ai/TrainingAI.ts"],"sourcesContent":["/**\n * TrainingAI - AI opponent system for training mode\n *\n * Integrates AIPersonality, DecisionTree, and ComboSystem to create\n * a configurable AI opponent for training scenarios.\n *\n * **Korean Philosophy (훈련 AI 철학)**:\n * - 단계적 난이도 (Stepped Difficulty): Progressive challenge levels\n * - 교육적 피드백 (Educational Feedback): AI teaches through behavior\n * - 적응형 전투 (Adaptive Combat): AI adjusts to player skill\n */\n\nimport { Position, TrigramStance } from \"@/types\";\nimport { PlayerState } from \"../player\";\nimport { AdaptiveDifficulty } from \"./AdaptiveDifficulty\";\nimport { AIPersonality, AI_PERSONALITIES } from \"./AIPersonality\";\nimport { AIComboSystem } from \"./ComboSystem\";\nimport { AIDecision, AIDecisionTree, CombatContext } from \"./DecisionTree\";\n\n/**\n * Training AI difficulty levels\n */\nexport type AITrainingDifficulty = \"easy\" | \"medium\" | \"hard\";\n\n/**\n * Training AI state\n */\nexport interface TrainingAIState {\n readonly difficulty: AITrainingDifficulty;\n readonly personality: AIPersonality;\n readonly currentAction: AIDecision | null;\n readonly position: Position;\n readonly stance: TrigramStance;\n readonly isActive: boolean;\n readonly reactionTime: number; // ms delay before responding\n readonly blockChance: number; // 0.0-1.0\n readonly counterChance: number; // 0.0-1.0\n readonly lastActionTime: number;\n}\n\n/**\n * Training AI configuration based on difficulty\n */\ninterface DifficultyConfig {\n readonly reactionTime: number;\n readonly blockChance: number;\n readonly counterChance: number;\n readonly aggressionMultiplier: number;\n readonly aiSkillLevel: number; // For DecisionTree\n}\n\nconst DIFFICULTY_CONFIGS: Record<AITrainingDifficulty, DifficultyConfig> = {\n easy: {\n reactionTime: 500, // 500ms reaction delay\n blockChance: 0.3,\n counterChance: 0.1,\n aggressionMultiplier: 0.6,\n aiSkillLevel: 0.3,\n },\n medium: {\n reactionTime: 300, // 300ms reaction delay\n blockChance: 0.5,\n counterChance: 0.3,\n aggressionMultiplier: 0.8,\n aiSkillLevel: 0.6,\n },\n hard: {\n reactionTime: 150, // 150ms reaction delay\n blockChance: 0.7,\n counterChance: 0.5,\n aggressionMultiplier: 1.0,\n aiSkillLevel: 0.9,\n },\n};\n\n/**\n * TrainingAI System\n *\n * Manages AI opponent behavior in training mode using existing AI systems.\n * Provides configurable difficulty and realistic martial arts behavior.\n */\nexport class TrainingAI {\n private state: TrainingAIState;\n private decisionTree: AIDecisionTree;\n private comboSystem: AIComboSystem;\n private adaptiveDifficulty: AdaptiveDifficulty;\n private actionDelayTimer: number = 0;\n\n constructor(\n difficulty: AITrainingDifficulty = \"medium\",\n initialPosition: Position = { x: 5, y: 0 },\n personalityKey?: string,\n ) {\n // Select personality based on difficulty or use provided key\n const personality = personalityKey\n ? (AI_PERSONALITIES[personalityKey] ?? AI_PERSONALITIES.BALANCED_FIGHTER)\n : this.selectPersonalityForDifficulty(difficulty);\n\n const config = DIFFICULTY_CONFIGS[difficulty];\n\n this.state = {\n difficulty,\n personality,\n currentAction: null,\n position: initialPosition,\n stance: personality.favoredStances[0] ?? TrigramStance.GEON,\n isActive: false,\n reactionTime: config.reactionTime,\n blockChance: config.blockChance,\n counterChance: config.counterChance,\n lastActionTime: 0,\n };\n\n // Initialize AI systems\n this.decisionTree = new AIDecisionTree();\n this.decisionTree.setDifficultyLevel(config.aiSkillLevel);\n\n this.comboSystem = new AIComboSystem();\n this.adaptiveDifficulty = new AdaptiveDifficulty();\n }\n\n /**\n * Select appropriate personality for difficulty level\n */\n private selectPersonalityForDifficulty(\n difficulty: AITrainingDifficulty,\n ): AIPersonality {\n switch (difficulty) {\n case \"easy\":\n return AI_PERSONALITIES.DEFENSIVE_SPECIALIST; // Less aggressive\n case \"medium\":\n return AI_PERSONALITIES.BALANCED_FIGHTER; // Balanced approach\n case \"hard\":\n return AI_PERSONALITIES.AGGRESSIVE_STRIKER; // More aggressive\n default:\n return AI_PERSONALITIES.BALANCED_FIGHTER;\n }\n }\n\n /**\n * Activate AI opponent\n */\n activate(): void {\n this.state = {\n ...this.state,\n isActive: true,\n lastActionTime: Date.now(),\n };\n }\n\n /**\n * Deactivate AI opponent\n */\n deactivate(): void {\n this.state = {\n ...this.state,\n isActive: false,\n currentAction: null,\n };\n }\n\n /**\n * Update AI behavior (60fps game loop)\n *\n * Internal method called each frame by the TrainingAI system to process AI decision-making and update state.\n * Respects reaction time delays based on difficulty level.\n *\n * @param deltaTime - Time since last frame in seconds\n * @param playerState - Current player state\n * @param aiPlayerState - Current AI player state (for combat systems)\n * @returns Updated AI decision or null if inactive/delayed\n */\n update(\n deltaTime: number,\n playerState: PlayerState,\n aiPlayerState: PlayerState,\n ): AIDecision | null {\n if (!this.state.isActive) {\n return null;\n }\n\n const now = Date.now();\n\n // Update action delay timer\n this.actionDelayTimer = Math.max(\n 0,\n this.actionDelayTimer - deltaTime * 1000,\n );\n\n // Check if enough time has passed since last decision (reaction time)\n if (this.actionDelayTimer > 0) {\n return this.state.currentAction;\n }\n\n // Build combat context\n const context: CombatContext = {\n playerPosition: this.state.position,\n opponentPosition: playerState.position,\n playerHealth: aiPlayerState.health,\n playerMaxHealth: aiPlayerState.maxHealth,\n playerKi: aiPlayerState.ki,\n playerMaxKi: aiPlayerState.maxKi,\n playerStamina: aiPlayerState.stamina,\n playerMaxStamina: aiPlayerState.maxStamina,\n opponentHealth: playerState.health,\n opponentStance: playerState.currentStance,\n playerStance: this.state.stance,\n distanceToOpponent: this.calculateDistance(\n this.state.position,\n playerState.position,\n ),\n timeInMatch: (now - this.state.lastActionTime) / 1000,\n isOpponentAttacking: this.isPlayerAttacking(playerState),\n recentDamageTaken: aiPlayerState.totalDamageReceived,\n arenaBounds: {\n x: -8,\n y: -6,\n width: 16,\n height: 12,\n worldWidthMeters: 10, // Training area is 10m wide\n worldDepthMeters: 7.5, // Training area is 7.5m deep (4:3 ratio)\n },\n };\n\n // Get adjusted personality from adaptive difficulty\n const adjustedPersonality = this.adjustPersonalityForTraining(\n this.state.personality,\n );\n\n // Make decision using decision tree\n const decision = this.decisionTree.makeDecision(\n context,\n adjustedPersonality,\n this.comboSystem,\n );\n\n // Apply reaction time delay for next action\n this.actionDelayTimer = this.state.reactionTime;\n\n // Update state with new decision\n this.state = {\n ...this.state,\n currentAction: decision,\n lastActionTime: now,\n };\n\n return decision;\n }\n\n /**\n * Adjust personality based on training context\n */\n private adjustPersonalityForTraining(\n basePersonality: AIPersonality,\n ): AIPersonality {\n const config = DIFFICULTY_CONFIGS[this.state.difficulty];\n\n // Apply difficulty multiplier to aggression\n return {\n ...basePersonality,\n aggressionLevel:\n basePersonality.aggressionLevel * config.aggressionMultiplier,\n defensePreference:\n basePersonality.defensePreference * (2 - config.aggressionMultiplier),\n };\n }\n\n /**\n * Calculate distance between two positions\n */\n private calculateDistance(pos1: Position, pos2: Position): number {\n const dx = pos2.x - pos1.x;\n const dy = pos2.y - pos1.y;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Determine if player is currently attacking\n */\n private isPlayerAttacking(playerState: PlayerState): boolean {\n const timeSinceLastAction = Date.now() - playerState.lastActionTime;\n return timeSinceLastAction < 500; // 500ms attack window\n }\n\n /**\n * Update AI position (for movement actions)\n */\n updatePosition(newPosition: Position): void {\n this.state = {\n ...this.state,\n position: newPosition,\n };\n }\n\n /**\n * Update AI stance\n */\n updateStance(newStance: TrigramStance): void {\n this.state = {\n ...this.state,\n stance: newStance,\n };\n }\n\n /**\n * Set difficulty\n */\n setDifficulty(difficulty: AITrainingDifficulty): void {\n const config = DIFFICULTY_CONFIGS[difficulty];\n const personality = this.selectPersonalityForDifficulty(difficulty);\n\n this.state = {\n ...this.state,\n difficulty,\n personality,\n reactionTime: config.reactionTime,\n blockChance: config.blockChance,\n counterChance: config.counterChance,\n };\n\n this.decisionTree.setDifficultyLevel(config.aiSkillLevel);\n }\n\n /**\n * Reset AI state\n */\n reset(): void {\n this.decisionTree.reset();\n this.comboSystem.resetCombo();\n this.actionDelayTimer = 0;\n\n this.state = {\n ...this.state,\n currentAction: null,\n lastActionTime: Date.now(),\n };\n }\n\n /**\n * Get current AI state (for display/debugging)\n */\n getState(): Readonly<TrainingAIState> {\n return this.state;\n }\n\n /**\n * Check if AI should block incoming attack\n */\n shouldBlock(): boolean {\n return Math.random() < this.state.blockChance;\n }\n\n /**\n * Check if AI should counter incoming attack\n */\n shouldCounter(): boolean {\n return Math.random() < this.state.counterChance;\n }\n\n /**\n * Get AI's current decision for debugging\n */\n getCurrentDecision(): AIDecision | null {\n return this.state.currentAction;\n }\n\n /**\n * Update adaptive difficulty based on match performance\n */\n updateAdaptiveDifficulty(matchData: {\n readonly hitsLanded: number;\n readonly totalAttacks: number;\n readonly combosExecuted: number;\n readonly perfectBlockCount: number;\n readonly avgReactionTimeMs: number;\n readonly vitalPointsHit: number;\n readonly effectiveStanceChanges: number;\n readonly damageDealt: number;\n readonly damageTaken: number;\n }): void {\n this.adaptiveDifficulty.updateSkillMetrics(matchData);\n\n // Optionally adjust difficulty based on adaptive system\n // For training, we might want to keep difficulty stable\n }\n}\n\nexport default TrainingAI;\n"],"mappings":"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"}
1
+ {"version":3,"file":"TrainingAI.js","names":[],"sources":["../../../src/systems/ai/TrainingAI.ts"],"sourcesContent":["/**\n * TrainingAI - AI opponent system for training mode\n *\n * Integrates AIPersonality, DecisionTree, and ComboSystem to create\n * a configurable AI opponent for training scenarios.\n *\n * **Korean Philosophy (훈련 AI 철학)**:\n * - 단계적 난이도 (Stepped Difficulty): Progressive challenge levels\n * - 교육적 피드백 (Educational Feedback): AI teaches through behavior\n * - 적응형 전투 (Adaptive Combat): AI adjusts to player skill\n */\n\nimport { Position, TrigramStance } from \"@/types\";\nimport { PlayerState } from \"../player\";\nimport { AdaptiveDifficulty } from \"./AdaptiveDifficulty\";\nimport { AIPersonality, AI_PERSONALITIES } from \"./AIPersonality\";\nimport { AIComboSystem } from \"./ComboSystem\";\nimport { AIDecision, AIDecisionTree, CombatContext } from \"./DecisionTree\";\n\n/**\n * Training AI difficulty levels\n */\nexport type AITrainingDifficulty = \"easy\" | \"medium\" | \"hard\";\n\n/**\n * Training AI state\n */\nexport interface TrainingAIState {\n readonly difficulty: AITrainingDifficulty;\n readonly personality: AIPersonality;\n readonly currentAction: AIDecision | null;\n readonly position: Position;\n readonly stance: TrigramStance;\n readonly isActive: boolean;\n readonly reactionTime: number; // ms delay before responding\n readonly blockChance: number; // 0.0-1.0\n readonly counterChance: number; // 0.0-1.0\n readonly lastActionTime: number;\n}\n\n/**\n * Training AI configuration based on difficulty\n */\ninterface DifficultyConfig {\n readonly reactionTime: number;\n readonly blockChance: number;\n readonly counterChance: number;\n readonly aggressionMultiplier: number;\n readonly aiSkillLevel: number; // For DecisionTree\n}\n\nconst DIFFICULTY_CONFIGS: Record<AITrainingDifficulty, DifficultyConfig> = {\n easy: {\n reactionTime: 500, // 500ms reaction delay\n blockChance: 0.3,\n counterChance: 0.1,\n aggressionMultiplier: 0.6,\n aiSkillLevel: 0.3,\n },\n medium: {\n reactionTime: 300, // 300ms reaction delay\n blockChance: 0.5,\n counterChance: 0.3,\n aggressionMultiplier: 0.8,\n aiSkillLevel: 0.6,\n },\n hard: {\n reactionTime: 150, // 150ms reaction delay\n blockChance: 0.7,\n counterChance: 0.5,\n aggressionMultiplier: 1.0,\n aiSkillLevel: 0.9,\n },\n};\n\n/**\n * TrainingAI System\n *\n * Manages AI opponent behavior in training mode using existing AI systems.\n * Provides configurable difficulty and realistic martial arts behavior.\n */\nexport class TrainingAI {\n private state: TrainingAIState;\n private decisionTree: AIDecisionTree;\n private comboSystem: AIComboSystem;\n private adaptiveDifficulty: AdaptiveDifficulty;\n private actionDelayTimer: number = 0;\n\n constructor(\n difficulty: AITrainingDifficulty = \"medium\",\n initialPosition: Position = { x: 5, y: 0 },\n personalityKey?: string,\n ) {\n // Select personality based on difficulty or use provided key\n const personality = personalityKey\n ? (AI_PERSONALITIES[personalityKey] ?? AI_PERSONALITIES.BALANCED_FIGHTER)\n : this.selectPersonalityForDifficulty(difficulty);\n\n const config = DIFFICULTY_CONFIGS[difficulty];\n\n this.state = {\n difficulty,\n personality,\n currentAction: null,\n position: initialPosition,\n stance: personality.favoredStances[0] ?? TrigramStance.GEON,\n isActive: false,\n reactionTime: config.reactionTime,\n blockChance: config.blockChance,\n counterChance: config.counterChance,\n lastActionTime: 0,\n };\n\n // Initialize AI systems\n this.decisionTree = new AIDecisionTree();\n this.decisionTree.setDifficultyLevel(config.aiSkillLevel);\n\n this.comboSystem = new AIComboSystem();\n this.adaptiveDifficulty = new AdaptiveDifficulty();\n }\n\n /**\n * Select appropriate personality for difficulty level\n */\n private selectPersonalityForDifficulty(\n difficulty: AITrainingDifficulty,\n ): AIPersonality {\n switch (difficulty) {\n case \"easy\":\n return AI_PERSONALITIES.DEFENSIVE_SPECIALIST; // Less aggressive\n case \"medium\":\n return AI_PERSONALITIES.BALANCED_FIGHTER; // Balanced approach\n case \"hard\":\n return AI_PERSONALITIES.AGGRESSIVE_STRIKER; // More aggressive\n default:\n return AI_PERSONALITIES.BALANCED_FIGHTER;\n }\n }\n\n /**\n * Activate AI opponent\n */\n activate(): void {\n this.state = {\n ...this.state,\n isActive: true,\n lastActionTime: Date.now(),\n };\n }\n\n /**\n * Deactivate AI opponent\n */\n deactivate(): void {\n this.state = {\n ...this.state,\n isActive: false,\n currentAction: null,\n };\n }\n\n /**\n * Update AI behavior (60fps game loop)\n *\n * Internal method called each frame by the TrainingAI system to process AI decision-making and update state.\n * Respects reaction time delays based on difficulty level.\n *\n * @param deltaTime - Time since last frame in seconds\n * @param playerState - Current player state\n * @param aiPlayerState - Current AI player state (for combat systems)\n * @returns Updated AI decision or null if inactive/delayed\n */\n update(\n deltaTime: number,\n playerState: PlayerState,\n aiPlayerState: PlayerState,\n ): AIDecision | null {\n if (!this.state.isActive) {\n return null;\n }\n\n const now = Date.now();\n\n // Update action delay timer\n this.actionDelayTimer = Math.max(\n 0,\n this.actionDelayTimer - deltaTime * 1000,\n );\n\n // Check if enough time has passed since last decision (reaction time)\n if (this.actionDelayTimer > 0) {\n return this.state.currentAction;\n }\n\n // Build combat context\n const context: CombatContext = {\n playerPosition: this.state.position,\n opponentPosition: playerState.position,\n playerHealth: aiPlayerState.health,\n playerMaxHealth: aiPlayerState.maxHealth,\n playerKi: aiPlayerState.ki,\n playerMaxKi: aiPlayerState.maxKi,\n playerStamina: aiPlayerState.stamina,\n playerMaxStamina: aiPlayerState.maxStamina,\n opponentHealth: playerState.health,\n opponentStance: playerState.currentStance,\n playerStance: this.state.stance,\n distanceToOpponent: this.calculateDistance(\n this.state.position,\n playerState.position,\n ),\n timeInMatch: (now - this.state.lastActionTime) / 1000,\n isOpponentAttacking: this.isPlayerAttacking(playerState),\n recentDamageTaken: aiPlayerState.totalDamageReceived,\n arenaBounds: {\n x: -8,\n y: -6,\n width: 16,\n height: 12,\n worldWidthMeters: 10, // Training area is 10m wide\n worldDepthMeters: 7.5, // Training area is 7.5m deep (4:3 ratio)\n },\n };\n\n // Get adjusted personality from adaptive difficulty\n const adjustedPersonality = this.adjustPersonalityForTraining(\n this.state.personality,\n );\n\n // Make decision using decision tree\n const decision = this.decisionTree.makeDecision(\n context,\n adjustedPersonality,\n this.comboSystem,\n );\n\n // Apply reaction time delay for next action\n this.actionDelayTimer = this.state.reactionTime;\n\n // Update state with new decision\n this.state = {\n ...this.state,\n currentAction: decision,\n lastActionTime: now,\n };\n\n return decision;\n }\n\n /**\n * Adjust personality based on training context\n */\n private adjustPersonalityForTraining(\n basePersonality: AIPersonality,\n ): AIPersonality {\n const config = DIFFICULTY_CONFIGS[this.state.difficulty];\n\n // Apply difficulty multiplier to aggression\n return {\n ...basePersonality,\n aggressionLevel:\n basePersonality.aggressionLevel * config.aggressionMultiplier,\n defensePreference:\n basePersonality.defensePreference * (2 - config.aggressionMultiplier),\n };\n }\n\n /**\n * Calculate distance between two positions\n */\n private calculateDistance(pos1: Position, pos2: Position): number {\n const dx = pos2.x - pos1.x;\n const dy = pos2.y - pos1.y;\n return Math.sqrt(dx * dx + dy * dy);\n }\n\n /**\n * Determine if player is currently attacking\n */\n private isPlayerAttacking(playerState: PlayerState): boolean {\n const timeSinceLastAction = Date.now() - playerState.lastActionTime;\n return timeSinceLastAction < 500; // 500ms attack window\n }\n\n /**\n * Update AI position (for movement actions)\n */\n updatePosition(newPosition: Position): void {\n this.state = {\n ...this.state,\n position: newPosition,\n };\n }\n\n /**\n * Update AI stance\n */\n updateStance(newStance: TrigramStance): void {\n this.state = {\n ...this.state,\n stance: newStance,\n };\n }\n\n /**\n * Set difficulty\n */\n setDifficulty(difficulty: AITrainingDifficulty): void {\n const config = DIFFICULTY_CONFIGS[difficulty];\n const personality = this.selectPersonalityForDifficulty(difficulty);\n\n this.state = {\n ...this.state,\n difficulty,\n personality,\n reactionTime: config.reactionTime,\n blockChance: config.blockChance,\n counterChance: config.counterChance,\n };\n\n this.decisionTree.setDifficultyLevel(config.aiSkillLevel);\n }\n\n /**\n * Reset AI state\n */\n reset(): void {\n this.decisionTree.reset();\n this.comboSystem.resetCombo();\n this.actionDelayTimer = 0;\n\n this.state = {\n ...this.state,\n currentAction: null,\n lastActionTime: Date.now(),\n };\n }\n\n /**\n * Get current AI state (for display/debugging)\n */\n getState(): Readonly<TrainingAIState> {\n return this.state;\n }\n\n /**\n * Check if AI should block incoming attack\n */\n shouldBlock(): boolean {\n return Math.random() < this.state.blockChance;\n }\n\n /**\n * Check if AI should counter incoming attack\n */\n shouldCounter(): boolean {\n return Math.random() < this.state.counterChance;\n }\n\n /**\n * Get AI's current decision for debugging\n */\n getCurrentDecision(): AIDecision | null {\n return this.state.currentAction;\n }\n\n /**\n * Update adaptive difficulty based on match performance\n */\n updateAdaptiveDifficulty(matchData: {\n readonly hitsLanded: number;\n readonly totalAttacks: number;\n readonly combosExecuted: number;\n readonly perfectBlockCount: number;\n readonly avgReactionTimeMs: number;\n readonly vitalPointsHit: number;\n readonly effectiveStanceChanges: number;\n readonly damageDealt: number;\n readonly damageTaken: number;\n }): void {\n this.adaptiveDifficulty.updateSkillMetrics(matchData);\n\n // Optionally adjust difficulty based on adaptive system\n // For training, we might want to keep difficulty stable\n }\n}\n\nexport default TrainingAI;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","names":[],"sources":["../../../src/systems/ai/types.ts"],"sourcesContent":["/**\n * AI Combat System Type Definitions\n *\n * Core types for AI decision-making and combat behavior.\n * Separated to avoid circular dependencies between modules.\n *\n * @module systems/ai/types\n * @category AI Combat\n * @korean AI 전투 시스템 타입 정의\n */\n\nimport { Position, TrigramStance } from \"@/types\";\nimport { BalanceState } from \"@/types/player-visual\";\nimport type { CounterOpportunity } from \"@/types/physics\";\n\n/**\n * AI action types\n *\n * @korean AI 행동 유형\n */\nexport enum AIActionType {\n ATTACK = \"attack\",\n TECHNIQUE = \"technique\",\n DEFEND = \"defend\",\n COUNTER = \"counter\",\n RETREAT = \"retreat\",\n APPROACH = \"approach\",\n CIRCLE = \"circle\",\n STANCE_CHANGE = \"stance_change\",\n FEINT = \"feint\",\n WAIT = \"wait\",\n COMBO = \"combo\",\n}\n\n/**\n * AI decision result\n *\n * @korean AI 결정 결과\n */\nexport interface AIDecision {\n readonly action: AIActionType;\n readonly targetPosition?: Position;\n readonly targetStance?: TrigramStance;\n readonly targetVitalPoint?: string; // ID of vital point to target\n readonly priority: number; // 0-10: Decision confidence\n readonly reason: string; // For debugging/analysis\n}\n\n/**\n * Vulnerability assessment context for exploitation tactics\n *\n * Comprehensive analysis of opponent's defenseless states:\n * - **isHelpless**: Balance === HELPLESS (90% takedown priority)\n * - **isVulnerable**: Balance === VULNERABLE or HELPLESS (70% aggressive attack priority)\n * - **isShaken**: Balance === SHAKEN, VULNERABLE, or HELPLESS (50% pressure tactics priority)\n * - **hasLowStamina**: Stamina < 20% (60% exploitation priority)\n * - **hasNoKi**: Ki < 10% (50% technique spam priority)\n * - **overallVulnerability**: Composite vulnerability score (0.0-1.0)\n *\n * @korean 취약성 평가 컨텍스트\n */\nexport interface VulnerabilityContext {\n readonly isHelpless: boolean; // balance === HELPLESS\n readonly isVulnerable: boolean; // balance === VULNERABLE or HELPLESS\n readonly isShaken: boolean; // balance === SHAKEN, VULNERABLE, or HELPLESS\n readonly hasLowStamina: boolean; // stamina < 20%\n readonly hasNoKi: boolean; // ki < 10%\n readonly overallVulnerability: number; // 0.0-1.0 composite score\n}\n\n/**\n * Combat context for decision making\n *\n * @korean 전투 컨텍스트\n */\nexport interface CombatContext {\n readonly playerPosition: Position;\n readonly opponentPosition: Position;\n readonly playerHealth: number;\n readonly playerMaxHealth: number;\n readonly playerKi: number;\n readonly playerMaxKi: number;\n readonly playerStamina: number;\n readonly playerMaxStamina: number;\n readonly opponentHealth: number;\n readonly opponentMaxHealth?: number; // Opponent max health (if undefined, assumes symmetric with playerMaxHealth)\n readonly opponentStance: TrigramStance;\n readonly playerStance: TrigramStance;\n readonly distanceToOpponent: number;\n readonly timeInMatch: number;\n readonly isOpponentAttacking: boolean;\n readonly recentDamageTaken: number;\n readonly opponentBalance?: BalanceState; // Balance state: \"READY\" | \"SHAKEN\" | \"VULNERABLE\" | \"HELPLESS\"\n readonly opponentStamina?: number; // Opponent stamina for exploitation\n readonly opponentMaxStamina?: number; // Opponent max stamina\n readonly opponentKi?: number; // Opponent ki for exploitation\n readonly opponentMaxKi?: number; // Opponent max ki\n readonly stanceFatigue?: {\n readonly timeInStance: number; // Milliseconds in current stance\n };\n readonly arenaBounds: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly worldWidthMeters: number; // Arena width in meters for physics calculations\n readonly worldDepthMeters: number; // Arena depth in meters for physics calculations\n };\n /**\n * Detected counter-attack opportunity from opponent's limb exposure.\n * Includes exposed limb, timing window, vulnerability multiplier, and recommended counters.\n * **Korean**: 반격 기회 (Counter Opportunity)\n */\n readonly counterOpportunity?: CounterOpportunity;\n}\n"],"mappings":";;;;;;AAoBA,IAAY,eAAL,yBAAA,cAAA;AACL,cAAA,YAAS;AACT,cAAA,eAAY;AACZ,cAAA,YAAS;AACT,cAAA,aAAU;AACV,cAAA,aAAU;AACV,cAAA,cAAW;AACX,cAAA,YAAS;AACT,cAAA,mBAAgB;AAChB,cAAA,WAAQ;AACR,cAAA,UAAO;AACP,cAAA,WAAQ;;KACT"}
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/systems/ai/types.ts"],"sourcesContent":["/**\n * AI Combat System Type Definitions\n *\n * Core types for AI decision-making and combat behavior.\n * Separated to avoid circular dependencies between modules.\n *\n * @module systems/ai/types\n * @category AI Combat\n * @korean AI 전투 시스템 타입 정의\n */\n\nimport { Position, TrigramStance } from \"@/types\";\nimport { BalanceState } from \"@/types/player-visual\";\nimport type { CounterOpportunity } from \"@/types/physics\";\n\n/**\n * AI action types\n *\n * @korean AI 행동 유형\n */\nexport enum AIActionType {\n ATTACK = \"attack\",\n TECHNIQUE = \"technique\",\n DEFEND = \"defend\",\n COUNTER = \"counter\",\n RETREAT = \"retreat\",\n APPROACH = \"approach\",\n CIRCLE = \"circle\",\n STANCE_CHANGE = \"stance_change\",\n FEINT = \"feint\",\n WAIT = \"wait\",\n COMBO = \"combo\",\n}\n\n/**\n * AI decision result\n *\n * @korean AI 결정 결과\n */\nexport interface AIDecision {\n readonly action: AIActionType;\n readonly targetPosition?: Position;\n readonly targetStance?: TrigramStance;\n readonly targetVitalPoint?: string; // ID of vital point to target\n readonly priority: number; // 0-10: Decision confidence\n readonly reason: string; // For debugging/analysis\n}\n\n/**\n * Vulnerability assessment context for exploitation tactics\n *\n * Comprehensive analysis of opponent's defenseless states:\n * - **isHelpless**: Balance === HELPLESS (90% takedown priority)\n * - **isVulnerable**: Balance === VULNERABLE or HELPLESS (70% aggressive attack priority)\n * - **isShaken**: Balance === SHAKEN, VULNERABLE, or HELPLESS (50% pressure tactics priority)\n * - **hasLowStamina**: Stamina < 20% (60% exploitation priority)\n * - **hasNoKi**: Ki < 10% (50% technique spam priority)\n * - **overallVulnerability**: Composite vulnerability score (0.0-1.0)\n *\n * @korean 취약성 평가 컨텍스트\n */\nexport interface VulnerabilityContext {\n readonly isHelpless: boolean; // balance === HELPLESS\n readonly isVulnerable: boolean; // balance === VULNERABLE or HELPLESS\n readonly isShaken: boolean; // balance === SHAKEN, VULNERABLE, or HELPLESS\n readonly hasLowStamina: boolean; // stamina < 20%\n readonly hasNoKi: boolean; // ki < 10%\n readonly overallVulnerability: number; // 0.0-1.0 composite score\n}\n\n/**\n * Combat context for decision making\n *\n * @korean 전투 컨텍스트\n */\nexport interface CombatContext {\n readonly playerPosition: Position;\n readonly opponentPosition: Position;\n readonly playerHealth: number;\n readonly playerMaxHealth: number;\n readonly playerKi: number;\n readonly playerMaxKi: number;\n readonly playerStamina: number;\n readonly playerMaxStamina: number;\n readonly opponentHealth: number;\n readonly opponentMaxHealth?: number; // Opponent max health (if undefined, assumes symmetric with playerMaxHealth)\n readonly opponentStance: TrigramStance;\n readonly playerStance: TrigramStance;\n readonly distanceToOpponent: number;\n readonly timeInMatch: number;\n readonly isOpponentAttacking: boolean;\n readonly recentDamageTaken: number;\n readonly opponentBalance?: BalanceState; // Balance state: \"READY\" | \"SHAKEN\" | \"VULNERABLE\" | \"HELPLESS\"\n readonly opponentStamina?: number; // Opponent stamina for exploitation\n readonly opponentMaxStamina?: number; // Opponent max stamina\n readonly opponentKi?: number; // Opponent ki for exploitation\n readonly opponentMaxKi?: number; // Opponent max ki\n readonly stanceFatigue?: {\n readonly timeInStance: number; // Milliseconds in current stance\n };\n readonly arenaBounds: {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n readonly worldWidthMeters: number; // Arena width in meters for physics calculations\n readonly worldDepthMeters: number; // Arena depth in meters for physics calculations\n };\n /**\n * Detected counter-attack opportunity from opponent's limb exposure.\n * Includes exposed limb, timing window, vulnerability multiplier, and recommended counters.\n * **Korean**: 반격 기회 (Counter Opportunity)\n */\n readonly counterOpportunity?: CounterOpportunity;\n}\n"],"mappings":";;;;;;AAoBA,IAAY,eAAL,yBAAA,cAAA;CACL,aAAA,YAAS;CACT,aAAA,eAAY;CACZ,aAAA,YAAS;CACT,aAAA,aAAU;CACV,aAAA,aAAU;CACV,aAAA,cAAW;CACX,aAAA,YAAS;CACT,aAAA,mBAAgB;CAChB,aAAA,WAAQ;CACR,aAAA,UAAO;CACP,aAAA,WAAQ;;KACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"AnimationBuilder.js","names":[],"sources":["../../../../src/systems/animation/builders/AnimationBuilder.ts"],"sourcesContent":["/**\n * Animation Builder - Fluent API for creating skeletal animations\n *\n * Provides a cleaner, more maintainable way to define animations with\n * reduced boilerplate and better readability.\n *\n * @module systems/animation/AnimationBuilder\n * @category Animation System\n * @korean 애니메이션빌더\n */\n\nimport * as THREE from \"three\";\nimport type { AnimationKeyframe, SkeletalAnimation } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\n\n/**\n * Keyframe builder for fluent keyframe construction\n * @korean 키프레임빌더\n */\nclass KeyframeBuilder {\n private time: number;\n private easing: string;\n private boneRotations: Map<BoneName, THREE.Euler>;\n private bonePositions: Map<BoneName, THREE.Vector3>;\n private parentBuilder: AnimationBuilder | null = null;\n\n constructor(time: number, easing: string = \"linear\") {\n this.time = time;\n this.easing = easing;\n this.boneRotations = new Map();\n this.bonePositions = new Map();\n }\n\n /**\n * Set parent animation builder (for chaining)\n * @internal\n */\n setParent(parent: AnimationBuilder): this {\n this.parentBuilder = parent;\n return this;\n }\n\n /**\n * Add bone rotation to keyframe\n * @param bone - Bone to rotate\n * @param x - X rotation in radians\n * @param y - Y rotation in radians\n * @param z - Z rotation in radians\n * @param order - Rotation order (default: XYZ)\n * @returns This builder for chaining\n */\n rotate(\n bone: BoneName,\n x: number,\n y: number,\n z: number,\n order: THREE.EulerOrder = \"XYZ\",\n ): this {\n this.boneRotations.set(bone, new THREE.Euler(x, y, z, order));\n return this;\n }\n\n /**\n * Add bone position to keyframe\n * @param bone - Bone to position\n * @param x - X position\n * @param y - Y position\n * @param z - Z position\n * @returns This builder for chaining\n */\n position(bone: BoneName, x: number, y: number, z: number): this {\n this.bonePositions.set(bone, new THREE.Vector3(x, y, z));\n return this;\n }\n\n /**\n * Build the keyframe and return to animation builder\n * @returns Animation builder for chaining\n */\n build(): AnimationBuilder {\n const keyframe: AnimationKeyframe = {\n time: this.time,\n easing: this.easing as \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\",\n boneRotations: this.boneRotations,\n bonePositions: this.bonePositions,\n };\n\n if (this.parentBuilder) {\n this.parentBuilder.addKeyframe(keyframe);\n return this.parentBuilder;\n }\n\n // This indicates incorrect usage of the builder API; parent must be set via setParent(...)\n throw new Error(\n \"KeyframeBuilder.build() called without a parent AnimationBuilder. Ensure setParent(...) is called before build().\",\n );\n }\n}\n\n/**\n * Animation builder for fluent animation construction\n * @korean 애니메이션빌더\n */\nexport class AnimationBuilder {\n private animationName: string;\n private koreanName: string;\n private duration: number;\n private loop: boolean;\n private type: \"attack\" | \"defense\" | \"movement\" | \"idle\";\n private keyframes: AnimationKeyframe[];\n\n private constructor(name: string) {\n this.animationName = name;\n this.koreanName = name;\n this.duration = 1.0;\n this.loop = false;\n this.type = \"idle\";\n this.keyframes = [];\n }\n\n /**\n * Create a new animation builder\n * @param name - Animation name\n * @returns New animation builder\n */\n static create(name: string): AnimationBuilder {\n return new AnimationBuilder(name);\n }\n\n /**\n * Set Korean name for animation\n * @param name - Korean name\n * @returns This builder for chaining\n */\n withKoreanName(name: string): this {\n this.koreanName = name;\n return this;\n }\n\n /**\n * Set animation duration\n * @param seconds - Duration in seconds\n * @returns This builder for chaining\n */\n withDuration(seconds: number): this {\n this.duration = seconds;\n return this;\n }\n\n /**\n * Set animation loop behavior\n * @param shouldLoop - Whether animation should loop\n * @returns This builder for chaining\n */\n withLoop(shouldLoop: boolean): this {\n this.loop = shouldLoop;\n return this;\n }\n\n /**\n * Set animation type\n * @param animType - Animation type\n * @returns This builder for chaining\n */\n withType(animType: \"attack\" | \"defense\" | \"movement\" | \"idle\"): this {\n this.type = animType;\n return this;\n }\n\n /**\n * Add a keyframe to the animation\n * @param time - Time of keyframe in seconds\n * @param easing - Easing function name\n * @returns Keyframe builder for defining keyframe contents\n */\n keyframe(time: number, easing: string = \"linear\"): KeyframeBuilder {\n const kfBuilder = new KeyframeBuilder(time, easing);\n kfBuilder.setParent(this);\n return kfBuilder;\n }\n\n /**\n * Add a pre-built keyframe directly\n * @param keyframe - Complete keyframe\n * @returns This builder for chaining\n */\n addKeyframe(keyframe: AnimationKeyframe): this {\n this.keyframes.push(keyframe);\n return this;\n }\n\n /**\n * Build the complete animation\n * @returns Complete skeletal animation\n */\n build(): SkeletalAnimation {\n return {\n name: this.animationName,\n koreanName: this.koreanName,\n duration: this.duration,\n loop: this.loop,\n type: this.type,\n keyframes: this.keyframes,\n };\n }\n}\n\n/**\n * Common keyframe factories for reusable animation patterns\n * @korean 키프레임팩토리\n */\nexport class KeyframeFactories {\n /**\n * Create a guard return keyframe (return to defensive position)\n * @param time - Time of keyframe\n * @returns Guard position keyframe\n */\n static guardReturn(time: number): AnimationKeyframe {\n return {\n time,\n easing: \"ease-in\",\n boneRotations: new Map([\n [BoneName.SHOULDER_R, new THREE.Euler(-0.35, 0.35, -0.14, \"XYZ\")],\n [BoneName.SHOULDER_L, new THREE.Euler(-0.35, -0.35, 0.14, \"XYZ\")],\n [BoneName.ELBOW_R, new THREE.Euler(0, 0, 1.75, \"XYZ\")],\n [BoneName.ELBOW_L, new THREE.Euler(0, 0, -1.75, \"XYZ\")],\n [BoneName.SPINE_UPPER, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.SPINE_MIDDLE, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.PELVIS, new THREE.Euler(0, 0, 0, \"XYZ\")],\n ]),\n bonePositions: new Map([\n [BoneName.HAND_R, new THREE.Vector3(0, 0, 0)],\n [BoneName.HAND_L, new THREE.Vector3(0, 0, 0)],\n ]),\n };\n }\n\n /**\n * Create a neutral stance keyframe\n * @param time - Time of keyframe\n * @returns Neutral stance keyframe\n */\n static neutralStance(time: number): AnimationKeyframe {\n return {\n time,\n easing: \"linear\",\n boneRotations: new Map([\n [BoneName.SPINE_UPPER, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.SPINE_MIDDLE, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.PELVIS, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.HIP_L, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.HIP_R, new THREE.Euler(0, 0, 0, \"XYZ\")],\n ]),\n bonePositions: new Map(),\n };\n }\n\n /**\n * Create a torso rotation keyframe\n * @param time - Time of keyframe\n * @param angle - Rotation angle in radians (positive = clockwise)\n * @param easing - Easing function\n * @returns Torso rotation keyframe\n */\n static rotateTorso(\n time: number,\n angle: number,\n easing: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\" = \"linear\",\n ): AnimationKeyframe {\n return {\n time,\n easing,\n boneRotations: new Map([\n [BoneName.SPINE_UPPER, new THREE.Euler(0, angle, 0, \"XYZ\")],\n [BoneName.SPINE_MIDDLE, new THREE.Euler(0, angle * 0.75, 0, \"XYZ\")],\n [BoneName.PELVIS, new THREE.Euler(0, angle * 0.5, 0, \"XYZ\")],\n ]),\n bonePositions: new Map(),\n };\n }\n}\n\n/**\n * Bone rotation helper utilities\n * @korean 뼈회전헬퍼\n */\nexport class BoneRotationHelpers {\n /**\n * Create shoulder rotation for arm extension\n * @param side - \"L\" or \"R\"\n * @param forward - Forward rotation amount\n * @param up - Upward rotation amount\n * @returns Euler rotation\n */\n static shoulderExtension(\n side: \"L\" | \"R\",\n forward: number,\n up: number = 0,\n ): THREE.Euler {\n const sign = side === \"L\" ? -1 : 1;\n return new THREE.Euler(up, 0, forward * sign, \"XYZ\");\n }\n\n /**\n * Create elbow rotation for arm bend\n * @param side - \"L\" or \"R\"\n * @param bend - Bend amount (0 = straight, PI/2 = 90 degrees)\n * @returns Euler rotation\n */\n static elbowBend(side: \"L\" | \"R\", bend: number): THREE.Euler {\n const sign = side === \"L\" ? -1 : 1;\n return new THREE.Euler(0, 0, bend * sign, \"XYZ\");\n }\n\n /**\n * Create hip rotation for leg movement\n * @param _side - \"L\" or \"R\" (reserved for future asymmetric animations)\n * @param forward - Forward rotation (positive = leg forward)\n * @param outward - Outward rotation (positive = leg out)\n * @returns Euler rotation\n */\n static hipRotation(\n _side: \"L\" | \"R\",\n forward: number,\n outward: number = 0,\n ): THREE.Euler {\n return new THREE.Euler(forward, outward, 0, \"XYZ\");\n }\n\n /**\n * Create knee rotation for leg bend\n * @param _side - \"L\" or \"R\" (reserved for future asymmetric animations)\n * @param bend - Bend amount (positive = knee bends)\n * @returns Euler rotation\n */\n static kneeBend(_side: \"L\" | \"R\", bend: number): THREE.Euler {\n // NOTE: `_side` is intentionally unused: knee bends are currently symmetric for both legs.\n // The parameter is kept to preserve API compatibility for future asymmetric leg animations.\n void _side;\n // Knee flexion is on X axis (legs extend along -Y, X rotation swings shin forward/backward)\n // Negative X = flexion (bend), so negate the positive 'bend' input\n return new THREE.Euler(-bend, 0, 0, \"XYZ\");\n }\n}\n\n/**\n * Reusable animation presets for common combat patterns\n * @korean 재사용애니메이션프리셋\n */\nexport class AnimationPresets {\n /**\n * Standard fighting guard position - protects face and body\n * Both elbows tight, hands at chin/temple level\n * @korean 기본방어자세\n */\n static readonly FIGHTING_GUARD = {\n leftArm: {\n shoulder: new THREE.Euler(-0.35, -0.35, 0.14), // Arms forward, hands near chin\n elbow: new THREE.Euler(0, 0, -1.75), // ~100° bend (중단막기)\n wrist: new THREE.Euler(0.1, 0, 0), // Fist aligned\n },\n rightArm: {\n shoulder: new THREE.Euler(-0.35, 0.35, -0.14), // Mirror\n elbow: new THREE.Euler(0, 0, 1.75), // ~100° bend (중단막기)\n wrist: new THREE.Euler(0.1, 0, 0), // Fist aligned\n },\n } as const;\n\n /**\n * High guard protecting head - both hands at temple level\n * Used during kicks or when expecting high attacks\n * @korean 상단방어자세\n */\n static readonly HIGH_GUARD = {\n leftArm: {\n shoulder: new THREE.Euler(-0.52, -0.44, 0.17), // Raised, arms forward (상단막기)\n elbow: new THREE.Euler(0, 0, -2.09), // ~120° bend tight guard\n wrist: new THREE.Euler(0.1, 0, 0), // Hand near temple\n },\n rightArm: {\n shoulder: new THREE.Euler(-0.52, 0.44, -0.17), // Mirror\n elbow: new THREE.Euler(0, 0, 2.09), // ~120° bend tight guard\n wrist: new THREE.Euler(0.1, 0, 0), // Hand near temple\n },\n } as const;\n\n /**\n * Kick chamber position - leg lifted, hip rotated\n * Shared starting position for most kicks\n * @korean 킥체임버자세\n */\n static readonly KICK_CHAMBER_RIGHT = {\n hip: new THREE.Euler(1.57, 0, 0), // 90° hip flexion\n knee: new THREE.Euler(-2.0, 0, 0), // Tight chamber\n ankle: new THREE.Euler(0, 0, 0), // Relaxed\n supportKnee: new THREE.Euler(-0.25, 0, 0), // Slight bend for balance\n pelvis: new THREE.Euler(-0.1, 0, 0), // Slight backward tilt\n } as const;\n\n /**\n * Kick extension position - leg fully extended\n * @korean 킥확장자세\n */\n static readonly KICK_EXTENSION_RIGHT = {\n hip: new THREE.Euler(1.7, 0, 0), // Hip drives forward\n knee: new THREE.Euler(0.1, 0, 0), // Full extension\n ankle: new THREE.Euler(0.5, 0, 0), // Dorsiflexion for ball strike\n supportKnee: new THREE.Euler(-0.35, 0, 0), // Deeper bend for balance\n pelvis: new THREE.Euler(0.15, 0, 0), // Forward drive\n } as const;\n\n /**\n * Punch wind-up - arm coiled, torso rotated back\n * @korean 펀치준비자세\n */\n static readonly PUNCH_WINDUP_RIGHT = {\n shoulder: new THREE.Euler(0.3, 0, -0.3),\n elbow: new THREE.Euler(0, 0, 1.8),\n spine: new THREE.Euler(0, -0.15, 0),\n pelvis: new THREE.Euler(0, -0.1, 0),\n } as const;\n\n /**\n * Punch extension - arm extended with torso rotation\n * @korean 펀치확장자세\n */\n static readonly PUNCH_EXTENSION_RIGHT = {\n shoulder: new THREE.Euler(-0.7, 0, 0.5),\n elbow: new THREE.Euler(0, 0, 0.05),\n spine: new THREE.Euler(0, 0.35, 0),\n pelvis: new THREE.Euler(0, 0.2, 0),\n } as const;\n}\n\n/**\n * Applies common animation patterns to KeyframeBuilder\n * Allows reusing shared motion patterns across animations\n * @korean 애니메이션패턴헬퍼\n */\nexport class AnimationPatternHelpers {\n /**\n * Apply fighting guard to a keyframe\n * Keeps hands protecting face during kicks\n * @param kf - KeyframeBuilder to modify\n * @returns Modified KeyframeBuilder\n */\n static applyFightingGuard(kf: KeyframeBuilder): KeyframeBuilder {\n const guard = AnimationPresets.FIGHTING_GUARD;\n return kf\n .rotate(\n BoneName.SHOULDER_L,\n guard.leftArm.shoulder.x,\n guard.leftArm.shoulder.y,\n guard.leftArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_L,\n guard.leftArm.elbow.x,\n guard.leftArm.elbow.y,\n guard.leftArm.elbow.z,\n )\n .rotate(\n BoneName.SHOULDER_R,\n guard.rightArm.shoulder.x,\n guard.rightArm.shoulder.y,\n guard.rightArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_R,\n guard.rightArm.elbow.x,\n guard.rightArm.elbow.y,\n guard.rightArm.elbow.z,\n );\n }\n\n /**\n * Apply high guard during kicks\n * @param kf - KeyframeBuilder to modify\n * @returns Modified KeyframeBuilder\n */\n static applyHighGuard(kf: KeyframeBuilder): KeyframeBuilder {\n const guard = AnimationPresets.HIGH_GUARD;\n return kf\n .rotate(\n BoneName.SHOULDER_L,\n guard.leftArm.shoulder.x,\n guard.leftArm.shoulder.y,\n guard.leftArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_L,\n guard.leftArm.elbow.x,\n guard.leftArm.elbow.y,\n guard.leftArm.elbow.z,\n )\n .rotate(\n BoneName.SHOULDER_R,\n guard.rightArm.shoulder.x,\n guard.rightArm.shoulder.y,\n guard.rightArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_R,\n guard.rightArm.elbow.x,\n guard.rightArm.elbow.y,\n guard.rightArm.elbow.z,\n );\n }\n\n /**\n * Apply kick chamber for right leg\n * @param kf - KeyframeBuilder to modify\n * @returns Modified KeyframeBuilder\n */\n static applyKickChamber(kf: KeyframeBuilder): KeyframeBuilder {\n const chamber = AnimationPresets.KICK_CHAMBER_RIGHT;\n return kf\n .rotate(BoneName.HIP_R, chamber.hip.x, chamber.hip.y, chamber.hip.z)\n .rotate(BoneName.KNEE_R, chamber.knee.x, chamber.knee.y, chamber.knee.z)\n .rotate(\n BoneName.KNEE_L,\n chamber.supportKnee.x,\n chamber.supportKnee.y,\n chamber.supportKnee.z,\n )\n .rotate(\n BoneName.PELVIS,\n chamber.pelvis.x,\n chamber.pelvis.y,\n chamber.pelvis.z,\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AnimationBuilder.js","names":[],"sources":["../../../../src/systems/animation/builders/AnimationBuilder.ts"],"sourcesContent":["/**\n * Animation Builder - Fluent API for creating skeletal animations\n *\n * Provides a cleaner, more maintainable way to define animations with\n * reduced boilerplate and better readability.\n *\n * @module systems/animation/AnimationBuilder\n * @category Animation System\n * @korean 애니메이션빌더\n */\n\nimport * as THREE from \"three\";\nimport type { AnimationKeyframe, SkeletalAnimation } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\n\n/**\n * Keyframe builder for fluent keyframe construction\n * @korean 키프레임빌더\n */\nclass KeyframeBuilder {\n private time: number;\n private easing: string;\n private boneRotations: Map<BoneName, THREE.Euler>;\n private bonePositions: Map<BoneName, THREE.Vector3>;\n private parentBuilder: AnimationBuilder | null = null;\n\n constructor(time: number, easing: string = \"linear\") {\n this.time = time;\n this.easing = easing;\n this.boneRotations = new Map();\n this.bonePositions = new Map();\n }\n\n /**\n * Set parent animation builder (for chaining)\n * @internal\n */\n setParent(parent: AnimationBuilder): this {\n this.parentBuilder = parent;\n return this;\n }\n\n /**\n * Add bone rotation to keyframe\n * @param bone - Bone to rotate\n * @param x - X rotation in radians\n * @param y - Y rotation in radians\n * @param z - Z rotation in radians\n * @param order - Rotation order (default: XYZ)\n * @returns This builder for chaining\n */\n rotate(\n bone: BoneName,\n x: number,\n y: number,\n z: number,\n order: THREE.EulerOrder = \"XYZ\",\n ): this {\n this.boneRotations.set(bone, new THREE.Euler(x, y, z, order));\n return this;\n }\n\n /**\n * Add bone position to keyframe\n * @param bone - Bone to position\n * @param x - X position\n * @param y - Y position\n * @param z - Z position\n * @returns This builder for chaining\n */\n position(bone: BoneName, x: number, y: number, z: number): this {\n this.bonePositions.set(bone, new THREE.Vector3(x, y, z));\n return this;\n }\n\n /**\n * Build the keyframe and return to animation builder\n * @returns Animation builder for chaining\n */\n build(): AnimationBuilder {\n const keyframe: AnimationKeyframe = {\n time: this.time,\n easing: this.easing as \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\",\n boneRotations: this.boneRotations,\n bonePositions: this.bonePositions,\n };\n\n if (this.parentBuilder) {\n this.parentBuilder.addKeyframe(keyframe);\n return this.parentBuilder;\n }\n\n // This indicates incorrect usage of the builder API; parent must be set via setParent(...)\n throw new Error(\n \"KeyframeBuilder.build() called without a parent AnimationBuilder. Ensure setParent(...) is called before build().\",\n );\n }\n}\n\n/**\n * Animation builder for fluent animation construction\n * @korean 애니메이션빌더\n */\nexport class AnimationBuilder {\n private animationName: string;\n private koreanName: string;\n private duration: number;\n private loop: boolean;\n private type: \"attack\" | \"defense\" | \"movement\" | \"idle\";\n private keyframes: AnimationKeyframe[];\n\n private constructor(name: string) {\n this.animationName = name;\n this.koreanName = name;\n this.duration = 1.0;\n this.loop = false;\n this.type = \"idle\";\n this.keyframes = [];\n }\n\n /**\n * Create a new animation builder\n * @param name - Animation name\n * @returns New animation builder\n */\n static create(name: string): AnimationBuilder {\n return new AnimationBuilder(name);\n }\n\n /**\n * Set Korean name for animation\n * @param name - Korean name\n * @returns This builder for chaining\n */\n withKoreanName(name: string): this {\n this.koreanName = name;\n return this;\n }\n\n /**\n * Set animation duration\n * @param seconds - Duration in seconds\n * @returns This builder for chaining\n */\n withDuration(seconds: number): this {\n this.duration = seconds;\n return this;\n }\n\n /**\n * Set animation loop behavior\n * @param shouldLoop - Whether animation should loop\n * @returns This builder for chaining\n */\n withLoop(shouldLoop: boolean): this {\n this.loop = shouldLoop;\n return this;\n }\n\n /**\n * Set animation type\n * @param animType - Animation type\n * @returns This builder for chaining\n */\n withType(animType: \"attack\" | \"defense\" | \"movement\" | \"idle\"): this {\n this.type = animType;\n return this;\n }\n\n /**\n * Add a keyframe to the animation\n * @param time - Time of keyframe in seconds\n * @param easing - Easing function name\n * @returns Keyframe builder for defining keyframe contents\n */\n keyframe(time: number, easing: string = \"linear\"): KeyframeBuilder {\n const kfBuilder = new KeyframeBuilder(time, easing);\n kfBuilder.setParent(this);\n return kfBuilder;\n }\n\n /**\n * Add a pre-built keyframe directly\n * @param keyframe - Complete keyframe\n * @returns This builder for chaining\n */\n addKeyframe(keyframe: AnimationKeyframe): this {\n this.keyframes.push(keyframe);\n return this;\n }\n\n /**\n * Build the complete animation\n * @returns Complete skeletal animation\n */\n build(): SkeletalAnimation {\n return {\n name: this.animationName,\n koreanName: this.koreanName,\n duration: this.duration,\n loop: this.loop,\n type: this.type,\n keyframes: this.keyframes,\n };\n }\n}\n\n/**\n * Common keyframe factories for reusable animation patterns\n * @korean 키프레임팩토리\n */\nexport class KeyframeFactories {\n /**\n * Create a guard return keyframe (return to defensive position)\n * @param time - Time of keyframe\n * @returns Guard position keyframe\n */\n static guardReturn(time: number): AnimationKeyframe {\n return {\n time,\n easing: \"ease-in\",\n boneRotations: new Map([\n [BoneName.SHOULDER_R, new THREE.Euler(-0.35, 0.35, -0.14, \"XYZ\")],\n [BoneName.SHOULDER_L, new THREE.Euler(-0.35, -0.35, 0.14, \"XYZ\")],\n [BoneName.ELBOW_R, new THREE.Euler(0, 0, 1.75, \"XYZ\")],\n [BoneName.ELBOW_L, new THREE.Euler(0, 0, -1.75, \"XYZ\")],\n [BoneName.SPINE_UPPER, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.SPINE_MIDDLE, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.PELVIS, new THREE.Euler(0, 0, 0, \"XYZ\")],\n ]),\n bonePositions: new Map([\n [BoneName.HAND_R, new THREE.Vector3(0, 0, 0)],\n [BoneName.HAND_L, new THREE.Vector3(0, 0, 0)],\n ]),\n };\n }\n\n /**\n * Create a neutral stance keyframe\n * @param time - Time of keyframe\n * @returns Neutral stance keyframe\n */\n static neutralStance(time: number): AnimationKeyframe {\n return {\n time,\n easing: \"linear\",\n boneRotations: new Map([\n [BoneName.SPINE_UPPER, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.SPINE_MIDDLE, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.PELVIS, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.HIP_L, new THREE.Euler(0, 0, 0, \"XYZ\")],\n [BoneName.HIP_R, new THREE.Euler(0, 0, 0, \"XYZ\")],\n ]),\n bonePositions: new Map(),\n };\n }\n\n /**\n * Create a torso rotation keyframe\n * @param time - Time of keyframe\n * @param angle - Rotation angle in radians (positive = clockwise)\n * @param easing - Easing function\n * @returns Torso rotation keyframe\n */\n static rotateTorso(\n time: number,\n angle: number,\n easing: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\" = \"linear\",\n ): AnimationKeyframe {\n return {\n time,\n easing,\n boneRotations: new Map([\n [BoneName.SPINE_UPPER, new THREE.Euler(0, angle, 0, \"XYZ\")],\n [BoneName.SPINE_MIDDLE, new THREE.Euler(0, angle * 0.75, 0, \"XYZ\")],\n [BoneName.PELVIS, new THREE.Euler(0, angle * 0.5, 0, \"XYZ\")],\n ]),\n bonePositions: new Map(),\n };\n }\n}\n\n/**\n * Bone rotation helper utilities\n * @korean 뼈회전헬퍼\n */\nexport class BoneRotationHelpers {\n /**\n * Create shoulder rotation for arm extension\n * @param side - \"L\" or \"R\"\n * @param forward - Forward rotation amount\n * @param up - Upward rotation amount\n * @returns Euler rotation\n */\n static shoulderExtension(\n side: \"L\" | \"R\",\n forward: number,\n up: number = 0,\n ): THREE.Euler {\n const sign = side === \"L\" ? -1 : 1;\n return new THREE.Euler(up, 0, forward * sign, \"XYZ\");\n }\n\n /**\n * Create elbow rotation for arm bend\n * @param side - \"L\" or \"R\"\n * @param bend - Bend amount (0 = straight, PI/2 = 90 degrees)\n * @returns Euler rotation\n */\n static elbowBend(side: \"L\" | \"R\", bend: number): THREE.Euler {\n const sign = side === \"L\" ? -1 : 1;\n return new THREE.Euler(0, 0, bend * sign, \"XYZ\");\n }\n\n /**\n * Create hip rotation for leg movement\n * @param _side - \"L\" or \"R\" (reserved for future asymmetric animations)\n * @param forward - Forward rotation (positive = leg forward)\n * @param outward - Outward rotation (positive = leg out)\n * @returns Euler rotation\n */\n static hipRotation(\n _side: \"L\" | \"R\",\n forward: number,\n outward: number = 0,\n ): THREE.Euler {\n return new THREE.Euler(forward, outward, 0, \"XYZ\");\n }\n\n /**\n * Create knee rotation for leg bend\n * @param _side - \"L\" or \"R\" (reserved for future asymmetric animations)\n * @param bend - Bend amount (positive = knee bends)\n * @returns Euler rotation\n */\n static kneeBend(_side: \"L\" | \"R\", bend: number): THREE.Euler {\n // NOTE: `_side` is intentionally unused: knee bends are currently symmetric for both legs.\n // The parameter is kept to preserve API compatibility for future asymmetric leg animations.\n void _side;\n // Knee flexion is on X axis (legs extend along -Y, X rotation swings shin forward/backward)\n // Negative X = flexion (bend), so negate the positive 'bend' input\n return new THREE.Euler(-bend, 0, 0, \"XYZ\");\n }\n}\n\n/**\n * Reusable animation presets for common combat patterns\n * @korean 재사용애니메이션프리셋\n */\nexport class AnimationPresets {\n /**\n * Standard fighting guard position - protects face and body\n * Both elbows tight, hands at chin/temple level\n * @korean 기본방어자세\n */\n static readonly FIGHTING_GUARD = {\n leftArm: {\n shoulder: new THREE.Euler(-0.35, -0.35, 0.14), // Arms forward, hands near chin\n elbow: new THREE.Euler(0, 0, -1.75), // ~100° bend (중단막기)\n wrist: new THREE.Euler(0.1, 0, 0), // Fist aligned\n },\n rightArm: {\n shoulder: new THREE.Euler(-0.35, 0.35, -0.14), // Mirror\n elbow: new THREE.Euler(0, 0, 1.75), // ~100° bend (중단막기)\n wrist: new THREE.Euler(0.1, 0, 0), // Fist aligned\n },\n } as const;\n\n /**\n * High guard protecting head - both hands at temple level\n * Used during kicks or when expecting high attacks\n * @korean 상단방어자세\n */\n static readonly HIGH_GUARD = {\n leftArm: {\n shoulder: new THREE.Euler(-0.52, -0.44, 0.17), // Raised, arms forward (상단막기)\n elbow: new THREE.Euler(0, 0, -2.09), // ~120° bend tight guard\n wrist: new THREE.Euler(0.1, 0, 0), // Hand near temple\n },\n rightArm: {\n shoulder: new THREE.Euler(-0.52, 0.44, -0.17), // Mirror\n elbow: new THREE.Euler(0, 0, 2.09), // ~120° bend tight guard\n wrist: new THREE.Euler(0.1, 0, 0), // Hand near temple\n },\n } as const;\n\n /**\n * Kick chamber position - leg lifted, hip rotated\n * Shared starting position for most kicks\n * @korean 킥체임버자세\n */\n static readonly KICK_CHAMBER_RIGHT = {\n hip: new THREE.Euler(1.57, 0, 0), // 90° hip flexion\n knee: new THREE.Euler(-2.0, 0, 0), // Tight chamber\n ankle: new THREE.Euler(0, 0, 0), // Relaxed\n supportKnee: new THREE.Euler(-0.25, 0, 0), // Slight bend for balance\n pelvis: new THREE.Euler(-0.1, 0, 0), // Slight backward tilt\n } as const;\n\n /**\n * Kick extension position - leg fully extended\n * @korean 킥확장자세\n */\n static readonly KICK_EXTENSION_RIGHT = {\n hip: new THREE.Euler(1.7, 0, 0), // Hip drives forward\n knee: new THREE.Euler(0.1, 0, 0), // Full extension\n ankle: new THREE.Euler(0.5, 0, 0), // Dorsiflexion for ball strike\n supportKnee: new THREE.Euler(-0.35, 0, 0), // Deeper bend for balance\n pelvis: new THREE.Euler(0.15, 0, 0), // Forward drive\n } as const;\n\n /**\n * Punch wind-up - arm coiled, torso rotated back\n * @korean 펀치준비자세\n */\n static readonly PUNCH_WINDUP_RIGHT = {\n shoulder: new THREE.Euler(0.3, 0, -0.3),\n elbow: new THREE.Euler(0, 0, 1.8),\n spine: new THREE.Euler(0, -0.15, 0),\n pelvis: new THREE.Euler(0, -0.1, 0),\n } as const;\n\n /**\n * Punch extension - arm extended with torso rotation\n * @korean 펀치확장자세\n */\n static readonly PUNCH_EXTENSION_RIGHT = {\n shoulder: new THREE.Euler(-0.7, 0, 0.5),\n elbow: new THREE.Euler(0, 0, 0.05),\n spine: new THREE.Euler(0, 0.35, 0),\n pelvis: new THREE.Euler(0, 0.2, 0),\n } as const;\n}\n\n/**\n * Applies common animation patterns to KeyframeBuilder\n * Allows reusing shared motion patterns across animations\n * @korean 애니메이션패턴헬퍼\n */\nexport class AnimationPatternHelpers {\n /**\n * Apply fighting guard to a keyframe\n * Keeps hands protecting face during kicks\n * @param kf - KeyframeBuilder to modify\n * @returns Modified KeyframeBuilder\n */\n static applyFightingGuard(kf: KeyframeBuilder): KeyframeBuilder {\n const guard = AnimationPresets.FIGHTING_GUARD;\n return kf\n .rotate(\n BoneName.SHOULDER_L,\n guard.leftArm.shoulder.x,\n guard.leftArm.shoulder.y,\n guard.leftArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_L,\n guard.leftArm.elbow.x,\n guard.leftArm.elbow.y,\n guard.leftArm.elbow.z,\n )\n .rotate(\n BoneName.SHOULDER_R,\n guard.rightArm.shoulder.x,\n guard.rightArm.shoulder.y,\n guard.rightArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_R,\n guard.rightArm.elbow.x,\n guard.rightArm.elbow.y,\n guard.rightArm.elbow.z,\n );\n }\n\n /**\n * Apply high guard during kicks\n * @param kf - KeyframeBuilder to modify\n * @returns Modified KeyframeBuilder\n */\n static applyHighGuard(kf: KeyframeBuilder): KeyframeBuilder {\n const guard = AnimationPresets.HIGH_GUARD;\n return kf\n .rotate(\n BoneName.SHOULDER_L,\n guard.leftArm.shoulder.x,\n guard.leftArm.shoulder.y,\n guard.leftArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_L,\n guard.leftArm.elbow.x,\n guard.leftArm.elbow.y,\n guard.leftArm.elbow.z,\n )\n .rotate(\n BoneName.SHOULDER_R,\n guard.rightArm.shoulder.x,\n guard.rightArm.shoulder.y,\n guard.rightArm.shoulder.z,\n )\n .rotate(\n BoneName.ELBOW_R,\n guard.rightArm.elbow.x,\n guard.rightArm.elbow.y,\n guard.rightArm.elbow.z,\n );\n }\n\n /**\n * Apply kick chamber for right leg\n * @param kf - KeyframeBuilder to modify\n * @returns Modified KeyframeBuilder\n */\n static applyKickChamber(kf: KeyframeBuilder): KeyframeBuilder {\n const chamber = AnimationPresets.KICK_CHAMBER_RIGHT;\n return kf\n .rotate(BoneName.HIP_R, chamber.hip.x, chamber.hip.y, chamber.hip.z)\n .rotate(BoneName.KNEE_R, chamber.knee.x, chamber.knee.y, chamber.knee.z)\n .rotate(\n BoneName.KNEE_L,\n chamber.supportKnee.x,\n chamber.supportKnee.y,\n chamber.supportKnee.z,\n )\n .rotate(\n BoneName.PELVIS,\n chamber.pelvis.x,\n chamber.pelvis.y,\n chamber.pelvis.z,\n );\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"HandPoseApplicator.js","names":[],"sources":["../../../../src/systems/animation/builders/HandPoseApplicator.ts"],"sourcesContent":["/**\n * Hand Pose Application Utilities\n *\n * Utilities for applying hand poses to animation keyframes.\n * 손 모양 적용 유틸리티\n *\n * @module systems/animation/HandPoseApplicator\n * @korean 손모양적용기\n */\n\nimport * as THREE from \"three\";\nimport type { AnimationKeyframe } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport type { KeyframeConfig } from \"./KeyframeConfig\";\nimport { HAND_POSES } from \"./MartialArtsConstants\";\n\n/** Hand pose type from HAND_POSES constant */\nexport type HandPose = (typeof HAND_POSES)[keyof typeof HAND_POSES];\n\n/** Which hand(s) to apply a pose to */\nexport type HandSelection = \"left\" | \"right\" | \"both\";\n\n/**\n * Finger bone mapping for a hand\n * @internal\n */\ninterface FingerBoneMapping {\n readonly thumb_meta: BoneName;\n readonly thumb_prox: BoneName;\n readonly thumb_dist: BoneName;\n readonly index_meta: BoneName;\n readonly index_prox: BoneName;\n readonly index_inter: BoneName;\n readonly index_dist: BoneName;\n readonly middle_meta: BoneName;\n readonly middle_prox: BoneName;\n readonly middle_inter: BoneName;\n readonly middle_dist: BoneName;\n readonly ring_meta: BoneName;\n readonly ring_prox: BoneName;\n readonly ring_inter: BoneName;\n readonly ring_dist: BoneName;\n readonly pinky_meta: BoneName;\n readonly pinky_prox: BoneName;\n readonly pinky_inter: BoneName;\n readonly pinky_dist: BoneName;\n}\n\n/** Left hand bone mapping */\nconst LEFT_HAND_BONES: FingerBoneMapping = {\n thumb_meta: BoneName.THUMB_META_L,\n thumb_prox: BoneName.THUMB_PROX_L,\n thumb_dist: BoneName.THUMB_DIST_L,\n index_meta: BoneName.INDEX_META_L,\n index_prox: BoneName.INDEX_PROX_L,\n index_inter: BoneName.INDEX_INTER_L,\n index_dist: BoneName.INDEX_DIST_L,\n middle_meta: BoneName.MIDDLE_META_L,\n middle_prox: BoneName.MIDDLE_PROX_L,\n middle_inter: BoneName.MIDDLE_INTER_L,\n middle_dist: BoneName.MIDDLE_DIST_L,\n ring_meta: BoneName.RING_META_L,\n ring_prox: BoneName.RING_PROX_L,\n ring_inter: BoneName.RING_INTER_L,\n ring_dist: BoneName.RING_DIST_L,\n pinky_meta: BoneName.PINKY_META_L,\n pinky_prox: BoneName.PINKY_PROX_L,\n pinky_inter: BoneName.PINKY_INTER_L,\n pinky_dist: BoneName.PINKY_DIST_L,\n};\n\n/** Right hand bone mapping */\nconst RIGHT_HAND_BONES: FingerBoneMapping = {\n thumb_meta: BoneName.THUMB_META_R,\n thumb_prox: BoneName.THUMB_PROX_R,\n thumb_dist: BoneName.THUMB_DIST_R,\n index_meta: BoneName.INDEX_META_R,\n index_prox: BoneName.INDEX_PROX_R,\n index_inter: BoneName.INDEX_INTER_R,\n index_dist: BoneName.INDEX_DIST_R,\n middle_meta: BoneName.MIDDLE_META_R,\n middle_prox: BoneName.MIDDLE_PROX_R,\n middle_inter: BoneName.MIDDLE_INTER_R,\n middle_dist: BoneName.MIDDLE_DIST_R,\n ring_meta: BoneName.RING_META_R,\n ring_prox: BoneName.RING_PROX_R,\n ring_inter: BoneName.RING_INTER_R,\n ring_dist: BoneName.RING_DIST_R,\n pinky_meta: BoneName.PINKY_META_R,\n pinky_prox: BoneName.PINKY_PROX_R,\n pinky_inter: BoneName.PINKY_INTER_R,\n pinky_dist: BoneName.PINKY_DIST_R,\n};\n\n/** Finger bone keys in the pose object */\nconst FINGER_KEYS = [\n \"thumb_meta\",\n \"thumb_prox\",\n \"thumb_dist\",\n \"index_meta\",\n \"index_prox\",\n \"index_inter\",\n \"index_dist\",\n \"middle_meta\",\n \"middle_prox\",\n \"middle_inter\",\n \"middle_dist\",\n \"ring_meta\",\n \"ring_prox\",\n \"ring_inter\",\n \"ring_dist\",\n \"pinky_meta\",\n \"pinky_prox\",\n \"pinky_inter\",\n \"pinky_dist\",\n] as const;\n\n/**\n * Apply hand pose to a KeyframeConfig (builder pattern)\n *\n * @param kf - KeyframeConfig to apply pose to\n * @param pose - Hand pose data from HAND_POSES\n * @param hand - Which hand(s) to apply (\"left\" | \"right\" | \"both\")\n *\n * @example\n * ```typescript\n * applyHandPoseToConfig(kf, HAND_POSES.FIST, \"right\");\n * ```\n *\n * @korean KeyframeConfig에손모양적용\n */\nexport function applyHandPoseToConfig(\n kf: KeyframeConfig,\n pose: HandPose,\n hand: HandSelection\n): void {\n const applyToHand = (bones: FingerBoneMapping) => {\n for (const key of FINGER_KEYS) {\n const rotation = pose[key];\n kf.rotate(bones[key], rotation[0], rotation[1], rotation[2]);\n }\n };\n\n if (hand === \"left\" || hand === \"both\") {\n applyToHand(LEFT_HAND_BONES);\n }\n if (hand === \"right\" || hand === \"both\") {\n applyToHand(RIGHT_HAND_BONES);\n }\n}\n\n/**\n * Apply hand pose to an AnimationKeyframe (direct mutation)\n *\n * @param kf - AnimationKeyframe to apply pose to\n * @param pose - Hand pose data from HAND_POSES\n * @param hand - Which hand(s) to apply (\"left\" | \"right\" | \"both\")\n *\n * @example\n * ```typescript\n * applyHandPoseToKeyframe(animKeyframe, HAND_POSES.GRAB, \"both\");\n * ```\n *\n * @korean AnimationKeyframe에손모양적용\n */\nexport function applyHandPoseToKeyframe(\n kf: AnimationKeyframe,\n pose: HandPose,\n hand: HandSelection\n): void {\n const applyToHand = (bones: FingerBoneMapping) => {\n for (const key of FINGER_KEYS) {\n const rotation = pose[key];\n kf.boneRotations.set(\n bones[key],\n new THREE.Euler(rotation[0], rotation[1], rotation[2])\n );\n }\n };\n\n if (hand === \"left\" || hand === \"both\") {\n applyToHand(LEFT_HAND_BONES);\n }\n if (hand === \"right\" || hand === \"both\") {\n applyToHand(RIGHT_HAND_BONES);\n }\n}\n\n/**\n * Get a hand pose by name\n *\n * @param poseName - Name of the pose from HAND_POSES\n * @returns The hand pose data\n *\n * @korean 손모양가져오기\n */\nexport function getHandPose(poseName: keyof typeof HAND_POSES): HandPose {\n return HAND_POSES[poseName];\n}\n"],"mappings":";;;;;;;;;;;;;AAiDA,IAAM,kBAAqC;CACzC,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,aAAa,SAAS;CACtB,cAAc,SAAS;CACvB,aAAa,SAAS;CACtB,WAAW,SAAS;CACpB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACtB;;AAGD,IAAM,mBAAsC;CAC1C,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,aAAa,SAAS;CACtB,cAAc,SAAS;CACvB,aAAa,SAAS;CACtB,WAAW,SAAS;CACpB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACtB;;AAGD,IAAM,cAAc;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;;;;;;;;AAgBD,SAAgB,sBACd,IACA,MACA,MACM;CACN,MAAM,eAAe,UAA6B;AAChD,OAAK,MAAM,OAAO,aAAa;GAC7B,MAAM,WAAW,KAAK;AACtB,MAAG,OAAO,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,SAAS,GAAG;;;AAIhE,KAAI,SAAS,UAAU,SAAS,OAC9B,aAAY,gBAAgB;AAE9B,KAAI,SAAS,WAAW,SAAS,OAC/B,aAAY,iBAAiB;;;;;;;;;;;;;;;;AAkBjC,SAAgB,wBACd,IACA,MACA,MACM;CACN,MAAM,eAAe,UAA6B;AAChD,OAAK,MAAM,OAAO,aAAa;GAC7B,MAAM,WAAW,KAAK;AACtB,MAAG,cAAc,IACf,MAAM,MACN,IAAI,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,SAAS,GAAG,CACvD;;;AAIL,KAAI,SAAS,UAAU,SAAS,OAC9B,aAAY,gBAAgB;AAE9B,KAAI,SAAS,WAAW,SAAS,OAC/B,aAAY,iBAAiB"}
1
+ {"version":3,"file":"HandPoseApplicator.js","names":[],"sources":["../../../../src/systems/animation/builders/HandPoseApplicator.ts"],"sourcesContent":["/**\n * Hand Pose Application Utilities\n *\n * Utilities for applying hand poses to animation keyframes.\n * 손 모양 적용 유틸리티\n *\n * @module systems/animation/HandPoseApplicator\n * @korean 손모양적용기\n */\n\nimport * as THREE from \"three\";\nimport type { AnimationKeyframe } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport type { KeyframeConfig } from \"./KeyframeConfig\";\nimport { HAND_POSES } from \"./MartialArtsConstants\";\n\n/** Hand pose type from HAND_POSES constant */\nexport type HandPose = (typeof HAND_POSES)[keyof typeof HAND_POSES];\n\n/** Which hand(s) to apply a pose to */\nexport type HandSelection = \"left\" | \"right\" | \"both\";\n\n/**\n * Finger bone mapping for a hand\n * @internal\n */\ninterface FingerBoneMapping {\n readonly thumb_meta: BoneName;\n readonly thumb_prox: BoneName;\n readonly thumb_dist: BoneName;\n readonly index_meta: BoneName;\n readonly index_prox: BoneName;\n readonly index_inter: BoneName;\n readonly index_dist: BoneName;\n readonly middle_meta: BoneName;\n readonly middle_prox: BoneName;\n readonly middle_inter: BoneName;\n readonly middle_dist: BoneName;\n readonly ring_meta: BoneName;\n readonly ring_prox: BoneName;\n readonly ring_inter: BoneName;\n readonly ring_dist: BoneName;\n readonly pinky_meta: BoneName;\n readonly pinky_prox: BoneName;\n readonly pinky_inter: BoneName;\n readonly pinky_dist: BoneName;\n}\n\n/** Left hand bone mapping */\nconst LEFT_HAND_BONES: FingerBoneMapping = {\n thumb_meta: BoneName.THUMB_META_L,\n thumb_prox: BoneName.THUMB_PROX_L,\n thumb_dist: BoneName.THUMB_DIST_L,\n index_meta: BoneName.INDEX_META_L,\n index_prox: BoneName.INDEX_PROX_L,\n index_inter: BoneName.INDEX_INTER_L,\n index_dist: BoneName.INDEX_DIST_L,\n middle_meta: BoneName.MIDDLE_META_L,\n middle_prox: BoneName.MIDDLE_PROX_L,\n middle_inter: BoneName.MIDDLE_INTER_L,\n middle_dist: BoneName.MIDDLE_DIST_L,\n ring_meta: BoneName.RING_META_L,\n ring_prox: BoneName.RING_PROX_L,\n ring_inter: BoneName.RING_INTER_L,\n ring_dist: BoneName.RING_DIST_L,\n pinky_meta: BoneName.PINKY_META_L,\n pinky_prox: BoneName.PINKY_PROX_L,\n pinky_inter: BoneName.PINKY_INTER_L,\n pinky_dist: BoneName.PINKY_DIST_L,\n};\n\n/** Right hand bone mapping */\nconst RIGHT_HAND_BONES: FingerBoneMapping = {\n thumb_meta: BoneName.THUMB_META_R,\n thumb_prox: BoneName.THUMB_PROX_R,\n thumb_dist: BoneName.THUMB_DIST_R,\n index_meta: BoneName.INDEX_META_R,\n index_prox: BoneName.INDEX_PROX_R,\n index_inter: BoneName.INDEX_INTER_R,\n index_dist: BoneName.INDEX_DIST_R,\n middle_meta: BoneName.MIDDLE_META_R,\n middle_prox: BoneName.MIDDLE_PROX_R,\n middle_inter: BoneName.MIDDLE_INTER_R,\n middle_dist: BoneName.MIDDLE_DIST_R,\n ring_meta: BoneName.RING_META_R,\n ring_prox: BoneName.RING_PROX_R,\n ring_inter: BoneName.RING_INTER_R,\n ring_dist: BoneName.RING_DIST_R,\n pinky_meta: BoneName.PINKY_META_R,\n pinky_prox: BoneName.PINKY_PROX_R,\n pinky_inter: BoneName.PINKY_INTER_R,\n pinky_dist: BoneName.PINKY_DIST_R,\n};\n\n/** Finger bone keys in the pose object */\nconst FINGER_KEYS = [\n \"thumb_meta\",\n \"thumb_prox\",\n \"thumb_dist\",\n \"index_meta\",\n \"index_prox\",\n \"index_inter\",\n \"index_dist\",\n \"middle_meta\",\n \"middle_prox\",\n \"middle_inter\",\n \"middle_dist\",\n \"ring_meta\",\n \"ring_prox\",\n \"ring_inter\",\n \"ring_dist\",\n \"pinky_meta\",\n \"pinky_prox\",\n \"pinky_inter\",\n \"pinky_dist\",\n] as const;\n\n/**\n * Apply hand pose to a KeyframeConfig (builder pattern)\n *\n * @param kf - KeyframeConfig to apply pose to\n * @param pose - Hand pose data from HAND_POSES\n * @param hand - Which hand(s) to apply (\"left\" | \"right\" | \"both\")\n *\n * @example\n * ```typescript\n * applyHandPoseToConfig(kf, HAND_POSES.FIST, \"right\");\n * ```\n *\n * @korean KeyframeConfig에손모양적용\n */\nexport function applyHandPoseToConfig(\n kf: KeyframeConfig,\n pose: HandPose,\n hand: HandSelection\n): void {\n const applyToHand = (bones: FingerBoneMapping) => {\n for (const key of FINGER_KEYS) {\n const rotation = pose[key];\n kf.rotate(bones[key], rotation[0], rotation[1], rotation[2]);\n }\n };\n\n if (hand === \"left\" || hand === \"both\") {\n applyToHand(LEFT_HAND_BONES);\n }\n if (hand === \"right\" || hand === \"both\") {\n applyToHand(RIGHT_HAND_BONES);\n }\n}\n\n/**\n * Apply hand pose to an AnimationKeyframe (direct mutation)\n *\n * @param kf - AnimationKeyframe to apply pose to\n * @param pose - Hand pose data from HAND_POSES\n * @param hand - Which hand(s) to apply (\"left\" | \"right\" | \"both\")\n *\n * @example\n * ```typescript\n * applyHandPoseToKeyframe(animKeyframe, HAND_POSES.GRAB, \"both\");\n * ```\n *\n * @korean AnimationKeyframe에손모양적용\n */\nexport function applyHandPoseToKeyframe(\n kf: AnimationKeyframe,\n pose: HandPose,\n hand: HandSelection\n): void {\n const applyToHand = (bones: FingerBoneMapping) => {\n for (const key of FINGER_KEYS) {\n const rotation = pose[key];\n kf.boneRotations.set(\n bones[key],\n new THREE.Euler(rotation[0], rotation[1], rotation[2])\n );\n }\n };\n\n if (hand === \"left\" || hand === \"both\") {\n applyToHand(LEFT_HAND_BONES);\n }\n if (hand === \"right\" || hand === \"both\") {\n applyToHand(RIGHT_HAND_BONES);\n }\n}\n\n/**\n * Get a hand pose by name\n *\n * @param poseName - Name of the pose from HAND_POSES\n * @returns The hand pose data\n *\n * @korean 손모양가져오기\n */\nexport function getHandPose(poseName: keyof typeof HAND_POSES): HandPose {\n return HAND_POSES[poseName];\n}\n"],"mappings":";;;;;;;;;;;;;AAiDA,IAAM,kBAAqC;CACzC,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,aAAa,SAAS;CACtB,cAAc,SAAS;CACvB,aAAa,SAAS;CACtB,WAAW,SAAS;CACpB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACtB;;AAGD,IAAM,mBAAsC;CAC1C,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,aAAa,SAAS;CACtB,cAAc,SAAS;CACvB,aAAa,SAAS;CACtB,WAAW,SAAS;CACpB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,WAAW,SAAS;CACpB,YAAY,SAAS;CACrB,YAAY,SAAS;CACrB,aAAa,SAAS;CACtB,YAAY,SAAS;CACtB;;AAGD,IAAM,cAAc;CAClB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;;;;;;;;;;;;;;;AAgBD,SAAgB,sBACd,IACA,MACA,MACM;CACN,MAAM,eAAe,UAA6B;EAChD,KAAK,MAAM,OAAO,aAAa;GAC7B,MAAM,WAAW,KAAK;GACtB,GAAG,OAAO,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,SAAS,GAAG;;;CAIhE,IAAI,SAAS,UAAU,SAAS,QAC9B,YAAY,gBAAgB;CAE9B,IAAI,SAAS,WAAW,SAAS,QAC/B,YAAY,iBAAiB;;;;;;;;;;;;;;;;AAkBjC,SAAgB,wBACd,IACA,MACA,MACM;CACN,MAAM,eAAe,UAA6B;EAChD,KAAK,MAAM,OAAO,aAAa;GAC7B,MAAM,WAAW,KAAK;GACtB,GAAG,cAAc,IACf,MAAM,MACN,IAAI,MAAM,MAAM,SAAS,IAAI,SAAS,IAAI,SAAS,GAAG,CACvD;;;CAIL,IAAI,SAAS,UAAU,SAAS,QAC9B,YAAY,gBAAgB;CAE9B,IAAI,SAAS,WAAW,SAAS,QAC/B,YAAY,iBAAiB"}
@@ -1 +1 @@
1
- {"version":3,"file":"HandPoses.js","names":[],"sources":["../../../../src/systems/animation/builders/HandPoses.ts"],"sourcesContent":["/**\n * Hand pose definitions for Korean martial arts techniques\n *\n * Defines authentic hand poses from Taekwondo, Hapkido, and Taekyon\n * including finger positions, wrist rotations, and striking surfaces.\n *\n * @module systems/animation/HandPoses\n * @category Animation System\n * @korean 손자세시스템\n */\n\nimport * as THREE from \"three\";\nimport type {\n FingerCurl,\n FingerSpread,\n HandAnimationState,\n HandPose,\n TechniqueHandPose,\n} from \"@/types/hand-animation\";\nimport { HandPoseType } from \"@/types/hand-animation\";\n\n/**\n * Standard finger curl values for common poses\n * @korean 기본손가락구부림값\n */\nconst FINGER_CURL = {\n /** Fully extended fingers */\n EXTENDED: { thumb: 0.0, index: 0.0, middle: 0.0, ring: 0.0, pinky: 0.0 },\n /** Fully curled fist */\n CURLED: { thumb: 0.8, index: 1.0, middle: 1.0, ring: 1.0, pinky: 1.0 },\n /** Half curled (slightly bent) */\n HALF: { thumb: 0.3, index: 0.5, middle: 0.5, ring: 0.5, pinky: 0.5 },\n /** Relaxed natural position */\n RELAXED: { thumb: 0.2, index: 0.2, middle: 0.2, ring: 0.2, pinky: 0.2 },\n} as const;\n\n/**\n * Standard finger spread values\n * @korean 기본손가락벌림값\n */\nconst FINGER_SPREAD = {\n /** Fingers together */\n TOGETHER: {\n thumbIndex: 0.0,\n indexMiddle: 0.0,\n middleRing: 0.0,\n ringPinky: 0.0,\n },\n /** Fingers naturally spread */\n NATURAL: {\n thumbIndex: 0.3,\n indexMiddle: 0.1,\n middleRing: 0.1,\n ringPinky: 0.1,\n },\n /** Fingers wide spread */\n WIDE: { thumbIndex: 0.8, indexMiddle: 0.4, middleRing: 0.4, ringPinky: 0.4 },\n} as const;\n\n/**\n * 주먹 (Fist) - Closed fist for punching\n *\n * Traditional Taekwondo fist formation:\n * - All fingers tightly curled\n * - Thumb wrapped over index/middle fingers\n * - Knuckles aligned for impact\n * - Wrist straight for power transfer\n *\n * @korean 주먹자세\n */\nexport const FIST_POSE: HandPose = {\n type: HandPoseType.FIST,\n nameKorean: \"주먹\",\n nameEnglish: \"Fist\",\n romanized: \"Jumeok\",\n fingerCurl: FINGER_CURL.CURLED,\n fingerSpread: FINGER_SPREAD.TOGETHER,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean:\n \"태권도 기본 주먹. 손가락을 단단히 말아 쥐고 엄지는 검지와 중지 위에 감싼다.\",\n english:\n \"Traditional Taekwondo fist. Fingers tightly curled with thumb wrapped over index and middle fingers.\",\n },\n martialArtOrigin: \"taekwondo\",\n strikingSurface: \"knuckles\",\n};\n\n/**\n * 수도 (Knife-Hand) - Rigid hand edge strike\n *\n * Hapkido/Taekwondo knife-hand technique:\n * - Fingers fully extended and together\n * - Thumb tucked against palm\n * - Hand rotated edge-down (90 degrees)\n * - Rigid for chopping strikes to neck/collar\n *\n * @korean 수도자세\n */\nexport const KNIFE_HAND_POSE: HandPose = {\n type: HandPoseType.KNIFE_HAND,\n nameKorean: \"수도\",\n nameEnglish: \"Knife-Hand\",\n romanized: \"Sudo\",\n fingerCurl: {\n thumb: 0.5, // Thumb tucked against palm\n index: 0.0,\n middle: 0.0,\n ring: 0.0,\n pinky: 0.0,\n },\n fingerSpread: FINGER_SPREAD.TOGETHER,\n wristRotation: new THREE.Euler(0, 0, -Math.PI / 2), // Edge-down rotation\n description: {\n korean:\n \"합기도/태권도 수도치기. 손가락을 펴서 모으고 손날로 목이나 쇄골을 가격한다.\",\n english:\n \"Hapkido/Taekwondo knife-hand strike. Fingers extended together, striking with hand edge to neck or collar.\",\n },\n martialArtOrigin: \"hapkido\",\n strikingSurface: \"knife_edge\",\n};\n\n/**\n * 관수 (Spear-Hand) - Pointed finger thrust\n *\n * Traditional Korean spear-hand thrust:\n * - All fingers extended and pressed together\n * - Thumb extended alongside\n * - Fingertips form a point\n * - For precise strikes to soft targets (throat, eyes, solar plexus)\n *\n * @korean 관수자세\n */\nexport const SPEAR_HAND_POSE: HandPose = {\n type: HandPoseType.SPEAR_HAND,\n nameKorean: \"관수\",\n nameEnglish: \"Spear-Hand\",\n romanized: \"Gwansu\",\n fingerCurl: FINGER_CURL.EXTENDED,\n fingerSpread: FINGER_SPREAD.TOGETHER,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean:\n \"전통 한국 무술 관수. 손가락을 펴서 모아 뾰족하게 만들어 목구멍, 눈, 명치 등을 찌른다.\",\n english:\n \"Traditional Korean spear-hand. Fingers extended together forming a point for precise strikes to throat, eyes, solar plexus.\",\n },\n martialArtOrigin: \"traditional\",\n strikingSurface: \"fingertips\",\n};\n\n/**\n * 장력 (Palm-Heel) - Palm-heel strike\n *\n * Taekwondo palm-heel strike:\n * - Fingers curled back (not tightly)\n * - Wrist extended back\n * - Palm heel exposed for striking\n * - For powerful upward strikes to chin/jaw\n *\n * @korean 장력자세\n */\nexport const PALM_HEEL_POSE: HandPose = {\n type: HandPoseType.PALM_HEEL,\n nameKorean: \"장력\",\n nameEnglish: \"Palm-Heel\",\n romanized: \"Jangryeok\",\n fingerCurl: FINGER_CURL.HALF,\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(-0.3, 0, 0), // Wrist extended back\n description: {\n korean:\n \"태권도 장력치기. 손가락을 약간 구부리고 손목을 꺾어 손바닥 아래쪽으로 턱이나 명치를 가격한다.\",\n english:\n \"Taekwondo palm-heel strike. Fingers slightly curled, wrist extended back, striking with palm heel to chin or solar plexus.\",\n },\n martialArtOrigin: \"taekwondo\",\n strikingSurface: \"palm_heel\",\n};\n\n/**\n * 잡기 (Grappling) - Grasping hand\n *\n * Hapkido grappling hand position:\n * - Fingers curved for gripping\n * - Thumb opposed for control\n * - Natural spread for maximum grip\n * - For joint locks and throws\n *\n * @korean 잡기자세\n */\nexport const GRAPPLING_POSE: HandPose = {\n type: HandPoseType.GRAPPLING,\n nameKorean: \"잡기\",\n nameEnglish: \"Grappling\",\n romanized: \"Japgi\",\n fingerCurl: {\n thumb: 0.6,\n index: 0.6,\n middle: 0.6,\n ring: 0.6,\n pinky: 0.6,\n },\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean:\n \"합기도 잡기 자세. 손가락을 자연스럽게 구부려 상대를 잡거나 관절기를 건다.\",\n english:\n \"Hapkido grappling position. Fingers naturally curved for gripping opponent or applying joint locks.\",\n },\n martialArtOrigin: \"hapkido\",\n strikingSurface: \"whole_hand\",\n};\n\n/**\n * 펴기 (Open) - Neutral open hand\n *\n * Relaxed open hand position:\n * - Fingers slightly curled (natural relaxation)\n * - Natural spread\n * - Neutral wrist\n * - Default/idle position\n *\n * @korean 펴기자세\n */\nexport const OPEN_POSE: HandPose = {\n type: HandPoseType.OPEN,\n nameKorean: \"펴기\",\n nameEnglish: \"Open\",\n romanized: \"Pyeogi\",\n fingerCurl: FINGER_CURL.RELAXED,\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean: \"자연스러운 열린 손. 휴식이나 기본 자세에서 사용한다.\",\n english: \"Natural open hand. Used in idle or default position.\",\n },\n martialArtOrigin: \"traditional\",\n strikingSurface: \"whole_hand\",\n};\n\n/**\n * 휴식 (Relaxed) - Natural relaxed hand for walking/idle\n *\n * Very relaxed hand position:\n * - Fingers slightly more curled than open\n * - Natural spread\n * - Slightly angled wrist\n * - Used during walking and natural movements\n *\n * @korean 휴식자세\n */\nexport const RELAXED_POSE: HandPose = {\n type: HandPoseType.RELAXED,\n nameKorean: \"휴식\",\n nameEnglish: \"Relaxed\",\n romanized: \"Hyusik\",\n fingerCurl: { thumb: 0.3, index: 0.35, middle: 0.35, ring: 0.4, pinky: 0.45 },\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(0.1, 0, 0), // Slight downward angle\n description: {\n korean: \"자연스럽게 힘을 뺀 손. 걸을 때나 휴식 시 사용한다.\",\n english: \"Naturally relaxed hand. Used while walking or at rest.\",\n },\n martialArtOrigin: \"traditional\",\n strikingSurface: \"whole_hand\",\n};\n\n/**\n * All hand poses indexed by type\n * @korean 모든손자세맵\n */\nexport const HAND_POSES: Record<HandPoseType, HandPose> = {\n [HandPoseType.FIST]: FIST_POSE,\n [HandPoseType.KNIFE_HAND]: KNIFE_HAND_POSE,\n [HandPoseType.SPEAR_HAND]: SPEAR_HAND_POSE,\n [HandPoseType.PALM_HEEL]: PALM_HEEL_POSE,\n [HandPoseType.GRAPPLING]: GRAPPLING_POSE,\n [HandPoseType.OPEN]: OPEN_POSE,\n [HandPoseType.RELAXED]: RELAXED_POSE,\n};\n\n/**\n * Get hand pose by type\n *\n * @param poseType - Hand pose type\n * @returns Hand pose configuration\n * @korean 손자세가져오기\n */\nexport const getHandPose = (poseType: HandPoseType): HandPose => {\n return HAND_POSES[poseType];\n};\n\n/**\n * Technique to hand pose mappings\n *\n * Maps attack technique names to appropriate hand poses for both hands.\n *\n * @korean 기술손자세매핑\n */\nexport const TECHNIQUE_HAND_POSES: Record<string, TechniqueHandPose> = {\n idle: {\n techniqueName: \"idle\",\n leftHandPose: HandPoseType.OPEN,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.3,\n },\n jab: {\n techniqueName: \"jab\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n cross: {\n techniqueName: \"cross\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n hook: {\n techniqueName: \"hook\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n uppercut: {\n techniqueName: \"uppercut\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n knife_hand_strike: {\n techniqueName: \"knife_hand_strike\",\n leftHandPose: HandPoseType.KNIFE_HAND,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.15,\n },\n spear_hand_thrust: {\n techniqueName: \"spear_hand_thrust\",\n leftHandPose: HandPoseType.SPEAR_HAND,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.15,\n },\n palm_heel_strike: {\n techniqueName: \"palm_heel_strike\",\n leftHandPose: HandPoseType.PALM_HEEL,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.12,\n },\n grab: {\n techniqueName: \"grab\",\n leftHandPose: HandPoseType.GRAPPLING,\n rightHandPose: HandPoseType.GRAPPLING,\n transitionDuration: 0.2,\n },\n block: {\n techniqueName: \"block\",\n leftHandPose: HandPoseType.OPEN,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.1,\n },\n};\n\n/**\n * Get hand pose configuration for a technique\n *\n * @param techniqueName - Technique identifier\n * @returns Hand pose configuration for both hands, or default open pose\n * @korean 기술손자세가져오기\n */\nexport const getTechniqueHandPose = (\n techniqueName: string\n): TechniqueHandPose => {\n return (\n TECHNIQUE_HAND_POSES[techniqueName] ?? {\n techniqueName,\n leftHandPose: HandPoseType.OPEN,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.3,\n }\n );\n};\n\n/**\n * Interpolate between two finger curl configurations\n *\n * @param from - Starting finger curl\n * @param to - Target finger curl\n * @param progress - Interpolation progress (0-1)\n * @returns Interpolated finger curl\n * @korean 손가락구부림보간\n */\nexport const interpolateFingerCurl = (\n from: FingerCurl,\n to: FingerCurl,\n progress: number\n): FingerCurl => {\n const t = Math.max(0, Math.min(1, progress)); // Clamp to [0, 1]\n return {\n thumb: from.thumb + (to.thumb - from.thumb) * t,\n index: from.index + (to.index - from.index) * t,\n middle: from.middle + (to.middle - from.middle) * t,\n ring: from.ring + (to.ring - from.ring) * t,\n pinky: from.pinky + (to.pinky - from.pinky) * t,\n };\n};\n\n/**\n * Interpolate between two finger spread configurations\n *\n * @param from - Starting finger spread\n * @param to - Target finger spread\n * @param progress - Interpolation progress (0-1)\n * @returns Interpolated finger spread\n * @korean 손가락벌림보간\n */\nexport const interpolateFingerSpread = (\n from: FingerSpread,\n to: FingerSpread,\n progress: number\n): FingerSpread => {\n const t = Math.max(0, Math.min(1, progress));\n return {\n thumbIndex: from.thumbIndex + (to.thumbIndex - from.thumbIndex) * t,\n indexMiddle: from.indexMiddle + (to.indexMiddle - from.indexMiddle) * t,\n middleRing: from.middleRing + (to.middleRing - from.middleRing) * t,\n ringPinky: from.ringPinky + (to.ringPinky - from.ringPinky) * t,\n };\n};\n\n/**\n * Interpolate between two wrist rotations\n *\n * @param from - Starting wrist rotation\n * @param to - Target wrist rotation\n * @param progress - Interpolation progress (0-1)\n * @returns Interpolated wrist rotation\n * @korean 손목회전보간\n */\nexport const interpolateWristRotation = (\n from: THREE.Euler,\n to: THREE.Euler,\n progress: number\n): THREE.Euler => {\n const t = Math.max(0, Math.min(1, progress));\n return new THREE.Euler(\n from.x + (to.x - from.x) * t,\n from.y + (to.y - from.y) * t,\n from.z + (to.z - from.z) * t,\n from.order\n );\n};\n\n/**\n * Create initial hand animation state\n *\n * @param initialPose - Starting hand pose\n * @returns Initial hand animation state\n * @korean 손애니메이션상태초기화\n */\nexport const createInitialHandAnimationState = (\n initialPose: HandPoseType = HandPoseType.OPEN\n): HandAnimationState => {\n const pose = getHandPose(initialPose);\n return {\n currentPose: initialPose,\n targetPose: null,\n transitionProgress: 1.0, // Fully transitioned to current pose\n currentFingerCurl: pose.fingerCurl,\n currentFingerSpread: pose.fingerSpread,\n currentWristRotation: pose.wristRotation.clone(),\n isHighlighted: false,\n highlightMode: null,\n };\n};\n\n/**\n * Update hand animation state with transition\n *\n * @param state - Current hand animation state\n * @param targetPose - Target hand pose to transition to\n * @param deltaTime - Time since last update (seconds)\n * @param transitionDuration - Total transition duration (seconds)\n * @returns Updated hand animation state\n * @korean 손애니메이션상태업데이트\n */\nexport const updateHandAnimationState = (\n state: HandAnimationState,\n targetPose: HandPoseType | null,\n deltaTime: number,\n transitionDuration: number = 0.2\n): HandAnimationState => {\n // No transition needed\n if (targetPose === null || targetPose === state.currentPose) {\n return {\n ...state,\n targetPose: null,\n transitionProgress: 1.0,\n };\n }\n\n // Start new transition when target pose changes\n if (state.targetPose !== targetPose) {\n // Compute initial progress so we begin interpolating immediately\n const initialProgress = Math.min(1.0, deltaTime / transitionDuration);\n\n // Use the current interpolated state as the starting point for smoother continuity\n const fromFingerCurl = state.currentFingerCurl;\n const fromFingerSpread = state.currentFingerSpread;\n const fromWristRotation = state.currentWristRotation;\n\n const toPose = getHandPose(targetPose);\n\n const newFingerCurl = interpolateFingerCurl(\n fromFingerCurl,\n toPose.fingerCurl,\n initialProgress\n );\n const newFingerSpread = interpolateFingerSpread(\n fromFingerSpread,\n toPose.fingerSpread,\n initialProgress\n );\n const newWristRotation = interpolateWristRotation(\n fromWristRotation,\n toPose.wristRotation,\n initialProgress\n );\n\n return {\n ...state,\n targetPose,\n transitionProgress: initialProgress,\n currentFingerCurl: newFingerCurl,\n currentFingerSpread: newFingerSpread,\n currentWristRotation: newWristRotation,\n };\n }\n\n // Continue existing transition\n const newProgress = Math.min(\n 1.0,\n state.transitionProgress + deltaTime / transitionDuration\n );\n\n // Get poses for interpolation\n const fromPose = getHandPose(state.currentPose);\n const toPose = getHandPose(targetPose);\n\n // Interpolate values\n const newFingerCurl = interpolateFingerCurl(\n fromPose.fingerCurl,\n toPose.fingerCurl,\n newProgress\n );\n const newFingerSpread = interpolateFingerSpread(\n fromPose.fingerSpread,\n toPose.fingerSpread,\n newProgress\n );\n const newWristRotation = interpolateWristRotation(\n fromPose.wristRotation,\n toPose.wristRotation,\n newProgress\n );\n\n // Check if transition is complete\n if (newProgress >= 1.0) {\n return {\n ...state,\n currentPose: targetPose,\n targetPose: null,\n transitionProgress: 1.0,\n currentFingerCurl: toPose.fingerCurl,\n currentFingerSpread: toPose.fingerSpread,\n currentWristRotation: toPose.wristRotation.clone(),\n };\n }\n\n return {\n ...state,\n transitionProgress: newProgress,\n currentFingerCurl: newFingerCurl,\n currentFingerSpread: newFingerSpread,\n currentWristRotation: newWristRotation,\n };\n};\n\n/**\n * Set hand highlight mode for vital point targeting\n *\n * @param state - Current hand animation state\n * @param isHighlighted - Whether hand is highlighted\n * @param mode - Highlight mode for striking surface\n * @returns Updated hand animation state\n * @korean 손표시설정\n */\nexport const setHandHighlight = (\n state: HandAnimationState,\n isHighlighted: boolean,\n mode: HandAnimationState[\"highlightMode\"] = null\n): HandAnimationState => {\n return {\n ...state,\n isHighlighted,\n highlightMode: isHighlighted ? mode : null,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"HandPoses.js","names":[],"sources":["../../../../src/systems/animation/builders/HandPoses.ts"],"sourcesContent":["/**\n * Hand pose definitions for Korean martial arts techniques\n *\n * Defines authentic hand poses from Taekwondo, Hapkido, and Taekyon\n * including finger positions, wrist rotations, and striking surfaces.\n *\n * @module systems/animation/HandPoses\n * @category Animation System\n * @korean 손자세시스템\n */\n\nimport * as THREE from \"three\";\nimport type {\n FingerCurl,\n FingerSpread,\n HandAnimationState,\n HandPose,\n TechniqueHandPose,\n} from \"@/types/hand-animation\";\nimport { HandPoseType } from \"@/types/hand-animation\";\n\n/**\n * Standard finger curl values for common poses\n * @korean 기본손가락구부림값\n */\nconst FINGER_CURL = {\n /** Fully extended fingers */\n EXTENDED: { thumb: 0.0, index: 0.0, middle: 0.0, ring: 0.0, pinky: 0.0 },\n /** Fully curled fist */\n CURLED: { thumb: 0.8, index: 1.0, middle: 1.0, ring: 1.0, pinky: 1.0 },\n /** Half curled (slightly bent) */\n HALF: { thumb: 0.3, index: 0.5, middle: 0.5, ring: 0.5, pinky: 0.5 },\n /** Relaxed natural position */\n RELAXED: { thumb: 0.2, index: 0.2, middle: 0.2, ring: 0.2, pinky: 0.2 },\n} as const;\n\n/**\n * Standard finger spread values\n * @korean 기본손가락벌림값\n */\nconst FINGER_SPREAD = {\n /** Fingers together */\n TOGETHER: {\n thumbIndex: 0.0,\n indexMiddle: 0.0,\n middleRing: 0.0,\n ringPinky: 0.0,\n },\n /** Fingers naturally spread */\n NATURAL: {\n thumbIndex: 0.3,\n indexMiddle: 0.1,\n middleRing: 0.1,\n ringPinky: 0.1,\n },\n /** Fingers wide spread */\n WIDE: { thumbIndex: 0.8, indexMiddle: 0.4, middleRing: 0.4, ringPinky: 0.4 },\n} as const;\n\n/**\n * 주먹 (Fist) - Closed fist for punching\n *\n * Traditional Taekwondo fist formation:\n * - All fingers tightly curled\n * - Thumb wrapped over index/middle fingers\n * - Knuckles aligned for impact\n * - Wrist straight for power transfer\n *\n * @korean 주먹자세\n */\nexport const FIST_POSE: HandPose = {\n type: HandPoseType.FIST,\n nameKorean: \"주먹\",\n nameEnglish: \"Fist\",\n romanized: \"Jumeok\",\n fingerCurl: FINGER_CURL.CURLED,\n fingerSpread: FINGER_SPREAD.TOGETHER,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean:\n \"태권도 기본 주먹. 손가락을 단단히 말아 쥐고 엄지는 검지와 중지 위에 감싼다.\",\n english:\n \"Traditional Taekwondo fist. Fingers tightly curled with thumb wrapped over index and middle fingers.\",\n },\n martialArtOrigin: \"taekwondo\",\n strikingSurface: \"knuckles\",\n};\n\n/**\n * 수도 (Knife-Hand) - Rigid hand edge strike\n *\n * Hapkido/Taekwondo knife-hand technique:\n * - Fingers fully extended and together\n * - Thumb tucked against palm\n * - Hand rotated edge-down (90 degrees)\n * - Rigid for chopping strikes to neck/collar\n *\n * @korean 수도자세\n */\nexport const KNIFE_HAND_POSE: HandPose = {\n type: HandPoseType.KNIFE_HAND,\n nameKorean: \"수도\",\n nameEnglish: \"Knife-Hand\",\n romanized: \"Sudo\",\n fingerCurl: {\n thumb: 0.5, // Thumb tucked against palm\n index: 0.0,\n middle: 0.0,\n ring: 0.0,\n pinky: 0.0,\n },\n fingerSpread: FINGER_SPREAD.TOGETHER,\n wristRotation: new THREE.Euler(0, 0, -Math.PI / 2), // Edge-down rotation\n description: {\n korean:\n \"합기도/태권도 수도치기. 손가락을 펴서 모으고 손날로 목이나 쇄골을 가격한다.\",\n english:\n \"Hapkido/Taekwondo knife-hand strike. Fingers extended together, striking with hand edge to neck or collar.\",\n },\n martialArtOrigin: \"hapkido\",\n strikingSurface: \"knife_edge\",\n};\n\n/**\n * 관수 (Spear-Hand) - Pointed finger thrust\n *\n * Traditional Korean spear-hand thrust:\n * - All fingers extended and pressed together\n * - Thumb extended alongside\n * - Fingertips form a point\n * - For precise strikes to soft targets (throat, eyes, solar plexus)\n *\n * @korean 관수자세\n */\nexport const SPEAR_HAND_POSE: HandPose = {\n type: HandPoseType.SPEAR_HAND,\n nameKorean: \"관수\",\n nameEnglish: \"Spear-Hand\",\n romanized: \"Gwansu\",\n fingerCurl: FINGER_CURL.EXTENDED,\n fingerSpread: FINGER_SPREAD.TOGETHER,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean:\n \"전통 한국 무술 관수. 손가락을 펴서 모아 뾰족하게 만들어 목구멍, 눈, 명치 등을 찌른다.\",\n english:\n \"Traditional Korean spear-hand. Fingers extended together forming a point for precise strikes to throat, eyes, solar plexus.\",\n },\n martialArtOrigin: \"traditional\",\n strikingSurface: \"fingertips\",\n};\n\n/**\n * 장력 (Palm-Heel) - Palm-heel strike\n *\n * Taekwondo palm-heel strike:\n * - Fingers curled back (not tightly)\n * - Wrist extended back\n * - Palm heel exposed for striking\n * - For powerful upward strikes to chin/jaw\n *\n * @korean 장력자세\n */\nexport const PALM_HEEL_POSE: HandPose = {\n type: HandPoseType.PALM_HEEL,\n nameKorean: \"장력\",\n nameEnglish: \"Palm-Heel\",\n romanized: \"Jangryeok\",\n fingerCurl: FINGER_CURL.HALF,\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(-0.3, 0, 0), // Wrist extended back\n description: {\n korean:\n \"태권도 장력치기. 손가락을 약간 구부리고 손목을 꺾어 손바닥 아래쪽으로 턱이나 명치를 가격한다.\",\n english:\n \"Taekwondo palm-heel strike. Fingers slightly curled, wrist extended back, striking with palm heel to chin or solar plexus.\",\n },\n martialArtOrigin: \"taekwondo\",\n strikingSurface: \"palm_heel\",\n};\n\n/**\n * 잡기 (Grappling) - Grasping hand\n *\n * Hapkido grappling hand position:\n * - Fingers curved for gripping\n * - Thumb opposed for control\n * - Natural spread for maximum grip\n * - For joint locks and throws\n *\n * @korean 잡기자세\n */\nexport const GRAPPLING_POSE: HandPose = {\n type: HandPoseType.GRAPPLING,\n nameKorean: \"잡기\",\n nameEnglish: \"Grappling\",\n romanized: \"Japgi\",\n fingerCurl: {\n thumb: 0.6,\n index: 0.6,\n middle: 0.6,\n ring: 0.6,\n pinky: 0.6,\n },\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean:\n \"합기도 잡기 자세. 손가락을 자연스럽게 구부려 상대를 잡거나 관절기를 건다.\",\n english:\n \"Hapkido grappling position. Fingers naturally curved for gripping opponent or applying joint locks.\",\n },\n martialArtOrigin: \"hapkido\",\n strikingSurface: \"whole_hand\",\n};\n\n/**\n * 펴기 (Open) - Neutral open hand\n *\n * Relaxed open hand position:\n * - Fingers slightly curled (natural relaxation)\n * - Natural spread\n * - Neutral wrist\n * - Default/idle position\n *\n * @korean 펴기자세\n */\nexport const OPEN_POSE: HandPose = {\n type: HandPoseType.OPEN,\n nameKorean: \"펴기\",\n nameEnglish: \"Open\",\n romanized: \"Pyeogi\",\n fingerCurl: FINGER_CURL.RELAXED,\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(0, 0, 0),\n description: {\n korean: \"자연스러운 열린 손. 휴식이나 기본 자세에서 사용한다.\",\n english: \"Natural open hand. Used in idle or default position.\",\n },\n martialArtOrigin: \"traditional\",\n strikingSurface: \"whole_hand\",\n};\n\n/**\n * 휴식 (Relaxed) - Natural relaxed hand for walking/idle\n *\n * Very relaxed hand position:\n * - Fingers slightly more curled than open\n * - Natural spread\n * - Slightly angled wrist\n * - Used during walking and natural movements\n *\n * @korean 휴식자세\n */\nexport const RELAXED_POSE: HandPose = {\n type: HandPoseType.RELAXED,\n nameKorean: \"휴식\",\n nameEnglish: \"Relaxed\",\n romanized: \"Hyusik\",\n fingerCurl: { thumb: 0.3, index: 0.35, middle: 0.35, ring: 0.4, pinky: 0.45 },\n fingerSpread: FINGER_SPREAD.NATURAL,\n wristRotation: new THREE.Euler(0.1, 0, 0), // Slight downward angle\n description: {\n korean: \"자연스럽게 힘을 뺀 손. 걸을 때나 휴식 시 사용한다.\",\n english: \"Naturally relaxed hand. Used while walking or at rest.\",\n },\n martialArtOrigin: \"traditional\",\n strikingSurface: \"whole_hand\",\n};\n\n/**\n * All hand poses indexed by type\n * @korean 모든손자세맵\n */\nexport const HAND_POSES: Record<HandPoseType, HandPose> = {\n [HandPoseType.FIST]: FIST_POSE,\n [HandPoseType.KNIFE_HAND]: KNIFE_HAND_POSE,\n [HandPoseType.SPEAR_HAND]: SPEAR_HAND_POSE,\n [HandPoseType.PALM_HEEL]: PALM_HEEL_POSE,\n [HandPoseType.GRAPPLING]: GRAPPLING_POSE,\n [HandPoseType.OPEN]: OPEN_POSE,\n [HandPoseType.RELAXED]: RELAXED_POSE,\n};\n\n/**\n * Get hand pose by type\n *\n * @param poseType - Hand pose type\n * @returns Hand pose configuration\n * @korean 손자세가져오기\n */\nexport const getHandPose = (poseType: HandPoseType): HandPose => {\n return HAND_POSES[poseType];\n};\n\n/**\n * Technique to hand pose mappings\n *\n * Maps attack technique names to appropriate hand poses for both hands.\n *\n * @korean 기술손자세매핑\n */\nexport const TECHNIQUE_HAND_POSES: Record<string, TechniqueHandPose> = {\n idle: {\n techniqueName: \"idle\",\n leftHandPose: HandPoseType.OPEN,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.3,\n },\n jab: {\n techniqueName: \"jab\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n cross: {\n techniqueName: \"cross\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n hook: {\n techniqueName: \"hook\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n uppercut: {\n techniqueName: \"uppercut\",\n leftHandPose: HandPoseType.FIST,\n rightHandPose: HandPoseType.FIST,\n transitionDuration: 0.1,\n },\n knife_hand_strike: {\n techniqueName: \"knife_hand_strike\",\n leftHandPose: HandPoseType.KNIFE_HAND,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.15,\n },\n spear_hand_thrust: {\n techniqueName: \"spear_hand_thrust\",\n leftHandPose: HandPoseType.SPEAR_HAND,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.15,\n },\n palm_heel_strike: {\n techniqueName: \"palm_heel_strike\",\n leftHandPose: HandPoseType.PALM_HEEL,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.12,\n },\n grab: {\n techniqueName: \"grab\",\n leftHandPose: HandPoseType.GRAPPLING,\n rightHandPose: HandPoseType.GRAPPLING,\n transitionDuration: 0.2,\n },\n block: {\n techniqueName: \"block\",\n leftHandPose: HandPoseType.OPEN,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.1,\n },\n};\n\n/**\n * Get hand pose configuration for a technique\n *\n * @param techniqueName - Technique identifier\n * @returns Hand pose configuration for both hands, or default open pose\n * @korean 기술손자세가져오기\n */\nexport const getTechniqueHandPose = (\n techniqueName: string\n): TechniqueHandPose => {\n return (\n TECHNIQUE_HAND_POSES[techniqueName] ?? {\n techniqueName,\n leftHandPose: HandPoseType.OPEN,\n rightHandPose: HandPoseType.OPEN,\n transitionDuration: 0.3,\n }\n );\n};\n\n/**\n * Interpolate between two finger curl configurations\n *\n * @param from - Starting finger curl\n * @param to - Target finger curl\n * @param progress - Interpolation progress (0-1)\n * @returns Interpolated finger curl\n * @korean 손가락구부림보간\n */\nexport const interpolateFingerCurl = (\n from: FingerCurl,\n to: FingerCurl,\n progress: number\n): FingerCurl => {\n const t = Math.max(0, Math.min(1, progress)); // Clamp to [0, 1]\n return {\n thumb: from.thumb + (to.thumb - from.thumb) * t,\n index: from.index + (to.index - from.index) * t,\n middle: from.middle + (to.middle - from.middle) * t,\n ring: from.ring + (to.ring - from.ring) * t,\n pinky: from.pinky + (to.pinky - from.pinky) * t,\n };\n};\n\n/**\n * Interpolate between two finger spread configurations\n *\n * @param from - Starting finger spread\n * @param to - Target finger spread\n * @param progress - Interpolation progress (0-1)\n * @returns Interpolated finger spread\n * @korean 손가락벌림보간\n */\nexport const interpolateFingerSpread = (\n from: FingerSpread,\n to: FingerSpread,\n progress: number\n): FingerSpread => {\n const t = Math.max(0, Math.min(1, progress));\n return {\n thumbIndex: from.thumbIndex + (to.thumbIndex - from.thumbIndex) * t,\n indexMiddle: from.indexMiddle + (to.indexMiddle - from.indexMiddle) * t,\n middleRing: from.middleRing + (to.middleRing - from.middleRing) * t,\n ringPinky: from.ringPinky + (to.ringPinky - from.ringPinky) * t,\n };\n};\n\n/**\n * Interpolate between two wrist rotations\n *\n * @param from - Starting wrist rotation\n * @param to - Target wrist rotation\n * @param progress - Interpolation progress (0-1)\n * @returns Interpolated wrist rotation\n * @korean 손목회전보간\n */\nexport const interpolateWristRotation = (\n from: THREE.Euler,\n to: THREE.Euler,\n progress: number\n): THREE.Euler => {\n const t = Math.max(0, Math.min(1, progress));\n return new THREE.Euler(\n from.x + (to.x - from.x) * t,\n from.y + (to.y - from.y) * t,\n from.z + (to.z - from.z) * t,\n from.order\n );\n};\n\n/**\n * Create initial hand animation state\n *\n * @param initialPose - Starting hand pose\n * @returns Initial hand animation state\n * @korean 손애니메이션상태초기화\n */\nexport const createInitialHandAnimationState = (\n initialPose: HandPoseType = HandPoseType.OPEN\n): HandAnimationState => {\n const pose = getHandPose(initialPose);\n return {\n currentPose: initialPose,\n targetPose: null,\n transitionProgress: 1.0, // Fully transitioned to current pose\n currentFingerCurl: pose.fingerCurl,\n currentFingerSpread: pose.fingerSpread,\n currentWristRotation: pose.wristRotation.clone(),\n isHighlighted: false,\n highlightMode: null,\n };\n};\n\n/**\n * Update hand animation state with transition\n *\n * @param state - Current hand animation state\n * @param targetPose - Target hand pose to transition to\n * @param deltaTime - Time since last update (seconds)\n * @param transitionDuration - Total transition duration (seconds)\n * @returns Updated hand animation state\n * @korean 손애니메이션상태업데이트\n */\nexport const updateHandAnimationState = (\n state: HandAnimationState,\n targetPose: HandPoseType | null,\n deltaTime: number,\n transitionDuration: number = 0.2\n): HandAnimationState => {\n // No transition needed\n if (targetPose === null || targetPose === state.currentPose) {\n return {\n ...state,\n targetPose: null,\n transitionProgress: 1.0,\n };\n }\n\n // Start new transition when target pose changes\n if (state.targetPose !== targetPose) {\n // Compute initial progress so we begin interpolating immediately\n const initialProgress = Math.min(1.0, deltaTime / transitionDuration);\n\n // Use the current interpolated state as the starting point for smoother continuity\n const fromFingerCurl = state.currentFingerCurl;\n const fromFingerSpread = state.currentFingerSpread;\n const fromWristRotation = state.currentWristRotation;\n\n const toPose = getHandPose(targetPose);\n\n const newFingerCurl = interpolateFingerCurl(\n fromFingerCurl,\n toPose.fingerCurl,\n initialProgress\n );\n const newFingerSpread = interpolateFingerSpread(\n fromFingerSpread,\n toPose.fingerSpread,\n initialProgress\n );\n const newWristRotation = interpolateWristRotation(\n fromWristRotation,\n toPose.wristRotation,\n initialProgress\n );\n\n return {\n ...state,\n targetPose,\n transitionProgress: initialProgress,\n currentFingerCurl: newFingerCurl,\n currentFingerSpread: newFingerSpread,\n currentWristRotation: newWristRotation,\n };\n }\n\n // Continue existing transition\n const newProgress = Math.min(\n 1.0,\n state.transitionProgress + deltaTime / transitionDuration\n );\n\n // Get poses for interpolation\n const fromPose = getHandPose(state.currentPose);\n const toPose = getHandPose(targetPose);\n\n // Interpolate values\n const newFingerCurl = interpolateFingerCurl(\n fromPose.fingerCurl,\n toPose.fingerCurl,\n newProgress\n );\n const newFingerSpread = interpolateFingerSpread(\n fromPose.fingerSpread,\n toPose.fingerSpread,\n newProgress\n );\n const newWristRotation = interpolateWristRotation(\n fromPose.wristRotation,\n toPose.wristRotation,\n newProgress\n );\n\n // Check if transition is complete\n if (newProgress >= 1.0) {\n return {\n ...state,\n currentPose: targetPose,\n targetPose: null,\n transitionProgress: 1.0,\n currentFingerCurl: toPose.fingerCurl,\n currentFingerSpread: toPose.fingerSpread,\n currentWristRotation: toPose.wristRotation.clone(),\n };\n }\n\n return {\n ...state,\n transitionProgress: newProgress,\n currentFingerCurl: newFingerCurl,\n currentFingerSpread: newFingerSpread,\n currentWristRotation: newWristRotation,\n };\n};\n\n/**\n * Set hand highlight mode for vital point targeting\n *\n * @param state - Current hand animation state\n * @param isHighlighted - Whether hand is highlighted\n * @param mode - Highlight mode for striking surface\n * @returns Updated hand animation state\n * @korean 손표시설정\n */\nexport const setHandHighlight = (\n state: HandAnimationState,\n isHighlighted: boolean,\n mode: HandAnimationState[\"highlightMode\"] = null\n): HandAnimationState => {\n return {\n ...state,\n isHighlighted,\n highlightMode: isHighlighted ? mode : null,\n };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"KeyframeConfig.js","names":[],"sources":["../../../../src/systems/animation/builders/KeyframeConfig.ts"],"sourcesContent":["/**\n * Keyframe Configuration Helper\n *\n * Helper class for configuring animation keyframes with bone rotations, positions,\n * and integrated anatomy state (hands, feet, facial expressions, muscle activations).\n * 애니메이션 키프레임 설정 헬퍼 클래스 (해부학 상태 통합)\n *\n * @module systems/animation/KeyframeConfig\n * @korean 키프레임설정\n */\n\nimport type { AnimationKeyframe, SkeletalAnimation } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport * as THREE from \"three\";\nimport type { GuardPositionType } from \"./KoreanGuardPositions\";\nimport { getGuardPosition } from \"./KoreanGuardPositions\";\n\n/** Hand highlight mode for striking surface visualization */\nexport type HandHighlightMode =\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\";\n\n// Forward declaration for builder type\ninterface AnimationBuilderLike {\n _addKeyframe(kf: AnimationKeyframe): void;\n at(time: number, easing?: string): KeyframeConfig;\n build(): SkeletalAnimation;\n}\n\n/**\n * Keyframe configuration helper\n *\n * Provides a fluent API for configuring bone rotations, positions,\n * and anatomy state (hands, feet, facial expressions) within a single keyframe.\n *\n * @example\n * ```typescript\n * const kf = new KeyframeConfig();\n * kf.rotate(BoneName.SHOULDER_R, -0.5, 0, 0.3)\n * .position(BoneName.HAND_R, 0.1, 0, 0)\n * .setLeftHandPose(\"fist\")\n * .setRightHandPose(\"fist\", \"knuckles\")\n * .setFootHighlight(\"right\", true)\n * .setFacialExpression(\"focused\");\n * ```\n *\n * @korean 키프레임설정헬퍼\n */\nexport class KeyframeConfig {\n /** Bone rotation data (bone -> euler rotation) */\n rotations = new Map<BoneName, THREE.Euler>();\n\n /** Bone position data (bone -> position offset) */\n positions = new Map<BoneName, THREE.Vector3>();\n\n /** Parent builder reference for fluent chaining */\n private builder: AnimationBuilderLike | null = null;\n\n /** Keyframe time */\n private time: number = 0;\n\n /** Keyframe easing function */\n private easing: string = \"linear\";\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ANATOMY STATE (해부학 상태) - Integrated hand, foot, and facial animation\n // ═══════════════════════════════════════════════════════════════════════════\n\n /** Left hand pose type */\n private _leftHandPose?: string;\n\n /** Right hand pose type */\n private _rightHandPose?: string;\n\n /** Left hand highlight mode */\n private _leftHandHighlightMode?: HandHighlightMode;\n\n /** Right hand highlight mode */\n private _rightHandHighlightMode?: HandHighlightMode;\n\n /** Left foot highlight state */\n private _leftFootHighlight?: boolean;\n\n /** Right foot highlight state */\n private _rightFootHighlight?: boolean;\n\n /** Facial expression */\n private _facialExpression?: string;\n\n /** Muscle activation targets */\n private _muscleActivations?: Map<string, number>;\n\n /**\n * Associate this keyframe with a builder for the `done()` method\n * @internal\n */\n setBuilder(\n builder: AnimationBuilderLike,\n time: number,\n easing: string,\n ): void {\n this.builder = builder;\n this.time = time;\n this.easing = easing;\n }\n\n /**\n * Set bone rotation (euler angles in radians)\n *\n * @param bone - Target bone name\n * @param x - X rotation (radians)\n * @param y - Y rotation (radians)\n * @param z - Z rotation (radians)\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * kf.rotate(BoneName.SHOULDER_R, -0.5, 0, 0.3);\n * ```\n *\n * @korean 뼈회전설정\n */\n rotate(bone: BoneName, x: number, y: number, z: number): this {\n this.rotations.set(bone, new THREE.Euler(x, y, z));\n return this;\n }\n\n /**\n * Set bone position offset\n *\n * @param bone - Target bone name\n * @param x - X position offset\n * @param y - Y position offset\n * @param z - Z position offset\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * kf.position(BoneName.FOOT_R, 0, 0.5, 0.3);\n * ```\n *\n * @korean 뼈위치설정\n */\n position(bone: BoneName, x: number, y: number, z: number): this {\n this.positions.set(bone, new THREE.Vector3(x, y, z));\n return this;\n }\n\n /**\n * Apply Korean guard position to arms\n *\n * Sets proper Korean martial arts guard positions (막기자세) for defensive posture.\n * Supports applying guard to one side or both sides.\n *\n * @param guardType - Type of guard (\"HIGH_GUARD\" | \"MIDDLE_GUARD\" | \"LOW_GUARD\")\n * @param side - Which side to apply (\"left\" | \"right\" | \"both\")\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * // Apply middle guard to both hands\n * kf.withGuard(\"MIDDLE_GUARD\");\n *\n * // Apply middle guard only to left hand (right hand attacks)\n * kf.withGuard(\"MIDDLE_GUARD\", \"left\");\n * ```\n *\n * @korean 방어자세적용\n */\n withGuard(\n guardType: GuardPositionType,\n side: \"left\" | \"right\" | \"both\" = \"both\",\n ): this {\n const guard = getGuardPosition(guardType);\n\n if (side === \"left\" || side === \"both\") {\n this.rotate(\n BoneName.SHOULDER_L,\n guard.left.shoulder[0],\n guard.left.shoulder[1],\n guard.left.shoulder[2],\n );\n this.rotate(\n BoneName.ELBOW_L,\n guard.left.elbow[0],\n guard.left.elbow[1],\n guard.left.elbow[2],\n );\n this.rotate(\n BoneName.WRIST_L,\n guard.left.wrist[0],\n guard.left.wrist[1],\n guard.left.wrist[2],\n );\n }\n\n if (side === \"right\" || side === \"both\") {\n this.rotate(\n BoneName.SHOULDER_R,\n guard.right.shoulder[0],\n guard.right.shoulder[1],\n guard.right.shoulder[2],\n );\n this.rotate(\n BoneName.ELBOW_R,\n guard.right.elbow[0],\n guard.right.elbow[1],\n guard.right.elbow[2],\n );\n this.rotate(\n BoneName.WRIST_R,\n guard.right.wrist[0],\n guard.right.wrist[1],\n guard.right.wrist[2],\n );\n }\n\n return this;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ANATOMY STATE SETTERS (해부학 상태 설정)\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Set left hand pose for this keyframe\n *\n * @param pose - Hand pose type (e.g., \"fist\", \"knife_hand\", \"open\")\n * @param highlightMode - Optional highlight mode for striking surface\n * @returns this for chaining\n *\n * @korean 왼손자세설정\n */\n setLeftHandPose(pose: string, highlightMode?: HandHighlightMode): this {\n this._leftHandPose = pose;\n if (highlightMode) {\n this._leftHandHighlightMode = highlightMode;\n }\n return this;\n }\n\n /**\n * Set right hand pose for this keyframe\n *\n * @param pose - Hand pose type (e.g., \"fist\", \"knife_hand\", \"open\")\n * @param highlightMode - Optional highlight mode for striking surface\n * @returns this for chaining\n *\n * @korean 오른손자세설정\n */\n setRightHandPose(pose: string, highlightMode?: HandHighlightMode): this {\n this._rightHandPose = pose;\n if (highlightMode) {\n this._rightHandHighlightMode = highlightMode;\n }\n return this;\n }\n\n /**\n * Set both hands to the same pose\n *\n * @param pose - Hand pose type for both hands\n * @returns this for chaining\n *\n * @korean 양손자세설정\n */\n setBothHandPoses(pose: string): this {\n this._leftHandPose = pose;\n this._rightHandPose = pose;\n return this;\n }\n\n /**\n * Set foot highlight state for kicks\n *\n * @param side - Which foot (\"left\" | \"right\" | \"both\")\n * @param highlighted - Whether to highlight\n * @returns this for chaining\n *\n * @korean 발강조설정\n */\n setFootHighlight(\n side: \"left\" | \"right\" | \"both\",\n highlighted: boolean,\n ): this {\n if (side === \"left\" || side === \"both\") {\n this._leftFootHighlight = highlighted;\n }\n if (side === \"right\" || side === \"both\") {\n this._rightFootHighlight = highlighted;\n }\n return this;\n }\n\n /**\n * Set facial expression for this keyframe\n *\n * @param expression - Facial expression (e.g., \"neutral\", \"focused\", \"pained\")\n * @returns this for chaining\n *\n * @korean 얼굴표정설정\n */\n setFacialExpression(expression: string): this {\n this._facialExpression = expression;\n return this;\n }\n\n /**\n * Set muscle activation target for this keyframe\n *\n * @param muscleGroup - Muscle group name (e.g., \"BICEP_R\", \"QUAD_L\")\n * @param tension - Tension level (0-1)\n * @returns this for chaining\n *\n * @korean 근육활성화설정\n */\n setMuscleActivation(muscleGroup: string, tension: number): this {\n this._muscleActivations ??= new Map();\n this._muscleActivations.set(muscleGroup, Math.max(0, Math.min(1, tension)));\n return this;\n }\n\n /**\n * Set multiple muscle activations at once\n *\n * @param activations - Map or object of muscle group to tension\n * @returns this for chaining\n *\n * @korean 다중근육활성화설정\n */\n setMuscleActivations(\n activations: Map<string, number> | Record<string, number>,\n ): this {\n this._muscleActivations ??= new Map();\n if (activations instanceof Map) {\n activations.forEach((tension, group) => {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- initialized above\n this._muscleActivations!.set(group, Math.max(0, Math.min(1, tension)));\n });\n } else {\n Object.entries(activations).forEach(([group, tension]) => {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- initialized above\n this._muscleActivations!.set(group, Math.max(0, Math.min(1, tension)));\n });\n }\n return this;\n }\n\n /**\n * Complete keyframe configuration and return to builder\n *\n * @returns Parent builder for method chaining\n * @throws Error if not associated with a builder\n *\n * @korean 키프레임완료\n */\n done<T extends AnimationBuilderLike>(): T {\n if (!this.builder) {\n throw new Error(\"KeyframeConfig not associated with builder\");\n }\n this.builder._addKeyframe({\n time: this.time,\n easing: this.easing as \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\",\n boneRotations: this.rotations,\n bonePositions: this.positions,\n // Anatomy state\n leftHandPose: this._leftHandPose,\n rightHandPose: this._rightHandPose,\n leftHandHighlightMode: this._leftHandHighlightMode,\n rightHandHighlightMode: this._rightHandHighlightMode,\n leftFootHighlight: this._leftFootHighlight,\n rightFootHighlight: this._rightFootHighlight,\n facialExpression: this._facialExpression,\n muscleActivations: this._muscleActivations,\n });\n return this.builder as T;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"KeyframeConfig.js","names":[],"sources":["../../../../src/systems/animation/builders/KeyframeConfig.ts"],"sourcesContent":["/**\n * Keyframe Configuration Helper\n *\n * Helper class for configuring animation keyframes with bone rotations, positions,\n * and integrated anatomy state (hands, feet, facial expressions, muscle activations).\n * 애니메이션 키프레임 설정 헬퍼 클래스 (해부학 상태 통합)\n *\n * @module systems/animation/KeyframeConfig\n * @korean 키프레임설정\n */\n\nimport type { AnimationKeyframe, SkeletalAnimation } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport * as THREE from \"three\";\nimport type { GuardPositionType } from \"./KoreanGuardPositions\";\nimport { getGuardPosition } from \"./KoreanGuardPositions\";\n\n/** Hand highlight mode for striking surface visualization */\nexport type HandHighlightMode =\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\";\n\n// Forward declaration for builder type\ninterface AnimationBuilderLike {\n _addKeyframe(kf: AnimationKeyframe): void;\n at(time: number, easing?: string): KeyframeConfig;\n build(): SkeletalAnimation;\n}\n\n/**\n * Keyframe configuration helper\n *\n * Provides a fluent API for configuring bone rotations, positions,\n * and anatomy state (hands, feet, facial expressions) within a single keyframe.\n *\n * @example\n * ```typescript\n * const kf = new KeyframeConfig();\n * kf.rotate(BoneName.SHOULDER_R, -0.5, 0, 0.3)\n * .position(BoneName.HAND_R, 0.1, 0, 0)\n * .setLeftHandPose(\"fist\")\n * .setRightHandPose(\"fist\", \"knuckles\")\n * .setFootHighlight(\"right\", true)\n * .setFacialExpression(\"focused\");\n * ```\n *\n * @korean 키프레임설정헬퍼\n */\nexport class KeyframeConfig {\n /** Bone rotation data (bone -> euler rotation) */\n rotations = new Map<BoneName, THREE.Euler>();\n\n /** Bone position data (bone -> position offset) */\n positions = new Map<BoneName, THREE.Vector3>();\n\n /** Parent builder reference for fluent chaining */\n private builder: AnimationBuilderLike | null = null;\n\n /** Keyframe time */\n private time: number = 0;\n\n /** Keyframe easing function */\n private easing: string = \"linear\";\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ANATOMY STATE (해부학 상태) - Integrated hand, foot, and facial animation\n // ═══════════════════════════════════════════════════════════════════════════\n\n /** Left hand pose type */\n private _leftHandPose?: string;\n\n /** Right hand pose type */\n private _rightHandPose?: string;\n\n /** Left hand highlight mode */\n private _leftHandHighlightMode?: HandHighlightMode;\n\n /** Right hand highlight mode */\n private _rightHandHighlightMode?: HandHighlightMode;\n\n /** Left foot highlight state */\n private _leftFootHighlight?: boolean;\n\n /** Right foot highlight state */\n private _rightFootHighlight?: boolean;\n\n /** Facial expression */\n private _facialExpression?: string;\n\n /** Muscle activation targets */\n private _muscleActivations?: Map<string, number>;\n\n /**\n * Associate this keyframe with a builder for the `done()` method\n * @internal\n */\n setBuilder(\n builder: AnimationBuilderLike,\n time: number,\n easing: string,\n ): void {\n this.builder = builder;\n this.time = time;\n this.easing = easing;\n }\n\n /**\n * Set bone rotation (euler angles in radians)\n *\n * @param bone - Target bone name\n * @param x - X rotation (radians)\n * @param y - Y rotation (radians)\n * @param z - Z rotation (radians)\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * kf.rotate(BoneName.SHOULDER_R, -0.5, 0, 0.3);\n * ```\n *\n * @korean 뼈회전설정\n */\n rotate(bone: BoneName, x: number, y: number, z: number): this {\n this.rotations.set(bone, new THREE.Euler(x, y, z));\n return this;\n }\n\n /**\n * Set bone position offset\n *\n * @param bone - Target bone name\n * @param x - X position offset\n * @param y - Y position offset\n * @param z - Z position offset\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * kf.position(BoneName.FOOT_R, 0, 0.5, 0.3);\n * ```\n *\n * @korean 뼈위치설정\n */\n position(bone: BoneName, x: number, y: number, z: number): this {\n this.positions.set(bone, new THREE.Vector3(x, y, z));\n return this;\n }\n\n /**\n * Apply Korean guard position to arms\n *\n * Sets proper Korean martial arts guard positions (막기자세) for defensive posture.\n * Supports applying guard to one side or both sides.\n *\n * @param guardType - Type of guard (\"HIGH_GUARD\" | \"MIDDLE_GUARD\" | \"LOW_GUARD\")\n * @param side - Which side to apply (\"left\" | \"right\" | \"both\")\n * @returns this for chaining\n *\n * @example\n * ```typescript\n * // Apply middle guard to both hands\n * kf.withGuard(\"MIDDLE_GUARD\");\n *\n * // Apply middle guard only to left hand (right hand attacks)\n * kf.withGuard(\"MIDDLE_GUARD\", \"left\");\n * ```\n *\n * @korean 방어자세적용\n */\n withGuard(\n guardType: GuardPositionType,\n side: \"left\" | \"right\" | \"both\" = \"both\",\n ): this {\n const guard = getGuardPosition(guardType);\n\n if (side === \"left\" || side === \"both\") {\n this.rotate(\n BoneName.SHOULDER_L,\n guard.left.shoulder[0],\n guard.left.shoulder[1],\n guard.left.shoulder[2],\n );\n this.rotate(\n BoneName.ELBOW_L,\n guard.left.elbow[0],\n guard.left.elbow[1],\n guard.left.elbow[2],\n );\n this.rotate(\n BoneName.WRIST_L,\n guard.left.wrist[0],\n guard.left.wrist[1],\n guard.left.wrist[2],\n );\n }\n\n if (side === \"right\" || side === \"both\") {\n this.rotate(\n BoneName.SHOULDER_R,\n guard.right.shoulder[0],\n guard.right.shoulder[1],\n guard.right.shoulder[2],\n );\n this.rotate(\n BoneName.ELBOW_R,\n guard.right.elbow[0],\n guard.right.elbow[1],\n guard.right.elbow[2],\n );\n this.rotate(\n BoneName.WRIST_R,\n guard.right.wrist[0],\n guard.right.wrist[1],\n guard.right.wrist[2],\n );\n }\n\n return this;\n }\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ANATOMY STATE SETTERS (해부학 상태 설정)\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Set left hand pose for this keyframe\n *\n * @param pose - Hand pose type (e.g., \"fist\", \"knife_hand\", \"open\")\n * @param highlightMode - Optional highlight mode for striking surface\n * @returns this for chaining\n *\n * @korean 왼손자세설정\n */\n setLeftHandPose(pose: string, highlightMode?: HandHighlightMode): this {\n this._leftHandPose = pose;\n if (highlightMode) {\n this._leftHandHighlightMode = highlightMode;\n }\n return this;\n }\n\n /**\n * Set right hand pose for this keyframe\n *\n * @param pose - Hand pose type (e.g., \"fist\", \"knife_hand\", \"open\")\n * @param highlightMode - Optional highlight mode for striking surface\n * @returns this for chaining\n *\n * @korean 오른손자세설정\n */\n setRightHandPose(pose: string, highlightMode?: HandHighlightMode): this {\n this._rightHandPose = pose;\n if (highlightMode) {\n this._rightHandHighlightMode = highlightMode;\n }\n return this;\n }\n\n /**\n * Set both hands to the same pose\n *\n * @param pose - Hand pose type for both hands\n * @returns this for chaining\n *\n * @korean 양손자세설정\n */\n setBothHandPoses(pose: string): this {\n this._leftHandPose = pose;\n this._rightHandPose = pose;\n return this;\n }\n\n /**\n * Set foot highlight state for kicks\n *\n * @param side - Which foot (\"left\" | \"right\" | \"both\")\n * @param highlighted - Whether to highlight\n * @returns this for chaining\n *\n * @korean 발강조설정\n */\n setFootHighlight(\n side: \"left\" | \"right\" | \"both\",\n highlighted: boolean,\n ): this {\n if (side === \"left\" || side === \"both\") {\n this._leftFootHighlight = highlighted;\n }\n if (side === \"right\" || side === \"both\") {\n this._rightFootHighlight = highlighted;\n }\n return this;\n }\n\n /**\n * Set facial expression for this keyframe\n *\n * @param expression - Facial expression (e.g., \"neutral\", \"focused\", \"pained\")\n * @returns this for chaining\n *\n * @korean 얼굴표정설정\n */\n setFacialExpression(expression: string): this {\n this._facialExpression = expression;\n return this;\n }\n\n /**\n * Set muscle activation target for this keyframe\n *\n * @param muscleGroup - Muscle group name (e.g., \"BICEP_R\", \"QUAD_L\")\n * @param tension - Tension level (0-1)\n * @returns this for chaining\n *\n * @korean 근육활성화설정\n */\n setMuscleActivation(muscleGroup: string, tension: number): this {\n this._muscleActivations ??= new Map();\n this._muscleActivations.set(muscleGroup, Math.max(0, Math.min(1, tension)));\n return this;\n }\n\n /**\n * Set multiple muscle activations at once\n *\n * @param activations - Map or object of muscle group to tension\n * @returns this for chaining\n *\n * @korean 다중근육활성화설정\n */\n setMuscleActivations(\n activations: Map<string, number> | Record<string, number>,\n ): this {\n this._muscleActivations ??= new Map();\n if (activations instanceof Map) {\n activations.forEach((tension, group) => {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- initialized above\n this._muscleActivations!.set(group, Math.max(0, Math.min(1, tension)));\n });\n } else {\n Object.entries(activations).forEach(([group, tension]) => {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion -- initialized above\n this._muscleActivations!.set(group, Math.max(0, Math.min(1, tension)));\n });\n }\n return this;\n }\n\n /**\n * Complete keyframe configuration and return to builder\n *\n * @returns Parent builder for method chaining\n * @throws Error if not associated with a builder\n *\n * @korean 키프레임완료\n */\n done<T extends AnimationBuilderLike>(): T {\n if (!this.builder) {\n throw new Error(\"KeyframeConfig not associated with builder\");\n }\n this.builder._addKeyframe({\n time: this.time,\n easing: this.easing as \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\",\n boneRotations: this.rotations,\n bonePositions: this.positions,\n // Anatomy state\n leftHandPose: this._leftHandPose,\n rightHandPose: this._rightHandPose,\n leftHandHighlightMode: this._leftHandHighlightMode,\n rightHandHighlightMode: this._rightHandHighlightMode,\n leftFootHighlight: this._leftFootHighlight,\n rightFootHighlight: this._rightFootHighlight,\n facialExpression: this._facialExpression,\n muscleActivations: this._muscleActivations,\n });\n return this.builder as T;\n }\n}\n"],"mappings":"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"}
@@ -1,91 +1,4 @@
1
1
  import * as THREE from "three";
2
- //#region src/systems/animation/builders/KeyframeInterpolation.ts
3
- /**
4
- * Keyframe interpolation for smooth skeletal animations
5
- *
6
- * Provides interpolation between animation keyframes for smooth 60fps playback.
7
- * Supports linear, ease-in, ease-out, and ease-in-out easing functions.
8
- *
9
- * @module systems/animation/KeyframeInterpolation
10
- * @category Animation System
11
- * @korean 키프레임보간
12
- */
13
- /**
14
- * Cubic bezier easing for natural movement
15
- *
16
- * **Korean**: 3차 베지어 이징
17
- *
18
- * Implements cubic bezier curve interpolation for smooth, natural motion.
19
- * Based on CSS cubic-bezier() function specification.
20
- *
21
- * This function uses a configuration object approach for better API clarity.
22
- * By default, uses simplified approximation (x progresses linearly with t) which
23
- * provides good results for animation with minimal overhead. Enable precisionMode
24
- * for exact calculations when needed.
25
- *
26
- * @param t - Input time (0-1)
27
- * @param options - Bezier control points and configuration
28
- * @returns Eased value
29
- *
30
- * @example
31
- * ```typescript
32
- * // Natural Korean martial arts movement (physics-based)
33
- * const eased = cubicBezierWithOptions(0.5, {
34
- * p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0
35
- * });
36
- *
37
- * // With precision mode for exact calculation
38
- * const precise = cubicBezierWithOptions(0.5, {
39
- * p1x: 0.42, p1y: 0, p2x: 0.58, p2y: 1.0,
40
- * precisionMode: true
41
- * });
42
- * ```
43
- *
44
- * @korean 3차베지어이징옵션
45
- */
46
- function cubicBezierWithOptions(t, options) {
47
- const clampedT = Math.max(0, Math.min(1, t));
48
- const u = 1 - clampedT;
49
- return 3 * u * u * clampedT * options.p1y + 3 * u * clampedT * clampedT * options.p2y + clampedT * clampedT * clampedT;
50
- }
51
- /**
52
- * Cubic bezier easing (legacy function signature for backward compatibility)
53
- *
54
- * **Korean**: 3차 베지어 이징 (레거시)
55
- *
56
- * @param t - Input time (0-1)
57
- * @param p1x - First control point x (0-1) - currently unused, reserved for precision mode
58
- * @param p1y - First control point y (can exceed 0-1 for overshoot)
59
- * @param p2x - Second control point x (0-1) - currently unused, reserved for precision mode
60
- * @param p2y - Second control point y (can exceed 0-1 for overshoot)
61
- * @returns Eased value
62
- *
63
- * @deprecated Use cubicBezierWithOptions for clearer API
64
- * @korean 3차베지어이징레거시
65
- */
66
- function cubicBezier(t, p1x, p1y, p2x, p2y) {
67
- return cubicBezierWithOptions(t, {
68
- p1x,
69
- p1y,
70
- p2x,
71
- p2y
72
- });
73
- }
74
- /**
75
- * Create a cubic bezier easing function with control points
76
- *
77
- * **Korean**: 베지어 이징 함수 생성
78
- *
79
- * Factory function to create reusable bezier easing functions.
80
- *
81
- * @param points - Bezier control points
82
- * @returns Easing function
83
- *
84
- * @korean 베지어이징함수생성
85
- */
86
- function createBezierEasing(points) {
87
- return (t) => cubicBezier(t, points.p1x, points.p1y, points.p2x, points.p2y);
88
- }
89
2
  /**
90
3
  * Preset bezier easing curves for Korean martial arts movements
91
4
  *
@@ -152,9 +65,9 @@ var BEZIER_PRESETS = {
152
65
  p2y: .4
153
66
  }
154
67
  };
155
- createBezierEasing(BEZIER_PRESETS.naturalMotion);
156
- createBezierEasing(BEZIER_PRESETS.smoothTransition);
157
- createBezierEasing(BEZIER_PRESETS.explosivePower);
68
+ BEZIER_PRESETS.naturalMotion;
69
+ BEZIER_PRESETS.smoothTransition;
70
+ BEZIER_PRESETS.explosivePower;
158
71
  /**
159
72
  * Create motion prediction state
160
73
  *