왼쪽, 오른쪽, 그리고 둘 다
투비트 첫 화면에는 '왼쪽, 오른쪽. 버튼 두 개면 충분합니다.'라는 한 줄이 있습니다. 키보드에서는 한쪽에 키가 다섯 개씩 있습니다. 왼쪽은 F·D·S·A·←, 오른쪽은 J·K·L·;·→입니다. 휴대폰에서는 화면 왼쪽 절반과 오른쪽 절반이 버튼이고, 손가락을 하나하나 따로 추적하므로 두 엄지로 동시에 누를 수 있습니다. 표준 게임패드도 됩니다. LB/L1·LT/L2·방향 버튼 ←·X/□가 왼쪽, RB/R1·RT/R2·방향 버튼 →·A/×가 오른쪽입니다.
양쪽을 함께 누르는 것이 세 번째 동작입니다. 장단 곡이 아닌 다섯 곡에서는 쉬움과 어려움 모두 큰 구간이 시작되는 첫 박이 보통 양손 노트입니다. 장단 곡에서는 이 동작에 실제 뜻이 있습니다. 왼쪽 줄은 장구의 낮은 궁편(쿵), 오른쪽 줄은 높은 채편(덕), 둘을 함께 치면 덩입니다. 이렇게 짝을 지어 두었기 때문에 오늘의 곡은 다른 곡의 좌우를 뒤집는 날이 있어도 장단 곡은 절대 뒤집지 않습니다.
음원 대신 코드로 쓴 곡
투비트에는 음원 파일이 하나도 없습니다. 곡마다 조·음계·코드 진행·구간을 코드로 적은 악보가 있고, 브라우저가 Web Audio로 그 자리에서 합성해 연주합니다. 화면과 서버가 같은 파일(shared/beat.mjs)을 쓰기 때문에, 서버는 플레이어 기기를 믿지 않고도 어떤 판이든 똑같은 채보를 스스로 다시 만들 수 있습니다.
곡은 일곱 곡입니다. 새벽 버스(로파이, 96 BPM, 80초), 네온 줄넘기(신스팝, 124 BPM, 62초), 고양이 행진(칩튠, 138 BPM, 59초), 별똥별 스윙(110 BPM, 70초), 캐논 변주곡(96 BPM, 80초), 그리고 장단 곡인 굿거리 마당(102초)과 자진모리 장터(97초)입니다.
앞의 네 곡은 시드로 구간마다 멜로디 모티프를 하나씩 만듭니다. 16칸짜리 리듬과 음높이입니다. 이름이 같은 구간은 같은 모티프를 다시 씁니다. 반복이 있어야 소리의 나열이 곡처럼 들리기 때문입니다. drop 구간은 멜로디가 더 촘촘하고 킥이 매 박 들어가며, 네 마디마다 마지막 마디는 모티프를 음계 한 칸 올려 변주합니다.
캐논 변주곡은 예외입니다. 파헬벨 캐논의 주제와 반복 베이스를 바탕으로 한 고정 편곡이고, 음을 하나하나 적어 두었습니다. 시드 때문에 잘 알려진 선율이 엉뚱한 멜로디로 바뀌는 일이 없게 하려는 것입니다. 40초부터 65초까지는 빠른 주제를 끝까지 연주합니다. 2026-10-04에 더한 장단 곡은 한 장단이 12칸입니다. 네 박을 각각 셋으로 나눈 것입니다. 북·징·꽹과리가 박을 받치고 대금 소리가 5음 음계 가락을 붑니다. 반주 장구는 늘 어려움 가락을 치므로, 쉬움으로 쳐도 내가 줄여서 치는 원래 장단을 온전히 들을 수 있습니다.
음악을 따라가는 채보
채보도 같은 악보에서 나옵니다. 쉬움은 박 위의 드럼을 따라갑니다. 킥은 왼쪽, 스네어는 오른쪽이고, 두 마디마다 첫 박 킥은 짧은 롱노트가 됩니다. 어려움은 멜로디의 오르내림을 따라갑니다. 선율이 올라가면 오른쪽, 내려가면 왼쪽, 같은 음이면 같은 줄입니다. 네 칸 이상 이어지는 멜로디 음은 롱노트가 되고, 마디 첫 박에 킥이 있으면 다른 손에 탭 노트가 하나 더 붙습니다.
자동으로 만든 채보에는 칠 수 있게 하는 간격 규칙이 두 가지 있습니다. 같은 줄의 노트는 어려움에서 8분음표, 쉬움에서 한 박 이상 떨어지고, 이 간격은 롱노트가 끝난 자리부터 셉니다. 또 롱노트를 누르고 있는 동안에는 그 줄에 노트가 나오지 않습니다.
보통은 따로 쓰지 않고 어려움에서 만듭니다. 노트 수는 쉬움과 어려움의 중간쯤으로 두고, 손마다 노트를 고르게 솎아 냅니다. 롱노트는 네 칸까지로 줄이고, 같은 손이 다시 누르기 전에 손을 뗄 두 칸을 남깁니다. 그 여유가 없는 장단 곡의 굴림은 탭 노트로 바뀝니다. 18초 연습은 네온 줄넘기의 첫 본 구간부터 여덟 마디를 잘라 낸 것이고, 롱노트는 모두 탭으로 바꿨습니다.
귀에 들리는 소리를 기준으로 판정하기
판정 창은 PERFECT ±45ms, GREAT ±90ms, GOOD ±135ms입니다. 1,000,000점 가운데 90%는 판정 점수(노트마다 1,000·700·300점), 10%는 최대 콤보로 정해집니다. 롱노트는 머리와 꼬리를 따로 세고, 끝나기 120ms 전까지 누르고 있으면 꼬리도 성공입니다. ±20ms 안쪽 PERFECT는 ★ 크리티컬로 따로 셉니다. 점수는 같지만 결과 화면과 순위표에 그 개수가 나옵니다.
더 어려운 문제는 '지금'이 언제냐는 것입니다. 투비트는 오디오 장치의 시계 하나만 씁니다. 브라우저의 오디오 시계는 장치가 소리를 한 덩어리씩 가져갈 때마다 뚝뚝 뛰어오릅니다. 맥 크롬은 약 5.3ms, 윈도는 10ms, 파이어폭스는 20ms가 넘습니다. 이 값을 그대로 읽으면 노트가 떨렸습니다. 그래서 오디오 시계와 performance.now()의 차이 가운데 위쪽 봉우리를 따라가고, 브라우저가 알려 주는 기본 지연과 출력 지연을 뺍니다. 헤드리스 크롬에서 재 보니 프레임 사이 떨림의 표준편차가 2.65ms에서 약 0.05ms로 줄었습니다. 블루투스 이어폰을 연결할 때처럼 지연값이 50ms 넘게 바뀌면 천천히 따라가지 않고 바로 새 값을 씁니다.
키와 터치 입력은 코드가 처리한 시각이 아니라 이벤트가 생긴 순간(event.timeStamp)으로 판정합니다. 게임패드는 4ms마다 읽고 패드가 알려 주는 시각을 씁니다. 화면은 1.5프레임에 화면 싱크 설정을 더한 만큼 앞의 곡 시각을 그립니다. 그린 프레임은 한두 프레임 뒤에야 화면에 나타나기 때문입니다. 소리 출력에서는 컴프레서를 뺐습니다. 미리 듣기(룩어헤드) 때문에 모든 소리가 6ms씩 늦어졌기 때문이고, 대신 지연 없는 소프트 클리퍼를 넣었습니다.
믿을 수 있는 싱크 보정
보정은 딸깍 소리가 아니라 드럼과 셰이커가 도는 박에 맞춰 누릅니다. 사람은 맨 딸깍 소리에 맞출 때 드럼에 맞출 때보다 눈에 띄게 일찍 치므로, 실제로 연주할 때의 버릇을 재려면 드럼으로 재야 합니다. 처음 네 박은 몸풀기로 버리고, 그다음 여덟 번 누른 값의 중앙값을 5ms 단위로 반올림해 제안합니다. 누른 값이 35ms 넘게 흩어지면 결과가 불안정하다고 표시합니다. 화면 싱크는 드럼이 울릴 때마다 바닥에 닿는 공을 보며 그림과 소리를 맞춥니다.
2026-10-05 검토에서, 터치·키보드·게임패드가 보정값 하나를 같이 쓰면 기기를 바꿀 때마다 판정이 다르게 느껴진다는 지적이 나왔습니다. 그래서 지금은 기기별로 보정합니다. 기본·터치·키보드·게임패드 프로필마다 판정 싱크와 화면 싱크, 마지막으로 잰 날짜를 따로 저장합니다. 한 판에서 20타 이상 쳤는데 오차의 중앙값이 한쪽으로 12ms 이상 치우치면, 결과 화면에 지금 쓰는 프로필을 바로 고치는 '판정 싱크 a → b' 단추가 나옵니다.
두 가지 추가 모드
리듬 놀이터와 덩덕 장고의 지금 모습은 2026-10-03에 리듬 세상(리듬 천국)·태고의 달인·파타퐁을 살펴보고 다시 짠 것입니다. 리듬 놀이터는 주고받기입니다. 로봇이 한 마디를 치면 다음 마디에 내가 따라 칩니다. 메트로놈 딸깍 대신 셰이커·뒷박 화음·베이스가 박을 받치고, 로봇 마디 마지막 박에 '쉬익' 소리가 차오르면 내 차례입니다. 공은 내가 칠 자리로 미리 튀어 갑니다.
덩덕 장고는 꽹과리·북·징 위에서 장구를 칩니다. 처음에는 16분음표 격자로 만들었는데 장단이 뻣뻣하게 들려서, 한 박을 셋으로 나눈 격자로 다시 만들었습니다(빠른 휘모리만 둘). 가이드 장구는 잘 맞히면 작아지고 놓치면 다시 커집니다. 늘 크게 울리면 내 소리와 겹쳐 두 번 치는 것처럼 들리고, 가이드에 기대게 되기 때문입니다. 판정에 쓰는 타악기 소리는 모두 3ms 안에 최대 음량에 이르고, 소리가 천천히 차오르는 징은 20ms 일찍 칩니다. 두 모드 모두 C(700,000점) 이상이면 다섯 스테이지 중 다음 스테이지가 열리고, 이 점수는 기기에만 저장되며 순위에 오르지 않습니다.
휴대폰과 접근성
터치 화면에서는 판정선 아래 표시가 F·J에서 ◀·▶로 바뀝니다. 곡 모드에서는 맞힐 때마다 아주 짧게 진동합니다. PERFECT는 8ms, 그 밖에는 5ms이고, 10콤보 이상이 끊기면 30ms 동안 떨립니다. 진동은 모두 GameNow 공통 진동 설정을 따릅니다. 다른 탭으로 가거나 창을 벗어나면 곡을 버리지 않고 멈추고, 다시 시작하면 3초를 센 뒤 이어서 연주합니다.
두 줄은 색뿐 아니라 모양으로도 구분합니다. 모든 모드에서 왼쪽은 파랑 ●, 오른쪽은 분홍 ◆입니다. 처음부터 그랬던 것은 아니고, 2026-10-04 검토에서 두 추가 모드의 색이 본편과 반대라는 지적을 받고 고쳤습니다. 움직임 줄이기를 켜면 박마다 밝아지는 연출이 꺼지고, 번쩍임은 약해지고, 판정 글자는 크기와 자리가 고정되며, 흔들림과 불꽃이 나오지 않습니다. 음악과 타격음은 음량 조절이 따로 있고, 값을 제곱해 적용하므로 한 칸씩 줄일 때 귀에 고르게 줄어듭니다.
서버가 검증할 수 있는 점수
2026-10-04까지 리플레이는 화면이 판정한 노트와 오차 목록이었습니다. 서버는 범위와 흩어짐만 볼 수 있었고, 그럴듯한 오차를 지어내 보내면 S+가 나왔습니다. 규칙 2판부터는 입력 원본을 보냅니다. 곡 시각(ms), 줄, 누름·뗌입니다. 서버는 게임과 같은 판정 함수를 다시 돌려 노트와 오차, 누른 시간을 스스로 정합니다. 결과 화면도 같은 방식으로 점수를 다시 계산하므로, 화면에 보이는 점수가 곧 순위에 오르는 점수입니다.
없앨 수 없는 한계도 있습니다. 리듬 게임에서는 입력 시각을 기기가 보고하므로, 서버가 사람이 쳤다는 것을 증명할 수는 없습니다. 다만 30타 이상인데 오차의 표준편차가 4ms도 안 되는 기록은 받지 않습니다. 사람의 손은 떨리기 때문입니다.
시험 뒤에 바꾼 것
무엇을 언제 바꿨는지 날짜순으로 적습니다.
- 2026-10-04: 시험 플레이가 18초 연습을 S와 S+ 풀 콤보로 끝낼 만큼 판정이 넉넉해서, 순위 위쪽이 갈리지 않았습니다. 새로 생긴 어려움 판(장단 곡, 그리고 2026-10-05부터의 오늘의 곡)은 PERFECT를 ±33ms로 좁혔습니다. 이미 기록이 쌓인 판은 예전 창 그대로 두어 기록끼리 비교할 수 있게 했습니다.
- 2026-10-04: 리플레이를 판정 결과 대신 입력 원본으로 바꿨고, 장단 곡 두 곡이 들어왔습니다. 97초·102초로, 2026-10-04 검토에서 짧다는 지적을 받은 원래 다섯 곡보다 깁니다.
- 2026-10-07(1.0.46 배포)까지: 음악·타격음 음량 따로 조절, 모든 모드에서 같은 줄 색과 ●/◆ 모양, 기기별 보정 프로필, 마디 연습이 들어갔습니다. 결과 화면에 가장 많이 놓친 마디 세 곳을 표시하고, 마디를 골라 그 앞 두 박부터 0.75배·0.9배·원래 속도로 연습할 수 있습니다. 구간 연습 기록은 제출하지 않습니다.
- 2026-10-08: C 미만은 실패로 셉니다. 그전에는 0점 D도 성공으로 표시될 수 있었습니다.
- 2026-10-09: 통과·풀콤보·올 퍼펙트 램프(로그인하지 않아도 이 기기에 저장), 다음 추천 판, 다음 등급까지 남은 점수, 빠름·느림 분포, 곡이 drop 구간에 들어서면 뜨는 DROP 띠, 곡 모드에서 맞힐 때마다 나는 가벼운 탭 소리.
- 2026-10-10: 롱노트 진행 막대를 판정 시계로 채우도록 바꿔, 화면 싱크 값 때문에 노트가 끝나기 전에 막대가 다 찬 것처럼 보이지 않게 했습니다.
알고 있는 절충
곡 모드의 탭 소리는 기본으로 켜져 있습니다. 지연이 큰 블루투스 이어폰에서 음악과 겹쳐 거슬리면 ⚙의 타격음 음량만 줄이면 됩니다. 음악 음량은 그대로입니다. 로그인하지 않고 남긴 점수와 램프는 그 기기에만 남고, 나중에 로그인해도 계정으로 옮겨지지 않습니다.