"첫 30초"를 만드는 데 집중한 세션. 인트로 카메라가 NPC를 보여주면서 살아있는 마을을 연출합니다.

인트로 카메라 진화 과정

총 6번 반복했습니다.

버전 문제
v1: 사인파 패닝 + 줌아웃 밋밋함, NPC 안 보임
v2: NPC 4명 순회 줌아웃이라 전체만 보임
v3: 줌인 1.15x 여전히 NPC에 포커스 안 됨
v4: 줌인 1.8x 내 캐릭터만 크게 보임
v5: 플레이어 위치를 NPC로 이동 플레이어가 텔레포트
v6: 가상 카메라 위치 플레이어 고정, 카메라만 이동

최종 구조

플레이어: (20, 25)에 고정 — 안 움직임
intraCamPos: 가상 카메라 위치 — NPC를 순회
renderer._cameraFollowTarget: intraCamPos (인트로 중만)

렌더러가 매 프레임 _cameraFollowTarget || player를 따라가므로, 인트로 중에는 가상 위치를, 인트로 후에는 플레이어를 따라갑니다.

인트로 시퀀스

NPC1: 혼잣말 중얼거리는 모습 (2.5초, 줌인)
  ↓
NPC쌍: 두 NPC가 대화하는 모습 (2.5초, 줌인)
  ↓
NPC2: 혼잣말 중얼거리는 모습 (2.5초, 줌인)
  ↓
카메라가 플레이어 위치로 부드럽게 복귀

카메라가 비추는 NPC에게 LLM 혼잣말/대화를 트리거합니다. triggerIntroSpeech()가 타겟이 바뀔 때 1회만 호출.

NPC간 대화 빈도

Before

nextSocialAt = world.totalMinutes + 22 + Math.random() * 34;
// 22~56분마다 — 사실상 안 일어남

After

nextSocialAt = now + 10000 + Math.random() * 15000;
// 10~25초마다 — 혼잣말(8~20초)과 비슷

가장 가까운 NPC 쌍을 찾아서 대화시킵니다. 6타일 이내면 서로 걸어가게.

Rule-base 혼잣말 → 이모티콘만

// Before
ambient_solo: ["🎵", "🎶", "~♪", "흠흠", "후~", "라라~", "음~"]
ambient_chat: ["ㅎㅎ", "와~", "그래?", "맞아", "음음", "오~", "헤헤"]

// After
ambient_solo: ["🎵", "🎶", "~♪", "💭", "✨"]
ambient_chat: ["😄", "😮", "🤭", "👋", "💬"]

LLM이 생성하는 혼잣말(가장 가까운 NPC)은 여전히 텍스트. 나머지는 이모티콘으로 깔끔하게.

같은 NPC 연속 혼잣말 방지

lastAmbientNpcId를 기억해서, 직전과 같은 NPC면 2번째로 가까운 NPC 선택.

오디오

Web Audio API → HTML5 <audio> 전환. 치지직/하울링 해결. BGM을 동물의 숲 스타일 트랙으로 교체 (Pixabay: Chill Yume).

핵심

인트로가 보여주는 것:

카메라가 마을을 비추면, NPC가 혼잣말을 하고, 다른 NPC끼리 대화하고 있다. 이 마을은 내가 오기 전부터 살아있었다.

그리고 카메라가 플레이어에게 돌아오면, 유진이 걸어오며 인사한다.

이게 "첫 30초"입니다.