blacktrigram 0.7.47 → 0.7.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (471) hide show
  1. package/lib/App2.js.map +1 -1
  2. package/lib/audio/AudioAssetLoader.js.map +1 -1
  3. package/lib/audio/AudioAssetRegistry.js.map +1 -1
  4. package/lib/audio/AudioCache.js.map +1 -1
  5. package/lib/audio/AudioManager.js.map +1 -1
  6. package/lib/audio/AudioMonitor.js.map +1 -1
  7. package/lib/audio/AudioPool.js.map +1 -1
  8. package/lib/audio/AudioProvider.js.map +1 -1
  9. package/lib/audio/AudioUtils.js.map +1 -1
  10. package/lib/audio/BoneImpactAudioMap.js.map +1 -1
  11. package/lib/audio/VariantSelector.js.map +1 -1
  12. package/lib/audio/types.js.map +1 -1
  13. package/lib/components/screens/combat/CombatScreen3D.d.ts.map +1 -1
  14. package/lib/components/screens/combat/CombatScreen3D.js +29 -25
  15. package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
  16. package/lib/components/screens/combat/components/controls/CombatButtons.js.map +1 -1
  17. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
  18. package/lib/components/screens/combat/components/controls/ControlsGuide.js.map +1 -1
  19. package/lib/components/screens/combat/components/controls/KeyboardHints.js.map +1 -1
  20. package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
  21. package/lib/components/screens/combat/components/controls/PauseMenuButton.js.map +1 -1
  22. package/lib/components/screens/combat/components/controls/QuickSettings.js.map +1 -1
  23. package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
  24. package/lib/components/screens/combat/components/effects/BloodLossOverlayHtml.js.map +1 -1
  25. package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
  26. package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
  27. package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
  28. package/lib/components/screens/combat/components/effects/ConsciousnessBlur.js.map +1 -1
  29. package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
  30. package/lib/components/screens/combat/components/effects/PainVignette.js.map +1 -1
  31. package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
  32. package/lib/components/screens/combat/components/effects/TraumaOverlay3D.js.map +1 -1
  33. package/lib/components/screens/combat/components/feedback/MatchCountdown.js.map +1 -1
  34. package/lib/components/screens/combat/components/feedback/RoundAnnouncementOverlayHtml.js.map +1 -1
  35. package/lib/components/screens/combat/components/feedback/RoundDisplayStatus.js.map +1 -1
  36. package/lib/components/screens/combat/components/feedback/RoundStartAnnouncementOverlayHtml.js.map +1 -1
  37. package/lib/components/screens/combat/components/hud/CombatBottomHUD.d.ts.map +1 -1
  38. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js +2 -2
  39. package/lib/components/screens/combat/components/hud/CombatBottomHUD.js.map +1 -1
  40. package/lib/components/screens/combat/components/hud/CombatLeftHUD.js.map +1 -1
  41. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js +1 -1
  42. package/lib/components/screens/combat/components/hud/CombatPortraitStatusStrip.js.map +1 -1
  43. package/lib/components/screens/combat/components/hud/CombatRightHUD.js.map +1 -1
  44. package/lib/components/screens/combat/components/hud/CombatTopHUD.d.ts.map +1 -1
  45. package/lib/components/screens/combat/components/hud/CombatTopHUD.js +2 -1
  46. package/lib/components/screens/combat/components/hud/CombatTopHUD.js.map +1 -1
  47. package/lib/components/screens/combat/components/hud/DifficultyIndicator.js.map +1 -1
  48. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  49. package/lib/components/screens/combat/components/hud/MobileControlsWrapper.js.map +1 -1
  50. package/lib/components/screens/combat/components/hud/PlayerStateOverlayHtml.js.map +1 -1
  51. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  52. package/lib/components/screens/combat/components/indicators/InputBufferDisplay.js.map +1 -1
  53. package/lib/components/screens/combat/components/indicators/StaminaWarning.js.map +1 -1
  54. package/lib/components/screens/combat/components/indicators/TechniqueNameDisplay.js.map +1 -1
  55. package/lib/components/screens/combat/helpers/AnimationUpdater.d.ts.map +1 -1
  56. package/lib/components/screens/combat/helpers/AnimationUpdater.js +4 -2
  57. package/lib/components/screens/combat/helpers/AnimationUpdater.js.map +1 -1
  58. package/lib/components/screens/combat/helpers/combatHelpers.js.map +1 -1
  59. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  60. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  61. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  62. package/lib/components/screens/combat/hooks/useCombatAudio.js.map +1 -1
  63. package/lib/components/screens/combat/hooks/useCombatLayout.d.ts.map +1 -1
  64. package/lib/components/screens/combat/hooks/useCombatLayout.js +11 -5
  65. package/lib/components/screens/combat/hooks/useCombatLayout.js.map +1 -1
  66. package/lib/components/screens/combat/hooks/useCombatState.js.map +1 -1
  67. package/lib/components/screens/controls/ControlsScreen3D.js +1 -1
  68. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  69. package/lib/components/screens/controls/components/ControlBindingsOverlayHtml.js.map +1 -1
  70. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  71. package/lib/components/screens/controls/components/GamepadVisualization3D.js.map +1 -1
  72. package/lib/components/screens/controls/components/InteractiveControlDemoOverlayHtml.js.map +1 -1
  73. package/lib/components/screens/controls/components/Key3D.js.map +1 -1
  74. package/lib/components/screens/controls/components/VisualKeyboard3D.js.map +1 -1
  75. package/lib/components/screens/controls/constants/ControlsConstants.js.map +1 -1
  76. package/lib/components/screens/controls/hooks/useControlsState.js.map +1 -1
  77. package/lib/components/screens/endscreen/EndScreen3D.js.map +1 -1
  78. package/lib/components/screens/endscreen/components/DefeatAnimation3D.js.map +1 -1
  79. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  80. package/lib/components/screens/endscreen/components/NavigationButtonsOverlayHtml.js.map +1 -1
  81. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  82. package/lib/components/screens/endscreen/components/PerformanceRatingOverlayHtml.js.map +1 -1
  83. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  84. package/lib/components/screens/endscreen/components/WinnerDisplayOverlayHtml.js.map +1 -1
  85. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  86. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  87. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  88. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  89. package/lib/components/screens/intro/components/ArchetypeCardOverlayHtml.js.map +1 -1
  90. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  91. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  92. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  93. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  94. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  95. package/lib/components/screens/philosophy/PhilosophyScreen3D.js +1 -1
  96. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  97. package/lib/components/screens/training/TrainingScreen3D.d.ts.map +1 -1
  98. package/lib/components/screens/training/TrainingScreen3D.js +3 -11
  99. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  100. package/lib/components/screens/training/components/AnatomyControlsOverlayHtml.js.map +1 -1
  101. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  102. package/lib/components/screens/training/components/FootPlacementMarkers3D.js.map +1 -1
  103. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  104. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  105. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  106. package/lib/components/screens/training/components/TrainingControlsOverlayHtml.js.map +1 -1
  107. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  108. package/lib/components/screens/training/components/TrainingFeedbackOverlayHtml.js.map +1 -1
  109. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  110. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  111. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  112. package/lib/components/screens/training/components/VitalPointTrainingOverlayHtml.js.map +1 -1
  113. package/lib/components/screens/training/components/hud/TrainingBottomHUD.d.ts.map +1 -1
  114. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js +2 -2
  115. package/lib/components/screens/training/components/hud/TrainingBottomHUD.js.map +1 -1
  116. package/lib/components/screens/training/components/hud/TrainingLeftHUD.js.map +1 -1
  117. package/lib/components/screens/training/components/hud/TrainingRightHUD.js.map +1 -1
  118. package/lib/components/screens/training/components/hud/TrainingTopHUD.js.map +1 -1
  119. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  120. package/lib/components/screens/training/hooks/useTrainingActions.d.ts +1 -0
  121. package/lib/components/screens/training/hooks/useTrainingActions.d.ts.map +1 -1
  122. package/lib/components/screens/training/hooks/useTrainingActions.js +6 -4
  123. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  124. package/lib/components/screens/training/hooks/useTrainingLayout.d.ts.map +1 -1
  125. package/lib/components/screens/training/hooks/useTrainingLayout.js +11 -5
  126. package/lib/components/screens/training/hooks/useTrainingLayout.js.map +1 -1
  127. package/lib/components/screens/training/hooks/useTrainingState.js.map +1 -1
  128. package/lib/components/shared/base/BaseButton.js.map +1 -1
  129. package/lib/components/shared/base/BaseButtonOverlayHtml.js.map +1 -1
  130. package/lib/components/shared/base/BasePanel.js.map +1 -1
  131. package/lib/components/shared/base/BaseText.js.map +1 -1
  132. package/lib/components/shared/base/useKoreanTheme.js.map +1 -1
  133. package/lib/components/shared/debug/PerformanceDebugOverlayHtml.js.map +1 -1
  134. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  135. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  136. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  137. package/lib/components/shared/mobile/MobileControlsPure.js.map +1 -1
  138. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  139. package/lib/components/shared/mobile/TouchOptimizer.js.map +1 -1
  140. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  141. package/lib/components/shared/three/anatomy/BodySurface.js.map +1 -1
  142. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  143. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  144. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  145. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  146. package/lib/components/shared/three/anatomy/Foot3D.js.map +1 -1
  147. package/lib/components/shared/three/anatomy/Hand3D.js.map +1 -1
  148. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  149. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  150. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  151. package/lib/components/shared/three/effects/PlayerStateIndicators.js.map +1 -1
  152. package/lib/components/shared/three/effects/StanceSymbol3D.js.map +1 -1
  153. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  154. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  155. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  156. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  157. package/lib/components/shared/three/indicators/HapticFeedback.js.map +1 -1
  158. package/lib/components/shared/three/indicators/StanceChangeIndicator.js.map +1 -1
  159. package/lib/components/shared/three/models/Player3DWithTransitions.js.map +1 -1
  160. package/lib/components/shared/three/models/SkeletalPlayer3D.d.ts.map +1 -1
  161. package/lib/components/shared/three/models/SkeletalPlayer3D.js +7 -5
  162. package/lib/components/shared/three/models/SkeletalPlayer3D.js.map +1 -1
  163. package/lib/components/shared/three/optimization/AdaptiveQuality.js.map +1 -1
  164. package/lib/components/shared/three/scene/AtmosphericParticles3D.js.map +1 -1
  165. package/lib/components/shared/three/scene/BackgroundScene3D.js.map +1 -1
  166. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  167. package/lib/components/shared/three/scene/KoreanSignage3D.js.map +1 -1
  168. package/lib/components/shared/three/ui/ArchetypeCard.js.map +1 -1
  169. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  170. package/lib/components/shared/three/ui/BreathingIndicator2.js.map +1 -1
  171. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  172. package/lib/components/shared/three/ui/ComboCounter.js.map +1 -1
  173. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  174. package/lib/components/shared/three/ui/KoreanButton.js.map +1 -1
  175. package/lib/components/shared/three/ui/KoreanPanel.js.map +1 -1
  176. package/lib/components/shared/three/ui/KoreanText.js.map +1 -1
  177. package/lib/components/shared/three/ui/MenuList.js.map +1 -1
  178. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  179. package/lib/components/shared/three/ui/ProgressBar.js.map +1 -1
  180. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  181. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  182. package/lib/components/shared/three/ui/TechniqueBar.js.map +1 -1
  183. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  184. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  185. package/lib/components/shared/ui/BackButton.js.map +1 -1
  186. package/lib/components/shared/ui/BaseHUDContainer.js.map +1 -1
  187. package/lib/components/shared/ui/CombatTimer.js.map +1 -1
  188. package/lib/components/shared/ui/ErrorModal.js.map +1 -1
  189. package/lib/components/shared/ui/LoadingState.js.map +1 -1
  190. package/lib/components/shared/ui/SplashScreen.js +2 -2
  191. package/lib/components/shared/ui/SplashScreen.js.map +1 -1
  192. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  193. package/lib/components/shared/ui/VolumeControl.js.map +1 -1
  194. package/lib/components/shared/ui/shared/ConfirmDialog.js.map +1 -1
  195. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  196. package/lib/constants/bodyDimensions.js.map +1 -1
  197. package/lib/constants/bodyRenderingConstants.js.map +1 -1
  198. package/lib/data/archetypeClothing.js.map +1 -1
  199. package/lib/data/archetypePhysicalAttributes.js.map +1 -1
  200. package/lib/data/techniqueMappings.js.map +1 -1
  201. package/lib/data/techniques.js.map +1 -1
  202. package/lib/hooks/useActionFeedback.js.map +1 -1
  203. package/lib/hooks/useBalanceAnimations.js.map +1 -1
  204. package/lib/hooks/useCombatTimer.js.map +1 -1
  205. package/lib/hooks/useDebounce.js.map +1 -1
  206. package/lib/hooks/useHUDLayout.d.ts.map +1 -1
  207. package/lib/hooks/useHUDLayout.js +3 -2
  208. package/lib/hooks/useHUDLayout.js.map +1 -1
  209. package/lib/hooks/useHandPoseTransitions.js.map +1 -1
  210. package/lib/hooks/useKeyboardControls.js.map +1 -1
  211. package/lib/hooks/useMatchCountdown.js.map +1 -1
  212. package/lib/hooks/useMuscleActivation.js.map +1 -1
  213. package/lib/hooks/usePauseMenu.js.map +1 -1
  214. package/lib/hooks/usePlayerAnimation.js.map +1 -1
  215. package/lib/hooks/useResponsiveLayout.js.map +1 -1
  216. package/lib/hooks/useRoundTransition.js.map +1 -1
  217. package/lib/hooks/useSkeletalAnimation.d.ts.map +1 -1
  218. package/lib/hooks/useSkeletalAnimation.js +1 -1
  219. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  220. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  221. package/lib/hooks/useThrottle.js.map +1 -1
  222. package/lib/hooks/useTouchControls.js.map +1 -1
  223. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  224. package/lib/hooks/useWindowSize.js.map +1 -1
  225. package/lib/systems/CombatSystem.js.map +1 -1
  226. package/lib/systems/EffectCalculator.js.map +1 -1
  227. package/lib/systems/LayoutSystem.js.map +1 -1
  228. package/lib/systems/PlayerEffectManager.js.map +1 -1
  229. package/lib/systems/ResponsiveScaling.js.map +1 -1
  230. package/lib/systems/TrigramSystem.js.map +1 -1
  231. package/lib/systems/VitalPointSystem.js.map +1 -1
  232. package/lib/systems/ai/AIPersonality.js.map +1 -1
  233. package/lib/systems/ai/AdaptiveDifficulty.js +16 -16
  234. package/lib/systems/ai/AdaptiveDifficulty.js.map +1 -1
  235. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  236. package/lib/systems/ai/ComboSystem.js.map +1 -1
  237. package/lib/systems/ai/DecisionTree.js.map +1 -1
  238. package/lib/systems/ai/TrainingAI.js.map +1 -1
  239. package/lib/systems/ai/types.js.map +1 -1
  240. package/lib/systems/animation/builders/AnimationBuilder.js.map +1 -1
  241. package/lib/systems/animation/builders/HandPoseApplicator.js.map +1 -1
  242. package/lib/systems/animation/builders/HandPoses.js.map +1 -1
  243. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  244. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  245. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts +6 -0
  246. package/lib/systems/animation/builders/KickPhaseApplicator.d.ts.map +1 -1
  247. package/lib/systems/animation/builders/KickPhaseApplicator.js +16 -9
  248. package/lib/systems/animation/builders/KickPhaseApplicator.js.map +1 -1
  249. package/lib/systems/animation/builders/KoreanGuardPositions.d.ts +4 -4
  250. package/lib/systems/animation/builders/KoreanGuardPositions.js.map +1 -1
  251. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts +1 -1
  252. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.d.ts.map +1 -1
  253. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js +5 -5
  254. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  255. package/lib/systems/animation/builders/MartialArtsConstants.d.ts +112 -71
  256. package/lib/systems/animation/builders/MartialArtsConstants.d.ts.map +1 -1
  257. package/lib/systems/animation/builders/MartialArtsConstants.js +113 -72
  258. package/lib/systems/animation/builders/MartialArtsConstants.js.map +1 -1
  259. package/lib/systems/animation/builders/MartialPoseApplicator.js.map +1 -1
  260. package/lib/systems/animation/builders/PunchPhaseApplicator.js.map +1 -1
  261. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  262. package/lib/systems/animation/builders/TrigramGuardApplicator.js.map +1 -1
  263. package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
  264. package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
  265. package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
  266. package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
  267. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  268. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
  269. package/lib/systems/animation/catalogs/EnhancedAttackAnimations.js.map +1 -1
  270. package/lib/systems/animation/catalogs/EnhancedElbowKneeAnimations.js.map +1 -1
  271. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  272. package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
  273. package/lib/systems/animation/catalogs/GamStanceAnimations.js +21 -0
  274. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -0
  275. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js +34 -2
  276. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
  277. package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
  278. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
  279. package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
  280. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts +9 -0
  281. package/lib/systems/animation/catalogs/GonTechniqueAnimations.d.ts.map +1 -1
  282. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +288 -0
  283. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -0
  284. package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
  285. package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
  286. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
  287. package/lib/systems/animation/catalogs/KickAnimations.d.ts +2 -2
  288. package/lib/systems/animation/catalogs/KickAnimations.js +2 -2
  289. package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
  290. package/lib/systems/animation/catalogs/LiStanceAnimations.js +14 -1
  291. package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
  292. package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
  293. package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
  294. package/lib/systems/animation/catalogs/PunchAnimations.d.ts +1 -1
  295. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  296. package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
  297. package/lib/systems/animation/catalogs/RecoveryAnimations.js.map +1 -1
  298. package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
  299. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
  300. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
  301. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  302. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  303. package/lib/systems/animation/catalogs/StanceGuardPoses.d.ts +6 -6
  304. package/lib/systems/animation/catalogs/StanceGuardPoses.js +36 -36
  305. package/lib/systems/animation/catalogs/StanceGuardPoses.js.map +1 -1
  306. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  307. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  308. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  309. package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
  310. package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
  311. package/lib/systems/animation/constants/AnatomicalLimits.js.map +1 -1
  312. package/lib/systems/animation/core/AnimationHitTiming.js.map +1 -1
  313. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  314. package/lib/systems/animation/core/AnimationPriority.js +15 -15
  315. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  316. package/lib/systems/animation/core/AnimationRegistry.d.ts +30 -0
  317. package/lib/systems/animation/core/AnimationRegistry.d.ts.map +1 -1
  318. package/lib/systems/animation/core/AnimationRegistry.js +74 -12
  319. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  320. package/lib/systems/animation/core/AnimationStateMachine.js +16 -16
  321. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  322. package/lib/systems/animation/core/AnimationTransitions.d.ts.map +1 -1
  323. package/lib/systems/animation/core/AnimationTransitions.js +34 -0
  324. package/lib/systems/animation/core/AnimationTransitions.js.map +1 -1
  325. package/lib/systems/animation/core/LateralityTransform.js.map +1 -1
  326. package/lib/systems/animation/core/RecoveryPhaseEnhancer.js.map +1 -1
  327. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  328. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  329. package/lib/systems/animation/core/index.d.ts +1 -1
  330. package/lib/systems/animation/core/index.d.ts.map +1 -1
  331. package/lib/systems/animation/core/types.d.ts +24 -0
  332. package/lib/systems/animation/core/types.d.ts.map +1 -1
  333. package/lib/systems/animation/core/types.js +27 -11
  334. package/lib/systems/animation/core/types.js.map +1 -1
  335. package/lib/systems/animation/systems/AdvancedJointMovements.js.map +1 -1
  336. package/lib/systems/animation/systems/BodyFacingSystem.js.map +1 -1
  337. package/lib/systems/animation/systems/FacialExpressions.js.map +1 -1
  338. package/lib/systems/animation/systems/FallAnimations.js.map +1 -1
  339. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  340. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  341. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  342. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  343. package/lib/systems/bodypart/CombatInjuryIntegration.js.map +1 -1
  344. package/lib/systems/bodypart/InjuryIntegration.js.map +1 -1
  345. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  346. package/lib/systems/bodypart/MovementPenaltySystem.js.map +1 -1
  347. package/lib/systems/bodypart/PlayerInjuryTrackingManager.js.map +1 -1
  348. package/lib/systems/bodypart/types.js.map +1 -1
  349. package/lib/systems/breathing/BreathingDisruptionSystem.js +19 -19
  350. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  351. package/lib/systems/breathing/feedback.js.map +1 -1
  352. package/lib/systems/breathing/integration.js.map +1 -1
  353. package/lib/systems/combat/BalanceSystem.js +19 -19
  354. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  355. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  356. package/lib/systems/combat/CombatStateSystem.js +17 -17
  357. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  358. package/lib/systems/combat/ConsciousnessSystem.js +24 -24
  359. package/lib/systems/combat/ConsciousnessSystem.js.map +1 -1
  360. package/lib/systems/combat/FallIntegration.js.map +1 -1
  361. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  362. package/lib/systems/combat/LimbExposureSystem.js.map +1 -1
  363. package/lib/systems/combat/PainResponseSystem.js +21 -21
  364. package/lib/systems/combat/PainResponseSystem.js.map +1 -1
  365. package/lib/systems/combat/TrainingCombatSystem.js.map +1 -1
  366. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  367. package/lib/systems/combat/typeGuards.js.map +1 -1
  368. package/lib/systems/effects.js.map +1 -1
  369. package/lib/systems/game.js.map +1 -1
  370. package/lib/systems/movement/InjuryMovementModifier.js.map +1 -1
  371. package/lib/systems/movement/helpers/AccelerationUpdater.js.map +1 -1
  372. package/lib/systems/movement/helpers/accelerationUtils.js.map +1 -1
  373. package/lib/systems/movement/integration.js.map +1 -1
  374. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  375. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  376. package/lib/systems/physics/CoordinateMapper.js.map +1 -1
  377. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  378. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  379. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  380. package/lib/systems/physics/SpeedModifierSystem.js +6 -6
  381. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  382. package/lib/systems/trigram/KoreanCulture.js.map +1 -1
  383. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  384. package/lib/systems/trigram/StanceManager.js.map +1 -1
  385. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  386. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  387. package/lib/systems/trigram/techniques/DarkOpsTechniques.js.map +1 -1
  388. package/lib/systems/trigram/techniques/GamTechniques.js.map +1 -1
  389. package/lib/systems/trigram/techniques/GanTechniques.js.map +1 -1
  390. package/lib/systems/trigram/techniques/GeonTechniques.js.map +1 -1
  391. package/lib/systems/trigram/techniques/GonTechniques.js.map +1 -1
  392. package/lib/systems/trigram/techniques/JinTechniques.js.map +1 -1
  393. package/lib/systems/trigram/techniques/LiTechniques.js.map +1 -1
  394. package/lib/systems/trigram/techniques/SonTechniques.js.map +1 -1
  395. package/lib/systems/trigram/techniques/TaeTechniques.js.map +1 -1
  396. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  397. package/lib/systems/trigram/techniques/index.js.map +1 -1
  398. package/lib/systems/trigram/types/GonTechniqueExtensions.js.map +1 -1
  399. package/lib/systems/trigram/types.js.map +1 -1
  400. package/lib/systems/types.js.map +1 -1
  401. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  402. package/lib/systems/vitalpoint/HitDetection.js.map +1 -1
  403. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  404. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  405. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  406. package/lib/systems/vitalpoint/VitalPointsData.js.map +1 -1
  407. package/lib/types/AccessibilityTypes.js.map +1 -1
  408. package/lib/types/LayoutTypes.js.map +1 -1
  409. package/lib/types/PhysicsTypes.js.map +1 -1
  410. package/lib/types/common.js.map +1 -1
  411. package/lib/types/constants/animations.js.map +1 -1
  412. package/lib/types/constants/colors.js.map +1 -1
  413. package/lib/types/constants/designSystem.js.map +1 -1
  414. package/lib/types/constants/index.js.map +1 -1
  415. package/lib/types/constants/layout.d.ts +21 -0
  416. package/lib/types/constants/layout.d.ts.map +1 -1
  417. package/lib/types/constants/layout.js +22 -1
  418. package/lib/types/constants/layout.js.map +1 -1
  419. package/lib/types/constants/performance.js.map +1 -1
  420. package/lib/types/constants/typography.js.map +1 -1
  421. package/lib/types/constants/ui.js.map +1 -1
  422. package/lib/types/facial.js +19 -19
  423. package/lib/types/facial.js.map +1 -1
  424. package/lib/types/hand-animation.js.map +1 -1
  425. package/lib/types/injury.js.map +1 -1
  426. package/lib/types/muscle.js.map +1 -1
  427. package/lib/types/physics.js.map +1 -1
  428. package/lib/types/physicsConstants.js.map +1 -1
  429. package/lib/types/player-visual.d.ts +1 -1
  430. package/lib/types/player-visual.d.ts.map +1 -1
  431. package/lib/types/skeletal.js.map +1 -1
  432. package/lib/types/techniqueId.js.map +1 -1
  433. package/lib/utils/accessibility.js.map +1 -1
  434. package/lib/utils/arenaWorldDimensions.js.map +1 -1
  435. package/lib/utils/assetConfig.js.map +1 -1
  436. package/lib/utils/characterScaling.js.map +1 -1
  437. package/lib/utils/colorHelpers.js.map +1 -1
  438. package/lib/utils/colorUtils.js.map +1 -1
  439. package/lib/utils/combatReadiness.js.map +1 -1
  440. package/lib/utils/controlMapping.js.map +1 -1
  441. package/lib/utils/deviceDetection.js +6 -7
  442. package/lib/utils/deviceDetection.js.map +1 -1
  443. package/lib/utils/effectUtils.js.map +1 -1
  444. package/lib/utils/fabricTextures.js.map +1 -1
  445. package/lib/utils/hapticFeedback.js.map +1 -1
  446. package/lib/utils/haptics.js.map +1 -1
  447. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  448. package/lib/utils/inputSystem.js.map +1 -1
  449. package/lib/utils/koreanThemeHelpers.js.map +1 -1
  450. package/lib/utils/math.js.map +1 -1
  451. package/lib/utils/mobileLayoutHelpers.js.map +1 -1
  452. package/lib/utils/mobileUIUtils.js.map +1 -1
  453. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  454. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  455. package/lib/utils/performance/usePerformanceMonitor.js.map +1 -1
  456. package/lib/utils/performanceOptimization.js.map +1 -1
  457. package/lib/utils/player3DHelpers.js.map +1 -1
  458. package/lib/utils/playerUtils.js.map +1 -1
  459. package/lib/utils/responsiveLayout.js.map +1 -1
  460. package/lib/utils/responsiveLayoutHelpers.d.ts +7 -0
  461. package/lib/utils/responsiveLayoutHelpers.d.ts.map +1 -1
  462. package/lib/utils/responsiveLayoutHelpers.js +16 -2
  463. package/lib/utils/responsiveLayoutHelpers.js.map +1 -1
  464. package/lib/utils/responsiveOrientationConstants.js.map +1 -1
  465. package/lib/utils/safeAreaUtils.js.map +1 -1
  466. package/lib/utils/sharedPhysicsConfig.js.map +1 -1
  467. package/lib/utils/skeletonScaling.js.map +1 -1
  468. package/lib/utils/stanceHelpers.js.map +1 -1
  469. package/lib/utils/threeObjectPool.js.map +1 -1
  470. package/lib/utils/visualEffects.js.map +1 -1
  471. package/package.json +7 -7
@@ -1 +1 @@
1
- {"version":3,"file":"ArchetypeCardOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/ArchetypeCardOverlayHtml.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport { PlayerArchetype } from \"../../../../types/common\";\nimport { FALLBACK_ARCHETYPE_IMAGE, FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString, hexColorToCSS } from \"../../../../utils/colorUtils\";\nimport { BaseButtonOverlayHtml } from \"../../../shared/base/BaseButtonOverlayHtml\";\nimport { AbilityList } from \"./AbilityListOverlayHtml\";\nimport { StatBar } from \"./StatBarOverlayHtml\";\n\nexport interface ArchetypeCardData {\n readonly archetype: PlayerArchetype;\n readonly id: string;\n readonly korean: string;\n readonly english: string;\n readonly description: string;\n readonly color: number;\n readonly textureKey: string;\n readonly stats: {\n readonly attackPower: number;\n readonly defense: number;\n readonly speed: number;\n readonly technique: number;\n };\n readonly philosophy: {\n readonly korean: string;\n readonly english: string;\n };\n readonly specialAbilities?: readonly string[];\n}\n\nexport interface ArchetypeCardProps {\n readonly data: ArchetypeCardData;\n readonly isSelected: boolean;\n readonly onSelect: () => void;\n readonly onConfirm?: () => void;\n readonly isMobile?: boolean;\n readonly width?: number;\n readonly showSelectButton?: boolean;\n}\n\n/**\n * ArchetypeCard component - Displays detailed archetype preview card\n * Shows stats, abilities, philosophy, and selection interface\n */\nexport const ArchetypeCard: React.FC<ArchetypeCardProps> = React.memo(\n ({\n data,\n isSelected,\n onSelect,\n onConfirm,\n isMobile = false,\n width = 380,\n showSelectButton = true,\n }) => {\n const {\n archetype,\n korean,\n english,\n color,\n textureKey,\n stats,\n philosophy,\n specialAbilities = [],\n } = data;\n\n const cardWidth = isMobile ? Math.min(280, width) : width;\n const imageSize = isMobile ? 120 : 160;\n const padding = isMobile ? 16 : 24;\n const gap = isMobile ? 10 : 16;\n\n const colors = useMemo(\n () => ({\n background: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.95),\n border: hexToRgbaString(\n isSelected ? KOREAN_COLORS.ACCENT_GOLD : color,\n isSelected ? 1 : 0.7\n ),\n cardColor: hexColorToCSS(color),\n titleColor: isSelected\n ? hexColorToCSS(KOREAN_COLORS.ACCENT_GOLD)\n : hexColorToCSS(color),\n philosophyColor: hexColorToCSS(KOREAN_COLORS.TEXT_SECONDARY),\n buttonBackground: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.9),\n buttonText: hexColorToCSS(KOREAN_COLORS.UI_BACKGROUND_DARK),\n imageGlow: hexToRgbaString(color, 0.3),\n }),\n [color, isSelected]\n );\n\n const handleCardClick = useCallback(() => {\n if (!isSelected) {\n onSelect();\n }\n }, [isSelected, onSelect]);\n\n const handleConfirmClick = useCallback(() => {\n onConfirm?.();\n }, [onConfirm]);\n\n const imagePath = `/assets/visual/archetypes/${textureKey}.png`;\n\n const statBars = useMemo(\n () => [\n {\n label: \"공격 | Attack\",\n value: stats.attackPower,\n },\n {\n label: \"방어 | Defense\",\n value: stats.defense,\n },\n {\n label: \"속도 | Speed\",\n value: stats.speed,\n },\n {\n label: \"기술 | Technique\",\n value: stats.technique,\n },\n ],\n [stats]\n );\n\n return (\n <div\n onClick={handleCardClick}\n onKeyDown={(e) => {\n if ((e.key === \"Enter\" || e.key === \" \") && !isSelected) {\n e.preventDefault();\n onSelect();\n }\n }}\n tabIndex={0}\n role=\"button\"\n aria-label={`${korean} ${english} archetype card`}\n aria-pressed={isSelected}\n style={{\n width: `${cardWidth}px`,\n padding: `${padding}px`,\n backgroundColor: colors.background,\n border: `${isSelected ? \"3px\" : \"2px\"} solid ${colors.border}`,\n borderRadius: \"12px\",\n cursor: isSelected ? \"default\" : \"pointer\",\n transition: \"all 0.3s ease\",\n transform: isSelected ? \"scale(1.05)\" : \"scale(1)\",\n boxShadow: isSelected\n ? `0 0 20px ${colors.imageGlow}, 0 4px 8px rgba(0, 0, 0, 0.3)`\n : \"0 2px 4px rgba(0, 0, 0, 0.2)\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: `${gap}px`,\n position: \"relative\",\n overflow: \"hidden\",\n }}\n data-testid={`archetype-card-${archetype}`}\n >\n {/* Selected indicator badge */}\n {isSelected && (\n <div\n style={{\n position: \"absolute\",\n top: 10,\n right: 10,\n padding: \"4px 8px\",\n background: colors.buttonBackground,\n color: colors.buttonText,\n fontSize: isMobile ? \"10px\" : \"12px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n borderRadius: \"4px\",\n zIndex: 10,\n }}\n data-testid=\"selected-badge\"\n >\n 선택됨 | Selected\n </div>\n )}\n\n {/* Character Image */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n marginBottom: `${gap / 2}px`,\n }}\n >\n <div\n style={{\n width: `${imageSize}px`,\n height: `${imageSize}px`,\n background: `radial-gradient(circle, ${colors.imageGlow}, transparent)`,\n borderRadius: \"8px\",\n border: `2px solid ${colors.cardColor}`,\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n overflow: \"hidden\",\n }}\n data-testid=\"archetype-image-container\"\n >\n <img\n src={imagePath}\n alt={`${korean} - ${english}`}\n style={{\n width: `${imageSize - 10}px`,\n height: `${imageSize - 10}px`,\n objectFit: \"contain\",\n }}\n data-testid=\"archetype-image\"\n onError={(e) => {\n const target = e.currentTarget as HTMLImageElement;\n if (!target.src.endsWith(FALLBACK_ARCHETYPE_IMAGE)) {\n target.src = FALLBACK_ARCHETYPE_IMAGE;\n }\n }}\n />\n </div>\n </div>\n\n {/* Archetype Name */}\n <h2\n style={{\n fontSize: isMobile ? \"20px\" : \"28px\",\n color: colors.titleColor,\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n margin: 0,\n textAlign: \"center\",\n textShadow: `0 0 10px ${colors.imageGlow}`,\n }}\n data-testid=\"archetype-name\"\n >\n {korean}\n <br />\n <span\n style={{\n fontSize: isMobile ? \"16px\" : \"22px\",\n }}\n >\n {english}\n </span>\n </h2>\n\n {/* Philosophy/Description */}\n <p\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: colors.philosophyColor,\n fontFamily: FONT_FAMILY.KOREAN,\n margin: 0,\n lineHeight: \"1.5\",\n textAlign: \"center\",\n fontStyle: \"italic\",\n }}\n data-testid=\"archetype-philosophy\"\n >\n {philosophy.korean}\n <br />\n {philosophy.english}\n </p>\n\n {/* Stats Visualization */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n marginTop: `${gap / 2}px`,\n }}\n data-testid=\"archetype-stats\"\n >\n <div\n style={{\n fontSize: isMobile ? \"14px\" : \"16px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: colors.cardColor,\n }}\n >\n 전투 능력치 | Combat Stats\n </div>\n\n {statBars.map((stat) => (\n <StatBar\n key={stat.label}\n label={stat.label}\n value={stat.value}\n max={100}\n color={color}\n height={isMobile ? 10 : 12}\n showValue={true}\n isMobile={isMobile}\n />\n ))}\n </div>\n\n {/* Special Abilities */}\n {specialAbilities.length > 0 && (\n <div style={{ marginTop: `${gap / 2}px` }}>\n <AbilityList\n abilities={specialAbilities}\n maxAbilities={3}\n color={color}\n isMobile={isMobile}\n />\n </div>\n )}\n\n {/* Select Button */}\n {isSelected && showSelectButton && onConfirm && (\n <div \n style={{ marginTop: `${gap}px` }}\n onClick={(e) => e.stopPropagation()}\n >\n <BaseButtonOverlayHtml\n korean=\"선택\"\n english=\"Select\"\n onClick={handleConfirmClick}\n variant=\"primary\"\n size={isMobile ? \"sm\" : \"md\"}\n fullWidth={true}\n testId={`select-button-${archetype}`}\n isMobile={isMobile}\n ariaLabel={`Select ${korean} ${english} archetype`}\n />\n </div>\n )}\n </div>\n );\n }\n);\n\nArchetypeCard.displayName = \"ArchetypeCard\";\n\nexport default ArchetypeCard;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ArchetypeCardOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/ArchetypeCardOverlayHtml.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport { PlayerArchetype } from \"../../../../types/common\";\nimport { FALLBACK_ARCHETYPE_IMAGE, FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString, hexColorToCSS } from \"../../../../utils/colorUtils\";\nimport { BaseButtonOverlayHtml } from \"../../../shared/base/BaseButtonOverlayHtml\";\nimport { AbilityList } from \"./AbilityListOverlayHtml\";\nimport { StatBar } from \"./StatBarOverlayHtml\";\n\nexport interface ArchetypeCardData {\n readonly archetype: PlayerArchetype;\n readonly id: string;\n readonly korean: string;\n readonly english: string;\n readonly description: string;\n readonly color: number;\n readonly textureKey: string;\n readonly stats: {\n readonly attackPower: number;\n readonly defense: number;\n readonly speed: number;\n readonly technique: number;\n };\n readonly philosophy: {\n readonly korean: string;\n readonly english: string;\n };\n readonly specialAbilities?: readonly string[];\n}\n\nexport interface ArchetypeCardProps {\n readonly data: ArchetypeCardData;\n readonly isSelected: boolean;\n readonly onSelect: () => void;\n readonly onConfirm?: () => void;\n readonly isMobile?: boolean;\n readonly width?: number;\n readonly showSelectButton?: boolean;\n}\n\n/**\n * ArchetypeCard component - Displays detailed archetype preview card\n * Shows stats, abilities, philosophy, and selection interface\n */\nexport const ArchetypeCard: React.FC<ArchetypeCardProps> = React.memo(\n ({\n data,\n isSelected,\n onSelect,\n onConfirm,\n isMobile = false,\n width = 380,\n showSelectButton = true,\n }) => {\n const {\n archetype,\n korean,\n english,\n color,\n textureKey,\n stats,\n philosophy,\n specialAbilities = [],\n } = data;\n\n const cardWidth = isMobile ? Math.min(280, width) : width;\n const imageSize = isMobile ? 120 : 160;\n const padding = isMobile ? 16 : 24;\n const gap = isMobile ? 10 : 16;\n\n const colors = useMemo(\n () => ({\n background: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.95),\n border: hexToRgbaString(\n isSelected ? KOREAN_COLORS.ACCENT_GOLD : color,\n isSelected ? 1 : 0.7\n ),\n cardColor: hexColorToCSS(color),\n titleColor: isSelected\n ? hexColorToCSS(KOREAN_COLORS.ACCENT_GOLD)\n : hexColorToCSS(color),\n philosophyColor: hexColorToCSS(KOREAN_COLORS.TEXT_SECONDARY),\n buttonBackground: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.9),\n buttonText: hexColorToCSS(KOREAN_COLORS.UI_BACKGROUND_DARK),\n imageGlow: hexToRgbaString(color, 0.3),\n }),\n [color, isSelected]\n );\n\n const handleCardClick = useCallback(() => {\n if (!isSelected) {\n onSelect();\n }\n }, [isSelected, onSelect]);\n\n const handleConfirmClick = useCallback(() => {\n onConfirm?.();\n }, [onConfirm]);\n\n const imagePath = `/assets/visual/archetypes/${textureKey}.png`;\n\n const statBars = useMemo(\n () => [\n {\n label: \"공격 | Attack\",\n value: stats.attackPower,\n },\n {\n label: \"방어 | Defense\",\n value: stats.defense,\n },\n {\n label: \"속도 | Speed\",\n value: stats.speed,\n },\n {\n label: \"기술 | Technique\",\n value: stats.technique,\n },\n ],\n [stats]\n );\n\n return (\n <div\n onClick={handleCardClick}\n onKeyDown={(e) => {\n if ((e.key === \"Enter\" || e.key === \" \") && !isSelected) {\n e.preventDefault();\n onSelect();\n }\n }}\n tabIndex={0}\n role=\"button\"\n aria-label={`${korean} ${english} archetype card`}\n aria-pressed={isSelected}\n style={{\n width: `${cardWidth}px`,\n padding: `${padding}px`,\n backgroundColor: colors.background,\n border: `${isSelected ? \"3px\" : \"2px\"} solid ${colors.border}`,\n borderRadius: \"12px\",\n cursor: isSelected ? \"default\" : \"pointer\",\n transition: \"all 0.3s ease\",\n transform: isSelected ? \"scale(1.05)\" : \"scale(1)\",\n boxShadow: isSelected\n ? `0 0 20px ${colors.imageGlow}, 0 4px 8px rgba(0, 0, 0, 0.3)`\n : \"0 2px 4px rgba(0, 0, 0, 0.2)\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: `${gap}px`,\n position: \"relative\",\n overflow: \"hidden\",\n }}\n data-testid={`archetype-card-${archetype}`}\n >\n {/* Selected indicator badge */}\n {isSelected && (\n <div\n style={{\n position: \"absolute\",\n top: 10,\n right: 10,\n padding: \"4px 8px\",\n background: colors.buttonBackground,\n color: colors.buttonText,\n fontSize: isMobile ? \"10px\" : \"12px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n borderRadius: \"4px\",\n zIndex: 10,\n }}\n data-testid=\"selected-badge\"\n >\n 선택됨 | Selected\n </div>\n )}\n\n {/* Character Image */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n marginBottom: `${gap / 2}px`,\n }}\n >\n <div\n style={{\n width: `${imageSize}px`,\n height: `${imageSize}px`,\n background: `radial-gradient(circle, ${colors.imageGlow}, transparent)`,\n borderRadius: \"8px\",\n border: `2px solid ${colors.cardColor}`,\n display: \"flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n overflow: \"hidden\",\n }}\n data-testid=\"archetype-image-container\"\n >\n <img\n src={imagePath}\n alt={`${korean} - ${english}`}\n style={{\n width: `${imageSize - 10}px`,\n height: `${imageSize - 10}px`,\n objectFit: \"contain\",\n }}\n data-testid=\"archetype-image\"\n onError={(e) => {\n const target = e.currentTarget as HTMLImageElement;\n if (!target.src.endsWith(FALLBACK_ARCHETYPE_IMAGE)) {\n target.src = FALLBACK_ARCHETYPE_IMAGE;\n }\n }}\n />\n </div>\n </div>\n\n {/* Archetype Name */}\n <h2\n style={{\n fontSize: isMobile ? \"20px\" : \"28px\",\n color: colors.titleColor,\n fontFamily: FONT_FAMILY.KOREAN,\n fontWeight: \"bold\",\n margin: 0,\n textAlign: \"center\",\n textShadow: `0 0 10px ${colors.imageGlow}`,\n }}\n data-testid=\"archetype-name\"\n >\n {korean}\n <br />\n <span\n style={{\n fontSize: isMobile ? \"16px\" : \"22px\",\n }}\n >\n {english}\n </span>\n </h2>\n\n {/* Philosophy/Description */}\n <p\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: colors.philosophyColor,\n fontFamily: FONT_FAMILY.KOREAN,\n margin: 0,\n lineHeight: \"1.5\",\n textAlign: \"center\",\n fontStyle: \"italic\",\n }}\n data-testid=\"archetype-philosophy\"\n >\n {philosophy.korean}\n <br />\n {philosophy.english}\n </p>\n\n {/* Stats Visualization */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n marginTop: `${gap / 2}px`,\n }}\n data-testid=\"archetype-stats\"\n >\n <div\n style={{\n fontSize: isMobile ? \"14px\" : \"16px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: colors.cardColor,\n }}\n >\n 전투 능력치 | Combat Stats\n </div>\n\n {statBars.map((stat) => (\n <StatBar\n key={stat.label}\n label={stat.label}\n value={stat.value}\n max={100}\n color={color}\n height={isMobile ? 10 : 12}\n showValue={true}\n isMobile={isMobile}\n />\n ))}\n </div>\n\n {/* Special Abilities */}\n {specialAbilities.length > 0 && (\n <div style={{ marginTop: `${gap / 2}px` }}>\n <AbilityList\n abilities={specialAbilities}\n maxAbilities={3}\n color={color}\n isMobile={isMobile}\n />\n </div>\n )}\n\n {/* Select Button */}\n {isSelected && showSelectButton && onConfirm && (\n <div \n style={{ marginTop: `${gap}px` }}\n onClick={(e) => e.stopPropagation()}\n >\n <BaseButtonOverlayHtml\n korean=\"선택\"\n english=\"Select\"\n onClick={handleConfirmClick}\n variant=\"primary\"\n size={isMobile ? \"sm\" : \"md\"}\n fullWidth={true}\n testId={`select-button-${archetype}`}\n isMobile={isMobile}\n ariaLabel={`Select ${korean} ${english} archetype`}\n />\n </div>\n )}\n </div>\n );\n }\n);\n\nArchetypeCard.displayName = \"ArchetypeCard\";\n\nexport default ArchetypeCard;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"ArchetypeDisplayOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/ArchetypeDisplayOverlayHtml.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport {\n FALLBACK_ARCHETYPE_IMAGE,\n FONT_FAMILY,\n KOREAN_COLORS,\n} from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport { getEnhancedKoreanOverlayStyles } from \"../../../../utils/koreanThemeHelpers\";\nimport {\n getKoreanFontOptimization,\n getNeonTextShadow,\n getSmoothTransition,\n} from \"../../../../utils/visualEffects\";\nimport { StatBar } from \"./StatBarOverlayHtml\";\n\nexport interface ArchetypeDataShape {\n readonly id: string;\n readonly korean: string;\n readonly english: string;\n readonly description: string;\n readonly color: number;\n readonly textureKey: string;\n readonly stats: {\n readonly attackPower: number;\n readonly defense: number;\n readonly speed: number;\n readonly technique: number;\n };\n readonly philosophy: {\n readonly korean: string;\n readonly english: string;\n };\n readonly specialAbilities?: readonly string[]; // Optional special abilities\n}\n\nexport interface ArchetypeDisplayOverlayHtmlProps {\n readonly archetypes: readonly ArchetypeDataShape[];\n readonly selectedIndex: number;\n readonly onArchetypeChange: (index: number) => void;\n readonly onPlaySFX: (sound: string) => void;\n readonly width?: number;\n readonly height?: number;\n readonly isMobile?: boolean;\n}\n\n/**\n * HTML-based ArchetypeDisplay component for Three.js integration\n */\nexport const ArchetypeDisplayOverlayHtml: React.FC<ArchetypeDisplayOverlayHtmlProps> =\n React.memo(\n ({\n archetypes,\n selectedIndex,\n onArchetypeChange,\n onPlaySFX,\n width = 800,\n height = 300,\n isMobile: _isMobile = false, // Kept for interface compatibility, layout uses width\n }) => {\n void _isMobile;\n const selectedArchetype = archetypes[selectedIndex];\n\n const isSmallScreen = width < 768;\n const isLargeContainer = width >= 1100;\n const archImageWidth = isSmallScreen ? 140 : isLargeContainer ? 120 : 180;\n const archImageHeight = isSmallScreen\n ? 200\n : isLargeContainer\n ? 170\n : 260;\n const containerPadding = isSmallScreen ? 20 : isLargeContainer ? 12 : 20;\n const contentGap = isSmallScreen ? 10 : isLargeContainer ? 8 : 16;\n const infoGap = isSmallScreen ? 8 : isLargeContainer ? 6 : 12;\n const titleFontSize = isSmallScreen ? 14 : isLargeContainer ? 14 : 18;\n const philosophyFontSize = isSmallScreen\n ? 10\n : isLargeContainer\n ? 10\n : 12;\n const statBarHeight = isSmallScreen ? 10 : isLargeContainer ? 10 : 12;\n\n const handlePrevious = useCallback(() => {\n const newIndex =\n selectedIndex === 0 ? archetypes.length - 1 : selectedIndex - 1;\n onArchetypeChange(newIndex);\n onPlaySFX(\"menu_hover\");\n }, [selectedIndex, archetypes.length, onArchetypeChange, onPlaySFX]);\n\n const handleNext = useCallback(() => {\n const newIndex = (selectedIndex + 1) % archetypes.length;\n onArchetypeChange(newIndex);\n onPlaySFX(\"menu_hover\");\n }, [selectedIndex, archetypes.length, onArchetypeChange, onPlaySFX]);\n\n const combatStats = useMemo(() => {\n const maxStatValue = 100;\n return [\n {\n korean: \"공격\",\n english: \"Attack\",\n value: selectedArchetype.stats.attackPower / maxStatValue,\n rawValue: selectedArchetype.stats.attackPower,\n },\n {\n korean: \"방어\",\n english: \"Defense\",\n value: selectedArchetype.stats.defense / maxStatValue,\n rawValue: selectedArchetype.stats.defense,\n },\n {\n korean: \"속도\",\n english: \"Speed\",\n value: selectedArchetype.stats.speed / maxStatValue,\n rawValue: selectedArchetype.stats.speed,\n },\n {\n korean: \"기술\",\n english: \"Technique\",\n value: selectedArchetype.stats.technique / maxStatValue,\n rawValue: selectedArchetype.stats.technique,\n },\n ];\n }, [selectedArchetype.stats]);\n\n const colors = useMemo(\n () => ({\n archetypeColor: `#${selectedArchetype.color\n .toString(16)\n .padStart(6, \"0\")}`,\n titleGold: `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n statsBackground: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n 0.9,\n ),\n statsBorder: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.5),\n statBarBackground: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n 1,\n ),\n statBarFill: hexToRgbaString(selectedArchetype.color, 0.9),\n }),\n [selectedArchetype.color],\n );\n\n const containerStyle = useMemo(\n () => ({\n ...getEnhancedKoreanOverlayStyles({\n opacity: 0.95,\n glowIntensity: \"medium\",\n includeGradient: false,\n includeBackdropBlur: false,\n depthLayers: 3,\n }),\n width: `${width}px`,\n height: `${height}px`,\n display: \"flex\",\n flexDirection: \"row\" as const,\n alignItems: \"flex-start\",\n justifyContent: \"flex-start\",\n gap: `${contentGap}px`,\n border: `2px solid ${colors.archetypeColor}`,\n padding: `${containerPadding}px`,\n position: \"relative\" as const,\n overflow: \"hidden\" as const,\n }),\n [width, height, contentGap, containerPadding, colors.archetypeColor],\n );\n\n const archetypeImagePath = useMemo(() => {\n return `/assets/visual/archetypes/${selectedArchetype.textureKey}.png`;\n }, [selectedArchetype.textureKey]);\n\n return (\n <div style={containerStyle} data-testid=\"archetype-display-container\">\n {/* Left Side - Character Image and Navigation */}\n <div\n style={{\n width: `${archImageWidth + 40}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: `${infoGap}px`,\n flexShrink: 0,\n }}\n data-testid=\"archetype-image-section\"\n >\n {/* Character Image */}\n <div\n style={{\n width: `${archImageWidth + 20}px`,\n height: `${archImageHeight + 20}px`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"relative\",\n background: `radial-gradient(circle, ${colors.archetypeColor}26, transparent)`,\n borderRadius: \"4px\",\n border: `2px solid ${colors.archetypeColor}`,\n }}\n data-testid=\"archetype-image-container\"\n >\n <img\n src={archetypeImagePath}\n alt={`${selectedArchetype.korean} - ${selectedArchetype.english}`}\n style={{\n width: `${archImageWidth}px`,\n height: `${archImageHeight}px`,\n objectFit: \"contain\",\n cursor: \"pointer\",\n }}\n onClick={handleNext}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleNext();\n }\n }}\n tabIndex={0}\n role=\"button\"\n aria-label={`${selectedArchetype.korean} ${selectedArchetype.english} - Click or press Enter to cycle to next archetype`}\n data-testid=\"archetype-image\"\n onError={(e) => {\n const target = e.currentTarget as HTMLImageElement;\n if (!target.src.endsWith(FALLBACK_ARCHETYPE_IMAGE)) {\n target.src = FALLBACK_ARCHETYPE_IMAGE;\n target.alt = `${selectedArchetype.korean} (image unavailable)`;\n }\n }}\n />\n </div>\n\n {/* Navigation Buttons */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n gap: \"8px\",\n width: \"100%\",\n }}\n data-testid=\"archetype-navigation\"\n >\n <button\n onClick={handlePrevious}\n aria-label=\"Previous archetype\"\n style={{\n flex: 1,\n height: \"30px\",\n fontSize: \"14px\",\n fontWeight: \"bold\",\n color: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n background: colors.statsBackground,\n border: `1px solid ${hexToRgbaString(\n KOREAN_COLORS.ACCENT_GOLD,\n 0.7,\n )}`,\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.outline = `3px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD)}`;\n e.currentTarget.style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n e.currentTarget.style.outline = \"none\";\n }}\n data-testid=\"prev-archetype-button\"\n >\n ◀\n </button>\n <button\n onClick={handleNext}\n aria-label=\"Next archetype\"\n style={{\n flex: 1,\n height: \"30px\",\n fontSize: \"14px\",\n fontWeight: \"bold\",\n color: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n background: colors.statsBackground,\n border: `1px solid ${hexToRgbaString(\n KOREAN_COLORS.ACCENT_GOLD,\n 0.7,\n )}`,\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.outline = `3px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD)}`;\n e.currentTarget.style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n e.currentTarget.style.outline = \"none\";\n }}\n data-testid=\"next-archetype-button\"\n >\n ▶\n </button>\n </div>\n </div>\n\n {/* Right Side - Archetype Information */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"flex-start\",\n justifyContent: \"flex-start\",\n gap: `${infoGap}px`,\n minWidth: 0,\n overflow: \"hidden\",\n }}\n data-testid=\"archetype-info\"\n >\n {/* Header with name and counter */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: colors.archetypeColor,\n textShadow: getNeonTextShadow(\n selectedArchetype.color,\n \"strong\",\n ),\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n data-testid=\"archetype-title\"\n >\n {selectedArchetype.korean} | {selectedArchetype.english}\n </div>\n <div\n style={{\n fontSize: \"12px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.PRIMARY,\n color: colors.archetypeColor,\n textShadow: getNeonTextShadow(\n selectedArchetype.color,\n \"subtle\",\n ),\n }}\n data-testid=\"archetype-counter\"\n >\n {selectedIndex + 1} / {archetypes.length}\n </div>\n </div>\n\n {/* Philosophy */}\n <div\n style={{\n fontSize: `${philosophyFontSize}px`,\n fontStyle: \"italic\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: `#${KOREAN_COLORS.TEXT_SECONDARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n lineHeight: \"1.4\",\n ...getKoreanFontOptimization(philosophyFontSize, \"normal\"),\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n data-testid=\"archetype-philosophy\"\n >\n {selectedArchetype.philosophy.korean} |{\" \"}\n {selectedArchetype.philosophy.english}\n </div>\n\n {/* Combat Stats */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n }}\n data-testid=\"combat-stats\"\n >\n <div\n style={{\n fontSize: isSmallScreen ? \"12px\" : \"14px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n }}\n >\n 전투 능력치 | Combat Stats\n </div>\n\n {/* Individual stat bars using refactored StatBar component */}\n {combatStats.map((stat) => (\n <StatBar\n key={stat.korean}\n label={`${stat.korean} | ${stat.english}`}\n value={stat.rawValue}\n max={100}\n color={selectedArchetype.color}\n height={statBarHeight}\n showValue={true}\n isMobile={isSmallScreen}\n />\n ))}\n </div>\n </div>\n </div>\n );\n },\n );\n\nArchetypeDisplayOverlayHtml.displayName = \"ArchetypeDisplayOverlayHtml\";\n\nexport default ArchetypeDisplayOverlayHtml;\n"],"mappings":"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"}
1
+ {"version":3,"file":"ArchetypeDisplayOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/ArchetypeDisplayOverlayHtml.tsx"],"sourcesContent":["import React, { useCallback, useMemo } from \"react\";\nimport {\n FALLBACK_ARCHETYPE_IMAGE,\n FONT_FAMILY,\n KOREAN_COLORS,\n} from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport { getEnhancedKoreanOverlayStyles } from \"../../../../utils/koreanThemeHelpers\";\nimport {\n getKoreanFontOptimization,\n getNeonTextShadow,\n getSmoothTransition,\n} from \"../../../../utils/visualEffects\";\nimport { StatBar } from \"./StatBarOverlayHtml\";\n\nexport interface ArchetypeDataShape {\n readonly id: string;\n readonly korean: string;\n readonly english: string;\n readonly description: string;\n readonly color: number;\n readonly textureKey: string;\n readonly stats: {\n readonly attackPower: number;\n readonly defense: number;\n readonly speed: number;\n readonly technique: number;\n };\n readonly philosophy: {\n readonly korean: string;\n readonly english: string;\n };\n readonly specialAbilities?: readonly string[]; // Optional special abilities\n}\n\nexport interface ArchetypeDisplayOverlayHtmlProps {\n readonly archetypes: readonly ArchetypeDataShape[];\n readonly selectedIndex: number;\n readonly onArchetypeChange: (index: number) => void;\n readonly onPlaySFX: (sound: string) => void;\n readonly width?: number;\n readonly height?: number;\n readonly isMobile?: boolean;\n}\n\n/**\n * HTML-based ArchetypeDisplay component for Three.js integration\n */\nexport const ArchetypeDisplayOverlayHtml: React.FC<ArchetypeDisplayOverlayHtmlProps> =\n React.memo(\n ({\n archetypes,\n selectedIndex,\n onArchetypeChange,\n onPlaySFX,\n width = 800,\n height = 300,\n isMobile: _isMobile = false, // Kept for interface compatibility, layout uses width\n }) => {\n void _isMobile;\n const selectedArchetype = archetypes[selectedIndex];\n\n const isSmallScreen = width < 768;\n const isLargeContainer = width >= 1100;\n const archImageWidth = isSmallScreen ? 140 : isLargeContainer ? 120 : 180;\n const archImageHeight = isSmallScreen\n ? 200\n : isLargeContainer\n ? 170\n : 260;\n const containerPadding = isSmallScreen ? 20 : isLargeContainer ? 12 : 20;\n const contentGap = isSmallScreen ? 10 : isLargeContainer ? 8 : 16;\n const infoGap = isSmallScreen ? 8 : isLargeContainer ? 6 : 12;\n const titleFontSize = isSmallScreen ? 14 : isLargeContainer ? 14 : 18;\n const philosophyFontSize = isSmallScreen\n ? 10\n : isLargeContainer\n ? 10\n : 12;\n const statBarHeight = isSmallScreen ? 10 : isLargeContainer ? 10 : 12;\n\n const handlePrevious = useCallback(() => {\n const newIndex =\n selectedIndex === 0 ? archetypes.length - 1 : selectedIndex - 1;\n onArchetypeChange(newIndex);\n onPlaySFX(\"menu_hover\");\n }, [selectedIndex, archetypes.length, onArchetypeChange, onPlaySFX]);\n\n const handleNext = useCallback(() => {\n const newIndex = (selectedIndex + 1) % archetypes.length;\n onArchetypeChange(newIndex);\n onPlaySFX(\"menu_hover\");\n }, [selectedIndex, archetypes.length, onArchetypeChange, onPlaySFX]);\n\n const combatStats = useMemo(() => {\n const maxStatValue = 100;\n return [\n {\n korean: \"공격\",\n english: \"Attack\",\n value: selectedArchetype.stats.attackPower / maxStatValue,\n rawValue: selectedArchetype.stats.attackPower,\n },\n {\n korean: \"방어\",\n english: \"Defense\",\n value: selectedArchetype.stats.defense / maxStatValue,\n rawValue: selectedArchetype.stats.defense,\n },\n {\n korean: \"속도\",\n english: \"Speed\",\n value: selectedArchetype.stats.speed / maxStatValue,\n rawValue: selectedArchetype.stats.speed,\n },\n {\n korean: \"기술\",\n english: \"Technique\",\n value: selectedArchetype.stats.technique / maxStatValue,\n rawValue: selectedArchetype.stats.technique,\n },\n ];\n }, [selectedArchetype.stats]);\n\n const colors = useMemo(\n () => ({\n archetypeColor: `#${selectedArchetype.color\n .toString(16)\n .padStart(6, \"0\")}`,\n titleGold: `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n statsBackground: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n 0.9,\n ),\n statsBorder: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.5),\n statBarBackground: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n 1,\n ),\n statBarFill: hexToRgbaString(selectedArchetype.color, 0.9),\n }),\n [selectedArchetype.color],\n );\n\n const containerStyle = useMemo(\n () => ({\n ...getEnhancedKoreanOverlayStyles({\n opacity: 0.95,\n glowIntensity: \"medium\",\n includeGradient: false,\n includeBackdropBlur: false,\n depthLayers: 3,\n }),\n width: `${width}px`,\n height: `${height}px`,\n display: \"flex\",\n flexDirection: \"row\" as const,\n alignItems: \"flex-start\",\n justifyContent: \"flex-start\",\n gap: `${contentGap}px`,\n border: `2px solid ${colors.archetypeColor}`,\n padding: `${containerPadding}px`,\n position: \"relative\" as const,\n overflow: \"hidden\" as const,\n }),\n [width, height, contentGap, containerPadding, colors.archetypeColor],\n );\n\n const archetypeImagePath = useMemo(() => {\n return `/assets/visual/archetypes/${selectedArchetype.textureKey}.png`;\n }, [selectedArchetype.textureKey]);\n\n return (\n <div style={containerStyle} data-testid=\"archetype-display-container\">\n {/* Left Side - Character Image and Navigation */}\n <div\n style={{\n width: `${archImageWidth + 40}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: `${infoGap}px`,\n flexShrink: 0,\n }}\n data-testid=\"archetype-image-section\"\n >\n {/* Character Image */}\n <div\n style={{\n width: `${archImageWidth + 20}px`,\n height: `${archImageHeight + 20}px`,\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n position: \"relative\",\n background: `radial-gradient(circle, ${colors.archetypeColor}26, transparent)`,\n borderRadius: \"4px\",\n border: `2px solid ${colors.archetypeColor}`,\n }}\n data-testid=\"archetype-image-container\"\n >\n <img\n src={archetypeImagePath}\n alt={`${selectedArchetype.korean} - ${selectedArchetype.english}`}\n style={{\n width: `${archImageWidth}px`,\n height: `${archImageHeight}px`,\n objectFit: \"contain\",\n cursor: \"pointer\",\n }}\n onClick={handleNext}\n onKeyDown={(e) => {\n if (e.key === \"Enter\" || e.key === \" \") {\n e.preventDefault();\n handleNext();\n }\n }}\n tabIndex={0}\n role=\"button\"\n aria-label={`${selectedArchetype.korean} ${selectedArchetype.english} - Click or press Enter to cycle to next archetype`}\n data-testid=\"archetype-image\"\n onError={(e) => {\n const target = e.currentTarget as HTMLImageElement;\n if (!target.src.endsWith(FALLBACK_ARCHETYPE_IMAGE)) {\n target.src = FALLBACK_ARCHETYPE_IMAGE;\n target.alt = `${selectedArchetype.korean} (image unavailable)`;\n }\n }}\n />\n </div>\n\n {/* Navigation Buttons */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"row\",\n gap: \"8px\",\n width: \"100%\",\n }}\n data-testid=\"archetype-navigation\"\n >\n <button\n onClick={handlePrevious}\n aria-label=\"Previous archetype\"\n style={{\n flex: 1,\n height: \"30px\",\n fontSize: \"14px\",\n fontWeight: \"bold\",\n color: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n background: colors.statsBackground,\n border: `1px solid ${hexToRgbaString(\n KOREAN_COLORS.ACCENT_GOLD,\n 0.7,\n )}`,\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.outline = `3px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD)}`;\n e.currentTarget.style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n e.currentTarget.style.outline = \"none\";\n }}\n data-testid=\"prev-archetype-button\"\n >\n ◀\n </button>\n <button\n onClick={handleNext}\n aria-label=\"Next archetype\"\n style={{\n flex: 1,\n height: \"30px\",\n fontSize: \"14px\",\n fontWeight: \"bold\",\n color: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n background: colors.statsBackground,\n border: `1px solid ${hexToRgbaString(\n KOREAN_COLORS.ACCENT_GOLD,\n 0.7,\n )}`,\n borderRadius: \"4px\",\n cursor: \"pointer\",\n }}\n onFocus={(e) => {\n e.currentTarget.style.outline = `3px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD)}`;\n e.currentTarget.style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n e.currentTarget.style.outline = \"none\";\n }}\n data-testid=\"next-archetype-button\"\n >\n ▶\n </button>\n </div>\n </div>\n\n {/* Right Side - Archetype Information */}\n <div\n style={{\n flex: 1,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"flex-start\",\n justifyContent: \"flex-start\",\n gap: `${infoGap}px`,\n minWidth: 0,\n overflow: \"hidden\",\n }}\n data-testid=\"archetype-info\"\n >\n {/* Header with name and counter */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n }}\n >\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: colors.archetypeColor,\n textShadow: getNeonTextShadow(\n selectedArchetype.color,\n \"strong\",\n ),\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n data-testid=\"archetype-title\"\n >\n {selectedArchetype.korean} | {selectedArchetype.english}\n </div>\n <div\n style={{\n fontSize: \"12px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.PRIMARY,\n color: colors.archetypeColor,\n textShadow: getNeonTextShadow(\n selectedArchetype.color,\n \"subtle\",\n ),\n }}\n data-testid=\"archetype-counter\"\n >\n {selectedIndex + 1} / {archetypes.length}\n </div>\n </div>\n\n {/* Philosophy */}\n <div\n style={{\n fontSize: `${philosophyFontSize}px`,\n fontStyle: \"italic\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: `#${KOREAN_COLORS.TEXT_SECONDARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n lineHeight: \"1.4\",\n ...getKoreanFontOptimization(philosophyFontSize, \"normal\"),\n transition: getSmoothTransition(\"all\", \"normal\"),\n }}\n data-testid=\"archetype-philosophy\"\n >\n {selectedArchetype.philosophy.korean} |{\" \"}\n {selectedArchetype.philosophy.english}\n </div>\n\n {/* Combat Stats */}\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"8px\",\n }}\n data-testid=\"combat-stats\"\n >\n <div\n style={{\n fontSize: isSmallScreen ? \"12px\" : \"14px\",\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n color: `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n }}\n >\n 전투 능력치 | Combat Stats\n </div>\n\n {/* Individual stat bars using refactored StatBar component */}\n {combatStats.map((stat) => (\n <StatBar\n key={stat.korean}\n label={`${stat.korean} | ${stat.english}`}\n value={stat.rawValue}\n max={100}\n color={selectedArchetype.color}\n height={statBarHeight}\n showValue={true}\n isMobile={isSmallScreen}\n />\n ))}\n </div>\n </div>\n </div>\n );\n },\n );\n\nArchetypeDisplayOverlayHtml.displayName = \"ArchetypeDisplayOverlayHtml\";\n\nexport default ArchetypeDisplayOverlayHtml;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"EnhancedArchetypeDisplayOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from \"react\";\nimport { PlayerArchetype } from \"../../../../types/common\";\nimport { BaseButtonOverlayHtml } from \"../../../shared/base/BaseButtonOverlayHtml\";\nimport { ArchetypeCardGrid } from \"./ArchetypeCardGridOverlayHtml\";\nimport {\n ArchetypeDataShape,\n ArchetypeDisplayOverlayHtml,\n} from \"./ArchetypeDisplayOverlayHtml\";\n\nexport interface EnhancedArchetypeDisplayProps {\n readonly archetypes: readonly ArchetypeDataShape[];\n readonly selectedIndex: number;\n readonly onArchetypeChange: (index: number) => void;\n readonly onPlaySFX: (sound: string) => void;\n readonly width?: number;\n readonly height?: number;\n readonly isMobile?: boolean; // For controls/haptics only, use width for layout sizing\n readonly allowDetailedView?: boolean; // Allow switching to card grid view\n}\n\n/**\n * EnhancedArchetypeDisplay - Provides both compact and detailed card view modes\n * Can switch between ArchetypeDisplayOverlayHtml (compact) and ArchetypeCardGrid (detailed)\n */\nexport const EnhancedArchetypeDisplay: React.FC<EnhancedArchetypeDisplayProps> =\n React.memo(\n ({\n archetypes,\n selectedIndex,\n onArchetypeChange,\n onPlaySFX,\n width = 800,\n height = 300,\n isMobile = false,\n allowDetailedView = true,\n }) => {\n const [viewMode, setViewMode] = useState<\"compact\" | \"detailed\">(\n \"compact\",\n );\n\n const isSmallScreen = width < 768;\n\n const cardData = useMemo(() => {\n return archetypes.map((archetype) => ({\n archetype: Object.values(PlayerArchetype).find(\n (key) => key === archetype.id,\n ) as PlayerArchetype,\n id: archetype.id,\n korean: archetype.korean,\n english: archetype.english,\n description: archetype.description,\n color: archetype.color,\n textureKey: archetype.textureKey,\n stats: archetype.stats,\n philosophy: archetype.philosophy,\n specialAbilities: archetype.specialAbilities ?? [], // Use actual data or empty array\n }));\n }, [archetypes]);\n\n const currentArchetype = useMemo(() => {\n const archetype = archetypes[selectedIndex];\n return Object.values(PlayerArchetype).find(\n (key) => key === archetype.id,\n ) as PlayerArchetype;\n }, [archetypes, selectedIndex]);\n\n const handleToggleView = useCallback(() => {\n setViewMode((prev) => (prev === \"compact\" ? \"detailed\" : \"compact\"));\n onPlaySFX(\"menu_hover\");\n }, [onPlaySFX]);\n\n const handleArchetypeChangeFromGrid = useCallback(\n (archetype: PlayerArchetype) => {\n const index = archetypes.findIndex((a) => a.id === archetype);\n if (index !== -1) {\n onArchetypeChange(index);\n }\n },\n [archetypes, onArchetypeChange],\n );\n\n const detailedHeight = useMemo(\n () => Math.max(height * 2, 600),\n [height],\n );\n\n return (\n <div\n style={{\n width: `${width}px`,\n display: \"flex\",\n flexDirection: \"column\",\n gap: isSmallScreen ? \"10px\" : \"16px\",\n }}\n data-testid=\"enhanced-archetype-display\"\n >\n {/* View toggle button (only show if allowed and not small screen) */}\n {allowDetailedView && !isSmallScreen && (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"flex-end\",\n width: \"100%\",\n }}\n >\n <BaseButtonOverlayHtml\n korean={viewMode === \"compact\" ? \"상세 보기\" : \"간단 보기\"}\n english={viewMode === \"compact\" ? \"Detailed View\" : \"Compact View\"}\n onClick={handleToggleView}\n variant=\"secondary\"\n size=\"sm\"\n testId=\"view-toggle-button\"\n ariaLabel={`Toggle ${viewMode === \"compact\" ? \"detailed\" : \"compact\"} view`}\n />\n </div>\n )}\n\n {/* Render appropriate view */}\n {viewMode === \"compact\" ? (\n <ArchetypeDisplayOverlayHtml\n archetypes={archetypes}\n selectedIndex={selectedIndex}\n onArchetypeChange={onArchetypeChange}\n onPlaySFX={onPlaySFX}\n width={width}\n height={height}\n isMobile={isMobile}\n />\n ) : (\n <ArchetypeCardGrid\n archetypes={cardData}\n selectedArchetype={currentArchetype}\n onArchetypeChange={handleArchetypeChangeFromGrid}\n onPlaySFX={onPlaySFX}\n width={width}\n height={detailedHeight}\n isMobile={isMobile}\n />\n )}\n </div>\n );\n },\n );\n\nEnhancedArchetypeDisplay.displayName = \"EnhancedArchetypeDisplay\";\n\nexport default EnhancedArchetypeDisplay;\n"],"mappings":";;;;;;;;;;;AAwBA,IAAa,2BACX,MAAM,MACH,EACC,YACA,eACA,mBACA,WACA,QAAQ,KACR,SAAS,KACT,WAAW,OACX,oBAAoB,WAChB;CACJ,MAAM,CAAC,UAAU,eAAe,SAC9B,UACD;CAED,MAAM,gBAAgB,QAAQ;CAE9B,MAAM,WAAW,cAAc;EAC7B,OAAO,WAAW,KAAK,eAAe;GACpC,WAAW,OAAO,OAAO,gBAAgB,CAAC,MACvC,QAAQ,QAAQ,UAAU,GAC5B;GACD,IAAI,UAAU;GACd,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,aAAa,UAAU;GACvB,OAAO,UAAU;GACjB,YAAY,UAAU;GACtB,OAAO,UAAU;GACjB,YAAY,UAAU;GACtB,kBAAkB,UAAU,oBAAoB,EAAE;GACnD,EAAE;IACF,CAAC,WAAW,CAAC;CAEhB,MAAM,mBAAmB,cAAc;EACrC,MAAM,YAAY,WAAW;EAC7B,OAAO,OAAO,OAAO,gBAAgB,CAAC,MACnC,QAAQ,QAAQ,UAAU,GAC5B;IACA,CAAC,YAAY,cAAc,CAAC;CAE/B,MAAM,mBAAmB,kBAAkB;EACzC,aAAa,SAAU,SAAS,YAAY,aAAa,UAAW;EACpE,UAAU,aAAa;IACtB,CAAC,UAAU,CAAC;CAEf,MAAM,gCAAgC,aACnC,cAA+B;EAC9B,MAAM,QAAQ,WAAW,WAAW,MAAM,EAAE,OAAO,UAAU;EAC7D,IAAI,UAAU,IACZ,kBAAkB,MAAM;IAG5B,CAAC,YAAY,kBAAkB,CAChC;CAED,MAAM,iBAAiB,cACf,KAAK,IAAI,SAAS,GAAG,IAAI,EAC/B,CAAC,OAAO,CACT;CAED,OACE,qBAAC,OAAD;EACE,OAAO;GACL,OAAO,GAAG,MAAM;GAChB,SAAS;GACT,eAAe;GACf,KAAK,gBAAgB,SAAS;GAC/B;EACD,eAAY;YAPd,CAUG,qBAAqB,CAAC,iBACrB,oBAAC,OAAD;GACE,OAAO;IACL,SAAS;IACT,gBAAgB;IAChB,OAAO;IACR;aAED,oBAAC,uBAAD;IACE,QAAQ,aAAa,YAAY,UAAU;IAC3C,SAAS,aAAa,YAAY,kBAAkB;IACpD,SAAS;IACT,SAAQ;IACR,MAAK;IACL,QAAO;IACP,WAAW,UAAU,aAAa,YAAY,aAAa,UAAU;IACrE,CAAA;GACE,CAAA,EAIP,aAAa,YACZ,oBAAC,6BAAD;GACc;GACG;GACI;GACR;GACJ;GACC;GACE;GACV,CAAA,GAEF,oBAAC,mBAAD;GACE,YAAY;GACZ,mBAAmB;GACnB,mBAAmB;GACR;GACJ;GACP,QAAQ;GACE;GACV,CAAA,CAEA;;EAGX;AAEH,yBAAyB,cAAc"}
1
+ {"version":3,"file":"EnhancedArchetypeDisplayOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.tsx"],"sourcesContent":["import React, { useCallback, useMemo, useState } from \"react\";\nimport { PlayerArchetype } from \"../../../../types/common\";\nimport { BaseButtonOverlayHtml } from \"../../../shared/base/BaseButtonOverlayHtml\";\nimport { ArchetypeCardGrid } from \"./ArchetypeCardGridOverlayHtml\";\nimport {\n ArchetypeDataShape,\n ArchetypeDisplayOverlayHtml,\n} from \"./ArchetypeDisplayOverlayHtml\";\n\nexport interface EnhancedArchetypeDisplayProps {\n readonly archetypes: readonly ArchetypeDataShape[];\n readonly selectedIndex: number;\n readonly onArchetypeChange: (index: number) => void;\n readonly onPlaySFX: (sound: string) => void;\n readonly width?: number;\n readonly height?: number;\n readonly isMobile?: boolean; // For controls/haptics only, use width for layout sizing\n readonly allowDetailedView?: boolean; // Allow switching to card grid view\n}\n\n/**\n * EnhancedArchetypeDisplay - Provides both compact and detailed card view modes\n * Can switch between ArchetypeDisplayOverlayHtml (compact) and ArchetypeCardGrid (detailed)\n */\nexport const EnhancedArchetypeDisplay: React.FC<EnhancedArchetypeDisplayProps> =\n React.memo(\n ({\n archetypes,\n selectedIndex,\n onArchetypeChange,\n onPlaySFX,\n width = 800,\n height = 300,\n isMobile = false,\n allowDetailedView = true,\n }) => {\n const [viewMode, setViewMode] = useState<\"compact\" | \"detailed\">(\n \"compact\",\n );\n\n const isSmallScreen = width < 768;\n\n const cardData = useMemo(() => {\n return archetypes.map((archetype) => ({\n archetype: Object.values(PlayerArchetype).find(\n (key) => key === archetype.id,\n ) as PlayerArchetype,\n id: archetype.id,\n korean: archetype.korean,\n english: archetype.english,\n description: archetype.description,\n color: archetype.color,\n textureKey: archetype.textureKey,\n stats: archetype.stats,\n philosophy: archetype.philosophy,\n specialAbilities: archetype.specialAbilities ?? [], // Use actual data or empty array\n }));\n }, [archetypes]);\n\n const currentArchetype = useMemo(() => {\n const archetype = archetypes[selectedIndex];\n return Object.values(PlayerArchetype).find(\n (key) => key === archetype.id,\n ) as PlayerArchetype;\n }, [archetypes, selectedIndex]);\n\n const handleToggleView = useCallback(() => {\n setViewMode((prev) => (prev === \"compact\" ? \"detailed\" : \"compact\"));\n onPlaySFX(\"menu_hover\");\n }, [onPlaySFX]);\n\n const handleArchetypeChangeFromGrid = useCallback(\n (archetype: PlayerArchetype) => {\n const index = archetypes.findIndex((a) => a.id === archetype);\n if (index !== -1) {\n onArchetypeChange(index);\n }\n },\n [archetypes, onArchetypeChange],\n );\n\n const detailedHeight = useMemo(\n () => Math.max(height * 2, 600),\n [height],\n );\n\n return (\n <div\n style={{\n width: `${width}px`,\n display: \"flex\",\n flexDirection: \"column\",\n gap: isSmallScreen ? \"10px\" : \"16px\",\n }}\n data-testid=\"enhanced-archetype-display\"\n >\n {/* View toggle button (only show if allowed and not small screen) */}\n {allowDetailedView && !isSmallScreen && (\n <div\n style={{\n display: \"flex\",\n justifyContent: \"flex-end\",\n width: \"100%\",\n }}\n >\n <BaseButtonOverlayHtml\n korean={viewMode === \"compact\" ? \"상세 보기\" : \"간단 보기\"}\n english={viewMode === \"compact\" ? \"Detailed View\" : \"Compact View\"}\n onClick={handleToggleView}\n variant=\"secondary\"\n size=\"sm\"\n testId=\"view-toggle-button\"\n ariaLabel={`Toggle ${viewMode === \"compact\" ? \"detailed\" : \"compact\"} view`}\n />\n </div>\n )}\n\n {/* Render appropriate view */}\n {viewMode === \"compact\" ? (\n <ArchetypeDisplayOverlayHtml\n archetypes={archetypes}\n selectedIndex={selectedIndex}\n onArchetypeChange={onArchetypeChange}\n onPlaySFX={onPlaySFX}\n width={width}\n height={height}\n isMobile={isMobile}\n />\n ) : (\n <ArchetypeCardGrid\n archetypes={cardData}\n selectedArchetype={currentArchetype}\n onArchetypeChange={handleArchetypeChangeFromGrid}\n onPlaySFX={onPlaySFX}\n width={width}\n height={detailedHeight}\n isMobile={isMobile}\n />\n )}\n </div>\n );\n },\n );\n\nEnhancedArchetypeDisplay.displayName = \"EnhancedArchetypeDisplay\";\n\nexport default EnhancedArchetypeDisplay;\n"],"mappings":";;;;;;;;;;;AAwBA,IAAa,2BACX,MAAM,MACH,EACC,YACA,eACA,mBACA,WACA,QAAQ,KACR,SAAS,KACT,WAAW,OACX,oBAAoB,WAChB;CACJ,MAAM,CAAC,UAAU,eAAe,SAC9B,SACF;CAEA,MAAM,gBAAgB,QAAQ;CAE9B,MAAM,WAAW,cAAc;EAC7B,OAAO,WAAW,KAAK,eAAe;GACpC,WAAW,OAAO,OAAO,eAAe,EAAE,MACvC,QAAQ,QAAQ,UAAU,EAC7B;GACA,IAAI,UAAU;GACd,QAAQ,UAAU;GAClB,SAAS,UAAU;GACnB,aAAa,UAAU;GACvB,OAAO,UAAU;GACjB,YAAY,UAAU;GACtB,OAAO,UAAU;GACjB,YAAY,UAAU;GACtB,kBAAkB,UAAU,oBAAoB,CAAC;EACnD,EAAE;CACJ,GAAG,CAAC,UAAU,CAAC;CAEf,MAAM,mBAAmB,cAAc;EACrC,MAAM,YAAY,WAAW;EAC7B,OAAO,OAAO,OAAO,eAAe,EAAE,MACnC,QAAQ,QAAQ,UAAU,EAC7B;CACF,GAAG,CAAC,YAAY,aAAa,CAAC;CAE9B,MAAM,mBAAmB,kBAAkB;EACzC,aAAa,SAAU,SAAS,YAAY,aAAa,SAAU;EACnE,UAAU,YAAY;CACxB,GAAG,CAAC,SAAS,CAAC;CAEd,MAAM,gCAAgC,aACnC,cAA+B;EAC9B,MAAM,QAAQ,WAAW,WAAW,MAAM,EAAE,OAAO,SAAS;EAC5D,IAAI,UAAU,IACZ,kBAAkB,KAAK;CAE3B,GACA,CAAC,YAAY,iBAAiB,CAChC;CAEA,MAAM,iBAAiB,cACf,KAAK,IAAI,SAAS,GAAG,GAAG,GAC9B,CAAC,MAAM,CACT;CAEA,OACE,qBAAC,OAAD;EACE,OAAO;GACL,OAAO,GAAG,MAAM;GAChB,SAAS;GACT,eAAe;GACf,KAAK,gBAAgB,SAAS;EAChC;EACA,eAAY;YAPd,CAUG,qBAAqB,CAAC,iBACrB,oBAAC,OAAD;GACE,OAAO;IACL,SAAS;IACT,gBAAgB;IAChB,OAAO;GACT;aAEA,oBAAC,uBAAD;IACE,QAAQ,aAAa,YAAY,UAAU;IAC3C,SAAS,aAAa,YAAY,kBAAkB;IACpD,SAAS;IACT,SAAQ;IACR,MAAK;IACL,QAAO;IACP,WAAW,UAAU,aAAa,YAAY,aAAa,UAAU;GACtE,CAAA;EACE,CAAA,GAIN,aAAa,YACZ,oBAAC,6BAAD;GACc;GACG;GACI;GACR;GACJ;GACC;GACE;EACX,CAAA,IAED,oBAAC,mBAAD;GACE,YAAY;GACZ,mBAAmB;GACnB,mBAAmB;GACR;GACJ;GACP,QAAQ;GACE;EACX,CAAA,CAEA;;AAET,CACF;AAEF,yBAAyB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"MenuButtonsOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/MenuButtonsOverlayHtml.tsx"],"sourcesContent":["/**\n * MenuButtons - Reusable menu button grid for IntroScreen\n * \n * Provides 2x2 grid (desktop) or column (mobile) layout for menu navigation.\n * Extracted from MenuSectionOverlayHtml to reduce code duplication.\n * \n * @module components/screens/intro\n * @category Intro UI\n * @korean 메뉴버튼\n */\n\nimport React, { useCallback, useMemo } from \"react\";\nimport { GameMode } from \"../../../../types/common\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport { UIHaptics } from \"../../../../utils/hapticFeedback\";\nimport {\n getButtonVisualEffectsOnly,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport { getMobileKoreanFontSize } from \"../../../../utils/mobileUIUtils\";\nimport {\n getKoreanFontOptimization,\n} from \"../../../../utils/visualEffects\";\n\nexport interface MenuButtonsProps {\n /** Array of menu items to display */\n readonly menuItems: Array<{\n mode: GameMode;\n korean: string;\n english: string;\n }>;\n /** Currently selected menu item index */\n readonly selectedIndex: number;\n /** Index of currently hovered menu item (null if none) */\n readonly hoveredIndex: number | null;\n /** Callback when a menu item is selected */\n readonly onModeSelect: (mode: GameMode) => void;\n /** Callback when hover state changes */\n readonly onHoverChange: (index: number | null) => void;\n /** Callback to play sound effects */\n readonly onPlaySFX?: (sound: string) => void;\n /** Screen width for responsive sizing */\n readonly width?: number;\n /** Whether on mobile device (for haptics) */\n readonly isMobile?: boolean;\n}\n\n/**\n * MenuButtons Component\n * \n * Displays menu navigation buttons with:\n * - 2x2 grid layout on larger screens\n * - Column layout on small screens\n * - Selected/hovered state visualization\n * - Korean bilingual text\n * - Haptic feedback support\n * \n * This component delegates to inline button elements with custom styling\n * since BaseButtonOverlayHtml doesn't support the complex selection state\n * and color transitions needed for menu navigation.\n * \n * Reduces code duplication by 62 lines (MenuSectionOverlayHtml: 372 → 310)\n * \n * @example\n * ```tsx\n * <MenuButtons\n * menuItems={MENU_ITEMS}\n * selectedIndex={0}\n * hoveredIndex={null}\n * onModeSelect={(mode) => handleModeSelect(mode)}\n * onHoverChange={(idx) => setHovered(idx)}\n * width={800}\n * />\n * ```\n */\nexport const MenuButtons: React.FC<MenuButtonsProps> = ({\n menuItems,\n selectedIndex,\n hoveredIndex,\n onModeSelect,\n onHoverChange,\n onPlaySFX,\n width = 800,\n isMobile: _isMobile = false, // Prefix with _ to indicate intentionally unused\n}) => {\n const isSmallScreen = width < 768;\n const useGridLayout = !isSmallScreen;\n const buttonHeight = isSmallScreen ? 44 : 40;\n const buttonFontSize = isSmallScreen\n ? getMobileKoreanFontSize(\"SMALL\", width ?? 375)\n : 13;\n const buttonGap = isSmallScreen ? 6 : 8;\n\n const colors = useMemo(\n () => ({\n buttonSelectedBg: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.98),\n buttonHoveredBg: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_LIGHT, 0.92),\n buttonDefaultBg: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n 0.92,\n ),\n buttonSelectedBorder: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_DARK,\n 1.0,\n ),\n buttonHoveredBorder: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.8),\n buttonDefaultBorder: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.7),\n textSelected: `#${KOREAN_COLORS.UI_BACKGROUND_DARK.toString(16).padStart(6, \"0\")}`,\n textHovered: `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(6, \"0\")}`,\n textDefault: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(6, \"0\")}`,\n }),\n [],\n );\n\n const handleButtonClick = useCallback(\n (mode: GameMode) => {\n UIHaptics.buttonTap();\n onModeSelect(mode);\n onPlaySFX?.(\"menu_select\");\n },\n [onModeSelect, onPlaySFX],\n );\n\n const handleButtonHover = useCallback(\n (index: number, isHovering: boolean) => {\n const newIndex = isHovering ? index : null;\n onHoverChange(newIndex);\n if (isHovering) {\n UIHaptics.menuHover();\n onPlaySFX?.(\"menu_hover\");\n }\n },\n [onHoverChange, onPlaySFX],\n );\n\n return (\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: useGridLayout ? \"1fr 1fr\" : \"1fr\",\n gap: `${buttonGap}px`,\n width: \"100%\",\n }}\n data-testid=\"main-menu-buttons\"\n >\n {menuItems.map((item, index) => {\n const isSelected = selectedIndex === index;\n const isHovered = hoveredIndex === index;\n\n const visualEffects = getButtonVisualEffectsOnly({\n variant: \"primary\",\n isHovered,\n isPressed: false,\n isFocused: false,\n glowIntensity: isSelected\n ? \"medium\"\n : isHovered\n ? \"medium\"\n : \"subtle\",\n hoverAnimation: \"combined\",\n });\n\n return (\n <button\n key={item.mode}\n onClick={() => handleButtonClick(item.mode)}\n onMouseEnter={() => handleButtonHover(index, true)}\n onMouseLeave={() => handleButtonHover(index, false)}\n onFocus={(e) => {\n e.currentTarget.style.outline = `3px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD)}`;\n e.currentTarget.style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n e.currentTarget.style.outline = \"none\";\n }}\n aria-label={`${item.korean} (${item.english})`}\n aria-selected={isSelected}\n role=\"menuitem\"\n style={{\n ...visualEffects,\n ...getKoreanFontOptimization(\n buttonFontSize,\n isSelected ? \"bold\" : \"normal\",\n ),\n fontFamily: FONT_FAMILY.KOREAN,\n width: \"100%\",\n height: `${buttonHeight}px`,\n color: isSelected\n ? colors.textSelected\n : isHovered\n ? colors.textHovered\n : colors.textDefault,\n background: isSelected\n ? colors.buttonSelectedBg\n : isHovered\n ? colors.buttonHoveredBg\n : colors.buttonDefaultBg,\n border: isSelected\n ? `3px solid ${colors.buttonSelectedBorder}`\n : isHovered\n ? `2px solid ${colors.buttonHoveredBorder}`\n : `2px solid ${colors.buttonDefaultBorder}`,\n cursor: \"pointer\",\n }}\n data-testid={`menu-item-${item.mode}`}\n >\n {/* Add test ID aliases for backward compatibility */}\n {item.mode === GameMode.TRAINING && (\n <span\n data-testid=\"training-button\"\n style={{ display: \"none\" }}\n />\n )}\n {item.mode === GameMode.VERSUS && (\n <span data-testid=\"combat-button\" style={{ display: \"none\" }} />\n )}\n {item.korean} ({item.english})\n </button>\n );\n })}\n </div>\n );\n};\n\nexport default MenuButtons;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2EA,IAAa,eAA2C,EACtD,WACA,eACA,cACA,cACA,eACA,WACA,QAAQ,KACR,UAAU,YAAY,YAClB;CACJ,MAAM,gBAAgB,QAAQ;CAC9B,MAAM,gBAAgB,CAAC;CACvB,MAAM,eAAe,gBAAgB,KAAK;CAC1C,MAAM,iBAAiB,gBACnB,wBAAwB,SAAS,SAAS,IAAI,GAC9C;CACJ,MAAM,YAAY,gBAAgB,IAAI;CAEtC,MAAM,SAAS,eACN;EACL,kBAAkB,gBAAgB,cAAc,aAAa,IAAK;EAClE,iBAAiB,gBAAgB,cAAc,qBAAqB,IAAK;EACzE,iBAAiB,gBACf,cAAc,sBACd,IACD;EACD,sBAAsB,gBACpB,cAAc,oBACd,EACD;EACD,qBAAqB,gBAAgB,cAAc,aAAa,GAAI;EACpE,qBAAqB,gBAAgB,cAAc,cAAc,GAAI;EACrE,cAAc,IAAI,cAAc,mBAAmB,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;EAChF,aAAa,IAAI,cAAc,YAAY,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;EACxE,aAAa,IAAI,cAAc,aAAa,SAAS,GAAG,CAAC,SAAS,GAAG,IAAI;EAC1E,GACD,EAAE,CACH;CAED,MAAM,oBAAoB,aACvB,SAAmB;EAClB,UAAU,WAAW;EACrB,aAAa,KAAK;EAClB,YAAY,cAAc;IAE5B,CAAC,cAAc,UAAU,CAC1B;CAED,MAAM,oBAAoB,aACvB,OAAe,eAAwB;EAEtC,cADiB,aAAa,QAAQ,KACf;EACvB,IAAI,YAAY;GACd,UAAU,WAAW;GACrB,YAAY,aAAa;;IAG7B,CAAC,eAAe,UAAU,CAC3B;CAED,OACE,oBAAC,OAAD;EACE,OAAO;GACL,SAAS;GACT,qBAAqB,gBAAgB,YAAY;GACjD,KAAK,GAAG,UAAU;GAClB,OAAO;GACR;EACD,eAAY;YAEX,UAAU,KAAK,MAAM,UAAU;GAC9B,MAAM,aAAa,kBAAkB;GACrC,MAAM,YAAY,iBAAiB;GAEnC,MAAM,gBAAgB,2BAA2B;IAC/C,SAAS;IACT;IACA,WAAW;IACX,WAAW;IACX,eAAe,aACX,WACA,YACE,WACA;IACN,gBAAgB;IACjB,CAAC;GAEF,OACE,qBAAC,UAAD;IAEE,eAAe,kBAAkB,KAAK,KAAK;IAC3C,oBAAoB,kBAAkB,OAAO,KAAK;IAClD,oBAAoB,kBAAkB,OAAO,MAAM;IACnD,UAAU,MAAM;KACd,EAAE,cAAc,MAAM,UAAU,aAAa,gBAAgB,cAAc,YAAY;KACvF,EAAE,cAAc,MAAM,gBAAgB;;IAExC,SAAS,MAAM;KACb,EAAE,cAAc,MAAM,UAAU;;IAElC,cAAY,GAAG,KAAK,OAAO,IAAI,KAAK,QAAQ;IAC5C,iBAAe;IACf,MAAK;IACL,OAAO;KACL,GAAG;KACH,GAAG,0BACD,gBACA,aAAa,SAAS,SACvB;KACD,YAAY,YAAY;KACxB,OAAO;KACP,QAAQ,GAAG,aAAa;KACxB,OAAO,aACH,OAAO,eACP,YACE,OAAO,cACP,OAAO;KACb,YAAY,aACR,OAAO,mBACP,YACE,OAAO,kBACP,OAAO;KACb,QAAQ,aACJ,aAAa,OAAO,yBACpB,YACE,aAAa,OAAO,wBACpB,aAAa,OAAO;KAC1B,QAAQ;KACT;IACD,eAAa,aAAa,KAAK;cAzCjC;KA4CG,KAAK,SAAS,SAAS,YACtB,oBAAC,QAAD;MACE,eAAY;MACZ,OAAO,EAAE,SAAS,QAAQ;MAC1B,CAAA;KAEH,KAAK,SAAS,SAAS,UACtB,oBAAC,QAAD;MAAM,eAAY;MAAgB,OAAO,EAAE,SAAS,QAAQ;MAAI,CAAA;KAEjE,KAAK;KAAO;KAAG,KAAK;KAAQ;KACtB;MArDF,KAAK,KAqDH;IAEX;EACE,CAAA"}
1
+ {"version":3,"file":"MenuButtonsOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/MenuButtonsOverlayHtml.tsx"],"sourcesContent":["/**\n * MenuButtons - Reusable menu button grid for IntroScreen\n * \n * Provides 2x2 grid (desktop) or column (mobile) layout for menu navigation.\n * Extracted from MenuSectionOverlayHtml to reduce code duplication.\n * \n * @module components/screens/intro\n * @category Intro UI\n * @korean 메뉴버튼\n */\n\nimport React, { useCallback, useMemo } from \"react\";\nimport { GameMode } from \"../../../../types/common\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString } from \"../../../../utils/colorUtils\";\nimport { UIHaptics } from \"../../../../utils/hapticFeedback\";\nimport {\n getButtonVisualEffectsOnly,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport { getMobileKoreanFontSize } from \"../../../../utils/mobileUIUtils\";\nimport {\n getKoreanFontOptimization,\n} from \"../../../../utils/visualEffects\";\n\nexport interface MenuButtonsProps {\n /** Array of menu items to display */\n readonly menuItems: Array<{\n mode: GameMode;\n korean: string;\n english: string;\n }>;\n /** Currently selected menu item index */\n readonly selectedIndex: number;\n /** Index of currently hovered menu item (null if none) */\n readonly hoveredIndex: number | null;\n /** Callback when a menu item is selected */\n readonly onModeSelect: (mode: GameMode) => void;\n /** Callback when hover state changes */\n readonly onHoverChange: (index: number | null) => void;\n /** Callback to play sound effects */\n readonly onPlaySFX?: (sound: string) => void;\n /** Screen width for responsive sizing */\n readonly width?: number;\n /** Whether on mobile device (for haptics) */\n readonly isMobile?: boolean;\n}\n\n/**\n * MenuButtons Component\n * \n * Displays menu navigation buttons with:\n * - 2x2 grid layout on larger screens\n * - Column layout on small screens\n * - Selected/hovered state visualization\n * - Korean bilingual text\n * - Haptic feedback support\n * \n * This component delegates to inline button elements with custom styling\n * since BaseButtonOverlayHtml doesn't support the complex selection state\n * and color transitions needed for menu navigation.\n * \n * Reduces code duplication by 62 lines (MenuSectionOverlayHtml: 372 → 310)\n * \n * @example\n * ```tsx\n * <MenuButtons\n * menuItems={MENU_ITEMS}\n * selectedIndex={0}\n * hoveredIndex={null}\n * onModeSelect={(mode) => handleModeSelect(mode)}\n * onHoverChange={(idx) => setHovered(idx)}\n * width={800}\n * />\n * ```\n */\nexport const MenuButtons: React.FC<MenuButtonsProps> = ({\n menuItems,\n selectedIndex,\n hoveredIndex,\n onModeSelect,\n onHoverChange,\n onPlaySFX,\n width = 800,\n isMobile: _isMobile = false, // Prefix with _ to indicate intentionally unused\n}) => {\n const isSmallScreen = width < 768;\n const useGridLayout = !isSmallScreen;\n const buttonHeight = isSmallScreen ? 44 : 40;\n const buttonFontSize = isSmallScreen\n ? getMobileKoreanFontSize(\"SMALL\", width ?? 375)\n : 13;\n const buttonGap = isSmallScreen ? 6 : 8;\n\n const colors = useMemo(\n () => ({\n buttonSelectedBg: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.98),\n buttonHoveredBg: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_LIGHT, 0.92),\n buttonDefaultBg: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_MEDIUM,\n 0.92,\n ),\n buttonSelectedBorder: hexToRgbaString(\n KOREAN_COLORS.UI_BACKGROUND_DARK,\n 1.0,\n ),\n buttonHoveredBorder: hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD, 0.8),\n buttonDefaultBorder: hexToRgbaString(KOREAN_COLORS.PRIMARY_CYAN, 0.7),\n textSelected: `#${KOREAN_COLORS.UI_BACKGROUND_DARK.toString(16).padStart(6, \"0\")}`,\n textHovered: `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(6, \"0\")}`,\n textDefault: `#${KOREAN_COLORS.TEXT_PRIMARY.toString(16).padStart(6, \"0\")}`,\n }),\n [],\n );\n\n const handleButtonClick = useCallback(\n (mode: GameMode) => {\n UIHaptics.buttonTap();\n onModeSelect(mode);\n onPlaySFX?.(\"menu_select\");\n },\n [onModeSelect, onPlaySFX],\n );\n\n const handleButtonHover = useCallback(\n (index: number, isHovering: boolean) => {\n const newIndex = isHovering ? index : null;\n onHoverChange(newIndex);\n if (isHovering) {\n UIHaptics.menuHover();\n onPlaySFX?.(\"menu_hover\");\n }\n },\n [onHoverChange, onPlaySFX],\n );\n\n return (\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: useGridLayout ? \"1fr 1fr\" : \"1fr\",\n gap: `${buttonGap}px`,\n width: \"100%\",\n }}\n data-testid=\"main-menu-buttons\"\n >\n {menuItems.map((item, index) => {\n const isSelected = selectedIndex === index;\n const isHovered = hoveredIndex === index;\n\n const visualEffects = getButtonVisualEffectsOnly({\n variant: \"primary\",\n isHovered,\n isPressed: false,\n isFocused: false,\n glowIntensity: isSelected\n ? \"medium\"\n : isHovered\n ? \"medium\"\n : \"subtle\",\n hoverAnimation: \"combined\",\n });\n\n return (\n <button\n key={item.mode}\n onClick={() => handleButtonClick(item.mode)}\n onMouseEnter={() => handleButtonHover(index, true)}\n onMouseLeave={() => handleButtonHover(index, false)}\n onFocus={(e) => {\n e.currentTarget.style.outline = `3px solid ${hexToRgbaString(KOREAN_COLORS.ACCENT_GOLD)}`;\n e.currentTarget.style.outlineOffset = \"2px\";\n }}\n onBlur={(e) => {\n e.currentTarget.style.outline = \"none\";\n }}\n aria-label={`${item.korean} (${item.english})`}\n aria-selected={isSelected}\n role=\"menuitem\"\n style={{\n ...visualEffects,\n ...getKoreanFontOptimization(\n buttonFontSize,\n isSelected ? \"bold\" : \"normal\",\n ),\n fontFamily: FONT_FAMILY.KOREAN,\n width: \"100%\",\n height: `${buttonHeight}px`,\n color: isSelected\n ? colors.textSelected\n : isHovered\n ? colors.textHovered\n : colors.textDefault,\n background: isSelected\n ? colors.buttonSelectedBg\n : isHovered\n ? colors.buttonHoveredBg\n : colors.buttonDefaultBg,\n border: isSelected\n ? `3px solid ${colors.buttonSelectedBorder}`\n : isHovered\n ? `2px solid ${colors.buttonHoveredBorder}`\n : `2px solid ${colors.buttonDefaultBorder}`,\n cursor: \"pointer\",\n }}\n data-testid={`menu-item-${item.mode}`}\n >\n {/* Add test ID aliases for backward compatibility */}\n {item.mode === GameMode.TRAINING && (\n <span\n data-testid=\"training-button\"\n style={{ display: \"none\" }}\n />\n )}\n {item.mode === GameMode.VERSUS && (\n <span data-testid=\"combat-button\" style={{ display: \"none\" }} />\n )}\n {item.korean} ({item.english})\n </button>\n );\n })}\n </div>\n );\n};\n\nexport default MenuButtons;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2EA,IAAa,eAA2C,EACtD,WACA,eACA,cACA,cACA,eACA,WACA,QAAQ,KACR,UAAU,YAAY,YAClB;CACJ,MAAM,gBAAgB,QAAQ;CAC9B,MAAM,gBAAgB,CAAC;CACvB,MAAM,eAAe,gBAAgB,KAAK;CAC1C,MAAM,iBAAiB,gBACnB,wBAAwB,SAAS,SAAS,GAAG,IAC7C;CACJ,MAAM,YAAY,gBAAgB,IAAI;CAEtC,MAAM,SAAS,eACN;EACL,kBAAkB,gBAAgB,cAAc,aAAa,GAAI;EACjE,iBAAiB,gBAAgB,cAAc,qBAAqB,GAAI;EACxE,iBAAiB,gBACf,cAAc,sBACd,GACF;EACA,sBAAsB,gBACpB,cAAc,oBACd,CACF;EACA,qBAAqB,gBAAgB,cAAc,aAAa,EAAG;EACnE,qBAAqB,gBAAgB,cAAc,cAAc,EAAG;EACpE,cAAc,IAAI,cAAc,mBAAmB,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;EAC/E,aAAa,IAAI,cAAc,YAAY,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;EACvE,aAAa,IAAI,cAAc,aAAa,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG;CAC1E,IACA,CAAC,CACH;CAEA,MAAM,oBAAoB,aACvB,SAAmB;EAClB,UAAU,UAAU;EACpB,aAAa,IAAI;EACjB,YAAY,aAAa;CAC3B,GACA,CAAC,cAAc,SAAS,CAC1B;CAEA,MAAM,oBAAoB,aACvB,OAAe,eAAwB;EAEtC,cADiB,aAAa,QAAQ,IAChB;EACtB,IAAI,YAAY;GACd,UAAU,UAAU;GACpB,YAAY,YAAY;EAC1B;CACF,GACA,CAAC,eAAe,SAAS,CAC3B;CAEA,OACE,oBAAC,OAAD;EACE,OAAO;GACL,SAAS;GACT,qBAAqB,gBAAgB,YAAY;GACjD,KAAK,GAAG,UAAU;GAClB,OAAO;EACT;EACA,eAAY;YAEX,UAAU,KAAK,MAAM,UAAU;GAC9B,MAAM,aAAa,kBAAkB;GACrC,MAAM,YAAY,iBAAiB;GAEnC,MAAM,gBAAgB,2BAA2B;IAC/C,SAAS;IACT;IACA,WAAW;IACX,WAAW;IACX,eAAe,aACX,WACA,YACE,WACA;IACN,gBAAgB;GAClB,CAAC;GAED,OACE,qBAAC,UAAD;IAEE,eAAe,kBAAkB,KAAK,IAAI;IAC1C,oBAAoB,kBAAkB,OAAO,IAAI;IACjD,oBAAoB,kBAAkB,OAAO,KAAK;IAClD,UAAU,MAAM;KACd,EAAE,cAAc,MAAM,UAAU,aAAa,gBAAgB,cAAc,WAAW;KACtF,EAAE,cAAc,MAAM,gBAAgB;IACxC;IACA,SAAS,MAAM;KACb,EAAE,cAAc,MAAM,UAAU;IAClC;IACA,cAAY,GAAG,KAAK,OAAO,IAAI,KAAK,QAAQ;IAC5C,iBAAe;IACf,MAAK;IACL,OAAO;KACL,GAAG;KACH,GAAG,0BACD,gBACA,aAAa,SAAS,QACxB;KACA,YAAY,YAAY;KACxB,OAAO;KACP,QAAQ,GAAG,aAAa;KACxB,OAAO,aACH,OAAO,eACP,YACE,OAAO,cACP,OAAO;KACb,YAAY,aACR,OAAO,mBACP,YACE,OAAO,kBACP,OAAO;KACb,QAAQ,aACJ,aAAa,OAAO,yBACpB,YACE,aAAa,OAAO,wBACpB,aAAa,OAAO;KAC1B,QAAQ;IACV;IACA,eAAa,aAAa,KAAK;cAzCjC;KA4CG,KAAK,SAAS,SAAS,YACtB,oBAAC,QAAD;MACE,eAAY;MACZ,OAAO,EAAE,SAAS,OAAO;KAC1B,CAAA;KAEF,KAAK,SAAS,SAAS,UACtB,oBAAC,QAAD;MAAM,eAAY;MAAgB,OAAO,EAAE,SAAS,OAAO;KAAI,CAAA;KAEhE,KAAK;KAAO;KAAG,KAAK;KAAQ;IACvB;MArDD,KAAK,IAqDJ;EAEZ,CAAC;CACE,CAAA;AAET"}
@@ -1 +1 @@
1
- {"version":3,"file":"MenuSectionOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/MenuSectionOverlayHtml.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from \"react\";\nimport { GameMode } from \"../../../../types/common\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport {\n getEnhancedKoreanOverlayStyles,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport { getMobileKoreanFontSize } from \"../../../../utils/mobileUIUtils\";\nimport { getSafeAreaPadding } from \"../../../../utils/safeAreaUtils\";\nimport {\n getNeonTextShadow,\n} from \"../../../../utils/visualEffects\";\nimport { MenuButtons } from \"./MenuButtonsOverlayHtml\";\n\nexport interface MenuSectionOverlayHtmlProps {\n readonly menuItems: Array<{\n mode: GameMode;\n korean: string;\n english: string;\n }>;\n readonly selectedIndex: number;\n readonly onModeSelect: (mode: GameMode) => void;\n readonly onSelectedIndexChange?: (index: number) => void;\n readonly onPlaySFX?: (sound: string) => void;\n readonly width?: number;\n readonly height?: number;\n readonly isMobile?: boolean; // For controls/haptics only, use width for layout sizing\n}\n\n/**\n * HTML-based MenuSection component for Three.js integration\n *\n * Optimized with React.memo for 60fps performance:\n * - Memoized to prevent unnecessary re-renders\n * - All callbacks use useCallback\n * - Styles pre-calculated and memoized\n */\nexport const MenuSectionOverlayHtml = React.memo<MenuSectionOverlayHtmlProps>(\n ({\n menuItems,\n selectedIndex,\n onModeSelect,\n onSelectedIndexChange,\n onPlaySFX,\n width = 800,\n height = 300,\n isMobile = false, // Default to false, parent should pass proper device detection\n }) => {\n const [hoveredItem, setHoveredItem] = useState<number | null>(null);\n const [focused, setFocused] = useState<boolean>(false);\n\n const enhancedOverlayStyles = useMemo(\n () =>\n getEnhancedKoreanOverlayStyles({\n opacity: 0.96,\n glowIntensity: focused ? \"medium\" : \"subtle\",\n includeGradient: false,\n includeBackdropBlur: false,\n depthLayers: 2,\n }),\n [focused],\n );\n\n const titleColor = useMemo(\n () => `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(6, \"0\")}`,\n [],\n );\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!onSelectedIndexChange) return;\n\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n event.stopPropagation();\n const nextIndex =\n selectedIndex === 0 ? menuItems.length - 1 : selectedIndex - 1;\n onSelectedIndexChange(nextIndex);\n onPlaySFX?.(\"menu_hover\");\n } else if (event.key === \"ArrowDown\") {\n event.preventDefault();\n event.stopPropagation();\n const nextIndex =\n selectedIndex === menuItems.length - 1 ? 0 : selectedIndex + 1;\n onSelectedIndexChange(nextIndex);\n onPlaySFX?.(\"menu_hover\");\n } else if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n event.stopPropagation();\n onPlaySFX?.(\"menu_select\");\n onModeSelect(menuItems[selectedIndex].mode);\n } else {\n const numKey = parseInt(event.key);\n if (numKey >= 1 && numKey <= menuItems.length) {\n event.stopPropagation();\n const targetIndex = numKey - 1;\n onSelectedIndexChange(targetIndex);\n onPlaySFX?.(\"menu_select\");\n onModeSelect(menuItems[targetIndex].mode);\n }\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n selectedIndex,\n menuItems,\n onSelectedIndexChange,\n onModeSelect,\n onPlaySFX,\n ]);\n\n useEffect(() => {\n const handleFocus = () => setFocused(true);\n const handleBlur = () => setFocused(false);\n window.addEventListener(\"focusin\", handleFocus);\n window.addEventListener(\"focusout\", handleBlur);\n return () => {\n window.removeEventListener(\"focusin\", handleFocus);\n window.removeEventListener(\"focusout\", handleBlur);\n };\n }, []);\n\n const isSmallScreen = width < 768; // Mobile-sized screens\n\n const containerPadding = isSmallScreen ? 16 : 12;\n const titleFontSize = isSmallScreen\n ? getMobileKoreanFontSize(\"SMALL\", width ?? 375)\n : 14;\n const sectionGap = isSmallScreen ? 8 : 6;\n\n const safeAreaStyles = useMemo(\n () =>\n isMobile ? getSafeAreaPadding([\"top\", \"bottom\"], containerPadding) : {},\n [isMobile, containerPadding],\n );\n\n return (\n <div\n style={{\n ...enhancedOverlayStyles,\n ...safeAreaStyles,\n width: `${width}px`,\n minHeight: `${height}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: `${sectionGap}px`,\n padding: `${containerPadding}px`,\n position: \"relative\",\n overflow: \"visible\",\n }}\n data-testid=\"main-menu-section\"\n >\n {/* Menu Title */}\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n color: titleColor,\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n textAlign: \"center\",\n textShadow: getNeonTextShadow(KOREAN_COLORS.ACCENT_GOLD, \"medium\"),\n }}\n data-testid=\"menu-title\"\n >\n 메인 메뉴 | Main Menu\n </div>\n\n {/* Menu Buttons - Extracted to MenuButtons component */}\n <MenuButtons\n menuItems={menuItems}\n selectedIndex={selectedIndex}\n hoveredIndex={hoveredItem}\n onModeSelect={onModeSelect}\n onHoverChange={setHoveredItem}\n onPlaySFX={onPlaySFX}\n width={width}\n isMobile={isMobile}\n />\n\n {/* Navigation Instructions */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: isSmallScreen ? \"4px\" : \"6px\",\n textAlign: \"center\",\n fontSize: isSmallScreen ? \"10px\" : \"12px\",\n color: `#${KOREAN_COLORS.TEXT_SECONDARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n fontFamily: FONT_FAMILY.KOREAN,\n marginTop: \"auto\",\n }}\n data-testid=\"navigation-hint-container\"\n >\n <div data-testid=\"menu-navigation-hint-korean\">\n 방향키/마우스로 이동 • Enter/클릭으로 선택 • 숫자키로 바로가기\n </div>\n <div\n style={{ fontSize: isSmallScreen ? \"9px\" : \"10px\" }}\n data-testid=\"menu-navigation-hint-english\"\n >\n Arrow keys/mouse to navigate • Enter/click to select • Number keys for\n shortcuts\n </div>\n </div>\n </div>\n );\n },\n (prevProps, nextProps) => {\n return (\n prevProps.selectedIndex === nextProps.selectedIndex &&\n prevProps.width === nextProps.width &&\n prevProps.height === nextProps.height &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.menuItems.length === nextProps.menuItems.length &&\n prevProps.onModeSelect === nextProps.onModeSelect &&\n prevProps.onSelectedIndexChange === nextProps.onSelectedIndexChange &&\n prevProps.onPlaySFX === nextProps.onPlaySFX\n );\n },\n);\n\nMenuSectionOverlayHtml.displayName = \"MenuSectionOverlayHtml\";\n\nexport default MenuSectionOverlayHtml;\n"],"mappings":"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"}
1
+ {"version":3,"file":"MenuSectionOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/MenuSectionOverlayHtml.tsx"],"sourcesContent":["import React, { useEffect, useMemo, useState } from \"react\";\nimport { GameMode } from \"../../../../types/common\";\nimport { FONT_FAMILY, KOREAN_COLORS } from \"../../../../types/constants\";\nimport {\n getEnhancedKoreanOverlayStyles,\n} from \"../../../../utils/koreanThemeHelpers\";\nimport { getMobileKoreanFontSize } from \"../../../../utils/mobileUIUtils\";\nimport { getSafeAreaPadding } from \"../../../../utils/safeAreaUtils\";\nimport {\n getNeonTextShadow,\n} from \"../../../../utils/visualEffects\";\nimport { MenuButtons } from \"./MenuButtonsOverlayHtml\";\n\nexport interface MenuSectionOverlayHtmlProps {\n readonly menuItems: Array<{\n mode: GameMode;\n korean: string;\n english: string;\n }>;\n readonly selectedIndex: number;\n readonly onModeSelect: (mode: GameMode) => void;\n readonly onSelectedIndexChange?: (index: number) => void;\n readonly onPlaySFX?: (sound: string) => void;\n readonly width?: number;\n readonly height?: number;\n readonly isMobile?: boolean; // For controls/haptics only, use width for layout sizing\n}\n\n/**\n * HTML-based MenuSection component for Three.js integration\n *\n * Optimized with React.memo for 60fps performance:\n * - Memoized to prevent unnecessary re-renders\n * - All callbacks use useCallback\n * - Styles pre-calculated and memoized\n */\nexport const MenuSectionOverlayHtml = React.memo<MenuSectionOverlayHtmlProps>(\n ({\n menuItems,\n selectedIndex,\n onModeSelect,\n onSelectedIndexChange,\n onPlaySFX,\n width = 800,\n height = 300,\n isMobile = false, // Default to false, parent should pass proper device detection\n }) => {\n const [hoveredItem, setHoveredItem] = useState<number | null>(null);\n const [focused, setFocused] = useState<boolean>(false);\n\n const enhancedOverlayStyles = useMemo(\n () =>\n getEnhancedKoreanOverlayStyles({\n opacity: 0.96,\n glowIntensity: focused ? \"medium\" : \"subtle\",\n includeGradient: false,\n includeBackdropBlur: false,\n depthLayers: 2,\n }),\n [focused],\n );\n\n const titleColor = useMemo(\n () => `#${KOREAN_COLORS.ACCENT_GOLD.toString(16).padStart(6, \"0\")}`,\n [],\n );\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (!onSelectedIndexChange) return;\n\n if (event.key === \"ArrowUp\") {\n event.preventDefault();\n event.stopPropagation();\n const nextIndex =\n selectedIndex === 0 ? menuItems.length - 1 : selectedIndex - 1;\n onSelectedIndexChange(nextIndex);\n onPlaySFX?.(\"menu_hover\");\n } else if (event.key === \"ArrowDown\") {\n event.preventDefault();\n event.stopPropagation();\n const nextIndex =\n selectedIndex === menuItems.length - 1 ? 0 : selectedIndex + 1;\n onSelectedIndexChange(nextIndex);\n onPlaySFX?.(\"menu_hover\");\n } else if (event.key === \" \" || event.key === \"Enter\") {\n event.preventDefault();\n event.stopPropagation();\n onPlaySFX?.(\"menu_select\");\n onModeSelect(menuItems[selectedIndex].mode);\n } else {\n const numKey = parseInt(event.key);\n if (numKey >= 1 && numKey <= menuItems.length) {\n event.stopPropagation();\n const targetIndex = numKey - 1;\n onSelectedIndexChange(targetIndex);\n onPlaySFX?.(\"menu_select\");\n onModeSelect(menuItems[targetIndex].mode);\n }\n }\n };\n window.addEventListener(\"keydown\", handleKeyDown);\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [\n selectedIndex,\n menuItems,\n onSelectedIndexChange,\n onModeSelect,\n onPlaySFX,\n ]);\n\n useEffect(() => {\n const handleFocus = () => setFocused(true);\n const handleBlur = () => setFocused(false);\n window.addEventListener(\"focusin\", handleFocus);\n window.addEventListener(\"focusout\", handleBlur);\n return () => {\n window.removeEventListener(\"focusin\", handleFocus);\n window.removeEventListener(\"focusout\", handleBlur);\n };\n }, []);\n\n const isSmallScreen = width < 768; // Mobile-sized screens\n\n const containerPadding = isSmallScreen ? 16 : 12;\n const titleFontSize = isSmallScreen\n ? getMobileKoreanFontSize(\"SMALL\", width ?? 375)\n : 14;\n const sectionGap = isSmallScreen ? 8 : 6;\n\n const safeAreaStyles = useMemo(\n () =>\n isMobile ? getSafeAreaPadding([\"top\", \"bottom\"], containerPadding) : {},\n [isMobile, containerPadding],\n );\n\n return (\n <div\n style={{\n ...enhancedOverlayStyles,\n ...safeAreaStyles,\n width: `${width}px`,\n minHeight: `${height}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n gap: `${sectionGap}px`,\n padding: `${containerPadding}px`,\n position: \"relative\",\n overflow: \"visible\",\n }}\n data-testid=\"main-menu-section\"\n >\n {/* Menu Title */}\n <div\n style={{\n fontSize: `${titleFontSize}px`,\n color: titleColor,\n fontWeight: \"bold\",\n fontFamily: FONT_FAMILY.KOREAN,\n textAlign: \"center\",\n textShadow: getNeonTextShadow(KOREAN_COLORS.ACCENT_GOLD, \"medium\"),\n }}\n data-testid=\"menu-title\"\n >\n 메인 메뉴 | Main Menu\n </div>\n\n {/* Menu Buttons - Extracted to MenuButtons component */}\n <MenuButtons\n menuItems={menuItems}\n selectedIndex={selectedIndex}\n hoveredIndex={hoveredItem}\n onModeSelect={onModeSelect}\n onHoverChange={setHoveredItem}\n onPlaySFX={onPlaySFX}\n width={width}\n isMobile={isMobile}\n />\n\n {/* Navigation Instructions */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: isSmallScreen ? \"4px\" : \"6px\",\n textAlign: \"center\",\n fontSize: isSmallScreen ? \"10px\" : \"12px\",\n color: `#${KOREAN_COLORS.TEXT_SECONDARY.toString(16).padStart(\n 6,\n \"0\",\n )}`,\n fontFamily: FONT_FAMILY.KOREAN,\n marginTop: \"auto\",\n }}\n data-testid=\"navigation-hint-container\"\n >\n <div data-testid=\"menu-navigation-hint-korean\">\n 방향키/마우스로 이동 • Enter/클릭으로 선택 • 숫자키로 바로가기\n </div>\n <div\n style={{ fontSize: isSmallScreen ? \"9px\" : \"10px\" }}\n data-testid=\"menu-navigation-hint-english\"\n >\n Arrow keys/mouse to navigate • Enter/click to select • Number keys for\n shortcuts\n </div>\n </div>\n </div>\n );\n },\n (prevProps, nextProps) => {\n return (\n prevProps.selectedIndex === nextProps.selectedIndex &&\n prevProps.width === nextProps.width &&\n prevProps.height === nextProps.height &&\n prevProps.isMobile === nextProps.isMobile &&\n prevProps.menuItems.length === nextProps.menuItems.length &&\n prevProps.onModeSelect === nextProps.onModeSelect &&\n prevProps.onSelectedIndexChange === nextProps.onSelectedIndexChange &&\n prevProps.onPlaySFX === nextProps.onPlaySFX\n );\n },\n);\n\nMenuSectionOverlayHtml.displayName = \"MenuSectionOverlayHtml\";\n\nexport default MenuSectionOverlayHtml;\n"],"mappings":";;;;;;;;;;;;;;;;;;AAoCA,IAAa,yBAAyB,MAAM,MACzC,EACC,WACA,eACA,cACA,uBACA,WACA,QAAQ,KACR,SAAS,KACT,WAAW,YACP;CACN,MAAM,CAAC,aAAa,kBAAkB,SAAwB,IAAI;CAClE,MAAM,CAAC,SAAS,cAAc,SAAkB,KAAK;CAErD,MAAM,wBAAwB,cAE1B,+BAA+B;EAC7B,SAAS;EACT,eAAe,UAAU,WAAW;EACpC,iBAAiB;EACjB,qBAAqB;EACrB,aAAa;CACf,CAAC,GACH,CAAC,OAAO,CACV;CAEA,MAAM,aAAa,cACX,IAAI,cAAc,YAAY,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,KAChE,CAAC,CACH;CAEA,gBAAgB;EACd,MAAM,iBAAiB,UAAyB;GAC9C,IAAI,CAAC,uBAAuB;GAE5B,IAAI,MAAM,QAAQ,WAAW;IAC3B,MAAM,eAAe;IACrB,MAAM,gBAAgB;IAGtB,sBADE,kBAAkB,IAAI,UAAU,SAAS,IAAI,gBAAgB,CAChC;IAC/B,YAAY,YAAY;GAC1B,OAAO,IAAI,MAAM,QAAQ,aAAa;IACpC,MAAM,eAAe;IACrB,MAAM,gBAAgB;IAGtB,sBADE,kBAAkB,UAAU,SAAS,IAAI,IAAI,gBAAgB,CAChC;IAC/B,YAAY,YAAY;GAC1B,OAAO,IAAI,MAAM,QAAQ,OAAO,MAAM,QAAQ,SAAS;IACrD,MAAM,eAAe;IACrB,MAAM,gBAAgB;IACtB,YAAY,aAAa;IACzB,aAAa,UAAU,eAAe,IAAI;GAC5C,OAAO;IACL,MAAM,SAAS,SAAS,MAAM,GAAG;IACjC,IAAI,UAAU,KAAK,UAAU,UAAU,QAAQ;KAC7C,MAAM,gBAAgB;KACtB,MAAM,cAAc,SAAS;KAC7B,sBAAsB,WAAW;KACjC,YAAY,aAAa;KACzB,aAAa,UAAU,aAAa,IAAI;IAC1C;GACF;EACF;EACA,OAAO,iBAAiB,WAAW,aAAa;EAChD,aAAa,OAAO,oBAAoB,WAAW,aAAa;CAClE,GAAG;EACD;EACA;EACA;EACA;EACA;CACF,CAAC;CAED,gBAAgB;EACd,MAAM,oBAAoB,WAAW,IAAI;EACzC,MAAM,mBAAmB,WAAW,KAAK;EACzC,OAAO,iBAAiB,WAAW,WAAW;EAC9C,OAAO,iBAAiB,YAAY,UAAU;EAC9C,aAAa;GACX,OAAO,oBAAoB,WAAW,WAAW;GACjD,OAAO,oBAAoB,YAAY,UAAU;EACnD;CACF,GAAG,CAAC,CAAC;CAEL,MAAM,gBAAgB,QAAQ;CAE9B,MAAM,mBAAmB,gBAAgB,KAAK;CAC9C,MAAM,gBAAgB,gBAClB,wBAAwB,SAAS,SAAS,GAAG,IAC7C;CACJ,MAAM,aAAa,gBAAgB,IAAI;CAEvC,MAAM,iBAAiB,cAEnB,WAAW,mBAAmB,CAAC,OAAO,QAAQ,GAAG,gBAAgB,IAAI,CAAC,GACxE,CAAC,UAAU,gBAAgB,CAC7B;CAEA,OACE,qBAAC,OAAD;EACE,OAAO;GACL,GAAG;GACH,GAAG;GACH,OAAO,GAAG,MAAM;GAChB,WAAW,GAAG,OAAO;GACrB,SAAS;GACT,eAAe;GACf,YAAY;GACZ,gBAAgB;GAChB,KAAK,GAAG,WAAW;GACnB,SAAS,GAAG,iBAAiB;GAC7B,UAAU;GACV,UAAU;EACZ;EACA,eAAY;YAfd;GAkBE,oBAAC,OAAD;IACE,OAAO;KACL,UAAU,GAAG,cAAc;KAC3B,OAAO;KACP,YAAY;KACZ,YAAY,YAAY;KACxB,WAAW;KACX,YAAY,kBAAkB,cAAc,aAAa,QAAQ;IACnE;IACA,eAAY;cACb;GAEI,CAAA;GAGL,oBAAC,aAAD;IACa;IACI;IACf,cAAc;IACA;IACd,eAAe;IACJ;IACJ;IACG;GACX,CAAA;GAGD,qBAAC,OAAD;IACE,OAAO;KACL,SAAS;KACT,eAAe;KACf,KAAK,gBAAgB,QAAQ;KAC7B,WAAW;KACX,UAAU,gBAAgB,SAAS;KACnC,OAAO,IAAI,cAAc,eAAe,SAAS,EAAE,EAAE,SACnD,GACA,GACF;KACA,YAAY,YAAY;KACxB,WAAW;IACb;IACA,eAAY;cAdd,CAgBE,oBAAC,OAAD;KAAK,eAAY;eAA8B;IAE1C,CAAA,GACL,oBAAC,OAAD;KACE,OAAO,EAAE,UAAU,gBAAgB,QAAQ,OAAO;KAClD,eAAY;eACb;IAGI,CAAA,CACF;;EACF;;AAEP,IACC,WAAW,cAAc;CACxB,OACE,UAAU,kBAAkB,UAAU,iBACtC,UAAU,UAAU,UAAU,SAC9B,UAAU,WAAW,UAAU,UAC/B,UAAU,aAAa,UAAU,YACjC,UAAU,UAAU,WAAW,UAAU,UAAU,UACnD,UAAU,iBAAiB,UAAU,gBACrC,UAAU,0BAA0B,UAAU,yBAC9C,UAAU,cAAc,UAAU;AAEtC,CACF;AAEA,uBAAuB,cAAc"}
@@ -1 +1 @@
1
- {"version":3,"file":"StatBarOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/StatBarOverlayHtml.tsx"],"sourcesContent":["/**\n * StatBar - Enhanced stat visualization component with Korean theming\n * \n * Refactored to use useKoreanTheme hook for consistent styling\n * Displays horizontal bar chart for combat statistics\n * \n * Performance optimized with React.memo and useMemo\n * \n * @module components/screens/intro\n * @category Intro UI\n * @korean 능력치바\n */\n\nimport React, { useMemo } from \"react\";\nimport { useKoreanTheme } from \"../../../shared/base/useKoreanTheme\";\nimport { KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString, hexColorToCSS } from \"../../../../utils/colorUtils\";\n\nexport interface StatBarProps {\n readonly label: string; // Format: \"Korean | English\"\n readonly value: number; // 0-100 range\n readonly max?: number; // Maximum value for scaling\n readonly color?: number; // Hex color for bar\n readonly height?: number; // Bar height in pixels\n readonly showValue?: boolean; // Show numeric value\n readonly isMobile?: boolean;\n}\n\n/**\n * StatBar component - Displays a horizontal bar chart for stats\n * \n * Refactored to use useKoreanTheme for consistent Korean theming:\n * - Uses Korean typography configuration\n * - Applies Korean color palette\n * - Responsive sizing based on device type\n * - Memoized for optimal performance\n * \n * Used in archetype cards to visualize combat statistics\n * \n * @example\n * ```tsx\n * <StatBar\n * label=\"공격 | Attack\"\n * value={85}\n * max={100}\n * color={KOREAN_COLORS.PRIMARY_CYAN}\n * isMobile={false}\n * />\n * ```\n */\nexport const StatBar: React.FC<StatBarProps> = React.memo(\n ({\n label,\n value,\n max = 100,\n color = KOREAN_COLORS.PRIMARY_CYAN,\n height = 12,\n showValue = true,\n isMobile = false,\n }) => {\n const { koreanTypography, colors: themeColors, calculateResponsiveSize } = useKoreanTheme({\n size: \"small\",\n isMobile,\n });\n\n const percentage = useMemo(\n () => Math.min(100, Math.max(0, (value / max) * 100)),\n [value, max]\n );\n\n const statBarColors = useMemo(\n () => ({\n barBackground: hexToRgbaString(themeColors.UI_BACKGROUND_MEDIUM, 1),\n barFill: hexToRgbaString(color, 0.9),\n barBorder: hexToRgbaString(color, 0.7),\n labelColor: hexColorToCSS(themeColors.TEXT_SECONDARY),\n valueColor: hexColorToCSS(color),\n }),\n [color, themeColors]\n );\n\n const fontSize = calculateResponsiveSize(isMobile ? 9 : 11);\n const labelWidth = calculateResponsiveSize(isMobile ? 70 : 80);\n const valueWidth = calculateResponsiveSize(isMobile ? 25 : 30);\n\n return (\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: `${calculateResponsiveSize(12)}px`,\n }}\n data-testid={`stat-bar-${label.split(\"|\")[0].trim()}`}\n >\n {/* Stat label with Korean typography */}\n <div\n style={{\n width: `${labelWidth}px`,\n fontSize: `${fontSize}px`,\n fontFamily: koreanTypography.fontFamily,\n color: statBarColors.labelColor,\n flexShrink: 0,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n lineHeight: koreanTypography.lineHeight,\n letterSpacing: koreanTypography.letterSpacing,\n wordBreak: koreanTypography.wordBreak,\n }}\n data-testid=\"stat-label\"\n >\n {label}\n </div>\n\n {/* Stat bar container */}\n <div\n style={{\n flex: 1,\n height: `${height}px`,\n background: statBarColors.barBackground,\n borderRadius: \"2px\",\n position: \"relative\",\n border: `1px solid ${statBarColors.barBorder}`,\n overflow: \"hidden\",\n }}\n data-testid=\"stat-bar-container\"\n >\n {/* Stat bar fill with smooth transition */}\n <div\n style={{\n width: `${percentage}%`,\n height: \"100%\",\n background: statBarColors.barFill,\n borderRadius: \"2px\",\n transition: \"width 0.3s ease\",\n boxShadow: `0 0 8px ${hexToRgbaString(color, 0.5)}`,\n }}\n data-testid=\"stat-bar-fill\"\n />\n </div>\n\n {/* Stat value */}\n {showValue && (\n <div\n style={{\n width: `${valueWidth}px`,\n fontSize: `${fontSize}px`,\n fontWeight: \"bold\",\n fontFamily: koreanTypography.fontFamily,\n color: statBarColors.valueColor,\n textAlign: \"right\",\n flexShrink: 0,\n }}\n data-testid=\"stat-value\"\n >\n {Math.round(value)}\n </div>\n )}\n </div>\n );\n }\n);\n\nStatBar.displayName = \"StatBar\";\n\nexport default StatBar;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,IAAa,UAAkC,MAAM,MAClD,EACC,OACA,OACA,MAAM,KACN,QAAQ,cAAc,cACtB,SAAS,IACT,YAAY,MACZ,WAAW,YACP;CACJ,MAAM,EAAE,kBAAkB,QAAQ,aAAa,4BAA4B,eAAe;EACxF,MAAM;EACN;EACD,CAAC;CAEF,MAAM,aAAa,cACX,KAAK,IAAI,KAAK,KAAK,IAAI,GAAI,QAAQ,MAAO,IAAI,CAAC,EACrD,CAAC,OAAO,IAAI,CACb;CAED,MAAM,gBAAgB,eACb;EACL,eAAe,gBAAgB,YAAY,sBAAsB,EAAE;EACnE,SAAS,gBAAgB,OAAO,GAAI;EACpC,WAAW,gBAAgB,OAAO,GAAI;EACtC,YAAY,cAAc,YAAY,eAAe;EACrD,YAAY,cAAc,MAAM;EACjC,GACD,CAAC,OAAO,YAAY,CACrB;CAED,MAAM,WAAW,wBAAwB,WAAW,IAAI,GAAG;CAC3D,MAAM,aAAa,wBAAwB,WAAW,KAAK,GAAG;CAC9D,MAAM,aAAa,wBAAwB,WAAW,KAAK,GAAG;CAE9D,OACE,qBAAC,OAAD;EACE,OAAO;GACL,OAAO;GACP,SAAS;GACT,eAAe;GACf,YAAY;GACZ,KAAK,GAAG,wBAAwB,GAAG,CAAC;GACrC;EACD,eAAa,YAAY,MAAM,MAAM,IAAI,CAAC,GAAG,MAAM;YARrD;GAWE,oBAAC,OAAD;IACE,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,UAAU,GAAG,SAAS;KACtB,YAAY,iBAAiB;KAC7B,OAAO,cAAc;KACrB,YAAY;KACZ,YAAY;KACZ,UAAU;KACV,cAAc;KACd,YAAY,iBAAiB;KAC7B,eAAe,iBAAiB;KAChC,WAAW,iBAAiB;KAC7B;IACD,eAAY;cAEX;IACG,CAAA;GAGN,oBAAC,OAAD;IACE,OAAO;KACL,MAAM;KACN,QAAQ,GAAG,OAAO;KAClB,YAAY,cAAc;KAC1B,cAAc;KACd,UAAU;KACV,QAAQ,aAAa,cAAc;KACnC,UAAU;KACX;IACD,eAAY;cAGZ,oBAAC,OAAD;KACE,OAAO;MACL,OAAO,GAAG,WAAW;MACrB,QAAQ;MACR,YAAY,cAAc;MAC1B,cAAc;MACd,YAAY;MACZ,WAAW,WAAW,gBAAgB,OAAO,GAAI;MAClD;KACD,eAAY;KACZ,CAAA;IACE,CAAA;GAGL,aACC,oBAAC,OAAD;IACE,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,UAAU,GAAG,SAAS;KACtB,YAAY;KACZ,YAAY,iBAAiB;KAC7B,OAAO,cAAc;KACrB,WAAW;KACX,YAAY;KACb;IACD,eAAY;cAEX,KAAK,MAAM,MAAM;IACd,CAAA;GAEJ;;EAGX;AAED,QAAQ,cAAc"}
1
+ {"version":3,"file":"StatBarOverlayHtml.js","names":[],"sources":["../../../../../src/components/screens/intro/components/StatBarOverlayHtml.tsx"],"sourcesContent":["/**\n * StatBar - Enhanced stat visualization component with Korean theming\n * \n * Refactored to use useKoreanTheme hook for consistent styling\n * Displays horizontal bar chart for combat statistics\n * \n * Performance optimized with React.memo and useMemo\n * \n * @module components/screens/intro\n * @category Intro UI\n * @korean 능력치바\n */\n\nimport React, { useMemo } from \"react\";\nimport { useKoreanTheme } from \"../../../shared/base/useKoreanTheme\";\nimport { KOREAN_COLORS } from \"../../../../types/constants\";\nimport { hexToRgbaString, hexColorToCSS } from \"../../../../utils/colorUtils\";\n\nexport interface StatBarProps {\n readonly label: string; // Format: \"Korean | English\"\n readonly value: number; // 0-100 range\n readonly max?: number; // Maximum value for scaling\n readonly color?: number; // Hex color for bar\n readonly height?: number; // Bar height in pixels\n readonly showValue?: boolean; // Show numeric value\n readonly isMobile?: boolean;\n}\n\n/**\n * StatBar component - Displays a horizontal bar chart for stats\n * \n * Refactored to use useKoreanTheme for consistent Korean theming:\n * - Uses Korean typography configuration\n * - Applies Korean color palette\n * - Responsive sizing based on device type\n * - Memoized for optimal performance\n * \n * Used in archetype cards to visualize combat statistics\n * \n * @example\n * ```tsx\n * <StatBar\n * label=\"공격 | Attack\"\n * value={85}\n * max={100}\n * color={KOREAN_COLORS.PRIMARY_CYAN}\n * isMobile={false}\n * />\n * ```\n */\nexport const StatBar: React.FC<StatBarProps> = React.memo(\n ({\n label,\n value,\n max = 100,\n color = KOREAN_COLORS.PRIMARY_CYAN,\n height = 12,\n showValue = true,\n isMobile = false,\n }) => {\n const { koreanTypography, colors: themeColors, calculateResponsiveSize } = useKoreanTheme({\n size: \"small\",\n isMobile,\n });\n\n const percentage = useMemo(\n () => Math.min(100, Math.max(0, (value / max) * 100)),\n [value, max]\n );\n\n const statBarColors = useMemo(\n () => ({\n barBackground: hexToRgbaString(themeColors.UI_BACKGROUND_MEDIUM, 1),\n barFill: hexToRgbaString(color, 0.9),\n barBorder: hexToRgbaString(color, 0.7),\n labelColor: hexColorToCSS(themeColors.TEXT_SECONDARY),\n valueColor: hexColorToCSS(color),\n }),\n [color, themeColors]\n );\n\n const fontSize = calculateResponsiveSize(isMobile ? 9 : 11);\n const labelWidth = calculateResponsiveSize(isMobile ? 70 : 80);\n const valueWidth = calculateResponsiveSize(isMobile ? 25 : 30);\n\n return (\n <div\n style={{\n width: \"100%\",\n display: \"flex\",\n flexDirection: \"row\",\n alignItems: \"center\",\n gap: `${calculateResponsiveSize(12)}px`,\n }}\n data-testid={`stat-bar-${label.split(\"|\")[0].trim()}`}\n >\n {/* Stat label with Korean typography */}\n <div\n style={{\n width: `${labelWidth}px`,\n fontSize: `${fontSize}px`,\n fontFamily: koreanTypography.fontFamily,\n color: statBarColors.labelColor,\n flexShrink: 0,\n whiteSpace: \"nowrap\",\n overflow: \"hidden\",\n textOverflow: \"ellipsis\",\n lineHeight: koreanTypography.lineHeight,\n letterSpacing: koreanTypography.letterSpacing,\n wordBreak: koreanTypography.wordBreak,\n }}\n data-testid=\"stat-label\"\n >\n {label}\n </div>\n\n {/* Stat bar container */}\n <div\n style={{\n flex: 1,\n height: `${height}px`,\n background: statBarColors.barBackground,\n borderRadius: \"2px\",\n position: \"relative\",\n border: `1px solid ${statBarColors.barBorder}`,\n overflow: \"hidden\",\n }}\n data-testid=\"stat-bar-container\"\n >\n {/* Stat bar fill with smooth transition */}\n <div\n style={{\n width: `${percentage}%`,\n height: \"100%\",\n background: statBarColors.barFill,\n borderRadius: \"2px\",\n transition: \"width 0.3s ease\",\n boxShadow: `0 0 8px ${hexToRgbaString(color, 0.5)}`,\n }}\n data-testid=\"stat-bar-fill\"\n />\n </div>\n\n {/* Stat value */}\n {showValue && (\n <div\n style={{\n width: `${valueWidth}px`,\n fontSize: `${fontSize}px`,\n fontWeight: \"bold\",\n fontFamily: koreanTypography.fontFamily,\n color: statBarColors.valueColor,\n textAlign: \"right\",\n flexShrink: 0,\n }}\n data-testid=\"stat-value\"\n >\n {Math.round(value)}\n </div>\n )}\n </div>\n );\n }\n);\n\nStatBar.displayName = \"StatBar\";\n\nexport default StatBar;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkDA,IAAa,UAAkC,MAAM,MAClD,EACC,OACA,OACA,MAAM,KACN,QAAQ,cAAc,cACtB,SAAS,IACT,YAAY,MACZ,WAAW,YACP;CACJ,MAAM,EAAE,kBAAkB,QAAQ,aAAa,4BAA4B,eAAe;EACxF,MAAM;EACN;CACF,CAAC;CAED,MAAM,aAAa,cACX,KAAK,IAAI,KAAK,KAAK,IAAI,GAAI,QAAQ,MAAO,GAAG,CAAC,GACpD,CAAC,OAAO,GAAG,CACb;CAEA,MAAM,gBAAgB,eACb;EACL,eAAe,gBAAgB,YAAY,sBAAsB,CAAC;EAClE,SAAS,gBAAgB,OAAO,EAAG;EACnC,WAAW,gBAAgB,OAAO,EAAG;EACrC,YAAY,cAAc,YAAY,cAAc;EACpD,YAAY,cAAc,KAAK;CACjC,IACA,CAAC,OAAO,WAAW,CACrB;CAEA,MAAM,WAAW,wBAAwB,WAAW,IAAI,EAAE;CAC1D,MAAM,aAAa,wBAAwB,WAAW,KAAK,EAAE;CAC7D,MAAM,aAAa,wBAAwB,WAAW,KAAK,EAAE;CAE7D,OACE,qBAAC,OAAD;EACE,OAAO;GACL,OAAO;GACP,SAAS;GACT,eAAe;GACf,YAAY;GACZ,KAAK,GAAG,wBAAwB,EAAE,EAAE;EACtC;EACA,eAAa,YAAY,MAAM,MAAM,GAAG,EAAE,GAAG,KAAK;YARpD;GAWE,oBAAC,OAAD;IACE,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,UAAU,GAAG,SAAS;KACtB,YAAY,iBAAiB;KAC7B,OAAO,cAAc;KACrB,YAAY;KACZ,YAAY;KACZ,UAAU;KACV,cAAc;KACd,YAAY,iBAAiB;KAC7B,eAAe,iBAAiB;KAChC,WAAW,iBAAiB;IAC9B;IACA,eAAY;cAEX;GACE,CAAA;GAGL,oBAAC,OAAD;IACE,OAAO;KACL,MAAM;KACN,QAAQ,GAAG,OAAO;KAClB,YAAY,cAAc;KAC1B,cAAc;KACd,UAAU;KACV,QAAQ,aAAa,cAAc;KACnC,UAAU;IACZ;IACA,eAAY;cAGZ,oBAAC,OAAD;KACE,OAAO;MACL,OAAO,GAAG,WAAW;MACrB,QAAQ;MACR,YAAY,cAAc;MAC1B,cAAc;MACd,YAAY;MACZ,WAAW,WAAW,gBAAgB,OAAO,EAAG;KAClD;KACA,eAAY;IACb,CAAA;GACE,CAAA;GAGJ,aACC,oBAAC,OAAD;IACE,OAAO;KACL,OAAO,GAAG,WAAW;KACrB,UAAU,GAAG,SAAS;KACtB,YAAY;KACZ,YAAY,iBAAiB;KAC7B,OAAO,cAAc;KACrB,WAAW;KACX,YAAY;IACd;IACA,eAAY;cAEX,KAAK,MAAM,KAAK;GACd,CAAA;EAEJ;;AAET,CACF;AAEA,QAAQ,cAAc"}
@@ -4,11 +4,11 @@ import { TRIGRAM_DATA } from "../../../systems/trigram/types.js";
4
4
  import { PLAYER_ARCHETYPES_DATA } from "../../../systems/types.js";
5
5
  import { useWebGLContextLossHandler } from "../../../hooks/useWebGLContextLossHandler.js";
6
6
  import { KoreanCulture } from "../../../systems/trigram/KoreanCulture.js";
7
+ import { getLayoutConstants } from "../../../utils/responsiveLayoutHelpers.js";
7
8
  import { hexToRgbaString } from "../../../utils/colorUtils.js";
8
9
  import { useKoreanTheme } from "../../shared/base/useKoreanTheme.js";
9
10
  import { VolumeControl } from "../../shared/ui/VolumeControl.js";
10
11
  import { shouldUseMobileControls } from "../../../utils/deviceDetection.js";
11
- import { getLayoutConstants } from "../../../utils/responsiveLayoutHelpers.js";
12
12
  import BackgroundScene3D from "../../shared/three/scene/BackgroundScene3D.js";
13
13
  import useWindowSize from "../../../hooks/useWindowSize.js";
14
14
  import { BackButton, LinkButton } from "../../shared/ui/BackButton.js";
@@ -1 +1 @@
1
- {"version":3,"file":"PhilosophyScreen3D.js","names":[],"sources":["../../../../src/components/screens/philosophy/PhilosophyScreen3D.tsx"],"sourcesContent":["import { Canvas } from \"@react-three/fiber\";\nimport React, { useCallback, useEffect, useMemo } from \"react\";\nimport { useAudio } from \"../../../audio/AudioProvider\";\nimport { useWebGLContextLossHandler } from \"../../../hooks/useWebGLContextLossHandler\";\nimport { useWindowSize } from \"../../../hooks/useWindowSize\";\nimport { PLAYER_ARCHETYPES_DATA } from \"../../../systems\";\nimport { KoreanCulture } from \"../../../systems/trigram/KoreanCulture\";\nimport { TRIGRAM_DATA } from \"../../../systems/trigram/types\";\nimport { TrigramStance } from \"../../../types\";\nimport { Z_INDEX } from \"../../../types/LayoutTypes\";\nimport { hexToRgbaString } from \"../../../utils/colorUtils\";\nimport { shouldUseMobileControls } from \"../../../utils/deviceDetection\";\nimport { getLayoutConstants } from \"../../../utils/responsiveLayoutHelpers\";\nimport { useKoreanTheme } from \"../../shared/base/useKoreanTheme\";\nimport { BackgroundScene3D } from \"../../shared/three\";\nimport { BackButton, LinkButton } from \"../../shared/ui/BackButton\";\nimport { VolumeControl } from \"../../shared/ui/VolumeControl\";\n\nexport interface PhilosophyScreen3DProps {\n readonly onReturnToMenu: () => void;\n readonly width?: number;\n readonly height?: number;\n}\n\n/**\n * Three.js-based PhilosophyScreen Component\n */\nexport const PhilosophyScreen3D: React.FC<PhilosophyScreen3DProps> = ({\n onReturnToMenu,\n width: propWidth,\n height: propHeight,\n}) => {\n\n useWebGLContextLossHandler({\n onContextLost: () => {\n console.warn(\"⚠️ WebGL context lost in PhilosophyScreen\");\n },\n onContextRestored: () => {\n console.log(\"✓ WebGL context restored in PhilosophyScreen\");\n },\n autoRestore: true,\n });\n\n const audio = useAudio();\n const { width, height } = useWindowSize();\n\n const screenWidth = propWidth ?? width;\n const screenHeight = propHeight ?? height;\n\n const isMobile = shouldUseMobileControls();\n const isTablet = useMemo(\n () => !isMobile && screenWidth >= 768 && screenWidth < 1024,\n [isMobile, screenWidth],\n );\n const isLargeDesktop = useMemo(\n () => !isMobile && screenWidth >= 1920,\n [isMobile, screenWidth],\n ); // 4K/2K displays\n\n const layoutConstants = useMemo(\n () => getLayoutConstants(screenWidth),\n [screenWidth],\n );\n\n const theme = useKoreanTheme({\n variant: \"primary\",\n size: \"md\",\n isMobile,\n });\n\n const scrollbarStyle = useMemo(\n () => ({\n __html: `\n .philosophy-scrollbar::-webkit-scrollbar {\n width: 12px !important;\n display: block !important;\n }\n .philosophy-scrollbar::-webkit-scrollbar-track {\n background: ${hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.8)};\n border-radius: 6px;\n }\n .philosophy-scrollbar::-webkit-scrollbar-thumb {\n background: ${hexToRgbaString(theme.colors.ACCENT_GOLD, 1)};\n border-radius: 6px;\n border: 2px solid ${hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.8)};\n }\n .philosophy-scrollbar::-webkit-scrollbar-thumb:hover {\n background: ${hexToRgbaString(theme.colors.PRIMARY_CYAN, 1)};\n }\n `,\n }),\n [theme],\n );\n\n const colors = useMemo(\n () => ({\n background: hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.95),\n headerBg: hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.9),\n sectionBg: hexToRgbaString(theme.colors.UI_BACKGROUND_LIGHT, 0.8),\n borderGold: hexToRgbaString(theme.colors.ACCENT_GOLD, 0.8),\n borderCyan: hexToRgbaString(theme.colors.PRIMARY_CYAN, 0.6),\n borderMagenta: hexToRgbaString(theme.colors.SECONDARY_MAGENTA, 0.6),\n borderRed: hexToRgbaString(theme.colors.KOREAN_RED, 0.6),\n textPrimary: `#${theme.colors.TEXT_PRIMARY.toString(16).padStart(6, \"0\")}`,\n textSecondary: `#${theme.colors.TEXT_SECONDARY.toString(16).padStart(6, \"0\")}`,\n textTertiary: `#${theme.colors.TEXT_TERTIARY.toString(16).padStart(6, \"0\")}`,\n accentGold: `#${theme.colors.ACCENT_GOLD.toString(16).padStart(6, \"0\")}`,\n accentCyan: `#${theme.colors.PRIMARY_CYAN.toString(16).padStart(6, \"0\")}`,\n }),\n [theme],\n );\n\n useEffect(() => {\n const startMusic = async () => {\n await audio.fadeIn(\"underground_theme\", 2000);\n };\n void startMusic().catch((err) =>\n console.warn(\"Failed to start philosophy music:\", err),\n );\n\n return () => {\n void audio\n .fadeOut(2000)\n .then(() => audio.stopMusic())\n .catch((err) => console.warn(\"Failed to stop philosophy music:\", err));\n };\n }, [audio]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" || event.key.toLowerCase() === \"m\") {\n event.preventDefault();\n audio.playSFX(\"menu_back\");\n onReturnToMenu();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown, { passive: false });\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [onReturnToMenu, audio]);\n\n const handleBackClick = useCallback(() => {\n audio.playSFX(\"menu_back\");\n onReturnToMenu();\n }, [audio, onReturnToMenu]);\n\n const handleISMSClick = useCallback(() => {\n audio.playSFX(\"menu_select\");\n window.open(\"https://github.com/Hack23/ISMS-PUBLIC\", \"_blank\");\n }, [audio]);\n\n const martialValues = useMemo(\n () => Object.entries(KoreanCulture.MARTIAL_VALUES),\n [],\n );\n\n const trigramPhilosophies = useMemo(\n () =>\n Object.entries(TRIGRAM_DATA).map(([stance, data]) => ({\n stance: stance as TrigramStance,\n ...data,\n })),\n [],\n );\n\n const archetypes = useMemo(() => Object.entries(PLAYER_ARCHETYPES_DATA), []);\n\n const valuesPerRow = isMobile ? 3 : isTablet ? 4 : isLargeDesktop ? 8 : 6;\n const trigramsPerRow = isMobile ? 2 : isTablet ? 3 : isLargeDesktop ? 5 : 4;\n\n return (\n <div\n style={{\n width: screenWidth,\n height: screenHeight,\n position: \"relative\",\n overflow: \"hidden\",\n }}\n data-testid=\"philosophy-screen\"\n >\n {/* Volume Control - outside Canvas to maintain AudioProvider context */}\n <VolumeControl position=\"top-right\" compact={isMobile} />\n\n {/* Three.js Canvas for 3D background */}\n <Canvas\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n zIndex: Z_INDEX.ARENA,\n }}\n gl={{\n antialias: true,\n alpha: false,\n powerPreference: \"high-performance\",\n }}\n dpr={[1, 2]}\n camera={{ position: [0, 5, 10], fov: 75 }}\n onCreated={({ gl }) => {\n gl.setClearColor(theme.colors.UI_BACKGROUND_DARK, 1);\n }}\n >\n {/* 3D Background Scene */}\n <BackgroundScene3D theme=\"philosophy\" />\n </Canvas>\n\n {/* UI Overlay (positioned absolutely over Canvas) - matches CombatScreen pattern */}\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n pointerEvents: \"none\",\n zIndex: Z_INDEX.HUD,\n }}\n data-testid=\"philosophy-hud-overlay\"\n >\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n color: colors.textPrimary,\n fontFamily: theme.koreanTypography.fontFamily,\n lineHeight: theme.koreanTypography.lineHeight,\n pointerEvents: \"auto\",\n }}\n >\n {/* Header */}\n <div\n style={{\n height: `${layoutConstants.headerHeight}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: colors.headerBg,\n borderBottom: `3px solid ${colors.borderGold}`,\n padding: `${layoutConstants.padding}px`,\n position: \"relative\",\n }}\n data-testid=\"philosophy-header\"\n >\n <h1\n style={{\n fontSize: isMobile ? \"28px\" : \"36px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: 0,\n textShadow: `0 0 15px ${hexToRgbaString(\n theme.colors.ACCENT_GOLD,\n 0.6,\n )}`,\n }}\n >\n 흑괘 무도 철학\n </h1>\n <p\n style={{\n fontSize: isMobile ? \"14px\" : \"18px\",\n color: colors.textSecondary,\n margin: \"8px 0 0 0\",\n }}\n >\n Black Trigram Martial Philosophy\n </p>\n\n {/* Decorative line */}\n <div\n style={{\n width: \"80%\",\n height: \"2px\",\n background: `linear-gradient(90deg, transparent, ${colors.borderGold}, transparent)`,\n marginTop: \"10px\",\n }}\n />\n </div>\n\n {/* WebKit Scrollbar Styling - Using !important to override global hide */}\n <style dangerouslySetInnerHTML={scrollbarStyle} />\n\n {/* Content Area - Scrollable */}\n <div\n className=\"philosophy-scrollbar\"\n style={{\n flex: 1,\n overflowY: \"auto\",\n overflowX: \"hidden\",\n padding: `${layoutConstants.padding}px`,\n scrollbarWidth: \"thin\",\n scrollbarColor: `${colors.accentGold} ${colors.sectionBg}`,\n }}\n data-testid=\"philosophy-content\"\n >\n {/* Martial Values Section */}\n <div\n style={{\n marginBottom: `${layoutConstants.sectionSpacing}px`,\n background: colors.sectionBg,\n borderRadius: \"10px\",\n border: `2px solid ${colors.borderRed}`,\n padding: \"20px\",\n }}\n data-testid=\"martial-values\"\n >\n <h2\n style={{\n fontSize: isMobile ? \"18px\" : \"22px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: \"0 0 20px 0\",\n }}\n >\n 무도 가치관 (Martial Values)\n </h2>\n\n {/* Values Grid */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${valuesPerRow}, 1fr)`,\n gap: \"10px\",\n }}\n >\n {martialValues.map(([key, value]) => (\n <div\n key={key}\n style={{\n background: hexToRgbaString(\n theme.colors.UI_BACKGROUND_DARK,\n 0.7,\n ),\n borderRadius: \"6px\",\n border: `1px solid ${colors.borderGold}`,\n padding: \"12px\",\n textAlign: \"center\",\n }}\n data-testid={`martial-value-${key}`}\n >\n <div\n style={{\n fontSize: isMobile ? \"16px\" : \"18px\",\n fontWeight: \"bold\",\n color: colors.textPrimary,\n marginBottom: \"4px\",\n }}\n >\n {value.korean}\n </div>\n <div\n style={{\n fontSize: isMobile ? \"11px\" : \"13px\",\n color: colors.textSecondary,\n }}\n >\n {value.english}\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {/* Trigram Philosophy Section */}\n <div\n style={{\n marginBottom: `${layoutConstants.sectionSpacing}px`,\n background: colors.sectionBg,\n borderRadius: \"10px\",\n border: `2px solid ${colors.borderCyan}`,\n padding: \"20px\",\n }}\n data-testid=\"trigram-philosophy\"\n >\n <h2\n style={{\n fontSize: isMobile ? \"18px\" : \"22px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: \"0 0 20px 0\",\n }}\n >\n 팔괘 철학 (Eight Trigrams Philosophy)\n </h2>\n\n {/* Trigrams Grid */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${trigramsPerRow}, 1fr)`,\n gap: \"15px\",\n }}\n >\n {trigramPhilosophies.map((trigram) => (\n <div\n key={trigram.stance}\n style={{\n background: hexToRgbaString(trigram.theme.primary, 0.25),\n borderRadius: \"8px\",\n border: `2px solid #${trigram.theme.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n padding: \"15px\",\n }}\n data-testid={`trigram-${trigram.stance}`}\n >\n {/* Trigram Symbol */}\n <div\n style={{\n fontSize: isMobile ? \"32px\" : \"40px\",\n color: `#${trigram.theme.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n textAlign: \"center\",\n marginBottom: \"10px\",\n }}\n >\n {trigram.symbol}\n </div>\n\n {/* Name with Chinese character */}\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n fontWeight: \"bold\",\n color: colors.textPrimary,\n textAlign: \"center\",\n marginBottom: \"4px\",\n }}\n >\n {trigram.name.korean} ({trigram.name.english})\n </div>\n\n {/* Chinese character and attribute */}\n <div\n style={{\n fontSize: isMobile ? \"11px\" : \"13px\",\n color: colors.accentGold,\n textAlign: \"center\",\n marginBottom: \"8px\",\n fontWeight: \"bold\",\n }}\n >\n {trigram.chinese} - {trigram.attribute.chinese},{\" \"}\n {trigram.attribute.korean}\n </div>\n\n {/* Core meaning */}\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n color: colors.accentCyan,\n textAlign: \"center\",\n marginBottom: \"8px\",\n }}\n >\n {trigram.meaning.korean} | {trigram.meaning.english}\n </div>\n\n {/* Philosophy */}\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n color: colors.textSecondary,\n textAlign: \"center\",\n marginBottom: \"6px\",\n }}\n >\n {trigram.philosophy.korean}\n </div>\n\n {/* Combat description */}\n <div\n style={{\n fontSize: isMobile ? \"9px\" : \"10px\",\n color: colors.textTertiary,\n textAlign: \"center\",\n fontStyle: \"italic\",\n }}\n >\n {trigram.combat.english}\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {/* Archetype Philosophy Section */}\n <div\n style={{\n marginBottom: `${layoutConstants.sectionSpacing}px`,\n background: colors.sectionBg,\n borderRadius: \"10px\",\n border: `2px solid ${colors.borderMagenta}`,\n padding: \"20px\",\n }}\n data-testid=\"archetype-philosophy\"\n >\n <h2\n style={{\n fontSize: isMobile ? \"18px\" : \"22px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: \"0 0 20px 0\",\n }}\n >\n 무사 유형 철학 (Warrior Archetype Philosophy)\n </h2>\n\n {/* Archetypes List */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {archetypes.map(([archetype, data]) => (\n <div\n key={archetype}\n style={{\n background: hexToRgbaString(data.colors.primary, 0.2),\n borderRadius: \"6px\",\n border: `1px solid #${data.colors.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n padding: \"15px\",\n }}\n data-testid={`archetype-${archetype}`}\n >\n {/* Name */}\n <div\n style={{\n fontSize: isMobile ? \"16px\" : \"18px\",\n fontWeight: \"bold\",\n color: `#${data.colors.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n marginBottom: \"8px\",\n }}\n >\n {data.name.korean} ({data.name.english})\n </div>\n\n {/* Description */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: isMobile ? \"1fr\" : \"1fr 1fr\",\n gap: \"10px\",\n }}\n >\n <div\n style={{\n fontSize: isMobile ? \"11px\" : \"13px\",\n color: colors.textPrimary,\n }}\n >\n {data.description.korean}\n </div>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"12px\",\n color: colors.textSecondary,\n }}\n >\n {data.description.english}\n </div>\n </div>\n\n {/* Specialist tag */}\n <div\n style={{\n marginTop: \"8px\",\n fontSize: isMobile ? \"9px\" : \"11px\",\n color: colors.textTertiary,\n }}\n >\n 전통 무예 전문가\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n\n {/* Footer */}\n <div\n style={{\n minHeight: `${layoutConstants.footerHeight}px`,\n background: colors.headerBg,\n borderTop: `3px solid ${colors.borderGold}`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: `${layoutConstants.padding}px`,\n gap: \"15px\",\n }}\n data-testid=\"philosophy-footer\"\n >\n {/* Motivation Quote */}\n <div\n style={{\n background: hexToRgbaString(theme.colors.ACCENT_GOLD, 0.15),\n borderRadius: \"8px\",\n border: `1px solid ${colors.borderGold}`,\n padding: \"15px\",\n textAlign: \"center\",\n maxWidth: \"90%\",\n }}\n >\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: colors.accentGold,\n fontStyle: \"italic\",\n marginBottom: \"4px\",\n }}\n >\n 무술은 단순한 격투가 아닌, 자신을 수양하고 상대를 존중하는\n 도(道)입니다\n </div>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"12px\",\n color: colors.textSecondary,\n fontStyle: \"italic\",\n }}\n >\n Martial arts is not mere combat, but the Way (道) of\n self-cultivation and respect for others\n </div>\n </div>\n\n {/* ISMS Link */}\n <LinkButton\n onClick={handleISMSClick}\n korean=\"공개 보안 정책\"\n english=\"View Security Policies\"\n icon=\"🔐\"\n isMobile={isMobile}\n testId=\"isms-public-link\"\n />\n\n {/* Action Row */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n width: \"100%\",\n gap: \"15px\",\n }}\n >\n {/* Back Button */}\n <BackButton\n onClick={handleBackClick}\n korean=\"돌아가기\"\n english=\"Return\"\n isMobile={isMobile}\n testId=\"philosophy-back-button\"\n />\n\n {/* Keyboard Hint */}\n <div\n style={{\n background: hexToRgbaString(\n theme.colors.UI_BACKGROUND_MEDIUM,\n 0.9,\n ),\n borderRadius: \"6px\",\n padding: \"8px 12px\",\n fontSize: isMobile ? \"11px\" : \"12px\",\n fontWeight: \"bold\",\n color: `#${theme.colors.SECONDARY_MAGENTA.toString(\n 16,\n ).padStart(6, \"0\")}`,\n border: `1px solid ${colors.borderGold}`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"2px\",\n }}\n data-testid=\"keyboard-shortcuts\"\n >\n <span>ESC</span>\n <span>M</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default PhilosophyScreen3D;\n"],"mappings":"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"}
1
+ {"version":3,"file":"PhilosophyScreen3D.js","names":[],"sources":["../../../../src/components/screens/philosophy/PhilosophyScreen3D.tsx"],"sourcesContent":["import { Canvas } from \"@react-three/fiber\";\nimport React, { useCallback, useEffect, useMemo } from \"react\";\nimport { useAudio } from \"../../../audio/AudioProvider\";\nimport { useWebGLContextLossHandler } from \"../../../hooks/useWebGLContextLossHandler\";\nimport { useWindowSize } from \"../../../hooks/useWindowSize\";\nimport { PLAYER_ARCHETYPES_DATA } from \"../../../systems\";\nimport { KoreanCulture } from \"../../../systems/trigram/KoreanCulture\";\nimport { TRIGRAM_DATA } from \"../../../systems/trigram/types\";\nimport { TrigramStance } from \"../../../types\";\nimport { Z_INDEX } from \"../../../types/LayoutTypes\";\nimport { hexToRgbaString } from \"../../../utils/colorUtils\";\nimport { shouldUseMobileControls } from \"../../../utils/deviceDetection\";\nimport { getLayoutConstants } from \"../../../utils/responsiveLayoutHelpers\";\nimport { useKoreanTheme } from \"../../shared/base/useKoreanTheme\";\nimport { BackgroundScene3D } from \"../../shared/three\";\nimport { BackButton, LinkButton } from \"../../shared/ui/BackButton\";\nimport { VolumeControl } from \"../../shared/ui/VolumeControl\";\n\nexport interface PhilosophyScreen3DProps {\n readonly onReturnToMenu: () => void;\n readonly width?: number;\n readonly height?: number;\n}\n\n/**\n * Three.js-based PhilosophyScreen Component\n */\nexport const PhilosophyScreen3D: React.FC<PhilosophyScreen3DProps> = ({\n onReturnToMenu,\n width: propWidth,\n height: propHeight,\n}) => {\n\n useWebGLContextLossHandler({\n onContextLost: () => {\n console.warn(\"⚠️ WebGL context lost in PhilosophyScreen\");\n },\n onContextRestored: () => {\n console.log(\"✓ WebGL context restored in PhilosophyScreen\");\n },\n autoRestore: true,\n });\n\n const audio = useAudio();\n const { width, height } = useWindowSize();\n\n const screenWidth = propWidth ?? width;\n const screenHeight = propHeight ?? height;\n\n const isMobile = shouldUseMobileControls();\n const isTablet = useMemo(\n () => !isMobile && screenWidth >= 768 && screenWidth < 1024,\n [isMobile, screenWidth],\n );\n const isLargeDesktop = useMemo(\n () => !isMobile && screenWidth >= 1920,\n [isMobile, screenWidth],\n ); // 4K/2K displays\n\n const layoutConstants = useMemo(\n () => getLayoutConstants(screenWidth),\n [screenWidth],\n );\n\n const theme = useKoreanTheme({\n variant: \"primary\",\n size: \"md\",\n isMobile,\n });\n\n const scrollbarStyle = useMemo(\n () => ({\n __html: `\n .philosophy-scrollbar::-webkit-scrollbar {\n width: 12px !important;\n display: block !important;\n }\n .philosophy-scrollbar::-webkit-scrollbar-track {\n background: ${hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.8)};\n border-radius: 6px;\n }\n .philosophy-scrollbar::-webkit-scrollbar-thumb {\n background: ${hexToRgbaString(theme.colors.ACCENT_GOLD, 1)};\n border-radius: 6px;\n border: 2px solid ${hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.8)};\n }\n .philosophy-scrollbar::-webkit-scrollbar-thumb:hover {\n background: ${hexToRgbaString(theme.colors.PRIMARY_CYAN, 1)};\n }\n `,\n }),\n [theme],\n );\n\n const colors = useMemo(\n () => ({\n background: hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.95),\n headerBg: hexToRgbaString(theme.colors.UI_BACKGROUND_DARK, 0.9),\n sectionBg: hexToRgbaString(theme.colors.UI_BACKGROUND_LIGHT, 0.8),\n borderGold: hexToRgbaString(theme.colors.ACCENT_GOLD, 0.8),\n borderCyan: hexToRgbaString(theme.colors.PRIMARY_CYAN, 0.6),\n borderMagenta: hexToRgbaString(theme.colors.SECONDARY_MAGENTA, 0.6),\n borderRed: hexToRgbaString(theme.colors.KOREAN_RED, 0.6),\n textPrimary: `#${theme.colors.TEXT_PRIMARY.toString(16).padStart(6, \"0\")}`,\n textSecondary: `#${theme.colors.TEXT_SECONDARY.toString(16).padStart(6, \"0\")}`,\n textTertiary: `#${theme.colors.TEXT_TERTIARY.toString(16).padStart(6, \"0\")}`,\n accentGold: `#${theme.colors.ACCENT_GOLD.toString(16).padStart(6, \"0\")}`,\n accentCyan: `#${theme.colors.PRIMARY_CYAN.toString(16).padStart(6, \"0\")}`,\n }),\n [theme],\n );\n\n useEffect(() => {\n const startMusic = async () => {\n await audio.fadeIn(\"underground_theme\", 2000);\n };\n void startMusic().catch((err) =>\n console.warn(\"Failed to start philosophy music:\", err),\n );\n\n return () => {\n void audio\n .fadeOut(2000)\n .then(() => audio.stopMusic())\n .catch((err) => console.warn(\"Failed to stop philosophy music:\", err));\n };\n }, [audio]);\n\n useEffect(() => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === \"Escape\" || event.key.toLowerCase() === \"m\") {\n event.preventDefault();\n audio.playSFX(\"menu_back\");\n onReturnToMenu();\n }\n };\n\n window.addEventListener(\"keydown\", handleKeyDown, { passive: false });\n return () => window.removeEventListener(\"keydown\", handleKeyDown);\n }, [onReturnToMenu, audio]);\n\n const handleBackClick = useCallback(() => {\n audio.playSFX(\"menu_back\");\n onReturnToMenu();\n }, [audio, onReturnToMenu]);\n\n const handleISMSClick = useCallback(() => {\n audio.playSFX(\"menu_select\");\n window.open(\"https://github.com/Hack23/ISMS-PUBLIC\", \"_blank\");\n }, [audio]);\n\n const martialValues = useMemo(\n () => Object.entries(KoreanCulture.MARTIAL_VALUES),\n [],\n );\n\n const trigramPhilosophies = useMemo(\n () =>\n Object.entries(TRIGRAM_DATA).map(([stance, data]) => ({\n stance: stance as TrigramStance,\n ...data,\n })),\n [],\n );\n\n const archetypes = useMemo(() => Object.entries(PLAYER_ARCHETYPES_DATA), []);\n\n const valuesPerRow = isMobile ? 3 : isTablet ? 4 : isLargeDesktop ? 8 : 6;\n const trigramsPerRow = isMobile ? 2 : isTablet ? 3 : isLargeDesktop ? 5 : 4;\n\n return (\n <div\n style={{\n width: screenWidth,\n height: screenHeight,\n position: \"relative\",\n overflow: \"hidden\",\n }}\n data-testid=\"philosophy-screen\"\n >\n {/* Volume Control - outside Canvas to maintain AudioProvider context */}\n <VolumeControl position=\"top-right\" compact={isMobile} />\n\n {/* Three.js Canvas for 3D background */}\n <Canvas\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n zIndex: Z_INDEX.ARENA,\n }}\n gl={{\n antialias: true,\n alpha: false,\n powerPreference: \"high-performance\",\n }}\n dpr={[1, 2]}\n camera={{ position: [0, 5, 10], fov: 75 }}\n onCreated={({ gl }) => {\n gl.setClearColor(theme.colors.UI_BACKGROUND_DARK, 1);\n }}\n >\n {/* 3D Background Scene */}\n <BackgroundScene3D theme=\"philosophy\" />\n </Canvas>\n\n {/* UI Overlay (positioned absolutely over Canvas) - matches CombatScreen pattern */}\n <div\n style={{\n position: \"absolute\",\n top: 0,\n left: 0,\n width: \"100%\",\n height: \"100%\",\n pointerEvents: \"none\",\n zIndex: Z_INDEX.HUD,\n }}\n data-testid=\"philosophy-hud-overlay\"\n >\n <div\n style={{\n width: \"100%\",\n height: \"100%\",\n display: \"flex\",\n flexDirection: \"column\",\n color: colors.textPrimary,\n fontFamily: theme.koreanTypography.fontFamily,\n lineHeight: theme.koreanTypography.lineHeight,\n pointerEvents: \"auto\",\n }}\n >\n {/* Header */}\n <div\n style={{\n height: `${layoutConstants.headerHeight}px`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n background: colors.headerBg,\n borderBottom: `3px solid ${colors.borderGold}`,\n padding: `${layoutConstants.padding}px`,\n position: \"relative\",\n }}\n data-testid=\"philosophy-header\"\n >\n <h1\n style={{\n fontSize: isMobile ? \"28px\" : \"36px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: 0,\n textShadow: `0 0 15px ${hexToRgbaString(\n theme.colors.ACCENT_GOLD,\n 0.6,\n )}`,\n }}\n >\n 흑괘 무도 철학\n </h1>\n <p\n style={{\n fontSize: isMobile ? \"14px\" : \"18px\",\n color: colors.textSecondary,\n margin: \"8px 0 0 0\",\n }}\n >\n Black Trigram Martial Philosophy\n </p>\n\n {/* Decorative line */}\n <div\n style={{\n width: \"80%\",\n height: \"2px\",\n background: `linear-gradient(90deg, transparent, ${colors.borderGold}, transparent)`,\n marginTop: \"10px\",\n }}\n />\n </div>\n\n {/* WebKit Scrollbar Styling - Using !important to override global hide */}\n <style dangerouslySetInnerHTML={scrollbarStyle} />\n\n {/* Content Area - Scrollable */}\n <div\n className=\"philosophy-scrollbar\"\n style={{\n flex: 1,\n overflowY: \"auto\",\n overflowX: \"hidden\",\n padding: `${layoutConstants.padding}px`,\n scrollbarWidth: \"thin\",\n scrollbarColor: `${colors.accentGold} ${colors.sectionBg}`,\n }}\n data-testid=\"philosophy-content\"\n >\n {/* Martial Values Section */}\n <div\n style={{\n marginBottom: `${layoutConstants.sectionSpacing}px`,\n background: colors.sectionBg,\n borderRadius: \"10px\",\n border: `2px solid ${colors.borderRed}`,\n padding: \"20px\",\n }}\n data-testid=\"martial-values\"\n >\n <h2\n style={{\n fontSize: isMobile ? \"18px\" : \"22px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: \"0 0 20px 0\",\n }}\n >\n 무도 가치관 (Martial Values)\n </h2>\n\n {/* Values Grid */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${valuesPerRow}, 1fr)`,\n gap: \"10px\",\n }}\n >\n {martialValues.map(([key, value]) => (\n <div\n key={key}\n style={{\n background: hexToRgbaString(\n theme.colors.UI_BACKGROUND_DARK,\n 0.7,\n ),\n borderRadius: \"6px\",\n border: `1px solid ${colors.borderGold}`,\n padding: \"12px\",\n textAlign: \"center\",\n }}\n data-testid={`martial-value-${key}`}\n >\n <div\n style={{\n fontSize: isMobile ? \"16px\" : \"18px\",\n fontWeight: \"bold\",\n color: colors.textPrimary,\n marginBottom: \"4px\",\n }}\n >\n {value.korean}\n </div>\n <div\n style={{\n fontSize: isMobile ? \"11px\" : \"13px\",\n color: colors.textSecondary,\n }}\n >\n {value.english}\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {/* Trigram Philosophy Section */}\n <div\n style={{\n marginBottom: `${layoutConstants.sectionSpacing}px`,\n background: colors.sectionBg,\n borderRadius: \"10px\",\n border: `2px solid ${colors.borderCyan}`,\n padding: \"20px\",\n }}\n data-testid=\"trigram-philosophy\"\n >\n <h2\n style={{\n fontSize: isMobile ? \"18px\" : \"22px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: \"0 0 20px 0\",\n }}\n >\n 팔괘 철학 (Eight Trigrams Philosophy)\n </h2>\n\n {/* Trigrams Grid */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${trigramsPerRow}, 1fr)`,\n gap: \"15px\",\n }}\n >\n {trigramPhilosophies.map((trigram) => (\n <div\n key={trigram.stance}\n style={{\n background: hexToRgbaString(trigram.theme.primary, 0.25),\n borderRadius: \"8px\",\n border: `2px solid #${trigram.theme.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n padding: \"15px\",\n }}\n data-testid={`trigram-${trigram.stance}`}\n >\n {/* Trigram Symbol */}\n <div\n style={{\n fontSize: isMobile ? \"32px\" : \"40px\",\n color: `#${trigram.theme.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n textAlign: \"center\",\n marginBottom: \"10px\",\n }}\n >\n {trigram.symbol}\n </div>\n\n {/* Name with Chinese character */}\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n fontWeight: \"bold\",\n color: colors.textPrimary,\n textAlign: \"center\",\n marginBottom: \"4px\",\n }}\n >\n {trigram.name.korean} ({trigram.name.english})\n </div>\n\n {/* Chinese character and attribute */}\n <div\n style={{\n fontSize: isMobile ? \"11px\" : \"13px\",\n color: colors.accentGold,\n textAlign: \"center\",\n marginBottom: \"8px\",\n fontWeight: \"bold\",\n }}\n >\n {trigram.chinese} - {trigram.attribute.chinese},{\" \"}\n {trigram.attribute.korean}\n </div>\n\n {/* Core meaning */}\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n color: colors.accentCyan,\n textAlign: \"center\",\n marginBottom: \"8px\",\n }}\n >\n {trigram.meaning.korean} | {trigram.meaning.english}\n </div>\n\n {/* Philosophy */}\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"11px\",\n color: colors.textSecondary,\n textAlign: \"center\",\n marginBottom: \"6px\",\n }}\n >\n {trigram.philosophy.korean}\n </div>\n\n {/* Combat description */}\n <div\n style={{\n fontSize: isMobile ? \"9px\" : \"10px\",\n color: colors.textTertiary,\n textAlign: \"center\",\n fontStyle: \"italic\",\n }}\n >\n {trigram.combat.english}\n </div>\n </div>\n ))}\n </div>\n </div>\n\n {/* Archetype Philosophy Section */}\n <div\n style={{\n marginBottom: `${layoutConstants.sectionSpacing}px`,\n background: colors.sectionBg,\n borderRadius: \"10px\",\n border: `2px solid ${colors.borderMagenta}`,\n padding: \"20px\",\n }}\n data-testid=\"archetype-philosophy\"\n >\n <h2\n style={{\n fontSize: isMobile ? \"18px\" : \"22px\",\n fontWeight: \"bold\",\n color: colors.accentGold,\n margin: \"0 0 20px 0\",\n }}\n >\n 무사 유형 철학 (Warrior Archetype Philosophy)\n </h2>\n\n {/* Archetypes List */}\n <div\n style={{\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"12px\",\n }}\n >\n {archetypes.map(([archetype, data]) => (\n <div\n key={archetype}\n style={{\n background: hexToRgbaString(data.colors.primary, 0.2),\n borderRadius: \"6px\",\n border: `1px solid #${data.colors.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n padding: \"15px\",\n }}\n data-testid={`archetype-${archetype}`}\n >\n {/* Name */}\n <div\n style={{\n fontSize: isMobile ? \"16px\" : \"18px\",\n fontWeight: \"bold\",\n color: `#${data.colors.primary\n .toString(16)\n .padStart(6, \"0\")}`,\n marginBottom: \"8px\",\n }}\n >\n {data.name.korean} ({data.name.english})\n </div>\n\n {/* Description */}\n <div\n style={{\n display: \"grid\",\n gridTemplateColumns: isMobile ? \"1fr\" : \"1fr 1fr\",\n gap: \"10px\",\n }}\n >\n <div\n style={{\n fontSize: isMobile ? \"11px\" : \"13px\",\n color: colors.textPrimary,\n }}\n >\n {data.description.korean}\n </div>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"12px\",\n color: colors.textSecondary,\n }}\n >\n {data.description.english}\n </div>\n </div>\n\n {/* Specialist tag */}\n <div\n style={{\n marginTop: \"8px\",\n fontSize: isMobile ? \"9px\" : \"11px\",\n color: colors.textTertiary,\n }}\n >\n 전통 무예 전문가\n </div>\n </div>\n ))}\n </div>\n </div>\n </div>\n\n {/* Footer */}\n <div\n style={{\n minHeight: `${layoutConstants.footerHeight}px`,\n background: colors.headerBg,\n borderTop: `3px solid ${colors.borderGold}`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: `${layoutConstants.padding}px`,\n gap: \"15px\",\n }}\n data-testid=\"philosophy-footer\"\n >\n {/* Motivation Quote */}\n <div\n style={{\n background: hexToRgbaString(theme.colors.ACCENT_GOLD, 0.15),\n borderRadius: \"8px\",\n border: `1px solid ${colors.borderGold}`,\n padding: \"15px\",\n textAlign: \"center\",\n maxWidth: \"90%\",\n }}\n >\n <div\n style={{\n fontSize: isMobile ? \"12px\" : \"14px\",\n color: colors.accentGold,\n fontStyle: \"italic\",\n marginBottom: \"4px\",\n }}\n >\n 무술은 단순한 격투가 아닌, 자신을 수양하고 상대를 존중하는\n 도(道)입니다\n </div>\n <div\n style={{\n fontSize: isMobile ? \"10px\" : \"12px\",\n color: colors.textSecondary,\n fontStyle: \"italic\",\n }}\n >\n Martial arts is not mere combat, but the Way (道) of\n self-cultivation and respect for others\n </div>\n </div>\n\n {/* ISMS Link */}\n <LinkButton\n onClick={handleISMSClick}\n korean=\"공개 보안 정책\"\n english=\"View Security Policies\"\n icon=\"🔐\"\n isMobile={isMobile}\n testId=\"isms-public-link\"\n />\n\n {/* Action Row */}\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n justifyContent: \"space-between\",\n width: \"100%\",\n gap: \"15px\",\n }}\n >\n {/* Back Button */}\n <BackButton\n onClick={handleBackClick}\n korean=\"돌아가기\"\n english=\"Return\"\n isMobile={isMobile}\n testId=\"philosophy-back-button\"\n />\n\n {/* Keyboard Hint */}\n <div\n style={{\n background: hexToRgbaString(\n theme.colors.UI_BACKGROUND_MEDIUM,\n 0.9,\n ),\n borderRadius: \"6px\",\n padding: \"8px 12px\",\n fontSize: isMobile ? \"11px\" : \"12px\",\n fontWeight: \"bold\",\n color: `#${theme.colors.SECONDARY_MAGENTA.toString(\n 16,\n ).padStart(6, \"0\")}`,\n border: `1px solid ${colors.borderGold}`,\n display: \"flex\",\n flexDirection: \"column\",\n alignItems: \"center\",\n gap: \"2px\",\n }}\n data-testid=\"keyboard-shortcuts\"\n >\n <span>ESC</span>\n <span>M</span>\n </div>\n </div>\n </div>\n </div>\n </div>\n </div>\n );\n};\n\nexport default PhilosophyScreen3D;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"TrainingScreen3D.d.ts","sourceRoot":"","sources":["../../../../src/components/screens/training/TrainingScreen3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAeH,OAAO,KAMN,MAAM,OAAO,CAAC;AAQf,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAc/C,OAAO,EAEL,eAAe,EAIhB,MAAM,gBAAgB,CAAC;AAoExB;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACjE,sCAAsC;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,eAAe,CAAC;CAC7C;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAuqC5D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
1
+ {"version":3,"file":"TrainingScreen3D.d.ts","sourceRoot":"","sources":["../../../../src/components/screens/training/TrainingScreen3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAeH,OAAO,KAMN,MAAM,OAAO,CAAC;AAQf,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAc/C,OAAO,EAEL,eAAe,EAIhB,MAAM,gBAAgB,CAAC;AAqExB;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,sCAAsC;IACtC,QAAQ,CAAC,cAAc,EAAE,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,CAAC,KAAK,IAAI,CAAC;IACjE,sCAAsC;IACtC,QAAQ,CAAC,cAAc,EAAE,MAAM,IAAI,CAAC;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,+CAA+C;IAC/C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,eAAe,CAAC;CAC7C;AAED;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,EAAE,KAAK,CAAC,EAAE,CAAC,qBAAqB,CAwpC5D,CAAC;AAEF,eAAe,gBAAgB,CAAC"}