blacktrigram 0.7.67 → 0.7.69

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 (219) hide show
  1. package/lib/App2.js.map +1 -1
  2. package/lib/assets/index.css +987 -987
  3. package/lib/audio/AudioAssetLoader.js.map +1 -1
  4. package/lib/audio/AudioAssetRegistry.js +2 -2
  5. package/lib/audio/AudioAssetRegistry.js.map +1 -1
  6. package/lib/audio/AudioCache.js.map +1 -1
  7. package/lib/audio/AudioManager.js +1 -1
  8. package/lib/audio/AudioManager.js.map +1 -1
  9. package/lib/audio/AudioMonitor.js.map +1 -1
  10. package/lib/audio/AudioPool.js.map +1 -1
  11. package/lib/audio/AudioProvider.js.map +1 -1
  12. package/lib/audio/AudioUtils.js.map +1 -1
  13. package/lib/audio/BoneImpactAudioMap.js.map +1 -1
  14. package/lib/components/screens/combat/CombatScreen3D.js +3 -3
  15. package/lib/components/screens/combat/CombatScreen3D.js.map +1 -1
  16. package/lib/components/screens/combat/components/controls/CombatControlsPanel.js.map +1 -1
  17. package/lib/components/screens/combat/components/controls/PauseMenu.js.map +1 -1
  18. package/lib/components/screens/combat/components/effects/BloodDecals3D.js.map +1 -1
  19. package/lib/components/screens/combat/components/effects/BloodParticles3D.js.map +1 -1
  20. package/lib/components/screens/combat/components/effects/BloodViscosity3D.js.map +1 -1
  21. package/lib/components/screens/combat/components/effects/CombatParticleEffects3D.js.map +1 -1
  22. package/lib/components/screens/combat/components/effects/InternalDamage3D.js.map +1 -1
  23. package/lib/components/screens/combat/components/effects/ParticleAudio3D.js.map +1 -1
  24. package/lib/components/screens/combat/components/hud/FPSMonitor.js.map +1 -1
  25. package/lib/components/screens/combat/components/indicators/BalanceIndicator.js.map +1 -1
  26. package/lib/components/screens/combat/hooks/useAICombat.js.map +1 -1
  27. package/lib/components/screens/combat/hooks/useCombatActions.js.map +1 -1
  28. package/lib/components/screens/combat/hooks/useCombatAttackMovement.js.map +1 -1
  29. package/lib/components/screens/controls/ControlsScreen3D.js.map +1 -1
  30. package/lib/components/screens/controls/components/ControlCategoryTabsOverlayHtml.js.map +1 -1
  31. package/lib/components/screens/endscreen/components/MatchStatisticsDisplayOverlayHtml.js.map +1 -1
  32. package/lib/components/screens/endscreen/components/PerformanceBreakdownOverlayHtml.js.map +1 -1
  33. package/lib/components/screens/endscreen/components/VictoryAnimation3D.js.map +1 -1
  34. package/lib/components/screens/intro/IntroScreen3D.js +1 -1
  35. package/lib/components/screens/intro/IntroScreen3D.js.map +1 -1
  36. package/lib/components/screens/intro/components/AbilityListOverlayHtml.js.map +1 -1
  37. package/lib/components/screens/intro/components/ArchetypeCardGridOverlayHtml.js.map +1 -1
  38. package/lib/components/screens/intro/components/ArchetypeDisplayOverlayHtml.js.map +1 -1
  39. package/lib/components/screens/intro/components/EnhancedArchetypeDisplayOverlayHtml.js.map +1 -1
  40. package/lib/components/screens/intro/components/MenuButtonsOverlayHtml.js.map +1 -1
  41. package/lib/components/screens/intro/components/MenuSectionOverlayHtml.js.map +1 -1
  42. package/lib/components/screens/intro/components/StatBarOverlayHtml.js.map +1 -1
  43. package/lib/components/screens/philosophy/PhilosophyScreen3D.js.map +1 -1
  44. package/lib/components/screens/training/TrainingScreen3D.js +1 -1
  45. package/lib/components/screens/training/TrainingScreen3D.js.map +1 -1
  46. package/lib/components/screens/training/components/AnatomyOverlay3D.js.map +1 -1
  47. package/lib/components/screens/training/components/FootworkDrillsOverlayHtml.js.map +1 -1
  48. package/lib/components/screens/training/components/HitFeedbackEffect3D.js.map +1 -1
  49. package/lib/components/screens/training/components/TrainingButtonsOverlayHtml.js.map +1 -1
  50. package/lib/components/screens/training/components/TrainingDummy3D.js.map +1 -1
  51. package/lib/components/screens/training/components/TrainingModeSelectorOverlayHtml.js.map +1 -1
  52. package/lib/components/screens/training/components/TrainingStatsOverlayHtml.js.map +1 -1
  53. package/lib/components/screens/training/components/VitalPointMarker3D.js.map +1 -1
  54. package/lib/components/screens/training/hooks/useAttackMovement.js.map +1 -1
  55. package/lib/components/screens/training/hooks/useTrainingActions.js.map +1 -1
  56. package/lib/components/shared/mobile/ActionButtons.js.map +1 -1
  57. package/lib/components/shared/mobile/GestureRecognizerPure.js.map +1 -1
  58. package/lib/components/shared/mobile/HapticController.js.map +1 -1
  59. package/lib/components/shared/mobile/StanceWheelPure.js.map +1 -1
  60. package/lib/components/shared/mobile/VirtualDPad.js.map +1 -1
  61. package/lib/components/shared/three/anatomy/BoneAttachedMuscles.js.map +1 -1
  62. package/lib/components/shared/three/anatomy/BoneClothing.js.map +1 -1
  63. package/lib/components/shared/three/anatomy/BoneRenderer.js.map +1 -1
  64. package/lib/components/shared/three/anatomy/Face3D.js.map +1 -1
  65. package/lib/components/shared/three/effects/ActionFeedback.js.map +1 -1
  66. package/lib/components/shared/three/effects/DamageNumbers.js.map +1 -1
  67. package/lib/components/shared/three/effects/HitEffects3D.js.map +1 -1
  68. package/lib/components/shared/three/effects/StanceTransitionEffect.js.map +1 -1
  69. package/lib/components/shared/three/effects/VitalPointMarkers3D.js.map +1 -1
  70. package/lib/components/shared/three/indicators/ElementalColorSystem.js.map +1 -1
  71. package/lib/components/shared/three/indicators/GuardIndicator.js.map +1 -1
  72. package/lib/components/shared/three/scene/CombatArena3D.js.map +1 -1
  73. package/lib/components/shared/three/ui/BodyPartHealthDisplay.js.map +1 -1
  74. package/lib/components/shared/three/ui/CombatReadinessBar.js.map +1 -1
  75. package/lib/components/shared/three/ui/HealthBar.js.map +1 -1
  76. package/lib/components/shared/three/ui/PlayerHUD.js.map +1 -1
  77. package/lib/components/shared/three/ui/SpeedIndicatorHUD.js.map +1 -1
  78. package/lib/components/shared/three/ui/StaminaBar.js.map +1 -1
  79. package/lib/components/shared/three/ui/TechniqueCard.js.map +1 -1
  80. package/lib/components/shared/three/ui/VitalPointOverlayControlsHtml.js.map +1 -1
  81. package/lib/components/shared/ui/SplashScreen.js +2 -2
  82. package/lib/components/shared/ui/VitalPointOverlayControlsPure.js.map +1 -1
  83. package/lib/components/ui/combat/BalanceIndicatorOverlayHtml.js.map +1 -1
  84. package/lib/data/techniques.js.map +1 -1
  85. package/lib/hooks/useCombatTimer.js.map +1 -1
  86. package/lib/hooks/useKeyboardControls.js.map +1 -1
  87. package/lib/hooks/useSkeletalAnimation.js +2 -2
  88. package/lib/hooks/useSkeletalAnimation.js.map +1 -1
  89. package/lib/hooks/useTechniqueSelection.js.map +1 -1
  90. package/lib/hooks/useWebGLContextLossHandler.js.map +1 -1
  91. package/lib/index.js +2 -2
  92. package/lib/systems/CombatSystem.js.map +1 -1
  93. package/lib/systems/EffectCalculator.js.map +1 -1
  94. package/lib/systems/ResponsiveScaling.js.map +1 -1
  95. package/lib/systems/TrigramSystem.js.map +1 -1
  96. package/lib/systems/ai/AIPersonality.js.map +1 -1
  97. package/lib/systems/ai/ArchetypeEnforcer.js.map +1 -1
  98. package/lib/systems/ai/DecisionTree.js.map +1 -1
  99. package/lib/systems/animation/builders/KeyframeConfig.js.map +1 -1
  100. package/lib/systems/animation/builders/KeyframeInterpolation.js.map +1 -1
  101. package/lib/systems/animation/builders/MartialArtsAnimationBuilder.js.map +1 -1
  102. package/lib/systems/animation/builders/SkeletonRig.js +1 -1
  103. package/lib/systems/animation/builders/SkeletonRig.js.map +1 -1
  104. package/lib/systems/animation/catalogs/AttackAnimations.js +1 -1
  105. package/lib/systems/animation/catalogs/AttackAnimations.js.map +1 -1
  106. package/lib/systems/animation/catalogs/BasicAnimations.js +1 -1
  107. package/lib/systems/animation/catalogs/BasicAnimations.js.map +1 -1
  108. package/lib/systems/animation/catalogs/ComboAnimations.js +1 -1
  109. package/lib/systems/animation/catalogs/ComboAnimations.js.map +1 -1
  110. package/lib/systems/animation/catalogs/DarkOpsAnimations.js +1 -1
  111. package/lib/systems/animation/catalogs/DarkOpsAnimations.js.map +1 -1
  112. package/lib/systems/animation/catalogs/DefensiveAnimations.js +2 -11
  113. package/lib/systems/animation/catalogs/DefensiveAnimations.js.map +1 -1
  114. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js +1 -1
  115. package/lib/systems/animation/catalogs/ElbowKneeAnimations.js.map +1 -1
  116. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js +1 -1
  117. package/lib/systems/animation/catalogs/FootworkSkeletalAnimations.js.map +1 -1
  118. package/lib/systems/animation/catalogs/GamRedirectionAnimations.js.map +1 -1
  119. package/lib/systems/animation/catalogs/GamStanceAnimations.js.map +1 -1
  120. package/lib/systems/animation/catalogs/GamTechniqueAnimations.js.map +1 -1
  121. package/lib/systems/animation/catalogs/GanStanceAnimations.js +1 -1
  122. package/lib/systems/animation/catalogs/GanStanceAnimations.js.map +1 -1
  123. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js +1 -1
  124. package/lib/systems/animation/catalogs/GanTechniqueAnimations.js.map +1 -1
  125. package/lib/systems/animation/catalogs/GeonStanceAnimations.js +1 -1
  126. package/lib/systems/animation/catalogs/GeonStanceAnimations.js.map +1 -1
  127. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js +1 -1
  128. package/lib/systems/animation/catalogs/GonTechniqueAnimations.js.map +1 -1
  129. package/lib/systems/animation/catalogs/GrapplingAnimations.js +1 -1
  130. package/lib/systems/animation/catalogs/GrapplingAnimations.js.map +1 -1
  131. package/lib/systems/animation/catalogs/JinStanceAnimations.js +1 -1
  132. package/lib/systems/animation/catalogs/JinStanceAnimations.js.map +1 -1
  133. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js +1 -1
  134. package/lib/systems/animation/catalogs/JinTechniqueAnimations.js.map +1 -1
  135. package/lib/systems/animation/catalogs/KickAnimations.js +1 -1
  136. package/lib/systems/animation/catalogs/KickAnimations.js.map +1 -1
  137. package/lib/systems/animation/catalogs/LiStanceAnimations.js +1 -1
  138. package/lib/systems/animation/catalogs/LiStanceAnimations.js.map +1 -1
  139. package/lib/systems/animation/catalogs/LiTechniqueAnimations.js.map +1 -1
  140. package/lib/systems/animation/catalogs/MovementAnimations.js +1 -1
  141. package/lib/systems/animation/catalogs/MovementAnimations.js.map +1 -1
  142. package/lib/systems/animation/catalogs/PunchAnimations.js +1 -1
  143. package/lib/systems/animation/catalogs/PunchAnimations.js.map +1 -1
  144. package/lib/systems/animation/catalogs/SonStanceAnimations.js +1 -1
  145. package/lib/systems/animation/catalogs/SonStanceAnimations.js.map +1 -1
  146. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js +1 -1
  147. package/lib/systems/animation/catalogs/SonTechniqueAnimations.js.map +1 -1
  148. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js +1 -1
  149. package/lib/systems/animation/catalogs/SpecializedPunchAnimations.js.map +1 -1
  150. package/lib/systems/animation/catalogs/StanceAnimations.js +1 -1
  151. package/lib/systems/animation/catalogs/StanceAnimations.js.map +1 -1
  152. package/lib/systems/animation/catalogs/StanceAttackAnimations.js +215 -272
  153. package/lib/systems/animation/catalogs/StanceAttackAnimations.js.map +1 -1
  154. package/lib/systems/animation/catalogs/StanceIdleAnimations.js +2 -11
  155. package/lib/systems/animation/catalogs/StanceIdleAnimations.js.map +1 -1
  156. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js +2 -2
  157. package/lib/systems/animation/catalogs/StanceLocomotionAnimations.js.map +1 -1
  158. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js +1 -1
  159. package/lib/systems/animation/catalogs/StepSkeletalAnimations.js.map +1 -1
  160. package/lib/systems/animation/catalogs/TaeJointLockAnimations.js.map +1 -1
  161. package/lib/systems/animation/catalogs/TaeStanceAnimations.js +1 -1
  162. package/lib/systems/animation/catalogs/TaeStanceAnimations.js.map +1 -1
  163. package/lib/systems/animation/core/AnimationOptimizations.js +1 -1
  164. package/lib/systems/animation/core/AnimationOptimizations.js.map +1 -1
  165. package/lib/systems/animation/core/AnimationPriority.js.map +1 -1
  166. package/lib/systems/animation/core/AnimationRegistry.js +11 -209
  167. package/lib/systems/animation/core/AnimationRegistry.js.map +1 -1
  168. package/lib/systems/animation/core/AnimationStateMachine.js +2 -2
  169. package/lib/systems/animation/core/AnimationStateMachine.js.map +1 -1
  170. package/lib/systems/animation/core/TechniqueAnimationMapper.js +1 -1
  171. package/lib/systems/animation/core/TechniqueAnimationMapper.js.map +1 -1
  172. package/lib/systems/animation/core/TechniqueAnimationMapping.js +1 -1
  173. package/lib/systems/animation/core/TechniqueAnimationMapping.js.map +1 -1
  174. package/lib/systems/animation/systems/MuscleActivation.js.map +1 -1
  175. package/lib/systems/bodypart/BodyPartDamageIntegration.js.map +1 -1
  176. package/lib/systems/bodypart/BodyPartHealthSystem.js.map +1 -1
  177. package/lib/systems/bodypart/BodyPartPositionMapping.js.map +1 -1
  178. package/lib/systems/bodypart/InjuryTracker.js.map +1 -1
  179. package/lib/systems/breathing/BreathingDisruptionSystem.js.map +1 -1
  180. package/lib/systems/combat/BalanceSystem.js.map +1 -1
  181. package/lib/systems/combat/BreakingStatusEffects.js.map +1 -1
  182. package/lib/systems/combat/CombatStateSystem.js.map +1 -1
  183. package/lib/systems/combat/GrappleSystem.js.map +1 -1
  184. package/lib/systems/combat/painConsciousnessUtils.js.map +1 -1
  185. package/lib/systems/combat/typeGuards.js.map +1 -1
  186. package/lib/systems/index.js +2 -2
  187. package/lib/systems/movement/integration.js.map +1 -1
  188. package/lib/systems/physics/AttackMovementPhysics.js.map +1 -1
  189. package/lib/systems/physics/CollisionDetection.js +1 -1
  190. package/lib/systems/physics/CollisionDetection.js.map +1 -1
  191. package/lib/systems/physics/KnockbackPhysics.js.map +1 -1
  192. package/lib/systems/physics/MovementPhysics.js.map +1 -1
  193. package/lib/systems/physics/PhysicalReachCalculator.js.map +1 -1
  194. package/lib/systems/physics/SpeedModifierSystem.js.map +1 -1
  195. package/lib/systems/trigram/KoreanTechniques.js.map +1 -1
  196. package/lib/systems/trigram/StanceManager.js.map +1 -1
  197. package/lib/systems/trigram/TransitionCalculator.js.map +1 -1
  198. package/lib/systems/trigram/TrigramCalculator.js.map +1 -1
  199. package/lib/systems/trigram/techniques/TechniqueConfig.js.map +1 -1
  200. package/lib/systems/trigram/techniques/index.js.map +1 -1
  201. package/lib/systems/trigram/types.js.map +1 -1
  202. package/lib/systems/vitalpoint/DamageCalculator.js.map +1 -1
  203. package/lib/systems/vitalpoint/KoreanAnatomy.js.map +1 -1
  204. package/lib/systems/vitalpoint/KoreanVitalPoints.js.map +1 -1
  205. package/lib/systems/vitalpoint/MeridianVitalPointMapping.js.map +1 -1
  206. package/lib/types/constants/designSystem.js.map +1 -1
  207. package/lib/utils/colorHelpers.js.map +1 -1
  208. package/lib/utils/colorUtils.js.map +1 -1
  209. package/lib/utils/controlMapping.js.map +1 -1
  210. package/lib/utils/deviceDetection.js.map +1 -1
  211. package/lib/utils/effectUtils.js.map +1 -1
  212. package/lib/utils/fabricTextures.js.map +1 -1
  213. package/lib/utils/htmlOverlayHelpers.js.map +1 -1
  214. package/lib/utils/performance/PerformanceMonitor.js.map +1 -1
  215. package/lib/utils/performance/PerformanceOverlay3D.js.map +1 -1
  216. package/lib/utils/safeAreaUtils.js.map +1 -1
  217. package/lib/utils/stanceHelpers.js.map +1 -1
  218. package/lib/utils/visualEffects.js.map +1 -1
  219. package/package.json +9 -9
@@ -1 +1 @@
1
- {"version":3,"file":"PerformanceOverlay3D.js","names":[],"sources":["../../../src/utils/performance/PerformanceOverlay3D.tsx"],"sourcesContent":["/**\n * PerformanceOverlay3D - Development-only performance stats overlay for Three.js\n *\n * Displays real-time FPS, memory, and draw call statistics\n * Only visible in development mode\n */\n\nimport { Html } from \"@react-three/drei\";\nimport React from \"react\";\nimport { usePerformanceMonitor } from \"./usePerformanceMonitor\";\n\nexport interface PerformanceOverlay3DProps {\n readonly visible?: boolean;\n}\n\n/**\n * 3D Performance overlay component for development\n * Shows FPS, memory, draw calls, and warnings\n * Uses screen-space positioning (bottom-left corner)\n */\nexport const PerformanceOverlay3D: React.FC<PerformanceOverlay3DProps> = ({\n visible = import.meta.env.DEV,\n}) => {\n const { metrics, isGood, warnings } = usePerformanceMonitor({\n enabled: visible,\n updateInterval: 500, // Update UI every 500ms\n });\n\n if (!visible) {\n return null;\n }\n\n const fpsColor = isGood\n ? \"#00ff88\"\n : metrics.avgFps < 30\n ? \"#ff4444\"\n : \"#ffaa00\";\n\n return (\n <Html fullscreen style={{ pointerEvents: \"none\" }}>\n <div\n style={{\n position: \"absolute\",\n bottom: \"20px\",\n left: \"20px\",\n backgroundColor: \"rgba(0, 0, 0, 0.85)\",\n border: \"2px solid #00ffff\",\n borderRadius: \"8px\",\n padding: \"12px 16px\",\n fontFamily: \"monospace\",\n fontSize: \"12px\",\n color: \"#00ffff\",\n minWidth: \"220px\",\n maxWidth: \"280px\",\n userSelect: \"none\",\n pointerEvents: \"none\",\n zIndex: 200,\n }}\n data-testid=\"performance-overlay\"\n >\n {/* Title */}\n <div\n style={{\n fontSize: \"14px\",\n fontWeight: \"bold\",\n marginBottom: \"8px\",\n borderBottom: \"1px solid #00ffff\",\n paddingBottom: \"4px\",\n }}\n >\n ⚡ Performance Monitor\n </div>\n\n {/* FPS Stats */}\n <div style={{ marginBottom: \"8px\" }}>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>FPS:</span>\n <span style={{ color: fpsColor, fontWeight: \"bold\" }}>\n {metrics.fps.toFixed(1)}\n </span>\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Avg FPS:</span>\n <span style={{ color: fpsColor }}>{metrics.avgFps.toFixed(1)}</span>\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Min/Max:</span>\n <span>\n {metrics.minFps.toFixed(1)} / {metrics.maxFps.toFixed(1)}\n </span>\n </div>\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <span>Frame Time:</span>\n <span>{metrics.frameTime.toFixed(2)}ms</span>\n </div>\n </div>\n\n {/* System Stats */}\n <div\n style={{\n marginBottom: \"8px\",\n borderTop: \"1px solid #444\",\n paddingTop: \"8px\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Memory:</span>\n <span\n style={{\n color:\n metrics.memoryMB > 300\n ? \"#ff4444\"\n : metrics.memoryMB > 250\n ? \"#ffaa00\"\n : \"#00ffff\",\n }}\n >\n {metrics.memoryMB > 0\n ? `${metrics.memoryMB.toFixed(1)}MB`\n : \"N/A\"}\n </span>\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Draw Calls:</span>\n <span\n style={{\n color:\n metrics.drawCalls > 150\n ? \"#ff4444\"\n : metrics.drawCalls > 100\n ? \"#ffaa00\"\n : \"#00ffff\",\n }}\n >\n {metrics.drawCalls}\n </span>\n </div>\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <span>Triangles:</span>\n <span>{(metrics.triangles / 1000).toFixed(1)}k</span>\n </div>\n </div>\n\n {/* Performance Status */}\n <div style={{ borderTop: \"1px solid #444\", paddingTop: \"8px\" }}>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n <span\n style={{\n width: \"12px\",\n height: \"12px\",\n borderRadius: \"50%\",\n backgroundColor: isGood ? \"#00ff88\" : \"#ff4444\",\n display: \"inline-block\",\n }}\n />\n <span style={{ fontWeight: \"bold\" }}>\n {isGood ? \"Performance Good\" : \"Performance Degraded\"}\n </span>\n </div>\n </div>\n\n {/* Warnings */}\n {warnings.length > 0 && (\n <div\n style={{\n marginTop: \"8px\",\n borderTop: \"1px solid #ff4444\",\n paddingTop: \"8px\",\n }}\n >\n <div\n style={{\n color: \"#ff4444\",\n fontWeight: \"bold\",\n marginBottom: \"4px\",\n }}\n >\n ⚠️ Warnings:\n </div>\n {warnings.map((warning, index) => (\n <div\n key={index}\n style={{\n fontSize: \"11px\",\n color: \"#ffaa00\",\n marginBottom: \"2px\",\n }}\n >\n {warning}\n </div>\n ))}\n </div>\n )}\n </div>\n </Html>\n );\n};\n\nexport default PerformanceOverlay3D;\n"],"mappings":"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"}
1
+ {"version":3,"file":"PerformanceOverlay3D.js","names":[],"sources":["../../../src/utils/performance/PerformanceOverlay3D.tsx"],"sourcesContent":["/**\n * PerformanceOverlay3D - Development-only performance stats overlay for Three.js\n *\n * Displays real-time FPS, memory, and draw call statistics\n * Only visible in development mode\n */\n\nimport { Html } from \"@react-three/drei\";\nimport React from \"react\";\nimport { usePerformanceMonitor } from \"./usePerformanceMonitor\";\n\nexport interface PerformanceOverlay3DProps {\n readonly visible?: boolean;\n}\n\n/**\n * 3D Performance overlay component for development\n * Shows FPS, memory, draw calls, and warnings\n * Uses screen-space positioning (bottom-left corner)\n */\nexport const PerformanceOverlay3D: React.FC<PerformanceOverlay3DProps> = ({\n visible = import.meta.env.DEV,\n}) => {\n const { metrics, isGood, warnings } = usePerformanceMonitor({\n enabled: visible,\n updateInterval: 500, // Update UI every 500ms\n });\n\n if (!visible) {\n return null;\n }\n\n const fpsColor = isGood\n ? \"#00ff88\"\n : metrics.avgFps < 30\n ? \"#ff4444\"\n : \"#ffaa00\";\n\n return (\n <Html fullscreen style={{ pointerEvents: \"none\" }}>\n <div\n style={{\n position: \"absolute\",\n bottom: \"20px\",\n left: \"20px\",\n backgroundColor: \"rgba(0, 0, 0, 0.85)\",\n border: \"2px solid #00ffff\",\n borderRadius: \"8px\",\n padding: \"12px 16px\",\n fontFamily: \"monospace\",\n fontSize: \"12px\",\n color: \"#00ffff\",\n minWidth: \"220px\",\n maxWidth: \"280px\",\n userSelect: \"none\",\n pointerEvents: \"none\",\n zIndex: 200,\n }}\n data-testid=\"performance-overlay\"\n >\n {/* Title */}\n <div\n style={{\n fontSize: \"14px\",\n fontWeight: \"bold\",\n marginBottom: \"8px\",\n borderBottom: \"1px solid #00ffff\",\n paddingBottom: \"4px\",\n }}\n >\n ⚡ Performance Monitor\n </div>\n\n {/* FPS Stats */}\n <div style={{ marginBottom: \"8px\" }}>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>FPS:</span>\n <span style={{ color: fpsColor, fontWeight: \"bold\" }}>\n {metrics.fps.toFixed(1)}\n </span>\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Avg FPS:</span>\n <span style={{ color: fpsColor }}>{metrics.avgFps.toFixed(1)}</span>\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Min/Max:</span>\n <span>\n {metrics.minFps.toFixed(1)} / {metrics.maxFps.toFixed(1)}\n </span>\n </div>\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <span>Frame Time:</span>\n <span>{metrics.frameTime.toFixed(2)}ms</span>\n </div>\n </div>\n\n {/* System Stats */}\n <div\n style={{\n marginBottom: \"8px\",\n borderTop: \"1px solid #444\",\n paddingTop: \"8px\",\n }}\n >\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Memory:</span>\n <span\n style={{\n color:\n metrics.memoryMB > 300\n ? \"#ff4444\"\n : metrics.memoryMB > 250\n ? \"#ffaa00\"\n : \"#00ffff\",\n }}\n >\n {metrics.memoryMB > 0\n ? `${metrics.memoryMB.toFixed(1)}MB`\n : \"N/A\"}\n </span>\n </div>\n <div\n style={{\n display: \"flex\",\n justifyContent: \"space-between\",\n marginBottom: \"2px\",\n }}\n >\n <span>Draw Calls:</span>\n <span\n style={{\n color:\n metrics.drawCalls > 150\n ? \"#ff4444\"\n : metrics.drawCalls > 100\n ? \"#ffaa00\"\n : \"#00ffff\",\n }}\n >\n {metrics.drawCalls}\n </span>\n </div>\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <span>Triangles:</span>\n <span>{(metrics.triangles / 1000).toFixed(1)}k</span>\n </div>\n </div>\n\n {/* Performance Status */}\n <div style={{ borderTop: \"1px solid #444\", paddingTop: \"8px\" }}>\n <div\n style={{\n display: \"flex\",\n alignItems: \"center\",\n gap: \"8px\",\n }}\n >\n <span\n style={{\n width: \"12px\",\n height: \"12px\",\n borderRadius: \"50%\",\n backgroundColor: isGood ? \"#00ff88\" : \"#ff4444\",\n display: \"inline-block\",\n }}\n />\n <span style={{ fontWeight: \"bold\" }}>\n {isGood ? \"Performance Good\" : \"Performance Degraded\"}\n </span>\n </div>\n </div>\n\n {/* Warnings */}\n {warnings.length > 0 && (\n <div\n style={{\n marginTop: \"8px\",\n borderTop: \"1px solid #ff4444\",\n paddingTop: \"8px\",\n }}\n >\n <div\n style={{\n color: \"#ff4444\",\n fontWeight: \"bold\",\n marginBottom: \"4px\",\n }}\n >\n ⚠️ Warnings:\n </div>\n {warnings.map((warning, index) => (\n <div\n key={index}\n style={{\n fontSize: \"11px\",\n color: \"#ffaa00\",\n marginBottom: \"2px\",\n }}\n >\n {warning}\n </div>\n ))}\n </div>\n )}\n </div>\n </Html>\n );\n};\n\nexport default PerformanceOverlay3D;\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"safeAreaUtils.js","names":[],"sources":["../../src/utils/safeAreaUtils.ts"],"sourcesContent":["/**\n * Safe area utilities for handling notched devices\n * \n * Provides CSS safe area inset helpers for iOS and Android devices\n * with notches, home indicators, and other screen intrusions.\n * \n * @module utils/safeAreaUtils\n * @category UI Utilities\n * @korean 안전영역유틸리티\n */\n\nimport { SAFE_AREA_INSETS } from \"../types/constants/ui\";\n\n/**\n * Safe area edge types\n * \n * @category Safe Area\n * @korean 안전영역가장자리타입\n */\nexport type SafeAreaEdge = \"top\" | \"bottom\" | \"left\" | \"right\";\n\n/**\n * Get CSS safe area inset with fallback\n * Returns CSS `env()` with fallback to constant values\n * \n * @param edge - Which edge to get inset for\n * @param fallback - Optional custom fallback value in pixels\n * @returns CSS string with env() and fallback\n * \n * @example\n * ```typescript\n * getSafeAreaInset('top'); // \"env(safe-area-inset-top, 44px)\"\n * getSafeAreaInset('bottom', 20); // \"env(safe-area-inset-bottom, 20px)\"\n * ```\n * \n * @korean 안전영역삽입얻기\n */\nexport function getSafeAreaInset(\n edge: SafeAreaEdge,\n fallback?: number\n): string {\n const defaultFallback =\n edge === \"top\"\n ? SAFE_AREA_INSETS.TOP\n : edge === \"bottom\"\n ? SAFE_AREA_INSETS.BOTTOM\n : edge === \"left\"\n ? SAFE_AREA_INSETS.LEFT\n : SAFE_AREA_INSETS.RIGHT;\n\n const fallbackValue = fallback ?? defaultFallback;\n return `env(safe-area-inset-${edge}, ${fallbackValue}px)`;\n}\n\n/**\n * Get safe area padding for a container\n * Returns CSS padding object with safe area support\n * \n * @param edges - Which edges to apply safe area padding\n * @param additionalPadding - Additional padding to add (in pixels)\n * @returns CSS padding object\n * \n * @example\n * ```typescript\n * getSafeAreaPadding(['top', 'bottom'], 16);\n * // {\n * // paddingTop: \"max(16px, env(safe-area-inset-top))\",\n * // paddingBottom: \"max(16px, env(safe-area-inset-bottom))\"\n * // }\n * ```\n * \n * @korean 안전영역패딩얻기\n */\nexport function getSafeAreaPadding(\n edges: readonly SafeAreaEdge[],\n additionalPadding = 0\n): Partial<Record<`padding${Capitalize<SafeAreaEdge>}`, string>> {\n const result: Partial<Record<`padding${Capitalize<SafeAreaEdge>}`, string>> =\n {};\n\n for (const edge of edges) {\n const capitalizedEdge =\n (edge.charAt(0).toUpperCase() + edge.slice(1)) as Capitalize<SafeAreaEdge>;\n const key = `padding${capitalizedEdge}` as const;\n\n result[key] = `max(${additionalPadding}px, ${getSafeAreaInset(edge)})`;\n }\n\n return result;\n}\n\n/**\n * Get safe area aware positioning styles\n * Useful for fixed/absolute positioned elements\n * \n * @param edge - Which edge to position from\n * @param baseOffset - Base offset in pixels\n * @returns CSS positioning string\n * \n * @example\n * ```typescript\n * getSafeAreaPosition('bottom', 20);\n * // \"calc(20px + env(safe-area-inset-bottom, 34px))\"\n * ```\n * \n * @korean 안전영역위치얻기\n */\nexport function getSafeAreaPosition(\n edge: SafeAreaEdge,\n baseOffset = 0\n): string {\n return `calc(${baseOffset}px + ${getSafeAreaInset(edge)})`;\n}\n\n/**\n * Get safe area aware height calculation\n * Useful for full-height containers\n * \n * @param excludeEdges - Which edges to exclude from height\n * @returns CSS calc() string for height\n * \n * @example\n * ```typescript\n * getSafeAreaHeight(['top', 'bottom']);\n * // \"calc(100vh - env(safe-area-inset-top, 44px) - env(safe-area-inset-bottom, 34px))\"\n * ```\n * \n * @korean 안전영역높이얻기\n */\nexport function getSafeAreaHeight(\n excludeEdges: readonly SafeAreaEdge[]\n): string {\n const insets = excludeEdges.map((edge) => getSafeAreaInset(edge)).join(\" - \");\n return `calc(100vh - ${insets})`;\n}\n\n/**\n * Check if device likely has safe area insets\n * Uses user agent detection (not perfect but useful)\n * \n * @returns Whether device likely has safe area insets\n * \n * @example\n * ```typescript\n * if (hasSafeAreaInsets()) {\n * // Apply safe area styles\n * }\n * ```\n * \n * @korean 안전영역삽입여부\n */\nexport function hasSafeAreaInsets(): boolean {\n // Check if CSS env() is supported\n if (typeof CSS !== \"undefined\" && CSS.supports) {\n return CSS.supports(\"padding-top\", \"env(safe-area-inset-top)\");\n }\n\n // Fallback: Check for iPhone X+ user agents\n const ua = navigator.userAgent;\n return (\n /iPhone/.test(ua) &&\n ((screen.width === 375 && screen.height === 812) || // iPhone X, XS, 11 Pro\n (screen.width === 414 && screen.height === 896) || // iPhone XR, XS Max, 11, 11 Pro Max\n (screen.width === 390 && screen.height === 844) || // iPhone 12, 12 Pro, 13, 13 Pro, 14\n (screen.width === 393 && screen.height === 852) || // iPhone 14 Pro\n (screen.width === 428 && screen.height === 926)) // iPhone 12/13/14 Pro Max\n );\n}\n\n/**\n * Get comprehensive safe area styles for a container\n * Combines padding and positioning for complete safe area support\n * \n * @param options - Configuration options\n * @returns React CSSProperties object\n * \n * @example\n * ```typescript\n * const styles = getSafeAreaStyles({\n * applyPadding: ['top', 'bottom'],\n * additionalPadding: 16,\n * position: 'fixed'\n * });\n * ```\n * \n * @korean 안전영역스타일얻기\n */\nexport function getSafeAreaStyles(options: {\n readonly applyPadding?: readonly SafeAreaEdge[];\n readonly additionalPadding?: number;\n readonly position?: \"fixed\" | \"absolute\" | \"sticky\";\n}): React.CSSProperties {\n const { applyPadding = [], additionalPadding = 0, position } = options;\n\n const paddingStyles = getSafeAreaPadding(applyPadding, additionalPadding);\n\n return {\n ...paddingStyles,\n ...(position && { position }),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,iBACd,MACA,UACQ;CACR,MAAM,kBACJ,SAAS,QACL,iBAAiB,MACjB,SAAS,WACT,iBAAiB,SACjB,SAAS,SACT,iBAAiB,OACjB,iBAAiB;CAGvB,OAAO,uBAAuB,KAAK,IADb,YAAY,gBACmB;AACvD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,mBACd,OACA,oBAAoB,GAC2C;CAC/D,MAAM,SACJ,CAAC;CAEH,KAAK,MAAM,QAAQ,OAAO;EAGxB,MAAM,MAAM,UADT,KAAK,OAAO,CAAC,EAAE,YAAY,IAAI,KAAK,MAAM,CAAC;EAG9C,OAAO,OAAO,OAAO,kBAAkB,MAAM,iBAAiB,IAAI,EAAE;CACtE;CAEA,OAAO;AACT"}
1
+ {"version":3,"file":"safeAreaUtils.js","names":[],"sources":["../../src/utils/safeAreaUtils.ts"],"sourcesContent":["/**\n * Safe area utilities for handling notched devices\n * \n * Provides CSS safe area inset helpers for iOS and Android devices\n * with notches, home indicators, and other screen intrusions.\n * \n * @module utils/safeAreaUtils\n * @category UI Utilities\n * @korean 안전영역유틸리티\n */\n\nimport { SAFE_AREA_INSETS } from \"../types/constants/ui\";\n\n/**\n * Safe area edge types\n * \n * @category Safe Area\n * @korean 안전영역가장자리타입\n */\nexport type SafeAreaEdge = \"top\" | \"bottom\" | \"left\" | \"right\";\n\n/**\n * Get CSS safe area inset with fallback\n * Returns CSS `env()` with fallback to constant values\n * \n * @param edge - Which edge to get inset for\n * @param fallback - Optional custom fallback value in pixels\n * @returns CSS string with env() and fallback\n * \n * @example\n * ```typescript\n * getSafeAreaInset('top'); // \"env(safe-area-inset-top, 44px)\"\n * getSafeAreaInset('bottom', 20); // \"env(safe-area-inset-bottom, 20px)\"\n * ```\n * \n * @korean 안전영역삽입얻기\n */\nexport function getSafeAreaInset(\n edge: SafeAreaEdge,\n fallback?: number\n): string {\n const defaultFallback =\n edge === \"top\"\n ? SAFE_AREA_INSETS.TOP\n : edge === \"bottom\"\n ? SAFE_AREA_INSETS.BOTTOM\n : edge === \"left\"\n ? SAFE_AREA_INSETS.LEFT\n : SAFE_AREA_INSETS.RIGHT;\n\n const fallbackValue = fallback ?? defaultFallback;\n return `env(safe-area-inset-${edge}, ${fallbackValue}px)`;\n}\n\n/**\n * Get safe area padding for a container\n * Returns CSS padding object with safe area support\n * \n * @param edges - Which edges to apply safe area padding\n * @param additionalPadding - Additional padding to add (in pixels)\n * @returns CSS padding object\n * \n * @example\n * ```typescript\n * getSafeAreaPadding(['top', 'bottom'], 16);\n * // {\n * // paddingTop: \"max(16px, env(safe-area-inset-top))\",\n * // paddingBottom: \"max(16px, env(safe-area-inset-bottom))\"\n * // }\n * ```\n * \n * @korean 안전영역패딩얻기\n */\nexport function getSafeAreaPadding(\n edges: readonly SafeAreaEdge[],\n additionalPadding = 0\n): Partial<Record<`padding${Capitalize<SafeAreaEdge>}`, string>> {\n const result: Partial<Record<`padding${Capitalize<SafeAreaEdge>}`, string>> =\n {};\n\n for (const edge of edges) {\n const capitalizedEdge =\n (edge.charAt(0).toUpperCase() + edge.slice(1)) as Capitalize<SafeAreaEdge>;\n const key = `padding${capitalizedEdge}` as const;\n\n result[key] = `max(${additionalPadding}px, ${getSafeAreaInset(edge)})`;\n }\n\n return result;\n}\n\n/**\n * Get safe area aware positioning styles\n * Useful for fixed/absolute positioned elements\n * \n * @param edge - Which edge to position from\n * @param baseOffset - Base offset in pixels\n * @returns CSS positioning string\n * \n * @example\n * ```typescript\n * getSafeAreaPosition('bottom', 20);\n * // \"calc(20px + env(safe-area-inset-bottom, 34px))\"\n * ```\n * \n * @korean 안전영역위치얻기\n */\nexport function getSafeAreaPosition(\n edge: SafeAreaEdge,\n baseOffset = 0\n): string {\n return `calc(${baseOffset}px + ${getSafeAreaInset(edge)})`;\n}\n\n/**\n * Get safe area aware height calculation\n * Useful for full-height containers\n * \n * @param excludeEdges - Which edges to exclude from height\n * @returns CSS calc() string for height\n * \n * @example\n * ```typescript\n * getSafeAreaHeight(['top', 'bottom']);\n * // \"calc(100vh - env(safe-area-inset-top, 44px) - env(safe-area-inset-bottom, 34px))\"\n * ```\n * \n * @korean 안전영역높이얻기\n */\nexport function getSafeAreaHeight(\n excludeEdges: readonly SafeAreaEdge[]\n): string {\n const insets = excludeEdges.map((edge) => getSafeAreaInset(edge)).join(\" - \");\n return `calc(100vh - ${insets})`;\n}\n\n/**\n * Check if device likely has safe area insets\n * Uses user agent detection (not perfect but useful)\n * \n * @returns Whether device likely has safe area insets\n * \n * @example\n * ```typescript\n * if (hasSafeAreaInsets()) {\n * // Apply safe area styles\n * }\n * ```\n * \n * @korean 안전영역삽입여부\n */\nexport function hasSafeAreaInsets(): boolean {\n // Check if CSS env() is supported\n if (typeof CSS !== \"undefined\" && CSS.supports) {\n return CSS.supports(\"padding-top\", \"env(safe-area-inset-top)\");\n }\n\n // Fallback: Check for iPhone X+ user agents\n const ua = navigator.userAgent;\n return (\n /iPhone/.test(ua) &&\n ((screen.width === 375 && screen.height === 812) || // iPhone X, XS, 11 Pro\n (screen.width === 414 && screen.height === 896) || // iPhone XR, XS Max, 11, 11 Pro Max\n (screen.width === 390 && screen.height === 844) || // iPhone 12, 12 Pro, 13, 13 Pro, 14\n (screen.width === 393 && screen.height === 852) || // iPhone 14 Pro\n (screen.width === 428 && screen.height === 926)) // iPhone 12/13/14 Pro Max\n );\n}\n\n/**\n * Get comprehensive safe area styles for a container\n * Combines padding and positioning for complete safe area support\n * \n * @param options - Configuration options\n * @returns React CSSProperties object\n * \n * @example\n * ```typescript\n * const styles = getSafeAreaStyles({\n * applyPadding: ['top', 'bottom'],\n * additionalPadding: 16,\n * position: 'fixed'\n * });\n * ```\n * \n * @korean 안전영역스타일얻기\n */\nexport function getSafeAreaStyles(options: {\n readonly applyPadding?: readonly SafeAreaEdge[];\n readonly additionalPadding?: number;\n readonly position?: \"fixed\" | \"absolute\" | \"sticky\";\n}): React.CSSProperties {\n const { applyPadding = [], additionalPadding = 0, position } = options;\n\n const paddingStyles = getSafeAreaPadding(applyPadding, additionalPadding);\n\n return {\n ...paddingStyles,\n ...(position && { position }),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqCA,SAAgB,iBACd,MACA,UACQ;CACR,MAAM,kBACJ,SAAS,QACL,iBAAiB,MACjB,SAAS,WACT,iBAAiB,SACjB,SAAS,SACT,iBAAiB,OACjB,iBAAiB;CAGvB,OAAO,uBAAuB,KAAK,IADb,YAAY,gBACmB;AACvD;;;;;;;;;;;;;;;;;;;;AAqBA,SAAgB,mBACd,OACA,oBAAoB,GAC2C;CAC/D,MAAM,SACJ,CAAC;CAEH,KAAK,MAAM,QAAQ,OAAO;EAGxB,MAAM,MAAM,UADT,KAAK,OAAO,CAAC,CAAC,CAAC,YAAY,IAAI,KAAK,MAAM,CAAC;EAG9C,OAAO,OAAO,OAAO,kBAAkB,MAAM,iBAAiB,IAAI,EAAE;CACtE;CAEA,OAAO;AACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"stanceHelpers.js","names":[],"sources":["../../src/utils/stanceHelpers.ts"],"sourcesContent":["/**\n * Shared utility functions for stance-related operations\n *\n * Provides common helpers for stance colors, names, and symbols\n * to avoid duplication across components.\n *\n * @module utils/stanceHelpers\n * @category Utilities\n * @korean 자세도우미\n */\n\nimport { TrigramStance } from \"../types/common\";\nimport { KOREAN_COLORS } from \"@/types/constants\";\n\n/**\n * Get color for each trigram stance\n * Maps 8 trigrams to Korean cyberpunk color palette\n *\n * @param stance - Current trigram stance\n * @returns Hex color number\n * @korean 자세색상가져오기\n */\nexport const getStanceColor = (stance: TrigramStance): number => {\n const stanceColors = {\n [TrigramStance.GEON]: KOREAN_COLORS.TRIGRAM_GEON_PRIMARY, // Heaven - Gold\n [TrigramStance.TAE]: KOREAN_COLORS.TRIGRAM_TAE_PRIMARY, // Lake - Sky Blue\n [TrigramStance.LI]: KOREAN_COLORS.TRIGRAM_LI_PRIMARY, // Fire - Orange Red\n [TrigramStance.JIN]: KOREAN_COLORS.TRIGRAM_JIN_PRIMARY, // Thunder - Purple\n [TrigramStance.SON]: KOREAN_COLORS.TRIGRAM_SON_PRIMARY, // Wind - Light Green\n [TrigramStance.GAM]: KOREAN_COLORS.TRIGRAM_GAM_PRIMARY, // Water - Blue\n [TrigramStance.GAN]: KOREAN_COLORS.TRIGRAM_GAN_PRIMARY, // Mountain - Brown\n [TrigramStance.GON]: KOREAN_COLORS.TRIGRAM_GON_PRIMARY, // Earth - Dark Khaki\n };\n return stanceColors[stance] ?? KOREAN_COLORS.PRIMARY_CYAN;\n};\n\n/**\n * Get stance display names (Korean + English)\n *\n * @param stance - Current trigram stance\n * @returns Object with korean, english, and romanized names\n * @korean 자세이름가져오기\n */\nexport const getStanceNames = (stance: TrigramStance) => {\n const names = {\n [TrigramStance.GEON]: {\n korean: \"건\",\n english: \"Heaven\",\n romanized: \"Geon\",\n },\n [TrigramStance.TAE]: { korean: \"태\", english: \"Lake\", romanized: \"Tae\" },\n [TrigramStance.LI]: { korean: \"리\", english: \"Fire\", romanized: \"Li\" },\n [TrigramStance.JIN]: { korean: \"진\", english: \"Thunder\", romanized: \"Jin\" },\n [TrigramStance.SON]: { korean: \"손\", english: \"Wind\", romanized: \"Son\" },\n [TrigramStance.GAM]: { korean: \"감\", english: \"Water\", romanized: \"Gam\" },\n [TrigramStance.GAN]: {\n korean: \"간\",\n english: \"Mountain\",\n romanized: \"Gan\",\n },\n [TrigramStance.GON]: { korean: \"곤\", english: \"Earth\", romanized: \"Gon\" },\n };\n return (\n names[stance] ?? { korean: \"건\", english: \"Heaven\", romanized: \"Geon\" }\n );\n};\n\n/**\n * Get trigram Unicode symbol for each stance\n *\n * @param stance - Current trigram stance\n * @returns Unicode trigram symbol\n * @korean 팔괘기호가져오기\n */\nexport const getTrigramSymbol = (stance: TrigramStance): string => {\n const symbols = {\n [TrigramStance.GEON]: \"☰\", // Heaven\n [TrigramStance.TAE]: \"☱\", // Lake\n [TrigramStance.LI]: \"☲\", // Fire\n [TrigramStance.JIN]: \"☳\", // Thunder\n [TrigramStance.SON]: \"☴\", // Wind\n [TrigramStance.GAM]: \"☵\", // Water\n [TrigramStance.GAN]: \"☶\", // Mountain\n [TrigramStance.GON]: \"☷\", // Earth\n };\n return symbols[stance] ?? \"☰\";\n};\n\n/**\n * Get Korean name for each stance\n *\n * @param stance - Current trigram stance\n * @returns Korean name (Hangul)\n * @korean 자세한글이름가져오기\n */\nexport const getStanceKoreanName = (stance: TrigramStance): string => {\n return getStanceNames(stance).korean;\n};\n\n/**\n * Get color as hex string for CSS usage\n *\n * @param stance - Current trigram stance\n * @returns Hex color string (e.g., \"#FFD700\")\n * @korean 자세CSS색상가져오기\n */\nexport const getStanceColorHex = (stance: TrigramStance): string => {\n const color = getStanceColor(stance);\n return `#${color.toString(16).padStart(6, \"0\").toLowerCase()}`;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,kBAAkB,WAAkC;CAW/D,OAAO;GATJ,cAAc,OAAO,cAAc;GACnC,cAAc,MAAM,cAAc;GAClC,cAAc,KAAK,cAAc;GACjC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;CAE9B,EAAa,WAAW,cAAc;AAC/C;;;;;;;;AASA,IAAa,kBAAkB,WAA0B;CAmBvD,OACE;GAlBC,cAAc,OAAO;GACpB,QAAQ;GACR,SAAS;GACT,WAAW;EACb;GACC,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAQ,WAAW;EAAM;GACrE,cAAc,KAAK;GAAE,QAAQ;GAAK,SAAS;GAAQ,WAAW;EAAK;GACnE,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAW,WAAW;EAAM;GACxE,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAQ,WAAW;EAAM;GACrE,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAS,WAAW;EAAM;GACtE,cAAc,MAAM;GACnB,QAAQ;GACR,SAAS;GACT,WAAW;EACb;GACC,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAS,WAAW;EAAM;CAGvE,EAAM,WAAW;EAAE,QAAQ;EAAK,SAAS;EAAU,WAAW;CAAO;AAEzE;;;;;;;;AASA,IAAa,oBAAoB,WAAkC;CAWjE,OAAO;GATJ,cAAc,OAAO;GACrB,cAAc,MAAM;GACpB,cAAc,KAAK;GACnB,cAAc,MAAM;GACpB,cAAc,MAAM;GACpB,cAAc,MAAM;GACpB,cAAc,MAAM;GACpB,cAAc,MAAM;CAEhB,EAAQ,WAAW;AAC5B;;;;;;;;AASA,IAAa,uBAAuB,WAAkC;CACpE,OAAO,eAAe,MAAM,EAAE;AAChC;;;;;;;;AASA,IAAa,qBAAqB,WAAkC;CAElE,OAAO,IADO,eAAe,MAClB,EAAM,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,EAAE,YAAY;AAC7D"}
1
+ {"version":3,"file":"stanceHelpers.js","names":[],"sources":["../../src/utils/stanceHelpers.ts"],"sourcesContent":["/**\n * Shared utility functions for stance-related operations\n *\n * Provides common helpers for stance colors, names, and symbols\n * to avoid duplication across components.\n *\n * @module utils/stanceHelpers\n * @category Utilities\n * @korean 자세도우미\n */\n\nimport { TrigramStance } from \"../types/common\";\nimport { KOREAN_COLORS } from \"@/types/constants\";\n\n/**\n * Get color for each trigram stance\n * Maps 8 trigrams to Korean cyberpunk color palette\n *\n * @param stance - Current trigram stance\n * @returns Hex color number\n * @korean 자세색상가져오기\n */\nexport const getStanceColor = (stance: TrigramStance): number => {\n const stanceColors = {\n [TrigramStance.GEON]: KOREAN_COLORS.TRIGRAM_GEON_PRIMARY, // Heaven - Gold\n [TrigramStance.TAE]: KOREAN_COLORS.TRIGRAM_TAE_PRIMARY, // Lake - Sky Blue\n [TrigramStance.LI]: KOREAN_COLORS.TRIGRAM_LI_PRIMARY, // Fire - Orange Red\n [TrigramStance.JIN]: KOREAN_COLORS.TRIGRAM_JIN_PRIMARY, // Thunder - Purple\n [TrigramStance.SON]: KOREAN_COLORS.TRIGRAM_SON_PRIMARY, // Wind - Light Green\n [TrigramStance.GAM]: KOREAN_COLORS.TRIGRAM_GAM_PRIMARY, // Water - Blue\n [TrigramStance.GAN]: KOREAN_COLORS.TRIGRAM_GAN_PRIMARY, // Mountain - Brown\n [TrigramStance.GON]: KOREAN_COLORS.TRIGRAM_GON_PRIMARY, // Earth - Dark Khaki\n };\n return stanceColors[stance] ?? KOREAN_COLORS.PRIMARY_CYAN;\n};\n\n/**\n * Get stance display names (Korean + English)\n *\n * @param stance - Current trigram stance\n * @returns Object with korean, english, and romanized names\n * @korean 자세이름가져오기\n */\nexport const getStanceNames = (stance: TrigramStance) => {\n const names = {\n [TrigramStance.GEON]: {\n korean: \"건\",\n english: \"Heaven\",\n romanized: \"Geon\",\n },\n [TrigramStance.TAE]: { korean: \"태\", english: \"Lake\", romanized: \"Tae\" },\n [TrigramStance.LI]: { korean: \"리\", english: \"Fire\", romanized: \"Li\" },\n [TrigramStance.JIN]: { korean: \"진\", english: \"Thunder\", romanized: \"Jin\" },\n [TrigramStance.SON]: { korean: \"손\", english: \"Wind\", romanized: \"Son\" },\n [TrigramStance.GAM]: { korean: \"감\", english: \"Water\", romanized: \"Gam\" },\n [TrigramStance.GAN]: {\n korean: \"간\",\n english: \"Mountain\",\n romanized: \"Gan\",\n },\n [TrigramStance.GON]: { korean: \"곤\", english: \"Earth\", romanized: \"Gon\" },\n };\n return (\n names[stance] ?? { korean: \"건\", english: \"Heaven\", romanized: \"Geon\" }\n );\n};\n\n/**\n * Get trigram Unicode symbol for each stance\n *\n * @param stance - Current trigram stance\n * @returns Unicode trigram symbol\n * @korean 팔괘기호가져오기\n */\nexport const getTrigramSymbol = (stance: TrigramStance): string => {\n const symbols = {\n [TrigramStance.GEON]: \"☰\", // Heaven\n [TrigramStance.TAE]: \"☱\", // Lake\n [TrigramStance.LI]: \"☲\", // Fire\n [TrigramStance.JIN]: \"☳\", // Thunder\n [TrigramStance.SON]: \"☴\", // Wind\n [TrigramStance.GAM]: \"☵\", // Water\n [TrigramStance.GAN]: \"☶\", // Mountain\n [TrigramStance.GON]: \"☷\", // Earth\n };\n return symbols[stance] ?? \"☰\";\n};\n\n/**\n * Get Korean name for each stance\n *\n * @param stance - Current trigram stance\n * @returns Korean name (Hangul)\n * @korean 자세한글이름가져오기\n */\nexport const getStanceKoreanName = (stance: TrigramStance): string => {\n return getStanceNames(stance).korean;\n};\n\n/**\n * Get color as hex string for CSS usage\n *\n * @param stance - Current trigram stance\n * @returns Hex color string (e.g., \"#FFD700\")\n * @korean 자세CSS색상가져오기\n */\nexport const getStanceColorHex = (stance: TrigramStance): string => {\n const color = getStanceColor(stance);\n return `#${color.toString(16).padStart(6, \"0\").toLowerCase()}`;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAsBA,IAAa,kBAAkB,WAAkC;CAW/D,OAAO;GATJ,cAAc,OAAO,cAAc;GACnC,cAAc,MAAM,cAAc;GAClC,cAAc,KAAK,cAAc;GACjC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;GAClC,cAAc,MAAM,cAAc;CAE9B,EAAa,WAAW,cAAc;AAC/C;;;;;;;;AASA,IAAa,kBAAkB,WAA0B;CAmBvD,OACE;GAlBC,cAAc,OAAO;GACpB,QAAQ;GACR,SAAS;GACT,WAAW;EACb;GACC,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAQ,WAAW;EAAM;GACrE,cAAc,KAAK;GAAE,QAAQ;GAAK,SAAS;GAAQ,WAAW;EAAK;GACnE,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAW,WAAW;EAAM;GACxE,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAQ,WAAW;EAAM;GACrE,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAS,WAAW;EAAM;GACtE,cAAc,MAAM;GACnB,QAAQ;GACR,SAAS;GACT,WAAW;EACb;GACC,cAAc,MAAM;GAAE,QAAQ;GAAK,SAAS;GAAS,WAAW;EAAM;CAGvE,EAAM,WAAW;EAAE,QAAQ;EAAK,SAAS;EAAU,WAAW;CAAO;AAEzE;;;;;;;;AASA,IAAa,oBAAoB,WAAkC;CAWjE,OAAO;GATJ,cAAc,OAAO;GACrB,cAAc,MAAM;GACpB,cAAc,KAAK;GACnB,cAAc,MAAM;GACpB,cAAc,MAAM;GACpB,cAAc,MAAM;GACpB,cAAc,MAAM;GACpB,cAAc,MAAM;CAEhB,EAAQ,WAAW;AAC5B;;;;;;;;AASA,IAAa,uBAAuB,WAAkC;CACpE,OAAO,eAAe,MAAM,CAAC,CAAC;AAChC;;;;;;;;AASA,IAAa,qBAAqB,WAAkC;CAElE,OAAO,IADO,eAAe,MAClB,CAAA,CAAM,SAAS,EAAE,CAAC,CAAC,SAAS,GAAG,GAAG,CAAC,CAAC,YAAY;AAC7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"visualEffects.js","names":[],"sources":["../../src/utils/visualEffects.ts"],"sourcesContent":["/**\n * Visual Effects Utilities for Korean Cyberpunk Aesthetic\n *\n * Provides advanced visual effects for HTML overlay components including:\n * - Neon glow effects (box-shadow, text-shadow)\n * - Depth effects (layered shadows, gradients, backdrop-blur)\n * - Smooth transitions and animations\n * - Korean font rendering optimization\n * - Hover and focus state generators\n *\n * All effects follow Korean martial arts cyberpunk theme with 60fps performance target.\n *\n * @module utils/visualEffects\n * @category UI Utilities\n * @korean 시각효과유틸리티\n */\n\nimport { KOREAN_COLORS } from \"@/types/constants\";\nimport { hexToRgbaString } from \"./colorUtils\";\n\n/**\n * Neon glow intensity levels\n * @korean 네온글로우강도\n */\nexport type GlowIntensity = \"subtle\" | \"medium\" | \"strong\" | \"intense\";\n\n/**\n * Hover state animation types\n * @korean 호버상태애니메이션\n */\nexport type HoverAnimationType =\n | \"glow\"\n | \"scale\"\n | \"lift\"\n | \"pulse\"\n | \"combined\";\n\n/**\n * Transition timing presets\n * @korean 전환타이밍프리셋\n */\nexport type TransitionTiming = \"fast\" | \"normal\" | \"slow\" | \"smooth\";\n\n/**\n * Depth effect layer configuration\n * @korean 깊이효과레이어설정\n */\nexport interface DepthEffectConfig {\n readonly layers: number;\n readonly baseOffset: number;\n readonly baseBlur: number;\n readonly color: number;\n readonly opacity: number;\n}\n\n/**\n * Get neon glow effect CSS string\n *\n * Creates cyberpunk-style neon glow using box-shadow with Korean colors.\n * Supports multiple intensity levels for different UI elements.\n *\n * @param color - Hex color value from KOREAN_COLORS\n * @param intensity - Glow intensity level\n * @param includeInset - Whether to include inset glow (default: true)\n * @returns CSS box-shadow string with neon glow effect\n *\n * @example\n * ```typescript\n * const glow = getNeonGlowEffect(KOREAN_COLORS.PRIMARY_CYAN, 'medium', true);\n * // Returns: \"0 0 20px rgba(0,230,230,0.6), inset 0 0 10px rgba(0,230,230,0.3)\"\n * // Note: Color conversion is handled by hexToRgbaString utility\n * ```\n *\n * @korean 네온글로우효과얻기\n */\nexport function getNeonGlowEffect(\n color: number,\n intensity: GlowIntensity = \"medium\",\n includeInset: boolean = true,\n): string {\n const glowConfig = {\n subtle: { outer: 10, outerOpacity: 0.4, inner: 5, innerOpacity: 0.2 },\n medium: { outer: 20, outerOpacity: 0.6, inner: 10, innerOpacity: 0.3 },\n strong: { outer: 30, outerOpacity: 0.8, inner: 15, innerOpacity: 0.4 },\n intense: { outer: 40, outerOpacity: 1.0, inner: 20, innerOpacity: 0.5 },\n };\n\n const config = glowConfig[intensity];\n const outerGlow = `0 0 ${config.outer}px ${hexToRgbaString(color, config.outerOpacity)}`;\n const insetGlow = includeInset\n ? `, inset 0 0 ${config.inner}px ${hexToRgbaString(color, config.innerOpacity)}`\n : \"\";\n\n return `${outerGlow}${insetGlow}`;\n}\n\n/**\n * Get neon text shadow effect\n *\n * Creates glowing text effect for Korean and English text using text-shadow.\n * Multiple shadow layers create authentic neon glow appearance.\n *\n * @param color - Hex color value from KOREAN_COLORS\n * @param intensity - Glow intensity level\n * @returns CSS text-shadow string with neon glow\n *\n * @example\n * ```typescript\n * const textGlow = getNeonTextShadow(KOREAN_COLORS.ACCENT_GOLD, 'strong');\n * // Returns: \"0 0 10px rgba(255,196,0,0.8), 0 0 20px rgba(255,196,0,0.6), 0 0 30px rgba(255,196,0,0.4)\"\n * ```\n *\n * @korean 네온텍스트그림자얻기\n */\nexport function getNeonTextShadow(\n color: number,\n intensity: GlowIntensity = \"medium\",\n): string {\n const shadowConfig = {\n subtle: [\n { blur: 5, opacity: 0.6 },\n { blur: 10, opacity: 0.4 },\n ],\n medium: [\n { blur: 10, opacity: 0.8 },\n { blur: 20, opacity: 0.6 },\n { blur: 30, opacity: 0.4 },\n ],\n strong: [\n { blur: 15, opacity: 1.0 },\n { blur: 30, opacity: 0.8 },\n { blur: 45, opacity: 0.6 },\n ],\n intense: [\n { blur: 20, opacity: 1.0 },\n { blur: 40, opacity: 0.9 },\n { blur: 60, opacity: 0.7 },\n { blur: 80, opacity: 0.5 },\n ],\n };\n\n const shadows = shadowConfig[intensity];\n return shadows\n .map(\n ({ blur, opacity }) => `0 0 ${blur}px ${hexToRgbaString(color, opacity)}`,\n )\n .join(\", \");\n}\n\n/**\n * Get layered depth effect\n *\n * Creates depth using multiple shadow layers with increasing offset and blur.\n * Provides 3D-like appearance for Korean-themed UI panels.\n *\n * @param config - Depth effect configuration\n * @returns CSS box-shadow string with layered depth\n *\n * @example\n * ```typescript\n * const depth = getLayeredDepthEffect({\n * layers: 3,\n * baseOffset: 2,\n * baseBlur: 4,\n * color: KOREAN_COLORS.BLACK_SOLID,\n * opacity: 0.5,\n * });\n * ```\n *\n * @korean 레이어깊이효과얻기\n */\nexport function getLayeredDepthEffect(config: DepthEffectConfig): string {\n const { layers, baseOffset, baseBlur, color, opacity } = config;\n const shadows: string[] = [];\n\n for (let i = 1; i <= layers; i++) {\n const offset = baseOffset * i;\n const blur = baseBlur * i;\n const layerOpacity = opacity * (1 - ((i - 1) / layers) * 0.3); // Fade each layer\n shadows.push(\n `0 ${offset}px ${blur}px ${hexToRgbaString(color, layerOpacity)}`,\n );\n }\n\n return shadows.join(\", \");\n}\n\n/**\n * Get cyberpunk gradient background\n *\n * Creates Korean-themed gradient with cyberpunk colors.\n * Supports both linear and radial gradients.\n *\n * @param primaryColor - Primary hex color\n * @param secondaryColor - Secondary hex color\n * @param angle - Gradient angle in degrees (default: 135)\n * @param type - Gradient type ('linear' | 'radial')\n * @returns CSS gradient string\n *\n * @example\n * ```typescript\n * const gradient = getCyberpunkGradient(\n * KOREAN_COLORS.PRIMARY_CYAN,\n * KOREAN_COLORS.UI_BACKGROUND_DARK,\n * 135,\n * 'linear'\n * );\n * ```\n *\n * @korean 사이버펑크그라디언트얻기\n */\nexport function getCyberpunkGradient(\n primaryColor: number,\n secondaryColor: number,\n angle: number = 135,\n type: \"linear\" | \"radial\" = \"linear\",\n): string {\n const color1 = hexToRgbaString(primaryColor, 0.2);\n const color2 = hexToRgbaString(secondaryColor, 0.9);\n\n if (type === \"radial\") {\n return `radial-gradient(circle at top left, ${color1} 0%, ${color2} 100%)`;\n }\n\n return `linear-gradient(${angle}deg, ${color1} 0%, ${color2} 100%)`;\n}\n\n/**\n * Get smooth transition CSS\n *\n * Returns standardized transition string for consistent animations.\n * All transitions target 60fps performance.\n *\n * @param properties - CSS properties to transition (default: 'all')\n * @param timing - Timing preset\n * @returns CSS transition string\n *\n * @example\n * ```typescript\n * const transition = getSmoothTransition('all', 'normal');\n * // Returns: \"all 0.2s ease-in-out\"\n * ```\n *\n * @korean 부드러운전환얻기\n */\nexport function getSmoothTransition(\n properties: string = \"all\",\n timing: TransitionTiming = \"normal\",\n): string {\n const timingConfig = {\n fast: { duration: \"0.15s\", easing: \"ease-out\" },\n normal: { duration: \"0.2s\", easing: \"ease-in-out\" },\n slow: { duration: \"0.3s\", easing: \"ease-in-out\" },\n smooth: { duration: \"0.25s\", easing: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n };\n\n const config = timingConfig[timing];\n return `${properties} ${config.duration} ${config.easing}`;\n}\n\n/**\n * Get Korean font optimization styles\n *\n * Applies optimal font rendering for Korean characters (Hangul).\n * Includes anti-aliasing, subpixel rendering, and letter spacing.\n *\n * @param fontSize - Font size in pixels\n * @param fontWeight - Font weight (default: 'normal')\n * @returns React.CSSProperties with Korean font optimization\n *\n * @example\n * ```typescript\n * const fontStyle = getKoreanFontOptimization(16, 'bold');\n * // Returns: { fontSize: '16px', WebkitFontSmoothing: 'antialiased', ... }\n * ```\n *\n * @korean 한글폰트최적화얻기\n */\nexport function getKoreanFontOptimization(\n fontSize: number,\n fontWeight: \"normal\" | \"bold\" = \"normal\",\n): React.CSSProperties & {\n WebkitFontSmoothing?: string;\n MozOsxFontSmoothing?: string;\n} {\n return {\n fontSize: `${fontSize}px`,\n fontWeight,\n WebkitFontSmoothing: \"antialiased\",\n MozOsxFontSmoothing: \"grayscale\",\n textRendering: \"optimizeLegibility\",\n letterSpacing: \"0.02em\",\n // Korean characters need slightly more line height\n lineHeight: 1.5,\n };\n}\n\n/**\n * Map numeric glow intensity to GlowIntensity type\n *\n * Helper to standardize glow intensity mapping across components.\n * Converts numeric intensity values to discrete levels.\n *\n * @param glowIntensity - Numeric glow intensity (0-2+ scale)\n * @returns GlowIntensity level (\"subtle\", \"medium\", \"strong\", \"intense\")\n *\n * Mapping thresholds:\n * - intense: >= 1.5\n * - strong: >= 1.0\n * - medium: >= 0.6\n * - subtle: < 0.6\n *\n * @example\n * ```typescript\n * const level = mapGlowIntensityLevel(0.8);\n * // Returns: \"medium\"\n * mapGlowIntensityLevel(2.0);\n * // Returns: \"intense\"\n * ```\n *\n * @korean 광도레벨매핑\n */\nexport function mapGlowIntensityLevel(glowIntensity: number): GlowIntensity {\n if (glowIntensity >= 1.5) return \"intense\";\n if (glowIntensity >= 1.0) return \"strong\";\n if (glowIntensity >= 0.6) return \"medium\";\n return \"subtle\";\n}\n\n/**\n * Get hover state styles with glow effect\n *\n * Generates hover state styles with Korean cyberpunk animations.\n * Includes glow intensification, scale, and lift effects.\n *\n * @param baseColor - Base hex color\n * @param animation - Animation type\n * @param intensity - Glow intensity for hover state\n * @returns React.CSSProperties for hover state\n *\n * @example\n * ```typescript\n * const hoverStyle = getHoverStateStyles(\n * KOREAN_COLORS.PRIMARY_CYAN,\n * 'combined',\n * 'strong'\n * );\n * ```\n *\n * @korean 호버상태스타일얻기\n */\nexport function getHoverStateStyles(\n baseColor: number,\n animation: HoverAnimationType = \"combined\",\n intensity: GlowIntensity = \"strong\",\n): React.CSSProperties {\n const baseStyles: React.CSSProperties = {\n transition: getSmoothTransition(\"all\", \"normal\"),\n cursor: \"pointer\",\n };\n\n const glowStyles: React.CSSProperties = {\n boxShadow: getNeonGlowEffect(baseColor, intensity, true),\n };\n\n const scaleStyles: React.CSSProperties = {\n transform: \"scale(1.05)\",\n };\n\n const liftStyles: React.CSSProperties = {\n transform: \"translateY(-2px)\",\n boxShadow: getLayeredDepthEffect({\n layers: 3,\n baseOffset: 4,\n baseBlur: 8,\n color: KOREAN_COLORS.BLACK_SOLID,\n opacity: 0.6,\n }),\n };\n\n const pulseStyles: React.CSSProperties = {\n animation: \"pulse 1.5s ease-in-out infinite\",\n };\n\n switch (animation) {\n case \"glow\":\n return { ...baseStyles, ...glowStyles };\n case \"scale\":\n return { ...baseStyles, ...scaleStyles };\n case \"lift\":\n return { ...baseStyles, ...liftStyles };\n case \"pulse\":\n return { ...baseStyles, ...pulseStyles };\n case \"combined\":\n return {\n ...baseStyles,\n ...glowStyles,\n transform: \"scale(1.02) translateY(-1px)\",\n };\n default:\n return baseStyles;\n }\n}\n\n/**\n * Get focus state styles with accessibility\n *\n * Creates WCAG-compliant focus indicators with Korean cyberpunk styling.\n * Ensures 2px border with high contrast (4.5:1 minimum).\n *\n * Note: While outline is set to \"none\", the custom 2px border provides\n * equivalent accessibility. For users relying on high-contrast mode or\n * custom browser settings, consider using outline-offset as an additional\n * fallback or ensure the custom border has sufficient contrast (4.5:1+).\n *\n * @param color - Hex color for focus indicator\n * @param includeGlow - Whether to include glow effect (default: true)\n * @returns React.CSSProperties for focus state\n *\n * @example\n * ```typescript\n * const focusStyle = getFocusStateStyles(KOREAN_COLORS.ACCENT_GOLD, true);\n * ```\n *\n * @korean 포커스상태스타일얻기\n */\nexport function getFocusStateStyles(\n color: number,\n includeGlow: boolean = true,\n): React.CSSProperties {\n const baseStyles: React.CSSProperties = {\n outline: \"none\",\n border: `2px solid ${hexToRgbaString(color, 1.0)}`,\n };\n\n if (includeGlow) {\n return {\n ...baseStyles,\n boxShadow: getNeonGlowEffect(color, \"medium\", false),\n };\n }\n\n return baseStyles;\n}\n\n/**\n * Get backdrop blur effect\n *\n * Creates frosted glass effect for Korean-themed overlays.\n * GPU-accelerated for 60fps performance.\n *\n * @param blurAmount - Blur amount in pixels (default: 10)\n * @param saturation - Color saturation multiplier (default: 1.5)\n * @returns React.CSSProperties with backdrop blur\n *\n * @example\n * ```typescript\n * const backdropStyle = getBackdropBlurEffect(12, 1.8);\n * ```\n *\n * @korean 배경블러효과얻기\n */\nexport function getBackdropBlurEffect(\n blurAmount: number = 10,\n saturation: number = 1.5,\n): React.CSSProperties & {\n WebkitBackdropFilter?: string;\n} {\n return {\n backdropFilter: `blur(${blurAmount}px) saturate(${saturation})`,\n WebkitBackdropFilter: `blur(${blurAmount}px) saturate(${saturation})`,\n // Fallback for browsers without backdrop-filter support\n backgroundColor: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.8),\n };\n}\n\n/**\n * Get trigram symbol glow effect\n *\n * Creates glowing effect for Eight Trigram symbols (☰☱☲☳☴☵☶☷).\n * Uses stance-specific colors from KOREAN_COLORS.\n *\n * @param trigramColor - Trigram-specific hex color\n * @param isActive - Whether trigram is currently active\n * @returns React.CSSProperties with trigram glow\n *\n * @example\n * ```typescript\n * const trigramGlow = getTrigramSymbolGlow(\n * KOREAN_COLORS.TRIGRAM_GEON_PRIMARY,\n * true\n * );\n * ```\n *\n * @korean 팔괘상징글로우얻기\n */\nexport function getTrigramSymbolGlow(\n trigramColor: number,\n isActive: boolean,\n): React.CSSProperties {\n const intensity = isActive ? \"intense\" : \"subtle\";\n const scale = isActive ? 1.1 : 1.0;\n\n return {\n color: hexToRgbaString(trigramColor, 1.0),\n textShadow: getNeonTextShadow(trigramColor, intensity),\n transform: `scale(${scale})`,\n transition: getSmoothTransition(\"all\", \"normal\"),\n filter: isActive ? \"brightness(1.2)\" : \"brightness(1.0)\",\n };\n}\n\n/**\n * Get GPU-accelerated animation hint\n *\n * Applies will-change CSS property to hint GPU acceleration.\n * Use sparingly - only for actively animating elements.\n *\n * @param properties - Properties that will animate\n * @returns React.CSSProperties with GPU hints\n *\n * @example\n * ```typescript\n * const gpuHint = getGPUAccelerationHint('transform, opacity');\n * ```\n *\n * @korean GPU가속힌트얻기\n */\nexport function getGPUAccelerationHint(\n properties: string = \"transform\",\n): React.CSSProperties {\n return {\n willChange: properties,\n transform: \"translateZ(0)\", // Force GPU layer\n };\n}\n\n/**\n * Combine multiple shadow effects\n *\n * Merges multiple box-shadow strings into a single CSS value.\n * Useful for combining glow, depth, and custom shadows.\n *\n * @param shadows - Array of box-shadow strings\n * @returns Combined box-shadow CSS string\n *\n * @example\n * ```typescript\n * const combined = combineShadowEffects([\n * getNeonGlowEffect(KOREAN_COLORS.PRIMARY_CYAN, 'medium'),\n * getLayeredDepthEffect({ layers: 2, baseOffset: 2, baseBlur: 4, color: 0x000000, opacity: 0.5 })\n * ]);\n * ```\n *\n * @korean 그림자효과결합\n */\nexport function combineShadowEffects(shadows: string[]): string {\n return shadows.filter(Boolean).join(\", \");\n}\n\n/**\n * Get pulsing animation keyframes\n *\n * Returns CSS keyframe animation for pulsing glow effect.\n * Should be injected into global styles or style tag once.\n * Use unique animation names to avoid conflicts.\n *\n * @param animationName - Unique name for the animation (default: 'pulse')\n * @returns CSS keyframes string\n *\n * @example\n * ```typescript\n * const keyframes = getPulsingKeyframes('pulse-glow');\n * // Inject into global styles once:\n * const style = document.createElement('style');\n * style.innerHTML = keyframes;\n * document.head.appendChild(style);\n * ```\n *\n * @warning SSR and Duplicate Keyframes\n * When using this in Server-Side Rendering (SSR) environments or with multiple\n * component instances, ensure keyframe definitions are registered globally only once.\n * Consider using a global registry or checking for existing keyframe definitions\n * before injection to prevent duplicates and hydration mismatches. Example:\n * ```typescript\n * if (!document.querySelector(`style[data-keyframe=\"${animationName}\"]`)) {\n * const style = document.createElement('style');\n * style.setAttribute('data-keyframe', animationName);\n * style.innerHTML = getPulsingKeyframes(animationName);\n * document.head.appendChild(style);\n * }\n * ```\n *\n * @korean 펄스애니메이션키프레임얻기\n */\nexport function getPulsingKeyframes(animationName: string = \"pulse\"): string {\n return `\n @keyframes ${animationName} {\n 0%, 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.05);\n }\n }\n `;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA2EA,SAAgB,kBACd,OACA,YAA2B,UAC3B,eAAwB,MAChB;CAQR,MAAM,SAAS;EANb,QAAQ;GAAE,OAAO;GAAI,cAAc;GAAK,OAAO;GAAG,cAAc;EAAI;EACpE,QAAQ;GAAE,OAAO;GAAI,cAAc;GAAK,OAAO;GAAI,cAAc;EAAI;EACrE,QAAQ;GAAE,OAAO;GAAI,cAAc;GAAK,OAAO;GAAI,cAAc;EAAI;EACrE,SAAS;GAAE,OAAO;GAAI,cAAc;GAAK,OAAO;GAAI,cAAc;EAAI;CAGzD,EAAW;CAM1B,OAAO,GAAG,OALe,OAAO,MAAM,KAAK,gBAAgB,OAAO,OAAO,YAAY,MACnE,eACd,eAAe,OAAO,MAAM,KAAK,gBAAgB,OAAO,OAAO,YAAY,MAC3E;AAGN;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,kBACd,OACA,YAA2B,UACnB;CAyBR,OADgB;EAtBd,QAAQ,CACN;GAAE,MAAM;GAAG,SAAS;EAAI,GACxB;GAAE,MAAM;GAAI,SAAS;EAAI,CAC3B;EACA,QAAQ;GACN;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;EAC3B;EACA,QAAQ;GACN;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;EAC3B;EACA,SAAS;GACP;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;GACzB;IAAE,MAAM;IAAI,SAAS;GAAI;EAC3B;CAGc,EAAa,WAE1B,KACE,EAAE,MAAM,cAAc,OAAO,KAAK,KAAK,gBAAgB,OAAO,OAAO,GACxE,EACC,KAAK,IAAI;AACd;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,sBAAsB,QAAmC;CACvE,MAAM,EAAE,QAAQ,YAAY,UAAU,OAAO,YAAY;CACzD,MAAM,UAAoB,CAAC;CAE3B,KAAK,IAAI,IAAI,GAAG,KAAK,QAAQ,KAAK;EAChC,MAAM,SAAS,aAAa;EAC5B,MAAM,OAAO,WAAW;EACxB,MAAM,eAAe,WAAW,KAAM,IAAI,KAAK,SAAU;EACzD,QAAQ,KACN,KAAK,OAAO,KAAK,KAAK,KAAK,gBAAgB,OAAO,YAAY,GAChE;CACF;CAEA,OAAO,QAAQ,KAAK,IAAI;AAC1B;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,SAAgB,qBACd,cACA,gBACA,QAAgB,KAChB,OAA4B,UACpB;CACR,MAAM,SAAS,gBAAgB,cAAc,EAAG;CAChD,MAAM,SAAS,gBAAgB,gBAAgB,EAAG;CAElD,IAAI,SAAS,UACX,OAAO,uCAAuC,OAAO,OAAO,OAAO;CAGrE,OAAO,mBAAmB,MAAM,OAAO,OAAO,OAAO,OAAO;AAC9D;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,oBACd,aAAqB,OACrB,SAA2B,UACnB;CAQR,MAAM,SAAS;EANb,MAAM;GAAE,UAAU;GAAS,QAAQ;EAAW;EAC9C,QAAQ;GAAE,UAAU;GAAQ,QAAQ;EAAc;EAClD,MAAM;GAAE,UAAU;GAAQ,QAAQ;EAAc;EAChD,QAAQ;GAAE,UAAU;GAAS,QAAQ;EAA+B;CAGvD,EAAa;CAC5B,OAAO,GAAG,WAAW,GAAG,OAAO,SAAS,GAAG,OAAO;AACpD;;;;;;;;;;;;;;;;;;;AAoBA,SAAgB,0BACd,UACA,aAAgC,UAIhC;CACA,OAAO;EACL,UAAU,GAAG,SAAS;EACtB;EACA,qBAAqB;EACrB,qBAAqB;EACrB,eAAe;EACf,eAAe;EAEf,YAAY;CACd;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwDA,SAAgB,oBACd,WACA,YAAgC,YAChC,YAA2B,UACN;CACrB,MAAM,aAAkC;EACtC,YAAY,oBAAoB,OAAO,QAAQ;EAC/C,QAAQ;CACV;CAEA,MAAM,aAAkC,EACtC,WAAW,kBAAkB,WAAW,WAAW,IAAI,EACzD;CAEA,MAAM,cAAmC,EACvC,WAAW,cACb;CAEA,MAAM,aAAkC;EACtC,WAAW;EACX,WAAW,sBAAsB;GAC/B,QAAQ;GACR,YAAY;GACZ,UAAU;GACV,OAAO,cAAc;GACrB,SAAS;EACX,CAAC;CACH;CAEA,MAAM,cAAmC,EACvC,WAAW,kCACb;CAEA,QAAQ,WAAR;EACE,KAAK,QACH,OAAO;GAAE,GAAG;GAAY,GAAG;EAAW;EACxC,KAAK,SACH,OAAO;GAAE,GAAG;GAAY,GAAG;EAAY;EACzC,KAAK,QACH,OAAO;GAAE,GAAG;GAAY,GAAG;EAAW;EACxC,KAAK,SACH,OAAO;GAAE,GAAG;GAAY,GAAG;EAAY;EACzC,KAAK,YACH,OAAO;GACL,GAAG;GACH,GAAG;GACH,WAAW;EACb;EACF,SACE,OAAO;CACX;AACF;;;;;;;;;;;;;;;;;;;;;;;AAwBA,SAAgB,oBACd,OACA,cAAuB,MACF;CACrB,MAAM,aAAkC;EACtC,SAAS;EACT,QAAQ,aAAa,gBAAgB,OAAO,CAAG;CACjD;CAEA,IAAI,aACF,OAAO;EACL,GAAG;EACH,WAAW,kBAAkB,OAAO,UAAU,KAAK;CACrD;CAGF,OAAO;AACT;;;;;;;;;;;;;;;;;;AAmBA,SAAgB,sBACd,aAAqB,IACrB,aAAqB,KAGrB;CACA,OAAO;EACL,gBAAgB,QAAQ,WAAW,eAAe,WAAW;EAC7D,sBAAsB,QAAQ,WAAW,eAAe,WAAW;EAEnE,iBAAiB,gBAAgB,cAAc,oBAAoB,EAAG;CACxE;AACF;;;;;;;;;;;;;;;;;;;;AAkFA,SAAgB,qBAAqB,SAA2B;CAC9D,OAAO,QAAQ,OAAO,OAAO,EAAE,KAAK,IAAI;AAC1C"}
1
+ {"version":3,"file":"visualEffects.js","names":[],"sources":["../../src/utils/visualEffects.ts"],"sourcesContent":["/**\n * Visual Effects Utilities for Korean Cyberpunk Aesthetic\n *\n * Provides advanced visual effects for HTML overlay components including:\n * - Neon glow effects (box-shadow, text-shadow)\n * - Depth effects (layered shadows, gradients, backdrop-blur)\n * - Smooth transitions and animations\n * - Korean font rendering optimization\n * - Hover and focus state generators\n *\n * All effects follow Korean martial arts cyberpunk theme with 60fps performance target.\n *\n * @module utils/visualEffects\n * @category UI Utilities\n * @korean 시각효과유틸리티\n */\n\nimport { KOREAN_COLORS } from \"@/types/constants\";\nimport { hexToRgbaString } from \"./colorUtils\";\n\n/**\n * Neon glow intensity levels\n * @korean 네온글로우강도\n */\nexport type GlowIntensity = \"subtle\" | \"medium\" | \"strong\" | \"intense\";\n\n/**\n * Hover state animation types\n * @korean 호버상태애니메이션\n */\nexport type HoverAnimationType =\n | \"glow\"\n | \"scale\"\n | \"lift\"\n | \"pulse\"\n | \"combined\";\n\n/**\n * Transition timing presets\n * @korean 전환타이밍프리셋\n */\nexport type TransitionTiming = \"fast\" | \"normal\" | \"slow\" | \"smooth\";\n\n/**\n * Depth effect layer configuration\n * @korean 깊이효과레이어설정\n */\nexport interface DepthEffectConfig {\n readonly layers: number;\n readonly baseOffset: number;\n readonly baseBlur: number;\n readonly color: number;\n readonly opacity: number;\n}\n\n/**\n * Get neon glow effect CSS string\n *\n * Creates cyberpunk-style neon glow using box-shadow with Korean colors.\n * Supports multiple intensity levels for different UI elements.\n *\n * @param color - Hex color value from KOREAN_COLORS\n * @param intensity - Glow intensity level\n * @param includeInset - Whether to include inset glow (default: true)\n * @returns CSS box-shadow string with neon glow effect\n *\n * @example\n * ```typescript\n * const glow = getNeonGlowEffect(KOREAN_COLORS.PRIMARY_CYAN, 'medium', true);\n * // Returns: \"0 0 20px rgba(0,230,230,0.6), inset 0 0 10px rgba(0,230,230,0.3)\"\n * // Note: Color conversion is handled by hexToRgbaString utility\n * ```\n *\n * @korean 네온글로우효과얻기\n */\nexport function getNeonGlowEffect(\n color: number,\n intensity: GlowIntensity = \"medium\",\n includeInset: boolean = true,\n): string {\n const glowConfig = {\n subtle: { outer: 10, outerOpacity: 0.4, inner: 5, innerOpacity: 0.2 },\n medium: { outer: 20, outerOpacity: 0.6, inner: 10, innerOpacity: 0.3 },\n strong: { outer: 30, outerOpacity: 0.8, inner: 15, innerOpacity: 0.4 },\n intense: { outer: 40, outerOpacity: 1.0, inner: 20, innerOpacity: 0.5 },\n };\n\n const config = glowConfig[intensity];\n const outerGlow = `0 0 ${config.outer}px ${hexToRgbaString(color, config.outerOpacity)}`;\n const insetGlow = includeInset\n ? `, inset 0 0 ${config.inner}px ${hexToRgbaString(color, config.innerOpacity)}`\n : \"\";\n\n return `${outerGlow}${insetGlow}`;\n}\n\n/**\n * Get neon text shadow effect\n *\n * Creates glowing text effect for Korean and English text using text-shadow.\n * Multiple shadow layers create authentic neon glow appearance.\n *\n * @param color - Hex color value from KOREAN_COLORS\n * @param intensity - Glow intensity level\n * @returns CSS text-shadow string with neon glow\n *\n * @example\n * ```typescript\n * const textGlow = getNeonTextShadow(KOREAN_COLORS.ACCENT_GOLD, 'strong');\n * // Returns: \"0 0 10px rgba(255,196,0,0.8), 0 0 20px rgba(255,196,0,0.6), 0 0 30px rgba(255,196,0,0.4)\"\n * ```\n *\n * @korean 네온텍스트그림자얻기\n */\nexport function getNeonTextShadow(\n color: number,\n intensity: GlowIntensity = \"medium\",\n): string {\n const shadowConfig = {\n subtle: [\n { blur: 5, opacity: 0.6 },\n { blur: 10, opacity: 0.4 },\n ],\n medium: [\n { blur: 10, opacity: 0.8 },\n { blur: 20, opacity: 0.6 },\n { blur: 30, opacity: 0.4 },\n ],\n strong: [\n { blur: 15, opacity: 1.0 },\n { blur: 30, opacity: 0.8 },\n { blur: 45, opacity: 0.6 },\n ],\n intense: [\n { blur: 20, opacity: 1.0 },\n { blur: 40, opacity: 0.9 },\n { blur: 60, opacity: 0.7 },\n { blur: 80, opacity: 0.5 },\n ],\n };\n\n const shadows = shadowConfig[intensity];\n return shadows\n .map(\n ({ blur, opacity }) => `0 0 ${blur}px ${hexToRgbaString(color, opacity)}`,\n )\n .join(\", \");\n}\n\n/**\n * Get layered depth effect\n *\n * Creates depth using multiple shadow layers with increasing offset and blur.\n * Provides 3D-like appearance for Korean-themed UI panels.\n *\n * @param config - Depth effect configuration\n * @returns CSS box-shadow string with layered depth\n *\n * @example\n * ```typescript\n * const depth = getLayeredDepthEffect({\n * layers: 3,\n * baseOffset: 2,\n * baseBlur: 4,\n * color: KOREAN_COLORS.BLACK_SOLID,\n * opacity: 0.5,\n * });\n * ```\n *\n * @korean 레이어깊이효과얻기\n */\nexport function getLayeredDepthEffect(config: DepthEffectConfig): string {\n const { layers, baseOffset, baseBlur, color, opacity } = config;\n const shadows: string[] = [];\n\n for (let i = 1; i <= layers; i++) {\n const offset = baseOffset * i;\n const blur = baseBlur * i;\n const layerOpacity = opacity * (1 - ((i - 1) / layers) * 0.3); // Fade each layer\n shadows.push(\n `0 ${offset}px ${blur}px ${hexToRgbaString(color, layerOpacity)}`,\n );\n }\n\n return shadows.join(\", \");\n}\n\n/**\n * Get cyberpunk gradient background\n *\n * Creates Korean-themed gradient with cyberpunk colors.\n * Supports both linear and radial gradients.\n *\n * @param primaryColor - Primary hex color\n * @param secondaryColor - Secondary hex color\n * @param angle - Gradient angle in degrees (default: 135)\n * @param type - Gradient type ('linear' | 'radial')\n * @returns CSS gradient string\n *\n * @example\n * ```typescript\n * const gradient = getCyberpunkGradient(\n * KOREAN_COLORS.PRIMARY_CYAN,\n * KOREAN_COLORS.UI_BACKGROUND_DARK,\n * 135,\n * 'linear'\n * );\n * ```\n *\n * @korean 사이버펑크그라디언트얻기\n */\nexport function getCyberpunkGradient(\n primaryColor: number,\n secondaryColor: number,\n angle: number = 135,\n type: \"linear\" | \"radial\" = \"linear\",\n): string {\n const color1 = hexToRgbaString(primaryColor, 0.2);\n const color2 = hexToRgbaString(secondaryColor, 0.9);\n\n if (type === \"radial\") {\n return `radial-gradient(circle at top left, ${color1} 0%, ${color2} 100%)`;\n }\n\n return `linear-gradient(${angle}deg, ${color1} 0%, ${color2} 100%)`;\n}\n\n/**\n * Get smooth transition CSS\n *\n * Returns standardized transition string for consistent animations.\n * All transitions target 60fps performance.\n *\n * @param properties - CSS properties to transition (default: 'all')\n * @param timing - Timing preset\n * @returns CSS transition string\n *\n * @example\n * ```typescript\n * const transition = getSmoothTransition('all', 'normal');\n * // Returns: \"all 0.2s ease-in-out\"\n * ```\n *\n * @korean 부드러운전환얻기\n */\nexport function getSmoothTransition(\n properties: string = \"all\",\n timing: TransitionTiming = \"normal\",\n): string {\n const timingConfig = {\n fast: { duration: \"0.15s\", easing: \"ease-out\" },\n normal: { duration: \"0.2s\", easing: \"ease-in-out\" },\n slow: { duration: \"0.3s\", easing: \"ease-in-out\" },\n smooth: { duration: \"0.25s\", easing: \"cubic-bezier(0.4, 0, 0.2, 1)\" },\n };\n\n const config = timingConfig[timing];\n return `${properties} ${config.duration} ${config.easing}`;\n}\n\n/**\n * Get Korean font optimization styles\n *\n * Applies optimal font rendering for Korean characters (Hangul).\n * Includes anti-aliasing, subpixel rendering, and letter spacing.\n *\n * @param fontSize - Font size in pixels\n * @param fontWeight - Font weight (default: 'normal')\n * @returns React.CSSProperties with Korean font optimization\n *\n * @example\n * ```typescript\n * const fontStyle = getKoreanFontOptimization(16, 'bold');\n * // Returns: { fontSize: '16px', WebkitFontSmoothing: 'antialiased', ... }\n * ```\n *\n * @korean 한글폰트최적화얻기\n */\nexport function getKoreanFontOptimization(\n fontSize: number,\n fontWeight: \"normal\" | \"bold\" = \"normal\",\n): React.CSSProperties & {\n WebkitFontSmoothing?: string;\n MozOsxFontSmoothing?: string;\n} {\n return {\n fontSize: `${fontSize}px`,\n fontWeight,\n WebkitFontSmoothing: \"antialiased\",\n MozOsxFontSmoothing: \"grayscale\",\n textRendering: \"optimizeLegibility\",\n letterSpacing: \"0.02em\",\n // Korean characters need slightly more line height\n lineHeight: 1.5,\n };\n}\n\n/**\n * Map numeric glow intensity to GlowIntensity type\n *\n * Helper to standardize glow intensity mapping across components.\n * Converts numeric intensity values to discrete levels.\n *\n * @param glowIntensity - Numeric glow intensity (0-2+ scale)\n * @returns GlowIntensity level (\"subtle\", \"medium\", \"strong\", \"intense\")\n *\n * Mapping thresholds:\n * - intense: >= 1.5\n * - strong: >= 1.0\n * - medium: >= 0.6\n * - subtle: < 0.6\n *\n * @example\n * ```typescript\n * const level = mapGlowIntensityLevel(0.8);\n * // Returns: \"medium\"\n * mapGlowIntensityLevel(2.0);\n * // Returns: \"intense\"\n * ```\n *\n * @korean 광도레벨매핑\n */\nexport function mapGlowIntensityLevel(glowIntensity: number): GlowIntensity {\n if (glowIntensity >= 1.5) return \"intense\";\n if (glowIntensity >= 1.0) return \"strong\";\n if (glowIntensity >= 0.6) return \"medium\";\n return \"subtle\";\n}\n\n/**\n * Get hover state styles with glow effect\n *\n * Generates hover state styles with Korean cyberpunk animations.\n * Includes glow intensification, scale, and lift effects.\n *\n * @param baseColor - Base hex color\n * @param animation - Animation type\n * @param intensity - Glow intensity for hover state\n * @returns React.CSSProperties for hover state\n *\n * @example\n * ```typescript\n * const hoverStyle = getHoverStateStyles(\n * KOREAN_COLORS.PRIMARY_CYAN,\n * 'combined',\n * 'strong'\n * );\n * ```\n *\n * @korean 호버상태스타일얻기\n */\nexport function getHoverStateStyles(\n baseColor: number,\n animation: HoverAnimationType = \"combined\",\n intensity: GlowIntensity = \"strong\",\n): React.CSSProperties {\n const baseStyles: React.CSSProperties = {\n transition: getSmoothTransition(\"all\", \"normal\"),\n cursor: \"pointer\",\n };\n\n const glowStyles: React.CSSProperties = {\n boxShadow: getNeonGlowEffect(baseColor, intensity, true),\n };\n\n const scaleStyles: React.CSSProperties = {\n transform: \"scale(1.05)\",\n };\n\n const liftStyles: React.CSSProperties = {\n transform: \"translateY(-2px)\",\n boxShadow: getLayeredDepthEffect({\n layers: 3,\n baseOffset: 4,\n baseBlur: 8,\n color: KOREAN_COLORS.BLACK_SOLID,\n opacity: 0.6,\n }),\n };\n\n const pulseStyles: React.CSSProperties = {\n animation: \"pulse 1.5s ease-in-out infinite\",\n };\n\n switch (animation) {\n case \"glow\":\n return { ...baseStyles, ...glowStyles };\n case \"scale\":\n return { ...baseStyles, ...scaleStyles };\n case \"lift\":\n return { ...baseStyles, ...liftStyles };\n case \"pulse\":\n return { ...baseStyles, ...pulseStyles };\n case \"combined\":\n return {\n ...baseStyles,\n ...glowStyles,\n transform: \"scale(1.02) translateY(-1px)\",\n };\n default:\n return baseStyles;\n }\n}\n\n/**\n * Get focus state styles with accessibility\n *\n * Creates WCAG-compliant focus indicators with Korean cyberpunk styling.\n * Ensures 2px border with high contrast (4.5:1 minimum).\n *\n * Note: While outline is set to \"none\", the custom 2px border provides\n * equivalent accessibility. For users relying on high-contrast mode or\n * custom browser settings, consider using outline-offset as an additional\n * fallback or ensure the custom border has sufficient contrast (4.5:1+).\n *\n * @param color - Hex color for focus indicator\n * @param includeGlow - Whether to include glow effect (default: true)\n * @returns React.CSSProperties for focus state\n *\n * @example\n * ```typescript\n * const focusStyle = getFocusStateStyles(KOREAN_COLORS.ACCENT_GOLD, true);\n * ```\n *\n * @korean 포커스상태스타일얻기\n */\nexport function getFocusStateStyles(\n color: number,\n includeGlow: boolean = true,\n): React.CSSProperties {\n const baseStyles: React.CSSProperties = {\n outline: \"none\",\n border: `2px solid ${hexToRgbaString(color, 1.0)}`,\n };\n\n if (includeGlow) {\n return {\n ...baseStyles,\n boxShadow: getNeonGlowEffect(color, \"medium\", false),\n };\n }\n\n return baseStyles;\n}\n\n/**\n * Get backdrop blur effect\n *\n * Creates frosted glass effect for Korean-themed overlays.\n * GPU-accelerated for 60fps performance.\n *\n * @param blurAmount - Blur amount in pixels (default: 10)\n * @param saturation - Color saturation multiplier (default: 1.5)\n * @returns React.CSSProperties with backdrop blur\n *\n * @example\n * ```typescript\n * const backdropStyle = getBackdropBlurEffect(12, 1.8);\n * ```\n *\n * @korean 배경블러효과얻기\n */\nexport function getBackdropBlurEffect(\n blurAmount: number = 10,\n saturation: number = 1.5,\n): React.CSSProperties & {\n WebkitBackdropFilter?: string;\n} {\n return {\n backdropFilter: `blur(${blurAmount}px) saturate(${saturation})`,\n WebkitBackdropFilter: `blur(${blurAmount}px) saturate(${saturation})`,\n // Fallback for browsers without backdrop-filter support\n backgroundColor: hexToRgbaString(KOREAN_COLORS.UI_BACKGROUND_DARK, 0.8),\n };\n}\n\n/**\n * Get trigram symbol glow effect\n *\n * Creates glowing effect for Eight Trigram symbols (☰☱☲☳☴☵☶☷).\n * Uses stance-specific colors from KOREAN_COLORS.\n *\n * @param trigramColor - Trigram-specific hex color\n * @param isActive - Whether trigram is currently active\n * @returns React.CSSProperties with trigram glow\n *\n * @example\n * ```typescript\n * const trigramGlow = getTrigramSymbolGlow(\n * KOREAN_COLORS.TRIGRAM_GEON_PRIMARY,\n * true\n * );\n * ```\n *\n * @korean 팔괘상징글로우얻기\n */\nexport function getTrigramSymbolGlow(\n trigramColor: number,\n isActive: boolean,\n): React.CSSProperties {\n const intensity = isActive ? \"intense\" : \"subtle\";\n const scale = isActive ? 1.1 : 1.0;\n\n return {\n color: hexToRgbaString(trigramColor, 1.0),\n textShadow: getNeonTextShadow(trigramColor, intensity),\n transform: `scale(${scale})`,\n transition: getSmoothTransition(\"all\", \"normal\"),\n filter: isActive ? \"brightness(1.2)\" : \"brightness(1.0)\",\n };\n}\n\n/**\n * Get GPU-accelerated animation hint\n *\n * Applies will-change CSS property to hint GPU acceleration.\n * Use sparingly - only for actively animating elements.\n *\n * @param properties - Properties that will animate\n * @returns React.CSSProperties with GPU hints\n *\n * @example\n * ```typescript\n * const gpuHint = getGPUAccelerationHint('transform, opacity');\n * ```\n *\n * @korean GPU가속힌트얻기\n */\nexport function getGPUAccelerationHint(\n properties: string = \"transform\",\n): React.CSSProperties {\n return {\n willChange: properties,\n transform: \"translateZ(0)\", // Force GPU layer\n };\n}\n\n/**\n * Combine multiple shadow effects\n *\n * Merges multiple box-shadow strings into a single CSS value.\n * Useful for combining glow, depth, and custom shadows.\n *\n * @param shadows - Array of box-shadow strings\n * @returns Combined box-shadow CSS string\n *\n * @example\n * ```typescript\n * const combined = combineShadowEffects([\n * getNeonGlowEffect(KOREAN_COLORS.PRIMARY_CYAN, 'medium'),\n * getLayeredDepthEffect({ layers: 2, baseOffset: 2, baseBlur: 4, color: 0x000000, opacity: 0.5 })\n * ]);\n * ```\n *\n * @korean 그림자효과결합\n */\nexport function combineShadowEffects(shadows: string[]): string {\n return shadows.filter(Boolean).join(\", \");\n}\n\n/**\n * Get pulsing animation keyframes\n *\n * Returns CSS keyframe animation for pulsing glow effect.\n * Should be injected into global styles or style tag once.\n * Use unique animation names to avoid conflicts.\n *\n * @param animationName - Unique name for the animation (default: 'pulse')\n * @returns CSS keyframes string\n *\n * @example\n * ```typescript\n * const keyframes = getPulsingKeyframes('pulse-glow');\n * // Inject into global styles once:\n * const style = document.createElement('style');\n * style.innerHTML = keyframes;\n * document.head.appendChild(style);\n * ```\n *\n * @warning SSR and Duplicate Keyframes\n * When using this in Server-Side Rendering (SSR) environments or with multiple\n * component instances, ensure keyframe definitions are registered globally only once.\n * Consider using a global registry or checking for existing keyframe definitions\n * before injection to prevent duplicates and hydration mismatches. Example:\n * ```typescript\n * if (!document.querySelector(`style[data-keyframe=\"${animationName}\"]`)) {\n * const style = document.createElement('style');\n * style.setAttribute('data-keyframe', animationName);\n * style.innerHTML = getPulsingKeyframes(animationName);\n * document.head.appendChild(style);\n * }\n * ```\n *\n * @korean 펄스애니메이션키프레임얻기\n */\nexport function getPulsingKeyframes(animationName: string = \"pulse\"): string {\n return `\n @keyframes ${animationName} {\n 0%, 100% {\n opacity: 1;\n transform: scale(1);\n }\n 50% {\n opacity: 0.8;\n transform: scale(1.05);\n }\n }\n `;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "blacktrigram",
3
- "version": "0.7.67",
3
+ "version": "0.7.69",
4
4
  "description": "Black Trigram (흑괘) - Korean Martial Arts Combat Simulator. Reusable game systems, combat mechanics, animation framework, and Korean martial arts data built with React, Three.js, and TypeScript.",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -188,7 +188,7 @@
188
188
  "three": "0.184.0"
189
189
  },
190
190
  "devDependencies": {
191
- "@aws-sdk/client-bedrock-runtime": "3.1072.0",
191
+ "@aws-sdk/client-bedrock-runtime": "3.1075.0",
192
192
  "@eslint/js": "10.0.1",
193
193
  "@react-three/drei": "10.7.7",
194
194
  "@react-three/fiber": "9.6.1",
@@ -201,10 +201,10 @@
201
201
  "@types/react": "19.2.17",
202
202
  "@types/react-dom": "19.2.3",
203
203
  "@types/three": "0.184.1",
204
- "@vitejs/plugin-react": "6.0.2",
204
+ "@vitejs/plugin-react": "6.0.3",
205
205
  "@vitest/coverage-v8": "4.1.9",
206
206
  "@vitest/ui": "4.1.9",
207
- "cypress": "15.17.0",
207
+ "cypress": "15.18.0",
208
208
  "cypress-junit-reporter": "1.3.1",
209
209
  "cypress-multi-reporters": "2.0.5",
210
210
  "cypress-wait-until": "3.0.2",
@@ -213,10 +213,10 @@
213
213
  "eslint": "10.5.0",
214
214
  "eslint-plugin-react-hooks": "7.1.1",
215
215
  "eslint-plugin-react-refresh": "0.5.3",
216
- "globals": "17.6.0",
216
+ "globals": "17.7.0",
217
217
  "jest-axe": "10.0.0",
218
218
  "jsdom": "29.1.1",
219
- "knip": "6.17.1",
219
+ "knip": "6.18.0",
220
220
  "license-compliance": "3.0.1",
221
221
  "mermaid": "11.15.0",
222
222
  "mocha-junit-reporter": "2.2.1",
@@ -224,7 +224,7 @@
224
224
  "mochawesome-merge": "5.1.1",
225
225
  "mochawesome-report-generator": "6.3.2",
226
226
  "openai": "6.44.0",
227
- "playwright": "1.61.0",
227
+ "playwright": "1.61.1",
228
228
  "postprocessing": "6.39.1",
229
229
  "react": "19.2.7",
230
230
  "react-dom": "19.2.7",
@@ -239,8 +239,8 @@
239
239
  "typedoc-plugin-mermaid": "1.12.0",
240
240
  "typedoc-plugin-missing-exports": "4.1.3",
241
241
  "typescript": "6.0.3",
242
- "typescript-eslint": "8.61.1",
243
- "vite": "8.0.16",
242
+ "typescript-eslint": "8.62.0",
243
+ "vite": "8.1.0",
244
244
  "vite-bundle-analyzer": "1.3.8",
245
245
  "vite-tsconfig-paths": "6.1.1",
246
246
  "vitest": "4.1.9"