blacktrigram 0.7.44 → 0.7.45
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/audio/AudioManager.d.ts +26 -0
- package/lib/audio/AudioManager.d.ts.map +1 -1
- package/lib/audio/AudioManager.js +26 -0
- package/lib/audio/AudioManager.js.map +1 -1
- package/lib/audio/index.d.ts.map +1 -1
- package/lib/audio/index.js.map +1 -1
- package/lib/audio/types.d.ts +18 -2
- package/lib/audio/types.d.ts.map +1 -1
- package/lib/audio/types.js +1 -0
- package/lib/audio/types.js.map +1 -1
- package/lib/components/effects/WindParticles3D.d.ts.map +1 -1
- package/lib/components/index.d.ts.map +1 -1
- package/lib/components/index.js.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
- package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.d.ts +0 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.d.ts.map +1 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.js +0 -1
- package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenu.d.ts.map +1 -1
- package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ArterialSpray3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodDecals3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodParticles3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodViscosity3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/BoneCrackParticles3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ConsciousnessBlur.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
- package/lib/components/screens/combat/components/effects/DustClouds3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/EarthCrackEffect3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/EarthHealingEffect3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/ImpactSparks3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/InternalDamage3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/LiPrecisionTargetingOverlay.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/NerveStrikeParticles3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/PainVignette.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
- package/lib/components/screens/combat/components/effects/ParticleAudio3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/TraumaOverlay3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
- package/lib/components/screens/combat/components/effects/WaterRipple3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/WaterWave3D.d.ts.map +1 -1
- package/lib/components/screens/combat/components/effects/index.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/MatchCountdown.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatLeftHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
- package/lib/components/screens/combat/components/hud/DifficultyIndicator.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/hud/FPSMonitor.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
- package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/BalanceIndicator.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.d.ts +0 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js +0 -1
- package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/StaminaWarning.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.d.ts +0 -2
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.d.ts.map +1 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js +0 -1
- package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
- package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
- package/lib/components/screens/combat/helpers/combatHelpers.d.ts.map +1 -1
- package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
- package/lib/components/screens/combat/hooks/useAICombat.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatActions.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAttackMovement.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAudio.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
- package/lib/components/screens/combat/hooks/useGrapplingAudio.d.ts.map +1 -1
- package/lib/components/screens/combat/hooks/usePreloadCombatAudio.d.ts.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.d.ts.map +1 -1
- package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
- package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/GamepadVisualization3D.d.ts.map +1 -1
- package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
- package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
- package/lib/components/screens/controls/components/Key3D.d.ts.map +1 -1
- package/lib/components/screens/controls/components/Key3D.js.map +1 -1
- package/lib/components/screens/controls/components/VisualKeyboard3D.d.ts.map +1 -1
- package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
- package/lib/components/screens/controls/constants/ControlsConstants.d.ts.map +1 -1
- package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
- package/lib/components/screens/controls/hooks/useControlsState.d.ts.map +1 -1
- package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
- package/lib/components/screens/endscreen/EndScreen3D.d.ts.map +1 -1
- package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/DefeatAnimation3D.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/VictoryAnimation3D.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
- package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/endscreen/components/index.d.ts.map +1 -1
- package/lib/components/screens/endscreen/index.d.ts.map +1 -1
- package/lib/components/screens/intro/IntroScreen3D.d.ts.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.d.ts.map +1 -1
- package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/MenuSectionOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
- package/lib/components/screens/intro/components/StatBarOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.d.ts.map +1 -1
- package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
- package/lib/components/screens/philosophy/components/InteractiveTrigramGridOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/InteractiveTrigramGridOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/PhilosophyNavigationOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/PhilosophyNavigationOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/PhilosophySectionOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/PhilosophySectionOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/PhilosophyTextOverlayHtml.d.ts +0 -1
- package/lib/components/screens/philosophy/components/PhilosophyTextOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/TrigramSymbol3D.d.ts +0 -1
- package/lib/components/screens/philosophy/components/TrigramSymbol3D.d.ts.map +1 -1
- package/lib/components/screens/philosophy/components/TrigramVisualization3D.d.ts +0 -1
- package/lib/components/screens/philosophy/components/TrigramVisualization3D.d.ts.map +1 -1
- package/lib/components/screens/philosophy/hooks/usePhilosophyState.d.ts +0 -1
- package/lib/components/screens/philosophy/hooks/usePhilosophyState.d.ts.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
- package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/AnatomyOverlay3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
- package/lib/components/screens/training/components/DamageNumber3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/FootPlacementMarkers3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
- package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/HitFeedbackEffect3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingAICharacter3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingArena3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingControlsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingDummy3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
- package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingHitEffects3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/TrainingStatsOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointMarker3D.d.ts.map +1 -1
- package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
- package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.d.ts.map +1 -1
- package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingLeftHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingRightHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingTopHUD.d.ts.map +1 -1
- package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
- package/lib/components/screens/training/components/index.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useAttackMovement.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingState.d.ts.map +1 -1
- package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
- package/lib/components/shared/base/AccessibilityProvider.d.ts.map +1 -1
- package/lib/components/shared/base/BaseButton.d.ts.map +1 -1
- package/lib/components/shared/base/BaseButton.js.map +1 -1
- package/lib/components/shared/base/BaseButtonOverlayHtml.d.ts.map +1 -1
- package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
- package/lib/components/shared/base/BasePanel.d.ts.map +1 -1
- package/lib/components/shared/base/BasePanel.js.map +1 -1
- package/lib/components/shared/base/BaseText.d.ts.map +1 -1
- package/lib/components/shared/base/BaseText.js.map +1 -1
- package/lib/components/shared/base/ResponsiveContainer.d.ts.map +1 -1
- package/lib/components/shared/base/index.d.ts.map +1 -1
- package/lib/components/shared/base/useKoreanTheme.d.ts.map +1 -1
- package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
- package/lib/components/shared/debug/PerformanceDebugOverlayHtml.d.ts.map +1 -1
- package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
- package/lib/components/shared/effects/ScreenFlash.d.ts.map +1 -1
- package/lib/components/shared/mobile/ActionButtons.d.ts.map +1 -1
- package/lib/components/shared/mobile/ActionButtons.js +0 -1
- package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.d.ts +0 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.d.ts.map +1 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.js +0 -1
- package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
- package/lib/components/shared/mobile/HapticController.d.ts +0 -13
- package/lib/components/shared/mobile/HapticController.d.ts.map +1 -1
- package/lib/components/shared/mobile/HapticController.js +0 -10
- package/lib/components/shared/mobile/HapticController.js.map +1 -1
- package/lib/components/shared/mobile/MobileControlsPure.d.ts.map +1 -1
- package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
- package/lib/components/shared/mobile/PerformanceMonitor.d.ts +0 -15
- package/lib/components/shared/mobile/PerformanceMonitor.d.ts.map +1 -1
- package/lib/components/shared/mobile/StanceWheelPure.d.ts +0 -1
- package/lib/components/shared/mobile/StanceWheelPure.d.ts.map +1 -1
- package/lib/components/shared/mobile/StanceWheelPure.js +0 -1
- package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
- package/lib/components/shared/mobile/TouchOptimizer.d.ts +0 -4
- package/lib/components/shared/mobile/TouchOptimizer.d.ts.map +1 -1
- package/lib/components/shared/mobile/TouchOptimizer.js +0 -3
- package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
- package/lib/components/shared/mobile/VirtualDPad.d.ts.map +1 -1
- package/lib/components/shared/mobile/VirtualDPad.js +0 -1
- package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
- package/lib/components/shared/mobile/index.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BodySurface.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneAttachedMuscles.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneClothing.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.d.ts +0 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
- package/lib/components/shared/three/anatomy/Face3D.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Foot3D.d.ts +0 -1
- package/lib/components/shared/three/anatomy/Foot3D.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
- package/lib/components/shared/three/anatomy/Hand3D.d.ts +0 -1
- package/lib/components/shared/three/anatomy/Hand3D.d.ts.map +1 -1
- package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
- package/lib/components/shared/three/effects/ActionFeedback.d.ts.map +1 -1
- package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
- package/lib/components/shared/three/effects/DamageNumbers.d.ts.map +1 -1
- package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
- package/lib/components/shared/three/effects/ExplosiveBurstEffect3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/GrapplingIndicator3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/HitEffects3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
- package/lib/components/shared/three/effects/LimbExposureIndicator3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/NerveDisruptionEffect3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/PlayerStateIndicators.d.ts.map +1 -1
- package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
- package/lib/components/shared/three/effects/StanceSymbol3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
- package/lib/components/shared/three/effects/StanceTransitionEffect.d.ts.map +1 -1
- package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
- package/lib/components/shared/three/effects/ThunderEffect3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/VitalPointMarkers3D.d.ts.map +1 -1
- package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
- package/lib/components/shared/three/index.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/ElementalColorSystem.d.ts +0 -6
- package/lib/components/shared/three/indicators/ElementalColorSystem.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/ElementalColorSystem.js +0 -4
- package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
- package/lib/components/shared/three/indicators/GuardIndicator.d.ts +0 -1
- package/lib/components/shared/three/indicators/GuardIndicator.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/GuardIndicator.js +0 -1
- package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
- package/lib/components/shared/three/indicators/HapticFeedback.d.ts +0 -7
- package/lib/components/shared/three/indicators/HapticFeedback.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/HapticFeedback.js +0 -2
- package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.d.ts +0 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.d.ts.map +1 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.js +0 -1
- package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
- package/lib/components/shared/three/indicators/TrigramSymbol3D.d.ts +0 -1
- package/lib/components/shared/three/indicators/TrigramSymbol3D.d.ts.map +1 -1
- package/lib/components/shared/three/models/Player3DWithTransitions.d.ts.map +1 -1
- package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
- package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
- package/lib/components/shared/three/optimization/AdaptiveQuality.d.ts.map +1 -1
- package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
- package/lib/components/shared/three/optimization/InstancedGeometry.d.ts.map +1 -1
- package/lib/components/shared/three/optimization/LODSystem.d.ts.map +1 -1
- package/lib/components/shared/three/scene/AtmosphericParticles3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
- package/lib/components/shared/three/scene/BackgroundScene3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
- package/lib/components/shared/three/scene/CombatArena3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
- package/lib/components/shared/three/scene/DebugCollision.d.ts +0 -2
- package/lib/components/shared/three/scene/DebugCollision.d.ts.map +1 -1
- package/lib/components/shared/three/scene/KoreanSignage3D.d.ts.map +1 -1
- package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
- package/lib/components/shared/three/ui/ArchetypeCard.d.ts.map +1 -1
- package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
- package/lib/components/shared/three/ui/BodyPartHealthDisplay.d.ts.map +1 -1
- package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
- package/lib/components/shared/three/ui/BreathingIndicator.d.ts.map +1 -1
- package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
- package/lib/components/shared/three/ui/CombatReadinessBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
- package/lib/components/shared/three/ui/ComboCounter.d.ts.map +1 -1
- package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
- package/lib/components/shared/three/ui/HealthBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanButton.d.ts.map +1 -1
- package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanPanel.d.ts.map +1 -1
- package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
- package/lib/components/shared/three/ui/KoreanText.d.ts.map +1 -1
- package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
- package/lib/components/shared/three/ui/MenuList.d.ts.map +1 -1
- package/lib/components/shared/three/ui/MenuList.js.map +1 -1
- package/lib/components/shared/three/ui/PlayerHUD.d.ts.map +1 -1
- package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
- package/lib/components/shared/three/ui/ProgressBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.d.ts +0 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.d.ts.map +1 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.js +0 -1
- package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
- package/lib/components/shared/three/ui/StaminaBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBar.d.ts.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
- package/lib/components/shared/three/ui/TechniqueBarContainer.d.ts.map +1 -1
- package/lib/components/shared/three/ui/TechniqueCard.d.ts.map +1 -1
- package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
- package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.d.ts.map +1 -1
- package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
- package/lib/components/shared/three/ui/VulnerabilityWindowHUD.d.ts.map +1 -1
- package/lib/components/shared/ui/BaseHUDContainer.d.ts.map +1 -1
- package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
- package/lib/components/shared/ui/CombatTimer.d.ts.map +1 -1
- package/lib/components/shared/ui/CombatTimer.js.map +1 -1
- package/lib/components/shared/ui/ErrorBoundary.d.ts.map +1 -1
- package/lib/components/shared/ui/ErrorModal.d.ts.map +1 -1
- package/lib/components/shared/ui/ErrorModal.js.map +1 -1
- package/lib/components/shared/ui/HUDSection.d.ts.map +1 -1
- package/lib/components/shared/ui/LoadingState.d.ts.map +1 -1
- package/lib/components/shared/ui/LoadingState.js.map +1 -1
- package/lib/components/shared/ui/MobileHUDLayout.d.ts +0 -1
- package/lib/components/shared/ui/MobileHUDLayout.d.ts.map +1 -1
- package/lib/components/shared/ui/ResponsiveContainer.d.ts +0 -1
- package/lib/components/shared/ui/ResponsiveContainer.d.ts.map +1 -1
- package/lib/components/shared/ui/SplashScreen.d.ts.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/StyledHUDPanel.d.ts.map +1 -1
- package/lib/components/shared/ui/VitalPointOverlayControlsPure.d.ts.map +1 -1
- package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
- package/lib/components/shared/ui/VolumeControl.d.ts.map +1 -1
- package/lib/components/shared/ui/VolumeControl.js.map +1 -1
- package/lib/components/shared/ui/shared/ConfirmDialog.d.ts.map +1 -1
- package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
- package/lib/components/test/Hello3D.d.ts.map +1 -1
- package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.d.ts.map +1 -1
- package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
- package/lib/components/ui/combat/ComboCounter.d.ts.map +1 -1
- package/lib/components/ui/combat/PressureMeter.d.ts.map +1 -1
- package/lib/systems/CombatSystem.d.ts +0 -6
- package/lib/systems/CombatSystem.d.ts.map +1 -1
- package/lib/systems/CombatSystem.js +0 -6
- package/lib/systems/CombatSystem.js.map +1 -1
- package/lib/systems/EffectCalculator.d.ts +0 -7
- package/lib/systems/EffectCalculator.d.ts.map +1 -1
- package/lib/systems/EffectCalculator.js +0 -4
- package/lib/systems/EffectCalculator.js.map +1 -1
- package/lib/systems/LayoutSystem.d.ts +0 -1
- package/lib/systems/LayoutSystem.d.ts.map +1 -1
- package/lib/systems/LayoutSystem.js +0 -1
- package/lib/systems/LayoutSystem.js.map +1 -1
- package/lib/systems/PlayerEffectManager.d.ts +0 -10
- package/lib/systems/PlayerEffectManager.d.ts.map +1 -1
- package/lib/systems/PlayerEffectManager.js +0 -3
- package/lib/systems/PlayerEffectManager.js.map +1 -1
- package/lib/systems/ResponsiveScaling.d.ts +0 -12
- package/lib/systems/ResponsiveScaling.d.ts.map +1 -1
- package/lib/systems/ResponsiveScaling.js +0 -12
- package/lib/systems/ResponsiveScaling.js.map +1 -1
- package/lib/systems/TrigramSystem.d.ts +0 -13
- package/lib/systems/TrigramSystem.d.ts.map +1 -1
- package/lib/systems/TrigramSystem.js +0 -13
- package/lib/systems/TrigramSystem.js.map +1 -1
- package/lib/systems/VitalPointSystem.d.ts +0 -10
- package/lib/systems/VitalPointSystem.d.ts.map +1 -1
- package/lib/systems/VitalPointSystem.js +0 -10
- package/lib/systems/VitalPointSystem.js.map +1 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.d.ts +0 -4
- package/lib/systems/animation/builders/KeyframeInterpolation.d.ts.map +1 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.js +0 -1
- package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
- package/lib/systems/animation/builders/SkeletonRig.d.ts +0 -4
- package/lib/systems/animation/builders/SkeletonRig.d.ts.map +1 -1
- package/lib/systems/animation/builders/SkeletonRig.js +0 -3
- package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.d.ts +0 -5
- package/lib/systems/animation/catalogs/RecoveryAnimations.d.ts.map +1 -1
- package/lib/systems/animation/catalogs/RecoveryAnimations.js +0 -5
- package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
- package/lib/systems/animation/core/AnimationHitTiming.d.ts +0 -6
- package/lib/systems/animation/core/AnimationHitTiming.d.ts.map +1 -1
- package/lib/systems/animation/core/AnimationHitTiming.js +0 -4
- package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.d.ts +0 -3
- package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
- package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
- package/lib/systems/animation/core/LateralityTransform.d.ts +0 -3
- package/lib/systems/animation/core/LateralityTransform.d.ts.map +1 -1
- package/lib/systems/animation/core/LateralityTransform.js +0 -1
- package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.d.ts +0 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.d.ts.map +1 -1
- package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapper.d.ts +0 -10
- package/lib/systems/animation/core/TechniqueAnimationMapper.d.ts.map +1 -1
- package/lib/systems/animation/core/TechniqueAnimationMapper.js +0 -8
- package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
- package/lib/systems/animation/core/TrigramAnimationMapping.d.ts +0 -10
- package/lib/systems/animation/core/TrigramAnimationMapping.d.ts.map +1 -1
- package/lib/systems/animation/core/TrigramStanceTransitions.d.ts +0 -2
- package/lib/systems/animation/core/TrigramStanceTransitions.d.ts.map +1 -1
- package/lib/systems/animation/core/types.d.ts +0 -39
- package/lib/systems/animation/core/types.d.ts.map +1 -1
- package/lib/systems/animation/core/types.js +0 -9
- package/lib/systems/animation/core/types.js.map +1 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.d.ts +0 -27
- package/lib/systems/animation/systems/AdvancedJointMovements.d.ts.map +1 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.js +0 -1
- package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
- package/lib/systems/animation/systems/BodyFacingSystem.d.ts +0 -19
- package/lib/systems/animation/systems/BodyFacingSystem.d.ts.map +1 -1
- package/lib/systems/animation/systems/BodyFacingSystem.js +0 -14
- package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
- package/lib/systems/animation/systems/FacialExpressions.d.ts +0 -10
- package/lib/systems/animation/systems/FacialExpressions.d.ts.map +1 -1
- package/lib/systems/animation/systems/FacialExpressions.js +0 -2
- package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
- package/lib/systems/animation/systems/FallAnimations.d.ts +0 -4
- package/lib/systems/animation/systems/FallAnimations.d.ts.map +1 -1
- package/lib/systems/animation/systems/FallAnimations.js +0 -2
- package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
- package/lib/systems/animation/systems/HeadMovements.d.ts +0 -10
- package/lib/systems/animation/systems/HeadMovements.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartDamageIntegration.d.ts +0 -7
- package/lib/systems/bodypart/BodyPartDamageIntegration.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartDamageIntegration.js +0 -7
- package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
- package/lib/systems/bodypart/BodyPartHealthSystem.d.ts +0 -13
- package/lib/systems/bodypart/BodyPartHealthSystem.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartHealthSystem.js +0 -13
- package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
- package/lib/systems/bodypart/BodyPartPositionMapping.d.ts +0 -6
- package/lib/systems/bodypart/BodyPartPositionMapping.d.ts.map +1 -1
- package/lib/systems/bodypart/BodyPartPositionMapping.js +0 -6
- package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
- package/lib/systems/bodypart/CombatInjuryIntegration.d.ts +0 -10
- package/lib/systems/bodypart/CombatInjuryIntegration.d.ts.map +1 -1
- package/lib/systems/bodypart/CombatInjuryIntegration.js +0 -8
- package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryIntegration.d.ts +0 -2
- package/lib/systems/bodypart/InjuryIntegration.d.ts.map +1 -1
- package/lib/systems/bodypart/InjuryIntegration.js +0 -2
- package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
- package/lib/systems/bodypart/InjuryTracker.d.ts +0 -14
- package/lib/systems/bodypart/InjuryTracker.d.ts.map +1 -1
- package/lib/systems/bodypart/InjuryTracker.js +0 -12
- package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
- package/lib/systems/bodypart/MovementPenaltySystem.d.ts +0 -8
- package/lib/systems/bodypart/MovementPenaltySystem.d.ts.map +1 -1
- package/lib/systems/bodypart/MovementPenaltySystem.js +0 -8
- package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.d.ts +0 -8
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.d.ts.map +1 -1
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.js +0 -8
- package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
- package/lib/systems/bodypart/types.d.ts +0 -13
- package/lib/systems/bodypart/types.d.ts.map +1 -1
- package/lib/systems/bodypart/types.js +0 -5
- package/lib/systems/bodypart/types.js.map +1 -1
- package/lib/systems/breathing/BreathingDisruptionSystem.d.ts +0 -3
- package/lib/systems/breathing/BreathingDisruptionSystem.d.ts.map +1 -1
- package/lib/systems/breathing/BreathingDisruptionSystem.js +0 -2
- package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
- package/lib/systems/combat/BalanceSystem.d.ts +0 -25
- package/lib/systems/combat/BalanceSystem.d.ts.map +1 -1
- package/lib/systems/combat/BalanceSystem.js +0 -25
- package/lib/systems/combat/BalanceSystem.js.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.d.ts +0 -4
- package/lib/systems/combat/BreakingStatusEffects.d.ts.map +1 -1
- package/lib/systems/combat/BreakingStatusEffects.js +0 -3
- package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
- package/lib/systems/combat/CombatStateSystem.d.ts +0 -9
- package/lib/systems/combat/CombatStateSystem.d.ts.map +1 -1
- package/lib/systems/combat/CombatStateSystem.js +0 -9
- package/lib/systems/combat/CombatStateSystem.js.map +1 -1
- package/lib/systems/combat/ConsciousnessSystem.d.ts +0 -16
- package/lib/systems/combat/ConsciousnessSystem.d.ts.map +1 -1
- package/lib/systems/combat/ConsciousnessSystem.js +0 -16
- package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
- package/lib/systems/combat/FallIntegration.d.ts +0 -3
- package/lib/systems/combat/FallIntegration.d.ts.map +1 -1
- package/lib/systems/combat/FallIntegration.js +0 -3
- package/lib/systems/combat/FallIntegration.js.map +1 -1
- package/lib/systems/combat/GrappleSystem.d.ts +0 -2
- package/lib/systems/combat/GrappleSystem.d.ts.map +1 -1
- package/lib/systems/combat/GrappleSystem.js +0 -2
- package/lib/systems/combat/GrappleSystem.js.map +1 -1
- package/lib/systems/combat/LimbExposureSystem.d.ts +0 -7
- package/lib/systems/combat/LimbExposureSystem.d.ts.map +1 -1
- package/lib/systems/combat/LimbExposureSystem.js +0 -7
- package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
- package/lib/systems/combat/PainResponseSystem.d.ts +0 -11
- package/lib/systems/combat/PainResponseSystem.d.ts.map +1 -1
- package/lib/systems/combat/PainResponseSystem.js +0 -11
- package/lib/systems/combat/PainResponseSystem.js.map +1 -1
- package/lib/systems/combat/painConsciousnessUtils.d.ts +0 -7
- package/lib/systems/combat/painConsciousnessUtils.d.ts.map +1 -1
- package/lib/systems/combat/painConsciousnessUtils.js +0 -7
- package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
- package/lib/systems/effects.d.ts +11 -0
- package/lib/systems/effects.d.ts.map +1 -1
- package/lib/systems/effects.js +10 -0
- package/lib/systems/effects.js.map +1 -1
- package/lib/systems/game.d.ts +16 -0
- package/lib/systems/game.d.ts.map +1 -1
- package/lib/systems/game.js +1 -0
- package/lib/systems/game.js.map +1 -1
- package/lib/systems/index.d.ts +5 -1
- package/lib/systems/index.d.ts.map +1 -1
- package/lib/systems/index.js.map +1 -1
- package/lib/systems/movement/InjuryMovementModifier.d.ts +0 -10
- package/lib/systems/movement/InjuryMovementModifier.d.ts.map +1 -1
- package/lib/systems/movement/InjuryMovementModifier.js +0 -7
- package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
- package/lib/systems/movement/integration.d.ts +0 -3
- package/lib/systems/movement/integration.d.ts.map +1 -1
- package/lib/systems/movement/integration.js +0 -3
- package/lib/systems/movement/integration.js.map +1 -1
- package/lib/systems/physics/AttackMovementPhysics.d.ts +0 -9
- package/lib/systems/physics/AttackMovementPhysics.d.ts.map +1 -1
- package/lib/systems/physics/AttackMovementPhysics.js +0 -7
- package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
- package/lib/systems/physics/CollisionDetection.d.ts +0 -6
- package/lib/systems/physics/CollisionDetection.d.ts.map +1 -1
- package/lib/systems/physics/CollisionDetection.js +0 -6
- package/lib/systems/physics/CollisionDetection.js.map +1 -1
- package/lib/systems/physics/CoordinateMapper.d.ts +0 -1
- package/lib/systems/physics/CoordinateMapper.d.ts.map +1 -1
- package/lib/systems/physics/CoordinateMapper.js +0 -1
- package/lib/systems/physics/CoordinateMapper.js.map +1 -1
- package/lib/systems/physics/KnockbackPhysics.d.ts +0 -11
- package/lib/systems/physics/KnockbackPhysics.d.ts.map +1 -1
- package/lib/systems/physics/KnockbackPhysics.js +0 -8
- package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
- package/lib/systems/physics/MovementPhysics.d.ts +0 -10
- package/lib/systems/physics/MovementPhysics.d.ts.map +1 -1
- package/lib/systems/physics/MovementPhysics.js +0 -8
- package/lib/systems/physics/MovementPhysics.js.map +1 -1
- package/lib/systems/physics/PhysicalReachCalculator.d.ts +0 -6
- package/lib/systems/physics/PhysicalReachCalculator.d.ts.map +1 -1
- package/lib/systems/physics/PhysicalReachCalculator.js +0 -5
- package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
- package/lib/systems/physics/SpeedModifierSystem.d.ts +0 -5
- package/lib/systems/physics/SpeedModifierSystem.d.ts.map +1 -1
- package/lib/systems/physics/SpeedModifierSystem.js +0 -4
- package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
- package/lib/systems/player.d.ts +0 -5
- package/lib/systems/player.d.ts.map +1 -1
- package/lib/systems/trigram/TrigramCalculator.d.ts +0 -1
- package/lib/systems/trigram/TrigramCalculator.d.ts.map +1 -1
- package/lib/systems/trigram/TrigramCalculator.js +0 -1
- package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
- package/lib/systems/trigram/types.d.ts +0 -4
- package/lib/systems/trigram/types.d.ts.map +1 -1
- package/lib/systems/trigram/types.js +0 -2
- package/lib/systems/trigram/types.js.map +1 -1
- package/lib/systems/types.d.ts +7 -2
- package/lib/systems/types.d.ts.map +1 -1
- package/lib/systems/types.js.map +1 -1
- package/lib/systems/vitalpoint/DamageCalculator.d.ts +0 -3
- package/lib/systems/vitalpoint/DamageCalculator.d.ts.map +1 -1
- package/lib/systems/vitalpoint/DamageCalculator.js +0 -3
- package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
- package/lib/systems/vitalpoint/KoreanVitalPoints.d.ts +0 -8
- package/lib/systems/vitalpoint/KoreanVitalPoints.d.ts.map +1 -1
- package/lib/systems/vitalpoint/KoreanVitalPoints.js +0 -8
- package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
- package/lib/systems/vitalpoint/VitalPointsData.d.ts +0 -3
- package/lib/systems/vitalpoint/VitalPointsData.d.ts.map +1 -1
- package/lib/systems/vitalpoint/VitalPointsData.js +0 -1
- package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
- package/lib/types/PhysicsTypes.d.ts +21 -78
- package/lib/types/PhysicsTypes.d.ts.map +1 -1
- package/lib/types/PhysicsTypes.js +17 -63
- package/lib/types/PhysicsTypes.js.map +1 -1
- package/lib/types/clothing.d.ts +0 -9
- package/lib/types/clothing.d.ts.map +1 -1
- package/lib/types/constants/animations.d.ts +35 -1
- package/lib/types/constants/animations.d.ts.map +1 -1
- package/lib/types/constants/animations.js +12 -1
- package/lib/types/constants/animations.js.map +1 -1
- package/lib/types/constants/colors.d.ts +28 -2
- package/lib/types/constants/colors.d.ts.map +1 -1
- package/lib/types/constants/colors.js +30 -4
- package/lib/types/constants/colors.js.map +1 -1
- package/lib/types/constants/index.d.ts +5 -1
- package/lib/types/constants/index.d.ts.map +1 -1
- package/lib/types/constants/index.js.map +1 -1
- package/lib/types/constants/performance.d.ts +0 -2
- package/lib/types/constants/performance.d.ts.map +1 -1
- package/lib/types/constants/performance.js +0 -2
- package/lib/types/constants/performance.js.map +1 -1
- package/lib/types/constants/typography.d.ts +40 -2
- package/lib/types/constants/typography.d.ts.map +1 -1
- package/lib/types/constants/typography.js +40 -2
- package/lib/types/constants/typography.js.map +1 -1
- package/lib/types/constants/ui.d.ts +89 -1
- package/lib/types/constants/ui.d.ts.map +1 -1
- package/lib/types/constants/ui.js +33 -1
- package/lib/types/constants/ui.js.map +1 -1
- package/lib/types/facial.d.ts +0 -15
- package/lib/types/facial.d.ts.map +1 -1
- package/lib/types/facial.js +0 -8
- package/lib/types/facial.js.map +1 -1
- package/lib/types/hand-animation.d.ts +34 -147
- package/lib/types/hand-animation.d.ts.map +1 -1
- package/lib/types/hand-animation.js +0 -2
- package/lib/types/hand-animation.js.map +1 -1
- package/lib/types/injury.d.ts +0 -2
- package/lib/types/injury.d.ts.map +1 -1
- package/lib/types/injury.js +0 -1
- package/lib/types/injury.js.map +1 -1
- package/lib/types/physics.d.ts +0 -21
- package/lib/types/physics.d.ts.map +1 -1
- package/lib/types/physics.js +0 -6
- package/lib/types/physics.js.map +1 -1
- package/lib/types/physicsConstants.d.ts +0 -12
- package/lib/types/physicsConstants.d.ts.map +1 -1
- package/lib/types/physicsConstants.js +0 -12
- package/lib/types/physicsConstants.js.map +1 -1
- package/lib/types/player-visual.d.ts +45 -189
- package/lib/types/player-visual.d.ts.map +1 -1
- package/lib/types/technique.d.ts +1 -5
- package/lib/types/technique.d.ts.map +1 -1
- package/lib/types/techniqueId.d.ts +0 -1
- package/lib/types/techniqueId.d.ts.map +1 -1
- package/lib/types/techniqueId.js +0 -1
- package/lib/types/techniqueId.js.map +1 -1
- package/lib/utils/arenaWorldDimensions.d.ts +0 -11
- package/lib/utils/arenaWorldDimensions.d.ts.map +1 -1
- package/lib/utils/arenaWorldDimensions.js +0 -6
- package/lib/utils/arenaWorldDimensions.js.map +1 -1
- package/lib/utils/controlMapping.d.ts +3 -4
- package/lib/utils/controlMapping.d.ts.map +1 -1
- package/lib/utils/controlMapping.js +1 -2
- package/lib/utils/controlMapping.js.map +1 -1
- package/lib/utils/deviceDetection.d.ts +0 -5
- package/lib/utils/deviceDetection.d.ts.map +1 -1
- package/lib/utils/deviceDetection.js +0 -5
- package/lib/utils/deviceDetection.js.map +1 -1
- package/lib/utils/hapticFeedback.d.ts +23 -95
- package/lib/utils/hapticFeedback.d.ts.map +1 -1
- package/lib/utils/hapticFeedback.js +9 -39
- package/lib/utils/hapticFeedback.js.map +1 -1
- package/lib/utils/haptics.d.ts +0 -3
- package/lib/utils/haptics.d.ts.map +1 -1
- package/lib/utils/haptics.js +0 -1
- package/lib/utils/haptics.js.map +1 -1
- package/lib/utils/math.d.ts +0 -3
- package/lib/utils/math.d.ts.map +1 -1
- package/lib/utils/math.js +0 -2
- package/lib/utils/math.js.map +1 -1
- package/lib/utils/mobileLayoutHelpers.d.ts +0 -3
- package/lib/utils/mobileLayoutHelpers.d.ts.map +1 -1
- package/lib/utils/mobileLayoutHelpers.js +0 -1
- package/lib/utils/mobileLayoutHelpers.js.map +1 -1
- package/lib/utils/mobileUIUtils.d.ts +5 -100
- package/lib/utils/mobileUIUtils.d.ts.map +1 -1
- package/lib/utils/mobileUIUtils.js +0 -9
- package/lib/utils/mobileUIUtils.js.map +1 -1
- package/lib/utils/physicalAttributeValidation.d.ts.map +1 -1
- package/lib/utils/player3DHelpers.d.ts.map +1 -1
- package/lib/utils/player3DHelpers.js.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.d.ts +0 -65
- package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
- package/lib/utils/responsiveLayoutHelpers.js +0 -65
- package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
- package/lib/utils/responsiveOrientationConstants.d.ts +0 -7
- package/lib/utils/responsiveOrientationConstants.d.ts.map +1 -1
- package/lib/utils/responsiveOrientationConstants.js +0 -7
- package/lib/utils/responsiveOrientationConstants.js.map +1 -1
- package/lib/utils/safeAreaUtils.d.ts +0 -6
- package/lib/utils/safeAreaUtils.d.ts.map +1 -1
- package/lib/utils/safeAreaUtils.js +0 -2
- package/lib/utils/safeAreaUtils.js.map +1 -1
- package/lib/utils/sharedPhysicsConfig.d.ts +0 -4
- package/lib/utils/sharedPhysicsConfig.d.ts.map +1 -1
- package/lib/utils/sharedPhysicsConfig.js +0 -2
- package/lib/utils/sharedPhysicsConfig.js.map +1 -1
- package/lib/utils/skeletonScaling.d.ts +0 -9
- package/lib/utils/skeletonScaling.d.ts.map +1 -1
- package/lib/utils/skeletonScaling.js +0 -1
- package/lib/utils/skeletonScaling.js.map +1 -1
- package/package.json +7 -7
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DamageNumber3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/DamageNumber3D.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAA0B,MAAM,OAAO,CAAC;AAI/C;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACjD,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAChC,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"DamageNumber3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/DamageNumber3D.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAA0B,MAAM,OAAO,CAAC;AAI/C;;GAEG;AACH,MAAM,WAAW,mBAAmB;IAClC,0BAA0B;IAC1B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,8BAA8B;IAC9B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kCAAkC;IAClC,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,SAAS,GAAG,UAAU,CAAC;IACjD,wCAAwC;IACxC,QAAQ,CAAC,UAAU,EAAE,MAAM,IAAI,CAAC;IAChC,oCAAoC;IACpC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;;GAGG;AACH,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA0ExD,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FootPlacementMarkers3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/FootPlacementMarkers3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAA0B,MAAM,OAAO,CAAC;AAG/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,GACvC,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,sCAAsC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,wCAAwC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kCAAkC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;
|
|
1
|
+
{"version":3,"file":"FootPlacementMarkers3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/FootPlacementMarkers3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAIH,OAAO,KAA0B,MAAM,OAAO,CAAC;AAG/C,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAEjE;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAC5B,OAAO,CAAC,aAAa,EAAE,eAAe,CAAC,GACvC,MAAM,CAAC;AAEX;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C,sCAAsC;IACtC,QAAQ,CAAC,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACnD,uCAAuC;IACvC,QAAQ,CAAC,OAAO,EAAE,oBAAoB,CAAC;IACvC,wCAAwC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,kCAAkC;IAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAuKD;;;;;;;GAOG;AACH,eAAO,MAAM,sBAAsB,EAAE,KAAK,CAAC,EAAE,CAAC,2BAA2B,CA+BxE,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FootPlacementMarkers3D.js","names":[],"sources":["../../../../../src/components/screens/training/components/FootPlacementMarkers3D.tsx"],"sourcesContent":["/**\n * FootPlacementMarkers3D - 3D markers showing foot placement for footwork drills\n * \n * Renders visual indicators on the ground to guide footwork training,\n * showing target positions for Korean martial arts footwork patterns.\n * \n * @module components/screens/training/components/FootPlacementMarkers3D\n * @category Training 3D Components\n * @korean 발위치표시3D컴포넌트\n */\n\nimport { Html } from \"@react-three/drei\";\nimport { useFrame } from \"@react-three/fiber\";\nimport React, { useRef, useMemo } from \"react\";\nimport * as THREE from \"three\";\nimport { KOREAN_COLORS } from \"../../../../types/constants\";\nimport type { FootworkDrill } from \"./FootworkDrillsOverlayHtml\";\n\n/**\n * Footwork drill pattern types for 3D visualization\n * \n * Derived from FootworkDrill, excluding \"free_practice\" (which has no pattern),\n * and adding a \"none\" sentinel for cases with no active pattern.\n */\nexport type FootworkDrillPattern = \n | Exclude<FootworkDrill, \"free_practice\">\n | \"none\";\n\n/**\n * Props for FootPlacementMarkers3D component\n */\nexport interface FootPlacementMarkers3DProps {\n /** Center position for the pattern */\n readonly centerPosition?: [number, number, number];\n /** Current drill pattern to display */\n readonly pattern: FootworkDrillPattern;\n /** Current step in pattern (0-based) */\n readonly currentStep?: number;\n /** Whether markers are visible */\n readonly visible?: boolean;\n /** Scale factor for markers */\n readonly scale?: number;\n /** Whether to animate markers */\n readonly animated?: boolean;\n}\n\n/**\n * Generate footwork pattern positions\n * \n * @korean 보법패턴위치생성\n */\nfunction getPatternPositions(\n pattern: FootworkDrillPattern,\n center: [number, number, number]\n): Array<{ position: [number, number, number]; label: string }> {\n const [cx, cy, cz] = center;\n const radius = 2.0; // 2 meters radius for circular patterns\n const stepDist = 0.3; // 30cm step distance\n\n switch (pattern) {\n case \"circular_left\":\n // 4 positions in a circle (left rotation)\n return [\n { position: [cx + radius, cy, cz], label: \"1\" },\n { position: [cx, cy, cz - radius], label: \"2\" },\n { position: [cx - radius, cy, cz], label: \"3\" },\n { position: [cx, cy, cz + radius], label: \"4\" },\n ];\n\n case \"circular_right\":\n // 4 positions in a circle (right rotation)\n return [\n { position: [cx + radius, cy, cz], label: \"1\" },\n { position: [cx, cy, cz + radius], label: \"2\" },\n { position: [cx - radius, cy, cz], label: \"3\" },\n { position: [cx, cy, cz - radius], label: \"4\" },\n ];\n\n case \"pivot_combo\":\n // Pivot left and right positions\n return [\n { position: [cx, cy, cz], label: \"Start\" },\n { position: [cx - 0.5, cy, cz + 0.5], label: \"Pivot L\" },\n { position: [cx, cy, cz], label: \"Center\" },\n { position: [cx + 0.5, cy, cz + 0.5], label: \"Pivot R\" },\n ];\n\n case \"triangle_step\":\n // Triangle stepping pattern\n return [\n { position: [cx, cy, cz], label: \"Start\" },\n { position: [cx, cy, cz - stepDist * 2], label: \"Forward\" },\n { position: [cx + stepDist * 1.5, cy, cz], label: \"Right\" },\n { position: [cx, cy, cz], label: \"Back\" },\n ];\n\n case \"slide_drill\":\n // Four-direction slide pattern (cross shape)\n return [\n { position: [cx, cy, cz], label: \"Center\" },\n { position: [cx, cy, cz - stepDist], label: \"Forward\" },\n { position: [cx + stepDist, cy, cz], label: \"Right\" },\n { position: [cx, cy, cz + stepDist], label: \"Back\" },\n { position: [cx - stepDist, cy, cz], label: \"Left\" },\n ];\n\n case \"shuffle_practice\":\n // Quick forward shuffles\n return [\n { position: [cx, cy, cz], label: \"Start\" },\n { position: [cx, cy, cz - 0.15], label: \"Shuffle 1\" },\n { position: [cx, cy, cz - 0.30], label: \"Shuffle 2\" },\n { position: [cx, cy, cz - 0.45], label: \"Shuffle 3\" },\n ];\n\n case \"none\":\n default:\n return [];\n }\n}\n\n/**\n * Single foot placement marker\n */\nconst FootMarker: React.FC<{\n position: [number, number, number];\n label: string;\n isActive: boolean;\n isCompleted: boolean;\n animated: boolean;\n}> = ({ position, label, isActive, isCompleted, animated }) => {\n const meshRef = useRef<THREE.Mesh>(null);\n const ringRef = useRef<THREE.Mesh>(null);\n\n // Pulsing animation for active marker\n useFrame((state) => {\n if (!animated) return;\n \n if (meshRef.current && isActive) {\n const pulse = Math.sin(state.clock.elapsedTime * 3) * 0.1 + 1;\n meshRef.current.scale.setScalar(pulse);\n }\n\n if (ringRef.current && isActive) {\n const ringPulse = Math.sin(state.clock.elapsedTime * 2) * 0.2 + 1;\n ringRef.current.scale.setScalar(ringPulse);\n }\n });\n\n const markerColor = isCompleted\n ? KOREAN_COLORS.ACCENT_GREEN\n : isActive\n ? KOREAN_COLORS.PRIMARY_CYAN\n : KOREAN_COLORS.ACCENT_GOLD;\n\n return (\n <group position={position}>\n {/* Ground circle marker */}\n <mesh ref={meshRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.01, 0]}>\n <circleGeometry args={[0.2, 32]} />\n <meshBasicMaterial\n color={markerColor}\n transparent\n opacity={isActive ? 0.9 : 0.6}\n side={THREE.DoubleSide}\n />\n </mesh>\n\n {/* Outer ring */}\n <mesh ref={ringRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.02, 0]}>\n <ringGeometry args={[0.2, 0.25, 32]} />\n <meshBasicMaterial\n color={markerColor}\n transparent\n opacity={isActive ? 0.7 : 0.4}\n side={THREE.DoubleSide}\n />\n </mesh>\n\n {/* Label */}\n <Html\n position={[0, 0.1, 0]}\n center\n style={{\n pointerEvents: \"none\",\n userSelect: \"none\",\n }}\n >\n <div\n style={{\n fontSize: \"12px\",\n fontWeight: \"bold\",\n color: isActive ? \"#00ffff\" : \"#ffffff\",\n textShadow: \"0 0 4px rgba(0,0,0,0.8)\",\n background: \"rgba(0,0,0,0.6)\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n }}\n >\n {label}\n </div>\n </Html>\n\n {/* Vertical beam for active marker */}\n {isActive && (\n <mesh position={[0, 0.5, 0]}>\n <cylinderGeometry args={[0.02, 0.02, 1, 8]} />\n <meshBasicMaterial\n color={KOREAN_COLORS.PRIMARY_CYAN}\n transparent\n opacity={0.4}\n />\n </mesh>\n )}\n </group>\n );\n};\n\n/**\n * FootPlacementMarkers3D Component\n * \n * Displays 3D foot placement markers on the ground for footwork drills,\n * with Korean martial arts-themed visual feedback.\n * \n * @korean 발위치표시3D\n */\nexport const FootPlacementMarkers3D: React.FC<FootPlacementMarkers3DProps> = ({\n centerPosition = [5, 0, 0],\n pattern,\n currentStep = 0,\n visible = true,\n scale = 1.0,\n animated = true,\n}) => {\n const positions = useMemo(\n () => getPatternPositions(pattern, centerPosition),\n [pattern, centerPosition]\n );\n\n if (!visible || pattern === \"none\" || positions.length === 0) {\n return null;\n }\n\n return (\n <group scale={scale}>\n {positions.map((marker, index) => (\n <FootMarker\n key={`${pattern}-${index}`}\n position={marker.position}\n label={marker.label}\n isActive={index === currentStep}\n isCompleted={index < currentStep}\n animated={animated}\n />\n ))}\n </group>\n );\n};\n\nexport default FootPlacementMarkers3D;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FootPlacementMarkers3D.js","names":[],"sources":["../../../../../src/components/screens/training/components/FootPlacementMarkers3D.tsx"],"sourcesContent":["/**\n * FootPlacementMarkers3D - 3D markers showing foot placement for footwork drills\n * \n * Renders visual indicators on the ground to guide footwork training,\n * showing target positions for Korean martial arts footwork patterns.\n * \n * @module components/screens/training/components/FootPlacementMarkers3D\n * @category Training 3D Components\n * @korean 발위치표시3D컴포넌트\n */\n\nimport { Html } from \"@react-three/drei\";\nimport { useFrame } from \"@react-three/fiber\";\nimport React, { useRef, useMemo } from \"react\";\nimport * as THREE from \"three\";\nimport { KOREAN_COLORS } from \"../../../../types/constants\";\nimport type { FootworkDrill } from \"./FootworkDrillsOverlayHtml\";\n\n/**\n * Footwork drill pattern types for 3D visualization\n * \n * Derived from FootworkDrill, excluding \"free_practice\" (which has no pattern),\n * and adding a \"none\" sentinel for cases with no active pattern.\n */\nexport type FootworkDrillPattern = \n | Exclude<FootworkDrill, \"free_practice\">\n | \"none\";\n\n/**\n * Props for FootPlacementMarkers3D component\n */\nexport interface FootPlacementMarkers3DProps {\n /** Center position for the pattern */\n readonly centerPosition?: [number, number, number];\n /** Current drill pattern to display */\n readonly pattern: FootworkDrillPattern;\n /** Current step in pattern (0-based) */\n readonly currentStep?: number;\n /** Whether markers are visible */\n readonly visible?: boolean;\n /** Scale factor for markers */\n readonly scale?: number;\n /** Whether to animate markers */\n readonly animated?: boolean;\n}\n\n/**\n * Generate footwork pattern positions\n * \n * @korean 보법패턴위치생성\n */\nfunction getPatternPositions(\n pattern: FootworkDrillPattern,\n center: [number, number, number]\n): Array<{ position: [number, number, number]; label: string }> {\n const [cx, cy, cz] = center;\n const radius = 2.0; // 2 meters radius for circular patterns\n const stepDist = 0.3; // 30cm step distance\n\n switch (pattern) {\n case \"circular_left\":\n return [\n { position: [cx + radius, cy, cz], label: \"1\" },\n { position: [cx, cy, cz - radius], label: \"2\" },\n { position: [cx - radius, cy, cz], label: \"3\" },\n { position: [cx, cy, cz + radius], label: \"4\" },\n ];\n\n case \"circular_right\":\n return [\n { position: [cx + radius, cy, cz], label: \"1\" },\n { position: [cx, cy, cz + radius], label: \"2\" },\n { position: [cx - radius, cy, cz], label: \"3\" },\n { position: [cx, cy, cz - radius], label: \"4\" },\n ];\n\n case \"pivot_combo\":\n return [\n { position: [cx, cy, cz], label: \"Start\" },\n { position: [cx - 0.5, cy, cz + 0.5], label: \"Pivot L\" },\n { position: [cx, cy, cz], label: \"Center\" },\n { position: [cx + 0.5, cy, cz + 0.5], label: \"Pivot R\" },\n ];\n\n case \"triangle_step\":\n return [\n { position: [cx, cy, cz], label: \"Start\" },\n { position: [cx, cy, cz - stepDist * 2], label: \"Forward\" },\n { position: [cx + stepDist * 1.5, cy, cz], label: \"Right\" },\n { position: [cx, cy, cz], label: \"Back\" },\n ];\n\n case \"slide_drill\":\n return [\n { position: [cx, cy, cz], label: \"Center\" },\n { position: [cx, cy, cz - stepDist], label: \"Forward\" },\n { position: [cx + stepDist, cy, cz], label: \"Right\" },\n { position: [cx, cy, cz + stepDist], label: \"Back\" },\n { position: [cx - stepDist, cy, cz], label: \"Left\" },\n ];\n\n case \"shuffle_practice\":\n return [\n { position: [cx, cy, cz], label: \"Start\" },\n { position: [cx, cy, cz - 0.15], label: \"Shuffle 1\" },\n { position: [cx, cy, cz - 0.30], label: \"Shuffle 2\" },\n { position: [cx, cy, cz - 0.45], label: \"Shuffle 3\" },\n ];\n\n case \"none\":\n default:\n return [];\n }\n}\n\n/**\n * Single foot placement marker\n */\nconst FootMarker: React.FC<{\n position: [number, number, number];\n label: string;\n isActive: boolean;\n isCompleted: boolean;\n animated: boolean;\n}> = ({ position, label, isActive, isCompleted, animated }) => {\n const meshRef = useRef<THREE.Mesh>(null);\n const ringRef = useRef<THREE.Mesh>(null);\n\n useFrame((state) => {\n if (!animated) return;\n \n if (meshRef.current && isActive) {\n const pulse = Math.sin(state.clock.elapsedTime * 3) * 0.1 + 1;\n meshRef.current.scale.setScalar(pulse);\n }\n\n if (ringRef.current && isActive) {\n const ringPulse = Math.sin(state.clock.elapsedTime * 2) * 0.2 + 1;\n ringRef.current.scale.setScalar(ringPulse);\n }\n });\n\n const markerColor = isCompleted\n ? KOREAN_COLORS.ACCENT_GREEN\n : isActive\n ? KOREAN_COLORS.PRIMARY_CYAN\n : KOREAN_COLORS.ACCENT_GOLD;\n\n return (\n <group position={position}>\n {/* Ground circle marker */}\n <mesh ref={meshRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.01, 0]}>\n <circleGeometry args={[0.2, 32]} />\n <meshBasicMaterial\n color={markerColor}\n transparent\n opacity={isActive ? 0.9 : 0.6}\n side={THREE.DoubleSide}\n />\n </mesh>\n\n {/* Outer ring */}\n <mesh ref={ringRef} rotation={[-Math.PI / 2, 0, 0]} position={[0, 0.02, 0]}>\n <ringGeometry args={[0.2, 0.25, 32]} />\n <meshBasicMaterial\n color={markerColor}\n transparent\n opacity={isActive ? 0.7 : 0.4}\n side={THREE.DoubleSide}\n />\n </mesh>\n\n {/* Label */}\n <Html\n position={[0, 0.1, 0]}\n center\n style={{\n pointerEvents: \"none\",\n userSelect: \"none\",\n }}\n >\n <div\n style={{\n fontSize: \"12px\",\n fontWeight: \"bold\",\n color: isActive ? \"#00ffff\" : \"#ffffff\",\n textShadow: \"0 0 4px rgba(0,0,0,0.8)\",\n background: \"rgba(0,0,0,0.6)\",\n padding: \"2px 6px\",\n borderRadius: \"4px\",\n }}\n >\n {label}\n </div>\n </Html>\n\n {/* Vertical beam for active marker */}\n {isActive && (\n <mesh position={[0, 0.5, 0]}>\n <cylinderGeometry args={[0.02, 0.02, 1, 8]} />\n <meshBasicMaterial\n color={KOREAN_COLORS.PRIMARY_CYAN}\n transparent\n opacity={0.4}\n />\n </mesh>\n )}\n </group>\n );\n};\n\n/**\n * FootPlacementMarkers3D Component\n * \n * Displays 3D foot placement markers on the ground for footwork drills,\n * with Korean martial arts-themed visual feedback.\n * \n * @korean 발위치표시3D\n */\nexport const FootPlacementMarkers3D: React.FC<FootPlacementMarkers3DProps> = ({\n centerPosition = [5, 0, 0],\n pattern,\n currentStep = 0,\n visible = true,\n scale = 1.0,\n animated = true,\n}) => {\n const positions = useMemo(\n () => getPatternPositions(pattern, centerPosition),\n [pattern, centerPosition]\n );\n\n if (!visible || pattern === \"none\" || positions.length === 0) {\n return null;\n }\n\n return (\n <group scale={scale}>\n {positions.map((marker, index) => (\n <FootMarker\n key={`${pattern}-${index}`}\n position={marker.position}\n label={marker.label}\n isActive={index === currentStep}\n isCompleted={index < currentStep}\n animated={animated}\n />\n ))}\n </group>\n );\n};\n\nexport default FootPlacementMarkers3D;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FootworkDrillsOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/FootworkDrillsOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAIhE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,gBAAgB,GAChB,aAAa,GACb,eAAe,GACf,aAAa,GACb,kBAAkB,GAClB,eAAe,CAAC;AAiEpB;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C,+BAA+B;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,kCAAkC;IAClC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACvD,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IACrC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IACpC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,
|
|
1
|
+
{"version":3,"file":"FootworkDrillsOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/FootworkDrillsOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAIhE;;;;GAIG;AACH,MAAM,MAAM,aAAa,GACrB,eAAe,GACf,gBAAgB,GAChB,aAAa,GACb,eAAe,GACf,aAAa,GACb,kBAAkB,GAClB,eAAe,CAAC;AAiEpB;;GAEG;AACH,MAAM,WAAW,8BAA8B;IAC7C,+BAA+B;IAC/B,QAAQ,CAAC,YAAY,EAAE,aAAa,CAAC;IACrC,kCAAkC;IAClC,QAAQ,CAAC,aAAa,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACvD,8CAA8C;IAC9C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,yEAAyE;IACzE,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IACrC,wCAAwC;IACxC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,mCAAmC;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IACpC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,yBAAyB,4DAsPpC,CAAC;AAIH,eAAe,yBAAyB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FootworkDrillsOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/FootworkDrillsOverlayHtml.tsx"],"sourcesContent":["/**\n * FootworkDrillsOverlayHtml - Training component for footwork drills\n * \n * Provides specialized footwork training exercises for Korean martial arts\n * footwork patterns (보법, Bobeop).\n * \n * @module components/screens/training/components/FootworkDrillsOverlayHtml\n * @category Training Components\n * @korean 보법훈련컴포넌트\n */\n\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\n\n/**\n * Footwork drill types for training\n * \n * @korean 보법훈련타입\n */\nexport type FootworkDrill = \n | \"circular_left\" // 원형보 좌 - Circle left around target\n | \"circular_right\" // 원형보 우 - Circle right around target\n | \"pivot_combo\" // 축족회전 - Pivot left-right combo\n | \"triangle_step\" // 삼각보법 - Triangle stepping pattern\n | \"slide_drill\" // 미끄럼보 - Four-direction slide drill\n | \"shuffle_practice\" // 섞음보 - Quick shuffle adjustments\n | \"free_practice\"; // 자유 연습 - Free practice mode\n\n/**\n * Drill information with Korean terminology\n * \n * @korean 훈련정보\n */\nconst DRILL_INFO: Record<FootworkDrill, { \n korean: string; \n english: string; \n description: string;\n pattern: string[];\n keyHints: string;\n}> = {\n circular_left: {\n korean: \"원형보 좌회전\",\n english: \"Circular Left\",\n description: \"원형보 좌측 | Circle stepping left\",\n pattern: [\"Ctrl+A\", \"Ctrl+A\", \"Ctrl+A\", \"Ctrl+A\"],\n keyHints: \"Hold Ctrl+A to circle left\",\n },\n circular_right: {\n korean: \"원형보 우회전\",\n english: \"Circular Right\",\n description: \"원형보 우측 | Circle stepping right\",\n pattern: [\"Ctrl+D\", \"Ctrl+D\", \"Ctrl+D\", \"Ctrl+D\"],\n keyHints: \"Hold Ctrl+D to circle right\",\n },\n pivot_combo: {\n korean: \"축족회전 연속\",\n english: \"Pivot Combo\",\n description: \"좌우 연속 회전 | Continuous pivot rotations\",\n pattern: [\"Shift+Ctrl+A\", \"Shift+Ctrl+D\", \"Shift+Ctrl+A\", \"Shift+Ctrl+D\"],\n keyHints: \"Alternate Shift+Ctrl+A/D\",\n },\n triangle_step: {\n korean: \"삼각보법\",\n english: \"Triangle Step\",\n description: \"삼각형 발놀림 | Triangle footwork pattern\",\n pattern: [\"Ctrl+W\", \"Shift+Ctrl+D\", \"Ctrl+S\", \"Shift+Ctrl+A\"],\n keyHints: \"Forward → Pivot → Back → Pivot\",\n },\n slide_drill: {\n korean: \"미끄럼보 사방\",\n english: \"Slide Drill\",\n description: \"사방 미끄럼 | Four-direction slides\",\n pattern: [\"Ctrl+W\", \"Alt+D\", \"Ctrl+S\", \"Alt+A\"],\n keyHints: \"Slide in all four directions\",\n },\n shuffle_practice: {\n korean: \"섞음보 연습\",\n english: \"Shuffle Practice\",\n description: \"빠른 조정 | Quick micro-adjustments\",\n pattern: [\"Shift+Ctrl+W\", \"Shift+Ctrl+W\", \"Shift+Ctrl+W\"],\n keyHints: \"Rapid Shift+Ctrl+W/S\",\n },\n free_practice: {\n korean: \"자유 연습\",\n english: \"Free Practice\",\n description: \"자유 보법 | Free footwork exploration\",\n pattern: [],\n keyHints: \"Use any footwork combination\",\n },\n};\n\n/**\n * Props for FootworkDrillsOverlayHtml component\n */\nexport interface FootworkDrillsOverlayHtmlProps {\n /** Currently selected drill */\n readonly currentDrill: FootworkDrill;\n /** Callback when drill changes */\n readonly onDrillChange: (drill: FootworkDrill) => void;\n /** Current step in drill pattern (0-based) */\n readonly currentStep: number;\n /** Callback when drill step completes (optional, not yet implemented) */\n readonly onStepComplete?: () => void;\n /** Whether drill is currently active */\n readonly isActive: boolean;\n /** Callback to start/stop drill */\n readonly onToggleActive: () => void;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n}\n\n/**\n * FootworkDrillsOverlayHtml Component\n * \n * Provides UI for footwork training drills with step-by-step guidance\n * and Korean martial arts terminology.\n * \n * @korean 보법훈련UI컴포넌트\n */\nexport const FootworkDrillsOverlayHtml = React.memo<FootworkDrillsOverlayHtmlProps>(\n ({\n currentDrill,\n onDrillChange,\n currentStep,\n // onStepComplete, // TODO: Use this for drill pattern validation\n isActive,\n onToggleActive,\n isMobile,\n }) => {\n const drillInfo = DRILL_INFO[currentDrill];\n const [showInstructions, setShowInstructions] = useState(true);\n\n // Auto-hide instructions after 5 seconds when drill is active\n useEffect(() => {\n if (isActive && showInstructions) {\n const timer = setTimeout(() => setShowInstructions(false), 5000);\n return () => clearTimeout(timer);\n }\n }, [isActive, showInstructions]);\n\n const handleDrillSelect = useCallback((drill: FootworkDrill) => {\n onDrillChange(drill);\n setShowInstructions(true);\n }, [onDrillChange]);\n\n const panelWidth = isMobile ? 280 : 340;\n const buttonFontSize = isMobile ? \"10px\" : \"11px\";\n const titleFontSize = isMobile ? \"13px\" : \"15px\";\n\n return (\n <div\n style={{\n width: `${panelWidth}px`,\n background: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.95),\n border: `2px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.9)}`,\n borderRadius: \"12px\",\n padding: isMobile ? \"10px\" : \"12px\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n boxShadow: `0 4px 20px ${hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.5)}`,\n }}\n data-testid=\"footwork-drills-html\"\n >\n {/* Header */}\n <div style={{ marginBottom: \"12px\", textAlign: \"center\" }}>\n <div\n style={{\n fontSize: titleFontSize,\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 1),\n marginBottom: \"4px\",\n }}\n >\n 보법 훈련 | Footwork Drills\n </div>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n color: hexToRgbaString(KOREAN_COLORS.TEXT_SECONDARY, 1),\n }}\n >\n {drillInfo.korean} | {drillInfo.english}\n </div>\n </div>\n\n {/* Drill Selection Grid */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: isMobile ? \"1fr 1fr\" : \"1fr 1fr 1fr\",\n gap: \"6px\",\n marginBottom: \"12px\",\n }}\n >\n {(Object.keys(DRILL_INFO) as FootworkDrill[]).map((drill) => (\n <button\n key={drill}\n onClick={() => handleDrillSelect(drill)}\n style={{\n padding: isMobile ? \"6px 4px\" : \"8px 6px\",\n fontSize: buttonFontSize,\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: currentDrill === drill ? \"bold\" : \"normal\",\n background: \n currentDrill === drill\n ? hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.9)\n : hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_MEDIUM, 0.8),\n color: \n currentDrill === drill\n ? hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 1)\n : hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n border: `1px solid ${hexToRgbaString(\n currentDrill === drill\n ? KOREAN_COLORS.ACCENT_GOLD\n : KOREAN_COLORS.UI_BORDER,\n 0.6\n )}`,\n borderRadius: \"6px\",\n cursor: \"pointer\",\n transition: \"all 0.2s ease\",\n textAlign: \"center\",\n lineHeight: 1.2,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n }}\n >\n {DRILL_INFO[drill].korean.split(\" \")[0]}\n </button>\n ))}\n </div>\n\n {/* Drill Description */}\n <div\n style={{\n padding: \"8px\",\n background: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_MEDIUM, 0.6),\n borderRadius: \"6px\",\n marginBottom: \"10px\",\n fontSize: isMobile ? \"10px\" : \"11px\",\n textAlign: \"center\",\n }}\n >\n {drillInfo.description}\n </div>\n\n {/* Pattern Steps (if drill has pattern) */}\n {drillInfo.pattern.length > 0 && (\n <div style={{ marginBottom: \"10px\" }}>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 1),\n marginBottom: \"6px\",\n textAlign: \"center\",\n }}\n >\n Pattern Steps:\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n gap: \"4px\",\n flexWrap: \"wrap\",\n }}\n >\n {drillInfo.pattern.map((step, index) => (\n <div\n key={index}\n style={{\n padding: \"4px 8px\",\n fontSize: isMobile ? \"9px\" : \"10px\",\n fontFamily: FONT_FAMILY.KOREAN,\n background: \n isActive && index === currentStep\n ? hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.9)\n : index < currentStep\n ? hexToRgbaString(KOREAN_COLORS.ACCENT_GREEN, 0.6)\n : hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_MEDIUM, 0.7),\n color: \n isActive && index === currentStep\n ? hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 1)\n : hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n border: `1px solid ${hexToRgbaString(\n isActive && index === currentStep\n ? KOREAN_COLORS.PRIMARY_CYAN\n : KOREAN_COLORS.UI_BORDER,\n 0.8\n )}`,\n borderRadius: \"4px\",\n fontWeight: isActive && index === currentStep ? \"bold\" : \"normal\",\n }}\n >\n {index + 1}. {step}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Key Hints */}\n {showInstructions && (\n <div\n style={{\n padding: \"8px\",\n background: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.2),\n border: `1px solid ${hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.6)}`,\n borderRadius: \"6px\",\n marginBottom: \"10px\",\n fontSize: isMobile ? \"9px\" : \"10px\",\n textAlign: \"center\",\n color: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 1),\n }}\n >\n 💡 {drillInfo.keyHints}\n </div>\n )}\n\n {/* Start/Stop Button */}\n <button\n onClick={onToggleActive}\n style={{\n width: \"100%\",\n padding: isMobile ? \"10px\" : \"12px\",\n fontSize: isMobile ? \"12px\" : \"14px\",\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n background: isActive\n ? hexToRgbaString(KOREAN_COLORS.ACCENT_RED, 0.9)\n : hexToRgbaString(KOREAN_COLORS.ACCENT_GREEN, 0.9),\n color: hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n transition: \"all 0.2s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n e.currentTarget.style.boxShadow = `0 0 20px ${hexToRgbaString(\n isActive ? KOREAN_COLORS.ACCENT_RED : KOREAN_COLORS.ACCENT_GREEN,\n 0.8\n )}`;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n e.currentTarget.style.boxShadow = \"none\";\n }}\n >\n {isActive ? \"훈련 중지 | Stop Drill\" : \"훈련 시작 | Start Drill\"}\n </button>\n </div>\n );\n},\n(prevProps, nextProps) => {\n // Re-render when drill state, mobile state, or callbacks change\n // Including callback props prevents stale closures when parent provides\n // new functions that capture updated state.\n return (\n prevProps.currentDrill === nextProps.currentDrill &&\n prevProps.currentStep === nextProps.currentStep &&\n prevProps.isActive === nextProps.isActive &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.onDrillChange === nextProps.onDrillChange &&\n prevProps.onToggleActive === nextProps.onToggleActive\n );\n});\n\nFootworkDrillsOverlayHtml.displayName = \"FootworkDrillsOverlayHtml\";\n\nexport default FootworkDrillsOverlayHtml;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FootworkDrillsOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/FootworkDrillsOverlayHtml.tsx"],"sourcesContent":["/**\n * FootworkDrillsOverlayHtml - Training component for footwork drills\n * \n * Provides specialized footwork training exercises for Korean martial arts\n * footwork patterns (보법, Bobeop).\n * \n * @module components/screens/training/components/FootworkDrillsOverlayHtml\n * @category Training Components\n * @korean 보법훈련컴포넌트\n */\n\nimport React, { useCallback, useEffect, useState } from \"react\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\n\n/**\n * Footwork drill types for training\n * \n * @korean 보법훈련타입\n */\nexport type FootworkDrill = \n | \"circular_left\" // 원형보 좌 - Circle left around target\n | \"circular_right\" // 원형보 우 - Circle right around target\n | \"pivot_combo\" // 축족회전 - Pivot left-right combo\n | \"triangle_step\" // 삼각보법 - Triangle stepping pattern\n | \"slide_drill\" // 미끄럼보 - Four-direction slide drill\n | \"shuffle_practice\" // 섞음보 - Quick shuffle adjustments\n | \"free_practice\"; // 자유 연습 - Free practice mode\n\n/**\n * Drill information with Korean terminology\n * \n * @korean 훈련정보\n */\nconst DRILL_INFO: Record<FootworkDrill, { \n korean: string; \n english: string; \n description: string;\n pattern: string[];\n keyHints: string;\n}> = {\n circular_left: {\n korean: \"원형보 좌회전\",\n english: \"Circular Left\",\n description: \"원형보 좌측 | Circle stepping left\",\n pattern: [\"Ctrl+A\", \"Ctrl+A\", \"Ctrl+A\", \"Ctrl+A\"],\n keyHints: \"Hold Ctrl+A to circle left\",\n },\n circular_right: {\n korean: \"원형보 우회전\",\n english: \"Circular Right\",\n description: \"원형보 우측 | Circle stepping right\",\n pattern: [\"Ctrl+D\", \"Ctrl+D\", \"Ctrl+D\", \"Ctrl+D\"],\n keyHints: \"Hold Ctrl+D to circle right\",\n },\n pivot_combo: {\n korean: \"축족회전 연속\",\n english: \"Pivot Combo\",\n description: \"좌우 연속 회전 | Continuous pivot rotations\",\n pattern: [\"Shift+Ctrl+A\", \"Shift+Ctrl+D\", \"Shift+Ctrl+A\", \"Shift+Ctrl+D\"],\n keyHints: \"Alternate Shift+Ctrl+A/D\",\n },\n triangle_step: {\n korean: \"삼각보법\",\n english: \"Triangle Step\",\n description: \"삼각형 발놀림 | Triangle footwork pattern\",\n pattern: [\"Ctrl+W\", \"Shift+Ctrl+D\", \"Ctrl+S\", \"Shift+Ctrl+A\"],\n keyHints: \"Forward → Pivot → Back → Pivot\",\n },\n slide_drill: {\n korean: \"미끄럼보 사방\",\n english: \"Slide Drill\",\n description: \"사방 미끄럼 | Four-direction slides\",\n pattern: [\"Ctrl+W\", \"Alt+D\", \"Ctrl+S\", \"Alt+A\"],\n keyHints: \"Slide in all four directions\",\n },\n shuffle_practice: {\n korean: \"섞음보 연습\",\n english: \"Shuffle Practice\",\n description: \"빠른 조정 | Quick micro-adjustments\",\n pattern: [\"Shift+Ctrl+W\", \"Shift+Ctrl+W\", \"Shift+Ctrl+W\"],\n keyHints: \"Rapid Shift+Ctrl+W/S\",\n },\n free_practice: {\n korean: \"자유 연습\",\n english: \"Free Practice\",\n description: \"자유 보법 | Free footwork exploration\",\n pattern: [],\n keyHints: \"Use any footwork combination\",\n },\n};\n\n/**\n * Props for FootworkDrillsOverlayHtml component\n */\nexport interface FootworkDrillsOverlayHtmlProps {\n /** Currently selected drill */\n readonly currentDrill: FootworkDrill;\n /** Callback when drill changes */\n readonly onDrillChange: (drill: FootworkDrill) => void;\n /** Current step in drill pattern (0-based) */\n readonly currentStep: number;\n /** Callback when drill step completes (optional, not yet implemented) */\n readonly onStepComplete?: () => void;\n /** Whether drill is currently active */\n readonly isActive: boolean;\n /** Callback to start/stop drill */\n readonly onToggleActive: () => void;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n}\n\n/**\n * FootworkDrillsOverlayHtml Component\n * \n * Provides UI for footwork training drills with step-by-step guidance\n * and Korean martial arts terminology.\n * \n * @korean 보법훈련UI컴포넌트\n */\nexport const FootworkDrillsOverlayHtml = React.memo<FootworkDrillsOverlayHtmlProps>(\n ({\n currentDrill,\n onDrillChange,\n currentStep,\n isActive,\n onToggleActive,\n isMobile,\n }) => {\n const drillInfo = DRILL_INFO[currentDrill];\n const [showInstructions, setShowInstructions] = useState(true);\n\n useEffect(() => {\n if (isActive && showInstructions) {\n const timer = setTimeout(() => setShowInstructions(false), 5000);\n return () => clearTimeout(timer);\n }\n }, [isActive, showInstructions]);\n\n const handleDrillSelect = useCallback((drill: FootworkDrill) => {\n onDrillChange(drill);\n setShowInstructions(true);\n }, [onDrillChange]);\n\n const panelWidth = isMobile ? 280 : 340;\n const buttonFontSize = isMobile ? \"10px\" : \"11px\";\n const titleFontSize = isMobile ? \"13px\" : \"15px\";\n\n return (\n <div\n style={{\n width: `${panelWidth}px`,\n background: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.95),\n border: `2px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.9)}`,\n borderRadius: \"12px\",\n padding: isMobile ? \"10px\" : \"12px\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n boxShadow: `0 4px 20px ${hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.5)}`,\n }}\n data-testid=\"footwork-drills-html\"\n >\n {/* Header */}\n <div style={{ marginBottom: \"12px\", textAlign: \"center\" }}>\n <div\n style={{\n fontSize: titleFontSize,\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 1),\n marginBottom: \"4px\",\n }}\n >\n 보법 훈련 | Footwork Drills\n </div>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n color: hexToRgbaString(KOREAN_COLORS.TEXT_SECONDARY, 1),\n }}\n >\n {drillInfo.korean} | {drillInfo.english}\n </div>\n </div>\n\n {/* Drill Selection Grid */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: isMobile ? \"1fr 1fr\" : \"1fr 1fr 1fr\",\n gap: \"6px\",\n marginBottom: \"12px\",\n }}\n >\n {(Object.keys(DRILL_INFO) as FootworkDrill[]).map((drill) => (\n <button\n key={drill}\n onClick={() => handleDrillSelect(drill)}\n style={{\n padding: isMobile ? \"6px 4px\" : \"8px 6px\",\n fontSize: buttonFontSize,\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: currentDrill === drill ? \"bold\" : \"normal\",\n background: \n currentDrill === drill\n ? hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.9)\n : hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_MEDIUM, 0.8),\n color: \n currentDrill === drill\n ? hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 1)\n : hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n border: `1px solid ${hexToRgbaString(\n currentDrill === drill\n ? KOREAN_COLORS.ACCENT_GOLD\n : KOREAN_COLORS.UI_BORDER,\n 0.6\n )}`,\n borderRadius: \"6px\",\n cursor: \"pointer\",\n transition: \"all 0.2s ease\",\n textAlign: \"center\",\n lineHeight: 1.2,\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n }}\n >\n {DRILL_INFO[drill].korean.split(\" \")[0]}\n </button>\n ))}\n </div>\n\n {/* Drill Description */}\n <div\n style={{\n padding: \"8px\",\n background: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_MEDIUM, 0.6),\n borderRadius: \"6px\",\n marginBottom: \"10px\",\n fontSize: isMobile ? \"10px\" : \"11px\",\n textAlign: \"center\",\n }}\n >\n {drillInfo.description}\n </div>\n\n {/* Pattern Steps (if drill has pattern) */}\n {drillInfo.pattern.length > 0 && (\n <div style={{ marginBottom: \"10px\" }}>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 1),\n marginBottom: \"6px\",\n textAlign: \"center\",\n }}\n >\n Pattern Steps:\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"center\",\n gap: \"4px\",\n flexWrap: \"wrap\",\n }}\n >\n {drillInfo.pattern.map((step, index) => (\n <div\n key={index}\n style={{\n padding: \"4px 8px\",\n fontSize: isMobile ? \"9px\" : \"10px\",\n fontFamily: FONT_FAMILY.KOREAN,\n background: \n isActive && index === currentStep\n ? hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.9)\n : index < currentStep\n ? hexToRgbaString(KOREAN_COLORS.ACCENT_GREEN, 0.6)\n : hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_MEDIUM, 0.7),\n color: \n isActive && index === currentStep\n ? hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 1)\n : hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n border: `1px solid ${hexToRgbaString(\n isActive && index === currentStep\n ? KOREAN_COLORS.PRIMARY_CYAN\n : KOREAN_COLORS.UI_BORDER,\n 0.8\n )}`,\n borderRadius: \"4px\",\n fontWeight: isActive && index === currentStep ? \"bold\" : \"normal\",\n }}\n >\n {index + 1}. {step}\n </div>\n ))}\n </div>\n </div>\n )}\n\n {/* Key Hints */}\n {showInstructions && (\n <div\n style={{\n padding: \"8px\",\n background: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.2),\n border: `1px solid ${hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.6)}`,\n borderRadius: \"6px\",\n marginBottom: \"10px\",\n fontSize: isMobile ? \"9px\" : \"10px\",\n textAlign: \"center\",\n color: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 1),\n }}\n >\n 💡 {drillInfo.keyHints}\n </div>\n )}\n\n {/* Start/Stop Button */}\n <button\n onClick={onToggleActive}\n style={{\n width: \"100%\",\n padding: isMobile ? \"10px\" : \"12px\",\n fontSize: isMobile ? \"12px\" : \"14px\",\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n background: isActive\n ? hexToRgbaString(KOREAN_COLORS.ACCENT_RED, 0.9)\n : hexToRgbaString(KOREAN_COLORS.ACCENT_GREEN, 0.9),\n color: hexToRgbaString(KOREAN_COLORS.TEXT_PRIMARY, 1),\n border: \"none\",\n borderRadius: \"8px\",\n cursor: \"pointer\",\n transition: \"all 0.2s ease\",\n }}\n onMouseEnter={(e) => {\n e.currentTarget.style.transform = \"scale(1.05)\";\n e.currentTarget.style.boxShadow = `0 0 20px ${hexToRgbaString(\n isActive ? KOREAN_COLORS.ACCENT_RED : KOREAN_COLORS.ACCENT_GREEN,\n 0.8\n )}`;\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.transform = \"scale(1)\";\n e.currentTarget.style.boxShadow = \"none\";\n }}\n >\n {isActive ? \"훈련 중지 | Stop Drill\" : \"훈련 시작 | Start Drill\"}\n </button>\n </div>\n );\n},\n(prevProps, nextProps) => {\n return (\n prevProps.currentDrill === nextProps.currentDrill &&\n prevProps.currentStep === nextProps.currentStep &&\n prevProps.isActive === nextProps.isActive &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.onDrillChange === nextProps.onDrillChange &&\n prevProps.onToggleActive === nextProps.onToggleActive\n );\n});\n\nFootworkDrillsOverlayHtml.displayName = \"FootworkDrillsOverlayHtml\";\n\nexport default FootworkDrillsOverlayHtml;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HitFeedbackEffect3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/HitFeedbackEffect3D.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC9C,mCAAmC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;
|
|
1
|
+
{"version":3,"file":"HitFeedbackEffect3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/HitFeedbackEffect3D.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,yCAAyC;IACzC,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC9C,mCAAmC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,gCAAgC;IAChC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,qCAAqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAyND;;;GAGG;AACH,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAmGlE,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HitFeedbackEffect3D.js","names":[],"sources":["../../../../../src/components/screens/training/components/HitFeedbackEffect3D.tsx"],"sourcesContent":["/**\n * HitFeedbackEffect3D - Visual hit confirmation with damage numbers\n *\n * Provides particle effects, color flashes, and floating damage numbers\n * for training hit feedback\n */\n\nimport { Html } from \"@react-three/drei\";\nimport { useFrame } from \"@react-three/fiber\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport * as THREE from \"three\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { ThreeObjectPools } from \"../../../../utils/threeObjectPool\";\n\n/**\n * Props for HitFeedbackEffect3D component\n */\nexport interface HitFeedbackEffect3DProps {\n /** 3D position where hit occurred */\n readonly position: [number, number, number];\n /** Type of hit (affects visual style) */\n readonly type: \"success\" | \"perfect\" | \"miss\";\n /** Damage dealt (if applicable) */\n readonly damage?: number;\n /** Whether effect is visible */\n readonly visible?: boolean;\n /** Callback when effect completes */\n readonly onComplete?: () => void;\n /** Duration in milliseconds */\n readonly duration?: number;\n /** Whether on mobile device */\n readonly isMobile?: boolean;\n}\n\n/**\n * Impact particle system\n */\nconst ImpactParticles: React.FC<{\n position: [number, number, number];\n color: number;\n count: number;\n}> = ({ position, color, count }) => {\n const pointsRef = useRef<THREE.Points>(null);\n\n // Store velocities in a ref that persists across renders\n const velocitiesRef = useRef<Float32Array | null>(null);\n\n // Store initial position for seeded random - use useState to capture at mount\n // Note: This intentionally ignores position prop changes to maintain consistent\n // particle behavior throughout the effect's lifetime. To update particles when\n // position changes, add a key prop to the parent component to force remount.\n const [initialPosition] = useState(position);\n\n // Initialize particle positions and velocities - use seed based on initial position\n const { positions, velocities } = useMemo(() => {\n const pos = new Float32Array(count * 3);\n const vel = new Float32Array(count * 3);\n\n // Use initial position as seed for deterministic but varying particles\n const seed =\n initialPosition[0] + initialPosition[1] * 10 + initialPosition[2] * 100;\n\n // Simple seeded random using position\n // Large multiplier (10000) ensures sufficient entropy for randomness while keeping values deterministic\n function seededRandom(index: number): number {\n const x = Math.sin(seed + index) * 10000;\n return x - Math.floor(x);\n }\n\n // Use pooled vector for velocity calculations to reduce allocations\n // Pool strategy: Acquire once, reuse for all particles, release\n const tempVel = ThreeObjectPools.vector3.acquire();\n \n try {\n for (let i = 0; i < count; i++) {\n const i3 = i * 3;\n // Start at center\n pos[i3] = 0;\n pos[i3 + 1] = 0;\n pos[i3 + 2] = 0;\n\n // Random outward velocities using seeded random\n const theta = seededRandom(i * 3) * Math.PI * 2;\n const phi = seededRandom(i * 3 + 1) * Math.PI;\n const speed = 0.5 + seededRandom(i * 3 + 2) * 1.5;\n\n tempVel.set(\n Math.sin(phi) * Math.cos(theta),\n Math.cos(phi),\n Math.sin(phi) * Math.sin(theta)\n );\n tempVel.normalize().multiplyScalar(speed);\n \n // Add upward bias\n vel[i3] = tempVel.x;\n vel[i3 + 1] = tempVel.y + 1;\n vel[i3 + 2] = tempVel.z;\n }\n } finally {\n // Always release pooled vector\n ThreeObjectPools.vector3.release(tempVel);\n }\n\n return { positions: pos, velocities: vel };\n }, [count, initialPosition]); // initialPosition is captured at mount and won't change\n\n // Update velocities ref in useEffect to avoid ref access during render\n useEffect(() => {\n velocitiesRef.current = velocities;\n }, [velocities]);\n\n // Animate particles\n useFrame((_, delta) => {\n if (!pointsRef.current || !velocitiesRef.current) return;\n\n const attr = pointsRef.current.geometry.attributes.position;\n const array = attr.array as Float32Array;\n const vel = velocitiesRef.current;\n\n for (let i = 0; i < count; i++) {\n const i3 = i * 3;\n\n // Update positions\n array[i3] += vel[i3] * delta * 10;\n array[i3 + 1] += vel[i3 + 1] * delta * 10;\n array[i3 + 2] += vel[i3 + 2] * delta * 10;\n\n // Apply gravity\n // Note: Intentionally mutating velocitiesRef.current (Float32Array) for performance.\n // This is safe and won't trigger React re-renders since it's a ref.\n vel[i3 + 1] -= 9.8 * delta;\n\n // Fade out particles that go too far\n if (array[i3 + 1] < -2) {\n array[i3 + 1] = -2;\n }\n }\n\n attr.needsUpdate = true;\n });\n\n return (\n <points ref={pointsRef} position={position}>\n <bufferGeometry>\n <bufferAttribute attach=\"attributes-position\" args={[positions, 3]} />\n </bufferGeometry>\n <pointsMaterial\n size={0.08}\n color={color}\n transparent\n opacity={1.0}\n sizeAttenuation\n depthWrite={false}\n blending={THREE.AdditiveBlending}\n />\n </points>\n );\n};\n\n/**\n * Expanding ring effect\n */\nconst RingEffect: React.FC<{\n position: [number, number, number];\n color: number;\n maxRadius: number;\n}> = ({ position, color, maxRadius }) => {\n const meshRef = useRef<THREE.Mesh>(null);\n const startTime = useRef<number>(0);\n\n // Initialize start time on mount using useEffect\n useEffect(() => {\n if (startTime.current === 0) {\n startTime.current = Date.now();\n }\n }, []);\n\n useFrame(() => {\n if (!meshRef.current) return;\n\n const elapsed = (Date.now() - startTime.current) / 1000;\n const progress = Math.min(elapsed / 0.5, 1); // 0.5 second duration\n\n // Expand ring - use pooled vector for scale to avoid allocation\n const radius = progress * maxRadius;\n const tempScale = ThreeObjectPools.vector3.acquire();\n try {\n tempScale.setScalar(radius);\n meshRef.current.scale.copy(tempScale);\n } finally {\n ThreeObjectPools.vector3.release(tempScale);\n }\n\n // Fade out\n const material = meshRef.current.material as THREE.MeshBasicMaterial;\n material.opacity = 1 - progress;\n });\n\n return (\n <mesh ref={meshRef} position={position} rotation={[Math.PI / 2, 0, 0]}>\n <ringGeometry args={[0.9, 1.0, 32]} />\n <meshBasicMaterial\n color={color}\n transparent\n opacity={1}\n side={THREE.DoubleSide}\n />\n </mesh>\n );\n};\n\n/**\n * Floating damage number\n */\nconst DamageNumber: React.FC<{\n position: [number, number, number];\n damage: number;\n type: \"perfect\" | \"normal\" | \"miss\";\n isMobile: boolean;\n onComplete: () => void;\n}> = ({ position, damage, type, isMobile, onComplete }) => {\n const [offset, setOffset] = useState(0);\n const [opacity, setOpacity] = useState(1);\n const startTime = useRef<number>(0);\n const completedRef = useRef(false);\n\n // Initialize start time on mount using useEffect\n useEffect(() => {\n if (startTime.current === 0) {\n startTime.current = Date.now();\n }\n }, []);\n\n useFrame(() => {\n const elapsed = (Date.now() - startTime.current) / 1000;\n const progress = Math.min(elapsed / 1.5, 1); // 1.5 second duration\n\n // Float upward\n setOffset(progress * 1);\n\n // Fade out\n setOpacity(1 - progress);\n\n // Complete when done (only once)\n if (progress >= 1 && !completedRef.current && onComplete) {\n completedRef.current = true;\n onComplete();\n }\n });\n\n const color =\n type === \"perfect\" ? \"#ffd700\" : type === \"normal\" ? \"#00ffff\" : \"#ff4444\";\n const text = type === \"miss\" ? \"빗나감 | MISS\" : `${damage}`; // Korean: 빗나감 = miss/deflected\n\n return (\n <Html\n position={[position[0], position[1] + offset, position[2]]}\n center\n distanceFactor={10}\n style={{ pointerEvents: \"none\", opacity }}\n >\n <div\n style={{\n fontSize: isMobile ? \"20px\" : \"28px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color,\n textShadow: \"0 0 10px rgba(0, 0, 0, 0.8)\",\n whiteSpace: \"nowrap\",\n }}\n data-testid=\"damage-number\"\n >\n {text}\n </div>\n </Html>\n );\n};\n\n/**\n * HitFeedbackEffect3D Component\n * Main hit feedback visualization\n */\nexport const HitFeedbackEffect3D: React.FC<HitFeedbackEffect3DProps> = ({\n position,\n type,\n damage,\n visible = true,\n onComplete,\n duration = 1500,\n isMobile = false,\n}) => {\n const [showEffect, setShowEffect] = useState(visible);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n // Get colors based on hit type\n const effectColor = useMemo(() => {\n switch (type) {\n case \"perfect\":\n return KOREAN_COLORS.ACCENT_GOLD;\n case \"success\":\n return KOREAN_COLORS.PRIMARY_CYAN;\n case \"miss\":\n return KOREAN_COLORS.TEXT_SECONDARY;\n default:\n return KOREAN_COLORS.PRIMARY_CYAN;\n }\n }, [type]);\n\n // Reduce particle counts on mobile to avoid frame drops\n const particleCount = useMemo(() => {\n const isPerfect = type === \"perfect\";\n const isSuccess = type === \"success\";\n\n if (isMobile) {\n return isPerfect ? 30 : isSuccess ? 20 : 10;\n }\n\n // Higher fidelity on non-mobile devices\n return isPerfect ? 80 : isSuccess ? 50 : 25;\n }, [type, isMobile]);\n const ringRadius = type === \"perfect\" ? 1.5 : 1.0;\n\n // Track completion to prevent multiple calls\n const completedRef = useRef(false);\n\n // Handle effect completion (only once)\n const handleComplete = useCallback(() => {\n if (completedRef.current) return;\n completedRef.current = true;\n setShowEffect(false);\n onComplete?.();\n }, [onComplete]);\n\n // Auto-complete after duration\n useEffect(() => {\n if (visible && showEffect) {\n timeoutRef.current = setTimeout(handleComplete, duration);\n }\n\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [visible, showEffect, duration, handleComplete]);\n\n if (!showEffect) return null;\n\n return (\n <group name={`hit-feedback-${type}`}>\n {/* Particle burst */}\n <ImpactParticles\n position={position}\n color={effectColor}\n count={particleCount}\n />\n\n {/* Expanding ring */}\n <RingEffect\n position={position}\n color={effectColor}\n maxRadius={ringRadius}\n />\n\n {/* Floating damage number */}\n {damage !== undefined && type !== \"miss\" && (\n <DamageNumber\n position={position}\n damage={damage}\n type={type === \"perfect\" ? \"perfect\" : \"normal\"}\n isMobile={isMobile}\n onComplete={handleComplete}\n />\n )}\n\n {/* Miss indicator */}\n {type === \"miss\" && (\n <DamageNumber\n position={position}\n damage={0}\n type=\"miss\"\n isMobile={isMobile}\n onComplete={handleComplete}\n />\n )}\n </group>\n );\n};\n\nexport default HitFeedbackEffect3D;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HitFeedbackEffect3D.js","names":[],"sources":["../../../../../src/components/screens/training/components/HitFeedbackEffect3D.tsx"],"sourcesContent":["/**\n * HitFeedbackEffect3D - Visual hit confirmation with damage numbers\n *\n * Provides particle effects, color flashes, and floating damage numbers\n * for training hit feedback\n */\n\nimport { Html } from \"@react-three/drei\";\nimport { useFrame } from \"@react-three/fiber\";\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport * as THREE from \"three\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { ThreeObjectPools } from \"../../../../utils/threeObjectPool\";\n\n/**\n * Props for HitFeedbackEffect3D component\n */\nexport interface HitFeedbackEffect3DProps {\n /** 3D position where hit occurred */\n readonly position: [number, number, number];\n /** Type of hit (affects visual style) */\n readonly type: \"success\" | \"perfect\" | \"miss\";\n /** Damage dealt (if applicable) */\n readonly damage?: number;\n /** Whether effect is visible */\n readonly visible?: boolean;\n /** Callback when effect completes */\n readonly onComplete?: () => void;\n /** Duration in milliseconds */\n readonly duration?: number;\n /** Whether on mobile device */\n readonly isMobile?: boolean;\n}\n\n/**\n * Impact particle system\n */\nconst ImpactParticles: React.FC<{\n position: [number, number, number];\n color: number;\n count: number;\n}> = ({ position, color, count }) => {\n const pointsRef = useRef<THREE.Points>(null);\n\n const velocitiesRef = useRef<Float32Array | null>(null);\n\n const [initialPosition] = useState(position);\n\n const { positions, velocities } = useMemo(() => {\n const pos = new Float32Array(count * 3);\n const vel = new Float32Array(count * 3);\n\n const seed =\n initialPosition[0] + initialPosition[1] * 10 + initialPosition[2] * 100;\n\n function seededRandom(index: number): number {\n const x = Math.sin(seed + index) * 10000;\n return x - Math.floor(x);\n }\n\n const tempVel = ThreeObjectPools.vector3.acquire();\n \n try {\n for (let i = 0; i < count; i++) {\n const i3 = i * 3;\n pos[i3] = 0;\n pos[i3 + 1] = 0;\n pos[i3 + 2] = 0;\n\n const theta = seededRandom(i * 3) * Math.PI * 2;\n const phi = seededRandom(i * 3 + 1) * Math.PI;\n const speed = 0.5 + seededRandom(i * 3 + 2) * 1.5;\n\n tempVel.set(\n Math.sin(phi) * Math.cos(theta),\n Math.cos(phi),\n Math.sin(phi) * Math.sin(theta)\n );\n tempVel.normalize().multiplyScalar(speed);\n \n vel[i3] = tempVel.x;\n vel[i3 + 1] = tempVel.y + 1;\n vel[i3 + 2] = tempVel.z;\n }\n } finally {\n ThreeObjectPools.vector3.release(tempVel);\n }\n\n return { positions: pos, velocities: vel };\n }, [count, initialPosition]); // initialPosition is captured at mount and won't change\n\n useEffect(() => {\n velocitiesRef.current = velocities;\n }, [velocities]);\n\n useFrame((_, delta) => {\n if (!pointsRef.current || !velocitiesRef.current) return;\n\n const attr = pointsRef.current.geometry.attributes.position;\n const array = attr.array as Float32Array;\n const vel = velocitiesRef.current;\n\n for (let i = 0; i < count; i++) {\n const i3 = i * 3;\n\n array[i3] += vel[i3] * delta * 10;\n array[i3 + 1] += vel[i3 + 1] * delta * 10;\n array[i3 + 2] += vel[i3 + 2] * delta * 10;\n\n vel[i3 + 1] -= 9.8 * delta;\n\n if (array[i3 + 1] < -2) {\n array[i3 + 1] = -2;\n }\n }\n\n attr.needsUpdate = true;\n });\n\n return (\n <points ref={pointsRef} position={position}>\n <bufferGeometry>\n <bufferAttribute attach=\"attributes-position\" args={[positions, 3]} />\n </bufferGeometry>\n <pointsMaterial\n size={0.08}\n color={color}\n transparent\n opacity={1.0}\n sizeAttenuation\n depthWrite={false}\n blending={THREE.AdditiveBlending}\n />\n </points>\n );\n};\n\n/**\n * Expanding ring effect\n */\nconst RingEffect: React.FC<{\n position: [number, number, number];\n color: number;\n maxRadius: number;\n}> = ({ position, color, maxRadius }) => {\n const meshRef = useRef<THREE.Mesh>(null);\n const startTime = useRef<number>(0);\n\n useEffect(() => {\n if (startTime.current === 0) {\n startTime.current = Date.now();\n }\n }, []);\n\n useFrame(() => {\n if (!meshRef.current) return;\n\n const elapsed = (Date.now() - startTime.current) / 1000;\n const progress = Math.min(elapsed / 0.5, 1); // 0.5 second duration\n\n const radius = progress * maxRadius;\n const tempScale = ThreeObjectPools.vector3.acquire();\n try {\n tempScale.setScalar(radius);\n meshRef.current.scale.copy(tempScale);\n } finally {\n ThreeObjectPools.vector3.release(tempScale);\n }\n\n const material = meshRef.current.material as THREE.MeshBasicMaterial;\n material.opacity = 1 - progress;\n });\n\n return (\n <mesh ref={meshRef} position={position} rotation={[Math.PI / 2, 0, 0]}>\n <ringGeometry args={[0.9, 1.0, 32]} />\n <meshBasicMaterial\n color={color}\n transparent\n opacity={1}\n side={THREE.DoubleSide}\n />\n </mesh>\n );\n};\n\n/**\n * Floating damage number\n */\nconst DamageNumber: React.FC<{\n position: [number, number, number];\n damage: number;\n type: \"perfect\" | \"normal\" | \"miss\";\n isMobile: boolean;\n onComplete: () => void;\n}> = ({ position, damage, type, isMobile, onComplete }) => {\n const [offset, setOffset] = useState(0);\n const [opacity, setOpacity] = useState(1);\n const startTime = useRef<number>(0);\n const completedRef = useRef(false);\n\n useEffect(() => {\n if (startTime.current === 0) {\n startTime.current = Date.now();\n }\n }, []);\n\n useFrame(() => {\n const elapsed = (Date.now() - startTime.current) / 1000;\n const progress = Math.min(elapsed / 1.5, 1); // 1.5 second duration\n\n setOffset(progress * 1);\n\n setOpacity(1 - progress);\n\n if (progress >= 1 && !completedRef.current && onComplete) {\n completedRef.current = true;\n onComplete();\n }\n });\n\n const color =\n type === \"perfect\" ? \"#ffd700\" : type === \"normal\" ? \"#00ffff\" : \"#ff4444\";\n const text = type === \"miss\" ? \"빗나감 | MISS\" : `${damage}`; // Korean: 빗나감 = miss/deflected\n\n return (\n <Html\n position={[position[0], position[1] + offset, position[2]]}\n center\n distanceFactor={10}\n style={{ pointerEvents: \"none\", opacity }}\n >\n <div\n style={{\n fontSize: isMobile ? \"20px\" : \"28px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color,\n textShadow: \"0 0 10px rgba(0, 0, 0, 0.8)\",\n whiteSpace: \"nowrap\",\n }}\n data-testid=\"damage-number\"\n >\n {text}\n </div>\n </Html>\n );\n};\n\n/**\n * HitFeedbackEffect3D Component\n * Main hit feedback visualization\n */\nexport const HitFeedbackEffect3D: React.FC<HitFeedbackEffect3DProps> = ({\n position,\n type,\n damage,\n visible = true,\n onComplete,\n duration = 1500,\n isMobile = false,\n}) => {\n const [showEffect, setShowEffect] = useState(visible);\n const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const effectColor = useMemo(() => {\n switch (type) {\n case \"perfect\":\n return KOREAN_COLORS.ACCENT_GOLD;\n case \"success\":\n return KOREAN_COLORS.PRIMARY_CYAN;\n case \"miss\":\n return KOREAN_COLORS.TEXT_SECONDARY;\n default:\n return KOREAN_COLORS.PRIMARY_CYAN;\n }\n }, [type]);\n\n const particleCount = useMemo(() => {\n const isPerfect = type === \"perfect\";\n const isSuccess = type === \"success\";\n\n if (isMobile) {\n return isPerfect ? 30 : isSuccess ? 20 : 10;\n }\n\n return isPerfect ? 80 : isSuccess ? 50 : 25;\n }, [type, isMobile]);\n const ringRadius = type === \"perfect\" ? 1.5 : 1.0;\n\n const completedRef = useRef(false);\n\n const handleComplete = useCallback(() => {\n if (completedRef.current) return;\n completedRef.current = true;\n setShowEffect(false);\n onComplete?.();\n }, [onComplete]);\n\n useEffect(() => {\n if (visible && showEffect) {\n timeoutRef.current = setTimeout(handleComplete, duration);\n }\n\n return () => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n }\n };\n }, [visible, showEffect, duration, handleComplete]);\n\n if (!showEffect) return null;\n\n return (\n <group name={`hit-feedback-${type}`}>\n {/* Particle burst */}\n <ImpactParticles\n position={position}\n color={effectColor}\n count={particleCount}\n />\n\n {/* Expanding ring */}\n <RingEffect\n position={position}\n color={effectColor}\n maxRadius={ringRadius}\n />\n\n {/* Floating damage number */}\n {damage !== undefined && type !== \"miss\" && (\n <DamageNumber\n position={position}\n damage={damage}\n type={type === \"perfect\" ? \"perfect\" : \"normal\"}\n isMobile={isMobile}\n onComplete={handleComplete}\n />\n )}\n\n {/* Miss indicator */}\n {type === \"miss\" && (\n <DamageNumber\n position={position}\n damage={0}\n type=\"miss\"\n isMobile={isMobile}\n onComplete={handleComplete}\n />\n )}\n </group>\n );\n};\n\nexport default HitFeedbackEffect3D;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingAICharacter3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingAICharacter3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAqC,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,wCAAwC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC;IAC7C,8BAA8B;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAoBD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,
|
|
1
|
+
{"version":3,"file":"TrainingAICharacter3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingAICharacter3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAqC,MAAM,OAAO,CAAC;AAE1D,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAGzD,OAAO,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAE9D;;GAEG;AACH,MAAM,WAAW,0BAA0B;IACzC,2BAA2B;IAC3B,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,6BAA6B;IAC7B,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,wCAAwC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,oEAAoE;IACpE,QAAQ,CAAC,mBAAmB,CAAC,EAAE,aAAa,CAAC;IAC7C,8BAA8B;IAC9B,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;CACjC;AAoBD;;;GAGG;AACH,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CA2MtE,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingArena3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingArena3D.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAqC,MAAM,OAAO,CAAC;AAI1D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,
|
|
1
|
+
{"version":3,"file":"TrainingArena3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingArena3D.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAqC,MAAM,OAAO,CAAC;AAI1D;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,wCAAwC;IACxC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,mDAAmD;IACnD,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAoE1D,CAAC;AAuDF,eAAe,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingControlsOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingControlsOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAiB1B,OAAO,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,IAAI,CAAC;IACrC,gCAAgC;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IACpC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"TrainingControlsOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingControlsOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAiB1B,OAAO,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,2CAA2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,iCAAiC;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,IAAI,CAAC;IACrC,gCAAgC;IAChC,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IACpC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,yDAAyD;IACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;CACxC;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,eAAO,MAAM,2BAA2B,8DA0IvC,CAAC;AAIF,eAAe,2BAA2B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingControlsOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingControlsOverlayHtml.tsx"],"sourcesContent":["/**\n * TrainingControlsOverlayHtml - Html overlay for training controls\n * \n * Displays start/stop button and training status with consistent Korean theming.\n * Uses KOREAN_COLORS constants and bilingual formatting.\n * \n * @module components/screens/training\n * @category Training UI\n * @korean 훈련제어오버레이\n */\n\nimport React from \"react\";\nimport {\n FONT_FAMILY,\n KOREAN_COLORS,\n} from \"../../../../types/constants\";\nimport { SPACING } from \"../../../../types/constants/ui\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport {\n formatBilingualText,\n getEnhancedKoreanOverlayStyles,\n getKoreanButtonWithGlow,\n getResponsiveSpacing,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport {\n getNeonTextShadow,\n getSmoothTransition,\n} from \"../../../../utils/visualEffects\";\nimport \"../training.css\";\n\n/**\n * Props for TrainingControlsOverlayHtml component\n */\nexport interface TrainingControlsOverlayHtmlProps {\n /** Whether training is currently active */\n readonly isTraining: boolean;\n /** Callback to start training */\n readonly onStartTraining: () => void;\n /** Callback to stop training */\n readonly onStopTraining: () => void;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n /** Compact mode for embedding inside the slim top HUD */\n readonly variant?: \"panel\" | \"compact\";\n}\n\n/**\n * TrainingControlsOverlayHtml Component\n * \n * Html overlay showing training status and start/stop controls with Korean theming.\n * All colors use KOREAN_COLORS constants for consistency.\n *\n * Optimized with React.memo for 60fps performance:\n * - Prevents re-renders when isTraining state hasn't changed\n * - Callbacks expected to be stable (parent should use useCallback)\n * \n * @example\n * ```tsx\n * <TrainingControlsOverlayHtml\n * isTraining={true}\n * onStartTraining={() => console.log('start')}\n * onStopTraining={() => console.log('stop')}\n * isMobile={false}\n * />\n * ```\n * \n * @korean 훈련제어오버레이컴포넌트\n */\nexport const TrainingControlsOverlayHtml = React.memo<TrainingControlsOverlayHtmlProps>(\n ({\n isTraining,\n onStartTraining,\n onStopTraining,\n isMobile,\n variant = \"panel\",\n }) => {\n const isCompact = variant === \"compact\";\n const panelWidth = isCompact ? (isMobile ? 180 : 210) : isMobile ? 200 : 220;\n const panelHeight = isCompact ? (isMobile ? 40 : 44) : isMobile ? 90 : 100;\n const padding = isCompact ? getResponsiveSpacing(\"xs\", isMobile) : getResponsiveSpacing(\"sm\", isMobile);\n\n // Use Korean colors for border based on training state\n const stateColor = isTraining ? KOREAN_COLORS.ACCENT_GREEN : KOREAN_COLORS.ACCENT_RED;\n const borderColor = hexToRgbaString(stateColor, 0.9);\n\n // Enhanced panel styles with neon glow\n const panelStyle: React.CSSProperties = {\n ...getEnhancedKoreanOverlayStyles({\n opacity: 0.88,\n glowIntensity: isTraining ? \"medium\" : \"subtle\",\n includeGradient: false,\n includeBackdropBlur: true,\n depthLayers: 2,\n }),\n width: `${panelWidth}px`,\n height: `${panelHeight}px`,\n padding: `${padding}px`,\n border: `2px solid ${borderColor}`,\n position: \"relative\",\n display: \"flex\",\n flexDirection: isCompact ? \"row\" : \"column\",\n alignItems: isCompact ? \"center\" : \"stretch\",\n justifyContent: isCompact ? \"space-between\" : \"flex-start\",\n gap: `${padding}px`,\n boxSizing: \"border-box\",\n fontFamily: FONT_FAMILY.KOREAN,\n };\n\n // Enhanced button styles (memoized, interaction states handled internally by getKoreanButtonWithGlow)\n const buttonStyles = React.useMemo(\n () =>\n getKoreanButtonWithGlow({\n variant: isTraining ? \"danger\" : \"success\",\n glowIntensity: \"strong\",\n hoverAnimation: \"combined\",\n }),\n [isTraining]\n );\n\n const titleFontSize = isCompact ? (isMobile ? 11 : 12) : isMobile ? 13 : 14;\n const infoFontSize = isMobile ? 9 : 10;\n\n return (\n <div style={panelStyle} data-testid=\"training-controls-html\">\n {/* Header with bilingual status */}\n <div style={{ marginBottom: isCompact ? 0 : `${SPACING.SM}px`, minWidth: 0 }}>\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n fontWeight: \"bold\",\n color: hexToRgbaString(stateColor),\n textShadow: getNeonTextShadow(stateColor, isTraining ? \"medium\" : \"subtle\"),\n transition: getSmoothTransition(\"all\", \"normal\"),\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {formatBilingualText(\n isTraining ? \"훈련 진행중\" : \"훈련 대기\",\n isTraining ? \"Training Active\" : \"Training Stopped\",\n \"pipe\"\n )}\n </div>\n </div>\n\n {/* Status Indicator with CSS animation */}\n <div\n className={`status-indicator ${isTraining ? \"active\" : \"inactive\"}`}\n style={{\n position: \"absolute\",\n top: isCompact ? \"6px\" : \"12px\",\n right: isCompact ? \"6px\" : \"12px\",\n }}\n />\n\n {/* Start/Stop Button with Korean theming */}\n <button\n onClick={isTraining ? onStopTraining : onStartTraining}\n className={`training-button ${isTraining ? \"training-button-stop\" : \"training-button-start\"}`}\n style={{\n ...buttonStyles,\n // Note: fontSize from buttonStyles is intentionally overridden with titleFontSize\n // to maintain consistent sizing with the training header/title typography\n fontSize: `${titleFontSize}px`,\n height: isCompact ? \"30px\" : \"35px\",\n minWidth: isCompact ? \"72px\" : undefined,\n padding: isCompact ? \"4px 8px\" : buttonStyles.padding,\n flexShrink: 0,\n }}\n data-testid=\"training-toggle-button\"\n data-training-state={isTraining ? \"active\" : \"inactive\"}\n >\n <span>{isTraining ? \"⏹\" : \"▶\"}</span>\n <span>\n {formatBilingualText(\n isTraining ? \"중지\" : \"시작\",\n isTraining ? \"Stop\" : \"Start\",\n \"pipe\"\n )}\n </span>\n </button>\n\n {/* Info text about auto-restart with Korean colors */}\n {!isCompact && !isTraining && (\n <div\n style={{\n fontSize: `${infoFontSize}px`,\n color: hexToRgbaString(KOREAN_COLORS.TEXT_TERTIARY),\n textAlign: \"center\",\n marginTop: `${SPACING.XS}px`,\n fontFamily: FONT_FAMILY.KOREAN,\n lineHeight: \"1.4\",\n }}\n >\n <div>모드 변경시 자동 재시작</div>\n <div>Auto-restarts on mode change</div>\n </div>\n )}\n </div>\n );\n },\n (prevProps, nextProps) => {\n // Re-render when training state, mobile state, variant, or callbacks change.\n // variant must be compared so switching between \"panel\" and \"compact\"\n // triggers a re-render and the layout updates accordingly.\n // Including callback props here avoids stale-closure issues where the\n // component would keep calling outdated handlers that reference old state.\n return (\n prevProps.isTraining === nextProps.isTraining &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.variant === nextProps.variant &&\n prevProps.onStartTraining === nextProps.onStartTraining &&\n prevProps.onStopTraining === nextProps.onStopTraining\n );\n },\n);\n\nTrainingControlsOverlayHtml.displayName = \"TrainingControlsOverlayHtml\";\n\nexport default TrainingControlsOverlayHtml;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TrainingControlsOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingControlsOverlayHtml.tsx"],"sourcesContent":["/**\n * TrainingControlsOverlayHtml - Html overlay for training controls\n * \n * Displays start/stop button and training status with consistent Korean theming.\n * Uses KOREAN_COLORS constants and bilingual formatting.\n * \n * @module components/screens/training\n * @category Training UI\n * @korean 훈련제어오버레이\n */\n\nimport React from \"react\";\nimport {\n FONT_FAMILY,\n KOREAN_COLORS,\n} from \"../../../../types/constants\";\nimport { SPACING } from \"../../../../types/constants/ui\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport {\n formatBilingualText,\n getEnhancedKoreanOverlayStyles,\n getKoreanButtonWithGlow,\n getResponsiveSpacing,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport {\n getNeonTextShadow,\n getSmoothTransition,\n} from \"../../../../utils/visualEffects\";\nimport \"../training.css\";\n\n/**\n * Props for TrainingControlsOverlayHtml component\n */\nexport interface TrainingControlsOverlayHtmlProps {\n /** Whether training is currently active */\n readonly isTraining: boolean;\n /** Callback to start training */\n readonly onStartTraining: () => void;\n /** Callback to stop training */\n readonly onStopTraining: () => void;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n /** Compact mode for embedding inside the slim top HUD */\n readonly variant?: \"panel\" | \"compact\";\n}\n\n/**\n * TrainingControlsOverlayHtml Component\n * \n * Html overlay showing training status and start/stop controls with Korean theming.\n * All colors use KOREAN_COLORS constants for consistency.\n *\n * Optimized with React.memo for 60fps performance:\n * - Prevents re-renders when isTraining state hasn't changed\n * - Callbacks expected to be stable (parent should use useCallback)\n * \n * @example\n * ```tsx\n * <TrainingControlsOverlayHtml\n * isTraining={true}\n * onStartTraining={() => console.log('start')}\n * onStopTraining={() => console.log('stop')}\n * isMobile={false}\n * />\n * ```\n * \n * @korean 훈련제어오버레이컴포넌트\n */\nexport const TrainingControlsOverlayHtml = React.memo<TrainingControlsOverlayHtmlProps>(\n ({\n isTraining,\n onStartTraining,\n onStopTraining,\n isMobile,\n variant = \"panel\",\n }) => {\n const isCompact = variant === \"compact\";\n const panelWidth = isCompact ? (isMobile ? 180 : 210) : isMobile ? 200 : 220;\n const panelHeight = isCompact ? (isMobile ? 40 : 44) : isMobile ? 90 : 100;\n const padding = isCompact ? getResponsiveSpacing(\"xs\", isMobile) : getResponsiveSpacing(\"sm\", isMobile);\n\n const stateColor = isTraining ? KOREAN_COLORS.ACCENT_GREEN : KOREAN_COLORS.ACCENT_RED;\n const borderColor = hexToRgbaString(stateColor, 0.9);\n\n const panelStyle: React.CSSProperties = {\n ...getEnhancedKoreanOverlayStyles({\n opacity: 0.88,\n glowIntensity: isTraining ? \"medium\" : \"subtle\",\n includeGradient: false,\n includeBackdropBlur: true,\n depthLayers: 2,\n }),\n width: `${panelWidth}px`,\n height: `${panelHeight}px`,\n padding: `${padding}px`,\n border: `2px solid ${borderColor}`,\n position: \"relative\",\n display: \"flex\",\n flexDirection: isCompact ? \"row\" : \"column\",\n alignItems: isCompact ? \"center\" : \"stretch\",\n justifyContent: isCompact ? \"space-between\" : \"flex-start\",\n gap: `${padding}px`,\n boxSizing: \"border-box\",\n fontFamily: FONT_FAMILY.KOREAN,\n };\n\n const buttonStyles = React.useMemo(\n () =>\n getKoreanButtonWithGlow({\n variant: isTraining ? \"danger\" : \"success\",\n glowIntensity: \"strong\",\n hoverAnimation: \"combined\",\n }),\n [isTraining]\n );\n\n const titleFontSize = isCompact ? (isMobile ? 11 : 12) : isMobile ? 13 : 14;\n const infoFontSize = isMobile ? 9 : 10;\n\n return (\n <div style={panelStyle} data-testid=\"training-controls-html\">\n {/* Header with bilingual status */}\n <div style={{ marginBottom: isCompact ? 0 : `${SPACING.SM}px`, minWidth: 0 }}>\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n fontWeight: \"bold\",\n color: hexToRgbaString(stateColor),\n textShadow: getNeonTextShadow(stateColor, isTraining ? \"medium\" : \"subtle\"),\n transition: getSmoothTransition(\"all\", \"normal\"),\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n whiteSpace: \"nowrap\",\n }}\n >\n {formatBilingualText(\n isTraining ? \"훈련 진행중\" : \"훈련 대기\",\n isTraining ? \"Training Active\" : \"Training Stopped\",\n \"pipe\"\n )}\n </div>\n </div>\n\n {/* Status Indicator with CSS animation */}\n <div\n className={`status-indicator ${isTraining ? \"active\" : \"inactive\"}`}\n style={{\n position: \"absolute\",\n top: isCompact ? \"6px\" : \"12px\",\n right: isCompact ? \"6px\" : \"12px\",\n }}\n />\n\n {/* Start/Stop Button with Korean theming */}\n <button\n onClick={isTraining ? onStopTraining : onStartTraining}\n className={`training-button ${isTraining ? \"training-button-stop\" : \"training-button-start\"}`}\n style={{\n ...buttonStyles,\n fontSize: `${titleFontSize}px`,\n height: isCompact ? \"30px\" : \"35px\",\n minWidth: isCompact ? \"72px\" : undefined,\n padding: isCompact ? \"4px 8px\" : buttonStyles.padding,\n flexShrink: 0,\n }}\n data-testid=\"training-toggle-button\"\n data-training-state={isTraining ? \"active\" : \"inactive\"}\n >\n <span>{isTraining ? \"⏹\" : \"▶\"}</span>\n <span>\n {formatBilingualText(\n isTraining ? \"중지\" : \"시작\",\n isTraining ? \"Stop\" : \"Start\",\n \"pipe\"\n )}\n </span>\n </button>\n\n {/* Info text about auto-restart with Korean colors */}\n {!isCompact && !isTraining && (\n <div\n style={{\n fontSize: `${infoFontSize}px`,\n color: hexToRgbaString(KOREAN_COLORS.TEXT_TERTIARY),\n textAlign: \"center\",\n marginTop: `${SPACING.XS}px`,\n fontFamily: FONT_FAMILY.KOREAN,\n lineHeight: \"1.4\",\n }}\n >\n <div>모드 변경시 자동 재시작</div>\n <div>Auto-restarts on mode change</div>\n </div>\n )}\n </div>\n );\n },\n (prevProps, nextProps) => {\n return (\n prevProps.isTraining === nextProps.isTraining &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.variant === nextProps.variant &&\n prevProps.onStartTraining === nextProps.onStartTraining &&\n prevProps.onStopTraining === nextProps.onStopTraining\n );\n },\n);\n\nTrainingControlsOverlayHtml.displayName = \"TrainingControlsOverlayHtml\";\n\nexport default TrainingControlsOverlayHtml;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingDummy3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingDummy3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAMN,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK1E;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,mDAAmD;IACnD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,iCAAiC;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,uCAAuC;IACvC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,sCAAsC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;IACrC,+CAA+C;IAC/C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC;IACrC,mCAAmC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;CACjC;
|
|
1
|
+
{"version":3,"file":"TrainingDummy3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingDummy3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,KAMN,MAAM,OAAO,CAAC;AAGf,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAK1E;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,GAAG,MAAM,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,oBAAoB;IACnC,qCAAqC;IACrC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,mDAAmD;IACnD,QAAQ,CAAC,kBAAkB,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3C,iCAAiC;IACjC,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC;IAC7B,sCAAsC;IACtC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,8BAA8B;IAC9B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,uCAAuC;IACvC,QAAQ,CAAC,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,sCAAsC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,UAAU,CAAC,EAAE,cAAc,CAAC;IACrC,+CAA+C;IAC/C,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,8DAA8D;IAC9D,QAAQ,CAAC,SAAS,CAAC,EAAE,eAAe,CAAC;IACrC,mCAAmC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;CACjC;AAwID;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CA+I1D,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingDummy3D.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingDummy3D.tsx"],"sourcesContent":["/**\n * TrainingDummy3D - 3D training dummy with vital points\n *\n * Provides anatomically accurate training dummy using SkeletalPlayer3D\n * for Korean martial arts practice. Supports anatomy overlays and difficulty modes.\n *\n * Refactored to extend SkeletalPlayer3D for visual consistency with player characters.\n *\n * @module components/screens/training/TrainingDummy3D\n * @category 3D Components\n * @korean 훈련인형3D컴포넌트\n */\n\nimport { useFrame } from \"@react-three/fiber\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport * as THREE from \"three\";\nimport { KOREAN_VITAL_POINTS } from \"../../../../systems/vitalpoint/KoreanVitalPoints\";\nimport { PlayerArchetype, TrigramStance } from \"../../../../types/common\";\nimport { KOREAN_COLORS } from \"../../../../types/constants\";\nimport SkeletalPlayer3D from \"../../../shared/three/models/SkeletalPlayer3D\";\nimport VitalPointMarker3D from \"./VitalPointMarker3D\";\n\n/**\n * Difficulty mode for training\n * @korean 난이도모드\n */\nexport type DifficultyMode = \"easy\" | \"normal\" | \"hard\";\n\n/**\n * Props for TrainingDummy3D component\n * @korean 훈련인형3D속성\n */\nexport interface TrainingDummy3DProps {\n /** 3D world position of the dummy */\n readonly position: [number, number, number];\n /** Currently selected vital point for targeting */\n readonly selectedVitalPoint: string | null;\n /** Whether training is active */\n readonly isTraining: boolean;\n /** Current health of dummy (0-100) */\n readonly health?: number;\n /** Maximum health of dummy */\n readonly maxHealth?: number;\n /** Callback when vital point is hit */\n readonly onVitalPointHit?: (vitalPointId: string) => void;\n /** Callback when dummy is defeated */\n readonly onDefeated?: () => void;\n /** Difficulty mode (affects marker sizes) */\n readonly difficulty?: DifficultyMode;\n /** Number of vital points to display (3-70) */\n readonly vitalPointCount?: number;\n /** Whether on mobile device */\n readonly isMobile?: boolean;\n /** Archetype to display (affects body type and appearance) */\n readonly archetype?: PlayerArchetype;\n /** Current stance for the dummy */\n readonly stance?: TrigramStance;\n}\n\n/**\n * Map body region to 3D position on dummy\n *\n * Positions are calibrated for SkeletalPlayer3D bone structure.\n *\n * @param pointId - Unique identifier for the vital point\n * @param category - Anatomical category (head, neck, torso, etc.)\n * @returns 3D coordinates [x, y, z] relative to dummy center\n * @korean 급소위치계산\n */\nconst getVitalPointPosition = (\n pointId: string,\n category: string,\n): [number, number, number] => {\n // Base positions calibrated for SkeletalPlayer3D skeletal rig\n // These align with the 28-bone humanoid rig structure\n const positions: Record<string, [number, number, number]> = {\n head: [0, 1.75, 0.12], // Head bone + offset\n neck: [0, 1.5, 0.1], // Neck bone\n torso: [0, 1.15, 0.18], // Chest/spine area\n chest: [0, 1.2, 0.2], // Upper chest\n abdomen: [0, 0.85, 0.18], // Lower torso\n back: [0, 1.1, -0.15], // Spine back\n arm: [-0.45, 1.15, 0], // Upper arm area\n leg: [-0.18, 0.4, 0.05], // Thigh area\n neurological: [0, 1.7, 0.08], // Temple/head neural points\n vascular: [0, 1.45, 0.12], // Neck vascular points\n muscular: [0, 1.1, 0.2], // Muscle groups\n skeletal: [0, 0.9, 0.15], // Joints/bones\n };\n\n // Get base position or default to center torso\n const basePos = positions[category.toLowerCase()] ?? [0, 1.1, 0.15];\n\n // Add deterministic offset for multiple points in same region\n // Uses character code of pointId for consistent positioning\n const hash =\n pointId.split(\"\").reduce((acc, char) => acc + char.charCodeAt(0), 0) *\n 0.001;\n return [\n basePos[0] + Math.sin(hash * 7.3) * 0.08,\n basePos[1] + Math.cos(hash * 5.1) * 0.08,\n basePos[2] + Math.sin(hash * 3.7) * 0.03,\n ];\n};\n\n/**\n * Health bar component for training dummy\n *\n * Displays above the dummy with Korean cyberpunk styling.\n * @korean 훈련인형체력바\n */\n\n// Constants defined outside component to avoid recreation\nconst HEALTH_BAR_WIDTH = 1.2;\nconst HEALTH_BAR_HEIGHT = 0.1;\n\nconst DummyHealthBar: React.FC<{\n readonly health: number;\n readonly maxHealth: number;\n readonly position: [number, number, number];\n}> = ({ health, maxHealth, position }) => {\n // Health percentage\n const healthPercent = Math.max(0, Math.min(100, (health / maxHealth) * 100));\n\n // Memoize geometries to avoid recreating on every render\n const bgGeometry = useMemo(\n () => new THREE.BoxGeometry(HEALTH_BAR_WIDTH, HEALTH_BAR_HEIGHT, 0.02),\n [],\n );\n const healthGeometry = useMemo(\n () => new THREE.BoxGeometry(HEALTH_BAR_WIDTH, HEALTH_BAR_HEIGHT, 0.02),\n [],\n );\n const borderGeometry = useMemo(\n () =>\n new THREE.BoxGeometry(\n HEALTH_BAR_WIDTH + 0.04,\n HEALTH_BAR_HEIGHT + 0.04,\n 0.01,\n ),\n [],\n );\n\n // Determine health bar color based on health percentage\n const healthColor = useMemo(() => {\n if (healthPercent > 70) return KOREAN_COLORS.HEALTH_FULL;\n if (healthPercent > 40) return KOREAN_COLORS.HEALTH_MEDIUM;\n if (healthPercent > 20) return KOREAN_COLORS.HEALTH_LOW;\n return KOREAN_COLORS.HEALTH_CRITICAL;\n }, [healthPercent]);\n\n // Use scale instead of recreating geometry\n const healthScale: [number, number, number] = useMemo(\n () => [healthPercent / 100, 1, 1],\n [healthPercent],\n );\n\n // Cleanup geometries on unmount\n useEffect(() => {\n return () => {\n bgGeometry.dispose();\n healthGeometry.dispose();\n borderGeometry.dispose();\n };\n }, [bgGeometry, healthGeometry, borderGeometry]);\n\n return (\n <group position={position} name=\"dummy-health-bar\">\n {/* Background bar */}\n <mesh>\n <primitive object={bgGeometry} />\n <meshBasicMaterial\n color={KOREAN_COLORS.UI_BACKGROUND_DARK}\n transparent\n opacity={0.7}\n />\n </mesh>\n\n {/* Health bar (scaled based on health, anchored to left edge) */}\n <mesh\n position={[\n -(HEALTH_BAR_WIDTH * (1 - healthPercent / 100)) / 2,\n 0,\n 0.01,\n ]}\n scale={healthScale}\n >\n <primitive object={healthGeometry} />\n <meshBasicMaterial color={healthColor} transparent opacity={0.9} />\n </mesh>\n\n {/* Border frame - outline using EdgesGeometry for crisp border */}\n <lineSegments>\n <edgesGeometry args={[borderGeometry]} />\n <lineBasicMaterial\n color={KOREAN_COLORS.PRIMARY_CYAN}\n transparent\n opacity={0.8}\n />\n </lineSegments>\n </group>\n );\n};\n\n/**\n * TrainingDummy3D Component\n *\n * Main training dummy using SkeletalPlayer3D for consistent visual appearance.\n * Displays vital points for martial arts practice with difficulty-based sizing.\n *\n * @example\n * ```tsx\n * <TrainingDummy3D\n * position={[0, 0, 5]}\n * selectedVitalPoint=\"temple\"\n * isTraining={true}\n * health={75}\n * difficulty=\"normal\"\n * onVitalPointHit={(id) => console.log(`Hit ${id}`)}\n * />\n * ```\n *\n * @korean 훈련인형3D컴포넌트\n */\nexport const TrainingDummy3D: React.FC<TrainingDummy3DProps> = ({\n position,\n selectedVitalPoint,\n isTraining,\n health = 100,\n maxHealth = 100,\n onVitalPointHit,\n onDefeated,\n difficulty = \"normal\",\n vitalPointCount = 12,\n isMobile = false,\n archetype = PlayerArchetype.MUSA,\n stance = TrigramStance.GEON,\n}) => {\n const groupRef = useRef<THREE.Group>(null);\n const [isStunned, setIsStunned] = useState(false);\n\n // Select vital points to display based on count (expandable to 70)\n const vitalPoints = useMemo(\n () =>\n KOREAN_VITAL_POINTS.slice(\n 0,\n Math.min(vitalPointCount, KOREAN_VITAL_POINTS.length),\n ),\n [vitalPointCount],\n );\n\n // Calculate size multiplier based on difficulty\n const sizeMultiplier = useMemo(() => {\n switch (difficulty) {\n case \"easy\":\n return 1.5; // Larger targets\n case \"normal\":\n return 1.0; // Standard size\n case \"hard\":\n return 0.7; // Smaller targets\n default:\n return 1.0;\n }\n }, [difficulty]);\n\n // Track previous health to detect defeat\n const prevHealthRef = useRef(health);\n\n // Store latest onDefeated callback in a ref to avoid stale closure\n const onDefeatedRef = useRef(onDefeated);\n useEffect(() => {\n onDefeatedRef.current = onDefeated;\n }, [onDefeated]);\n\n // Check for defeat and trigger stun effect on significant damage\n useEffect(() => {\n // Defeated check\n if (prevHealthRef.current > 0 && health <= 0) {\n onDefeatedRef.current?.();\n }\n\n // Stun on significant damage (more than 20 points)\n if (prevHealthRef.current - health > 20) {\n setIsStunned(true);\n const timer = setTimeout(() => setIsStunned(false), 500);\n return () => clearTimeout(timer);\n }\n\n prevHealthRef.current = health;\n return undefined;\n }, [health]);\n\n // Subtle idle animation for training dummy\n useFrame((state) => {\n if (!groupRef.current) return;\n\n // Gentle breathing/swaying motion\n const time = state.clock.elapsedTime;\n const breathScale = Math.sin(time * 1.5) * 0.01 + 1;\n groupRef.current.scale.y = breathScale;\n\n // Subtle rotation as if waiting for attack\n groupRef.current.rotation.y = Math.sin(time * 0.5) * 0.02;\n });\n\n // Handle vital point hit\n const handlePointHit = useCallback(\n (pointId: string) => {\n onVitalPointHit?.(pointId);\n },\n [onVitalPointHit],\n );\n\n return (\n <group ref={groupRef} position={position} name=\"training-dummy-3d\">\n {/* SkeletalPlayer3D as the base character model */}\n <SkeletalPlayer3D\n playerId=\"training-dummy\"\n archetype={archetype}\n stance={stance}\n position={[0, 0, 0]}\n rotation={Math.PI} // Face the player\n facing=\"left\"\n health={health}\n maxHealth={maxHealth}\n stamina={100}\n ki={50}\n balance=\"READY\"\n pain={0}\n consciousness={100}\n isMobile={isMobile}\n currentAnimation=\"idle\"\n isBlocking={false}\n isStunned={isStunned}\n showHealthBar={false} // We use custom health bar\n showStanceIndicator={false}\n enableFacialExpressions={true}\n enableEyeTracking={true}\n />\n\n {/* Vital point markers overlaid on the skeletal model */}\n {vitalPoints.map((point) => (\n <group\n key={point.id}\n position={getVitalPointPosition(point.id, point.category)}\n >\n <VitalPointMarker3D\n vitalPoint={point}\n isSelected={point.id === selectedVitalPoint}\n isTraining={isTraining}\n isMobile={isMobile}\n onHit={handlePointHit}\n sizeMultiplier={sizeMultiplier}\n />\n </group>\n ))}\n\n {/* Health bar above dummy */}\n {isTraining && (\n <DummyHealthBar\n health={health}\n maxHealth={maxHealth}\n position={[0, 2.3, 0]}\n />\n )}\n\n {/* Training mode indicator glow */}\n {isTraining && (\n <pointLight\n position={[0, 1.2, 0.5]}\n color={KOREAN_COLORS.PRIMARY_CYAN}\n intensity={0.3}\n distance={3}\n decay={2}\n />\n )}\n </group>\n );\n};\n\nexport default TrainingDummy3D;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"TrainingDummy3D.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingDummy3D.tsx"],"sourcesContent":["/**\n * TrainingDummy3D - 3D training dummy with vital points\n *\n * Provides anatomically accurate training dummy using SkeletalPlayer3D\n * for Korean martial arts practice. Supports anatomy overlays and difficulty modes.\n *\n * Refactored to extend SkeletalPlayer3D for visual consistency with player characters.\n *\n * @module components/screens/training/TrainingDummy3D\n * @category 3D Components\n * @korean 훈련인형3D컴포넌트\n */\n\nimport { useFrame } from \"@react-three/fiber\";\nimport React, {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport * as THREE from \"three\";\nimport { KOREAN_VITAL_POINTS } from \"../../../../systems/vitalpoint/KoreanVitalPoints\";\nimport { PlayerArchetype, TrigramStance } from \"../../../../types/common\";\nimport { KOREAN_COLORS } from \"../../../../types/constants\";\nimport SkeletalPlayer3D from \"../../../shared/three/models/SkeletalPlayer3D\";\nimport VitalPointMarker3D from \"./VitalPointMarker3D\";\n\n/**\n * Difficulty mode for training\n * @korean 난이도모드\n */\nexport type DifficultyMode = \"easy\" | \"normal\" | \"hard\";\n\n/**\n * Props for TrainingDummy3D component\n * @korean 훈련인형3D속성\n */\nexport interface TrainingDummy3DProps {\n /** 3D world position of the dummy */\n readonly position: [number, number, number];\n /** Currently selected vital point for targeting */\n readonly selectedVitalPoint: string | null;\n /** Whether training is active */\n readonly isTraining: boolean;\n /** Current health of dummy (0-100) */\n readonly health?: number;\n /** Maximum health of dummy */\n readonly maxHealth?: number;\n /** Callback when vital point is hit */\n readonly onVitalPointHit?: (vitalPointId: string) => void;\n /** Callback when dummy is defeated */\n readonly onDefeated?: () => void;\n /** Difficulty mode (affects marker sizes) */\n readonly difficulty?: DifficultyMode;\n /** Number of vital points to display (3-70) */\n readonly vitalPointCount?: number;\n /** Whether on mobile device */\n readonly isMobile?: boolean;\n /** Archetype to display (affects body type and appearance) */\n readonly archetype?: PlayerArchetype;\n /** Current stance for the dummy */\n readonly stance?: TrigramStance;\n}\n\n/**\n * Map body region to 3D position on dummy\n *\n * Positions are calibrated for SkeletalPlayer3D bone structure.\n *\n * @param pointId - Unique identifier for the vital point\n * @param category - Anatomical category (head, neck, torso, etc.)\n * @returns 3D coordinates [x, y, z] relative to dummy center\n * @korean 급소위치계산\n */\nconst getVitalPointPosition = (\n pointId: string,\n category: string,\n): [number, number, number] => {\n const positions: Record<string, [number, number, number]> = {\n head: [0, 1.75, 0.12], // Head bone + offset\n neck: [0, 1.5, 0.1], // Neck bone\n torso: [0, 1.15, 0.18], // Chest/spine area\n chest: [0, 1.2, 0.2], // Upper chest\n abdomen: [0, 0.85, 0.18], // Lower torso\n back: [0, 1.1, -0.15], // Spine back\n arm: [-0.45, 1.15, 0], // Upper arm area\n leg: [-0.18, 0.4, 0.05], // Thigh area\n neurological: [0, 1.7, 0.08], // Temple/head neural points\n vascular: [0, 1.45, 0.12], // Neck vascular points\n muscular: [0, 1.1, 0.2], // Muscle groups\n skeletal: [0, 0.9, 0.15], // Joints/bones\n };\n\n const basePos = positions[category.toLowerCase()] ?? [0, 1.1, 0.15];\n\n const hash =\n pointId.split(\"\").reduce((acc, char) => acc + char.charCodeAt(0), 0) *\n 0.001;\n return [\n basePos[0] + Math.sin(hash * 7.3) * 0.08,\n basePos[1] + Math.cos(hash * 5.1) * 0.08,\n basePos[2] + Math.sin(hash * 3.7) * 0.03,\n ];\n};\n\n/**\n * Health bar component for training dummy\n *\n * Displays above the dummy with Korean cyberpunk styling.\n * @korean 훈련인형체력바\n */\n\nconst HEALTH_BAR_WIDTH = 1.2;\nconst HEALTH_BAR_HEIGHT = 0.1;\n\nconst DummyHealthBar: React.FC<{\n readonly health: number;\n readonly maxHealth: number;\n readonly position: [number, number, number];\n}> = ({ health, maxHealth, position }) => {\n const healthPercent = Math.max(0, Math.min(100, (health / maxHealth) * 100));\n\n const bgGeometry = useMemo(\n () => new THREE.BoxGeometry(HEALTH_BAR_WIDTH, HEALTH_BAR_HEIGHT, 0.02),\n [],\n );\n const healthGeometry = useMemo(\n () => new THREE.BoxGeometry(HEALTH_BAR_WIDTH, HEALTH_BAR_HEIGHT, 0.02),\n [],\n );\n const borderGeometry = useMemo(\n () =>\n new THREE.BoxGeometry(\n HEALTH_BAR_WIDTH + 0.04,\n HEALTH_BAR_HEIGHT + 0.04,\n 0.01,\n ),\n [],\n );\n\n const healthColor = useMemo(() => {\n if (healthPercent > 70) return KOREAN_COLORS.HEALTH_FULL;\n if (healthPercent > 40) return KOREAN_COLORS.HEALTH_MEDIUM;\n if (healthPercent > 20) return KOREAN_COLORS.HEALTH_LOW;\n return KOREAN_COLORS.HEALTH_CRITICAL;\n }, [healthPercent]);\n\n const healthScale: [number, number, number] = useMemo(\n () => [healthPercent / 100, 1, 1],\n [healthPercent],\n );\n\n useEffect(() => {\n return () => {\n bgGeometry.dispose();\n healthGeometry.dispose();\n borderGeometry.dispose();\n };\n }, [bgGeometry, healthGeometry, borderGeometry]);\n\n return (\n <group position={position} name=\"dummy-health-bar\">\n {/* Background bar */}\n <mesh>\n <primitive object={bgGeometry} />\n <meshBasicMaterial\n color={KOREAN_COLORS.UI_BACKGROUND_DARK}\n transparent\n opacity={0.7}\n />\n </mesh>\n\n {/* Health bar (scaled based on health, anchored to left edge) */}\n <mesh\n position={[\n -(HEALTH_BAR_WIDTH * (1 - healthPercent / 100)) / 2,\n 0,\n 0.01,\n ]}\n scale={healthScale}\n >\n <primitive object={healthGeometry} />\n <meshBasicMaterial color={healthColor} transparent opacity={0.9} />\n </mesh>\n\n {/* Border frame - outline using EdgesGeometry for crisp border */}\n <lineSegments>\n <edgesGeometry args={[borderGeometry]} />\n <lineBasicMaterial\n color={KOREAN_COLORS.PRIMARY_CYAN}\n transparent\n opacity={0.8}\n />\n </lineSegments>\n </group>\n );\n};\n\n/**\n * TrainingDummy3D Component\n *\n * Main training dummy using SkeletalPlayer3D for consistent visual appearance.\n * Displays vital points for martial arts practice with difficulty-based sizing.\n *\n * @example\n * ```tsx\n * <TrainingDummy3D\n * position={[0, 0, 5]}\n * selectedVitalPoint=\"temple\"\n * isTraining={true}\n * health={75}\n * difficulty=\"normal\"\n * onVitalPointHit={(id) => console.log(`Hit ${id}`)}\n * />\n * ```\n *\n * @korean 훈련인형3D컴포넌트\n */\nexport const TrainingDummy3D: React.FC<TrainingDummy3DProps> = ({\n position,\n selectedVitalPoint,\n isTraining,\n health = 100,\n maxHealth = 100,\n onVitalPointHit,\n onDefeated,\n difficulty = \"normal\",\n vitalPointCount = 12,\n isMobile = false,\n archetype = PlayerArchetype.MUSA,\n stance = TrigramStance.GEON,\n}) => {\n const groupRef = useRef<THREE.Group>(null);\n const [isStunned, setIsStunned] = useState(false);\n\n const vitalPoints = useMemo(\n () =>\n KOREAN_VITAL_POINTS.slice(\n 0,\n Math.min(vitalPointCount, KOREAN_VITAL_POINTS.length),\n ),\n [vitalPointCount],\n );\n\n const sizeMultiplier = useMemo(() => {\n switch (difficulty) {\n case \"easy\":\n return 1.5; // Larger targets\n case \"normal\":\n return 1.0; // Standard size\n case \"hard\":\n return 0.7; // Smaller targets\n default:\n return 1.0;\n }\n }, [difficulty]);\n\n const prevHealthRef = useRef(health);\n\n const onDefeatedRef = useRef(onDefeated);\n useEffect(() => {\n onDefeatedRef.current = onDefeated;\n }, [onDefeated]);\n\n useEffect(() => {\n if (prevHealthRef.current > 0 && health <= 0) {\n onDefeatedRef.current?.();\n }\n\n if (prevHealthRef.current - health > 20) {\n setIsStunned(true);\n const timer = setTimeout(() => setIsStunned(false), 500);\n return () => clearTimeout(timer);\n }\n\n prevHealthRef.current = health;\n return undefined;\n }, [health]);\n\n useFrame((state) => {\n if (!groupRef.current) return;\n\n const time = state.clock.elapsedTime;\n const breathScale = Math.sin(time * 1.5) * 0.01 + 1;\n groupRef.current.scale.y = breathScale;\n\n groupRef.current.rotation.y = Math.sin(time * 0.5) * 0.02;\n });\n\n const handlePointHit = useCallback(\n (pointId: string) => {\n onVitalPointHit?.(pointId);\n },\n [onVitalPointHit],\n );\n\n return (\n <group ref={groupRef} position={position} name=\"training-dummy-3d\">\n {/* SkeletalPlayer3D as the base character model */}\n <SkeletalPlayer3D\n playerId=\"training-dummy\"\n archetype={archetype}\n stance={stance}\n position={[0, 0, 0]}\n rotation={Math.PI} // Face the player\n facing=\"left\"\n health={health}\n maxHealth={maxHealth}\n stamina={100}\n ki={50}\n balance=\"READY\"\n pain={0}\n consciousness={100}\n isMobile={isMobile}\n currentAnimation=\"idle\"\n isBlocking={false}\n isStunned={isStunned}\n showHealthBar={false} // We use custom health bar\n showStanceIndicator={false}\n enableFacialExpressions={true}\n enableEyeTracking={true}\n />\n\n {/* Vital point markers overlaid on the skeletal model */}\n {vitalPoints.map((point) => (\n <group\n key={point.id}\n position={getVitalPointPosition(point.id, point.category)}\n >\n <VitalPointMarker3D\n vitalPoint={point}\n isSelected={point.id === selectedVitalPoint}\n isTraining={isTraining}\n isMobile={isMobile}\n onHit={handlePointHit}\n sizeMultiplier={sizeMultiplier}\n />\n </group>\n ))}\n\n {/* Health bar above dummy */}\n {isTraining && (\n <DummyHealthBar\n health={health}\n maxHealth={maxHealth}\n position={[0, 2.3, 0]}\n />\n )}\n\n {/* Training mode indicator glow */}\n {isTraining && (\n <pointLight\n position={[0, 1.2, 0.5]}\n color={KOREAN_COLORS.PRIMARY_CYAN}\n intensity={0.3}\n distance={3}\n decay={2}\n />\n )}\n </group>\n );\n};\n\nexport default TrainingDummy3D;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingFeedbackOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingFeedbackOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,
|
|
1
|
+
{"version":3,"file":"TrainingFeedbackOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingFeedbackOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,OAAO,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,WAAW,gCAAgC;IAC/C,kCAAkC;IAClC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AAED;;;;;GAKG;AACH,eAAO,MAAM,2BAA2B,8DAyBtC,CAAC;AAIH,eAAe,2BAA2B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingFeedbackOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingFeedbackOverlayHtml.tsx"],"sourcesContent":["/**\n * TrainingFeedbackOverlayHtml - Html overlay for training feedback messages\n * \n * Displays temporary feedback messages for hits, misses, and achievements\n * with consistent Korean martial arts cyberpunk theming.\n * \n * @module components/screens/training/components/TrainingFeedbackOverlayHtml\n * @category Training UI\n * @korean 훈련피드백오버레이\n */\n\nimport React from \"react\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport \"../training.css\";\n\n/**\n * Props for TrainingFeedbackOverlayHtml component\n */\nexport interface TrainingFeedbackOverlayHtmlProps {\n /** Feedback message to display */\n readonly message: string;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n}\n\n/**\n * TrainingFeedbackOverlayHtml Component\n * Html overlay for displaying training feedback with Korean theming\n * \n * @korean 훈련피드백오버레이컴포넌트\n */\nexport const TrainingFeedbackOverlayHtml = React.memo<TrainingFeedbackOverlayHtmlProps>(\n ({\n message,\n isMobile,\n }) => {\n return (\n <div\n className={`training-feedback ${isMobile ? \"mobile\" : \"desktop\"}`}\n style={{\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD),\n textShadow: `0 2px 10px ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.5)}`,\n }}\n data-testid=\"training-feedback-html\"\n >\n {message}\n </div>\n );\n},\n(prevProps, nextProps) => {\n
|
|
1
|
+
{"version":3,"file":"TrainingFeedbackOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingFeedbackOverlayHtml.tsx"],"sourcesContent":["/**\n * TrainingFeedbackOverlayHtml - Html overlay for training feedback messages\n * \n * Displays temporary feedback messages for hits, misses, and achievements\n * with consistent Korean martial arts cyberpunk theming.\n * \n * @module components/screens/training/components/TrainingFeedbackOverlayHtml\n * @category Training UI\n * @korean 훈련피드백오버레이\n */\n\nimport React from \"react\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport \"../training.css\";\n\n/**\n * Props for TrainingFeedbackOverlayHtml component\n */\nexport interface TrainingFeedbackOverlayHtmlProps {\n /** Feedback message to display */\n readonly message: string;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n}\n\n/**\n * TrainingFeedbackOverlayHtml Component\n * Html overlay for displaying training feedback with Korean theming\n * \n * @korean 훈련피드백오버레이컴포넌트\n */\nexport const TrainingFeedbackOverlayHtml = React.memo<TrainingFeedbackOverlayHtmlProps>(\n ({\n message,\n isMobile,\n }) => {\n return (\n <div\n className={`training-feedback ${isMobile ? \"mobile\" : \"desktop\"}`}\n style={{\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD),\n textShadow: `0 2px 10px ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.5)}`,\n }}\n data-testid=\"training-feedback-html\"\n >\n {message}\n </div>\n );\n},\n(prevProps, nextProps) => {\n return (\n prevProps.message === nextProps.message &&\n prevProps.isMobile === nextProps.isMobile\n );\n});\n\nTrainingFeedbackOverlayHtml.displayName = \"TrainingFeedbackOverlayHtml\";\n\nexport default TrainingFeedbackOverlayHtml;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAgCA,IAAa,8BAA8B,MAAM,MAC9C,EACC,SACA,eACI;CACN,OACE,oBAAC,OAAD;EACE,WAAW,qBAAqB,WAAW,WAAW;EACtD,OAAO;GACL,YAAY,YAAY;GACxB,YAAY;GACZ,OAAO,gBAAgB,cAAc,YAAY;GACjD,YAAY,cAAc,gBAAgB,cAAc,aAAa,GAAI;GAC1E;EACD,eAAY;YAEX;EACG,CAAA;IAGT,WAAW,cAAc;CACxB,OACE,UAAU,YAAY,UAAU,WAChC,UAAU,aAAa,UAAU;EAEnC;AAEF,4BAA4B,cAAc"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingHitEffects3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingHitEffects3D.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAA+C,MAAM,OAAO,CAAC;AAKpE;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC9C,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AA6CD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,
|
|
1
|
+
{"version":3,"file":"TrainingHitEffects3D.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingHitEffects3D.tsx"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAA+C,MAAM,OAAO,CAAC;AAKpE;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACxC,sCAAsC;IACtC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,yBAAyB;IACzB,QAAQ,CAAC,IAAI,EAAE,SAAS,GAAG,SAAS,GAAG,MAAM,CAAC;IAC9C,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,qCAAqC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AA6CD;;;GAGG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EAAE,CAAC,yBAAyB,CA2JpE,CAAC;AAEF,eAAe,oBAAoB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingModeSelectorOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingModeSelectorOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,UAAU,GACV,MAAM,GACN,iBAAiB,GACjB,aAAa,GACb,gBAAgB,GAChB,UAAU,CAAC;AAEf;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACnD,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;IACnC,iCAAiC;IACjC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACpD,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AA8CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,+BAA+B,
|
|
1
|
+
{"version":3,"file":"TrainingModeSelectorOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingModeSelectorOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,MAAM,OAAO,CAAC;AAa1B,OAAO,iBAAiB,CAAC;AAEzB;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,QAAQ,GACR,UAAU,GACV,MAAM,GACN,iBAAiB,GACjB,aAAa,GACb,gBAAgB,GAChB,UAAU,CAAC;AAEf;;GAEG;AACH,MAAM,WAAW,oCAAoC;IACnD,uCAAuC;IACvC,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC;IACnC,iCAAiC;IACjC,QAAQ,CAAC,YAAY,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACpD,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;CAC5B;AA8CD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,+BAA+B,kEAsIzC,CAAC;AAIJ,eAAe,+BAA+B,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingModeSelectorOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingModeSelectorOverlayHtml.tsx"],"sourcesContent":["/**\n * TrainingModeSelectorOverlayHtml - Html overlay for training mode selection\n *\n * Allows switching between different training modes with consistent Korean theming.\n * Uses KOREAN_COLORS constants and bilingual formatting.\n *\n * @module components/screens/training\n * @category Training UI\n * @korean 훈련모드선택오버레이\n */\n\nimport React from \"react\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { SPACING } from \"../../../../types/constants/ui\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport {\n formatBilingualText,\n getEnhancedKoreanOverlayStyles,\n getResponsiveSpacing,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport {\n getNeonTextShadow,\n getSmoothTransition,\n} from \"../../../../utils/visualEffects\";\nimport \"../training.css\";\n\n/**\n * Training mode types\n */\nexport type TrainingMode =\n | \"basics\" // Basic Training - Simple striking practice\n | \"advanced\" // Advanced Training - Vital point precision\n | \"free\" // Free Practice - Open combat vs AI\n | \"stance_training\" // Stance Training - Practice 8 trigrams\n | \"vital_point\" // Vital Point Training - Precision targeting\n | \"combo_practice\" // Combo Practice - Multi-hit techniques\n | \"footwork\"; // Footwork Training - Movement drills (보법 훈련)\n\n/**\n * Props for TrainingModeSelectorOverlayHtml component\n */\nexport interface TrainingModeSelectorOverlayHtmlProps {\n /** Currently selected training mode */\n readonly currentMode: TrainingMode;\n /** Callback when mode changes */\n readonly onModeChange: (mode: TrainingMode) => void;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n}\n\n/**\n * Mode information\n */\nconst MODE_INFO: Record<\n TrainingMode,\n { korean: string; english: string; description: string }\n> = {\n basics: {\n korean: \"기본 훈련\",\n english: \"Basic Training\",\n description: \"기초 타격 연습 | Basic striking practice\",\n },\n advanced: {\n korean: \"고급 훈련\",\n english: \"Advanced Training\",\n description: \"급소 정밀 타격 | Vital point precision\",\n },\n free: {\n korean: \"자유 훈련\",\n english: \"Free Practice\",\n description: \"AI 대련 | Combat vs AI opponent\",\n },\n stance_training: {\n korean: \"팔괘 수련\",\n english: \"Stance Training\",\n description: \"팔괘 전환 연습 | Eight trigrams mastery\",\n },\n vital_point: {\n korean: \"급소 훈련\",\n english: \"Vital Point Training\",\n description: \"정밀 타격 연습 | Precision targeting drill\",\n },\n combo_practice: {\n korean: \"연속 기술\",\n english: \"Combo Practice\",\n description: \"연속 타격 훈련 | Multi-hit techniques\",\n },\n footwork: {\n korean: \"보법 훈련\",\n english: \"Footwork Training\",\n description: \"보법 수련 | Movement drills\",\n },\n};\n\n/**\n * TrainingModeSelectorOverlayHtml Component\n *\n * Html overlay for selecting training mode with Korean theming.\n * Compact horizontal grid layout optimized for desktop and mobile.\n *\n * Optimized with React.memo for 60fps performance:\n * - Prevents re-renders when currentMode hasn't changed\n * - Callback expected to be stable (parent should use useCallback)\n *\n * @example\n * ```tsx\n * <TrainingModeSelectorOverlayHtml\n * currentMode=\"vital_point\"\n * onModeChange={(mode) => console.log(mode)}\n * isMobile={false}\n * />\n * ```\n *\n * @korean 훈련모드선택오버레이컴포넌트\n */\nexport const TrainingModeSelectorOverlayHtml =\n React.memo<TrainingModeSelectorOverlayHtmlProps>(\n ({ currentMode, onModeChange, isMobile }) => {\n // Use 100% width to fill container instead of fixed width\n const padding = getResponsiveSpacing(\"sm\", isMobile);\n const gap = getResponsiveSpacing(\"xs\", isMobile);\n\n // Enhanced panel styles with neon glow - now uses 100% width\n const panelStyle: React.CSSProperties = {\n ...getEnhancedKoreanOverlayStyles({\n opacity: 0.9,\n glowIntensity: \"medium\",\n includeGradient: false,\n includeBackdropBlur: true,\n depthLayers: 3,\n }),\n width: \"100%\",\n padding: `${padding}px`,\n boxSizing: \"border-box\",\n };\n\n const titleFontSize = isMobile ? 13 : 15;\n const descFontSize = isMobile ? 9 : 10;\n\n return (\n <div style={panelStyle} data-testid=\"training-mode-selector-html\">\n {/* Header with bilingual title */}\n <div style={{ marginBottom: `${SPACING.SM}px`, textAlign: \"center\" }}>\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN),\n fontFamily: FONT_FAMILY.KOREAN,\n textShadow: getNeonTextShadow(\n KOREAN_COLORS.PRIMARY_CYAN,\n \"medium\",\n ),\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n >\n {formatBilingualText(\"훈련 모드\", \"Training Mode\", \"pipe\")}\n </div>\n <div\n style={{\n fontSize: `${descFontSize}px`,\n color: hexToRgbaString(KOREAN_COLORS.TEXT_TERTIARY),\n fontStyle: \"italic\",\n marginTop: \"2px\",\n minHeight: \"16px\",\n fontFamily: FONT_FAMILY.KOREAN,\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n >\n {MODE_INFO[currentMode].description}\n </div>\n </div>\n\n {/* Mode Buttons - Grid layout (2 columns to fit narrow side HUD) */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: \"repeat(2, 1fr)\",\n gap: `${gap}px`,\n }}\n >\n {(Object.keys(MODE_INFO) as TrainingMode[]).map((mode) => {\n const isSelected = mode === currentMode;\n const info = MODE_INFO[mode];\n\n return (\n <button\n key={mode}\n onClick={() => onModeChange(mode)}\n className={`mode-button ${isSelected ? \"selected\" : \"\"}`}\n style={{\n padding: isMobile ? \"6px 4px\" : \"8px 6px\",\n textAlign: \"center\",\n fontSize: isMobile ? \"10px\" : \"11px\",\n minHeight: isMobile ? \"45px\" : \"50px\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n fontFamily: FONT_FAMILY.KOREAN,\n }}\n data-testid={`mode-${mode}`}\n >\n <div\n style={{\n fontWeight: \"bold\",\n color: hexToRgbaString(\n isSelected\n ? KOREAN_COLORS.PRIMARY_CYAN\n : KOREAN_COLORS.TEXT_PRIMARY,\n ),\n fontSize: isMobile ? \"11px\" : \"12px\",\n marginBottom: \"2px\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n width: \"100%\",\n minWidth: 0,\n }}\n >\n {info.korean}\n </div>\n <div\n style={{\n fontSize: isMobile ? \"8px\" : \"9px\",\n color: hexToRgbaString(\n isSelected\n ? KOREAN_COLORS.ACCENT_GOLD\n : KOREAN_COLORS.TEXT_TERTIARY,\n ),\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n width: \"100%\",\n minWidth: 0,\n }}\n >\n {info.english}\n </div>\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n (prevProps, nextProps) => {\n // Only re-render if current mode, mobile state, or mode change callback changes.\n // Including onModeChange here prevents stale callback closures when the parent\n // provides a new function that captures updated state.\n return (\n prevProps.currentMode === nextProps.currentMode &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.onModeChange === nextProps.onModeChange\n );\n },\n );\n\nTrainingModeSelectorOverlayHtml.displayName = \"TrainingModeSelectorOverlayHtml\";\n\nexport default TrainingModeSelectorOverlayHtml;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAqDA,IAAM,YAGF;CACF,QAAQ;EACN,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACD,UAAU;EACR,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACD,MAAM;EACJ,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACD,iBAAiB;EACf,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACD,aAAa;EACX,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACD,gBAAgB;EACd,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACD,UAAU;EACR,QAAQ;EACR,SAAS;EACT,aAAa;EACd;CACF;;;;;;;;;;;;;;;;;;;;;;AAuBD,IAAa,kCACX,MAAM,MACH,EAAE,aAAa,cAAc,eAAe;CAE3C,MAAM,UAAU,qBAAqB,MAAM,SAAS;CACpD,MAAM,MAAM,qBAAqB,MAAM,SAAS;CAGhD,MAAM,aAAkC;EACtC,GAAG,+BAA+B;GAChC,SAAS;GACT,eAAe;GACf,iBAAiB;GACjB,qBAAqB;GACrB,aAAa;GACd,CAAC;EACF,OAAO;EACP,SAAS,GAAG,QAAQ;EACpB,WAAW;EACZ;CAED,MAAM,gBAAgB,WAAW,KAAK;CACtC,MAAM,eAAe,WAAW,IAAI;CAEpC,OACE,qBAAC,OAAD;EAAK,OAAO;EAAY,eAAY;YAApC,CAEE,qBAAC,OAAD;GAAK,OAAO;IAAE,cAAc,GAAG,QAAQ,GAAG;IAAK,WAAW;IAAU;aAApE,CACE,oBAAC,OAAD;IACE,OAAO;KACL,UAAU,GAAG,cAAc;KAC3B,YAAY;KACZ,OAAO,gBAAgB,cAAc,aAAa;KAClD,YAAY,YAAY;KACxB,YAAY,kBACV,cAAc,cACd,SACD;KACD,YAAY,oBAAoB,OAAO,SAAS;KACjD;cAEA,oBAAoB,SAAS,iBAAiB,OAAO;IAClD,CAAA,EACN,oBAAC,OAAD;IACE,OAAO;KACL,UAAU,GAAG,aAAa;KAC1B,OAAO,gBAAgB,cAAc,cAAc;KACnD,WAAW;KACX,WAAW;KACX,WAAW;KACX,YAAY,YAAY;KACxB,YAAY,oBAAoB,OAAO,SAAS;KACjD;cAEA,UAAU,aAAa;IACpB,CAAA,CACF;MAGN,oBAAC,OAAD;GACE,OAAO;IACL,SAAS;IACT,qBAAqB;IACrB,KAAK,GAAG,IAAI;IACb;aAEC,OAAO,KAAK,UAAU,CAAoB,KAAK,SAAS;IACxD,MAAM,aAAa,SAAS;IAC5B,MAAM,OAAO,UAAU;IAEvB,OACE,qBAAC,UAAD;KAEE,eAAe,aAAa,KAAK;KACjC,WAAW,eAAe,aAAa,aAAa;KACpD,OAAO;MACL,SAAS,WAAW,YAAY;MAChC,WAAW;MACX,UAAU,WAAW,SAAS;MAC9B,WAAW,WAAW,SAAS;MAC/B,SAAS;MACT,eAAe;MACf,gBAAgB;MAChB,YAAY;MACZ,YAAY,YAAY;MACzB;KACD,eAAa,QAAQ;eAfvB,CAiBE,oBAAC,OAAD;MACE,OAAO;OACL,YAAY;OACZ,OAAO,gBACL,aACI,cAAc,eACd,cAAc,aACnB;OACD,UAAU,WAAW,SAAS;OAC9B,cAAc;OACd,UAAU;OACV,cAAc;OACd,OAAO;OACP,UAAU;OACX;gBAEA,KAAK;MACF,CAAA,EACN,oBAAC,OAAD;MACE,OAAO;OACL,UAAU,WAAW,QAAQ;OAC7B,OAAO,gBACL,aACI,cAAc,cACd,cAAc,cACnB;OACD,UAAU;OACV,cAAc;OACd,OAAO;OACP,UAAU;OACX;gBAEA,KAAK;MACF,CAAA,CACC;OAlDF,KAkDE;KAEX;GACE,CAAA,CACF;;IAGT,WAAW,cAAc;CAIxB,OACE,UAAU,gBAAgB,UAAU,eACpC,UAAU,aAAa,UAAU,YACjC,UAAU,iBAAiB,UAAU;EAG1C;AAEH,gCAAgC,cAAc"}
|
|
1
|
+
{"version":3,"file":"TrainingModeSelectorOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/training/components/TrainingModeSelectorOverlayHtml.tsx"],"sourcesContent":["/**\n * TrainingModeSelectorOverlayHtml - Html overlay for training mode selection\n *\n * Allows switching between different training modes with consistent Korean theming.\n * Uses KOREAN_COLORS constants and bilingual formatting.\n *\n * @module components/screens/training\n * @category Training UI\n * @korean 훈련모드선택오버레이\n */\n\nimport React from \"react\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { SPACING } from \"../../../../types/constants/ui\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport {\n formatBilingualText,\n getEnhancedKoreanOverlayStyles,\n getResponsiveSpacing,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport {\n getNeonTextShadow,\n getSmoothTransition,\n} from \"../../../../utils/visualEffects\";\nimport \"../training.css\";\n\n/**\n * Training mode types\n */\nexport type TrainingMode =\n | \"basics\" // Basic Training - Simple striking practice\n | \"advanced\" // Advanced Training - Vital point precision\n | \"free\" // Free Practice - Open combat vs AI\n | \"stance_training\" // Stance Training - Practice 8 trigrams\n | \"vital_point\" // Vital Point Training - Precision targeting\n | \"combo_practice\" // Combo Practice - Multi-hit techniques\n | \"footwork\"; // Footwork Training - Movement drills (보법 훈련)\n\n/**\n * Props for TrainingModeSelectorOverlayHtml component\n */\nexport interface TrainingModeSelectorOverlayHtmlProps {\n /** Currently selected training mode */\n readonly currentMode: TrainingMode;\n /** Callback when mode changes */\n readonly onModeChange: (mode: TrainingMode) => void;\n /** Whether on mobile device */\n readonly isMobile: boolean;\n}\n\n/**\n * Mode information\n */\nconst MODE_INFO: Record<\n TrainingMode,\n { korean: string; english: string; description: string }\n> = {\n basics: {\n korean: \"기본 훈련\",\n english: \"Basic Training\",\n description: \"기초 타격 연습 | Basic striking practice\",\n },\n advanced: {\n korean: \"고급 훈련\",\n english: \"Advanced Training\",\n description: \"급소 정밀 타격 | Vital point precision\",\n },\n free: {\n korean: \"자유 훈련\",\n english: \"Free Practice\",\n description: \"AI 대련 | Combat vs AI opponent\",\n },\n stance_training: {\n korean: \"팔괘 수련\",\n english: \"Stance Training\",\n description: \"팔괘 전환 연습 | Eight trigrams mastery\",\n },\n vital_point: {\n korean: \"급소 훈련\",\n english: \"Vital Point Training\",\n description: \"정밀 타격 연습 | Precision targeting drill\",\n },\n combo_practice: {\n korean: \"연속 기술\",\n english: \"Combo Practice\",\n description: \"연속 타격 훈련 | Multi-hit techniques\",\n },\n footwork: {\n korean: \"보법 훈련\",\n english: \"Footwork Training\",\n description: \"보법 수련 | Movement drills\",\n },\n};\n\n/**\n * TrainingModeSelectorOverlayHtml Component\n *\n * Html overlay for selecting training mode with Korean theming.\n * Compact horizontal grid layout optimized for desktop and mobile.\n *\n * Optimized with React.memo for 60fps performance:\n * - Prevents re-renders when currentMode hasn't changed\n * - Callback expected to be stable (parent should use useCallback)\n *\n * @example\n * ```tsx\n * <TrainingModeSelectorOverlayHtml\n * currentMode=\"vital_point\"\n * onModeChange={(mode) => console.log(mode)}\n * isMobile={false}\n * />\n * ```\n *\n * @korean 훈련모드선택오버레이컴포넌트\n */\nexport const TrainingModeSelectorOverlayHtml =\n React.memo<TrainingModeSelectorOverlayHtmlProps>(\n ({ currentMode, onModeChange, isMobile }) => {\n const padding = getResponsiveSpacing(\"sm\", isMobile);\n const gap = getResponsiveSpacing(\"xs\", isMobile);\n\n const panelStyle: React.CSSProperties = {\n ...getEnhancedKoreanOverlayStyles({\n opacity: 0.9,\n glowIntensity: \"medium\",\n includeGradient: false,\n includeBackdropBlur: true,\n depthLayers: 3,\n }),\n width: \"100%\",\n padding: `${padding}px`,\n boxSizing: \"border-box\",\n };\n\n const titleFontSize = isMobile ? 13 : 15;\n const descFontSize = isMobile ? 9 : 10;\n\n return (\n <div style={panelStyle} data-testid=\"training-mode-selector-html\">\n {/* Header with bilingual title */}\n <div style={{ marginBottom: `${SPACING.SM}px`, textAlign: \"center\" }}>\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n fontWeight: \"bold\",\n color: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN),\n fontFamily: FONT_FAMILY.KOREAN,\n textShadow: getNeonTextShadow(\n KOREAN_COLORS.PRIMARY_CYAN,\n \"medium\",\n ),\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n >\n {formatBilingualText(\"훈련 모드\", \"Training Mode\", \"pipe\")}\n </div>\n <div\n style={{\n fontSize: `${descFontSize}px`,\n color: hexToRgbaString(KOREAN_COLORS.TEXT_TERTIARY),\n fontStyle: \"italic\",\n marginTop: \"2px\",\n minHeight: \"16px\",\n fontFamily: FONT_FAMILY.KOREAN,\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n >\n {MODE_INFO[currentMode].description}\n </div>\n </div>\n\n {/* Mode Buttons - Grid layout (2 columns to fit narrow side HUD) */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: \"repeat(2, 1fr)\",\n gap: `${gap}px`,\n }}\n >\n {(Object.keys(MODE_INFO) as TrainingMode[]).map((mode) => {\n const isSelected = mode === currentMode;\n const info = MODE_INFO[mode];\n\n return (\n <button\n key={mode}\n onClick={() => onModeChange(mode)}\n className={`mode-button ${isSelected ? \"selected\" : \"\"}`}\n style={{\n padding: isMobile ? \"6px 4px\" : \"8px 6px\",\n textAlign: \"center\",\n fontSize: isMobile ? \"10px\" : \"11px\",\n minHeight: isMobile ? \"45px\" : \"50px\",\n display: \"flex\",\n flexDirection: \"column\",\n justifyContent: \"center\",\n alignItems: \"center\",\n fontFamily: FONT_FAMILY.KOREAN,\n }}\n data-testid={`mode-${mode}`}\n >\n <div\n style={{\n fontWeight: \"bold\",\n color: hexToRgbaString(\n isSelected\n ? KOREAN_COLORS.PRIMARY_CYAN\n : KOREAN_COLORS.TEXT_PRIMARY,\n ),\n fontSize: isMobile ? \"11px\" : \"12px\",\n marginBottom: \"2px\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n width: \"100%\",\n minWidth: 0,\n }}\n >\n {info.korean}\n </div>\n <div\n style={{\n fontSize: isMobile ? \"8px\" : \"9px\",\n color: hexToRgbaString(\n isSelected\n ? KOREAN_COLORS.ACCENT_GOLD\n : KOREAN_COLORS.TEXT_TERTIARY,\n ),\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n width: \"100%\",\n minWidth: 0,\n }}\n >\n {info.english}\n </div>\n </button>\n );\n })}\n </div>\n </div>\n );\n },\n (prevProps, nextProps) => {\n return (\n prevProps.currentMode === nextProps.currentMode &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.onModeChange === nextProps.onModeChange\n );\n },\n );\n\nTrainingModeSelectorOverlayHtml.displayName = \"TrainingModeSelectorOverlayHtml\";\n\nexport default TrainingModeSelectorOverlayHtml;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TrainingStatsOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingStatsOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAgBvC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,
|
|
1
|
+
{"version":3,"file":"TrainingStatsOverlayHtml.d.ts","sourceRoot":"","sources":["../../../../../src/components/screens/training/components/TrainingStatsOverlayHtml.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAgBvC;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,kCAAkC;IAClC,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC;IAC9B,+BAA+B;IAC/B,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;CAClC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,eAAO,MAAM,wBAAwB,2DAuPlC,CAAC;AAkFJ,eAAe,wBAAwB,CAAC"}
|