애니메이션

단순한 키프레임을 넘어 동적, 절차적, 표현 기반 애니메이션을 생성하기 위한 고급 애니메이션 시스템입니다.

애니메이션 유형

애니메이션 시스템은 전통적인 키프레임 외에 여러 유형을 지원합니다:

  • 표현: 프레임별로 평가되는 JavaScript 표현
  • 절차적: 내장된 절차적 애니메이션 패턴
  • 시퀀스: 단계 기반의 순차적 애니메이션
  • 경로: 베지어 경로를 따라 움직임

이러한 고급 애니메이션은 요소의 animations 배열 속성에 정의됩니다.

노드 애니메이션 vs 키프레임

노드 애니메이션 (animations 배열):

  • 절차적, 표현 기반, 또는 경로를 따르는 애니메이션
  • 매 프레임마다 평가됨
  • 키프레임보다 높은 우선순위
  • 키프레임 값을 재정의할 수 있음

키프레임 (keyframes 배열):

  • 정의된 점 사이의 간단한 속성 보간
  • 낮은 우선순위
  • 예측 가능하고 편집하기 쉬움

애니메이션 우선순위

여러 애니메이션 방법이 동일한 속성을 목표로 할 때:

  1. 가장 높음: 노드 애니메이션 (표현, 절차적, 경로, 시퀀스)
  2. 중간: 키프레임 애니메이션
  3. 가장 낮음: 정적 속성 값
소품유형필수예시값 범위설명
typestringtrue-expression | procedural | sequence | path애니메이션의 유형입니다.
enabledbooleanfalse--애니메이션이 활성화되어 있는지 여부입니다.
targetstringtrue--애니메이션할 속성 경로 (예: "x", "rotation", "scaleX")입니다.
startTimenumberfalse--요소 시작에 대한 애니메이션의 시작 시간(초)입니다.
durationnumberfalse--애니메이션의 지속 시간(초)입니다. 반복 애니메이션의 경우, 이는 루프 주기입니다.
loopbooleanfalse--애니메이션이 반복되는지 여부입니다.
blendModestringfalse-replace | add | multiply이 애니메이션이 다른 애니메이션과 결합되는 방식: 교체 (재정의), 추가 (합), 곱하기 (스케일).
blendWeightnumberfalse--이 애니메이션의 강도/영향력 (0-1). 여러 애니메이션을 혼합하는 데 사용됩니다.

표현 애니메이션

표현은 애니메이션 컨텍스트 변수에 접근할 수 있는 매 프레임 평가되는 JavaScript 코드입니다.

사용 가능한 컨텍스트 변수

{
  time: number; // 현재 절대 시간 (초)
  localTime: number; // 요소 시작에 대한 시간
  duration: number; // 요소 지속 시간
  progress: number; // 정규화된 진행 상황 (0-1)
  index: number; // 그룹 내 요소 인덱스
  total: number; // 그룹 내 총 요소 수
  fps: number; // 초당 프레임
  width: number; // 캔버스 너비
  height: number; // 캔버스 높이
  value: any; // 현재 속성 값
}

표현 예제

수학 함수를 사용한 튕김 애니메이션:

expressionAnimation.json
{
"id": "element-1",
"type": "Image",
"start": 0,
"duration": 5,
"animations": [
  {
    "type": "expression",
    "target": "y",
    "enabled": true,
    "expression": "100 + Math.abs(Math.sin(localTime * 3)) * 200",
    "startTime": 0,
    "duration": 5,
    "loop": true
  }
]
}

복합 표현

여러 효과를 결합:

complexExpression.json
{
"animations": [
  {
    "type": "expression",
    "target": "rotation",
    "expression": "(localTime * 2 * Math.PI / duration) + Math.sin(localTime * 4) * 0.1",
    "loop": true
  },
  {
    "type": "expression",
    "target": "scaleX",
    "expression": "1 + Math.sin(localTime * 5) * 0.2",
    "loop": true
  }
]
}

절차적 애니메이션

구성 가능한 매개변수를 가진 내장 애니메이션 패턴입니다.

절차적 유형

  • wiggle: 임의의 진동 (핸드헬드 카메라 효과에 유용)
  • wave: 사인/코사인 파동 운동
  • bounce: 탄력적인 튕김 효과
  • pulse: 리드미컬한 스케일링

Wiggle 예제

wiggleAnimation.json
{
"animations": [
  {
    "type": "procedural",
    "proceduralType": "wiggle",
    "target": "rotation",
    "enabled": true,
    "frequency": 2,
    "amplitude": 0.1,
    "loop": true
  }
]
}

시퀀스 애니메이션

특정 간격에서 값을 변경하는 단계 기반 애니메이션입니다.

소품유형필수예시값 범위설명
valuesarraytrue--단계별로 진행할 값의 배열입니다.
stepDurationnumbertrue--각 단계의 지속 시간(초)입니다.
loopbooleanfalse--시퀀스를 반복할지 여부입니다.

시퀀스 예제

다양한 크기로 텍스트 순환:

sequenceAnimation.json
{
"animations": [
  {
    "type": "sequence",
    "target": "fontSize",
    "enabled": true,
    "values": [24, 32, 40, 32, 24],
    "stepDuration": 0.5,
    "loop": true
  }
]
}

경로 애니메이션

베지어 곡선 경로를 따라 요소를 애니메이션합니다.

소품유형필수예시값 범위설명
pathstring | arraytrue--SVG 경로 데이터 (d 속성) 또는 경로 점의 배열입니다.
autoRotatebooleanfalse--경로 탄젠트를 따라 요소를 자동으로 회전할지 여부입니다.
durationnumbertrue--전체 경로를 완료하는 데 걸리는 시간입니다.

경로 예제

원형 움직임:

pathAnimation.json
{
"animations": [
  {
    "type": "path",
    "target": "position",
    "enabled": true,
    "path": "M 100,100 a 200,200 0 1,1 0,1 Z",
    "autoRotate": true,
    "duration": 4,
    "loop": true
  }
]
}

속성 경로 구문

target 속성은 점 표기법을 사용하여 중첩 속성을 지정합니다:

  • 단순: "x", "y", "rotation"
  • 중첩: "scale.x", "position.y"
  • 배열: "colors[0]", "points[2].x"

대상 해석 예제

{
  "target": "x"              // 요소의 x 위치
  "target": "scaleX"         // 수평 스케일
  "target": "alpha"          // 불투명도
  "target": "fill.color"     // 채우기 색상 (채우기가 객체인 경우)
  "target": "points[0].x"    // 첫 번째 점의 x 좌표
}

혼합 모드

여러 애니메이션이 동일한 속성을 대상으로 할 때 애니메이션이 결합되는 방식을 제어합니다:

교체 (기본값)

{
  "blendMode": "replace",
  "blendWeight": 1.0
}

속성 값을 완전히 대체합니다.

추가

{
  "blendMode": "add",
  "blendWeight": 0.5
}

기존 값에 더합니다 (가중치). 오프셋을 누적하는 데 유용합니다.

곱하기

{
  "blendMode": "multiply",
  "blendWeight": 1.0
}

기존 값을 곱합니다. 스케일링 효과에 유용합니다.

여러 애니메이션 예제

다양한 애니메이션 유형을 결합:

multipleAnimations.json
{
"id": "animated-element",
"type": "Shape",
"animations": [
  {
    "type": "expression",
    "target": "x",
    "expression": "width / 2 + Math.sin(localTime * 2) * 300",
    "blendMode": "replace",
    "loop": true
  },
  {
    "type": "procedural",
    "proceduralType": "wiggle",
    "target": "rotation",
    "frequency": 3,
    "amplitude": 0.2,
    "blendMode": "add",
    "blendWeight": 0.5
  },
  {
    "type": "sequence",
    "target": "alpha",
    "values": [1, 0.8, 1],
    "stepDuration": 0.3,
    "loop": true,
    "blendMode": "multiply"
  }
],
"keyframes": [
  {
    "id": "kf-1",
    "time": 0,
    "stateObj": { "scaleX": 1 }
  },
  {
    "id": "kf-2",
    "time": 2,
    "stateObj": { "scaleX": 1.5 }
  }
]
}

이 예제에서:

  • 표현은 수평 위치를 제어합니다 (교체 모드)
  • 절차적 wiggle은 미세한 회전 변화를 추가합니다
  • 시퀀스는 불투명도를 펄스합니다
  • 키프레임은 요소를 스케일링합니다 (가장 낮은 우선순위)

중요한 노트

표현 샌드박스

  • 표현은 보안을 위해 제한된 컨텍스트에서 실행됩니다
  • 애니메이션 컨텍스트 변수에만 접근 가능
  • DOM, 외부 라이브러리 또는 Node.js API에 접근할 수 없음
  • 평가 오류는 애니메이션을 비활성화합니다

성능

  • 표현: 매 프레임마다 평가됨 - 간단하게 유지하세요
  • 절차적: 최적화된 내장 함수 - 매우 효율적입니다
  • 시퀀스: 최소한의 오버헤드, 불연속적인 변화에 적합
  • 경로: 중간 비용, 경로 복잡도에 따라 다름

타이밍

  • startTimeduration은 요소의 start 시간에 상대적입니다
  • 표현의 localTime은 요소가 시작될 때 0에서 시작합니다
  • 애니메이션은 요소의 전체 duration 경계를 존중합니다

디버깅

  • 애니메이션이 작동하지 않는 경우 확인하세요:
    • enabled: true
    • 요소에 target 속성이 존재하는지
    • 표현 구문이 유효한 JavaScript인지
    • startTime이 요소의 지속 시간 내에 있는지
    • 속성 경로 오타가 없는지

일반적인 사용 사례

부드러운 추적 효과

{
  "type": "expression",
  "target": "x",
  "expression": "value + (targetX - value) * 0.1"
}

탄력적인 튕김

{
  "type": "expression",
  "target": "scaleY",
  "expression": "1 + Math.exp(-localTime * 3) * Math.cos(localTime * 8) * 0.5"
}

카메라 흔들림

{
  "type": "procedural",
  "proceduralType": "wiggle",
  "target": "x",
  "frequency": 10,
  "amplitude": 5
}

계단식 애니메이션 (그룹 내에서)

{
  "type": "expression",
  "target": "alpha",
  "expression": "Math.max(0, Math.min(1, (localTime - index * 0.1) * 2))"
}