blacktrigram 0.7.47 → 0.7.49
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.
- package/lib/App2.js.map +1 -1
- package/lib/audio/AudioAssetLoader.js.map +1 -1
- package/lib/audio/AudioAssetRegistry.js.map +1 -1
- package/lib/audio/AudioCache.js.map +1 -1
- package/lib/audio/AudioManager.js.map +1 -1
- package/lib/audio/AudioMonitor.js.map +1 -1
- package/lib/audio/AudioPool.js.map +1 -1
- package/lib/audio/AudioProvider.js.map +1 -1
- package/lib/audio/AudioUtils.js.map +1 -1
- package/lib/audio/BoneImpactAudioMap.js.map +1 -1
- package/lib/audio/VariantSelector.js.map +1 -1
- package/lib/audio/types.js.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.js +29 -25
- package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
- package/lib/components/screens/combat/components/controls/CombatButtons.js.map +1 -1
- package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
- package/lib/components/screens/combat/components/controls/ControlsGuide.js.map +1 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenuButton.js.map +1 -1
- package/lib/components/screens/combat/components/controls/QuickSettings.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
- package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js +2 -2
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js +2 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
- package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
- package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.js +4 -2
- package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
- package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
- package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.js +11 -5
- package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.js +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
- package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
- package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/Key3D.js.map +1 -1
- package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
- package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
- package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
- package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/IntroScreen3D.js +1 -1
- package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
- package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.js +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.js +3 -11
- package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
- package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
- package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js +2 -2
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
- package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.d.ts +1 -0
- package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.js +6 -4
- package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.js +11 -5
- package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
- package/lib/components/shared/base/BaseButton.js.map +1 -1
- package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
- package/lib/components/shared/base/BasePanel.js.map +1 -1
- package/lib/components/shared/base/BaseText.js.map +1 -1
- package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
- package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
- package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
- package/lib/components/shared/mobile/HapticController.js.map +1 -1
- package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
- package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
- package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
- package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
- package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
- package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
- package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
- package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
- package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
- package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
- package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
- package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
- package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
- package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
- package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
- package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
- package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.js +7 -5
- package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
- package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
- package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
- package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
- package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
- package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
- package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
- package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
- package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
- package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
- package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
- package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
- package/lib/components/shared/three/ui/MenuList.js.map +1 -1
- package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
- package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
- package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
- package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
- package/lib/components/shared/ui/BackButton.js.map +1 -1
- package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
- package/lib/components/shared/ui/CombatTimer.js.map +1 -1
- package/lib/components/shared/ui/ErrorModal.js.map +1 -1
- package/lib/components/shared/ui/LoadingState.js.map +1 -1
- package/lib/components/shared/ui/SplashScreen.js +2 -2
- package/lib/components/shared/ui/SplashScreen.js.map +1 -1
- package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
- package/lib/components/shared/ui/VolumeControl.js.map +1 -1
- package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
- package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
- package/lib/constants/bodyDimensions.js.map +1 -1
- package/lib/constants/bodyRenderingConstants.js.map +1 -1
- package/lib/data/archetypeClothing.js.map +1 -1
- package/lib/data/archetypePhysicalAttributes.js.map +1 -1
- package/lib/data/techniqueMappings.js.map +1 -1
- package/lib/data/techniques.js.map +1 -1
- package/lib/hooks/useActionFeedback.js.map +1 -1
- package/lib/hooks/useBalanceAnimations.js.map +1 -1
- package/lib/hooks/useCombatTimer.js.map +1 -1
- package/lib/hooks/useDebounce.js.map +1 -1
- package/lib/hooks/useHUDLayout.d.ts.map +1 -1
- package/lib/hooks/useHUDLayout.js +3 -2
- package/lib/hooks/useHUDLayout.js.map +1 -1
- package/lib/hooks/useHandPoseTransitions.js.map +1 -1
- package/lib/hooks/useKeyboardControls.js.map +1 -1
- package/lib/hooks/useMatchCountdown.js.map +1 -1
- package/lib/hooks/useMuscleActivation.js.map +1 -1
- package/lib/hooks/usePauseMenu.js.map +1 -1
- package/lib/hooks/usePlayerAnimation.js.map +1 -1
- package/lib/hooks/useResponsiveLayout.js.map +1 -1
- package/lib/hooks/useRoundTransition.js.map +1 -1
- package/lib/hooks/useSkeletalAnimation.d.ts.map +1 -1
- package/lib/hooks/useSkeletalAnimation.js +1 -1
- package/lib/hooks/useSkeletalAnimation.js.map +1 -1
- package/lib/hooks/useTechniqueSelection.js.map +1 -1
- package/lib/hooks/useThrottle.js.map +1 -1
- package/lib/hooks/useTouchControls.js.map +1 -1
- package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
- package/lib/hooks/useWindowSize.js.map +1 -1
- package/lib/systems/CombatSystem.js.map +1 -1
- package/lib/systems/EffectCalculator.js.map +1 -1
- package/lib/systems/LayoutSystem.js.map +1 -1
- package/lib/systems/PlayerEffectManager.js.map +1 -1
- package/lib/systems/ResponsiveScaling.js.map +1 -1
- package/lib/systems/TrigramSystem.js.map +1 -1
- package/lib/systems/VitalPointSystem.js.map +1 -1
- package/lib/systems/ai/AIPersonality.js.map +1 -1
- package/lib/systems/ai/AdaptiveDifficulty.js +16 -16
- package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
- package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
- package/lib/systems/ai/ComboSystem.js.map +1 -1
- package/lib/systems/ai/DecisionTree.js.map +1 -1
- package/lib/systems/ai/TrainingAI.js.map +1 -1
- package/lib/systems/ai/types.js.map +1 -1
- package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
- package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/HandPoses.js.map +1 -1
- package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
- package/lib/systems/animation/builders/KickPhaseApplicator.d.ts +6 -0
- package/lib/systems/animation/builders/KickPhaseApplicator.d.ts.map +1 -1
- package/lib/systems/animation/builders/KickPhaseApplicator.js +16 -9
- package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/KoreanGuardPositions.d.ts +4 -4
- package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
- package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts +1 -1
- package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts.map +1 -1
- package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js +5 -5
- package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
- package/lib/systems/animation/builders/MartialArtsConstants.d.ts +112 -71
- package/lib/systems/animation/builders/MartialArtsConstants.d.ts.map +1 -1
- package/lib/systems/animation/builders/MartialArtsConstants.js +113 -72
- package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
- package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
- package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
- package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/EnhancedAttackAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/EnhancedElbowKneeAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/GamStanceAnimations.js +21 -0
- package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -0
- package/lib/systems/animation/catalogs/GamTechniqueAnimations.js +34 -2
- package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts +9 -0
- package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts.map +1 -1
- package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +288 -0
- package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -0
- package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/KickAnimations.d.ts +2 -2
- package/lib/systems/animation/catalogs/KickAnimations.js +2 -2
- package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/LiStanceAnimations.js +14 -1
- package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/PunchAnimations.d.ts +1 -1
- package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
- package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceGuardPoses.d.ts +6 -6
- package/lib/systems/animation/catalogs/StanceGuardPoses.js +36 -36
- package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
- package/lib/systems/animation/constants/AnatomicalLimits.js.map +1 -1
- package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
- package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
- package/lib/systems/animation/core/AnimationPriority.js +15 -15
- package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
- package/lib/systems/animation/core/AnimationRegistry.d.ts +30 -0
- package/lib/systems/animation/core/AnimationRegistry.d.ts.map +1 -1
- package/lib/systems/animation/core/AnimationRegistry.js +74 -12
- package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
- package/lib/systems/animation/core/AnimationStateMachine.js +16 -16
- package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.js +34 -0
- package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
- package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
- package/lib/systems/animation/core/index.d.ts +1 -1
- package/lib/systems/animation/core/index.d.ts.map +1 -1
- package/lib/systems/animation/core/types.d.ts +24 -0
- package/lib/systems/animation/core/types.d.ts.map +1 -1
- package/lib/systems/animation/core/types.js +27 -11
- package/lib/systems/animation/core/types.js.map +1 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
- package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
- package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
- package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
- package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
- package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
- package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
- package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
- package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
- package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
- package/lib/systems/bodypart/types.js.map +1 -1
- package/lib/systems/breathing/BreathingDisruptionSystem.js +19 -19
- package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
- package/lib/systems/breathing/feedback.js.map +1 -1
- package/lib/systems/breathing/integration.js.map +1 -1
- package/lib/systems/combat/BalanceSystem.js +19 -19
- package/lib/systems/combat/BalanceSystem.js.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
- package/lib/systems/combat/CombatStateSystem.js +17 -17
- package/lib/systems/combat/CombatStateSystem.js.map +1 -1
- package/lib/systems/combat/ConsciousnessSystem.js +24 -24
- package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
- package/lib/systems/combat/FallIntegration.js.map +1 -1
- package/lib/systems/combat/GrappleSystem.js.map +1 -1
- package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
- package/lib/systems/combat/PainResponseSystem.js +21 -21
- package/lib/systems/combat/PainResponseSystem.js.map +1 -1
- package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
- package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
- package/lib/systems/combat/typeGuards.js.map +1 -1
- package/lib/systems/effects.js.map +1 -1
- package/lib/systems/game.js.map +1 -1
- package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
- package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
- package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
- package/lib/systems/movement/integration.js.map +1 -1
- package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
- package/lib/systems/physics/CollisionDetection.js.map +1 -1
- package/lib/systems/physics/CoordinateMapper.js.map +1 -1
- package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
- package/lib/systems/physics/MovementPhysics.js.map +1 -1
- package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
- package/lib/systems/physics/SpeedModifierSystem.js +6 -6
- package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
- package/lib/systems/trigram/KoreanCulture.js.map +1 -1
- package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
- package/lib/systems/trigram/StanceManager.js.map +1 -1
- package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
- package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
- package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GeonTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/JinTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/LiTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/TaeTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
- package/lib/systems/trigram/techniques/index.js.map +1 -1
- package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
- package/lib/systems/trigram/types.js.map +1 -1
- package/lib/systems/types.js.map +1 -1
- package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
- package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
- package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
- package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
- package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
- package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
- package/lib/types/AccessibilityTypes.js.map +1 -1
- package/lib/types/LayoutTypes.js.map +1 -1
- package/lib/types/PhysicsTypes.js.map +1 -1
- package/lib/types/common.js.map +1 -1
- package/lib/types/constants/animations.js.map +1 -1
- package/lib/types/constants/colors.js.map +1 -1
- package/lib/types/constants/designSystem.js.map +1 -1
- package/lib/types/constants/index.js.map +1 -1
- package/lib/types/constants/layout.d.ts +21 -0
- package/lib/types/constants/layout.d.ts.map +1 -1
- package/lib/types/constants/layout.js +22 -1
- package/lib/types/constants/layout.js.map +1 -1
- package/lib/types/constants/performance.js.map +1 -1
- package/lib/types/constants/typography.js.map +1 -1
- package/lib/types/constants/ui.js.map +1 -1
- package/lib/types/facial.js +19 -19
- package/lib/types/facial.js.map +1 -1
- package/lib/types/hand-animation.js.map +1 -1
- package/lib/types/injury.js.map +1 -1
- package/lib/types/muscle.js.map +1 -1
- package/lib/types/physics.js.map +1 -1
- package/lib/types/physicsConstants.js.map +1 -1
- package/lib/types/player-visual.d.ts +1 -1
- package/lib/types/player-visual.d.ts.map +1 -1
- package/lib/types/skeletal.js.map +1 -1
- package/lib/types/techniqueId.js.map +1 -1
- package/lib/utils/accessibility.js.map +1 -1
- package/lib/utils/arenaWorldDimensions.js.map +1 -1
- package/lib/utils/assetConfig.js.map +1 -1
- package/lib/utils/characterScaling.js.map +1 -1
- package/lib/utils/colorHelpers.js.map +1 -1
- package/lib/utils/colorUtils.js.map +1 -1
- package/lib/utils/combatReadiness.js.map +1 -1
- package/lib/utils/controlMapping.js.map +1 -1
- package/lib/utils/deviceDetection.js +6 -7
- package/lib/utils/deviceDetection.js.map +1 -1
- package/lib/utils/effectUtils.js.map +1 -1
- package/lib/utils/fabricTextures.js.map +1 -1
- package/lib/utils/hapticFeedback.js.map +1 -1
- package/lib/utils/haptics.js.map +1 -1
- package/lib/utils/htmlOverlayHelpers.js.map +1 -1
- package/lib/utils/inputSystem.js.map +1 -1
- package/lib/utils/koreanThemeHelpers.js.map +1 -1
- package/lib/utils/math.js.map +1 -1
- package/lib/utils/mobileLayoutHelpers.js.map +1 -1
- package/lib/utils/mobileUIUtils.js.map +1 -1
- package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
- package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
- package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
- package/lib/utils/performanceOptimization.js.map +1 -1
- package/lib/utils/player3DHelpers.js.map +1 -1
- package/lib/utils/playerUtils.js.map +1 -1
- package/lib/utils/responsiveLayout.js.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.d.ts +7 -0
- package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.js +16 -2
- package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
- package/lib/utils/responsiveOrientationConstants.js.map +1 -1
- package/lib/utils/safeAreaUtils.js.map +1 -1
- package/lib/utils/sharedPhysicsConfig.js.map +1 -1
- package/lib/utils/skeletonScaling.js.map +1 -1
- package/lib/utils/stanceHelpers.js.map +1 -1
- package/lib/utils/threeObjectPool.js.map +1 -1
- package/lib/utils/visualEffects.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SkeletonRig.js","names":[],"sources":["../../../../src/systems/animation/builders/SkeletonRig.ts"],"sourcesContent":["/**\n * Skeleton rig implementation for articulated body model\n *\n * Creates and manages humanoid skeletal rig with 28 bones for realistic\n * martial arts animations. Implements bone hierarchy following Korean martial\n * arts body mechanics.\n *\n * Now supports dynamic scaling based on player physical attributes for\n * anatomically accurate body proportions per archetype.\n *\n * @module systems/animation/SkeletonRig\n * @category Animation System\n * @korean 골격시스템\n */\n\nimport { PhysicalAttributes } from \"@/types/common\";\nimport type {\n Bone,\n BoneChain,\n JointConstraint,\n SkeletalRig,\n} from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport {\n calculateSkeletonDimensions,\n cmToMeters,\n} from \"@/utils/characterScaling\";\nimport * as THREE from \"three\";\n\n/**\n * Create a bone with default rest pose\n *\n * Helper function to create a bone with position, rotation, and scale.\n * Sets up rest pose for animation blending.\n *\n * @param name - Unique bone identifier\n * @param parent - Parent bone (null for root)\n * @param position - Local position relative to parent [x, y, z]\n * @param length - Bone length for rendering\n * @returns Newly created bone\n *\n * @korean 뼈생성\n */\nexport const createBone = (\n name: string,\n parent: Bone | null,\n position: [number, number, number],\n length = 0.1,\n): Bone => {\n const pos = new THREE.Vector3(position[0], position[1], position[2]);\n const rot = new THREE.Euler(0, 0, 0);\n const scale = new THREE.Vector3(1, 1, 1);\n\n const bone: Bone = {\n name,\n parent,\n position: pos.clone(),\n rotation: rot.clone(),\n scale: scale.clone(),\n children: [],\n length,\n restPosition: pos.clone(),\n restRotation: rot.clone(),\n };\n\n // Add to parent's children\n if (parent) {\n parent.children.push(bone);\n }\n\n return bone;\n};\n\n/**\n * Create complete humanoid skeletal rig\n *\n * Creates 28-bone humanoid skeleton following Korean martial arts anatomy:\n * - 1 root (pelvis)\n * - 3 spine bones\n * - 2 head bones (neck, head)\n * - 12 arm bones (6 per arm)\n * - 10 leg bones (5 per leg)\n *\n * Total: 28 bones (under 30 bone limit for 60fps performance)\n *\n * @returns Complete skeletal rig with bone hierarchy\n *\n * @example\n * ```typescript\n * const rig = createHumanoidRig();\n * const rightHand = rig.bones.get(BoneName.HAND_R);\n * console.log(`Hand position: ${rightHand?.position}`);\n * ```\n *\n * @korean 인간형골격생성\n */\nexport const createHumanoidRig = (): SkeletalRig => {\n // Root (pelvis) - center of mass at hip height\n // Pelvis height = sum of leg segments (hip + thigh + knee + shin + foot)\n // = 0.1 + 0.3 + 0.3 + 0.3 + 0.1 = 1.1 to have feet at Y=0\n const root = createBone(BoneName.PELVIS, null, [0, 1.1, 0], 0.15);\n\n // Spine chain (3 bones)\n const spine1 = createBone(BoneName.SPINE_LOWER, root, [0, 0.15, 0], 0.2);\n const spine2 = createBone(BoneName.SPINE_MIDDLE, spine1, [0, 0.2, 0], 0.2);\n const spine3 = createBone(BoneName.SPINE_UPPER, spine2, [0, 0.2, 0], 0.2);\n\n // Head chain (2 bones)\n const neck = createBone(BoneName.NECK, spine3, [0, 0.15, 0], 0.1);\n const head = createBone(BoneName.HEAD, neck, [0, 0.2, 0], 0.2);\n\n // Left arm chain (6 bones)\n const leftShoulder = createBone(\n BoneName.SHOULDER_L,\n spine3,\n [-0.15, 0.1, 0],\n 0.1,\n );\n const leftUpperArm = createBone(\n BoneName.UPPER_ARM_L,\n leftShoulder,\n [-0.15, 0, 0],\n 0.25,\n );\n const leftElbow = createBone(\n BoneName.ELBOW_L,\n leftUpperArm,\n [-0.25, 0, 0],\n 0.05,\n );\n const leftForearm = createBone(\n BoneName.FOREARM_L,\n leftElbow,\n [-0.25, 0, 0],\n 0.25,\n );\n const leftWrist = createBone(\n BoneName.WRIST_L,\n leftForearm,\n [-0.15, 0, 0],\n 0.05,\n );\n const leftHand = createBone(BoneName.HAND_L, leftWrist, [-0.08, 0, 0], 0.08);\n\n // Right arm chain (6 bones - mirror of left)\n const rightShoulder = createBone(\n BoneName.SHOULDER_R,\n spine3,\n [0.15, 0.1, 0],\n 0.1,\n );\n const rightUpperArm = createBone(\n BoneName.UPPER_ARM_R,\n rightShoulder,\n [0.15, 0, 0],\n 0.25,\n );\n const rightElbow = createBone(\n BoneName.ELBOW_R,\n rightUpperArm,\n [0.25, 0, 0],\n 0.05,\n );\n const rightForearm = createBone(\n BoneName.FOREARM_R,\n rightElbow,\n [0.25, 0, 0],\n 0.25,\n );\n const rightWrist = createBone(\n BoneName.WRIST_R,\n rightForearm,\n [0.15, 0, 0],\n 0.05,\n );\n const rightHand = createBone(BoneName.HAND_R, rightWrist, [0.08, 0, 0], 0.08);\n\n // Left leg chain (5 bones)\n const leftHip = createBone(BoneName.HIP_L, root, [-0.1, -0.1, 0], 0.1);\n const leftThigh = createBone(BoneName.THIGH_L, leftHip, [0, -0.3, 0], 0.3);\n const leftKnee = createBone(BoneName.KNEE_L, leftThigh, [0, -0.3, 0], 0.05);\n const leftShin = createBone(BoneName.SHIN_L, leftKnee, [0, -0.3, 0], 0.3);\n const leftFoot = createBone(BoneName.FOOT_L, leftShin, [0, -0.1, 0.1], 0.15);\n\n // Right leg chain (5 bones - mirror of left)\n const rightHip = createBone(BoneName.HIP_R, root, [0.1, -0.1, 0], 0.1);\n const rightThigh = createBone(BoneName.THIGH_R, rightHip, [0, -0.3, 0], 0.3);\n const rightKnee = createBone(BoneName.KNEE_R, rightThigh, [0, -0.3, 0], 0.05);\n const rightShin = createBone(BoneName.SHIN_R, rightKnee, [0, -0.3, 0], 0.3);\n const rightFoot = createBone(\n BoneName.FOOT_R,\n rightShin,\n [0, -0.1, 0.1],\n 0.15,\n );\n\n // Create bone map for fast lookup\n const bones = new Map<string, Bone>([\n [BoneName.PELVIS, root],\n [BoneName.SPINE_LOWER, spine1],\n [BoneName.SPINE_MIDDLE, spine2],\n [BoneName.SPINE_UPPER, spine3],\n [BoneName.NECK, neck],\n [BoneName.HEAD, head],\n [BoneName.SHOULDER_L, leftShoulder],\n [BoneName.UPPER_ARM_L, leftUpperArm],\n [BoneName.ELBOW_L, leftElbow],\n [BoneName.FOREARM_L, leftForearm],\n [BoneName.WRIST_L, leftWrist],\n [BoneName.HAND_L, leftHand],\n [BoneName.SHOULDER_R, rightShoulder],\n [BoneName.UPPER_ARM_R, rightUpperArm],\n [BoneName.ELBOW_R, rightElbow],\n [BoneName.FOREARM_R, rightForearm],\n [BoneName.WRIST_R, rightWrist],\n [BoneName.HAND_R, rightHand],\n [BoneName.HIP_L, leftHip],\n [BoneName.THIGH_L, leftThigh],\n [BoneName.KNEE_L, leftKnee],\n [BoneName.SHIN_L, leftShin],\n [BoneName.FOOT_L, leftFoot],\n [BoneName.HIP_R, rightHip],\n [BoneName.THIGH_R, rightThigh],\n [BoneName.KNEE_R, rightKnee],\n [BoneName.SHIN_R, rightShin],\n [BoneName.FOOT_R, rightFoot],\n ]);\n\n return {\n root,\n bones,\n boneCount: bones.size,\n };\n};\n\n/**\n * Create humanoid rig with dynamic scaling based on physical attributes.\n *\n * **Korean**: 신체 속성 기반 골격 생성 (Physical Attributes-Based Skeleton Creation)\n *\n * Creates a 28-bone humanoid skeleton with bone lengths scaled according to\n * the fighter's physical attributes. This allows each archetype to have\n * anatomically accurate body proportions that affect combat hitboxes, vital\n * point positioning, and visual representation.\n *\n * ## Visual Amplification\n *\n * The scaling system applies amplification factors to create distinct visual\n * silhouettes while maintaining anatomical realism:\n *\n * - **2.5x limb amplification**: Makes reach differences clearly visible\n * - **1.15x shoulder amplification**: Creates recognizable body width differences\n * - **1.5x height amplification**: Subtle overall size differences\n *\n * ### Archetype Silhouettes Created\n *\n * The following table shows the effective shoulder span after amplification\n * (full span = offset * 2). Values show raw attribute → amplified visual span.\n *\n * | Archetype | Shoulders (Raw → Amplified Span) | Height | Silhouette |\n * |-----------|----------------------------------|--------|------------|\n * | Hacker | 43cm → 49.5cm | 175cm | Compact, narrow |\n * | Amsalja | 44cm → 50.6cm | 186cm | Tall, lean |\n * | Jeongbo | 45cm → 51.8cm | 179cm | Balanced |\n * | Musa | 46cm → 52.9cm | 180cm | Athletic |\n * | Jojik | 54cm → 62.1cm | 188cm | Massive, wide |\n *\n * Note: Amplified span = raw width * 1.15 (shoulder amplification factor)\n * Percentage differences remain constant, but absolute gaps are amplified:\n * - Raw gap: Jojik (54cm) - Hacker (43cm) = 11cm\n * - Amplified gap: 62.1cm - 49.5cm = 12.6cm (15% larger absolute difference)\n *\n * @param attributes - Physical attributes to scale the skeleton\n * @returns Complete skeletal rig with scaled bone dimensions\n *\n * @example\n * ```typescript\n * import { AMSALJA_PHYSICAL } from \"@/data/archetypePhysicalAttributes\";\n *\n * // Create skeleton for lean assassin archetype\n * const amsaljaRig = createScaledHumanoidRig(AMSALJA_PHYSICAL);\n * // Results in taller skeleton with longer limbs, narrower shoulders\n * // Height: 186cm, Legs: 102cm, Arms: 82cm, Shoulders: 44cm\n *\n * // Create skeleton for heavy brawler archetype\n * const jojikRig = createScaledHumanoidRig(JOJIK_PHYSICAL);\n * // Results in stockier skeleton with wider shoulders, thicker torso\n * // Height: 188cm, Legs: 100cm, Arms: 84cm, Shoulders: 54cm (25% wider!)\n * ```\n *\n * @korean 크기조정된인간형골격생성\n */\nexport const createScaledHumanoidRig = (\n attributes: PhysicalAttributes,\n): SkeletalRig => {\n // Calculate anatomically correct bone dimensions in meters\n const dims = calculateSkeletonDimensions(attributes);\n\n // Calculate shoulder offset (half of shoulder width) in meters\n const shoulderOffsetMeters = cmToMeters(attributes.shoulderWidth) / 2;\n const hipOffsetMeters = cmToMeters(attributes.shoulderWidth) * 0.35; // Hips are ~70% of shoulder width\n\n // Root (pelvis) - position at pelvis height (ground + leg length + foot)\n // This ensures feet are at Y=0\n const root = createBone(\n BoneName.PELVIS,\n null,\n [0, dims.pelvisHeight, 0],\n dims.hip,\n );\n\n // Spine chain (3 bones) - using actual torso segment lengths\n const spine1 = createBone(\n BoneName.SPINE_LOWER,\n root,\n [0, dims.spineLower * 0.5, 0], // Start half a segment up from pelvis\n dims.spineLower,\n );\n const spine2 = createBone(\n BoneName.SPINE_MIDDLE,\n spine1,\n [0, dims.spineMiddle, 0],\n dims.spineMiddle,\n );\n const spine3 = createBone(\n BoneName.SPINE_UPPER,\n spine2,\n [0, dims.spineUpper, 0],\n dims.spineUpper,\n );\n\n // Head chain (2 bones) - using actual neck and head sizes\n const neck = createBone(\n BoneName.NECK,\n spine3,\n [0, dims.neck * 0.5, 0], // Start from top of spine\n dims.neck,\n );\n const head = createBone(\n BoneName.HEAD,\n neck,\n [0, dims.head * 0.75, 0], // Head center offset\n dims.head,\n );\n\n // Left arm chain (6 bones) - using actual arm segment lengths\n const leftShoulder = createBone(\n BoneName.SHOULDER_L,\n spine3,\n [-shoulderOffsetMeters * 0.7, dims.neck * 0.3, 0], // Shoulder starts inward from edge\n dims.shoulder,\n );\n const leftUpperArm = createBone(\n BoneName.UPPER_ARM_L,\n leftShoulder,\n [-dims.shoulder, 0, 0], // Extend outward by shoulder length\n dims.upperArm,\n );\n const leftElbow = createBone(\n BoneName.ELBOW_L,\n leftUpperArm,\n [-dims.upperArm, 0, 0], // End of upper arm\n dims.elbow,\n );\n const leftForearm = createBone(\n BoneName.FOREARM_L,\n leftElbow,\n [-dims.elbow, 0, 0], // Past elbow joint\n dims.forearm,\n );\n const leftWrist = createBone(\n BoneName.WRIST_L,\n leftForearm,\n [-dims.forearm, 0, 0], // End of forearm\n dims.wrist,\n );\n const leftHand = createBone(\n BoneName.HAND_L,\n leftWrist,\n [-dims.wrist, 0, 0], // Past wrist\n dims.hand,\n );\n\n // Right arm chain (6 bones - mirror of left)\n const rightShoulder = createBone(\n BoneName.SHOULDER_R,\n spine3,\n [shoulderOffsetMeters * 0.7, dims.neck * 0.3, 0],\n dims.shoulder,\n );\n const rightUpperArm = createBone(\n BoneName.UPPER_ARM_R,\n rightShoulder,\n [dims.shoulder, 0, 0],\n dims.upperArm,\n );\n const rightElbow = createBone(\n BoneName.ELBOW_R,\n rightUpperArm,\n [dims.upperArm, 0, 0],\n dims.elbow,\n );\n const rightForearm = createBone(\n BoneName.FOREARM_R,\n rightElbow,\n [dims.elbow, 0, 0],\n dims.forearm,\n );\n const rightWrist = createBone(\n BoneName.WRIST_R,\n rightForearm,\n [dims.forearm, 0, 0],\n dims.wrist,\n );\n const rightHand = createBone(\n BoneName.HAND_R,\n rightWrist,\n [dims.wrist, 0, 0],\n dims.hand,\n );\n\n // Left leg chain (5 bones) - using actual leg segment lengths\n const leftHip = createBone(\n BoneName.HIP_L,\n root,\n [-hipOffsetMeters, -dims.hip * 0.5, 0],\n dims.hip,\n );\n const leftThigh = createBone(\n BoneName.THIGH_L,\n leftHip,\n [0, -dims.hip, 0], // Drop down from hip\n dims.thigh,\n );\n const leftKnee = createBone(\n BoneName.KNEE_L,\n leftThigh,\n [0, -dims.thigh, 0], // End of thigh\n dims.knee,\n );\n const leftShin = createBone(\n BoneName.SHIN_L,\n leftKnee,\n [0, -dims.knee, 0], // Past knee\n dims.shin,\n );\n const leftFoot = createBone(\n BoneName.FOOT_L,\n leftShin,\n [0, -dims.shin, dims.foot * 0.5], // End of shin, slight forward for foot\n dims.foot,\n );\n\n // Right leg chain (5 bones - mirror of left)\n const rightHip = createBone(\n BoneName.HIP_R,\n root,\n [hipOffsetMeters, -dims.hip * 0.5, 0],\n dims.hip,\n );\n const rightThigh = createBone(\n BoneName.THIGH_R,\n rightHip,\n [0, -dims.hip, 0],\n dims.thigh,\n );\n const rightKnee = createBone(\n BoneName.KNEE_R,\n rightThigh,\n [0, -dims.thigh, 0],\n dims.knee,\n );\n const rightShin = createBone(\n BoneName.SHIN_R,\n rightKnee,\n [0, -dims.knee, 0],\n dims.shin,\n );\n const rightFoot = createBone(\n BoneName.FOOT_R,\n rightShin,\n [0, -dims.shin, dims.foot * 0.5],\n dims.foot,\n );\n\n // Create bone map for fast lookup\n const bones = new Map<string, Bone>([\n [BoneName.PELVIS, root],\n [BoneName.SPINE_LOWER, spine1],\n [BoneName.SPINE_MIDDLE, spine2],\n [BoneName.SPINE_UPPER, spine3],\n [BoneName.NECK, neck],\n [BoneName.HEAD, head],\n [BoneName.SHOULDER_L, leftShoulder],\n [BoneName.UPPER_ARM_L, leftUpperArm],\n [BoneName.ELBOW_L, leftElbow],\n [BoneName.FOREARM_L, leftForearm],\n [BoneName.WRIST_L, leftWrist],\n [BoneName.HAND_L, leftHand],\n [BoneName.SHOULDER_R, rightShoulder],\n [BoneName.UPPER_ARM_R, rightUpperArm],\n [BoneName.ELBOW_R, rightElbow],\n [BoneName.FOREARM_R, rightForearm],\n [BoneName.WRIST_R, rightWrist],\n [BoneName.HAND_R, rightHand],\n [BoneName.HIP_L, leftHip],\n [BoneName.THIGH_L, leftThigh],\n [BoneName.KNEE_L, leftKnee],\n [BoneName.SHIN_L, leftShin],\n [BoneName.FOOT_L, leftFoot],\n [BoneName.HIP_R, rightHip],\n [BoneName.THIGH_R, rightThigh],\n [BoneName.KNEE_R, rightKnee],\n [BoneName.SHIN_R, rightShin],\n [BoneName.FOOT_R, rightFoot],\n ]);\n\n return {\n root,\n bones,\n boneCount: bones.size,\n };\n};\n\n/**\n * Joint constraints for anatomically correct movement\n *\n * Defines rotation limits for each joint to prevent unrealistic poses.\n * Based on human anatomy and Korean martial arts biomechanics.\n *\n * @korean 관절제약조건들\n */\nexport const JOINT_CONSTRAINTS: JointConstraint[] = [\n // Elbow joints - can only bend one direction\n {\n boneName: BoneName.ELBOW_L,\n minRotation: new THREE.Vector3(0, 0, -2.4), // ~-137 degrees\n maxRotation: new THREE.Vector3(0, 0, 0),\n canTwist: false,\n },\n {\n boneName: BoneName.ELBOW_R,\n minRotation: new THREE.Vector3(0, 0, 0),\n maxRotation: new THREE.Vector3(0, 0, 2.4), // ~137 degrees\n canTwist: false,\n },\n\n // Knee joints - can only bend backward\n {\n boneName: BoneName.KNEE_L,\n minRotation: new THREE.Vector3(-2.4, 0, 0), // ~-137 degrees\n maxRotation: new THREE.Vector3(0, 0, 0),\n canTwist: false,\n },\n {\n boneName: BoneName.KNEE_R,\n minRotation: new THREE.Vector3(-2.4, 0, 0), // ~-137 degrees\n maxRotation: new THREE.Vector3(0, 0, 0),\n canTwist: false,\n },\n\n // Shoulder joints - full range of motion\n {\n boneName: BoneName.SHOULDER_L,\n minRotation: new THREE.Vector3(-1.5, -1.5, -3.0),\n maxRotation: new THREE.Vector3(1.5, 1.5, 3.0),\n canTwist: true,\n },\n {\n boneName: BoneName.SHOULDER_R,\n minRotation: new THREE.Vector3(-1.5, -1.5, -3.0),\n maxRotation: new THREE.Vector3(1.5, 1.5, 3.0),\n canTwist: true,\n },\n\n // Hip joints - large range for kicks\n {\n boneName: BoneName.HIP_L,\n minRotation: new THREE.Vector3(-1.8, -0.8, -1.5),\n maxRotation: new THREE.Vector3(1.8, 0.8, 1.5),\n canTwist: true,\n },\n {\n boneName: BoneName.HIP_R,\n minRotation: new THREE.Vector3(-1.8, -0.8, -1.5),\n maxRotation: new THREE.Vector3(1.8, 0.8, 1.5),\n canTwist: true,\n },\n\n // Neck - moderate range\n {\n boneName: BoneName.NECK,\n minRotation: new THREE.Vector3(-0.5, -0.8, -0.5),\n maxRotation: new THREE.Vector3(0.5, 0.8, 0.5),\n canTwist: true,\n },\n\n // Spine bones - limited rotation for realism\n {\n boneName: BoneName.SPINE_LOWER,\n minRotation: new THREE.Vector3(-0.3, -0.5, -0.3),\n maxRotation: new THREE.Vector3(0.3, 0.5, 0.3),\n canTwist: true,\n },\n {\n boneName: BoneName.SPINE_MIDDLE,\n minRotation: new THREE.Vector3(-0.3, -0.5, -0.3),\n maxRotation: new THREE.Vector3(0.3, 0.5, 0.3),\n canTwist: true,\n },\n {\n boneName: BoneName.SPINE_UPPER,\n minRotation: new THREE.Vector3(-0.3, -0.5, -0.3),\n maxRotation: new THREE.Vector3(0.3, 0.5, 0.3),\n canTwist: true,\n },\n];\n\n/**\n * Bone chains for IK (Inverse Kinematics)\n *\n * Defines logical bone chains for limbs, used for IK solving\n * and animation retargeting.\n *\n * @korean 뼈체인들\n */\nexport const BONE_CHAINS: BoneChain[] = [\n // Left arm chain\n {\n name: \"left_arm\",\n startBone: BoneName.SHOULDER_L,\n endBone: BoneName.HAND_L,\n bones: [\n BoneName.SHOULDER_L,\n BoneName.UPPER_ARM_L,\n BoneName.ELBOW_L,\n BoneName.FOREARM_L,\n BoneName.WRIST_L,\n BoneName.HAND_L,\n ],\n },\n\n // Right arm chain\n {\n name: \"right_arm\",\n startBone: BoneName.SHOULDER_R,\n endBone: BoneName.HAND_R,\n bones: [\n BoneName.SHOULDER_R,\n BoneName.UPPER_ARM_R,\n BoneName.ELBOW_R,\n BoneName.FOREARM_R,\n BoneName.WRIST_R,\n BoneName.HAND_R,\n ],\n },\n\n // Left leg chain\n {\n name: \"left_leg\",\n startBone: BoneName.HIP_L,\n endBone: BoneName.FOOT_L,\n bones: [\n BoneName.HIP_L,\n BoneName.THIGH_L,\n BoneName.KNEE_L,\n BoneName.SHIN_L,\n BoneName.FOOT_L,\n ],\n },\n\n // Right leg chain\n {\n name: \"right_leg\",\n startBone: BoneName.HIP_R,\n endBone: BoneName.FOOT_R,\n bones: [\n BoneName.HIP_R,\n BoneName.THIGH_R,\n BoneName.KNEE_R,\n BoneName.SHIN_R,\n BoneName.FOOT_R,\n ],\n },\n\n // Spine chain\n {\n name: \"spine\",\n startBone: BoneName.PELVIS,\n endBone: BoneName.HEAD,\n bones: [\n BoneName.PELVIS,\n BoneName.SPINE_LOWER,\n BoneName.SPINE_MIDDLE,\n BoneName.SPINE_UPPER,\n BoneName.NECK,\n BoneName.HEAD,\n ],\n },\n];\n\n/**\n * Apply joint constraints to bone rotation\n *\n * Clamps bone rotation to anatomically correct ranges.\n * Prevents unrealistic poses like backward-bending elbows.\n *\n * @param bone - Bone to constrain\n * @param constraints - Joint constraint to apply\n *\n * @korean 관절제약적용\n */\nexport const applyJointConstraint = (\n bone: Bone,\n constraint: JointConstraint,\n): void => {\n // Clamp X rotation\n bone.rotation.x = Math.max(\n constraint.minRotation.x,\n Math.min(constraint.maxRotation.x, bone.rotation.x),\n );\n\n // Clamp Y rotation\n bone.rotation.y = Math.max(\n constraint.minRotation.y,\n Math.min(constraint.maxRotation.y, bone.rotation.y),\n );\n\n // Clamp Z rotation\n bone.rotation.z = Math.max(\n constraint.minRotation.z,\n Math.min(constraint.maxRotation.z, bone.rotation.z),\n );\n};\n\n// Reusable matrix objects for world transform calculations (avoid allocations in useFrame)\nconst tempMatrix = new THREE.Matrix4();\nconst tempQuaternion = new THREE.Quaternion();\nconst tempScale = new THREE.Vector3();\n\n/**\n * Get world position of bone\n *\n * Calculates absolute world position by traversing parent chain.\n * Uses proper matrix multiplication to account for parent rotations.\n *\n * @param bone - Bone to get world position for\n * @returns World position as Vector3\n *\n * @korean 뼈의세계위치구하기\n */\nexport const getBoneWorldPosition = (bone: Bone): THREE.Vector3 => {\n // Build the bone chain from root to this bone\n const boneChain: Bone[] = [];\n let currentBone: Bone | null = bone;\n while (currentBone) {\n boneChain.unshift(currentBone);\n currentBone = currentBone.parent;\n }\n\n // Compose world matrix by multiplying all local transforms\n const worldMatrix = new THREE.Matrix4();\n worldMatrix.identity();\n\n for (const b of boneChain) {\n tempMatrix.compose(\n b.position,\n tempQuaternion.setFromEuler(b.rotation),\n b.scale,\n );\n worldMatrix.multiply(tempMatrix);\n }\n\n // Extract world position from composed matrix\n const worldPos = new THREE.Vector3();\n worldMatrix.decompose(worldPos, tempQuaternion, tempScale);\n return worldPos;\n};\n\n/**\n * Get world rotation of bone\n *\n * Calculates absolute world rotation by traversing parent chain.\n * Uses proper quaternion multiplication for correct rotation composition.\n *\n * @param bone - Bone to get world rotation for\n * @returns World rotation as Euler\n *\n * @korean 뼈의세계회전구하기\n */\nexport const getBoneWorldRotation = (bone: Bone): THREE.Euler => {\n // Build the bone chain from root to this bone\n const boneChain: Bone[] = [];\n let currentBone: Bone | null = bone;\n while (currentBone) {\n boneChain.unshift(currentBone);\n currentBone = currentBone.parent;\n }\n\n // Compose world rotation by multiplying quaternions (proper rotation composition)\n const worldQuat = new THREE.Quaternion();\n worldQuat.identity();\n\n for (const b of boneChain) {\n tempQuaternion.setFromEuler(b.rotation);\n worldQuat.multiply(tempQuaternion);\n }\n\n // Convert back to Euler\n const worldRot = new THREE.Euler();\n worldRot.setFromQuaternion(worldQuat);\n return worldRot;\n};\n\n/**\n * Reset bone to rest pose\n *\n * Resets bone position and rotation to default rest pose.\n * Useful for animation blending and initialization.\n *\n * @param bone - Bone to reset\n *\n * @korean 뼈를기본자세로초기화\n */\nexport const resetBoneToRestPose = (bone: Bone): void => {\n bone.position.copy(bone.restPosition);\n bone.rotation.copy(bone.restRotation);\n bone.scale.set(1, 1, 1);\n};\n\n/**\n * Reset entire rig to rest pose\n *\n * Resets all bones in rig to rest pose.\n *\n * @param rig - Skeletal rig to reset\n *\n * @korean 골격을기본자세로초기화\n */\nexport const resetRigToRestPose = (rig: SkeletalRig): void => {\n rig.bones.forEach((bone) => {\n resetBoneToRestPose(bone);\n });\n};\n\n/**\n * Create hand bones with 5 fingers\n *\n * Creates detailed hand structure with 5 fingers (thumb, index, middle, ring, pinky),\n * attached to an existing hand/palm bone.\n * Each finger has 3-4 bones for realistic animation.\n *\n * Finger bone structure:\n * - Thumb: 3 bones (metacarpal, proximal, distal) - no intermediate\n * - Other fingers: 4 bones (metacarpal, proximal, intermediate, distal)\n *\n * Total created by this function: 19 finger bones per hand (3 thumb + 4*4 other fingers),\n * all attached to the provided hand bone.\n *\n * @param handBone - Parent hand bone (acts as the palm/root for finger bones)\n * @param side - Hand side (\"left\" or \"right\")\n * @returns Map of finger bones added to the rig\n *\n * @korean 손뼈생성\n */\nexport const createHandBones = (\n handBone: Bone,\n side: \"left\" | \"right\",\n): Map<string, Bone> => {\n const fingerBones = new Map<string, Bone>();\n\n // Hand orientation: left hand extends to -X, right hand extends to +X\n const sideMultiplier = side === \"left\" ? -1 : 1;\n\n // Thumb (3 bones) - offset slightly toward palm center and forward\n const thumbMeta = createBone(\n `${\n BoneName[`THUMB_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [0.015 * sideMultiplier, 0.02, 0.01],\n 0.025,\n );\n const thumbProx = createBone(\n `${\n BoneName[`THUMB_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n thumbMeta,\n [0.015 * sideMultiplier, 0.015, 0.01],\n 0.02,\n );\n const thumbDist = createBone(\n `${\n BoneName[`THUMB_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n thumbProx,\n [0.01 * sideMultiplier, 0.01, 0],\n 0.015,\n );\n\n fingerBones.set(thumbMeta.name, thumbMeta);\n fingerBones.set(thumbProx.name, thumbProx);\n fingerBones.set(thumbDist.name, thumbDist);\n\n // Index finger (4 bones)\n const indexMeta = createBone(\n `${\n BoneName[`INDEX_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [0.015 * sideMultiplier, 0.06, 0],\n 0.03,\n );\n const indexProx = createBone(\n `${\n BoneName[`INDEX_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n indexMeta,\n [0, 0.025, 0],\n 0.025,\n );\n const indexInter = createBone(\n `${\n BoneName[`INDEX_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n indexProx,\n [0, 0.02, 0],\n 0.02,\n );\n const indexDist = createBone(\n `${\n BoneName[`INDEX_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n indexInter,\n [0, 0.015, 0],\n 0.015,\n );\n\n fingerBones.set(indexMeta.name, indexMeta);\n fingerBones.set(indexProx.name, indexProx);\n fingerBones.set(indexInter.name, indexInter);\n fingerBones.set(indexDist.name, indexDist);\n\n // Middle finger (4 bones) - longest finger\n const middleMeta = createBone(\n `${\n BoneName[`MIDDLE_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [0.005 * sideMultiplier, 0.065, 0],\n 0.035,\n );\n const middleProx = createBone(\n `${\n BoneName[`MIDDLE_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n middleMeta,\n [0, 0.03, 0],\n 0.03,\n );\n const middleInter = createBone(\n `${\n BoneName[`MIDDLE_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n middleProx,\n [0, 0.025, 0],\n 0.025,\n );\n const middleDist = createBone(\n `${\n BoneName[`MIDDLE_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n middleInter,\n [0, 0.02, 0],\n 0.02,\n );\n\n fingerBones.set(middleMeta.name, middleMeta);\n fingerBones.set(middleProx.name, middleProx);\n fingerBones.set(middleInter.name, middleInter);\n fingerBones.set(middleDist.name, middleDist);\n\n // Ring finger (4 bones)\n const ringMeta = createBone(\n `${\n BoneName[`RING_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [-0.005 * sideMultiplier, 0.06, 0],\n 0.03,\n );\n const ringProx = createBone(\n `${\n BoneName[`RING_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n ringMeta,\n [0, 0.025, 0],\n 0.025,\n );\n const ringInter = createBone(\n `${\n BoneName[`RING_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n ringProx,\n [0, 0.02, 0],\n 0.02,\n );\n const ringDist = createBone(\n `${\n BoneName[`RING_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n ringInter,\n [0, 0.015, 0],\n 0.015,\n );\n\n fingerBones.set(ringMeta.name, ringMeta);\n fingerBones.set(ringProx.name, ringProx);\n fingerBones.set(ringInter.name, ringInter);\n fingerBones.set(ringDist.name, ringDist);\n\n // Pinky finger (4 bones) - shortest finger\n const pinkyMeta = createBone(\n `${\n BoneName[`PINKY_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [-0.015 * sideMultiplier, 0.05, 0],\n 0.025,\n );\n const pinkyProx = createBone(\n `${\n BoneName[`PINKY_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n pinkyMeta,\n [0, 0.02, 0],\n 0.02,\n );\n const pinkyInter = createBone(\n `${\n BoneName[`PINKY_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n pinkyProx,\n [0, 0.015, 0],\n 0.015,\n );\n const pinkyDist = createBone(\n `${\n BoneName[`PINKY_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n pinkyInter,\n [0, 0.01, 0],\n 0.01,\n );\n\n fingerBones.set(pinkyMeta.name, pinkyMeta);\n fingerBones.set(pinkyProx.name, pinkyProx);\n fingerBones.set(pinkyInter.name, pinkyInter);\n fingerBones.set(pinkyDist.name, pinkyDist);\n\n return fingerBones;\n};\n\n/**\n * Create humanoid rig with optional hand bones\n *\n * Creates complete skeletal rig with optional detailed hand bones.\n * Hand bones can be excluded for performance (LOD system).\n *\n * @param includeHandBones - Whether to include detailed hand bones (default: false)\n * @returns Complete skeletal rig with or without hand bones\n *\n * @korean 손뼈포함골격생성\n */\nexport const createHumanoidRigWithHands = (\n includeHandBones: boolean = false,\n): SkeletalRig => {\n // Create base rig\n const baseRig = createHumanoidRig();\n\n // If hand bones not requested, return base rig\n if (!includeHandBones) {\n return baseRig;\n }\n\n // Get hand bones from base rig\n const leftHand = baseRig.bones.get(BoneName.HAND_L);\n const rightHand = baseRig.bones.get(BoneName.HAND_R);\n\n if (!leftHand || !rightHand) {\n console.warn(\"Hand bones not found in base rig\");\n return baseRig;\n }\n\n // Create finger bones\n const leftFingerBones = createHandBones(leftHand, \"left\");\n const rightFingerBones = createHandBones(rightHand, \"right\");\n\n // Add finger bones to rig bone map\n leftFingerBones.forEach((bone, name) => {\n baseRig.bones.set(name, bone);\n });\n rightFingerBones.forEach((bone, name) => {\n baseRig.bones.set(name, bone);\n });\n\n return {\n ...baseRig,\n boneCount: baseRig.bones.size,\n };\n};\n\n/**\n * Torso rotation constraints for anatomically correct upper/lower body movement\n *\n * Defines limits and behavior for independent torso rotation relative to hips,\n * enabling realistic strafing and lateral movement while facing opponent.\n *\n * Korean terminology:\n * - 허리회전 (Heorhwoejeon) - Torso rotation\n * - 해부학적제약 (Haebuhakjeok Jeyak) - Anatomical constraints\n *\n * @korean 허리회전제약조건\n */\nexport const TORSO_CONSTRAINTS = {\n /**\n * Maximum torso rotation relative to hips (radians)\n * ±90° = π/2 radians - anatomically safe rotation limit\n *\n * @korean 최대회전각도\n */\n MAX_ROTATION: Math.PI / 2,\n\n /**\n * Minimum torso rotation relative to hips (radians)\n * -90° = -π/2 radians\n *\n * @korean 최소회전각도\n */\n MIN_ROTATION: -Math.PI / 2,\n\n /**\n * Target interpolation time in seconds\n * 200ms provides smooth, natural rotation feel\n *\n * @korean 보간시간\n */\n INTERPOLATION_TIME: 0.2,\n\n /**\n * Power modifier range for hip rotation\n * [min, max] = [10%, 30%] damage bonus from proper hip engagement\n *\n * @korean 파워배율범위\n */\n POWER_MODIFIER_RANGE: [0.1, 0.3] as const,\n} as const;\n\n/**\n * Calculate torso rotation to face opponent while moving\n *\n * Determines optimal torso rotation angle to keep upper body facing opponent\n * while hips/legs are oriented in movement direction. Enforces anatomical\n * constraints (±90° max rotation).\n *\n * @param currentPosition - Player's current world position\n * @param opponentPosition - Opponent's current world position\n * @param _movementDirection - Direction of player movement (reserved for future use)\n * @param hipRotation - Current hip/pelvis rotation in radians\n * @returns Torso rotation in radians relative to hips (clamped to ±90°)\n *\n * @example\n * ```typescript\n * const playerPos = new THREE.Vector3(0, 0, 0);\n * const opponentPos = new THREE.Vector3(0, 0, 5); // Directly in front along Z+\n * const moveDir = new THREE.Vector3(0, 0, 1); // Moving forward\n * const hipRot = 0; // Hips facing forward (Z+)\n *\n * const torsoRot = calculateTorsoRotation(playerPos, opponentPos, moveDir, hipRot);\n * // Returns 0 (opponent is already aligned with hips)\n * ```\n *\n * @korean 상대를향한허리회전계산\n */\nexport function calculateTorsoRotation(\n currentPosition: THREE.Vector3,\n opponentPosition: THREE.Vector3,\n _movementDirection: THREE.Vector3,\n hipRotation: number,\n): number {\n // Calculate angle to opponent\n const directionToOpponent = opponentPosition\n .clone()\n .sub(currentPosition)\n .normalize();\n // Use atan2(x, z) - X is horizontal, Z is forward/back in Three.js\n const angleToOpponent = Math.atan2(\n directionToOpponent.x,\n directionToOpponent.z,\n );\n\n // Calculate torso rotation relative to hips\n let torsoRotation = angleToOpponent - hipRotation;\n\n // Normalize to -π to π range\n while (torsoRotation > Math.PI) torsoRotation -= 2 * Math.PI;\n while (torsoRotation < -Math.PI) torsoRotation += 2 * Math.PI;\n\n // Apply anatomical constraints (±90°)\n torsoRotation = Math.max(\n TORSO_CONSTRAINTS.MIN_ROTATION,\n Math.min(TORSO_CONSTRAINTS.MAX_ROTATION, torsoRotation),\n );\n\n return torsoRotation;\n}\n\n/**\n * Calculate damage modifier from hip rotation\n *\n * Determines power bonus applied to techniques based on hip rotation angle.\n * Greater hip rotation generates more power through proper biomechanics,\n * with strikes benefiting most from full rotation.\n *\n * @param hipRotationAngle - Hip rotation angle in radians (typically from torso twist)\n * @param techniqueType - Type of technique ('strike', 'throw', or 'joint')\n * @returns Damage multiplier (1.0-1.3 for strikes, 1.0-1.1 for throws/joints)\n *\n * @example\n * ```typescript\n * // Full hip rotation on strike technique\n * const modifier = calculateHipRotationPowerModifier(Math.PI / 2, 'strike');\n * // Returns 1.30 (30% damage bonus)\n *\n * // Half rotation on throw\n * const throwMod = calculateHipRotationPowerModifier(Math.PI / 4, 'throw');\n * // Returns 1.05 (5% damage bonus)\n * ```\n *\n * @korean 허리회전으로인한데미지배율계산\n */\nexport function calculateHipRotationPowerModifier(\n hipRotationAngle: number,\n techniqueType: \"strike\" | \"throw\" | \"joint\",\n): number {\n // Normalize rotation to 0-1 range (0 = no rotation, 1 = max rotation)\n // Clamp to max rotation first to handle any values exceeding ±90°\n const clampedAngle = Math.max(\n -TORSO_CONSTRAINTS.MAX_ROTATION,\n Math.min(TORSO_CONSTRAINTS.MAX_ROTATION, Math.abs(hipRotationAngle)),\n );\n const normalizedRotation = clampedAngle / TORSO_CONSTRAINTS.MAX_ROTATION;\n\n // Strikes benefit most from hip rotation (up to 30% bonus)\n // Throws get moderate benefit (up to 10% bonus)\n // Joint locks get minimal benefit (up to 10% bonus)\n const baseModifier = techniqueType === \"strike\" ? 0.3 : 0.1;\n\n return 1.0 + normalizedRotation * baseModifier;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"SkeletonRig.js","names":[],"sources":["../../../../src/systems/animation/builders/SkeletonRig.ts"],"sourcesContent":["/**\n * Skeleton rig implementation for articulated body model\n *\n * Creates and manages humanoid skeletal rig with 28 bones for realistic\n * martial arts animations. Implements bone hierarchy following Korean martial\n * arts body mechanics.\n *\n * Now supports dynamic scaling based on player physical attributes for\n * anatomically accurate body proportions per archetype.\n *\n * @module systems/animation/SkeletonRig\n * @category Animation System\n * @korean 골격시스템\n */\n\nimport { PhysicalAttributes } from \"@/types/common\";\nimport type {\n Bone,\n BoneChain,\n JointConstraint,\n SkeletalRig,\n} from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport {\n calculateSkeletonDimensions,\n cmToMeters,\n} from \"@/utils/characterScaling\";\nimport * as THREE from \"three\";\n\n/**\n * Create a bone with default rest pose\n *\n * Helper function to create a bone with position, rotation, and scale.\n * Sets up rest pose for animation blending.\n *\n * @param name - Unique bone identifier\n * @param parent - Parent bone (null for root)\n * @param position - Local position relative to parent [x, y, z]\n * @param length - Bone length for rendering\n * @returns Newly created bone\n *\n * @korean 뼈생성\n */\nexport const createBone = (\n name: string,\n parent: Bone | null,\n position: [number, number, number],\n length = 0.1,\n): Bone => {\n const pos = new THREE.Vector3(position[0], position[1], position[2]);\n const rot = new THREE.Euler(0, 0, 0);\n const scale = new THREE.Vector3(1, 1, 1);\n\n const bone: Bone = {\n name,\n parent,\n position: pos.clone(),\n rotation: rot.clone(),\n scale: scale.clone(),\n children: [],\n length,\n restPosition: pos.clone(),\n restRotation: rot.clone(),\n };\n\n // Add to parent's children\n if (parent) {\n parent.children.push(bone);\n }\n\n return bone;\n};\n\n/**\n * Create complete humanoid skeletal rig\n *\n * Creates 28-bone humanoid skeleton following Korean martial arts anatomy:\n * - 1 root (pelvis)\n * - 3 spine bones\n * - 2 head bones (neck, head)\n * - 12 arm bones (6 per arm)\n * - 10 leg bones (5 per leg)\n *\n * Total: 28 bones (under 30 bone limit for 60fps performance)\n *\n * @returns Complete skeletal rig with bone hierarchy\n *\n * @example\n * ```typescript\n * const rig = createHumanoidRig();\n * const rightHand = rig.bones.get(BoneName.HAND_R);\n * console.log(`Hand position: ${rightHand?.position}`);\n * ```\n *\n * @korean 인간형골격생성\n */\nexport const createHumanoidRig = (): SkeletalRig => {\n // Root (pelvis) - center of mass at hip height\n // Pelvis height = sum of leg segments (hip + thigh + knee + shin + foot)\n // = 0.1 + 0.3 + 0.3 + 0.3 + 0.1 = 1.1 to have feet at Y=0\n const root = createBone(BoneName.PELVIS, null, [0, 1.1, 0], 0.15);\n\n // Spine chain (3 bones)\n const spine1 = createBone(BoneName.SPINE_LOWER, root, [0, 0.15, 0], 0.2);\n const spine2 = createBone(BoneName.SPINE_MIDDLE, spine1, [0, 0.2, 0], 0.2);\n const spine3 = createBone(BoneName.SPINE_UPPER, spine2, [0, 0.2, 0], 0.2);\n\n // Head chain (2 bones)\n const neck = createBone(BoneName.NECK, spine3, [0, 0.15, 0], 0.1);\n const head = createBone(BoneName.HEAD, neck, [0, 0.2, 0], 0.2);\n\n // Left arm chain (6 bones)\n const leftShoulder = createBone(\n BoneName.SHOULDER_L,\n spine3,\n [-0.15, 0.1, 0],\n 0.1,\n );\n const leftUpperArm = createBone(\n BoneName.UPPER_ARM_L,\n leftShoulder,\n [-0.15, 0, 0],\n 0.25,\n );\n const leftElbow = createBone(\n BoneName.ELBOW_L,\n leftUpperArm,\n [-0.25, 0, 0],\n 0.05,\n );\n const leftForearm = createBone(\n BoneName.FOREARM_L,\n leftElbow,\n [-0.25, 0, 0],\n 0.25,\n );\n const leftWrist = createBone(\n BoneName.WRIST_L,\n leftForearm,\n [-0.15, 0, 0],\n 0.05,\n );\n const leftHand = createBone(BoneName.HAND_L, leftWrist, [-0.08, 0, 0], 0.08);\n\n // Right arm chain (6 bones - mirror of left)\n const rightShoulder = createBone(\n BoneName.SHOULDER_R,\n spine3,\n [0.15, 0.1, 0],\n 0.1,\n );\n const rightUpperArm = createBone(\n BoneName.UPPER_ARM_R,\n rightShoulder,\n [0.15, 0, 0],\n 0.25,\n );\n const rightElbow = createBone(\n BoneName.ELBOW_R,\n rightUpperArm,\n [0.25, 0, 0],\n 0.05,\n );\n const rightForearm = createBone(\n BoneName.FOREARM_R,\n rightElbow,\n [0.25, 0, 0],\n 0.25,\n );\n const rightWrist = createBone(\n BoneName.WRIST_R,\n rightForearm,\n [0.15, 0, 0],\n 0.05,\n );\n const rightHand = createBone(BoneName.HAND_R, rightWrist, [0.08, 0, 0], 0.08);\n\n // Left leg chain (5 bones)\n const leftHip = createBone(BoneName.HIP_L, root, [-0.1, -0.1, 0], 0.1);\n const leftThigh = createBone(BoneName.THIGH_L, leftHip, [0, -0.3, 0], 0.3);\n const leftKnee = createBone(BoneName.KNEE_L, leftThigh, [0, -0.3, 0], 0.05);\n const leftShin = createBone(BoneName.SHIN_L, leftKnee, [0, -0.3, 0], 0.3);\n const leftFoot = createBone(BoneName.FOOT_L, leftShin, [0, -0.1, 0.1], 0.15);\n\n // Right leg chain (5 bones - mirror of left)\n const rightHip = createBone(BoneName.HIP_R, root, [0.1, -0.1, 0], 0.1);\n const rightThigh = createBone(BoneName.THIGH_R, rightHip, [0, -0.3, 0], 0.3);\n const rightKnee = createBone(BoneName.KNEE_R, rightThigh, [0, -0.3, 0], 0.05);\n const rightShin = createBone(BoneName.SHIN_R, rightKnee, [0, -0.3, 0], 0.3);\n const rightFoot = createBone(\n BoneName.FOOT_R,\n rightShin,\n [0, -0.1, 0.1],\n 0.15,\n );\n\n // Create bone map for fast lookup\n const bones = new Map<string, Bone>([\n [BoneName.PELVIS, root],\n [BoneName.SPINE_LOWER, spine1],\n [BoneName.SPINE_MIDDLE, spine2],\n [BoneName.SPINE_UPPER, spine3],\n [BoneName.NECK, neck],\n [BoneName.HEAD, head],\n [BoneName.SHOULDER_L, leftShoulder],\n [BoneName.UPPER_ARM_L, leftUpperArm],\n [BoneName.ELBOW_L, leftElbow],\n [BoneName.FOREARM_L, leftForearm],\n [BoneName.WRIST_L, leftWrist],\n [BoneName.HAND_L, leftHand],\n [BoneName.SHOULDER_R, rightShoulder],\n [BoneName.UPPER_ARM_R, rightUpperArm],\n [BoneName.ELBOW_R, rightElbow],\n [BoneName.FOREARM_R, rightForearm],\n [BoneName.WRIST_R, rightWrist],\n [BoneName.HAND_R, rightHand],\n [BoneName.HIP_L, leftHip],\n [BoneName.THIGH_L, leftThigh],\n [BoneName.KNEE_L, leftKnee],\n [BoneName.SHIN_L, leftShin],\n [BoneName.FOOT_L, leftFoot],\n [BoneName.HIP_R, rightHip],\n [BoneName.THIGH_R, rightThigh],\n [BoneName.KNEE_R, rightKnee],\n [BoneName.SHIN_R, rightShin],\n [BoneName.FOOT_R, rightFoot],\n ]);\n\n return {\n root,\n bones,\n boneCount: bones.size,\n };\n};\n\n/**\n * Create humanoid rig with dynamic scaling based on physical attributes.\n *\n * **Korean**: 신체 속성 기반 골격 생성 (Physical Attributes-Based Skeleton Creation)\n *\n * Creates a 28-bone humanoid skeleton with bone lengths scaled according to\n * the fighter's physical attributes. This allows each archetype to have\n * anatomically accurate body proportions that affect combat hitboxes, vital\n * point positioning, and visual representation.\n *\n * ## Visual Amplification\n *\n * The scaling system applies amplification factors to create distinct visual\n * silhouettes while maintaining anatomical realism:\n *\n * - **2.5x limb amplification**: Makes reach differences clearly visible\n * - **1.15x shoulder amplification**: Creates recognizable body width differences\n * - **1.5x height amplification**: Subtle overall size differences\n *\n * ### Archetype Silhouettes Created\n *\n * The following table shows the effective shoulder span after amplification\n * (full span = offset * 2). Values show raw attribute → amplified visual span.\n *\n * | Archetype | Shoulders (Raw → Amplified Span) | Height | Silhouette |\n * |-----------|----------------------------------|--------|------------|\n * | Hacker | 43cm → 49.5cm | 175cm | Compact, narrow |\n * | Amsalja | 44cm → 50.6cm | 186cm | Tall, lean |\n * | Jeongbo | 45cm → 51.8cm | 179cm | Balanced |\n * | Musa | 46cm → 52.9cm | 180cm | Athletic |\n * | Jojik | 54cm → 62.1cm | 188cm | Massive, wide |\n *\n * Note: Amplified span = raw width * 1.15 (shoulder amplification factor)\n * Percentage differences remain constant, but absolute gaps are amplified:\n * - Raw gap: Jojik (54cm) - Hacker (43cm) = 11cm\n * - Amplified gap: 62.1cm - 49.5cm = 12.6cm (15% larger absolute difference)\n *\n * @param attributes - Physical attributes to scale the skeleton\n * @returns Complete skeletal rig with scaled bone dimensions\n *\n * @example\n * ```typescript\n * import { AMSALJA_PHYSICAL } from \"@/data/archetypePhysicalAttributes\";\n *\n * // Create skeleton for lean assassin archetype\n * const amsaljaRig = createScaledHumanoidRig(AMSALJA_PHYSICAL);\n * // Results in taller skeleton with longer limbs, narrower shoulders\n * // Height: 186cm, Legs: 102cm, Arms: 82cm, Shoulders: 44cm\n *\n * // Create skeleton for heavy brawler archetype\n * const jojikRig = createScaledHumanoidRig(JOJIK_PHYSICAL);\n * // Results in stockier skeleton with wider shoulders, thicker torso\n * // Height: 188cm, Legs: 100cm, Arms: 84cm, Shoulders: 54cm (25% wider!)\n * ```\n *\n * @korean 크기조정된인간형골격생성\n */\nexport const createScaledHumanoidRig = (\n attributes: PhysicalAttributes,\n): SkeletalRig => {\n // Calculate anatomically correct bone dimensions in meters\n const dims = calculateSkeletonDimensions(attributes);\n\n // Calculate shoulder offset (half of shoulder width) in meters\n const shoulderOffsetMeters = cmToMeters(attributes.shoulderWidth) / 2;\n const hipOffsetMeters = cmToMeters(attributes.shoulderWidth) * 0.35; // Hips are ~70% of shoulder width\n\n // Root (pelvis) - position at pelvis height (ground + leg length + foot)\n // This ensures feet are at Y=0\n const root = createBone(\n BoneName.PELVIS,\n null,\n [0, dims.pelvisHeight, 0],\n dims.hip,\n );\n\n // Spine chain (3 bones) - using actual torso segment lengths\n const spine1 = createBone(\n BoneName.SPINE_LOWER,\n root,\n [0, dims.spineLower * 0.5, 0], // Start half a segment up from pelvis\n dims.spineLower,\n );\n const spine2 = createBone(\n BoneName.SPINE_MIDDLE,\n spine1,\n [0, dims.spineMiddle, 0],\n dims.spineMiddle,\n );\n const spine3 = createBone(\n BoneName.SPINE_UPPER,\n spine2,\n [0, dims.spineUpper, 0],\n dims.spineUpper,\n );\n\n // Head chain (2 bones) - using actual neck and head sizes\n const neck = createBone(\n BoneName.NECK,\n spine3,\n [0, dims.neck * 0.5, 0], // Start from top of spine\n dims.neck,\n );\n const head = createBone(\n BoneName.HEAD,\n neck,\n [0, dims.head * 0.75, 0], // Head center offset\n dims.head,\n );\n\n // Left arm chain (6 bones) - using actual arm segment lengths\n const leftShoulder = createBone(\n BoneName.SHOULDER_L,\n spine3,\n [-shoulderOffsetMeters * 0.7, dims.neck * 0.3, 0], // Shoulder starts inward from edge\n dims.shoulder,\n );\n const leftUpperArm = createBone(\n BoneName.UPPER_ARM_L,\n leftShoulder,\n [-dims.shoulder, 0, 0], // Extend outward by shoulder length\n dims.upperArm,\n );\n const leftElbow = createBone(\n BoneName.ELBOW_L,\n leftUpperArm,\n [-dims.upperArm, 0, 0], // End of upper arm\n dims.elbow,\n );\n const leftForearm = createBone(\n BoneName.FOREARM_L,\n leftElbow,\n [-dims.elbow, 0, 0], // Past elbow joint\n dims.forearm,\n );\n const leftWrist = createBone(\n BoneName.WRIST_L,\n leftForearm,\n [-dims.forearm, 0, 0], // End of forearm\n dims.wrist,\n );\n const leftHand = createBone(\n BoneName.HAND_L,\n leftWrist,\n [-dims.wrist, 0, 0], // Past wrist\n dims.hand,\n );\n\n // Right arm chain (6 bones - mirror of left)\n const rightShoulder = createBone(\n BoneName.SHOULDER_R,\n spine3,\n [shoulderOffsetMeters * 0.7, dims.neck * 0.3, 0],\n dims.shoulder,\n );\n const rightUpperArm = createBone(\n BoneName.UPPER_ARM_R,\n rightShoulder,\n [dims.shoulder, 0, 0],\n dims.upperArm,\n );\n const rightElbow = createBone(\n BoneName.ELBOW_R,\n rightUpperArm,\n [dims.upperArm, 0, 0],\n dims.elbow,\n );\n const rightForearm = createBone(\n BoneName.FOREARM_R,\n rightElbow,\n [dims.elbow, 0, 0],\n dims.forearm,\n );\n const rightWrist = createBone(\n BoneName.WRIST_R,\n rightForearm,\n [dims.forearm, 0, 0],\n dims.wrist,\n );\n const rightHand = createBone(\n BoneName.HAND_R,\n rightWrist,\n [dims.wrist, 0, 0],\n dims.hand,\n );\n\n // Left leg chain (5 bones) - using actual leg segment lengths\n const leftHip = createBone(\n BoneName.HIP_L,\n root,\n [-hipOffsetMeters, -dims.hip * 0.5, 0],\n dims.hip,\n );\n const leftThigh = createBone(\n BoneName.THIGH_L,\n leftHip,\n [0, -dims.hip, 0], // Drop down from hip\n dims.thigh,\n );\n const leftKnee = createBone(\n BoneName.KNEE_L,\n leftThigh,\n [0, -dims.thigh, 0], // End of thigh\n dims.knee,\n );\n const leftShin = createBone(\n BoneName.SHIN_L,\n leftKnee,\n [0, -dims.knee, 0], // Past knee\n dims.shin,\n );\n const leftFoot = createBone(\n BoneName.FOOT_L,\n leftShin,\n [0, -dims.shin, dims.foot * 0.5], // End of shin, slight forward for foot\n dims.foot,\n );\n\n // Right leg chain (5 bones - mirror of left)\n const rightHip = createBone(\n BoneName.HIP_R,\n root,\n [hipOffsetMeters, -dims.hip * 0.5, 0],\n dims.hip,\n );\n const rightThigh = createBone(\n BoneName.THIGH_R,\n rightHip,\n [0, -dims.hip, 0],\n dims.thigh,\n );\n const rightKnee = createBone(\n BoneName.KNEE_R,\n rightThigh,\n [0, -dims.thigh, 0],\n dims.knee,\n );\n const rightShin = createBone(\n BoneName.SHIN_R,\n rightKnee,\n [0, -dims.knee, 0],\n dims.shin,\n );\n const rightFoot = createBone(\n BoneName.FOOT_R,\n rightShin,\n [0, -dims.shin, dims.foot * 0.5],\n dims.foot,\n );\n\n // Create bone map for fast lookup\n const bones = new Map<string, Bone>([\n [BoneName.PELVIS, root],\n [BoneName.SPINE_LOWER, spine1],\n [BoneName.SPINE_MIDDLE, spine2],\n [BoneName.SPINE_UPPER, spine3],\n [BoneName.NECK, neck],\n [BoneName.HEAD, head],\n [BoneName.SHOULDER_L, leftShoulder],\n [BoneName.UPPER_ARM_L, leftUpperArm],\n [BoneName.ELBOW_L, leftElbow],\n [BoneName.FOREARM_L, leftForearm],\n [BoneName.WRIST_L, leftWrist],\n [BoneName.HAND_L, leftHand],\n [BoneName.SHOULDER_R, rightShoulder],\n [BoneName.UPPER_ARM_R, rightUpperArm],\n [BoneName.ELBOW_R, rightElbow],\n [BoneName.FOREARM_R, rightForearm],\n [BoneName.WRIST_R, rightWrist],\n [BoneName.HAND_R, rightHand],\n [BoneName.HIP_L, leftHip],\n [BoneName.THIGH_L, leftThigh],\n [BoneName.KNEE_L, leftKnee],\n [BoneName.SHIN_L, leftShin],\n [BoneName.FOOT_L, leftFoot],\n [BoneName.HIP_R, rightHip],\n [BoneName.THIGH_R, rightThigh],\n [BoneName.KNEE_R, rightKnee],\n [BoneName.SHIN_R, rightShin],\n [BoneName.FOOT_R, rightFoot],\n ]);\n\n return {\n root,\n bones,\n boneCount: bones.size,\n };\n};\n\n/**\n * Joint constraints for anatomically correct movement\n *\n * Defines rotation limits for each joint to prevent unrealistic poses.\n * Based on human anatomy and Korean martial arts biomechanics.\n *\n * @korean 관절제약조건들\n */\nexport const JOINT_CONSTRAINTS: JointConstraint[] = [\n // Elbow joints - can only bend one direction\n {\n boneName: BoneName.ELBOW_L,\n minRotation: new THREE.Vector3(0, 0, -2.4), // ~-137 degrees\n maxRotation: new THREE.Vector3(0, 0, 0),\n canTwist: false,\n },\n {\n boneName: BoneName.ELBOW_R,\n minRotation: new THREE.Vector3(0, 0, 0),\n maxRotation: new THREE.Vector3(0, 0, 2.4), // ~137 degrees\n canTwist: false,\n },\n\n // Knee joints - can only bend backward\n {\n boneName: BoneName.KNEE_L,\n minRotation: new THREE.Vector3(-2.4, 0, 0), // ~-137 degrees\n maxRotation: new THREE.Vector3(0, 0, 0),\n canTwist: false,\n },\n {\n boneName: BoneName.KNEE_R,\n minRotation: new THREE.Vector3(-2.4, 0, 0), // ~-137 degrees\n maxRotation: new THREE.Vector3(0, 0, 0),\n canTwist: false,\n },\n\n // Shoulder joints - full range of motion\n {\n boneName: BoneName.SHOULDER_L,\n minRotation: new THREE.Vector3(-1.5, -1.5, -3.0),\n maxRotation: new THREE.Vector3(1.5, 1.5, 3.0),\n canTwist: true,\n },\n {\n boneName: BoneName.SHOULDER_R,\n minRotation: new THREE.Vector3(-1.5, -1.5, -3.0),\n maxRotation: new THREE.Vector3(1.5, 1.5, 3.0),\n canTwist: true,\n },\n\n // Hip joints - large range for kicks\n {\n boneName: BoneName.HIP_L,\n minRotation: new THREE.Vector3(-1.8, -0.8, -1.5),\n maxRotation: new THREE.Vector3(1.8, 0.8, 1.5),\n canTwist: true,\n },\n {\n boneName: BoneName.HIP_R,\n minRotation: new THREE.Vector3(-1.8, -0.8, -1.5),\n maxRotation: new THREE.Vector3(1.8, 0.8, 1.5),\n canTwist: true,\n },\n\n // Neck - moderate range\n {\n boneName: BoneName.NECK,\n minRotation: new THREE.Vector3(-0.5, -0.8, -0.5),\n maxRotation: new THREE.Vector3(0.5, 0.8, 0.5),\n canTwist: true,\n },\n\n // Spine bones - limited rotation for realism\n {\n boneName: BoneName.SPINE_LOWER,\n minRotation: new THREE.Vector3(-0.3, -0.5, -0.3),\n maxRotation: new THREE.Vector3(0.3, 0.5, 0.3),\n canTwist: true,\n },\n {\n boneName: BoneName.SPINE_MIDDLE,\n minRotation: new THREE.Vector3(-0.3, -0.5, -0.3),\n maxRotation: new THREE.Vector3(0.3, 0.5, 0.3),\n canTwist: true,\n },\n {\n boneName: BoneName.SPINE_UPPER,\n minRotation: new THREE.Vector3(-0.3, -0.5, -0.3),\n maxRotation: new THREE.Vector3(0.3, 0.5, 0.3),\n canTwist: true,\n },\n];\n\n/**\n * Bone chains for IK (Inverse Kinematics)\n *\n * Defines logical bone chains for limbs, used for IK solving\n * and animation retargeting.\n *\n * @korean 뼈체인들\n */\nexport const BONE_CHAINS: BoneChain[] = [\n // Left arm chain\n {\n name: \"left_arm\",\n startBone: BoneName.SHOULDER_L,\n endBone: BoneName.HAND_L,\n bones: [\n BoneName.SHOULDER_L,\n BoneName.UPPER_ARM_L,\n BoneName.ELBOW_L,\n BoneName.FOREARM_L,\n BoneName.WRIST_L,\n BoneName.HAND_L,\n ],\n },\n\n // Right arm chain\n {\n name: \"right_arm\",\n startBone: BoneName.SHOULDER_R,\n endBone: BoneName.HAND_R,\n bones: [\n BoneName.SHOULDER_R,\n BoneName.UPPER_ARM_R,\n BoneName.ELBOW_R,\n BoneName.FOREARM_R,\n BoneName.WRIST_R,\n BoneName.HAND_R,\n ],\n },\n\n // Left leg chain\n {\n name: \"left_leg\",\n startBone: BoneName.HIP_L,\n endBone: BoneName.FOOT_L,\n bones: [\n BoneName.HIP_L,\n BoneName.THIGH_L,\n BoneName.KNEE_L,\n BoneName.SHIN_L,\n BoneName.FOOT_L,\n ],\n },\n\n // Right leg chain\n {\n name: \"right_leg\",\n startBone: BoneName.HIP_R,\n endBone: BoneName.FOOT_R,\n bones: [\n BoneName.HIP_R,\n BoneName.THIGH_R,\n BoneName.KNEE_R,\n BoneName.SHIN_R,\n BoneName.FOOT_R,\n ],\n },\n\n // Spine chain\n {\n name: \"spine\",\n startBone: BoneName.PELVIS,\n endBone: BoneName.HEAD,\n bones: [\n BoneName.PELVIS,\n BoneName.SPINE_LOWER,\n BoneName.SPINE_MIDDLE,\n BoneName.SPINE_UPPER,\n BoneName.NECK,\n BoneName.HEAD,\n ],\n },\n];\n\n/**\n * Apply joint constraints to bone rotation\n *\n * Clamps bone rotation to anatomically correct ranges.\n * Prevents unrealistic poses like backward-bending elbows.\n *\n * @param bone - Bone to constrain\n * @param constraints - Joint constraint to apply\n *\n * @korean 관절제약적용\n */\nexport const applyJointConstraint = (\n bone: Bone,\n constraint: JointConstraint,\n): void => {\n // Clamp X rotation\n bone.rotation.x = Math.max(\n constraint.minRotation.x,\n Math.min(constraint.maxRotation.x, bone.rotation.x),\n );\n\n // Clamp Y rotation\n bone.rotation.y = Math.max(\n constraint.minRotation.y,\n Math.min(constraint.maxRotation.y, bone.rotation.y),\n );\n\n // Clamp Z rotation\n bone.rotation.z = Math.max(\n constraint.minRotation.z,\n Math.min(constraint.maxRotation.z, bone.rotation.z),\n );\n};\n\n// Reusable matrix objects for world transform calculations (avoid allocations in useFrame)\nconst tempMatrix = new THREE.Matrix4();\nconst tempQuaternion = new THREE.Quaternion();\nconst tempScale = new THREE.Vector3();\n\n/**\n * Get world position of bone\n *\n * Calculates absolute world position by traversing parent chain.\n * Uses proper matrix multiplication to account for parent rotations.\n *\n * @param bone - Bone to get world position for\n * @returns World position as Vector3\n *\n * @korean 뼈의세계위치구하기\n */\nexport const getBoneWorldPosition = (bone: Bone): THREE.Vector3 => {\n // Build the bone chain from root to this bone\n const boneChain: Bone[] = [];\n let currentBone: Bone | null = bone;\n while (currentBone) {\n boneChain.unshift(currentBone);\n currentBone = currentBone.parent;\n }\n\n // Compose world matrix by multiplying all local transforms\n const worldMatrix = new THREE.Matrix4();\n worldMatrix.identity();\n\n for (const b of boneChain) {\n tempMatrix.compose(\n b.position,\n tempQuaternion.setFromEuler(b.rotation),\n b.scale,\n );\n worldMatrix.multiply(tempMatrix);\n }\n\n // Extract world position from composed matrix\n const worldPos = new THREE.Vector3();\n worldMatrix.decompose(worldPos, tempQuaternion, tempScale);\n return worldPos;\n};\n\n/**\n * Get world rotation of bone\n *\n * Calculates absolute world rotation by traversing parent chain.\n * Uses proper quaternion multiplication for correct rotation composition.\n *\n * @param bone - Bone to get world rotation for\n * @returns World rotation as Euler\n *\n * @korean 뼈의세계회전구하기\n */\nexport const getBoneWorldRotation = (bone: Bone): THREE.Euler => {\n // Build the bone chain from root to this bone\n const boneChain: Bone[] = [];\n let currentBone: Bone | null = bone;\n while (currentBone) {\n boneChain.unshift(currentBone);\n currentBone = currentBone.parent;\n }\n\n // Compose world rotation by multiplying quaternions (proper rotation composition)\n const worldQuat = new THREE.Quaternion();\n worldQuat.identity();\n\n for (const b of boneChain) {\n tempQuaternion.setFromEuler(b.rotation);\n worldQuat.multiply(tempQuaternion);\n }\n\n // Convert back to Euler\n const worldRot = new THREE.Euler();\n worldRot.setFromQuaternion(worldQuat);\n return worldRot;\n};\n\n/**\n * Reset bone to rest pose\n *\n * Resets bone position and rotation to default rest pose.\n * Useful for animation blending and initialization.\n *\n * @param bone - Bone to reset\n *\n * @korean 뼈를기본자세로초기화\n */\nexport const resetBoneToRestPose = (bone: Bone): void => {\n bone.position.copy(bone.restPosition);\n bone.rotation.copy(bone.restRotation);\n bone.scale.set(1, 1, 1);\n};\n\n/**\n * Reset entire rig to rest pose\n *\n * Resets all bones in rig to rest pose.\n *\n * @param rig - Skeletal rig to reset\n *\n * @korean 골격을기본자세로초기화\n */\nexport const resetRigToRestPose = (rig: SkeletalRig): void => {\n rig.bones.forEach((bone) => {\n resetBoneToRestPose(bone);\n });\n};\n\n/**\n * Create hand bones with 5 fingers\n *\n * Creates detailed hand structure with 5 fingers (thumb, index, middle, ring, pinky),\n * attached to an existing hand/palm bone.\n * Each finger has 3-4 bones for realistic animation.\n *\n * Finger bone structure:\n * - Thumb: 3 bones (metacarpal, proximal, distal) - no intermediate\n * - Other fingers: 4 bones (metacarpal, proximal, intermediate, distal)\n *\n * Total created by this function: 19 finger bones per hand (3 thumb + 4*4 other fingers),\n * all attached to the provided hand bone.\n *\n * @param handBone - Parent hand bone (acts as the palm/root for finger bones)\n * @param side - Hand side (\"left\" or \"right\")\n * @returns Map of finger bones added to the rig\n *\n * @korean 손뼈생성\n */\nexport const createHandBones = (\n handBone: Bone,\n side: \"left\" | \"right\",\n): Map<string, Bone> => {\n const fingerBones = new Map<string, Bone>();\n\n // Hand orientation: left hand extends to -X, right hand extends to +X\n const sideMultiplier = side === \"left\" ? -1 : 1;\n\n // Thumb (3 bones) - offset slightly toward palm center and forward\n const thumbMeta = createBone(\n `${\n BoneName[`THUMB_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [0.015 * sideMultiplier, 0.02, 0.01],\n 0.025,\n );\n const thumbProx = createBone(\n `${\n BoneName[`THUMB_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n thumbMeta,\n [0.015 * sideMultiplier, 0.015, 0.01],\n 0.02,\n );\n const thumbDist = createBone(\n `${\n BoneName[`THUMB_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n thumbProx,\n [0.01 * sideMultiplier, 0.01, 0],\n 0.015,\n );\n\n fingerBones.set(thumbMeta.name, thumbMeta);\n fingerBones.set(thumbProx.name, thumbProx);\n fingerBones.set(thumbDist.name, thumbDist);\n\n // Index finger (4 bones)\n const indexMeta = createBone(\n `${\n BoneName[`INDEX_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [0.015 * sideMultiplier, 0.06, 0],\n 0.03,\n );\n const indexProx = createBone(\n `${\n BoneName[`INDEX_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n indexMeta,\n [0, 0.025, 0],\n 0.025,\n );\n const indexInter = createBone(\n `${\n BoneName[`INDEX_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n indexProx,\n [0, 0.02, 0],\n 0.02,\n );\n const indexDist = createBone(\n `${\n BoneName[`INDEX_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n indexInter,\n [0, 0.015, 0],\n 0.015,\n );\n\n fingerBones.set(indexMeta.name, indexMeta);\n fingerBones.set(indexProx.name, indexProx);\n fingerBones.set(indexInter.name, indexInter);\n fingerBones.set(indexDist.name, indexDist);\n\n // Middle finger (4 bones) - longest finger\n const middleMeta = createBone(\n `${\n BoneName[`MIDDLE_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [0.005 * sideMultiplier, 0.065, 0],\n 0.035,\n );\n const middleProx = createBone(\n `${\n BoneName[`MIDDLE_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n middleMeta,\n [0, 0.03, 0],\n 0.03,\n );\n const middleInter = createBone(\n `${\n BoneName[`MIDDLE_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n middleProx,\n [0, 0.025, 0],\n 0.025,\n );\n const middleDist = createBone(\n `${\n BoneName[`MIDDLE_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n middleInter,\n [0, 0.02, 0],\n 0.02,\n );\n\n fingerBones.set(middleMeta.name, middleMeta);\n fingerBones.set(middleProx.name, middleProx);\n fingerBones.set(middleInter.name, middleInter);\n fingerBones.set(middleDist.name, middleDist);\n\n // Ring finger (4 bones)\n const ringMeta = createBone(\n `${\n BoneName[`RING_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [-0.005 * sideMultiplier, 0.06, 0],\n 0.03,\n );\n const ringProx = createBone(\n `${\n BoneName[`RING_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n ringMeta,\n [0, 0.025, 0],\n 0.025,\n );\n const ringInter = createBone(\n `${\n BoneName[`RING_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n ringProx,\n [0, 0.02, 0],\n 0.02,\n );\n const ringDist = createBone(\n `${\n BoneName[`RING_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n ringInter,\n [0, 0.015, 0],\n 0.015,\n );\n\n fingerBones.set(ringMeta.name, ringMeta);\n fingerBones.set(ringProx.name, ringProx);\n fingerBones.set(ringInter.name, ringInter);\n fingerBones.set(ringDist.name, ringDist);\n\n // Pinky finger (4 bones) - shortest finger\n const pinkyMeta = createBone(\n `${\n BoneName[`PINKY_META_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n handBone,\n [-0.015 * sideMultiplier, 0.05, 0],\n 0.025,\n );\n const pinkyProx = createBone(\n `${\n BoneName[`PINKY_PROX_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n pinkyMeta,\n [0, 0.02, 0],\n 0.02,\n );\n const pinkyInter = createBone(\n `${\n BoneName[`PINKY_INTER_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n pinkyProx,\n [0, 0.015, 0],\n 0.015,\n );\n const pinkyDist = createBone(\n `${\n BoneName[`PINKY_DIST_${side.toUpperCase()[0]}` as keyof typeof BoneName]\n }`,\n pinkyInter,\n [0, 0.01, 0],\n 0.01,\n );\n\n fingerBones.set(pinkyMeta.name, pinkyMeta);\n fingerBones.set(pinkyProx.name, pinkyProx);\n fingerBones.set(pinkyInter.name, pinkyInter);\n fingerBones.set(pinkyDist.name, pinkyDist);\n\n return fingerBones;\n};\n\n/**\n * Create humanoid rig with optional hand bones\n *\n * Creates complete skeletal rig with optional detailed hand bones.\n * Hand bones can be excluded for performance (LOD system).\n *\n * @param includeHandBones - Whether to include detailed hand bones (default: false)\n * @returns Complete skeletal rig with or without hand bones\n *\n * @korean 손뼈포함골격생성\n */\nexport const createHumanoidRigWithHands = (\n includeHandBones: boolean = false,\n): SkeletalRig => {\n // Create base rig\n const baseRig = createHumanoidRig();\n\n // If hand bones not requested, return base rig\n if (!includeHandBones) {\n return baseRig;\n }\n\n // Get hand bones from base rig\n const leftHand = baseRig.bones.get(BoneName.HAND_L);\n const rightHand = baseRig.bones.get(BoneName.HAND_R);\n\n if (!leftHand || !rightHand) {\n console.warn(\"Hand bones not found in base rig\");\n return baseRig;\n }\n\n // Create finger bones\n const leftFingerBones = createHandBones(leftHand, \"left\");\n const rightFingerBones = createHandBones(rightHand, \"right\");\n\n // Add finger bones to rig bone map\n leftFingerBones.forEach((bone, name) => {\n baseRig.bones.set(name, bone);\n });\n rightFingerBones.forEach((bone, name) => {\n baseRig.bones.set(name, bone);\n });\n\n return {\n ...baseRig,\n boneCount: baseRig.bones.size,\n };\n};\n\n/**\n * Torso rotation constraints for anatomically correct upper/lower body movement\n *\n * Defines limits and behavior for independent torso rotation relative to hips,\n * enabling realistic strafing and lateral movement while facing opponent.\n *\n * Korean terminology:\n * - 허리회전 (Heorhwoejeon) - Torso rotation\n * - 해부학적제약 (Haebuhakjeok Jeyak) - Anatomical constraints\n *\n * @korean 허리회전제약조건\n */\nexport const TORSO_CONSTRAINTS = {\n /**\n * Maximum torso rotation relative to hips (radians)\n * ±90° = π/2 radians - anatomically safe rotation limit\n *\n * @korean 최대회전각도\n */\n MAX_ROTATION: Math.PI / 2,\n\n /**\n * Minimum torso rotation relative to hips (radians)\n * -90° = -π/2 radians\n *\n * @korean 최소회전각도\n */\n MIN_ROTATION: -Math.PI / 2,\n\n /**\n * Target interpolation time in seconds\n * 200ms provides smooth, natural rotation feel\n *\n * @korean 보간시간\n */\n INTERPOLATION_TIME: 0.2,\n\n /**\n * Power modifier range for hip rotation\n * [min, max] = [10%, 30%] damage bonus from proper hip engagement\n *\n * @korean 파워배율범위\n */\n POWER_MODIFIER_RANGE: [0.1, 0.3] as const,\n} as const;\n\n/**\n * Calculate torso rotation to face opponent while moving\n *\n * Determines optimal torso rotation angle to keep upper body facing opponent\n * while hips/legs are oriented in movement direction. Enforces anatomical\n * constraints (±90° max rotation).\n *\n * @param currentPosition - Player's current world position\n * @param opponentPosition - Opponent's current world position\n * @param _movementDirection - Direction of player movement (reserved for future use)\n * @param hipRotation - Current hip/pelvis rotation in radians\n * @returns Torso rotation in radians relative to hips (clamped to ±90°)\n *\n * @example\n * ```typescript\n * const playerPos = new THREE.Vector3(0, 0, 0);\n * const opponentPos = new THREE.Vector3(0, 0, 5); // Directly in front along Z+\n * const moveDir = new THREE.Vector3(0, 0, 1); // Moving forward\n * const hipRot = 0; // Hips facing forward (Z+)\n *\n * const torsoRot = calculateTorsoRotation(playerPos, opponentPos, moveDir, hipRot);\n * // Returns 0 (opponent is already aligned with hips)\n * ```\n *\n * @korean 상대를향한허리회전계산\n */\nexport function calculateTorsoRotation(\n currentPosition: THREE.Vector3,\n opponentPosition: THREE.Vector3,\n _movementDirection: THREE.Vector3,\n hipRotation: number,\n): number {\n // Calculate angle to opponent\n const directionToOpponent = opponentPosition\n .clone()\n .sub(currentPosition)\n .normalize();\n // Use atan2(x, z) - X is horizontal, Z is forward/back in Three.js\n const angleToOpponent = Math.atan2(\n directionToOpponent.x,\n directionToOpponent.z,\n );\n\n // Calculate torso rotation relative to hips\n let torsoRotation = angleToOpponent - hipRotation;\n\n // Normalize to -π to π range\n while (torsoRotation > Math.PI) torsoRotation -= 2 * Math.PI;\n while (torsoRotation < -Math.PI) torsoRotation += 2 * Math.PI;\n\n // Apply anatomical constraints (±90°)\n torsoRotation = Math.max(\n TORSO_CONSTRAINTS.MIN_ROTATION,\n Math.min(TORSO_CONSTRAINTS.MAX_ROTATION, torsoRotation),\n );\n\n return torsoRotation;\n}\n\n/**\n * Calculate damage modifier from hip rotation\n *\n * Determines power bonus applied to techniques based on hip rotation angle.\n * Greater hip rotation generates more power through proper biomechanics,\n * with strikes benefiting most from full rotation.\n *\n * @param hipRotationAngle - Hip rotation angle in radians (typically from torso twist)\n * @param techniqueType - Type of technique ('strike', 'throw', or 'joint')\n * @returns Damage multiplier (1.0-1.3 for strikes, 1.0-1.1 for throws/joints)\n *\n * @example\n * ```typescript\n * // Full hip rotation on strike technique\n * const modifier = calculateHipRotationPowerModifier(Math.PI / 2, 'strike');\n * // Returns 1.30 (30% damage bonus)\n *\n * // Half rotation on throw\n * const throwMod = calculateHipRotationPowerModifier(Math.PI / 4, 'throw');\n * // Returns 1.05 (5% damage bonus)\n * ```\n *\n * @korean 허리회전으로인한데미지배율계산\n */\nexport function calculateHipRotationPowerModifier(\n hipRotationAngle: number,\n techniqueType: \"strike\" | \"throw\" | \"joint\",\n): number {\n // Normalize rotation to 0-1 range (0 = no rotation, 1 = max rotation)\n // Clamp to max rotation first to handle any values exceeding ±90°\n const clampedAngle = Math.max(\n -TORSO_CONSTRAINTS.MAX_ROTATION,\n Math.min(TORSO_CONSTRAINTS.MAX_ROTATION, Math.abs(hipRotationAngle)),\n );\n const normalizedRotation = clampedAngle / TORSO_CONSTRAINTS.MAX_ROTATION;\n\n // Strikes benefit most from hip rotation (up to 30% bonus)\n // Throws get moderate benefit (up to 10% bonus)\n // Joint locks get minimal benefit (up to 10% bonus)\n const baseModifier = techniqueType === \"strike\" ? 0.3 : 0.1;\n\n return 1.0 + normalizedRotation * baseModifier;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA2CA,IAAa,cACX,MACA,QACA,UACA,SAAS,OACA;CACT,MAAM,MAAM,IAAI,MAAM,QAAQ,SAAS,IAAI,SAAS,IAAI,SAAS,EAAE;CACnE,MAAM,MAAM,IAAI,MAAM,MAAM,GAAG,GAAG,CAAC;CACnC,MAAM,QAAQ,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC;CAEvC,MAAM,OAAa;EACjB;EACA;EACA,UAAU,IAAI,MAAM;EACpB,UAAU,IAAI,MAAM;EACpB,OAAO,MAAM,MAAM;EACnB,UAAU,CAAC;EACX;EACA,cAAc,IAAI,MAAM;EACxB,cAAc,IAAI,MAAM;CAC1B;CAGA,IAAI,QACF,OAAO,SAAS,KAAK,IAAI;CAG3B,OAAO;AACT;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6NA,IAAa,2BACX,eACgB;CAEhB,MAAM,OAAO,4BAA4B,UAAU;CAGnD,MAAM,uBAAuB,WAAW,WAAW,aAAa,IAAI;CACpE,MAAM,kBAAkB,WAAW,WAAW,aAAa,IAAI;CAI/D,MAAM,OAAO,WACX,SAAS,QACT,MACA;EAAC;EAAG,KAAK;EAAc;CAAC,GACxB,KAAK,GACP;CAGA,MAAM,SAAS,WACb,SAAS,aACT,MACA;EAAC;EAAG,KAAK,aAAa;EAAK;CAAC,GAC5B,KAAK,UACP;CACA,MAAM,SAAS,WACb,SAAS,cACT,QACA;EAAC;EAAG,KAAK;EAAa;CAAC,GACvB,KAAK,WACP;CACA,MAAM,SAAS,WACb,SAAS,aACT,QACA;EAAC;EAAG,KAAK;EAAY;CAAC,GACtB,KAAK,UACP;CAGA,MAAM,OAAO,WACX,SAAS,MACT,QACA;EAAC;EAAG,KAAK,OAAO;EAAK;CAAC,GACtB,KAAK,IACP;CACA,MAAM,OAAO,WACX,SAAS,MACT,MACA;EAAC;EAAG,KAAK,OAAO;EAAM;CAAC,GACvB,KAAK,IACP;CAGA,MAAM,eAAe,WACnB,SAAS,YACT,QACA;EAAC,CAAC,uBAAuB;EAAK,KAAK,OAAO;EAAK;CAAC,GAChD,KAAK,QACP;CACA,MAAM,eAAe,WACnB,SAAS,aACT,cACA;EAAC,CAAC,KAAK;EAAU;EAAG;CAAC,GACrB,KAAK,QACP;CACA,MAAM,YAAY,WAChB,SAAS,SACT,cACA;EAAC,CAAC,KAAK;EAAU;EAAG;CAAC,GACrB,KAAK,KACP;CACA,MAAM,cAAc,WAClB,SAAS,WACT,WACA;EAAC,CAAC,KAAK;EAAO;EAAG;CAAC,GAClB,KAAK,OACP;CACA,MAAM,YAAY,WAChB,SAAS,SACT,aACA;EAAC,CAAC,KAAK;EAAS;EAAG;CAAC,GACpB,KAAK,KACP;CACA,MAAM,WAAW,WACf,SAAS,QACT,WACA;EAAC,CAAC,KAAK;EAAO;EAAG;CAAC,GAClB,KAAK,IACP;CAGA,MAAM,gBAAgB,WACpB,SAAS,YACT,QACA;EAAC,uBAAuB;EAAK,KAAK,OAAO;EAAK;CAAC,GAC/C,KAAK,QACP;CACA,MAAM,gBAAgB,WACpB,SAAS,aACT,eACA;EAAC,KAAK;EAAU;EAAG;CAAC,GACpB,KAAK,QACP;CACA,MAAM,aAAa,WACjB,SAAS,SACT,eACA;EAAC,KAAK;EAAU;EAAG;CAAC,GACpB,KAAK,KACP;CACA,MAAM,eAAe,WACnB,SAAS,WACT,YACA;EAAC,KAAK;EAAO;EAAG;CAAC,GACjB,KAAK,OACP;CACA,MAAM,aAAa,WACjB,SAAS,SACT,cACA;EAAC,KAAK;EAAS;EAAG;CAAC,GACnB,KAAK,KACP;CACA,MAAM,YAAY,WAChB,SAAS,QACT,YACA;EAAC,KAAK;EAAO;EAAG;CAAC,GACjB,KAAK,IACP;CAGA,MAAM,UAAU,WACd,SAAS,OACT,MACA;EAAC,CAAC;EAAiB,CAAC,KAAK,MAAM;EAAK;CAAC,GACrC,KAAK,GACP;CACA,MAAM,YAAY,WAChB,SAAS,SACT,SACA;EAAC;EAAG,CAAC,KAAK;EAAK;CAAC,GAChB,KAAK,KACP;CACA,MAAM,WAAW,WACf,SAAS,QACT,WACA;EAAC;EAAG,CAAC,KAAK;EAAO;CAAC,GAClB,KAAK,IACP;CACA,MAAM,WAAW,WACf,SAAS,QACT,UACA;EAAC;EAAG,CAAC,KAAK;EAAM;CAAC,GACjB,KAAK,IACP;CACA,MAAM,WAAW,WACf,SAAS,QACT,UACA;EAAC;EAAG,CAAC,KAAK;EAAM,KAAK,OAAO;CAAG,GAC/B,KAAK,IACP;CAGA,MAAM,WAAW,WACf,SAAS,OACT,MACA;EAAC;EAAiB,CAAC,KAAK,MAAM;EAAK;CAAC,GACpC,KAAK,GACP;CACA,MAAM,aAAa,WACjB,SAAS,SACT,UACA;EAAC;EAAG,CAAC,KAAK;EAAK;CAAC,GAChB,KAAK,KACP;CACA,MAAM,YAAY,WAChB,SAAS,QACT,YACA;EAAC;EAAG,CAAC,KAAK;EAAO;CAAC,GAClB,KAAK,IACP;CACA,MAAM,YAAY,WAChB,SAAS,QACT,WACA;EAAC;EAAG,CAAC,KAAK;EAAM;CAAC,GACjB,KAAK,IACP;CACA,MAAM,YAAY,WAChB,SAAS,QACT,WACA;EAAC;EAAG,CAAC,KAAK;EAAM,KAAK,OAAO;CAAG,GAC/B,KAAK,IACP;CAGA,MAAM,QAAQ,IAAI,IAAkB;EAClC,CAAC,SAAS,QAAQ,IAAI;EACtB,CAAC,SAAS,aAAa,MAAM;EAC7B,CAAC,SAAS,cAAc,MAAM;EAC9B,CAAC,SAAS,aAAa,MAAM;EAC7B,CAAC,SAAS,MAAM,IAAI;EACpB,CAAC,SAAS,MAAM,IAAI;EACpB,CAAC,SAAS,YAAY,YAAY;EAClC,CAAC,SAAS,aAAa,YAAY;EACnC,CAAC,SAAS,SAAS,SAAS;EAC5B,CAAC,SAAS,WAAW,WAAW;EAChC,CAAC,SAAS,SAAS,SAAS;EAC5B,CAAC,SAAS,QAAQ,QAAQ;EAC1B,CAAC,SAAS,YAAY,aAAa;EACnC,CAAC,SAAS,aAAa,aAAa;EACpC,CAAC,SAAS,SAAS,UAAU;EAC7B,CAAC,SAAS,WAAW,YAAY;EACjC,CAAC,SAAS,SAAS,UAAU;EAC7B,CAAC,SAAS,QAAQ,SAAS;EAC3B,CAAC,SAAS,OAAO,OAAO;EACxB,CAAC,SAAS,SAAS,SAAS;EAC5B,CAAC,SAAS,QAAQ,QAAQ;EAC1B,CAAC,SAAS,QAAQ,QAAQ;EAC1B,CAAC,SAAS,QAAQ,QAAQ;EAC1B,CAAC,SAAS,OAAO,QAAQ;EACzB,CAAC,SAAS,SAAS,UAAU;EAC7B,CAAC,SAAS,QAAQ,SAAS;EAC3B,CAAC,SAAS,QAAQ,SAAS;EAC3B,CAAC,SAAS,QAAQ,SAAS;CAC7B,CAAC;CAED,OAAO;EACL;EACA;EACA,WAAW,MAAM;CACnB;AACF;AAac,SAAS,SACN,IAAI,MAAM,QAAQ,GAAG,GAAG,IAAI,GAC5B,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC,GAI5B,SAAS,SACN,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC,GACzB,IAAI,MAAM,QAAQ,GAAG,GAAG,GAAG,GAM9B,SAAS,QACN,IAAI,MAAM,QAAQ,MAAM,GAAG,CAAC,GAC5B,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC,GAI5B,SAAS,QACN,IAAI,MAAM,QAAQ,MAAM,GAAG,CAAC,GAC5B,IAAI,MAAM,QAAQ,GAAG,GAAG,CAAC,GAM5B,SAAS,YACN,IAAI,MAAM,QAAQ,MAAM,MAAM,EAAI,GAClC,IAAI,MAAM,QAAQ,KAAK,KAAK,CAAG,GAIlC,SAAS,YACN,IAAI,MAAM,QAAQ,MAAM,MAAM,EAAI,GAClC,IAAI,MAAM,QAAQ,KAAK,KAAK,CAAG,GAMlC,SAAS,OACN,IAAI,MAAM,QAAQ,MAAM,KAAM,IAAI,GAClC,IAAI,MAAM,QAAQ,KAAK,IAAK,GAAG,GAIlC,SAAS,OACN,IAAI,MAAM,QAAQ,MAAM,KAAM,IAAI,GAClC,IAAI,MAAM,QAAQ,KAAK,IAAK,GAAG,GAMlC,SAAS,MACN,IAAI,MAAM,QAAQ,KAAM,KAAM,GAAI,GAClC,IAAI,MAAM,QAAQ,IAAK,IAAK,EAAG,GAMlC,SAAS,aACN,IAAI,MAAM,QAAQ,KAAM,KAAM,GAAI,GAClC,IAAI,MAAM,QAAQ,IAAK,IAAK,EAAG,GAIlC,SAAS,cACN,IAAI,MAAM,QAAQ,KAAM,KAAM,GAAI,GAClC,IAAI,MAAM,QAAQ,IAAK,IAAK,EAAG,GAIlC,SAAS,aACN,IAAI,MAAM,QAAQ,KAAM,KAAM,GAAI,GAClC,IAAI,MAAM,QAAQ,IAAK,IAAK,EAAG;AAiBjC,SAAS,YACX,SAAS,QAEhB,SAAS,YACT,SAAS,aACT,SAAS,SACT,SAAS,WACT,SAAS,SACT,SAAS,QAOA,SAAS,YACX,SAAS,QAEhB,SAAS,YACT,SAAS,aACT,SAAS,SACT,SAAS,WACT,SAAS,SACT,SAAS,QAOA,SAAS,OACX,SAAS,QAEhB,SAAS,OACT,SAAS,SACT,SAAS,QACT,SAAS,QACT,SAAS,QAOA,SAAS,OACX,SAAS,QAEhB,SAAS,OACT,SAAS,SACT,SAAS,QACT,SAAS,QACT,SAAS,QAOA,SAAS,QACX,SAAS,MAEhB,SAAS,QACT,SAAS,aACT,SAAS,cACT,SAAS,aACT,SAAS,MACT,SAAS;AAwCI,IAAI,MAAM,QAAQ;AACd,IAAI,MAAM,WAAW;AAC1B,IAAI,MAAM,QAAQ;;;;;;;;;;;;;AAkYpC,IAAa,oBAAoB;;;;;;;CAO/B,cAAc,KAAK,KAAK;;;;;;;CAQxB,cAAc,CAAC,KAAK,KAAK;;;;;;;CAQzB,oBAAoB;;;;;;;CAQpB,sBAAsB,CAAC,IAAK,EAAG;AACjC;;;;;;;;;;;;;;;;;;;;;;;;;AAqFA,SAAgB,kCACd,kBACA,eACQ;CAcR,OAAO,IAXc,KAAK,IACxB,CAAC,kBAAkB,cACnB,KAAK,IAAI,kBAAkB,cAAc,KAAK,IAAI,gBAAgB,CAAC,CAE1C,IAAe,kBAAkB,gBAKvC,kBAAkB,WAAW,KAAM;AAG1D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrigramGuardApplicator.js","names":[],"sources":["../../../../src/systems/animation/builders/TrigramGuardApplicator.ts"],"sourcesContent":["/**\n * Trigram Guard Applicator\n *\n * Applies full trigram-specific guard poses to animation keyframes.\n * Unlike the generic `withGuard()` method that only sets arm positions,\n * this applicator sets the complete body position including:\n * - Arms (shoulder, elbow, wrist)\n * - Legs (hip, knee, ankle)\n * - Torso and pelvis rotation\n *\n * This ensures that walk/run/idle animations maintain proper\n * trigram-specific guard positions for authentic Korean martial arts movement.\n *\n * @module systems/animation/builders/TrigramGuardApplicator\n * @korean 팔괘방어자세적용기\n */\n\nimport { TrigramStance } from \"@/types/common\";\nimport type { StanceGuardPose } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport type { StanceLaterality } from \"../../trigram/types\";\nimport {\n GAM_WATER_GUARD_POSE,\n GAN_MOUNTAIN_GUARD_POSE,\n GEON_HIGH_GUARD_POSE,\n getGuardPoseForStance,\n GON_EARTH_GUARD_POSE,\n JIN_THUNDER_GUARD_POSE,\n LI_FIRE_GUARD_POSE,\n SON_WIND_GUARD_POSE,\n TAE_FLUID_GUARD_POSE,\n} from \"../catalogs/StanceGuardPoses\";\nimport type { KeyframeConfig } from \"./KeyframeConfig\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// DIRECT GUARD POSE ACCESS MAP (For performance in locomotion)\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Direct access to guard poses by trigram stance name\n * Avoids repeated function calls in animation loops\n *\n * @korean 방어자세직접접근맵\n */\nexport const TRIGRAM_GUARD_POSES: Readonly<\n Record<TrigramStance, StanceGuardPose>\n> = {\n [TrigramStance.GEON]: GEON_HIGH_GUARD_POSE,\n [TrigramStance.TAE]: TAE_FLUID_GUARD_POSE,\n [TrigramStance.LI]: LI_FIRE_GUARD_POSE,\n [TrigramStance.JIN]: JIN_THUNDER_GUARD_POSE,\n [TrigramStance.SON]: SON_WIND_GUARD_POSE,\n [TrigramStance.GAM]: GAM_WATER_GUARD_POSE,\n [TrigramStance.GAN]: GAN_MOUNTAIN_GUARD_POSE,\n [TrigramStance.GON]: GON_EARTH_GUARD_POSE,\n} as const;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// APPLICATION OPTIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Options for applying trigram guard pose\n *\n * @korean 팔괘방어자세적용옵션\n */\nexport interface TrigramGuardOptions {\n /** Apply arm positions (shoulder, elbow, wrist) */\n readonly includeArms?: boolean;\n /** Apply leg positions (hip, knee, ankle) */\n readonly includeLegs?: boolean;\n /** Apply torso rotation */\n readonly includeTorso?: boolean;\n /** Apply pelvis rotation */\n readonly includePelvis?: boolean;\n /** Blend factor 0-1 for partial application (locomotion blending) */\n readonly blendFactor?: number;\n /** Stance laterality (\"left\" or \"right\") */\n readonly laterality?: StanceLaterality;\n}\n\n/**\n * Default options for full guard pose application\n */\nconst DEFAULT_OPTIONS: Required<TrigramGuardOptions> = {\n includeArms: true,\n includeLegs: true,\n includeTorso: true,\n includePelvis: true,\n blendFactor: 1.0,\n laterality: \"right\",\n} as const;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// CORE APPLICATION FUNCTION\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Apply trigram-specific guard pose to a KeyframeConfig\n *\n * Sets the complete body position for the specified trigram stance,\n * including arms, legs, torso, and pelvis. This creates authentic\n * Korean martial arts posture for each of the eight trigram stances.\n *\n * @param config - KeyframeConfig to apply guard pose to\n * @param stance - Trigram stance (e.g., TrigramStance.GEON)\n * @param options - Application options\n *\n * @example\n * ```typescript\n * // Full guard pose application\n * applyTrigramGuardToConfig(kf, TrigramStance.GEON);\n *\n * // Arms only (for locomotion that sets its own leg positions)\n * applyTrigramGuardToConfig(kf, TrigramStance.GEON, {\n * includeLegs: false,\n * includePelvis: false\n * });\n *\n * // Blended for walk cycle transitions\n * applyTrigramGuardToConfig(kf, TrigramStance.TAE, {\n * blendFactor: 0.7\n * });\n * ```\n *\n * @korean 팔괘방어자세설정적용\n */\nexport function applyTrigramGuardToConfig(\n config: KeyframeConfig,\n stance: TrigramStance,\n options: TrigramGuardOptions = {},\n): void {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n\n // Get guard pose for stance and laterality\n const guardPose =\n opts.laterality === \"right\"\n ? TRIGRAM_GUARD_POSES[stance]\n : getGuardPoseForStance(stance, opts.laterality);\n\n if (!guardPose) {\n console.warn(\n `[TrigramGuardApplicator] No guard pose found for stance: ${stance}`,\n );\n return;\n }\n\n const blend = opts.blendFactor;\n\n // Apply arm positions\n if (opts.includeArms) {\n applyArmsToConfig(config, guardPose, blend);\n }\n\n // Apply leg positions\n if (opts.includeLegs) {\n applyLegsToConfig(config, guardPose, blend);\n }\n\n // Apply torso rotation\n if (opts.includeTorso) {\n config.rotate(\n BoneName.SPINE_UPPER,\n guardPose.torso.x * blend,\n guardPose.torso.y * blend,\n guardPose.torso.z * blend,\n );\n }\n\n // Apply pelvis rotation\n if (opts.includePelvis) {\n config.rotate(\n BoneName.PELVIS,\n guardPose.pelvis.x * blend,\n guardPose.pelvis.y * blend,\n guardPose.pelvis.z * blend,\n );\n }\n}\n\n/**\n * Apply arm positions from guard pose to config\n */\nfunction applyArmsToConfig(\n config: KeyframeConfig,\n guardPose: StanceGuardPose,\n blend: number,\n): void {\n // Left arm\n config.rotate(\n BoneName.SHOULDER_L,\n guardPose.leftArm.shoulder.x * blend,\n guardPose.leftArm.shoulder.y * blend,\n guardPose.leftArm.shoulder.z * blend,\n );\n config.rotate(\n BoneName.ELBOW_L,\n guardPose.leftArm.elbow.x * blend,\n guardPose.leftArm.elbow.y * blend,\n guardPose.leftArm.elbow.z * blend,\n );\n config.rotate(\n BoneName.WRIST_L,\n guardPose.leftArm.wrist.x * blend,\n guardPose.leftArm.wrist.y * blend,\n guardPose.leftArm.wrist.z * blend,\n );\n\n // Right arm\n config.rotate(\n BoneName.SHOULDER_R,\n guardPose.rightArm.shoulder.x * blend,\n guardPose.rightArm.shoulder.y * blend,\n guardPose.rightArm.shoulder.z * blend,\n );\n config.rotate(\n BoneName.ELBOW_R,\n guardPose.rightArm.elbow.x * blend,\n guardPose.rightArm.elbow.y * blend,\n guardPose.rightArm.elbow.z * blend,\n );\n config.rotate(\n BoneName.WRIST_R,\n guardPose.rightArm.wrist.x * blend,\n guardPose.rightArm.wrist.y * blend,\n guardPose.rightArm.wrist.z * blend,\n );\n}\n\n/**\n * Apply leg positions from guard pose to config\n */\nfunction applyLegsToConfig(\n config: KeyframeConfig,\n guardPose: StanceGuardPose,\n blend: number,\n): void {\n // Left leg\n config.rotate(\n BoneName.HIP_L,\n guardPose.leftLeg.hip.x * blend,\n guardPose.leftLeg.hip.y * blend,\n guardPose.leftLeg.hip.z * blend,\n );\n config.rotate(\n BoneName.KNEE_L,\n guardPose.leftLeg.knee.x * blend,\n guardPose.leftLeg.knee.y * blend,\n guardPose.leftLeg.knee.z * blend,\n );\n config.rotate(\n BoneName.FOOT_L,\n guardPose.leftLeg.ankle.x * blend,\n guardPose.leftLeg.ankle.y * blend,\n guardPose.leftLeg.ankle.z * blend,\n );\n\n // Right leg\n config.rotate(\n BoneName.HIP_R,\n guardPose.rightLeg.hip.x * blend,\n guardPose.rightLeg.hip.y * blend,\n guardPose.rightLeg.hip.z * blend,\n );\n config.rotate(\n BoneName.KNEE_R,\n guardPose.rightLeg.knee.x * blend,\n guardPose.rightLeg.knee.y * blend,\n guardPose.rightLeg.knee.z * blend,\n );\n config.rotate(\n BoneName.FOOT_R,\n guardPose.rightLeg.ankle.x * blend,\n guardPose.rightLeg.ankle.y * blend,\n guardPose.rightLeg.ankle.z * blend,\n );\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// GUARD ARM HELPERS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Get guard arm base rotations without swing for a trigram\n *\n * Returns the base arm position for the trigram's guard pose.\n * Use this when you want to manually add swing offsets.\n *\n * @param stance - Trigram stance\n * @returns Left and right arm base rotations\n *\n * @korean 팔자세베이스가져오기\n */\nexport function getGuardArmBase(stance: TrigramStance): {\n left: {\n shoulder: [number, number, number];\n elbow: [number, number, number];\n };\n right: {\n shoulder: [number, number, number];\n elbow: [number, number, number];\n };\n} {\n const guardPose = TRIGRAM_GUARD_POSES[stance];\n if (!guardPose) {\n // Fallback neutral guard\n return {\n left: { shoulder: [-0.6, 0.4, 0.3], elbow: [0, 0, -1.6] },\n right: { shoulder: [-0.6, -0.4, -0.3], elbow: [0, 0, 1.6] },\n };\n }\n\n return {\n left: {\n shoulder: [\n guardPose.leftArm.shoulder.x,\n guardPose.leftArm.shoulder.y,\n guardPose.leftArm.shoulder.z,\n ],\n elbow: [\n guardPose.leftArm.elbow.x,\n guardPose.leftArm.elbow.y,\n guardPose.leftArm.elbow.z,\n ],\n },\n right: {\n shoulder: [\n guardPose.rightArm.shoulder.x,\n guardPose.rightArm.shoulder.y,\n guardPose.rightArm.shoulder.z,\n ],\n elbow: [\n guardPose.rightArm.elbow.x,\n guardPose.rightArm.elbow.y,\n guardPose.rightArm.elbow.z,\n ],\n },\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TrigramGuardApplicator.js","names":[],"sources":["../../../../src/systems/animation/builders/TrigramGuardApplicator.ts"],"sourcesContent":["/**\n * Trigram Guard Applicator\n *\n * Applies full trigram-specific guard poses to animation keyframes.\n * Unlike the generic `withGuard()` method that only sets arm positions,\n * this applicator sets the complete body position including:\n * - Arms (shoulder, elbow, wrist)\n * - Legs (hip, knee, ankle)\n * - Torso and pelvis rotation\n *\n * This ensures that walk/run/idle animations maintain proper\n * trigram-specific guard positions for authentic Korean martial arts movement.\n *\n * @module systems/animation/builders/TrigramGuardApplicator\n * @korean 팔괘방어자세적용기\n */\n\nimport { TrigramStance } from \"@/types/common\";\nimport type { StanceGuardPose } from \"@/types/skeletal\";\nimport { BoneName } from \"@/types/skeletal\";\nimport type { StanceLaterality } from \"../../trigram/types\";\nimport {\n GAM_WATER_GUARD_POSE,\n GAN_MOUNTAIN_GUARD_POSE,\n GEON_HIGH_GUARD_POSE,\n getGuardPoseForStance,\n GON_EARTH_GUARD_POSE,\n JIN_THUNDER_GUARD_POSE,\n LI_FIRE_GUARD_POSE,\n SON_WIND_GUARD_POSE,\n TAE_FLUID_GUARD_POSE,\n} from \"../catalogs/StanceGuardPoses\";\nimport type { KeyframeConfig } from \"./KeyframeConfig\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// DIRECT GUARD POSE ACCESS MAP (For performance in locomotion)\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Direct access to guard poses by trigram stance name\n * Avoids repeated function calls in animation loops\n *\n * @korean 방어자세직접접근맵\n */\nexport const TRIGRAM_GUARD_POSES: Readonly<\n Record<TrigramStance, StanceGuardPose>\n> = {\n [TrigramStance.GEON]: GEON_HIGH_GUARD_POSE,\n [TrigramStance.TAE]: TAE_FLUID_GUARD_POSE,\n [TrigramStance.LI]: LI_FIRE_GUARD_POSE,\n [TrigramStance.JIN]: JIN_THUNDER_GUARD_POSE,\n [TrigramStance.SON]: SON_WIND_GUARD_POSE,\n [TrigramStance.GAM]: GAM_WATER_GUARD_POSE,\n [TrigramStance.GAN]: GAN_MOUNTAIN_GUARD_POSE,\n [TrigramStance.GON]: GON_EARTH_GUARD_POSE,\n} as const;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// APPLICATION OPTIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Options for applying trigram guard pose\n *\n * @korean 팔괘방어자세적용옵션\n */\nexport interface TrigramGuardOptions {\n /** Apply arm positions (shoulder, elbow, wrist) */\n readonly includeArms?: boolean;\n /** Apply leg positions (hip, knee, ankle) */\n readonly includeLegs?: boolean;\n /** Apply torso rotation */\n readonly includeTorso?: boolean;\n /** Apply pelvis rotation */\n readonly includePelvis?: boolean;\n /** Blend factor 0-1 for partial application (locomotion blending) */\n readonly blendFactor?: number;\n /** Stance laterality (\"left\" or \"right\") */\n readonly laterality?: StanceLaterality;\n}\n\n/**\n * Default options for full guard pose application\n */\nconst DEFAULT_OPTIONS: Required<TrigramGuardOptions> = {\n includeArms: true,\n includeLegs: true,\n includeTorso: true,\n includePelvis: true,\n blendFactor: 1.0,\n laterality: \"right\",\n} as const;\n\n// ═══════════════════════════════════════════════════════════════════════════\n// CORE APPLICATION FUNCTION\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Apply trigram-specific guard pose to a KeyframeConfig\n *\n * Sets the complete body position for the specified trigram stance,\n * including arms, legs, torso, and pelvis. This creates authentic\n * Korean martial arts posture for each of the eight trigram stances.\n *\n * @param config - KeyframeConfig to apply guard pose to\n * @param stance - Trigram stance (e.g., TrigramStance.GEON)\n * @param options - Application options\n *\n * @example\n * ```typescript\n * // Full guard pose application\n * applyTrigramGuardToConfig(kf, TrigramStance.GEON);\n *\n * // Arms only (for locomotion that sets its own leg positions)\n * applyTrigramGuardToConfig(kf, TrigramStance.GEON, {\n * includeLegs: false,\n * includePelvis: false\n * });\n *\n * // Blended for walk cycle transitions\n * applyTrigramGuardToConfig(kf, TrigramStance.TAE, {\n * blendFactor: 0.7\n * });\n * ```\n *\n * @korean 팔괘방어자세설정적용\n */\nexport function applyTrigramGuardToConfig(\n config: KeyframeConfig,\n stance: TrigramStance,\n options: TrigramGuardOptions = {},\n): void {\n const opts = { ...DEFAULT_OPTIONS, ...options };\n\n // Get guard pose for stance and laterality\n const guardPose =\n opts.laterality === \"right\"\n ? TRIGRAM_GUARD_POSES[stance]\n : getGuardPoseForStance(stance, opts.laterality);\n\n if (!guardPose) {\n console.warn(\n `[TrigramGuardApplicator] No guard pose found for stance: ${stance}`,\n );\n return;\n }\n\n const blend = opts.blendFactor;\n\n // Apply arm positions\n if (opts.includeArms) {\n applyArmsToConfig(config, guardPose, blend);\n }\n\n // Apply leg positions\n if (opts.includeLegs) {\n applyLegsToConfig(config, guardPose, blend);\n }\n\n // Apply torso rotation\n if (opts.includeTorso) {\n config.rotate(\n BoneName.SPINE_UPPER,\n guardPose.torso.x * blend,\n guardPose.torso.y * blend,\n guardPose.torso.z * blend,\n );\n }\n\n // Apply pelvis rotation\n if (opts.includePelvis) {\n config.rotate(\n BoneName.PELVIS,\n guardPose.pelvis.x * blend,\n guardPose.pelvis.y * blend,\n guardPose.pelvis.z * blend,\n );\n }\n}\n\n/**\n * Apply arm positions from guard pose to config\n */\nfunction applyArmsToConfig(\n config: KeyframeConfig,\n guardPose: StanceGuardPose,\n blend: number,\n): void {\n // Left arm\n config.rotate(\n BoneName.SHOULDER_L,\n guardPose.leftArm.shoulder.x * blend,\n guardPose.leftArm.shoulder.y * blend,\n guardPose.leftArm.shoulder.z * blend,\n );\n config.rotate(\n BoneName.ELBOW_L,\n guardPose.leftArm.elbow.x * blend,\n guardPose.leftArm.elbow.y * blend,\n guardPose.leftArm.elbow.z * blend,\n );\n config.rotate(\n BoneName.WRIST_L,\n guardPose.leftArm.wrist.x * blend,\n guardPose.leftArm.wrist.y * blend,\n guardPose.leftArm.wrist.z * blend,\n );\n\n // Right arm\n config.rotate(\n BoneName.SHOULDER_R,\n guardPose.rightArm.shoulder.x * blend,\n guardPose.rightArm.shoulder.y * blend,\n guardPose.rightArm.shoulder.z * blend,\n );\n config.rotate(\n BoneName.ELBOW_R,\n guardPose.rightArm.elbow.x * blend,\n guardPose.rightArm.elbow.y * blend,\n guardPose.rightArm.elbow.z * blend,\n );\n config.rotate(\n BoneName.WRIST_R,\n guardPose.rightArm.wrist.x * blend,\n guardPose.rightArm.wrist.y * blend,\n guardPose.rightArm.wrist.z * blend,\n );\n}\n\n/**\n * Apply leg positions from guard pose to config\n */\nfunction applyLegsToConfig(\n config: KeyframeConfig,\n guardPose: StanceGuardPose,\n blend: number,\n): void {\n // Left leg\n config.rotate(\n BoneName.HIP_L,\n guardPose.leftLeg.hip.x * blend,\n guardPose.leftLeg.hip.y * blend,\n guardPose.leftLeg.hip.z * blend,\n );\n config.rotate(\n BoneName.KNEE_L,\n guardPose.leftLeg.knee.x * blend,\n guardPose.leftLeg.knee.y * blend,\n guardPose.leftLeg.knee.z * blend,\n );\n config.rotate(\n BoneName.FOOT_L,\n guardPose.leftLeg.ankle.x * blend,\n guardPose.leftLeg.ankle.y * blend,\n guardPose.leftLeg.ankle.z * blend,\n );\n\n // Right leg\n config.rotate(\n BoneName.HIP_R,\n guardPose.rightLeg.hip.x * blend,\n guardPose.rightLeg.hip.y * blend,\n guardPose.rightLeg.hip.z * blend,\n );\n config.rotate(\n BoneName.KNEE_R,\n guardPose.rightLeg.knee.x * blend,\n guardPose.rightLeg.knee.y * blend,\n guardPose.rightLeg.knee.z * blend,\n );\n config.rotate(\n BoneName.FOOT_R,\n guardPose.rightLeg.ankle.x * blend,\n guardPose.rightLeg.ankle.y * blend,\n guardPose.rightLeg.ankle.z * blend,\n );\n}\n\n// ═══════════════════════════════════════════════════════════════════════════\n// GUARD ARM HELPERS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Get guard arm base rotations without swing for a trigram\n *\n * Returns the base arm position for the trigram's guard pose.\n * Use this when you want to manually add swing offsets.\n *\n * @param stance - Trigram stance\n * @returns Left and right arm base rotations\n *\n * @korean 팔자세베이스가져오기\n */\nexport function getGuardArmBase(stance: TrigramStance): {\n left: {\n shoulder: [number, number, number];\n elbow: [number, number, number];\n };\n right: {\n shoulder: [number, number, number];\n elbow: [number, number, number];\n };\n} {\n const guardPose = TRIGRAM_GUARD_POSES[stance];\n if (!guardPose) {\n // Fallback neutral guard\n return {\n left: { shoulder: [-0.6, 0.4, 0.3], elbow: [0, 0, -1.6] },\n right: { shoulder: [-0.6, -0.4, -0.3], elbow: [0, 0, 1.6] },\n };\n }\n\n return {\n left: {\n shoulder: [\n guardPose.leftArm.shoulder.x,\n guardPose.leftArm.shoulder.y,\n guardPose.leftArm.shoulder.z,\n ],\n elbow: [\n guardPose.leftArm.elbow.x,\n guardPose.leftArm.elbow.y,\n guardPose.leftArm.elbow.z,\n ],\n },\n right: {\n shoulder: [\n guardPose.rightArm.shoulder.x,\n guardPose.rightArm.shoulder.y,\n guardPose.rightArm.shoulder.z,\n ],\n elbow: [\n guardPose.rightArm.elbow.x,\n guardPose.rightArm.elbow.y,\n guardPose.rightArm.elbow.z,\n ],\n },\n };\n}\n"],"mappings":"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"}
|