blacktrigram 0.7.39 → 0.7.40
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.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.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.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -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.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.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.js.map +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.map +1 -1
- 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.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.js.map +1 -1
- 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.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.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.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.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 +3 -90
- package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
- package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
- package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
- package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
- 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/DefensiveAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.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.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/core/AnimationHitTiming.js.map +1 -1
- package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
- package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
- package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
- package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
- 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/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.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.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
- package/lib/systems/combat/CombatStateSystem.js.map +1 -1
- 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.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.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/GonTechniques.js.map +1 -1
- package/lib/systems/trigram/techniques/SonTechniques.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/types/AccessibilityTypes.js.map +1 -1
- package/lib/types/PhysicsTypes.js.map +1 -1
- package/lib/types/common.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/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/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/physics.js.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.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.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 +5 -5
|
@@ -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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 * @public\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 +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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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DefensiveAnimations.js","names":[],"sources":["../../../../src/systems/animation/catalogs/DefensiveAnimations.ts"],"sourcesContent":["/**\n * Defensive animations for Eight Trigram stances\n *\n * Implements stance-specific defensive techniques based on Korean martial arts\n * and I Ching philosophy using the MartialArtsAnimationBuilder pattern.\n *\n * Coverage:\n * - 8 stances × 2 defensive moves = 16 defensive animations\n * - Block success, parry, guard break, and recovery animations\n * - Integration with existing AnimationStateMachine\n *\n * @module systems/animation/DefensiveAnimations\n * @category Animation\n * @korean 방어애니메이션\n */\n\nimport type { SkeletalAnimation } from \"@/types/skeletal\";\nimport { TrigramStance } from \"@/types/common\";\nimport { MartialArtsAnimationBuilder } from \"../builders/MartialArtsAnimationBuilder\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☰ 건 (GEON) - HEAVEN DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☰ 건 (Geon) - Heaven Defensive Move 1: High Block (상단막기)\n * Strong overhead block with both arms raised high. Direct force meets force.\n * @korean 건상단막기\n */\nexport const GEON_HIGH_BLOCK: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"geon_high_block\", \"건 상단막기\")\n .asDefense(0.2)\n .stance()\n .blockHigh(0.1, \"ease-out\")\n .blockHigh(0.1, \"linear\")\n .build();\n\n/**\n * ☰ 건 (Geon) - Heaven Defensive Move 2: Counter Strike (반격)\n * Quick counter punch after blocking, leveraging forward aggression.\n * @korean 건반격\n */\nexport const GEON_COUNTER_STRIKE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"geon_counter_strike\", \"건 반격\")\n .asDefense(0.25)\n .stance()\n .counterStrike(0.15, \"ease-out\")\n .recover(0.1, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☱ 태 (TAE) - LAKE DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☱ 태 (Tae) - Lake Defensive Move 1: Joint Lock Defense (관절꺾기 방어)\n * Circular deflection leading into joint manipulation. Fluid redirection.\n * @korean 태관절방어\n */\nexport const TAE_JOINT_LOCK_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"tae_joint_lock_defense\", \"태 관절방어\")\n .asDefense(0.3)\n .stance()\n .parry(0.1, \"ease-out\")\n .jointLock(0.12, \"linear\")\n .recover(0.08, \"ease-in\")\n .build();\n\n/**\n * ☱ 태 (Tae) - Lake Defensive Move 2: Sweep Defense (쓸어치기 방어)\n * Low sweeping motion to deflect and unbalance attacker.\n * @korean 태쓸어치기방어\n */\nexport const TAE_SWEEP_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"tae_sweep_defense\", \"태 쓸어치기방어\")\n .asDefense(0.28)\n .stance()\n .parry(0.08, \"ease-out\")\n .sweep(0.12, \"linear\")\n .recover(0.08, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☲ 리 (LI) - FIRE DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☲ 리 (Li) - Fire Defensive Move 1: Precision Parry (정밀 받아넘기기)\n * Precise hand deflection targeting specific attack points.\n * @korean 리정밀받아넘기기\n */\nexport const LI_PRECISION_PARRY: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"li_precision_parry\", \"리 정밀받아넘기기\")\n .asDefense(0.18)\n .stance()\n .parry(0.09, \"ease-out\")\n .recover(0.09, \"ease-in\")\n .build();\n\n/**\n * ☲ 리 (Li) - Fire Defensive Move 2: Nerve Strike Counter (신경타격 반격)\n * Quick nerve strike counter after deflection.\n * @korean 리신경타격반격\n */\nexport const LI_NERVE_STRIKE_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\n \"li_nerve_strike_counter\",\n \"리 신경타격반격\",\n )\n .asDefense(0.22)\n .stance()\n .counterParry(0.06, \"linear\")\n .counterStrike(0.1, \"ease-out\")\n .recover(0.06, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☳ 진 (JIN) - THUNDER DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☳ 진 (Jin) - Thunder Defensive Move 1: Explosive Block (폭발적 막기)\n * Powerful explosive block that can stagger attacker.\n * @korean 진폭발막기\n */\nexport const JIN_EXPLOSIVE_BLOCK: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"jin_explosive_block\", \"진 폭발막기\")\n .asDefense(0.15)\n .stance()\n .blockHigh(0.08, \"ease-out\")\n .recover(0.07, \"ease-in\")\n .build();\n\n/**\n * ☳ 진 (Jin) - Thunder Defensive Move 2: Shocking Counter (충격 반격)\n * Lightning-fast counter strike with explosive power.\n * @korean 진충격반격\n */\nexport const JIN_SHOCKING_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"jin_shocking_counter\", \"진 충격반격\")\n .asDefense(0.18)\n .stance()\n .counterStrike(0.09, \"ease-out\")\n .recover(0.09, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☴ 손 (SON) - WIND DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☴ 손 (Son) - Wind Defensive Move 1: Continuous Deflection (연속 막기)\n * Rapid circular deflections, multiple in succession.\n * @korean 손연속막기\n */\nexport const SON_CONTINUOUS_DEFLECTION: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"son_continuous_deflection\", \"손 연속막기\")\n .asDefense(0.35)\n .stance()\n .parry(0.1, \"linear\")\n .parry(0.1, \"linear\")\n .parry(0.08, \"linear\")\n .recover(0.07, \"ease-in\")\n .build();\n\n/**\n * ☴ 손 (Son) - Wind Defensive Move 2: Pressure Counter (압박 반격)\n * Multiple quick strikes after deflection, maintaining pressure.\n * @korean 손압박반격\n */\nexport const SON_PRESSURE_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"son_pressure_counter\", \"손 압박반격\")\n .asDefense(0.4)\n .stance()\n .counterStrike(0.1, \"ease-out\")\n .counterStrike(0.1, \"ease-out\")\n .counterStrike(0.1, \"ease-out\")\n .recover(0.1, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☵ 감 (GAM) - WATER DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☵ 감 (Gam) - Water Defensive Move 1: Flow Defense (흐름 방어)\n * Yielding circular defense that redirects force.\n * @korean 감흐름방어\n */\nexport const GAM_FLOW_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gam_flow_defense\", \"감 흐름방어\")\n .asDefense(0.32)\n .stance()\n .parry(0.12, \"ease-out\")\n .shift(0.1, \"linear\")\n .recover(0.1, \"ease-in\")\n .build();\n\n/**\n * ☵ 감 (Gam) - Water Defensive Move 2: Redirection Counter (전환 반격)\n * Uses opponent's momentum for counter strike.\n * @korean 감전환반격\n */\nexport const GAM_REDIRECTION_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gam_redirection_counter\", \"감 전환반격\")\n .asDefense(0.3)\n .stance()\n .parry(0.1, \"ease-out\")\n .counterStrike(0.12, \"ease-out\")\n .recover(0.08, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☶ 간 (GAN) - MOUNTAIN DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☶ 간 (Gan) - Mountain Defensive Move 1: Immovable Block (부동 막기)\n * Solid defensive stance that absorbs attacks.\n * @korean 간부동막기\n */\nexport const GAN_IMMOVABLE_BLOCK: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gan_immovable_block\", \"간 부동막기\")\n .asDefense(0.25)\n .stance()\n .blockHigh(0.13, \"linear\")\n .recover(0.12, \"ease-in\")\n .build();\n\n/**\n * ☶ 간 (Gan) - Mountain Defensive Move 2: Counter Fortress (반격 요새)\n * Strong defensive position with delayed power counter.\n * @korean 간반격요새\n */\nexport const GAN_COUNTER_FORTRESS: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gan_counter_fortress\", \"간 반격요새\")\n .asDefense(0.35)\n .stance()\n .blockHigh(0.12, \"linear\")\n .counterStrike(0.13, \"ease-out\")\n .recover(0.1, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☷ 곤 (GON) - EARTH DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☷ 곤 (Gon) - Earth Defensive Move 1: Grounding Defense (접지 방어)\n * Low defensive posture with strong base.\n * @korean 곤접지방어\n */\nexport const GON_GROUNDING_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gon_grounding_defense\", \"곤 접지방어\")\n .asDefense(0.28)\n .stance()\n .blockLow(0.14, \"ease-out\")\n .recover(0.14, \"ease-in\")\n .build();\n\n/**\n * ☷ 곤 (Gon) - Earth Defensive Move 2: Takedown Counter (꺾기 반격)\n * Defensive takedown using low center of gravity advantage.\n * @korean 곤꺾기반격\n */\nexport const GON_TAKEDOWN_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gon_takedown_counter\", \"곤 꺾기반격\")\n .asDefense(0.45)\n .stance()\n .takedownShoot(0.15, \"ease-out\")\n .takedownDump(0.15, \"linear\")\n .recover(0.15, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ANIMATION COLLECTIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Map of all defensive animations by stance\n * @korean 자세별방어애니메이션\n */\nexport const DEFENSIVE_ANIMATIONS_BY_STANCE: ReadonlyMap<\n TrigramStance,\n readonly SkeletalAnimation[]\n> = new Map([\n [TrigramStance.GEON, [GEON_HIGH_BLOCK, GEON_COUNTER_STRIKE] as const],\n [TrigramStance.TAE, [TAE_JOINT_LOCK_DEFENSE, TAE_SWEEP_DEFENSE] as const],\n [TrigramStance.LI, [LI_PRECISION_PARRY, LI_NERVE_STRIKE_COUNTER] as const],\n [TrigramStance.JIN, [JIN_EXPLOSIVE_BLOCK, JIN_SHOCKING_COUNTER] as const],\n [\n TrigramStance.SON,\n [SON_CONTINUOUS_DEFLECTION, SON_PRESSURE_COUNTER] as const,\n ],\n [TrigramStance.GAM, [GAM_FLOW_DEFENSE, GAM_REDIRECTION_COUNTER] as const],\n [TrigramStance.GAN, [GAN_IMMOVABLE_BLOCK, GAN_COUNTER_FORTRESS] as const],\n [TrigramStance.GON, [GON_GROUNDING_DEFENSE, GON_TAKEDOWN_COUNTER] as const],\n]);\n\n/**\n * All defensive animations in a single map for easy lookup\n * @korean 모든방어애니메이션\n */\nexport const ALL_DEFENSIVE_ANIMATIONS = new Map<string, SkeletalAnimation>([\n [\"geon_high_block\", GEON_HIGH_BLOCK],\n [\"geon_counter_strike\", GEON_COUNTER_STRIKE],\n [\"tae_joint_lock_defense\", TAE_JOINT_LOCK_DEFENSE],\n [\"tae_sweep_defense\", TAE_SWEEP_DEFENSE],\n [\"li_precision_parry\", LI_PRECISION_PARRY],\n [\"li_nerve_strike_counter\", LI_NERVE_STRIKE_COUNTER],\n [\"jin_explosive_block\", JIN_EXPLOSIVE_BLOCK],\n [\"jin_shocking_counter\", JIN_SHOCKING_COUNTER],\n [\"son_continuous_deflection\", SON_CONTINUOUS_DEFLECTION],\n [\"son_pressure_counter\", SON_PRESSURE_COUNTER],\n [\"gam_flow_defense\", GAM_FLOW_DEFENSE],\n [\"gam_redirection_counter\", GAM_REDIRECTION_COUNTER],\n [\"gan_immovable_block\", GAN_IMMOVABLE_BLOCK],\n [\"gan_counter_fortress\", GAN_COUNTER_FORTRESS],\n [\"gon_grounding_defense\", GON_GROUNDING_DEFENSE],\n [\"gon_takedown_counter\", GON_TAKEDOWN_COUNTER],\n]);\n\n/**\n * Get defensive animations for a specific stance\n * @korean 자세방어애니메이션가져오기\n */\nexport function getDefensiveAnimationsForStance(\n stance: TrigramStance,\n): readonly SkeletalAnimation[] {\n return DEFENSIVE_ANIMATIONS_BY_STANCE.get(stance) ?? [];\n}\n\n/**\n * Get a defensive animation by name\n * @korean 방어애니메이션가져오기\n */\nexport function getDefensiveAnimation(\n name: string,\n): SkeletalAnimation | undefined {\n return ALL_DEFENSIVE_ANIMATIONS.get(name);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"DefensiveAnimations.js","names":[],"sources":["../../../../src/systems/animation/catalogs/DefensiveAnimations.ts"],"sourcesContent":["/**\n * Defensive animations for Eight Trigram stances\n *\n * Implements stance-specific defensive techniques based on Korean martial arts\n * and I Ching philosophy using the MartialArtsAnimationBuilder pattern.\n *\n * Coverage:\n * - 8 stances × 2 defensive moves = 16 defensive animations\n * - Block success, parry, guard break, and recovery animations\n * - Integration with existing AnimationStateMachine\n *\n * @module systems/animation/DefensiveAnimations\n * @category Animation\n * @korean 방어애니메이션\n */\n\nimport type { SkeletalAnimation } from \"@/types/skeletal\";\nimport { TrigramStance } from \"@/types/common\";\nimport { MartialArtsAnimationBuilder } from \"../builders/MartialArtsAnimationBuilder\";\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☰ 건 (GEON) - HEAVEN DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☰ 건 (Geon) - Heaven Defensive Move 1: High Block (상단막기)\n * Strong overhead block with both arms raised high. Direct force meets force.\n * @korean 건상단막기\n */\nexport const GEON_HIGH_BLOCK: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"geon_high_block\", \"건 상단막기\")\n .asDefense(0.2)\n .stance()\n .blockHigh(0.1, \"ease-out\")\n .blockHigh(0.1, \"linear\")\n .build();\n\n/**\n * ☰ 건 (Geon) - Heaven Defensive Move 2: Counter Strike (반격)\n * Quick counter punch after blocking, leveraging forward aggression.\n * @korean 건반격\n */\nexport const GEON_COUNTER_STRIKE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"geon_counter_strike\", \"건 반격\")\n .asDefense(0.25)\n .stance()\n .counterStrike(0.15, \"ease-out\")\n .recover(0.1, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☱ 태 (TAE) - LAKE DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☱ 태 (Tae) - Lake Defensive Move 1: Joint Lock Defense (관절꺾기 방어)\n * Circular deflection leading into joint manipulation. Fluid redirection.\n * @korean 태관절방어\n */\nexport const TAE_JOINT_LOCK_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"tae_joint_lock_defense\", \"태 관절방어\")\n .asDefense(0.3)\n .stance()\n .parry(0.1, \"ease-out\")\n .jointLock(0.12, \"linear\")\n .recover(0.08, \"ease-in\")\n .build();\n\n/**\n * ☱ 태 (Tae) - Lake Defensive Move 2: Sweep Defense (쓸어치기 방어)\n * Low sweeping motion to deflect and unbalance attacker.\n * @korean 태쓸어치기방어\n */\nexport const TAE_SWEEP_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"tae_sweep_defense\", \"태 쓸어치기방어\")\n .asDefense(0.28)\n .stance()\n .parry(0.08, \"ease-out\")\n .sweep(0.12, \"linear\")\n .recover(0.08, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☲ 리 (LI) - FIRE DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☲ 리 (Li) - Fire Defensive Move 1: Precision Parry (정밀 받아넘기기)\n * Precise hand deflection targeting specific attack points.\n * @korean 리정밀받아넘기기\n */\nexport const LI_PRECISION_PARRY: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"li_precision_parry\", \"리 정밀받아넘기기\")\n .asDefense(0.18)\n .stance()\n .parry(0.09, \"ease-out\")\n .recover(0.09, \"ease-in\")\n .build();\n\n/**\n * ☲ 리 (Li) - Fire Defensive Move 2: Nerve Strike Counter (신경타격 반격)\n * Quick nerve strike counter after deflection.\n * @korean 리신경타격반격\n */\nexport const LI_NERVE_STRIKE_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\n \"li_nerve_strike_counter\",\n \"리 신경타격반격\",\n )\n .asDefense(0.22)\n .stance()\n .counterParry(0.06, \"linear\")\n .counterStrike(0.1, \"ease-out\")\n .recover(0.06, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☳ 진 (JIN) - THUNDER DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☳ 진 (Jin) - Thunder Defensive Move 1: Explosive Block (폭발적 막기)\n * Powerful explosive block that can stagger attacker.\n * @korean 진폭발막기\n */\nexport const JIN_EXPLOSIVE_BLOCK: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"jin_explosive_block\", \"진 폭발막기\")\n .asDefense(0.15)\n .stance()\n .blockHigh(0.08, \"ease-out\")\n .recover(0.07, \"ease-in\")\n .build();\n\n/**\n * ☳ 진 (Jin) - Thunder Defensive Move 2: Shocking Counter (충격 반격)\n * Lightning-fast counter strike with explosive power.\n * @korean 진충격반격\n */\nexport const JIN_SHOCKING_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"jin_shocking_counter\", \"진 충격반격\")\n .asDefense(0.18)\n .stance()\n .counterStrike(0.09, \"ease-out\")\n .recover(0.09, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☴ 손 (SON) - WIND DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☴ 손 (Son) - Wind Defensive Move 1: Continuous Deflection (연속 막기)\n * Rapid circular deflections, multiple in succession.\n * @korean 손연속막기\n */\nexport const SON_CONTINUOUS_DEFLECTION: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"son_continuous_deflection\", \"손 연속막기\")\n .asDefense(0.35)\n .stance()\n .parry(0.1, \"linear\")\n .parry(0.1, \"linear\")\n .parry(0.08, \"linear\")\n .recover(0.07, \"ease-in\")\n .build();\n\n/**\n * ☴ 손 (Son) - Wind Defensive Move 2: Pressure Counter (압박 반격)\n * Multiple quick strikes after deflection, maintaining pressure.\n * @korean 손압박반격\n */\nexport const SON_PRESSURE_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"son_pressure_counter\", \"손 압박반격\")\n .asDefense(0.4)\n .stance()\n .counterStrike(0.1, \"ease-out\")\n .counterStrike(0.1, \"ease-out\")\n .counterStrike(0.1, \"ease-out\")\n .recover(0.1, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☵ 감 (GAM) - WATER DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☵ 감 (Gam) - Water Defensive Move 1: Flow Defense (흐름 방어)\n * Yielding circular defense that redirects force.\n * @korean 감흐름방어\n */\nexport const GAM_FLOW_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gam_flow_defense\", \"감 흐름방어\")\n .asDefense(0.32)\n .stance()\n .parry(0.12, \"ease-out\")\n .shift(0.1, \"linear\")\n .recover(0.1, \"ease-in\")\n .build();\n\n/**\n * ☵ 감 (Gam) - Water Defensive Move 2: Redirection Counter (전환 반격)\n * Uses opponent's momentum for counter strike.\n * @korean 감전환반격\n */\nexport const GAM_REDIRECTION_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gam_redirection_counter\", \"감 전환반격\")\n .asDefense(0.3)\n .stance()\n .parry(0.1, \"ease-out\")\n .counterStrike(0.12, \"ease-out\")\n .recover(0.08, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☶ 간 (GAN) - MOUNTAIN DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☶ 간 (Gan) - Mountain Defensive Move 1: Immovable Block (부동 막기)\n * Solid defensive stance that absorbs attacks.\n * @korean 간부동막기\n */\nexport const GAN_IMMOVABLE_BLOCK: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gan_immovable_block\", \"간 부동막기\")\n .asDefense(0.25)\n .stance()\n .blockHigh(0.13, \"linear\")\n .recover(0.12, \"ease-in\")\n .build();\n\n/**\n * ☶ 간 (Gan) - Mountain Defensive Move 2: Counter Fortress (반격 요새)\n * Strong defensive position with delayed power counter.\n * @korean 간반격요새\n */\nexport const GAN_COUNTER_FORTRESS: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gan_counter_fortress\", \"간 반격요새\")\n .asDefense(0.35)\n .stance()\n .blockHigh(0.12, \"linear\")\n .counterStrike(0.13, \"ease-out\")\n .recover(0.1, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ☷ 곤 (GON) - EARTH DEFENSIVE ANIMATIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * ☷ 곤 (Gon) - Earth Defensive Move 1: Grounding Defense (접지 방어)\n * Low defensive posture with strong base.\n * @korean 곤접지방어\n */\nexport const GON_GROUNDING_DEFENSE: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gon_grounding_defense\", \"곤 접지방어\")\n .asDefense(0.28)\n .stance()\n .blockLow(0.14, \"ease-out\")\n .recover(0.14, \"ease-in\")\n .build();\n\n/**\n * ☷ 곤 (Gon) - Earth Defensive Move 2: Takedown Counter (꺾기 반격)\n * Defensive takedown using low center of gravity advantage.\n * @korean 곤꺾기반격\n */\nexport const GON_TAKEDOWN_COUNTER: SkeletalAnimation =\n MartialArtsAnimationBuilder.create(\"gon_takedown_counter\", \"곤 꺾기반격\")\n .asDefense(0.45)\n .stance()\n .takedownShoot(0.15, \"ease-out\")\n .takedownDump(0.15, \"linear\")\n .recover(0.15, \"ease-in\")\n .build();\n\n// ═══════════════════════════════════════════════════════════════════════════\n// ANIMATION COLLECTIONS\n// ═══════════════════════════════════════════════════════════════════════════\n\n/**\n * Map of all defensive animations by stance\n * @korean 자세별방어애니메이션\n */\nexport const DEFENSIVE_ANIMATIONS_BY_STANCE: ReadonlyMap<\n TrigramStance,\n readonly SkeletalAnimation[]\n> = new Map([\n [TrigramStance.GEON, [GEON_HIGH_BLOCK, GEON_COUNTER_STRIKE] as const],\n [TrigramStance.TAE, [TAE_JOINT_LOCK_DEFENSE, TAE_SWEEP_DEFENSE] as const],\n [TrigramStance.LI, [LI_PRECISION_PARRY, LI_NERVE_STRIKE_COUNTER] as const],\n [TrigramStance.JIN, [JIN_EXPLOSIVE_BLOCK, JIN_SHOCKING_COUNTER] as const],\n [\n TrigramStance.SON,\n [SON_CONTINUOUS_DEFLECTION, SON_PRESSURE_COUNTER] as const,\n ],\n [TrigramStance.GAM, [GAM_FLOW_DEFENSE, GAM_REDIRECTION_COUNTER] as const],\n [TrigramStance.GAN, [GAN_IMMOVABLE_BLOCK, GAN_COUNTER_FORTRESS] as const],\n [TrigramStance.GON, [GON_GROUNDING_DEFENSE, GON_TAKEDOWN_COUNTER] as const],\n]);\n\n/**\n * All defensive animations in a single map for easy lookup\n * @korean 모든방어애니메이션\n */\nexport const ALL_DEFENSIVE_ANIMATIONS = new Map<string, SkeletalAnimation>([\n [\"geon_high_block\", GEON_HIGH_BLOCK],\n [\"geon_counter_strike\", GEON_COUNTER_STRIKE],\n [\"tae_joint_lock_defense\", TAE_JOINT_LOCK_DEFENSE],\n [\"tae_sweep_defense\", TAE_SWEEP_DEFENSE],\n [\"li_precision_parry\", LI_PRECISION_PARRY],\n [\"li_nerve_strike_counter\", LI_NERVE_STRIKE_COUNTER],\n [\"jin_explosive_block\", JIN_EXPLOSIVE_BLOCK],\n [\"jin_shocking_counter\", JIN_SHOCKING_COUNTER],\n [\"son_continuous_deflection\", SON_CONTINUOUS_DEFLECTION],\n [\"son_pressure_counter\", SON_PRESSURE_COUNTER],\n [\"gam_flow_defense\", GAM_FLOW_DEFENSE],\n [\"gam_redirection_counter\", GAM_REDIRECTION_COUNTER],\n [\"gan_immovable_block\", GAN_IMMOVABLE_BLOCK],\n [\"gan_counter_fortress\", GAN_COUNTER_FORTRESS],\n [\"gon_grounding_defense\", GON_GROUNDING_DEFENSE],\n [\"gon_takedown_counter\", GON_TAKEDOWN_COUNTER],\n]);\n\n/**\n * Get defensive animations for a specific stance\n * @korean 자세방어애니메이션가져오기\n */\nexport function getDefensiveAnimationsForStance(\n stance: TrigramStance,\n): readonly SkeletalAnimation[] {\n return DEFENSIVE_ANIMATIONS_BY_STANCE.get(stance) ?? [];\n}\n\n/**\n * Get a defensive animation by name\n * @korean 방어애니메이션가져오기\n */\nexport function getDefensiveAnimation(\n name: string,\n): SkeletalAnimation | undefined {\n return ALL_DEFENSIVE_ANIMATIONS.get(name);\n}\n"],"mappings":"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"}
|