I Turned DEV.to Into a Walkable 3D Library — Debugging It Has Been a Nightmare
DEV.to를 걸어 다니는 3D 도서관으로 만들었습니다 — 디버깅은 악몽이었습니다
Forem API에서 DEV.to의 실제 글 목록을 불러와 탐색 가능한 3D 도서관으로 구현한 과정을 소개합니다. 글이 수천 건으로 늘면서 발생한 위치 이동과 React ref 타이밍 문제를 추적하고, 결정론적 경로와 선반 배치로 해결한 경험을 설명합니다.
- 주제
AI 요약
개발자는 DEV.to의 실제 글 목록을 Forem API로 가져와 걸어 다니며 둘러보는 3D 도서관으로 만들었습니다. Next.js와 Three.js를 사용했으며, 게임 엔진이나 시각 편집기 없이 좌표와 배치를 코드로 직접 조정합니다. 글이 몇 개뿐인 시제품에서 수천 개의 실시간 콘텐츠를 다루게 되자, 빠르게 생성한 장면을 실제로 유지하고 디버깅하는 일이 프로젝트의 큰 과제가 됐습니다.
꿈 기록 앱에서 도서관으로
프로젝트는 처음에 Oniria라는 1인칭 3D 꿈 기록 앱으로 시작했습니다. 기억을 빛나는 구체로 표현하고, 기억 사이를 연결하는 선을 따라 이동하는 구상이었습니다. 조명, 공간 음향, 꿈속 탐색, 기억의 변화 등 기능이 늘어 197개 커밋과 1만 3천 줄을 넘어섰습니다. 해커톤 범위에 맞춰 기능을 줄이기보다, 90초 안에 경험할 수 있는 한 가지 흐름을 정하고 나머지 기능을 보류했습니다.
그 과정에서 연결된 대상을 장소로 바꾸는 엔진 자체에 주목했습니다. 웹사이트 전체를 3D 공간에 불러오는 시도는 성공했지만, 글과 프로필, 태그, 검색 결과가 뒤섞여 어디부터 탐색해야 할지 알기 어려웠습니다. 작성자는 이를 렌더링 문제가 아닌 설계 문제로 보고 도서관이라는 비유를 적용했습니다. 주제는 방, 피드는 선반, 글은 책으로 구성하고 작성자에게도 각자의 방을 배정했습니다.
경로를 기준으로 공간 고정
실제 글이 페이지 단위로 들어오면서 선반이 수백 개, 수천 개로 늘자 탐색이 불안정해졌습니다. 선반들이 서로의 위치를 기준으로 배치되면서 새 페이지가 로드될 때마다 위치가 달라질 수 있었습니다. 일반 웹사이트라면 목록을 다시 그리는 정도지만, 1인칭 공간에서는 플레이어가 서 있는 장소가 바뀌거나 순간 이동하는 문제가 됩니다.
해결의 기준은 “경로가 기준이고 나머지는 경로를 꾸민다”는 원칙이었습니다. archivePathPoint(bay) 함수가 논리적인 bay 번호를 월드 좌표로 바꾸는 고정 경로를 만들었습니다. 선반, 안개, 스카이라인, 에너지 레인, 카메라 제한은 각자 위치를 정하지 않고 같은 경로를 기준으로 배치합니다. 선반은 선반 ID, 대략적인 bay, 경로의 어느 쪽인지, 약간의 흔들림 값을 입력으로 받는 시드 기반 결정론적 함수로 옮겼습니다. 덕분에 자연스러운 배치를 유지하면서도 React 상태가 갱신될 때마다 선반이 다른 곳으로 이동하지 않게 했습니다.
애니메이션 루프와 ref 타이밍 추적
별도의 런타임 오류는 zoneRef.current is not a function이었습니다. 애니메이션 루프에서 zoneRef.current(nearestSection)을 호출했지만, ref에 함수가 아직 할당되지 않은 상태였습니다. 작성자는 할당 위치를 추적해 currentSection을 의존성으로 둔 useEffect 안에서 ref를 설정한다는 점을 찾았습니다. 애니메이션 루프는 해당 effect가 처음 실행되기 전에 이미 돌기 시작했습니다. 렌더 루프가 ref를 호출하는 시점과 effect가 값을 넣는 시점이 어긋난 타이밍 문제였습니다.
작성자는 AI 보조 개발로 조명이나 공간 음향을 빠르게 만들더라도, effect가 렌더 루프와 어떤 순서로 실행되는지 확인하는 디버깅은 직접 해야 했다고 설명합니다. 현재 카탈로그는 한 번에 전부 요청하지 않고 제한된 페이지로 불러옵니다. 카메라는 장면을 다시 구성해도 유지하며, 구역은 고정 분류 대신 실제 글의 태그를 기준으로 나눕니다. 가까운 선반은 밝아지고 표지가 활성화되며 먼 선반은 어두워집니다. 3D 공간에서는 한 번에 보이는 선반이 많아 거리와 밝기가 정보의 위계를 전달하기 때문입니다.
아직 카탈로그를 얼마나 많이 메모리에 유지할지, 성능이 낮은 GPU에서도 스카이라인과 안개가 잘 동작할지는 확인 중입니다. 작성자는 이후 Sanity Challenge 제출 과정에서 CMS 쪽 구현도 소개하겠다고 밝혔습니다.
dev.to 반응
- @georgekobaidze — 누군가 제대로 만들고 있네요! 🔥 👀
원문: dev.to / 번역·요약: Trawling