Files
Dansori_Characters/Noeul_Live2D/06_Reactions/Reactions.md
T
2026-07-04 10:34:46 +09:00

4.3 KiB

반응 시퀀서 & 트리거 (Reactions)

상황 → 반응을 정의하는 레이어. 트리거 매퍼(reactions.json) + 반응 클립(clips/*.json)으로 구성.

Phase 2 런타임 구현됨: ../07_Viewer/reactions.html(더블클릭 재생) — idle=배경춤(풀캔버스 리그) + 트리거(idle/error/success/focus). baked 바디 + 표정 머리(목 정합·회전) 합성은 ../../_tools/reactions_layout_render.py가 만든 _layout.json을 사용(브라우저는 file:// alpha 판독 불가라 사전계산 필수). 오프라인 검증: _reaction_preview.png.

트리거 매퍼 (reactions.json)

상황키 → 반응 클립 이름. 앱은 상황키만 던지면 된다.

{ "error": "gesture_no", "success": "gesture_heart", "idle": "dance_idle" }

반응 클립 스키마 (clips/<name>.json)

하나의 반응 = 레이어드 타임라인.

{
  "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":"noeul_body_cozy_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)에 따라 사용.

노을 톤 (로파이) — 튜닝 방침

노을은 차분·나른·집중 캐릭터. 다른 캐릭터보다 모션 진폭을 작게(고개 ±6 이하), 속도를 느리게, 대사를 부드럽게("음, 안 돼요~" / "잘됐어요~"). 시그니처는 비트에 고개 까딱(로파이 감상).

상황 → 반응 카탈로그

상황키 클립 Body Face Mouth 잔모션
idle dance_idle rig smile/neutral 잔잔한 그루브 루프
error gesture_no baked cozy_armscross neutral→negative "음, 안 돼요~" 작은 고개 젓기(±6, 느리게)
success gesture_heart baked cozy_heart smile→love "잘됐어요~" 부드러운 바운스(±5)
focus ★시그니처 gesture_focus baked cozy_listen neutral→sleepy 허밍 "음~" 비트에 고개 까딱(루프, 4s) + "♪"
(확장) greet gesture_wave rig wave smile "안녕하세요~" 부드러운 손 흔들기
(확장) sleepy gesture_sleepy baked cozy_idle_upper sleepy (하품) 느린 끄덕

사용 자산(모두 Noeul/ 소스 md에 스펙됨): baked 포즈 noeul_body_cozy_{armscross,heart,listen,idle_upper} · 표정 noeul_head_wave_{neutral,negative,smile,love,sleepy,thinking} · hairmask. 생성 후 ../03_Assets/Library/로 분류 복사 → 시퀀서 연결.

트리거 API(개념)

Mascot.React("success")     // reactions.json으로 클립 결정 → 시퀀서 재생 → 종료 후 return 클립
Mascot.SetIdle("dance_idle")// 배경 기본 루프
Mascot.Say("...", expr)     // 임시 대사(mouth+face)만

상세 앱 연동: ../08_Roadmap/App_Integration.md.