import type {MotionPreset, MotionPresetDefinition, Point, RotationPresetChecker} from '../types'; /** * 프리셋 레지스트리 (내장 + 커스텀) */ const presetRegistry = new Map(); /** * 회전 프리셋 목록 */ const rotationPresets = new Set(['rotate-cw', 'rotate-ccw']); /** * 내장 프리셋 정의 */ const BUILT_IN_PRESETS: Record = { 'none': () => ({x: 0, y: 0}), 'horizontal': (strength) => ({x: strength, y: 0}), 'vertical': (strength) => ({x: 0, y: strength}), 'rotate-cw': (strength) => ({x: strength, y: 0}), 'rotate-ccw': (strength) => ({x: -strength, y: 0}), 'pulse': (strength) => ({x: strength, y: strength}), 'diagonal-1': (strength) => ({x: strength * 0.707, y: strength * 0.707}), 'diagonal-2': (strength) => ({x: strength * 0.707, y: -strength * 0.707}), }; // 내장 프리셋 등록 Object.entries(BUILT_IN_PRESETS).forEach(([name, definition]) => { presetRegistry.set(name, definition); }); /** * 커스텀 모션 프리셋 등록 * @param name 프리셋 이름 * @param definition 프리셋 정의 함수 (strength를 받아 Point 반환) * @param options 추가 옵션 * @param options.isRotation 회전 애니메이션 여부 (true면 원운동) * * @example * // 좌우 진짜 왕복 (좌↔우) * registerMotionPreset('horizontal-full', (strength) => ({ * x: strength * 2, // 진폭 2배 * y: 0 * })); * * // 8자 모양 운동 (회전) * registerMotionPreset('figure-8', (strength) => ({ * x: strength, * y: strength * 0.5 * }), { isRotation: true }); */ export function registerMotionPreset( name: string, definition: MotionPresetDefinition, options?: { isRotation?: boolean } ): void { presetRegistry.set(name, definition); if (options?.isRotation) { rotationPresets.add(name); } else { rotationPresets.delete(name); } } /** * 여러 프리셋을 한번에 등록 * @param presets 프리셋 맵 (이름 → 정의) * @param rotationPresetNames 회전 프리셋 이름 목록 * * @example * registerMotionPresets({ * 'horizontal-full': (s) => ({x: s * 2, y: 0}), * 'wave': (s) => ({x: s, y: s * 0.3}), * }, ['wave']); // wave는 회전 애니메이션 */ export function registerMotionPresets( presets: Record, rotationPresetNames?: string[] ): void { Object.entries(presets).forEach(([name, definition]) => { presetRegistry.set(name, definition); }); rotationPresetNames?.forEach(name => rotationPresets.add(name)); } /** * 프리셋 등록 해제 * @param name 프리셋 이름 * @returns 해제 성공 여부 */ export function unregisterMotionPreset(name: string): boolean { rotationPresets.delete(name); return presetRegistry.delete(name); } /** * 등록된 모든 프리셋 이름 조회 * @returns 프리셋 이름 배열 */ export function getRegisteredPresets(): string[] { return Array.from(presetRegistry.keys()); } /** * 프리셋 존재 여부 확인 * @param name 프리셋 이름 * @returns 존재 여부 */ export function hasPreset(name: string): boolean { return presetRegistry.has(name); } /** * 내장 프리셋으로 초기화 (커스텀 프리셋 모두 제거) */ export function resetToBuiltInPresets(): void { presetRegistry.clear(); rotationPresets.clear(); Object.entries(BUILT_IN_PRESETS).forEach(([name, definition]) => { presetRegistry.set(name, definition); }); rotationPresets.add('rotate-cw'); rotationPresets.add('rotate-ccw'); } /** * 모션 프리셋을 벡터로 변환 * @param preset 모션 프리셋 * @param strength 모션 강도 (기본값: 0.1) * @returns 계산된 벡터 (vectorA) */ export function presetToVector(preset: MotionPreset, strength: number = 0.1): Point { const definition = presetRegistry.get(preset); if (definition) { return definition(strength); } // 등록되지 않은 프리셋은 none으로 처리 console.warn(`Unknown motion preset: "${preset}". Falling back to "none".`); return {x: 0, y: 0}; } /** * 프리셋이 회전 타입인지 확인 */ export function isRotationPreset(preset?: MotionPreset): boolean { if (!preset) return false; return rotationPresets.has(preset); } /** * 커스텀 회전 프리셋 판별 함수 등록 * @param checker 판별 함수 * @deprecated isRotation 옵션을 registerMotionPreset에 전달하세요 */ export function setRotationChecker(checker: RotationPresetChecker): void { // Legacy support - 기존 코드 호환성을 위해 유지 console.warn('setRotationChecker is deprecated. Use registerMotionPreset with { isRotation: true } option instead.'); }