STILL CODING / NOTES
개발 노트
만들면서 배운 것을, 다시 쓸 수 있게.
앱 하나를 공개하기까지 고민한 설계, 부딪힌 문제, 선택한 해결책을 기록합니다. 코드 조각과 수치는 실제 서비스 코드를 기준으로 적었습니다.
앱별로 보기
- Direct Play게임을 고르고 링크로 초대하면 바로 시작되는 10개의 브라우저 게임노트 15편
- 가나 공방히라가나와 가타카나를 같은 소리와 손의 움직임으로 연결하는 학습 공방노트 5편
- Vocal Check내 목소리의 음정을 눈으로 확인하는 실시간 보컬 체크 도구노트 2편
- CollaBoard방은 서버가 만들고, 팀의 자료는 팀원 사이에만 남는 협업 공간노트 2편
- Bus Explorer버스의 흐름을 따라 도시를 새롭게 읽는 노선 탐색 도구노트 4편
- SongnoteABC 악보를 고치고 108건반으로 듣는 Songnote 스튜디오노트 2편
- Guitar Auto-Strum스트로크는 앱에게, 연주는 당신에게 맡기는 브라우저 기타 자동 반주노트 5편
- PDF Flow Studio서버 전송 없이 브라우저에서 안전하게 재배치·추출·결합하는 PDF 워크스페이스노트 2편
전체 노트
-
환승 경로를 어떻게 찾나 — 우선순위 큐가 무너진 자리에 라운드 탐색과 '건너편 정류장 걷기'를 놓다
버스 환승 경로 탐색을 우선순위 큐로 만들었더니 실제 질의에서 아무것도 찾지 못했습니다. 탑승 횟수별 라운드 탐색과 도보 환승으로 바꾼 과정, 후보를 고르는 규칙, 300개 질의로 잰 결과를 정리합니다.
-
시간표가 없는 버스 경로에 '몇 분'을 붙이는 법 — Bus Explorer의 소요 시간 추정
공공데이터에는 정류장 사이 소요 시간표가 없습니다. Bus Explorer가 실시간 도착 정보, 관측한 구간 중앙값, 기본값을 섞어 경로의 소요 시간을 추정하고, 그 추정이 어디서 왔는지 함께 보여 주는 방법을 코드로 정리합니다.
-
버스를 지켜보며 구간 시간을 배우다 — 모든 구간이 40초로 나온 이유와 하루 1만 번의 예산
Bus Explorer는 정류장 사이 소요 시간을 예측값이 아니라 관측으로 재려고 차량 위치를 반복 수집합니다. 첫 측정에서 모든 구간이 폴링 간격과 같은 40초로 나온 버그의 원인, 도착 시점을 중간에 놓는 해법, 하루 호출 한도 안에서 도는 수집기 설계를 정리합니다.
-
공공 API를 덜 두드리는 법 — 30초 캐시, 동시 요청 합치기, 실패한 뒤 물러서기
호출 한도가 있는 공공 버스 API를 쓰는 Bus Explorer가 실시간 위치를 캐시하는 방법을 정리합니다. 같은 키의 동시 요청 병합, 실패 시 30·60·120초 물러서기, 한도 초과 시 서비스 단위 차단, 오래된 값을 신선한 척하지 않는 규칙을 코드로 설명합니다.
-
sessionId는 비밀이 아니다 — CollaBoard의 식별자와 입장 권한 분리
CollaBoard에서 공개 식별자, 일회용 입장권, 멤버 토큰, 방장 토큰의 역할을 나눕니다. 참가자 번호를 아는 것과 입장·방장 권한을 갖는 것을 어떻게 갈랐는지 정리합니다.
-
샘플 없이 기타 소리 만들기 — 줄을 계산해서 강철과 나일론을 구별하기
Guitar Auto-Strum은 녹음된 기타 음원 없이 코드 계산만으로 기타 줄 소리를 만듭니다. 사인파 일곱 개를 더하던 방식이 강철과 나일론을 구별하지 못한 이유, Karplus-Strong 도파관으로 바꾼 구조, 음이 어긋나지 않게 지연을 맞춘 방법, 소리를 Node에서 측정하는 테스트를 정리합니다.
-
'소리가 안 바뀌었다'를 어떻게 증명하나 — 모든 리듬을 실제 엔진에 돌려 기록하는 골든 테스트
Guitar Auto-Strum은 모든 시스템 리듬을 실제 트랜스포트에 돌려, 엔진이 예약한 모든 음의 시각·세기·줄을 파일로 기록하고 비교합니다. 가짜 오디오 하네스, 결정적인 시간 진행, 의도한 변경일 때만 갱신하는 규칙, 스냅샷과 별개로 두는 성질 검사를 정리합니다.
-
카포를 마이너스로 — 진짜 카포에는 없는 방향을 넣은 이유
Guitar Auto-Strum의 카포는 −5에서 +7까지 움직입니다. 실제 카포로는 불가능한 낮추는 방향을 넣은 이유, 범위를 손과 귀의 한계로 정한 방법, 그리고 'C (→D)'처럼 두 이름을 함께 보여 주는 표기를 코드 주석과 함께 정리합니다.
-
정확한 박자는 기계처럼 들린다 — 스윙과 사람 같은 어긋남, 그리고 '랜덤이 랜덤이면 안 되는' 이유
Guitar Auto-Strum의 스윙과 휴머나이즈 기능이 어떻게 박자를 일부러 흔드는지 정리합니다. 뒷박을 늦추는 스윙 비율, 타이밍·세기·스트럼 속도의 미세한 변화, 그리고 난수 대신 '스트로크 번호와 시드로 정해지는 값'을 쓴 이유를 코드로 설명합니다.
-
박자가 흔들리지 않는 자동 반주 — 타이머는 흔들리고 오디오 시계는 흔들리지 않는다
브라우저의 setInterval로 음을 직접 울리면 박자가 흔들립니다. Guitar Auto-Strum이 오디오 시계 위에 음을 미리 예약하는 look-ahead 스케줄러로 박자를 지키고, 코드 변경과 마디 경계에서 생기는 문제를 다룬 방법을 코드로 정리합니다.
-
게임을 아홉 개로 늘려도 로비가 가벼운 이유 — Direct Play의 게임 모듈 구조
Direct Play가 게임 10개를 하나의 로비에서 다루기 위해 만든 카탈로그와 지연 로딩 레지스트리, 게임 모듈 계약, 순수 로직 분리를 설명합니다. 독립 앱 두 개를 같은 계약에 맞춰 옮긴 코드도 다룹니다.
-
6×6 미니 스도쿠: 해가 하나뿐인 문제를 비트마스크 솔버로 만들어 내기
Direct Play의 6×6 미니 스도쿠가 문제를 만드는 방법을 정리합니다. 6비트 후보 마스크, 후보가 가장 적은 칸부터 푸는 백트래킹, 해를 두 개까지만 세는 유일성 검사, 180도 대칭 제거를 코드로 보이고 난이도 평가의 한계도 적습니다.
-
게임마다 주소를 주면 생기는 일 — 문 하나짜리 서브도메인과 302 리다이렉트
spy-game.still-coding.cc처럼 게임마다 외우기 쉬운 주소를 주되, 실제 플레이는 한곳에서 하도록 만든 Direct Play의 게임 도메인 구조를 정리합니다. 리다이렉트 규칙, 저장소가 흩어지는 문제, 링크 하나가 방 하나를 쓰는 비용을 다룹니다.
-
숫자 야구: 판정은 스무 줄이고, 나머지는 입력을 막고 상태를 복원하는 일이었다
Direct Play 숫자 야구의 비밀 숫자 생성, 스트라이크·볼 판정, 중복 입력 차단, 세 상태 메모, 힌트, 새로고침 뒤 복원과 순위 정렬을 실제 코드로 정리합니다. 참가자가 정답을 볼 수 있다는 한계도 함께 적습니다.
-
사진 퍼즐: 제자리에 붙은 조각은 한 덩어리로 — Union-Find로 묶고 옮기기
Direct Play 사진퍼즐이 정답 옆에 놓인 조각을 하나의 그룹으로 묶어 함께 옮기는 방법을 설명합니다. Union-Find로 그룹을 찾고, 옮길 자리를 만들어 주는 이동 규칙, 세 단계 힌트, 멀티터치에서 보드가 잠기던 버그의 원인을 코드로 정리합니다.
-
PINHOLE: 본 만큼 점수가 깎이는 게임 — 128×72 격자로 '얼마나 봤는지' 재기
작은 원형 시야로 장면을 살피는 PINHOLE이 본 면적을 재는 방법과 점수 공식, 한국어 짧은 답을 판정하는 규칙을 코드로 설명합니다. 해커톤용 독립 앱에서 만든 게임을 Direct Play 모듈로 옮기면서 바뀐 것과 남은 한계도 정리합니다.
-
슬라이딩 사진퍼즐: 섞기는 거꾸로 걸어서, 풀이는 A*로 — 그리고 4×4부터 멈추는 풀이 버튼
Direct Play 슬라이딩 사진퍼즐이 풀 수 있는 배치만 만드는 방법, 한 줄을 통째로 미는 이동 규칙, 포기하면 보여 주는 정답 풀이(BFS·A*)를 코드로 설명합니다. 풀이가 3×3에서만 안정적이고 4×4부터 실패하는 것을 직접 재어 정리했습니다.
-
사진은 서버를 거치지 않는다 — Direct Play가 게임 자원을 P2P로 나눠 주는 법
사진퍼즐처럼 방장이 올린 사진이 게임의 재료인 앱에서, 서버에 사진을 저장하지 않고 참가자에게 전달하기 위해 Direct Play가 만든 자원 요청 라우팅, 16,000자 청크 전송, 해시 검증, 실패 처리를 정리합니다.
-
가위바위보 선택은 서버에만 보인다 — Durable Object로 만든 비공개 라운드
방장이 계산하는 대신 Durable Object가 참가자 등록, 비공개 선택, 승패 판정과 재접속 상태를 관리하는 Direct Play 가위바위보의 서버 권위 구조를 설명합니다.
-
방에도 수명이 있다 — 알람으로 청소하고 하루 500방으로 지키는 Direct Play의 서버 비용 설계
Direct Play는 설정 중 1시간 뒤 삭제, 활동 없이 3일 뒤 보관, 보관 후 7일 뒤 삭제를 예약합니다. Durable Object 알람으로 방을 정리하는 방법, 쓰기를 줄이는 장치, 하루 500방 한도를 전역 객체 하나로 세는 방법을 코드로 정리합니다.
-
포켓 레이스: 1분짜리 레이싱을 휴대폰 네 대로 — 방장이 계산하고 각자는 예측한다
브라우저끼리 최대 4명이 실시간으로 달리는 포켓 레이스의 네트워크 구조를 정리합니다. 방장 권위 시뮬레이션, 순서를 포기한 상태 채널과 신뢰할 수 있는 이벤트 채널, 초당 20번의 상태 전송, 내 차의 예측과 보정을 코드로 설명합니다.
-
스파이 게임의 진행 규칙 — 역할 확인, 투표, 마지막 추리
4~12명이 함께하는 Direct Play 스파이 게임의 투표와 결선, 마지막 추리 규칙을 설명합니다. 로컬 코드로 확인한 제한 시간 처리와 진행 상태 복원의 한계도 기록합니다.
-
사진 한 장으로 '여기가 어디게?' — EXIF GPS, 지도 임베드, 그리고 사진 만 장 중 한 장 고르기
Direct Play 사진퍼즐의 EXIF GPS 읽기, 지도 표시, 장소 이름 추천을 설명합니다. 공개 여부를 확인해야 하는 로컬 Flutter 사진첩 구현과 60초 타임아웃에 관한 커밋 기록도 다룹니다.
-
배포 뒤 MIME 오류가 남았다 — 서비스 워커의 빌드 파일 캐시를 걷어내기
가나 공방의 MIME 오류 관련 커밋 두 개와 현재 서비스 워커 코드를 대조합니다. HTML 폴백을 캐시에서 거르는 수정 뒤에 빌드 파일 요청을 가로채지 않도록 바뀐 과정, 기존 캐시를 지우는 장치, 오프라인 동작의 확인 범위를 다룹니다.
-
숫자합 퍼즐: 판을 거꾸로 만들면 시작하자마자 막히지 않는다
Direct Play 숫자합 퍼즐이 합이 목표인 조합을 먼저 만들고 판을 채우는 방식, 부분집합 합 DP로 종료를 판정하고 힌트를 찾는 방법, 그리고 완벽한 클리어가 보장되지 않는 이유를 코드로 설명합니다.
-
텍스트 악보를 마우스로 고치려면 — Songnote가 ABC를 문서 모델로 바꿔 편집하는 법
ABC는 손으로 쓰기엔 편하지만 음표를 클릭해서 고치기엔 불편한 텍스트입니다. Songnote의 시각 악보 편집기가 ABC를 구조화된 문서 모델로 바꿔 편집하고 다시 ABC로 되돌리는 방법, 실행 취소, 텍스트와 모델의 동기화 문제를 코드로 정리합니다.
-
iPad에서 짧은 획이 사라지고 시리가 뜬다 — 필기 캔버스의 입력 처리 보강
가나 공방의 개발 문서에 기록된 iPad·Apple Pencil의 짧은 획 유실과 현재 포인터 처리를 대조합니다. 시리 화면과 입력 중단이 겹친 기록, 캡처 제거와 window 추적, 기기에서 다시 확인할 항목을 설명합니다.
-
탁음·요음·외래어를 외우지 않고 '만들게' 하기 — 149개 표기를 7가지 규칙으로
가나 공방은 기초 46자 다음의 탁음, 반탁음, 요음, 촉음, 장음, 외래어 표기를 파생 규칙으로 가르칩니다. 데이터에서 원글자와 조립식을 생성하는 방법, 코스별 진도 분리, 예시 단어에서 확인된 내용과 남은 검토 항목을 다룹니다.
-
서버 없이 PDF를 읽는다 — PDF Flow Studio의 pdf.js 워커와 문서 캐시
PDF Flow Studio가 pdf.js로 PDF를 브라우저에서 읽는 구조를 정리합니다. 문서 Promise 캐시, 사본을 넘기는 이유, 600px 썸네일 생성, CDN에서 불러오는 워커 스크립트, Cursor 내장 브라우저용 Map 폴리필, 콘솔 성능 로그를 코드로 보입니다.
-
필기한 페이지는 이미지가 된다 — PDF Flow Studio가 편집 페이지를 합치는 방식
PDF Flow Studio가 여러 PDF의 페이지를 한 파일로 합칠 때 빈 페이지, 필기한 페이지, 손대지 않은 페이지를 어떻게 다르게 처리하는지 정리합니다. copyPages와 PNG 삽입의 차이, 캔버스 1200px 렌더링이 남기는 한계, 저장 시점을 코드로 보입니다.
-
SUM DROP: 합 10을 지우는 낙하 퍼즐 — 시드 하나로 같은 판을 만들고, 연쇄를 한 단계씩 기록하기
Direct Play의 SUM DROP이 시드 문자열에서 같은 보드와 같은 블록 순서를 만드는 방법, 합이 목표인 줄을 찾는 매처, 연쇄를 단계별로 기록해 애니메이션과 분리한 구조, 20개 손으로 만든 스테이지를 코드로 설명합니다. 해커톤 앱의 서버 검증이 사라진 것도 적습니다.
-
마이크는 켜는 것보다 끄는 것이 어렵다 — Vocal Check의 마이크 수명 관리
Vocal Check의 마이크 요청 번호와 종료 경로를 따라갑니다. 늦게 도착한 권한 응답, 탭 이탈, 장치 분리와 오류 안내를 다루고, 측정 화면에서 광고를 제외하는 앱 자체 규칙을 설명합니다.
-
글자가 획순대로 써지게 하려면 폰트로는 안 된다 — SVG로 만드는 획순 애니메이션
히라가나·가타카나를 한 획씩 써 보여 주는 애니메이션을 만들려면 획의 윤곽과 중심선이 필요합니다. 가나 공방이 AnimCJK 데이터와 SVG stroke-dashoffset으로 획순 예시를 구현한 방법과 라이선스 처리를 정리합니다.
-
일본어 타자를 가르치는데 한글 입력기가 켜져 있다면 — 물리 키로 받는 입력 연습
가나 공방의 '가나 입력 공방'은 로마자 입력 규칙 7가지를 연습시킵니다. event.code로 물리 키를 읽고 읽기 전용 입력창에 값을 표시하는 구조, 조합 이벤트 처리의 확인 범위, sessionRef로 최신 문제를 읽는 방식을 설명합니다.
-
서버는 방만 만든다 — CollaBoard의 WebRTC P2P 협업 구조
팀 자료를 서버에 저장하지 않는 협업 도구를 만들기 위해 CollaBoard가 선택한 시그널링, 메시와 스타 토폴로지, 16KB 청크 전송, 입장 보안 설계를 정리합니다.
-
텍스트로 쓰는 악보 ABC 표기법과, 샘플 없이 피아노 소리 만들기
Songnote(Piano Play)가 쓰는 ABC 악보 표기법의 기본 문법을 예제로 익히고, 오디오 샘플 없이 Web Audio 가산 합성으로 피아노 계열 소리를 만드는 방법을 설명합니다.
-
개인 개발자의 앱 포털 운영기 — Astro 정적 빌드와 Cloudflare Workers
여러 하위 도메인 앱을 한곳에서 소개하는 Still Coding 포털을 Astro 정적 빌드, Cloudflare Workers 정적 에셋, 한국어·영어 두 언어로 운영하는 방법과 그 과정의 결정들을 정리합니다.
-
브라우저에서 목소리 음정 읽기 — Vocal Check의 YIN 피치 검출
마이크 소리에서 음이름과 센트를 계산하는 과정을 Vocal Check의 실제 코드로 설명합니다. YIN 차이 함수, 누적 평균 정규화, 포물선 보간, 중앙값 필터까지.