
렌더러를 Canvas 2D에서 WebGL로 갈아엎으면서 만난 버그 중 가장 기억에 남는 건 화면을 깨뜨린 버그가 아니다. 크게 터지지 않지만, 조용히 문제를 만드는 버그 둘이었다. 본편("잘 돌아가던 렌더러를 갈아엎은 이유")에서 덜어냈던 사례를 여기 정리한다.
에러처럼 보이는 정보, 정보에 묻히는 에러
포즈 추정 WASM이 초기화되면서 내부 추론 가속 델리게이트 생성 메시지를 console.error 레벨로 뱉었다. 동작에는 무해한 정보성 로그다. 문제는 에러 레벨로 나온다는 점이다. 콘솔이 빨간 줄로 가득 차면 진짜 오류가 그 노이즈에 파묻힌다.
이건 고쳐야 할 버그가 아니라 관측 가능성을 망치는 노이즈다. 디버깅 중에 진짜 에러를 가리는 건 무해한 로그라도 비용이다. 해결은 로깅 레벨 필터링으로 정보성 로그가 에러처럼 보이지 않게 하는 것이었다.
타입은 늘렸는데 복제 로직은 모른다
더 무서운 쪽은 이쪽이다. 리그 메타데이터에 jointAdjustments(관절 길이·오프셋 보정값)를 추가하고 자동 계산을 붙였다. 그런데 메타데이터를 복제하는 로직이 새 필드를 모르고 지나쳤다. 복제 과정에서 보정값이 사라졌고, 스키닝 정확도가 떨어졌다.
예외도 안 나고 로그도 안 남는다. 캐릭터가 미묘하게 어색해질 뿐이다. 원인을 찾으려면 "왜 어색하지"에서 출발해 복제 경로까지 거슬러 올라가야 한다.
타입을 확장하면 그 타입을 다루는 모든 경로(생성·복제·직렬화)를 같이 손봐야 한다. 컴파일러는 타입이 늘어난 건 알지만, 복제 로직이 필드를 빠뜨린 건 모른다. 교훈은 한 줄이다. 타입 확장은 한 줄, 그 타입이 지나는 곳은 여러 곳.
시끄러운 버그는 스스로를 고발한다
색상 변환 예외처럼 시끄러운 버그는 터진 자리에서 잡힌다. 조용한 버그는 반대다. 로그 노이즈는 다른 버그의 발견을 늦추고, 조용한 데이터 손실은 자신의 발견을 늦춘다.
마이그레이션 계획에는 "옮길 것"만 적기 쉽다. 다음 마이그레이션 체크리스트에는 두 줄을 추가할 것이다. 로그의 레벨이 내용과 맞는지 검증할 것. 타입을 늘렸으면 그 타입이 지나는 모든 경로를 훑을 것.
다음에 읽을 글

357개 정점을 매 프레임 CPU로 움직이기
본편에서 걷어낸 수치와 공식의 기록. 합성 관절은 랜드마크 평균으로, 가중치는 역거리제곱으로, 회전은 atan2 참조 벡터로 구했다. 자료구조 다섯 개에 지오메트리 전체가 18KB. 규모가 작을 때 단순함은 성능보다 값지다.

SVG를 GPU가 그릴 수 있게 굽는 파이프라인
사용자 그림은 SVG인데 GPU는 삼각형만 안다. SVG 경로를 평탄화하고 earcut으로 삼각분해해 메시로 굽고, 형상(rig.svg)과 골격(rig.json)을 분리하고, 베이크 결과는 캐시했다. 깨지기 쉬운 산출물은 CI 검증이 빌드 단계에서 지킨다.

잘 돌아가던 렌더러를 갈아엎은 이유
손그림 캐릭터를 실시간으로 움직이는 렌더러는 잘 돌아갔다. 문제는 캔버스 2D 벡터 엔진이라 GPU를 적극 활용하기 어렵다는 점이었다. 코어를 테스트로 고정하고 새 WebGL 엔진을 옆에서 키운 뒤 구 라이브러리를 걷어냈다. 잘 돌아가는 코드를 버린 이유는 고장이 아니라 구조의 한계 때문이었다.