{"version":3,"sources":["../src/components/ImageDistortion.tsx","../src/engine/ThreeScene.ts","../src/engine/ShaderManager.ts","../src/utils/easing.ts","../src/utils/motionPresets.ts","../src/engine/AnimationLoop.ts","../src/hooks/useAnimationFrame.ts","../src/hooks/useMouseInteraction.ts","../src/hooks/useMouseVelocity.ts","../src/engine/SpringPhysics.ts","../src/utils/constants.ts","../src/editor/DistortionEditor.tsx","../src/editor/hooks/useDistortionEditor.ts","../src/editor/components/EditorCanvas.tsx","../src/editor/components/AreaList.tsx","../src/editor/components/ParameterPanel.tsx","../src/editor/constants.ts"],"sourcesContent":["import React, { useEffect, useRef, useState, useCallback } from 'react';\r\nimport * as THREE from 'three';\r\nimport { type DistortionArea } from '@/types';\r\nimport { ThreeScene } from '@/engine/ThreeScene';\r\nimport { ShaderManager } from '@/engine/ShaderManager';\r\nimport { AnimationLoop } from '@/engine/AnimationLoop';\r\nimport { useAnimationFrame } from '@/hooks/useAnimationFrame';\r\nimport { useMouseInteraction } from '@/hooks/useMouseInteraction';\r\nimport { SHADER_CONFIG } from '@/utils/constants';\r\nimport { MouseInteractionConfig } from '@/types/interaction';\r\n\r\n/**\r\n * ImageDistortion 컴포넌트 Props\r\n */\r\nexport interface ImageDistortionProps {\r\n /** 이미지 소스 URL */\r\n imageSrc: string;\r\n /** 왜곡 영역 배열 */\r\n areas: DistortionArea[];\r\n /** 버텍스 셰이더 경로 (선택사항) */\r\n vertexShaderPath?: string;\r\n /** 프래그먼트 셰이더 경로 (선택사항) */\r\n fragmentShaderPath?: string;\r\n /** 애니메이션 재생 여부 */\r\n isPlaying?: boolean;\r\n /** 컨테이너 스타일 */\r\n style?: React.CSSProperties;\r\n /** 컨테이너 클래스명 */\r\n className?: string;\r\n /** 마우스 인터랙션 설정 */\r\n mouseInteraction?: MouseInteractionConfig;\r\n}\r\n\r\n/**\r\n * GPU 가속 이미지 왜곡 컴포넌트\r\n * Three.js와 GLSL 셰이더를 사용하여 실시간 이미지 왜곡 효과를 제공합니다.\r\n */\r\nexport const ImageDistortion: React.FC = ({\r\n imageSrc,\r\n areas,\r\n vertexShaderPath,\r\n fragmentShaderPath,\r\n isPlaying = true,\r\n style,\r\n className,\r\n mouseInteraction,\r\n}) => {\r\n const containerRef = useRef(null);\r\n const sceneRef = useRef(null);\r\n const shaderManagerRef = useRef(new ShaderManager());\r\n const textureRef = useRef(null);\r\n\r\n const [isReady, setIsReady] = useState(false);\r\n const [imageLoaded, setImageLoaded] = useState(false);\r\n const [currentAreas, setCurrentAreas] = useState(areas);\r\n\r\n // 마우스 인터랙션 훅\r\n const mouseInteractionHook = useMouseInteraction(\r\n containerRef,\r\n mouseInteraction || {\r\n enabled: false,\r\n physics: {\r\n stiffness: 100,\r\n damping: 10,\r\n mass: 1,\r\n influenceRadius: 0.2,\r\n maxStrength: 1.0,\r\n },\r\n }\r\n );\r\n\r\n // 영역 변경 시 상태 업데이트\r\n useEffect(() => {\r\n setCurrentAreas(areas);\r\n }, [areas]);\r\n\r\n // 마우스 인터랙션 설정 변경 시 업데이트\r\n useEffect(() => {\r\n if (mouseInteraction) {\r\n mouseInteractionHook.updateConfig(mouseInteraction);\r\n }\r\n }, [mouseInteraction, mouseInteractionHook]);\r\n\r\n // Three.js 씬 초기화\r\n useEffect(() => {\r\n console.log('[ImageDistortion] useEffect 실행, containerRef.current:', containerRef.current);\r\n\r\n if (!containerRef.current) {\r\n console.warn('[ImageDistortion] containerRef.current가 null입니다. 컴포넌트가 제대로 마운트되지 않았습니다.');\r\n return;\r\n }\r\n\r\n console.log('[ImageDistortion] 초기화 시작');\r\n const scene = new ThreeScene(containerRef.current);\r\n sceneRef.current = scene;\r\n\r\n // 셰이더 로드\r\n const vertPath = vertexShaderPath || '/shaders/distortion.vert.glsl';\r\n const fragPath = fragmentShaderPath || '/shaders/distortion.frag.glsl';\r\n\r\n console.log('[ImageDistortion] 셰이더 로드 시도:', { vertPath, fragPath });\r\n\r\n shaderManagerRef.current\r\n .loadShaders(vertPath, fragPath)\r\n .then(({ vertex, fragment }) => {\r\n console.log('[ImageDistortion] 셰이더 로드 성공');\r\n scene.setShaderMaterial(vertex, fragment);\r\n setIsReady(true);\r\n })\r\n .catch((error) => {\r\n console.error('[ImageDistortion] 셰이더 로드 실패:', error);\r\n });\r\n\r\n return () => {\r\n scene.dispose();\r\n if (textureRef.current) {\r\n textureRef.current.dispose();\r\n }\r\n };\r\n }, [vertexShaderPath, fragmentShaderPath]);\r\n\r\n // 이미지 텍스처 로드\r\n useEffect(() => {\r\n if (!imageSrc || !isReady) {\r\n console.log('[ImageDistortion] 이미지 로드 스킵:', { imageSrc, isReady });\r\n return;\r\n }\r\n\r\n console.log('[ImageDistortion] 이미지 로드 시작:', imageSrc);\r\n setImageLoaded(false);\r\n\r\n const loader = new THREE.TextureLoader();\r\n loader.load(\r\n imageSrc,\r\n (texture) => {\r\n console.log('[ImageDistortion] 이미지 로드 성공!', {\r\n width: texture.image.width,\r\n height: texture.image.height\r\n });\r\n textureRef.current = texture;\r\n setImageLoaded(true);\r\n if (sceneRef.current) {\r\n sceneRef.current.updateUniforms({\r\n u_texture: { value: texture },\r\n });\r\n sceneRef.current.render();\r\n console.log('[ImageDistortion] 텍스처 업데이트 및 렌더링 완료');\r\n }\r\n },\r\n (progress) => {\r\n console.log('[ImageDistortion] 이미지 로딩 중...',\r\n Math.round((progress.loaded / progress.total) * 100) + '%'\r\n );\r\n },\r\n (error) => {\r\n console.error('[ImageDistortion] 이미지 로드 실패:', error);\r\n setImageLoaded(false);\r\n }\r\n );\r\n\r\n return () => {\r\n if (textureRef.current) {\r\n textureRef.current.dispose();\r\n textureRef.current = null;\r\n }\r\n };\r\n }, [imageSrc, isReady]);\r\n\r\n // 셰이더 유니폼 업데이트\r\n useEffect(() => {\r\n if (!sceneRef.current || !isReady) return;\r\n\r\n // 현재 해상도 가져오기\r\n const resolution = sceneRef.current.getResolution();\r\n\r\n // 포인트 배열 생성\r\n // UI는 좌상단 (0,0), WebGL은 좌하단 (0,0)이므로 y 좌표를 반전\r\n const points = new Float32Array(SHADER_CONFIG.MAX_POINTS * 2);\r\n currentAreas.forEach((area, areaIndex) => {\r\n area.basePoints.forEach((point, pointIndex) => {\r\n const index = (areaIndex * 4 + pointIndex) * 2;\r\n points[index] = point.x;\r\n points[index + 1] = 1.0 - point.y; // y 좌표 반전\r\n });\r\n });\r\n\r\n // 드래그 벡터 배열 생성\r\n // dragVector도 y 좌표계를 맞춰야 하므로 y를 반전\r\n const dragVectors = new Float32Array(SHADER_CONFIG.MAX_DRAG_VECTORS * 2);\r\n currentAreas.forEach((area, index) => {\r\n const baseIndex = index * 2;\r\n dragVectors[baseIndex] = area.dragVector.x;\r\n dragVectors[baseIndex + 1] = -area.dragVector.y; // y 방향 반전\r\n });\r\n\r\n // 강도 배열 생성\r\n const strengths = new Float32Array(SHADER_CONFIG.MAX_STRENGTHS);\r\n currentAreas.forEach((area, index) => {\r\n strengths[index] = area.distortionStrength;\r\n });\r\n\r\n sceneRef.current.updateUniforms({\r\n u_numAreas: { value: currentAreas.length },\r\n u_points: { value: points },\r\n u_dragVectors: { value: dragVectors },\r\n u_distortionStrengths: { value: strengths },\r\n });\r\n\r\n sceneRef.current.render();\r\n }, [currentAreas, isReady]);\r\n\r\n // 애니메이션 루프\r\n const animationCallback = useCallback((deltaTime: number) => {\r\n if (!isReady) return;\r\n\r\n setCurrentAreas((prevAreas) => {\r\n // 1. 기존 영역 애니메이션 업데이트\r\n let updatedAreas = AnimationLoop.updateProgress(prevAreas, deltaTime);\r\n updatedAreas = AnimationLoop.updateAreaDragVectors(updatedAreas);\r\n\r\n // 2. 마우스 인터랙션 적용 (기존 dragVector에 스프링 변위 추가)\r\n if (mouseInteraction?.enabled) {\r\n updatedAreas = mouseInteractionHook.updateInteraction(updatedAreas, deltaTime);\r\n }\r\n\r\n return updatedAreas;\r\n });\r\n }, [isReady, mouseInteraction, mouseInteractionHook]);\r\n\r\n // 애니메이션은 항상 실행 (마우스 인터랙션 포함)\r\n useAnimationFrame(animationCallback, isPlaying || mouseInteraction?.enabled || false);\r\n\r\n return (\r\n \r\n {!imageLoaded && (\r\n \r\n 이미지 로딩 중...\r\n \r\n )}\r\n \r\n );\r\n};","import * as THREE from 'three';\nimport type { ShaderUniforms } from '@/types';\n\n/**\n * Three.js 씬 관리 클래스\n */\nexport class ThreeScene {\n private scene: THREE.Scene;\n private camera: THREE.OrthographicCamera;\n private renderer: THREE.WebGLRenderer;\n private mesh: THREE.Mesh | null = null;\n private uniforms: ShaderUniforms;\n\n constructor(private container: HTMLElement) {\n // 씬 생성\n this.scene = new THREE.Scene();\n\n // 2D용 직교 카메라 설정\n this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, 0, 1);\n\n // 렌더러 설정\n this.renderer = new THREE.WebGLRenderer({\n antialias: true,\n alpha: false,\n });\n this.renderer.setPixelRatio(window.devicePixelRatio);\n this.container.appendChild(this.renderer.domElement);\n\n // 유니폼 초기화\n this.uniforms = {\n u_resolution: { value: new THREE.Vector2() },\n u_texture: { value: null },\n u_points: { value: new Float32Array(64) }, // 32포인트 × 2(x,y)\n u_numAreas: { value: 0 },\n u_dragVectors: { value: new Float32Array(16) }, // 8벡터 × 2(x,y)\n u_distortionStrengths: { value: new Float32Array(8) },\n };\n\n this.handleResize();\n window.addEventListener('resize', this.handleResize);\n }\n\n /**\n * 윈도우 리사이즈 핸들러\n */\n private handleResize = () => {\n const width = this.container.clientWidth;\n const height = this.container.clientHeight;\n\n this.renderer.setSize(width, height);\n this.uniforms.u_resolution.value.set(width, height);\n\n if (this.mesh) {\n this.render();\n }\n };\n\n /**\n * 셰이더 머티리얼 설정\n * @param vertexShader 버텍스 셰이더 소스\n * @param fragmentShader 프래그먼트 셰이더 소스\n */\n public setShaderMaterial(vertexShader: string, fragmentShader: string) {\n console.log('[ThreeScene] setShaderMaterial 호출됨');\n console.log('[ThreeScene] vertexShader 길이:', vertexShader.length);\n console.log('[ThreeScene] fragmentShader 길이:', fragmentShader.length);\n\n const geometry = new THREE.PlaneGeometry(2, 2);\n const material = new THREE.ShaderMaterial({\n uniforms: this.uniforms,\n vertexShader,\n fragmentShader,\n });\n\n console.log('[ThreeScene] ShaderMaterial 생성됨');\n\n // 셰이더 컴파일 에러 확인\n const renderer = this.renderer;\n const testScene = new THREE.Scene();\n const testMesh = new THREE.Mesh(new THREE.PlaneGeometry(1, 1), material);\n testScene.add(testMesh);\n\n try {\n renderer.compile(testScene, this.camera);\n console.log('[ThreeScene] 셰이더 컴파일 성공!');\n } catch (e) {\n console.error('[ThreeScene] 셰이더 컴파일 에러:', e);\n }\n\n if (this.mesh) {\n this.scene.remove(this.mesh);\n }\n\n this.mesh = new THREE.Mesh(geometry, material);\n this.scene.add(this.mesh);\n console.log('[ThreeScene] mesh를 씬에 추가함');\n }\n\n /**\n * 유니폼 값 업데이트\n * @param updates 업데이트할 유니폼 값들\n */\n public updateUniforms(updates: Partial) {\n Object.keys(updates).forEach((key) => {\n const uniformKey = key as keyof ShaderUniforms;\n this.uniforms[uniformKey].value = updates[uniformKey]!.value;\n });\n }\n\n /**\n * 씬 렌더링\n */\n public render() {\n this.renderer.render(this.scene, this.camera);\n }\n\n /**\n * 현재 해상도 가져오기\n */\n public getResolution(): { x: number; y: number } {\n return {\n x: this.uniforms.u_resolution.value.x,\n y: this.uniforms.u_resolution.value.y,\n };\n }\n\n /**\n * 리소스 정리\n */\n public dispose() {\n window.removeEventListener('resize', this.handleResize);\n this.renderer.dispose();\n if (this.mesh) {\n this.mesh.geometry.dispose();\n (this.mesh.material as THREE.Material).dispose();\n }\n if (this.container.contains(this.renderer.domElement)) {\n this.container.removeChild(this.renderer.domElement);\n }\n }\n}","/**\n * 셰이더 파일 로딩 및 관리 클래스\n */\nexport class ShaderManager {\n private vertexShaderSource: string | null = null;\n private fragmentShaderSource: string | null = null;\n\n /**\n * 셰이더 파일들을 비동기로 로드\n * @param vertexPath 버텍스 셰이더 파일 경로\n * @param fragmentPath 프래그먼트 셰이더 파일 경로\n * @returns 로드된 셰이더 소스 코드\n */\n public async loadShaders(\n vertexPath: string,\n fragmentPath: string\n ): Promise<{ vertex: string; fragment: string }> {\n console.log('[ShaderManager] loadShaders 시작:', { vertexPath, fragmentPath });\n\n try {\n console.log('[ShaderManager] fetch 시작...');\n const [vertexResponse, fragmentResponse] = await Promise.all([\n fetch(vertexPath),\n fetch(fragmentPath),\n ]);\n\n console.log('[ShaderManager] fetch 완료:', {\n vertexStatus: vertexResponse.status,\n fragmentStatus: fragmentResponse.status\n });\n\n if (!vertexResponse.ok) {\n throw new Error(`버텍스 셰이더 로드 실패: ${vertexResponse.statusText}`);\n }\n if (!fragmentResponse.ok) {\n throw new Error(`프래그먼트 셰이더 로드 실패: ${fragmentResponse.statusText}`);\n }\n\n console.log('[ShaderManager] text() 변환 시작...');\n this.vertexShaderSource = await vertexResponse.text();\n this.fragmentShaderSource = await fragmentResponse.text();\n\n console.log('[ShaderManager] 셰이더 로드 완료!', {\n vertexLength: this.vertexShaderSource.length,\n fragmentLength: this.fragmentShaderSource.length\n });\n\n return {\n vertex: this.vertexShaderSource,\n fragment: this.fragmentShaderSource,\n };\n } catch (error) {\n console.error('[ShaderManager] 셰이더 로드 실패:', error);\n throw new Error('셰이더 로딩에 실패했습니다');\n }\n }\n\n /**\n * 버텍스 셰이더 소스 코드 반환\n */\n public getVertexShader(): string {\n if (!this.vertexShaderSource) {\n throw new Error('버텍스 셰이더가 로드되지 않았습니다');\n }\n return this.vertexShaderSource;\n }\n\n /**\n * 프래그먼트 셰이더 소스 코드 반환\n */\n public getFragmentShader(): string {\n if (!this.fragmentShaderSource) {\n throw new Error('프래그먼트 셰이더가 로드되지 않았습니다');\n }\n return this.fragmentShaderSource;\n }\n}","import { type EasingFunction } from '../types';\r\n\r\ntype EasingFunc = (t: number) => number;\r\n\r\n/**\r\n * 이징 함수 구현 맵\r\n */\r\nconst easingFunctions: Record = {\r\n linear: (t) => t,\r\n\r\n easeIn: (t) => t * t,\r\n easeOut: (t) => t * (2 - t),\r\n easeInOut: (t) => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\r\n\r\n easeInQuad: (t) => t * t,\r\n easeOutQuad: (t) => t * (2 - t),\r\n};\r\n\r\n/**\r\n * 진행도에 이징 함수를 적용\r\n * @param progress 진행도 (0.0 - 1.0)\r\n * @param easingType 적용할 이징 함수 타입\r\n * @returns 이징이 적용된 진행도 (0.0 - 1.0)\r\n */\r\nexport const applyEasing = (\r\n progress: number,\r\n easingType: EasingFunction\r\n): number => {\r\n const clampedProgress = Math.max(0, Math.min(1, progress));\r\n return easingFunctions[easingType](clampedProgress);\r\n};","import type {MotionPreset, Point} from '../types';\r\n\r\n/**\r\n * 모션 프리셋을 벡터로 변환\r\n * @param preset 모션 프리셋\r\n * @param strength 모션 강도 (기본값: 0.1)\r\n * @returns 계산된 벡터 (vectorA)\r\n */\r\nexport function presetToVector(preset: MotionPreset, strength: number = 0.1): Point {\r\n\tswitch (preset) {\r\n\t\tcase 'none':\r\n\t\t\t// 애니메이션 없음\r\n\t\t\treturn {x: 0, y: 0};\r\n\r\n\t\tcase 'horizontal':\r\n\t\t\t// 좌우 왕복\r\n\t\t\treturn {x: strength, y: 0};\r\n\r\n\t\tcase 'vertical':\r\n\t\t\t// 상하 왕복\r\n\t\t\treturn {x: 0, y: strength};\r\n\r\n\t\tcase 'rotate-cw':\r\n\t\t\t// 시계방향 회전 (원운동의 시작점)\r\n\t\t\treturn {x: strength, y: 0};\r\n\r\n\t\tcase 'rotate-ccw':\r\n\t\t\t// 반시계방향 회전 (원운동의 시작점)\r\n\t\t\treturn {x: -strength, y: 0};\r\n\r\n\t\tcase 'pulse':\r\n\t\t\t// 펄스 (중심에서 바깥으로)\r\n\t\t\treturn {x: strength, y: strength};\r\n\r\n\t\tcase 'diagonal-1':\r\n\t\t\t// 대각선 (좌상→우하)\r\n\t\t\treturn {x: strength * 0.707, y: strength * 0.707}; // √2/2 ≈ 0.707\r\n\r\n\t\tcase 'diagonal-2':\r\n\t\t\t// 대각선 (우상→좌하)\r\n\t\t\treturn {x: strength * 0.707, y: -strength * 0.707};\r\n\r\n\t\tdefault:\r\n\t\t\treturn {x: 0, y: 0};\r\n\t}\r\n}\r\n\r\n/**\r\n * 프리셋이 회전 타입인지 확인\r\n */\r\nexport function isRotationPreset(preset?: MotionPreset): boolean {\r\n\treturn preset === 'rotate-cw' || preset === 'rotate-ccw';\r\n}\r\n","import { applyEasing } from '../utils/easing';\r\nimport { presetToVector, isRotationPreset } from '../utils/motionPresets';\r\nimport type {DistortionArea, Point} from \"../types\";\r\n\r\n/**\r\n * 애니메이션 루프 관리 클래스\r\n */\r\nexport class AnimationLoop {\r\n /**\r\n * 영역들의 드래그 벡터를 현재 진행도에 따라 업데이트\r\n * @param areas 왜곡 영역 배열\r\n * @returns 업데이트된 영역 배열\r\n */\r\n public static updateAreaDragVectors(\r\n areas: DistortionArea[]\r\n ): DistortionArea[] {\r\n return areas.map((area) => {\r\n const { progress, movement } = area;\r\n\r\n // duration이 0이거나 프리셋이 'none'이면 애니메이션 없음\r\n if (movement.duration <= 0 || movement.preset === 'none') {\r\n return {\r\n ...area,\r\n dragVector: { x: 0, y: 0 },\r\n };\r\n }\r\n\r\n // 프리셋이 설정되어 있으면 프리셋 기반 벡터 사용\r\n let baseVector: Point;\r\n if (movement.preset) {\r\n const strength = movement.strength ?? 0.1;\r\n baseVector = presetToVector(movement.preset, strength);\r\n } else {\r\n // 프리셋 없으면 기존 vectorA 사용 (하위 호환성)\r\n baseVector = movement.vectorA;\r\n }\r\n\r\n // 이징 적용\r\n const easedProgress = applyEasing(progress, movement.easing);\r\n\r\n // 벡터 계산\r\n let dragVector: Point;\r\n\r\n // 회전 프리셋인 경우 원운동\r\n if (movement.preset && isRotationPreset(movement.preset)) {\r\n const angle = easedProgress * Math.PI * 2;\r\n const radius = Math.sqrt(baseVector.x * baseVector.x + baseVector.y * baseVector.y);\r\n const direction = movement.preset === 'rotate-cw' ? 1 : -1;\r\n dragVector = {\r\n x: Math.cos(angle * direction) * radius,\r\n y: Math.sin(angle * direction) * radius,\r\n };\r\n } else {\r\n // 일반 왕복 모션\r\n if (easedProgress < 0.5) {\r\n // 0.0 -> 0.5: 0에서 baseVector로 보간\r\n const t = easedProgress * 2;\r\n dragVector = {\r\n x: baseVector.x * t,\r\n y: baseVector.y * t,\r\n };\r\n } else {\r\n // 0.5 -> 1.0: baseVector에서 0으로 보간\r\n const t = (easedProgress - 0.5) * 2;\r\n dragVector = {\r\n x: baseVector.x * (1 - t),\r\n y: baseVector.y * (1 - t),\r\n };\r\n }\r\n }\r\n\r\n return {\r\n ...area,\r\n dragVector,\r\n };\r\n });\r\n }\r\n\r\n /**\r\n * 모든 영역의 진행도를 델타 타임만큼 업데이트\r\n * @param areas 왜곡 영역 배열\r\n * @param deltaTime 델타 타임 (초)\r\n * @returns 업데이트된 영역 배열\r\n */\r\n public static updateProgress(\r\n areas: DistortionArea[],\r\n deltaTime: number\r\n ): DistortionArea[] {\r\n return areas.map((area) => {\r\n // duration이 0이면 progress 업데이트 안 함\r\n if (area.movement.duration <= 0) {\r\n return area;\r\n }\r\n\r\n let newProgress = area.progress + deltaTime / area.movement.duration;\r\n newProgress %= 1.0; // 루프\r\n\r\n return {\r\n ...area,\r\n progress: newProgress,\r\n };\r\n });\r\n }\r\n}","import { useEffect, useRef } from 'react';\n\n/**\n * requestAnimationFrame을 사용한 애니메이션 루프 훅\n * @param callback 매 프레임마다 호출될 콜백 (deltaTime을 인자로 받음)\n * @param isPlaying 애니메이션 재생 여부\n */\nexport const useAnimationFrame = (\n callback: (deltaTime: number) => void,\n isPlaying: boolean = true\n) => {\n const requestRef = useRef(undefined);\n const previousTimeRef = useRef(undefined);\n\n useEffect(() => {\n if (!isPlaying) return;\n\n const animate = (time: number) => {\n if (previousTimeRef.current !== undefined) {\n const deltaTime = (time - previousTimeRef.current) / 1000; // 밀리초를 초로 변환\n callback(deltaTime);\n }\n previousTimeRef.current = time;\n requestRef.current = requestAnimationFrame(animate);\n };\n\n requestRef.current = requestAnimationFrame(animate);\n\n return () => {\n if (requestRef.current) {\n cancelAnimationFrame(requestRef.current);\n }\n };\n }, [callback, isPlaying]);\n};","import { useRef, useCallback, useState } from 'react';\r\nimport { useMouseVelocity } from './useMouseVelocity';\r\nimport { SpringPhysics } from '@/engine/SpringPhysics';\r\nimport { DistortionArea, Point } from '@/types';\r\nimport { MouseInteractionConfig } from '@/types/interaction';\r\n\r\n/**\r\n * 점이 사각형 내부에 있는지 확인\r\n */\r\nconst isPointInPolygon = (point: Point, polygon: Point[]): boolean => {\r\n\tlet inside = false;\r\n\tfor (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\r\n\t\tconst xi = polygon[i].x, yi = polygon[i].y;\r\n\t\tconst xj = polygon[j].x, yj = polygon[j].y;\r\n\t\tconst intersect = ((yi > point.y) !== (yj > point.y))\r\n\t\t\t&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);\r\n\t\tif (intersect) inside = !inside;\r\n\t}\r\n\treturn inside;\r\n};\r\n\r\n/**\r\n * 마우스 인터랙션 기반 기존 영역 제어 훅\r\n * 마우스가 지나가는 모든 영역에 효과 적용\r\n */\r\nexport const useMouseInteraction = (\r\n\tcontainerRef: React.RefObject,\r\n\tconfig: MouseInteractionConfig\r\n) => {\r\n\tconst { getState } = useMouseVelocity(containerRef);\r\n\tconst [interactingAreaIndices, setInteractingAreaIndices] = useState>(new Set());\r\n\tconst springPhysicsMapRef = useRef>(new Map());\r\n\r\n\t/**\r\n\t * 특정 영역의 스프링 물리 엔진 가져오기 (없으면 생성)\r\n\t */\r\n\tconst getSpringPhysics = useCallback((areaIndex: number): SpringPhysics => {\r\n\t\tif (!springPhysicsMapRef.current.has(areaIndex)) {\r\n\t\t\tspringPhysicsMapRef.current.set(areaIndex, new SpringPhysics(config.physics));\r\n\t\t}\r\n\t\treturn springPhysicsMapRef.current.get(areaIndex)!;\r\n\t}, [config.physics]);\r\n\r\n\t/**\r\n\t * 기존 영역들의 dragVector를 마우스 인터랙션으로 업데이트\r\n\t */\r\n\tconst updateInteraction = useCallback((areas: DistortionArea[], deltaTime: number): DistortionArea[] => {\r\n\t\tif (!config.enabled) return areas;\r\n\r\n\t\tconst mouseState = getState();\r\n\r\n\t\t// 마우스 클릭/드래그 중이고 위치가 있으면\r\n\t\tif (mouseState.isDragging && mouseState.position) {\r\n\t\t\t// 현재 마우스 위치가 포함된 모든 영역 찾기\r\n\t\t\tconst currentlyInAreas = new Set();\r\n\t\t\tfor (let i = 0; i < areas.length; i++) {\r\n\t\t\t\tif (isPointInPolygon(mouseState.position, areas[i].basePoints)) {\r\n\t\t\t\t\tcurrentlyInAreas.add(i);\r\n\r\n\t\t\t\t\t// 새로 진입한 영역이면 스프링 리셋\r\n\t\t\t\t\tif (!interactingAreaIndices.has(i)) {\r\n\t\t\t\t\t\tgetSpringPhysics(i).reset();\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\r\n\t\t\t// 이전에 인터랙션하던 영역에서 벗어났으면 평형으로 복귀\r\n\t\t\tinteractingAreaIndices.forEach((areaIndex) => {\r\n\t\t\t\tif (!currentlyInAreas.has(areaIndex)) {\r\n\t\t\t\t\tgetSpringPhysics(areaIndex).returnToEquilibrium();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\r\n\t\t\t// 인터랙션 영역 업데이트\r\n\t\t\tsetInteractingAreaIndices(currentlyInAreas);\r\n\r\n\t\t\t// 현재 위치의 모든 영역에 속도 적용\r\n\t\t\tconst velocityMult = config.velocityMultiplier || 1.0;\r\n\t\t\tconst velocityMag = Math.sqrt(\r\n\t\t\t\tmouseState.velocity.x ** 2 + mouseState.velocity.y ** 2\r\n\t\t\t);\r\n\t\t\tconst minVel = config.minVelocity || 0.05;\r\n\t\t\tconst maxVel = config.maxVelocity || 5.0;\r\n\r\n\t\t\t// 속도 클램핑\r\n\t\t\tlet clampedVelocity = mouseState.velocity;\r\n\t\t\tif (velocityMag > maxVel) {\r\n\t\t\t\tconst scale = maxVel / velocityMag;\r\n\t\t\t\tclampedVelocity = {\r\n\t\t\t\t\tx: mouseState.velocity.x * scale,\r\n\t\t\t\t\ty: mouseState.velocity.y * scale,\r\n\t\t\t\t};\r\n\t\t\t}\r\n\r\n\t\t\tcurrentlyInAreas.forEach((areaIndex) => {\r\n\t\t\t\tconst spring = getSpringPhysics(areaIndex);\r\n\r\n\t\t\t\tif (velocityMag >= minVel) {\r\n\t\t\t\t\t// 드래그 중: 마우스 속도를 목표로 설정\r\n\t\t\t\t\tspring.setTarget(clampedVelocity, velocityMult);\r\n\t\t\t\t} else {\r\n\t\t\t\t\t// 드래그 중이지만 마우스가 멈춰있으면 평형으로 복귀\r\n\t\t\t\t\tspring.returnToEquilibrium();\r\n\t\t\t\t}\r\n\t\t\t});\r\n\t\t} else {\r\n\t\t\t// 마우스를 놓았으면 인터랙션 중이던 모든 영역에 튕김 효과\r\n\t\t\tif (interactingAreaIndices.size > 0) {\r\n\t\t\t\tconst velocityMult = config.velocityMultiplier || 1.0;\r\n\t\t\t\tconst maxVel = config.maxVelocity || 5.0;\r\n\r\n\t\t\t\t// 속도 클램핑\r\n\t\t\t\tconst velocityMag = Math.sqrt(\r\n\t\t\t\t\tmouseState.velocity.x ** 2 + mouseState.velocity.y ** 2\r\n\t\t\t\t);\r\n\t\t\t\tlet clampedVelocity = mouseState.velocity;\r\n\t\t\t\tif (velocityMag > maxVel) {\r\n\t\t\t\t\tconst scale = maxVel / velocityMag;\r\n\t\t\t\t\tclampedVelocity = {\r\n\t\t\t\t\t\tx: mouseState.velocity.x * scale,\r\n\t\t\t\t\t\ty: mouseState.velocity.y * scale,\r\n\t\t\t\t\t};\r\n\t\t\t\t}\r\n\r\n\t\t\t\t// 모든 인터랙션 영역에 초기 속도 설정\r\n\t\t\t\tinteractingAreaIndices.forEach((areaIndex) => {\r\n\t\t\t\t\tconst spring = getSpringPhysics(areaIndex);\r\n\t\t\t\t\tspring.setInitialVelocity(clampedVelocity, velocityMult);\r\n\t\t\t\t});\r\n\r\n\t\t\t\tsetInteractingAreaIndices(new Set());\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t// 모든 영역의 스프링 물리 업데이트\r\n\t\treturn areas.map((area, index) => {\r\n\t\t\tconst spring = springPhysicsMapRef.current.get(index);\r\n\t\t\tif (!spring) return area;\r\n\r\n\t\t\t// 현재 드래그 중인 영역이거나 스프링이 활성 상태일 때만 업데이트\r\n\t\t\tconst springVelocity = spring.getVelocity();\r\n\t\t\tconst springDisplacement = spring.getDisplacement();\r\n\t\t\tconst isSpringActive = Math.sqrt(springVelocity.x ** 2 + springVelocity.y ** 2) > 0.001 ||\r\n\t\t\t\tMath.sqrt(springDisplacement.x ** 2 + springDisplacement.y ** 2) > 0.001;\r\n\r\n\t\t\t// 드래그 중이 아니고 스프링도 비활성이면 업데이트 안 함\r\n\t\t\tif (!interactingAreaIndices.has(index) && !isSpringActive) {\r\n\t\t\t\treturn area;\r\n\t\t\t}\r\n\r\n\t\t\t// 스프링 물리 업데이트\r\n\t\t\tconst displacement = spring.update(deltaTime);\r\n\r\n\t\t\t// 변위가 거의 0이면 원래 dragVector 유지\r\n\t\t\tconst displacementMag = Math.sqrt(displacement.x ** 2 + displacement.y ** 2);\r\n\t\t\tif (displacementMag < 0.001) {\r\n\t\t\t\treturn area;\r\n\t\t\t}\r\n\r\n\t\t\t// 스프링 변위를 dragVector에 추가 (기존 애니메이션과 혼합)\r\n\t\t\t// dragVector는 텍스처 샘플링 좌표 이동이므로,\r\n\t\t\t// 마우스 드래그 방향과 반대로 적용해야 이미지가 드래그 방향으로 밀림\r\n\t\t\t// 예: 우→좌 드래그(velocity < 0) → dragVector > 0 → 이미지 왼쪽으로 밀림\r\n\t\t\treturn {\r\n\t\t\t\t...area,\r\n\t\t\t\tdragVector: {\r\n\t\t\t\t\tx: area.dragVector.x - displacement.x,\r\n\t\t\t\t\ty: area.dragVector.y - displacement.y,\r\n\t\t\t\t},\r\n\t\t\t};\r\n\t\t});\r\n\t}, [config, getState, interactingAreaIndices, getSpringPhysics]);\r\n\r\n\t/**\r\n\t * 물리 파라미터 업데이트\r\n\t */\r\n\tconst updateConfig = useCallback((newConfig: Partial) => {\r\n\t\tconst physicsConfig = newConfig.physics;\r\n\t\tif (physicsConfig) {\r\n\t\t\t// 모든 스프링 물리 엔진의 설정 업데이트\r\n\t\t\tspringPhysicsMapRef.current.forEach((spring) => {\r\n\t\t\t\tspring.setConfig(physicsConfig);\r\n\t\t\t});\r\n\t\t}\r\n\t}, []);\r\n\r\n\t/**\r\n\t * 모든 영역의 스프링 상태 리셋\r\n\t */\r\n\tconst reset = useCallback(() => {\r\n\t\tspringPhysicsMapRef.current.forEach((spring) => {\r\n\t\t\tspring.reset();\r\n\t\t});\r\n\t\tsetInteractingAreaIndices(new Set());\r\n\t}, []);\r\n\r\n\treturn {\r\n\t\tupdateInteraction,\r\n\t\tupdateConfig,\r\n\t\treset,\r\n\t};\r\n};\r\n","import { useRef, useCallback, useEffect } from 'react';\nimport { Point } from '@/types';\nimport { MouseState } from '@/types/interaction';\n\n/**\n * 마우스 위치, 속도, 가속도를 추적하는 훅\n */\nexport const useMouseVelocity = (containerRef: React.RefObject) => {\n\tconst mouseStateRef = useRef({\n\t\tposition: null,\n\t\tprevPosition: null,\n\t\tvelocity: { x: 0, y: 0 },\n\t\tacceleration: { x: 0, y: 0 },\n\t\tisHovering: false,\n\t\tisDragging: false,\n\t});\n\n\tconst lastUpdateTimeRef = useRef(Date.now());\n\tconst prevVelocityRef = useRef({ x: 0, y: 0 });\n\n\t/**\n\t * 픽셀 좌표를 정규화 좌표(0-1)로 변환\n\t */\n\tconst toNormalized = useCallback((clientX: number, clientY: number): Point | null => {\n\t\tif (!containerRef.current) return null;\n\t\tconst rect = containerRef.current.getBoundingClientRect();\n\t\treturn {\n\t\t\tx: (clientX - rect.left) / rect.width,\n\t\t\ty: (clientY - rect.top) / rect.height,\n\t\t};\n\t}, [containerRef]);\n\n\t/**\n\t * 위치 업데이트 (마우스/터치 공통 로직)\n\t */\n\tconst updatePosition = useCallback((clientX: number, clientY: number) => {\n\t\tconst now = Date.now();\n\t\tconst deltaTime = (now - lastUpdateTimeRef.current) / 1000; // 초 단위\n\t\tlastUpdateTimeRef.current = now;\n\n\t\tconst normalizedPos = toNormalized(clientX, clientY);\n\t\tif (!normalizedPos) return;\n\n\t\tconst state = mouseStateRef.current;\n\t\tconst prevPos = state.position;\n\n\t\t// 속도 계산 (변위 / 시간)\n\t\tlet velocity: Point = { x: 0, y: 0 };\n\t\tif (prevPos && deltaTime > 0) {\n\t\t\tvelocity = {\n\t\t\t\tx: (normalizedPos.x - prevPos.x) / deltaTime,\n\t\t\t\ty: (normalizedPos.y - prevPos.y) / deltaTime,\n\t\t\t};\n\t\t}\n\n\t\t// 가속도 계산 (속도 변화 / 시간)\n\t\tconst prevVel = prevVelocityRef.current;\n\t\tlet acceleration: Point = { x: 0, y: 0 };\n\t\tif (deltaTime > 0) {\n\t\t\tacceleration = {\n\t\t\t\tx: (velocity.x - prevVel.x) / deltaTime,\n\t\t\t\ty: (velocity.y - prevVel.y) / deltaTime,\n\t\t\t};\n\t\t}\n\n\t\t// 상태 업데이트\n\t\tmouseStateRef.current = {\n\t\t\tposition: normalizedPos,\n\t\t\tprevPosition: prevPos,\n\t\t\tvelocity,\n\t\t\tacceleration,\n\t\t\tisHovering: true,\n\t\t\tisDragging: state.isDragging,\n\t\t};\n\t\tprevVelocityRef.current = velocity;\n\t}, [toNormalized]);\n\n\t/**\n\t * 마우스 이동 핸들러\n\t */\n\tconst handleMouseMove = useCallback((e: MouseEvent) => {\n\t\tupdatePosition(e.clientX, e.clientY);\n\t}, [updatePosition]);\n\n\t/**\n\t * 마우스 진입\n\t */\n\tconst handleMouseEnter = useCallback(() => {\n\t\tmouseStateRef.current.isHovering = true;\n\t}, []);\n\n\t/**\n\t * 마우스 나감\n\t */\n\tconst handleMouseLeave = useCallback(() => {\n\t\tmouseStateRef.current = {\n\t\t\tposition: null,\n\t\t\tprevPosition: null,\n\t\t\tvelocity: { x: 0, y: 0 },\n\t\t\tacceleration: { x: 0, y: 0 },\n\t\t\tisHovering: false,\n\t\t\tisDragging: false,\n\t\t};\n\t\tprevVelocityRef.current = { x: 0, y: 0 };\n\t}, []);\n\n\t/**\n\t * 마우스 다운\n\t */\n\tconst handleMouseDown = useCallback(() => {\n\t\tmouseStateRef.current.isDragging = true;\n\t}, []);\n\n\t/**\n\t * 마우스 업\n\t */\n\tconst handleMouseUp = useCallback(() => {\n\t\tmouseStateRef.current.isDragging = false;\n\t}, []);\n\n\t/**\n\t * 터치 이동 핸들러\n\t */\n\tconst handleTouchMove = useCallback((e: TouchEvent) => {\n\t\te.preventDefault(); // 스크롤 방지\n\t\tif (e.touches.length > 0) {\n\t\t\tconst touch = e.touches[0];\n\t\t\tupdatePosition(touch.clientX, touch.clientY);\n\t\t}\n\t}, [updatePosition]);\n\n\t/**\n\t * 터치 시작 핸들러\n\t */\n\tconst handleTouchStart = useCallback((e: TouchEvent) => {\n\t\te.preventDefault(); // 스크롤 방지\n\t\tmouseStateRef.current.isDragging = true;\n\t\tmouseStateRef.current.isHovering = true;\n\t\tif (e.touches.length > 0) {\n\t\t\tconst touch = e.touches[0];\n\t\t\tupdatePosition(touch.clientX, touch.clientY);\n\t\t}\n\t}, [updatePosition]);\n\n\t/**\n\t * 터치 종료 핸들러\n\t */\n\tconst handleTouchEnd = useCallback(() => {\n\t\tmouseStateRef.current.isDragging = false;\n\t\tmouseStateRef.current.isHovering = false;\n\t\tmouseStateRef.current.position = null;\n\t\tmouseStateRef.current.prevPosition = null;\n\t\tmouseStateRef.current.velocity = { x: 0, y: 0 };\n\t\tmouseStateRef.current.acceleration = { x: 0, y: 0 };\n\t\tprevVelocityRef.current = { x: 0, y: 0 };\n\t}, []);\n\n\t/**\n\t * 이벤트 리스너 등록\n\t */\n\tuseEffect(() => {\n\t\tconst container = containerRef.current;\n\t\tif (!container) return;\n\n\t\t// 마우스 이벤트\n\t\tcontainer.addEventListener('mousemove', handleMouseMove);\n\t\tcontainer.addEventListener('mouseenter', handleMouseEnter);\n\t\tcontainer.addEventListener('mouseleave', handleMouseLeave);\n\t\tcontainer.addEventListener('mousedown', handleMouseDown);\n\t\twindow.addEventListener('mouseup', handleMouseUp);\n\n\t\t// 터치 이벤트 (passive: false로 스크롤 방지 가능)\n\t\tcontainer.addEventListener('touchmove', handleTouchMove, { passive: false });\n\t\tcontainer.addEventListener('touchstart', handleTouchStart, { passive: false });\n\t\tcontainer.addEventListener('touchend', handleTouchEnd);\n\t\tcontainer.addEventListener('touchcancel', handleTouchEnd);\n\n\t\treturn () => {\n\t\t\t// 마우스 이벤트 제거\n\t\t\tcontainer.removeEventListener('mousemove', handleMouseMove);\n\t\t\tcontainer.removeEventListener('mouseenter', handleMouseEnter);\n\t\t\tcontainer.removeEventListener('mouseleave', handleMouseLeave);\n\t\t\tcontainer.removeEventListener('mousedown', handleMouseDown);\n\t\t\twindow.removeEventListener('mouseup', handleMouseUp);\n\n\t\t\t// 터치 이벤트 제거\n\t\t\tcontainer.removeEventListener('touchmove', handleTouchMove);\n\t\t\tcontainer.removeEventListener('touchstart', handleTouchStart);\n\t\t\tcontainer.removeEventListener('touchend', handleTouchEnd);\n\t\t\tcontainer.removeEventListener('touchcancel', handleTouchEnd);\n\t\t};\n\t}, [containerRef, handleMouseMove, handleMouseEnter, handleMouseLeave, handleMouseDown, handleMouseUp, handleTouchMove, handleTouchStart, handleTouchEnd]);\n\n\t/**\n\t * 현재 마우스 상태 가져오기\n\t */\n\tconst getState = useCallback((): MouseState => {\n\t\treturn { ...mouseStateRef.current };\n\t}, []);\n\n\treturn {\n\t\tgetState,\n\t};\n};\n","import { Point } from '@/types';\r\nimport { SpringPhysicsConfig, SpringState } from '@/types/interaction';\r\n\r\n/**\r\n * 스프링 기반 물리 시뮬레이션 엔진\r\n * Hooke's Law와 감쇠를 적용한 스프링-댐퍼 시스템\r\n */\r\nexport class SpringPhysics {\r\n\tprivate config: SpringPhysicsConfig;\r\n\tprivate state: SpringState;\r\n\r\n\tconstructor(config: SpringPhysicsConfig) {\r\n\t\tthis.config = config;\r\n\t\tthis.state = {\r\n\t\t\tdisplacement: { x: 0, y: 0 },\r\n\t\t\tvelocity: { x: 0, y: 0 },\r\n\t\t\ttarget: { x: 0, y: 0 },\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * 물리 파라미터 업데이트\r\n\t */\r\n\tpublic setConfig(config: Partial) {\r\n\t\tthis.config = { ...this.config, ...config };\r\n\t}\r\n\r\n\t/**\r\n\t * 목표 위치 설정 (마우스 속도 기반)\r\n\t */\r\n\tpublic setTarget(velocity: Point, velocityMultiplier: number = 1.0) {\r\n\t\t// 속도에 승수를 곱해서 목표 변위로 설정\r\n\t\tthis.state.target = {\r\n\t\t\tx: velocity.x * velocityMultiplier,\r\n\t\t\ty: velocity.y * velocityMultiplier,\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * 초기 속도 설정 (드래그 방향과 속도를 즉시 반영)\r\n\t * 드래그 방향으로 즉시 튕기는 효과\r\n\t */\r\n\tpublic setInitialVelocity(velocity: Point, multiplier: number = 1.0) {\r\n\t\t// 현재 속도를 즉시 변경\r\n\t\tthis.state.velocity = {\r\n\t\t\tx: velocity.x * multiplier,\r\n\t\t\ty: velocity.y * multiplier,\r\n\t\t};\r\n\t\t// 목표는 0 (평형 상태로 돌아가도록)\r\n\t\tthis.state.target = { x: 0, y: 0 };\r\n\t}\r\n\r\n\t/**\r\n\t * 스프링 물리 업데이트 (Hooke's Law + Damping)\r\n\t * F = -k * x - c * v\r\n\t * a = F / m\r\n\t * v += a * dt\r\n\t * x += v * dt\r\n\t */\r\n\tpublic update(deltaTime: number): Point {\r\n\t\tconst { stiffness, damping, mass } = this.config;\r\n\t\tconst { displacement, velocity, target } = this.state;\r\n\r\n\t\t// 평형 위치로부터의 변위 (target은 마우스 속도에서 계산된 목표)\r\n\t\tconst dx = displacement.x - target.x;\r\n\t\tconst dy = displacement.y - target.y;\r\n\r\n\t\t// 스프링 힘: F = -k * x (복원력)\r\n\t\tconst springForceX = -stiffness * dx;\r\n\t\tconst springForceY = -stiffness * dy;\r\n\r\n\t\t// 감쇠 힘: F = -c * v (마찰력)\r\n\t\tconst dampingForceX = -damping * velocity.x;\r\n\t\tconst dampingForceY = -damping * velocity.y;\r\n\r\n\t\t// 총 힘\r\n\t\tconst totalForceX = springForceX + dampingForceX;\r\n\t\tconst totalForceY = springForceY + dampingForceY;\r\n\r\n\t\t// 가속도: a = F / m\r\n\t\tconst accelerationX = totalForceX / mass;\r\n\t\tconst accelerationY = totalForceY / mass;\r\n\r\n\t\t// 속도 업데이트: v += a * dt\r\n\t\tconst newVelocityX = velocity.x + accelerationX * deltaTime;\r\n\t\tconst newVelocityY = velocity.y + accelerationY * deltaTime;\r\n\r\n\t\t// 위치 업데이트: x += v * dt\r\n\t\tconst newDisplacementX = displacement.x + newVelocityX * deltaTime;\r\n\t\tconst newDisplacementY = displacement.y + newVelocityY * deltaTime;\r\n\r\n\t\t// 상태 저장\r\n\t\tthis.state = {\r\n\t\t\tdisplacement: { x: newDisplacementX, y: newDisplacementY },\r\n\t\t\tvelocity: { x: newVelocityX, y: newVelocityY },\r\n\t\t\ttarget,\r\n\t\t};\r\n\r\n\t\t// 매우 작은 움직임은 0으로 처리 (정지 판정)\r\n\t\tconst isNearlyZero = (val: number) => Math.abs(val) < 0.0001;\r\n\t\tif (isNearlyZero(this.state.displacement.x) && isNearlyZero(this.state.displacement.y) &&\r\n\t\t\tisNearlyZero(this.state.velocity.x) && isNearlyZero(this.state.velocity.y)) {\r\n\t\t\tthis.reset();\r\n\t\t}\r\n\r\n\t\treturn this.state.displacement;\r\n\t}\r\n\r\n\t/**\r\n\t * 즉시 충격 적용 (마우스 가속도 기반)\r\n\t */\r\n\tpublic applyImpulse(acceleration: Point, multiplier: number = 1.0) {\r\n\t\t// 가속도를 속도로 변환하여 즉시 적용\r\n\t\tthis.state.velocity.x += acceleration.x * multiplier;\r\n\t\tthis.state.velocity.y += acceleration.y * multiplier;\r\n\t}\r\n\r\n\t/**\r\n\t * 현재 변위 가져오기\r\n\t */\r\n\tpublic getDisplacement(): Point {\r\n\t\treturn { ...this.state.displacement };\r\n\t}\r\n\r\n\t/**\r\n\t * 현재 속도 가져오기\r\n\t */\r\n\tpublic getVelocity(): Point {\r\n\t\treturn { ...this.state.velocity };\r\n\t}\r\n\r\n\t/**\r\n\t * 상태 리셋\r\n\t */\r\n\tpublic reset() {\r\n\t\tthis.state = {\r\n\t\t\tdisplacement: { x: 0, y: 0 },\r\n\t\t\tvelocity: { x: 0, y: 0 },\r\n\t\t\ttarget: { x: 0, y: 0 },\r\n\t\t};\r\n\t}\r\n\r\n\t/**\r\n\t * 마우스가 멈췄을 때 목표를 0으로 설정 (평형 상태로 복귀)\r\n\t */\r\n\tpublic returnToEquilibrium() {\r\n\t\tthis.state.target = { x: 0, y: 0 };\r\n\t}\r\n}\r\n","/**\n * 셰이더 관련 설정\n */\nexport const SHADER_CONFIG = {\n /** 최대 영역 개수 */\n MAX_AREAS: 8,\n /** 최대 포인트 개수 (8영역 × 4포인트) */\n MAX_POINTS: 32,\n /** 최대 드래그 벡터 개수 */\n MAX_DRAG_VECTORS: 8,\n /** 최대 강도 배열 크기 */\n MAX_STRENGTHS: 8,\n} as const;\n\n/**\n * 애니메이션 관련 설정\n */\nexport const ANIMATION_CONFIG = {\n /** 목표 FPS */\n TARGET_FPS: 60,\n /** 델타 타임 (약 16.67ms) */\n DELTA_TIME: 1 / 60,\n} as const;\n\n/**\n * 기본 영역 설정값\n */\nexport const DEFAULT_AREA = {\n /** 기본 왜곡 강도 */\n DISTORTION_STRENGTH: 0.5,\n /** 기본 애니메이션 지속 시간 (초) */\n DURATION: 2.0,\n /** 기본 이징 함수 */\n EASING: 'easeInOut' as const,\n /** 기본 벡터 A */\n VECTOR_A: { x: 0.1, y: 0.1 },\n /** 기본 벡터 B */\n VECTOR_B: { x: -0.1, y: -0.1 },\n} as const;","import React, { useEffect, useState } from 'react';\r\nimport { DistortionArea } from '../types/area';\r\nimport { DistortionEditorProps } from './types';\r\nimport { useDistortionEditor } from './hooks/useDistortionEditor';\r\nimport { EditorCanvas } from './components/EditorCanvas';\r\nimport { AreaList } from './components/AreaList';\r\nimport { ParameterPanel } from './components/ParameterPanel';\r\nimport { DEFAULT_AREA } from '../utils/constants';\r\n\r\nexport const DistortionEditor: React.FC = ({\r\n\tinitialAreas = [],\r\n\timageSrc,\r\n\tonAreasChange,\r\n\tonSelectedAreaChange,\r\n\twidth = 800,\r\n\theight = 600,\r\n\tcanvasStyle,\r\n}) => {\r\n\tconst {\r\n\t\tstate,\r\n\t\tselectArea,\r\n\t\taddArea,\r\n\t\tremoveArea,\r\n\t\tupdateArea,\r\n\t\tupdatePoint,\r\n\t\tstartDragging,\r\n\t\tstopDragging,\r\n\t\tgetSelectedArea,\r\n\t} = useDistortionEditor(initialAreas);\r\n\r\n\t// 에디터 모드 토글 상태\r\n\tconst [showEditor, setShowEditor] = useState(true);\r\n\r\n\t// 영역 변경 시 콜백 호출\r\n\tuseEffect(() => {\r\n\t\tonAreasChange?.(state.areas);\r\n\t}, [state.areas, onAreasChange]);\r\n\r\n\t// 선택된 영역 변경 시 콜백 호출\r\n\tuseEffect(() => {\r\n\t\tonSelectedAreaChange?.(state.selectedAreaId);\r\n\t}, [state.selectedAreaId, onSelectedAreaChange]);\r\n\r\n\t// 새 영역 추가 핸들러\r\n\tconst handleAddArea = () => {\r\n\t\tconst newArea: DistortionArea = {\r\n\t\t\tid: `area-${Date.now()}`,\r\n\t\t\tbasePoints: [\r\n\t\t\t\t{ x: 0.3, y: 0.3 },\r\n\t\t\t\t{ x: 0.7, y: 0.3 },\r\n\t\t\t\t{ x: 0.7, y: 0.7 },\r\n\t\t\t\t{ x: 0.3, y: 0.7 },\r\n\t\t\t],\r\n\t\t\tmovement: {\r\n\t\t\t\tvectorA: { x: DEFAULT_AREA.VECTOR_A.x, y: DEFAULT_AREA.VECTOR_A.y },\r\n\t\t\t\tvectorB: { x: DEFAULT_AREA.VECTOR_B.x, y: DEFAULT_AREA.VECTOR_B.y },\r\n\t\t\t\tduration: DEFAULT_AREA.DURATION,\r\n\t\t\t\teasing: DEFAULT_AREA.EASING as any,\r\n\t\t\t},\r\n\t\t\tdistortionStrength: DEFAULT_AREA.DISTORTION_STRENGTH,\r\n\t\t\tprogress: 0,\r\n\t\t\tdragVector: { x: 0, y: 0 },\r\n\t\t};\r\n\t\taddArea(newArea);\r\n\t};\r\n\r\n\t// 파라미터 업데이트 핸들러\r\n\tconst handleUpdateArea = (updates: Partial) => {\r\n\t\tif (state.selectedAreaId) {\r\n\t\t\tupdateArea(state.selectedAreaId, updates);\r\n\t\t}\r\n\t};\r\n\r\n\tconst selectedArea = getSelectedArea();\r\n\r\n\treturn (\r\n\t\t
\r\n\t\t\t{/* 에디터 모드 토글 버튼 */}\r\n\t\t\t
\r\n\t\t\t\t setShowEditor(!showEditor)}\r\n\t\t\t\t\ttitle={showEditor ? '에디터 숨기기 (왜곡 효과만 보기)' : '에디터 표시'}\r\n\t\t\t\t>\r\n\t\t\t\t\t{showEditor ? '👁️ 에디터 숨기기' : '✏️ 에디터 표시'}\r\n\t\t\t\t\r\n\t\t\t
\r\n\r\n\t\t\t
\r\n\t\t\t\t{/* 왼쪽: 캔버스 */}\r\n\t\t\t\t
\r\n\t\t\t\t\t\r\n\t\t\t\t
\r\n\r\n\t\t\t\t{/* 오른쪽: 사이드바 */}\r\n\t\t\t\t
\r\n\t\t\t\t\t{/* 영역 목록 */}\r\n\t\t\t\t\t\r\n\r\n\t\t\t\t\t{/* 파라미터 패널 */}\r\n\t\t\t\t\t\r\n\t\t\t\t
\r\n\t\t\t
\r\n\t\t
\r\n\t);\r\n};\r\n","import { useState, useCallback } from 'react';\r\nimport { DistortionArea, Point } from '../../types/area';\r\nimport { EditorState } from '../types';\r\n\r\nexport const useDistortionEditor = (initialAreas: DistortionArea[] = []) => {\r\n\tconst [state, setState] = useState({\r\n\t\tselectedAreaId: initialAreas[0]?.id || null,\r\n\t\tareas: initialAreas,\r\n\t\teditMode: 'normal',\r\n\t\tdraggingPointIndex: null,\r\n\t});\r\n\r\n\t/** 영역 선택 */\r\n\tconst selectArea = useCallback((areaId: string | null) => {\r\n\t\tsetState((prev) => ({ ...prev, selectedAreaId: areaId }));\r\n\t}, []);\r\n\r\n\t/** 영역 추가 */\r\n\tconst addArea = useCallback((area: DistortionArea) => {\r\n\t\tsetState((prev) => ({\r\n\t\t\t...prev,\r\n\t\t\tareas: [...prev.areas, area],\r\n\t\t\tselectedAreaId: area.id,\r\n\t\t}));\r\n\t}, []);\r\n\r\n\t/** 영역 삭제 */\r\n\tconst removeArea = useCallback((areaId: string) => {\r\n\t\tsetState((prev) => {\r\n\t\t\tconst newAreas = prev.areas.filter((a) => a.id !== areaId);\r\n\t\t\treturn {\r\n\t\t\t\t...prev,\r\n\t\t\t\tareas: newAreas,\r\n\t\t\t\tselectedAreaId:\r\n\t\t\t\t\tprev.selectedAreaId === areaId ? newAreas[0]?.id || null : prev.selectedAreaId,\r\n\t\t\t};\r\n\t\t});\r\n\t}, []);\r\n\r\n\t/** 영역 업데이트 */\r\n\tconst updateArea = useCallback((areaId: string, updates: Partial) => {\r\n\t\tsetState((prev) => ({\r\n\t\t\t...prev,\r\n\t\t\tareas: prev.areas.map((area) => (area.id === areaId ? { ...area, ...updates } : area)),\r\n\t\t}));\r\n\t}, []);\r\n\r\n\t/** 포인트 업데이트 */\r\n\tconst updatePoint = useCallback((areaId: string, pointIndex: number, point: Point) => {\r\n\t\tsetState((prev) => ({\r\n\t\t\t...prev,\r\n\t\t\tareas: prev.areas.map((area) => {\r\n\t\t\t\tif (area.id === areaId) {\r\n\t\t\t\t\tconst newPoints = [...area.basePoints] as [Point, Point, Point, Point];\r\n\t\t\t\t\tnewPoints[pointIndex] = point;\r\n\t\t\t\t\treturn { ...area, basePoints: newPoints };\r\n\t\t\t\t}\r\n\t\t\t\treturn area;\r\n\t\t\t}),\r\n\t\t}));\r\n\t}, []);\r\n\r\n\t/** 드래그 시작 */\r\n\tconst startDragging = useCallback((pointIndex: number) => {\r\n\t\tsetState((prev) => ({ ...prev, draggingPointIndex: pointIndex }));\r\n\t}, []);\r\n\r\n\t/** 드래그 종료 */\r\n\tconst stopDragging = useCallback(() => {\r\n\t\tsetState((prev) => ({ ...prev, draggingPointIndex: null }));\r\n\t}, []);\r\n\r\n\t/** 편집 모드 변경 */\r\n\tconst setEditMode = useCallback((mode: EditorState['editMode']) => {\r\n\t\tsetState((prev) => ({ ...prev, editMode: mode }));\r\n\t}, []);\r\n\r\n\t/** 선택된 영역 가져오기 */\r\n\tconst getSelectedArea = useCallback(() => {\r\n\t\treturn state.areas.find((a) => a.id === state.selectedAreaId) || null;\r\n\t}, [state.areas, state.selectedAreaId]);\r\n\r\n\treturn {\r\n\t\tstate,\r\n\t\tselectArea,\r\n\t\taddArea,\r\n\t\tremoveArea,\r\n\t\tupdateArea,\r\n\t\tupdatePoint,\r\n\t\tstartDragging,\r\n\t\tstopDragging,\r\n\t\tsetEditMode,\r\n\t\tgetSelectedArea,\r\n\t};\r\n};\r\n","import React, {useRef, useEffect, useState, useCallback, useMemo} from 'react';\r\nimport {DistortionArea, Point} from '@/types';\r\nimport {ImageDistortion} from '@/components/ImageDistortion';\r\nimport {EditorCanvasStyle} from '../types';\r\nimport {DEFAULT_EDITOR_CANVAS_STYLE} from '@/editor';\r\n\r\ninterface EditorCanvasProps {\r\n\tareas: DistortionArea[];\r\n\tselectedAreaId: string | null;\r\n\timageSrc: string;\r\n\twidth: number;\r\n\theight: number;\r\n\tonUpdatePoint: (areaId: string, pointIndex: number, point: Point) => void;\r\n\tonUpdateArea: (areaId: string, updates: Partial) => void;\r\n\tdraggingPointIndex: number | null;\r\n\tonStartDragging: (pointIndex: number) => void;\r\n\tonStopDragging: () => void;\r\n\t/** 에디터 캔버스 스타일 커스터마이징 */\r\n\tstyle?: EditorCanvasStyle;\r\n\t/** 에디터 UI 표시 여부 (기본값: true) */\r\n\tshowEditor?: boolean;\r\n}\r\n\r\nexport const EditorCanvas: React.FC = ({\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t areas,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t selectedAreaId,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t imageSrc,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t width,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t height,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t onUpdatePoint,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t onUpdateArea,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t draggingPointIndex,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t onStartDragging,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t onStopDragging,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t style: customStyle,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t showEditor = true,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t }) => {\r\n\tconst containerRef = useRef(null);\r\n\tconst [canvasSize, setCanvasSize] = useState({width: 0, height: 0});\r\n\tconst [isDraggingArea, setIsDraggingArea] = useState(false);\r\n\tconst [dragStartPos, setDragStartPos] = useState(null);\r\n\r\n\t// 스타일 병합 (커스텀 스타일 우선)\r\n\tconst editorStyle = useMemo(() => ({\r\n\t\t...DEFAULT_EDITOR_CANVAS_STYLE,\r\n\t\t...customStyle,\r\n\t\tcircleLevels: customStyle?.circleLevels || DEFAULT_EDITOR_CANVAS_STYLE.circleLevels,\r\n\t\tcenterPoint: {\r\n\t\t\t...DEFAULT_EDITOR_CANVAS_STYLE.centerPoint,\r\n\t\t\t...customStyle?.centerPoint,\r\n\t\t},\r\n\t\tpointHandle: {\r\n\t\t\t...DEFAULT_EDITOR_CANVAS_STYLE.pointHandle,\r\n\t\t\t...customStyle?.pointHandle,\r\n\t\t},\r\n\t\tareaOutline: {\r\n\t\t\t...DEFAULT_EDITOR_CANVAS_STYLE.areaOutline,\r\n\t\t\t...customStyle?.areaOutline,\r\n\t\t},\r\n\t}), [customStyle]);\r\n\r\n\t// 컨테이너 크기 측정\r\n\tuseEffect(() => {\r\n\t\tif (!containerRef.current) return;\r\n\t\tconst rect = containerRef.current.getBoundingClientRect();\r\n\t\tsetCanvasSize({width: rect.width, height: rect.height});\r\n\t}, [width, height]);\r\n\r\n\t// 선택된 영역 찾기\r\n\tconst selectedArea = areas.find((a) => a.id === selectedAreaId);\r\n\r\n\t// 점이 사각형 내부에 있는지 확인 (Point-in-Polygon test)\r\n\tconst isPointInPolygon = useCallback((point: Point, polygon: Point[]): boolean => {\r\n\t\tlet inside = false;\r\n\t\tfor (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {\r\n\t\t\tconst xi = polygon[i].x, yi = polygon[i].y;\r\n\t\t\tconst xj = polygon[j].x, yj = polygon[j].y;\r\n\r\n\t\t\tconst intersect = ((yi > point.y) !== (yj > point.y))\r\n\t\t\t\t&& (point.x < (xj - xi) * (point.y - yi) / (yj - yi) + xi);\r\n\t\t\tif (intersect) inside = !inside;\r\n\t\t}\r\n\t\treturn inside;\r\n\t}, []);\r\n\r\n\t// 포인트 핸들 클릭/터치 핸들러\r\n\tconst handlePointDown = useCallback(\r\n\t\t(pointIndex: number) => (e: React.MouseEvent | React.TouchEvent) => {\r\n\t\t\te.preventDefault();\r\n\t\t\te.stopPropagation();\r\n\t\t\tonStartDragging(pointIndex);\r\n\t\t},\r\n\t\t[onStartDragging]\r\n\t);\r\n\r\n\t// 캔버스 다운 (마우스/터치 공통)\r\n\tconst handleCanvasDown = useCallback(\r\n\t\t(e: React.MouseEvent | React.TouchEvent) => {\r\n\t\t\t// 에디터가 숨겨진 상태면 동작하지 않음\r\n\t\t\tif (!showEditor || !selectedArea || !containerRef.current) return;\r\n\r\n\t\t\tconst rect = containerRef.current.getBoundingClientRect();\r\n\r\n\t\t\t// 마우스 또는 터치 좌표 추출\r\n\t\t\tlet clientX: number, clientY: number;\r\n\t\t\tif ('touches' in e) {\r\n\t\t\t\tif (e.touches.length === 0) return;\r\n\t\t\t\tclientX = e.touches[0].clientX;\r\n\t\t\t\tclientY = e.touches[0].clientY;\r\n\t\t\t} else {\r\n\t\t\t\tclientX = e.clientX;\r\n\t\t\t\tclientY = e.clientY;\r\n\t\t\t}\r\n\r\n\t\t\tconst x = (clientX - rect.left) / rect.width;\r\n\t\t\tconst y = (clientY - rect.top) / rect.height;\r\n\t\t\tconst clickPoint = { x, y };\r\n\r\n\t\t\t// 사각형 내부를 클릭했는지 확인\r\n\t\t\tif (isPointInPolygon(clickPoint, selectedArea.basePoints)) {\r\n\t\t\t\tsetIsDraggingArea(true);\r\n\t\t\t\tsetDragStartPos(clickPoint);\r\n\t\t\t\te.preventDefault();\r\n\t\t\t}\r\n\t\t},\r\n\t\t[showEditor, selectedArea, isPointInPolygon]\r\n\t);\r\n\r\n\t// 이동 (마우스/터치 공통)\r\n\tconst handleMove = useCallback(\r\n\t\t(e: React.MouseEvent | React.TouchEvent) => {\r\n\t\t\t// 에디터가 숨겨진 상태면 동작하지 않음\r\n\t\t\tif (!showEditor || !selectedArea || !containerRef.current) return;\r\n\r\n\t\t\t// 터치 이벤트면 스크롤 방지\r\n\t\t\tif ('touches' in e && (draggingPointIndex !== null || isDraggingArea)) {\r\n\t\t\t\te.preventDefault();\r\n\t\t\t}\r\n\r\n\t\t\tconst rect = containerRef.current.getBoundingClientRect();\r\n\r\n\t\t\t// 마우스 또는 터치 좌표 추출\r\n\t\t\tlet clientX: number, clientY: number;\r\n\t\t\tif ('touches' in e) {\r\n\t\t\t\tif (e.touches.length === 0) return;\r\n\t\t\t\tclientX = e.touches[0].clientX;\r\n\t\t\t\tclientY = e.touches[0].clientY;\r\n\t\t\t} else {\r\n\t\t\t\tclientX = e.clientX;\r\n\t\t\t\tclientY = e.clientY;\r\n\t\t\t}\r\n\r\n\t\t\tconst x = (clientX - rect.left) / rect.width;\r\n\t\t\tconst y = (clientY - rect.top) / rect.height;\r\n\r\n\t\t\t// 포인트 드래그 중\r\n\t\t\tif (draggingPointIndex !== null) {\r\n\t\t\t\tconst clampedX = Math.max(0, Math.min(1, x));\r\n\t\t\t\tconst clampedY = Math.max(0, Math.min(1, y));\r\n\t\t\t\tonUpdatePoint(selectedArea.id, draggingPointIndex, {x: clampedX, y: clampedY});\r\n\t\t\t}\r\n\t\t\t// 사각형 전체 드래그 중\r\n\t\t\telse if (isDraggingArea && dragStartPos) {\r\n\t\t\t\tconst deltaX = x - dragStartPos.x;\r\n\t\t\t\tconst deltaY = y - dragStartPos.y;\r\n\r\n\t\t\t\t// 모든 포인트를 delta만큼 이동\r\n\t\t\t\tconst newPoints = selectedArea.basePoints.map((point) => ({\r\n\t\t\t\t\tx: Math.max(0, Math.min(1, point.x + deltaX)),\r\n\t\t\t\t\ty: Math.max(0, Math.min(1, point.y + deltaY)),\r\n\t\t\t\t})) as [Point, Point, Point, Point];\r\n\r\n\t\t\t\tonUpdateArea(selectedArea.id, { basePoints: newPoints });\r\n\t\t\t\tsetDragStartPos({ x, y }); // 다음 프레임을 위해 시작 위치 업데이트\r\n\t\t\t}\r\n\t\t},\r\n\t\t[showEditor, draggingPointIndex, isDraggingArea, dragStartPos, selectedArea, onUpdatePoint, onUpdateArea]\r\n\t);\r\n\r\n\t// 업 (마우스/터치 공통)\r\n\tconst handleUp = useCallback(() => {\r\n\t\tif (draggingPointIndex !== null) {\r\n\t\t\tonStopDragging();\r\n\t\t}\r\n\t\tif (isDraggingArea) {\r\n\t\t\tsetIsDraggingArea(false);\r\n\t\t\tsetDragStartPos(null);\r\n\t\t}\r\n\t}, [draggingPointIndex, isDraggingArea, onStopDragging]);\r\n\r\n\t// 전역 업 이벤트 (마우스/터치)\r\n\tuseEffect(() => {\r\n\t\tif (draggingPointIndex !== null || isDraggingArea) {\r\n\t\t\twindow.addEventListener('mouseup', handleUp);\r\n\t\t\twindow.addEventListener('touchend', handleUp);\r\n\t\t\twindow.addEventListener('touchcancel', handleUp);\r\n\t\t\treturn () => {\r\n\t\t\t\twindow.removeEventListener('mouseup', handleUp);\r\n\t\t\t\twindow.removeEventListener('touchend', handleUp);\r\n\t\t\t\twindow.removeEventListener('touchcancel', handleUp);\r\n\t\t\t};\r\n\t\t}\r\n\t}, [draggingPointIndex, isDraggingArea, handleUp]);\r\n\r\n\t// UV 좌표를 픽셀 좌표로 변환 (셰이더와 동일한 bilinear interpolation)\r\n\tconst uvToPixel = (\r\n\t\tu: number,\r\n\t\tv: number,\r\n\t\tpoints: [Point, Point, Point, Point],\r\n\t\tcanvasWidth: number,\r\n\t\tcanvasHeight: number\r\n\t): { x: number; y: number } => {\r\n\t\t// p0=좌상, p1=우상, p2=우하, p3=좌하\r\n\t\tconst [p0, p1, p2, p3] = points;\r\n\r\n\t\t// 셰이더 computeUV와 동일한 순서로 bilinear interpolation\r\n\t\t// left = mix(p0, p1, u) -> 상단 가장자리\r\n\t\t// right = mix(p3, p2, u) -> 하단 가장자리\r\n\t\t// position = mix(left, right, v)\r\n\t\tconst leftX = p0.x * (1 - u) + p1.x * u;\r\n\t\tconst leftY = p0.y * (1 - u) + p1.y * u;\r\n\r\n\t\tconst rightX = p3.x * (1 - u) + p2.x * u;\r\n\t\tconst rightY = p3.y * (1 - u) + p2.y * u;\r\n\r\n\t\tconst posX = leftX * (1 - v) + rightX * v;\r\n\t\tconst posY = leftY * (1 - v) + rightY * v;\r\n\r\n\t\treturn {\r\n\t\t\tx: posX * canvasWidth,\r\n\t\t\ty: posY * canvasHeight,\r\n\t\t};\r\n\t};\r\n\r\n\t// UV 좌표계의 원을 정확히 그리기 (찌그러진 원 형태)\r\n\tconst drawDistortionCircle = useCallback((\r\n\t\tctx: CanvasRenderingContext2D,\r\n\t\tpoints: [Point, Point, Point, Point],\r\n\t\tcanvasWidth: number,\r\n\t\tcanvasHeight: number\r\n\t) => {\r\n\t\tconst segments = 128; // 원을 128개 세그먼트로 촘촘히 분할\r\n\t\tconst centerU = 0.5;\r\n\t\tconst centerV = 0.5;\r\n\r\n\t\tconst circleLevels = editorStyle.circleLevels || [];\r\n\r\n\t\t// 원 레벨별로 그리기 (외부 -> 내부 순)\r\n\t\tcircleLevels.forEach((level, index) => {\r\n\t\t\tconst levelPoints: { x: number; y: number }[] = [];\r\n\t\t\tfor (let i = 0; i <= segments; i++) {\r\n\t\t\t\tconst theta = (i / segments) * 2 * Math.PI;\r\n\t\t\t\tconst u = centerU - level.radius * Math.sin(theta);\r\n\t\t\t\tconst v = centerV + level.radius * Math.cos(theta);\r\n\t\t\t\tconst pixelPos = uvToPixel(u, v, points, canvasWidth, canvasHeight);\r\n\t\t\t\tlevelPoints.push(pixelPos);\r\n\t\t\t}\r\n\r\n\t\t\tctx.beginPath();\r\n\t\t\tctx.moveTo(levelPoints[0].x, levelPoints[0].y);\r\n\t\t\tfor (let i = 1; i < levelPoints.length; i++) {\r\n\t\t\t\tctx.lineTo(levelPoints[i].x, levelPoints[i].y);\r\n\t\t\t}\r\n\t\t\tctx.closePath();\r\n\r\n\t\t\t// 원 테두리\r\n\t\t\tconst baseColor = level.color || 'rgba(255, 200, 0, 1)';\r\n\t\t\t// baseColor에서 RGB 추출하고 opacity 적용\r\n\t\t\tconst colorWithOpacity = baseColor.replace(/rgba?\\(([^)]+)\\)/, (_, rgb) => {\r\n\t\t\t\tconst parts = rgb.split(',').map((p: string) => p.trim());\r\n\t\t\t\treturn `rgba(${parts[0]}, ${parts[1]}, ${parts[2]}, ${level.opacity})`;\r\n\t\t\t});\r\n\t\t\tctx.strokeStyle = colorWithOpacity;\r\n\t\t\tctx.lineWidth = level.lineWidth;\r\n\t\t\tif (level.dashPattern) {\r\n\t\t\t\tctx.setLineDash(level.dashPattern);\r\n\t\t\t}\r\n\t\t\tctx.stroke();\r\n\t\t\tctx.setLineDash([]);\r\n\r\n\t\t\t// 가장 외부 원만 내부 채우기\r\n\t\t\tif (index === 0 && editorStyle.circleFillColor) {\r\n\t\t\t\tctx.fillStyle = editorStyle.circleFillColor;\r\n\t\t\t\tctx.fill();\r\n\t\t\t}\r\n\t\t});\r\n\r\n\t\t// 중심점 표시\r\n\t\tconst centerPointStyle = editorStyle.centerPoint || {};\r\n\t\tconst centerPixel = uvToPixel(centerU, centerV, points, canvasWidth, canvasHeight);\r\n\t\tctx.beginPath();\r\n\t\tctx.arc(centerPixel.x, centerPixel.y, centerPointStyle.radius || 5, 0, 2 * Math.PI);\r\n\t\tif (centerPointStyle.fillColor) {\r\n\t\t\tctx.fillStyle = centerPointStyle.fillColor;\r\n\t\t\tctx.fill();\r\n\t\t}\r\n\t\tif (centerPointStyle.strokeColor) {\r\n\t\t\tctx.strokeStyle = centerPointStyle.strokeColor;\r\n\t\t\tctx.lineWidth = centerPointStyle.strokeWidth || 2;\r\n\t\t\tctx.stroke();\r\n\t\t}\r\n\t}, [editorStyle]);\r\n\r\n\t// 커서 스타일 결정\r\n\tconst getCursorStyle = () => {\r\n\t\tif (draggingPointIndex !== null) return 'grabbing';\r\n\t\tif (isDraggingArea) return 'grabbing';\r\n\t\treturn 'default';\r\n\t};\r\n\r\n\treturn (\r\n\t\t\r\n\t\t\t{/* ImageDistortion 컴포넌트 */}\r\n\t\t\t\r\n\r\n\t\t\t{/* 오버레이 SVG - 에디터 모드일 때만 표시 */}\r\n\t\t\t{showEditor && (\r\n\t\t\t\t\r\n\t\t\t\t\t{/* 모든 영역의 사각형 표시 */}\r\n\t\t\t\t\t{areas.map((area) => {\r\n\t\t\t\t\tconst isSelected = area.id === selectedAreaId;\r\n\t\t\t\t\tconst points = area.basePoints;\r\n\t\t\t\t\tconst outlineStyle = editorStyle.areaOutline || {};\r\n\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t{/* 사각형 배경 및 경계선 */}\r\n\t\t\t\t\t\t\t `${p.x * canvasSize.width},${p.y * canvasSize.height}`)\r\n\t\t\t\t\t\t\t\t\t.join(' ')}\r\n\t\t\t\t\t\t\t\tfill={isSelected ? (outlineStyle.selectedFillColor || 'rgba(0, 170, 255, 0.08)') : (outlineStyle.unselectedFillColor || 'rgba(136, 136, 136, 0.03)')}\r\n\t\t\t\t\t\t\t\tstroke={isSelected ? (outlineStyle.selectedColor || '#00aaff') : (outlineStyle.unselectedColor || '#888')}\r\n\t\t\t\t\t\t\t\tstrokeWidth={isSelected ? (outlineStyle.selectedWidth || 2) : (outlineStyle.unselectedWidth || 1)}\r\n\t\t\t\t\t\t\t\tstrokeDasharray={isSelected ? '0' : (outlineStyle.unselectedDashPattern?.join(',') || '5,5')}\r\n\t\t\t\t\t\t\t\topacity={isSelected ? 1 : 0.5}\r\n\t\t\t\t\t\t\t/>\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t);\r\n\t\t\t\t\t})}\r\n\t\t\t\t\r\n\t\t\t)}\r\n\r\n\t\t\t{/* 선택된 영역의 타원 가이드 (Canvas로 그리기) - 에디터 모드일 때만 표시 */}\r\n\t\t\t{showEditor && selectedArea && canvasSize.width > 0 && (\r\n\t\t\t\t {\r\n\t\t\t\t\t\tif (canvas) {\r\n\t\t\t\t\t\t\tconst ctx = canvas.getContext('2d');\r\n\t\t\t\t\t\t\tif (ctx) {\r\n\t\t\t\t\t\t\t\tctx.clearRect(0, 0, canvasSize.width, canvasSize.height);\r\n\t\t\t\t\t\t\t\tdrawDistortionCircle(ctx, selectedArea.basePoints, canvasSize.width, canvasSize.height);\r\n\t\t\t\t\t\t\t}\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}}\r\n\t\t\t\t/>\r\n\t\t\t)}\r\n\r\n\t\t\t{/* 선택된 영역의 포인트 핸들 - 에디터 모드일 때만 표시 */}\r\n\t\t\t{showEditor && selectedArea &&\r\n\t\t\t\tselectedArea.basePoints.map((point, index) => {\r\n\t\t\t\t\tconst handleStyle = editorStyle.pointHandle || {};\r\n\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\tP{index + 1}\r\n\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t);\r\n\t\t\t\t})}\r\n\t\t\r\n\t);\r\n};\r\n","import React from 'react';\nimport { DistortionArea } from '../../types/area';\n\ninterface AreaListProps {\n\tareas: DistortionArea[];\n\tselectedAreaId: string | null;\n\tonSelectArea: (areaId: string) => void;\n\tonRemoveArea: (areaId: string) => void;\n\tonAddArea: () => void;\n}\n\nexport const AreaList: React.FC = ({\n\tareas,\n\tselectedAreaId,\n\tonSelectArea,\n\tonRemoveArea,\n\tonAddArea,\n}) => {\n\treturn (\n\t\t
\n\t\t\t
\n\t\t\t\t

왜곡 영역

\n\t\t\t\t= 8}\n\t\t\t\t\tclassName=\"btn-add\"\n\t\t\t\t\ttitle={areas.length >= 8 ? '최대 8개 영역까지 지원' : '새 영역 추가'}\n\t\t\t\t>\n\t\t\t\t\t+ 추가\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t\t{areas.length === 0 ? (\n\t\t\t\t\t
영역이 없습니다. + 추가 버튼을 눌러주세요.
\n\t\t\t\t) : (\n\t\t\t\t\tareas.map((area, index) => (\n\t\t\t\t\t\t onSelectArea(area.id)}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t\t영역 {index + 1}\n\t\t\t\t\t\t\t\t강도: {(area.distortionStrength * 100).toFixed(0)}%\n\t\t\t\t\t\t\t
\n\t\t\t\t\t\t\t {\n\t\t\t\t\t\t\t\t\te.stopPropagation();\n\t\t\t\t\t\t\t\t\tonRemoveArea(area.id);\n\t\t\t\t\t\t\t\t}}\n\t\t\t\t\t\t\t\tclassName=\"btn-remove\"\n\t\t\t\t\t\t\t\ttitle=\"영역 삭제\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t×\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
\n\t\t\t\t\t))\n\t\t\t\t)}\n\t\t\t
\n\t\t\n\t);\n};\n","import React from 'react';\nimport { DistortionArea, EasingFunction } from '../../types/area';\n\ninterface ParameterPanelProps {\n\tarea: DistortionArea | null;\n\tonUpdateArea: (updates: Partial) => void;\n}\n\nconst EASING_OPTIONS: { value: EasingFunction; label: string }[] = [\n\t{ value: 'linear', label: '선형 (Linear)' },\n\t{ value: 'easeIn', label: '가속 (Ease In)' },\n\t{ value: 'easeOut', label: '감속 (Ease Out)' },\n\t{ value: 'easeInOut', label: '가감속 (Ease In Out)' },\n\t{ value: 'easeInQuad', label: '가속² (Ease In Quad)' },\n\t{ value: 'easeOutQuad', label: '감속² (Ease Out Quad)' },\n];\n\nexport const ParameterPanel: React.FC = ({ area, onUpdateArea }) => {\n\tif (!area) {\n\t\treturn (\n\t\t\t
\n\t\t\t\t
영역을 선택해주세요
\n\t\t\t
\n\t\t);\n\t}\n\n\treturn (\n\t\t
\n\t\t\t

파라미터 편집

\n\n\t\t\t{/* 왜곡 강도 */}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t onUpdateArea({ distortionStrength: parseFloat(e.target.value) })}\n\t\t\t\t\tclassName=\"slider\"\n\t\t\t\t/>\n\t\t\t
\n\n\t\t\t{/* 애니메이션 지속 시간 */}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\tonUpdateArea({\n\t\t\t\t\t\t\tmovement: { ...area.movement, duration: parseFloat(e.target.value) },\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"input-number\"\n\t\t\t\t/>\n\t\t\t
\n\n\t\t\t{/* 이징 함수 */}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\tonUpdateArea({\n\t\t\t\t\t\t\tmovement: { ...area.movement, easing: e.target.value as EasingFunction },\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"select\"\n\t\t\t\t>\n\t\t\t\t\t{EASING_OPTIONS.map((option) => (\n\t\t\t\t\t\t\n\t\t\t\t\t))}\n\t\t\t\t\n\t\t\t
\n\n\t\t\t{/* 벡터 A (X) */}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\tonUpdateArea({\n\t\t\t\t\t\t\tmovement: {\n\t\t\t\t\t\t\t\t...area.movement,\n\t\t\t\t\t\t\t\tvectorA: { ...area.movement.vectorA, x: parseFloat(e.target.value) },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"slider\"\n\t\t\t\t/>\n\t\t\t
\n\n\t\t\t{/* 벡터 A (Y) */}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\tonUpdateArea({\n\t\t\t\t\t\t\tmovement: {\n\t\t\t\t\t\t\t\t...area.movement,\n\t\t\t\t\t\t\t\tvectorA: { ...area.movement.vectorA, y: parseFloat(e.target.value) },\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t})\n\t\t\t\t\t}\n\t\t\t\t\tclassName=\"slider\"\n\t\t\t\t/>\n\t\t\t
\n\n\t\t\t{/* 포인트 좌표 (읽기 전용 표시) */}\n\t\t\t
\n\t\t\t\t\n\t\t\t\t
\n\t\t\t\t\t{area.basePoints.map((point, idx) => (\n\t\t\t\t\t\t
\n\t\t\t\t\t\t\tP{idx + 1}: ({point.x.toFixed(3)}, {point.y.toFixed(3)})\n\t\t\t\t\t\t
\n\t\t\t\t\t))}\n\t\t\t\t
\n\t\t\t
\n\t\t
\n\t);\n};\n","import { EditorCanvasStyle } from './types';\n\n/**\n * 기본 에디터 캔버스 스타일\n */\nexport const DEFAULT_EDITOR_CANVAS_STYLE: EditorCanvasStyle = {\n\t// 3단계 원 스타일 (외부 -> 내부)\n\tcircleLevels: [\n\t\t{\n\t\t\tradius: 0.5,\n\t\t\topacity: 0.3,\n\t\t\tlineWidth: 2,\n\t\t\tcolor: 'rgba(255, 200, 0, 1)',\n\t\t\tdashPattern: [8, 4],\n\t\t},\n\t\t{\n\t\t\tradius: 0.33,\n\t\t\topacity: 0.6,\n\t\t\tlineWidth: 2.5,\n\t\t\tcolor: 'rgba(255, 200, 0, 1)',\n\t\t\tdashPattern: [8, 4],\n\t\t},\n\t\t{\n\t\t\tradius: 0.167,\n\t\t\topacity: 0.9,\n\t\t\tlineWidth: 3,\n\t\t\tcolor: 'rgba(255, 200, 0, 1)',\n\t\t\tdashPattern: [8, 4],\n\t\t},\n\t],\n\t// 원 내부 채우기\n\tcircleFillColor: 'rgba(255, 200, 0, 0.08)',\n\t// 중심점\n\tcenterPoint: {\n\t\tradius: 5,\n\t\tfillColor: 'rgba(255, 200, 0, 1)',\n\t\tstrokeColor: 'rgba(255, 255, 255, 0.8)',\n\t\tstrokeWidth: 2,\n\t},\n\t// 포인트 핸들\n\tpointHandle: {\n\t\tsize: 16,\n\t\tfillColor: '#00aaff',\n\t\tstrokeColor: 'white',\n\t\tstrokeWidth: 2,\n\t\tlabelColor: '#00aaff',\n\t\tlabelFontSize: 11,\n\t},\n\t// 영역 외곽선\n\tareaOutline: {\n\t\tselectedColor: '#00aaff',\n\t\tunselectedColor: '#888',\n\t\tselectedWidth: 2,\n\t\tunselectedWidth: 1,\n\t\tunselectedDashPattern: [5, 5],\n\t\tselectedFillColor: 'rgba(0, 170, 255, 0.08)', // 선택된 영역 배경 (연한 파란색)\n\t\tunselectedFillColor: 'rgba(136, 136, 136, 0.03)', // 선택 안된 영역 배경 (연한 회색)\n\t},\n};\n"],"mappings":"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","names":["useEffect","useRef","useState","useCallback","THREE","useRef","useCallback","useRef","useEffect","useRef","useCallback","useRef","useState","useEffect","useCallback","useEffect","useState","useState","useCallback","useRef","useEffect","useState","useCallback","jsx","useRef","useState","useEffect","isPointInPolygon","useCallback","jsx","jsxs","jsx","jsxs","jsx","jsxs","useState","useEffect"]}