blacktrigram 0.7.23 → 0.7.24

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.
@@ -1 +1 @@
1
- {"version":3,"file":"common.js","names":[],"sources":["../../src/types/common.ts"],"sourcesContent":["/**\n * Common utility types for Korean martial arts game.\n *\n * This module provides foundational types used throughout the Black Trigram (흑괘) game,\n * including geometric types, Korean text support, and utility type helpers.\n *\n * @module types/common\n * @category Type Definitions\n * @korean 공통타입\n */\n\n/**\n * Represents a position in 2D space.\n *\n * **Unit Handling**: The coordinate units depend on the system using this type:\n * - **Combat System**: Coordinates are in **meters** (physics-first architecture)\n * - **Rendering System**: Coordinates are in **pixels** (screen rendering)\n * - **Legacy Systems**: May use pixels or other units\n *\n * When working with combat/physics, positions are in meters relative to arena center (0, 0).\n * Arena boundaries extend from ±worldWidthMeters/2 in X and ±worldDepthMeters/2 in Z (mapped to y).\n *\n * @example\n * ```typescript\n * // Combat position (meters, centered at origin)\n * const playerPos: Position = { x: 2.5, y: -1.0 }; // 2.5m right, 1m back from center\n *\n * // Rendering position (pixels, top-left origin)\n * const screenPos: Position = { x: 640, y: 480 }; // 640px right, 480px down\n * ```\n *\n * @public\n * @category Core Types\n */\nexport interface Position {\n /** X coordinate (meters in combat, pixels in rendering) */\n x: number;\n /** Y coordinate (meters in combat, pixels in rendering) */\n y: number;\n}\n\n/**\n * Represents size dimensions for game objects.\n *\n * @public\n * @category Core Types\n */\nexport interface Size {\n /** Width in pixels */\n readonly width: number;\n /** Height in pixels */\n readonly height: number;\n}\n\n/**\n * Represents rectangle bounds combining position and size.\n *\n * @public\n * @category Core Types\n */\nexport interface Bounds extends Position, Size {}\n\n/**\n * Color represented as a hexadecimal number (e.g., 0xFF0000 for red).\n *\n * @example\n * ```typescript\n * const primaryCyan: Color = 0x00FFFF;\n * const accentGold: Color = 0xFFAA00;\n * ```\n *\n * @public\n * @category Core Types\n */\nexport type Color = number;\n\n/**\n * Time duration in milliseconds.\n *\n * @public\n * @category Core Types\n */\nexport type Duration = number;\n\n/**\n * Percentage value represented as a decimal (0.0 to 1.0).\n *\n * @example\n * ```typescript\n * const halfHealth: Percentage = 0.5;\n * const fullAccuracy: Percentage = 1.0;\n * ```\n *\n * @public\n * @category Core Types\n */\nexport type Percentage = number;\n\n/**\n * Unique identifier string.\n *\n * @public\n * @category Core Types\n */\nexport type ID = string;\n\n/**\n * Generic callback function type.\n *\n * @typeParam T - Return type of the callback, defaults to void\n *\n * @public\n * @category Core Types\n */\nexport type Callback<T = void> = () => T;\n\n/**\n * Event handler function type.\n *\n * @typeParam T - Type of event data, defaults to any\n *\n * @public\n * @category Core Types\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Generic default allows flexible event handling\nexport type EventHandler<T = any> = (event: T) => void;\n\n/**\n * Utility type to make specific properties optional.\n *\n * @typeParam T - The base type\n * @typeParam K - Keys of T to make optional\n *\n * @public\n * @category Utility Types\n */\nexport type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\n/**\n * Utility type to make specific properties required.\n *\n * @typeParam T - The base type\n * @typeParam K - Keys of T to make required\n *\n * @public\n * @category Utility Types\n */\nexport type Required<T, K extends keyof T> = T & { [P in K]-?: T[P] };\n\n/**\n * Utility type to make all properties deeply readonly.\n *\n * @typeParam T - The type to make deeply readonly\n *\n * @public\n * @category Utility Types\n */\nexport type DeepReadonly<T> = {\n readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];\n};\n\n/**\n * Represents bilingual Korean-English text content.\n *\n * Used throughout the game to provide authentic Korean terminology with English translations,\n * supporting the cultural authenticity of the Korean martial arts theme.\n *\n * @example\n * ```typescript\n * const techniqueName: KoreanText = {\n * korean: \"천둥벽력\",\n * english: \"Thunder Strike\",\n * romanized: \"cheondu byeokryeok\"\n * };\n * ```\n *\n * @public\n * @category Korean Martial Arts\n * @korean 한글텍스트\n */\nexport interface KoreanText {\n /** Korean text in Hangul */\n readonly korean: string;\n /** English translation */\n readonly english: string;\n /** Optional romanized Korean pronunciation */\n readonly romanized?: string;\n}\n\n/**\n * Base entity interface with Korean naming support.\n *\n * Provides a foundation for game entities with bilingual identification.\n *\n * @public\n * @category Korean Martial Arts\n * @korean 한글개체\n */\nexport interface KoreanEntity {\n /** Unique identifier */\n readonly id: ID;\n /** Bilingual name */\n readonly name: KoreanText;\n /** Optional bilingual description */\n readonly description?: KoreanText;\n}\n\n/**\n * Font sizes for Korean text rendering.\n *\n * Provides consistent typography sizing across the game interface.\n *\n * @public\n * @category UI\n * @korean 글자크기\n */\nexport enum KoreanTextSize {\n /** Extra small: 10px */\n XSMALL = \"xsmall\",\n /** Tiny: 12px */\n TINY = \"tiny\",\n /** Small: 14px */\n SMALL = \"small\",\n /** Medium: 16px */\n MEDIUM = \"medium\",\n /** Large: 18px */\n LARGE = \"large\",\n /** Extra large: 20px */\n XLARGE = \"xlarge\",\n /** Double extra large: 24px */\n XXLARGE = \"xxlarge\",\n /** Huge: 32px */\n HUGE = \"huge\",\n /** Title: 48px */\n TITLE = \"title\",\n}\n\n/**\n * Font weights for Korean text rendering.\n *\n * Provides consistent typography weights for Korean Hangul characters.\n *\n * @public\n * @category UI\n * @korean 글자무게\n */\nexport enum KoreanTextWeight {\n /** Light weight: 300 */\n LIGHT = \"light\",\n /** Normal weight: 400 */\n NORMAL = \"normal\",\n /** Regular weight: 400 (alias for NORMAL) */\n REGULAR = \"regular\",\n /** Medium weight: 500 */\n MEDIUM = \"medium\",\n /** Semi-bold weight: 600 */\n SEMIBOLD = \"semibold\",\n /** Bold weight: 700 */\n BOLD = \"bold\",\n /** Heavy weight: 900 */\n HEAVY = \"heavy\",\n}\n\n/**\n * Text alignment options for Korean text.\n *\n * @public\n * @category UI\n */\nexport type KoreanTextAlignment = \"left\" | \"center\" | \"right\";\n\n/**\n * Styling configuration for Korean text rendering.\n *\n * @public\n * @category UI\n * @korean 글자스타일\n */\nexport interface KoreanTextStyle {\n /** Text size */\n readonly size: KoreanTextSize;\n /** Font weight */\n readonly weight: KoreanTextWeight;\n /** Text color as hex number */\n readonly color: number;\n /** Horizontal alignment */\n readonly alignment: KoreanTextAlignment;\n}\n\n/**\n * Represents a range of damage values for combat calculations.\n *\n * Used for techniques and vital point strikes to define variable damage output.\n *\n * @public\n * @category Combat\n * @korean 피해범위\n */\nexport interface DamageRange {\n /** Minimum damage value */\n readonly min: number;\n /** Maximum damage value */\n readonly max: number;\n /** Type of damage dealt */\n readonly type?: DamageType;\n /** Pre-calculated average damage */\n readonly average?: number;\n}\n\n/**\n * Game settings configuration interface for UI controls.\n *\n * Manages volume, graphics quality, control schemes, and language preferences.\n *\n * @public\n * @category UI\n * @korean 게임설정\n */\nexport interface UIGameSettings {\n /** Audio volume settings */\n readonly volume: {\n /** Master volume (0.0 - 1.0) */\n readonly master: number;\n /** Music volume (0.0 - 1.0) */\n readonly music: number;\n /** Sound effects volume (0.0 - 1.0) */\n readonly sfx: number;\n };\n /** Graphics settings */\n readonly graphics: {\n /** Graphics quality preset */\n readonly quality: \"low\" | \"medium\" | \"high\";\n /** Fullscreen mode enabled */\n readonly fullscreen: boolean;\n /** Vertical sync enabled */\n readonly vsync: boolean;\n };\n /** Control settings */\n readonly controls: {\n /** Keyboard layout preference */\n readonly keyboardLayout: \"qwerty\" | \"dvorak\" | \"colemak\";\n /** Mouse sensitivity multiplier */\n readonly mouseSensitivity: number;\n };\n /** Language preference */\n readonly language: \"korean\" | \"english\" | \"both\";\n}\n\n/**\n * Duration tracking for status effects.\n *\n * Tracks when an effect started, when it ends, and its total duration.\n *\n * @public\n * @category Combat\n * @korean 효과지속시간\n */\nexport interface EffectDuration {\n /** Effect start timestamp (milliseconds) */\n readonly startTime: number;\n /** Effect end timestamp (milliseconds) */\n readonly endTime: number;\n /** Total duration (milliseconds) */\n readonly duration: number;\n}\n\n/**\n * Generic game entity with positioning and visibility.\n *\n * Extends {@link KoreanEntity} with spatial and state properties.\n *\n * @public\n * @category Core Types\n * @korean 게임개체\n */\nexport interface GameEntity extends KoreanEntity {\n /** Position in game world */\n readonly position?: Position;\n /** Size dimensions */\n readonly size?: Size;\n /** Whether entity is active */\n readonly active?: boolean;\n /** Whether entity is visible */\n readonly visible?: boolean;\n}\n\n/**\n * Animation transition configuration.\n *\n * Defines how to transition between two states with timing and easing.\n *\n * @public\n * @category UI\n * @korean 전환\n */\nexport interface Transition {\n /** Starting state identifier */\n readonly from: string;\n /** Target state identifier */\n readonly to: string;\n /** Transition duration in milliseconds */\n readonly duration: Duration;\n /** Optional easing function name */\n readonly easing?: string;\n}\n\n/**\n * Theme color configuration.\n *\n * Defines primary colors used throughout the game UI.\n *\n * @public\n * @category UI\n * @korean 테마\n */\nexport interface Theme {\n /** Primary color */\n readonly primary: Color;\n /** Secondary color */\n readonly secondary: Color;\n /** Accent color */\n readonly accent?: Color;\n /** Background color */\n readonly background?: Color;\n /** Text color */\n readonly text?: Color;\n}\n\n/**\n * Generic configuration object.\n *\n * @public\n * @category Core Types\n */\nexport interface Config {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Config values can be of various types\n readonly [key: string]: any;\n}\n\n/**\n * Generic result wrapper for operations that may succeed or fail.\n *\n * @typeParam T - Type of successful result data\n * @typeParam E - Type of error, defaults to Error\n *\n * @example\n * ```typescript\n * const result: Result<PlayerState> = {\n * success: true,\n * data: playerState\n * };\n * ```\n *\n * @public\n * @category Core Types\n */\nexport interface Result<T, E = Error> {\n /** Whether operation succeeded */\n readonly success: boolean;\n /** Result data if successful */\n readonly data?: T;\n /** Error if operation failed */\n readonly error?: E;\n /** Optional message */\n readonly message?: string;\n}\n\n/**\n * Validation result with errors and warnings.\n *\n * @public\n * @category Core Types\n */\nexport interface ValidationResult {\n /** Whether validation passed */\n readonly valid: boolean;\n /** List of validation errors */\n readonly errors: readonly string[];\n /** Optional list of warnings */\n readonly warnings?: readonly string[];\n}\n\n/**\n * Game modes available in Black Trigram.\n *\n * Each mode offers different gameplay experiences and training opportunities.\n *\n * @public\n * @category Game Systems\n * @korean 게임모드\n */\nexport enum GameMode {\n /** Versus mode: Player vs AI or Player vs Player */\n VERSUS = \"versus\",\n /** Training mode: Practice techniques against training dummy */\n TRAINING = \"training\",\n /** Tutorial mode: Learn game mechanics and controls */\n TUTORIAL = \"tutorial\",\n /** Practice mode: Free form combat practice */\n PRACTICE = \"practice\",\n /** Story mode: Campaign with narrative */\n STORY = \"story\",\n /** Arcade mode: Progressive difficulty challenges */\n ARCADE = \"arcade\",\n /** Controls screen: View and customize controls */\n CONTROLS = \"controls\",\n /** Philosophy screen: Learn about Korean martial arts philosophy */\n PHILOSOPHY = \"philosophy\",\n}\n\n/**\n * Game phases representing the current state of the game.\n *\n * Controls which screen is displayed and what game logic is active.\n *\n * @public\n * @category Game Systems\n * @korean 게임단계\n */\nexport enum GamePhase {\n /** Intro/splash screen */\n INTRO = \"intro\",\n /** Main menu */\n MENU = \"menu\",\n /** Character selection screen */\n CHARACTER_SELECT = \"character_select\",\n /** Active combat */\n COMBAT = \"combat\",\n /** Training mode */\n TRAINING = \"training\",\n /** Victory screen */\n VICTORY = \"victory\",\n /** Defeat screen */\n DEFEAT = \"defeat\",\n /** Game paused */\n PAUSED = \"paused\",\n /** Game over screen */\n GAME_OVER = \"game_over\",\n /** Loading screen */\n LOADING = \"loading\",\n}\n\n/**\n * Player archetypes representing Korean martial arts combat specialists.\n *\n * **Korean**: 플레이어 원형 (Player Archetypes)\n *\n * Each archetype has unique combat styles, favored stances, and philosophical approaches\n * rooted in Korean martial arts traditions and modern cyberpunk adaptation.\n *\n * @example\n * ```typescript\n * const player = createPlayer({\n * archetype: PlayerArchetype.MUSA,\n * name: { korean: \"이순신\", english: \"Yi Sun-sin\" }\n * });\n * ```\n *\n * @public\n * @category Player & Archetypes\n * @korean 플레이어원형\n */\nexport enum PlayerArchetype {\n /**\n * 무사 (Musa) - Traditional Warrior\n *\n * Honor-bound martial artist following traditional Korean warrior codes.\n * Favors direct confrontation and disciplined techniques.\n */\n MUSA = \"musa\",\n\n /**\n * 암살자 (Amsalja) - Shadow Assassin\n *\n * Precision striker focused on vital point targeting and silent elimination.\n * Specializes in nerve strikes and pressure point techniques.\n */\n AMSALJA = \"amsalja\",\n\n /**\n * 해커 (Hacker) - Cyber Warrior\n *\n * Technology-enhanced combatant blending modern cybernetics with traditional techniques.\n * Uses augmented reflexes and data-driven combat analysis.\n */\n HACKER = \"hacker\",\n\n /**\n * 정보요원 (Jeongbo Yowon) - Intelligence Operative\n *\n * Strategic analyst who uses combat intelligence and tactical advantage.\n * Excels at reading opponent patterns and exploiting weaknesses.\n */\n JEONGBO_YOWON = \"jeongbo_yowon\",\n\n /**\n * 조직폭력배 (Jojik Pokryeokbae) - Organized Crime\n *\n * Ruthless pragmatist who ignores traditional honor codes.\n * Uses brutal, efficient techniques with no concern for ethics.\n */\n JOJIK_POKRYEOKBAE = \"jojik_pokryeokbae\",\n}\n\n/**\n * Physical attributes representing realistic body dimensions and composition.\n *\n * **Korean**: 신체 속성 (Body Attributes)\n *\n * These attributes affect combat calculations including reach, movement speed,\n * damage output, defense capability, and stamina. Based on realistic human\n * physiology and Korean martial arts biomechanics.\n *\n * ## Combat Impact\n *\n * - **Weight**: Affects movement speed, knockback resistance, and throw effectiveness\n * - **Leg Length**: Determines kick range and movement speed base\n * - **Arm Length**: Determines punch/strike range and grappling reach\n * - **Muscle Mass**: Affects base damage output and stamina pool\n * - **Fat Mass**: Affects defense absorption and stamina drain rate\n * - **Age**: Affects stamina recovery speed and Ki regeneration\n *\n * @example\n * ```typescript\n * const musaPhysical: PhysicalAttributes = {\n * weight: 75, // kg - balanced warrior\n * legLength: 95, // cm - average leg reach\n * armLength: 75, // cm - average arm reach\n * muscleMass: 38, // kg - high muscle for power\n * fatMass: 12, // kg - low fat for mobility\n * age: 32, // years - prime combat age\n * };\n * ```\n *\n * @public\n * @category Player & Archetypes\n * @korean 신체속성\n */\nexport interface PhysicalAttributes {\n /**\n * Body weight in kilograms.\n *\n * **Korean**: 체중 (Body Weight)\n *\n * Typical Range: 55-95 kg for combatants\n * - Affects movement speed (inversely)\n * - Affects knockback resistance (positively)\n * - Affects throw effectiveness (positively)\n * - Affects ground control (positively)\n */\n readonly weight: number;\n\n /**\n * Leg length in centimeters (hip to ankle).\n *\n * **Korean**: 다리 길이 (Leg Length)\n *\n * Typical Range: 85-105 cm\n * - Determines kick technique maximum range\n * - Affects base movement speed\n * - Affects sweep technique effectiveness\n * - Affects jumping attack height\n */\n readonly legLength: number;\n\n /**\n * Arm length in centimeters (shoulder to wrist).\n *\n * **Korean**: 팔 길이 (Arm Length)\n *\n * Typical Range: 65-85 cm\n * - Determines punch/strike technique range\n * - Affects grappling and throw range\n * - Affects block coverage area\n * - Affects elbow strike effectiveness\n */\n readonly armLength: number;\n\n /**\n * Muscle mass in kilograms.\n *\n * **Korean**: 근육량 (Muscle Mass)\n *\n * Typical Range: 25-45 kg\n * - Affects base damage output (positively)\n * - Affects maximum stamina pool (positively)\n * - Affects grappling and throw power\n * - Affects movement acceleration\n */\n readonly muscleMass: number;\n\n /**\n * Fat mass in kilograms.\n *\n * **Korean**: 지방량 (Fat Mass)\n *\n * Typical Range: 8-20 kg for combatants\n * - Affects blunt damage absorption (positively)\n * - Affects stamina drain rate (negatively)\n * - Affects movement speed (negatively)\n * - Affects recovery time between actions\n */\n readonly fatMass: number;\n\n /**\n * Age in years.\n *\n * **Korean**: 나이 (Age)\n *\n * Typical Range: 22-45 years for peak combatants\n * - Affects stamina recovery speed (optimal 25-35)\n * - Affects Ki regeneration rate (wisdom with age)\n * - Affects injury recovery time (slower with age)\n * - Affects technique execution speed (prime 28-35)\n */\n readonly age: number;\n\n /**\n * Total body height in centimeters.\n *\n * **Korean**: 키 (Height)\n *\n * Typical Range: 160-195 cm\n * - Scales entire skeleton proportionally\n * - Affects reach calculations (combined with limb ratios)\n * - Affects center of gravity positioning\n * - Determines visual body model scaling\n * - Influences balance and stability in stances\n */\n readonly totalHeight: number;\n\n /**\n * Torso length in centimeters (pelvis to shoulders).\n *\n * **Korean**: 몸통 길이 (Torso Length)\n *\n * Typical Range: 50-65 cm\n * - Affects core hitbox size and vital point positioning\n * - Influences breath control and stamina capacity\n * - Affects spinal rotation range in techniques\n * - Determines torso vital point target area\n * - Impacts center of mass calculations\n */\n readonly torsoLength: number;\n\n /**\n * Head size (diameter) in centimeters.\n *\n * **Korean**: 머리 크기 (Head Size)\n *\n * Typical Range: 20-24 cm\n * - Affects head vital point targeting precision\n * - Determines head hitbox size for strikes\n * - Influences helmet/headgear fit (if applicable)\n * - Affects visual skull scaling in 3D model\n * - Impacts consciousness vulnerability to head trauma\n */\n readonly headSize: number;\n\n /**\n * Neck length in centimeters (skull base to shoulders).\n *\n * **Korean**: 목 길이 (Neck Length)\n *\n * Typical Range: 8-12 cm\n * - Affects vulnerability to chokes and strangles\n * - Determines neck vital point target area\n * - Influences blood choke effectiveness\n * - Affects guillotine and rear naked choke mechanics\n * - Impacts head mobility and evasion capability\n */\n readonly neckLength: number;\n\n /**\n * Shoulder width in centimeters (shoulder to shoulder).\n *\n * **Korean**: 어깨 너비 (Shoulder Width)\n *\n * Typical Range: 38-48 cm\n * - Affects defense coverage area (blocking)\n * - Determines upper body strike zone width\n * - Influences grappling control positions\n * - Affects visual upper body model scaling\n * - Impacts balance and stability in wide stances\n */\n readonly shoulderWidth: number;\n\n /**\n * Base walking speed in meters per second.\n *\n * **Korean**: 걷기 속도 (Walk Speed)\n *\n * Typical Range: 5.0-6.5 m/s for combat movement\n * - Determines tactical repositioning speed\n * - Affected by weight and leg length\n * - Base speed for defensive movement\n * - Modified by stance and combat state\n */\n readonly walkSpeed: number;\n\n /**\n * Base running speed in meters per second.\n *\n * **Korean**: 달리기 속도 (Run Speed)\n *\n * Typical Range: 8.0-11.0 m/s for sprint movement\n * - Determines rapid repositioning speed\n * - Affected by muscle mass and conditioning\n * - Base speed for aggressive approach\n * - Consumes stamina during use\n */\n readonly runSpeed: number;\n\n /**\n * Base acceleration in meters per second squared.\n *\n * **Korean**: 가속도 (Acceleration)\n *\n * Typical Range: 9.0-15.0 m/s² for combat movement\n * - Determines how quickly fighter reaches max speed\n * - Based on muscle-to-weight ratio (explosiveness)\n * - Higher = more explosive starts and direction changes\n * - Affects combat responsiveness and evasion\n */\n readonly acceleration: number;\n}\n\n/**\n * Eight Trigram stances (팔괘) representing fundamental combat principles.\n *\n * **Korean**: 팔괘 자세 (Eight Trigram Stances)\n * **Origin**: I Ching (易經 / Yijing) divination system adapted for Korean martial arts\n *\n * The Eight Trigrams (Bagua / 八卦) form the foundation of the combat system.\n * Each trigram represents a natural element and combat philosophy, influencing\n * available techniques, movement patterns, and strategic advantages.\n *\n * ## Trigram Philosophy\n *\n * - **☰ 건 (Geon)** - Heaven: Yang energy, direct aggression, overwhelming force\n * - **☱ 태 (Tae)** - Lake: Joy and fluidity, joint locks and flow techniques\n * - **☲ 리 (Li)** - Fire: Precision and speed, nerve strikes and rapid attacks\n * - **☳ 진 (Jin)** - Thunder: Explosive power, shocking techniques\n * - **☴ 손 (Son)** - Wind: Continuous pressure, evasion and mobility\n * - **☵ 감 (Gam)** - Water: Adaptive flow, counters and redirection\n * - **☶ 간 (Gan)** - Mountain: Immovable defense, endurance and patience\n * - **☷ 곤 (Gon)** - Earth: Grounding techniques, takedowns and throws\n *\n * @example\n * ```typescript\n * // Change to Heaven stance for aggressive attack\n * player.currentStance = TrigramStance.GEON;\n *\n * // Execute heaven-aligned technique\n * const technique = getTrigramTechniques(TrigramStance.GEON)[0];\n * executeTechnique(player, opponent, technique);\n * ```\n *\n * @see {@link https://en.wikipedia.org/wiki/Bagua | Bagua (Eight Trigrams) - Wikipedia}\n * @see {@link https://en.wikipedia.org/wiki/I_Ching | I Ching - Wikipedia}\n *\n * @public\n * @category Trigram System\n * @category Korean Martial Arts\n * @korean 팔괘\n */\nexport enum TrigramStance {\n /**\n * ☰ 건 (Geon) - Heaven Stance\n *\n * **Element**: Heaven / Sky (天)\n * **Nature**: Yang, creative, strong\n * **Combat Style**: Direct force, aggressive techniques, overwhelming power\n * **Philosophy**: \"The creative principle - pure yang energy that drives forward\"\n *\n * Techniques emphasize straight attacks, powerful strikes, and dominant positioning.\n */\n GEON = \"geon\",\n\n /**\n * ☱ 태 (Tae) - Lake Stance\n *\n * **Element**: Lake / Marsh (澤)\n * **Nature**: Yin exterior, Yang interior - joyful movement\n * **Combat Style**: Fluid joint manipulation, flowing techniques, adaptable responses\n * **Philosophy**: \"The joyful - water above earth, freedom of movement\"\n *\n * Techniques focus on joint locks, throws, and using opponent's momentum.\n */\n TAE = \"tae\",\n\n /**\n * ☲ 리 (Li) - Fire Stance\n *\n * **Element**: Fire / Flame (火)\n * **Nature**: Yang exterior, Yin interior - bright and precise\n * **Combat Style**: Precise nerve strikes, rapid attacks, speed techniques\n * **Philosophy**: \"The clinging - illuminating and consuming\"\n *\n * Techniques emphasize vital point targeting, quick combinations, and precision.\n */\n LI = \"li\",\n\n /**\n * ☳ 진 (Jin) - Thunder Stance\n *\n * **Element**: Thunder / Arousing (雷)\n * **Nature**: Yang moving, sudden and shocking\n * **Combat Style**: Explosive power, shocking techniques, sudden movements\n * **Philosophy**: \"The arousing - thunder brings shock and awakening\"\n *\n * Techniques feature explosive bursts, stunning strikes, and overwhelming force.\n */\n JIN = \"jin\",\n\n /**\n * ☴ 손 (Son) - Wind Stance\n *\n * **Element**: Wind / Wood (風)\n * **Nature**: Yin, gentle but penetrating\n * **Combat Style**: Continuous pressure, evasion techniques, mobility\n * **Philosophy**: \"The gentle - penetrating like wind, persistent like wood\"\n *\n * Techniques emphasize movement, pressure point chains, and wearing down opponents.\n */\n SON = \"son\",\n\n /**\n * ☵ 감 (Gam) - Water Stance\n *\n * **Element**: Water / Abyss (水)\n * **Nature**: Yang surrounded by Yin - dangerous depths\n * **Combat Style**: Flow and adaptation, counter techniques, redirection\n * **Philosophy**: \"The abysmal - water flows around obstacles and fills voids\"\n *\n * Techniques focus on counters, deflections, and adaptive responses.\n */\n GAM = \"gam\",\n\n /**\n * ☶ 간 (Gan) - Mountain Stance\n *\n * **Element**: Mountain / Stillness (山)\n * **Nature**: Yang above Yin - firm and unyielding\n * **Combat Style**: Defensive mastery, immovable stance, endurance\n * **Philosophy**: \"The keeping still - mountains are firm and unmoving\"\n *\n * Techniques emphasize blocks, parries, and defensive positioning.\n */\n GAN = \"gan\",\n\n /**\n * ☷ 곤 (Gon) - Earth Stance\n *\n * **Element**: Earth / Receptive (地)\n * **Nature**: Pure Yin - receptive and yielding\n * **Combat Style**: Grounding techniques, takedowns, throws\n * **Philosophy**: \"The receptive - earth receives and supports all\"\n *\n * Techniques focus on sweeps, trips, takedowns, and ground control.\n */\n GON = \"gon\",\n}\n\n/**\n * Combat attack types available in the game.\n *\n * Defines the mechanical type of attack being performed, which affects\n * damage calculation, vital point targeting, and defensive options.\n *\n * @public\n * @category Combat System\n * @korean 공격타입\n */\nexport enum CombatAttackType {\n /** Standard striking attack */\n STRIKE = \"strike\",\n /** Thrusting attack with focused force */\n THRUST = \"thrust\",\n /** Defensive blocking action */\n BLOCK = \"block\",\n /** Counter-attack performed after successful defense */\n COUNTER_ATTACK = \"counter_attack\",\n /** Throwing technique to off-balance opponent */\n THROW = \"throw\",\n /** Grappling and joint control technique */\n GRAPPLE = \"grapple\",\n /** Precise pressure point strike */\n PRESSURE_POINT = \"pressure_point\",\n /** Nerve disruption strike */\n NERVE_STRIKE = \"nerve_strike\",\n /** Closed fist punch */\n PUNCH = \"punch\",\n /** Leg kick attack */\n KICK = \"kick\",\n /** Elbow strike */\n ELBOW = \"elbow\",\n /** Knee strike */\n KNEE = \"knee\",\n}\n\n/**\n * Damage types representing different methods of inflicting harm.\n *\n * Each damage type interacts differently with vital points and defensive techniques.\n * Some types are more effective against specific body regions or defense styles.\n *\n * @public\n * @category Combat System\n * @korean 피해타입\n */\nexport enum DamageType {\n /** Blunt force trauma */\n BLUNT = \"blunt\",\n /** Piercing damage penetrating tissue */\n PIERCING = \"piercing\",\n /** Slashing cuts */\n SLASHING = \"slashing\",\n /** Pressure point manipulation */\n PRESSURE = \"pressure\",\n /** Nerve disruption */\n NERVE = \"nerve\",\n /** Joint manipulation and locks */\n JOINT = \"joint\",\n /** Internal organ damage */\n INTERNAL = \"internal\",\n /** Impact shock */\n IMPACT = \"impact\",\n /** Crushing force */\n CRUSHING = \"crushing\",\n /** Sharp edge damage */\n SHARP = \"sharp\",\n /** Electric shock */\n ELECTRIC = \"electric\",\n /** Fire/heat damage */\n FIRE = \"fire\",\n /** Cold/freeze damage */\n ICE = \"ice\",\n /** Poison/toxin damage */\n POISON = \"poison\",\n /** Psychic/mental damage */\n PSYCHIC = \"psychic\",\n /** Blood loss damage */\n BLOOD = \"blood\",\n}\n\n/**\n * Vital point categories representing anatomical targeting systems.\n *\n * **Korean**: 급소 범주 (Vital Point Categories)\n *\n * The game features 70 Korean vital points (급소) based on traditional martial arts\n * knowledge and modern anatomical understanding. Each category represents different\n * physiological systems that can be targeted for combat effectiveness.\n *\n * @example\n * ```typescript\n * const vitalPoint: VitalPoint = {\n * id: \"GB-20\",\n * category: VitalPointCategory.NEUROLOGICAL,\n * severity: VitalPointSeverity.CRITICAL,\n * name: { korean: \"풍지\", english: \"Wind Pool\" }\n * };\n * ```\n *\n * @public\n * @category Vital Point System\n * @korean 급소범주\n */\nexport enum VitalPointCategory {\n /** Neurological system - nerve clusters and neural pathways */\n NEUROLOGICAL = \"neurological\",\n /** Vascular system - major blood vessels and circulation */\n VASCULAR = \"vascular\",\n /** Respiratory system - airways and breathing mechanisms */\n RESPIRATORY = \"respiratory\",\n /** Muscular system - muscle groups and tendons */\n MUSCULAR = \"muscular\",\n /** Skeletal system - bones and structural supports */\n SKELETAL = \"skeletal\",\n /** Organ system - internal organs */\n ORGAN = \"organ\",\n /** Circulatory system - heart and blood flow */\n CIRCULATORY = \"circulatory\",\n /** Lymphatic system - lymph nodes and immune response */\n LYMPHATIC = \"lymphatic\",\n /** Endocrine system - hormonal glands */\n ENDOCRINE = \"endocrine\",\n /** Joint system - articulation points */\n JOINT = \"joint\",\n /** Nerve system - peripheral nerves */\n NERVE = \"nerve\",\n /** Pressure system - pressure-sensitive areas */\n PRESSURE = \"pressure\",\n}\n\n/**\n * Vital point severity levels indicating potential impact.\n *\n * Determines the damage multiplier and status effects applied when\n * a vital point is successfully struck.\n *\n * ## Severity Guidelines\n *\n * - **MINOR**: 1.1-1.3x damage, temporary discomfort\n * - **MODERATE**: 1.5-2.0x damage, brief incapacitation\n * - **MAJOR**: 2.5-3.5x damage, significant impairment\n * - **CRITICAL**: 4.0-5.0x damage, severe trauma\n * - **LETHAL**: 6.0-10.0x damage, immediate incapacitation\n *\n * @public\n * @category Vital Point System\n * @korean 급소심각도\n */\nexport enum VitalPointSeverity {\n /** Minor impact - temporary pain or discomfort */\n MINOR = \"minor\",\n /** Moderate impact - brief stunning or reduced effectiveness */\n MODERATE = \"moderate\",\n /** Major impact - significant damage and impairment */\n MAJOR = \"major\",\n /** Critical impact - severe trauma requiring immediate response */\n CRITICAL = \"critical\",\n /** Lethal impact - immediate incapacitation or death */\n LETHAL = \"lethal\",\n}\n\n/**\n * Status effects that can result from vital point strikes.\n *\n * Each effect type represents a physiological response to targeting\n * specific anatomical structures. Effects stack and interact with\n * combat mechanics.\n *\n * @public\n * @category Vital Point System\n * @korean 급소효과\n */\nexport enum VitalPointEffectType {\n /** Loss of consciousness */\n UNCONSCIOUSNESS = \"unconsciousness\",\n /** Inability to breathe properly */\n BREATHLESSNESS = \"breathlessness\",\n /** Intense pain reducing combat effectiveness */\n PAIN = \"pain\",\n /** Temporary or permanent paralysis */\n PARALYSIS = \"paralysis\",\n /** Brief stunning preventing action */\n STUN = \"stun\",\n /** Reduced strength and effectiveness */\n WEAKNESS = \"weakness\",\n /** Confusion and impaired targeting */\n DISORIENTATION = \"disorientation\",\n /** Restricted blood flow to area */\n BLOOD_FLOW_RESTRICTION = \"blood_flow_restriction\",\n /** Nerve pathway interruption */\n NERVE_DISRUPTION = \"nerve_disruption\",\n /** Internal organ malfunction */\n ORGAN_DISRUPTION = \"organ_disruption\",\n}\n\n/**\n * Combat states representing the current action phase of a fighter.\n *\n * Determines available actions, defensive capabilities, and animation states.\n * State transitions follow combat flow logic and timing windows.\n *\n * @public\n * @category Combat System\n * @korean 전투상태\n */\nexport enum CombatState {\n /** Neutral state, all actions available */\n IDLE = \"idle\",\n /** Executing an attack, vulnerable to counters */\n ATTACKING = \"attacking\",\n /** In defensive stance, reduced offensive capability */\n DEFENDING = \"defending\",\n /** Temporarily incapacitated, cannot act */\n STUNNED = \"stunned\",\n /** Recovering from action, limited options */\n RECOVERING = \"recovering\",\n /** Executing a counter-attack */\n COUNTERING = \"countering\",\n /** Transitioning between stances */\n TRANSITIONING = \"transitioning\",\n /** Grappling/controlling opponent */\n GRAPPLING = \"grappling\",\n /** Being grappled/controlled */\n GRAPPLED = \"grappled\",\n}\n\n/**\n * Body regions for anatomical targeting in combat.\n *\n * Each region contains multiple vital points and has different\n * defensive properties and vulnerability profiles.\n *\n * @public\n * @category Combat System\n * @korean 신체부위\n */\nexport enum BodyRegion {\n /** Head region - contains critical neurological targets */\n HEAD = \"head\",\n /** Neck region - contains vascular and respiratory targets */\n NECK = \"neck\",\n /** Torso region - contains organ targets */\n TORSO = \"torso\",\n /** Left arm region - contains nerve and joint targets */\n LEFT_ARM = \"left_arm\",\n /** Right arm region - contains nerve and joint targets */\n RIGHT_ARM = \"right_arm\",\n /** Left leg region - contains structural and mobility targets */\n LEFT_LEG = \"left_leg\",\n /** Right leg region - contains structural and mobility targets */\n RIGHT_LEG = \"right_leg\",\n /** Core/center region - contains balance and power centers */\n CORE = \"core\",\n}\n\n/**\n * Grappling state representing control and hold status.\n *\n * **Korean**: 잡기 상태 (Grapple State)\n *\n * Tracks the current phase of a grappling exchange based on Hapkido\n * and Ssireum techniques. State transitions follow realistic grappling\n * flow where control must be established before manipulation.\n *\n * @public\n * @category Combat System\n * @korean 잡기상태\n */\nexport enum GrappleState {\n /** Not in grapple - normal combat */\n NONE = \"none\",\n /** Initiating grab attempt */\n GRABBING = \"grabbing\",\n /** Successfully controlling opponent */\n CONTROLLING = \"controlling\",\n /** Attempting to escape control */\n ESCAPING = \"escaping\",\n /** Transitioning to throw or takedown */\n THROWING = \"throwing\",\n /** Applying joint lock technique */\n LOCKING = \"locking\",\n}\n\n/**\n * Target for grappling techniques.\n *\n * **Korean**: 잡기 목표 (Grapple Target)\n *\n * Specifies which body part is being controlled in a grapple.\n * Different targets allow different follow-up techniques and\n * have different escape difficulties.\n *\n * @public\n * @category Combat System\n * @korean 잡기목표\n */\nexport enum GrappleTarget {\n /** Hand/wrist control - 손목잡기 */\n HAND = \"hand\",\n /** Arm control - 팔잡기 */\n ARM = \"arm\",\n /** Leg control - 다리잡기 */\n LEG = \"leg\",\n /** Torso/body control - 몸통잡기 */\n TORSO = \"torso\",\n /** Neck control - 목잡기 */\n NECK = \"neck\",\n /** Both arms control - 양팔잡기 */\n BOTH_ARMS = \"both_arms\",\n}\n\n/**\n * Grappling control information.\n *\n * **Korean**: 잡기 제어 (Grapple Control)\n *\n * Tracks active grappling state between combatants, including\n * control duration, grip strength, and target limb.\n *\n * @public\n * @category Combat System\n * @korean 잡기제어\n */\nexport interface GrappleControl {\n /** Current grapple state */\n readonly state: GrappleState;\n /** Body part being controlled */\n readonly target: GrappleTarget;\n /** ID of controlling player */\n readonly controllerId: string;\n /** ID of controlled player */\n readonly targetId: string;\n /** Grip strength (0-100) affecting escape difficulty */\n readonly gripStrength: number;\n /** Duration of control in milliseconds */\n readonly duration: number;\n /** Timestamp when grapple was initiated */\n readonly startTime: number;\n /** Whether control can be broken this frame */\n readonly canEscape: boolean;\n /** Stamina cost per second to maintain control */\n readonly staminaCostPerSecond: number;\n}\n\nexport default {};\n"],"mappings":"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"}
1
+ {"version":3,"file":"common.js","names":[],"sources":["../../src/types/common.ts"],"sourcesContent":["/**\n * Common utility types for Korean martial arts game.\n *\n * This module provides foundational types used throughout the Black Trigram (흑괘) game,\n * including geometric types, Korean text support, and utility type helpers.\n *\n * @module types/common\n * @category Type Definitions\n * @korean 공통타입\n */\n\n/**\n * Represents a position in 2D space.\n *\n * **Unit Handling**: The coordinate units depend on the system using this type:\n * - **Combat System**: Coordinates are in **meters** (physics-first architecture)\n * - **Rendering System**: Coordinates are in **pixels** (screen rendering)\n * - **Legacy Systems**: May use pixels or other units\n *\n * When working with combat/physics, positions are in meters relative to arena center (0, 0).\n * Arena boundaries extend from ±worldWidthMeters/2 in X and ±worldDepthMeters/2 in Z (mapped to y).\n *\n * @example\n * ```typescript\n * // Combat position (meters, centered at origin)\n * const playerPos: Position = { x: 2.5, y: -1.0 }; // 2.5m right, 1m back from center\n *\n * // Rendering position (pixels, top-left origin)\n * const screenPos: Position = { x: 640, y: 480 }; // 640px right, 480px down\n * ```\n *\n * @public\n * @category Core Types\n */\nexport interface Position {\n /** X coordinate (meters in combat, pixels in rendering) */\n x: number;\n /** Y coordinate (meters in combat, pixels in rendering) */\n y: number;\n}\n\n/**\n * Represents size dimensions for game objects.\n *\n * @public\n * @category Core Types\n */\nexport interface Size {\n /** Width in pixels */\n readonly width: number;\n /** Height in pixels */\n readonly height: number;\n}\n\n/**\n * Represents rectangle bounds combining position and size.\n *\n * @public\n * @category Core Types\n */\nexport interface Bounds extends Position, Size {}\n\n/**\n * Color represented as a hexadecimal number (e.g., 0xFF0000 for red).\n *\n * @example\n * ```typescript\n * const primaryCyan: Color = 0x00FFFF;\n * const accentGold: Color = 0xFFAA00;\n * ```\n *\n * @public\n * @category Core Types\n */\nexport type Color = number;\n\n/**\n * Time duration in milliseconds.\n *\n * @public\n * @category Core Types\n */\nexport type Duration = number;\n\n/**\n * Percentage value represented as a decimal (0.0 to 1.0).\n *\n * @example\n * ```typescript\n * const halfHealth: Percentage = 0.5;\n * const fullAccuracy: Percentage = 1.0;\n * ```\n *\n * @public\n * @category Core Types\n */\nexport type Percentage = number;\n\n/**\n * Unique identifier string.\n *\n * @public\n * @category Core Types\n */\nexport type ID = string;\n\n/**\n * Generic callback function type.\n *\n * @typeParam T - Return type of the callback, defaults to void\n *\n * @public\n * @category Core Types\n */\nexport type Callback<T = void> = () => T;\n\n/**\n * Event handler function type.\n *\n * @typeParam T - Type of event data, defaults to any\n *\n * @public\n * @category Core Types\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- Generic default allows flexible event handling\nexport type EventHandler<T = any> = (event: T) => void;\n\n/**\n * Utility type to make specific properties optional.\n *\n * @typeParam T - The base type\n * @typeParam K - Keys of T to make optional\n *\n * @public\n * @category Utility Types\n */\nexport type Optional<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;\n\n/**\n * Utility type to make specific properties required.\n *\n * @typeParam T - The base type\n * @typeParam K - Keys of T to make required\n *\n * @public\n * @category Utility Types\n */\nexport type Required<T, K extends keyof T> = T & { [P in K]-?: T[P] };\n\n/**\n * Utility type to make all properties deeply readonly.\n *\n * @typeParam T - The type to make deeply readonly\n *\n * @public\n * @category Utility Types\n */\nexport type DeepReadonly<T> = {\n readonly [P in keyof T]: T[P] extends object ? DeepReadonly<T[P]> : T[P];\n};\n\n/**\n * Represents bilingual Korean-English text content.\n *\n * Used throughout the game to provide authentic Korean terminology with English translations,\n * supporting the cultural authenticity of the Korean martial arts theme.\n *\n * @example\n * ```typescript\n * const techniqueName: KoreanText = {\n * korean: \"천둥벽력\",\n * english: \"Thunder Strike\",\n * romanized: \"cheondu byeokryeok\"\n * };\n * ```\n *\n * @public\n * @category Korean Martial Arts\n * @korean 한글텍스트\n */\nexport interface KoreanText {\n /** Korean text in Hangul */\n readonly korean: string;\n /** English translation */\n readonly english: string;\n /** Optional romanized Korean pronunciation */\n readonly romanized?: string;\n}\n\n/**\n * Base entity interface with Korean naming support.\n *\n * Provides a foundation for game entities with bilingual identification.\n *\n * @public\n * @category Korean Martial Arts\n * @korean 한글개체\n */\nexport interface KoreanEntity {\n /** Unique identifier */\n readonly id: ID;\n /** Bilingual name */\n readonly name: KoreanText;\n /** Optional bilingual description */\n readonly description?: KoreanText;\n}\n\n/**\n * Font sizes for Korean text rendering.\n *\n * Provides consistent typography sizing across the game interface.\n *\n * @public\n * @category UI\n * @korean 글자크기\n */\nexport enum KoreanTextSize {\n /** Extra small: 10px */\n XSMALL = \"xsmall\",\n /** Tiny: 12px */\n TINY = \"tiny\",\n /** Small: 14px */\n SMALL = \"small\",\n /** Medium: 16px */\n MEDIUM = \"medium\",\n /** Large: 18px */\n LARGE = \"large\",\n /** Extra large: 20px */\n XLARGE = \"xlarge\",\n /** Double extra large: 24px */\n XXLARGE = \"xxlarge\",\n /** Huge: 32px */\n HUGE = \"huge\",\n /** Title: 48px */\n TITLE = \"title\",\n}\n\n/**\n * Font weights for Korean text rendering.\n *\n * Provides consistent typography weights for Korean Hangul characters.\n *\n * @public\n * @category UI\n * @korean 글자무게\n */\nexport enum KoreanTextWeight {\n /** Light weight: 300 */\n LIGHT = \"light\",\n /** Normal weight: 400 */\n NORMAL = \"normal\",\n /** Regular weight: 400 (alias for NORMAL) */\n REGULAR = \"regular\",\n /** Medium weight: 500 */\n MEDIUM = \"medium\",\n /** Semi-bold weight: 600 */\n SEMIBOLD = \"semibold\",\n /** Bold weight: 700 */\n BOLD = \"bold\",\n /** Heavy weight: 900 */\n HEAVY = \"heavy\",\n}\n\n/**\n * Text alignment options for Korean text.\n *\n * @public\n * @category UI\n */\nexport type KoreanTextAlignment = \"left\" | \"center\" | \"right\";\n\n/**\n * Styling configuration for Korean text rendering.\n *\n * @public\n * @category UI\n * @korean 글자스타일\n */\nexport interface KoreanTextStyle {\n /** Text size */\n readonly size: KoreanTextSize;\n /** Font weight */\n readonly weight: KoreanTextWeight;\n /** Text color as hex number */\n readonly color: number;\n /** Horizontal alignment */\n readonly alignment: KoreanTextAlignment;\n}\n\n/**\n * Represents a range of damage values for combat calculations.\n *\n * Used for techniques and vital point strikes to define variable damage output.\n *\n * @public\n * @category Combat\n * @korean 피해범위\n */\nexport interface DamageRange {\n /** Minimum damage value */\n readonly min: number;\n /** Maximum damage value */\n readonly max: number;\n /** Type of damage dealt */\n readonly type?: DamageType;\n /** Pre-calculated average damage */\n readonly average?: number;\n}\n\n/**\n * Game settings configuration interface for UI controls.\n *\n * Manages volume, graphics quality, control schemes, and language preferences.\n *\n * @public\n * @category UI\n * @korean 게임설정\n */\nexport interface UIGameSettings {\n /** Audio volume settings */\n readonly volume: {\n /** Master volume (0.0 - 1.0) */\n readonly master: number;\n /** Music volume (0.0 - 1.0) */\n readonly music: number;\n /** Sound effects volume (0.0 - 1.0) */\n readonly sfx: number;\n };\n /** Graphics settings */\n readonly graphics: {\n /** Graphics quality preset */\n readonly quality: \"low\" | \"medium\" | \"high\";\n /** Fullscreen mode enabled */\n readonly fullscreen: boolean;\n /** Vertical sync enabled */\n readonly vsync: boolean;\n };\n /** Control settings */\n readonly controls: {\n /** Keyboard layout preference */\n readonly keyboardLayout: \"qwerty\" | \"dvorak\" | \"colemak\";\n /** Mouse sensitivity multiplier */\n readonly mouseSensitivity: number;\n };\n /** Language preference */\n readonly language: \"korean\" | \"english\" | \"both\";\n}\n\n/**\n * Duration tracking for status effects.\n *\n * Tracks when an effect started, when it ends, and its total duration.\n *\n * @public\n * @category Combat\n * @korean 효과지속시간\n */\nexport interface EffectDuration {\n /** Effect start timestamp (milliseconds) */\n readonly startTime: number;\n /** Effect end timestamp (milliseconds) */\n readonly endTime: number;\n /** Total duration (milliseconds) */\n readonly duration: number;\n}\n\n/**\n * Generic game entity with positioning and visibility.\n *\n * Extends {@link KoreanEntity} with spatial and state properties.\n *\n * @public\n * @category Core Types\n * @korean 게임개체\n */\nexport interface GameEntity extends KoreanEntity {\n /** Position in game world */\n readonly position?: Position;\n /** Size dimensions */\n readonly size?: Size;\n /** Whether entity is active */\n readonly active?: boolean;\n /** Whether entity is visible */\n readonly visible?: boolean;\n}\n\n/**\n * Animation transition configuration.\n *\n * Defines how to transition between two states with timing and easing.\n *\n * @public\n * @category UI\n * @korean 전환\n */\nexport interface Transition {\n /** Starting state identifier */\n readonly from: string;\n /** Target state identifier */\n readonly to: string;\n /** Transition duration in milliseconds */\n readonly duration: Duration;\n /** Optional easing function name */\n readonly easing?: string;\n}\n\n/**\n * Theme color configuration.\n *\n * Defines primary colors used throughout the game UI.\n *\n * @public\n * @category UI\n * @korean 테마\n */\nexport interface Theme {\n /** Primary color */\n readonly primary: Color;\n /** Secondary color */\n readonly secondary: Color;\n /** Accent color */\n readonly accent?: Color;\n /** Background color */\n readonly background?: Color;\n /** Text color */\n readonly text?: Color;\n}\n\n/**\n * Generic configuration object.\n *\n * @public\n * @category Core Types\n */\nexport interface Config {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any -- Config values can be of various types\n readonly [key: string]: any;\n}\n\n/**\n * Generic result wrapper for operations that may succeed or fail.\n *\n * @typeParam T - Type of successful result data\n * @typeParam E - Type of error, defaults to Error\n *\n * @example\n * ```typescript\n * const result: Result<PlayerState> = {\n * success: true,\n * data: playerState\n * };\n * ```\n *\n * @public\n * @category Core Types\n */\nexport interface Result<T, E = Error> {\n /** Whether operation succeeded */\n readonly success: boolean;\n /** Result data if successful */\n readonly data?: T;\n /** Error if operation failed */\n readonly error?: E;\n /** Optional message */\n readonly message?: string;\n}\n\n/**\n * Validation result with errors and warnings.\n *\n * @public\n * @category Core Types\n */\nexport interface ValidationResult {\n /** Whether validation passed */\n readonly valid: boolean;\n /** List of validation errors */\n readonly errors: readonly string[];\n /** Optional list of warnings */\n readonly warnings?: readonly string[];\n}\n\n/**\n * Game modes available in Black Trigram.\n *\n * Each mode offers different gameplay experiences and training opportunities.\n *\n * @public\n * @category Game Systems\n * @korean 게임모드\n */\nexport enum GameMode {\n /** Versus mode: Player vs AI or Player vs Player */\n VERSUS = \"versus\",\n /** Training mode: Practice techniques against training dummy */\n TRAINING = \"training\",\n /** Tutorial mode: Learn game mechanics and controls */\n TUTORIAL = \"tutorial\",\n /** Practice mode: Free form combat practice */\n PRACTICE = \"practice\",\n /** Story mode: Campaign with narrative */\n STORY = \"story\",\n /** Arcade mode: Progressive difficulty challenges */\n ARCADE = \"arcade\",\n /** Controls screen: View and customize controls */\n CONTROLS = \"controls\",\n /** Philosophy screen: Learn about Korean martial arts philosophy */\n PHILOSOPHY = \"philosophy\",\n}\n\n/**\n * Game phases representing the current state of the game.\n *\n * Controls which screen is displayed and what game logic is active.\n *\n * @public\n * @category Game Systems\n * @korean 게임단계\n */\nexport enum GamePhase {\n /** Intro/splash screen */\n INTRO = \"intro\",\n /** Main menu */\n MENU = \"menu\",\n /** Character selection screen */\n CHARACTER_SELECT = \"character_select\",\n /** Active combat */\n COMBAT = \"combat\",\n /** Training mode */\n TRAINING = \"training\",\n /** Victory screen */\n VICTORY = \"victory\",\n /** Defeat screen */\n DEFEAT = \"defeat\",\n /** Game paused */\n PAUSED = \"paused\",\n /** Game over screen */\n GAME_OVER = \"game_over\",\n /** Loading screen */\n LOADING = \"loading\",\n}\n\n/**\n * Player archetypes representing Korean martial arts combat specialists.\n *\n * **Korean**: 플레이어 원형 (Player Archetypes)\n *\n * Each archetype has unique combat styles, favored stances, and philosophical approaches\n * rooted in Korean martial arts traditions and modern cyberpunk adaptation.\n *\n * @example\n * ```typescript\n * const player = createPlayer({\n * archetype: PlayerArchetype.MUSA,\n * name: { korean: \"이순신\", english: \"Yi Sun-sin\" }\n * });\n * ```\n *\n * @public\n * @category Player & Archetypes\n * @korean 플레이어원형\n */\nexport enum PlayerArchetype {\n /**\n * 무사 (Musa) - Traditional Warrior\n *\n * Honor-bound martial artist following traditional Korean warrior codes.\n * Favors direct confrontation and disciplined techniques.\n */\n MUSA = \"musa\",\n\n /**\n * 암살자 (Amsalja) - Shadow Assassin\n *\n * Precision striker focused on vital point targeting and silent elimination.\n * Specializes in nerve strikes and pressure point techniques.\n */\n AMSALJA = \"amsalja\",\n\n /**\n * 해커 (Hacker) - Cyber Warrior\n *\n * Technology-enhanced combatant blending modern cybernetics with traditional techniques.\n * Uses augmented reflexes and data-driven combat analysis.\n */\n HACKER = \"hacker\",\n\n /**\n * 정보요원 (Jeongbo Yowon) - Intelligence Operative\n *\n * Strategic analyst who uses combat intelligence and tactical advantage.\n * Excels at reading opponent patterns and exploiting weaknesses.\n */\n JEONGBO_YOWON = \"jeongbo_yowon\",\n\n /**\n * 조직폭력배 (Jojik Pokryeokbae) - Organized Crime\n *\n * Ruthless pragmatist who ignores traditional honor codes.\n * Uses brutal, efficient techniques with no concern for ethics.\n */\n JOJIK_POKRYEOKBAE = \"jojik_pokryeokbae\",\n}\n\n/**\n * Physical attributes representing realistic body dimensions and composition.\n *\n * **Korean**: 신체 속성 (Body Attributes)\n *\n * These attributes affect combat calculations including reach, movement speed,\n * damage output, defense capability, and stamina. Based on realistic human\n * physiology and Korean martial arts biomechanics.\n *\n * ## Combat Impact\n *\n * - **Weight**: Affects movement speed, knockback resistance, and throw effectiveness\n * - **Leg Length**: Determines kick range and movement speed base\n * - **Arm Length**: Determines punch/strike range and grappling reach\n * - **Muscle Mass**: Affects base damage output and stamina pool\n * - **Fat Mass**: Affects defense absorption and stamina drain rate\n * - **Age**: Affects stamina recovery speed and Ki regeneration\n *\n * @example\n * ```typescript\n * const musaPhysical: PhysicalAttributes = {\n * weight: 75, // kg - balanced warrior\n * legLength: 95, // cm - average leg reach\n * armLength: 75, // cm - average arm reach\n * muscleMass: 38, // kg - high muscle for power\n * fatMass: 12, // kg - low fat for mobility\n * age: 32, // years - prime combat age\n * };\n * ```\n *\n * @public\n * @category Player & Archetypes\n * @korean 신체속성\n */\nexport interface PhysicalAttributes {\n /**\n * Body weight in kilograms.\n *\n * **Korean**: 체중 (Body Weight)\n *\n * Typical Range: 55-95 kg for combatants\n * - Affects movement speed (inversely)\n * - Affects knockback resistance (positively)\n * - Affects throw effectiveness (positively)\n * - Affects ground control (positively)\n */\n readonly weight: number;\n\n /**\n * Leg length in centimeters (hip to ankle).\n *\n * **Korean**: 다리 길이 (Leg Length)\n *\n * Typical Range: 85-105 cm\n * - Determines kick technique maximum range\n * - Affects base movement speed\n * - Affects sweep technique effectiveness\n * - Affects jumping attack height\n */\n readonly legLength: number;\n\n /**\n * Arm length in centimeters (shoulder to wrist).\n *\n * **Korean**: 팔 길이 (Arm Length)\n *\n * Typical Range: 65-85 cm\n * - Determines punch/strike technique range\n * - Affects grappling and throw range\n * - Affects block coverage area\n * - Affects elbow strike effectiveness\n */\n readonly armLength: number;\n\n /**\n * Muscle mass in kilograms.\n *\n * **Korean**: 근육량 (Muscle Mass)\n *\n * Typical Range: 25-45 kg\n * - Affects base damage output (positively)\n * - Affects maximum stamina pool (positively)\n * - Affects grappling and throw power\n * - Affects movement acceleration\n */\n readonly muscleMass: number;\n\n /**\n * Fat mass in kilograms.\n *\n * **Korean**: 지방량 (Fat Mass)\n *\n * Typical Range: 8-20 kg for combatants\n * - Affects blunt damage absorption (positively)\n * - Affects stamina drain rate (negatively)\n * - Affects movement speed (negatively)\n * - Affects recovery time between actions\n */\n readonly fatMass: number;\n\n /**\n * Age in years.\n *\n * **Korean**: 나이 (Age)\n *\n * Typical Range: 22-45 years for peak combatants\n * - Affects stamina recovery speed (optimal 25-35)\n * - Affects Ki regeneration rate (wisdom with age)\n * - Affects injury recovery time (slower with age)\n * - Affects technique execution speed (prime 28-35)\n */\n readonly age: number;\n\n /**\n * Total body height in centimeters.\n *\n * **Korean**: 키 (Height)\n *\n * Typical Range: 160-195 cm\n * - Scales entire skeleton proportionally\n * - Affects reach calculations (combined with limb ratios)\n * - Affects center of gravity positioning\n * - Determines visual body model scaling\n * - Influences balance and stability in stances\n */\n readonly totalHeight: number;\n\n /**\n * Torso length in centimeters (pelvis to shoulders).\n *\n * **Korean**: 몸통 길이 (Torso Length)\n *\n * Typical Range: 50-65 cm\n * - Affects core hitbox size and vital point positioning\n * - Influences breath control and stamina capacity\n * - Affects spinal rotation range in techniques\n * - Determines torso vital point target area\n * - Impacts center of mass calculations\n */\n readonly torsoLength: number;\n\n /**\n * Head size (diameter) in centimeters.\n *\n * **Korean**: 머리 크기 (Head Size)\n *\n * Typical Range: 20-24 cm\n * - Affects head vital point targeting precision\n * - Determines head hitbox size for strikes\n * - Influences helmet/headgear fit (if applicable)\n * - Affects visual skull scaling in 3D model\n * - Impacts consciousness vulnerability to head trauma\n */\n readonly headSize: number;\n\n /**\n * Neck length in centimeters (skull base to shoulders).\n *\n * **Korean**: 목 길이 (Neck Length)\n *\n * Typical Range: 8-12 cm\n * - Affects vulnerability to chokes and strangles\n * - Determines neck vital point target area\n * - Influences blood choke effectiveness\n * - Affects guillotine and rear naked choke mechanics\n * - Impacts head mobility and evasion capability\n */\n readonly neckLength: number;\n\n /**\n * Shoulder width in centimeters (shoulder to shoulder).\n *\n * **Korean**: 어깨 너비 (Shoulder Width)\n *\n * Typical Range: 38-48 cm\n * - Affects defense coverage area (blocking)\n * - Determines upper body strike zone width\n * - Influences grappling control positions\n * - Affects visual upper body model scaling\n * - Impacts balance and stability in wide stances\n */\n readonly shoulderWidth: number;\n\n /**\n * Base walking speed in meters per second.\n *\n * **Korean**: 걷기 속도 (Walk Speed)\n *\n * Typical Range: 5.0-6.5 m/s for combat movement\n * - Determines tactical repositioning speed\n * - Affected by weight and leg length\n * - Base speed for defensive movement\n * - Modified by stance and combat state\n */\n readonly walkSpeed: number;\n\n /**\n * Base running speed in meters per second.\n *\n * **Korean**: 달리기 속도 (Run Speed)\n *\n * Typical Range: 8.0-11.0 m/s for sprint movement\n * - Determines rapid repositioning speed\n * - Affected by muscle mass and conditioning\n * - Base speed for aggressive approach\n * - Consumes stamina during use\n */\n readonly runSpeed: number;\n\n /**\n * Base acceleration in meters per second squared.\n *\n * **Korean**: 가속도 (Acceleration)\n *\n * Typical Range: 9.0-15.0 m/s² for combat movement\n * - Determines how quickly fighter reaches max speed\n * - Based on muscle-to-weight ratio (explosiveness)\n * - Higher = more explosive starts and direction changes\n * - Affects combat responsiveness and evasion\n */\n readonly acceleration: number;\n}\n\n/**\n * Eight Trigram stances (팔괘) representing fundamental combat principles.\n *\n * **Korean**: 팔괘 자세 (Eight Trigram Stances)\n * **Origin**: I Ching (易經 / Yijing) divination system adapted for Korean martial arts\n *\n * The Eight Trigrams (Bagua / 八卦) form the foundation of the combat system.\n * Each trigram represents a natural element and combat philosophy, influencing\n * available techniques, movement patterns, and strategic advantages.\n *\n * ## Trigram Philosophy\n *\n * - **☰ 건 (Geon)** - Heaven: Yang energy, direct aggression, overwhelming force\n * - **☱ 태 (Tae)** - Lake: Joy and fluidity, joint locks and flow techniques\n * - **☲ 리 (Li)** - Fire: Precision and speed, nerve strikes and rapid attacks\n * - **☳ 진 (Jin)** - Thunder: Explosive power, shocking techniques\n * - **☴ 손 (Son)** - Wind: Continuous pressure, evasion and mobility\n * - **☵ 감 (Gam)** - Water: Adaptive flow, counters and redirection\n * - **☶ 간 (Gan)** - Mountain: Immovable defense, endurance and patience\n * - **☷ 곤 (Gon)** - Earth: Grounding techniques, takedowns and throws\n *\n * @example\n * ```typescript\n * // Change to Heaven stance for aggressive attack\n * player.currentStance = TrigramStance.GEON;\n *\n * // Execute heaven-aligned technique\n * const technique = getTrigramTechniques(TrigramStance.GEON)[0];\n * executeTechnique(player, opponent, technique);\n * ```\n *\n * @see {@link https://en.wikipedia.org/wiki/Bagua | Bagua (Eight Trigrams) - Wikipedia}\n * @see {@link https://en.wikipedia.org/wiki/I_Ching | I Ching - Wikipedia}\n *\n * @public\n * @category Trigram System\n * @category Korean Martial Arts\n * @korean 팔괘\n */\nexport enum TrigramStance {\n /**\n * ☰ 건 (Geon) - Heaven Stance\n *\n * **Element**: Heaven / Sky (天)\n * **Nature**: Yang, creative, strong\n * **Combat Style**: Direct force, aggressive techniques, overwhelming power\n * **Philosophy**: \"The creative principle - pure yang energy that drives forward\"\n *\n * Techniques emphasize straight attacks, powerful strikes, and dominant positioning.\n */\n GEON = \"geon\",\n\n /**\n * ☱ 태 (Tae) - Lake Stance\n *\n * **Element**: Lake / Marsh (澤)\n * **Nature**: Yin exterior, Yang interior - joyful movement\n * **Combat Style**: Fluid joint manipulation, flowing techniques, adaptable responses\n * **Philosophy**: \"The joyful - water above earth, freedom of movement\"\n *\n * Techniques focus on joint locks, throws, and using opponent's momentum.\n */\n TAE = \"tae\",\n\n /**\n * ☲ 리 (Li) - Fire Stance\n *\n * **Element**: Fire / Flame (火)\n * **Nature**: Yang exterior, Yin interior - bright and precise\n * **Combat Style**: Precise nerve strikes, rapid attacks, speed techniques\n * **Philosophy**: \"The clinging - illuminating and consuming\"\n *\n * Techniques emphasize vital point targeting, quick combinations, and precision.\n */\n LI = \"li\",\n\n /**\n * ☳ 진 (Jin) - Thunder Stance\n *\n * **Element**: Thunder / Arousing (雷)\n * **Nature**: Yang moving, sudden and shocking\n * **Combat Style**: Explosive power, shocking techniques, sudden movements\n * **Philosophy**: \"The arousing - thunder brings shock and awakening\"\n *\n * Techniques feature explosive bursts, stunning strikes, and overwhelming force.\n */\n JIN = \"jin\",\n\n /**\n * ☴ 손 (Son) - Wind Stance\n *\n * **Element**: Wind / Wood (風)\n * **Nature**: Yin, gentle but penetrating\n * **Combat Style**: Continuous pressure, evasion techniques, mobility\n * **Philosophy**: \"The gentle - penetrating like wind, persistent like wood\"\n *\n * Techniques emphasize movement, pressure point chains, and wearing down opponents.\n */\n SON = \"son\",\n\n /**\n * ☵ 감 (Gam) - Water Stance\n *\n * **Element**: Water / Abyss (水)\n * **Nature**: Yang surrounded by Yin - dangerous depths\n * **Combat Style**: Flow and adaptation, counter techniques, redirection\n * **Philosophy**: \"The abysmal - water flows around obstacles and fills voids\"\n *\n * Techniques focus on counters, deflections, and adaptive responses.\n */\n GAM = \"gam\",\n\n /**\n * ☶ 간 (Gan) - Mountain Stance\n *\n * **Element**: Mountain / Stillness (山)\n * **Nature**: Yang above Yin - firm and unyielding\n * **Combat Style**: Defensive mastery, immovable stance, endurance\n * **Philosophy**: \"The keeping still - mountains are firm and unmoving\"\n *\n * Techniques emphasize blocks, parries, and defensive positioning.\n */\n GAN = \"gan\",\n\n /**\n * ☷ 곤 (Gon) - Earth Stance\n *\n * **Element**: Earth / Receptive (地)\n * **Nature**: Pure Yin - receptive and yielding\n * **Combat Style**: Grounding techniques, takedowns, throws\n * **Philosophy**: \"The receptive - earth receives and supports all\"\n *\n * Techniques focus on sweeps, trips, takedowns, and ground control.\n */\n GON = \"gon\",\n}\n\n/**\n * Combat attack types available in the game.\n *\n * Defines the mechanical type of attack being performed, which affects\n * damage calculation, vital point targeting, and defensive options.\n *\n * @public\n * @category Combat System\n * @korean 공격타입\n */\nexport enum CombatAttackType {\n /** Standard striking attack */\n STRIKE = \"strike\",\n /** Thrusting attack with focused force */\n THRUST = \"thrust\",\n /** Defensive blocking action */\n BLOCK = \"block\",\n /** Counter-attack performed after successful defense */\n COUNTER_ATTACK = \"counter_attack\",\n /** Throwing technique to off-balance opponent */\n THROW = \"throw\",\n /** Grappling and joint control technique */\n GRAPPLE = \"grapple\",\n /** Precise pressure point strike */\n PRESSURE_POINT = \"pressure_point\",\n /** Nerve disruption strike */\n NERVE_STRIKE = \"nerve_strike\",\n /** Closed fist punch */\n PUNCH = \"punch\",\n /** Leg kick attack */\n KICK = \"kick\",\n /** Elbow strike */\n ELBOW = \"elbow\",\n /** Knee strike */\n KNEE = \"knee\",\n}\n\n/**\n * Damage types representing different methods of inflicting harm.\n *\n * Each damage type interacts differently with vital points and defensive techniques.\n * Some types are more effective against specific body regions or defense styles.\n *\n * @public\n * @category Combat System\n * @korean 피해타입\n */\nexport enum DamageType {\n /** Blunt force trauma */\n BLUNT = \"blunt\",\n /** Piercing damage penetrating tissue */\n PIERCING = \"piercing\",\n /** Slashing cuts */\n SLASHING = \"slashing\",\n /** Pressure point manipulation */\n PRESSURE = \"pressure\",\n /** Nerve disruption */\n NERVE = \"nerve\",\n /** Joint manipulation and locks */\n JOINT = \"joint\",\n /** Internal organ damage */\n INTERNAL = \"internal\",\n /** Impact shock */\n IMPACT = \"impact\",\n /** Crushing force */\n CRUSHING = \"crushing\",\n /** Sharp edge damage */\n SHARP = \"sharp\",\n /** Electric shock */\n ELECTRIC = \"electric\",\n /** Fire/heat damage */\n FIRE = \"fire\",\n /** Cold/freeze damage */\n ICE = \"ice\",\n /** Poison/toxin damage */\n POISON = \"poison\",\n /** Psychic/mental damage */\n PSYCHIC = \"psychic\",\n /** Blood loss damage */\n BLOOD = \"blood\",\n}\n\n/**\n * Vital point categories representing anatomical targeting systems.\n *\n * **Korean**: 급소 범주 (Vital Point Categories)\n *\n * The game features 70 Korean vital points (급소) based on traditional martial arts\n * knowledge and modern anatomical understanding. Each category represents different\n * physiological systems that can be targeted for combat effectiveness.\n *\n * @example\n * ```typescript\n * const vitalPoint: VitalPoint = {\n * id: \"GB-20\",\n * category: VitalPointCategory.NEUROLOGICAL,\n * severity: VitalPointSeverity.CRITICAL,\n * name: { korean: \"풍지\", english: \"Wind Pool\" }\n * };\n * ```\n *\n * @public\n * @category Vital Point System\n * @korean 급소범주\n */\nexport enum VitalPointCategory {\n /** Neurological system - nerve clusters and neural pathways */\n NEUROLOGICAL = \"neurological\",\n /** Vascular system - major blood vessels and circulation */\n VASCULAR = \"vascular\",\n /** Respiratory system - airways and breathing mechanisms */\n RESPIRATORY = \"respiratory\",\n /** Muscular system - muscle groups and tendons */\n MUSCULAR = \"muscular\",\n /** Skeletal system - bones and structural supports */\n SKELETAL = \"skeletal\",\n /** Organ system - internal organs */\n ORGAN = \"organ\",\n /** Circulatory system - heart and blood flow */\n CIRCULATORY = \"circulatory\",\n /** Lymphatic system - lymph nodes and immune response */\n LYMPHATIC = \"lymphatic\",\n /** Endocrine system - hormonal glands */\n ENDOCRINE = \"endocrine\",\n /** Joint system - articulation points */\n JOINT = \"joint\",\n /** Nerve system - peripheral nerves */\n NERVE = \"nerve\",\n /** Pressure system - pressure-sensitive areas */\n PRESSURE = \"pressure\",\n}\n\n/**\n * Vital point severity levels indicating potential impact.\n *\n * Determines the damage multiplier and status effects applied when\n * a vital point is successfully struck.\n *\n * ## Severity Guidelines\n *\n * - **MINOR**: 1.1-1.3x damage, temporary discomfort\n * - **MODERATE**: 1.5-2.0x damage, brief incapacitation\n * - **MAJOR**: 2.5-3.5x damage, significant impairment\n * - **CRITICAL**: 4.0-5.0x damage, severe trauma\n * - **LETHAL**: 6.0-10.0x damage, immediate incapacitation\n *\n * @public\n * @category Vital Point System\n * @korean 급소심각도\n */\nexport enum VitalPointSeverity {\n /** Minor impact - temporary pain or discomfort */\n MINOR = \"minor\",\n /** Moderate impact - brief stunning or reduced effectiveness */\n MODERATE = \"moderate\",\n /** Major impact - significant damage and impairment */\n MAJOR = \"major\",\n /** Critical impact - severe trauma requiring immediate response */\n CRITICAL = \"critical\",\n /** Lethal impact - immediate incapacitation or death */\n LETHAL = \"lethal\",\n}\n\n/**\n * Status effects that can result from vital point strikes.\n *\n * Each effect type represents a physiological response to targeting\n * specific anatomical structures. Effects stack and interact with\n * combat mechanics.\n *\n * @public\n * @category Vital Point System\n * @korean 급소효과\n */\nexport enum VitalPointEffectType {\n /** Loss of consciousness */\n UNCONSCIOUSNESS = \"unconsciousness\",\n /** Inability to breathe properly */\n BREATHLESSNESS = \"breathlessness\",\n /** Intense pain reducing combat effectiveness */\n PAIN = \"pain\",\n /** Temporary or permanent paralysis */\n PARALYSIS = \"paralysis\",\n /** Brief stunning preventing action */\n STUN = \"stun\",\n /** Reduced strength and effectiveness */\n WEAKNESS = \"weakness\",\n /** Confusion and impaired targeting */\n DISORIENTATION = \"disorientation\",\n /** Restricted blood flow to area */\n BLOOD_FLOW_RESTRICTION = \"blood_flow_restriction\",\n /** Nerve pathway interruption */\n NERVE_DISRUPTION = \"nerve_disruption\",\n /** Internal organ malfunction */\n ORGAN_DISRUPTION = \"organ_disruption\",\n}\n\n/**\n * Combat states representing the current action phase of a fighter.\n *\n * Determines available actions, defensive capabilities, and animation states.\n * State transitions follow combat flow logic and timing windows.\n *\n * @public\n * @category Combat System\n * @korean 전투상태\n */\nexport enum CombatState {\n /** Neutral state, all actions available */\n IDLE = \"idle\",\n /** Executing an attack, vulnerable to counters */\n ATTACKING = \"attacking\",\n /** In defensive stance, reduced offensive capability */\n DEFENDING = \"defending\",\n /** Temporarily incapacitated, cannot act */\n STUNNED = \"stunned\",\n /** Recovering from action, limited options */\n RECOVERING = \"recovering\",\n /** Executing a counter-attack */\n COUNTERING = \"countering\",\n /** Transitioning between stances */\n TRANSITIONING = \"transitioning\",\n /** Grappling/controlling opponent */\n GRAPPLING = \"grappling\",\n /** Being grappled/controlled */\n GRAPPLED = \"grappled\",\n}\n\n/**\n * Body regions for anatomical targeting in combat.\n *\n * Each region contains multiple vital points and has different\n * defensive properties and vulnerability profiles.\n *\n * @public\n * @category Combat System\n * @korean 신체부위\n */\nexport enum BodyRegion {\n /** Head region - contains critical neurological targets */\n HEAD = \"head\",\n /** Neck region - contains vascular and respiratory targets */\n NECK = \"neck\",\n /** Torso region - contains organ targets */\n TORSO = \"torso\",\n /** Left arm region - contains nerve and joint targets */\n LEFT_ARM = \"left_arm\",\n /** Right arm region - contains nerve and joint targets */\n RIGHT_ARM = \"right_arm\",\n /** Left leg region - contains structural and mobility targets */\n LEFT_LEG = \"left_leg\",\n /** Right leg region - contains structural and mobility targets */\n RIGHT_LEG = \"right_leg\",\n /** Core/center region - contains balance and power centers */\n CORE = \"core\",\n}\n\n/**\n * Grappling state representing control and hold status.\n *\n * **Korean**: 잡기 상태 (Grapple State)\n *\n * Tracks the current phase of a grappling exchange based on Hapkido\n * and Ssireum techniques. State transitions follow realistic grappling\n * flow where control must be established before manipulation.\n *\n * @public\n * @category Combat System\n * @korean 잡기상태\n */\nexport enum GrappleState {\n /** Not in grapple - normal combat */\n NONE = \"none\",\n /** Initiating grab attempt */\n GRABBING = \"grabbing\",\n /** Successfully controlling opponent */\n CONTROLLING = \"controlling\",\n /** Attempting to escape control */\n ESCAPING = \"escaping\",\n /** Transitioning to throw or takedown */\n THROWING = \"throwing\",\n /** Applying joint lock technique */\n LOCKING = \"locking\",\n}\n\n/**\n * Target for grappling techniques.\n *\n * **Korean**: 잡기 목표 (Grapple Target)\n *\n * Specifies which body part is being controlled in a grapple.\n * Different targets allow different follow-up techniques and\n * have different escape difficulties.\n *\n * @public\n * @category Combat System\n * @korean 잡기목표\n */\nexport enum GrappleTarget {\n /** Hand/wrist control - 손목잡기 */\n HAND = \"hand\",\n /** Arm control - 팔잡기 */\n ARM = \"arm\",\n /** Leg control - 다리잡기 */\n LEG = \"leg\",\n /** Torso/body control - 몸통잡기 */\n TORSO = \"torso\",\n /** Neck control - 목잡기 */\n NECK = \"neck\",\n /** Both arms control - 양팔잡기 */\n BOTH_ARMS = \"both_arms\",\n}\n\n/**\n * Grappling control information.\n *\n * **Korean**: 잡기 제어 (Grapple Control)\n *\n * Tracks active grappling state between combatants, including\n * control duration, grip strength, and target limb.\n *\n * @public\n * @category Combat System\n * @korean 잡기제어\n */\nexport interface GrappleControl {\n /** Current grapple state */\n readonly state: GrappleState;\n /** Body part being controlled */\n readonly target: GrappleTarget;\n /** ID of controlling player */\n readonly controllerId: string;\n /** ID of controlled player */\n readonly targetId: string;\n /** Grip strength (0-100) affecting escape difficulty */\n readonly gripStrength: number;\n /** Duration of control in milliseconds */\n readonly duration: number;\n /** Timestamp when grapple was initiated */\n readonly startTime: number;\n /** Whether control can be broken this frame */\n readonly canEscape: boolean;\n /** Stamina cost per second to maintain control */\n readonly staminaCostPerSecond: number;\n}\n\nexport default {};\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"facial.js","names":[],"sources":["../../src/types/facial.ts"],"sourcesContent":["/**\n * Facial animation types for realistic combat emotion and damage\n * \n * Defines facial expression system with damage tracking, eye tracking,\n * and smooth expression transitions for authentic human-like combat feedback.\n * \n * @module types/facial\n * @category Type Definitions\n * @korean 얼굴애니메이션타입\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Facial expression states for combat\n * \n * Represents emotional and physical states visible on fighter's face.\n * Each expression corresponds to specific combat situations.\n * \n * @public\n * @category Facial Animation\n * @korean 얼굴표정\n */\nexport enum FacialExpression {\n /** Calm, ready state */\n NEUTRAL = \"neutral\",\n /** Concentrated, ready to attack */\n FOCUSED = \"focused\",\n /** Pain response after hit */\n PAINED = \"pained\",\n /** Low stamina, heavy breathing */\n EXHAUSTED = \"exhausted\",\n /** Brief satisfaction after successful strike */\n VICTORIOUS = \"victorious\",\n /** Knocked out, unconscious */\n DEFEATED = \"defeated\",\n}\n\n/**\n * Bilingual names for facial expressions\n * \n * @public\n * @category Facial Animation\n * @korean 표정이름\n */\nexport const FACIAL_EXPRESSION_NAMES: Record<\n FacialExpression,\n { korean: string; english: string; romanized: string }\n> = {\n [FacialExpression.NEUTRAL]: {\n korean: \"평온\",\n english: \"Neutral\",\n romanized: \"pyeong-on\",\n },\n [FacialExpression.FOCUSED]: {\n korean: \"집중\",\n english: \"Focused\",\n romanized: \"jipjung\",\n },\n [FacialExpression.PAINED]: {\n korean: \"고통\",\n english: \"Pained\",\n romanized: \"gotong\",\n },\n [FacialExpression.EXHAUSTED]: {\n korean: \"지침\",\n english: \"Exhausted\",\n romanized: \"jichim\",\n },\n [FacialExpression.VICTORIOUS]: {\n korean: \"승리\",\n english: \"Victorious\",\n romanized: \"seungri\",\n },\n [FacialExpression.DEFEATED]: {\n korean: \"패배\",\n english: \"Defeated\",\n romanized: \"paebae\",\n },\n};\n\n/**\n * Facial damage state tracking\n * \n * Tracks accumulated damage to face for visual feedback.\n * Includes bruising, swelling, and bleeding effects.\n * \n * @public\n * @category Facial Animation\n * @korean 얼굴손상상태\n */\nexport interface FacialDamageState {\n /** Left eye swelling (0-1, 0=none, 1=fully swollen) */\n readonly leftEyeSwelling: number;\n \n /** Right eye swelling (0-1, 0=none, 1=fully swollen) */\n readonly rightEyeSwelling: number;\n \n /** Mouth/lip bleeding intensity (0-1) */\n readonly mouthBleeding: number;\n \n /** Nose bleeding intensity (0-1) */\n readonly noseBleeding: number;\n \n /** Bruise intensity on left cheek (0-1) */\n readonly leftCheekBruise: number;\n \n /** Bruise intensity on right cheek (0-1) */\n readonly rightCheekBruise: number;\n \n /** Forehead bruise/cut intensity (0-1) */\n readonly foreheadBruise: number;\n \n /** Jaw bruise intensity (0-1) */\n readonly jawBruise: number;\n \n /** Total facial damage accumulation (0-100) */\n readonly totalFacialDamage: number;\n}\n\n/**\n * Expression state with transition timing\n * \n * Manages current expression and smooth transition to next expression.\n * \n * @public\n * @category Facial Animation\n * @korean 표정상태\n */\nexport interface ExpressionState {\n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Expression intensity (0-1, affects degree of expression) */\n readonly intensity: number;\n \n /** Time to transition to new expression (seconds) */\n readonly transitionTime: number;\n \n /** Previous expression (for blending) */\n readonly previousExpression?: FacialExpression;\n \n /** Transition progress (0-1, 0=start, 1=complete) */\n readonly transitionProgress?: number;\n}\n\n/**\n * Eye openness values for expressions\n * \n * @public\n * @category Facial Animation\n * @korean 눈개방도\n */\nexport const EYE_OPENNESS: Record<FacialExpression, number> = {\n [FacialExpression.NEUTRAL]: 1.0, // Fully open\n [FacialExpression.FOCUSED]: 0.7, // Narrowed\n [FacialExpression.PAINED]: 0.3, // Squinted\n [FacialExpression.EXHAUSTED]: 0.5, // Half-closed\n [FacialExpression.VICTORIOUS]: 0.9, // Nearly fully open\n [FacialExpression.DEFEATED]: 0.0, // Closed\n};\n\n/**\n * Mouth openness values for expressions\n * \n * @public\n * @category Facial Animation\n * @korean 입개방도\n */\nexport const MOUTH_OPENNESS: Record<FacialExpression, number> = {\n [FacialExpression.NEUTRAL]: 0.0, // Closed\n [FacialExpression.FOCUSED]: 0.0, // Closed, determined\n [FacialExpression.PAINED]: 0.8, // Open, yelling\n [FacialExpression.EXHAUSTED]: 0.4, // Panting\n [FacialExpression.VICTORIOUS]: 0.2, // Slight smile\n [FacialExpression.DEFEATED]: 0.1, // Slack\n};\n\n/**\n * Head movement animation type\n * \n * Defines types of head movements for combat reactions.\n * \n * @public\n * @category Facial Animation\n * @korean 머리움직임타입\n */\nexport enum HeadMovementType {\n /** Head snaps back when hit */\n RECOIL = \"recoil\",\n /** Slight nod forward during attack */\n NOD = \"nod\",\n /** Head tilts to avoid strike */\n TILT = \"tilt\",\n /** Head turns to track opponent */\n TURN = \"turn\",\n /** Head shakes when stunned */\n SHAKE = \"shake\",\n /** Head drops when defeated */\n DROP = \"drop\",\n}\n\n/**\n * Head movement animation keyframes\n * \n * Sequence of Euler rotations for head movement animations.\n * \n * @public\n * @category Facial Animation\n * @korean 머리움직임키프레임\n */\nexport interface HeadMovementKeyframes {\n /** Movement type identifier */\n readonly type: HeadMovementType;\n \n /** Sequence of rotation keyframes */\n readonly rotations: readonly THREE.Euler[];\n \n /** Duration of each keyframe in seconds */\n readonly frameDuration: number;\n \n /** Total animation duration in seconds */\n readonly totalDuration: number;\n \n /** Whether animation loops */\n readonly loop: boolean;\n}\n\n/**\n * Eye tracking state\n * \n * Manages eye direction and pupil position for opponent tracking.\n * \n * @public\n * @category Facial Animation\n * @korean 눈추적상태\n */\nexport interface EyeTrackingState {\n /** Target position to look at (opponent position) */\n readonly targetPosition: THREE.Vector3;\n \n /** Current look direction (normalized) */\n readonly lookDirection: THREE.Vector3;\n \n /** Pupil offset from center (-1 to 1 for each axis) */\n readonly pupilOffset: { x: number; y: number };\n \n /** Tracking speed (smoothing factor) */\n readonly trackingSpeed: number;\n \n /** Whether tracking is enabled */\n readonly enabled: boolean;\n}\n\n/**\n * Default facial damage state (no damage)\n * \n * @public\n * @category Facial Animation\n * @korean 기본얼굴손상상태\n */\nexport const DEFAULT_FACIAL_DAMAGE: FacialDamageState = {\n leftEyeSwelling: 0,\n rightEyeSwelling: 0,\n mouthBleeding: 0,\n noseBleeding: 0,\n leftCheekBruise: 0,\n rightCheekBruise: 0,\n foreheadBruise: 0,\n jawBruise: 0,\n totalFacialDamage: 0,\n};\n\n/**\n * Default expression state (neutral)\n * \n * @public\n * @category Facial Animation\n * @korean 기본표정상태\n */\nexport const DEFAULT_EXPRESSION_STATE: ExpressionState = {\n expression: FacialExpression.NEUTRAL,\n intensity: 1.0,\n transitionTime: 0.2,\n};\n\n/**\n * Default eye tracking state\n * \n * @public\n * @category Facial Animation\n * @korean 기본눈추적상태\n */\nexport const DEFAULT_EYE_TRACKING: EyeTrackingState = {\n targetPosition: new THREE.Vector3(0, 1.9, 5), // Looking forward\n lookDirection: new THREE.Vector3(0, 0, 1), // Forward\n pupilOffset: { x: 0, y: 0 },\n trackingSpeed: 0.1,\n enabled: true,\n};\n\n/**\n * Face3D component props\n * \n * @public\n * @category Facial Animation\n * @korean 얼굴3D속성\n */\nexport interface Face3DProps {\n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Facial damage state */\n readonly damage: FacialDamageState;\n \n /** Opponent position for eye tracking */\n readonly opponentPosition: THREE.Vector3;\n \n /** Current head rotation (Euler angles) */\n readonly headRotation: THREE.Euler;\n \n /** Enable eye tracking (default: true) */\n readonly enableEyeTracking?: boolean;\n \n /** Enable damage visualization (default: true) */\n readonly enableDamageVisuals?: boolean;\n \n /** Mobile mode (simplified rendering) */\n readonly isMobile?: boolean;\n \n /** Skin tone color (default: 0xffdbac) */\n readonly skinColor?: number;\n}\n\n/**\n * Eye component props\n * \n * @public\n * @category Facial Animation\n * @korean 눈3D속성\n */\nexport interface EyeProps {\n /** Eye position relative to head */\n readonly position: [number, number, number];\n \n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Look direction for pupil tracking */\n readonly lookDirection: THREE.Vector3;\n \n /** Eye swelling amount (0-1) */\n readonly swelling: number;\n \n /** Whether this is the left or right eye */\n readonly side: \"left\" | \"right\";\n}\n\n/**\n * Mouth component props\n * \n * @public\n * @category Facial Animation\n * @korean 입3D속성\n */\nexport interface MouthProps {\n /** Mouth position relative to head */\n readonly position: [number, number, number];\n \n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Bleeding intensity (0-1) */\n readonly bleeding: number;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAY,mBAAL,yBAAA,kBAAA;;AAEL,kBAAA,aAAA;;AAEA,kBAAA,aAAA;;AAEA,kBAAA,YAAA;;AAEA,kBAAA,eAAA;;AAEA,kBAAA,gBAAA;;AAEA,kBAAA,cAAA;;KACD;;;;;;;;AASD,IAAa,0BAGT;EACD,iBAAiB,UAAU;EAC1B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,UAAU;EAC1B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,SAAS;EACzB,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,YAAY;EAC5B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,aAAa;EAC7B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,WAAW;EAC3B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;CACF;;;;;;;;AA0ED,IAAa,eAAiD;EAC3D,iBAAiB,UAAU;EAC3B,iBAAiB,UAAU;EAC3B,iBAAiB,SAAS;EAC1B,iBAAiB,YAAY;EAC7B,iBAAiB,aAAa;EAC9B,iBAAiB,WAAW;CAC9B;;;;;;;;AASD,IAAa,iBAAmD;EAC7D,iBAAiB,UAAU;EAC3B,iBAAiB,UAAU;EAC3B,iBAAiB,SAAS;EAC1B,iBAAiB,YAAY;EAC7B,iBAAiB,aAAa;EAC9B,iBAAiB,WAAW;CAC9B;;;;;;;;;;AAWD,IAAY,mBAAL,yBAAA,kBAAA;;AAEL,kBAAA,YAAA;;AAEA,kBAAA,SAAA;;AAEA,kBAAA,UAAA;;AAEA,kBAAA,UAAA;;AAEA,kBAAA,WAAA;;AAEA,kBAAA,UAAA;;KACD;;;;;;;;AA6DD,IAAa,wBAA2C;CACtD,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,cAAc;CACd,iBAAiB;CACjB,kBAAkB;CAClB,gBAAgB;CAChB,WAAW;CACX,mBAAmB;CACpB;;;;;;;;AASD,IAAa,2BAA4C;CACvD,YAAY,iBAAiB;CAC7B,WAAW;CACX,gBAAgB;CACjB;;;;;;;;AASD,IAAa,uBAAyC;CACpD,gBAAgB,IAAI,MAAM,QAAQ,GAAG,KAAK,EAAE;CAC5C,eAAe,IAAI,MAAM,QAAQ,GAAG,GAAG,EAAE;CACzC,aAAa;EAAE,GAAG;EAAG,GAAG;EAAG;CAC3B,eAAe;CACf,SAAS;CACV"}
1
+ {"version":3,"file":"facial.js","names":[],"sources":["../../src/types/facial.ts"],"sourcesContent":["/**\n * Facial animation types for realistic combat emotion and damage\n * \n * Defines facial expression system with damage tracking, eye tracking,\n * and smooth expression transitions for authentic human-like combat feedback.\n * \n * @module types/facial\n * @category Type Definitions\n * @korean 얼굴애니메이션타입\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Facial expression states for combat\n * \n * Represents emotional and physical states visible on fighter's face.\n * Each expression corresponds to specific combat situations.\n * \n * @public\n * @category Facial Animation\n * @korean 얼굴표정\n */\nexport enum FacialExpression {\n /** Calm, ready state */\n NEUTRAL = \"neutral\",\n /** Concentrated, ready to attack */\n FOCUSED = \"focused\",\n /** Pain response after hit */\n PAINED = \"pained\",\n /** Low stamina, heavy breathing */\n EXHAUSTED = \"exhausted\",\n /** Brief satisfaction after successful strike */\n VICTORIOUS = \"victorious\",\n /** Knocked out, unconscious */\n DEFEATED = \"defeated\",\n}\n\n/**\n * Bilingual names for facial expressions\n * \n * @public\n * @category Facial Animation\n * @korean 표정이름\n */\nexport const FACIAL_EXPRESSION_NAMES: Record<\n FacialExpression,\n { korean: string; english: string; romanized: string }\n> = {\n [FacialExpression.NEUTRAL]: {\n korean: \"평온\",\n english: \"Neutral\",\n romanized: \"pyeong-on\",\n },\n [FacialExpression.FOCUSED]: {\n korean: \"집중\",\n english: \"Focused\",\n romanized: \"jipjung\",\n },\n [FacialExpression.PAINED]: {\n korean: \"고통\",\n english: \"Pained\",\n romanized: \"gotong\",\n },\n [FacialExpression.EXHAUSTED]: {\n korean: \"지침\",\n english: \"Exhausted\",\n romanized: \"jichim\",\n },\n [FacialExpression.VICTORIOUS]: {\n korean: \"승리\",\n english: \"Victorious\",\n romanized: \"seungri\",\n },\n [FacialExpression.DEFEATED]: {\n korean: \"패배\",\n english: \"Defeated\",\n romanized: \"paebae\",\n },\n};\n\n/**\n * Facial damage state tracking\n * \n * Tracks accumulated damage to face for visual feedback.\n * Includes bruising, swelling, and bleeding effects.\n * \n * @public\n * @category Facial Animation\n * @korean 얼굴손상상태\n */\nexport interface FacialDamageState {\n /** Left eye swelling (0-1, 0=none, 1=fully swollen) */\n readonly leftEyeSwelling: number;\n \n /** Right eye swelling (0-1, 0=none, 1=fully swollen) */\n readonly rightEyeSwelling: number;\n \n /** Mouth/lip bleeding intensity (0-1) */\n readonly mouthBleeding: number;\n \n /** Nose bleeding intensity (0-1) */\n readonly noseBleeding: number;\n \n /** Bruise intensity on left cheek (0-1) */\n readonly leftCheekBruise: number;\n \n /** Bruise intensity on right cheek (0-1) */\n readonly rightCheekBruise: number;\n \n /** Forehead bruise/cut intensity (0-1) */\n readonly foreheadBruise: number;\n \n /** Jaw bruise intensity (0-1) */\n readonly jawBruise: number;\n \n /** Total facial damage accumulation (0-100) */\n readonly totalFacialDamage: number;\n}\n\n/**\n * Expression state with transition timing\n * \n * Manages current expression and smooth transition to next expression.\n * \n * @public\n * @category Facial Animation\n * @korean 표정상태\n */\nexport interface ExpressionState {\n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Expression intensity (0-1, affects degree of expression) */\n readonly intensity: number;\n \n /** Time to transition to new expression (seconds) */\n readonly transitionTime: number;\n \n /** Previous expression (for blending) */\n readonly previousExpression?: FacialExpression;\n \n /** Transition progress (0-1, 0=start, 1=complete) */\n readonly transitionProgress?: number;\n}\n\n/**\n * Eye openness values for expressions\n * \n * @public\n * @category Facial Animation\n * @korean 눈개방도\n */\nexport const EYE_OPENNESS: Record<FacialExpression, number> = {\n [FacialExpression.NEUTRAL]: 1.0, // Fully open\n [FacialExpression.FOCUSED]: 0.7, // Narrowed\n [FacialExpression.PAINED]: 0.3, // Squinted\n [FacialExpression.EXHAUSTED]: 0.5, // Half-closed\n [FacialExpression.VICTORIOUS]: 0.9, // Nearly fully open\n [FacialExpression.DEFEATED]: 0.0, // Closed\n};\n\n/**\n * Mouth openness values for expressions\n * \n * @public\n * @category Facial Animation\n * @korean 입개방도\n */\nexport const MOUTH_OPENNESS: Record<FacialExpression, number> = {\n [FacialExpression.NEUTRAL]: 0.0, // Closed\n [FacialExpression.FOCUSED]: 0.0, // Closed, determined\n [FacialExpression.PAINED]: 0.8, // Open, yelling\n [FacialExpression.EXHAUSTED]: 0.4, // Panting\n [FacialExpression.VICTORIOUS]: 0.2, // Slight smile\n [FacialExpression.DEFEATED]: 0.1, // Slack\n};\n\n/**\n * Head movement animation type\n * \n * Defines types of head movements for combat reactions.\n * \n * @public\n * @category Facial Animation\n * @korean 머리움직임타입\n */\nexport enum HeadMovementType {\n /** Head snaps back when hit */\n RECOIL = \"recoil\",\n /** Slight nod forward during attack */\n NOD = \"nod\",\n /** Head tilts to avoid strike */\n TILT = \"tilt\",\n /** Head turns to track opponent */\n TURN = \"turn\",\n /** Head shakes when stunned */\n SHAKE = \"shake\",\n /** Head drops when defeated */\n DROP = \"drop\",\n}\n\n/**\n * Head movement animation keyframes\n * \n * Sequence of Euler rotations for head movement animations.\n * \n * @public\n * @category Facial Animation\n * @korean 머리움직임키프레임\n */\nexport interface HeadMovementKeyframes {\n /** Movement type identifier */\n readonly type: HeadMovementType;\n \n /** Sequence of rotation keyframes */\n readonly rotations: readonly THREE.Euler[];\n \n /** Duration of each keyframe in seconds */\n readonly frameDuration: number;\n \n /** Total animation duration in seconds */\n readonly totalDuration: number;\n \n /** Whether animation loops */\n readonly loop: boolean;\n}\n\n/**\n * Eye tracking state\n * \n * Manages eye direction and pupil position for opponent tracking.\n * \n * @public\n * @category Facial Animation\n * @korean 눈추적상태\n */\nexport interface EyeTrackingState {\n /** Target position to look at (opponent position) */\n readonly targetPosition: THREE.Vector3;\n \n /** Current look direction (normalized) */\n readonly lookDirection: THREE.Vector3;\n \n /** Pupil offset from center (-1 to 1 for each axis) */\n readonly pupilOffset: { x: number; y: number };\n \n /** Tracking speed (smoothing factor) */\n readonly trackingSpeed: number;\n \n /** Whether tracking is enabled */\n readonly enabled: boolean;\n}\n\n/**\n * Default facial damage state (no damage)\n * \n * @public\n * @category Facial Animation\n * @korean 기본얼굴손상상태\n */\nexport const DEFAULT_FACIAL_DAMAGE: FacialDamageState = {\n leftEyeSwelling: 0,\n rightEyeSwelling: 0,\n mouthBleeding: 0,\n noseBleeding: 0,\n leftCheekBruise: 0,\n rightCheekBruise: 0,\n foreheadBruise: 0,\n jawBruise: 0,\n totalFacialDamage: 0,\n};\n\n/**\n * Default expression state (neutral)\n * \n * @public\n * @category Facial Animation\n * @korean 기본표정상태\n */\nexport const DEFAULT_EXPRESSION_STATE: ExpressionState = {\n expression: FacialExpression.NEUTRAL,\n intensity: 1.0,\n transitionTime: 0.2,\n};\n\n/**\n * Default eye tracking state\n * \n * @public\n * @category Facial Animation\n * @korean 기본눈추적상태\n */\nexport const DEFAULT_EYE_TRACKING: EyeTrackingState = {\n targetPosition: new THREE.Vector3(0, 1.9, 5), // Looking forward\n lookDirection: new THREE.Vector3(0, 0, 1), // Forward\n pupilOffset: { x: 0, y: 0 },\n trackingSpeed: 0.1,\n enabled: true,\n};\n\n/**\n * Face3D component props\n * \n * @public\n * @category Facial Animation\n * @korean 얼굴3D속성\n */\nexport interface Face3DProps {\n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Facial damage state */\n readonly damage: FacialDamageState;\n \n /** Opponent position for eye tracking */\n readonly opponentPosition: THREE.Vector3;\n \n /** Current head rotation (Euler angles) */\n readonly headRotation: THREE.Euler;\n \n /** Enable eye tracking (default: true) */\n readonly enableEyeTracking?: boolean;\n \n /** Enable damage visualization (default: true) */\n readonly enableDamageVisuals?: boolean;\n \n /** Mobile mode (simplified rendering) */\n readonly isMobile?: boolean;\n \n /** Skin tone color (default: 0xffdbac) */\n readonly skinColor?: number;\n}\n\n/**\n * Eye component props\n * \n * @public\n * @category Facial Animation\n * @korean 눈3D속성\n */\nexport interface EyeProps {\n /** Eye position relative to head */\n readonly position: [number, number, number];\n \n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Look direction for pupil tracking */\n readonly lookDirection: THREE.Vector3;\n \n /** Eye swelling amount (0-1) */\n readonly swelling: number;\n \n /** Whether this is the left or right eye */\n readonly side: \"left\" | \"right\";\n}\n\n/**\n * Mouth component props\n * \n * @public\n * @category Facial Animation\n * @korean 입3D속성\n */\nexport interface MouthProps {\n /** Mouth position relative to head */\n readonly position: [number, number, number];\n \n /** Current facial expression */\n readonly expression: FacialExpression;\n \n /** Bleeding intensity (0-1) */\n readonly bleeding: number;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAuBA,IAAY,mBAAL,yBAAA,kBAAA;;AAEL,kBAAA,aAAU;;AAEV,kBAAA,aAAU;;AAEV,kBAAA,YAAS;;AAET,kBAAA,eAAY;;AAEZ,kBAAA,gBAAa;;AAEb,kBAAA,cAAW;;KACZ;;;;;;;;AASD,IAAa,0BAGT;EACD,iBAAiB,UAAU;EAC1B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,UAAU;EAC1B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,SAAS;EACzB,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,YAAY;EAC5B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,aAAa;EAC7B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;EACA,iBAAiB,WAAW;EAC3B,QAAQ;EACR,SAAS;EACT,WAAW;EACZ;CACF;;;;;;;;AA0ED,IAAa,eAAiD;EAC3D,iBAAiB,UAAU;EAC3B,iBAAiB,UAAU;EAC3B,iBAAiB,SAAS;EAC1B,iBAAiB,YAAY;EAC7B,iBAAiB,aAAa;EAC9B,iBAAiB,WAAW;CAC9B;;;;;;;;AASD,IAAa,iBAAmD;EAC7D,iBAAiB,UAAU;EAC3B,iBAAiB,UAAU;EAC3B,iBAAiB,SAAS;EAC1B,iBAAiB,YAAY;EAC7B,iBAAiB,aAAa;EAC9B,iBAAiB,WAAW;CAC9B;;;;;;;;;;AAWD,IAAY,mBAAL,yBAAA,kBAAA;;AAEL,kBAAA,YAAS;;AAET,kBAAA,SAAM;;AAEN,kBAAA,UAAO;;AAEP,kBAAA,UAAO;;AAEP,kBAAA,WAAQ;;AAER,kBAAA,UAAO;;KACR;;;;;;;;AA6DD,IAAa,wBAA2C;CACtD,iBAAiB;CACjB,kBAAkB;CAClB,eAAe;CACf,cAAc;CACd,iBAAiB;CACjB,kBAAkB;CAClB,gBAAgB;CAChB,WAAW;CACX,mBAAmB;CACpB;;;;;;;;AASD,IAAa,2BAA4C;CACvD,YAAY,iBAAiB;CAC7B,WAAW;CACX,gBAAgB;CACjB;;;;;;;;AASD,IAAa,uBAAyC;CACpD,gBAAgB,IAAI,MAAM,QAAQ,GAAG,KAAK,EAAE;CAC5C,eAAe,IAAI,MAAM,QAAQ,GAAG,GAAG,EAAE;CACzC,aAAa;EAAE,GAAG;EAAG,GAAG;EAAG;CAC3B,eAAe;CACf,SAAS;CACV"}
@@ -1 +1 @@
1
- {"version":3,"file":"hand-animation.js","names":[],"sources":["../../src/types/hand-animation.ts"],"sourcesContent":["/**\n * Hand animation types for Korean martial arts techniques\n *\n * Defines hand poses, finger positions, and animation states for realistic\n * martial arts hand techniques including strikes, grappling, and precise\n * vital point targeting.\n *\n * @module types/hand-animation\n * @category Type Definitions\n * @korean 손애니메이션타입\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Martial arts hand pose types\n *\n * Traditional Korean martial arts hand formations:\n * - FIST (주먹): Closed fist for punching\n * - KNIFE_HAND (수도): Extended fingers, rigid hand edge for strikes\n * - SPEAR_HAND (관수): Extended fingers together, pointed thrust\n * - PALM_HEEL (장력): Palm-heel strike position with curled fingers\n * - GRAPPLING (잡기): Fingers curved for grabs and control\n * - OPEN (펴기): Neutral open hand position\n *\n * @public\n * @korean 손자세타입\n */\nexport enum HandPoseType {\n /** 주먹 - Closed fist for punching */\n FIST = \"fist\",\n /** 수도 - Knife-hand strike with rigid edge */\n KNIFE_HAND = \"knife_hand\",\n /** 관수 - Spear-hand thrust with pointed fingers */\n SPEAR_HAND = \"spear_hand\",\n /** 장력 - Palm-heel strike with curled fingers */\n PALM_HEEL = \"palm_heel\",\n /** 잡기 - Grappling hand for grabs */\n GRAPPLING = \"grappling\",\n /** 펴기 - Open hand neutral position */\n OPEN = \"open\",\n /** 휴식 - Relaxed natural hand position for walking/idle */\n RELAXED = \"relaxed\",\n}\n\n/**\n * Finger identification\n *\n * @public\n * @korean 손가락\n */\nexport enum FingerType {\n /** 엄지 - Thumb */\n THUMB = \"thumb\",\n /** 검지 - Index finger */\n INDEX = \"index\",\n /** 중지 - Middle finger */\n MIDDLE = \"middle\",\n /** 약지 - Ring finger */\n RING = \"ring\",\n /** 새끼 - Pinky finger */\n PINKY = \"pinky\",\n}\n\n/**\n * Finger curl amount (0 = fully extended, 1 = fully curled)\n *\n * Normalized values for finger joint angles:\n * - 0.0: Fully extended (straight)\n * - 0.5: Half curled (slightly bent)\n * - 1.0: Fully curled (tight fist)\n *\n * @public\n * @korean 손가락구부림량\n */\nexport interface FingerCurl {\n /** Thumb curl amount (0-1) */\n readonly thumb: number;\n /** Index finger curl amount (0-1) */\n readonly index: number;\n /** Middle finger curl amount (0-1) */\n readonly middle: number;\n /** Ring finger curl amount (0-1) */\n readonly ring: number;\n /** Pinky finger curl amount (0-1) */\n readonly pinky: number;\n}\n\n/**\n * Finger spread amount (0 = together, 1 = spread apart)\n *\n * Controls the lateral spacing between fingers.\n *\n * @public\n * @korean 손가락벌림량\n */\nexport interface FingerSpread {\n /** Spread between thumb and index (0-1) */\n readonly thumbIndex: number;\n /** Spread between index and middle (0-1) */\n readonly indexMiddle: number;\n /** Spread between middle and ring (0-1) */\n readonly middleRing: number;\n /** Spread between ring and pinky (0-1) */\n readonly ringPinky: number;\n}\n\n/**\n * Hand pose definition for martial arts techniques\n *\n * Complete hand configuration including finger positions and wrist rotation\n * for authentic Korean martial arts hand techniques.\n *\n * @public\n * @korean 손자세정의\n */\nexport interface HandPose {\n /**\n * Pose identifier\n * @korean 자세ID\n */\n readonly type: HandPoseType;\n\n /**\n * Korean name for the pose\n * @korean 한글이름\n */\n readonly nameKorean: string;\n\n /**\n * English name for the pose\n * @korean 영어이름\n */\n readonly nameEnglish: string;\n\n /**\n * Romanized Korean name\n * @korean 로마자이름\n */\n readonly romanized: string;\n\n /**\n * Finger curl amounts (0-1 per finger)\n * @korean 손가락구부림\n */\n readonly fingerCurl: FingerCurl;\n\n /**\n * Finger spread amounts (0-1 between fingers)\n * @korean 손가락벌림\n */\n readonly fingerSpread: FingerSpread;\n\n /**\n * Wrist rotation for the technique\n * @korean 손목회전\n */\n readonly wristRotation: THREE.Euler;\n\n /**\n * Description of the technique\n * @korean 설명\n */\n readonly description: {\n readonly korean: string;\n readonly english: string;\n };\n\n /**\n * Which martial art this pose comes from\n * @korean 무술출처\n */\n readonly martialArtOrigin:\n | \"taekwondo\"\n | \"hapkido\"\n | \"taekyon\"\n | \"traditional\";\n\n /**\n * Primary striking surface\n * @korean 타격면\n */\n readonly strikingSurface:\n | \"knuckles\"\n | \"palm_heel\"\n | \"knife_edge\"\n | \"fingertips\"\n | \"whole_hand\";\n}\n\n/**\n * Hand animation state\n *\n * Current state of hand animation including pose transition progress.\n *\n * @public\n * @korean 손애니메이션상태\n */\nexport interface HandAnimationState {\n /**\n * Current hand pose\n * @korean 현재자세\n */\n readonly currentPose: HandPoseType;\n\n /**\n * Target hand pose (during transition)\n * @korean 목표자세\n */\n readonly targetPose: HandPoseType | null;\n\n /**\n * Transition progress (0-1)\n * @korean 전환진행률\n */\n readonly transitionProgress: number;\n\n /**\n * Current finger curl values (interpolated)\n * @korean 현재손가락구부림\n */\n readonly currentFingerCurl: FingerCurl;\n\n /**\n * Current finger spread values (interpolated)\n * @korean 현재손가락벌림\n */\n readonly currentFingerSpread: FingerSpread;\n\n /**\n * Current wrist rotation (interpolated)\n * @korean 현재손목회전\n */\n readonly currentWristRotation: THREE.Euler;\n\n /**\n * Whether hand is highlighted for vital point targeting\n * @korean 급소표시여부\n */\n readonly isHighlighted: boolean;\n\n /**\n * Highlight mode for different striking surfaces\n * @korean 표시모드\n */\n readonly highlightMode:\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\"\n | null;\n}\n\n/**\n * Hand side identification\n *\n * @public\n * @korean 손쪽\n */\nexport type HandSide = \"left\" | \"right\";\n\n/**\n * Hand pose configuration for attack techniques\n *\n * Maps attack technique names to appropriate hand poses.\n *\n * @public\n * @korean 공격기술손자세\n */\nexport interface TechniqueHandPose {\n /**\n * Technique name (e.g., \"jab\", \"cross\", \"knife_hand_strike\")\n * @korean 기술이름\n */\n readonly techniqueName: string;\n\n /**\n * Hand pose for left hand\n * @korean 왼손자세\n */\n readonly leftHandPose: HandPoseType;\n\n /**\n * Hand pose for right hand\n * @korean 오른손자세\n */\n readonly rightHandPose: HandPoseType;\n\n /**\n * Transition duration in seconds\n * @korean 전환시간\n */\n readonly transitionDuration: number;\n}\n\n/**\n * Hand level of detail (LOD) settings\n *\n * Performance optimization by adjusting hand detail based on camera distance.\n *\n * @public\n * @korean 손상세도설정\n */\nexport interface HandLODConfig {\n /**\n * Detail level\n * - high: Full finger geometry (4 bones per finger)\n * - medium: Simplified fingers (3 bones per finger)\n * - low: No finger detail (hand as single unit)\n * @korean 상세도\n */\n readonly detailLevel: \"high\" | \"medium\" | \"low\";\n\n /**\n * Distance thresholds for LOD switching\n * @korean 거리기준\n */\n readonly distanceThresholds: {\n readonly high: number; // Camera distance for high detail (< 5 units)\n readonly medium: number; // Camera distance for medium detail (< 15 units)\n readonly low: number; // Camera distance for low detail (>= 15 units)\n };\n\n /**\n * Whether to render individual fingers\n * @korean 손가락렌더링여부\n */\n readonly renderFingers: boolean;\n\n /**\n * Number of segments per finger\n * @korean 손가락세그먼트수\n */\n readonly fingerSegments: number;\n}\n\n/**\n * Finger bone segments\n *\n * Anatomically correct finger bone structure:\n * - Metacarpal: Knuckle base (hand to finger connection)\n * - Proximal: First joint (knuckle joint)\n * - Intermediate: Middle joint\n * - Distal: Fingertip\n *\n * Note: Thumb has no intermediate phalanx (2 bones instead of 3)\n *\n * @public\n * @korean 손가락뼈세그먼트\n */\nexport interface FingerSegments {\n /**\n * Metacarpal bone (knuckle base)\n * @korean 중수골\n */\n readonly metacarpal: THREE.Vector3;\n\n /**\n * Proximal phalanx (first joint)\n * @korean 근위지골\n */\n readonly proximal: THREE.Vector3;\n\n /**\n * Intermediate phalanx (middle joint)\n * Note: Thumb does not have this bone\n * @korean 중위지골\n */\n readonly intermediate: THREE.Vector3 | null;\n\n /**\n * Distal phalanx (fingertip)\n * @korean 원위지골\n */\n readonly distal: THREE.Vector3;\n}\n\n/**\n * Complete hand structure with all finger bones\n *\n * @public\n * @korean 손뼈구조\n */\nexport interface HandStructure {\n /**\n * Palm base position\n * @korean 손바닥위치\n */\n readonly palm: THREE.Vector3;\n\n /**\n * Wrist position\n * @korean 손목위치\n */\n readonly wrist: THREE.Vector3;\n\n /**\n * Thumb segments (2 bones: no intermediate)\n * @korean 엄지뼈\n */\n readonly thumb: FingerSegments;\n\n /**\n * Index finger segments (3 bones)\n * @korean 검지뼈\n */\n readonly index: FingerSegments;\n\n /**\n * Middle finger segments (3 bones)\n * @korean 중지뼈\n */\n readonly middle: FingerSegments;\n\n /**\n * Ring finger segments (3 bones)\n * @korean 약지뼈\n */\n readonly ring: FingerSegments;\n\n /**\n * Pinky finger segments (3 bones)\n * @korean 새끼뼈\n */\n readonly pinky: FingerSegments;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,IAAY,eAAL,yBAAA,cAAA;;AAEL,cAAA,UAAA;;AAEA,cAAA,gBAAA;;AAEA,cAAA,gBAAA;;AAEA,cAAA,eAAA;;AAEA,cAAA,eAAA;;AAEA,cAAA,UAAA;;AAEA,cAAA,aAAA;;KACD;;;;;;;AAQD,IAAY,aAAL,yBAAA,YAAA;;AAEL,YAAA,WAAA;;AAEA,YAAA,WAAA;;AAEA,YAAA,YAAA;;AAEA,YAAA,UAAA;;AAEA,YAAA,WAAA;;KACD"}
1
+ {"version":3,"file":"hand-animation.js","names":[],"sources":["../../src/types/hand-animation.ts"],"sourcesContent":["/**\n * Hand animation types for Korean martial arts techniques\n *\n * Defines hand poses, finger positions, and animation states for realistic\n * martial arts hand techniques including strikes, grappling, and precise\n * vital point targeting.\n *\n * @module types/hand-animation\n * @category Type Definitions\n * @korean 손애니메이션타입\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Martial arts hand pose types\n *\n * Traditional Korean martial arts hand formations:\n * - FIST (주먹): Closed fist for punching\n * - KNIFE_HAND (수도): Extended fingers, rigid hand edge for strikes\n * - SPEAR_HAND (관수): Extended fingers together, pointed thrust\n * - PALM_HEEL (장력): Palm-heel strike position with curled fingers\n * - GRAPPLING (잡기): Fingers curved for grabs and control\n * - OPEN (펴기): Neutral open hand position\n *\n * @public\n * @korean 손자세타입\n */\nexport enum HandPoseType {\n /** 주먹 - Closed fist for punching */\n FIST = \"fist\",\n /** 수도 - Knife-hand strike with rigid edge */\n KNIFE_HAND = \"knife_hand\",\n /** 관수 - Spear-hand thrust with pointed fingers */\n SPEAR_HAND = \"spear_hand\",\n /** 장력 - Palm-heel strike with curled fingers */\n PALM_HEEL = \"palm_heel\",\n /** 잡기 - Grappling hand for grabs */\n GRAPPLING = \"grappling\",\n /** 펴기 - Open hand neutral position */\n OPEN = \"open\",\n /** 휴식 - Relaxed natural hand position for walking/idle */\n RELAXED = \"relaxed\",\n}\n\n/**\n * Finger identification\n *\n * @public\n * @korean 손가락\n */\nexport enum FingerType {\n /** 엄지 - Thumb */\n THUMB = \"thumb\",\n /** 검지 - Index finger */\n INDEX = \"index\",\n /** 중지 - Middle finger */\n MIDDLE = \"middle\",\n /** 약지 - Ring finger */\n RING = \"ring\",\n /** 새끼 - Pinky finger */\n PINKY = \"pinky\",\n}\n\n/**\n * Finger curl amount (0 = fully extended, 1 = fully curled)\n *\n * Normalized values for finger joint angles:\n * - 0.0: Fully extended (straight)\n * - 0.5: Half curled (slightly bent)\n * - 1.0: Fully curled (tight fist)\n *\n * @public\n * @korean 손가락구부림량\n */\nexport interface FingerCurl {\n /** Thumb curl amount (0-1) */\n readonly thumb: number;\n /** Index finger curl amount (0-1) */\n readonly index: number;\n /** Middle finger curl amount (0-1) */\n readonly middle: number;\n /** Ring finger curl amount (0-1) */\n readonly ring: number;\n /** Pinky finger curl amount (0-1) */\n readonly pinky: number;\n}\n\n/**\n * Finger spread amount (0 = together, 1 = spread apart)\n *\n * Controls the lateral spacing between fingers.\n *\n * @public\n * @korean 손가락벌림량\n */\nexport interface FingerSpread {\n /** Spread between thumb and index (0-1) */\n readonly thumbIndex: number;\n /** Spread between index and middle (0-1) */\n readonly indexMiddle: number;\n /** Spread between middle and ring (0-1) */\n readonly middleRing: number;\n /** Spread between ring and pinky (0-1) */\n readonly ringPinky: number;\n}\n\n/**\n * Hand pose definition for martial arts techniques\n *\n * Complete hand configuration including finger positions and wrist rotation\n * for authentic Korean martial arts hand techniques.\n *\n * @public\n * @korean 손자세정의\n */\nexport interface HandPose {\n /**\n * Pose identifier\n * @korean 자세ID\n */\n readonly type: HandPoseType;\n\n /**\n * Korean name for the pose\n * @korean 한글이름\n */\n readonly nameKorean: string;\n\n /**\n * English name for the pose\n * @korean 영어이름\n */\n readonly nameEnglish: string;\n\n /**\n * Romanized Korean name\n * @korean 로마자이름\n */\n readonly romanized: string;\n\n /**\n * Finger curl amounts (0-1 per finger)\n * @korean 손가락구부림\n */\n readonly fingerCurl: FingerCurl;\n\n /**\n * Finger spread amounts (0-1 between fingers)\n * @korean 손가락벌림\n */\n readonly fingerSpread: FingerSpread;\n\n /**\n * Wrist rotation for the technique\n * @korean 손목회전\n */\n readonly wristRotation: THREE.Euler;\n\n /**\n * Description of the technique\n * @korean 설명\n */\n readonly description: {\n readonly korean: string;\n readonly english: string;\n };\n\n /**\n * Which martial art this pose comes from\n * @korean 무술출처\n */\n readonly martialArtOrigin:\n | \"taekwondo\"\n | \"hapkido\"\n | \"taekyon\"\n | \"traditional\";\n\n /**\n * Primary striking surface\n * @korean 타격면\n */\n readonly strikingSurface:\n | \"knuckles\"\n | \"palm_heel\"\n | \"knife_edge\"\n | \"fingertips\"\n | \"whole_hand\";\n}\n\n/**\n * Hand animation state\n *\n * Current state of hand animation including pose transition progress.\n *\n * @public\n * @korean 손애니메이션상태\n */\nexport interface HandAnimationState {\n /**\n * Current hand pose\n * @korean 현재자세\n */\n readonly currentPose: HandPoseType;\n\n /**\n * Target hand pose (during transition)\n * @korean 목표자세\n */\n readonly targetPose: HandPoseType | null;\n\n /**\n * Transition progress (0-1)\n * @korean 전환진행률\n */\n readonly transitionProgress: number;\n\n /**\n * Current finger curl values (interpolated)\n * @korean 현재손가락구부림\n */\n readonly currentFingerCurl: FingerCurl;\n\n /**\n * Current finger spread values (interpolated)\n * @korean 현재손가락벌림\n */\n readonly currentFingerSpread: FingerSpread;\n\n /**\n * Current wrist rotation (interpolated)\n * @korean 현재손목회전\n */\n readonly currentWristRotation: THREE.Euler;\n\n /**\n * Whether hand is highlighted for vital point targeting\n * @korean 급소표시여부\n */\n readonly isHighlighted: boolean;\n\n /**\n * Highlight mode for different striking surfaces\n * @korean 표시모드\n */\n readonly highlightMode:\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\"\n | null;\n}\n\n/**\n * Hand side identification\n *\n * @public\n * @korean 손쪽\n */\nexport type HandSide = \"left\" | \"right\";\n\n/**\n * Hand pose configuration for attack techniques\n *\n * Maps attack technique names to appropriate hand poses.\n *\n * @public\n * @korean 공격기술손자세\n */\nexport interface TechniqueHandPose {\n /**\n * Technique name (e.g., \"jab\", \"cross\", \"knife_hand_strike\")\n * @korean 기술이름\n */\n readonly techniqueName: string;\n\n /**\n * Hand pose for left hand\n * @korean 왼손자세\n */\n readonly leftHandPose: HandPoseType;\n\n /**\n * Hand pose for right hand\n * @korean 오른손자세\n */\n readonly rightHandPose: HandPoseType;\n\n /**\n * Transition duration in seconds\n * @korean 전환시간\n */\n readonly transitionDuration: number;\n}\n\n/**\n * Hand level of detail (LOD) settings\n *\n * Performance optimization by adjusting hand detail based on camera distance.\n *\n * @public\n * @korean 손상세도설정\n */\nexport interface HandLODConfig {\n /**\n * Detail level\n * - high: Full finger geometry (4 bones per finger)\n * - medium: Simplified fingers (3 bones per finger)\n * - low: No finger detail (hand as single unit)\n * @korean 상세도\n */\n readonly detailLevel: \"high\" | \"medium\" | \"low\";\n\n /**\n * Distance thresholds for LOD switching\n * @korean 거리기준\n */\n readonly distanceThresholds: {\n readonly high: number; // Camera distance for high detail (< 5 units)\n readonly medium: number; // Camera distance for medium detail (< 15 units)\n readonly low: number; // Camera distance for low detail (>= 15 units)\n };\n\n /**\n * Whether to render individual fingers\n * @korean 손가락렌더링여부\n */\n readonly renderFingers: boolean;\n\n /**\n * Number of segments per finger\n * @korean 손가락세그먼트수\n */\n readonly fingerSegments: number;\n}\n\n/**\n * Finger bone segments\n *\n * Anatomically correct finger bone structure:\n * - Metacarpal: Knuckle base (hand to finger connection)\n * - Proximal: First joint (knuckle joint)\n * - Intermediate: Middle joint\n * - Distal: Fingertip\n *\n * Note: Thumb has no intermediate phalanx (2 bones instead of 3)\n *\n * @public\n * @korean 손가락뼈세그먼트\n */\nexport interface FingerSegments {\n /**\n * Metacarpal bone (knuckle base)\n * @korean 중수골\n */\n readonly metacarpal: THREE.Vector3;\n\n /**\n * Proximal phalanx (first joint)\n * @korean 근위지골\n */\n readonly proximal: THREE.Vector3;\n\n /**\n * Intermediate phalanx (middle joint)\n * Note: Thumb does not have this bone\n * @korean 중위지골\n */\n readonly intermediate: THREE.Vector3 | null;\n\n /**\n * Distal phalanx (fingertip)\n * @korean 원위지골\n */\n readonly distal: THREE.Vector3;\n}\n\n/**\n * Complete hand structure with all finger bones\n *\n * @public\n * @korean 손뼈구조\n */\nexport interface HandStructure {\n /**\n * Palm base position\n * @korean 손바닥위치\n */\n readonly palm: THREE.Vector3;\n\n /**\n * Wrist position\n * @korean 손목위치\n */\n readonly wrist: THREE.Vector3;\n\n /**\n * Thumb segments (2 bones: no intermediate)\n * @korean 엄지뼈\n */\n readonly thumb: FingerSegments;\n\n /**\n * Index finger segments (3 bones)\n * @korean 검지뼈\n */\n readonly index: FingerSegments;\n\n /**\n * Middle finger segments (3 bones)\n * @korean 중지뼈\n */\n readonly middle: FingerSegments;\n\n /**\n * Ring finger segments (3 bones)\n * @korean 약지뼈\n */\n readonly ring: FingerSegments;\n\n /**\n * Pinky finger segments (3 bones)\n * @korean 새끼뼈\n */\n readonly pinky: FingerSegments;\n}\n"],"mappings":";;;;;;;;;;;;;;;AA4BA,IAAY,eAAL,yBAAA,cAAA;;AAEL,cAAA,UAAO;;AAEP,cAAA,gBAAa;;AAEb,cAAA,gBAAa;;AAEb,cAAA,eAAY;;AAEZ,cAAA,eAAY;;AAEZ,cAAA,UAAO;;AAEP,cAAA,aAAU;;KACX;;;;;;;AAQD,IAAY,aAAL,yBAAA,YAAA;;AAEL,YAAA,WAAQ;;AAER,YAAA,WAAQ;;AAER,YAAA,YAAS;;AAET,YAAA,UAAO;;AAEP,YAAA,WAAQ;;KACT"}
@@ -1 +1 @@
1
- {"version":3,"file":"injury.js","names":[],"sources":["../../src/types/injury.ts"],"sourcesContent":["/**\n * Shared Injury Types\n * \n * **Korean**: 공유 부상 타입\n * \n * Common injury types and data structures used across the trauma visualization\n * system. Separated from React components to avoid coupling system logic to UI.\n * \n * @module types/injury\n * @category Types\n * @korean 부상타입\n */\n\nimport { BodyRegion } from \"./common\";\n\n/**\n * Injury type classification\n * \n * **Korean**: 부상 유형 분류\n * \n * @public\n */\nexport enum InjuryType {\n /** Blunt force trauma */\n BRUISE = \"bruise\",\n /** Sharp weapon/strike */\n CUT = \"cut\",\n /** Deep cut with blood trail */\n LACERATION = \"laceration\",\n /** Bone damage indicator */\n FRACTURE = \"fracture\",\n}\n\n/**\n * Individual injury data for visualization\n * \n * **Korean**: 시각화를 위한 개별 부상 데이터\n * \n * Used by both the injury tracking system and trauma visualization components.\n * \n * @public\n */\nexport interface Injury {\n /** Unique identifier */\n readonly id: string;\n /** Body region affected */\n readonly region: BodyRegion;\n /** Type of injury */\n readonly type: InjuryType;\n /** Position on body [x, y, z] relative to character center */\n readonly position: [number, number, number];\n /** Severity (0.0 to 1.0) */\n readonly severity: number;\n /** Number of hits to same location (for progressive bruising) */\n readonly hitCount: number;\n /** Timestamp when injury was created */\n readonly timestamp: number;\n /** Optional player ID for multi-player scenarios */\n readonly playerId?: string | number;\n}\n"],"mappings":";;;;;;;;AAsBA,IAAY,aAAL,yBAAA,YAAA;;AAEL,YAAA,YAAA;;AAEA,YAAA,SAAA;;AAEA,YAAA,gBAAA;;AAEA,YAAA,cAAA;;KACD"}
1
+ {"version":3,"file":"injury.js","names":[],"sources":["../../src/types/injury.ts"],"sourcesContent":["/**\n * Shared Injury Types\n * \n * **Korean**: 공유 부상 타입\n * \n * Common injury types and data structures used across the trauma visualization\n * system. Separated from React components to avoid coupling system logic to UI.\n * \n * @module types/injury\n * @category Types\n * @korean 부상타입\n */\n\nimport { BodyRegion } from \"./common\";\n\n/**\n * Injury type classification\n * \n * **Korean**: 부상 유형 분류\n * \n * @public\n */\nexport enum InjuryType {\n /** Blunt force trauma */\n BRUISE = \"bruise\",\n /** Sharp weapon/strike */\n CUT = \"cut\",\n /** Deep cut with blood trail */\n LACERATION = \"laceration\",\n /** Bone damage indicator */\n FRACTURE = \"fracture\",\n}\n\n/**\n * Individual injury data for visualization\n * \n * **Korean**: 시각화를 위한 개별 부상 데이터\n * \n * Used by both the injury tracking system and trauma visualization components.\n * \n * @public\n */\nexport interface Injury {\n /** Unique identifier */\n readonly id: string;\n /** Body region affected */\n readonly region: BodyRegion;\n /** Type of injury */\n readonly type: InjuryType;\n /** Position on body [x, y, z] relative to character center */\n readonly position: [number, number, number];\n /** Severity (0.0 to 1.0) */\n readonly severity: number;\n /** Number of hits to same location (for progressive bruising) */\n readonly hitCount: number;\n /** Timestamp when injury was created */\n readonly timestamp: number;\n /** Optional player ID for multi-player scenarios */\n readonly playerId?: string | number;\n}\n"],"mappings":";;;;;;;;AAsBA,IAAY,aAAL,yBAAA,YAAA;;AAEL,YAAA,YAAS;;AAET,YAAA,SAAM;;AAEN,YAAA,gBAAa;;AAEb,YAAA,cAAW;;KACZ"}
@@ -1 +1 @@
1
- {"version":3,"file":"skeletal.js","names":[],"sources":["../../src/types/skeletal.ts"],"sourcesContent":["/**\n * Skeletal rigging types for articulated body model\n *\n * Defines bone hierarchy, skeletal rig structure, and animation keyframes\n * for realistic human-like fighter animations with independent limb movement.\n *\n * @module types/skeletal\n * @category Type Definitions\n * @korean 골격타입\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Bone in skeletal rig hierarchy\n *\n * Represents a single bone with position, rotation, scale, and parent-child relationships.\n * Bones form a tree structure for realistic articulated body movement.\n *\n * @public\n * @category Skeletal System\n * @korean 뼈\n */\nexport interface Bone {\n /**\n * Unique identifier for the bone\n * @korean 이름\n */\n readonly name: string;\n\n /**\n * Parent bone (null for root bone)\n * @korean 부모뼈\n */\n parent: Bone | null;\n\n /**\n * Local position relative to parent\n * @korean 위치\n */\n position: THREE.Vector3;\n\n /**\n * Local rotation in Euler angles\n * @korean 회전\n */\n rotation: THREE.Euler;\n\n /**\n * Local scale\n * @korean 크기\n */\n scale: THREE.Vector3;\n\n /**\n * Child bones\n * @korean 자식뼈들\n */\n children: Bone[];\n\n /**\n * Length of the bone (for rendering)\n * @korean 길이\n */\n readonly length: number;\n\n /**\n * Rest pose position (default pose)\n * @korean 기본위치\n */\n readonly restPosition: THREE.Vector3;\n\n /**\n * Rest pose rotation (default pose)\n * @korean 기본회전\n */\n readonly restRotation: THREE.Euler;\n}\n\n/**\n * Skeletal rig with complete bone hierarchy\n *\n * Contains root bone and map of all bones for efficient lookup.\n * Maximum 30 bones for 60fps performance.\n *\n * @public\n * @category Skeletal System\n * @korean 골격\n */\nexport interface SkeletalRig {\n /**\n * Root bone (pelvis/center)\n * @korean 뿌리뼈\n */\n readonly root: Bone;\n\n /**\n * Map of bone name to bone for fast lookup\n * @korean 뼈맵\n */\n readonly bones: Map<string, Bone>;\n\n /**\n * Total number of bones in rig\n * @korean 뼈개수\n */\n readonly boneCount: number;\n}\n\n/**\n * Animation keyframe for skeletal animation\n *\n * Defines bone transformations at a specific time in the animation.\n * Keyframes are interpolated for smooth animation between poses.\n * Now includes integrated anatomy state for hands, feet, and facial expressions.\n *\n * @public\n * @category Animation\n * @korean 애니메이션키프레임\n */\nexport interface AnimationKeyframe {\n /**\n * Time in seconds from animation start\n * @korean 시간\n */\n readonly time: number;\n\n /**\n * Bone rotations at this keyframe\n * Map of bone name to rotation\n * @korean 뼈회전들\n */\n readonly boneRotations: Map<string, THREE.Euler>;\n\n /**\n * Bone positions at this keyframe (optional, for IK or special moves)\n * Map of bone name to position offset from rest pose\n * @korean 뼈위치들\n */\n readonly bonePositions: Map<string, THREE.Vector3>;\n\n /**\n * Optional easing function name for interpolation\n * @korean 이징함수\n */\n readonly easing?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ANATOMY STATE (해부학 상태) - Integrated hand, foot, and facial animation\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Left hand pose type at this keyframe\n * @korean 왼손자세\n */\n readonly leftHandPose?: string;\n\n /**\n * Right hand pose type at this keyframe\n * @korean 오른손자세\n */\n readonly rightHandPose?: string;\n\n /**\n * Whether left foot is highlighted (e.g., during kicks)\n * @korean 왼발강조\n */\n readonly leftFootHighlight?: boolean;\n\n /**\n * Whether right foot is highlighted (e.g., during kicks)\n * @korean 오른발강조\n */\n readonly rightFootHighlight?: boolean;\n\n /**\n * Left hand highlight mode for striking surface\n * @korean 왼손강조모드\n */\n readonly leftHandHighlightMode?:\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\";\n\n /**\n * Right hand highlight mode for striking surface\n * @korean 오른손강조모드\n */\n readonly rightHandHighlightMode?:\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\";\n\n /**\n * Facial expression at this keyframe\n * @korean 얼굴표정\n */\n readonly facialExpression?: string;\n\n /**\n * Muscle activation targets at this keyframe\n * Map of muscle group name to tension level (0-1)\n * @korean 근육활성화\n */\n readonly muscleActivations?: Map<string, number>;\n}\n\n/**\n * Attack animation type categories\n *\n * Defines the 5 base categories of attack animations with variants.\n * Each technique maps to one of these animation types.\n *\n * @public\n * @category Animation\n * @korean 공격애니메이션타입\n */\nexport enum AttackAnimationType {\n // Punch category (주먹 타격)\n PUNCH_HIGH = \"punch_high\",\n PUNCH_MID = \"punch_mid\",\n PUNCH_LOW = \"punch_low\",\n\n // Kick category (발차기)\n KICK_FRONT = \"kick_front\",\n KICK_SIDE = \"kick_side\",\n KICK_ROUNDHOUSE = \"kick_round\",\n\n // Elbow category (팔꿈치 타격)\n ELBOW_STRIKE = \"elbow_strike\",\n ELBOW_UPPERCUT = \"elbow_uppercut\",\n\n // Knee category (무릎 타격)\n KNEE_STRIKE = \"knee_strike\",\n KNEE_CLINCH = \"knee_clinch\",\n\n // Pressure point category (급소 타격)\n PRESSURE_POINT = \"pressure_point\",\n PRESSURE_POINT_RAPID = \"pressure_point_rapid\",\n}\n\n/**\n * Animation configuration for a technique\n *\n * Links a technique to its specific attack animation with speed modifier.\n *\n * @public\n * @category Animation\n * @korean 기술애니메이션설정\n */\nexport interface TechniqueAnimationConfig {\n /**\n * Type of attack animation to play\n * @korean 애니메이션타입\n */\n readonly type: AttackAnimationType;\n\n /**\n * Speed modifier (0.8-1.2)\n * - Light techniques: 1.2x speed\n * - Normal techniques: 1.0x speed\n * - Heavy techniques: 0.8x speed\n * @korean 속도배율\n */\n readonly speedModifier: number;\n}\n\n/**\n * Complete skeletal animation sequence\n *\n * Sequence of keyframes defining a complete animation\n * (e.g., jab, cross, roundhouse kick).\n *\n * @public\n * @category Animation\n * @korean 골격애니메이션\n */\nexport interface SkeletalAnimation {\n /**\n * Animation identifier\n * @korean 이름\n */\n readonly name: string;\n\n /**\n * Korean name for animation\n * @korean 한글이름\n */\n readonly koreanName: string;\n\n /**\n * Animation keyframes in chronological order\n * @korean 키프레임들\n */\n readonly keyframes: AnimationKeyframe[];\n\n /**\n * Total duration in seconds\n * @korean 지속시간\n */\n readonly duration: number;\n\n /**\n * Whether animation loops\n * @korean 반복여부\n */\n readonly loop: boolean;\n\n /**\n * Animation type (attack, defense, stance change, movement, etc.)\n * @korean 애니메이션타입\n */\n readonly type: \"attack\" | \"defense\" | \"stance\" | \"walk\" | \"idle\" | \"movement\";\n}\n\n/**\n * Bone chain definition for IK (Inverse Kinematics)\n *\n * Defines a chain of bones for IK solving (e.g., arm chain, leg chain).\n * Used for realistic limb positioning and movement.\n *\n * @public\n * @category Skeletal System\n * @korean 뼈체인\n */\nexport interface BoneChain {\n /**\n * Chain identifier\n * @korean 이름\n */\n readonly name: string;\n\n /**\n * Start bone (e.g., shoulder for arm chain)\n * @korean 시작뼈\n */\n readonly startBone: string;\n\n /**\n * End bone (e.g., hand for arm chain)\n * @korean 끝뼈\n */\n readonly endBone: string;\n\n /**\n * Bones in chain from start to end\n * @korean 뼈들\n */\n readonly bones: string[];\n\n /**\n * IK target position (for end effector)\n * @korean IK목표\n */\n ikTarget?: THREE.Vector3;\n}\n\n/**\n * Hand bone structure with 5 fingers\n *\n * Simplified hand model with palm and 5 fingers.\n * Each finger has 3 segments (proximal, middle, distal).\n *\n * @public\n * @category Skeletal System\n * @korean 손뼈\n */\nexport interface HandBones {\n /**\n * Palm bone\n * @korean 손바닥\n */\n readonly palm: Bone;\n\n /**\n * Thumb bones (3 segments)\n * @korean 엄지손가락\n */\n readonly thumb: [Bone, Bone, Bone];\n\n /**\n * Index finger bones (3 segments)\n * @korean 검지손가락\n */\n readonly index: [Bone, Bone, Bone];\n\n /**\n * Middle finger bones (3 segments)\n * @korean 중지손가락\n */\n readonly middle: [Bone, Bone, Bone];\n\n /**\n * Ring finger bones (3 segments)\n * @korean 약지손가락\n */\n readonly ring: [Bone, Bone, Bone];\n\n /**\n * Pinky finger bones (3 segments)\n * @korean 새끼손가락\n */\n readonly pinky: [Bone, Bone, Bone];\n}\n\n/**\n * Joint constraint for realistic movement\n *\n * Defines rotation limits for joints (e.g., elbow can't bend backward).\n * Ensures anatomically correct movement.\n *\n * @public\n * @category Skeletal System\n * @korean 관절제약\n */\nexport interface JointConstraint {\n /**\n * Bone name this constraint applies to\n * @korean 뼈이름\n */\n readonly boneName: string;\n\n /**\n * Minimum rotation angles (X, Y, Z) in radians\n * @korean 최소회전\n */\n readonly minRotation: THREE.Vector3;\n\n /**\n * Maximum rotation angles (X, Y, Z) in radians\n * @korean 최대회전\n */\n readonly maxRotation: THREE.Vector3;\n\n /**\n * Whether this joint can twist (rotate around its length)\n * @korean 비틀기가능\n */\n readonly canTwist: boolean;\n}\n\n/**\n * Bone names for humanoid rig\n *\n * Standard bone naming convention for humanoid skeleton.\n * Total: 28 bones base + optional 38 hand bones (19 per hand) = 66 bones max.\n *\n * Hand bones are optional and can be excluded for performance (LOD system).\n *\n * @public\n * @category Skeletal System\n * @korean 뼈이름들\n */\nexport enum BoneName {\n // Core (1 bone)\n PELVIS = \"pelvis\",\n\n // Spine (3 bones)\n SPINE_LOWER = \"spine_lower\",\n SPINE_MIDDLE = \"spine_middle\",\n SPINE_UPPER = \"spine_upper\",\n\n // Head (2 bones)\n NECK = \"neck\",\n HEAD = \"head\",\n\n // Left Arm (6 bones)\n SHOULDER_L = \"shoulder_L\",\n UPPER_ARM_L = \"upper_arm_L\",\n ELBOW_L = \"elbow_L\",\n FOREARM_L = \"forearm_L\",\n WRIST_L = \"wrist_L\",\n HAND_L = \"hand_L\",\n\n // Right Arm (6 bones)\n SHOULDER_R = \"shoulder_R\",\n UPPER_ARM_R = \"upper_arm_R\",\n ELBOW_R = \"elbow_R\",\n FOREARM_R = \"forearm_R\",\n WRIST_R = \"wrist_R\",\n HAND_R = \"hand_R\",\n\n // Left Leg (5 bones)\n HIP_L = \"hip_L\",\n THIGH_L = \"thigh_L\",\n KNEE_L = \"knee_L\",\n SHIN_L = \"shin_L\",\n FOOT_L = \"foot_L\",\n\n // Right Leg (5 bones)\n HIP_R = \"hip_R\",\n THIGH_R = \"thigh_R\",\n KNEE_R = \"knee_R\",\n SHIN_R = \"shin_R\",\n FOOT_R = \"foot_R\",\n\n // Left Hand Fingers (19 bones - optional for LOD)\n THUMB_META_L = \"thumb_meta_L\",\n THUMB_PROX_L = \"thumb_prox_L\",\n THUMB_DIST_L = \"thumb_dist_L\",\n INDEX_META_L = \"index_meta_L\",\n INDEX_PROX_L = \"index_prox_L\",\n INDEX_INTER_L = \"index_inter_L\",\n INDEX_DIST_L = \"index_dist_L\",\n MIDDLE_META_L = \"middle_meta_L\",\n MIDDLE_PROX_L = \"middle_prox_L\",\n MIDDLE_INTER_L = \"middle_inter_L\",\n MIDDLE_DIST_L = \"middle_dist_L\",\n RING_META_L = \"ring_meta_L\",\n RING_PROX_L = \"ring_prox_L\",\n RING_INTER_L = \"ring_inter_L\",\n RING_DIST_L = \"ring_dist_L\",\n PINKY_META_L = \"pinky_meta_L\",\n PINKY_PROX_L = \"pinky_prox_L\",\n PINKY_INTER_L = \"pinky_inter_L\",\n PINKY_DIST_L = \"pinky_dist_L\",\n\n // Right Hand Fingers (19 bones - optional for LOD)\n THUMB_META_R = \"thumb_meta_R\",\n THUMB_PROX_R = \"thumb_prox_R\",\n THUMB_DIST_R = \"thumb_dist_R\",\n INDEX_META_R = \"index_meta_R\",\n INDEX_PROX_R = \"index_prox_R\",\n INDEX_INTER_R = \"index_inter_R\",\n INDEX_DIST_R = \"index_dist_R\",\n MIDDLE_META_R = \"middle_meta_R\",\n MIDDLE_PROX_R = \"middle_prox_R\",\n MIDDLE_INTER_R = \"middle_inter_R\",\n MIDDLE_DIST_R = \"middle_dist_R\",\n RING_META_R = \"ring_meta_R\",\n RING_PROX_R = \"ring_prox_R\",\n RING_INTER_R = \"ring_inter_R\",\n RING_DIST_R = \"ring_dist_R\",\n PINKY_META_R = \"pinky_meta_R\",\n PINKY_PROX_R = \"pinky_prox_R\",\n PINKY_INTER_R = \"pinky_inter_R\",\n PINKY_DIST_R = \"pinky_dist_R\",\n}\n\n/**\n * Animation state for skeletal player\n *\n * Tracks current animation playback state for skeletal animations.\n *\n * @public\n * @category Animation\n * @korean 애니메이션상태\n */\nexport interface SkeletalAnimationState {\n /**\n * Current animation being played\n * @korean 현재애니메이션\n */\n currentAnimation: SkeletalAnimation | null;\n\n /**\n * Current time in animation (seconds)\n * @korean 현재시간\n */\n currentTime: number;\n\n /**\n * Whether animation is playing\n * @korean 재생중\n */\n isPlaying: boolean;\n\n /**\n * Animation playback speed multiplier\n * @korean 재생속도\n */\n playbackSpeed: number;\n\n /**\n * Previous keyframe index\n * @korean 이전키프레임\n */\n previousKeyframeIndex: number;\n\n /**\n * Next keyframe index\n * @korean 다음키프레임\n */\n nextKeyframeIndex: number;\n}\n\n/**\n * Fighting stance guard pose configuration\n *\n * Defines complete body positioning for authentic Korean martial arts stances.\n * Includes arms, torso, legs, and pelvis rotations based on traditional Taekwondo/Hapkido.\n *\n * Each stance corresponds to a real martial arts position with unique leg positioning.\n * Used for stance-specific idle animations at 60fps.\n *\n * @public\n * @category Animation\n * @korean 자세방어포즈\n */\nexport interface StanceGuardPose {\n /**\n * Left arm bone rotations (shoulder, elbow, wrist)\n * @korean 왼팔\n */\n readonly leftArm: {\n readonly shoulder: THREE.Euler;\n readonly elbow: THREE.Euler;\n readonly wrist: THREE.Euler;\n };\n\n /**\n * Right arm bone rotations (shoulder, elbow, wrist)\n * @korean 오른팔\n */\n readonly rightArm: {\n readonly shoulder: THREE.Euler;\n readonly elbow: THREE.Euler;\n readonly wrist: THREE.Euler;\n };\n\n /**\n * Torso rotation (spine upper bone)\n * @korean 몸통회전\n */\n readonly torso: THREE.Euler;\n\n /**\n * Left leg bone rotations (hip, knee, ankle)\n * NEW: For authentic Taekwondo stance positioning\n * @korean 왼다리\n */\n readonly leftLeg: {\n readonly hip: THREE.Euler; // Hip rotation/abduction\n readonly knee: THREE.Euler; // Knee bend angle\n readonly ankle: THREE.Euler; // Ankle dorsiflexion/plantarflexion\n };\n\n /**\n * Right leg bone rotations (hip, knee, ankle)\n * NEW: For authentic Taekwondo stance positioning\n * @korean 오른다리\n */\n readonly rightLeg: {\n readonly hip: THREE.Euler; // Hip rotation/abduction\n readonly knee: THREE.Euler; // Knee bend angle\n readonly ankle: THREE.Euler; // Ankle dorsiflexion/plantarflexion\n };\n\n /**\n * Pelvis rotation (hip tilt and rotation)\n * NEW: For proper stance base\n * @korean 골반회전\n */\n readonly pelvis: THREE.Euler;\n\n /**\n * Stance width (foot spacing in meters)\n * NEW: Defines lateral distance between feet\n * Range: 0.3 (narrow) to 1.5 (wide horse stance)\n *\n * This value describes the intended lateral spacing between the feet for this\n * stance configuration. Consumers (e.g. animation systems or positioning\n * overlays) may use it to drive foot placement, validation, or visualization\n * as needed.\n *\n * @korean 자세너비\n */\n readonly stanceWidth: number;\n\n /**\n * Stance depth (front-to-back foot spacing in meters)\n * Optional: Defaults to 0 for parallel stances (Juchum Seogi, Narani Seogi)\n *\n * For forward stances (Ap Koobi Seogi): positive value (~0.6-0.9m)\n * For back stances (Dwi Seogi): negative value (~-0.3m with back foot forward)\n *\n * Left foot gets -depth/2, right foot gets +depth/2 on Z-axis.\n * Combined with stanceWidth, this defines the full 2D foot placement.\n *\n * @korean 자세깊이\n */\n readonly stanceDepth?: number;\n\n /**\n * Pelvis height offset (vertical drop in meters)\n * Optional: Defaults to 0 for normal standing height\n *\n * For deep stances (Juchum Seogi, Joong Ha Seogi): negative value (~-0.15 to -0.3m)\n * This lowers the center of gravity for power and stability.\n *\n * @korean 골반높이\n */\n readonly pelvisHeight?: number;\n\n /**\n * Weight distribution (forward/neutral/back)\n * @korean 무게중심\n */\n readonly weight: \"forward\" | \"neutral\" | \"back\";\n\n /**\n * Breathing animation range (min/max for chest movement)\n * @korean 호흡범위\n */\n readonly breathingRange: {\n readonly min: number;\n readonly max: number;\n };\n}\n\n/**\n * Stance guard animation configuration\n *\n * Extends base AnimationConfig with stance-specific guard pose data.\n * Includes 4-6 frame breathing animation for realistic idle behavior.\n *\n * @public\n * @category Animation\n * @korean 자세방어애니메이션설정\n */\nexport interface StanceGuardAnimationConfig {\n /**\n * Trigram stance identifier\n * @korean 괘\n */\n readonly stance: string;\n\n /**\n * Korean name of stance\n * @korean 한글이름\n */\n readonly koreanName: string;\n\n /**\n * English name of stance\n * @korean 영어이름\n */\n readonly englishName: string;\n\n /**\n * Guard pose keyframe (default position)\n * @korean 방어포즈\n */\n readonly guardPose: StanceGuardPose;\n\n /**\n * Breathing animation frames (4-6 frames)\n * @korean 호흡프레임\n */\n readonly breathingFrames: number;\n\n /**\n * Target frames per second (60fps)\n * @korean 초당프레임\n */\n readonly fps: number;\n\n /**\n * Breathing cycle loop enabled\n * @korean 반복여부\n */\n readonly loop: boolean;\n\n /**\n * Animation priority (0 for idle guards)\n * @korean 우선순위\n */\n readonly priority: number;\n}\n\n/**\n * Mirror a guard pose for left/right stance laterality.\n *\n * **Korean**: 자세 좌우 대칭\n *\n * Creates a mirror-image guard pose by swapping left and right limb positions\n * and negating lateral (Y-axis and Z-axis) rotations. This enables authentic\n * left/right stance differentiation in Korean martial arts.\n *\n * Key transformations:\n * - Swap leftArm ↔ rightArm bone rotations\n * - Negate Y rotation (lateral twist)\n * - Negate Z rotation (roll)\n * - Preserve X rotation (forward/back bend)\n * - Keep weight distribution and breathing range unchanged\n *\n * @param pose - Original guard pose to mirror\n * @returns Mirrored guard pose with swapped and negated rotations\n *\n * @example\n * ```typescript\n * // Create right-handed version of a left-handed guard\n * const leftGeonGuard = GEON_HIGH_GUARD_POSE;\n * const rightGeonGuard = mirrorGuardPose(leftGeonGuard);\n *\n * // leftGeonGuard has left hand forward\n * // rightGeonGuard has right hand forward (mirrored)\n * ```\n *\n * @public\n * @category Animation\n * @korean 방어포즈대칭\n */\nexport function mirrorGuardPose(pose: StanceGuardPose): StanceGuardPose {\n // Helper to negate Y and Z rotations while preserving X\n const mirrorEuler = (euler: THREE.Euler): THREE.Euler => {\n return new THREE.Euler(\n euler.x, // Preserve forward/back bend\n -euler.y, // Negate lateral twist\n -euler.z // Negate roll\n );\n };\n\n return {\n // Swap left and right arms with mirrored rotations\n leftArm: {\n shoulder: mirrorEuler(pose.rightArm.shoulder),\n elbow: mirrorEuler(pose.rightArm.elbow),\n wrist: mirrorEuler(pose.rightArm.wrist),\n },\n rightArm: {\n shoulder: mirrorEuler(pose.leftArm.shoulder),\n elbow: mirrorEuler(pose.leftArm.elbow),\n wrist: mirrorEuler(pose.leftArm.wrist),\n },\n // Mirror torso rotation\n torso: mirrorEuler(pose.torso),\n // NEW: Swap and mirror leg positions\n leftLeg: {\n hip: mirrorEuler(pose.rightLeg.hip),\n knee: mirrorEuler(pose.rightLeg.knee),\n ankle: mirrorEuler(pose.rightLeg.ankle),\n },\n rightLeg: {\n hip: mirrorEuler(pose.leftLeg.hip),\n knee: mirrorEuler(pose.leftLeg.knee),\n ankle: mirrorEuler(pose.leftLeg.ankle),\n },\n // Mirror pelvis rotation\n pelvis: mirrorEuler(pose.pelvis),\n // Stance width remains the same\n stanceWidth: pose.stanceWidth,\n // Stance depth: negate for mirrored stance (front foot becomes back foot)\n stanceDepth: pose.stanceDepth !== undefined ? -pose.stanceDepth : undefined,\n // Pelvis height remains unchanged (not affected by laterality)\n pelvisHeight: pose.pelvisHeight,\n // Weight distribution remains the same\n weight: pose.weight,\n // Breathing range unchanged (not affected by laterality, reuse original object)\n breathingRange: pose.breathingRange,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"skeletal.js","names":[],"sources":["../../src/types/skeletal.ts"],"sourcesContent":["/**\n * Skeletal rigging types for articulated body model\n *\n * Defines bone hierarchy, skeletal rig structure, and animation keyframes\n * for realistic human-like fighter animations with independent limb movement.\n *\n * @module types/skeletal\n * @category Type Definitions\n * @korean 골격타입\n */\n\nimport * as THREE from \"three\";\n\n/**\n * Bone in skeletal rig hierarchy\n *\n * Represents a single bone with position, rotation, scale, and parent-child relationships.\n * Bones form a tree structure for realistic articulated body movement.\n *\n * @public\n * @category Skeletal System\n * @korean 뼈\n */\nexport interface Bone {\n /**\n * Unique identifier for the bone\n * @korean 이름\n */\n readonly name: string;\n\n /**\n * Parent bone (null for root bone)\n * @korean 부모뼈\n */\n parent: Bone | null;\n\n /**\n * Local position relative to parent\n * @korean 위치\n */\n position: THREE.Vector3;\n\n /**\n * Local rotation in Euler angles\n * @korean 회전\n */\n rotation: THREE.Euler;\n\n /**\n * Local scale\n * @korean 크기\n */\n scale: THREE.Vector3;\n\n /**\n * Child bones\n * @korean 자식뼈들\n */\n children: Bone[];\n\n /**\n * Length of the bone (for rendering)\n * @korean 길이\n */\n readonly length: number;\n\n /**\n * Rest pose position (default pose)\n * @korean 기본위치\n */\n readonly restPosition: THREE.Vector3;\n\n /**\n * Rest pose rotation (default pose)\n * @korean 기본회전\n */\n readonly restRotation: THREE.Euler;\n}\n\n/**\n * Skeletal rig with complete bone hierarchy\n *\n * Contains root bone and map of all bones for efficient lookup.\n * Maximum 30 bones for 60fps performance.\n *\n * @public\n * @category Skeletal System\n * @korean 골격\n */\nexport interface SkeletalRig {\n /**\n * Root bone (pelvis/center)\n * @korean 뿌리뼈\n */\n readonly root: Bone;\n\n /**\n * Map of bone name to bone for fast lookup\n * @korean 뼈맵\n */\n readonly bones: Map<string, Bone>;\n\n /**\n * Total number of bones in rig\n * @korean 뼈개수\n */\n readonly boneCount: number;\n}\n\n/**\n * Animation keyframe for skeletal animation\n *\n * Defines bone transformations at a specific time in the animation.\n * Keyframes are interpolated for smooth animation between poses.\n * Now includes integrated anatomy state for hands, feet, and facial expressions.\n *\n * @public\n * @category Animation\n * @korean 애니메이션키프레임\n */\nexport interface AnimationKeyframe {\n /**\n * Time in seconds from animation start\n * @korean 시간\n */\n readonly time: number;\n\n /**\n * Bone rotations at this keyframe\n * Map of bone name to rotation\n * @korean 뼈회전들\n */\n readonly boneRotations: Map<string, THREE.Euler>;\n\n /**\n * Bone positions at this keyframe (optional, for IK or special moves)\n * Map of bone name to position offset from rest pose\n * @korean 뼈위치들\n */\n readonly bonePositions: Map<string, THREE.Vector3>;\n\n /**\n * Optional easing function name for interpolation\n * @korean 이징함수\n */\n readonly easing?: \"linear\" | \"ease-in\" | \"ease-out\" | \"ease-in-out\";\n\n // ═══════════════════════════════════════════════════════════════════════════\n // ANATOMY STATE (해부학 상태) - Integrated hand, foot, and facial animation\n // ═══════════════════════════════════════════════════════════════════════════\n\n /**\n * Left hand pose type at this keyframe\n * @korean 왼손자세\n */\n readonly leftHandPose?: string;\n\n /**\n * Right hand pose type at this keyframe\n * @korean 오른손자세\n */\n readonly rightHandPose?: string;\n\n /**\n * Whether left foot is highlighted (e.g., during kicks)\n * @korean 왼발강조\n */\n readonly leftFootHighlight?: boolean;\n\n /**\n * Whether right foot is highlighted (e.g., during kicks)\n * @korean 오른발강조\n */\n readonly rightFootHighlight?: boolean;\n\n /**\n * Left hand highlight mode for striking surface\n * @korean 왼손강조모드\n */\n readonly leftHandHighlightMode?:\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\";\n\n /**\n * Right hand highlight mode for striking surface\n * @korean 오른손강조모드\n */\n readonly rightHandHighlightMode?:\n | \"none\"\n | \"knuckles\"\n | \"palm\"\n | \"knife_edge\"\n | \"fingertips\";\n\n /**\n * Facial expression at this keyframe\n * @korean 얼굴표정\n */\n readonly facialExpression?: string;\n\n /**\n * Muscle activation targets at this keyframe\n * Map of muscle group name to tension level (0-1)\n * @korean 근육활성화\n */\n readonly muscleActivations?: Map<string, number>;\n}\n\n/**\n * Attack animation type categories\n *\n * Defines the 5 base categories of attack animations with variants.\n * Each technique maps to one of these animation types.\n *\n * @public\n * @category Animation\n * @korean 공격애니메이션타입\n */\nexport enum AttackAnimationType {\n // Punch category (주먹 타격)\n PUNCH_HIGH = \"punch_high\",\n PUNCH_MID = \"punch_mid\",\n PUNCH_LOW = \"punch_low\",\n\n // Kick category (발차기)\n KICK_FRONT = \"kick_front\",\n KICK_SIDE = \"kick_side\",\n KICK_ROUNDHOUSE = \"kick_round\",\n\n // Elbow category (팔꿈치 타격)\n ELBOW_STRIKE = \"elbow_strike\",\n ELBOW_UPPERCUT = \"elbow_uppercut\",\n\n // Knee category (무릎 타격)\n KNEE_STRIKE = \"knee_strike\",\n KNEE_CLINCH = \"knee_clinch\",\n\n // Pressure point category (급소 타격)\n PRESSURE_POINT = \"pressure_point\",\n PRESSURE_POINT_RAPID = \"pressure_point_rapid\",\n}\n\n/**\n * Animation configuration for a technique\n *\n * Links a technique to its specific attack animation with speed modifier.\n *\n * @public\n * @category Animation\n * @korean 기술애니메이션설정\n */\nexport interface TechniqueAnimationConfig {\n /**\n * Type of attack animation to play\n * @korean 애니메이션타입\n */\n readonly type: AttackAnimationType;\n\n /**\n * Speed modifier (0.8-1.2)\n * - Light techniques: 1.2x speed\n * - Normal techniques: 1.0x speed\n * - Heavy techniques: 0.8x speed\n * @korean 속도배율\n */\n readonly speedModifier: number;\n}\n\n/**\n * Complete skeletal animation sequence\n *\n * Sequence of keyframes defining a complete animation\n * (e.g., jab, cross, roundhouse kick).\n *\n * @public\n * @category Animation\n * @korean 골격애니메이션\n */\nexport interface SkeletalAnimation {\n /**\n * Animation identifier\n * @korean 이름\n */\n readonly name: string;\n\n /**\n * Korean name for animation\n * @korean 한글이름\n */\n readonly koreanName: string;\n\n /**\n * Animation keyframes in chronological order\n * @korean 키프레임들\n */\n readonly keyframes: AnimationKeyframe[];\n\n /**\n * Total duration in seconds\n * @korean 지속시간\n */\n readonly duration: number;\n\n /**\n * Whether animation loops\n * @korean 반복여부\n */\n readonly loop: boolean;\n\n /**\n * Animation type (attack, defense, stance change, movement, etc.)\n * @korean 애니메이션타입\n */\n readonly type: \"attack\" | \"defense\" | \"stance\" | \"walk\" | \"idle\" | \"movement\";\n}\n\n/**\n * Bone chain definition for IK (Inverse Kinematics)\n *\n * Defines a chain of bones for IK solving (e.g., arm chain, leg chain).\n * Used for realistic limb positioning and movement.\n *\n * @public\n * @category Skeletal System\n * @korean 뼈체인\n */\nexport interface BoneChain {\n /**\n * Chain identifier\n * @korean 이름\n */\n readonly name: string;\n\n /**\n * Start bone (e.g., shoulder for arm chain)\n * @korean 시작뼈\n */\n readonly startBone: string;\n\n /**\n * End bone (e.g., hand for arm chain)\n * @korean 끝뼈\n */\n readonly endBone: string;\n\n /**\n * Bones in chain from start to end\n * @korean 뼈들\n */\n readonly bones: string[];\n\n /**\n * IK target position (for end effector)\n * @korean IK목표\n */\n ikTarget?: THREE.Vector3;\n}\n\n/**\n * Hand bone structure with 5 fingers\n *\n * Simplified hand model with palm and 5 fingers.\n * Each finger has 3 segments (proximal, middle, distal).\n *\n * @public\n * @category Skeletal System\n * @korean 손뼈\n */\nexport interface HandBones {\n /**\n * Palm bone\n * @korean 손바닥\n */\n readonly palm: Bone;\n\n /**\n * Thumb bones (3 segments)\n * @korean 엄지손가락\n */\n readonly thumb: [Bone, Bone, Bone];\n\n /**\n * Index finger bones (3 segments)\n * @korean 검지손가락\n */\n readonly index: [Bone, Bone, Bone];\n\n /**\n * Middle finger bones (3 segments)\n * @korean 중지손가락\n */\n readonly middle: [Bone, Bone, Bone];\n\n /**\n * Ring finger bones (3 segments)\n * @korean 약지손가락\n */\n readonly ring: [Bone, Bone, Bone];\n\n /**\n * Pinky finger bones (3 segments)\n * @korean 새끼손가락\n */\n readonly pinky: [Bone, Bone, Bone];\n}\n\n/**\n * Joint constraint for realistic movement\n *\n * Defines rotation limits for joints (e.g., elbow can't bend backward).\n * Ensures anatomically correct movement.\n *\n * @public\n * @category Skeletal System\n * @korean 관절제약\n */\nexport interface JointConstraint {\n /**\n * Bone name this constraint applies to\n * @korean 뼈이름\n */\n readonly boneName: string;\n\n /**\n * Minimum rotation angles (X, Y, Z) in radians\n * @korean 최소회전\n */\n readonly minRotation: THREE.Vector3;\n\n /**\n * Maximum rotation angles (X, Y, Z) in radians\n * @korean 최대회전\n */\n readonly maxRotation: THREE.Vector3;\n\n /**\n * Whether this joint can twist (rotate around its length)\n * @korean 비틀기가능\n */\n readonly canTwist: boolean;\n}\n\n/**\n * Bone names for humanoid rig\n *\n * Standard bone naming convention for humanoid skeleton.\n * Total: 28 bones base + optional 38 hand bones (19 per hand) = 66 bones max.\n *\n * Hand bones are optional and can be excluded for performance (LOD system).\n *\n * @public\n * @category Skeletal System\n * @korean 뼈이름들\n */\nexport enum BoneName {\n // Core (1 bone)\n PELVIS = \"pelvis\",\n\n // Spine (3 bones)\n SPINE_LOWER = \"spine_lower\",\n SPINE_MIDDLE = \"spine_middle\",\n SPINE_UPPER = \"spine_upper\",\n\n // Head (2 bones)\n NECK = \"neck\",\n HEAD = \"head\",\n\n // Left Arm (6 bones)\n SHOULDER_L = \"shoulder_L\",\n UPPER_ARM_L = \"upper_arm_L\",\n ELBOW_L = \"elbow_L\",\n FOREARM_L = \"forearm_L\",\n WRIST_L = \"wrist_L\",\n HAND_L = \"hand_L\",\n\n // Right Arm (6 bones)\n SHOULDER_R = \"shoulder_R\",\n UPPER_ARM_R = \"upper_arm_R\",\n ELBOW_R = \"elbow_R\",\n FOREARM_R = \"forearm_R\",\n WRIST_R = \"wrist_R\",\n HAND_R = \"hand_R\",\n\n // Left Leg (5 bones)\n HIP_L = \"hip_L\",\n THIGH_L = \"thigh_L\",\n KNEE_L = \"knee_L\",\n SHIN_L = \"shin_L\",\n FOOT_L = \"foot_L\",\n\n // Right Leg (5 bones)\n HIP_R = \"hip_R\",\n THIGH_R = \"thigh_R\",\n KNEE_R = \"knee_R\",\n SHIN_R = \"shin_R\",\n FOOT_R = \"foot_R\",\n\n // Left Hand Fingers (19 bones - optional for LOD)\n THUMB_META_L = \"thumb_meta_L\",\n THUMB_PROX_L = \"thumb_prox_L\",\n THUMB_DIST_L = \"thumb_dist_L\",\n INDEX_META_L = \"index_meta_L\",\n INDEX_PROX_L = \"index_prox_L\",\n INDEX_INTER_L = \"index_inter_L\",\n INDEX_DIST_L = \"index_dist_L\",\n MIDDLE_META_L = \"middle_meta_L\",\n MIDDLE_PROX_L = \"middle_prox_L\",\n MIDDLE_INTER_L = \"middle_inter_L\",\n MIDDLE_DIST_L = \"middle_dist_L\",\n RING_META_L = \"ring_meta_L\",\n RING_PROX_L = \"ring_prox_L\",\n RING_INTER_L = \"ring_inter_L\",\n RING_DIST_L = \"ring_dist_L\",\n PINKY_META_L = \"pinky_meta_L\",\n PINKY_PROX_L = \"pinky_prox_L\",\n PINKY_INTER_L = \"pinky_inter_L\",\n PINKY_DIST_L = \"pinky_dist_L\",\n\n // Right Hand Fingers (19 bones - optional for LOD)\n THUMB_META_R = \"thumb_meta_R\",\n THUMB_PROX_R = \"thumb_prox_R\",\n THUMB_DIST_R = \"thumb_dist_R\",\n INDEX_META_R = \"index_meta_R\",\n INDEX_PROX_R = \"index_prox_R\",\n INDEX_INTER_R = \"index_inter_R\",\n INDEX_DIST_R = \"index_dist_R\",\n MIDDLE_META_R = \"middle_meta_R\",\n MIDDLE_PROX_R = \"middle_prox_R\",\n MIDDLE_INTER_R = \"middle_inter_R\",\n MIDDLE_DIST_R = \"middle_dist_R\",\n RING_META_R = \"ring_meta_R\",\n RING_PROX_R = \"ring_prox_R\",\n RING_INTER_R = \"ring_inter_R\",\n RING_DIST_R = \"ring_dist_R\",\n PINKY_META_R = \"pinky_meta_R\",\n PINKY_PROX_R = \"pinky_prox_R\",\n PINKY_INTER_R = \"pinky_inter_R\",\n PINKY_DIST_R = \"pinky_dist_R\",\n}\n\n/**\n * Animation state for skeletal player\n *\n * Tracks current animation playback state for skeletal animations.\n *\n * @public\n * @category Animation\n * @korean 애니메이션상태\n */\nexport interface SkeletalAnimationState {\n /**\n * Current animation being played\n * @korean 현재애니메이션\n */\n currentAnimation: SkeletalAnimation | null;\n\n /**\n * Current time in animation (seconds)\n * @korean 현재시간\n */\n currentTime: number;\n\n /**\n * Whether animation is playing\n * @korean 재생중\n */\n isPlaying: boolean;\n\n /**\n * Animation playback speed multiplier\n * @korean 재생속도\n */\n playbackSpeed: number;\n\n /**\n * Previous keyframe index\n * @korean 이전키프레임\n */\n previousKeyframeIndex: number;\n\n /**\n * Next keyframe index\n * @korean 다음키프레임\n */\n nextKeyframeIndex: number;\n}\n\n/**\n * Fighting stance guard pose configuration\n *\n * Defines complete body positioning for authentic Korean martial arts stances.\n * Includes arms, torso, legs, and pelvis rotations based on traditional Taekwondo/Hapkido.\n *\n * Each stance corresponds to a real martial arts position with unique leg positioning.\n * Used for stance-specific idle animations at 60fps.\n *\n * @public\n * @category Animation\n * @korean 자세방어포즈\n */\nexport interface StanceGuardPose {\n /**\n * Left arm bone rotations (shoulder, elbow, wrist)\n * @korean 왼팔\n */\n readonly leftArm: {\n readonly shoulder: THREE.Euler;\n readonly elbow: THREE.Euler;\n readonly wrist: THREE.Euler;\n };\n\n /**\n * Right arm bone rotations (shoulder, elbow, wrist)\n * @korean 오른팔\n */\n readonly rightArm: {\n readonly shoulder: THREE.Euler;\n readonly elbow: THREE.Euler;\n readonly wrist: THREE.Euler;\n };\n\n /**\n * Torso rotation (spine upper bone)\n * @korean 몸통회전\n */\n readonly torso: THREE.Euler;\n\n /**\n * Left leg bone rotations (hip, knee, ankle)\n * NEW: For authentic Taekwondo stance positioning\n * @korean 왼다리\n */\n readonly leftLeg: {\n readonly hip: THREE.Euler; // Hip rotation/abduction\n readonly knee: THREE.Euler; // Knee bend angle\n readonly ankle: THREE.Euler; // Ankle dorsiflexion/plantarflexion\n };\n\n /**\n * Right leg bone rotations (hip, knee, ankle)\n * NEW: For authentic Taekwondo stance positioning\n * @korean 오른다리\n */\n readonly rightLeg: {\n readonly hip: THREE.Euler; // Hip rotation/abduction\n readonly knee: THREE.Euler; // Knee bend angle\n readonly ankle: THREE.Euler; // Ankle dorsiflexion/plantarflexion\n };\n\n /**\n * Pelvis rotation (hip tilt and rotation)\n * NEW: For proper stance base\n * @korean 골반회전\n */\n readonly pelvis: THREE.Euler;\n\n /**\n * Stance width (foot spacing in meters)\n * NEW: Defines lateral distance between feet\n * Range: 0.3 (narrow) to 1.5 (wide horse stance)\n *\n * This value describes the intended lateral spacing between the feet for this\n * stance configuration. Consumers (e.g. animation systems or positioning\n * overlays) may use it to drive foot placement, validation, or visualization\n * as needed.\n *\n * @korean 자세너비\n */\n readonly stanceWidth: number;\n\n /**\n * Stance depth (front-to-back foot spacing in meters)\n * Optional: Defaults to 0 for parallel stances (Juchum Seogi, Narani Seogi)\n *\n * For forward stances (Ap Koobi Seogi): positive value (~0.6-0.9m)\n * For back stances (Dwi Seogi): negative value (~-0.3m with back foot forward)\n *\n * Left foot gets -depth/2, right foot gets +depth/2 on Z-axis.\n * Combined with stanceWidth, this defines the full 2D foot placement.\n *\n * @korean 자세깊이\n */\n readonly stanceDepth?: number;\n\n /**\n * Pelvis height offset (vertical drop in meters)\n * Optional: Defaults to 0 for normal standing height\n *\n * For deep stances (Juchum Seogi, Joong Ha Seogi): negative value (~-0.15 to -0.3m)\n * This lowers the center of gravity for power and stability.\n *\n * @korean 골반높이\n */\n readonly pelvisHeight?: number;\n\n /**\n * Weight distribution (forward/neutral/back)\n * @korean 무게중심\n */\n readonly weight: \"forward\" | \"neutral\" | \"back\";\n\n /**\n * Breathing animation range (min/max for chest movement)\n * @korean 호흡범위\n */\n readonly breathingRange: {\n readonly min: number;\n readonly max: number;\n };\n}\n\n/**\n * Stance guard animation configuration\n *\n * Extends base AnimationConfig with stance-specific guard pose data.\n * Includes 4-6 frame breathing animation for realistic idle behavior.\n *\n * @public\n * @category Animation\n * @korean 자세방어애니메이션설정\n */\nexport interface StanceGuardAnimationConfig {\n /**\n * Trigram stance identifier\n * @korean 괘\n */\n readonly stance: string;\n\n /**\n * Korean name of stance\n * @korean 한글이름\n */\n readonly koreanName: string;\n\n /**\n * English name of stance\n * @korean 영어이름\n */\n readonly englishName: string;\n\n /**\n * Guard pose keyframe (default position)\n * @korean 방어포즈\n */\n readonly guardPose: StanceGuardPose;\n\n /**\n * Breathing animation frames (4-6 frames)\n * @korean 호흡프레임\n */\n readonly breathingFrames: number;\n\n /**\n * Target frames per second (60fps)\n * @korean 초당프레임\n */\n readonly fps: number;\n\n /**\n * Breathing cycle loop enabled\n * @korean 반복여부\n */\n readonly loop: boolean;\n\n /**\n * Animation priority (0 for idle guards)\n * @korean 우선순위\n */\n readonly priority: number;\n}\n\n/**\n * Mirror a guard pose for left/right stance laterality.\n *\n * **Korean**: 자세 좌우 대칭\n *\n * Creates a mirror-image guard pose by swapping left and right limb positions\n * and negating lateral (Y-axis and Z-axis) rotations. This enables authentic\n * left/right stance differentiation in Korean martial arts.\n *\n * Key transformations:\n * - Swap leftArm ↔ rightArm bone rotations\n * - Negate Y rotation (lateral twist)\n * - Negate Z rotation (roll)\n * - Preserve X rotation (forward/back bend)\n * - Keep weight distribution and breathing range unchanged\n *\n * @param pose - Original guard pose to mirror\n * @returns Mirrored guard pose with swapped and negated rotations\n *\n * @example\n * ```typescript\n * // Create right-handed version of a left-handed guard\n * const leftGeonGuard = GEON_HIGH_GUARD_POSE;\n * const rightGeonGuard = mirrorGuardPose(leftGeonGuard);\n *\n * // leftGeonGuard has left hand forward\n * // rightGeonGuard has right hand forward (mirrored)\n * ```\n *\n * @public\n * @category Animation\n * @korean 방어포즈대칭\n */\nexport function mirrorGuardPose(pose: StanceGuardPose): StanceGuardPose {\n // Helper to negate Y and Z rotations while preserving X\n const mirrorEuler = (euler: THREE.Euler): THREE.Euler => {\n return new THREE.Euler(\n euler.x, // Preserve forward/back bend\n -euler.y, // Negate lateral twist\n -euler.z // Negate roll\n );\n };\n\n return {\n // Swap left and right arms with mirrored rotations\n leftArm: {\n shoulder: mirrorEuler(pose.rightArm.shoulder),\n elbow: mirrorEuler(pose.rightArm.elbow),\n wrist: mirrorEuler(pose.rightArm.wrist),\n },\n rightArm: {\n shoulder: mirrorEuler(pose.leftArm.shoulder),\n elbow: mirrorEuler(pose.leftArm.elbow),\n wrist: mirrorEuler(pose.leftArm.wrist),\n },\n // Mirror torso rotation\n torso: mirrorEuler(pose.torso),\n // NEW: Swap and mirror leg positions\n leftLeg: {\n hip: mirrorEuler(pose.rightLeg.hip),\n knee: mirrorEuler(pose.rightLeg.knee),\n ankle: mirrorEuler(pose.rightLeg.ankle),\n },\n rightLeg: {\n hip: mirrorEuler(pose.leftLeg.hip),\n knee: mirrorEuler(pose.leftLeg.knee),\n ankle: mirrorEuler(pose.leftLeg.ankle),\n },\n // Mirror pelvis rotation\n pelvis: mirrorEuler(pose.pelvis),\n // Stance width remains the same\n stanceWidth: pose.stanceWidth,\n // Stance depth: negate for mirrored stance (front foot becomes back foot)\n stanceDepth: pose.stanceDepth !== undefined ? -pose.stanceDepth : undefined,\n // Pelvis height remains unchanged (not affected by laterality)\n pelvisHeight: pose.pelvisHeight,\n // Weight distribution remains the same\n weight: pose.weight,\n // Breathing range unchanged (not affected by laterality, reuse original object)\n breathingRange: pose.breathingRange,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"techniqueId.js","names":[],"sources":["../../src/types/techniqueId.ts"],"sourcesContent":["/**\n * Technique ID enum for type-safe technique references\n *\n * **Korean**: 기술 ID 열거형\n *\n * Provides compile-time safety for all technique references across the codebase.\n * Every technique in the game has a unique ID defined here.\n *\n * @module types/techniqueId\n * @category Combat System\n * @korean 기술ID\n */\n\n/**\n * All technique IDs in the game system\n *\n * Each archetype has unique techniques:\n * - 무사 (Musa) - 4 techniques: musa_thunder_strike, musa_iron_defense, musa_dragon_fist, musa_mountain_breaker\n * - 암살자 (Amsalja) - 4 techniques: amsalja_shadow_strike, amsalja_nerve_strike, amsalja_deadly_precision, amsalja_silent_death\n * - 해커 (Hacker) - 4 techniques: hacker_electric_shock, hacker_data_strike, hacker_cyber_overdrive, hacker_system_crash\n * - 정보요원 (Jeongbo) - 5 techniques: jeongbo_tactical_strike, jeongbo_counter_intelligence, jeongbo_psychological_warfare, jeongbo_precision_takedown, jeongbo_intelligence_strike\n * - 조직폭력배 (Jojik) - 4 techniques: jojik_street_brawl, jojik_improvised_weapon, jojik_ruthless_assault, jojik_brutal_takedown\n *\n * @public\n * @category Combat System\n * @korean 기술ID열거형\n */\nexport enum TechniqueId {\n // 무사 (Musa) - Traditional Warrior\n MUSA_THUNDER_STRIKE = \"musa_thunder_strike\",\n MUSA_IRON_DEFENSE = \"musa_iron_defense\",\n MUSA_DRAGON_FIST = \"musa_dragon_fist\",\n MUSA_MOUNTAIN_BREAKER = \"musa_mountain_breaker\",\n\n // 암살자 (Amsalja) - Shadow Assassin\n AMSALJA_SHADOW_STRIKE = \"amsalja_shadow_strike\",\n AMSALJA_NERVE_STRIKE = \"amsalja_nerve_strike\",\n AMSALJA_DEADLY_PRECISION = \"amsalja_deadly_precision\",\n AMSALJA_SILENT_DEATH = \"amsalja_silent_death\",\n\n // 해커 (Hacker) - Cyber Warrior\n HACKER_ELECTRIC_SHOCK = \"hacker_electric_shock\",\n HACKER_DATA_STRIKE = \"hacker_data_strike\",\n HACKER_CYBER_OVERDRIVE = \"hacker_cyber_overdrive\",\n HACKER_SYSTEM_CRASH = \"hacker_system_crash\",\n\n // 정보요원 (Jeongbo Yowon) - Intelligence Operative\n JEONGBO_TACTICAL_STRIKE = \"jeongbo_tactical_strike\",\n JEONGBO_COUNTER_INTELLIGENCE = \"jeongbo_counter_intelligence\",\n JEONGBO_PSYCHOLOGICAL_WARFARE = \"jeongbo_psychological_warfare\",\n JEONGBO_PRECISION_TAKEDOWN = \"jeongbo_precision_takedown\",\n JEONGBO_INTELLIGENCE_STRIKE = \"jeongbo_intelligence_strike\",\n\n // 조직폭력배 (Jojik Pokryeokbae) - Organized Crime\n JOJIK_STREET_BRAWL = \"jojik_street_brawl\",\n JOJIK_IMPROVISED_WEAPON = \"jojik_improvised_weapon\",\n JOJIK_RUTHLESS_ASSAULT = \"jojik_ruthless_assault\",\n JOJIK_BRUTAL_TAKEDOWN = \"jojik_brutal_takedown\",\n}\n\nexport default TechniqueId;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAY,cAAL,yBAAA,aAAA;AAEL,aAAA,yBAAA;AACA,aAAA,uBAAA;AACA,aAAA,sBAAA;AACA,aAAA,2BAAA;AAGA,aAAA,2BAAA;AACA,aAAA,0BAAA;AACA,aAAA,8BAAA;AACA,aAAA,0BAAA;AAGA,aAAA,2BAAA;AACA,aAAA,wBAAA;AACA,aAAA,4BAAA;AACA,aAAA,yBAAA;AAGA,aAAA,6BAAA;AACA,aAAA,kCAAA;AACA,aAAA,mCAAA;AACA,aAAA,gCAAA;AACA,aAAA,iCAAA;AAGA,aAAA,wBAAA;AACA,aAAA,6BAAA;AACA,aAAA,4BAAA;AACA,aAAA,2BAAA;;KACD"}
1
+ {"version":3,"file":"techniqueId.js","names":[],"sources":["../../src/types/techniqueId.ts"],"sourcesContent":["/**\n * Technique ID enum for type-safe technique references\n *\n * **Korean**: 기술 ID 열거형\n *\n * Provides compile-time safety for all technique references across the codebase.\n * Every technique in the game has a unique ID defined here.\n *\n * @module types/techniqueId\n * @category Combat System\n * @korean 기술ID\n */\n\n/**\n * All technique IDs in the game system\n *\n * Each archetype has unique techniques:\n * - 무사 (Musa) - 4 techniques: musa_thunder_strike, musa_iron_defense, musa_dragon_fist, musa_mountain_breaker\n * - 암살자 (Amsalja) - 4 techniques: amsalja_shadow_strike, amsalja_nerve_strike, amsalja_deadly_precision, amsalja_silent_death\n * - 해커 (Hacker) - 4 techniques: hacker_electric_shock, hacker_data_strike, hacker_cyber_overdrive, hacker_system_crash\n * - 정보요원 (Jeongbo) - 5 techniques: jeongbo_tactical_strike, jeongbo_counter_intelligence, jeongbo_psychological_warfare, jeongbo_precision_takedown, jeongbo_intelligence_strike\n * - 조직폭력배 (Jojik) - 4 techniques: jojik_street_brawl, jojik_improvised_weapon, jojik_ruthless_assault, jojik_brutal_takedown\n *\n * @public\n * @category Combat System\n * @korean 기술ID열거형\n */\nexport enum TechniqueId {\n // 무사 (Musa) - Traditional Warrior\n MUSA_THUNDER_STRIKE = \"musa_thunder_strike\",\n MUSA_IRON_DEFENSE = \"musa_iron_defense\",\n MUSA_DRAGON_FIST = \"musa_dragon_fist\",\n MUSA_MOUNTAIN_BREAKER = \"musa_mountain_breaker\",\n\n // 암살자 (Amsalja) - Shadow Assassin\n AMSALJA_SHADOW_STRIKE = \"amsalja_shadow_strike\",\n AMSALJA_NERVE_STRIKE = \"amsalja_nerve_strike\",\n AMSALJA_DEADLY_PRECISION = \"amsalja_deadly_precision\",\n AMSALJA_SILENT_DEATH = \"amsalja_silent_death\",\n\n // 해커 (Hacker) - Cyber Warrior\n HACKER_ELECTRIC_SHOCK = \"hacker_electric_shock\",\n HACKER_DATA_STRIKE = \"hacker_data_strike\",\n HACKER_CYBER_OVERDRIVE = \"hacker_cyber_overdrive\",\n HACKER_SYSTEM_CRASH = \"hacker_system_crash\",\n\n // 정보요원 (Jeongbo Yowon) - Intelligence Operative\n JEONGBO_TACTICAL_STRIKE = \"jeongbo_tactical_strike\",\n JEONGBO_COUNTER_INTELLIGENCE = \"jeongbo_counter_intelligence\",\n JEONGBO_PSYCHOLOGICAL_WARFARE = \"jeongbo_psychological_warfare\",\n JEONGBO_PRECISION_TAKEDOWN = \"jeongbo_precision_takedown\",\n JEONGBO_INTELLIGENCE_STRIKE = \"jeongbo_intelligence_strike\",\n\n // 조직폭력배 (Jojik Pokryeokbae) - Organized Crime\n JOJIK_STREET_BRAWL = \"jojik_street_brawl\",\n JOJIK_IMPROVISED_WEAPON = \"jojik_improvised_weapon\",\n JOJIK_RUTHLESS_ASSAULT = \"jojik_ruthless_assault\",\n JOJIK_BRUTAL_TAKEDOWN = \"jojik_brutal_takedown\",\n}\n\nexport default TechniqueId;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;AA2BA,IAAY,cAAL,yBAAA,aAAA;AAEL,aAAA,yBAAsB;AACtB,aAAA,uBAAoB;AACpB,aAAA,sBAAmB;AACnB,aAAA,2BAAwB;AAGxB,aAAA,2BAAwB;AACxB,aAAA,0BAAuB;AACvB,aAAA,8BAA2B;AAC3B,aAAA,0BAAuB;AAGvB,aAAA,2BAAwB;AACxB,aAAA,wBAAqB;AACrB,aAAA,4BAAyB;AACzB,aAAA,yBAAsB;AAGtB,aAAA,6BAA0B;AAC1B,aAAA,kCAA+B;AAC/B,aAAA,mCAAgC;AAChC,aAAA,gCAA6B;AAC7B,aAAA,iCAA8B;AAG9B,aAAA,wBAAqB;AACrB,aAAA,6BAA0B;AAC1B,aAAA,4BAAyB;AACzB,aAAA,2BAAwB;;KACzB"}
@@ -1 +1 @@
1
- {"version":3,"file":"deviceDetection.js","names":[],"sources":["../../src/utils/deviceDetection.ts"],"sourcesContent":["/**\n * Device Detection Utility\n *\n * Provides robust mobile device detection combining:\n * - User-agent string analysis\n * - Screen size detection\n * - Touch capability detection\n *\n * This ensures mobile controls are shown on all mobile devices,\n * including high-resolution phones that exceed typical mobile breakpoints.\n *\n * @module utils/deviceDetection\n * @category Mobile\n * @korean 기기감지유틸리티\n */\n\n/**\n * Device type classification\n */\nexport enum DeviceType {\n /** Desktop computer or laptop */\n DESKTOP = \"desktop\",\n /** Mobile phone (iOS, Android, etc.) */\n MOBILE = \"mobile\",\n /** Tablet device (iPad, Android tablets) */\n TABLET = \"tablet\",\n}\n\n/**\n * Platform detection results\n */\nexport interface PlatformInfo {\n /** Operating system type */\n readonly os: \"ios\" | \"android\" | \"windows\" | \"macos\" | \"linux\" | \"unknown\";\n /** Device type classification */\n readonly deviceType: DeviceType;\n /** Whether device has touch capability */\n readonly hasTouch: boolean;\n /** Whether device is mobile phone */\n readonly isMobile: boolean;\n /** Whether device is tablet */\n readonly isTablet: boolean;\n /** Whether device is desktop */\n readonly isDesktop: boolean;\n /** Screen width in pixels */\n readonly screenWidth: number;\n /** Screen height in pixels */\n readonly screenHeight: number;\n}\n\n/**\n * Detect if user-agent indicates a mobile device\n * Checks for common mobile device identifiers in user-agent string\n *\n * @param userAgent - Browser user-agent string\n * @returns True if user-agent indicates mobile device\n */\nfunction isMobileUserAgent(userAgent: string): boolean {\n const mobileKeywords = [\n \"Android\",\n \"webOS\",\n \"iPhone\",\n // 'iPad' is handled separately in isTabletUserAgent\n \"iPod\",\n \"BlackBerry\",\n \"IEMobile\",\n \"Opera Mini\",\n \"Mobile\",\n \"mobile\",\n ];\n\n return mobileKeywords.some((keyword) => userAgent.includes(keyword));\n}\n\n/**\n * Detect if user-agent indicates a tablet device\n *\n * @param userAgent - Browser user-agent string\n * @returns True if user-agent indicates tablet\n */\nfunction isTabletUserAgent(userAgent: string): boolean {\n // iPad is always a tablet\n if (userAgent.includes(\"iPad\")) {\n return true;\n }\n\n // Android tablets typically include \"Tablet\" or have Mobile absent\n if (userAgent.includes(\"Android\")) {\n return userAgent.includes(\"Tablet\") || !userAgent.includes(\"Mobile\");\n }\n\n return false;\n}\n\n/**\n * Detect operating system from user-agent\n *\n * @param userAgent - Browser user-agent string\n * @returns Operating system identifier\n */\nfunction detectOS(userAgent: string): PlatformInfo[\"os\"] {\n if (\n userAgent.includes(\"iPhone\") ||\n userAgent.includes(\"iPad\") ||\n userAgent.includes(\"iPod\")\n ) {\n return \"ios\";\n }\n if (userAgent.includes(\"Android\")) {\n return \"android\";\n }\n if (userAgent.includes(\"Windows\")) {\n return \"windows\";\n }\n if (userAgent.includes(\"Mac\")) {\n // Handle iPadOS 13+ in desktop mode, which reports a Mac-like user agent\n // e.g. \"Macintosh; Intel Mac OS X\" but still has touch support\n const isLikelyIPadOSDesktop =\n typeof navigator !== \"undefined\" &&\n typeof navigator.maxTouchPoints === \"number\" &&\n navigator.maxTouchPoints > 1 &&\n userAgent.includes(\"Macintosh\");\n\n if (isLikelyIPadOSDesktop) {\n return \"ios\";\n }\n return \"macos\";\n }\n if (userAgent.includes(\"Linux\")) {\n return \"linux\";\n }\n return \"unknown\";\n}\n\n/**\n * Detect if device has touch capability\n * Uses multiple methods for reliability\n *\n * @returns True if touch is supported\n */\nfunction hasTouchSupport(): boolean {\n // Check for touch events support\n if (\"ontouchstart\" in window) {\n return true;\n }\n\n // Check for touch points (must be defined and > 0)\n if (\n typeof navigator !== \"undefined\" &&\n typeof navigator.maxTouchPoints !== \"undefined\" &&\n navigator.maxTouchPoints > 0\n ) {\n return true;\n }\n\n // Check for pointer events with touch\n if (\n typeof window !== \"undefined\" &&\n window.matchMedia?.(\"(pointer: coarse)\")?.matches\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Mobile screen size breakpoint\n * Devices with width <= this value are considered mobile by size\n */\nexport const MOBILE_BREAKPOINT = 768;\n\n/**\n * Tablet screen size breakpoint\n * Devices with width > MOBILE_BREAKPOINT and <= TABLET_BREAKPOINT are tablets\n */\nexport const TABLET_BREAKPOINT = 1024;\n\n/**\n * Cached CSS environment variable insets\n */\nlet cachedCSSEnvInsets: { top: number; bottom: number } | null = null;\n\n/**\n * Read CSS environment variables for safe area insets\n * Results are cached as they don't change during a session\n */\nfunction readCSSEnvInsets(): { top: number; bottom: number } | null {\n if (cachedCSSEnvInsets !== null) {\n return cachedCSSEnvInsets;\n }\n\n if (typeof window !== \"undefined\" && typeof getComputedStyle === \"function\") {\n try {\n const root = document.documentElement;\n const style = getComputedStyle(root);\n const topEnv = style.getPropertyValue(\"env(safe-area-inset-top)\");\n const bottomEnv = style.getPropertyValue(\"env(safe-area-inset-bottom)\");\n\n if (topEnv || bottomEnv) {\n const result = {\n top: parseInt(topEnv || \"0\", 10) || 0,\n bottom: parseInt(bottomEnv || \"0\", 10) || 0,\n };\n cachedCSSEnvInsets = result;\n return result;\n }\n } catch {\n // Fall through to null\n }\n }\n\n return null;\n}\n\n/**\n * Cached platform information to avoid re-parsing user-agent on every call\n */\nlet cachedPlatform: PlatformInfo | null = null;\nlet cachedScreenWidth = 0;\nlet cachedScreenHeight = 0;\n\n/**\n * Clear the cached platform information\n * Useful when window is resized or device emulation changes\n * Also clears CSS environment variable cache\n *\n * @public\n */\nexport function clearPlatformCache(): void {\n cachedPlatform = null;\n cachedScreenWidth = 0;\n cachedScreenHeight = 0;\n cachedCSSEnvInsets = null;\n}\n\n/**\n * Detect device type and platform information\n *\n * Combines multiple detection methods for reliability:\n * 1. User-agent string analysis (most reliable for device type)\n * 2. Screen dimensions\n * 3. Touch capability\n *\n * This ensures mobile controls are shown on:\n * - Standard mobile phones (< 768px width)\n * - High-resolution phones (>= 768px width but mobile user-agent)\n * - Android 15/16 devices with 2K/4K resolutions (1200px+, 1440px+)\n * - Tablets (user preference via touch support)\n *\n * **User-agent detection takes priority over screen size**, ensuring that\n * high-end Android phones with desktop-class resolutions (e.g., Galaxy S23 Ultra,\n * Pixel 9 Pro) are correctly identified as mobile devices.\n *\n * Results are cached to avoid re-parsing user-agent on every call.\n * Cache is invalidated when screen dimensions change.\n *\n * @returns Complete platform information\n *\n * @example\n * ```typescript\n * const platform = detectPlatform();\n *\n * if (platform.isMobile) {\n * // Show mobile controls even on 4K Android phones\n * return <MobileControls />;\n * }\n * ```\n *\n * @public\n * @korean 플랫폼감지\n */\nexport function detectPlatform(): PlatformInfo {\n const userAgent = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n const screenWidth = typeof window !== \"undefined\" ? window.innerWidth : 1920;\n const screenHeight =\n typeof window !== \"undefined\" ? window.innerHeight : 1080;\n\n // Return cached result if screen dimensions haven't changed\n if (\n cachedPlatform !== null &&\n cachedScreenWidth === screenWidth &&\n cachedScreenHeight === screenHeight\n ) {\n return cachedPlatform;\n }\n\n // Detect OS\n const os = detectOS(userAgent);\n\n // Detect touch capability\n const hasTouch = hasTouchSupport();\n\n // Detect if mobile by user-agent (most reliable method)\n const isMobileUA = isMobileUserAgent(userAgent);\n\n // Detect if tablet by user-agent\n const isTabletUA = isTabletUserAgent(userAgent);\n\n // Detect by screen size (fallback method)\n const isMobileBySize = screenWidth <= MOBILE_BREAKPOINT;\n const isTabletBySize =\n screenWidth > MOBILE_BREAKPOINT && screenWidth <= TABLET_BREAKPOINT;\n\n // Determine device type\n // Priority: User-agent > Screen size\n let deviceType: DeviceType;\n let isMobile: boolean;\n let isTablet: boolean;\n\n if (isMobileUA && !isTabletUA) {\n // User-agent indicates phone\n deviceType = DeviceType.MOBILE;\n isMobile = true;\n isTablet = false;\n } else if (isTabletUA) {\n // User-agent indicates tablet\n deviceType = DeviceType.TABLET;\n isMobile = false;\n isTablet = true;\n } else if (isMobileBySize) {\n // Small screen, assume mobile\n deviceType = DeviceType.MOBILE;\n isMobile = true;\n isTablet = false;\n } else if (isTabletBySize && hasTouch) {\n // Medium screen with touch, assume tablet\n deviceType = DeviceType.TABLET;\n isMobile = false;\n isTablet = true;\n } else {\n // Desktop\n deviceType = DeviceType.DESKTOP;\n isMobile = false;\n isTablet = false;\n }\n\n const isDesktop = deviceType === DeviceType.DESKTOP;\n\n const result: PlatformInfo = {\n os,\n deviceType,\n hasTouch,\n isMobile,\n isTablet,\n isDesktop,\n screenWidth,\n screenHeight,\n };\n\n // Cache the result along with screen dimensions\n cachedPlatform = result;\n cachedScreenWidth = screenWidth;\n cachedScreenHeight = screenHeight;\n\n return result;\n}\n\n/**\n * Simple mobile check for backward compatibility\n * Returns true for both mobile phones and tablets\n *\n * @returns True if device is mobile or tablet\n *\n * @public\n * @korean 모바일확인\n */\nexport function isMobileDevice(): boolean {\n const platform = detectPlatform();\n return platform.isMobile || platform.isTablet;\n}\n\n/**\n * Check if device should use mobile controls\n * Takes into account device type, screen size, and touch capability\n *\n * Uses user-agent detection to correctly identify mobile devices regardless\n * of screen resolution. This ensures high-end Android 15/16 phones with\n * 2K/4K displays (1200px+, 1440px+) show mobile controls.\n *\n * Also ensures tablets and touch-enabled devices always show mobile controls\n * regardless of resolution, for better UX on touch devices.\n *\n * @returns True if mobile controls should be shown\n *\n * @example\n * ```typescript\n * // High-res Android phone (1440x3168) → returns true via user-agent\n * // Desktop with 1440px screen → returns false (no mobile user-agent)\n * // iPad Pro 12.9\" (1024x1366) → returns true (tablet user-agent)\n * // Surface Pro in tablet mode → returns true (touch + tablet size)\n * if (shouldUseMobileControls()) {\n * return <VirtualDPad />; // Touch-optimized controls\n * }\n * ```\n *\n * @public\n * @korean 모바일컨트롤사용\n */\nexport function shouldUseMobileControls(): boolean {\n const platform = detectPlatform();\n\n // Always use mobile controls on phones\n if (platform.isMobile) {\n return true;\n }\n\n // Use mobile controls on tablets (better touch experience)\n if (platform.isTablet) {\n return true;\n }\n\n // Use mobile controls on any touch-enabled device up to tablet breakpoint\n // This catches Windows tablets, Chromebooks in tablet mode, etc.\n if (platform.hasTouch && platform.screenWidth <= TABLET_BREAKPOINT) {\n return true;\n }\n\n // Use mobile controls on small desktop screens with touch\n if (platform.screenWidth <= MOBILE_BREAKPOINT && platform.hasTouch) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Get safe area insets for device\n * Returns appropriate values based on device type and OS\n *\n * For iOS devices, attempts to detect if device has a notch by checking\n * screen dimensions. Falls back to CSS environment variables if available.\n *\n * @returns Safe area insets in pixels\n *\n * @public\n * @korean 안전영역인셋\n */\nexport function getSafeAreaInsets() {\n const platform = detectPlatform();\n\n // iOS devices - distinguish between notched and non-notched\n if (platform.os === \"ios\" && platform.isMobile) {\n // Try to read CSS environment variables first (most accurate)\n const cssEnvInsets = readCSSEnvInsets();\n if (cssEnvInsets) {\n return {\n top: cssEnvInsets.top,\n bottom: cssEnvInsets.bottom,\n left: 0,\n right: 0,\n };\n }\n\n // Detect orientation\n const isLandscape = platform.screenWidth > platform.screenHeight;\n\n // Heuristic: iPhone X and later have notches and specific screen dimensions\n // iPhone X/XS/11 Pro: 375x812, iPhone XR/11: 414x896, iPhone 12/13/14: 390x844, etc.\n // Only devices with height >= 812 (portrait) or width >= 812 (landscape) have notches\n const hasNotch =\n platform.screenHeight >= 812 || platform.screenWidth >= 812;\n\n if (hasNotch) {\n if (isLandscape) {\n // In landscape, notch is on the side\n return {\n top: 0,\n bottom: 21, // Home indicator\n left: 44, // Notch side\n right: 44, // Opposite side for symmetry\n };\n } else {\n // In portrait, notch is at top\n return {\n top: 44,\n bottom: 34,\n left: 0,\n right: 0,\n };\n }\n } else {\n // Older iPhones without notch (iPhone 8, SE, etc.)\n return {\n top: 20, // Status bar height\n bottom: 0,\n left: 0,\n right: 0,\n };\n }\n }\n\n // Android devices (standard status bar)\n if (platform.os === \"android\" && platform.isMobile) {\n return {\n top: 24,\n bottom: 0,\n left: 0,\n right: 0,\n };\n }\n\n // Tablets and desktop - no safe area needed\n return {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"deviceDetection.js","names":[],"sources":["../../src/utils/deviceDetection.ts"],"sourcesContent":["/**\n * Device Detection Utility\n *\n * Provides robust mobile device detection combining:\n * - User-agent string analysis\n * - Screen size detection\n * - Touch capability detection\n *\n * This ensures mobile controls are shown on all mobile devices,\n * including high-resolution phones that exceed typical mobile breakpoints.\n *\n * @module utils/deviceDetection\n * @category Mobile\n * @korean 기기감지유틸리티\n */\n\n/**\n * Device type classification\n */\nexport enum DeviceType {\n /** Desktop computer or laptop */\n DESKTOP = \"desktop\",\n /** Mobile phone (iOS, Android, etc.) */\n MOBILE = \"mobile\",\n /** Tablet device (iPad, Android tablets) */\n TABLET = \"tablet\",\n}\n\n/**\n * Platform detection results\n */\nexport interface PlatformInfo {\n /** Operating system type */\n readonly os: \"ios\" | \"android\" | \"windows\" | \"macos\" | \"linux\" | \"unknown\";\n /** Device type classification */\n readonly deviceType: DeviceType;\n /** Whether device has touch capability */\n readonly hasTouch: boolean;\n /** Whether device is mobile phone */\n readonly isMobile: boolean;\n /** Whether device is tablet */\n readonly isTablet: boolean;\n /** Whether device is desktop */\n readonly isDesktop: boolean;\n /** Screen width in pixels */\n readonly screenWidth: number;\n /** Screen height in pixels */\n readonly screenHeight: number;\n}\n\n/**\n * Detect if user-agent indicates a mobile device\n * Checks for common mobile device identifiers in user-agent string\n *\n * @param userAgent - Browser user-agent string\n * @returns True if user-agent indicates mobile device\n */\nfunction isMobileUserAgent(userAgent: string): boolean {\n const mobileKeywords = [\n \"Android\",\n \"webOS\",\n \"iPhone\",\n // 'iPad' is handled separately in isTabletUserAgent\n \"iPod\",\n \"BlackBerry\",\n \"IEMobile\",\n \"Opera Mini\",\n \"Mobile\",\n \"mobile\",\n ];\n\n return mobileKeywords.some((keyword) => userAgent.includes(keyword));\n}\n\n/**\n * Detect if user-agent indicates a tablet device\n *\n * @param userAgent - Browser user-agent string\n * @returns True if user-agent indicates tablet\n */\nfunction isTabletUserAgent(userAgent: string): boolean {\n // iPad is always a tablet\n if (userAgent.includes(\"iPad\")) {\n return true;\n }\n\n // Android tablets typically include \"Tablet\" or have Mobile absent\n if (userAgent.includes(\"Android\")) {\n return userAgent.includes(\"Tablet\") || !userAgent.includes(\"Mobile\");\n }\n\n return false;\n}\n\n/**\n * Detect operating system from user-agent\n *\n * @param userAgent - Browser user-agent string\n * @returns Operating system identifier\n */\nfunction detectOS(userAgent: string): PlatformInfo[\"os\"] {\n if (\n userAgent.includes(\"iPhone\") ||\n userAgent.includes(\"iPad\") ||\n userAgent.includes(\"iPod\")\n ) {\n return \"ios\";\n }\n if (userAgent.includes(\"Android\")) {\n return \"android\";\n }\n if (userAgent.includes(\"Windows\")) {\n return \"windows\";\n }\n if (userAgent.includes(\"Mac\")) {\n // Handle iPadOS 13+ in desktop mode, which reports a Mac-like user agent\n // e.g. \"Macintosh; Intel Mac OS X\" but still has touch support\n const isLikelyIPadOSDesktop =\n typeof navigator !== \"undefined\" &&\n typeof navigator.maxTouchPoints === \"number\" &&\n navigator.maxTouchPoints > 1 &&\n userAgent.includes(\"Macintosh\");\n\n if (isLikelyIPadOSDesktop) {\n return \"ios\";\n }\n return \"macos\";\n }\n if (userAgent.includes(\"Linux\")) {\n return \"linux\";\n }\n return \"unknown\";\n}\n\n/**\n * Detect if device has touch capability\n * Uses multiple methods for reliability\n *\n * @returns True if touch is supported\n */\nfunction hasTouchSupport(): boolean {\n // Check for touch events support\n if (\"ontouchstart\" in window) {\n return true;\n }\n\n // Check for touch points (must be defined and > 0)\n if (\n typeof navigator !== \"undefined\" &&\n typeof navigator.maxTouchPoints !== \"undefined\" &&\n navigator.maxTouchPoints > 0\n ) {\n return true;\n }\n\n // Check for pointer events with touch\n if (\n typeof window !== \"undefined\" &&\n window.matchMedia?.(\"(pointer: coarse)\")?.matches\n ) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Mobile screen size breakpoint\n * Devices with width <= this value are considered mobile by size\n */\nexport const MOBILE_BREAKPOINT = 768;\n\n/**\n * Tablet screen size breakpoint\n * Devices with width > MOBILE_BREAKPOINT and <= TABLET_BREAKPOINT are tablets\n */\nexport const TABLET_BREAKPOINT = 1024;\n\n/**\n * Cached CSS environment variable insets\n */\nlet cachedCSSEnvInsets: { top: number; bottom: number } | null = null;\n\n/**\n * Read CSS environment variables for safe area insets\n * Results are cached as they don't change during a session\n */\nfunction readCSSEnvInsets(): { top: number; bottom: number } | null {\n if (cachedCSSEnvInsets !== null) {\n return cachedCSSEnvInsets;\n }\n\n if (typeof window !== \"undefined\" && typeof getComputedStyle === \"function\") {\n try {\n const root = document.documentElement;\n const style = getComputedStyle(root);\n const topEnv = style.getPropertyValue(\"env(safe-area-inset-top)\");\n const bottomEnv = style.getPropertyValue(\"env(safe-area-inset-bottom)\");\n\n if (topEnv || bottomEnv) {\n const result = {\n top: parseInt(topEnv || \"0\", 10) || 0,\n bottom: parseInt(bottomEnv || \"0\", 10) || 0,\n };\n cachedCSSEnvInsets = result;\n return result;\n }\n } catch {\n // Fall through to null\n }\n }\n\n return null;\n}\n\n/**\n * Cached platform information to avoid re-parsing user-agent on every call\n */\nlet cachedPlatform: PlatformInfo | null = null;\nlet cachedScreenWidth = 0;\nlet cachedScreenHeight = 0;\n\n/**\n * Clear the cached platform information\n * Useful when window is resized or device emulation changes\n * Also clears CSS environment variable cache\n *\n * @public\n */\nexport function clearPlatformCache(): void {\n cachedPlatform = null;\n cachedScreenWidth = 0;\n cachedScreenHeight = 0;\n cachedCSSEnvInsets = null;\n}\n\n/**\n * Detect device type and platform information\n *\n * Combines multiple detection methods for reliability:\n * 1. User-agent string analysis (most reliable for device type)\n * 2. Screen dimensions\n * 3. Touch capability\n *\n * This ensures mobile controls are shown on:\n * - Standard mobile phones (< 768px width)\n * - High-resolution phones (>= 768px width but mobile user-agent)\n * - Android 15/16 devices with 2K/4K resolutions (1200px+, 1440px+)\n * - Tablets (user preference via touch support)\n *\n * **User-agent detection takes priority over screen size**, ensuring that\n * high-end Android phones with desktop-class resolutions (e.g., Galaxy S23 Ultra,\n * Pixel 9 Pro) are correctly identified as mobile devices.\n *\n * Results are cached to avoid re-parsing user-agent on every call.\n * Cache is invalidated when screen dimensions change.\n *\n * @returns Complete platform information\n *\n * @example\n * ```typescript\n * const platform = detectPlatform();\n *\n * if (platform.isMobile) {\n * // Show mobile controls even on 4K Android phones\n * return <MobileControls />;\n * }\n * ```\n *\n * @public\n * @korean 플랫폼감지\n */\nexport function detectPlatform(): PlatformInfo {\n const userAgent = typeof navigator !== \"undefined\" ? navigator.userAgent : \"\";\n const screenWidth = typeof window !== \"undefined\" ? window.innerWidth : 1920;\n const screenHeight =\n typeof window !== \"undefined\" ? window.innerHeight : 1080;\n\n // Return cached result if screen dimensions haven't changed\n if (\n cachedPlatform !== null &&\n cachedScreenWidth === screenWidth &&\n cachedScreenHeight === screenHeight\n ) {\n return cachedPlatform;\n }\n\n // Detect OS\n const os = detectOS(userAgent);\n\n // Detect touch capability\n const hasTouch = hasTouchSupport();\n\n // Detect if mobile by user-agent (most reliable method)\n const isMobileUA = isMobileUserAgent(userAgent);\n\n // Detect if tablet by user-agent\n const isTabletUA = isTabletUserAgent(userAgent);\n\n // Detect by screen size (fallback method)\n const isMobileBySize = screenWidth <= MOBILE_BREAKPOINT;\n const isTabletBySize =\n screenWidth > MOBILE_BREAKPOINT && screenWidth <= TABLET_BREAKPOINT;\n\n // Determine device type\n // Priority: User-agent > Screen size\n let deviceType: DeviceType;\n let isMobile: boolean;\n let isTablet: boolean;\n\n if (isMobileUA && !isTabletUA) {\n // User-agent indicates phone\n deviceType = DeviceType.MOBILE;\n isMobile = true;\n isTablet = false;\n } else if (isTabletUA) {\n // User-agent indicates tablet\n deviceType = DeviceType.TABLET;\n isMobile = false;\n isTablet = true;\n } else if (isMobileBySize) {\n // Small screen, assume mobile\n deviceType = DeviceType.MOBILE;\n isMobile = true;\n isTablet = false;\n } else if (isTabletBySize && hasTouch) {\n // Medium screen with touch, assume tablet\n deviceType = DeviceType.TABLET;\n isMobile = false;\n isTablet = true;\n } else {\n // Desktop\n deviceType = DeviceType.DESKTOP;\n isMobile = false;\n isTablet = false;\n }\n\n const isDesktop = deviceType === DeviceType.DESKTOP;\n\n const result: PlatformInfo = {\n os,\n deviceType,\n hasTouch,\n isMobile,\n isTablet,\n isDesktop,\n screenWidth,\n screenHeight,\n };\n\n // Cache the result along with screen dimensions\n cachedPlatform = result;\n cachedScreenWidth = screenWidth;\n cachedScreenHeight = screenHeight;\n\n return result;\n}\n\n/**\n * Simple mobile check for backward compatibility\n * Returns true for both mobile phones and tablets\n *\n * @returns True if device is mobile or tablet\n *\n * @public\n * @korean 모바일확인\n */\nexport function isMobileDevice(): boolean {\n const platform = detectPlatform();\n return platform.isMobile || platform.isTablet;\n}\n\n/**\n * Check if device should use mobile controls\n * Takes into account device type, screen size, and touch capability\n *\n * Uses user-agent detection to correctly identify mobile devices regardless\n * of screen resolution. This ensures high-end Android 15/16 phones with\n * 2K/4K displays (1200px+, 1440px+) show mobile controls.\n *\n * Also ensures tablets and touch-enabled devices always show mobile controls\n * regardless of resolution, for better UX on touch devices.\n *\n * @returns True if mobile controls should be shown\n *\n * @example\n * ```typescript\n * // High-res Android phone (1440x3168) → returns true via user-agent\n * // Desktop with 1440px screen → returns false (no mobile user-agent)\n * // iPad Pro 12.9\" (1024x1366) → returns true (tablet user-agent)\n * // Surface Pro in tablet mode → returns true (touch + tablet size)\n * if (shouldUseMobileControls()) {\n * return <VirtualDPad />; // Touch-optimized controls\n * }\n * ```\n *\n * @public\n * @korean 모바일컨트롤사용\n */\nexport function shouldUseMobileControls(): boolean {\n const platform = detectPlatform();\n\n // Always use mobile controls on phones\n if (platform.isMobile) {\n return true;\n }\n\n // Use mobile controls on tablets (better touch experience)\n if (platform.isTablet) {\n return true;\n }\n\n // Use mobile controls on any touch-enabled device up to tablet breakpoint\n // This catches Windows tablets, Chromebooks in tablet mode, etc.\n if (platform.hasTouch && platform.screenWidth <= TABLET_BREAKPOINT) {\n return true;\n }\n\n // Use mobile controls on small desktop screens with touch\n if (platform.screenWidth <= MOBILE_BREAKPOINT && platform.hasTouch) {\n return true;\n }\n\n return false;\n}\n\n/**\n * Get safe area insets for device\n * Returns appropriate values based on device type and OS\n *\n * For iOS devices, attempts to detect if device has a notch by checking\n * screen dimensions. Falls back to CSS environment variables if available.\n *\n * @returns Safe area insets in pixels\n *\n * @public\n * @korean 안전영역인셋\n */\nexport function getSafeAreaInsets() {\n const platform = detectPlatform();\n\n // iOS devices - distinguish between notched and non-notched\n if (platform.os === \"ios\" && platform.isMobile) {\n // Try to read CSS environment variables first (most accurate)\n const cssEnvInsets = readCSSEnvInsets();\n if (cssEnvInsets) {\n return {\n top: cssEnvInsets.top,\n bottom: cssEnvInsets.bottom,\n left: 0,\n right: 0,\n };\n }\n\n // Detect orientation\n const isLandscape = platform.screenWidth > platform.screenHeight;\n\n // Heuristic: iPhone X and later have notches and specific screen dimensions\n // iPhone X/XS/11 Pro: 375x812, iPhone XR/11: 414x896, iPhone 12/13/14: 390x844, etc.\n // Only devices with height >= 812 (portrait) or width >= 812 (landscape) have notches\n const hasNotch =\n platform.screenHeight >= 812 || platform.screenWidth >= 812;\n\n if (hasNotch) {\n if (isLandscape) {\n // In landscape, notch is on the side\n return {\n top: 0,\n bottom: 21, // Home indicator\n left: 44, // Notch side\n right: 44, // Opposite side for symmetry\n };\n } else {\n // In portrait, notch is at top\n return {\n top: 44,\n bottom: 34,\n left: 0,\n right: 0,\n };\n }\n } else {\n // Older iPhones without notch (iPhone 8, SE, etc.)\n return {\n top: 20, // Status bar height\n bottom: 0,\n left: 0,\n right: 0,\n };\n }\n }\n\n // Android devices (standard status bar)\n if (platform.os === \"android\" && platform.isMobile) {\n return {\n top: 24,\n bottom: 0,\n left: 0,\n right: 0,\n };\n }\n\n // Tablets and desktop - no safe area needed\n return {\n top: 0,\n bottom: 0,\n left: 0,\n right: 0,\n };\n}\n"],"mappings":"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"}