# AnimationSpec v2 사양서 — 나만의 "문자 움직임" 만들기

> 이 문서는 일본어 원문의 번역본입니다. **일본어판이 정본**이며, 내용에 차이가 있을 경우 일본어판이 우선합니다.

이 문서는 movlyric의 문자 움직임(가사 애니메이션) 정의인 "AnimationSpec v2"의 완전한 사양입니다.
앱의 "스타일 에디터 → 「움직임」 탭 → 문자 움직임 → 「사용자 지정」 → AI로 만들기…"에서 사용합니다(배경에 도형을 그리는 "배경 이펙트"는 별개이며,
그쪽은 `GRAPHIC_SPEC.md`가 사양입니다).
v1(모션만 있던 버전)으로 작성된 JSON은 그대로 v2로도 유효합니다. v2에서는 색상·테두리·발광·축별 신축이 추가되었습니다.
이 문서만 읽은 AI(또는 사람)가 앱에 그대로 붙여 넣어 통과하는 JSON을 작성할 수 있게 하는 것이 목적입니다.
문서 끝에 AI에게 전달할 프롬프트 템플릿이 있습니다. 이 문서 전체를 프롬프트의 일부로 붙여 넣어도 작동합니다.

## 1. 개요

movlyric은 가사(구절)를 시간에 맞춰 화면에 표시하는 동영상 엔진입니다.
하나의 구절은 다음 3단계로 움직입니다.

1. **입장(in)**: 구절 표시 창의 시작(구절 발성 시작 약 1초 전)부터, 문자/단어가 나타나는 움직임
2. **표시 중(정지 상태)**: 입장이 끝난 상태로 정지. 필요하면 **activePulse**(sin파 맥동)를 걸 수 있음
3. **퇴장(out)**: 표시 창의 끝(구절 발성 종료 약 1초 후)을 향해 사라지는 움직임

AnimationSpec은 이 in / out / activePulse를 **keyframe 기반의 선언적 JSON**으로 기술합니다.
코드나 수식은 쓸 수 없습니다. 쓸 수 있는 것은 아래 사양에 있는 필드뿐입니다.

## 2. JSON 형식의 완전한 사양

### 2.1 루트: AnimationSpec

```json
{ "in": <Phase>, "out": <Phase>, "activePulse": <Pulse> }
```

| 필드 | 타입 | 필수 | 설명 |
|---|---|---|---|
| `in` | Phase | **필수** | 입장 페이즈 |
| `out` | Phase | **필수** | 퇴장 페이즈(퇴장 연출이 필요 없어도 생략 불가. 변화 없이 두고 싶다면 §2.7 참고) |
| `activePulse` | Pulse | 선택 | 표시 중의 맥동. 필요 없으면 **키 자체를 생략**(null은 불가) |

루트 바로 아래에 쓸 수 있는 키는 이 3개뿐입니다.

### 2.2 Phase(in / out 공통)

| 필드 | 타입 | 필수 | 값 범위 | 설명 |
|---|---|---|---|---|
| `durationMs` | 정수 | **필수** | 50~4000 | 유닛(문자/단어) 1개의 페이즈 소요 시간(밀리초). **소수 불가** |
| `easing` | 문자열 | **필수** | §3의 31종 중 하나 | 페이즈 전체에 한 번 적용되는 이징(keyframe 구간마다 지정할 수 없음) |
| `stagger` | Stagger | **필수** | — | 유닛 간의 시간차. 시간차가 없어도 `{"unit":"none","delayMs":0,"from":"start"}`처럼 **3개 필드 모두 필수** |
| `keyframes` | Keyframe[] | **필수** | 2~8개 | 움직임의 나열. **t는 0..1의 진성 오름차순(같은 값도 불가), 첫 항목은 반드시 t=0, 마지막 항목은 반드시 t=1** |

### 2.3 Keyframe

| 필드 | 타입 | 필수 | 값 범위 | 의미·단위 |
|---|---|---|---|---|
| `t` | 숫자 | **필수** | 0~1 | 페이즈 내 정규화 시각(0=시작, 1=종료) |
| `alpha` | 숫자 | 선택 | 0~1 | 불투명도(0=투명, 1=불투명) |
| `scale` | 숫자 | 선택 | 0.1~3 | 확대율(1=등배) |
| `dx` | 숫자 | 선택 | -2~2 | 가로 오프셋. **단위는 글자 크기(fontSize) 비율**(1.0=글자 1개분). 양수=오른쪽 |
| `dy` | 숫자 | 선택 | -2~2 | 세로 오프셋. **단위는 글자 크기 비율**. 양수=아래(예: 아래에서 입장은 양수→0) |
| `rotate` | 숫자 | 선택 | -360~360 | 회전. **단위는 도**. 양수=시계 방향 |
| `scaleX` | 숫자 | 선택 | 0.1~3 | 가로만의 확대율. `scale`과 곱해짐 |
| `scaleY` | 숫자 | 선택 | 0.1~3 | 세로만의 확대율. `scale`과 곱해짐 |
| `tint` | 정수 | 선택 | 0~16777215 | 글자 색상(`0xRRGGBB`의 10진 또는 16진 표기) |
| `strokeWidth` | 숫자 | 선택 | 0~20 | 테두리 두께(px). 0이면 테두리 없음 |
| `strokeColor` | 정수 | 선택 | 0~16777215 | 테두리 색상 |
| `glow` | 숫자 | 선택 | 0~40 | 발광의 강도(흐림 반경 px). 0이면 발광 없음 |
| `glowColor` | 정수 | 선택 | 0~16777215 | 발광 색상. 생략하면 글자 색상으로 빛남(자체 발광) |

쓸 수 있는 속성은 위 13개뿐입니다. 다른 이름(`x`, `y`, `opacity`, `color`, `blur`, `shadow` 등)은 존재하지 않습니다.
단위(dx/dy=글자 크기 비율, rotate=도)는 앱 내 애니메이션 에디터의 표시 단위(가로/세로=글자 크기 비율, 회전=도)와 동일합니다.

**"지정하지 않음"의 의미는 속성마다 다릅니다.** 이를 혼동하면 의도하지 않은 모습이 됩니다.

| 속성 | 지정하지 않았을 때 |
|---|---|
| `alpha` / `scale` / `scaleX` / `scaleY` | 1(변화 없음) |
| `dx` / `dy` / `rotate` | 0(변화 없음) |
| `tint` | **글자 색상을 바꾸지 않음**(스타일의 가라오케 발성 색상이 그대로 적용됨) |
| `strokeWidth` / `strokeColor` | **스타일의 테두리를 그대로 사용**(0이 되지 않음) |
| `glow` / `glowColor` | 발광 없음 |

즉 **색상이나 테두리를 바꾸고 싶지 않다면 해당 속성을 쓰지 마세요.** `tint`를 쓰면 그 글자는 노래에 맞춘 색 전환(미발성→발성 완료)을 하지 않게 되고, 지정한 색으로 고정됩니다.

`scaleX`와 `scaleY`를 따로 움직이면 찌그러졌다 늘어나는 움직임(squash & stretch)을 만들 수 있습니다. 튀어 오르거나 착지하는 표현에서 이것이 있으면 움직임이 부드러워집니다.

### 2.4 Stagger(시간차)

| 필드 | 타입 | 필수 | 값 범위 | 설명 |
|---|---|---|---|---|
| `unit` | 문자열 | **필수** | `"none"` / `"char"` / `"word"` | 시간차의 단위. none=구절 전체가 동시에, char=글자마다, word=단어마다 |
| `delayMs` | 정수 | **필수** | 0~500 | 유닛 1개분의 지연(밀리초). **소수 불가**. unit이 none이라도 0을 명시 |
| `from` | 문자열 | **필수** | `"start"` / `"end"` / `"center"` | 기준점. start=처음부터, end=끝에서부터, center=중앙에서 바깥으로(짝수 개는 중앙 2개가 동시에 가장 먼저) |

n번째로 움직이는 유닛의 지연은 `순서×delayMs`입니다. 루비(후리가나)는 항상 **부모 단어와 같은 위상**으로 움직입니다.
in과 out에 서로 다른 stagger를 지정할 수 있습니다(예: 입장은 처음부터, 퇴장은 끝에서부터).

### 2.5 Pulse(activePulse, 선택)

| 필드 | 타입 | 필수 | 값 범위 | 설명 |
|---|---|---|---|---|
| `property` | 문자열 | **필수** | `"scale"` / `"alpha"` | 흔들 대상 |
| `amplitude` | 숫자 | **필수** | 0~0.5 | 흔들림 폭 |
| `periodMs` | 정수 | **필수** | 200~4000 | 주기(밀리초). **소수 불가** |

동작: 각 유닛의 **입장 완료 후~퇴장 시작 전까지만**, `1 + amplitude × sin(2π × nowMs / periodMs)`를 property에 곱합니다.
nowMs는 영상의 절대 시각이므로, 맥동의 위상은 구절을 넘나들며 연속됩니다(결정적 = 미리보기와 내보내기가 일치).
주의: `property:"alpha"`에서 정지 상태의 alpha가 1일 때, 1을 초과하는 반주기는 클램프되므로 "어두워지는 방향만" 보이게 됩니다(명멸 표현으로서는 그것이 자연스럽습니다).

### 2.6 보간의 의미론(성긴 keyframe)

- **속성마다 독립적으로 보간**합니다. 어떤 속성은 "그 속성을 가진 keyframe"만 이어서 선형 보간합니다.
  - 예: `alpha`는 t=0과 t=1에만 쓰고, `scale`은 t=0 / 0.5 / 1에 쓰는 식으로 성기게 쓸 수 있습니다.
- 해당 속성을 가진 첫 keyframe보다 **앞은 첫 값**을, 마지막 keyframe보다 **뒤는 마지막 값**을 유지합니다(최근접값 유지. 외삽은 하지 않음).
- 어떤 keyframe에도 쓰여 있지 않은 속성의 처리는 §2.3의 "지정하지 않았을 때" 표를 따릅니다. 모션 계열은 항등값(**alpha=1, scale=1, scaleX=1, scaleY=1, dx=0, dy=0, rotate=0**)이지만, **색상·테두리는 "덮어쓰지 않는다"**(스타일의 값이 그대로 남는다)는 점이 다릅니다.
- easing은 "페이즈의 진행 0→1"에 한 번만 적용되며, 그 eased 값으로 모든 속성을 보간합니다.

### 2.7 in과 out의 합성·정지 상태

in과 out은 항상 동시에 평가되며, **alpha와 scale은 곱셈, dx / dy / rotate는 덧셈**으로 합성됩니다. 따라서:

- **in의 t=1 = 표시 중의 정지 상태**입니다. 보통은 항등값(alpha 1, scale 1, dx 0, dy 0, rotate 0)으로 둡니다.
- **out의 t=0은 반드시 항등값**으로 하세요. 그렇지 않으면 표시 중의 모습이 out의 값만큼 계속 어긋납니다.
- 퇴장 연출을 없애고 싶다면 out을 "변화 없음"으로 만듭니다: `keyframes`를 `[{"t":0,"alpha":1},{"t":1,"alpha":1}]`처럼 같은 값으로 쓰면 움직이지 않습니다(t는 오름차순을 지킬 것).

합성 후의 alpha는 최종적으로 0..1로 클램프됩니다.

### 2.8 타임라인과 짧은 구절에서의 압축

- 표시 창은 구절 발성 구간의 앞뒤에 각각 약 1000ms의 여백을 가집니다. in은 창의 시작부터 시작되고, out은 "마지막 유닛의 t=1이 정확히 창의 끝"이 되도록 역산하여 배치됩니다.
- 페이즈 전체의 소요 시간은 `durationMs + 최대 stagger 지연(순서 최댓값×delayMs)`입니다. 이것이 표시 창보다 길면 **타임라인 전체가 등배로 압축**됩니다(창이 짧아도 글자가 나타나지 않은 채로 남지 않도록). 글자 수가 많은 가사에서 `char` stagger에 큰 delayMs를 쓰면 압축되기 쉬우므로, `durationMs + 글자수×delayMs`가 2000ms 정도에 들어오는 값을 권장합니다.

## 3. 이징 목록(31종)

`easing`에 쓸 수 있는 이름은 다음 **31종뿐**입니다(대소문자도 엄밀히 일치해야 함. `ease-in`이나 `easeOutBack` 같은 다른 표기는 불가).

| 이름 | 설명 |
|---|---|
| `linear` | 등속 |
| `inQuad` / `outQuad` / `inOutQuad` | 2차. 완만한 가속/감속/양쪽 |
| `inCubic` / `outCubic` / `inOutCubic` | 3차. 표준적인 가속/감속/양쪽 |
| `inQuart` / `outQuart` / `inOutQuart` | 4차. 강한 가속/감속/양쪽 |
| `inQuint` / `outQuint` / `inOutQuint` | 5차. 꽤 강한 가속/감속/양쪽 |
| `inSine` / `outSine` / `inOutSine` | sin파. 가장 부드러운 가속/감속/양쪽 |
| `inExpo` / `outExpo` / `inOutExpo` | 지수. 급격한 가속/감속/양쪽 |
| `inCirc` / `outCirc` / `inOutCirc` | 원호. 끝부분에서 급격한 가속/감속/양쪽 |
| `inBack` / `outBack` / `inOutBack` | 지나쳤다가 되돌아옴(반동) |
| `inElastic` / `outElastic` / `inOutElastic` | 용수철 같은 진동 |
| `inBounce` / `outBounce` / `inOutBounce` | 공이 튀는 듯한 바운드 |

**중요(엔진의 실제 동작)**: back / elastic 계열은 도중에 진행도가 0..1 범위 밖으로 나가지만, 보간은 최근접값 클램프이므로 **출력은 끝점 keyframe의 값에 머무릅니다**(t=1의 값을 넘어서 튀어나오는 일은 없습니다).
"지나쳤다가 되돌아오는" 모습을 확실히 내고 싶다면, 중간 keyframe에서 명시적으로 써 주세요(예: `scale`을 0 → 1.15 → 1로).

## 4. 흔한 실수(금지 사항)

다음은 검증 오류가 되거나 의도하지 않은 모습이 됩니다. **반드시 피하세요.**

- **값 범위 위반**: `scale: 0`이나 `3.5`, `alpha: 1.2`, `dx: 2.5`, `durationMs: 30`이나 `5000`, `delayMs: 600`, `amplitude: 0.8`, `periodMs: 100` 등은 모두 불가. §2의 값 범위 표를 엄밀히 따를 것
- **존재하지 않는 속성**: keyframe에 쓸 수 있는 것은 §2.3의 13개뿐(`t, alpha, scale, scaleX, scaleY, dx, dy, rotate, tint, strokeWidth, strokeColor, glow, glowColor`). `x`, `y`, `opacity`, `color`, `blur`, `skew`, `shadow` 등은 불가. keyframe마다의 easing 지정도 불가
- **색상을 정수 이외로 쓰기**: `"#ff0066"`나 `"red"`는 불가. `0xRRGGBB`를 정수로 쓸 것(16진 리터럴 `0xff0066` 또는 10진 `16711782`)
- **바꾸고 싶지 않은 속성을 0으로 쓰기**: `strokeWidth: 0`은 "테두리를 없앤다"는 지정. 스타일의 테두리를 남기고 싶다면 **쓰지 말 것**
- **t의 순서 위반**: t의 내림차순·같은 값의 중복은 불가(진성 오름차순). **첫 항목 t=0과 마지막 항목 t=1을 잊지 말 것**
- **keyframes의 개수**: 1개 이하·9개 이상은 불가(2~8개)
- **소수 금지 위치**: `durationMs` / `delayMs` / `periodMs`는 정수만 가능
- **easing 이름의 표기 흔들림**: §3의 31종과 엄밀히 일치하게 쓸 것
- **in / out의 생략**: 둘 다 필수. stagger의 3개 필드(unit / delayMs / from)도 항상 필수
- **out의 t=0을 항등값 이외로 하기**: 표시 중의 모습이 어긋남(§2.7)
- **JSON 이외의 혼입**: 주석, 끝 쉼표, 수식(`"dy": "0.5 * 2"` 등)은 불가. 값은 모두 숫자 리터럴이거나 허용된 문자열

## 5. 예시

셋 다 그대로 앱에 붙여 넣으면 통과하는 완전한 JSON입니다.

### 5.1 두둥실 떠오르기

글자가 조금 아래에서 부드럽게 페이드인하고, 퇴장은 위로 빠져나가며 페이드아웃.

```json
{
  "in": {
    "durationMs": 700,
    "easing": "outSine",
    "stagger": { "unit": "char", "delayMs": 40, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 0, "dy": 0.4 },
      { "t": 1, "alpha": 1, "dy": 0 }
    ]
  },
  "out": {
    "durationMs": 600,
    "easing": "inSine",
    "stagger": { "unit": "char", "delayMs": 30, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 1, "dy": 0 },
      { "t": 1, "alpha": 0, "dy": -0.3 }
    ]
  }
}
```

### 5.2 글자가 회전하며 튀어 오르듯 등장

작게 회전한 상태에서, 지나침(scale 1.15)을 중간 keyframe으로 명시하여 튀어 오르는 입장. 퇴장은 끝 글자부터 역회전하며 축소.
`alpha`는 성기게 지정한 예: in에서는 t=0.6까지 1에 도달하고, 이후는 마지막 값 1을 유지합니다.

```json
{
  "in": {
    "durationMs": 800,
    "easing": "outBack",
    "stagger": { "unit": "char", "delayMs": 60, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 0, "scale": 0.3, "rotate": -180 },
      { "t": 0.6, "alpha": 1, "scale": 1.15, "rotate": 20 },
      { "t": 1, "scale": 1, "rotate": 0 }
    ]
  },
  "out": {
    "durationMs": 500,
    "easing": "inBack",
    "stagger": { "unit": "char", "delayMs": 40, "from": "end" },
    "keyframes": [
      { "t": 0, "alpha": 1, "scale": 1, "rotate": 0 },
      { "t": 1, "alpha": 0, "scale": 0.3, "rotate": 180 }
    ]
  }
}
```

### 5.3 단어마다 아래에서 슬라이드인 + 표시 중 천천히 명멸

단어 단위의 stagger로 아래에서 순서대로 나타나고, 표시 중에는 activePulse로 천천히 명멸. 퇴장은 구절 전체가 동시에 페이드아웃.

```json
{
  "in": {
    "durationMs": 600,
    "easing": "outCubic",
    "stagger": { "unit": "word", "delayMs": 120, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 0, "dy": 0.8 },
      { "t": 1, "alpha": 1, "dy": 0 }
    ]
  },
  "out": {
    "durationMs": 400,
    "easing": "inQuad",
    "stagger": { "unit": "none", "delayMs": 0, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 1 },
      { "t": 1, "alpha": 0 }
    ]
  },
  "activePulse": { "property": "alpha", "amplitude": 0.25, "periodMs": 1600 }
}
```

### 5.4 네온처럼 빛나며 등장

`glow`로 발광시키고, `glowColor`로 빛의 색상을 지정. 퇴장에서는 발광을 0으로 수렴시킴. `tint`를 쓰지 않았으므로 글자 색상은 노래에 맞춘 색 전환이 그대로 적용됩니다.

```json
{
  "in": {
    "durationMs": 500,
    "easing": "outCubic",
    "stagger": { "unit": "char", "delayMs": 40, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 0, "glow": 0, "glowColor": 65535 },
      { "t": 0.6, "alpha": 1, "glow": 34, "glowColor": 65535 },
      { "t": 1, "alpha": 1, "glow": 20, "glowColor": 65535 }
    ]
  },
  "out": {
    "durationMs": 400,
    "easing": "inQuad",
    "stagger": { "unit": "none", "delayMs": 0, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 1, "glow": 20, "glowColor": 65535 },
      { "t": 1, "alpha": 0, "glow": 0, "glowColor": 65535 }
    ]
  }
}
```

### 5.5 색이 바뀌며 나타나기

`tint`를 움직이면 글자 색상이 보간됩니다. **`tint`를 쓴 구절은 노래에 맞춘 색 전환을 하지 않게 되므로**, 색상은 전부 이 spec에서 결정합니다.

```json
{
  "in": {
    "durationMs": 700,
    "easing": "outQuad",
    "stagger": { "unit": "char", "delayMs": 30, "from": "center" },
    "keyframes": [
      { "t": 0, "alpha": 0, "tint": 16711808 },
      { "t": 1, "alpha": 1, "tint": 16777215 }
    ]
  },
  "out": {
    "durationMs": 400,
    "easing": "inQuad",
    "stagger": { "unit": "none", "delayMs": 0, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 1 },
      { "t": 1, "alpha": 0 }
    ]
  }
}
```

### 5.6 찌그러졌다 늘어나며 착지(squash & stretch)

`scaleX`와 `scaleY`를 반대 방향으로 움직임. 떨어지는 동안은 세로로 길고, 착지하는 순간에 가로로 찌그러지며, 거기서부터 등배로 되돌립니다.

```json
{
  "in": {
    "durationMs": 550,
    "easing": "outBack",
    "stagger": { "unit": "char", "delayMs": 45, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 0, "dy": -1.2, "scaleX": 0.75, "scaleY": 1.35 },
      { "t": 0.7, "alpha": 1, "dy": 0, "scaleX": 1.3, "scaleY": 0.7 },
      { "t": 1, "alpha": 1, "dy": 0, "scaleX": 1, "scaleY": 1 }
    ]
  },
  "out": {
    "durationMs": 350,
    "easing": "inQuad",
    "stagger": { "unit": "none", "delayMs": 0, "from": "start" },
    "keyframes": [
      { "t": 0, "alpha": 1 },
      { "t": 1, "alpha": 0, "scaleY": 0.6 }
    ]
  }
}
```

## 6. AI용 프롬프트 템플릿

아래 틀 안의 내용을 복사해서 AI에게 전달하세요. 이 사양서 전체를 먼저 붙여 넣고, 그 직후에 템플릿을 이어 붙이는 방식을 권장합니다(사양서 없이 템플릿만 전달하면 AI가 값 범위나 easing 이름을 잘못 쓸 수 있습니다).

**여기서부터 복사**

```text
당신은 movlyric의 가사 애니메이션 설계자입니다. 위에 붙여 넣은 "AnimationSpec v2 사양서"를 엄밀히 따라, AnimationSpec의 JSON을 하나 작성해 주세요.

출력 규칙:
- JSON만 출력한다(설명문·서두·맺음말은 쓰지 않는다. JSON을 코드 펜스로 감싸는 것은 가능)
- 루트는 {"in": ..., "out": ...}이며, 필요한 경우에만 "activePulse"를 추가한다
- keyframes는 2~8개, t는 0..1의 진성 오름차순이며, 첫 항목은 반드시 t=0, 마지막 항목은 반드시 t=1
- keyframe에 쓸 수 있는 것은 t, alpha(0..1), scale(0.1..3), scaleX(0.1..3), scaleY(0.1..3), dx(-2..2), dy(-2..2), rotate(-360..360), tint(0..16777215), strokeWidth(0..20), strokeColor(0..16777215), glow(0..40), glowColor(0..16777215)뿐이다. 단위: dx/dy는 글자 크기 비율(양수=오른쪽/아래), rotate는 도, strokeWidth/glow는 px, 색상은 0xRRGGBB의 정수
- **바꾸고 싶지 않은 속성은 쓰지 않는다.** tint를 쓰면 노래에 맞춘 색 전환이 멈추고 지정한 색으로 고정된다. strokeWidth/strokeColor를 쓰지 않으면 스타일의 테두리가 그대로 남는다(쓰지 않음 = 0이 아니다)
- 빛나게 하고 싶을 때는 glow(오프셋 없는 발광)를 사용한다. glowColor를 생략하면 글자 색상으로 빛난다
- 찌그러뜨렸다 늘리는 움직임(squash & stretch)은 scaleX와 scaleY를 반대 방향으로 움직여 만든다
- durationMs(정수 50..4000) / stagger.delayMs(정수 0..500) / activePulse.periodMs(정수 200..4000)를 지킨다. stagger는 unit("none"/"char"/"word")·delayMs·from("start"/"end"/"center") 세 가지 모두 필수
- easing은 사양서의 이징 목록에 있는 31종의 이름만 사용한다(엄밀 일치)
- out의 t=0 keyframe은 항등값(alpha 1, scale 1, dx 0, dy 0, rotate 0에 해당)으로 한다
- 존재하지 않는 속성·주석·끝 쉼표·수식을 쓰지 않는다

만들고 싶은 움직임:
{여기에 만들고 싶은 움직임을 적는다}

(기존 애니메이션을 수정하고 싶을 때만, 아래에 현재 JSON을 붙여 넣으세요. 새로 만드는 경우에는 이 절 전체를 삭제하세요)
현재 JSON:
{현재 JSON}
```

**여기까지 복사**
