feat: Add motion preset registration API
- 모션 프리셋을 동적으로 등록하고 관리할 수 있는 API를 추가했습니다. - `registerMotionPreset`, `registerMotionPresets`, `unregisterMotionPreset`, `getRegisteredPresets`, `hasPreset`, `resetToBuiltInPresets` 함수를 제공합니다. - `MotionPreset` 타입을 `BuiltInMotionPreset`과 사용자 정의 문자열을 포함하도록 확장했습니다. - `MotionPresetDefinition` 타입을 추가하여 커스텀 프리셋 정의 방식을 명확히 했습니다.
This commit is contained in:
parent
5f6e780b40
commit
4db9839f28
73
dist/index.d.mts
vendored
73
dist/index.d.mts
vendored
@ -13,9 +13,20 @@ interface Point {
|
||||
*/
|
||||
type EasingFunction = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'easeInQuad' | 'easeOutQuad';
|
||||
/**
|
||||
* 모션 프리셋 타입
|
||||
* 내장 모션 프리셋 타입
|
||||
*/
|
||||
type MotionPreset = 'none' | 'horizontal' | 'vertical' | 'rotate-cw' | 'rotate-ccw' | 'pulse' | 'diagonal-1' | 'diagonal-2';
|
||||
type BuiltInMotionPreset = 'none' | 'horizontal' | 'vertical' | 'rotate-cw' | 'rotate-ccw' | 'pulse' | 'diagonal-1' | 'diagonal-2';
|
||||
/**
|
||||
* 모션 프리셋 타입 (내장 + 커스텀)
|
||||
* 커스텀 프리셋은 registerMotionPreset()으로 등록 후 사용
|
||||
*/
|
||||
type MotionPreset = BuiltInMotionPreset | (string & {});
|
||||
/**
|
||||
* 모션 프리셋 정의
|
||||
* @param strength 모션 강도 (기본값: 0.1)
|
||||
* @returns x, y 벡터값
|
||||
*/
|
||||
type MotionPresetDefinition = (strength: number) => Point;
|
||||
/**
|
||||
* 왜곡 애니메이션 움직임 설정
|
||||
*/
|
||||
@ -409,6 +420,62 @@ declare const DEFAULT_AREA: {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 커스텀 모션 프리셋 등록
|
||||
* @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 });
|
||||
*/
|
||||
declare function registerMotionPreset(name: string, definition: MotionPresetDefinition, options?: {
|
||||
isRotation?: boolean;
|
||||
}): void;
|
||||
/**
|
||||
* 여러 프리셋을 한번에 등록
|
||||
* @param presets 프리셋 맵 (이름 → 정의)
|
||||
* @param rotationPresetNames 회전 프리셋 이름 목록
|
||||
*
|
||||
* @example
|
||||
* registerMotionPresets({
|
||||
* 'horizontal-full': (s) => ({x: s * 2, y: 0}),
|
||||
* 'wave': (s) => ({x: s, y: s * 0.3}),
|
||||
* }, ['wave']); // wave는 회전 애니메이션
|
||||
*/
|
||||
declare function registerMotionPresets(presets: Record<string, MotionPresetDefinition>, rotationPresetNames?: string[]): void;
|
||||
/**
|
||||
* 프리셋 등록 해제
|
||||
* @param name 프리셋 이름
|
||||
* @returns 해제 성공 여부
|
||||
*/
|
||||
declare function unregisterMotionPreset(name: string): boolean;
|
||||
/**
|
||||
* 등록된 모든 프리셋 이름 조회
|
||||
* @returns 프리셋 이름 배열
|
||||
*/
|
||||
declare function getRegisteredPresets(): string[];
|
||||
/**
|
||||
* 프리셋 존재 여부 확인
|
||||
* @param name 프리셋 이름
|
||||
* @returns 존재 여부
|
||||
*/
|
||||
declare function hasPreset(name: string): boolean;
|
||||
/**
|
||||
* 내장 프리셋으로 초기화 (커스텀 프리셋 모두 제거)
|
||||
*/
|
||||
declare function resetToBuiltInPresets(): void;
|
||||
/**
|
||||
* 모션 프리셋을 벡터로 변환
|
||||
* @param preset 모션 프리셋
|
||||
@ -586,4 +653,4 @@ declare const useMouseInteraction: (containerRef: React.RefObject<HTMLElement |
|
||||
getInteractingAreaIndices: () => Set<number>;
|
||||
};
|
||||
|
||||
export { ANIMATION_CONFIG, AnimationLoop, type AnimationState, type AnimationTicker, type AreaBounds, AreaList, type AreaListProps, type AreaOutlineStyle, type CenterPointStyle, type CircleLevelStyle, DEFAULT_AREA, DEFAULT_EDITOR_CANVAS_STYLE, type DistortionArea, type DistortionMovement, type EasingFunction, type EditMode, EditorCanvas, type EditorCanvasProps, type EditorCanvasStyle, type EditorState, ImageDistortion, type ImageDistortionProps, type MotionPreset, type MouseInteractionConfig, type MouseState, ParameterPanel, type ParameterPanelProps, type Point, type PointHandleStyle, SHADER_CONFIG, type ShaderConfig, ShaderManager, type ShaderUniforms, SpringPhysics, type SpringPhysicsConfig, type SpringState, ThreeScene, applyEasing, isRotationPreset, presetToVector, useAnimationFrame, useDistortionEditor, useMouseInteraction, useMouseVelocity };
|
||||
export { ANIMATION_CONFIG, AnimationLoop, type AnimationState, type AnimationTicker, type AreaBounds, AreaList, type AreaListProps, type AreaOutlineStyle, type BuiltInMotionPreset, type CenterPointStyle, type CircleLevelStyle, DEFAULT_AREA, DEFAULT_EDITOR_CANVAS_STYLE, type DistortionArea, type DistortionMovement, type EasingFunction, type EditMode, EditorCanvas, type EditorCanvasProps, type EditorCanvasStyle, type EditorState, ImageDistortion, type ImageDistortionProps, type MotionPreset, type MotionPresetDefinition, type MouseInteractionConfig, type MouseState, ParameterPanel, type ParameterPanelProps, type Point, type PointHandleStyle, SHADER_CONFIG, type ShaderConfig, ShaderManager, type ShaderUniforms, SpringPhysics, type SpringPhysicsConfig, type SpringState, ThreeScene, applyEasing, getRegisteredPresets, hasPreset, isRotationPreset, presetToVector, registerMotionPreset, registerMotionPresets, resetToBuiltInPresets, unregisterMotionPreset, useAnimationFrame, useDistortionEditor, useMouseInteraction, useMouseVelocity };
|
||||
|
||||
73
dist/index.d.ts
vendored
73
dist/index.d.ts
vendored
@ -13,9 +13,20 @@ interface Point {
|
||||
*/
|
||||
type EasingFunction = 'linear' | 'easeIn' | 'easeOut' | 'easeInOut' | 'easeInQuad' | 'easeOutQuad';
|
||||
/**
|
||||
* 모션 프리셋 타입
|
||||
* 내장 모션 프리셋 타입
|
||||
*/
|
||||
type MotionPreset = 'none' | 'horizontal' | 'vertical' | 'rotate-cw' | 'rotate-ccw' | 'pulse' | 'diagonal-1' | 'diagonal-2';
|
||||
type BuiltInMotionPreset = 'none' | 'horizontal' | 'vertical' | 'rotate-cw' | 'rotate-ccw' | 'pulse' | 'diagonal-1' | 'diagonal-2';
|
||||
/**
|
||||
* 모션 프리셋 타입 (내장 + 커스텀)
|
||||
* 커스텀 프리셋은 registerMotionPreset()으로 등록 후 사용
|
||||
*/
|
||||
type MotionPreset = BuiltInMotionPreset | (string & {});
|
||||
/**
|
||||
* 모션 프리셋 정의
|
||||
* @param strength 모션 강도 (기본값: 0.1)
|
||||
* @returns x, y 벡터값
|
||||
*/
|
||||
type MotionPresetDefinition = (strength: number) => Point;
|
||||
/**
|
||||
* 왜곡 애니메이션 움직임 설정
|
||||
*/
|
||||
@ -409,6 +420,62 @@ declare const DEFAULT_AREA: {
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* 커스텀 모션 프리셋 등록
|
||||
* @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 });
|
||||
*/
|
||||
declare function registerMotionPreset(name: string, definition: MotionPresetDefinition, options?: {
|
||||
isRotation?: boolean;
|
||||
}): void;
|
||||
/**
|
||||
* 여러 프리셋을 한번에 등록
|
||||
* @param presets 프리셋 맵 (이름 → 정의)
|
||||
* @param rotationPresetNames 회전 프리셋 이름 목록
|
||||
*
|
||||
* @example
|
||||
* registerMotionPresets({
|
||||
* 'horizontal-full': (s) => ({x: s * 2, y: 0}),
|
||||
* 'wave': (s) => ({x: s, y: s * 0.3}),
|
||||
* }, ['wave']); // wave는 회전 애니메이션
|
||||
*/
|
||||
declare function registerMotionPresets(presets: Record<string, MotionPresetDefinition>, rotationPresetNames?: string[]): void;
|
||||
/**
|
||||
* 프리셋 등록 해제
|
||||
* @param name 프리셋 이름
|
||||
* @returns 해제 성공 여부
|
||||
*/
|
||||
declare function unregisterMotionPreset(name: string): boolean;
|
||||
/**
|
||||
* 등록된 모든 프리셋 이름 조회
|
||||
* @returns 프리셋 이름 배열
|
||||
*/
|
||||
declare function getRegisteredPresets(): string[];
|
||||
/**
|
||||
* 프리셋 존재 여부 확인
|
||||
* @param name 프리셋 이름
|
||||
* @returns 존재 여부
|
||||
*/
|
||||
declare function hasPreset(name: string): boolean;
|
||||
/**
|
||||
* 내장 프리셋으로 초기화 (커스텀 프리셋 모두 제거)
|
||||
*/
|
||||
declare function resetToBuiltInPresets(): void;
|
||||
/**
|
||||
* 모션 프리셋을 벡터로 변환
|
||||
* @param preset 모션 프리셋
|
||||
@ -586,4 +653,4 @@ declare const useMouseInteraction: (containerRef: React.RefObject<HTMLElement |
|
||||
getInteractingAreaIndices: () => Set<number>;
|
||||
};
|
||||
|
||||
export { ANIMATION_CONFIG, AnimationLoop, type AnimationState, type AnimationTicker, type AreaBounds, AreaList, type AreaListProps, type AreaOutlineStyle, type CenterPointStyle, type CircleLevelStyle, DEFAULT_AREA, DEFAULT_EDITOR_CANVAS_STYLE, type DistortionArea, type DistortionMovement, type EasingFunction, type EditMode, EditorCanvas, type EditorCanvasProps, type EditorCanvasStyle, type EditorState, ImageDistortion, type ImageDistortionProps, type MotionPreset, type MouseInteractionConfig, type MouseState, ParameterPanel, type ParameterPanelProps, type Point, type PointHandleStyle, SHADER_CONFIG, type ShaderConfig, ShaderManager, type ShaderUniforms, SpringPhysics, type SpringPhysicsConfig, type SpringState, ThreeScene, applyEasing, isRotationPreset, presetToVector, useAnimationFrame, useDistortionEditor, useMouseInteraction, useMouseVelocity };
|
||||
export { ANIMATION_CONFIG, AnimationLoop, type AnimationState, type AnimationTicker, type AreaBounds, AreaList, type AreaListProps, type AreaOutlineStyle, type BuiltInMotionPreset, type CenterPointStyle, type CircleLevelStyle, DEFAULT_AREA, DEFAULT_EDITOR_CANVAS_STYLE, type DistortionArea, type DistortionMovement, type EasingFunction, type EditMode, EditorCanvas, type EditorCanvasProps, type EditorCanvasStyle, type EditorState, ImageDistortion, type ImageDistortionProps, type MotionPreset, type MotionPresetDefinition, type MouseInteractionConfig, type MouseState, ParameterPanel, type ParameterPanelProps, type Point, type PointHandleStyle, SHADER_CONFIG, type ShaderConfig, ShaderManager, type ShaderUniforms, SpringPhysics, type SpringPhysicsConfig, type SpringState, ThreeScene, applyEasing, getRegisteredPresets, hasPreset, isRotationPreset, presetToVector, registerMotionPreset, registerMotionPresets, resetToBuiltInPresets, unregisterMotionPreset, useAnimationFrame, useDistortionEditor, useMouseInteraction, useMouseVelocity };
|
||||
|
||||
90
dist/index.js
vendored
90
dist/index.js
vendored
@ -43,8 +43,14 @@ __export(index_exports, {
|
||||
SpringPhysics: () => SpringPhysics,
|
||||
ThreeScene: () => ThreeScene,
|
||||
applyEasing: () => applyEasing,
|
||||
getRegisteredPresets: () => getRegisteredPresets,
|
||||
hasPreset: () => hasPreset,
|
||||
isRotationPreset: () => isRotationPreset,
|
||||
presetToVector: () => presetToVector,
|
||||
registerMotionPreset: () => registerMotionPreset,
|
||||
registerMotionPresets: () => registerMotionPresets,
|
||||
resetToBuiltInPresets: () => resetToBuiltInPresets,
|
||||
unregisterMotionPreset: () => unregisterMotionPreset,
|
||||
useAnimationFrame: () => useAnimationFrame,
|
||||
useDistortionEditor: () => useDistortionEditor,
|
||||
useMouseInteraction: () => useMouseInteraction,
|
||||
@ -250,31 +256,65 @@ var applyEasing = (progress, easingType) => {
|
||||
};
|
||||
|
||||
// src/utils/motionPresets.ts
|
||||
function presetToVector(preset, strength = 0.1) {
|
||||
switch (preset) {
|
||||
case "none":
|
||||
return { x: 0, y: 0 };
|
||||
case "horizontal":
|
||||
return { x: strength, y: 0 };
|
||||
case "vertical":
|
||||
return { x: 0, y: strength };
|
||||
case "rotate-cw":
|
||||
return { x: strength, y: 0 };
|
||||
case "rotate-ccw":
|
||||
return { x: -strength, y: 0 };
|
||||
case "pulse":
|
||||
return { x: strength, y: strength };
|
||||
case "diagonal-1":
|
||||
return { x: strength * 0.707, y: strength * 0.707 };
|
||||
// √2/2 ≈ 0.707
|
||||
case "diagonal-2":
|
||||
return { x: strength * 0.707, y: -strength * 0.707 };
|
||||
default:
|
||||
return { x: 0, y: 0 };
|
||||
var presetRegistry = /* @__PURE__ */ new Map();
|
||||
var rotationPresets = /* @__PURE__ */ new Set(["rotate-cw", "rotate-ccw"]);
|
||||
var BUILT_IN_PRESETS = {
|
||||
"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);
|
||||
});
|
||||
function registerMotionPreset(name, definition, options) {
|
||||
presetRegistry.set(name, definition);
|
||||
if (options?.isRotation) {
|
||||
rotationPresets.add(name);
|
||||
} else {
|
||||
rotationPresets.delete(name);
|
||||
}
|
||||
}
|
||||
function registerMotionPresets(presets, rotationPresetNames) {
|
||||
Object.entries(presets).forEach(([name, definition]) => {
|
||||
presetRegistry.set(name, definition);
|
||||
});
|
||||
rotationPresetNames?.forEach((name) => rotationPresets.add(name));
|
||||
}
|
||||
function unregisterMotionPreset(name) {
|
||||
rotationPresets.delete(name);
|
||||
return presetRegistry.delete(name);
|
||||
}
|
||||
function getRegisteredPresets() {
|
||||
return Array.from(presetRegistry.keys());
|
||||
}
|
||||
function hasPreset(name) {
|
||||
return presetRegistry.has(name);
|
||||
}
|
||||
function resetToBuiltInPresets() {
|
||||
presetRegistry.clear();
|
||||
rotationPresets.clear();
|
||||
Object.entries(BUILT_IN_PRESETS).forEach(([name, definition]) => {
|
||||
presetRegistry.set(name, definition);
|
||||
});
|
||||
rotationPresets.add("rotate-cw");
|
||||
rotationPresets.add("rotate-ccw");
|
||||
}
|
||||
function presetToVector(preset, strength = 0.1) {
|
||||
const definition = presetRegistry.get(preset);
|
||||
if (definition) {
|
||||
return definition(strength);
|
||||
}
|
||||
console.warn(`Unknown motion preset: "${preset}". Falling back to "none".`);
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
function isRotationPreset(preset) {
|
||||
return preset === "rotate-cw" || preset === "rotate-ccw";
|
||||
if (!preset) return false;
|
||||
return rotationPresets.has(preset);
|
||||
}
|
||||
|
||||
// src/engine/AnimationLoop.ts
|
||||
@ -1616,8 +1656,14 @@ var EditorCanvas = ({
|
||||
SpringPhysics,
|
||||
ThreeScene,
|
||||
applyEasing,
|
||||
getRegisteredPresets,
|
||||
hasPreset,
|
||||
isRotationPreset,
|
||||
presetToVector,
|
||||
registerMotionPreset,
|
||||
registerMotionPresets,
|
||||
resetToBuiltInPresets,
|
||||
unregisterMotionPreset,
|
||||
useAnimationFrame,
|
||||
useDistortionEditor,
|
||||
useMouseInteraction,
|
||||
|
||||
2
dist/index.js.map
vendored
2
dist/index.js.map
vendored
File diff suppressed because one or more lines are too long
84
dist/index.mjs
vendored
84
dist/index.mjs
vendored
@ -196,31 +196,65 @@ var applyEasing = (progress, easingType) => {
|
||||
};
|
||||
|
||||
// src/utils/motionPresets.ts
|
||||
function presetToVector(preset, strength = 0.1) {
|
||||
switch (preset) {
|
||||
case "none":
|
||||
return { x: 0, y: 0 };
|
||||
case "horizontal":
|
||||
return { x: strength, y: 0 };
|
||||
case "vertical":
|
||||
return { x: 0, y: strength };
|
||||
case "rotate-cw":
|
||||
return { x: strength, y: 0 };
|
||||
case "rotate-ccw":
|
||||
return { x: -strength, y: 0 };
|
||||
case "pulse":
|
||||
return { x: strength, y: strength };
|
||||
case "diagonal-1":
|
||||
return { x: strength * 0.707, y: strength * 0.707 };
|
||||
// √2/2 ≈ 0.707
|
||||
case "diagonal-2":
|
||||
return { x: strength * 0.707, y: -strength * 0.707 };
|
||||
default:
|
||||
return { x: 0, y: 0 };
|
||||
var presetRegistry = /* @__PURE__ */ new Map();
|
||||
var rotationPresets = /* @__PURE__ */ new Set(["rotate-cw", "rotate-ccw"]);
|
||||
var BUILT_IN_PRESETS = {
|
||||
"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);
|
||||
});
|
||||
function registerMotionPreset(name, definition, options) {
|
||||
presetRegistry.set(name, definition);
|
||||
if (options?.isRotation) {
|
||||
rotationPresets.add(name);
|
||||
} else {
|
||||
rotationPresets.delete(name);
|
||||
}
|
||||
}
|
||||
function registerMotionPresets(presets, rotationPresetNames) {
|
||||
Object.entries(presets).forEach(([name, definition]) => {
|
||||
presetRegistry.set(name, definition);
|
||||
});
|
||||
rotationPresetNames?.forEach((name) => rotationPresets.add(name));
|
||||
}
|
||||
function unregisterMotionPreset(name) {
|
||||
rotationPresets.delete(name);
|
||||
return presetRegistry.delete(name);
|
||||
}
|
||||
function getRegisteredPresets() {
|
||||
return Array.from(presetRegistry.keys());
|
||||
}
|
||||
function hasPreset(name) {
|
||||
return presetRegistry.has(name);
|
||||
}
|
||||
function resetToBuiltInPresets() {
|
||||
presetRegistry.clear();
|
||||
rotationPresets.clear();
|
||||
Object.entries(BUILT_IN_PRESETS).forEach(([name, definition]) => {
|
||||
presetRegistry.set(name, definition);
|
||||
});
|
||||
rotationPresets.add("rotate-cw");
|
||||
rotationPresets.add("rotate-ccw");
|
||||
}
|
||||
function presetToVector(preset, strength = 0.1) {
|
||||
const definition = presetRegistry.get(preset);
|
||||
if (definition) {
|
||||
return definition(strength);
|
||||
}
|
||||
console.warn(`Unknown motion preset: "${preset}". Falling back to "none".`);
|
||||
return { x: 0, y: 0 };
|
||||
}
|
||||
function isRotationPreset(preset) {
|
||||
return preset === "rotate-cw" || preset === "rotate-ccw";
|
||||
if (!preset) return false;
|
||||
return rotationPresets.has(preset);
|
||||
}
|
||||
|
||||
// src/engine/AnimationLoop.ts
|
||||
@ -1561,8 +1595,14 @@ export {
|
||||
SpringPhysics,
|
||||
ThreeScene,
|
||||
applyEasing,
|
||||
getRegisteredPresets,
|
||||
hasPreset,
|
||||
isRotationPreset,
|
||||
presetToVector,
|
||||
registerMotionPreset,
|
||||
registerMotionPresets,
|
||||
resetToBuiltInPresets,
|
||||
unregisterMotionPreset,
|
||||
useAnimationFrame,
|
||||
useDistortionEditor,
|
||||
useMouseInteraction,
|
||||
|
||||
2
dist/index.mjs.map
vendored
2
dist/index.mjs.map
vendored
File diff suppressed because one or more lines are too long
14
package-lock.json
generated
14
package-lock.json
generated
@ -1,12 +1,13 @@
|
||||
{
|
||||
"name": "responsive-image-canvas",
|
||||
"version": "1.0.0",
|
||||
"name": "@baekryang/responsive-image-canvas",
|
||||
"version": "1.0.5",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "responsive-image-canvas",
|
||||
"version": "1.0.0",
|
||||
"name": "@baekryang/responsive-image-canvas",
|
||||
"version": "1.0.5",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/react": "^19.2.2",
|
||||
"@types/react-dom": "^19.2.2",
|
||||
@ -16,6 +17,11 @@
|
||||
"three": "^0.181.0",
|
||||
"tsup": "^8.5.0",
|
||||
"typescript": "^5.5.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.0.0 || ^19.0.0",
|
||||
"react-dom": "^18.0.0 || ^19.0.0",
|
||||
"three": ">=0.150.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@dimforge/rapier3d-compat": {
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@baekryang/responsive-image-canvas",
|
||||
"version": "1.0.5",
|
||||
"version": "1.1.0",
|
||||
"publishConfig": {
|
||||
"registry": "https://git.bnovalab.com/api/packages/baekryang/npm/"
|
||||
},
|
||||
|
||||
14
src/index.ts
14
src/index.ts
@ -31,7 +31,9 @@ export { DEFAULT_EDITOR_CANVAS_STYLE } from './editor/constants';
|
||||
export type {
|
||||
Point,
|
||||
EasingFunction,
|
||||
BuiltInMotionPreset,
|
||||
MotionPreset,
|
||||
MotionPresetDefinition,
|
||||
DistortionMovement,
|
||||
DistortionArea,
|
||||
AreaBounds,
|
||||
@ -52,7 +54,17 @@ export type {
|
||||
// 유틸리티 함수
|
||||
export { applyEasing } from './utils/easing';
|
||||
export { SHADER_CONFIG, ANIMATION_CONFIG, DEFAULT_AREA } from './utils/constants';
|
||||
export { presetToVector, isRotationPreset } from './utils/motionPresets';
|
||||
export {
|
||||
presetToVector,
|
||||
isRotationPreset,
|
||||
// 프리셋 레지스트리 API
|
||||
registerMotionPreset,
|
||||
registerMotionPresets,
|
||||
unregisterMotionPreset,
|
||||
getRegisteredPresets,
|
||||
hasPreset,
|
||||
resetToBuiltInPresets,
|
||||
} from './utils/motionPresets';
|
||||
|
||||
// 엔진 클래스 (고급 사용자용)
|
||||
export { ThreeScene } from './engine/ThreeScene';
|
||||
|
||||
@ -18,9 +18,9 @@ export type EasingFunction =
|
||||
| 'easeOutQuad';
|
||||
|
||||
/**
|
||||
* 모션 프리셋 타입
|
||||
* 내장 모션 프리셋 타입
|
||||
*/
|
||||
export type MotionPreset =
|
||||
export type BuiltInMotionPreset =
|
||||
| 'none' // 없음 (애니메이션 없음)
|
||||
| 'horizontal' // 좌우 왕복
|
||||
| 'vertical' // 상하 왕복
|
||||
@ -30,6 +30,24 @@ export type MotionPreset =
|
||||
| 'diagonal-1' // 대각선 (좌상→우하)
|
||||
| 'diagonal-2'; // 대각선 (우상→좌하)
|
||||
|
||||
/**
|
||||
* 모션 프리셋 타입 (내장 + 커스텀)
|
||||
* 커스텀 프리셋은 registerMotionPreset()으로 등록 후 사용
|
||||
*/
|
||||
export type MotionPreset = BuiltInMotionPreset | (string & {});
|
||||
|
||||
/**
|
||||
* 모션 프리셋 정의
|
||||
* @param strength 모션 강도 (기본값: 0.1)
|
||||
* @returns x, y 벡터값
|
||||
*/
|
||||
export type MotionPresetDefinition = (strength: number) => Point;
|
||||
|
||||
/**
|
||||
* 회전 프리셋 판별 함수
|
||||
*/
|
||||
export type RotationPresetChecker = (preset: MotionPreset) => boolean;
|
||||
|
||||
/**
|
||||
* 왜곡 애니메이션 움직임 설정
|
||||
*/
|
||||
|
||||
@ -1,4 +1,130 @@
|
||||
import type {MotionPreset, Point} from '../types';
|
||||
import type {MotionPreset, MotionPresetDefinition, Point, RotationPresetChecker} from '../types';
|
||||
|
||||
/**
|
||||
* 프리셋 레지스트리 (내장 + 커스텀)
|
||||
*/
|
||||
const presetRegistry = new Map<string, MotionPresetDefinition>();
|
||||
|
||||
/**
|
||||
* 회전 프리셋 목록
|
||||
*/
|
||||
const rotationPresets = new Set<string>(['rotate-cw', 'rotate-ccw']);
|
||||
|
||||
/**
|
||||
* 내장 프리셋 정의
|
||||
*/
|
||||
const BUILT_IN_PRESETS: Record<string, MotionPresetDefinition> = {
|
||||
'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<string, MotionPresetDefinition>,
|
||||
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');
|
||||
}
|
||||
|
||||
/**
|
||||
* 모션 프리셋을 벡터로 변환
|
||||
@ -7,47 +133,31 @@ import type {MotionPreset, Point} from '../types';
|
||||
* @returns 계산된 벡터 (vectorA)
|
||||
*/
|
||||
export function presetToVector(preset: MotionPreset, strength: number = 0.1): Point {
|
||||
switch (preset) {
|
||||
case 'none':
|
||||
// 애니메이션 없음
|
||||
return {x: 0, y: 0};
|
||||
const definition = presetRegistry.get(preset);
|
||||
|
||||
case 'horizontal':
|
||||
// 좌우 왕복
|
||||
return {x: strength, y: 0};
|
||||
|
||||
case 'vertical':
|
||||
// 상하 왕복
|
||||
return {x: 0, y: strength};
|
||||
|
||||
case 'rotate-cw':
|
||||
// 시계방향 회전 (원운동의 시작점)
|
||||
return {x: strength, y: 0};
|
||||
|
||||
case 'rotate-ccw':
|
||||
// 반시계방향 회전 (원운동의 시작점)
|
||||
return {x: -strength, y: 0};
|
||||
|
||||
case 'pulse':
|
||||
// 펄스 (중심에서 바깥으로)
|
||||
return {x: strength, y: strength};
|
||||
|
||||
case 'diagonal-1':
|
||||
// 대각선 (좌상→우하)
|
||||
return {x: strength * 0.707, y: strength * 0.707}; // √2/2 ≈ 0.707
|
||||
|
||||
case 'diagonal-2':
|
||||
// 대각선 (우상→좌하)
|
||||
return {x: strength * 0.707, y: -strength * 0.707};
|
||||
|
||||
default:
|
||||
return {x: 0, y: 0};
|
||||
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 {
|
||||
return preset === 'rotate-cw' || preset === 'rotate-ccw';
|
||||
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.');
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user