blacktrigram 0.7.39 → 0.7.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +8 -8
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnimationStateMachine.js","names":[],"sources":["../../../../src/systems/animation/core/AnimationStateMachine.ts"],"sourcesContent":["/**\n * Player Animation State Machine for Black Trigram\n *\n * Manages player character animations with frame-accurate timing at 60fps.\n * Supports animation priorities, transitions, and event callbacks.\n *\n * Based on game-design.md specifications:\n * - Attack: 12 frames (200ms at 60fps)\n * - Block: 4 frames (67ms at 60fps)\n * - Walk: 6 frames\n * - Stance change: 600ms\n *\n * @module systems/animation/AnimationStateMachine\n * @category Animation\n * @korean 애니메이션상태머신\n */\n\nimport { TrigramStance } from \"@/types/common\";\nimport type { AnimationKeyframe } from \"@/types/skeletal\";\nimport {\n createMotionPredictionState,\n predictFutureKeyframe,\n updateMotionPrediction,\n type EasingName,\n type MotionPredictionState,\n} from \"../builders/KeyframeInterpolation\";\nimport {\n AnimationQueue,\n canInterrupt,\n type AnimationRequest,\n type ConflictResolutionStrategy,\n} from \"./AnimationPriority\";\nimport {\n getStanceTransition,\n isTransitionAllowed,\n type StanceTransition,\n} from \"./AnimationTransitions\";\nimport type {\n AnimationConfig,\n AnimationEvents,\n AnimationMachineState,\n AnimationPriority,\n AnimationUpdateResult,\n FallType,\n MutableAnimationConfig,\n} from \"./types\";\nimport { AnimationState, FALL_TO_GROUND_MAP, STEP_PRIORITY } from \"./types\";\n\n/**\n * Default animation configurations based on game-design.md\n *\n * Frame timings:\n * - Attack: 12 frames = 200ms at 60fps\n * - Block: 4 frames = 67ms at 60fps\n * - Walk: 6 frames = 100ms at 60fps\n * - Hit: 4 frames = 67ms at 60fps\n * - Stance change: 36 frames = 600ms at 60fps\n * - Stance guards: 4-6 frames = breathing animation at 60fps\n * - Tactical steps: 18 frames = 300ms at 60fps, 30cm distance\n *\n * Defensive animations (방어 애니메이션):\n * - Block Success (막기): 8 frames = 133ms - absorb impact, maintain guard\n * - Parry Deflect (받아넘기기): 10 frames = 167ms - redirect attack, counter window\n * - Guard Break (방어붕괴): 15 frames = 250ms - arms forced wide, vulnerable\n * - Guard Recovery (방어복구): 12 frames = 200ms - restore guard position\n *\n * @korean 기본애니메이션설정\n */\nexport const DEFAULT_ANIMATION_CONFIGS: Map<AnimationState, AnimationConfig> =\n new Map<AnimationState, AnimationConfig>([\n [\n AnimationState.IDLE,\n {\n state: AnimationState.IDLE,\n frames: 4,\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.WALK,\n {\n state: AnimationState.WALK,\n frames: 6,\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 1 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.RUN,\n {\n state: AnimationState.RUN,\n frames: 8,\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 2 as AnimationPriority,\n duration: 8 / 60,\n },\n ],\n [\n AnimationState.STANCE_CHANGE,\n {\n state: AnimationState.STANCE_CHANGE,\n frames: 36, // 600ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 3 as AnimationPriority,\n duration: 0.6,\n easing: \"smooth-transition\", // Smooth S-curve for stance changes\n },\n ],\n [\n AnimationState.STANCE_SIDE_SWITCH,\n {\n state: AnimationState.STANCE_SIDE_SWITCH,\n frames: 24, // 400ms at 60fps for left↔right switch\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 3 as AnimationPriority,\n duration: 0.4,\n },\n ],\n [\n AnimationState.DEFEND,\n {\n state: AnimationState.DEFEND,\n frames: 4, // 67ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n // Defensive animations (방어 애니메이션) - Enhanced guard break system\n [\n AnimationState.DEFEND_BLOCK_SUCCESS,\n {\n state: AnimationState.DEFEND_BLOCK_SUCCESS,\n frames: 8, // 133ms at 60fps - absorb impact, maintain guard\n fps: 60,\n loop: false,\n interruptible: false, // Must complete block animation\n priority: 6 as AnimationPriority, // Higher than defend, same as hit\n duration: 0.133,\n easing: \"controlled-slow\", // Controlled deceleration for impact absorption\n },\n ],\n [\n AnimationState.DEFEND_PARRY,\n {\n state: AnimationState.DEFEND_PARRY,\n frames: 10, // 167ms at 60fps - redirect attack, open counter opportunity\n fps: 60,\n loop: false,\n interruptible: false, // Must complete parry animation\n priority: 7 as AnimationPriority, // Higher than block, creates counter window\n duration: 0.167,\n counterWindow: 0.2, // 200ms counter-attack opportunity after parry\n },\n ],\n [\n AnimationState.DEFEND_GUARD_BREAK,\n {\n state: AnimationState.DEFEND_GUARD_BREAK,\n frames: 15, // 250ms at 60fps - arms forced wide, vulnerable state\n fps: 60,\n loop: false,\n interruptible: false, // Cannot interrupt guard break\n priority: 8 as AnimationPriority, // Highest priority (same as fall)\n duration: 0.25,\n vulnerabilityDuration: 0.5, // 500ms vulnerable state after guard break\n },\n ],\n [\n AnimationState.DEFEND_RECOVERY,\n {\n state: AnimationState.DEFEND_RECOVERY,\n frames: 12, // 200ms at 60fps - restore guard position\n fps: 60,\n loop: false,\n interruptible: true, // Can be interrupted by attacks\n priority: 2 as AnimationPriority, // Same as run, lower than defend\n duration: 0.2,\n easing: \"natural-motion\", // Physics-based recovery\n },\n ],\n [\n AnimationState.ATTACK,\n {\n state: AnimationState.ATTACK,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: STEP_PRIORITY,\n duration: 12 / 60,\n easing: \"explosive-power\", // Explosive acceleration for attacks\n },\n ],\n [\n AnimationState.HIT,\n {\n state: AnimationState.HIT,\n frames: 4, // 67ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 6 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.KO,\n {\n state: AnimationState.KO,\n frames: 30, // 500ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 7 as AnimationPriority,\n duration: 0.5,\n },\n ],\n // Fall animations (낙법 애니메이션) - Priority 8 (highest)\n [\n AnimationState.FALL_FORWARD,\n {\n state: AnimationState.FALL_FORWARD,\n frames: 24, // 400ms at 60fps - stumble forward, knee collapse, hands brace, face-down\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.4,\n },\n ],\n [\n AnimationState.FALL_BACKWARD,\n {\n state: AnimationState.FALL_BACKWARD,\n frames: 30, // 500ms at 60fps - backward stumble, sit, back impact, supine\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.5,\n },\n ],\n [\n AnimationState.FALL_SIDE_LEFT,\n {\n state: AnimationState.FALL_SIDE_LEFT,\n frames: 27, // 450ms at 60fps - rotation, shoulder roll, side sprawl\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.45,\n },\n ],\n [\n AnimationState.FALL_SIDE_RIGHT,\n {\n state: AnimationState.FALL_SIDE_RIGHT,\n frames: 27, // 450ms at 60fps - rotation, shoulder roll, side sprawl\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.45,\n },\n ],\n // Ground state animations (지면 자세) - Breathing loops\n [\n AnimationState.GROUND_PRONE,\n {\n state: AnimationState.GROUND_PRONE,\n frames: 4, // Breathing loop on ground (face down)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.GROUND_SUPINE,\n {\n state: AnimationState.GROUND_SUPINE,\n frames: 4, // Breathing loop on ground (face up)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.GROUND_SIDE_LEFT,\n {\n state: AnimationState.GROUND_SIDE_LEFT,\n frames: 4, // Breathing loop on ground (left side)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.GROUND_SIDE_RIGHT,\n {\n state: AnimationState.GROUND_SIDE_RIGHT,\n frames: 4, // Breathing loop on ground (right side)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n // Recovery animations (기상 애니메이션) - Priority 9 (higher than falls)\n [\n AnimationState.RECOVERY_PRONE_STANDUP,\n {\n state: AnimationState.RECOVERY_PRONE_STANDUP,\n frames: 30, // 500ms at 60fps - push up from prone, rise to standing\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.5,\n },\n ],\n [\n AnimationState.RECOVERY_SUPINE_STANDUP,\n {\n state: AnimationState.RECOVERY_SUPINE_STANDUP,\n frames: 36, // 600ms at 60fps - sit up, roll forward, stand\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.6,\n },\n ],\n [\n AnimationState.RECOVERY_ROLL,\n {\n state: AnimationState.RECOVERY_ROLL,\n frames: 24, // 400ms at 60fps - roll to side, spring to feet (quick recovery)\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.4,\n },\n ],\n [\n AnimationState.RECOVERY_DEFENSIVE,\n {\n state: AnimationState.RECOVERY_DEFENSIVE,\n frames: 42, // 700ms at 60fps - slow rise with guard up (vulnerable but defended)\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.7,\n },\n ],\n // 180-degree turn animations (180도 회전 애니메이션)\n [\n AnimationState.TURN_LEFT,\n {\n state: AnimationState.TURN_LEFT,\n frames: 12, // 200ms at 60fps for 180° turn\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY, // Same priority as attacks/steps - committed action\n duration: 12 / 60,\n },\n ],\n [\n AnimationState.TURN_RIGHT,\n {\n state: AnimationState.TURN_RIGHT,\n frames: 12, // 200ms at 60fps for 180° turn\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY, // Same priority as attacks/steps - committed action\n duration: 12 / 60,\n },\n ],\n // Stance-specific guard animations (팔괘 방어 자세)\n [\n AnimationState.STANCE_GUARD_GEON,\n {\n state: AnimationState.STANCE_GUARD_GEON,\n frames: 6, // Breathing animation\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_TAE,\n {\n state: AnimationState.STANCE_GUARD_TAE,\n frames: 6, // Breathing animation\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_LI,\n {\n state: AnimationState.STANCE_GUARD_LI,\n frames: 4, // Controlled breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_JIN,\n {\n state: AnimationState.STANCE_GUARD_JIN,\n frames: 5, // Deep breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 5 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_SON,\n {\n state: AnimationState.STANCE_GUARD_SON,\n frames: 6, // Rhythmic breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_GAM,\n {\n state: AnimationState.STANCE_GUARD_GAM,\n frames: 6, // Flowing breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_GAN,\n {\n state: AnimationState.STANCE_GUARD_GAN,\n frames: 4, // Steady breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_GON,\n {\n state: AnimationState.STANCE_GUARD_GON,\n frames: 5, // Deep diaphragm breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 5 / 60,\n },\n ],\n // Tactical step animations (전술적 발걸음)\n // 18 frames = 300ms at 60fps, 30cm distance per step\n [\n AnimationState.STEP_FORWARD,\n {\n state: AnimationState.STEP_FORWARD,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false, // Non-interruptible for commitment\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_BACK,\n {\n state: AnimationState.STEP_BACK,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_LEFT,\n {\n state: AnimationState.STEP_LEFT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_RIGHT,\n {\n state: AnimationState.STEP_RIGHT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_FORWARD_LEFT,\n {\n state: AnimationState.STEP_FORWARD_LEFT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_FORWARD_RIGHT,\n {\n state: AnimationState.STEP_FORWARD_RIGHT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_BACK_LEFT,\n {\n state: AnimationState.STEP_BACK_LEFT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_BACK_RIGHT,\n {\n state: AnimationState.STEP_BACK_RIGHT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n // Footwork patterns (보법) - Korean martial arts specialized footwork\n // Circular step (원형보) - Lateral movement maintaining guard facing\n [\n AnimationState.FOOTWORK_CIRCULAR_LEFT,\n {\n state: AnimationState.FOOTWORK_CIRCULAR_LEFT,\n frames: 18, // 300ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false, // Committed footwork\n priority: STEP_PRIORITY, // Same as tactical steps\n duration: 0.3,\n },\n ],\n [\n AnimationState.FOOTWORK_CIRCULAR_RIGHT,\n {\n state: AnimationState.FOOTWORK_CIRCULAR_RIGHT,\n frames: 18, // 300ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n // Pivot step (축족회전) - Rotation on planted foot\n [\n AnimationState.FOOTWORK_PIVOT_LEFT,\n {\n state: AnimationState.FOOTWORK_PIVOT_LEFT,\n frames: 15, // 250ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.25,\n },\n ],\n [\n AnimationState.FOOTWORK_PIVOT_RIGHT,\n {\n state: AnimationState.FOOTWORK_PIVOT_RIGHT,\n frames: 15, // 250ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.25,\n },\n ],\n // Slide step (미끄럼보) - Both feet move together\n [\n AnimationState.FOOTWORK_SLIDE_FORWARD,\n {\n state: AnimationState.FOOTWORK_SLIDE_FORWARD,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true, // Can be interrupted\n priority: 4 as AnimationPriority, // Same as defend\n duration: 0.2,\n },\n ],\n [\n AnimationState.FOOTWORK_SLIDE_BACK,\n {\n state: AnimationState.FOOTWORK_SLIDE_BACK,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 0.2,\n },\n ],\n [\n AnimationState.FOOTWORK_SLIDE_LEFT,\n {\n state: AnimationState.FOOTWORK_SLIDE_LEFT,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 0.2,\n },\n ],\n [\n AnimationState.FOOTWORK_SLIDE_RIGHT,\n {\n state: AnimationState.FOOTWORK_SLIDE_RIGHT,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 0.2,\n },\n ],\n // Shuffle step (섞음보) - Quick micro-adjustment\n [\n AnimationState.FOOTWORK_SHUFFLE,\n {\n state: AnimationState.FOOTWORK_SHUFFLE,\n frames: 6, // 100ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 3 as AnimationPriority, // Same as stance_change\n duration: 0.1,\n },\n ],\n ]);\n\n/**\n * Player Animation State Machine\n *\n * Manages animation state, transitions, and timing with frame-accurate updates.\n * Integrates priority system, automatic animation queueing, and event callbacks.\n *\n * **Animation Queue**: Enabled by default with max size 3 and timestamp-based\n * conflict resolution. Automatically queues animations that cannot execute\n * immediately and processes them when the current animation completes.\n *\n * @example\n * ```typescript\n * const machine = new PlayerAnimationStateMachine(DEFAULT_ANIMATION_CONFIGS, {\n * onAnimationStart: (state) => console.log(`Started ${state}`),\n * onAnimationComplete: (state) => console.log(`Completed ${state}`),\n * onFrame: (frame, state) => {\n * if (state === \"attack\" && frame === 6) {\n * // Execute attack at midpoint (frame 6 of 12)\n * executeAttackLogic();\n * }\n * }\n * });\n *\n * // Animation queue is enabled by default\n * // Use transitionToQueued() for automatic queueing\n * machine.transitionToQueued(AnimationState.ATTACK); // Queues if can't execute\n *\n * // Or use regular transitionTo() (no queueing)\n * machine.transitionTo(AnimationState.ATTACK); // Fails if can't execute\n *\n * // In game loop (useFrame)\n * useFrame((state, delta) => {\n * const result = machine.update(delta);\n * updatePlayerVisuals(result.state, result.frame);\n * });\n * ```\n *\n * @korean 플레이어애니메이션상태머신\n */\nexport class PlayerAnimationStateMachine {\n /**\n * Static mapping from TrigramStance to guard AnimationState\n * Prevents repeated object allocation in transitionToStanceGuard()\n * @korean 자세방어상태맵\n */\n private static readonly GUARD_STATE_MAP: Record<\n TrigramStance,\n AnimationState\n > = {\n [TrigramStance.GEON]: AnimationState.STANCE_GUARD_GEON,\n [TrigramStance.TAE]: AnimationState.STANCE_GUARD_TAE,\n [TrigramStance.LI]: AnimationState.STANCE_GUARD_LI,\n [TrigramStance.JIN]: AnimationState.STANCE_GUARD_JIN,\n [TrigramStance.SON]: AnimationState.STANCE_GUARD_SON,\n [TrigramStance.GAM]: AnimationState.STANCE_GUARD_GAM,\n [TrigramStance.GAN]: AnimationState.STANCE_GUARD_GAN,\n [TrigramStance.GON]: AnimationState.STANCE_GUARD_GON,\n };\n\n /**\n * Static reverse mapping from guard AnimationState to TrigramStance\n * Prevents repeated object allocation in getCurrentGuardStance()\n * @korean 방어상태자세맵\n */\n private static readonly STANCE_FROM_GUARD_MAP: Record<string, TrigramStance> =\n {\n [AnimationState.STANCE_GUARD_GEON]: TrigramStance.GEON,\n [AnimationState.STANCE_GUARD_TAE]: TrigramStance.TAE,\n [AnimationState.STANCE_GUARD_LI]: TrigramStance.LI,\n [AnimationState.STANCE_GUARD_JIN]: TrigramStance.JIN,\n [AnimationState.STANCE_GUARD_SON]: TrigramStance.SON,\n [AnimationState.STANCE_GUARD_GAM]: TrigramStance.GAM,\n [AnimationState.STANCE_GUARD_GAN]: TrigramStance.GAN,\n [AnimationState.STANCE_GUARD_GON]: TrigramStance.GON,\n };\n\n private currentState: AnimationState = AnimationState.IDLE;\n private frameIndex = 0;\n private timeAccumulator = 0;\n private previousState: AnimationState | null = null;\n private justStarted = false;\n private justCompleted = false;\n\n /**\n * Current stance transition data (null when not in stance_change animation)\n *\n * **Korean**: 현재 자세 전환 데이터\n *\n * Tracks the active stance transition for use during stance_change animation.\n * Provides access to keyframes and blend weights for smooth interpolation.\n *\n * @korean 현재자세전환데이터\n */\n private currentStanceTransition: StanceTransition | null = null;\n\n /**\n * Motion prediction state for latency reduction\n *\n * **Korean**: 동작 예측 상태\n *\n * Tracks animation velocities for motion prediction to reduce perceived latency.\n * Updated each frame with velocity calculations for smooth anticipation.\n *\n * @korean 동작예측상태\n */\n private motionPrediction: MotionPredictionState =\n createMotionPredictionState();\n\n /**\n * Enable motion prediction for latency reduction\n *\n * **Korean**: 동작 예측 활성화\n *\n * When enabled, predicts future animation frames based on current velocity\n * to reduce perceived input latency by 16-33ms (1-2 frames at 60fps).\n *\n * @korean 동작예측활성화\n */\n private enableMotionPrediction: boolean = false;\n\n /**\n * Motion prediction time ahead (seconds)\n *\n * **Korean**: 예측 시간\n *\n * How far ahead to predict motion (default: 1 frame = 16.67ms at 60fps).\n * Typical range: 0.016-0.033 seconds for <50ms total latency.\n *\n * @korean 예측시간\n */\n private predictionTimeAhead: number = 0.01667; // 1 frame at 60fps\n\n /**\n * Previous keyframe for motion prediction velocity calculation\n *\n * **Korean**: 이전 키프레임\n *\n * @korean 이전키프레임\n */\n private previousKeyframe: AnimationKeyframe | null = null;\n\n /**\n * Preferred easing function for smooth transitions\n *\n * **Korean**: 선호 이징 함수\n *\n * Default easing curve for animation blending and transitions.\n * Can be overridden per animation or transition.\n *\n * @korean 선호이징함수\n */\n private preferredEasing: EasingName = \"natural-motion\";\n\n /**\n * Animation queue for pending animations\n *\n * **Korean**: 애니메이션 대기열\n *\n * Stores animation requests that couldn't be executed immediately\n * due to non-interruptible animations or priority conflicts.\n * Processed automatically when current animation completes.\n *\n * Enabled by default with max size 3 and timestamp-based conflict resolution.\n * Can be disabled with disableQueue() or reconfigured with enableQueue().\n *\n * @korean 애니메이션대기열\n */\n private animationQueue: AnimationQueue | null = new AnimationQueue(\n 3,\n \"timestamp\",\n );\n\n /**\n * Conflict resolution strategy for equal-priority animations\n *\n * **Korean**: 충돌 해결 전략\n *\n * Determines how to resolve conflicts when multiple animations\n * have equal priority. Default: timestamp (FIFO).\n *\n * @korean 충돌해결전략\n */\n private conflictStrategy: ConflictResolutionStrategy = \"timestamp\";\n\n /**\n * Create a new animation state machine\n *\n * Clones the provided config map so per-instance mutations\n * (e.g. dynamic attack duration) don't affect shared defaults.\n *\n * @param animations - Map of animation configurations (cloned internally)\n * @param events - Optional event callbacks\n *\n * @korean 생성자\n */\n private readonly animations: Map<AnimationState, MutableAnimationConfig>;\n\n constructor(\n animations: Map<AnimationState, AnimationConfig>,\n private readonly events?: AnimationEvents,\n ) {\n // Clone so we can safely mutate per-instance (e.g. attack duration)\n this.animations = new Map(\n Array.from(animations.entries()).map(([k, v]) => [k, { ...v }]),\n );\n }\n\n /**\n * Update animation state with delta time\n *\n * Call this in useFrame for 60fps updates.\n * Handles frame progression, looping, and completion.\n *\n * @param deltaTime - Time elapsed since last update (in seconds)\n * @returns Animation update result with current state and frame\n *\n * @korean 업데이트\n */\n update(deltaTime: number): AnimationUpdateResult {\n const currentAnim = this.animations.get(this.currentState);\n if (!currentAnim) {\n return {\n state: this.currentState,\n frame: 0,\n progress: 0,\n justCompleted: false,\n justStarted: false,\n };\n }\n\n // Reset just started/completed flags\n const wasJustStarted = this.justStarted;\n this.justStarted = false;\n const previousJustCompleted = this.justCompleted;\n this.justCompleted = false;\n\n // Accumulate time\n this.timeAccumulator += deltaTime;\n const frameDuration = 1 / currentAnim.fps;\n\n // Check if we should advance to next frame\n if (this.timeAccumulator >= frameDuration) {\n const previousFrame = this.frameIndex;\n this.frameIndex++;\n this.timeAccumulator -= frameDuration;\n\n // Emit frame event\n if (this.events?.onFrame && previousFrame !== this.frameIndex) {\n this.events.onFrame(this.frameIndex, this.currentState);\n }\n\n // Handle animation completion\n if (this.frameIndex >= currentAnim.frames) {\n if (currentAnim.loop) {\n // Loop back to start\n this.frameIndex = 0;\n } else {\n // Animation completed\n this.justCompleted = true;\n if (this.events?.onAnimationComplete) {\n this.events.onAnimationComplete(this.currentState);\n }\n\n // Auto-transition logic\n // Fall animations transition to ground states using the mapping\n if (this.currentState.startsWith(\"fall_\")) {\n const fallType = this.currentState.replace(\"fall_\", \"\");\n\n // Validate that fallType is a valid FallType before using in map\n if (\n fallType === \"forward\" ||\n fallType === \"backward\" ||\n fallType === \"side_left\" ||\n fallType === \"side_right\"\n ) {\n const groundState = FALL_TO_GROUND_MAP[fallType as FallType];\n const groundAnimKey = `ground_${groundState}`;\n\n // Validate that the constructed ground animation state actually exists\n if (\n DEFAULT_ANIMATION_CONFIGS.has(groundAnimKey as AnimationState)\n ) {\n const groundAnimState = groundAnimKey as AnimationState;\n\n this.previousState = this.currentState;\n this.currentState = groundAnimState;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(groundAnimState);\n }\n } else {\n // Fallback: if mapping is invalid, safely transition to idle\n // instead of entering an undefined animation state.\n console.warn(\n \"[AnimationStateMachine] Invalid ground animation mapping for fall type:\",\n fallType,\n \"->\",\n groundAnimKey,\n );\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n }\n } else {\n // Invalid fall type - fallback to idle\n console.warn(\n \"[AnimationStateMachine] Invalid fall animation state:\",\n this.currentState,\n );\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n }\n }\n // Recovery animations transition to idle when complete\n else if (this.currentState.startsWith(\"recovery_\")) {\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n }\n // Non-fall, non-recovery, non-looping animations transition to idle\n else if (\n this.currentState !== AnimationState.IDLE &&\n this.currentState !== AnimationState.KO &&\n !this.currentState.startsWith(\"ground_\")\n ) {\n // Clear stance transition data if completing stance_change\n if (this.currentState === AnimationState.STANCE_CHANGE) {\n this.clearStanceTransition();\n }\n\n // Transition to idle first\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n\n // Then try to process next queued animation (from idle state)\n this.processNextQueuedAnimation();\n } else {\n // Stay on last frame (for ko and ground states)\n this.frameIndex = currentAnim.frames - 1;\n }\n }\n }\n }\n\n const progress =\n currentAnim.frames > 0 ? this.frameIndex / currentAnim.frames : 0;\n\n return {\n state: this.currentState,\n frame: this.frameIndex,\n progress,\n justCompleted: previousJustCompleted,\n justStarted: wasJustStarted,\n };\n }\n\n /**\n * Attempt to transition to a new animation state\n *\n * Checks transition rules and priority system before transitioning.\n *\n * @param newState - Target animation state\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // Successful transitions\n * machine.transitionTo(\"walk\"); // idle -> walk\n * machine.transitionTo(\"attack\"); // walk -> attack\n *\n * // Failed transition (invalid or lower priority)\n * machine.transitionTo(\"walk\"); // attack -> walk (blocked, must complete first)\n * ```\n *\n * @korean 상태전환\n */\n transitionTo(newState: AnimationState): boolean {\n // Don't transition to same state\n if (this.currentState === newState) {\n return false;\n }\n\n // Check if transition is allowed by rules\n if (!isTransitionAllowed(this.currentState, newState)) {\n return false;\n }\n\n const currentAnim = this.animations.get(this.currentState);\n const newAnim = this.animations.get(newState);\n\n if (!newAnim) {\n return false;\n }\n\n // Check priority system\n if (\n currentAnim &&\n !canInterrupt(this.currentState, newState, currentAnim.interruptible)\n ) {\n return false;\n }\n\n // Emit interrupt event if current animation wasn't completed\n if (this.frameIndex < (currentAnim?.frames ?? 0) - 1) {\n if (this.events?.onAnimationInterrupted) {\n this.events.onAnimationInterrupted(this.currentState, newState);\n }\n }\n\n // Clear stance transition data if interrupting stance_change\n if (this.currentState === AnimationState.STANCE_CHANGE) {\n this.clearStanceTransition();\n }\n\n // Execute transition\n this.previousState = this.currentState;\n this.currentState = newState;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n this.justCompleted = false;\n\n // Emit start event\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(newState);\n }\n\n return true;\n }\n\n /**\n * Transition to ATTACK state with a technique-specific duration.\n *\n * The default ATTACK config is 200ms (12 frames), but real techniques\n * range from 350ms to 1200ms. This method overrides the ATTACK frame\n * count to match the actual skeletal animation duration so the state\n * machine stays in ATTACK for the full technique.\n *\n * @param durationSeconds - The skeletal animation duration in seconds\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // Jab animation is 0.55s (TECHNIQUE_TIMING.FAST)\n * machine.transitionToAttack(0.55);\n * ```\n *\n * @korean 공격전환 (기술별 지속시간)\n */\n transitionToAttack(durationSeconds: number): boolean {\n const attackConfig = this.animations.get(AnimationState.ATTACK);\n if (attackConfig) {\n const fps = attackConfig.fps || 60;\n attackConfig.frames = Math.max(1, Math.round(durationSeconds * fps));\n attackConfig.duration = durationSeconds;\n }\n return this.transitionTo(AnimationState.ATTACK);\n }\n\n /**\n * Get current animation state\n *\n * @returns Current animation state\n * @korean 현재상태가져오기\n */\n getCurrentState(): AnimationState {\n return this.currentState;\n }\n\n /**\n * Get current frame index\n *\n * @returns Current frame index (0 to frames-1)\n * @korean 현재프레임가져오기\n */\n getCurrentFrame(): number {\n return this.frameIndex;\n }\n\n /**\n * Get previous animation state\n *\n * @returns Previous animation state or null\n * @korean 이전상태가져오기\n */\n getPreviousState(): AnimationState | null {\n return this.previousState;\n }\n\n /**\n * Get current animation configuration\n *\n * @returns Current animation config or undefined\n * @korean 현재애니메이션설정가져오기\n */\n getCurrentAnimation(): AnimationConfig | undefined {\n return this.animations.get(this.currentState);\n }\n\n /**\n * Reset animation state machine to idle\n *\n * @korean 초기화\n */\n reset(): void {\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.previousState = null;\n this.justStarted = false;\n this.justCompleted = false;\n }\n\n /**\n * Get full internal state (for debugging/testing)\n *\n * @returns Current state machine state\n * @korean 상태가져오기\n */\n getState(): AnimationMachineState {\n return {\n currentState: this.currentState,\n frameIndex: this.frameIndex,\n timeAccumulator: this.timeAccumulator,\n isPlaying: true,\n previousState: this.previousState,\n };\n }\n\n /**\n * Transition to stance-specific guard animation\n *\n * Convenience method to transition to a stance guard based on trigram stance.\n * Automatically maps trigram stance to corresponding guard animation state.\n *\n * @param stance - Trigram stance identifier\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // When player changes to Fire stance\n * machine.transitionToStanceGuard(TrigramStance.LI);\n * // Internally transitions to \"stance_guard_li\" animation state\n * ```\n *\n * @korean 자세방어전환\n */\n transitionToStanceGuard(stance: TrigramStance): boolean {\n const guardAnimationState =\n PlayerAnimationStateMachine.GUARD_STATE_MAP[stance];\n\n // Verify the guard animation exists in our configs\n if (!guardAnimationState || !this.animations.has(guardAnimationState)) {\n console.warn(`No guard animation configured for stance: ${stance}`);\n return false;\n }\n\n return this.transitionTo(guardAnimationState);\n }\n\n /**\n * Check if current animation is a stance guard\n *\n * @returns True if currently in a stance guard animation\n * @korean 자세방어상태확인\n */\n isInStanceGuard(): boolean {\n return this.currentState.startsWith(\"stance_guard_\");\n }\n\n /**\n * Get current guard stance if in a guard animation\n *\n * @returns Trigram stance or null if not in guard\n * @korean 현재방어자세가져오기\n */\n getCurrentGuardStance(): TrigramStance | null {\n if (!this.isInStanceGuard()) {\n return null;\n }\n\n const stance =\n PlayerAnimationStateMachine.STANCE_FROM_GUARD_MAP[this.currentState];\n\n // Validate that we got a valid stance\n if (!stance) {\n console.warn(`Invalid guard state detected: ${this.currentState}`);\n return null;\n }\n\n return stance;\n }\n\n /**\n * Transition to stance_change animation with specific stance transition data\n *\n * **Korean**: 자세 전환 애니메이션 시작\n *\n * Initiates a stance change animation with the specific transition data\n * from the 64-transition matrix. This provides stance-specific keyframes\n * and blend weights for smooth interpolation.\n *\n * @param fromStance - Source trigram stance\n * @param toStance - Target trigram stance\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // Start transition from Heaven to Lake stance\n * const success = machine.transitionToStanceChange(\n * TrigramStance.GEON,\n * TrigramStance.TAE\n * );\n *\n * if (success) {\n * // During update loop, use getStanceTransitionBlend() to interpolate\n * const blend = machine.getStanceTransitionBlend();\n * if (blend) {\n * // Apply blend weights to stance poses\n * applyStanceBlend(blend);\n * }\n * }\n * ```\n *\n * @korean 자세전환애니메이션시작\n */\n transitionToStanceChange(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n ): boolean {\n // Get the specific transition data from the 64-transition matrix\n const transitionData = getStanceTransition(fromStance, toStance);\n\n if (!transitionData) {\n console.warn(\n `[AnimationStateMachine] No transition data found for ${fromStance} -> ${toStance}`,\n );\n return false;\n }\n\n // Store current transition data in case we need to restore it\n const previousTransitionData = this.currentStanceTransition;\n\n // Temporarily set the new transition data\n this.currentStanceTransition = transitionData;\n\n // Initiate the stance_change animation\n const success = this.transitionTo(AnimationState.STANCE_CHANGE);\n\n // If transition failed, restore previous transition data\n if (!success) {\n this.currentStanceTransition = previousTransitionData;\n }\n\n return success;\n }\n\n /**\n * Get current stance transition data\n *\n * **Korean**: 현재 자세 전환 데이터 가져오기\n *\n * Returns the active stance transition data during stance_change animation.\n * Null if not currently in a stance transition.\n *\n * @returns Current stance transition or null\n *\n * @korean 현재자세전환데이터가져오기\n */\n getCurrentStanceTransition(): StanceTransition | null {\n return this.currentStanceTransition;\n }\n\n /**\n * Get interpolated blend weights for current stance transition frame\n *\n * **Korean**: 현재 프레임 블렌드 가중치\n *\n * Returns the interpolated blend data for the current frame during\n * stance_change animation. Uses the keyframe data from the transition\n * matrix to provide smooth stance interpolation.\n *\n * @returns Blend data with stance and weight, or null if not in transition\n *\n * @example\n * ```typescript\n * // In rendering loop during stance transition\n * const blend = machine.getStanceTransitionBlend();\n * if (blend) {\n * console.log(`Frame ${blend.frame}: ${blend.stance} at ${blend.blend}x weight`);\n * // Apply blended pose: blend.blend * targetPose + (1 - blend.blend) * sourcePose\n * }\n * ```\n *\n * @korean 현재프레임블렌드가중치\n */\n getStanceTransitionBlend(): {\n frame: number;\n stance: TrigramStance | \"neutral\";\n blend: number;\n } | null {\n // Only valid during stance_change animation\n if (\n this.currentState !== AnimationState.STANCE_CHANGE ||\n !this.currentStanceTransition\n ) {\n return null;\n }\n\n const keyframes = this.currentStanceTransition.keyframes;\n const currentFrame = this.frameIndex;\n\n // Find the two keyframes to interpolate between\n let prevKeyframe = keyframes[0];\n let nextKeyframe = keyframes[keyframes.length - 1];\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n if (\n keyframes[i].frame <= currentFrame &&\n keyframes[i + 1].frame > currentFrame\n ) {\n prevKeyframe = keyframes[i];\n nextKeyframe = keyframes[i + 1];\n break;\n }\n }\n\n // If we're exactly on a keyframe, return it directly\n const exactKeyframe = keyframes.find((kf) => kf.frame === currentFrame);\n if (exactKeyframe) {\n return {\n frame: currentFrame,\n stance: exactKeyframe.stance,\n blend: exactKeyframe.blend,\n };\n }\n\n // Linear interpolation between keyframes\n const frameRange = nextKeyframe.frame - prevKeyframe.frame;\n const frameProgress =\n frameRange > 0 ? (currentFrame - prevKeyframe.frame) / frameRange : 0;\n\n const interpolatedBlend =\n prevKeyframe.blend +\n (nextKeyframe.blend - prevKeyframe.blend) * frameProgress;\n\n // Use the next keyframe's stance as we're transitioning towards it\n return {\n frame: currentFrame,\n stance: nextKeyframe.stance,\n blend: interpolatedBlend,\n };\n }\n\n /**\n * Check if currently in a stance transition animation\n *\n * **Korean**: 자세 전환 중 확인\n *\n * @returns True if currently executing a stance_change animation\n * @korean 자세전환중확인\n */\n isInStanceTransition(): boolean {\n return (\n this.currentState === AnimationState.STANCE_CHANGE &&\n this.currentStanceTransition !== null\n );\n }\n\n /**\n * Clear stance transition data (called automatically when transition completes)\n *\n * **Korean**: 자세 전환 데이터 초기화\n *\n * @internal\n * @korean 자세전환데이터초기화\n */\n private clearStanceTransition(): void {\n this.currentStanceTransition = null;\n }\n\n /**\n * Enable or disable motion prediction\n *\n * **Korean**: 동작 예측 설정\n *\n * Enables motion prediction to reduce perceived input latency by predicting\n * future animation frames based on current velocity (1-2 frames ahead).\n *\n * @param enabled - Whether to enable motion prediction\n * @param predictionTime - Optional: time ahead to predict (default: 16.67ms)\n *\n * @example\n * ```typescript\n * // Enable motion prediction for 1 frame (16.67ms at 60fps)\n * machine.setMotionPrediction(true);\n *\n * // Enable with 2 frames prediction (33.33ms)\n * machine.setMotionPrediction(true, 0.03333);\n * ```\n *\n * @korean 동작예측설정\n */\n setMotionPrediction(enabled: boolean, predictionTime?: number): void {\n this.enableMotionPrediction = enabled;\n if (predictionTime !== undefined) {\n // Clamp to 50ms maximum for <50ms total latency\n this.predictionTimeAhead = Math.min(predictionTime, 0.05);\n }\n }\n\n /**\n * Get motion prediction state\n *\n * **Korean**: 동작 예측 상태 가져오기\n *\n * @returns Current motion prediction state\n * @korean 동작예측상태가져오기\n */\n getMotionPredictionState(): MotionPredictionState {\n return this.motionPrediction;\n }\n\n /**\n * Check if motion prediction is enabled\n *\n * **Korean**: 동작 예측 활성화 확인\n *\n * @returns True if motion prediction is enabled\n * @korean 동작예측활성화확인\n */\n isMotionPredictionEnabled(): boolean {\n return this.enableMotionPrediction;\n }\n\n /**\n * Set preferred easing function for transitions\n *\n * **Korean**: 선호 이징 함수 설정\n *\n * Sets the default easing curve for animation transitions.\n * Can use presets like \"natural-motion\", \"smooth-transition\", etc.\n *\n * @param easingName - Easing function name\n *\n * @example\n * ```typescript\n * // Use natural motion for Korean martial arts\n * machine.setPreferredEasing(\"natural-motion\");\n *\n * // Use explosive power for strike animations\n * machine.setPreferredEasing(\"explosive-power\");\n * ```\n *\n * @korean 선호이징함수설정\n */\n setPreferredEasing(easingName: EasingName): void {\n this.preferredEasing = easingName;\n }\n\n /**\n * Get preferred easing function\n *\n * **Korean**: 선호 이징 함수 가져오기\n *\n * @returns Current preferred easing name\n * @korean 선호이징함수가져오기\n */\n getPreferredEasing(): EasingName {\n return this.preferredEasing;\n }\n\n /**\n * Update motion prediction with skeletal keyframe data\n *\n * **Korean**: 동작 예측 업데이트\n *\n * This should be called from the skeletal animation layer when applying\n * interpolated keyframes to the rig. It updates velocity tracking for\n * motion prediction to reduce perceived latency.\n *\n * Integration point: Call this from your skeletal animation system after\n * computing the current interpolated keyframe (e.g., from getInterpolatedKeyframe).\n *\n * @param currentKeyframe - Current skeletal animation keyframe with bone positions/rotations\n * @param deltaTime - Time elapsed since last update\n *\n * @example\n * ```typescript\n * // In your skeletal animation update loop:\n * const currentKeyframe = getInterpolatedKeyframe(animation, time);\n *\n * // Update motion prediction (for next frame)\n * if (machine.isMotionPredictionEnabled()) {\n * machine.updateMotionPredictionState(currentKeyframe, deltaTime);\n * }\n *\n * // Apply keyframe to rig\n * applyKeyframeToRig(rig, currentKeyframe);\n * ```\n *\n * @korean 동작예측업데이트\n */\n updateMotionPredictionState(\n currentKeyframe: AnimationKeyframe,\n deltaTime: number,\n ): void {\n if (!this.enableMotionPrediction) {\n return;\n }\n\n // Update velocity tracking if we have a previous keyframe\n if (this.previousKeyframe) {\n this.motionPrediction = updateMotionPrediction(\n this.motionPrediction,\n this.previousKeyframe,\n currentKeyframe,\n deltaTime,\n );\n }\n\n // Store current keyframe for next update\n this.previousKeyframe = currentKeyframe;\n }\n\n /**\n * Get predicted future keyframe for latency reduction\n *\n * **Korean**: 예측된 미래 키프레임 가져오기\n *\n * Returns a keyframe predicted ahead by predictionTimeAhead (default: 1 frame).\n * This reduces perceived input latency by showing where the animation will be\n * in the near future rather than where it currently is.\n *\n * Integration point: Use this instead of the current keyframe when applying\n * to the rig if motion prediction is enabled.\n *\n * @param currentKeyframe - Current skeletal animation keyframe\n * @returns Predicted future keyframe, or current if prediction disabled\n *\n * @example\n * ```typescript\n * // In your skeletal animation update loop:\n * let keyframeToApply = currentKeyframe;\n *\n * if (machine.isMotionPredictionEnabled()) {\n * keyframeToApply = machine.getPredictedKeyframe(currentKeyframe);\n * }\n *\n * applyKeyframeToRig(rig, keyframeToApply);\n * ```\n *\n * @korean 예측키프레임가져오기\n */\n getPredictedKeyframe(currentKeyframe: AnimationKeyframe): AnimationKeyframe {\n if (!this.enableMotionPrediction || !this.previousKeyframe) {\n return currentKeyframe;\n }\n\n return predictFutureKeyframe(\n currentKeyframe,\n this.motionPrediction,\n this.predictionTimeAhead,\n );\n }\n\n // ===== Animation Queue Methods (애니메이션 대기열) =====\n\n /**\n * Enable or reconfigure animation queue system\n *\n * **Korean**: 애니메이션 대기열 활성화/재설정\n *\n * The queue is enabled by default. Use this method to reconfigure the\n * queue size or conflict resolution strategy.\n *\n * @param maxSize - Maximum queue size (default: 3)\n * @param conflictStrategy - Conflict resolution strategy (default: \"timestamp\")\n *\n * @example\n * ```typescript\n * // Queue is enabled by default, but you can reconfigure it\n * machine.enableQueue(5, \"requested\");\n * ```\n *\n * @korean 대기열활성화\n */\n enableQueue(\n maxSize: number = 3,\n conflictStrategy: ConflictResolutionStrategy = \"timestamp\",\n ): void {\n this.animationQueue = new AnimationQueue(maxSize, conflictStrategy);\n this.conflictStrategy = conflictStrategy;\n }\n\n /**\n * Disable animation queue system\n *\n * **Korean**: 애니메이션 대기열 비활성화\n *\n * Disables the queue and clears any pending animations.\n *\n * @korean 대기열비활성화\n */\n disableQueue(): void {\n this.animationQueue = null;\n }\n\n /**\n * Check if queue is enabled\n *\n * **Korean**: 대기열 활성화 여부\n *\n * @returns True if queue is enabled\n * @korean 대기열활성화여부\n */\n isQueueEnabled(): boolean {\n return this.animationQueue !== null;\n }\n\n /**\n * Attempt to transition to a new animation state with queue support\n *\n * **Korean**: 대기열 지원 상태 전환\n *\n * Enhanced version of transitionTo() that automatically queues animations\n * when they cannot be executed immediately. Since the queue is enabled by\n * default, this is the recommended method for animation transitions.\n *\n * The queued animation will be automatically processed when the current\n * animation completes, following priority and conflict resolution rules.\n *\n * @param newState - Target animation state\n * @returns Whether transition was successful, queued, or failed\n *\n * @example\n * ```typescript\n * // Queue is enabled by default\n * const result = machine.transitionToQueued(AnimationState.ATTACK);\n * // Returns \"success\" if transitioned immediately\n * // Returns \"queued\" if couldn't interrupt but was queued\n * // Returns \"failed\" if queue is full or disabled\n * ```\n *\n * @korean 대기열상태전환\n */\n transitionToQueued(\n newState: AnimationState,\n ): \"success\" | \"queued\" | \"failed\" {\n // Try normal transition first\n const timestamp = performance.now();\n const priority = this.animations.get(newState)?.priority ?? 0;\n\n const success = this.transitionTo(newState);\n if (success) {\n return \"success\";\n }\n\n // If transition failed and queue is enabled, try to enqueue\n if (this.animationQueue) {\n const request: AnimationRequest = {\n state: newState,\n timestamp,\n priority,\n };\n\n const enqueued = this.animationQueue.enqueue(request);\n return enqueued ? \"queued\" : \"failed\";\n }\n\n return \"failed\";\n }\n\n /**\n * Process next queued animation if available\n *\n * **Korean**: 다음 대기열 애니메이션 처리\n *\n * Should be called automatically when an animation completes.\n * Dequeues and executes the highest priority pending animation.\n *\n * @returns Whether a queued animation was executed\n *\n * @internal\n * @korean 다음대기열처리\n */\n private processNextQueuedAnimation(): boolean {\n if (!this.animationQueue || this.animationQueue.isEmpty()) {\n return false;\n }\n\n const nextRequest = this.animationQueue.dequeue();\n if (!nextRequest) {\n return false;\n }\n\n // Try to execute the queued animation\n const success = this.transitionTo(nextRequest.state);\n\n if (!success) {\n // Log failure so queued animations do not disappear silently\n // Korean: 대기열 애니메이션 전이가 실패했음을 로그로 남깁니다.\n // This helps diagnose cases where transition rules, missing states,\n // or priority conflicts prevent a queued animation from playing.\n console.warn(\n \"[AnimationStateMachine] Failed to transition to queued animation state\",\n {\n requestedState: nextRequest.state,\n currentState: this.currentState,\n },\n );\n }\n\n return success;\n }\n\n /**\n * Get current animation queue state\n *\n * **Korean**: 현재 대기열 상태\n *\n * Returns information about the current queue state for debugging\n * or UI display.\n *\n * @returns Queue state information\n *\n * @korean 현재대기열상태\n */\n getQueueState(): {\n enabled: boolean;\n size: number;\n maxSize: number;\n pending: readonly AnimationRequest[];\n } {\n if (!this.animationQueue) {\n return {\n enabled: false,\n size: 0,\n maxSize: 0,\n pending: [],\n };\n }\n\n return {\n enabled: true,\n size: this.animationQueue.size(),\n maxSize: this.animationQueue.getMaxSize(),\n pending: this.animationQueue.getAll(),\n };\n }\n\n /**\n * Clear all pending queued animations\n *\n * **Korean**: 모든 대기열 초기화\n *\n * Removes all pending animations from the queue.\n *\n * @korean 모든대기열초기화\n */\n clearQueue(): void {\n this.animationQueue?.clear();\n }\n\n /**\n * Set conflict resolution strategy\n *\n * **Korean**: 충돌 해결 전략 설정\n *\n * Changes the strategy used to resolve equal-priority conflicts.\n *\n * @param strategy - Conflict resolution strategy\n *\n * @korean 충돌해결전략설정\n */\n setConflictStrategy(strategy: ConflictResolutionStrategy): void {\n this.conflictStrategy = strategy;\n\n // Keep the animation queue's strategy in sync with the state machine\n if (this.animationQueue) {\n this.animationQueue.setConflictStrategy(strategy);\n }\n }\n\n /**\n * Get current conflict resolution strategy\n *\n * **Korean**: 충돌 해결 전략 가져오기\n *\n * @returns Current conflict resolution strategy\n * @korean 충돌해결전략가져오기\n */\n getConflictStrategy(): ConflictResolutionStrategy {\n return this.conflictStrategy;\n }\n\n /**\n * Dispose of the animation state machine\n *\n * **Korean**: 애니메이션 상태 머신 해제\n *\n * Clears all internal state, queues, and references to prevent memory leaks.\n * Should be called when the state machine is no longer needed (e.g., component unmount).\n *\n * @korean 애니메이션상태머신해제\n */\n dispose(): void {\n // Clear animation queue\n this.animationQueue?.clear();\n this.animationQueue = null;\n\n // Clear stance transition data\n this.currentStanceTransition = null;\n\n // Clear motion prediction state\n this.motionPrediction = createMotionPredictionState();\n this.previousKeyframe = null;\n\n // Reset state to initial values\n this.currentState = AnimationState.IDLE;\n this.previousState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = false;\n this.justCompleted = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,IAAa,4BACX,IAAI,IAAqC;CACvC,CACE,eAAe,MACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,MACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,KACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,QAAQ;EACT,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,QACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CAED,CACE,eAAe,sBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,QAAQ;EACT,CACF;CACD,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,eAAe;EAChB,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,uBAAuB;EACxB,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,QAAQ;EACT,CACF;CACD,CACE,eAAe,QACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,KAAK;EACf,QAAQ;EACT,CACF;CACD,CACE,eAAe,KACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,IACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CAED,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,gBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CAED,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,mBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CAED,CACE,eAAe,wBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,yBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CAED,CACE,eAAe,WACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,KAAK;EAChB,CACF;CACD,CACE,eAAe,YACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,KAAK;EAChB,CACF;CAED,CACE,eAAe,mBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CAGD,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,WACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,WACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,YACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,mBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,gBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EA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"}
|
|
1
|
+
{"version":3,"file":"AnimationStateMachine.js","names":[],"sources":["../../../../src/systems/animation/core/AnimationStateMachine.ts"],"sourcesContent":["/**\n * Player Animation State Machine for Black Trigram\n *\n * Manages player character animations with frame-accurate timing at 60fps.\n * Supports animation priorities, transitions, and event callbacks.\n *\n * Based on game-design.md specifications:\n * - Attack: 12 frames (200ms at 60fps)\n * - Block: 4 frames (67ms at 60fps)\n * - Walk: 6 frames\n * - Stance change: 600ms\n *\n * @module systems/animation/AnimationStateMachine\n * @category Animation\n * @korean 애니메이션상태머신\n */\n\nimport { TrigramStance } from \"@/types/common\";\nimport type { AnimationKeyframe } from \"@/types/skeletal\";\nimport {\n createMotionPredictionState,\n predictFutureKeyframe,\n updateMotionPrediction,\n type EasingName,\n type MotionPredictionState,\n} from \"../builders/KeyframeInterpolation\";\nimport {\n AnimationQueue,\n canInterrupt,\n type AnimationRequest,\n type ConflictResolutionStrategy,\n} from \"./AnimationPriority\";\nimport {\n getStanceTransition,\n isTransitionAllowed,\n type StanceTransition,\n} from \"./AnimationTransitions\";\nimport type {\n AnimationConfig,\n AnimationEvents,\n AnimationMachineState,\n AnimationPriority,\n AnimationUpdateResult,\n FallType,\n MutableAnimationConfig,\n} from \"./types\";\nimport { AnimationState, FALL_TO_GROUND_MAP, STEP_PRIORITY } from \"./types\";\n\n/**\n * Default animation configurations based on game-design.md\n *\n * Frame timings:\n * - Attack: 12 frames = 200ms at 60fps\n * - Block: 4 frames = 67ms at 60fps\n * - Walk: 6 frames = 100ms at 60fps\n * - Hit: 4 frames = 67ms at 60fps\n * - Stance change: 36 frames = 600ms at 60fps\n * - Stance guards: 4-6 frames = breathing animation at 60fps\n * - Tactical steps: 18 frames = 300ms at 60fps, 30cm distance\n *\n * Defensive animations (방어 애니메이션):\n * - Block Success (막기): 8 frames = 133ms - absorb impact, maintain guard\n * - Parry Deflect (받아넘기기): 10 frames = 167ms - redirect attack, counter window\n * - Guard Break (방어붕괴): 15 frames = 250ms - arms forced wide, vulnerable\n * - Guard Recovery (방어복구): 12 frames = 200ms - restore guard position\n *\n * @korean 기본애니메이션설정\n */\nexport const DEFAULT_ANIMATION_CONFIGS: Map<AnimationState, AnimationConfig> =\n new Map<AnimationState, AnimationConfig>([\n [\n AnimationState.IDLE,\n {\n state: AnimationState.IDLE,\n frames: 4,\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.WALK,\n {\n state: AnimationState.WALK,\n frames: 6,\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 1 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.RUN,\n {\n state: AnimationState.RUN,\n frames: 8,\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 2 as AnimationPriority,\n duration: 8 / 60,\n },\n ],\n [\n AnimationState.STANCE_CHANGE,\n {\n state: AnimationState.STANCE_CHANGE,\n frames: 36, // 600ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 3 as AnimationPriority,\n duration: 0.6,\n easing: \"smooth-transition\", // Smooth S-curve for stance changes\n },\n ],\n [\n AnimationState.STANCE_SIDE_SWITCH,\n {\n state: AnimationState.STANCE_SIDE_SWITCH,\n frames: 24, // 400ms at 60fps for left↔right switch\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 3 as AnimationPriority,\n duration: 0.4,\n },\n ],\n [\n AnimationState.DEFEND,\n {\n state: AnimationState.DEFEND,\n frames: 4, // 67ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n // Defensive animations (방어 애니메이션) - Enhanced guard break system\n [\n AnimationState.DEFEND_BLOCK_SUCCESS,\n {\n state: AnimationState.DEFEND_BLOCK_SUCCESS,\n frames: 8, // 133ms at 60fps - absorb impact, maintain guard\n fps: 60,\n loop: false,\n interruptible: false, // Must complete block animation\n priority: 6 as AnimationPriority, // Higher than defend, same as hit\n duration: 0.133,\n easing: \"controlled-slow\", // Controlled deceleration for impact absorption\n },\n ],\n [\n AnimationState.DEFEND_PARRY,\n {\n state: AnimationState.DEFEND_PARRY,\n frames: 10, // 167ms at 60fps - redirect attack, open counter opportunity\n fps: 60,\n loop: false,\n interruptible: false, // Must complete parry animation\n priority: 7 as AnimationPriority, // Higher than block, creates counter window\n duration: 0.167,\n counterWindow: 0.2, // 200ms counter-attack opportunity after parry\n },\n ],\n [\n AnimationState.DEFEND_GUARD_BREAK,\n {\n state: AnimationState.DEFEND_GUARD_BREAK,\n frames: 15, // 250ms at 60fps - arms forced wide, vulnerable state\n fps: 60,\n loop: false,\n interruptible: false, // Cannot interrupt guard break\n priority: 8 as AnimationPriority, // Highest priority (same as fall)\n duration: 0.25,\n vulnerabilityDuration: 0.5, // 500ms vulnerable state after guard break\n },\n ],\n [\n AnimationState.DEFEND_RECOVERY,\n {\n state: AnimationState.DEFEND_RECOVERY,\n frames: 12, // 200ms at 60fps - restore guard position\n fps: 60,\n loop: false,\n interruptible: true, // Can be interrupted by attacks\n priority: 2 as AnimationPriority, // Same as run, lower than defend\n duration: 0.2,\n easing: \"natural-motion\", // Physics-based recovery\n },\n ],\n [\n AnimationState.ATTACK,\n {\n state: AnimationState.ATTACK,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: STEP_PRIORITY,\n duration: 12 / 60,\n easing: \"explosive-power\", // Explosive acceleration for attacks\n },\n ],\n [\n AnimationState.HIT,\n {\n state: AnimationState.HIT,\n frames: 4, // 67ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 6 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.KO,\n {\n state: AnimationState.KO,\n frames: 30, // 500ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 7 as AnimationPriority,\n duration: 0.5,\n },\n ],\n // Fall animations (낙법 애니메이션) - Priority 8 (highest)\n [\n AnimationState.FALL_FORWARD,\n {\n state: AnimationState.FALL_FORWARD,\n frames: 24, // 400ms at 60fps - stumble forward, knee collapse, hands brace, face-down\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.4,\n },\n ],\n [\n AnimationState.FALL_BACKWARD,\n {\n state: AnimationState.FALL_BACKWARD,\n frames: 30, // 500ms at 60fps - backward stumble, sit, back impact, supine\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.5,\n },\n ],\n [\n AnimationState.FALL_SIDE_LEFT,\n {\n state: AnimationState.FALL_SIDE_LEFT,\n frames: 27, // 450ms at 60fps - rotation, shoulder roll, side sprawl\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.45,\n },\n ],\n [\n AnimationState.FALL_SIDE_RIGHT,\n {\n state: AnimationState.FALL_SIDE_RIGHT,\n frames: 27, // 450ms at 60fps - rotation, shoulder roll, side sprawl\n fps: 60,\n loop: false,\n interruptible: false,\n priority: 8 as AnimationPriority,\n duration: 0.45,\n },\n ],\n // Ground state animations (지면 자세) - Breathing loops\n [\n AnimationState.GROUND_PRONE,\n {\n state: AnimationState.GROUND_PRONE,\n frames: 4, // Breathing loop on ground (face down)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.GROUND_SUPINE,\n {\n state: AnimationState.GROUND_SUPINE,\n frames: 4, // Breathing loop on ground (face up)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.GROUND_SIDE_LEFT,\n {\n state: AnimationState.GROUND_SIDE_LEFT,\n frames: 4, // Breathing loop on ground (left side)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.GROUND_SIDE_RIGHT,\n {\n state: AnimationState.GROUND_SIDE_RIGHT,\n frames: 4, // Breathing loop on ground (right side)\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n // Recovery animations (기상 애니메이션) - Priority 9 (higher than falls)\n [\n AnimationState.RECOVERY_PRONE_STANDUP,\n {\n state: AnimationState.RECOVERY_PRONE_STANDUP,\n frames: 30, // 500ms at 60fps - push up from prone, rise to standing\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.5,\n },\n ],\n [\n AnimationState.RECOVERY_SUPINE_STANDUP,\n {\n state: AnimationState.RECOVERY_SUPINE_STANDUP,\n frames: 36, // 600ms at 60fps - sit up, roll forward, stand\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.6,\n },\n ],\n [\n AnimationState.RECOVERY_ROLL,\n {\n state: AnimationState.RECOVERY_ROLL,\n frames: 24, // 400ms at 60fps - roll to side, spring to feet (quick recovery)\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.4,\n },\n ],\n [\n AnimationState.RECOVERY_DEFENSIVE,\n {\n state: AnimationState.RECOVERY_DEFENSIVE,\n frames: 42, // 700ms at 60fps - slow rise with guard up (vulnerable but defended)\n fps: 60,\n loop: false,\n interruptible: false, // Last 6 frames (100ms) are interruptible\n priority: 9 as AnimationPriority,\n duration: 0.7,\n },\n ],\n // 180-degree turn animations (180도 회전 애니메이션)\n [\n AnimationState.TURN_LEFT,\n {\n state: AnimationState.TURN_LEFT,\n frames: 12, // 200ms at 60fps for 180° turn\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY, // Same priority as attacks/steps - committed action\n duration: 12 / 60,\n },\n ],\n [\n AnimationState.TURN_RIGHT,\n {\n state: AnimationState.TURN_RIGHT,\n frames: 12, // 200ms at 60fps for 180° turn\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY, // Same priority as attacks/steps - committed action\n duration: 12 / 60,\n },\n ],\n // Stance-specific guard animations (팔괘 방어 자세)\n [\n AnimationState.STANCE_GUARD_GEON,\n {\n state: AnimationState.STANCE_GUARD_GEON,\n frames: 6, // Breathing animation\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_TAE,\n {\n state: AnimationState.STANCE_GUARD_TAE,\n frames: 6, // Breathing animation\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_LI,\n {\n state: AnimationState.STANCE_GUARD_LI,\n frames: 4, // Controlled breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_JIN,\n {\n state: AnimationState.STANCE_GUARD_JIN,\n frames: 5, // Deep breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 5 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_SON,\n {\n state: AnimationState.STANCE_GUARD_SON,\n frames: 6, // Rhythmic breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_GAM,\n {\n state: AnimationState.STANCE_GUARD_GAM,\n frames: 6, // Flowing breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 6 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_GAN,\n {\n state: AnimationState.STANCE_GUARD_GAN,\n frames: 4, // Steady breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 4 / 60,\n },\n ],\n [\n AnimationState.STANCE_GUARD_GON,\n {\n state: AnimationState.STANCE_GUARD_GON,\n frames: 5, // Deep diaphragm breathing\n fps: 60,\n loop: true,\n interruptible: true,\n priority: 0 as AnimationPriority,\n duration: 5 / 60,\n },\n ],\n // Tactical step animations (전술적 발걸음)\n // 18 frames = 300ms at 60fps, 30cm distance per step\n [\n AnimationState.STEP_FORWARD,\n {\n state: AnimationState.STEP_FORWARD,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false, // Non-interruptible for commitment\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_BACK,\n {\n state: AnimationState.STEP_BACK,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_LEFT,\n {\n state: AnimationState.STEP_LEFT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_RIGHT,\n {\n state: AnimationState.STEP_RIGHT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_FORWARD_LEFT,\n {\n state: AnimationState.STEP_FORWARD_LEFT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_FORWARD_RIGHT,\n {\n state: AnimationState.STEP_FORWARD_RIGHT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_BACK_LEFT,\n {\n state: AnimationState.STEP_BACK_LEFT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n [\n AnimationState.STEP_BACK_RIGHT,\n {\n state: AnimationState.STEP_BACK_RIGHT,\n frames: 18,\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n // Footwork patterns (보법) - Korean martial arts specialized footwork\n // Circular step (원형보) - Lateral movement maintaining guard facing\n [\n AnimationState.FOOTWORK_CIRCULAR_LEFT,\n {\n state: AnimationState.FOOTWORK_CIRCULAR_LEFT,\n frames: 18, // 300ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false, // Committed footwork\n priority: STEP_PRIORITY, // Same as tactical steps\n duration: 0.3,\n },\n ],\n [\n AnimationState.FOOTWORK_CIRCULAR_RIGHT,\n {\n state: AnimationState.FOOTWORK_CIRCULAR_RIGHT,\n frames: 18, // 300ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.3,\n },\n ],\n // Pivot step (축족회전) - Rotation on planted foot\n [\n AnimationState.FOOTWORK_PIVOT_LEFT,\n {\n state: AnimationState.FOOTWORK_PIVOT_LEFT,\n frames: 15, // 250ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.25,\n },\n ],\n [\n AnimationState.FOOTWORK_PIVOT_RIGHT,\n {\n state: AnimationState.FOOTWORK_PIVOT_RIGHT,\n frames: 15, // 250ms at 60fps\n fps: 60,\n loop: false,\n interruptible: false,\n priority: STEP_PRIORITY,\n duration: 0.25,\n },\n ],\n // Slide step (미끄럼보) - Both feet move together\n [\n AnimationState.FOOTWORK_SLIDE_FORWARD,\n {\n state: AnimationState.FOOTWORK_SLIDE_FORWARD,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true, // Can be interrupted\n priority: 4 as AnimationPriority, // Same as defend\n duration: 0.2,\n },\n ],\n [\n AnimationState.FOOTWORK_SLIDE_BACK,\n {\n state: AnimationState.FOOTWORK_SLIDE_BACK,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 0.2,\n },\n ],\n [\n AnimationState.FOOTWORK_SLIDE_LEFT,\n {\n state: AnimationState.FOOTWORK_SLIDE_LEFT,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 0.2,\n },\n ],\n [\n AnimationState.FOOTWORK_SLIDE_RIGHT,\n {\n state: AnimationState.FOOTWORK_SLIDE_RIGHT,\n frames: 12, // 200ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 4 as AnimationPriority,\n duration: 0.2,\n },\n ],\n // Shuffle step (섞음보) - Quick micro-adjustment\n [\n AnimationState.FOOTWORK_SHUFFLE,\n {\n state: AnimationState.FOOTWORK_SHUFFLE,\n frames: 6, // 100ms at 60fps\n fps: 60,\n loop: false,\n interruptible: true,\n priority: 3 as AnimationPriority, // Same as stance_change\n duration: 0.1,\n },\n ],\n ]);\n\n/**\n * Player Animation State Machine\n *\n * Manages animation state, transitions, and timing with frame-accurate updates.\n * Integrates priority system, automatic animation queueing, and event callbacks.\n *\n * **Animation Queue**: Enabled by default with max size 3 and timestamp-based\n * conflict resolution. Automatically queues animations that cannot execute\n * immediately and processes them when the current animation completes.\n *\n * @example\n * ```typescript\n * const machine = new PlayerAnimationStateMachine(DEFAULT_ANIMATION_CONFIGS, {\n * onAnimationStart: (state) => console.log(`Started ${state}`),\n * onAnimationComplete: (state) => console.log(`Completed ${state}`),\n * onFrame: (frame, state) => {\n * if (state === \"attack\" && frame === 6) {\n * // Execute attack at midpoint (frame 6 of 12)\n * executeAttackLogic();\n * }\n * }\n * });\n *\n * // Animation queue is enabled by default\n * // Use transitionToQueued() for automatic queueing\n * machine.transitionToQueued(AnimationState.ATTACK); // Queues if can't execute\n *\n * // Or use regular transitionTo() (no queueing)\n * machine.transitionTo(AnimationState.ATTACK); // Fails if can't execute\n *\n * // In game loop (useFrame)\n * useFrame((state, delta) => {\n * const result = machine.update(delta);\n * updatePlayerVisuals(result.state, result.frame);\n * });\n * ```\n *\n * @korean 플레이어애니메이션상태머신\n */\nexport class PlayerAnimationStateMachine {\n /**\n * Static mapping from TrigramStance to guard AnimationState\n * Prevents repeated object allocation in transitionToStanceGuard()\n * @korean 자세방어상태맵\n */\n private static readonly GUARD_STATE_MAP: Record<\n TrigramStance,\n AnimationState\n > = {\n [TrigramStance.GEON]: AnimationState.STANCE_GUARD_GEON,\n [TrigramStance.TAE]: AnimationState.STANCE_GUARD_TAE,\n [TrigramStance.LI]: AnimationState.STANCE_GUARD_LI,\n [TrigramStance.JIN]: AnimationState.STANCE_GUARD_JIN,\n [TrigramStance.SON]: AnimationState.STANCE_GUARD_SON,\n [TrigramStance.GAM]: AnimationState.STANCE_GUARD_GAM,\n [TrigramStance.GAN]: AnimationState.STANCE_GUARD_GAN,\n [TrigramStance.GON]: AnimationState.STANCE_GUARD_GON,\n };\n\n /**\n * Static reverse mapping from guard AnimationState to TrigramStance\n * Prevents repeated object allocation in getCurrentGuardStance()\n * @korean 방어상태자세맵\n */\n private static readonly STANCE_FROM_GUARD_MAP: Record<string, TrigramStance> =\n {\n [AnimationState.STANCE_GUARD_GEON]: TrigramStance.GEON,\n [AnimationState.STANCE_GUARD_TAE]: TrigramStance.TAE,\n [AnimationState.STANCE_GUARD_LI]: TrigramStance.LI,\n [AnimationState.STANCE_GUARD_JIN]: TrigramStance.JIN,\n [AnimationState.STANCE_GUARD_SON]: TrigramStance.SON,\n [AnimationState.STANCE_GUARD_GAM]: TrigramStance.GAM,\n [AnimationState.STANCE_GUARD_GAN]: TrigramStance.GAN,\n [AnimationState.STANCE_GUARD_GON]: TrigramStance.GON,\n };\n\n private currentState: AnimationState = AnimationState.IDLE;\n private frameIndex = 0;\n private timeAccumulator = 0;\n private previousState: AnimationState | null = null;\n private justStarted = false;\n private justCompleted = false;\n\n /**\n * Current stance transition data (null when not in stance_change animation)\n *\n * **Korean**: 현재 자세 전환 데이터\n *\n * Tracks the active stance transition for use during stance_change animation.\n * Provides access to keyframes and blend weights for smooth interpolation.\n *\n * @korean 현재자세전환데이터\n */\n private currentStanceTransition: StanceTransition | null = null;\n\n /**\n * Motion prediction state for latency reduction\n *\n * **Korean**: 동작 예측 상태\n *\n * Tracks animation velocities for motion prediction to reduce perceived latency.\n * Updated each frame with velocity calculations for smooth anticipation.\n *\n * @korean 동작예측상태\n */\n private motionPrediction: MotionPredictionState =\n createMotionPredictionState();\n\n /**\n * Enable motion prediction for latency reduction\n *\n * **Korean**: 동작 예측 활성화\n *\n * When enabled, predicts future animation frames based on current velocity\n * to reduce perceived input latency by 16-33ms (1-2 frames at 60fps).\n *\n * @korean 동작예측활성화\n */\n private enableMotionPrediction: boolean = false;\n\n /**\n * Motion prediction time ahead (seconds)\n *\n * **Korean**: 예측 시간\n *\n * How far ahead to predict motion (default: 1 frame = 16.67ms at 60fps).\n * Typical range: 0.016-0.033 seconds for <50ms total latency.\n *\n * @korean 예측시간\n */\n private predictionTimeAhead: number = 0.01667; // 1 frame at 60fps\n\n /**\n * Previous keyframe for motion prediction velocity calculation\n *\n * **Korean**: 이전 키프레임\n *\n * @korean 이전키프레임\n */\n private previousKeyframe: AnimationKeyframe | null = null;\n\n /**\n * Preferred easing function for smooth transitions\n *\n * **Korean**: 선호 이징 함수\n *\n * Default easing curve for animation blending and transitions.\n * Can be overridden per animation or transition.\n *\n * @korean 선호이징함수\n */\n private preferredEasing: EasingName = \"natural-motion\";\n\n /**\n * Animation queue for pending animations\n *\n * **Korean**: 애니메이션 대기열\n *\n * Stores animation requests that couldn't be executed immediately\n * due to non-interruptible animations or priority conflicts.\n * Processed automatically when current animation completes.\n *\n * Enabled by default with max size 3 and timestamp-based conflict resolution.\n * Can be disabled with disableQueue() or reconfigured with enableQueue().\n *\n * @korean 애니메이션대기열\n */\n private animationQueue: AnimationQueue | null = new AnimationQueue(\n 3,\n \"timestamp\",\n );\n\n /**\n * Conflict resolution strategy for equal-priority animations\n *\n * **Korean**: 충돌 해결 전략\n *\n * Determines how to resolve conflicts when multiple animations\n * have equal priority. Default: timestamp (FIFO).\n *\n * @korean 충돌해결전략\n */\n private conflictStrategy: ConflictResolutionStrategy = \"timestamp\";\n\n /**\n * Create a new animation state machine\n *\n * Clones the provided config map so per-instance mutations\n * (e.g. dynamic attack duration) don't affect shared defaults.\n *\n * @param animations - Map of animation configurations (cloned internally)\n * @param events - Optional event callbacks\n *\n * @korean 생성자\n */\n private readonly animations: Map<AnimationState, MutableAnimationConfig>;\n\n constructor(\n animations: Map<AnimationState, AnimationConfig>,\n private readonly events?: AnimationEvents,\n ) {\n // Clone so we can safely mutate per-instance (e.g. attack duration)\n this.animations = new Map(\n Array.from(animations.entries()).map(([k, v]) => [k, { ...v }]),\n );\n }\n\n /**\n * Update animation state with delta time\n *\n * Call this in useFrame for 60fps updates.\n * Handles frame progression, looping, and completion.\n *\n * @param deltaTime - Time elapsed since last update (in seconds)\n * @returns Animation update result with current state and frame\n *\n * @korean 업데이트\n */\n update(deltaTime: number): AnimationUpdateResult {\n const currentAnim = this.animations.get(this.currentState);\n if (!currentAnim) {\n return {\n state: this.currentState,\n frame: 0,\n progress: 0,\n justCompleted: false,\n justStarted: false,\n };\n }\n\n // Reset just started/completed flags\n const wasJustStarted = this.justStarted;\n this.justStarted = false;\n const previousJustCompleted = this.justCompleted;\n this.justCompleted = false;\n\n // Accumulate time\n this.timeAccumulator += deltaTime;\n const frameDuration = 1 / currentAnim.fps;\n\n // Check if we should advance to next frame\n if (this.timeAccumulator >= frameDuration) {\n const previousFrame = this.frameIndex;\n this.frameIndex++;\n this.timeAccumulator -= frameDuration;\n\n // Emit frame event\n if (this.events?.onFrame && previousFrame !== this.frameIndex) {\n this.events.onFrame(this.frameIndex, this.currentState);\n }\n\n // Handle animation completion\n if (this.frameIndex >= currentAnim.frames) {\n if (currentAnim.loop) {\n // Loop back to start\n this.frameIndex = 0;\n } else {\n // Animation completed\n this.justCompleted = true;\n if (this.events?.onAnimationComplete) {\n this.events.onAnimationComplete(this.currentState);\n }\n\n // Auto-transition logic\n // Fall animations transition to ground states using the mapping\n if (this.currentState.startsWith(\"fall_\")) {\n const fallType = this.currentState.replace(\"fall_\", \"\");\n\n // Validate that fallType is a valid FallType before using in map\n if (\n fallType === \"forward\" ||\n fallType === \"backward\" ||\n fallType === \"side_left\" ||\n fallType === \"side_right\"\n ) {\n const groundState = FALL_TO_GROUND_MAP[fallType as FallType];\n const groundAnimKey = `ground_${groundState}`;\n\n // Validate that the constructed ground animation state actually exists\n if (\n DEFAULT_ANIMATION_CONFIGS.has(groundAnimKey as AnimationState)\n ) {\n const groundAnimState = groundAnimKey as AnimationState;\n\n this.previousState = this.currentState;\n this.currentState = groundAnimState;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(groundAnimState);\n }\n } else {\n // Fallback: if mapping is invalid, safely transition to idle\n // instead of entering an undefined animation state.\n console.warn(\n \"[AnimationStateMachine] Invalid ground animation mapping for fall type:\",\n fallType,\n \"->\",\n groundAnimKey,\n );\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n }\n } else {\n // Invalid fall type - fallback to idle\n console.warn(\n \"[AnimationStateMachine] Invalid fall animation state:\",\n this.currentState,\n );\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n }\n }\n // Recovery animations transition to idle when complete\n else if (this.currentState.startsWith(\"recovery_\")) {\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n }\n // Non-fall, non-recovery, non-looping animations transition to idle\n else if (\n this.currentState !== AnimationState.IDLE &&\n this.currentState !== AnimationState.KO &&\n !this.currentState.startsWith(\"ground_\")\n ) {\n // Clear stance transition data if completing stance_change\n if (this.currentState === AnimationState.STANCE_CHANGE) {\n this.clearStanceTransition();\n }\n\n // Transition to idle first\n this.previousState = this.currentState;\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(AnimationState.IDLE);\n }\n\n // Then try to process next queued animation (from idle state)\n this.processNextQueuedAnimation();\n } else {\n // Stay on last frame (for ko and ground states)\n this.frameIndex = currentAnim.frames - 1;\n }\n }\n }\n }\n\n const progress =\n currentAnim.frames > 0 ? this.frameIndex / currentAnim.frames : 0;\n\n return {\n state: this.currentState,\n frame: this.frameIndex,\n progress,\n justCompleted: previousJustCompleted,\n justStarted: wasJustStarted,\n };\n }\n\n /**\n * Attempt to transition to a new animation state\n *\n * Checks transition rules and priority system before transitioning.\n *\n * @param newState - Target animation state\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // Successful transitions\n * machine.transitionTo(\"walk\"); // idle -> walk\n * machine.transitionTo(\"attack\"); // walk -> attack\n *\n * // Failed transition (invalid or lower priority)\n * machine.transitionTo(\"walk\"); // attack -> walk (blocked, must complete first)\n * ```\n *\n * @korean 상태전환\n */\n transitionTo(newState: AnimationState): boolean {\n // Don't transition to same state\n if (this.currentState === newState) {\n return false;\n }\n\n // Check if transition is allowed by rules\n if (!isTransitionAllowed(this.currentState, newState)) {\n return false;\n }\n\n const currentAnim = this.animations.get(this.currentState);\n const newAnim = this.animations.get(newState);\n\n if (!newAnim) {\n return false;\n }\n\n // Check priority system\n if (\n currentAnim &&\n !canInterrupt(this.currentState, newState, currentAnim.interruptible)\n ) {\n return false;\n }\n\n // Emit interrupt event if current animation wasn't completed\n if (this.frameIndex < (currentAnim?.frames ?? 0) - 1) {\n if (this.events?.onAnimationInterrupted) {\n this.events.onAnimationInterrupted(this.currentState, newState);\n }\n }\n\n // Clear stance transition data if interrupting stance_change\n if (this.currentState === AnimationState.STANCE_CHANGE) {\n this.clearStanceTransition();\n }\n\n // Execute transition\n this.previousState = this.currentState;\n this.currentState = newState;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = true;\n this.justCompleted = false;\n\n // Emit start event\n if (this.events?.onAnimationStart) {\n this.events.onAnimationStart(newState);\n }\n\n return true;\n }\n\n /**\n * Transition to ATTACK state with a technique-specific duration.\n *\n * The default ATTACK config is 200ms (12 frames), but real techniques\n * range from 350ms to 1200ms. This method overrides the ATTACK frame\n * count to match the actual skeletal animation duration so the state\n * machine stays in ATTACK for the full technique.\n *\n * @param durationSeconds - The skeletal animation duration in seconds\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // Jab animation is 0.55s (TECHNIQUE_TIMING.FAST)\n * machine.transitionToAttack(0.55);\n * ```\n *\n * @korean 공격전환 (기술별 지속시간)\n */\n transitionToAttack(durationSeconds: number): boolean {\n const attackConfig = this.animations.get(AnimationState.ATTACK);\n if (attackConfig) {\n const fps = attackConfig.fps || 60;\n attackConfig.frames = Math.max(1, Math.round(durationSeconds * fps));\n attackConfig.duration = durationSeconds;\n }\n return this.transitionTo(AnimationState.ATTACK);\n }\n\n /**\n * Get current animation state\n *\n * @returns Current animation state\n * @korean 현재상태가져오기\n */\n getCurrentState(): AnimationState {\n return this.currentState;\n }\n\n /**\n * Get current frame index\n *\n * @returns Current frame index (0 to frames-1)\n * @korean 현재프레임가져오기\n */\n getCurrentFrame(): number {\n return this.frameIndex;\n }\n\n /**\n * Get previous animation state\n *\n * @returns Previous animation state or null\n * @korean 이전상태가져오기\n */\n getPreviousState(): AnimationState | null {\n return this.previousState;\n }\n\n /**\n * Get current animation configuration\n *\n * @returns Current animation config or undefined\n * @korean 현재애니메이션설정가져오기\n */\n getCurrentAnimation(): AnimationConfig | undefined {\n return this.animations.get(this.currentState);\n }\n\n /**\n * Reset animation state machine to idle\n *\n * @korean 초기화\n */\n reset(): void {\n this.currentState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.previousState = null;\n this.justStarted = false;\n this.justCompleted = false;\n }\n\n /**\n * Get full internal state (for debugging/testing)\n *\n * @returns Current state machine state\n * @korean 상태가져오기\n */\n getState(): AnimationMachineState {\n return {\n currentState: this.currentState,\n frameIndex: this.frameIndex,\n timeAccumulator: this.timeAccumulator,\n isPlaying: true,\n previousState: this.previousState,\n };\n }\n\n /**\n * Transition to stance-specific guard animation\n *\n * Convenience method to transition to a stance guard based on trigram stance.\n * Automatically maps trigram stance to corresponding guard animation state.\n *\n * @param stance - Trigram stance identifier\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // When player changes to Fire stance\n * machine.transitionToStanceGuard(TrigramStance.LI);\n * // Internally transitions to \"stance_guard_li\" animation state\n * ```\n *\n * @korean 자세방어전환\n */\n transitionToStanceGuard(stance: TrigramStance): boolean {\n const guardAnimationState =\n PlayerAnimationStateMachine.GUARD_STATE_MAP[stance];\n\n // Verify the guard animation exists in our configs\n if (!guardAnimationState || !this.animations.has(guardAnimationState)) {\n console.warn(`No guard animation configured for stance: ${stance}`);\n return false;\n }\n\n return this.transitionTo(guardAnimationState);\n }\n\n /**\n * Check if current animation is a stance guard\n *\n * @returns True if currently in a stance guard animation\n * @korean 자세방어상태확인\n */\n isInStanceGuard(): boolean {\n return this.currentState.startsWith(\"stance_guard_\");\n }\n\n /**\n * Get current guard stance if in a guard animation\n *\n * @returns Trigram stance or null if not in guard\n * @korean 현재방어자세가져오기\n */\n getCurrentGuardStance(): TrigramStance | null {\n if (!this.isInStanceGuard()) {\n return null;\n }\n\n const stance =\n PlayerAnimationStateMachine.STANCE_FROM_GUARD_MAP[this.currentState];\n\n // Validate that we got a valid stance\n if (!stance) {\n console.warn(`Invalid guard state detected: ${this.currentState}`);\n return null;\n }\n\n return stance;\n }\n\n /**\n * Transition to stance_change animation with specific stance transition data\n *\n * **Korean**: 자세 전환 애니메이션 시작\n *\n * Initiates a stance change animation with the specific transition data\n * from the 64-transition matrix. This provides stance-specific keyframes\n * and blend weights for smooth interpolation.\n *\n * @param fromStance - Source trigram stance\n * @param toStance - Target trigram stance\n * @returns Whether transition was successful\n *\n * @example\n * ```typescript\n * // Start transition from Heaven to Lake stance\n * const success = machine.transitionToStanceChange(\n * TrigramStance.GEON,\n * TrigramStance.TAE\n * );\n *\n * if (success) {\n * // During update loop, use getStanceTransitionBlend() to interpolate\n * const blend = machine.getStanceTransitionBlend();\n * if (blend) {\n * // Apply blend weights to stance poses\n * applyStanceBlend(blend);\n * }\n * }\n * ```\n *\n * @korean 자세전환애니메이션시작\n */\n transitionToStanceChange(\n fromStance: TrigramStance,\n toStance: TrigramStance,\n ): boolean {\n // Get the specific transition data from the 64-transition matrix\n const transitionData = getStanceTransition(fromStance, toStance);\n\n if (!transitionData) {\n console.warn(\n `[AnimationStateMachine] No transition data found for ${fromStance} -> ${toStance}`,\n );\n return false;\n }\n\n // Store current transition data in case we need to restore it\n const previousTransitionData = this.currentStanceTransition;\n\n // Temporarily set the new transition data\n this.currentStanceTransition = transitionData;\n\n // Initiate the stance_change animation\n const success = this.transitionTo(AnimationState.STANCE_CHANGE);\n\n // If transition failed, restore previous transition data\n if (!success) {\n this.currentStanceTransition = previousTransitionData;\n }\n\n return success;\n }\n\n /**\n * Get current stance transition data\n *\n * **Korean**: 현재 자세 전환 데이터 가져오기\n *\n * Returns the active stance transition data during stance_change animation.\n * Null if not currently in a stance transition.\n *\n * @returns Current stance transition or null\n *\n * @korean 현재자세전환데이터가져오기\n */\n getCurrentStanceTransition(): StanceTransition | null {\n return this.currentStanceTransition;\n }\n\n /**\n * Get interpolated blend weights for current stance transition frame\n *\n * **Korean**: 현재 프레임 블렌드 가중치\n *\n * Returns the interpolated blend data for the current frame during\n * stance_change animation. Uses the keyframe data from the transition\n * matrix to provide smooth stance interpolation.\n *\n * @returns Blend data with stance and weight, or null if not in transition\n *\n * @example\n * ```typescript\n * // In rendering loop during stance transition\n * const blend = machine.getStanceTransitionBlend();\n * if (blend) {\n * console.log(`Frame ${blend.frame}: ${blend.stance} at ${blend.blend}x weight`);\n * // Apply blended pose: blend.blend * targetPose + (1 - blend.blend) * sourcePose\n * }\n * ```\n *\n * @korean 현재프레임블렌드가중치\n */\n getStanceTransitionBlend(): {\n frame: number;\n stance: TrigramStance | \"neutral\";\n blend: number;\n } | null {\n // Only valid during stance_change animation\n if (\n this.currentState !== AnimationState.STANCE_CHANGE ||\n !this.currentStanceTransition\n ) {\n return null;\n }\n\n const keyframes = this.currentStanceTransition.keyframes;\n const currentFrame = this.frameIndex;\n\n // Find the two keyframes to interpolate between\n let prevKeyframe = keyframes[0];\n let nextKeyframe = keyframes[keyframes.length - 1];\n\n for (let i = 0; i < keyframes.length - 1; i++) {\n if (\n keyframes[i].frame <= currentFrame &&\n keyframes[i + 1].frame > currentFrame\n ) {\n prevKeyframe = keyframes[i];\n nextKeyframe = keyframes[i + 1];\n break;\n }\n }\n\n // If we're exactly on a keyframe, return it directly\n const exactKeyframe = keyframes.find((kf) => kf.frame === currentFrame);\n if (exactKeyframe) {\n return {\n frame: currentFrame,\n stance: exactKeyframe.stance,\n blend: exactKeyframe.blend,\n };\n }\n\n // Linear interpolation between keyframes\n const frameRange = nextKeyframe.frame - prevKeyframe.frame;\n const frameProgress =\n frameRange > 0 ? (currentFrame - prevKeyframe.frame) / frameRange : 0;\n\n const interpolatedBlend =\n prevKeyframe.blend +\n (nextKeyframe.blend - prevKeyframe.blend) * frameProgress;\n\n // Use the next keyframe's stance as we're transitioning towards it\n return {\n frame: currentFrame,\n stance: nextKeyframe.stance,\n blend: interpolatedBlend,\n };\n }\n\n /**\n * Check if currently in a stance transition animation\n *\n * **Korean**: 자세 전환 중 확인\n *\n * @returns True if currently executing a stance_change animation\n * @korean 자세전환중확인\n */\n isInStanceTransition(): boolean {\n return (\n this.currentState === AnimationState.STANCE_CHANGE &&\n this.currentStanceTransition !== null\n );\n }\n\n /**\n * Clear stance transition data (called automatically when transition completes)\n *\n * **Korean**: 자세 전환 데이터 초기화\n *\n * @internal\n * @korean 자세전환데이터초기화\n */\n private clearStanceTransition(): void {\n this.currentStanceTransition = null;\n }\n\n /**\n * Enable or disable motion prediction\n *\n * **Korean**: 동작 예측 설정\n *\n * Enables motion prediction to reduce perceived input latency by predicting\n * future animation frames based on current velocity (1-2 frames ahead).\n *\n * @param enabled - Whether to enable motion prediction\n * @param predictionTime - Optional: time ahead to predict (default: 16.67ms)\n *\n * @example\n * ```typescript\n * // Enable motion prediction for 1 frame (16.67ms at 60fps)\n * machine.setMotionPrediction(true);\n *\n * // Enable with 2 frames prediction (33.33ms)\n * machine.setMotionPrediction(true, 0.03333);\n * ```\n *\n * @korean 동작예측설정\n */\n setMotionPrediction(enabled: boolean, predictionTime?: number): void {\n this.enableMotionPrediction = enabled;\n if (predictionTime !== undefined) {\n // Clamp to 50ms maximum for <50ms total latency\n this.predictionTimeAhead = Math.min(predictionTime, 0.05);\n }\n }\n\n /**\n * Get motion prediction state\n *\n * **Korean**: 동작 예측 상태 가져오기\n *\n * @returns Current motion prediction state\n * @korean 동작예측상태가져오기\n */\n getMotionPredictionState(): MotionPredictionState {\n return this.motionPrediction;\n }\n\n /**\n * Check if motion prediction is enabled\n *\n * **Korean**: 동작 예측 활성화 확인\n *\n * @returns True if motion prediction is enabled\n * @korean 동작예측활성화확인\n */\n isMotionPredictionEnabled(): boolean {\n return this.enableMotionPrediction;\n }\n\n /**\n * Set preferred easing function for transitions\n *\n * **Korean**: 선호 이징 함수 설정\n *\n * Sets the default easing curve for animation transitions.\n * Can use presets like \"natural-motion\", \"smooth-transition\", etc.\n *\n * @param easingName - Easing function name\n *\n * @example\n * ```typescript\n * // Use natural motion for Korean martial arts\n * machine.setPreferredEasing(\"natural-motion\");\n *\n * // Use explosive power for strike animations\n * machine.setPreferredEasing(\"explosive-power\");\n * ```\n *\n * @korean 선호이징함수설정\n */\n setPreferredEasing(easingName: EasingName): void {\n this.preferredEasing = easingName;\n }\n\n /**\n * Get preferred easing function\n *\n * **Korean**: 선호 이징 함수 가져오기\n *\n * @returns Current preferred easing name\n * @korean 선호이징함수가져오기\n */\n getPreferredEasing(): EasingName {\n return this.preferredEasing;\n }\n\n /**\n * Update motion prediction with skeletal keyframe data\n *\n * **Korean**: 동작 예측 업데이트\n *\n * This should be called from the skeletal animation layer when applying\n * interpolated keyframes to the rig. It updates velocity tracking for\n * motion prediction to reduce perceived latency.\n *\n * Integration point: Call this from your skeletal animation system after\n * computing the current interpolated keyframe (e.g., from getInterpolatedKeyframe).\n *\n * @param currentKeyframe - Current skeletal animation keyframe with bone positions/rotations\n * @param deltaTime - Time elapsed since last update\n *\n * @example\n * ```typescript\n * // In your skeletal animation update loop:\n * const currentKeyframe = getInterpolatedKeyframe(animation, time);\n *\n * // Update motion prediction (for next frame)\n * if (machine.isMotionPredictionEnabled()) {\n * machine.updateMotionPredictionState(currentKeyframe, deltaTime);\n * }\n *\n * // Apply keyframe to rig\n * applyKeyframeToRig(rig, currentKeyframe);\n * ```\n *\n * @korean 동작예측업데이트\n */\n updateMotionPredictionState(\n currentKeyframe: AnimationKeyframe,\n deltaTime: number,\n ): void {\n if (!this.enableMotionPrediction) {\n return;\n }\n\n // Update velocity tracking if we have a previous keyframe\n if (this.previousKeyframe) {\n this.motionPrediction = updateMotionPrediction(\n this.motionPrediction,\n this.previousKeyframe,\n currentKeyframe,\n deltaTime,\n );\n }\n\n // Store current keyframe for next update\n this.previousKeyframe = currentKeyframe;\n }\n\n /**\n * Get predicted future keyframe for latency reduction\n *\n * **Korean**: 예측된 미래 키프레임 가져오기\n *\n * Returns a keyframe predicted ahead by predictionTimeAhead (default: 1 frame).\n * This reduces perceived input latency by showing where the animation will be\n * in the near future rather than where it currently is.\n *\n * Integration point: Use this instead of the current keyframe when applying\n * to the rig if motion prediction is enabled.\n *\n * @param currentKeyframe - Current skeletal animation keyframe\n * @returns Predicted future keyframe, or current if prediction disabled\n *\n * @example\n * ```typescript\n * // In your skeletal animation update loop:\n * let keyframeToApply = currentKeyframe;\n *\n * if (machine.isMotionPredictionEnabled()) {\n * keyframeToApply = machine.getPredictedKeyframe(currentKeyframe);\n * }\n *\n * applyKeyframeToRig(rig, keyframeToApply);\n * ```\n *\n * @korean 예측키프레임가져오기\n */\n getPredictedKeyframe(currentKeyframe: AnimationKeyframe): AnimationKeyframe {\n if (!this.enableMotionPrediction || !this.previousKeyframe) {\n return currentKeyframe;\n }\n\n return predictFutureKeyframe(\n currentKeyframe,\n this.motionPrediction,\n this.predictionTimeAhead,\n );\n }\n\n // ===== Animation Queue Methods (애니메이션 대기열) =====\n\n /**\n * Enable or reconfigure animation queue system\n *\n * **Korean**: 애니메이션 대기열 활성화/재설정\n *\n * The queue is enabled by default. Use this method to reconfigure the\n * queue size or conflict resolution strategy.\n *\n * @param maxSize - Maximum queue size (default: 3)\n * @param conflictStrategy - Conflict resolution strategy (default: \"timestamp\")\n *\n * @example\n * ```typescript\n * // Queue is enabled by default, but you can reconfigure it\n * machine.enableQueue(5, \"requested\");\n * ```\n *\n * @korean 대기열활성화\n */\n enableQueue(\n maxSize: number = 3,\n conflictStrategy: ConflictResolutionStrategy = \"timestamp\",\n ): void {\n this.animationQueue = new AnimationQueue(maxSize, conflictStrategy);\n this.conflictStrategy = conflictStrategy;\n }\n\n /**\n * Disable animation queue system\n *\n * **Korean**: 애니메이션 대기열 비활성화\n *\n * Disables the queue and clears any pending animations.\n *\n * @korean 대기열비활성화\n */\n disableQueue(): void {\n this.animationQueue = null;\n }\n\n /**\n * Check if queue is enabled\n *\n * **Korean**: 대기열 활성화 여부\n *\n * @returns True if queue is enabled\n * @korean 대기열활성화여부\n */\n isQueueEnabled(): boolean {\n return this.animationQueue !== null;\n }\n\n /**\n * Attempt to transition to a new animation state with queue support\n *\n * **Korean**: 대기열 지원 상태 전환\n *\n * Enhanced version of transitionTo() that automatically queues animations\n * when they cannot be executed immediately. Since the queue is enabled by\n * default, this is the recommended method for animation transitions.\n *\n * The queued animation will be automatically processed when the current\n * animation completes, following priority and conflict resolution rules.\n *\n * @param newState - Target animation state\n * @returns Whether transition was successful, queued, or failed\n *\n * @example\n * ```typescript\n * // Queue is enabled by default\n * const result = machine.transitionToQueued(AnimationState.ATTACK);\n * // Returns \"success\" if transitioned immediately\n * // Returns \"queued\" if couldn't interrupt but was queued\n * // Returns \"failed\" if queue is full or disabled\n * ```\n *\n * @korean 대기열상태전환\n */\n transitionToQueued(\n newState: AnimationState,\n ): \"success\" | \"queued\" | \"failed\" {\n // Try normal transition first\n const timestamp = performance.now();\n const priority = this.animations.get(newState)?.priority ?? 0;\n\n const success = this.transitionTo(newState);\n if (success) {\n return \"success\";\n }\n\n // If transition failed and queue is enabled, try to enqueue\n if (this.animationQueue) {\n const request: AnimationRequest = {\n state: newState,\n timestamp,\n priority,\n };\n\n const enqueued = this.animationQueue.enqueue(request);\n return enqueued ? \"queued\" : \"failed\";\n }\n\n return \"failed\";\n }\n\n /**\n * Process next queued animation if available\n *\n * **Korean**: 다음 대기열 애니메이션 처리\n *\n * Should be called automatically when an animation completes.\n * Dequeues and executes the highest priority pending animation.\n *\n * @returns Whether a queued animation was executed\n *\n * @internal\n * @korean 다음대기열처리\n */\n private processNextQueuedAnimation(): boolean {\n if (!this.animationQueue || this.animationQueue.isEmpty()) {\n return false;\n }\n\n const nextRequest = this.animationQueue.dequeue();\n if (!nextRequest) {\n return false;\n }\n\n // Try to execute the queued animation\n const success = this.transitionTo(nextRequest.state);\n\n if (!success) {\n // Log failure so queued animations do not disappear silently\n // Korean: 대기열 애니메이션 전이가 실패했음을 로그로 남깁니다.\n // This helps diagnose cases where transition rules, missing states,\n // or priority conflicts prevent a queued animation from playing.\n console.warn(\n \"[AnimationStateMachine] Failed to transition to queued animation state\",\n {\n requestedState: nextRequest.state,\n currentState: this.currentState,\n },\n );\n }\n\n return success;\n }\n\n /**\n * Get current animation queue state\n *\n * **Korean**: 현재 대기열 상태\n *\n * Returns information about the current queue state for debugging\n * or UI display.\n *\n * @returns Queue state information\n *\n * @korean 현재대기열상태\n */\n getQueueState(): {\n enabled: boolean;\n size: number;\n maxSize: number;\n pending: readonly AnimationRequest[];\n } {\n if (!this.animationQueue) {\n return {\n enabled: false,\n size: 0,\n maxSize: 0,\n pending: [],\n };\n }\n\n return {\n enabled: true,\n size: this.animationQueue.size(),\n maxSize: this.animationQueue.getMaxSize(),\n pending: this.animationQueue.getAll(),\n };\n }\n\n /**\n * Clear all pending queued animations\n *\n * **Korean**: 모든 대기열 초기화\n *\n * Removes all pending animations from the queue.\n *\n * @korean 모든대기열초기화\n */\n clearQueue(): void {\n this.animationQueue?.clear();\n }\n\n /**\n * Set conflict resolution strategy\n *\n * **Korean**: 충돌 해결 전략 설정\n *\n * Changes the strategy used to resolve equal-priority conflicts.\n *\n * @param strategy - Conflict resolution strategy\n *\n * @korean 충돌해결전략설정\n */\n setConflictStrategy(strategy: ConflictResolutionStrategy): void {\n this.conflictStrategy = strategy;\n\n // Keep the animation queue's strategy in sync with the state machine\n if (this.animationQueue) {\n this.animationQueue.setConflictStrategy(strategy);\n }\n }\n\n /**\n * Get current conflict resolution strategy\n *\n * **Korean**: 충돌 해결 전략 가져오기\n *\n * @returns Current conflict resolution strategy\n * @korean 충돌해결전략가져오기\n */\n getConflictStrategy(): ConflictResolutionStrategy {\n return this.conflictStrategy;\n }\n\n /**\n * Dispose of the animation state machine\n *\n * **Korean**: 애니메이션 상태 머신 해제\n *\n * Clears all internal state, queues, and references to prevent memory leaks.\n * Should be called when the state machine is no longer needed (e.g., component unmount).\n *\n * @korean 애니메이션상태머신해제\n */\n dispose(): void {\n // Clear animation queue\n this.animationQueue?.clear();\n this.animationQueue = null;\n\n // Clear stance transition data\n this.currentStanceTransition = null;\n\n // Clear motion prediction state\n this.motionPrediction = createMotionPredictionState();\n this.previousKeyframe = null;\n\n // Reset state to initial values\n this.currentState = AnimationState.IDLE;\n this.previousState = AnimationState.IDLE;\n this.frameIndex = 0;\n this.timeAccumulator = 0;\n this.justStarted = false;\n this.justCompleted = false;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoEA,IAAa,4BACX,IAAI,IAAqC;CACvC,CACE,eAAe,MACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,MACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,KACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,QAAQ;EACT,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,QACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CAED,CACE,eAAe,sBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,QAAQ;EACT,CACF;CACD,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,eAAe;EAChB,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,uBAAuB;EACxB,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACV,QAAQ;EACT,CACF;CACD,CACE,eAAe,QACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,KAAK;EACf,QAAQ;EACT,CACF;CACD,CACE,eAAe,KACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,IACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CAED,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,gBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CAED,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,mBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CAED,CACE,eAAe,wBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,yBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,eACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CAED,CACE,eAAe,WACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,KAAK;EAChB,CACF;CACD,CACE,eAAe,YACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,KAAK;EAChB,CACF;CAED,CACE,eAAe,mBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CACD,CACE,eAAe,kBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU,IAAI;EACf,CACF;CAGD,CACE,eAAe,cACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,WACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,WACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,YACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,mBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,oBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,gBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EACV,UAAU;EACX,CACF;CACD,CACE,eAAe,iBACf;EACE,OAAO,eAAe;EACtB,QAAQ;EACR,KAAK;EACL,MAAM;EACN,eAAe;EACf,UAAU;EA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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AnimationTransitions.js","names":[],"sources":["../../../../src/systems/animation/core/AnimationTransitions.ts"],"sourcesContent":["/**\n * Animation transition rules for Black Trigram\n *\n * Defines valid transitions between animation states.\n * Based on game-design.md specifications and combat flow.\n *\n * Transition rules:\n * - idle ↔ walk ↔ run (movement states)\n * - stance_guard_{stance} ↔ other states (stance-specific guards)\n * - attack → idle (after completion)\n * - defend → idle (after completion)\n * - hit → idle (after completion)\n * - stance_change → idle (after completion)\n * - ko is terminal (no transitions out)\n * - hit can interrupt any non-ko state (high priority)\n *\n * @module systems/animation/AnimationTransitions\n * @category Animation\n * @korean 애니메이션전환\n */\n\nimport { KoreanText } from \"@/types\";\nimport { TrigramStance } from \"@/types/common\";\nimport {\n AnimationState,\n FALL_TO_GROUND_MAP,\n FallType,\n TransitionRule,\n} from \"./types\";\n\n/**\n * Stance guard animation states (팔괘 방어 자세)\n * @korean 자세방어상태들\n */\nconst STANCE_GUARD_STATES: readonly AnimationState[] = [\n AnimationState.STANCE_GUARD_GEON,\n AnimationState.STANCE_GUARD_TAE,\n AnimationState.STANCE_GUARD_LI,\n AnimationState.STANCE_GUARD_JIN,\n AnimationState.STANCE_GUARD_SON,\n AnimationState.STANCE_GUARD_GAM,\n AnimationState.STANCE_GUARD_GAN,\n AnimationState.STANCE_GUARD_GON,\n] as const;\n\n/**\n * Type of stance transition based on stance adjacency\n *\n * **Korean**: 자세 전환 유형\n *\n * - **direct**: Adjacent stances (e.g., geon→tae) - smooth, fast transition\n * - **indirect**: Opposite stances (e.g., geon→gon) - requires intermediate neutral position\n * - **self**: Same stance (no transition needed)\n *\n * @public\n * @category Animation\n * @korean 자세전환유형\n */\nexport type StanceTransitionType = \"direct\" | \"indirect\" | \"self\";\n\n/**\n * Keyframe for stance transition animation with blend weight\n *\n * **Korean**: 자세 전환 키프레임\n *\n * Defines a single keyframe in a stance transition animation, specifying\n * which stance pose to blend and how much weight to apply.\n *\n * @public\n * @category Animation\n * @korean 자세전환키프레임\n */\nexport interface StanceTransitionKeyframe {\n /** Frame number (0-36 for 600ms at 60fps) */\n readonly frame: number;\n /** Stance pose to blend towards */\n readonly stance: TrigramStance | \"neutral\";\n /** Blend weight (0.0 to 1.0) */\n readonly blend: number;\n}\n\n/**\n * Complete stance transition animation configuration\n *\n * **Korean**: 자세 전환 애니메이션\n *\n * Defines a complete transition animation between two trigram stances,\n * including keyframes, timing, and transition type.\n *\n * @public\n * @category Animation\n * @korean 자세전환애니메이션\n */\nexport interface StanceTransition {\n /** Source stance */\n readonly from: TrigramStance;\n /** Target stance */\n readonly to: TrigramStance;\n /** Transition type based on adjacency */\n readonly type: StanceTransitionType;\n /** Duration in milliseconds (600ms standard) */\n readonly duration: number;\n /** Animation keyframes */\n readonly keyframes: readonly StanceTransitionKeyframe[];\n /** Bilingual description */\n readonly description: KoreanText;\n}\n\n/**\n * Order of trigram stances in the stance wheel (circular arrangement)\n *\n * **Korean**: 팔괘 순서\n *\n * The 8 trigrams arranged in traditional order around the Bagua octagon.\n * Adjacent stances in this array are considered \"adjacent\" for transition purposes.\n *\n * @korean 팔괘순서\n */\nexport const TRIGRAM_STANCES_ORDER: readonly TrigramStance[] = [\n TrigramStance.GEON, // ☰ Heaven\n TrigramStance.TAE, // ☱ Lake\n TrigramStance.LI, // ☲ Fire\n TrigramStance.JIN, // ☳ Thunder\n TrigramStance.SON, // ☴ Wind\n TrigramStance.GAM, // ☵ Water\n TrigramStance.GAN, // ☶ Mountain\n TrigramStance.GON, // ☷ Earth\n] as const;\n\n/**\n * Fall animation states (낙법 상태)\n * @korean 낙법상태들\n */\nconst FALL_STATES: readonly AnimationState[] = [\n AnimationState.FALL_FORWARD,\n AnimationState.FALL_BACKWARD,\n AnimationState.FALL_SIDE_LEFT,\n AnimationState.FALL_SIDE_RIGHT,\n] as const;\n\n/**\n * Ground position states (지면 자세)\n * @korean 지면자세들\n */\nconst GROUND_STATES: readonly AnimationState[] = [\n AnimationState.GROUND_PRONE,\n AnimationState.GROUND_SUPINE,\n AnimationState.GROUND_SIDE_LEFT,\n AnimationState.GROUND_SIDE_RIGHT,\n] as const;\n\n/**\n * Recovery animation states (기상 애니메이션)\n * @korean 회복애니메이션들\n */\nconst RECOVERY_STATES: readonly AnimationState[] = [\n AnimationState.RECOVERY_PRONE_STANDUP,\n AnimationState.RECOVERY_SUPINE_STANDUP,\n AnimationState.RECOVERY_ROLL,\n AnimationState.RECOVERY_DEFENSIVE,\n] as const;\n\n/**\n * Generate transition rules for fall animations\n *\n * Fall animations have highest priority and can interrupt any state.\n * Falls automatically transition to ground states upon completion.\n * Ground states can transition to recovery animations.\n * Recovery animations transition to idle upon completion.\n *\n * @korean 낙법전환규칙생성\n */\nfunction generateFallTransitions(): TransitionRule[] {\n const transitions: TransitionRule[] = [];\n\n // All states (except falls and ko) can transition to fall states\n const nonFallStates: AnimationState[] = [\n AnimationState.IDLE,\n AnimationState.WALK,\n AnimationState.RUN,\n AnimationState.ATTACK,\n AnimationState.DEFEND,\n AnimationState.HIT,\n AnimationState.STANCE_CHANGE,\n AnimationState.STANCE_SIDE_SWITCH,\n ...STANCE_GUARD_STATES,\n ];\n\n for (const fromState of nonFallStates) {\n for (const fallState of FALL_STATES) {\n transitions.push({\n from: fromState,\n to: fallState,\n allowed: true,\n });\n }\n }\n\n // Fall states automatically transition to ground states (handled in state machine)\n for (const fallState of FALL_STATES) {\n // Falls can only go to their corresponding ground state\n // Use FALL_TO_GROUND_MAP for type-safe mapping\n const fallType = fallState.replace(\"fall_\", \"\");\n\n // Validate that fallType is a valid FallType before using in map\n if (\n fallType === \"forward\" ||\n fallType === \"backward\" ||\n fallType === \"side_left\" ||\n fallType === \"side_right\"\n ) {\n const groundState = FALL_TO_GROUND_MAP[fallType as FallType];\n const groundAnimState = `ground_${groundState}` as AnimationState;\n transitions.push({\n from: fallState,\n to: groundAnimState,\n allowed: true,\n });\n }\n }\n\n // Ground states can transition to recovery animations\n for (const groundState of GROUND_STATES) {\n // Allow transitions to all recovery types from any ground state\n for (const recoveryState of RECOVERY_STATES) {\n transitions.push({\n from: groundState,\n to: recoveryState,\n allowed: true,\n });\n }\n\n // Ground states can still be interrupted by hit or ko\n transitions.push(\n { from: groundState, to: AnimationState.HIT, allowed: true },\n { from: groundState, to: AnimationState.KO, allowed: true },\n );\n\n // Falls can interrupt ground states (getting hit while down)\n for (const fallState of FALL_STATES) {\n transitions.push({\n from: groundState,\n to: fallState,\n allowed: true,\n });\n }\n }\n\n // Recovery animations can be interrupted by high-priority states\n // (falls, hit, ko) but transition to idle when complete\n for (const recoveryState of RECOVERY_STATES) {\n // Falls can interrupt recovery (getting hit during recovery)\n for (const fallState of FALL_STATES) {\n transitions.push({\n from: recoveryState,\n to: fallState,\n allowed: true,\n });\n }\n\n // Hit and KO can interrupt recovery\n transitions.push(\n { from: recoveryState, to: AnimationState.HIT, allowed: true },\n { from: recoveryState, to: AnimationState.KO, allowed: true },\n );\n\n // Recovery animations automatically transition to idle (handled in state machine)\n transitions.push({\n from: recoveryState,\n to: AnimationState.IDLE,\n allowed: true,\n });\n }\n\n return transitions;\n}\n\n/**\n * Generate transition rules for stance guards\n *\n * Each stance guard can transition to:\n * - walk, run (movement)\n * - attack, defend (combat actions)\n * - step_{direction} (tactical steps while maintaining guard)\n * - stance_change (changing stance)\n * - hit, ko (being hit)\n * - other stance guards (direct stance change with guard)\n *\n * @korean 자세방어전환규칙생성\n */\nfunction generateStanceGuardTransitions(): TransitionRule[] {\n const transitions: TransitionRule[] = [];\n\n // Step directions for guard transitions\n const stepDirections: AnimationState[] = [\n AnimationState.STEP_FORWARD,\n AnimationState.STEP_BACK,\n AnimationState.STEP_LEFT,\n AnimationState.STEP_RIGHT,\n AnimationState.STEP_FORWARD_LEFT,\n AnimationState.STEP_FORWARD_RIGHT,\n AnimationState.STEP_BACK_LEFT,\n AnimationState.STEP_BACK_RIGHT,\n ];\n\n for (const guardState of STANCE_GUARD_STATES) {\n // Guard can transition to movement\n transitions.push(\n { from: guardState, to: AnimationState.IDLE, allowed: true },\n { from: guardState, to: AnimationState.WALK, allowed: true },\n { from: guardState, to: AnimationState.RUN, allowed: true },\n );\n\n // Guard can transition to combat actions\n transitions.push(\n { from: guardState, to: AnimationState.ATTACK, allowed: true },\n { from: guardState, to: AnimationState.DEFEND, allowed: true },\n { from: guardState, to: AnimationState.STANCE_CHANGE, allowed: true },\n );\n\n // Guard can transition to tactical steps (guard maintained during step)\n for (const stepDirection of stepDirections) {\n transitions.push({ from: guardState, to: stepDirection, allowed: true });\n }\n\n // Guard can be interrupted by hits\n transitions.push(\n { from: guardState, to: AnimationState.HIT, allowed: true },\n { from: guardState, to: AnimationState.KO, allowed: true },\n );\n\n // Guards can transition between each other (direct stance change)\n for (const otherGuard of STANCE_GUARD_STATES) {\n if (guardState !== otherGuard) {\n transitions.push({ from: guardState, to: otherGuard, allowed: true });\n }\n }\n\n // Other states can transition to guards\n transitions.push(\n { from: AnimationState.IDLE, to: guardState, allowed: true },\n { from: AnimationState.WALK, to: guardState, allowed: true },\n { from: AnimationState.RUN, to: guardState, allowed: true },\n { from: AnimationState.DEFEND, to: guardState, allowed: true },\n );\n\n // Steps can return to guard (guard maintained throughout step)\n for (const stepDirection of stepDirections) {\n transitions.push({ from: stepDirection, to: guardState, allowed: true });\n }\n }\n\n return transitions;\n}\n\n/**\n * Default transition rules for animation states\n *\n * @korean 기본전환규칙\n */\nexport const DEFAULT_TRANSITIONS: readonly TransitionRule[] = [\n // Idle transitions\n { from: AnimationState.IDLE, to: AnimationState.WALK, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.RUN, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.ATTACK, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.DEFEND, allowed: true },\n {\n from: AnimationState.IDLE,\n to: AnimationState.STANCE_CHANGE,\n allowed: true,\n },\n { from: AnimationState.IDLE, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.KO, allowed: true },\n\n // Walk transitions\n { from: AnimationState.WALK, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.RUN, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.ATTACK, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.DEFEND, allowed: true },\n {\n from: AnimationState.WALK,\n to: AnimationState.STANCE_CHANGE,\n allowed: true,\n },\n { from: AnimationState.WALK, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.KO, allowed: true },\n\n // Run transitions\n { from: AnimationState.RUN, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.WALK, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.ATTACK, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.DEFEND, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.STANCE_CHANGE, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.KO, allowed: true },\n\n // Attack transitions (typically returns to idle after completion)\n { from: AnimationState.ATTACK, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.ATTACK, to: AnimationState.HIT, allowed: true }, // Can be interrupted by hit\n { from: AnimationState.ATTACK, to: AnimationState.KO, allowed: true },\n\n // Defend transitions (typically returns to idle after completion)\n { from: AnimationState.DEFEND, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.DEFEND, to: AnimationState.WALK, allowed: true },\n { from: AnimationState.DEFEND, to: AnimationState.HIT, allowed: true }, // Can be interrupted by hit\n { from: AnimationState.DEFEND, to: AnimationState.KO, allowed: true },\n\n // Hit transitions (returns to idle after completion)\n { from: AnimationState.HIT, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.HIT, to: AnimationState.HIT, allowed: true }, // Can take multiple hits\n { from: AnimationState.HIT, to: AnimationState.KO, allowed: true },\n\n // Stance change transitions (returns to idle after completion)\n {\n from: AnimationState.STANCE_CHANGE,\n to: AnimationState.IDLE,\n allowed: true,\n },\n { from: AnimationState.STANCE_CHANGE, to: AnimationState.HIT, allowed: true }, // Can be interrupted by hit\n { from: AnimationState.STANCE_CHANGE, to: AnimationState.KO, allowed: true },\n\n // Tactical step transitions (non-interruptible, returns to idle/guard after completion)\n // Steps can be initiated from idle, walk, or guard states\n // 전진보법 (Forward Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_FORWARD, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_FORWARD, allowed: true },\n { from: AnimationState.STEP_FORWARD, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_FORWARD, to: AnimationState.HIT, allowed: true }, // Can be hit during step\n { from: AnimationState.STEP_FORWARD, to: AnimationState.KO, allowed: true },\n\n // 후퇴보법 (Retreat Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_BACK, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_BACK, allowed: true },\n { from: AnimationState.STEP_BACK, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_BACK, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.STEP_BACK, to: AnimationState.KO, allowed: true },\n\n // 좌측면보법 (Left Side Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_LEFT, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_LEFT, allowed: true },\n { from: AnimationState.STEP_LEFT, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_LEFT, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.STEP_LEFT, to: AnimationState.KO, allowed: true },\n\n // 우측면보법 (Right Side Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_RIGHT, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_RIGHT, allowed: true },\n { from: AnimationState.STEP_RIGHT, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_RIGHT, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.STEP_RIGHT, to: AnimationState.KO, allowed: true },\n\n // 전좌측보법 (Forward-Left Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_FORWARD_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_FORWARD_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_LEFT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_LEFT,\n to: AnimationState.HIT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_LEFT,\n to: AnimationState.KO,\n allowed: true,\n },\n\n // 전우측보법 (Forward-Right Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_FORWARD_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_FORWARD_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_RIGHT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_RIGHT,\n to: AnimationState.HIT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_RIGHT,\n to: AnimationState.KO,\n allowed: true,\n },\n\n // 후좌측보법 (Back-Left Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_BACK_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_BACK_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_LEFT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_LEFT,\n to: AnimationState.HIT,\n allowed: true,\n },\n { from: AnimationState.STEP_BACK_LEFT, to: AnimationState.KO, allowed: true },\n\n // 후우측보법 (Back-Right Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_BACK_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_BACK_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_RIGHT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_RIGHT,\n to: AnimationState.HIT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_RIGHT,\n to: AnimationState.KO,\n allowed: true,\n },\n\n // KO is terminal - no transitions out\n // (Player must be revived/reset to leave KO state)\n\n // Fall transitions (generated dynamically)\n ...generateFallTransitions(),\n\n // Stance guard transitions (generated dynamically)\n ...generateStanceGuardTransitions(),\n] as const;\n\n/**\n * Check if a transition from one animation state to another is allowed\n *\n * @param from - Source animation state\n * @param to - Target animation state\n * @param transitions - Optional custom transition rules (defaults to DEFAULT_TRANSITIONS)\n * @returns Whether the transition is allowed\n *\n * @example\n * ```typescript\n * // Valid transitions\n * isTransitionAllowed(\"idle\", \"walk\"); // true\n * isTransitionAllowed(\"attack\", \"idle\"); // true\n * isTransitionAllowed(\"hit\", \"idle\"); // true\n *\n * // Invalid transitions\n * isTransitionAllowed(\"ko\", \"idle\"); // false (KO is terminal)\n * isTransitionAllowed(\"attack\", \"walk\"); // false (must return to idle first)\n * ```\n *\n * @korean 전환허용여부확인\n */\nexport function isTransitionAllowed(\n from: AnimationState,\n to: AnimationState,\n transitions: readonly TransitionRule[] = DEFAULT_TRANSITIONS,\n): boolean {\n // Same state is always allowed\n if (from === to) {\n return true;\n }\n\n // Find matching transition rule\n const rule = transitions.find((t) => t.from === from && t.to === to);\n\n if (!rule) {\n return false;\n }\n\n // Check condition if provided\n if (rule.condition) {\n return rule.condition();\n }\n\n return rule.allowed;\n}\n\n/**\n * Get all valid transitions from a given animation state\n *\n * @param from - Source animation state\n * @param transitions - Optional custom transition rules (defaults to DEFAULT_TRANSITIONS)\n * @returns Array of allowed target animation states\n *\n * @example\n * ```typescript\n * getValidTransitions(\"idle\");\n * // Returns: [\"walk\", \"run\", \"attack\", \"defend\", \"stance_change\", \"hit\", \"ko\"]\n *\n * getValidTransitions(\"ko\");\n * // Returns: [] (KO is terminal)\n * ```\n *\n * @korean 유효전환목록가져오기\n */\nexport function getValidTransitions(\n from: AnimationState,\n transitions: readonly TransitionRule[] = DEFAULT_TRANSITIONS,\n): AnimationState[] {\n return transitions\n .filter((t) => t.from === from && t.allowed)\n .map((t) => t.to)\n .filter((to) => isTransitionAllowed(from, to, transitions));\n}\n\n/**\n * Build a transition map for fast lookups\n *\n * @param transitions - Transition rules to build map from\n * @returns Map of from->to->allowed\n *\n * @korean 전환맵생성\n */\nexport function buildTransitionMap(\n transitions: readonly TransitionRule[] = DEFAULT_TRANSITIONS,\n): Map<AnimationState, Set<AnimationState>> {\n const map = new Map<AnimationState, Set<AnimationState>>();\n\n for (const rule of transitions) {\n if (!rule.allowed) continue;\n\n if (!map.has(rule.from)) {\n map.set(rule.from, new Set());\n }\n\n map.get(rule.from)?.add(rule.to);\n }\n\n return map;\n}\n\n/**\n * Calculate stance adjacency (distance around the stance wheel)\n *\n * **Korean**: 자세 인접도 계산\n *\n * Determines how many steps apart two stances are on the octagonal stance wheel.\n * Returns 0 for same stance, 1-3 for adjacent stances, 4 for opposite stances.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Number of steps apart (0-4)\n *\n * @example\n * ```typescript\n * calculateStanceDistance(TrigramStance.GEON, TrigramStance.TAE); // 1 (adjacent)\n * calculateStanceDistance(TrigramStance.GEON, TrigramStance.SON); // 4 (opposite)\n * calculateStanceDistance(TrigramStance.GEON, TrigramStance.GEON); // 0 (same)\n * ```\n *\n * @korean 자세거리계산\n */\nexport function calculateStanceDistance(\n from: TrigramStance,\n to: TrigramStance,\n): number {\n if (from === to) return 0;\n\n const fromIndex = TRIGRAM_STANCES_ORDER.indexOf(from);\n const toIndex = TRIGRAM_STANCES_ORDER.indexOf(to);\n\n if (fromIndex === -1 || toIndex === -1) {\n console.warn(`Invalid stance in distance calculation: ${from} -> ${to}`);\n return 4; // Treat as opposite stance\n }\n\n // Calculate shortest distance around the circular wheel\n const directDistance = Math.abs(toIndex - fromIndex);\n const wrapDistance = TRIGRAM_STANCES_ORDER.length - directDistance;\n\n return Math.min(directDistance, wrapDistance);\n}\n\n/**\n * Determine transition type based on stance distance\n *\n * **Korean**: 전환 유형 결정\n *\n * Classifies transition as direct (adjacent), indirect (opposite), or self.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition type\n *\n * @korean 전환유형결정\n */\nexport function determineTransitionType(\n from: TrigramStance,\n to: TrigramStance,\n): StanceTransitionType {\n const distance = calculateStanceDistance(from, to);\n\n if (distance === 0) return \"self\";\n if (distance <= 2) return \"direct\"; // Adjacent or near-adjacent\n return \"indirect\"; // Opposite or far apart\n}\n\n/**\n * Generate keyframes for direct stance transition (adjacent stances)\n *\n * **Korean**: 직접 전환 키프레임 생성\n *\n * Creates smooth keyframes for transitions between adjacent stances.\n * Phase breakdown:\n * - Frames 0-12: Weight shift away from source stance\n * - Frames 12-24: Foot repositioning\n * - Frames 24-36: Guard change to target stance\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Array of keyframes\n *\n * @korean 직접전환키프레임생성\n */\nfunction generateDirectTransitionKeyframes(\n from: TrigramStance,\n to: TrigramStance,\n): readonly StanceTransitionKeyframe[] {\n return [\n // Phase 1: Initial weight shift (frames 0-12)\n { frame: 0, stance: from, blend: 1.0 },\n { frame: 6, stance: from, blend: 0.8 },\n { frame: 12, stance: \"neutral\", blend: 0.5 },\n\n // Phase 2: Foot repositioning (frames 12-24)\n { frame: 18, stance: \"neutral\", blend: 0.4 },\n { frame: 24, stance: to, blend: 0.3 },\n\n // Phase 3: Guard position change (frames 24-36)\n { frame: 30, stance: to, blend: 0.7 },\n { frame: 36, stance: to, blend: 1.0 },\n ];\n}\n\n/**\n * Generate keyframes for indirect stance transition (opposite stances)\n *\n * **Korean**: 간접 전환 키프레임 생성\n *\n * Creates keyframes for transitions between opposite stances via neutral position.\n * Longer neutral phase for more complex repositioning.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Array of keyframes\n *\n * @korean 간접전환키프레임생성\n */\nfunction generateIndirectTransitionKeyframes(\n from: TrigramStance,\n to: TrigramStance,\n): readonly StanceTransitionKeyframe[] {\n return [\n // Phase 1: Exit source stance (frames 0-12)\n { frame: 0, stance: from, blend: 1.0 },\n { frame: 6, stance: from, blend: 0.7 },\n { frame: 12, stance: \"neutral\", blend: 0.5 },\n\n // Phase 2: Extended neutral position (frames 12-24)\n { frame: 18, stance: \"neutral\", blend: 0.5 },\n { frame: 24, stance: \"neutral\", blend: 0.4 },\n\n // Phase 3: Enter target stance (frames 24-36)\n { frame: 30, stance: to, blend: 0.6 },\n { frame: 36, stance: to, blend: 1.0 },\n ];\n}\n\n/**\n * Create a stance transition configuration\n *\n * **Korean**: 자세 전환 생성\n *\n * Generates complete transition configuration between two stances.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Complete stance transition configuration\n *\n * @korean 자세전환생성\n */\nexport function createStanceTransition(\n from: TrigramStance,\n to: TrigramStance,\n): StanceTransition {\n const type = determineTransitionType(from, to);\n\n // Self-transition (no animation)\n if (type === \"self\") {\n return {\n from,\n to,\n type: \"self\",\n duration: 0,\n keyframes: [{ frame: 0, stance: from, blend: 1.0 }],\n description: {\n korean: `${from} 자세 유지`,\n english: `Maintain ${from} stance`,\n },\n };\n }\n\n // Generate keyframes based on transition type\n const keyframes =\n type === \"direct\"\n ? generateDirectTransitionKeyframes(from, to)\n : generateIndirectTransitionKeyframes(from, to);\n\n return {\n from,\n to,\n type,\n duration: 600, // 600ms standard transition\n keyframes,\n description: {\n korean: `${from}에서 ${to}로 전환`,\n english: `Transition from ${from} to ${to}`,\n },\n };\n}\n\n/**\n * Stance transition matrix containing all 64 transitions (8x8)\n *\n * **Korean**: 팔괘 전환 행렬\n *\n * Maps from every stance to every other stance, including self-transitions.\n * Key format: \"from_to\" (e.g., \"geon_tae\")\n *\n * Total transitions: 64 (8 source stances × 8 target stances)\n * - 8 self-transitions (0ms)\n * - ~24 direct transitions (600ms, adjacent stances)\n * - ~32 indirect transitions (600ms, opposite stances)\n *\n * @korean 팔괘전환행렬\n */\nexport const STANCE_TRANSITIONS: Map<string, StanceTransition> = new Map();\n\n/**\n * Initialize the stance transition matrix\n *\n * **Korean**: 전환 행렬 초기화\n *\n * Generates all 64 stance transitions and populates the transition map.\n * Call this during system initialization.\n *\n * @korean 전환행렬초기화\n */\nexport function initializeStanceTransitions(): void {\n // Generate all 64 transitions (8 from × 8 to)\n for (const from of TRIGRAM_STANCES_ORDER) {\n for (const to of TRIGRAM_STANCES_ORDER) {\n const key = `${from}_${to}`;\n const transition = createStanceTransition(from, to);\n STANCE_TRANSITIONS.set(key, transition);\n }\n }\n\n if (process.env.NODE_ENV === \"development\") {\n console.log(\n `[StanceTransitions] Initialized ${STANCE_TRANSITIONS.size} stance transitions`,\n );\n }\n}\n\n/**\n * Get stance transition configuration\n *\n * **Korean**: 자세 전환 가져오기\n *\n * Retrieves the transition configuration for moving from one stance to another.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition configuration, or undefined if not found\n *\n * @example\n * ```typescript\n * const transition = getStanceTransition(TrigramStance.GEON, TrigramStance.TAE);\n * console.log(transition.duration); // 600\n * console.log(transition.type); // \"direct\"\n * ```\n *\n * @korean 자세전환가져오기\n */\nexport function getStanceTransition(\n from: TrigramStance,\n to: TrigramStance,\n): StanceTransition | undefined {\n const key = `${from}_${to}`;\n return STANCE_TRANSITIONS.get(key);\n}\n\n/**\n * Get all valid transitions from a stance\n *\n * **Korean**: 유효한 전환 목록\n *\n * Returns all possible transitions from the given stance.\n *\n * @param from - Source stance\n * @returns Array of all transitions from this stance\n *\n * @korean 유효한전환목록\n */\nexport function getTransitionsFromStance(\n from: TrigramStance,\n): StanceTransition[] {\n const transitions: StanceTransition[] = [];\n\n for (const to of TRIGRAM_STANCES_ORDER) {\n const transition = getStanceTransition(from, to);\n if (transition) {\n transitions.push(transition);\n }\n }\n\n return transitions;\n}\n\n/**\n * Clear all cached stance transitions\n *\n * **Korean**: 자세 전환 캐시 초기화\n *\n * Clears the stance transition cache to free memory.\n * Useful for session cleanup or hot reloading.\n * Call initializeStanceTransitions() to repopulate after clearing.\n *\n * @korean 자세전환캐시초기화\n */\nexport function clearStanceTransitions(): void {\n STANCE_TRANSITIONS.clear();\n}\n\n// Note: For production use, consider calling initializeStanceTransitions()\n// during application startup to avoid blocking the main thread.\n// For now, initialize on module load for convenience.\ninitializeStanceTransitions();\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"AnimationTransitions.js","names":[],"sources":["../../../../src/systems/animation/core/AnimationTransitions.ts"],"sourcesContent":["/**\n * Animation transition rules for Black Trigram\n *\n * Defines valid transitions between animation states.\n * Based on game-design.md specifications and combat flow.\n *\n * Transition rules:\n * - idle ↔ walk ↔ run (movement states)\n * - stance_guard_{stance} ↔ other states (stance-specific guards)\n * - attack → idle (after completion)\n * - defend → idle (after completion)\n * - hit → idle (after completion)\n * - stance_change → idle (after completion)\n * - ko is terminal (no transitions out)\n * - hit can interrupt any non-ko state (high priority)\n *\n * @module systems/animation/AnimationTransitions\n * @category Animation\n * @korean 애니메이션전환\n */\n\nimport { KoreanText } from \"@/types\";\nimport { TrigramStance } from \"@/types/common\";\nimport {\n AnimationState,\n FALL_TO_GROUND_MAP,\n FallType,\n TransitionRule,\n} from \"./types\";\n\n/**\n * Stance guard animation states (팔괘 방어 자세)\n * @korean 자세방어상태들\n */\nconst STANCE_GUARD_STATES: readonly AnimationState[] = [\n AnimationState.STANCE_GUARD_GEON,\n AnimationState.STANCE_GUARD_TAE,\n AnimationState.STANCE_GUARD_LI,\n AnimationState.STANCE_GUARD_JIN,\n AnimationState.STANCE_GUARD_SON,\n AnimationState.STANCE_GUARD_GAM,\n AnimationState.STANCE_GUARD_GAN,\n AnimationState.STANCE_GUARD_GON,\n] as const;\n\n/**\n * Type of stance transition based on stance adjacency\n *\n * **Korean**: 자세 전환 유형\n *\n * - **direct**: Adjacent stances (e.g., geon→tae) - smooth, fast transition\n * - **indirect**: Opposite stances (e.g., geon→gon) - requires intermediate neutral position\n * - **self**: Same stance (no transition needed)\n *\n * @public\n * @category Animation\n * @korean 자세전환유형\n */\nexport type StanceTransitionType = \"direct\" | \"indirect\" | \"self\";\n\n/**\n * Keyframe for stance transition animation with blend weight\n *\n * **Korean**: 자세 전환 키프레임\n *\n * Defines a single keyframe in a stance transition animation, specifying\n * which stance pose to blend and how much weight to apply.\n *\n * @public\n * @category Animation\n * @korean 자세전환키프레임\n */\nexport interface StanceTransitionKeyframe {\n /** Frame number (0-36 for 600ms at 60fps) */\n readonly frame: number;\n /** Stance pose to blend towards */\n readonly stance: TrigramStance | \"neutral\";\n /** Blend weight (0.0 to 1.0) */\n readonly blend: number;\n}\n\n/**\n * Complete stance transition animation configuration\n *\n * **Korean**: 자세 전환 애니메이션\n *\n * Defines a complete transition animation between two trigram stances,\n * including keyframes, timing, and transition type.\n *\n * @public\n * @category Animation\n * @korean 자세전환애니메이션\n */\nexport interface StanceTransition {\n /** Source stance */\n readonly from: TrigramStance;\n /** Target stance */\n readonly to: TrigramStance;\n /** Transition type based on adjacency */\n readonly type: StanceTransitionType;\n /** Duration in milliseconds (600ms standard) */\n readonly duration: number;\n /** Animation keyframes */\n readonly keyframes: readonly StanceTransitionKeyframe[];\n /** Bilingual description */\n readonly description: KoreanText;\n}\n\n/**\n * Order of trigram stances in the stance wheel (circular arrangement)\n *\n * **Korean**: 팔괘 순서\n *\n * The 8 trigrams arranged in traditional order around the Bagua octagon.\n * Adjacent stances in this array are considered \"adjacent\" for transition purposes.\n *\n * @korean 팔괘순서\n */\nexport const TRIGRAM_STANCES_ORDER: readonly TrigramStance[] = [\n TrigramStance.GEON, // ☰ Heaven\n TrigramStance.TAE, // ☱ Lake\n TrigramStance.LI, // ☲ Fire\n TrigramStance.JIN, // ☳ Thunder\n TrigramStance.SON, // ☴ Wind\n TrigramStance.GAM, // ☵ Water\n TrigramStance.GAN, // ☶ Mountain\n TrigramStance.GON, // ☷ Earth\n] as const;\n\n/**\n * Fall animation states (낙법 상태)\n * @korean 낙법상태들\n */\nconst FALL_STATES: readonly AnimationState[] = [\n AnimationState.FALL_FORWARD,\n AnimationState.FALL_BACKWARD,\n AnimationState.FALL_SIDE_LEFT,\n AnimationState.FALL_SIDE_RIGHT,\n] as const;\n\n/**\n * Ground position states (지면 자세)\n * @korean 지면자세들\n */\nconst GROUND_STATES: readonly AnimationState[] = [\n AnimationState.GROUND_PRONE,\n AnimationState.GROUND_SUPINE,\n AnimationState.GROUND_SIDE_LEFT,\n AnimationState.GROUND_SIDE_RIGHT,\n] as const;\n\n/**\n * Recovery animation states (기상 애니메이션)\n * @korean 회복애니메이션들\n */\nconst RECOVERY_STATES: readonly AnimationState[] = [\n AnimationState.RECOVERY_PRONE_STANDUP,\n AnimationState.RECOVERY_SUPINE_STANDUP,\n AnimationState.RECOVERY_ROLL,\n AnimationState.RECOVERY_DEFENSIVE,\n] as const;\n\n/**\n * Generate transition rules for fall animations\n *\n * Fall animations have highest priority and can interrupt any state.\n * Falls automatically transition to ground states upon completion.\n * Ground states can transition to recovery animations.\n * Recovery animations transition to idle upon completion.\n *\n * @korean 낙법전환규칙생성\n */\nfunction generateFallTransitions(): TransitionRule[] {\n const transitions: TransitionRule[] = [];\n\n // All states (except falls and ko) can transition to fall states\n const nonFallStates: AnimationState[] = [\n AnimationState.IDLE,\n AnimationState.WALK,\n AnimationState.RUN,\n AnimationState.ATTACK,\n AnimationState.DEFEND,\n AnimationState.HIT,\n AnimationState.STANCE_CHANGE,\n AnimationState.STANCE_SIDE_SWITCH,\n ...STANCE_GUARD_STATES,\n ];\n\n for (const fromState of nonFallStates) {\n for (const fallState of FALL_STATES) {\n transitions.push({\n from: fromState,\n to: fallState,\n allowed: true,\n });\n }\n }\n\n // Fall states automatically transition to ground states (handled in state machine)\n for (const fallState of FALL_STATES) {\n // Falls can only go to their corresponding ground state\n // Use FALL_TO_GROUND_MAP for type-safe mapping\n const fallType = fallState.replace(\"fall_\", \"\");\n\n // Validate that fallType is a valid FallType before using in map\n if (\n fallType === \"forward\" ||\n fallType === \"backward\" ||\n fallType === \"side_left\" ||\n fallType === \"side_right\"\n ) {\n const groundState = FALL_TO_GROUND_MAP[fallType as FallType];\n const groundAnimState = `ground_${groundState}` as AnimationState;\n transitions.push({\n from: fallState,\n to: groundAnimState,\n allowed: true,\n });\n }\n }\n\n // Ground states can transition to recovery animations\n for (const groundState of GROUND_STATES) {\n // Allow transitions to all recovery types from any ground state\n for (const recoveryState of RECOVERY_STATES) {\n transitions.push({\n from: groundState,\n to: recoveryState,\n allowed: true,\n });\n }\n\n // Ground states can still be interrupted by hit or ko\n transitions.push(\n { from: groundState, to: AnimationState.HIT, allowed: true },\n { from: groundState, to: AnimationState.KO, allowed: true },\n );\n\n // Falls can interrupt ground states (getting hit while down)\n for (const fallState of FALL_STATES) {\n transitions.push({\n from: groundState,\n to: fallState,\n allowed: true,\n });\n }\n }\n\n // Recovery animations can be interrupted by high-priority states\n // (falls, hit, ko) but transition to idle when complete\n for (const recoveryState of RECOVERY_STATES) {\n // Falls can interrupt recovery (getting hit during recovery)\n for (const fallState of FALL_STATES) {\n transitions.push({\n from: recoveryState,\n to: fallState,\n allowed: true,\n });\n }\n\n // Hit and KO can interrupt recovery\n transitions.push(\n { from: recoveryState, to: AnimationState.HIT, allowed: true },\n { from: recoveryState, to: AnimationState.KO, allowed: true },\n );\n\n // Recovery animations automatically transition to idle (handled in state machine)\n transitions.push({\n from: recoveryState,\n to: AnimationState.IDLE,\n allowed: true,\n });\n }\n\n return transitions;\n}\n\n/**\n * Generate transition rules for stance guards\n *\n * Each stance guard can transition to:\n * - walk, run (movement)\n * - attack, defend (combat actions)\n * - step_{direction} (tactical steps while maintaining guard)\n * - stance_change (changing stance)\n * - hit, ko (being hit)\n * - other stance guards (direct stance change with guard)\n *\n * @korean 자세방어전환규칙생성\n */\nfunction generateStanceGuardTransitions(): TransitionRule[] {\n const transitions: TransitionRule[] = [];\n\n // Step directions for guard transitions\n const stepDirections: AnimationState[] = [\n AnimationState.STEP_FORWARD,\n AnimationState.STEP_BACK,\n AnimationState.STEP_LEFT,\n AnimationState.STEP_RIGHT,\n AnimationState.STEP_FORWARD_LEFT,\n AnimationState.STEP_FORWARD_RIGHT,\n AnimationState.STEP_BACK_LEFT,\n AnimationState.STEP_BACK_RIGHT,\n ];\n\n for (const guardState of STANCE_GUARD_STATES) {\n // Guard can transition to movement\n transitions.push(\n { from: guardState, to: AnimationState.IDLE, allowed: true },\n { from: guardState, to: AnimationState.WALK, allowed: true },\n { from: guardState, to: AnimationState.RUN, allowed: true },\n );\n\n // Guard can transition to combat actions\n transitions.push(\n { from: guardState, to: AnimationState.ATTACK, allowed: true },\n { from: guardState, to: AnimationState.DEFEND, allowed: true },\n { from: guardState, to: AnimationState.STANCE_CHANGE, allowed: true },\n );\n\n // Guard can transition to tactical steps (guard maintained during step)\n for (const stepDirection of stepDirections) {\n transitions.push({ from: guardState, to: stepDirection, allowed: true });\n }\n\n // Guard can be interrupted by hits\n transitions.push(\n { from: guardState, to: AnimationState.HIT, allowed: true },\n { from: guardState, to: AnimationState.KO, allowed: true },\n );\n\n // Guards can transition between each other (direct stance change)\n for (const otherGuard of STANCE_GUARD_STATES) {\n if (guardState !== otherGuard) {\n transitions.push({ from: guardState, to: otherGuard, allowed: true });\n }\n }\n\n // Other states can transition to guards\n transitions.push(\n { from: AnimationState.IDLE, to: guardState, allowed: true },\n { from: AnimationState.WALK, to: guardState, allowed: true },\n { from: AnimationState.RUN, to: guardState, allowed: true },\n { from: AnimationState.DEFEND, to: guardState, allowed: true },\n );\n\n // Steps can return to guard (guard maintained throughout step)\n for (const stepDirection of stepDirections) {\n transitions.push({ from: stepDirection, to: guardState, allowed: true });\n }\n }\n\n return transitions;\n}\n\n/**\n * Default transition rules for animation states\n *\n * @korean 기본전환규칙\n */\nexport const DEFAULT_TRANSITIONS: readonly TransitionRule[] = [\n // Idle transitions\n { from: AnimationState.IDLE, to: AnimationState.WALK, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.RUN, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.ATTACK, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.DEFEND, allowed: true },\n {\n from: AnimationState.IDLE,\n to: AnimationState.STANCE_CHANGE,\n allowed: true,\n },\n { from: AnimationState.IDLE, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.IDLE, to: AnimationState.KO, allowed: true },\n\n // Walk transitions\n { from: AnimationState.WALK, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.RUN, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.ATTACK, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.DEFEND, allowed: true },\n {\n from: AnimationState.WALK,\n to: AnimationState.STANCE_CHANGE,\n allowed: true,\n },\n { from: AnimationState.WALK, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.KO, allowed: true },\n\n // Run transitions\n { from: AnimationState.RUN, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.WALK, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.ATTACK, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.DEFEND, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.STANCE_CHANGE, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.RUN, to: AnimationState.KO, allowed: true },\n\n // Attack transitions (typically returns to idle after completion)\n { from: AnimationState.ATTACK, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.ATTACK, to: AnimationState.HIT, allowed: true }, // Can be interrupted by hit\n { from: AnimationState.ATTACK, to: AnimationState.KO, allowed: true },\n\n // Defend transitions (typically returns to idle after completion)\n { from: AnimationState.DEFEND, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.DEFEND, to: AnimationState.WALK, allowed: true },\n { from: AnimationState.DEFEND, to: AnimationState.HIT, allowed: true }, // Can be interrupted by hit\n { from: AnimationState.DEFEND, to: AnimationState.KO, allowed: true },\n\n // Hit transitions (returns to idle after completion)\n { from: AnimationState.HIT, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.HIT, to: AnimationState.HIT, allowed: true }, // Can take multiple hits\n { from: AnimationState.HIT, to: AnimationState.KO, allowed: true },\n\n // Stance change transitions (returns to idle after completion)\n {\n from: AnimationState.STANCE_CHANGE,\n to: AnimationState.IDLE,\n allowed: true,\n },\n { from: AnimationState.STANCE_CHANGE, to: AnimationState.HIT, allowed: true }, // Can be interrupted by hit\n { from: AnimationState.STANCE_CHANGE, to: AnimationState.KO, allowed: true },\n\n // Tactical step transitions (non-interruptible, returns to idle/guard after completion)\n // Steps can be initiated from idle, walk, or guard states\n // 전진보법 (Forward Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_FORWARD, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_FORWARD, allowed: true },\n { from: AnimationState.STEP_FORWARD, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_FORWARD, to: AnimationState.HIT, allowed: true }, // Can be hit during step\n { from: AnimationState.STEP_FORWARD, to: AnimationState.KO, allowed: true },\n\n // 후퇴보법 (Retreat Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_BACK, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_BACK, allowed: true },\n { from: AnimationState.STEP_BACK, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_BACK, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.STEP_BACK, to: AnimationState.KO, allowed: true },\n\n // 좌측면보법 (Left Side Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_LEFT, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_LEFT, allowed: true },\n { from: AnimationState.STEP_LEFT, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_LEFT, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.STEP_LEFT, to: AnimationState.KO, allowed: true },\n\n // 우측면보법 (Right Side Step)\n { from: AnimationState.IDLE, to: AnimationState.STEP_RIGHT, allowed: true },\n { from: AnimationState.WALK, to: AnimationState.STEP_RIGHT, allowed: true },\n { from: AnimationState.STEP_RIGHT, to: AnimationState.IDLE, allowed: true },\n { from: AnimationState.STEP_RIGHT, to: AnimationState.HIT, allowed: true },\n { from: AnimationState.STEP_RIGHT, to: AnimationState.KO, allowed: true },\n\n // 전좌측보법 (Forward-Left Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_FORWARD_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_FORWARD_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_LEFT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_LEFT,\n to: AnimationState.HIT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_LEFT,\n to: AnimationState.KO,\n allowed: true,\n },\n\n // 전우측보법 (Forward-Right Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_FORWARD_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_FORWARD_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_RIGHT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_RIGHT,\n to: AnimationState.HIT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_FORWARD_RIGHT,\n to: AnimationState.KO,\n allowed: true,\n },\n\n // 후좌측보법 (Back-Left Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_BACK_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_BACK_LEFT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_LEFT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_LEFT,\n to: AnimationState.HIT,\n allowed: true,\n },\n { from: AnimationState.STEP_BACK_LEFT, to: AnimationState.KO, allowed: true },\n\n // 후우측보법 (Back-Right Diagonal Step)\n {\n from: AnimationState.IDLE,\n to: AnimationState.STEP_BACK_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.WALK,\n to: AnimationState.STEP_BACK_RIGHT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_RIGHT,\n to: AnimationState.IDLE,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_RIGHT,\n to: AnimationState.HIT,\n allowed: true,\n },\n {\n from: AnimationState.STEP_BACK_RIGHT,\n to: AnimationState.KO,\n allowed: true,\n },\n\n // KO is terminal - no transitions out\n // (Player must be revived/reset to leave KO state)\n\n // Fall transitions (generated dynamically)\n ...generateFallTransitions(),\n\n // Stance guard transitions (generated dynamically)\n ...generateStanceGuardTransitions(),\n] as const;\n\n/**\n * Check if a transition from one animation state to another is allowed\n *\n * @param from - Source animation state\n * @param to - Target animation state\n * @param transitions - Optional custom transition rules (defaults to DEFAULT_TRANSITIONS)\n * @returns Whether the transition is allowed\n *\n * @example\n * ```typescript\n * // Valid transitions\n * isTransitionAllowed(\"idle\", \"walk\"); // true\n * isTransitionAllowed(\"attack\", \"idle\"); // true\n * isTransitionAllowed(\"hit\", \"idle\"); // true\n *\n * // Invalid transitions\n * isTransitionAllowed(\"ko\", \"idle\"); // false (KO is terminal)\n * isTransitionAllowed(\"attack\", \"walk\"); // false (must return to idle first)\n * ```\n *\n * @korean 전환허용여부확인\n */\nexport function isTransitionAllowed(\n from: AnimationState,\n to: AnimationState,\n transitions: readonly TransitionRule[] = DEFAULT_TRANSITIONS,\n): boolean {\n // Same state is always allowed\n if (from === to) {\n return true;\n }\n\n // Find matching transition rule\n const rule = transitions.find((t) => t.from === from && t.to === to);\n\n if (!rule) {\n return false;\n }\n\n // Check condition if provided\n if (rule.condition) {\n return rule.condition();\n }\n\n return rule.allowed;\n}\n\n/**\n * Get all valid transitions from a given animation state\n *\n * @param from - Source animation state\n * @param transitions - Optional custom transition rules (defaults to DEFAULT_TRANSITIONS)\n * @returns Array of allowed target animation states\n *\n * @example\n * ```typescript\n * getValidTransitions(\"idle\");\n * // Returns: [\"walk\", \"run\", \"attack\", \"defend\", \"stance_change\", \"hit\", \"ko\"]\n *\n * getValidTransitions(\"ko\");\n * // Returns: [] (KO is terminal)\n * ```\n *\n * @korean 유효전환목록가져오기\n */\nexport function getValidTransitions(\n from: AnimationState,\n transitions: readonly TransitionRule[] = DEFAULT_TRANSITIONS,\n): AnimationState[] {\n return transitions\n .filter((t) => t.from === from && t.allowed)\n .map((t) => t.to)\n .filter((to) => isTransitionAllowed(from, to, transitions));\n}\n\n/**\n * Build a transition map for fast lookups\n *\n * @param transitions - Transition rules to build map from\n * @returns Map of from->to->allowed\n *\n * @korean 전환맵생성\n */\nexport function buildTransitionMap(\n transitions: readonly TransitionRule[] = DEFAULT_TRANSITIONS,\n): Map<AnimationState, Set<AnimationState>> {\n const map = new Map<AnimationState, Set<AnimationState>>();\n\n for (const rule of transitions) {\n if (!rule.allowed) continue;\n\n if (!map.has(rule.from)) {\n map.set(rule.from, new Set());\n }\n\n map.get(rule.from)?.add(rule.to);\n }\n\n return map;\n}\n\n/**\n * Calculate stance adjacency (distance around the stance wheel)\n *\n * **Korean**: 자세 인접도 계산\n *\n * Determines how many steps apart two stances are on the octagonal stance wheel.\n * Returns 0 for same stance, 1-3 for adjacent stances, 4 for opposite stances.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Number of steps apart (0-4)\n *\n * @example\n * ```typescript\n * calculateStanceDistance(TrigramStance.GEON, TrigramStance.TAE); // 1 (adjacent)\n * calculateStanceDistance(TrigramStance.GEON, TrigramStance.SON); // 4 (opposite)\n * calculateStanceDistance(TrigramStance.GEON, TrigramStance.GEON); // 0 (same)\n * ```\n *\n * @korean 자세거리계산\n */\nexport function calculateStanceDistance(\n from: TrigramStance,\n to: TrigramStance,\n): number {\n if (from === to) return 0;\n\n const fromIndex = TRIGRAM_STANCES_ORDER.indexOf(from);\n const toIndex = TRIGRAM_STANCES_ORDER.indexOf(to);\n\n if (fromIndex === -1 || toIndex === -1) {\n console.warn(`Invalid stance in distance calculation: ${from} -> ${to}`);\n return 4; // Treat as opposite stance\n }\n\n // Calculate shortest distance around the circular wheel\n const directDistance = Math.abs(toIndex - fromIndex);\n const wrapDistance = TRIGRAM_STANCES_ORDER.length - directDistance;\n\n return Math.min(directDistance, wrapDistance);\n}\n\n/**\n * Determine transition type based on stance distance\n *\n * **Korean**: 전환 유형 결정\n *\n * Classifies transition as direct (adjacent), indirect (opposite), or self.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition type\n *\n * @korean 전환유형결정\n */\nexport function determineTransitionType(\n from: TrigramStance,\n to: TrigramStance,\n): StanceTransitionType {\n const distance = calculateStanceDistance(from, to);\n\n if (distance === 0) return \"self\";\n if (distance <= 2) return \"direct\"; // Adjacent or near-adjacent\n return \"indirect\"; // Opposite or far apart\n}\n\n/**\n * Generate keyframes for direct stance transition (adjacent stances)\n *\n * **Korean**: 직접 전환 키프레임 생성\n *\n * Creates smooth keyframes for transitions between adjacent stances.\n * Phase breakdown:\n * - Frames 0-12: Weight shift away from source stance\n * - Frames 12-24: Foot repositioning\n * - Frames 24-36: Guard change to target stance\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Array of keyframes\n *\n * @korean 직접전환키프레임생성\n */\nfunction generateDirectTransitionKeyframes(\n from: TrigramStance,\n to: TrigramStance,\n): readonly StanceTransitionKeyframe[] {\n return [\n // Phase 1: Initial weight shift (frames 0-12)\n { frame: 0, stance: from, blend: 1.0 },\n { frame: 6, stance: from, blend: 0.8 },\n { frame: 12, stance: \"neutral\", blend: 0.5 },\n\n // Phase 2: Foot repositioning (frames 12-24)\n { frame: 18, stance: \"neutral\", blend: 0.4 },\n { frame: 24, stance: to, blend: 0.3 },\n\n // Phase 3: Guard position change (frames 24-36)\n { frame: 30, stance: to, blend: 0.7 },\n { frame: 36, stance: to, blend: 1.0 },\n ];\n}\n\n/**\n * Generate keyframes for indirect stance transition (opposite stances)\n *\n * **Korean**: 간접 전환 키프레임 생성\n *\n * Creates keyframes for transitions between opposite stances via neutral position.\n * Longer neutral phase for more complex repositioning.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Array of keyframes\n *\n * @korean 간접전환키프레임생성\n */\nfunction generateIndirectTransitionKeyframes(\n from: TrigramStance,\n to: TrigramStance,\n): readonly StanceTransitionKeyframe[] {\n return [\n // Phase 1: Exit source stance (frames 0-12)\n { frame: 0, stance: from, blend: 1.0 },\n { frame: 6, stance: from, blend: 0.7 },\n { frame: 12, stance: \"neutral\", blend: 0.5 },\n\n // Phase 2: Extended neutral position (frames 12-24)\n { frame: 18, stance: \"neutral\", blend: 0.5 },\n { frame: 24, stance: \"neutral\", blend: 0.4 },\n\n // Phase 3: Enter target stance (frames 24-36)\n { frame: 30, stance: to, blend: 0.6 },\n { frame: 36, stance: to, blend: 1.0 },\n ];\n}\n\n/**\n * Create a stance transition configuration\n *\n * **Korean**: 자세 전환 생성\n *\n * Generates complete transition configuration between two stances.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Complete stance transition configuration\n *\n * @korean 자세전환생성\n */\nexport function createStanceTransition(\n from: TrigramStance,\n to: TrigramStance,\n): StanceTransition {\n const type = determineTransitionType(from, to);\n\n // Self-transition (no animation)\n if (type === \"self\") {\n return {\n from,\n to,\n type: \"self\",\n duration: 0,\n keyframes: [{ frame: 0, stance: from, blend: 1.0 }],\n description: {\n korean: `${from} 자세 유지`,\n english: `Maintain ${from} stance`,\n },\n };\n }\n\n // Generate keyframes based on transition type\n const keyframes =\n type === \"direct\"\n ? generateDirectTransitionKeyframes(from, to)\n : generateIndirectTransitionKeyframes(from, to);\n\n return {\n from,\n to,\n type,\n duration: 600, // 600ms standard transition\n keyframes,\n description: {\n korean: `${from}에서 ${to}로 전환`,\n english: `Transition from ${from} to ${to}`,\n },\n };\n}\n\n/**\n * Stance transition matrix containing all 64 transitions (8x8)\n *\n * **Korean**: 팔괘 전환 행렬\n *\n * Maps from every stance to every other stance, including self-transitions.\n * Key format: \"from_to\" (e.g., \"geon_tae\")\n *\n * Total transitions: 64 (8 source stances × 8 target stances)\n * - 8 self-transitions (0ms)\n * - ~24 direct transitions (600ms, adjacent stances)\n * - ~32 indirect transitions (600ms, opposite stances)\n *\n * @korean 팔괘전환행렬\n */\nexport const STANCE_TRANSITIONS: Map<string, StanceTransition> = new Map();\n\n/**\n * Initialize the stance transition matrix\n *\n * **Korean**: 전환 행렬 초기화\n *\n * Generates all 64 stance transitions and populates the transition map.\n * Call this during system initialization.\n *\n * @korean 전환행렬초기화\n */\nexport function initializeStanceTransitions(): void {\n // Generate all 64 transitions (8 from × 8 to)\n for (const from of TRIGRAM_STANCES_ORDER) {\n for (const to of TRIGRAM_STANCES_ORDER) {\n const key = `${from}_${to}`;\n const transition = createStanceTransition(from, to);\n STANCE_TRANSITIONS.set(key, transition);\n }\n }\n\n if (process.env.NODE_ENV === \"development\") {\n console.log(\n `[StanceTransitions] Initialized ${STANCE_TRANSITIONS.size} stance transitions`,\n );\n }\n}\n\n/**\n * Get stance transition configuration\n *\n * **Korean**: 자세 전환 가져오기\n *\n * Retrieves the transition configuration for moving from one stance to another.\n *\n * @param from - Source stance\n * @param to - Target stance\n * @returns Transition configuration, or undefined if not found\n *\n * @example\n * ```typescript\n * const transition = getStanceTransition(TrigramStance.GEON, TrigramStance.TAE);\n * console.log(transition.duration); // 600\n * console.log(transition.type); // \"direct\"\n * ```\n *\n * @korean 자세전환가져오기\n */\nexport function getStanceTransition(\n from: TrigramStance,\n to: TrigramStance,\n): StanceTransition | undefined {\n const key = `${from}_${to}`;\n return STANCE_TRANSITIONS.get(key);\n}\n\n/**\n * Get all valid transitions from a stance\n *\n * **Korean**: 유효한 전환 목록\n *\n * Returns all possible transitions from the given stance.\n *\n * @param from - Source stance\n * @returns Array of all transitions from this stance\n *\n * @korean 유효한전환목록\n */\nexport function getTransitionsFromStance(\n from: TrigramStance,\n): StanceTransition[] {\n const transitions: StanceTransition[] = [];\n\n for (const to of TRIGRAM_STANCES_ORDER) {\n const transition = getStanceTransition(from, to);\n if (transition) {\n transitions.push(transition);\n }\n }\n\n return transitions;\n}\n\n/**\n * Clear all cached stance transitions\n *\n * **Korean**: 자세 전환 캐시 초기화\n *\n * Clears the stance transition cache to free memory.\n * Useful for session cleanup or hot reloading.\n * Call initializeStanceTransitions() to repopulate after clearing.\n *\n * @korean 자세전환캐시초기화\n */\nexport function clearStanceTransitions(): void {\n STANCE_TRANSITIONS.clear();\n}\n\n// Note: For production use, consider calling initializeStanceTransitions()\n// during application startup to avoid blocking the main thread.\n// For now, initialize on module load for convenience.\ninitializeStanceTransitions();\n"],"mappings":"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"}
|