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":"KeyframeInterpolation.js","names":[],"sources":["../../../../src/systems/animation/builders/KeyframeInterpolation.ts"],"sourcesContent":["/**\n * Keyframe interpolation for smooth skeletal animations\n * \n * Provides interpolation between animation keyframes for smooth 60fps playback.\n * Supports linear, ease-in, ease-out, and ease-in-out easing functions.\n * \n * @module systems/animation/KeyframeInterpolation\n * @category Animation System\n * @korean 키프레임보간\n */\n\nimport * as THREE from \"three\";\nimport type {\n AnimationKeyframe,\n SkeletalAnimation,\n SkeletalRig,\n} from \"@/types/skeletal\";\n\n/**\n * Easing function type\n * \n * @param t - Time value between 0 and 1\n * @returns Eased value between 0 and 1\n * \n * @korean 이징함수타입\n */\ntype EasingFunction = (t: number) => number;\n\n/**\n * Cubic bezier control points for easing curves\n * \n * **Korean**: 3차 베지어 제어점\n * \n * @public\n * @category Animation\n * @korean 베지어제어점\n */\nexport interface BezierControlPoints {\n /** First control point x (0-1) */\n readonly p1x: number;\n /** First control point y (0-1) */\n readonly p1y: number;\n /** Second control point x (0-1) */\n readonly p2x: number;\n /** Second control point y (0-1) */\n readonly p2y: number;\n /** \n * Enable precision mode for exact bezier curve calculation\n * \n * **Reserved for future implementation.**\n * \n * When false (default), uses simplified approximation assuming x progresses linearly with t.\n * This is standard for CSS cubic-bezier() and provides good results with minimal overhead.\n * \n * When true (future), will perform iterative solving for accurate x-t mapping (higher CPU cost).\n * This would enable non-linear time progression for more complex easing curves.\n * \n * Currently unused - kept in interface for forward compatibility without breaking API changes.\n * \n * @korean 정밀모드\n */\n readonly precisionMode?: boolean;\n}\n\n/**\n * Cubic bezier easing for natural movement\n * \n * **Korean**: 3차 베지어 이징\n * \n * Implements cubic bezier curve interpolation for smooth, natural motion.\n * Based on CSS cubic-bezier() function specification.\n * \n * This function uses a configuration object approach for better API clarity.\n * By default, uses simplified approximation (x progresses linearly with t) which\n * provides good results for animation with minimal overhead. Enable precisionMode\n * for exact calculations when needed.\n * \n * @param t - Input time (0-1)\n * @param options - Bezier control points and configuration\n * @returns Eased value\n * \n * @example\n * ```typescript\n * // Natural Korean martial arts movement (physics-based)\n * const eased = cubicBezierWithOptions(0.5, { \n * p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 \n * });\n * \n * // With precision mode for exact calculation\n * const precise = cubicBezierWithOptions(0.5, {\n * p1x: 0.42, p1y: 0, p2x: 0.58, p2y: 1.0,\n * precisionMode: true\n * });\n * ```\n * \n * @korean 3차베지어이징옵션\n */\nexport function cubicBezierWithOptions(\n t: number,\n options: BezierControlPoints\n): number {\n // Clamp t to [0, 1]\n const clampedT = Math.max(0, Math.min(1, t));\n \n // For performance, use direct calculation (standard for CSS cubic-bezier)\n // Note: options.precisionMode is currently unused and reserved for future implementation\n // where we could add iterative solving for exact x-t mapping\n const u = 1 - clampedT;\n \n // Cubic bezier formula: B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃\n // For easing, P₀ = (0,0) and P₃ = (1,1), so:\n // y(t) = 3(1-t)²t*p1y + 3(1-t)t²*p2y + t³\n const result = 3 * u * u * clampedT * options.p1y + \n 3 * u * clampedT * clampedT * options.p2y + \n clampedT * clampedT * clampedT;\n \n return result;\n}\n\n/**\n * Cubic bezier easing (legacy function signature for backward compatibility)\n * \n * **Korean**: 3차 베지어 이징 (레거시)\n * \n * @param t - Input time (0-1)\n * @param p1x - First control point x (0-1) - currently unused, reserved for precision mode\n * @param p1y - First control point y (can exceed 0-1 for overshoot)\n * @param p2x - Second control point x (0-1) - currently unused, reserved for precision mode\n * @param p2y - Second control point y (can exceed 0-1 for overshoot)\n * @returns Eased value\n * \n * @deprecated Use cubicBezierWithOptions for clearer API\n * @korean 3차베지어이징레거시\n */\nexport function cubicBezier(\n t: number,\n p1x: number,\n p1y: number,\n p2x: number,\n p2y: number\n): number {\n return cubicBezierWithOptions(t, { p1x, p1y, p2x, p2y });\n}\n\n/**\n * Create a cubic bezier easing function with control points\n * \n * **Korean**: 베지어 이징 함수 생성\n * \n * Factory function to create reusable bezier easing functions.\n * \n * @param points - Bezier control points\n * @returns Easing function\n * \n * @korean 베지어이징함수생성\n */\nexport function createBezierEasing(points: BezierControlPoints): EasingFunction {\n return (t: number) => cubicBezier(t, points.p1x, points.p1y, points.p2x, points.p2y);\n}\n\n/**\n * Preset bezier easing curves for Korean martial arts movements\n * \n * **Korean**: 무도 동작 이징 곡선\n * \n * @public\n * @category Animation\n * @korean 무도동작이징곡선\n */\nexport const BEZIER_PRESETS = {\n /**\n * Natural motion with physics-based acceleration/deceleration\n * Ideal for: Stance transitions, body rotations, weight shifts\n * **Korean**: 자연스러운 물리 기반 동작\n */\n naturalMotion: { p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Smooth S-curve for fluid transitions\n * Ideal for: Attack wind-ups, defensive positioning, footwork\n * **Korean**: 부드러운 S곡선 전환\n */\n smoothTransition: { p1x: 0.42, p1y: 0.0, p2x: 0.58, p2y: 1.0 },\n \n /**\n * Quick start with gentle landing\n * Ideal for: Strike recoil, guard recovery, step completion\n * **Korean**: 빠른 시작과 부드러운 착지\n */\n quickStart: { p1x: 0.1, p1y: 0.8, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Explosive power curve\n * Ideal for: Explosive strikes, power techniques, ki projection\n * **Korean**: 폭발적 힘 곡선\n */\n explosivePower: { p1x: 0.05, p1y: 0.9, p2x: 0.2, p2y: 1.0 },\n \n /**\n * Controlled deceleration\n * Ideal for: Defensive withdrawals, cautious movements, guard stance\n * **Korean**: 제어된 감속\n */\n controlledSlow: { p1x: 0.6, p1y: 0.0, p2x: 0.9, p2y: 0.4 },\n} as const;\n\n/**\n * Linear easing (no easing)\n * \n * @param t - Input time (0-1)\n * @returns Same as input\n * \n * @korean 선형이징\n */\nexport const easeLinear: EasingFunction = (t: number): number => t;\n\n/**\n * Ease-in (slow start, fast end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인\n */\nexport const easeIn: EasingFunction = (t: number): number => t * t;\n\n/**\n * Ease-out (fast start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈아웃\n */\nexport const easeOut: EasingFunction = (t: number): number => t * (2 - t);\n\n/**\n * Ease-in-out (slow start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인아웃\n */\nexport const easeInOut: EasingFunction = (t: number): number => {\n if (t < 0.5) {\n return 2 * t * t;\n }\n return -1 + (4 - 2 * t) * t;\n};\n\n/**\n * Natural motion bezier easing (preset)\n * \n * **Korean**: 자연스러운 동작 이징\n * \n * Physics-based movement ideal for Korean martial arts.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 자연동작이징\n */\nexport const easeNaturalMotion: EasingFunction = createBezierEasing(BEZIER_PRESETS.naturalMotion);\n\n/**\n * Smooth transition bezier easing (preset)\n * \n * **Korean**: 부드러운 전환 이징\n * \n * S-curve for fluid stance transitions.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 부드러운전환이징\n */\nexport const easeSmoothTransition: EasingFunction = createBezierEasing(BEZIER_PRESETS.smoothTransition);\n\n/**\n * Explosive power bezier easing (preset)\n * \n * **Korean**: 폭발적 힘 이징\n * \n * Explosive acceleration for power strikes.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 폭발적힘이징\n */\nexport const easeExplosivePower: EasingFunction = createBezierEasing(BEZIER_PRESETS.explosivePower);\n\n/**\n * Extended easing function names including bezier presets\n * \n * **Korean**: 확장된 이징 함수 이름\n * \n * @public\n * @category Animation\n * @korean 확장이징함수이름\n */\nexport type EasingName = \n | \"linear\"\n | \"ease-in\" \n | \"ease-out\" \n | \"ease-in-out\"\n | \"natural-motion\"\n | \"smooth-transition\"\n | \"quick-start\"\n | \"explosive-power\"\n | \"controlled-slow\";\n\n/**\n * Get easing function by name\n * \n * **Korean**: 이름으로 이징 함수 구하기\n * \n * @param name - Easing function name (supports bezier presets)\n * @returns Easing function\n * \n * @example\n * ```typescript\n * // Get natural motion easing for Korean martial arts\n * const easing = getEasingFunction(\"natural-motion\");\n * const easedValue = easing(0.5); // Smooth physics-based interpolation\n * \n * // Get explosive power for strike animations\n * const powerEasing = getEasingFunction(\"explosive-power\");\n * ```\n * \n * @korean 이징함수구하기\n */\nexport const getEasingFunction = (\n name: EasingName = \"linear\"\n): EasingFunction => {\n switch (name) {\n case \"ease-in\":\n return easeIn;\n case \"ease-out\":\n return easeOut;\n case \"ease-in-out\":\n return easeInOut;\n case \"natural-motion\":\n return easeNaturalMotion;\n case \"smooth-transition\":\n return easeSmoothTransition;\n case \"quick-start\":\n return createBezierEasing(BEZIER_PRESETS.quickStart);\n case \"explosive-power\":\n return easeExplosivePower;\n case \"controlled-slow\":\n return createBezierEasing(BEZIER_PRESETS.controlledSlow);\n default:\n return easeLinear;\n }\n};\n\n/**\n * Find keyframes surrounding current time\n * \n * Returns the two keyframes to interpolate between for current animation time.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Tuple of [previousKeyframe, nextKeyframe, interpolationFactor]\n * \n * @korean 주변키프레임찾기\n */\nexport const findSurroundingKeyframes = (\n animation: SkeletalAnimation,\n currentTime: number\n): [AnimationKeyframe, AnimationKeyframe, number] => {\n const { keyframes } = animation;\n\n // Clamp time to animation duration\n const clampedTime = Math.max(\n 0,\n Math.min(currentTime, animation.duration)\n );\n\n // Find keyframes\n let prevKeyframe = keyframes[0];\n let nextKeyframe = keyframes[keyframes.length - 1];\n let interpolationFactor = 0;\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n const current = keyframes[i];\n const next = keyframes[i + 1];\n\n if (clampedTime >= current.time && clampedTime <= next.time) {\n prevKeyframe = current;\n nextKeyframe = next;\n\n // Calculate interpolation factor (0 to 1)\n const timeDelta = next.time - current.time;\n if (timeDelta > 0) {\n interpolationFactor = (clampedTime - current.time) / timeDelta;\n }\n break;\n }\n }\n\n return [prevKeyframe, nextKeyframe, interpolationFactor];\n};\n\n/**\n * Interpolate between two Euler rotations\n * \n * Performs spherical linear interpolation (slerp) for smooth rotation.\n * \n * @param from - Start rotation\n * @param to - End rotation\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated rotation\n * \n * @korean 회전보간\n */\nexport const interpolateRotation = (\n from: THREE.Euler,\n to: THREE.Euler,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Euler => {\n const easedT = easingFn(t);\n\n // Convert Euler to Quaternion for proper slerp\n const fromQuat = new THREE.Quaternion().setFromEuler(from);\n const toQuat = new THREE.Quaternion().setFromEuler(to);\n\n // Slerp between quaternions\n const result = new THREE.Quaternion().slerpQuaternions(\n fromQuat,\n toQuat,\n easedT\n );\n\n // Convert back to Euler\n const resultEuler = new THREE.Euler().setFromQuaternion(result);\n return resultEuler;\n};\n\n/**\n * Interpolate between two Vector3 positions\n * \n * Performs linear interpolation for smooth position changes.\n * \n * @param from - Start position\n * @param to - End position\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated position\n * \n * @korean 위치보간\n */\nexport const interpolatePosition = (\n from: THREE.Vector3,\n to: THREE.Vector3,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Vector3 => {\n const easedT = easingFn(t);\n return new THREE.Vector3().lerpVectors(from, to, easedT);\n};\n\n/**\n * Get interpolated keyframe at current time\n * \n * Calculates bone transformations by interpolating between keyframes.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Interpolated keyframe\n * \n * @korean 보간된키프레임구하기\n */\nexport const getInterpolatedKeyframe = (\n animation: SkeletalAnimation,\n currentTime: number\n): AnimationKeyframe => {\n const [prevKeyframe, nextKeyframe, t] =\n findSurroundingKeyframes(animation, currentTime);\n\n // Get easing function from next keyframe\n const easingFn = getEasingFunction(nextKeyframe.easing);\n\n // Interpolate bone rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBoneNames = new Set([\n ...prevKeyframe.boneRotations.keys(),\n ...nextKeyframe.boneRotations.keys(),\n ]);\n\n for (const boneName of allBoneNames) {\n const prevRotation =\n prevKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n const nextRotation =\n nextKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n\n const interpolated = interpolateRotation(\n prevRotation,\n nextRotation,\n t,\n easingFn\n );\n boneRotations.set(boneName, interpolated);\n }\n\n // Interpolate bone positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...prevKeyframe.bonePositions.keys(),\n ...nextKeyframe.bonePositions.keys(),\n ]);\n\n for (const boneName of allPositionBones) {\n const prevPosition =\n prevKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n const nextPosition =\n nextKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n\n const interpolated = interpolatePosition(\n prevPosition,\n nextPosition,\n t,\n easingFn\n );\n bonePositions.set(boneName, interpolated);\n }\n\n return {\n time: currentTime,\n boneRotations,\n bonePositions,\n easing: nextKeyframe.easing,\n };\n};\n\n/**\n * Apply keyframe to skeletal rig\n * \n * Updates all bone transformations based on keyframe data.\n * \n * @param rig - Skeletal rig to update\n * @param keyframe - Keyframe to apply\n * \n * @korean 키프레임적용\n */\nexport const applyKeyframeToRig = (\n rig: SkeletalRig,\n keyframe: AnimationKeyframe\n): void => {\n // Apply bone rotations\n keyframe.boneRotations.forEach((rotation, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n bone.rotation.copy(rotation);\n }\n });\n\n // Apply bone positions (offset from rest pose)\n keyframe.bonePositions.forEach((position, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n // Add position offset to rest position\n bone.position.copy(bone.restPosition).add(position);\n }\n });\n};\n\n/**\n * Blend between two keyframes\n * \n * Creates smooth transition between two animations for animation blending.\n * Useful for transitioning between stance change and attack, etc.\n * \n * @param keyframe1 - First keyframe\n * @param keyframe2 - Second keyframe\n * @param blendFactor - Blend amount (0 = keyframe1, 1 = keyframe2)\n * @returns Blended keyframe\n * \n * @korean 키프레임블렌드\n */\nexport const blendKeyframes = (\n keyframe1: AnimationKeyframe,\n keyframe2: AnimationKeyframe,\n blendFactor: number\n): AnimationKeyframe => {\n const clampedBlend = Math.max(0, Math.min(1, blendFactor));\n\n // Blend rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBones = new Set([\n ...keyframe1.boneRotations.keys(),\n ...keyframe2.boneRotations.keys(),\n ]);\n\n allBones.forEach((boneName) => {\n const rot1 = keyframe1.boneRotations.get(boneName) ?? new THREE.Euler();\n const rot2 = keyframe2.boneRotations.get(boneName) ?? new THREE.Euler();\n const blended = interpolateRotation(rot1, rot2, clampedBlend);\n boneRotations.set(boneName, blended);\n });\n\n // Blend positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...keyframe1.bonePositions.keys(),\n ...keyframe2.bonePositions.keys(),\n ]);\n\n allPositionBones.forEach((boneName) => {\n const pos1 = keyframe1.bonePositions.get(boneName) ?? new THREE.Vector3();\n const pos2 = keyframe2.bonePositions.get(boneName) ?? new THREE.Vector3();\n const blended = interpolatePosition(pos1, pos2, clampedBlend);\n bonePositions.set(boneName, blended);\n });\n\n return {\n time: 0,\n boneRotations,\n bonePositions,\n easing: \"linear\",\n };\n};\n\n/**\n * Update animation state\n * \n * Advances animation time and returns current interpolated keyframe.\n * Handles looping animations automatically.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation\n * @param deltaTime - Time since last update (seconds)\n * @param playbackSpeed - Speed multiplier (1.0 = normal)\n * @returns Updated time and current keyframe\n * \n * @korean 애니메이션상태업데이트\n */\nexport const updateAnimation = (\n animation: SkeletalAnimation,\n currentTime: number,\n deltaTime: number,\n playbackSpeed = 1.0\n): { time: number; keyframe: AnimationKeyframe; completed: boolean } => {\n // Advance time\n let newTime = currentTime + deltaTime * playbackSpeed;\n let completed = false;\n\n // Handle looping or completion\n if (newTime >= animation.duration) {\n if (animation.loop) {\n newTime = newTime % animation.duration;\n } else {\n newTime = animation.duration;\n completed = true;\n }\n }\n\n // Get interpolated keyframe\n const keyframe = getInterpolatedKeyframe(animation, newTime);\n\n return {\n time: newTime,\n keyframe,\n completed,\n };\n};\n\n/**\n * Cross-fade blend between two animations\n * \n * **Korean**: 크로스페이드 블렌드\n * \n * Smoothly blends between two overlapping animations to prevent popping.\n * Uses cubic bezier easing for natural transitions.\n * \n * @param animation1 - First animation\n * @param time1 - Current time in first animation\n * @param animation2 - Second animation\n * @param time2 - Current time in second animation\n * @param blendFactor - Blend weight (0 = animation1, 1 = animation2)\n * @param easingName - Easing curve for blend transition\n * @returns Blended keyframe\n * \n * @example\n * ```typescript\n * // Cross-fade from idle to attack over 100ms\n * const blended = crossFadeAnimations(\n * idleAnim, idleTime,\n * attackAnim, attackTime,\n * 0.5, // 50% blend\n * \"smooth-transition\"\n * );\n * applyKeyframeToRig(rig, blended);\n * ```\n * \n * @korean 크로스페이드블렌드\n */\nexport const crossFadeAnimations = (\n animation1: SkeletalAnimation,\n time1: number,\n animation2: SkeletalAnimation,\n time2: number,\n blendFactor: number,\n easingName: EasingName = \"smooth-transition\"\n): AnimationKeyframe => {\n const keyframe1 = getInterpolatedKeyframe(animation1, time1);\n const keyframe2 = getInterpolatedKeyframe(animation2, time2);\n \n // Apply easing to blend factor\n const easingFn = getEasingFunction(easingName);\n const easedBlend = easingFn(Math.max(0, Math.min(1, blendFactor)));\n \n return blendKeyframes(keyframe1, keyframe2, easedBlend);\n};\n\n/**\n * Motion prediction state for latency reduction\n * \n * **Korean**: 동작 예측 상태\n * \n * Stores recent animation velocities for motion prediction.\n * \n * @public\n * @category Animation\n * @korean 동작예측상태\n */\nexport interface MotionPredictionState {\n /** Recent position velocities per bone */\n readonly velocities: Map<string, THREE.Vector3>;\n /** Recent rotation velocities per bone */\n readonly angularVelocities: Map<string, THREE.Euler>;\n /** Last update timestamp */\n readonly lastUpdateTime: number;\n}\n\n/**\n * Create motion prediction state\n * \n * **Korean**: 동작 예측 상태 생성\n * \n * @returns Initial motion prediction state\n * @korean 동작예측상태생성\n */\nexport const createMotionPredictionState = (): MotionPredictionState => ({\n velocities: new Map(),\n angularVelocities: new Map(),\n lastUpdateTime: 0,\n});\n\n/**\n * Update motion prediction state with new keyframe\n * \n * **Korean**: 동작 예측 상태 업데이트\n * \n * Calculates velocities from keyframe differences for motion prediction.\n * \n * @param state - Current prediction state\n * @param previousKeyframe - Previous animation keyframe\n * @param currentKeyframe - Current animation keyframe\n * @param deltaTime - Time elapsed between keyframes\n * @returns Updated prediction state\n * \n * @korean 동작예측상태업데이트\n */\nexport const updateMotionPrediction = (\n state: MotionPredictionState,\n previousKeyframe: AnimationKeyframe,\n currentKeyframe: AnimationKeyframe,\n deltaTime: number\n): MotionPredictionState => {\n if (deltaTime <= 0) return state;\n \n const newVelocities = new Map<string, THREE.Vector3>();\n const newAngularVelocities = new Map<string, THREE.Euler>();\n \n // Calculate position velocities\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const prevPos = previousKeyframe.bonePositions.get(boneName);\n if (prevPos) {\n const velocity = new THREE.Vector3()\n .subVectors(currentPos, prevPos)\n .divideScalar(deltaTime);\n newVelocities.set(boneName, velocity);\n }\n });\n \n // Calculate angular velocities using quaternion-based rotation differences\n // This avoids gimbal lock and angle wrapping issues with Euler angle differences\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const prevRot = previousKeyframe.boneRotations.get(boneName);\n if (prevRot) {\n // Convert Euler rotations to quaternions\n const qCurrent = new THREE.Quaternion().setFromEuler(currentRot);\n const qPrev = new THREE.Quaternion().setFromEuler(prevRot);\n \n // Calculate relative rotation: qDiff = qCurrent * qPrev^(-1)\n const qDiff = qCurrent.clone().multiply(qPrev.clone().invert());\n \n // Extract axis-angle representation for angular velocity\n const axis = new THREE.Vector3();\n const wClamped = THREE.MathUtils.clamp(qDiff.w, -1, 1);\n let angle = 2 * Math.acos(wClamped);\n const sinHalfAngle = Math.sqrt(1 - wClamped * wClamped);\n \n if (sinHalfAngle < 0.0001) {\n // If sinHalfAngle is too small, rotation is negligible - use zero velocity\n axis.set(0, 0, 0);\n angle = 0;\n } else {\n // Extract normalized axis from quaternion\n axis.set(\n qDiff.x / sinHalfAngle,\n qDiff.y / sinHalfAngle,\n qDiff.z / sinHalfAngle\n );\n }\n \n // Use shortest rotation path\n if (angle > Math.PI) {\n angle -= 2 * Math.PI;\n }\n \n // Angular velocity vector = axis * (angle / deltaTime)\n const angularVelocityVec = axis.multiplyScalar(angle / deltaTime);\n \n // Store as Euler for consistency with existing API\n const angularVel = new THREE.Euler(\n angularVelocityVec.x,\n angularVelocityVec.y,\n angularVelocityVec.z,\n currentRot.order\n );\n newAngularVelocities.set(boneName, angularVel);\n }\n });\n \n return {\n velocities: newVelocities,\n angularVelocities: newAngularVelocities,\n lastUpdateTime: performance.now(),\n };\n};\n\n/**\n * Predict future keyframe using motion prediction\n * \n * **Korean**: 동작 예측으로 미래 키프레임 예측\n * \n * Reduces perceived latency by predicting future bone positions/rotations\n * based on current velocities. Typical prediction: 16-33ms (1-2 frames at 60fps).\n * \n * @param currentKeyframe - Current animation keyframe\n * @param predictionState - Motion prediction state\n * @param predictionTime - Time ahead to predict (seconds, typically 0.016-0.033)\n * @returns Predicted keyframe\n * \n * @example\n * ```typescript\n * // Predict 1 frame ahead (16.67ms at 60fps) for <50ms total latency\n * const predicted = predictFutureKeyframe(\n * currentKeyframe,\n * motionState,\n * 0.01667\n * );\n * applyKeyframeToRig(rig, predicted);\n * ```\n * \n * @korean 미래키프레임예측\n */\nexport const predictFutureKeyframe = (\n currentKeyframe: AnimationKeyframe,\n predictionState: MotionPredictionState,\n predictionTime: number\n): AnimationKeyframe => {\n // Clamp prediction time to reasonable bounds (max 50ms)\n const clampedPrediction = Math.min(predictionTime, 0.05);\n \n // Predict bone positions\n const predictedPositions = new Map<string, THREE.Vector3>();\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const velocity = predictionState.velocities.get(boneName);\n if (velocity) {\n // Apply damping to prevent overshoot (0.8 factor for natural motion)\n const predicted = currentPos.clone().add(\n velocity.clone().multiplyScalar(clampedPrediction * 0.8)\n );\n predictedPositions.set(boneName, predicted);\n } else {\n predictedPositions.set(boneName, currentPos.clone());\n }\n });\n \n // Predict bone rotations\n const predictedRotations = new Map<string, THREE.Euler>();\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const angularVel = predictionState.angularVelocities.get(boneName);\n if (angularVel) {\n // Apply damping to prevent overshoot\n const predicted = new THREE.Euler(\n currentRot.x + angularVel.x * clampedPrediction * 0.8,\n currentRot.y + angularVel.y * clampedPrediction * 0.8,\n currentRot.z + angularVel.z * clampedPrediction * 0.8,\n currentRot.order\n );\n predictedRotations.set(boneName, predicted);\n } else {\n predictedRotations.set(boneName, currentRot.clone());\n }\n });\n \n return {\n time: currentKeyframe.time + clampedPrediction,\n boneRotations: predictedRotations,\n bonePositions: predictedPositions,\n easing: currentKeyframe.easing,\n };\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"KeyframeInterpolation.js","names":[],"sources":["../../../../src/systems/animation/builders/KeyframeInterpolation.ts"],"sourcesContent":["/**\n * Keyframe interpolation for smooth skeletal animations\n * \n * Provides interpolation between animation keyframes for smooth 60fps playback.\n * Supports linear, ease-in, ease-out, and ease-in-out easing functions.\n * \n * @module systems/animation/KeyframeInterpolation\n * @category Animation System\n * @korean 키프레임보간\n */\n\nimport * as THREE from \"three\";\nimport type {\n AnimationKeyframe,\n SkeletalAnimation,\n SkeletalRig,\n} from \"@/types/skeletal\";\n\n/**\n * Easing function type\n * \n * @param t - Time value between 0 and 1\n * @returns Eased value between 0 and 1\n * \n * @korean 이징함수타입\n */\ntype EasingFunction = (t: number) => number;\n\n/**\n * Cubic bezier control points for easing curves\n * \n * **Korean**: 3차 베지어 제어점\n * \n * @public\n * @category Animation\n * @korean 베지어제어점\n */\nexport interface BezierControlPoints {\n /** First control point x (0-1) */\n readonly p1x: number;\n /** First control point y (0-1) */\n readonly p1y: number;\n /** Second control point x (0-1) */\n readonly p2x: number;\n /** Second control point y (0-1) */\n readonly p2y: number;\n /** \n * Enable precision mode for exact bezier curve calculation\n * \n * **Reserved for future implementation.**\n * \n * When false (default), uses simplified approximation assuming x progresses linearly with t.\n * This is standard for CSS cubic-bezier() and provides good results with minimal overhead.\n * \n * When true (future), will perform iterative solving for accurate x-t mapping (higher CPU cost).\n * This would enable non-linear time progression for more complex easing curves.\n * \n * Currently unused - kept in interface for forward compatibility without breaking API changes.\n * \n * @korean 정밀모드\n */\n readonly precisionMode?: boolean;\n}\n\n/**\n * Cubic bezier easing for natural movement\n * \n * **Korean**: 3차 베지어 이징\n * \n * Implements cubic bezier curve interpolation for smooth, natural motion.\n * Based on CSS cubic-bezier() function specification.\n * \n * This function uses a configuration object approach for better API clarity.\n * By default, uses simplified approximation (x progresses linearly with t) which\n * provides good results for animation with minimal overhead. Enable precisionMode\n * for exact calculations when needed.\n * \n * @param t - Input time (0-1)\n * @param options - Bezier control points and configuration\n * @returns Eased value\n * \n * @example\n * ```typescript\n * // Natural Korean martial arts movement (physics-based)\n * const eased = cubicBezierWithOptions(0.5, { \n * p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 \n * });\n * \n * // With precision mode for exact calculation\n * const precise = cubicBezierWithOptions(0.5, {\n * p1x: 0.42, p1y: 0, p2x: 0.58, p2y: 1.0,\n * precisionMode: true\n * });\n * ```\n * \n * @korean 3차베지어이징옵션\n */\nexport function cubicBezierWithOptions(\n t: number,\n options: BezierControlPoints\n): number {\n // Clamp t to [0, 1]\n const clampedT = Math.max(0, Math.min(1, t));\n \n // For performance, use direct calculation (standard for CSS cubic-bezier)\n // Note: options.precisionMode is currently unused and reserved for future implementation\n // where we could add iterative solving for exact x-t mapping\n const u = 1 - clampedT;\n \n // Cubic bezier formula: B(t) = (1-t)³P₀ + 3(1-t)²tP₁ + 3(1-t)t²P₂ + t³P₃\n // For easing, P₀ = (0,0) and P₃ = (1,1), so:\n // y(t) = 3(1-t)²t*p1y + 3(1-t)t²*p2y + t³\n const result = 3 * u * u * clampedT * options.p1y + \n 3 * u * clampedT * clampedT * options.p2y + \n clampedT * clampedT * clampedT;\n \n return result;\n}\n\n/**\n * Cubic bezier easing (legacy function signature for backward compatibility)\n * \n * **Korean**: 3차 베지어 이징 (레거시)\n * \n * @param t - Input time (0-1)\n * @param p1x - First control point x (0-1) - currently unused, reserved for precision mode\n * @param p1y - First control point y (can exceed 0-1 for overshoot)\n * @param p2x - Second control point x (0-1) - currently unused, reserved for precision mode\n * @param p2y - Second control point y (can exceed 0-1 for overshoot)\n * @returns Eased value\n * \n * @deprecated Use cubicBezierWithOptions for clearer API\n * @korean 3차베지어이징레거시\n */\nexport function cubicBezier(\n t: number,\n p1x: number,\n p1y: number,\n p2x: number,\n p2y: number\n): number {\n return cubicBezierWithOptions(t, { p1x, p1y, p2x, p2y });\n}\n\n/**\n * Create a cubic bezier easing function with control points\n * \n * **Korean**: 베지어 이징 함수 생성\n * \n * Factory function to create reusable bezier easing functions.\n * \n * @param points - Bezier control points\n * @returns Easing function\n * \n * @korean 베지어이징함수생성\n */\nexport function createBezierEasing(points: BezierControlPoints): EasingFunction {\n return (t: number) => cubicBezier(t, points.p1x, points.p1y, points.p2x, points.p2y);\n}\n\n/**\n * Preset bezier easing curves for Korean martial arts movements\n * \n * **Korean**: 무도 동작 이징 곡선\n * \n * @public\n * @category Animation\n * @korean 무도동작이징곡선\n */\nexport const BEZIER_PRESETS = {\n /**\n * Natural motion with physics-based acceleration/deceleration\n * Ideal for: Stance transitions, body rotations, weight shifts\n * **Korean**: 자연스러운 물리 기반 동작\n */\n naturalMotion: { p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Smooth S-curve for fluid transitions\n * Ideal for: Attack wind-ups, defensive positioning, footwork\n * **Korean**: 부드러운 S곡선 전환\n */\n smoothTransition: { p1x: 0.42, p1y: 0.0, p2x: 0.58, p2y: 1.0 },\n \n /**\n * Quick start with gentle landing\n * Ideal for: Strike recoil, guard recovery, step completion\n * **Korean**: 빠른 시작과 부드러운 착지\n */\n quickStart: { p1x: 0.1, p1y: 0.8, p2x: 0.25, p2y: 1.0 },\n \n /**\n * Explosive power curve\n * Ideal for: Explosive strikes, power techniques, ki projection\n * **Korean**: 폭발적 힘 곡선\n */\n explosivePower: { p1x: 0.05, p1y: 0.9, p2x: 0.2, p2y: 1.0 },\n \n /**\n * Controlled deceleration\n * Ideal for: Defensive withdrawals, cautious movements, guard stance\n * **Korean**: 제어된 감속\n */\n controlledSlow: { p1x: 0.6, p1y: 0.0, p2x: 0.9, p2y: 0.4 },\n} as const;\n\n/**\n * Linear easing (no easing)\n * \n * @param t - Input time (0-1)\n * @returns Same as input\n * \n * @korean 선형이징\n */\nexport const easeLinear: EasingFunction = (t: number): number => t;\n\n/**\n * Ease-in (slow start, fast end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인\n */\nexport const easeIn: EasingFunction = (t: number): number => t * t;\n\n/**\n * Ease-out (fast start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈아웃\n */\nexport const easeOut: EasingFunction = (t: number): number => t * (2 - t);\n\n/**\n * Ease-in-out (slow start, slow end) - Simple quadratic\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 이즈인아웃\n */\nexport const easeInOut: EasingFunction = (t: number): number => {\n if (t < 0.5) {\n return 2 * t * t;\n }\n return -1 + (4 - 2 * t) * t;\n};\n\n/**\n * Natural motion bezier easing (preset)\n * \n * **Korean**: 자연스러운 동작 이징\n * \n * Physics-based movement ideal for Korean martial arts.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 자연동작이징\n */\nexport const easeNaturalMotion: EasingFunction = createBezierEasing(BEZIER_PRESETS.naturalMotion);\n\n/**\n * Smooth transition bezier easing (preset)\n * \n * **Korean**: 부드러운 전환 이징\n * \n * S-curve for fluid stance transitions.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 부드러운전환이징\n */\nexport const easeSmoothTransition: EasingFunction = createBezierEasing(BEZIER_PRESETS.smoothTransition);\n\n/**\n * Explosive power bezier easing (preset)\n * \n * **Korean**: 폭발적 힘 이징\n * \n * Explosive acceleration for power strikes.\n * \n * @param t - Input time (0-1)\n * @returns Eased value\n * \n * @korean 폭발적힘이징\n */\nexport const easeExplosivePower: EasingFunction = createBezierEasing(BEZIER_PRESETS.explosivePower);\n\n/**\n * Extended easing function names including bezier presets\n * \n * **Korean**: 확장된 이징 함수 이름\n * \n * @public\n * @category Animation\n * @korean 확장이징함수이름\n */\nexport type EasingName = \n | \"linear\"\n | \"ease-in\" \n | \"ease-out\" \n | \"ease-in-out\"\n | \"natural-motion\"\n | \"smooth-transition\"\n | \"quick-start\"\n | \"explosive-power\"\n | \"controlled-slow\";\n\n/**\n * Get easing function by name\n * \n * **Korean**: 이름으로 이징 함수 구하기\n * \n * @param name - Easing function name (supports bezier presets)\n * @returns Easing function\n * \n * @example\n * ```typescript\n * // Get natural motion easing for Korean martial arts\n * const easing = getEasingFunction(\"natural-motion\");\n * const easedValue = easing(0.5); // Smooth physics-based interpolation\n * \n * // Get explosive power for strike animations\n * const powerEasing = getEasingFunction(\"explosive-power\");\n * ```\n * \n * @korean 이징함수구하기\n */\nexport const getEasingFunction = (\n name: EasingName = \"linear\"\n): EasingFunction => {\n switch (name) {\n case \"ease-in\":\n return easeIn;\n case \"ease-out\":\n return easeOut;\n case \"ease-in-out\":\n return easeInOut;\n case \"natural-motion\":\n return easeNaturalMotion;\n case \"smooth-transition\":\n return easeSmoothTransition;\n case \"quick-start\":\n return createBezierEasing(BEZIER_PRESETS.quickStart);\n case \"explosive-power\":\n return easeExplosivePower;\n case \"controlled-slow\":\n return createBezierEasing(BEZIER_PRESETS.controlledSlow);\n default:\n return easeLinear;\n }\n};\n\n/**\n * Find keyframes surrounding current time\n * \n * Returns the two keyframes to interpolate between for current animation time.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Tuple of [previousKeyframe, nextKeyframe, interpolationFactor]\n * \n * @korean 주변키프레임찾기\n */\nexport const findSurroundingKeyframes = (\n animation: SkeletalAnimation,\n currentTime: number\n): [AnimationKeyframe, AnimationKeyframe, number] => {\n const { keyframes } = animation;\n\n // Clamp time to animation duration\n const clampedTime = Math.max(\n 0,\n Math.min(currentTime, animation.duration)\n );\n\n // Find keyframes\n let prevKeyframe = keyframes[0];\n let nextKeyframe = keyframes[keyframes.length - 1];\n let interpolationFactor = 0;\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n const current = keyframes[i];\n const next = keyframes[i + 1];\n\n if (clampedTime >= current.time && clampedTime <= next.time) {\n prevKeyframe = current;\n nextKeyframe = next;\n\n // Calculate interpolation factor (0 to 1)\n const timeDelta = next.time - current.time;\n if (timeDelta > 0) {\n interpolationFactor = (clampedTime - current.time) / timeDelta;\n }\n break;\n }\n }\n\n return [prevKeyframe, nextKeyframe, interpolationFactor];\n};\n\n/**\n * Interpolate between two Euler rotations\n * \n * Performs spherical linear interpolation (slerp) for smooth rotation.\n * \n * @param from - Start rotation\n * @param to - End rotation\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated rotation\n * \n * @korean 회전보간\n */\nexport const interpolateRotation = (\n from: THREE.Euler,\n to: THREE.Euler,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Euler => {\n const easedT = easingFn(t);\n\n // Convert Euler to Quaternion for proper slerp\n const fromQuat = new THREE.Quaternion().setFromEuler(from);\n const toQuat = new THREE.Quaternion().setFromEuler(to);\n\n // Slerp between quaternions\n const result = new THREE.Quaternion().slerpQuaternions(\n fromQuat,\n toQuat,\n easedT\n );\n\n // Convert back to Euler\n const resultEuler = new THREE.Euler().setFromQuaternion(result);\n return resultEuler;\n};\n\n/**\n * Interpolate between two Vector3 positions\n * \n * Performs linear interpolation for smooth position changes.\n * \n * @param from - Start position\n * @param to - End position\n * @param t - Interpolation factor (0-1)\n * @param easingFn - Easing function to apply\n * @returns Interpolated position\n * \n * @korean 위치보간\n */\nexport const interpolatePosition = (\n from: THREE.Vector3,\n to: THREE.Vector3,\n t: number,\n easingFn: EasingFunction = easeLinear\n): THREE.Vector3 => {\n const easedT = easingFn(t);\n return new THREE.Vector3().lerpVectors(from, to, easedT);\n};\n\n/**\n * Get interpolated keyframe at current time\n * \n * Calculates bone transformations by interpolating between keyframes.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation (seconds)\n * @returns Interpolated keyframe\n * \n * @korean 보간된키프레임구하기\n */\nexport const getInterpolatedKeyframe = (\n animation: SkeletalAnimation,\n currentTime: number\n): AnimationKeyframe => {\n const [prevKeyframe, nextKeyframe, t] =\n findSurroundingKeyframes(animation, currentTime);\n\n // Get easing function from next keyframe\n const easingFn = getEasingFunction(nextKeyframe.easing);\n\n // Interpolate bone rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBoneNames = new Set([\n ...prevKeyframe.boneRotations.keys(),\n ...nextKeyframe.boneRotations.keys(),\n ]);\n\n for (const boneName of allBoneNames) {\n const prevRotation =\n prevKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n const nextRotation =\n nextKeyframe.boneRotations.get(boneName) ?? new THREE.Euler();\n\n const interpolated = interpolateRotation(\n prevRotation,\n nextRotation,\n t,\n easingFn\n );\n boneRotations.set(boneName, interpolated);\n }\n\n // Interpolate bone positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...prevKeyframe.bonePositions.keys(),\n ...nextKeyframe.bonePositions.keys(),\n ]);\n\n for (const boneName of allPositionBones) {\n const prevPosition =\n prevKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n const nextPosition =\n nextKeyframe.bonePositions.get(boneName) ?? new THREE.Vector3();\n\n const interpolated = interpolatePosition(\n prevPosition,\n nextPosition,\n t,\n easingFn\n );\n bonePositions.set(boneName, interpolated);\n }\n\n return {\n time: currentTime,\n boneRotations,\n bonePositions,\n easing: nextKeyframe.easing,\n };\n};\n\n/**\n * Apply keyframe to skeletal rig\n * \n * Updates all bone transformations based on keyframe data.\n * \n * @param rig - Skeletal rig to update\n * @param keyframe - Keyframe to apply\n * \n * @korean 키프레임적용\n */\nexport const applyKeyframeToRig = (\n rig: SkeletalRig,\n keyframe: AnimationKeyframe\n): void => {\n // Apply bone rotations\n keyframe.boneRotations.forEach((rotation, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n bone.rotation.copy(rotation);\n }\n });\n\n // Apply bone positions (offset from rest pose)\n keyframe.bonePositions.forEach((position, boneName) => {\n const bone = rig.bones.get(boneName);\n if (bone) {\n // Add position offset to rest position\n bone.position.copy(bone.restPosition).add(position);\n }\n });\n};\n\n/**\n * Blend between two keyframes\n * \n * Creates smooth transition between two animations for animation blending.\n * Useful for transitioning between stance change and attack, etc.\n * \n * @param keyframe1 - First keyframe\n * @param keyframe2 - Second keyframe\n * @param blendFactor - Blend amount (0 = keyframe1, 1 = keyframe2)\n * @returns Blended keyframe\n * \n * @korean 키프레임블렌드\n */\nexport const blendKeyframes = (\n keyframe1: AnimationKeyframe,\n keyframe2: AnimationKeyframe,\n blendFactor: number\n): AnimationKeyframe => {\n const clampedBlend = Math.max(0, Math.min(1, blendFactor));\n\n // Blend rotations\n const boneRotations = new Map<string, THREE.Euler>();\n const allBones = new Set([\n ...keyframe1.boneRotations.keys(),\n ...keyframe2.boneRotations.keys(),\n ]);\n\n allBones.forEach((boneName) => {\n const rot1 = keyframe1.boneRotations.get(boneName) ?? new THREE.Euler();\n const rot2 = keyframe2.boneRotations.get(boneName) ?? new THREE.Euler();\n const blended = interpolateRotation(rot1, rot2, clampedBlend);\n boneRotations.set(boneName, blended);\n });\n\n // Blend positions\n const bonePositions = new Map<string, THREE.Vector3>();\n const allPositionBones = new Set([\n ...keyframe1.bonePositions.keys(),\n ...keyframe2.bonePositions.keys(),\n ]);\n\n allPositionBones.forEach((boneName) => {\n const pos1 = keyframe1.bonePositions.get(boneName) ?? new THREE.Vector3();\n const pos2 = keyframe2.bonePositions.get(boneName) ?? new THREE.Vector3();\n const blended = interpolatePosition(pos1, pos2, clampedBlend);\n bonePositions.set(boneName, blended);\n });\n\n return {\n time: 0,\n boneRotations,\n bonePositions,\n easing: \"linear\",\n };\n};\n\n/**\n * Update animation state\n * \n * Advances animation time and returns current interpolated keyframe.\n * Handles looping animations automatically.\n * \n * @param animation - Skeletal animation\n * @param currentTime - Current time in animation\n * @param deltaTime - Time since last update (seconds)\n * @param playbackSpeed - Speed multiplier (1.0 = normal)\n * @returns Updated time and current keyframe\n * \n * @korean 애니메이션상태업데이트\n */\nexport const updateAnimation = (\n animation: SkeletalAnimation,\n currentTime: number,\n deltaTime: number,\n playbackSpeed = 1.0\n): { time: number; keyframe: AnimationKeyframe; completed: boolean } => {\n // Advance time\n let newTime = currentTime + deltaTime * playbackSpeed;\n let completed = false;\n\n // Handle looping or completion\n if (newTime >= animation.duration) {\n if (animation.loop) {\n newTime = newTime % animation.duration;\n } else {\n newTime = animation.duration;\n completed = true;\n }\n }\n\n // Get interpolated keyframe\n const keyframe = getInterpolatedKeyframe(animation, newTime);\n\n return {\n time: newTime,\n keyframe,\n completed,\n };\n};\n\n/**\n * Cross-fade blend between two animations\n * \n * **Korean**: 크로스페이드 블렌드\n * \n * Smoothly blends between two overlapping animations to prevent popping.\n * Uses cubic bezier easing for natural transitions.\n * \n * @param animation1 - First animation\n * @param time1 - Current time in first animation\n * @param animation2 - Second animation\n * @param time2 - Current time in second animation\n * @param blendFactor - Blend weight (0 = animation1, 1 = animation2)\n * @param easingName - Easing curve for blend transition\n * @returns Blended keyframe\n * \n * @example\n * ```typescript\n * // Cross-fade from idle to attack over 100ms\n * const blended = crossFadeAnimations(\n * idleAnim, idleTime,\n * attackAnim, attackTime,\n * 0.5, // 50% blend\n * \"smooth-transition\"\n * );\n * applyKeyframeToRig(rig, blended);\n * ```\n * \n * @korean 크로스페이드블렌드\n */\nexport const crossFadeAnimations = (\n animation1: SkeletalAnimation,\n time1: number,\n animation2: SkeletalAnimation,\n time2: number,\n blendFactor: number,\n easingName: EasingName = \"smooth-transition\"\n): AnimationKeyframe => {\n const keyframe1 = getInterpolatedKeyframe(animation1, time1);\n const keyframe2 = getInterpolatedKeyframe(animation2, time2);\n \n // Apply easing to blend factor\n const easingFn = getEasingFunction(easingName);\n const easedBlend = easingFn(Math.max(0, Math.min(1, blendFactor)));\n \n return blendKeyframes(keyframe1, keyframe2, easedBlend);\n};\n\n/**\n * Motion prediction state for latency reduction\n * \n * **Korean**: 동작 예측 상태\n * \n * Stores recent animation velocities for motion prediction.\n * \n * @public\n * @category Animation\n * @korean 동작예측상태\n */\nexport interface MotionPredictionState {\n /** Recent position velocities per bone */\n readonly velocities: Map<string, THREE.Vector3>;\n /** Recent rotation velocities per bone */\n readonly angularVelocities: Map<string, THREE.Euler>;\n /** Last update timestamp */\n readonly lastUpdateTime: number;\n}\n\n/**\n * Create motion prediction state\n * \n * **Korean**: 동작 예측 상태 생성\n * \n * @returns Initial motion prediction state\n * @korean 동작예측상태생성\n */\nexport const createMotionPredictionState = (): MotionPredictionState => ({\n velocities: new Map(),\n angularVelocities: new Map(),\n lastUpdateTime: 0,\n});\n\n/**\n * Update motion prediction state with new keyframe\n * \n * **Korean**: 동작 예측 상태 업데이트\n * \n * Calculates velocities from keyframe differences for motion prediction.\n * \n * @param state - Current prediction state\n * @param previousKeyframe - Previous animation keyframe\n * @param currentKeyframe - Current animation keyframe\n * @param deltaTime - Time elapsed between keyframes\n * @returns Updated prediction state\n * \n * @korean 동작예측상태업데이트\n */\nexport const updateMotionPrediction = (\n state: MotionPredictionState,\n previousKeyframe: AnimationKeyframe,\n currentKeyframe: AnimationKeyframe,\n deltaTime: number\n): MotionPredictionState => {\n if (deltaTime <= 0) return state;\n \n const newVelocities = new Map<string, THREE.Vector3>();\n const newAngularVelocities = new Map<string, THREE.Euler>();\n \n // Calculate position velocities\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const prevPos = previousKeyframe.bonePositions.get(boneName);\n if (prevPos) {\n const velocity = new THREE.Vector3()\n .subVectors(currentPos, prevPos)\n .divideScalar(deltaTime);\n newVelocities.set(boneName, velocity);\n }\n });\n \n // Calculate angular velocities using quaternion-based rotation differences\n // This avoids gimbal lock and angle wrapping issues with Euler angle differences\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const prevRot = previousKeyframe.boneRotations.get(boneName);\n if (prevRot) {\n // Convert Euler rotations to quaternions\n const qCurrent = new THREE.Quaternion().setFromEuler(currentRot);\n const qPrev = new THREE.Quaternion().setFromEuler(prevRot);\n \n // Calculate relative rotation: qDiff = qCurrent * qPrev^(-1)\n const qDiff = qCurrent.clone().multiply(qPrev.clone().invert());\n \n // Extract axis-angle representation for angular velocity\n const axis = new THREE.Vector3();\n const wClamped = THREE.MathUtils.clamp(qDiff.w, -1, 1);\n let angle = 2 * Math.acos(wClamped);\n const sinHalfAngle = Math.sqrt(1 - wClamped * wClamped);\n \n if (sinHalfAngle < 0.0001) {\n // If sinHalfAngle is too small, rotation is negligible - use zero velocity\n axis.set(0, 0, 0);\n angle = 0;\n } else {\n // Extract normalized axis from quaternion\n axis.set(\n qDiff.x / sinHalfAngle,\n qDiff.y / sinHalfAngle,\n qDiff.z / sinHalfAngle\n );\n }\n \n // Use shortest rotation path\n if (angle > Math.PI) {\n angle -= 2 * Math.PI;\n }\n \n // Angular velocity vector = axis * (angle / deltaTime)\n const angularVelocityVec = axis.multiplyScalar(angle / deltaTime);\n \n // Store as Euler for consistency with existing API\n const angularVel = new THREE.Euler(\n angularVelocityVec.x,\n angularVelocityVec.y,\n angularVelocityVec.z,\n currentRot.order\n );\n newAngularVelocities.set(boneName, angularVel);\n }\n });\n \n return {\n velocities: newVelocities,\n angularVelocities: newAngularVelocities,\n lastUpdateTime: performance.now(),\n };\n};\n\n/**\n * Predict future keyframe using motion prediction\n * \n * **Korean**: 동작 예측으로 미래 키프레임 예측\n * \n * Reduces perceived latency by predicting future bone positions/rotations\n * based on current velocities. Typical prediction: 16-33ms (1-2 frames at 60fps).\n * \n * @param currentKeyframe - Current animation keyframe\n * @param predictionState - Motion prediction state\n * @param predictionTime - Time ahead to predict (seconds, typically 0.016-0.033)\n * @returns Predicted keyframe\n * \n * @example\n * ```typescript\n * // Predict 1 frame ahead (16.67ms at 60fps) for <50ms total latency\n * const predicted = predictFutureKeyframe(\n * currentKeyframe,\n * motionState,\n * 0.01667\n * );\n * applyKeyframeToRig(rig, predicted);\n * ```\n * \n * @korean 미래키프레임예측\n */\nexport const predictFutureKeyframe = (\n currentKeyframe: AnimationKeyframe,\n predictionState: MotionPredictionState,\n predictionTime: number\n): AnimationKeyframe => {\n // Clamp prediction time to reasonable bounds (max 50ms)\n const clampedPrediction = Math.min(predictionTime, 0.05);\n \n // Predict bone positions\n const predictedPositions = new Map<string, THREE.Vector3>();\n currentKeyframe.bonePositions.forEach((currentPos, boneName) => {\n const velocity = predictionState.velocities.get(boneName);\n if (velocity) {\n // Apply damping to prevent overshoot (0.8 factor for natural motion)\n const predicted = currentPos.clone().add(\n velocity.clone().multiplyScalar(clampedPrediction * 0.8)\n );\n predictedPositions.set(boneName, predicted);\n } else {\n predictedPositions.set(boneName, currentPos.clone());\n }\n });\n \n // Predict bone rotations\n const predictedRotations = new Map<string, THREE.Euler>();\n currentKeyframe.boneRotations.forEach((currentRot, boneName) => {\n const angularVel = predictionState.angularVelocities.get(boneName);\n if (angularVel) {\n // Apply damping to prevent overshoot\n const predicted = new THREE.Euler(\n currentRot.x + angularVel.x * clampedPrediction * 0.8,\n currentRot.y + angularVel.y * clampedPrediction * 0.8,\n currentRot.z + angularVel.z * clampedPrediction * 0.8,\n currentRot.order\n );\n predictedRotations.set(boneName, predicted);\n } else {\n predictedRotations.set(boneName, currentRot.clone());\n }\n });\n \n return {\n time: currentKeyframe.time + clampedPrediction,\n boneRotations: predictedRotations,\n bonePositions: predictedPositions,\n easing: currentKeyframe.easing,\n };\n};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"KickPhaseApplicator.js","names":[],"sources":["../../../../src/systems/animation/builders/KickPhaseApplicator.ts"],"sourcesContent":["/**\n * Kick Phase Application Utilities\n *\n * Utilities for applying kick phase poses to keyframes with integrated\n * anatomy awareness (foot highlighting for kicks).\n * 발차기 단계 적용 유틸리티 (해부학 통합)\n *\n * @module systems/animation/KickPhaseApplicator\n * @korean 발차기단계적용기\n */\n\nimport { BoneName } from \"@/types/skeletal\";\nimport type { KeyframeConfig } from \"./KeyframeConfig\";\nimport { KICK_PHASES } from \"./MartialArtsConstants\";\n\n/**\n * Interface for basic kick phases (CHAMBER, EXTENSION, HIGH_PEAK)\n * These phases have pelvis as a tuple [x, y, z]\n */\ninterface BasicKickPhase {\n readonly hip: readonly [number, number, number];\n readonly knee: readonly [number, number, number];\n readonly ankle?: readonly [number, number, number];\n readonly supportKnee?: readonly [number, number, number];\n readonly pelvis?: readonly [number, number, number];\n}\n\n/**\n * Interface for rotational kick phases (ROUNDHOUSE_CHAMBER, SIDE_CHAMBER)\n * These phases have pelvisY as a single Y-axis value\n */\ninterface RotationalKickPhase {\n readonly hip: readonly [number, number, number];\n readonly knee: readonly [number, number, number];\n readonly pelvisY?: number;\n readonly spineY?: number;\n readonly spineLean?: number;\n}\n\n/** Phase name keys */\nexport type KickPhaseName = keyof typeof KICK_PHASES;\n\n/** Kick side for left/right leg distinction */\nexport type KickSide = \"left\" | \"right\";\n\n/**\n * Apply basic kick phase to a KeyframeConfig with anatomy integration\n * Handles common kick phase bones: hip, knee, supportKnee, pelvis, ankle\n * Now includes automatic foot highlighting for kick visualization\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Basic kick phase data (CHAMBER, EXTENSION, HIGH_PEAK)\n * @param options - Configuration including anatomy options\n *\n * @example\n * ```typescript\n * // Apply kick with automatic foot highlight\n * applyKickPhaseToConfig(kf, KICK_PHASES.EXTENSION, {\n * highlightKickingFoot: true\n * });\n * ```\n *\n * @korean KeyframeConfig에발차기단계적용\n */\nexport function applyKickPhaseToConfig(\n kf: KeyframeConfig,\n phase: BasicKickPhase,\n options: {\n readonly includeAnkle?: boolean;\n readonly includePelvis?: boolean;\n readonly resetFoot?: boolean;\n // Anatomy integration\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const {\n includeAnkle = false,\n includePelvis = true,\n resetFoot = false,\n side = \"right\",\n highlightKickingFoot = false,\n } = options;\n\n // Select bones based on kicking leg\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n const footBone = side === \"right\" ? BoneName.FOOT_R : BoneName.FOOT_L;\n const supportKneeBone = side === \"right\" ? BoneName.KNEE_L : BoneName.KNEE_R;\n\n // Required bones for all kick phases\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n if (phase.supportKnee) {\n kf.rotate(\n supportKneeBone,\n phase.supportKnee[0],\n phase.supportKnee[1],\n phase.supportKnee[2],\n );\n }\n\n // Optional pelvis - includes both tilt (X) and rotation (Y)\n if (includePelvis && phase.pelvis) {\n // Use pelvisY if defined (for hip rotation power), otherwise pelvis[1]\n const pelvisYRotation =\n \"pelvisY\" in phase && typeof phase.pelvisY === \"number\"\n ? phase.pelvisY\n : phase.pelvis[1];\n kf.rotate(\n BoneName.PELVIS,\n phase.pelvis[0],\n pelvisYRotation,\n phase.pelvis[2],\n );\n }\n\n // Optional ankle\n if (includeAnkle && phase.ankle) {\n kf.rotate(footBone, phase.ankle[0], phase.ankle[1], phase.ankle[2]);\n }\n\n // Reset foot position\n if (resetFoot) {\n kf.rotate(footBone, 0, 0, 0);\n }\n\n // Anatomy integration: Highlight kicking foot\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/**\n * Apply roundhouse-specific kick phase with anatomy integration\n * Includes pelvisY and spineY single-axis rotations\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Rotational kick phase data (ROUNDHOUSE_CHAMBER)\n * @param options - Configuration including anatomy options\n *\n * @korean 돌려차기단계적용\n */\nexport function applyRoundhousePhaseToConfig(\n kf: KeyframeConfig,\n phase: RotationalKickPhase,\n options: {\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const { side = \"right\", highlightKickingFoot = false } = options;\n\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n // Y-axis only rotations for roundhouse\n if (phase.pelvisY !== undefined) {\n kf.rotate(BoneName.PELVIS, 0, phase.pelvisY, 0);\n }\n if (phase.spineY !== undefined) {\n kf.rotate(BoneName.SPINE_UPPER, 0, phase.spineY, 0);\n }\n\n // Anatomy integration\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/**\n * Apply side kick phase with anatomy integration\n * Includes pelvisY, spineY, and spineLean\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Rotational kick phase data (SIDE_CHAMBER)\n * @param options - Configuration including anatomy options\n *\n * @korean 옆차기단계적용\n */\nexport function applySideKickPhaseToConfig(\n kf: KeyframeConfig,\n phase: RotationalKickPhase,\n options: {\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const { side = \"right\", highlightKickingFoot = false } = options;\n\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n // Side kick specific rotations\n if (phase.pelvisY !== undefined) {\n kf.rotate(BoneName.PELVIS, 0, phase.pelvisY, 0);\n }\n if (phase.spineY !== undefined) {\n const lean = phase.spineLean ?? 0;\n kf.rotate(BoneName.SPINE_LOWER, 0, phase.spineY, 0);\n kf.rotate(BoneName.SPINE_UPPER, 0, phase.spineY, lean);\n }\n\n // Anatomy integration\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/**\n * Apply high peak phase (axe kick rise) with anatomy integration\n * Includes full pelvis tuple and support knee\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Basic kick phase data (HIGH_PEAK)\n * @param options - Configuration including anatomy options\n *\n * @korean 높이올리기단계적용\n */\nexport function applyHighPeakPhaseToConfig(\n kf: KeyframeConfig,\n phase: BasicKickPhase,\n options: {\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const { side = \"right\", highlightKickingFoot = false } = options;\n\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n const footBone = side === \"right\" ? BoneName.FOOT_R : BoneName.FOOT_L;\n const supportKneeBone = side === \"right\" ? BoneName.KNEE_L : BoneName.KNEE_R;\n\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n if (phase.ankle) {\n kf.rotate(footBone, phase.ankle[0], phase.ankle[1], phase.ankle[2]);\n }\n if (phase.supportKnee) {\n kf.rotate(\n supportKneeBone,\n phase.supportKnee[0],\n phase.supportKnee[1],\n phase.supportKnee[2],\n );\n }\n if (phase.pelvis) {\n kf.rotate(\n BoneName.PELVIS,\n phase.pelvis[0],\n phase.pelvis[1],\n phase.pelvis[2],\n );\n }\n\n // Anatomy integration\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/** Union type for any kick phase from KICK_PHASES */\nexport type KickPhase = (typeof KICK_PHASES)[keyof typeof KICK_PHASES];\n\n/**\n * Get a kick phase by name\n *\n * @param phaseName - Name of the phase from KICK_PHASES\n * @returns The kick phase data\n *\n * @korean 발차기단계가져오기\n */\nexport function getKickPhase(phaseName: KickPhaseName): KickPhase {\n return KICK_PHASES[phaseName];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"KickPhaseApplicator.js","names":[],"sources":["../../../../src/systems/animation/builders/KickPhaseApplicator.ts"],"sourcesContent":["/**\n * Kick Phase Application Utilities\n *\n * Utilities for applying kick phase poses to keyframes with integrated\n * anatomy awareness (foot highlighting for kicks).\n * 발차기 단계 적용 유틸리티 (해부학 통합)\n *\n * @module systems/animation/KickPhaseApplicator\n * @korean 발차기단계적용기\n */\n\nimport { BoneName } from \"@/types/skeletal\";\nimport type { KeyframeConfig } from \"./KeyframeConfig\";\nimport { KICK_PHASES } from \"./MartialArtsConstants\";\n\n/**\n * Interface for basic kick phases (CHAMBER, EXTENSION, HIGH_PEAK)\n * These phases have pelvis as a tuple [x, y, z]\n */\ninterface BasicKickPhase {\n readonly hip: readonly [number, number, number];\n readonly knee: readonly [number, number, number];\n readonly ankle?: readonly [number, number, number];\n readonly supportKnee?: readonly [number, number, number];\n readonly pelvis?: readonly [number, number, number];\n}\n\n/**\n * Interface for rotational kick phases (ROUNDHOUSE_CHAMBER, SIDE_CHAMBER)\n * These phases have pelvisY as a single Y-axis value\n */\ninterface RotationalKickPhase {\n readonly hip: readonly [number, number, number];\n readonly knee: readonly [number, number, number];\n readonly pelvisY?: number;\n readonly spineY?: number;\n readonly spineLean?: number;\n}\n\n/** Phase name keys */\nexport type KickPhaseName = keyof typeof KICK_PHASES;\n\n/** Kick side for left/right leg distinction */\nexport type KickSide = \"left\" | \"right\";\n\n/**\n * Apply basic kick phase to a KeyframeConfig with anatomy integration\n * Handles common kick phase bones: hip, knee, supportKnee, pelvis, ankle\n * Now includes automatic foot highlighting for kick visualization\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Basic kick phase data (CHAMBER, EXTENSION, HIGH_PEAK)\n * @param options - Configuration including anatomy options\n *\n * @example\n * ```typescript\n * // Apply kick with automatic foot highlight\n * applyKickPhaseToConfig(kf, KICK_PHASES.EXTENSION, {\n * highlightKickingFoot: true\n * });\n * ```\n *\n * @korean KeyframeConfig에발차기단계적용\n */\nexport function applyKickPhaseToConfig(\n kf: KeyframeConfig,\n phase: BasicKickPhase,\n options: {\n readonly includeAnkle?: boolean;\n readonly includePelvis?: boolean;\n readonly resetFoot?: boolean;\n // Anatomy integration\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const {\n includeAnkle = false,\n includePelvis = true,\n resetFoot = false,\n side = \"right\",\n highlightKickingFoot = false,\n } = options;\n\n // Select bones based on kicking leg\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n const footBone = side === \"right\" ? BoneName.FOOT_R : BoneName.FOOT_L;\n const supportKneeBone = side === \"right\" ? BoneName.KNEE_L : BoneName.KNEE_R;\n\n // Required bones for all kick phases\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n if (phase.supportKnee) {\n kf.rotate(\n supportKneeBone,\n phase.supportKnee[0],\n phase.supportKnee[1],\n phase.supportKnee[2],\n );\n }\n\n // Optional pelvis - includes both tilt (X) and rotation (Y)\n if (includePelvis && phase.pelvis) {\n // Use pelvisY if defined (for hip rotation power), otherwise pelvis[1]\n const pelvisYRotation =\n \"pelvisY\" in phase && typeof phase.pelvisY === \"number\"\n ? phase.pelvisY\n : phase.pelvis[1];\n kf.rotate(\n BoneName.PELVIS,\n phase.pelvis[0],\n pelvisYRotation,\n phase.pelvis[2],\n );\n }\n\n // Optional ankle\n if (includeAnkle && phase.ankle) {\n kf.rotate(footBone, phase.ankle[0], phase.ankle[1], phase.ankle[2]);\n }\n\n // Reset foot position\n if (resetFoot) {\n kf.rotate(footBone, 0, 0, 0);\n }\n\n // Anatomy integration: Highlight kicking foot\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/**\n * Apply roundhouse-specific kick phase with anatomy integration\n * Includes pelvisY and spineY single-axis rotations\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Rotational kick phase data (ROUNDHOUSE_CHAMBER)\n * @param options - Configuration including anatomy options\n *\n * @korean 돌려차기단계적용\n */\nexport function applyRoundhousePhaseToConfig(\n kf: KeyframeConfig,\n phase: RotationalKickPhase,\n options: {\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const { side = \"right\", highlightKickingFoot = false } = options;\n\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n // Y-axis only rotations for roundhouse\n if (phase.pelvisY !== undefined) {\n kf.rotate(BoneName.PELVIS, 0, phase.pelvisY, 0);\n }\n if (phase.spineY !== undefined) {\n kf.rotate(BoneName.SPINE_UPPER, 0, phase.spineY, 0);\n }\n\n // Anatomy integration\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/**\n * Apply side kick phase with anatomy integration\n * Includes pelvisY, spineY, and spineLean\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Rotational kick phase data (SIDE_CHAMBER)\n * @param options - Configuration including anatomy options\n *\n * @korean 옆차기단계적용\n */\nexport function applySideKickPhaseToConfig(\n kf: KeyframeConfig,\n phase: RotationalKickPhase,\n options: {\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const { side = \"right\", highlightKickingFoot = false } = options;\n\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n // Side kick specific rotations\n if (phase.pelvisY !== undefined) {\n kf.rotate(BoneName.PELVIS, 0, phase.pelvisY, 0);\n }\n if (phase.spineY !== undefined) {\n const lean = phase.spineLean ?? 0;\n kf.rotate(BoneName.SPINE_LOWER, 0, phase.spineY, 0);\n kf.rotate(BoneName.SPINE_UPPER, 0, phase.spineY, lean);\n }\n\n // Anatomy integration\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/**\n * Apply high peak phase (axe kick rise) with anatomy integration\n * Includes full pelvis tuple and support knee\n *\n * @param kf - KeyframeConfig to apply phase to\n * @param phase - Basic kick phase data (HIGH_PEAK)\n * @param options - Configuration including anatomy options\n *\n * @korean 높이올리기단계적용\n */\nexport function applyHighPeakPhaseToConfig(\n kf: KeyframeConfig,\n phase: BasicKickPhase,\n options: {\n readonly side?: KickSide;\n readonly highlightKickingFoot?: boolean;\n } = {},\n): void {\n const { side = \"right\", highlightKickingFoot = false } = options;\n\n const hipBone = side === \"right\" ? BoneName.HIP_R : BoneName.HIP_L;\n const kneeBone = side === \"right\" ? BoneName.KNEE_R : BoneName.KNEE_L;\n const footBone = side === \"right\" ? BoneName.FOOT_R : BoneName.FOOT_L;\n const supportKneeBone = side === \"right\" ? BoneName.KNEE_L : BoneName.KNEE_R;\n\n kf.rotate(hipBone, phase.hip[0], phase.hip[1], phase.hip[2]);\n kf.rotate(kneeBone, phase.knee[0], phase.knee[1], phase.knee[2]);\n\n if (phase.ankle) {\n kf.rotate(footBone, phase.ankle[0], phase.ankle[1], phase.ankle[2]);\n }\n if (phase.supportKnee) {\n kf.rotate(\n supportKneeBone,\n phase.supportKnee[0],\n phase.supportKnee[1],\n phase.supportKnee[2],\n );\n }\n if (phase.pelvis) {\n kf.rotate(\n BoneName.PELVIS,\n phase.pelvis[0],\n phase.pelvis[1],\n phase.pelvis[2],\n );\n }\n\n // Anatomy integration\n if (highlightKickingFoot) {\n kf.setFootHighlight(side, true);\n }\n}\n\n/** Union type for any kick phase from KICK_PHASES */\nexport type KickPhase = (typeof KICK_PHASES)[keyof typeof KICK_PHASES];\n\n/**\n * Get a kick phase by name\n *\n * @param phaseName - Name of the phase from KICK_PHASES\n * @returns The kick phase data\n *\n * @korean 발차기단계가져오기\n */\nexport function getKickPhase(phaseName: KickPhaseName): KickPhase {\n return KICK_PHASES[phaseName];\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"KoreanGuardPositions.js","names":[],"sources":["../../../../src/systems/animation/builders/KoreanGuardPositions.ts"],"sourcesContent":["import { BoneName } from \"@/types/skeletal\";\n\n// Minimal contract to apply guard rotations without depending on KeyframeConfig\ninterface GuardRotatable {\n rotate: (bone: BoneName, x: number, y: number, z: number) => unknown;\n}\n\n/**\n * Korean Guard Positions (막기자세)\n *\n * Defines authentic Korean martial arts guard positions for all animations.\n * Guards protect vital areas and provide optimal positioning for techniques.\n *\n * Korean martial arts emphasize three primary guard levels:\n * - 상단막기 (Sangdan Makgi) - High guard protecting head\n * - 중단막기 (Jungdan Makgi) - Middle guard protecting torso\n * - 하단막기 (Hadan Makgi) - Low guard protecting lower body\n *\n * Each guard position includes:\n * - Proper shoulder and elbow angles\n * - Hand pose (주먹쥐기 - fist formation)\n * - Guard height description\n * - Korean/English terminology\n *\n * @module systems/animation/KoreanGuardPositions\n * @category Animation System\n * @korean 막기자세시스템\n */\n\n/**\n * Guard position for a single arm\n * @korean 팔방어위치\n */\nexport interface GuardArmPosition {\n /** Shoulder rotation in radians (x, y, z) */\n readonly shoulder: readonly [number, number, number];\n /** Elbow rotation in radians (x, y, z) */\n readonly elbow: readonly [number, number, number];\n /** Wrist rotation in radians (x, y, z) */\n readonly wrist: readonly [number, number, number];\n}\n\n/**\n * Complete guard position configuration\n * @korean 방어자세설정\n */\nexport interface GuardPosition {\n /** Korean name */\n readonly korean: string;\n /** English name */\n readonly english: string;\n /** Romanization */\n readonly romanized: string;\n /** Description of guard purpose and application */\n readonly description: {\n readonly korean: string;\n readonly english: string;\n };\n /** Left arm guard position */\n readonly left: GuardArmPosition;\n /** Right arm guard position */\n readonly right: GuardArmPosition;\n /** Height level of guard */\n readonly height: \"temple_level\" | \"chest_level\" | \"abdomen_level\";\n /**\n * Default hand pose description for this guard.\n *\n * NOTE: This field is documentation/metadata only and is not wired into the\n * hand pose system or the HandPoseType enum. Actual hand poses are applied\n * directly in animation code (e.g., via HAND_POSES.FIST). Do not use these\n * string literal values for programmatic logic.\n *\n * @see HandPoseType for the actual hand pose enum values\n * @see HAND_POSES for applying hand poses in animations\n */\n readonly handPose: \"fist_vertical\" | \"fist_horizontal\" | \"open_hand\";\n /** Vital areas protected by this guard */\n readonly protects: readonly string[];\n}\n\n/**\n * Helper to convert degrees to radians\n * @param degrees - Angle in degrees\n * @returns Angle in radians\n * @korean 도를라디안으로\n */\nconst toRadians = (degrees: number): number => (degrees * Math.PI) / 180;\n\n/**\n * 상단막기 (Sangdan Makgi) - High Guard\n *\n * Traditional Taekwondo high block position protecting head and face.\n * Both hands at temple/forehead level with elbows bent tight.\n * Fists vertical (thumb-side up) for maximum protection.\n *\n * Protects against:\n * - High strikes to head (머리 공격)\n * - Overhead attacks (위쪽 공격)\n * - Face punches (얼굴 주먹)\n *\n * Application:\n * - Default guard for Geon (Heaven) stance\n * - Used in high kicking techniques\n * - Transitional guard for head-level attacks\n *\n * Biomechanics:\n * - Shoulders raised (~15° abduction)\n * - Elbows bent ~110° (tight guard)\n * - Fists at temple level\n * - Forearms vertical for deflection\n *\n * @korean 상단막기자세\n */\nexport const HIGH_GUARD: GuardPosition = {\n korean: \"상단막기\",\n english: \"High Guard\",\n romanized: \"Sangdan Makgi\",\n description: {\n korean:\n \"머리와 얼굴을 보호하는 높은 방어 자세. 주먹을 관자놀이 높이에 두고 팔꿈치를 단단히 구부림.\",\n english:\n \"High guard protecting head and face. Fists at temple level with elbows bent tight.\",\n },\n left: {\n shoulder: [toRadians(-30), toRadians(-25), toRadians(10)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(-120)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n right: {\n shoulder: [toRadians(-30), toRadians(25), toRadians(-10)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(120)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n height: \"temple_level\",\n handPose: \"fist_vertical\",\n protects: [\"head\", \"temple\", \"forehead\", \"eyes\", \"nose\", \"jaw\"] as const,\n};\n\n/**\n * 중단막기 (Jungdan Makgi) - Middle Guard\n *\n * Standard Korean martial arts guard at chest/solar plexus level.\n * Most versatile guard position, used in most fighting stances.\n * Elbows at 90° protecting ribs and torso.\n *\n * Protects against:\n * - Body punches (몸통 주먹)\n * - Solar plexus strikes (명치 공격)\n * - Rib attacks (갈비뼈 공격)\n * - Liver strikes (간 공격)\n *\n * Application:\n * - Default guard for most stances\n * - Starting position for most techniques\n * - Balanced offensive/defensive posture\n *\n * Biomechanics:\n * - Shoulders neutral (~10° forward)\n * - Elbows bent ~90° (classic guard)\n * - Fists at chest/chin level\n * - Ready to attack or defend\n *\n * @korean 중단막기자세\n */\nexport const MIDDLE_GUARD: GuardPosition = {\n korean: \"중단막기\",\n english: \"Middle Guard\",\n romanized: \"Jungdan Makgi\",\n description: {\n korean:\n \"가슴과 명치를 보호하는 중간 방어 자세. 팔꿈치를 90도 구부려 몸통을 보호함.\",\n english:\n \"Middle guard protecting chest and solar plexus. Elbows bent at 90° protecting torso.\",\n },\n left: {\n shoulder: [toRadians(-20), toRadians(-20), toRadians(8)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(-100)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n right: {\n shoulder: [toRadians(-20), toRadians(20), toRadians(-8)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(100)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n height: \"chest_level\",\n handPose: \"fist_vertical\",\n protects: [\n \"chest\",\n \"solar_plexus\",\n \"ribs\",\n \"liver\",\n \"spleen\",\n \"heart\",\n ] as const,\n};\n\n/**\n * 하단막기 (Hadan Makgi) - Low Guard\n *\n * Low guard position protecting lower body and groin.\n * Used in grappling and ground-fighting scenarios.\n * Hands at abdomen/hip level ready for low attacks.\n *\n * Protects against:\n * - Low kicks (낮은 발차기)\n * - Body kicks (몸통 발차기)\n * - Groin attacks (낭심 공격)\n * - Takedown attempts (넘어뜨리기)\n *\n * Application:\n * - Default for Gon (Earth) stance\n * - Grappling and clinch range\n * - Defense against low attacks\n *\n * Biomechanics:\n * - Shoulders forward (~20° flexion)\n * - Elbows bent ~70° (wider guard)\n * - Fists at abdomen/hip level\n * - Ready to sprawl or clinch\n *\n * @korean 하단막기자세\n */\nexport const LOW_GUARD: GuardPosition = {\n korean: \"하단막기\",\n english: \"Low Guard\",\n romanized: \"Hadan Makgi\",\n description: {\n korean:\n \"하복부와 낭심을 보호하는 낮은 방어 자세. 손을 배 높이에 두고 낮은 공격에 대비함.\",\n english:\n \"Low guard protecting lower body and groin. Hands at abdomen level ready for low attacks.\",\n },\n left: {\n shoulder: [toRadians(15), toRadians(-10), toRadians(12)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(-75)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n right: {\n shoulder: [toRadians(15), toRadians(10), toRadians(-12)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(75)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n height: \"abdomen_level\",\n handPose: \"fist_vertical\",\n protects: [\"abdomen\", \"groin\", \"hip\", \"thigh\", \"lower_ribs\"] as const,\n};\n\n/**\n * All Korean guard positions indexed by name\n * @korean 모든방어자세\n */\nexport const KOREAN_GUARD_POSITIONS = {\n HIGH_GUARD,\n MIDDLE_GUARD,\n LOW_GUARD,\n} as const;\n\n/**\n * Guard position type\n * @korean 방어자세타입\n */\nexport type GuardPositionType = keyof typeof KOREAN_GUARD_POSITIONS;\n\n/**\n * Get guard position by type\n *\n * @param type - Guard position type\n * @returns Guard position configuration\n * @korean 방어자세가져오기\n */\nexport const getGuardPosition = (type: GuardPositionType): GuardPosition => {\n return KOREAN_GUARD_POSITIONS[type];\n};\n\n/**\n * Get appropriate guard for stance height\n *\n * Determines which guard position is most appropriate based on\n * the stance configuration and fighting context.\n *\n * @param stanceType - Type of stance (\"high\" | \"middle\" | \"low\")\n * @returns Recommended guard position\n * @korean 자세높이에맞는방어자세\n */\nexport const getGuardForStanceHeight = (\n stanceType: \"high\" | \"middle\" | \"low\",\n): GuardPosition => {\n switch (stanceType) {\n case \"high\":\n return HIGH_GUARD;\n case \"low\":\n return LOW_GUARD;\n case \"middle\":\n default:\n return MIDDLE_GUARD;\n }\n};\n\n/**\n * Apply guard position to KeyframeConfig\n *\n * Applies a Korean martial arts guard position to a keyframe configuration.\n * Can apply to one hand (for techniques where one hand strikes) or both hands.\n *\n * Usage:\n * ```typescript\n * const kf = new KeyframeConfig(0.0);\n * applyGuardPositionToConfig(kf, MIDDLE_GUARD, \"both\"); // Both hands in guard\n * applyGuardPositionToConfig(kf, MIDDLE_GUARD, \"left\"); // Only left hand guards\n * ```\n *\n * @param config - KeyframeConfig to apply guard to\n * @param guardPosition - Guard position configuration\n * @param hand - Which hand(s) to apply (\"left\" | \"right\" | \"both\")\n * @korean KeyframeConfig에방어자세적용\n */\nexport const applyGuardPositionToConfig = (\n config: GuardRotatable,\n guardPosition: GuardPosition,\n hand: \"left\" | \"right\" | \"both\" = \"both\",\n): void => {\n // Apply left hand guard\n if (hand === \"left\" || hand === \"both\") {\n config.rotate(\n BoneName.SHOULDER_L,\n guardPosition.left.shoulder[0],\n guardPosition.left.shoulder[1],\n guardPosition.left.shoulder[2],\n );\n config.rotate(\n BoneName.ELBOW_L,\n guardPosition.left.elbow[0],\n guardPosition.left.elbow[1],\n guardPosition.left.elbow[2],\n );\n config.rotate(\n BoneName.WRIST_L,\n guardPosition.left.wrist[0],\n guardPosition.left.wrist[1],\n guardPosition.left.wrist[2],\n );\n }\n\n // Apply right hand guard\n if (hand === \"right\" || hand === \"both\") {\n config.rotate(\n BoneName.SHOULDER_R,\n guardPosition.right.shoulder[0],\n guardPosition.right.shoulder[1],\n guardPosition.right.shoulder[2],\n );\n config.rotate(\n BoneName.ELBOW_R,\n guardPosition.right.elbow[0],\n guardPosition.right.elbow[1],\n guardPosition.right.elbow[2],\n );\n config.rotate(\n BoneName.WRIST_R,\n guardPosition.right.wrist[0],\n guardPosition.right.wrist[1],\n guardPosition.right.wrist[2],\n );\n }\n};\n"],"mappings":";;;;;;;AAsFA,IAAM,aAAa,YAA6B,UAAU,KAAK,KAAM;;;;;AAqKrE,IAAa,yBAAyB;CACpC;EA1IA,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;GACX,QACE;GACF,SACE;GACH;EACD,MAAM;GACJ,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,IAAI;IAAE,UAAU,GAAG;IAAC;GACzD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,KAAK;IAAC;GACpD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,OAAO;GACL,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,GAAG;IAAE,UAAU,IAAI;IAAC;GACzD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,IAAI;IAAC;GACnD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,QAAQ;EACR,UAAU;EACV,UAAU;GAAC;GAAQ;GAAU;GAAY;GAAQ;GAAQ;GAAM;EAqH/D;CACA;EAxFA,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;GACX,QACE;GACF,SACE;GACH;EACD,MAAM;GACJ,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,IAAI;IAAE,UAAU,EAAE;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,KAAK;IAAC;GACpD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,OAAO;GACL,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,GAAG;IAAE,UAAU,GAAG;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,IAAI;IAAC;GACnD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,QAAQ;EACR,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACD;EA4DD;CACA;EA/BA,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;GACX,QACE;GACF,SACE;GACH;EACD,MAAM;GACJ,UAAU;IAAC,UAAU,GAAG;IAAE,UAAU,IAAI;IAAE,UAAU,GAAG;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,IAAI;IAAC;GACnD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,OAAO;GACL,UAAU;IAAC,UAAU,GAAG;IAAE,UAAU,GAAG;IAAE,UAAU,IAAI;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,GAAG;IAAC;GAClD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,QAAQ;EACR,UAAU;EACV,UAAU;GAAC;GAAW;GAAS;GAAO;GAAS;GAAa;EAU5D;CACD;;;;;;;;AAeD,IAAa,oBAAoB,SAA2C;AAC1E,QAAO,uBAAuB"}
1
+ {"version":3,"file":"KoreanGuardPositions.js","names":[],"sources":["../../../../src/systems/animation/builders/KoreanGuardPositions.ts"],"sourcesContent":["import { BoneName } from \"@/types/skeletal\";\n\n// Minimal contract to apply guard rotations without depending on KeyframeConfig\ninterface GuardRotatable {\n rotate: (bone: BoneName, x: number, y: number, z: number) => unknown;\n}\n\n/**\n * Korean Guard Positions (막기자세)\n *\n * Defines authentic Korean martial arts guard positions for all animations.\n * Guards protect vital areas and provide optimal positioning for techniques.\n *\n * Korean martial arts emphasize three primary guard levels:\n * - 상단막기 (Sangdan Makgi) - High guard protecting head\n * - 중단막기 (Jungdan Makgi) - Middle guard protecting torso\n * - 하단막기 (Hadan Makgi) - Low guard protecting lower body\n *\n * Each guard position includes:\n * - Proper shoulder and elbow angles\n * - Hand pose (주먹쥐기 - fist formation)\n * - Guard height description\n * - Korean/English terminology\n *\n * @module systems/animation/KoreanGuardPositions\n * @category Animation System\n * @korean 막기자세시스템\n */\n\n/**\n * Guard position for a single arm\n * @korean 팔방어위치\n */\nexport interface GuardArmPosition {\n /** Shoulder rotation in radians (x, y, z) */\n readonly shoulder: readonly [number, number, number];\n /** Elbow rotation in radians (x, y, z) */\n readonly elbow: readonly [number, number, number];\n /** Wrist rotation in radians (x, y, z) */\n readonly wrist: readonly [number, number, number];\n}\n\n/**\n * Complete guard position configuration\n * @korean 방어자세설정\n */\nexport interface GuardPosition {\n /** Korean name */\n readonly korean: string;\n /** English name */\n readonly english: string;\n /** Romanization */\n readonly romanized: string;\n /** Description of guard purpose and application */\n readonly description: {\n readonly korean: string;\n readonly english: string;\n };\n /** Left arm guard position */\n readonly left: GuardArmPosition;\n /** Right arm guard position */\n readonly right: GuardArmPosition;\n /** Height level of guard */\n readonly height: \"temple_level\" | \"chest_level\" | \"abdomen_level\";\n /**\n * Default hand pose description for this guard.\n *\n * NOTE: This field is documentation/metadata only and is not wired into the\n * hand pose system or the HandPoseType enum. Actual hand poses are applied\n * directly in animation code (e.g., via HAND_POSES.FIST). Do not use these\n * string literal values for programmatic logic.\n *\n * @see HandPoseType for the actual hand pose enum values\n * @see HAND_POSES for applying hand poses in animations\n */\n readonly handPose: \"fist_vertical\" | \"fist_horizontal\" | \"open_hand\";\n /** Vital areas protected by this guard */\n readonly protects: readonly string[];\n}\n\n/**\n * Helper to convert degrees to radians\n * @param degrees - Angle in degrees\n * @returns Angle in radians\n * @korean 도를라디안으로\n */\nconst toRadians = (degrees: number): number => (degrees * Math.PI) / 180;\n\n/**\n * 상단막기 (Sangdan Makgi) - High Guard\n *\n * Traditional Taekwondo high block position protecting head and face.\n * Both hands at temple/forehead level with elbows bent tight.\n * Fists vertical (thumb-side up) for maximum protection.\n *\n * Protects against:\n * - High strikes to head (머리 공격)\n * - Overhead attacks (위쪽 공격)\n * - Face punches (얼굴 주먹)\n *\n * Application:\n * - Default guard for Geon (Heaven) stance\n * - Used in high kicking techniques\n * - Transitional guard for head-level attacks\n *\n * Biomechanics:\n * - Shoulders raised (~15° abduction)\n * - Elbows bent ~110° (tight guard)\n * - Fists at temple level\n * - Forearms vertical for deflection\n *\n * @korean 상단막기자세\n */\nexport const HIGH_GUARD: GuardPosition = {\n korean: \"상단막기\",\n english: \"High Guard\",\n romanized: \"Sangdan Makgi\",\n description: {\n korean:\n \"머리와 얼굴을 보호하는 높은 방어 자세. 주먹을 관자놀이 높이에 두고 팔꿈치를 단단히 구부림.\",\n english:\n \"High guard protecting head and face. Fists at temple level with elbows bent tight.\",\n },\n left: {\n shoulder: [toRadians(-30), toRadians(-25), toRadians(10)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(-120)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n right: {\n shoulder: [toRadians(-30), toRadians(25), toRadians(-10)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(120)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n height: \"temple_level\",\n handPose: \"fist_vertical\",\n protects: [\"head\", \"temple\", \"forehead\", \"eyes\", \"nose\", \"jaw\"] as const,\n};\n\n/**\n * 중단막기 (Jungdan Makgi) - Middle Guard\n *\n * Standard Korean martial arts guard at chest/solar plexus level.\n * Most versatile guard position, used in most fighting stances.\n * Elbows at 90° protecting ribs and torso.\n *\n * Protects against:\n * - Body punches (몸통 주먹)\n * - Solar plexus strikes (명치 공격)\n * - Rib attacks (갈비뼈 공격)\n * - Liver strikes (간 공격)\n *\n * Application:\n * - Default guard for most stances\n * - Starting position for most techniques\n * - Balanced offensive/defensive posture\n *\n * Biomechanics:\n * - Shoulders neutral (~10° forward)\n * - Elbows bent ~90° (classic guard)\n * - Fists at chest/chin level\n * - Ready to attack or defend\n *\n * @korean 중단막기자세\n */\nexport const MIDDLE_GUARD: GuardPosition = {\n korean: \"중단막기\",\n english: \"Middle Guard\",\n romanized: \"Jungdan Makgi\",\n description: {\n korean:\n \"가슴과 명치를 보호하는 중간 방어 자세. 팔꿈치를 90도 구부려 몸통을 보호함.\",\n english:\n \"Middle guard protecting chest and solar plexus. Elbows bent at 90° protecting torso.\",\n },\n left: {\n shoulder: [toRadians(-20), toRadians(-20), toRadians(8)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(-100)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n right: {\n shoulder: [toRadians(-20), toRadians(20), toRadians(-8)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(100)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n height: \"chest_level\",\n handPose: \"fist_vertical\",\n protects: [\n \"chest\",\n \"solar_plexus\",\n \"ribs\",\n \"liver\",\n \"spleen\",\n \"heart\",\n ] as const,\n};\n\n/**\n * 하단막기 (Hadan Makgi) - Low Guard\n *\n * Low guard position protecting lower body and groin.\n * Used in grappling and ground-fighting scenarios.\n * Hands at abdomen/hip level ready for low attacks.\n *\n * Protects against:\n * - Low kicks (낮은 발차기)\n * - Body kicks (몸통 발차기)\n * - Groin attacks (낭심 공격)\n * - Takedown attempts (넘어뜨리기)\n *\n * Application:\n * - Default for Gon (Earth) stance\n * - Grappling and clinch range\n * - Defense against low attacks\n *\n * Biomechanics:\n * - Shoulders forward (~20° flexion)\n * - Elbows bent ~70° (wider guard)\n * - Fists at abdomen/hip level\n * - Ready to sprawl or clinch\n *\n * @korean 하단막기자세\n */\nexport const LOW_GUARD: GuardPosition = {\n korean: \"하단막기\",\n english: \"Low Guard\",\n romanized: \"Hadan Makgi\",\n description: {\n korean:\n \"하복부와 낭심을 보호하는 낮은 방어 자세. 손을 배 높이에 두고 낮은 공격에 대비함.\",\n english:\n \"Low guard protecting lower body and groin. Hands at abdomen level ready for low attacks.\",\n },\n left: {\n shoulder: [toRadians(15), toRadians(-10), toRadians(12)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(-75)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n right: {\n shoulder: [toRadians(15), toRadians(10), toRadians(-12)] as const,\n elbow: [toRadians(0), toRadians(0), toRadians(75)] as const,\n wrist: [toRadians(0), toRadians(0), toRadians(0)] as const,\n },\n height: \"abdomen_level\",\n handPose: \"fist_vertical\",\n protects: [\"abdomen\", \"groin\", \"hip\", \"thigh\", \"lower_ribs\"] as const,\n};\n\n/**\n * All Korean guard positions indexed by name\n * @korean 모든방어자세\n */\nexport const KOREAN_GUARD_POSITIONS = {\n HIGH_GUARD,\n MIDDLE_GUARD,\n LOW_GUARD,\n} as const;\n\n/**\n * Guard position type\n * @korean 방어자세타입\n */\nexport type GuardPositionType = keyof typeof KOREAN_GUARD_POSITIONS;\n\n/**\n * Get guard position by type\n *\n * @param type - Guard position type\n * @returns Guard position configuration\n * @korean 방어자세가져오기\n */\nexport const getGuardPosition = (type: GuardPositionType): GuardPosition => {\n return KOREAN_GUARD_POSITIONS[type];\n};\n\n/**\n * Get appropriate guard for stance height\n *\n * Determines which guard position is most appropriate based on\n * the stance configuration and fighting context.\n *\n * @param stanceType - Type of stance (\"high\" | \"middle\" | \"low\")\n * @returns Recommended guard position\n * @korean 자세높이에맞는방어자세\n */\nexport const getGuardForStanceHeight = (\n stanceType: \"high\" | \"middle\" | \"low\",\n): GuardPosition => {\n switch (stanceType) {\n case \"high\":\n return HIGH_GUARD;\n case \"low\":\n return LOW_GUARD;\n case \"middle\":\n default:\n return MIDDLE_GUARD;\n }\n};\n\n/**\n * Apply guard position to KeyframeConfig\n *\n * Applies a Korean martial arts guard position to a keyframe configuration.\n * Can apply to one hand (for techniques where one hand strikes) or both hands.\n *\n * Usage:\n * ```typescript\n * const kf = new KeyframeConfig(0.0);\n * applyGuardPositionToConfig(kf, MIDDLE_GUARD, \"both\"); // Both hands in guard\n * applyGuardPositionToConfig(kf, MIDDLE_GUARD, \"left\"); // Only left hand guards\n * ```\n *\n * @param config - KeyframeConfig to apply guard to\n * @param guardPosition - Guard position configuration\n * @param hand - Which hand(s) to apply (\"left\" | \"right\" | \"both\")\n * @korean KeyframeConfig에방어자세적용\n */\nexport const applyGuardPositionToConfig = (\n config: GuardRotatable,\n guardPosition: GuardPosition,\n hand: \"left\" | \"right\" | \"both\" = \"both\",\n): void => {\n // Apply left hand guard\n if (hand === \"left\" || hand === \"both\") {\n config.rotate(\n BoneName.SHOULDER_L,\n guardPosition.left.shoulder[0],\n guardPosition.left.shoulder[1],\n guardPosition.left.shoulder[2],\n );\n config.rotate(\n BoneName.ELBOW_L,\n guardPosition.left.elbow[0],\n guardPosition.left.elbow[1],\n guardPosition.left.elbow[2],\n );\n config.rotate(\n BoneName.WRIST_L,\n guardPosition.left.wrist[0],\n guardPosition.left.wrist[1],\n guardPosition.left.wrist[2],\n );\n }\n\n // Apply right hand guard\n if (hand === \"right\" || hand === \"both\") {\n config.rotate(\n BoneName.SHOULDER_R,\n guardPosition.right.shoulder[0],\n guardPosition.right.shoulder[1],\n guardPosition.right.shoulder[2],\n );\n config.rotate(\n BoneName.ELBOW_R,\n guardPosition.right.elbow[0],\n guardPosition.right.elbow[1],\n guardPosition.right.elbow[2],\n );\n config.rotate(\n BoneName.WRIST_R,\n guardPosition.right.wrist[0],\n guardPosition.right.wrist[1],\n guardPosition.right.wrist[2],\n );\n }\n};\n"],"mappings":";;;;;;;AAsFA,IAAM,aAAa,YAA6B,UAAU,KAAK,KAAM;;;;;AAqKrE,IAAa,yBAAyB;CACpC;EA1IA,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;GACX,QACE;GACF,SACE;GACH;EACD,MAAM;GACJ,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,IAAI;IAAE,UAAU,GAAG;IAAC;GACzD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,KAAK;IAAC;GACpD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,OAAO;GACL,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,GAAG;IAAE,UAAU,IAAI;IAAC;GACzD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,IAAI;IAAC;GACnD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,QAAQ;EACR,UAAU;EACV,UAAU;GAAC;GAAQ;GAAU;GAAY;GAAQ;GAAQ;GAAM;EAqH/D;CACA;EAxFA,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;GACX,QACE;GACF,SACE;GACH;EACD,MAAM;GACJ,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,IAAI;IAAE,UAAU,EAAE;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,KAAK;IAAC;GACpD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,OAAO;GACL,UAAU;IAAC,UAAU,IAAI;IAAE,UAAU,GAAG;IAAE,UAAU,GAAG;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,IAAI;IAAC;GACnD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,QAAQ;EACR,UAAU;EACV,UAAU;GACR;GACA;GACA;GACA;GACA;GACA;GACD;EA4DD;CACA;EA/BA,QAAQ;EACR,SAAS;EACT,WAAW;EACX,aAAa;GACX,QACE;GACF,SACE;GACH;EACD,MAAM;GACJ,UAAU;IAAC,UAAU,GAAG;IAAE,UAAU,IAAI;IAAE,UAAU,GAAG;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,IAAI;IAAC;GACnD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,OAAO;GACL,UAAU;IAAC,UAAU,GAAG;IAAE,UAAU,GAAG;IAAE,UAAU,IAAI;IAAC;GACxD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,GAAG;IAAC;GAClD,OAAO;IAAC,UAAU,EAAE;IAAE,UAAU,EAAE;IAAE,UAAU,EAAE;IAAC;GAClD;EACD,QAAQ;EACR,UAAU;EACV,UAAU;GAAC;GAAW;GAAS;GAAO;GAAS;GAAa;EAU5D;CACD;;;;;;;;AAeD,IAAa,oBAAoB,SAA2C;CAC1E,OAAO,uBAAuB"}