Initial Dansori character workspace
This commit is contained in:
@@ -0,0 +1,63 @@
|
||||
# 반응 시퀀서 & 트리거 (Reactions)
|
||||
|
||||
상황 → 반응을 정의하는 레이어. **트리거 매퍼**(`reactions.json`) + **반응 클립**(`clips/*.json`)으로 구성.
|
||||
> 이 스키마는 **Phase 2(반응 시퀀서 런타임)** 에서 구현해 재생한다. 현재 뷰어는 리그 클립만 재생(Phase 1). 여기 JSON은 그 목표 스펙/샘플이다.
|
||||
|
||||
## 트리거 매퍼 (`reactions.json`)
|
||||
상황키 → 반응 클립 이름. 앱은 상황키만 던지면 된다.
|
||||
```json
|
||||
{ "error": "gesture_no", "success": "gesture_heart", "idle": "dance_idle" }
|
||||
```
|
||||
|
||||
## 반응 클립 스키마 (`clips/<name>.json`)
|
||||
하나의 반응 = 레이어드 타임라인.
|
||||
```jsonc
|
||||
{
|
||||
"name": "gesture_no",
|
||||
"duration": 2.4, // 초
|
||||
"return": "idle", // 종료 후 복귀 클립(보통 배경 idle)
|
||||
"layers": {
|
||||
"body": [ // Body 트랙: 시간에 따라 rig 클립 or baked 포즈
|
||||
{ "t":0.0, "mode":"rig", "clip":"idle" },
|
||||
{ "t":0.15,"mode":"baked", "image":"isabel_body_club_armscross", "fade":0.2 }
|
||||
],
|
||||
"face": [ // 표정 프레임 트랙
|
||||
{ "t":0.0, "expr":"neutral" },
|
||||
{ "t":0.3, "expr":"negative" }
|
||||
],
|
||||
"mouth": [ // 말하기(유사 립싱크): expr↔talk 순환
|
||||
{ "t":0.5, "say":"안돼요", "dur":1.2, "pattern":"talk" }
|
||||
],
|
||||
"transform": { // 리그 위 잔모션(본별 delta) — Animation.md 스키마와 동일
|
||||
"head": { "rot":[ {"t":0.5,"v":0},{"t":0.8,"v":9},{"t":1.1,"v":-9},{"t":1.4,"v":9},{"t":1.7,"v":0} ] },
|
||||
"chest":{ "ty":[ {"t":0.0,"v":0},{"t":0.2,"v":-4},{"t":0.5,"v":0} ] }
|
||||
},
|
||||
"caption": [ { "t":0.5, "text":"안돼요", "dur":1.6 } ], // 옵션 말풍선
|
||||
"sfx": [ { "t":0.5, "id":"nope" } ] // 옵션 효과음
|
||||
}
|
||||
}
|
||||
```
|
||||
### 필드 규칙
|
||||
- `body[]`: 시간순. `mode:"rig"`+`clip` 또는 `mode:"baked"`+`image`(파일명, 확장자 생략 가능). `fade`=크로스페이드 초.
|
||||
- `face[]`: `expr` = 표정 프레임 키(20종 중). 시간에 스냅.
|
||||
- `mouth[]`: `say` 대사, `dur` 길이, `pattern:"talk"`(talk/talk_wide/현재 감정 프레임 순환). 립싱크는 근사.
|
||||
- `transform`: 본별 키프레임(리그 delta). Body가 baked여도 head/chest 등 트랜스폼은 적용(단 baked는 통짜라 파츠 분리 트랜스폼은 제한적 → 주로 전체/머리에 적용).
|
||||
- `caption`/`sfx`: 옵션. 앱 설정(말풍선/TTS)에 따라 사용.
|
||||
|
||||
## 상황 → 반응 카탈로그
|
||||
| 상황키 | 클립 | Body | Face | Mouth | 잔모션 |
|
||||
|---|---|---|---|---|---|
|
||||
| `error` | `gesture_no` | baked armscross | negative | "안돼요" | 고개 젓기 |
|
||||
| `success` | `gesture_heart` | baked heart | love/positive | "잘됐어요" | 통통 바운스 |
|
||||
| `idle` | `dance_idle` | rig | smile/neutral | — | 그루브 루프 |
|
||||
| *(확장)* `greet` | `gesture_wave` | rig wave | smile | "안녕하세요" | 손 흔들기 |
|
||||
| *(확장)* `explain` | `gesture_present` | rig present | neutral | 안내 대사 | 제시 |
|
||||
| *(확장)* `thinking` | `gesture_think` | rig idle_upper | thinking | — | 갸웃 |
|
||||
|
||||
## 트리거 API(개념)
|
||||
```
|
||||
Mascot.React("success") // reactions.json으로 클립 결정 → 시퀀서 재생 → 종료 후 return 클립
|
||||
Mascot.SetIdle("dance_idle")// 배경 기본 루프
|
||||
Mascot.Say("...", expr) // 임시 대사(mouth+face)만
|
||||
```
|
||||
상세 앱 연동: `../08_Roadmap/App_Integration.md`.
|
||||
@@ -0,0 +1,433 @@
|
||||
{
|
||||
"stage": {
|
||||
"w": 520,
|
||||
"h": 900
|
||||
},
|
||||
"neck": [
|
||||
260,
|
||||
250
|
||||
],
|
||||
"overlap": 6,
|
||||
"headTargetW": 150,
|
||||
"bodies": {
|
||||
"isabel_body_bikini_armscross": {
|
||||
"scale": 0.3528,
|
||||
"ox": -26.8,
|
||||
"oy": 227.1
|
||||
},
|
||||
"isabel_body_bikini_cheer": {
|
||||
"scale": 0.1603,
|
||||
"ox": 45.4,
|
||||
"oy": 244.7
|
||||
},
|
||||
"isabel_body_bikini_clap": {
|
||||
"scale": 0.2788,
|
||||
"ox": 10.3,
|
||||
"oy": 229.6
|
||||
},
|
||||
"isabel_body_bikini_control": {
|
||||
"scale": 0.2396,
|
||||
"ox": 76.6,
|
||||
"oy": 237.1
|
||||
},
|
||||
"isabel_body_bikini_dj": {
|
||||
"scale": 0.2972,
|
||||
"ox": -44.4,
|
||||
"oy": 228.0
|
||||
},
|
||||
"isabel_body_bikini_handwave": {
|
||||
"scale": 0.2182,
|
||||
"ox": 62.0,
|
||||
"oy": 233.0
|
||||
},
|
||||
"isabel_body_bikini_heart": {
|
||||
"scale": 0.2805,
|
||||
"ox": 42.8,
|
||||
"oy": 228.1
|
||||
},
|
||||
"isabel_body_bikini_idle_full": {
|
||||
"scale": 0.4822,
|
||||
"ox": 31.4,
|
||||
"oy": 199.4
|
||||
},
|
||||
"isabel_body_bikini_idle_upper": {
|
||||
"scale": 0.2748,
|
||||
"ox": 45.0,
|
||||
"oy": 228.3
|
||||
},
|
||||
"isabel_body_bikini_joy": {
|
||||
"scale": 0.3071,
|
||||
"ox": 222.7,
|
||||
"oy": 226.4
|
||||
},
|
||||
"isabel_body_bikini_listen": {
|
||||
"scale": 0.2937,
|
||||
"ox": 73.2,
|
||||
"oy": 230.6
|
||||
},
|
||||
"isabel_body_bikini_peace": {
|
||||
"scale": 0.3212,
|
||||
"ox": 82.0,
|
||||
"oy": 226.9
|
||||
},
|
||||
"isabel_body_bikini_piano": {
|
||||
"scale": 0.2871,
|
||||
"ox": 37.2,
|
||||
"oy": 234.2
|
||||
},
|
||||
"isabel_body_bikini_point": {
|
||||
"scale": 0.2381,
|
||||
"ox": 64.8,
|
||||
"oy": 230.5
|
||||
},
|
||||
"isabel_body_bikini_present": {
|
||||
"scale": 0.1923,
|
||||
"ox": 75.8,
|
||||
"oy": 235.8
|
||||
},
|
||||
"isabel_body_bikini_shrug": {
|
||||
"scale": 0.1773,
|
||||
"ox": 115.2,
|
||||
"oy": 235.8
|
||||
},
|
||||
"isabel_body_bikini_thumbsup": {
|
||||
"scale": 0.3083,
|
||||
"ox": 22.4,
|
||||
"oy": 224.7
|
||||
},
|
||||
"isabel_body_bikini_wave": {
|
||||
"scale": 0.2434,
|
||||
"ox": 193.2,
|
||||
"oy": 230.3
|
||||
},
|
||||
"isabel_body_ceo_armscross": {
|
||||
"scale": 0.3986,
|
||||
"ox": -37.2,
|
||||
"oy": 209.7
|
||||
},
|
||||
"isabel_body_ceo_cheer": {
|
||||
"scale": 0.2486,
|
||||
"ox": 184.7,
|
||||
"oy": 238.3
|
||||
},
|
||||
"isabel_body_ceo_clap": {
|
||||
"scale": 0.41,
|
||||
"ox": -44.6,
|
||||
"oy": 219.7
|
||||
},
|
||||
"isabel_body_ceo_control": {
|
||||
"scale": 0.2995,
|
||||
"ox": 143.4,
|
||||
"oy": 224.2
|
||||
},
|
||||
"isabel_body_ceo_dj": {
|
||||
"scale": 0.3377,
|
||||
"ox": -27.6,
|
||||
"oy": 228.0
|
||||
},
|
||||
"isabel_body_ceo_handwave": {
|
||||
"scale": 0.3087,
|
||||
"ox": 24.0,
|
||||
"oy": 221.0
|
||||
},
|
||||
"isabel_body_ceo_heart": {
|
||||
"scale": 0.3428,
|
||||
"ox": 0.2,
|
||||
"oy": 225.7
|
||||
},
|
||||
"isabel_body_ceo_idle_full": {
|
||||
"scale": 0.5033,
|
||||
"ox": 29.2,
|
||||
"oy": 201.2
|
||||
},
|
||||
"isabel_body_ceo_idle_upper": {
|
||||
"scale": 0.3528,
|
||||
"ox": -10.9,
|
||||
"oy": 228.8
|
||||
},
|
||||
"isabel_body_ceo_joy": {
|
||||
"scale": 0.2632,
|
||||
"ox": 120.4,
|
||||
"oy": 231.3
|
||||
},
|
||||
"isabel_body_ceo_listen": {
|
||||
"scale": 0.4078,
|
||||
"ox": -5.1,
|
||||
"oy": 232.5
|
||||
},
|
||||
"isabel_body_ceo_peace": {
|
||||
"scale": 0.4449,
|
||||
"ox": 34.9,
|
||||
"oy": 183.7
|
||||
},
|
||||
"isabel_body_ceo_piano": {
|
||||
"scale": 0.3746,
|
||||
"ox": -26.0,
|
||||
"oy": 227.9
|
||||
},
|
||||
"isabel_body_ceo_point": {
|
||||
"scale": 0.3358,
|
||||
"ox": 1.6,
|
||||
"oy": 221.1
|
||||
},
|
||||
"isabel_body_ceo_present": {
|
||||
"scale": 0.2386,
|
||||
"ox": 64.6,
|
||||
"oy": 224.7
|
||||
},
|
||||
"isabel_body_ceo_shrug": {
|
||||
"scale": 0.1808,
|
||||
"ox": 128.7,
|
||||
"oy": 228.3
|
||||
},
|
||||
"isabel_body_ceo_thumbsup": {
|
||||
"scale": 0.3125,
|
||||
"ox": 23.4,
|
||||
"oy": 228.4
|
||||
},
|
||||
"isabel_body_ceo_wave": {
|
||||
"scale": 0.3168,
|
||||
"ox": 176.2,
|
||||
"oy": 224.0
|
||||
},
|
||||
"isabel_body_club_armscross": {
|
||||
"scale": 0.4364,
|
||||
"ox": -56.4,
|
||||
"oy": 225.1
|
||||
},
|
||||
"isabel_body_club_cheer": {
|
||||
"scale": 0.211,
|
||||
"ox": 215.7,
|
||||
"oy": 241.8
|
||||
},
|
||||
"isabel_body_club_clap": {
|
||||
"scale": 0.4283,
|
||||
"ox": -67.2,
|
||||
"oy": 210.6
|
||||
},
|
||||
"isabel_body_club_control": {
|
||||
"scale": 0.3117,
|
||||
"ox": 42.6,
|
||||
"oy": 226.3
|
||||
},
|
||||
"isabel_body_club_dj": {
|
||||
"scale": 0.3662,
|
||||
"ox": -42.0,
|
||||
"oy": 217.0
|
||||
},
|
||||
"isabel_body_club_handwave": {
|
||||
"scale": 0.2908,
|
||||
"ox": 32.9,
|
||||
"oy": 225.0
|
||||
},
|
||||
"isabel_body_club_heart": {
|
||||
"scale": 0.3363,
|
||||
"ox": 0.2,
|
||||
"oy": 221.4
|
||||
},
|
||||
"isabel_body_club_idle_full": {
|
||||
"scale": 0.5665,
|
||||
"ox": -26.9,
|
||||
"oy": 197.9
|
||||
},
|
||||
"isabel_body_club_idle_upper": {
|
||||
"scale": 0.3348,
|
||||
"ox": 18.6,
|
||||
"oy": 207.8
|
||||
},
|
||||
"isabel_body_club_joy": {
|
||||
"scale": 0.3042,
|
||||
"ox": 225.6,
|
||||
"oy": 228.4
|
||||
},
|
||||
"isabel_body_club_listen": {
|
||||
"scale": 0.4049,
|
||||
"ox": 18.5,
|
||||
"oy": 210.7
|
||||
},
|
||||
"isabel_body_club_peace": {
|
||||
"scale": 0.3611,
|
||||
"ox": 71.3,
|
||||
"oy": 220.8
|
||||
},
|
||||
"isabel_body_club_piano": {
|
||||
"scale": 0.3686,
|
||||
"ox": -23.4,
|
||||
"oy": 218.3
|
||||
},
|
||||
"isabel_body_club_point": {
|
||||
"scale": 0.3239,
|
||||
"ox": 28.2,
|
||||
"oy": 224.7
|
||||
},
|
||||
"isabel_body_club_present": {
|
||||
"scale": 0.2632,
|
||||
"ox": 62.9,
|
||||
"oy": 220.0
|
||||
},
|
||||
"isabel_body_club_shrug": {
|
||||
"scale": 0.2019,
|
||||
"ox": 103.5,
|
||||
"oy": 232.4
|
||||
},
|
||||
"isabel_body_club_thumbsup": {
|
||||
"scale": 0.3146,
|
||||
"ox": 19.9,
|
||||
"oy": 225.5
|
||||
},
|
||||
"isabel_body_club_wave": {
|
||||
"scale": 0.3474,
|
||||
"ox": 152.3,
|
||||
"oy": 230.5
|
||||
}
|
||||
},
|
||||
"heads": {
|
||||
"isabel_head_wave": {
|
||||
"w": 952,
|
||||
"neckNorm": [
|
||||
0.4956,
|
||||
0.9689
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_blink": {
|
||||
"w": 946,
|
||||
"neckNorm": [
|
||||
0.4932,
|
||||
0.9825
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_confused": {
|
||||
"w": 940,
|
||||
"neckNorm": [
|
||||
0.4916,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_cool": {
|
||||
"w": 936,
|
||||
"neckNorm": [
|
||||
0.494,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_laugh": {
|
||||
"w": 939,
|
||||
"neckNorm": [
|
||||
0.4928,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_love": {
|
||||
"w": 939,
|
||||
"neckNorm": [
|
||||
0.4928,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_negative": {
|
||||
"w": 940,
|
||||
"neckNorm": [
|
||||
0.4924,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_neutral": {
|
||||
"w": 956,
|
||||
"neckNorm": [
|
||||
0.4964,
|
||||
0.9825
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_playful": {
|
||||
"w": 939,
|
||||
"neckNorm": [
|
||||
0.4928,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_positive": {
|
||||
"w": 940,
|
||||
"neckNorm": [
|
||||
0.4924,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_pout": {
|
||||
"w": 937,
|
||||
"neckNorm": [
|
||||
0.4928,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_proud": {
|
||||
"w": 949,
|
||||
"neckNorm": [
|
||||
0.4984,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_sad": {
|
||||
"w": 937,
|
||||
"neckNorm": [
|
||||
0.4936,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_shy": {
|
||||
"w": 942,
|
||||
"neckNorm": [
|
||||
0.4988,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_sleepy": {
|
||||
"w": 936,
|
||||
"neckNorm": [
|
||||
0.494,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_smile": {
|
||||
"w": 941,
|
||||
"neckNorm": [
|
||||
0.492,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_surprised": {
|
||||
"w": 939,
|
||||
"neckNorm": [
|
||||
0.492,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_talk": {
|
||||
"w": 944,
|
||||
"neckNorm": [
|
||||
0.4924,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_talk_wide": {
|
||||
"w": 941,
|
||||
"neckNorm": [
|
||||
0.492,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_thinking": {
|
||||
"w": 941,
|
||||
"neckNorm": [
|
||||
0.496,
|
||||
0.9992
|
||||
]
|
||||
},
|
||||
"isabel_head_wave_wink": {
|
||||
"w": 938,
|
||||
"neckNorm": [
|
||||
0.4924,
|
||||
0.9992
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 110 KiB |
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "gesture_heart",
|
||||
"desc": "손 하트를 그리며 밝게 '잘됐어요'",
|
||||
"duration": 2.2,
|
||||
"return": "idle",
|
||||
"layers": {
|
||||
"body": [
|
||||
{ "t": 0.0, "mode": "rig", "clip": "idle" },
|
||||
{ "t": 0.15, "mode": "baked", "image": "isabel_body_club_heart", "fade": 0.2 }
|
||||
],
|
||||
"face": [
|
||||
{ "t": 0.0, "expr": "smile" },
|
||||
{ "t": 0.25, "expr": "love" }
|
||||
],
|
||||
"mouth": [
|
||||
{ "t": 0.5, "say": "잘됐어요", "dur": 1.1, "pattern": "talk" }
|
||||
],
|
||||
"transform": {
|
||||
"pelvis": { "ty": [ {"t":0.4,"v":0}, {"t":0.7,"v":8}, {"t":1.0,"v":0}, {"t":1.3,"v":8}, {"t":1.6,"v":0} ] },
|
||||
"head": { "rot": [ {"t":0.4,"v":0}, {"t":0.7,"v":4}, {"t":1.0,"v":-4}, {"t":1.3,"v":4}, {"t":1.6,"v":0} ] }
|
||||
},
|
||||
"caption": [ { "t": 0.5, "text": "잘됐어요", "dur": 1.5 } ],
|
||||
"sfx": [ { "t": 0.45, "id": "success" } ]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "gesture_no",
|
||||
"desc": "서있다 → 팔짱 끼고 인상 쓰며 고개 저으며 '안돼요'",
|
||||
"duration": 2.4,
|
||||
"return": "idle",
|
||||
"layers": {
|
||||
"body": [
|
||||
{ "t": 0.0, "mode": "rig", "clip": "idle" },
|
||||
{ "t": 0.15, "mode": "baked", "image": "isabel_body_club_armscross", "fade": 0.2 }
|
||||
],
|
||||
"face": [
|
||||
{ "t": 0.0, "expr": "neutral" },
|
||||
{ "t": 0.3, "expr": "negative" }
|
||||
],
|
||||
"mouth": [
|
||||
{ "t": 0.55, "say": "안돼요", "dur": 1.2, "pattern": "talk" }
|
||||
],
|
||||
"transform": {
|
||||
"chest": { "ty": [ {"t":0.0,"v":0}, {"t":0.2,"v":-4}, {"t":0.5,"v":0} ] },
|
||||
"head": { "rot": [ {"t":0.5,"v":0}, {"t":0.8,"v":9}, {"t":1.1,"v":-9}, {"t":1.4,"v":9}, {"t":1.7,"v":-9}, {"t":2.0,"v":0} ] }
|
||||
},
|
||||
"caption": [ { "t": 0.55, "text": "안돼요", "dur": 1.6 } ],
|
||||
"sfx": [ { "t": 0.5, "id": "nope" } ]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "Isabel reactions map",
|
||||
"note": "상황키(app event) → 반응 클립 이름(clips/<name>.json). idle은 배경 기본 루프.",
|
||||
"idleDefault": "dance_idle",
|
||||
"map": {
|
||||
"idle": "dance_idle",
|
||||
"error": "gesture_no",
|
||||
"success": "gesture_heart"
|
||||
},
|
||||
"plannedExpansion": {
|
||||
"greet": "gesture_wave",
|
||||
"explain": "gesture_present",
|
||||
"thinking": "gesture_think"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user