수면 앱에 오프라인 ambient BGM과 트랙 선택 UI 추가
목차
수면 관련 앱에 ambient BGM 트랙들과 selector UI를 붙였다.
왜 이 타이밍에 오디오 에셋을 직접 번들링했나
사실 처음부터 번들링 방식으로 가려던 건 아니었다. 스트리밍 방식(CDN에서 끌어오기)도 테이블 위에 있었고, 팀 내에서도 의견이 갈렸다. 그런데 bedtime 기능 특성상 오프라인 환경에서도 끊김 없이 재생이 보장돼야 한다는 점이 결정타였다. 잠들려는 순간에 버퍼링이 걸리면 UX가 박살 난다. 당연한 얘기 같아도 실제로 이 트레이드오프를 팀 전체가 공유하고 결정하는 게 중요했다.
번들 사이즈 증가는 명확한 단점이었다. 그래서 트랙 선정 기준도 나름 엄격하게 잡았다.
rain.mp3— 백색소음 계열, 수면 유도 효과 검증된 정석 트랙fire.mp3— 모닥불 크래클링, rain과 함께 가장 수요 많은 ambient 카테고리birds.mp3— 이른 아침 기상 쪽 UX와 연결될 수 있는 자연음bell.mp3— 명상/마음챙김 계열 톤calm.mp3— 그 외 채울 수 없는 분위기 레이어
8 트랙 전체를 한 번에 커밋한 건 에셋 관리 측면에서 일부러 묶었다. 반쪽짜리 상태로 feature branch에 살아있는 게 더 리스크다.
selector chips UI 설계 포인트
chips 방식을 택한 이유가 있다. 탭이나 드롭다운 대비 현재 선택 상태가 시각적으로 명확하고, 한 화면에서 전체 옵션을 한눈에 볼 수 있다. bedtime 화면은 사용자가 어둠 속에서 반쯤 눈 감고 조작하는 상황이라 터치 영역과 피드백이 특히 중요하다.
// selector chip 구성 예시 패턴
const AMBIENT_TRACKS = [
{ id: 'rain', label: '빗소리', src: 'rain.mp3' },
{ id: 'fire', label: '모닥불', src: 'fire.mp3' },
{ id: 'birds', label: '새소리', src: 'birds.mp3' },
{ id: 'bell', label: '벨', src: 'bell.mp3' },
{ id: 'calm', label: 'Calm', src: 'calm.mp3' },
// ...
];
// chip 선택 → 이전 트랙 정지 → 새 트랙 로드 → 재생
function selectTrack(id) {
stopCurrent();
loadAndPlay(AMBIENT_TRACKS.find(t => t.id === id));
setSelected(id);
}
트랙 전환 시 크로스페이드 처리 여부도 잠깐 논의됐는데, 이건 일단 심플하게 끊고 새로 시작하는 방식으로 갔다. 크로스페이드는 구현 복잡도 대비 bedtime 컨텍스트에서 체감 차이가 크지 않다는 판단이었다.
CREDITS.md — 에셋 라이선스 관리
app/assets/audio/ambient/CREDITS.md 이 파일이 사실 이번 작업에서 제일 신경 쓰인 부분이다. 오디오 에셋을 번들에 포함할 때 라이선스 처리를 흐지부지하고 넘어가는 경우를 꽤 봤는데, 그게 나중에 법무/컴플라이언스 이슈로 튀어오르면 수습이 훨씬 힘들다. 초기에 CREDITS 문서 하나 제대로 만들어두는 게 팀 전체 리스크 관리 차원에서 맞다.
| 파일 | 용도 | 비고 |
|---|---|---|
CREDITS.md |
출처·라이선스 명시 | 필수 |
rain.mp3 |
빗소리 ambient | - |
fire.mp3 |
모닥불 크래클링 | - |
birds.mp3 |
자연음/새소리 | - |
bell.mp3 |
명상 톤 | - |
calm.mp3 |
복합 calm | - |
앞으로 트랙이 추가될 때도 CREDITS 업데이트를 PR 체크리스트에 박아두는 게 맞다고 생각해서 팀 내 PR 템플릿에도 항목 추가했다. 에셋 종류가 뭐든 외부 소스에서 가져오는 거라면 항상 같은 기준을 적용하는 게 낫다.
회고
사실 이 피처 자체가 코드보다 결정의 연속이었다. 번들 vs 스트리밍, 트랙 수와 용량, chip vs 다른 UI 패턴, 크로스페이드 여부. 각각은 작은 결정이지만 어느 하나 근거 없이 넘어간 게 없다. 이런 판단들을 코드 리뷰 때 설명할 수 있어야 하고, 팀원이 나중에 이 코드를 수정할 때도 왜 이렇게 짰는지 이해할 수 있어야 한다.
8 트랙 + selector 조합이 실제로 사용자 수면 경험에 얼마나 기여할지는 지표를 봐야 알겠지만, 적어도 이 작업이 왜 이 방식으로 들어갔는지는 팀 안에서 충분히 정리됐다.
끝.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.