프롤로그 — 루프 시작 전
이 개발일지는 본격적인 루프가 시작되기 전에 쓰는 서문이다. 지금까지 어떻게 여기까지 왔고, 내가 이 프로젝트를 어떻게 바라보고 있는지 정리해두고 싶었다.
여기까지 온 길
레포는 비어 있었다. 유저의 첫 마디는 "너 고양이 오이이아이 알아?"였다. 안다고 하자 "그거 mp3 인터넷에서 구해줘"가 다음이었고, Myinstants에서 90KB짜리 원곡을 받는 걸로 진짜 일이 시작됐다. 거기서부터 프로젝트는 유저의 한 마디 한 마디를 따라 덩치가 커졌다.
시간순으로 엉성하게 정리하면:
- 원곡 다운로드 → 단일 HTML에 Web Audio API로 파형 + 구간 슬라이더.
- Vite 프로젝트로 승격 + 한글 자모 키 매핑 (
ㅗ→ㅜ로 교체). - 파형 드래그로 구간 직접 지정하는 UX, 처음엔 선택하기 어려워서 "클릭=선택 / 바디 드래그=이동 / 엣지 드래그=리사이즈" 3단 인터랙션으로 재설계.
ㅣ를 하나로 단순화, 유저가 튜닝한 타임스탬프를 기본값으로 고정, A/B 보너스 슬롯 추가.- "졸라 화려하게" 요구에 따라 전체 화면 FX 캔버스 — 파티클·링·텍스트·플래시·빔.
- 연타하니 렉 걸려서 최적화 한 판 —
shadowBlur제거가 결정타였다. DPR 1.5 캡, 컬러별 배칭, MAX_ITEMS 900. - 꾹 누르면 지수 가속 + 1초 이상 홀드 뒤 EDM 드롭 (화면 흔들림 포함).
- Enter → 랜덤 DJ 이펙트에서 시작해서, 1~9 키 + 셀렉트로 매핑하는 슬롯 시스템으로 확장. 이펙트 수는 11 → 24로 불어났다.
- 같은 DJ 키 두 번 누르면 겹쳐 들리는 문제 — 모든
BufferSource/Oscillator를activeDjNodesSet에 넣고 다음 트리거 때 정지. - DJ 이펙트는 A 세그먼트 서브 버퍼를 쓰도록 리라우팅 — A 튜닝하면 DJ 톤이 같이 변한다.
- A키 → 고양이 GIF 랜덤 팝 (3종 애니메이션).
specs/LOOP.md로 자율 반복 프로토콜,tests/에 Playwright 파이프라인 (desktop + mobile), 이 개발일지 제도까지.
코드로 보면 src/main.js 혼자 너무 무거워졌고 effects.js는 그래도 경계가 선명하다. 튜닝 데이터는 전부 localStorage에 들어가 있고 버전이 이미 v6다 — 마이그레이션 없이 날리는 패턴이 여기까지는 통했다.
내 생각
이 프로젝트는 "고양이 밈 장난감"으로 시작했는데, 유저가 한 번씩 올려치는 요구 때문에 지금은 아슬아슬하게 musical toy 영역까지 와 있다. 의도된 건축이 아니라 축적의 결과다. 그래서 지금 시점에 LOOP.md로 "바이럴 + DJ + 모바일" 세 축을 박아둔 게 늦었지만 유효한 결정이라고 느낀다. 방향이 없었으면 아마 계속 비주얼 FX만 더 화려하게 만들다가 멈췄을 거다.
스펙을 쓰면서 제일 놀란 건 모바일이 사실상 비어 있다는 사실이다. 지금 이 앱은 키보드 전용이다. 카드 클릭이라는 터치 대안이 있긴 하지만 UI 자체가 데스크탑을 가정하고 그려져 있고, 무엇보다 iOS Safari에서 Web Audio가 첫 터치 때 어떻게 깨어날지 실기기로 검증한 적이 없다.
DJ 축도 얼핏 24개 이펙트로 화려해 보이지만, 실제 DJ가 좋아할 컨트롤은 없다. BPM도 없고, 루프 레이어도 없고, wet/dry도 없다. "버튼 누르면 5초짜리가 한 방 나간다"의 구조다. 이건 toy이지 tool이 아니다.
바이럴 축은 가장 무게가 덜하다. 공유할 게 없다. 녹화도 안 되고 링크 공유도 없고, "이거 봐" 할 수 있는 게 화면 캡처뿐이다.
느낌 / 셀프평가
시각·청각 임팩트는 이미 강하다. A 눌렀을 때 터지는 고양이 + 파티클 + 드롭 조합은 처음 보면 확실히 한 번 웃는다. 이 임팩트를 기본값으로 깔아둔 건 자산이다. 다만 자산은 어디까지나 입구고, 사람이 머무를 이유는 아직 없다.
- Viral: 10% — 눈에는 예쁘지만 나갈 길이 없음.
- DJ: 30% — 소리 도구는 있으나 프로가 만질 꼭지가 없음.
- Mobile: 5% — 사실상 미지의 영역.
다음에 하고 싶은 것
루프를 시작하면 모바일을 먼저 뚫고 싶다. 지금 상태로 모바일에서 열면 아무것도 안 될 가능성이 높다. 터치 패드 레이아웃 + iOS 오디오 언락만 해도 체감이 확 달라진다. 바이럴과 DJ는 모바일 위에서 훨씬 더 큰 값이 되기 때문에 순서상 모바일이 맨 앞.
그 다음 우선순위는 Session recording. 녹화해서 내릴 수 있게 되는 순간 바이럴 축이 0에서 1이 된다. DJ 축은 BPM 락. STUTTER·GATE·ECHO를 BPM에 스냅하는 것만으로 아마추어 티가 싹 빠질 거라고 예상한다.
무엇보다 매 루프를 눈에 보이는 변화로 쌓는 원칙을 지키고 싶다. 리팩터만 한 루프는 실패다. 매번 Playwright 스크린샷으로 "전후"가 남도록.
마음가짐
루프는 혼자 돌리는 작업이다. 유저가 매 iteration마다 방향을 잡아주지 않는다. 그래서 나는 두 가지를 특히 조심하고 싶다.
첫째, 판단을 미루지 않기. Backlog에 24개 항목이 있다고 24번의 루프가 저절로 의미 있는 게 아니다. 매번 "이게 이 프로덕트를 전진시키는가"를 묻고, 답이 애매하면 다른 걸 골라야 한다. 스펙에 있다고 관성으로 집지 말자.
둘째, 완결성에 강박 갖기. 작지만 끝난 것을 선호한다. 반쯤 된 BPM 시스템보다 작고 완결된 tap-tempo 하나가 낫다. 유저는 다음에 열었을 때 뭐가 되어 있는지를 본다. "될 뻔한" 상태는 가치가 없다.
그리고 무엇보다, 이건 장난감이기도 하다. 재미를 잃지 말자. 고양이 gif가 팝 하고 나오는 게 원래 이 프로젝트의 정체성이다.
메모
- 유저는 한글 대화, 짧은 터미널 출력 선호. devlog와 LOOP.md는 한글 중심.
- localStorage 버전이 v6까지 왔다. 버전 올려서 날리는 패턴이 유효했음. URL 공유 기능을 넣는 순간 이 구조가 외부 계약이 되니 마이그레이션을 진지하게 고민해야 함.
- DJ 효과 24개 중 유사한 것들(OVERDRIVE↔DISTORT, ECHO↔REV-ECHO) 통합/차별화 여부는 언젠가 청소할 것.
- FX 캔버스의
mix-blend-mode: screen은 데스크탑에서 예쁘지만 모바일 Safari에서 어떻게 나올지 미지수 — 모바일 작업 시 검증 대상. playwright.config.js의reuseExistingServer: true덕에 dev 서버를 띄워두면 테스트가 훨씬 빠르다. 루프 중에는 5174를 살려두는 게 낫다.- 루프 진입할 때 먼저
npm run test:desktop으로 baseline 녹색 확인 권장. 뭔가 이미 깨져 있다면 고친 다음에 새 기능에 착수.
다음 루프부터 진짜 시작이다. 작고 완결된 변화, 매번 스크린샷, 세 축 중 가장 약한 쪽부터. 유저가 다시 열었을 때 바로 "오" 할 수 있는 것으로.