Shifty는 웹에서 가장 빠른 TypeScript 기반 애니메이션 엔진 중 하나로, Tweenable 클래스를 통해 강력한 애니메이션 제어 기능을 제공합니다. 이 문서에서는 Tweenable 클래스의 내부 구현 원리와 고급 사용법을 살펴보며, 개발자가 이를 효과적으로 활용할 수 있도록 안내합니다.
Tweenable 클래스의 기본 구조
Tweenable은 Shifty의 핵심 구성 요소로, src/tweenable.ts 파일에 정의되어 있습니다. 이 클래스는 객체 지향 방식으로 애니메이션 생성, 실행, 관리를 캡슐화하여 다양한 API를 제공합니다.
주요 속성과 초기화
생성자는 초기 상태와 설정 객체를 받아 필요한 속성을 초기화합니다:
constructor(initialState: TweenState = {}, config?: TweenableConfig) {
this._currentState = initialState;
if (config) {
this.applyConfig(config);
}
}
핵심 속성들은 다음과 같습니다:
_currentState: 현재 진행 중인 애니메이션 상태_originalState: 애니메이션 시작 시점의 상태_targetState: 목표 상태_duration: 애니메이션 지속 시간 (기본값 500ms)_easing: 적용된 easing 함수
애니메이션 생명 주기 관리
Tweenable은 애니메이션의 전체 생명 주기를 세밀하게 관리하며, 아래와 같은 주요 메서드를 제공합니다.
tween() - 애니메이션 시작
tween() 메서드는 새로운 애니메이션을 시작하는 진입점입니다. 이미 실행 중인 애니메이션이 있다면 중지하고 새 설정을 적용합니다:
tween(config?: TweenableConfig): Tweenable {
if (this.isPlaying) {
this.halt();
}
if (config || !this.configExists()) {
this.applyConfig(config);
}
this.startTime = Tweenable.getCurrentTime();
this.startAnimation(this.currentState);
return this.continueFrom(this.startTime);
}
applyConfig() - 설정 적용
applyConfig() 메서드는 애니메이션의 시작 상태, 종료 상태, 지속 시간, easing 함수 등을 설정합니다:
applyConfig(config: TweenableConfig = {}): Tweenable {
// 설정 병합
// 상태 초기화
// easing 함수 설정
this._easing = buildEasingMap(this._currentState, config.easing);
return this;
}
제어 관련 메서드
다음과 같은 제어 기능들이 포함되어 있습니다:
- pause(): 애니메이션 일시정지
- resume(): 일시정지된 애니메이션 재개
- halt(): 애니메이션 즉시 종료
- cancel(): 애니메이션 취소 및 Promise 거부
- jumpTo(time): 특정 시간대로 이동
Easing 시스템 구현
Shifty의 easing 시스템은 성능 향상과 유연성을 위해 설계되었습니다. Tweenable 클래스는 정적 속성 easing을 통해 easing 함수들을 관리합니다:
static easing: Record<string, EasingFunction> = { ...standardEasings };
사용자는 커스텀 easing 함수를 등록할 수 있습니다:
Tweenable.easing['easeInQuad'] = (progress: number) => progress * progress;
또한 베지어 곡선을 이용해 easing 효과를 생성할 수도 있습니다:
import { createBezierCurve } from './bezier';
Tweenable.easing['bounceOut'] = createBezierCurve(0.68, -0.55, 0.735, 0.045);
고급 활용 및 팁
Promise 기반 처리
Tweenable은 Promise 인터페이스를 지원하므로 async/await 문법으로도 쉽게 다룰 수 있습니다:
await new Tweenable().tween({
from: { scale: 0 },
to: { scale: 1 },
duration: 800
});
console.log("애니메이션 완료!");
상태 접근 및 변경
getter/setter를 통해 애니메이션 상태를 동적으로 조작할 수 있습니다:
// 현재 상태 확인
const currentState = tweenable.currentState;
// 상태 업데이트
tweenable.updateState({ rotation: 90 });
데이터 바인딩
bindData() 메서드를 사용하면 DOM 요소나 다른 데이터를 애니메이션 인스턴스에 연결하여 콜백에서 사용할 수 있습니다:
tweenable.bindData({ node: element })
.tween({
from: { alpha: 0 },
to: { alpha: 1 },
step: (state, meta, boundData) => {
boundData.node.style.opacity = state.alpha;
}
});
필터 확장
Tweenable.filters를 통해 애니메이션 전후 처리를 확장할 수 있으며, 예를 들어 문자열 보간 기능도 구현 가능합니다:
Tweenable.filters['logFilter'] = {
shouldRun: () => true,
onCreate: (instance) => console.log('New tween created')
};
성능 최적화 팁
- 객체 재사용: 불필요한 인스턴스 생성 대신 기존 인스턴스를 재활용하세요.
- 일시정지 활용: 필요할 때만 애니메이션을 실행해야 한다면 새로 만들기보다 pause/resume을 사용하세요.
- 리소스 해제: 더 이상 사용하지 않는 인스턴스는 dispose()를 호출하여 메모리를 회수하세요.
- 그룹 처리: 여러 애니메이션을 동시에 실행할 경우 공통 타임라인을 사용하는 것이 효율적입니다.