죽은 F1 프로젝트를 되살리다: 우연히 레이스 인텔리전스 OS를 구축하다
요약
이 글은 원시 텔레메트리 데이터를 활용하여 포뮬러 1(F1) 레이스 인텔리전스 대시보드를 구축한 과정을 소개합니다. 이 시스템은 실시간 차량 추적, AI 전략 분석, 물리 기반 카메라 시각화 등 복합적인 기능을 제공하며, 단순 데이터 나열을 넘어선 인터랙티브 워룸 경험을 구현했습니다.
핵심 포인트
- 원시 텔레메트리 데이터를 활용한 풀스택 대시보드 구축 사례
- AI(Claude)를 이용한 실시간 레이스 전략 분석 기능 통합
- 물리 기반 카메라와 음성 해설 등 다중 미디어 요소 결합
- 단순 데이터 시각화를 넘어선 인터랙티브 워룸 경험 제공
이 글을 처음에는 제 예전 계정의 GitHub Finish-Up-A-Thon Challenge에 작성했습니다. 지금은 공개적으로 개발하고 있으므로 여기에 다시 게시합니다.
제가 구축한 것
저는 F1 Intelligence Studio를 만들었습니다. 이것은 원시 텔레메트리 데이터(raw telemetry data)를 2024년부터 2026년까지의 모든 레이스의 살아 숨 쉬는 시각화로 변환하는 풀스택 포뮬러 1 레이스 인텔리전스 대시보드입니다.
레이스 엔지니어의 워룸(war room)이라고 생각하시면 됩니다. 스무 대의 애니메이션 자동차가 실제 GPS 텔레메트리에서 그려진 서킷을 따라 서로를 추격합니다. AI 레이스 엔지니어(Claude)는 실시간으로 전략을 분석합니다. 스프링 물리 기반 카메라(spring-physics camera)는 실제 방송처럼 차량 간의 전투에 확대됩니다. ElevenLabs가 해설을 음성으로 제공합니다. 그리고 전략 시뮬레이터는 F1의 영원한 질문, 즉 '피트 스톱 할까 아니면 그냥 달릴까?'에 답합니다.
프레임 단위의 완벽한 정밀도로 어떤 레이스의 어느 순간이든 되감을 수 있습니다. 두 드라이버의 텔레메트리 추적(telemetry traces)을 나란히 비교하고, 타이어 사용량(tyre stints)이 전개되는 것을 관찰하며, 팀 라디오를 모니터링하고, 개발 중인 전투에 대한 AI 기반 통찰력을 얻을 수 있습니다.
단순한 API 호출로 테이블에 데이터를 덤프하던 것에서 시작하여, 이제는 12개의 패널과 드래그 앤 드롭 방식의 대시보드와 열두 개의 인터랙티브 컴포넌트로 완성되었습니다. 그 중간 어딘가에서 저는 경계선이 어디였는지 잊어버렸는데 — 이것이 바로 이 이야기 전체의 요점입니다.
이 프로젝트가 저에게 의미하는 것: 몇 년 만에 실제로 출시해 본 첫 사이드 프로젝트입니다. 제 GitHub는 반쯤 완성된 아이디어들의 무덤과 같습니다. 하지만 이번 프로젝트만은 살아남았습니다.
데모
🏎️ 라이브 데모: https://raceosf1.one/
📦 GitHub 레포: https://github.com/nilamadhab47/raceosf1
간단한 스크린샷:
🟢 실제 텔레메트리에서 파생된 서킷 위 20대의 자동차가 움직이는 애니메이션 트랙 지도

🟢 텔레메트리 비교 — 두 드라이버의 속도/스로틀/브레이크가 동일한 거리 축에 오버레이됨
🟢 AI 인사이트 패널 — Claude가 실시간으로 전략을 분석하고, 시뮬레이터가 피트 스톱 vs 체류(stay-out)의 차이를 보여줌
사용 기술 스택 (The Stack):
- 프론트엔드: Next.js 14, TypeScript, Zustand, GSAP, Recharts, react-grid-layout
- 백엔드: FastAPI (Python 3.12), FastF1, WebSocket 브로드캐스팅
- AI: Anthropic Claude (레이스 인사이트 + 채팅), ElevenLabs (음성 해설)
- 인프라: Vercel (무료 플랜) + Railway ($5/월)
총 인프라 비용: 월 커피 예산보다 적습니다. 스프링-댐퍼 카메라 시스템을 만드는 것이 제 공학 학위보다 더 많은 수학 지식을 필요로 했습니다.
부활 스토리 (The Comeback Story)
솔직히 말씀드리겠습니다.
제 GitHub는 무덤 같습니다. 백엔드가 없는 랜딩 페이지들. ChatGPT 채팅창에만 머물다 끝난 앱들에 대한 대화 내용들. 문서 폴더에서 썩어가고 있는 아이디어들. 저는 생계를 위해 프로덕션 시스템을 구축하는 풀스택 엔지니어이지만, 제 자신의 프로젝트는요? README조차 완성하지 못했습니다.
F1 프로젝트도 예외가 아니었습니다. 몇 달 전 Instagram에서 FastF1에 대한 개발 영상을 봤는데, 이 패키지는 포뮬러 1(Formula 1)의 텔레메트리 데이터에 사용되는 놀라운 Python 패키지입니다. 제 머리는 평소처럼 작동했습니다: _
- "이걸 누가 쓸까?"
- "수익 모델이 없어."
- "프론트엔드를 하는 척하는 백엔드 엔지니어네."
저 저장소는 몇 주 동안 그대로 방치되어 있었다. 손대지 않은 채, 그저 또 하나의 비석처럼 말이다.
무엇이 바뀌었나:
나는 나 자신에게 한 가지 규칙을 세웠다. 퇴근 후에 앉아 있는 것. 최소 15분은 투자하기. '일단 아키텍처를 계획부터 해야지'라는 변명(궁극의 미루기 수법)도, '월요일에 새롭게 시작할게'라는 말도 안 된다. 그냥 노트북을 열고 작은 것이라도 하나 배포하는 것.
시작은 보기 흉했다. 그저 형편없었다. 하지만 나는 계속 출근했다.
그러자 점차 규모가 커지기 시작했다:
- 1주 차: 테이블이 그래프로 바뀌었다. 조금 덜 지루해졌다.
- 2주 차: 그래프가 드라이버 비교표로 바뀌었다. 잠깐, 이거 의외로 흥미롭잖아?
- 3주 차: 비교표가 완전한 레이스 시뮬레이션으로 발전했다. 이제 실제 서킷 지도가 필요하다니?
- 4주 차: 원시 GPS 텔레메트리 데이터로부터 SVG 트랙을 그렸다. 밤 11시에 'viewBox란 무엇인가'를 구글링 했다. 부끄럽지 않았다.
- 5주 차: 20대의 애니메이션 차량들이 초당 60프레임(fps)으로 서로를 추격했다.
setState를 초당 60번 호출하는 것은 전쟁 범죄에 가깝기 때문에 React의 렌더링 사이클을 완전히 우회했다. - 6주 차: AI 레이스 엔지니어를 추가했다. 그다음 음성 해설을 넣었다. 그리고 실제 TV 방송처럼 전투 장면으로 확대되는 스프링 물리 기반 카메라를 구현했다.
키보드에서 고개를 들고 보니, 'F1 데이터를 테이블로 보여줄게'라는 생각으로 시작했던 것이 완전한 레이스 인텔리전스 운영 체제(Race Intelligence Operating System)로 변해 있었다. 나의 범위 확장(scope creep)은 Verstappen을 추월할 수 있을 정도였다.
마무리 작업의 고군분투:
이 도전 과제가 떨어졌을 때, 프로젝트는 대부분 작동했지만 거친 모서리들로 가득했다. 아무에게도 보여주지 못하게 만드는 그런 종류의 거친 모서리들. '나중에 다듬어야지'라는 미루기 목록(backlog). 익숙한가?
최종 마무리를 위해 내가 정리한 것들은 다음과 같다:
- 문서화. README는 한 문장이었습니다. 이제는 설정 방법, 아키텍처 다이어그램, 기여 가이드라인이 포함된 제대로 된 온보딩 문서가 되었습니다.
- 모든 패널에 오류 경계(Error boundaries) 구현. 이전에는 하나의 패널만 충돌해도 대시보드 전체가 다운될 수 있었습니다. 이제는 각 패널이 독립적으로 우아하게 실패합니다(fails gracefully).
- 로딩 스켈레톤(Loading skeletons). 이전에 대시보드는 데이터 가져오는 동안 빈 상자들만 깜빡였습니다. 이제 모든 요소에 적절한 로딩 상태가 있습니다.
- YouTube 콘텐츠 ID 문제. FOM이 타사 임베드(third-party embeds)를 차단했기 때문에, F1 비디오들이 운영 환경에서 계속 "비디오를 사용할 수 없음"을 표시했습니다. 3단계 폴백 시스템을 구축했습니다: Dailymotion → 차단되지 않은 YouTube → 외부 링크가 포함된 썸네일 카드.
- 배포(Deployment). Railway에서 Dockerfile 실패가 세 번 있었습니다. 경로 해석, 빌드 컨텍스트, 그리고 Railway의 startCommand가 쉘을 통해 실행되지 않아 확장되지 않는 악명 높은
$PORT변수 때문이었습니다. 마침내 모든 것을 녹색으로 만들었습니다. - 다듬기 작업(Polish pass). 온보딩 투어, 키보드 단축키, 모바일 반응형 그리드 프리셋, 그리고 사후 처리처럼 보이지 않는 다크 모드를 구현했습니다.
비포와 애프터의 격차는 "내 노트북 위의 물건"과 "사과하지 않고 사람들에게 보여줄 수 있는 물건" 사이의 차이입니다.
가장 큰 교훈은 기술적인 것이 아니었습니다. 그것은 시작이 당신에게 거짓말을 한다는 것입니다. 그것은 "이건 의미 없어" 그리고 _"너는 충분히 능숙하지 않아"_라고 속삭이며—만약 당신이 그 소리에 귀 기울인다면, 또 다른 저장소를 무덤에 추가하고 인스타그램을 켜게 만듭니다.
유일한 해답은 계속해서 나타나는 것입니다. 한 번에 15분씩이라도요.
GitHub Copilot으로 경험한 것
저는 마무리 단계에서 Copilot을 많이 사용했고, 솔직히 말해? 가장 빛을 발했던 부분이 바로 그곳이었습니다.
버려진 프로젝트를 되살리는 흥미로운 점은 재미있는 부분들은 이미 구축되어 있다는 것입니다. 남은 것은 지루하고 덜 매력적인 것들—다듬기 작업, 예외 케이스(edge cases), 드래그 및 크기 조정 로직, 디자인 시스템의 일관성 등입니다. 평소라면 제가 완성하기 전에 화를 내며 포기했을 것 같은 것들이죠. 바로 이 지점에서 Copilot이 제 역할을 다했습니다.
Copilot이 진정으로 도움이 된 부분:
🟢 대시보드 패널을 위한 드래그 및 크기 조절 아키텍처. 이것이 가장 큰 돌파구였습니다. 모든 패널이 드래그 가능하고, 크기 조절 가능하며, 컨테이너에 따라 자동 조정되어야 했지만, 각 내부 컴포넌트를 망가뜨리지는 않아야 했습니다. Copilot은 레이아웃 시스템을 설계하는 데 도움을 주었고, react-grid-layout을 기존 패널 컴포넌트와 연결(wire)하는 방법을 안내해 주었습니다. 가장 어려웠던 부분은 크기 조절이 SVG 트랙 맵, Recharts 그래프 또는 WebSocket 기반 애니메이션을 망가뜨리지 않도록 하는 것이었습니다. Copilot은 제가 각 패널을 처음부터 재설계할 필요 없이, 컨테이너 인식 자식 요소에 대한 ResizeObserver, 디바운스된(debounced) 크기 조절 핸들러, 까다로운 차트의 키 기반 리마운팅(key-based remounting)과 같은 적절한 패턴을 제안해 주었습니다.
🟢 FastF1 응답에 대한 타입 정의. FastF1은 깊게 중첩된 pandas DataFrame을 반환하며, 저는 이를 JSON으로 직렬화하고 있었습니다. 이들에 대한 TypeScript 타입을 수동으로 작성하는 것은 지루했습니다. Copilot은 제 Python 직렬화 코드에서 대부분의 타입을 추론해 냈고, 제가 필드 이름을 수동으로 옮겨 적는 일을 막아주었습니다.
🟢 디자인 시스템 일관성 + 성능 최적화. 12개의 패널에 걸쳐 시각적 언어(간격, 색상, 타이포그래피, 모션 타이밍)를 통일할 때, Copilot은 일관된 토큰 기반 패턴을 제안하는 데 탁월했고 제가 벗어난 부분을 알려주었습니다. 또한 성능 결정(언제 memoize 할지, 상태 대신 ref를 사용할지, 언제 가상화(virtualize)할지, 그리고 언제 하지 않을지)에서도 도움을 주었습니다. 항상 완벽하지는 않았지만 유용한 2차 의견이었습니다.
🟢 엣지 케이스 처리. API 엔드포인트를 강화하면서 Copilot은 제가 고려하지 못했던 검증 사례를 제안하는 데 탁월했습니다. _
Copilot이 덜 유용했던 경우:
🔴 창의적인 아키텍처 결정. 스프링-댐퍼 카메라, 1000점 SVG 샘플링 트릭, React를 우회하는 ref 기반 애니메이션 루프 등은 실제로 문제에 대해 생각해야 하는 부분이었습니다. Copilot은 제가 필요로 했던 특이한 해결책 대신 일반적인 해결책을 제안했습니다. 괜찮습니다. 그것은 팀원이 아니라 도구일 뿐입니다.
🔴 FastF1의 특이점과 관련된 모든 것. FastF1에는 세션별 행동(스프린트 주말, 예선 형식, 텔레메트리 가용성)이 많으며, Copilot의 학습 데이터가 이를 잘 다루지 못했습니다. 따라서 실제 데이터 형태에 작동하지 않는 그럴듯해 보이는 코드를 제안할 수 있었습니다.
🔴 진정으로 새로운 로직. 제가 처음 간격-트랙 분수 변환(offset = gap_seconds / avg_lap_time)을 작성했을 때, Copilot이 이를 도출하는 데 도움을 주지는 못했습니다. 저는 먼저 수학적 원리를 실제로 이해해야 했습니다.
🔴 프롬프트가 모호할 때의 환각 현상. 이것은 솔직한 단점입니다. 제가 프롬프트를 게을리 할 때마다(모호한 의도, 제약 조건 없음, 예시 없음), Copilot은 존재하지 않는 API나 상상의 라이브러리 버전에서 가져온 함수 시그니처를 자신 있게 환각하거나, 제가 요청하지 않은 완전히 과잉 설계된 해결책을 내놓았습니다. 작은 유틸리티를 요청했을 뿐인데 3개 계층의 상속 구조를 가진 200줄짜리 추상화 코드를 받곤 했습니다. 이 교훈은 힘든 경험을 통해 얻었습니다. Copilot의 출력 품질은 제가 원하는 것을 얼마나 정확하게 설명하는지에 직접적으로 연결되어 있습니다. 모호한 입력은 쓰레기 같은 결과(Garbage in, garbage out)를 낳습니다. AI의 잘못이 아니라, 구체적이지 못한 저의 책임입니다.
솔직한 결론:
Copilot은 무엇을 원하는지 알고 거기에 도달하기 위해 타이핑할 필요가 적을 때 가장 좋습니다. 반대로 무엇을 원하는지 모르고 자동 완성이 알아서 해결해주기를 바랄 때는 최악입니다. 포기된 프로젝트를 마무리하는 경우—이미 어려운 창의적 작업이 완료되었고 남은 것이 실행적인 다듬기일 때—거의 완벽합니다.
Copilot이 제 프로젝트 전체를 작성한 것은 아닙니다. 하지만 제가 그것을 완성하는 데 절대적으로 도움을 주었습니다.
다음 단계
묘지에는 여전히 거주자들이 있다. 이것이 첫 번째 발굴은 아니며, 마지막도 아니다. 나는 미완성된 아이디어들의 백로그를 가지고 있고, 그 모든 것을 찾아낼 것이다.
왜냐하면 이건 돈에 관한 것이 아니기 때문이다. ~ Brad Pitt, F1
FastF1 유지자인 theOehrly에게 거대한 찬사를 보낸다. 이 전체 프로젝트는 당신이 놀라운 것을 만들고 오픈 소스했기 때문에 존재한다. 이것이 바로 에너지다.
만약 지금 버려진 프로젝트를 가지고 있다면, 이게 너의 신호다. 노트북을 열어라. 15분만. 시작은 너에게 거짓말하고 있다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기
