blacktrigram 0.7.73 → 0.7.75

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 (218) hide show
  1. package/lib/App2.js +6 -6
  2. package/lib/audio/AudioAssetRegistry.js +1 -1
  3. package/lib/audio/AudioManager.js +1 -1
  4. package/lib/audio/AudioPool.js +1 -1
  5. package/lib/audio/AudioProvider.js +1 -1
  6. package/lib/audio/BoneImpactAudioMap.js +1 -1
  7. package/lib/audio/VariantSelector.js +1 -1
  8. package/lib/audio/index.js +3 -3
  9. package/lib/components/index.js +19 -19
  10. package/lib/components/screens/combat/CombatScreen3D.js +27 -27
  11. package/lib/components/screens/combat/components/controls/CombatButtons.js +1 -1
  12. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js +1 -1
  13. package/lib/components/screens/combat/components/controls/ControlsGuide.js +1 -1
  14. package/lib/components/screens/combat/components/controls/PauseMenu.js +5 -5
  15. package/lib/components/screens/combat/components/controls/PauseMenuButton.js +1 -1
  16. package/lib/components/screens/combat/components/controls/QuickSettings.js +1 -1
  17. package/lib/components/screens/combat/components/effects/BloodDecals3D.js +1 -1
  18. package/lib/components/screens/combat/components/effects/BloodParticles3D.js +1 -1
  19. package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js +1 -1
  20. package/lib/components/screens/combat/components/feedback/MatchCountdown.js +1 -1
  21. package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js +1 -1
  22. package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js +1 -1
  23. package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js +1 -1
  24. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js +2 -2
  25. package/lib/components/screens/combat/components/hud/CombatLeftHUD.js +4 -4
  26. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js +1 -1
  27. package/lib/components/screens/combat/components/hud/CombatRightHUD.js +4 -4
  28. package/lib/components/screens/combat/components/hud/CombatTopHUD.js +3 -3
  29. package/lib/components/screens/combat/components/hud/FPSMonitor.js +1 -1
  30. package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js +1 -1
  31. package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js +1 -1
  32. package/lib/components/screens/combat/helpers/AnimationUpdater.js +1 -1
  33. package/lib/components/screens/combat/hooks/useAICombat.js +1 -1
  34. package/lib/components/screens/combat/hooks/useCombatActions.js +1 -1
  35. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js +1 -1
  36. package/lib/components/screens/combat/hooks/useCombatAudio.js +1 -1
  37. package/lib/components/screens/controls/ControlsScreen3D.js +6 -6
  38. package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js +1 -1
  39. package/lib/components/screens/controls/components/GamepadVisualization3D.js +1 -1
  40. package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js +1 -1
  41. package/lib/components/screens/controls/components/Key3D.js +1 -1
  42. package/lib/components/screens/controls/components/VisualKeyboard3D.js +2 -2
  43. package/lib/components/screens/intro/IntroScreen3D.js +6 -6
  44. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js +1 -1
  45. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js +2 -2
  46. package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js +3 -3
  47. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js +2 -2
  48. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js +3 -3
  49. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js +1 -1
  50. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js +2 -2
  51. package/lib/components/screens/intro/components/StatBarOverlayHtml.js +1 -1
  52. package/lib/components/screens/philosophy/PhilosophyScreen3D.js +2 -2
  53. package/lib/components/screens/training/TrainingScreen3D.js +15 -15
  54. package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js +1 -1
  55. package/lib/components/screens/training/components/AnatomyOverlay3D.js +1 -1
  56. package/lib/components/screens/training/components/FootPlacementMarkers3D.js +1 -1
  57. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js +1 -1
  58. package/lib/components/screens/training/components/HitFeedbackEffect3D.js +1 -1
  59. package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js +1 -1
  60. package/lib/components/screens/training/components/TrainingDummy3D.js +4 -4
  61. package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js +1 -1
  62. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js +1 -1
  63. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js +1 -1
  64. package/lib/components/screens/training/components/VitalPointMarker3D.js +1 -1
  65. package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js +2 -2
  66. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js +3 -3
  67. package/lib/components/screens/training/components/hud/TrainingLeftHUD.js +3 -3
  68. package/lib/components/screens/training/components/hud/TrainingRightHUD.js +6 -6
  69. package/lib/components/screens/training/components/hud/TrainingTopHUD.js +2 -2
  70. package/lib/components/screens/training/hooks/useAttackMovement.js +2 -2
  71. package/lib/components/screens/training/hooks/useTrainingActions.js +1 -1
  72. package/lib/components/screens/training/hooks/useTrainingState.js +1 -1
  73. package/lib/components/shared/mobile/HapticController.js +1 -1
  74. package/lib/components/shared/mobile/MobileControlsPure.js +1 -1
  75. package/lib/components/shared/three/anatomy/BodySurface.js +1 -1
  76. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js +1 -1
  77. package/lib/components/shared/three/anatomy/BoneClothing.js +1 -1
  78. package/lib/components/shared/three/anatomy/BoneRenderer.js +7 -7
  79. package/lib/components/shared/three/anatomy/Face3D.js +1 -1
  80. package/lib/components/shared/three/anatomy/Foot3D.js +1 -1
  81. package/lib/components/shared/three/anatomy/Hand3D.js +1 -1
  82. package/lib/components/shared/three/effects/ActionFeedback.js +1 -1
  83. package/lib/components/shared/three/effects/DamageNumbers.js +1 -1
  84. package/lib/components/shared/three/effects/HitEffects3D.js +1 -1
  85. package/lib/components/shared/three/effects/PlayerStateIndicators.js +1 -1
  86. package/lib/components/shared/three/effects/StanceSymbol3D.js +1 -1
  87. package/lib/components/shared/three/effects/StanceTransitionEffect.js +1 -1
  88. package/lib/components/shared/three/effects/VitalPointMarkers3D.js +2 -2
  89. package/lib/components/shared/three/indicators/ElementalColorSystem.js +1 -1
  90. package/lib/components/shared/three/indicators/HapticFeedback.js +1 -1
  91. package/lib/components/shared/three/models/Player3DWithTransitions.js +4 -4
  92. package/lib/components/shared/three/models/SkeletalPlayer3D.js +3 -3
  93. package/lib/components/shared/three/optimization/AdaptiveQuality.js +1 -1
  94. package/lib/components/shared/three/scene/AtmosphericParticles3D.js +1 -1
  95. package/lib/components/shared/three/scene/BackgroundScene3D.js +1 -1
  96. package/lib/components/shared/three/scene/CombatArena3D.js +3 -3
  97. package/lib/components/shared/three/scene/KoreanSignage3D.js +1 -1
  98. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js +1 -1
  99. package/lib/components/shared/three/ui/CombatReadinessBar.js +1 -1
  100. package/lib/components/shared/three/ui/ComboCounter.js +1 -1
  101. package/lib/components/shared/three/ui/HealthBar.js +1 -1
  102. package/lib/components/shared/three/ui/PlayerHUD.js +4 -4
  103. package/lib/components/shared/three/ui/StaminaBar.js +1 -1
  104. package/lib/components/shared/three/ui/TechniqueBar.js +2 -2
  105. package/lib/components/shared/three/ui/TechniqueCard.js +1 -1
  106. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js +2 -2
  107. package/lib/components/shared/ui/BaseHUDContainer.js +1 -1
  108. package/lib/components/shared/ui/CombatTimer.js +1 -1
  109. package/lib/components/shared/ui/ErrorModal.js +1 -1
  110. package/lib/components/shared/ui/SplashScreen.js +3 -3
  111. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js +2 -2
  112. package/lib/components/shared/ui/shared/ConfirmDialog.js +1 -1
  113. package/lib/constants/bodyRenderingConstants.js +1 -1
  114. package/lib/data/index.js +1 -1
  115. package/lib/data/techniqueMappings.js +1 -1
  116. package/lib/hooks/index.js +1 -1
  117. package/lib/hooks/useActionFeedback.js +1 -1
  118. package/lib/hooks/useDebounce.js +1 -1
  119. package/lib/hooks/useMatchCountdown.js +1 -1
  120. package/lib/hooks/useRoundTransition.js +1 -1
  121. package/lib/hooks/useTechniqueSelection.js +1 -1
  122. package/lib/hooks/useThrottle.js +1 -1
  123. package/lib/hooks/useWindowSize.js +1 -1
  124. package/lib/index.js +39 -39
  125. package/lib/systems/CombatSystem.js +9 -9
  126. package/lib/systems/EffectCalculator.js +1 -1
  127. package/lib/systems/TrigramSystem.js +1 -1
  128. package/lib/systems/VitalPointSystem.js +2 -2
  129. package/lib/systems/ai/DecisionTree.js +3 -3
  130. package/lib/systems/ai/TrainingAI.js +1 -1
  131. package/lib/systems/animation/builders/HandPoses.js +1 -1
  132. package/lib/systems/animation/builders/KeyframeInterpolation.js +88 -1
  133. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  134. package/lib/systems/animation/builders/KoreanGuardPositions.js +237 -157
  135. package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
  136. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js +2 -2
  137. package/lib/systems/animation/builders/SkeletonRig.js +1 -1
  138. package/lib/systems/animation/catalogs/AttackAnimations.js +1 -1
  139. package/lib/systems/animation/catalogs/BasicAnimations.js +1 -1
  140. package/lib/systems/animation/catalogs/ComboAnimations.js +1 -1
  141. package/lib/systems/animation/catalogs/DarkOpsAnimations.js +1 -1
  142. package/lib/systems/animation/catalogs/DefensiveAnimations.js +1 -1
  143. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js +1 -1
  144. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js +1 -1
  145. package/lib/systems/animation/catalogs/GamStanceAnimations.js +100 -4
  146. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -1
  147. package/lib/systems/animation/catalogs/GanStanceAnimations.js +1 -1
  148. package/lib/systems/animation/catalogs/GeonStanceAnimations.js +1 -1
  149. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +1 -1
  150. package/lib/systems/animation/catalogs/GrapplingAnimations.js +1 -1
  151. package/lib/systems/animation/catalogs/KickAnimations.js +1 -1
  152. package/lib/systems/animation/catalogs/MovementAnimations.js +1 -1
  153. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  154. package/lib/systems/animation/catalogs/RecoveryAnimations.js +1 -1
  155. package/lib/systems/animation/catalogs/SonStanceAnimations.js +1 -1
  156. package/lib/systems/animation/catalogs/StanceAnimations.js +1 -1
  157. package/lib/systems/animation/catalogs/StanceAttackAnimations.js +1 -1
  158. package/lib/systems/animation/catalogs/StanceIdleAnimations.js +1 -1
  159. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js +1 -1
  160. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js +1 -1
  161. package/lib/systems/animation/catalogs/TaeStanceAnimations.js +1 -1
  162. package/lib/systems/animation/core/AnimationHitTiming.js +1 -1
  163. package/lib/systems/animation/core/AnimationOptimizations.js +1 -1
  164. package/lib/systems/animation/core/AnimationPriority.js +1 -1
  165. package/lib/systems/animation/core/AnimationRegistry.js +4 -4
  166. package/lib/systems/animation/core/AnimationTransitions.js +1 -1
  167. package/lib/systems/animation/core/TechniqueAnimationMapper.js +1 -1
  168. package/lib/systems/animation/core/TechniqueAnimationMapping.js +1 -1
  169. package/lib/systems/animation/systems/AdvancedJointMovements.js +1 -1
  170. package/lib/systems/animation/systems/BodyFacingSystem.js +1 -1
  171. package/lib/systems/animation/systems/MuscleActivation.js +1 -1
  172. package/lib/systems/combat/BalanceSystem.js +1 -1
  173. package/lib/systems/combat/BreakingStatusEffects.js +1 -1
  174. package/lib/systems/combat/CombatStateSystem.js +1 -1
  175. package/lib/systems/combat/ConsciousnessSystem.js +1 -1
  176. package/lib/systems/combat/GrappleSystem.js +1 -1
  177. package/lib/systems/combat/LimbExposureSystem.js +1 -1
  178. package/lib/systems/combat/PainResponseSystem.js +1 -1
  179. package/lib/systems/combat/TrainingCombatSystem.js +2 -2
  180. package/lib/systems/index.js +18 -18
  181. package/lib/systems/movement/helpers/AccelerationUpdater.js +1 -1
  182. package/lib/systems/movement/helpers/accelerationUtils.js +1 -1
  183. package/lib/systems/physics/AttackMovementPhysics.js +1 -1
  184. package/lib/systems/physics/CollisionDetection.js +2 -2
  185. package/lib/systems/physics/KnockbackPhysics.js +1 -1
  186. package/lib/systems/physics/PhysicalReachCalculator.js +1 -1
  187. package/lib/systems/trigram/KoreanTechniques.js +2 -2
  188. package/lib/systems/trigram/techniques/index.js +7 -7
  189. package/lib/systems/trigram/types/GonTechniqueExtensions.js +1 -1
  190. package/lib/systems/types.js +1 -1
  191. package/lib/systems/vitalpoint/DamageCalculator.js +1 -1
  192. package/lib/systems/vitalpoint/HitDetection.js +1 -1
  193. package/lib/systems/vitalpoint/KoreanAnatomy.js +1 -1
  194. package/lib/systems/vitalpoint/KoreanVitalPoints.js +2 -2
  195. package/lib/systems/vitalpoint/VitalPointsData.js +1 -1
  196. package/lib/types/constants/animations.js +1 -1
  197. package/lib/types/constants/index.js +8 -8
  198. package/lib/types/constants/layout.js +1 -1
  199. package/lib/types/constants/ui.js +1 -1
  200. package/lib/types/index.js +6 -6
  201. package/lib/types/techniqueId.js +1 -1
  202. package/lib/utils/accessibility.js +1 -1
  203. package/lib/utils/arenaWorldDimensions.js +1 -1
  204. package/lib/utils/characterScaling.js +1 -1
  205. package/lib/utils/combatReadiness.js +1 -1
  206. package/lib/utils/fabricTextures.js +1 -1
  207. package/lib/utils/hapticFeedback.js +1 -1
  208. package/lib/utils/haptics.js +1 -1
  209. package/lib/utils/index.js +2 -2
  210. package/lib/utils/koreanThemeHelpers.js +1 -1
  211. package/lib/utils/performance/PerformanceMonitor.js +1 -1
  212. package/lib/utils/performance/PerformanceOverlay3D.js +1 -1
  213. package/lib/utils/performance/usePerformanceMonitor.js +2 -2
  214. package/lib/utils/performanceOptimization.js +1 -1
  215. package/lib/utils/responsiveLayoutHelpers.js +1 -1
  216. package/lib/utils/responsiveOrientationConstants.js +1 -1
  217. package/lib/utils/safeAreaUtils.js +1 -1
  218. package/package.json +11 -5
package/lib/index.js CHANGED
@@ -1,21 +1,21 @@
1
1
  import { AudioAssetRegistry, audioAssetRegistry } from "./audio/AudioAssetRegistry.js";
2
2
  import { AudioCache } from "./audio/AudioCache.js";
3
- import AudioManager from "./audio/AudioManager.js";
3
+ import { AudioManager } from "./audio/AudioManager.js";
4
4
  import { AudioContext, AudioProvider, useAudio } from "./audio/AudioProvider.js";
5
5
  import { AUDIO_FORMATS, AudioUtils, canPlayType, clampVolume, createAudioElement, detectSupportedFormats, formatDuration, getBestFormatMetadata, getOptimalFormat, getPreferredFormat, isAudioSupported, normalizeVolume, selectAudioFormat, validateAudioUrl } from "./audio/AudioUtils.js";
6
6
  import { AudioCategory } from "./audio/types.js";
7
- import VariantSelector, { selectCombatMusic, selectCombatSound, selectHitSound } from "./audio/VariantSelector.js";
7
+ import { VariantSelector, selectCombatMusic, selectCombatSound, selectHitSound } from "./audio/VariantSelector.js";
8
8
  import { audio_exports } from "./audio/index.js";
9
9
  import { BodyRegion, CombatAttackType, CombatState, DamageType, GameMode, GamePhase, GrappleState, GrappleTarget, KoreanTextSize, KoreanTextWeight, PlayerArchetype, TrigramStance, VitalPointCategory, VitalPointEffectType, VitalPointSeverity } from "./types/common.js";
10
10
  import { CYBERPUNK_COLORS, KOREAN_COLORS } from "./types/constants/colors.js";
11
11
  import { FONT_FAMILY, FONT_SIZES, FONT_WEIGHTS, KOREAN_FONT_WEIGHTS, KOREAN_MOBILE_FONT_SIZES, KOREAN_TEXT_SIZES, getKoreanFontSize } from "./types/constants/typography.js";
12
- import UI_CONSTANTS, { HEALTH_COLORS, UI_DIMENSIONS } from "./types/constants/ui.js";
12
+ import { HEALTH_COLORS, UI_CONSTANTS, UI_DIMENSIONS } from "./types/constants/ui.js";
13
13
  import { BORDERS, BORDER_RADIUS, COMBAT_UI_DIMENSIONS, COMBAT_UI_DIMENSIONS_NUMERIC, FONT_SIZE_MULTIPLIERS, GRADIENTS, HIERARCHY, HUD_STYLE, LAYOUT_MULTIPLIERS, OPACITY, SPACING, SPACING_ADJUSTMENTS, SPACING_NUMERIC, TEXT_EFFECTS, TRANSITIONS, TYPOGRAPHY, TYPOGRAPHY_NUMERIC, getResponsiveFontSize, getResponsiveSpacing } from "./types/constants/designSystem.js";
14
14
  import { FRAME_TIME_BUDGET, PERFORMANCE_SETTINGS_BY_TIER, getPerformanceSettings, getPerformanceTier } from "./types/constants/performance.js";
15
15
  import { DEFAULT_RESIZE_TRANSITION, FONT_SCALE_MAP, FONT_SIZE_CONSTRAINTS, RESPONSIVE_BREAKPOINTS, SPACING_SCALE_MAP, calculateFontSize, calculateResponsiveValues, calculateSpacing, createResponsiveConfig, createTransitionString, getFontScale, getScreenSize, getSpacingScale, isDesktopSize, isMobileSize, isTabletSize, testScreenSize } from "./systems/ResponsiveScaling.js";
16
- import ANIMATION_DURATIONS from "./types/constants/animations.js";
16
+ import { ANIMATION_DURATIONS } from "./types/constants/animations.js";
17
17
  import { ARCHETYPE_ASSETS, ARCHETYPE_BACKGROUNDS, ARCHETYPE_TECHNIQUE_BONUSES, FALLBACK_ARCHETYPE_IMAGE, MAX_TRANSITION_COST_KI, MAX_TRANSITION_COST_STAMINA, MAX_TRANSITION_TIME_MILLISECONDS, PERFORMANCE_RATING_THRESHOLDS, ROUND_ANNOUNCEMENT_TIMINGS } from "./types/constants/index.js";
18
- import TechniqueId from "./types/techniqueId.js";
18
+ import { TechniqueId } from "./types/techniqueId.js";
19
19
  import { AttackAnimationType, BoneName, mirrorGuardPose } from "./types/skeletal.js";
20
20
  import { FingerType, HandPoseType } from "./types/hand-animation.js";
21
21
  import { HUD_HEIGHT, HUD_WIDTH_PERCENT, Z_INDEX } from "./types/LayoutTypes.js";
@@ -29,7 +29,7 @@ import { DEFAULT_MUSCLE_CONFIG } from "./types/muscle.js";
29
29
  import { types_exports } from "./types/index.js";
30
30
  import { TRIGRAM_DATA, TRIGRAM_STANCES_ORDER, combineStanceWithSide, parseStanceWithSide } from "./systems/trigram/types.js";
31
31
  import { BODY_PART_EFFECT_CONSTANTS, BodyPart, DEFAULT_BODY_PART_CONFIG, LegInjuryState, MOVEMENT_PENALTY_CONSTANTS } from "./systems/bodypart/types.js";
32
- import GAME_CONFIG, { ANIMATION_TIMINGS, AUDIO_DEFAULTS, BASE_PLAYER_STATS, CANVAS_ASPECT_RATIO, CENTER_POSITION_X, COMBAT_AUDIO_MAP, COMBAT_CONFIG, COMBAT_CONSTANTS, COMBAT_CONTROLS, COMBAT_PHASES, COMBAT_RANGES, COMBAT_STATE_MACHINE, COMBAT_TIMING, DAMAGE_CONSTANTS, DAMAGE_TYPES, DEFAULT_GAME_SPEED, DIFFICULTY_SETTINGS, EFFECTIVENESS_MODIFIERS, ENHANCED_DAMAGE_CONSTANTS, FRAME_TIME, GAME_METADATA, GAME_MODE_CONFIG, GAME_PHASES, GAME_STATES, HALF_CANVAS_HEIGHT, HALF_CANVAS_WIDTH, HIT_DETECTION, INPUT_CONSTANTS, KEYBOARD_MAPPING, MARTIAL_ARTS_CONFIG, PERFORMANCE_CONFIG, PERFORMANCE_THRESHOLDS, PLAYER_ARCHETYPES_DATA, PLAYER_COLORS, PLAYER_DISTANCE, RESOURCE_COSTS, STATUS_DURATIONS, TECHNIQUE_RESULTS, TICK_RATE, TRAINING_COMBAT_SETTINGS, TRAINING_CONFIG, TRAINING_STATE_MACHINE, UI_LAYOUT, VISUAL_EFFECTS, getStanceFromKey } from "./systems/types.js";
32
+ import { ANIMATION_TIMINGS, AUDIO_DEFAULTS, BASE_PLAYER_STATS, CANVAS_ASPECT_RATIO, CENTER_POSITION_X, COMBAT_AUDIO_MAP, COMBAT_CONFIG, COMBAT_CONSTANTS, COMBAT_CONTROLS, COMBAT_PHASES, COMBAT_RANGES, COMBAT_STATE_MACHINE, COMBAT_TIMING, DAMAGE_CONSTANTS, DAMAGE_TYPES, DEFAULT_GAME_SPEED, DIFFICULTY_SETTINGS, EFFECTIVENESS_MODIFIERS, ENHANCED_DAMAGE_CONSTANTS, FRAME_TIME, GAME_CONFIG, GAME_METADATA, GAME_MODE_CONFIG, GAME_PHASES, GAME_STATES, HALF_CANVAS_HEIGHT, HALF_CANVAS_WIDTH, HIT_DETECTION, INPUT_CONSTANTS, KEYBOARD_MAPPING, MARTIAL_ARTS_CONFIG, PERFORMANCE_CONFIG, PERFORMANCE_THRESHOLDS, PLAYER_ARCHETYPES_DATA, PLAYER_COLORS, PLAYER_DISTANCE, RESOURCE_COSTS, STATUS_DURATIONS, TECHNIQUE_RESULTS, TICK_RATE, TRAINING_COMBAT_SETTINGS, TRAINING_CONFIG, TRAINING_STATE_MACHINE, UI_LAYOUT, VISUAL_EFFECTS, getStanceFromKey } from "./systems/types.js";
33
33
  import { GEON_TECHNIQUES } from "./systems/trigram/techniques/GeonTechniques.js";
34
34
  import { JIN_TECHNIQUES } from "./systems/trigram/techniques/JinTechniques.js";
35
35
  import { LI_TECHNIQUES } from "./systems/trigram/techniques/LiTechniques.js";
@@ -54,60 +54,60 @@ import { PlayerInjuryTrackingManager, playerInjuryManager } from "./systems/body
54
54
  import { BreathingDisruptionLevel, BreathingDisruptionSystem } from "./systems/breathing/BreathingDisruptionSystem.js";
55
55
  import { applyBreathingDisruptionFromTorsoDamage, applyBreathingDisruptionFromVitalPoint, causesBreathingDisruption, getBreathingDisruptionLevel, updateBreathingDisruption, upgradeLegacyBreathlessness } from "./systems/breathing/integration.js";
56
56
  import { BREATHING_AUDIO_EFFECTS, BREATHING_INDICATOR_CONFIGS, BREATHING_POSTURE_STATES, createBreathingIndicator, getBreathingAudio, getBreathingPosture } from "./systems/breathing/feedback.js";
57
- import BalanceSystem, { BalanceLevel } from "./systems/combat/BalanceSystem.js";
58
- import ConsciousnessSystem, { ConsciousnessLevel } from "./systems/combat/ConsciousnessSystem.js";
57
+ import { BalanceLevel, BalanceSystem } from "./systems/combat/BalanceSystem.js";
58
+ import { ConsciousnessLevel, ConsciousnessSystem } from "./systems/combat/ConsciousnessSystem.js";
59
59
  import { extractVitalPointCategory, formatPainConsciousnessDisplay, getPainConsciousnessStatus, getRecommendedRecoveryTime, getShockPainRemainingDuration, isHeadTraumaHit, isShockPainActive } from "./systems/combat/painConsciousnessUtils.js";
60
- import PainResponseSystem, { PainLevel } from "./systems/combat/PainResponseSystem.js";
60
+ import { PainLevel, PainResponseSystem } from "./systems/combat/PainResponseSystem.js";
61
61
  import { KoreanCulture } from "./systems/trigram/KoreanCulture.js";
62
62
  import { STANCE_EFFECTIVENESS_MATRIX, TrigramCalculator } from "./systems/trigram/TrigramCalculator.js";
63
63
  import { StanceManager } from "./systems/trigram/StanceManager.js";
64
64
  import { TransitionCalculator } from "./systems/trigram/TransitionCalculator.js";
65
- import TrigramSystem, { COUNTER_STANCE_DAMAGE_MULTIPLIER, STANCE_COUNTERS, applyCounterStanceDamage } from "./systems/TrigramSystem.js";
65
+ import { COUNTER_STANCE_DAMAGE_MULTIPLIER, STANCE_COUNTERS, TrigramSystem, applyCounterStanceDamage } from "./systems/TrigramSystem.js";
66
66
  import { VITAL_POINT_MERIDIAN_MAP, getMeridianMappingStatistics, getMeridiansForVitalPoint, getVitalPointsForMeridian, isVitalPointOnMeridian } from "./systems/vitalpoint/MeridianVitalPointMapping.js";
67
- import SAMPLE_VITAL_POINTS, { ANATOMICAL_REGIONS_DATA, ELEMENTAL_RELATIONS, ENERGY_MERIDIANS, ENERGY_MERIDIANS_ARRAY, ENHANCED_ANATOMICAL_ZONES, KOREAN_ANATOMICAL_ZONES, KOREAN_ANATOMICAL_ZONES_ARRAY, KoreanAnatomySystem, calculateAnatomicalVulnerability, calculateEnhancedVulnerability, calculateMeridianFlow, createVitalPointEffect, findOptimalVitalPoints, generateMeridianEffects, generateVulnerabilityHeatMap, getAnatomicalZones, getEnhancedZonesByPosition, getMeridian, getMeridiansByElement, getRegionBoundaries, getRegionForPosition, getVitalPointsInRegion, getZoneByPosition, isPointInPolygon, isPositionInEnhancedZone, isPositionInRegion } from "./systems/vitalpoint/KoreanAnatomy.js";
68
- import VitalPointSystem from "./systems/VitalPointSystem.js";
69
- import GrappleSystem, { DEFAULT_GRAPPLE_CONFIG } from "./systems/combat/GrappleSystem.js";
70
- import CombatSystem, { createCombatResult } from "./systems/CombatSystem.js";
67
+ import { ANATOMICAL_REGIONS_DATA, ELEMENTAL_RELATIONS, ENERGY_MERIDIANS, ENERGY_MERIDIANS_ARRAY, ENHANCED_ANATOMICAL_ZONES, KOREAN_ANATOMICAL_ZONES, KOREAN_ANATOMICAL_ZONES_ARRAY, KoreanAnatomySystem, SAMPLE_VITAL_POINTS, calculateAnatomicalVulnerability, calculateEnhancedVulnerability, calculateMeridianFlow, createVitalPointEffect, findOptimalVitalPoints, generateMeridianEffects, generateVulnerabilityHeatMap, getAnatomicalZones, getEnhancedZonesByPosition, getMeridian, getMeridiansByElement, getRegionBoundaries, getRegionForPosition, getVitalPointsInRegion, getZoneByPosition, isPointInPolygon, isPositionInEnhancedZone, isPositionInRegion } from "./systems/vitalpoint/KoreanAnatomy.js";
68
+ import { VitalPointSystem } from "./systems/VitalPointSystem.js";
69
+ import { DEFAULT_GRAPPLE_CONFIG, GrappleSystem } from "./systems/combat/GrappleSystem.js";
70
+ import { CombatSystem, createCombatResult } from "./systems/CombatSystem.js";
71
71
  import { AI_PERSONALITIES, ARCHETYPE_BEHAVIORS, followsHonorCode, getAllPersonalities, getArchetypeBehavior, getOptimalRange, getPersonalityByArchetype, getPersonalityByName, getRandomPersonality } from "./systems/ai/AIPersonality.js";
72
72
  import { AIComboSystem, ARCHETYPE_SIGNATURE_COMBOS, getNextComboTechnique } from "./systems/ai/ComboSystem.js";
73
73
  import { AdaptiveDifficulty, DIFFICULTY_PARAMETERS, DifficultyTier, interpolateDifficultyParameters, skillScoreToTier } from "./systems/ai/AdaptiveDifficulty.js";
74
- import KOREAN_VITAL_POINTS, { getVitalPointById, getVitalPointsByCategory, getVitalPointsByDifficulty, getVitalPointsByRegion, getVitalPointsBySeverity, getVitalPointsByStance, getVitalPointsStats } from "./systems/vitalpoint/KoreanVitalPoints.js";
74
+ import { KOREAN_VITAL_POINTS, getVitalPointById, getVitalPointsByCategory, getVitalPointsByDifficulty, getVitalPointsByRegion, getVitalPointsBySeverity, getVitalPointsByStance, getVitalPointsStats } from "./systems/vitalpoint/KoreanVitalPoints.js";
75
75
  import { AIActionType } from "./systems/ai/types.js";
76
76
  import { ARCHETYPE_ENFORCEMENT, enforceArchetypeBehavior, getActionFrequency, getSignatureMove, isActionProhibited, shouldExecuteSignatureMove } from "./systems/ai/ArchetypeEnforcer.js";
77
77
  import { AIDecisionTree } from "./systems/ai/DecisionTree.js";
78
- import TrainingAI from "./systems/ai/TrainingAI.js";
78
+ import { TrainingAI } from "./systems/ai/TrainingAI.js";
79
79
  import { STANCE_SPEED_MODIFIERS } from "./systems/physics/MovementPhysics.js";
80
80
  import { DEFAULT_INJURY_MOVEMENT_CONFIG, InjuryMovementModifier, injuryMovementModifier } from "./systems/movement/InjuryMovementModifier.js";
81
81
  import { getColorRGB, mixColors, toHexColor } from "./utils/colorHelpers.js";
82
- import TrainingCombatSystem from "./systems/combat/TrainingCombatSystem.js";
82
+ import { TrainingCombatSystem } from "./systems/combat/TrainingCombatSystem.js";
83
83
  import { isValidArchetype, isVitalPoint, isVitalPointCategory } from "./systems/combat/typeGuards.js";
84
- import CombatStateSystem, { CombatReadinessState } from "./systems/combat/CombatStateSystem.js";
85
- import BREAKING_STATUS_EFFECT_IDS, { getAllBreakingStatusEffectIds, isBreakingStatusEffectId } from "./systems/combat/BreakingStatusEffects.js";
84
+ import { CombatReadinessState, CombatStateSystem } from "./systems/combat/CombatStateSystem.js";
85
+ import { BREAKING_STATUS_EFFECT_IDS, getAllBreakingStatusEffectIds, isBreakingStatusEffectId } from "./systems/combat/BreakingStatusEffects.js";
86
86
  import { calculateBreakingResult, calculateCounterOpportunity, calculateVulnerabilityMultiplier, canExecuteCounter, determineExposedLimb, generateLimbExposureWindow, mapLimbToBreakingTarget } from "./systems/combat/LimbExposureSystem.js";
87
87
  import { checkForFall, getFallTypeName, isInFallOrGroundState } from "./systems/combat/FallIntegration.js";
88
88
  import { GameEventType } from "./systems/game.js";
89
89
  import { DEFAULT_ROW_HEIGHT, LayoutSystem, alignHorizontal, alignVertical, calculateGridPosition, centerElement, defaultLayoutSystem } from "./systems/LayoutSystem.js";
90
90
  import { calculateInjuryMultiplier, calculateLegInjuryFactor, calculateMovementSpeed } from "./systems/movement/integration.js";
91
- import DamageCalculator from "./systems/vitalpoint/DamageCalculator.js";
92
- import HitDetection from "./systems/vitalpoint/HitDetection.js";
91
+ import { DamageCalculator } from "./systems/vitalpoint/DamageCalculator.js";
92
+ import { HitDetection } from "./systems/vitalpoint/HitDetection.js";
93
93
  import { systems_exports } from "./systems/index.js";
94
94
  import { applyDamage, applyStatusEffect, calculateCombatEffectiveness, canPlayerAct, createPlayerFromArchetype, getArchetypeAssets, getArchetypeBonuses, getPlayerLeadFoot, getPlayerRearFoot, getStanceEffectiveness, getVitalPointByOnPlayerId, hasEnoughResources, initializeBodyFacing, resetPlayerState, toggleStanceSide, updatePlayerState, updateStatusEffects } from "./utils/playerUtils.js";
95
95
  import { createCameraConfig, createPhysicsConfig } from "./utils/sharedPhysicsConfig.js";
96
96
  import { darkenColor, getArchetypeColors, getArchetypeSkinTone, getArchetypeVisualProperties, getColorWithAlpha, getContrastColor, getHealthColor, hexColorToCSS, hexToRgb, hexToRgbaString, interpolateColor, lightenColor, rgbToHex, toHex } from "./utils/colorUtils.js";
97
97
  import { KeyboardHints } from "./components/screens/combat/components/controls/KeyboardHints.js";
98
- import MatchCountdown from "./components/screens/combat/components/feedback/MatchCountdown.js";
99
- import RoundAnnouncement from "./components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js";
100
- import RoundDisplayStatus from "./components/screens/combat/components/feedback/RoundDisplayStatus.js";
101
- import RoundStartAnnouncement from "./components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js";
98
+ import { MatchCountdown } from "./components/screens/combat/components/feedback/MatchCountdown.js";
99
+ import { RoundAnnouncement } from "./components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js";
100
+ import { RoundDisplayStatus } from "./components/screens/combat/components/feedback/RoundDisplayStatus.js";
101
+ import { RoundStartAnnouncement } from "./components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js";
102
102
  import { InputBufferDisplay } from "./components/screens/combat/components/indicators/InputBufferDisplay.js";
103
103
  import { animationStateToPlayerAnimation, convertPlayerStateToProps, getBalanceState, getPlayerAnimation } from "./utils/player3DHelpers.js";
104
104
  import { applyHtmlOverlayStyles, calculateDistanceFactor, calculateSafePosition, createHtmlOverlayConfig, getDefaultSafeArea, getZIndexForLayer, measureTextBounds } from "./utils/htmlOverlayHelpers.js";
105
- import ControlsGuide from "./components/screens/combat/components/controls/ControlsGuide.js";
106
- import QuickSettings from "./components/screens/combat/components/controls/QuickSettings.js";
107
- import PauseMenu from "./components/screens/combat/components/controls/PauseMenu.js";
108
- import TraumaOverlay3D from "./components/screens/combat/components/effects/TraumaOverlay3D.js";
105
+ import { ControlsGuide } from "./components/screens/combat/components/controls/ControlsGuide.js";
106
+ import { QuickSettings } from "./components/screens/combat/components/controls/QuickSettings.js";
107
+ import { PauseMenu } from "./components/screens/combat/components/controls/PauseMenu.js";
108
+ import { TraumaOverlay3D } from "./components/screens/combat/components/effects/TraumaOverlay3D.js";
109
109
  import { DifficultyIndicator } from "./components/screens/combat/components/hud/DifficultyIndicator.js";
110
- import FPSMonitor from "./components/screens/combat/components/hud/FPSMonitor.js";
110
+ import { FPSMonitor } from "./components/screens/combat/components/hud/FPSMonitor.js";
111
111
  import { PainVignette } from "./components/screens/combat/components/effects/PainVignette.js";
112
112
  import { BalanceIndicator } from "./components/screens/combat/components/indicators/BalanceIndicator.js";
113
113
  import { ConsciousnessBlur } from "./components/screens/combat/components/effects/ConsciousnessBlur.js";
@@ -115,12 +115,12 @@ import { BloodLossOverlayHtml } from "./components/screens/combat/components/eff
115
115
  import { StaminaWarning } from "./components/screens/combat/components/indicators/StaminaWarning.js";
116
116
  import { PlayerStateOverlayHtml } from "./components/screens/combat/components/hud/PlayerStateOverlayHtml.js";
117
117
  import { DeviceType, MOBILE_BREAKPOINT, TABLET_BREAKPOINT, clearPlatformCache, detectPlatform, getSafeAreaInsets, isMobileDevice, shouldUseMobileControls } from "./utils/deviceDetection.js";
118
- import CombatScreen3D from "./components/screens/combat/CombatScreen3D.js";
119
- import BloodDecals3D from "./components/screens/combat/components/effects/BloodDecals3D.js";
120
- import BloodParticles3D from "./components/screens/combat/components/effects/BloodParticles3D.js";
121
- import TechniqueNameDisplay from "./components/screens/combat/components/indicators/TechniqueNameDisplay.js";
122
- import CombatControlsPanel from "./components/screens/combat/components/controls/CombatControlsPanel.js";
123
- import MobileControlsWrapper from "./components/screens/combat/components/hud/MobileControlsWrapper.js";
118
+ import { CombatScreen3D } from "./components/screens/combat/CombatScreen3D.js";
119
+ import { BloodDecals3D } from "./components/screens/combat/components/effects/BloodDecals3D.js";
120
+ import { BloodParticles3D } from "./components/screens/combat/components/effects/BloodParticles3D.js";
121
+ import { TechniqueNameDisplay } from "./components/screens/combat/components/indicators/TechniqueNameDisplay.js";
122
+ import { CombatControlsPanel } from "./components/screens/combat/components/controls/CombatControlsPanel.js";
123
+ import { MobileControlsWrapper } from "./components/screens/combat/components/hud/MobileControlsWrapper.js";
124
124
  import { KoreanButton } from "./components/shared/three/ui/KoreanButton.js";
125
125
  import { KoreanPanel } from "./components/shared/three/ui/KoreanPanel.js";
126
126
  import { KoreanText } from "./components/shared/three/ui/KoreanText.js";
@@ -129,9 +129,9 @@ import { ArchetypeCard } from "./components/shared/three/ui/ArchetypeCard.js";
129
129
  import { ProgressBar } from "./components/shared/three/ui/ProgressBar.js";
130
130
  import { TrainingScreen3D } from "./components/screens/training/TrainingScreen3D.js";
131
131
  import { EndScreen3D } from "./components/screens/endscreen/EndScreen3D.js";
132
- import ControlsScreen3D from "./components/screens/controls/ControlsScreen3D.js";
133
- import IntroScreen3D from "./components/screens/intro/IntroScreen3D.js";
134
- import PhilosophyScreen3D from "./components/screens/philosophy/PhilosophyScreen3D.js";
132
+ import { ControlsScreen3D } from "./components/screens/controls/ControlsScreen3D.js";
133
+ import { IntroScreen3D } from "./components/screens/intro/IntroScreen3D.js";
134
+ import { PhilosophyScreen3D } from "./components/screens/philosophy/PhilosophyScreen3D.js";
135
135
  import { components_exports } from "./components/index.js";
136
136
  import { getAssetBasePath, resolveAssetPath, setAssetBasePath } from "./utils/assetConfig.js";
137
137
  import { applyEffectModifiers, calculateEffectIntensity, combineEffects, createEffectFromKoreanText, createHitEffect, createKoreanStatusEffect, createStatusEffect, createTrigramEffect, getEffectDescription, getEffectDisplayText, getEffectDurationModifier, getHitEffectColor, groupEffectsByType, groupEffectsByTypeEnum, isEffectBeneficial, removeExpiredEffects, updateEffect } from "./utils/effectUtils.js";
@@ -5,8 +5,8 @@ import { isWithinHitWindow } from "./animation/core/AnimationHitTiming.js";
5
5
  import { calculateSpeedModifierForDamage, determineAnimationTypeForTechnique, getAdjustedAnimationDuration, getAnimationNameForType } from "./animation/core/TechniqueAnimationMapper.js";
6
6
  import { TRIGRAM_TECHNIQUES } from "./trigram/techniques/index.js";
7
7
  import { getTechniqueById } from "../data/techniques.js";
8
- import KnockbackPhysics from "./physics/KnockbackPhysics.js";
9
- import CollisionDetection from "./physics/CollisionDetection.js";
8
+ import { KnockbackPhysics } from "./physics/KnockbackPhysics.js";
9
+ import { CollisionDetection } from "./physics/CollisionDetection.js";
10
10
  import { physicalReachCalculator } from "./physics/PhysicalReachCalculator.js";
11
11
  import { getArchetypePhysicalAttributes } from "../data/archetypePhysicalAttributes.js";
12
12
  import { calculateBodyRadius } from "../utils/skeletonScaling.js";
@@ -14,14 +14,14 @@ import { applyDamageToBodyParts } from "./bodypart/BodyPartDamageIntegration.js"
14
14
  import { playerInjuryManager } from "./bodypart/PlayerInjuryTrackingManager.js";
15
15
  import { BreathingDisruptionSystem } from "./breathing/BreathingDisruptionSystem.js";
16
16
  import { applyBreathingDisruptionFromTorsoDamage, applyBreathingDisruptionFromVitalPoint, causesBreathingDisruption, updateBreathingDisruption } from "./breathing/integration.js";
17
- import BalanceSystem from "./combat/BalanceSystem.js";
18
- import ConsciousnessSystem from "./combat/ConsciousnessSystem.js";
17
+ import { BalanceSystem } from "./combat/BalanceSystem.js";
18
+ import { ConsciousnessSystem } from "./combat/ConsciousnessSystem.js";
19
19
  import { extractVitalPointCategory, isHeadTraumaHit } from "./combat/painConsciousnessUtils.js";
20
- import PainResponseSystem from "./combat/PainResponseSystem.js";
20
+ import { PainResponseSystem } from "./combat/PainResponseSystem.js";
21
21
  import { addEffectsToPlayer, getEffectModifiers, removeExpiredEffects } from "./PlayerEffectManager.js";
22
- import TrigramSystem from "./TrigramSystem.js";
23
- import VitalPointSystem from "./VitalPointSystem.js";
24
- import GrappleSystem from "./combat/GrappleSystem.js";
22
+ import { TrigramSystem } from "./TrigramSystem.js";
23
+ import { VitalPointSystem } from "./VitalPointSystem.js";
24
+ import { GrappleSystem } from "./combat/GrappleSystem.js";
25
25
  import * as THREE from "three";
26
26
  //#region src/systems/CombatSystem.ts
27
27
  /**
@@ -861,6 +861,6 @@ function createCombatResult(partialResult) {
861
861
  };
862
862
  }
863
863
  //#endregion
864
- export { createCombatResult, CombatSystem as default };
864
+ export { CombatSystem, CombatSystem as default, createCombatResult };
865
865
 
866
866
  //# sourceMappingURL=CombatSystem.js.map
@@ -242,6 +242,6 @@ function applyEffectStacking(currentEffects, newEffects, currentTime) {
242
242
  return activeEffects;
243
243
  }
244
244
  //#endregion
245
- export { applyEffectStacking, convertToStatusEffect };
245
+ export { applyEffectStacking, calculateEffectDuration, calculateEffectIntensity, convertToStatusEffect };
246
246
 
247
247
  //# sourceMappingURL=EffectCalculator.js.map
@@ -493,6 +493,6 @@ var TrigramSystem = class {
493
493
  }
494
494
  };
495
495
  //#endregion
496
- export { COUNTER_STANCE_DAMAGE_MULTIPLIER, STANCE_COUNTERS, applyCounterStanceDamage, TrigramSystem as default };
496
+ export { COUNTER_STANCE_DAMAGE_MULTIPLIER, STANCE_COUNTERS, TrigramSystem, TrigramSystem as default, applyCounterStanceDamage };
497
497
 
498
498
  //# sourceMappingURL=TrigramSystem.js.map
@@ -1,5 +1,5 @@
1
1
  import { PlayerArchetype, TrigramStance, VitalPointSeverity } from "../types/common.js";
2
- import VITAL_POINTS_DATA from "./vitalpoint/VitalPointsData.js";
2
+ import { VITAL_POINTS_DATA } from "./vitalpoint/VitalPointsData.js";
3
3
  import { convertToStatusEffect } from "./EffectCalculator.js";
4
4
  import { getMeridiansForVitalPoint } from "./vitalpoint/MeridianVitalPointMapping.js";
5
5
  import { calculateEnhancedVulnerability, calculateMeridianFlow, generateMeridianEffects } from "./vitalpoint/KoreanAnatomy.js";
@@ -440,6 +440,6 @@ var VitalPointSystem = class {
440
440
  }
441
441
  };
442
442
  //#endregion
443
- export { VitalPointSystem as default };
443
+ export { VitalPointSystem, VitalPointSystem as default };
444
444
 
445
445
  //# sourceMappingURL=VitalPointSystem.js.map
@@ -1,9 +1,9 @@
1
1
  import { PlayerArchetype, TrigramStance } from "../../types/common.js";
2
2
  import { AI_MOVEMENT_METERS } from "../../types/physicsConstants.js";
3
3
  import { getArchetypePhysicalAttributes } from "../../data/archetypePhysicalAttributes.js";
4
- import TrigramSystem from "../TrigramSystem.js";
4
+ import { TrigramSystem } from "../TrigramSystem.js";
5
5
  import { getArchetypeBehavior } from "./AIPersonality.js";
6
- import KOREAN_VITAL_POINTS, { getVitalPointById } from "../vitalpoint/KoreanVitalPoints.js";
6
+ import { KOREAN_VITAL_POINTS, getVitalPointById } from "../vitalpoint/KoreanVitalPoints.js";
7
7
  import { AIActionType } from "./types.js";
8
8
  import { enforceArchetypeBehavior } from "./ArchetypeEnforcer.js";
9
9
  //#region src/systems/ai/DecisionTree.ts
@@ -1514,6 +1514,6 @@ var AIDecisionTree = class AIDecisionTree {
1514
1514
  }
1515
1515
  };
1516
1516
  //#endregion
1517
- export { AIDecisionTree };
1517
+ export { AIActionType, AIDecisionTree };
1518
1518
 
1519
1519
  //# sourceMappingURL=DecisionTree.js.map
@@ -259,6 +259,6 @@ var TrainingAI = class {
259
259
  }
260
260
  };
261
261
  //#endregion
262
- export { TrainingAI as default };
262
+ export { TrainingAI, TrainingAI as default };
263
263
 
264
264
  //# sourceMappingURL=TrainingAI.js.map
@@ -511,6 +511,6 @@ var updateHandAnimationState = (state, targetPose, deltaTime, transitionDuration
511
511
  };
512
512
  };
513
513
  //#endregion
514
- export { createInitialHandAnimationState, getTechniqueHandPose, updateHandAnimationState };
514
+ export { FIST_POSE, GRAPPLING_POSE, HAND_POSES, KNIFE_HAND_POSE, OPEN_POSE, PALM_HEEL_POSE, RELAXED_POSE, SPEAR_HAND_POSE, TECHNIQUE_HAND_POSES, createInitialHandAnimationState, getHandPose, getTechniqueHandPose, interpolateFingerCurl, interpolateFingerSpread, interpolateWristRotation, updateHandAnimationState };
515
515
 
516
516
  //# sourceMappingURL=HandPoses.js.map
@@ -1,4 +1,91 @@
1
1
  import * as THREE from "three";
2
+ //#region src/systems/animation/builders/KeyframeInterpolation.ts
3
+ /**
4
+ * Keyframe interpolation for smooth skeletal animations
5
+ *
6
+ * Provides interpolation between animation keyframes for smooth 60fps playback.
7
+ * Supports linear, ease-in, ease-out, and ease-in-out easing functions.
8
+ *
9
+ * @module systems/animation/KeyframeInterpolation
10
+ * @category Animation System
11
+ * @korean 키프레임보간
12
+ */
13
+ /**
14
+ * Cubic bezier easing for natural movement
15
+ *
16
+ * **Korean**: 3차 베지어 이징
17
+ *
18
+ * Implements cubic bezier curve interpolation for smooth, natural motion.
19
+ * Based on CSS cubic-bezier() function specification.
20
+ *
21
+ * This function uses a configuration object approach for better API clarity.
22
+ * By default, uses simplified approximation (x progresses linearly with t) which
23
+ * provides good results for animation with minimal overhead. Enable precisionMode
24
+ * for exact calculations when needed.
25
+ *
26
+ * @param t - Input time (0-1)
27
+ * @param options - Bezier control points and configuration
28
+ * @returns Eased value
29
+ *
30
+ * @example
31
+ * ```typescript
32
+ * // Natural Korean martial arts movement (physics-based)
33
+ * const eased = cubicBezierWithOptions(0.5, {
34
+ * p1x: 0.25, p1y: 0.1, p2x: 0.25, p2y: 1.0
35
+ * });
36
+ *
37
+ * // With precision mode for exact calculation
38
+ * const precise = cubicBezierWithOptions(0.5, {
39
+ * p1x: 0.42, p1y: 0, p2x: 0.58, p2y: 1.0,
40
+ * precisionMode: true
41
+ * });
42
+ * ```
43
+ *
44
+ * @korean 3차베지어이징옵션
45
+ */
46
+ function cubicBezierWithOptions(t, options) {
47
+ const clampedT = Math.max(0, Math.min(1, t));
48
+ const u = 1 - clampedT;
49
+ return 3 * u * u * clampedT * options.p1y + 3 * u * clampedT * clampedT * options.p2y + clampedT * clampedT * clampedT;
50
+ }
51
+ /**
52
+ * Cubic bezier easing (legacy function signature for backward compatibility)
53
+ *
54
+ * **Korean**: 3차 베지어 이징 (레거시)
55
+ *
56
+ * @param t - Input time (0-1)
57
+ * @param p1x - First control point x (0-1) - currently unused, reserved for precision mode
58
+ * @param p1y - First control point y (can exceed 0-1 for overshoot)
59
+ * @param p2x - Second control point x (0-1) - currently unused, reserved for precision mode
60
+ * @param p2y - Second control point y (can exceed 0-1 for overshoot)
61
+ * @returns Eased value
62
+ *
63
+ * @deprecated Use cubicBezierWithOptions for clearer API
64
+ * @korean 3차베지어이징레거시
65
+ */
66
+ function cubicBezier(t, p1x, p1y, p2x, p2y) {
67
+ return cubicBezierWithOptions(t, {
68
+ p1x,
69
+ p1y,
70
+ p2x,
71
+ p2y
72
+ });
73
+ }
74
+ /**
75
+ * Create a cubic bezier easing function with control points
76
+ *
77
+ * **Korean**: 베지어 이징 함수 생성
78
+ *
79
+ * Factory function to create reusable bezier easing functions.
80
+ *
81
+ * @param points - Bezier control points
82
+ * @returns Easing function
83
+ *
84
+ * @korean 베지어이징함수생성
85
+ */
86
+ function createBezierEasing(points) {
87
+ return (t) => cubicBezier(t, points.p1x, points.p1y, points.p2x, points.p2y);
88
+ }
2
89
  /**
3
90
  * Preset bezier easing curves for Korean martial arts movements
4
91
  *
@@ -184,6 +271,6 @@ var predictFutureKeyframe = (currentKeyframe, predictionState, predictionTime) =
184
271
  };
185
272
  };
186
273
  //#endregion
187
- export { createMotionPredictionState, predictFutureKeyframe, updateMotionPrediction };
274
+ export { BEZIER_PRESETS, createBezierEasing, createMotionPredictionState, cubicBezier, cubicBezierWithOptions, predictFutureKeyframe, updateMotionPrediction };
188
275
 
189
276
  //# sourceMappingURL=KeyframeInterpolation.js.map
@@ -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 * @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 * @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 * @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 * @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 * @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 * @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 * @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 * @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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"}