5분 AI.
TrendShift 딥다이브 · 2026-08-22 · Daily #4

Google Timeline Visualizer 딥다이브
— 내 위치 기록을 "여행 영상"으로, 그것도 폰 안에서만

mahlernim/google-timeline-visualizer는 구글 지도의 타임라인(위치 기록) 내보내기 파일 Timeline.json을, 지도 위를 마커가 흐르는 애니메이션 여행 영상(MP4)으로 만들어 주는 도구다. 스포티파이 "Wrapped"의 위치 버전이라고 보면 된다. 특별한 점은 처리 방식이다. 파일 업로드도, 구글 로그인도, 위치 권한도 없이 — 고른 JSON 파일을 오직 기기 안에서만 읽어 영상까지 폰(또는 브라우저) 안에서 만든다. 네트워크로 나가는 건 지도 배경 타일 요청뿐이다. 본체는 안드로이드 앱(코틀린)이고, 아이폰·브라우저용 웹앱(타입스크립트)과 최초 원형이던 파이썬 CLI까지 세 구현이 같은 알고리즘을 공유한다.
(저장소: mahlernim/google-timeline-visualizer · Android(Kotlin) + Web(TypeScript) + Python · MIT · 앱 v2.2.12 · minSdk 26/Android 8.0+ · 9개 언어 지원 · GitHub 약 2.2k★, 8/20 GitHub 트렌딩 #1 · TrendShift Daily #4)
목차
  1. 프로젝트 한 줄 요약
  2. 왜 지금 주목받는가
  3. 기술 스택 전체 지도
  4. 아키텍처 심화 분석
  5. 디렉토리 구조 해부
  6. 학습 포인트
  7. 시스템 요구사항
  8. 직접 해볼 수 있는 실습 과제
  9. 관련 기술 심화 학습 로드맵
  10. 핵심 키워드 사전
  11. 참고 링크

1프로젝트 한 줄 요약

"구글이 폰으로 돌려준 내 위치 기록을, 프라이버시를 지키며 여행 영상으로 바꿔 주는 도구"

Timeline Visualizer가 하는 일은 한 문장으로 끝난다. 구글 지도에서 내보낸 위치 기록 파일(Timeline.json)을 넣으면, 지도 위를 작은 마커가 내가 다닌 경로를 따라 움직이는 여행 애니메이션 영상을 만들어 준다. 기간(월 범위 또는 정확한 날짜)을 고르고, 카메라 움직임을 정한 뒤 "영상 만들기"를 누르면 MP4가 저장된다. 긴 여행은 웅장하게 천천히, 짧은 출퇴근은 빠르게 — 이동 거리에 따라 재생 속도가 달라지는 게 이 영상의 매력이다.

이 프로젝트가 유독 신경 쓰는 지점은 "이 민감한 위치 데이터를 어디서 처리하느냐"다. 답은 전부 내 기기 안이다. 서버로 파일을 올리지 않고, 구글 계정에 로그인하지도 않으며, 앱은 위치 권한조차 요구하지 않는다. 내가 직접 고른 JSON 파일과 영상 파일만 읽고, 렌더링(그림 그리기)도 기기 안에서 끝낸다. 지도 배경(타일)만 지도 제공자에서 받아 온다.

한눈에 이해하는 비유

"스포티파이 Wrapped의 위치 버전 — 단, 데이터를 아무 데도 보내지 않는다"

연말이면 스포티파이가 "올해 이런 음악을 들으셨네요" 영상을 만들어 준다. 이 앱은 그 위치판이다 — "올해 이런 곳들을 다니셨네요"를 지도 위 여행 영상으로 보여 준다.

차이는 신뢰 모델이다. 스포티파이는 그들의 서버가 내 기록을 갖고 있어 가능하다. 이 앱은 내 위치 기록을 서버에 올리지 않고도 같은 결과를 만든다 — 계산이 전부 내 폰·브라우저 안에서 벌어지기 때문이다. "예쁜 결과물"과 "데이터 주권"을 동시에 챙긴 셈이다.

가장 빠른 체험은 설치가 필요 없는 아이폰/브라우저 웹앱이다. 사파리로 아래 주소를 열고, 폰에서 내보낸 Timeline.json을 고르면 된다.

# 설치 없이 브라우저에서 (사파리 16.4+ 권장)
https://ahn-lab.org/google-timeline-visualizer/
#  → Timeline.json 선택 → 기간·카메라 고르기 → Create MP4

안드로이드에서는 저장소의 최신 릴리스에서 TimelineVisualizer-*.apk를 받아 설치한다(아직 구글 플레이 등록 전이라 "출처를 알 수 없는 앱 설치" 허용이 한 번 필요). 데스크톱에서 돌려 보고 싶다면, 이 프로젝트의 최초 원형인 파이썬 CLI visualizer.py가 그대로 남아 있다.

2왜 지금 주목받는가

"구글의 타임라인 정책 변화 + 프라이버시 우선 + 공유 욕구를 자극하는 결과물"

비슷한 "위치 기록 시각화" 도구는 예전에도 있었다. 그런데 이 앱이 2026년 8월 GitHub 트렌딩 1위까지 오른 데는 타이밍이 결정적이었다. 세 가지가 겹쳤다.

① 구글이 타임라인을 "폰 안"으로 옮겼다 — 그래서 도구가 필요해졌다

구글은 2024년 말, 지도 타임라인을 클라우드에서 기기 저장으로 전환했다. 웹 버전 타임라인은 없어졌고, 계정에 있던 과거 기록은 최근 90일 치만 폰으로 옮겨지고 나머지는 사용자가 직접 백업하지 않으면 삭제됐다. 이제 내 위치 기록을 보려면 폰에서 직접 Timeline.json으로 내보내야 한다. "손에 JSON 파일은 생겼는데, 이걸로 뭘 하지?"라는 수요가 바로 이 시점에 폭발했고, 이 앱이 그 자리에 딱 맞아떨어졌다.

② 프라이버시가 세일즈 포인트가 됐다

위치 기록은 가장 민감한 개인정보다. "예쁜 영상 만들어 줄 테니 위치 파일 올리세요"라는 웹 서비스에 사람들이 선뜻 파일을 올릴 리 없다. 이 앱은 정반대다 — 아무것도 올리지 않는다. 구글 로그인 없음, 위치 권한 없음, 분석(애널리틱스) 없음, 광범위한 저장소 권한 없음. 첫 실행 때 "지도 타일만 지도 제공자에 요청한다"는 사실까지 설명하고 취소할 기회를 준다. 이 투명함이 신뢰를 샀다.

③ 결과물이 공유 욕구를 자극한다

기술이 아무리 좋아도 트렌딩까지 가려면 "보여 주고 싶은 결과물"이 있어야 한다. 지도 위를 마커가 흐르며 1년치 여행이 그려지는 영상은 SNS에 올리기 좋은 소재다. 긴 비행은 지구본 위 곡선(대권 경로)으로 부드럽게 이어지고, 마지막엔 전체 경로를 한 장으로 보여 주는 "여행 개요"까지 나온다. "올해의 나"를 요약하는 감성이 확산의 연료가 됐다.

방법특징이 앱과의 차이
구글 지도 타임라인내 기록을 지도에서 열람정적 열람만. 영상·애니메이션 생성 불가, 웹 버전은 폐지됨
업로드형 웹 시각화 서비스브라우저에서 바로 보기대개 파일을 서버로 전송. 민감한 위치 데이터엔 부담
직접 스크립트(pandas 등)자유도 높음코드·환경 구성 필요. "영상"까지 가려면 별도 작업
Timeline Visualizer온디바이스 영상 생성업로드 0 + 애니메이션 MP4 + 안드로이드/아이폰/파이썬 3구현 + 9개 언어

3기술 스택 전체 지도

"안드로이드(Kotlin) · 웹(TypeScript) · 파이썬 — 세 구현이 하나의 알고리즘을 공유"

이 저장소의 가장 큰 특징은 같은 일을 하는 세 개의 구현이 한 레포에 들어 있다는 점이다. 파이썬 CLI가 최초 원형(prototype)이었고, 그 알고리즘을 안드로이드 앱(본체)과 브라우저 웹앱으로 각각 이식했다 — 그래서 셋은 "파서 → 이상치 필터 → 투영 → 카메라 → 렌더 → 인코딩"이라는 동일한 파이프라인을 공유한다. 층별로 나눠 보면 이렇다.

안드로이드 앱 (본체 · app/)

요소 / 버전역할
Kotlin · minSdk 26 / targetSdk 36안드로이드 8.0+ 지원. 순수 안드로이드 View + ViewBinding UI(무거운 프레임워크 없음).
MediaCodec + MediaMuxer안드로이드 내장 하드웨어 H.264 인코더. 그린 프레임(Bitmap)을 받아 MP4로 묶는다. 외부 FFmpeg 없이 OS 기능만 사용.
Media3 (ExoPlayer) 1.11완성된 영상을 앱 안에서 전체화면 재생(탐색·공유·외부 플레이어 폴백).
kotlinx-coroutines파싱·타일 준비·인코딩의 비동기·취소 처리. 화면을 꺼도 계속 돌게 하는 뼈대.
Gson 2.13대용량 Timeline.json스트리밍(JsonReader)으로 읽어 메모리 폭발을 피한다.
Foreground Service영상 만들기는 포그라운드 서비스로 돌아, 앱을 벗어나거나 화면을 꺼도 진행·알림이 유지된다.

웹 · 아이폰 앱 (web/)

요소 / 버전역할
TypeScript · Vite 8빌드 타깃 safari16.4. 프레임워크 없는 순수 TS + DOM(가벼운 SPA).
WebCodecs + mediabunny 1.55브라우저의 VideoEncoder로 H.264 인코딩, mediabunny가 MP4로 muxing. 파일 업로드 없이 브라우저 안에서 인코딩.
PWA (service worker · manifest)"홈 화면에 추가"로 앱처럼 설치. GitHub Pages로 배포(ahn-lab.org).
자체 i18n외부 라이브러리 없이 {param} 치환형 다국어(9개 언어) 구현.

파이썬 CLI (원형 · visualizer.py)

요소역할
matplotlib (animation)프레임 애니메이션 렌더 + FFmpeg로 MP4 저장. 데스크톱용 원형.
numpy · pillow · python-dateutil좌표 계산 · 타일 이미지 합성 · 다양한 시간 포맷 파싱.
CARTO 타일 (light_all)세 구현 공통 지도 배경. OpenStreetMap 데이터 기반의 밝은 지도.
이 스택이 말해 주는 것

세 구현 모두 "무거운 의존성을 피하고 플랫폼 내장 기능을 직접 쓴다"는 취향이 뚜렷하다. 영상 인코딩은 서드파티 라이브러리가 아니라 각 플랫폼의 네이티브 인코더(안드로이드 MediaCodec, 브라우저 WebCodecs)를 직접 부른다. UI도 리액트 같은 프레임워크 없이 순정 도구로 짰다. 덕분에 앱이 가볍고, "업로드 없는 온디바이스 처리"라는 약속을 구조적으로 지킬 수 있다.

4아키텍처 심화 분석

"JSON 파싱 → 이상치 제거 → 웹 메르카토르 투영 → 카메라 무빙 → 타일 렌더 → 인코딩"

세 구현이 공유하는 파이프라인은 Timeline.json 한 덩어리를 여섯 단계로 흘려보낸다. 각 단계가 독립적이라, 한 단계(예: 이상치 필터)만 이해해도 나머지를 따로 배울 수 있다.

Timeline.json (내 위치 기록) │ ▼ [1] 파싱 (다형 파서) ── 여러 포맷/좌표계를 GeoPoint 리스트로 정규화 │ (배열형 · semanticSegments · 원시신호 폴백) ▼ [2] 이상치 제거 ── 물리적으로 불가능한 "튐"을 보수적으로 걸러냄 │ (선택 기간으로 자르고 시간순 정렬·중복 제거) ▼ [3] 웹 메르카토르 투영 ── (위도,경도) → 지도 평면 좌표 (x,y) ∈ [0,1] │ 긴 비행은 대권(great-circle) 곡선으로 보간 ▼ [4] 카메라 무빙 ── 경로를 따라갈 화면(뷰포트)을 프레임마다 계산 │ fixed / steady / dynamic 프로파일 ▼ [5] 프레임 렌더 ── CARTO 지도 타일 위에 경로·마커·꼬리·오버레이 그리기 │ (필요한 타일을 먼저 모아 캐시) ▼ [6] 인코딩 ── Android: MediaCodec · Web: WebCodecs · Py: matplotlib │ ▼ travel.mp4 (+ 1080×1080 여행 개요 이미지)

핵심 ① — 다형(polymorphic) 파서: 온갖 포맷을 하나로

구글의 타임라인 내보내기는 버전·기기마다 모양이 제각각이다. 그래서 파서가 여러 포맷을 모두 받아 준다 — 최신 안드로이드/iOS의 직접 배열형, 예전의 { "semanticSegments": [...] } 형태, 그리고 의미 있는 경로가 없을 때를 위한 원시 위치 신호 폴백까지. 좌표도 문자열·latLng·도(degree)·geo: URI·E7 정수(위경도에 1e7을 곱한 정수 표기)를 모두 해석하고, 국제 날짜변경선을 넘는 경로도 처리한다. 대용량 파일은 통째로 메모리에 올리지 않고 JsonReader로 스트리밍해 읽는다.

한 문장 정의
GeoPoint · 정규화(normalize)
파서의 목표는 제각각인 입력을 하나의 표준형으로 바꾸는 것이다. 모든 좌표를 GeoPoint(위도·경도·시각)로 통일하고, 시간순 정렬·중복 제거를 거쳐 깨끗한 리스트를 만든다. 이후 단계들은 입력이 어떤 포맷이었는지 신경 쓸 필요가 없다 — 정규화가 그 복잡함을 여기서 다 흡수한다.

핵심 ② — 물리 기반 이상치 필터: "순간이동"만 골라 지운다

GPS 기록에는 가끔 말도 안 되는 점이 섞인다 — 서울에 있다가 1분 만에 부산을 찍고 다시 서울로 돌아오는 식이다. 이 앱의 필터는 이런 "튐(excursion)"을 물리 법칙으로 판별한다. 짧은 시간 안에, 멀리 떨어진 곳으로, 사람이 낼 수 없는 속도로 갔다가 원래 자리로 되돌아오는 점들의 무리를 찾아 통째로 제거한다. 핵심은 보수적(conservative)이라는 점 — 조금이라도 애매하면 남긴다. 원본 JSON은 절대 건드리지 않고, 몇 개를 걸렀는지 사용자에게 보고한다.

이상치 판별 (한 무리의 점이 "튐"인지 검사) 이전점 ──(정상)── ? ? ? ──(정상)── 이후점 ╲ ╱ ╲ ╱ ← 이 무리가 아래 조건을 '전부' 만족하면 제거 조건: · 이전→이후 시간 간격이 짧고, 둘은 서로 가깝다(곧 돌아옴) · 무리로 나갈 때/들어올 때 속도가 사람 한계(MAX)를 넘는다 · 무리가 이전점·이후점 모두에서 충분히 멀다(진짜 '외출') → 하나라도 애매하면? 남긴다 (보수적)

핵심 ③ — 웹 메르카토르 투영과 카메라 무빙

지구는 둥글고 화면은 평평하다. 그 간극을 메우는 게 웹 메르카토르 투영 — 구글·OSM 등 웹 지도가 쓰는 표준 방식이다. (위도, 경도)를 지도 평면의 정규화 좌표 (x, y) ∈ [0,1]로 바꾼다(위도는 ±85.05°로 제한). 그 위를 카메라가 경로를 따라가는데, 무빙 프로파일이 세 가지다 — fixed(한 줌 고정), steady(안정적, 기본값), dynamic(지역 이동을 적극적으로 따라감). 장거리 비행처럼 점이 듬성듬성한 구간은 대권(great-circle) 경로로 보간해, 목적지로 순간이동하지 않고 지구본 위 곡선으로 부드럽게 쓸고 간다.

한 문장 정의
대권 보간 · 거리 기반 타이밍
대권(great-circle)은 지구 표면 두 점을 잇는 최단 곡선(비행기 항로처럼). 점 사이가 멀면 위경도를 3차원 벡터로 바꿔 그 곡선을 따라 중간점을 만든다. 여기에 거리 기반 타이밍이 더해져, 긴 이동은 시간을 넉넉히(웅장하게), 짧은 출퇴근은 빠르게 재생한다 — 경로 모양(geometry)은 그대로 두고 애니메이션 '속도'만 조절한다.

핵심 ④ — 온디바이스 인코딩 3인방

"업로드 없음"의 약속은 결국 인코딩을 어디서 하느냐로 지켜진다. 세 구현은 각자 플랫폼의 네이티브 인코더를 직접 부른다 — 안드로이드는 MediaCodec(하드웨어 H.264) + MediaMuxer, 브라우저는 WebCodecsVideoEncoder + mediabunny muxer, 파이썬은 matplotlib + FFmpeg. 렌더러가 한 장 한 장 그린 프레임(캔버스/Bitmap)을 이 인코더에 흘려 넣어 MP4를 완성한다. 지도 타일은 미리 필요한 것만 계산해 받아 두고(2단계 캐시: 메모리 LRU + 디스크 PNG), 렌더링 중에는 네트워크를 다시 타지 않는다.

알아 둘 것
지도 타일은 유일한 네트워크 — 그리고 브라우저 인코딩 요건

"업로드 없음"이 곧 "완전 오프라인"은 아니다. 지도 배경 타일은 CARTO 서버에서 받아 오므로, "내가 어느 지역을 봤는지"는 타일 제공자에게 드러날 수 있다(위치 기록 파일 자체는 전송되지 않는다). 앱은 첫 실행 때 이 사실을 설명하고 동의를 받는다.

웹앱의 MP4 생성은 사파리 16.4+와 H.264 인코딩 지원이 필요하고, 만드는 동안 탭을 열어 둬야 한다. 안드로이드 앱은 8.0+에서 동작한다.

5디렉토리 구조 해부

"app/(안드로이드) · web/(TS 웹앱) · visualizer.py(파이썬) · docs · play-store"

한 레포 안에 세 구현이 각자의 폴더로 깔끔히 갈려 있고, 세 곳에 같은 이름의 알고리즘 모듈이 반복되는 게 눈에 띈다(예: 안드로이드 data/LocationOutlierFilter.kt ↔ 웹 src/outlier.ts).

google-timeline-visualizer/ ├─ app/ ★ 안드로이드 앱 (본체, Kotlin) │ └─ src/main/java/.../timelinevisualizer/ │ ├─ data/ TimelineParser · LocationOutlierFilter · TileRepository │ │ RawSignalProcessor · TimelineCache · TimelineSourceStore │ ├─ export/ Mp4Exporter(MediaCodec) · VideoExportService(포그라운드) │ │ MapTilePreparer · VideoEncoderSupport · ExportEtaEstimator │ ├─ model/ TimelineModels(GeoPoint·Journey·보간) · WebMercator │ ├─ render/ TimelineAnimation · TimelinePainter · CameraSettings │ ├─ ui/ SettingsViewModel · 각종 Preferences · TimelineView │ └─ videos/ VideoLibraryViewModel · VideoStore (내 영상 라이브러리) │ └─ src/test, src/androidTest ← 40+ 테스트 (Robolectric 유닛 + 기기 테스트) ├─ web/ ★ 아이폰·브라우저 웹앱 (TypeScript) │ ├─ src/ geo(투영) · camera · animation · outlier · renderer · timeline │ │ video(WebCodecs) · overlay · i18n · locales/(9개 언어) │ ├─ public/service-worker.js · index.html · vite.config.ts (PWA) │ └─ *.test.ts ← vitest 유닛 테스트 ├─ visualizer.py ★ 최초 원형 (파이썬 CLI, matplotlib) ├─ requirements.txt numpy · matplotlib · pillow · python-dateutil ├─ docs/ privacy · terminology(용어 표준) · 릴리스 노트 30여 개 ├─ play-store/ 9개 언어 스토어 등록 문구 · 스크린샷 · 그래픽 ├─ test-fixtures/ · tests/ 샘플 Timeline 데이터 └─ .github/workflows/ validate · web-validate · release · pages (CI/CD)

폴더만 봐도 이 프로젝트의 규율이 보인다 — 세 구현이 알고리즘 이름을 맞춰 두고, 각각 독립 테스트를 갖추며(안드로이드 40여 개 + 웹 vitest), docs/terminology.md로 "타임라인 파일/이동 경로/영상" 같은 용어를 언어별로 못 박아 UI 문구까지 일관되게 관리한다. 개인 개발자의 앱치고 엔지니어링 기준이 상당히 높다.

눈여겨볼 폴더
docs/terminology.md — 용어 표준 원장
"Timeline file(타임라인 파일)", "Journey(이동 경로)", "Video(영상)", "Journey overview(전체 이동 경로)" 같은 핵심 용어의 영어·한국어·일본어 표기를 한 표로 고정한다. 버튼엔 짧은 동사, 제목엔 명사 등 문체 규칙까지 정해, 9개 언어로 번역돼도 제품 말투가 흔들리지 않게 한다. "번역 = 단어 바꾸기"가 아니라 "용어 체계 관리"임을 보여 주는 좋은 사례다.

6학습 포인트

"이 저장소 하나로 배우는 것 — 위치 데이터·지도 투영·이상치 필터·온디바이스 인코딩·프라이버시 설계"

여행 영상에 관심이 없더라도, 이 레포는 아래 주제들을 실전 코드 3벌(코틀린·TS·파이썬)로 비교하며 배울 수 있는 드문 교보재다.

① 위치 데이터 파싱과 좌표계

현실의 데이터는 지저분하다. E7 정수, geo: URI, latLng 문자열, semanticSegments... 하나의 파서가 이 모든 변형을 GeoPoint로 정규화하는 과정을 보며 "다형 입력을 표준형으로 흡수하는" 설계를 익힌다. 날짜변경선 처리 같은 지리 데이터 특유의 함정도 함께 배운다.

② 웹 메르카토르 투영과 지도 타일(XYZ)

웹 지도가 어떻게 둥근 지구를 평면 타일로 자르는지 — project(lat, lng)가 (x, y) ∈ [0,1]을 내놓고, 그걸 줌 레벨에 맞춰 z/x/y.png 타일 격자로 바꾸는 슬리피 맵(slippy map)의 원리를 30줄 남짓한 코드로 이해한다. 지도 앱을 만들려는 사람에게 최고의 입문 예제다.

③ 물리 기반 이상치 제거 heuristic

"통계로 이상치 제거"가 아니라 도메인 지식(사람의 최대 이동 속도)으로 판별하는 접근을 배운다. "애매하면 지우기"가 아니라 "애매하면 남기기"라는 보수적 설계가 왜 사용자 신뢰에 중요한지 — 원본을 훼손하지 않고 걸린 개수를 투명하게 보고하는 태도까지 포함해 좋은 참고가 된다.

④ 온디바이스 하드웨어 비디오 인코딩

같은 "H.264 MP4 만들기"를 두 플랫폼에서 비교할 수 있다 — 안드로이드 MediaCodec/MediaMuxer와 브라우저 WebCodecs. 특히 웹 쪽엔 H.264 코덱 문자열(avc1.42001f 등)과 레벨 계산을 해상도별로 꼼꼼히 따진 주석이 있어, 비디오 코덱의 저수준을 배우기 좋다.

⑤ 프라이버시 우선(privacy-first) 설계

"권한을 최소로, 데이터는 기기 밖으로 내보내지 않기"를 구조로 강제하는 법을 배운다. 위치 권한도, 로그인도 없이 사용자가 고른 파일만 읽고, 유일한 네트워크(지도 타일)조차 사전 고지·동의를 받는다. "프라이버시는 기능이 아니라 아키텍처 결정"이라는 걸 보여 준다.

⑥ 안드로이드 포그라운드 서비스 + 코루틴 생명주기

수십 초~수 분 걸리는 인코딩을 포그라운드 서비스로 빼서, 화면을 꺼도·앱을 나가도 진행되고 알림으로 상태를 보여 주는 패턴을 배운다. 코루틴의 구조적 취소(중간에 취소하면 미완성 파일 삭제)와 진행률·예상 시간 추정까지, 실무형 안드로이드 백그라운드 작업의 정석이다.

7시스템 요구사항

"안드로이드 8.0+ · 아이폰 사파리 16.4+ · (데스크톱) 파이썬 3.9+ · FFmpeg"

세 구현 모두 무거운 GPU가 필요 없다. 인코딩은 각 플랫폼의 기본 기능을 쓰고, 지도 배경만 인터넷이 필요하다.

구현요구 / 참고
안드로이드 앱Android 8.0+(minSdk 26). 최신 릴리스의 TimelineVisualizer-*.apk 설치("출처 불명 앱 설치" 1회 허용). 아직 구글 플레이 미등록.
아이폰 · 브라우저사파리 16.4+ + H.264 인코딩 지원. 설치 불필요(ahn-lab.org/google-timeline-visualizer/). 생성 중 탭 유지 필요.
데스크톱(파이썬)python 3.9+ + FFmpeg + pip install -r requirements.txt(numpy·matplotlib·pillow·python-dateutil).
입력 데이터폰에서 내보낸 Timeline.json. (안드로이드: 설정 → 위치 → 위치 서비스 → 타임라인 → 데이터 내보내기 / 아이폰: 지도 앱 → 설정 → 개인 콘텐츠)
네트워크지도 타일(CARTO)만 요청. 위치 기록 파일은 어떤 서버로도 전송하지 않음.
저장 위치안드로이드 10+는 Movies/Timeline Visualizer에 자동 저장. 8·9는 저장 위치 선택 창 사용.

8직접 해볼 수 있는 실습 과제

"영상 한 편 만들기부터, 파서·필터·인코더를 직접 손대기까지 — 난이도별 5단계"
LEVEL 1 · 입문 첫 영상

웹앱으로 샘플 데이터 영상 만들기

브라우저에서 ahn-lab.org/google-timeline-visualizer/를 열고, 내 Timeline.json(또는 저장소 test-fixtures/의 샘플)을 골라 기간·카메라를 정한 뒤 MP4를 만들어 본다. 목표: 파싱→영상까지 전체 흐름을 사용자 눈으로 한 번 통과하기. fixed/steady/dynamic 카메라의 차이를 눈으로 비교해 본다.

LEVEL 2 · 초급 파이썬 원형

visualizer.py로 데스크톱에서 직접 렌더

pip install -r requirements.txt(+FFmpeg) 후 아래를 돌린다. 알고리즘의 원형을 코드로 읽으며 이해하기 좋다.

python visualizer.py \
  --input Timeline.json --year 2025 \
  --output travel.mp4 --title "My 2025" \
  --camera-movement steady --long-trip-compression balanced

배우는 것: 거리 기반 타이밍, 500km 꼬리 페이드, CARTO 타일 합성이 한 파일 안에서 어떻게 엮이는지.

LEVEL 3 · 중급 파서 읽기

다형 파서 해부 + 작은 파서 직접 짜기

web/src/timeline.ts(또는 안드로이드 data/TimelineParser.kt)를 읽고, 직접 작은 JS/파이썬 스크립트로 Timeline.json에서 (위도, 경도, 시각)만 뽑아 개수·기간을 출력해 본다. E7 정수와 geo: URI를 각각 처리해 본다. 배우는 것: 지저분한 입력을 표준 GeoPoint로 정규화하는 실전 감각.

LEVEL 4 · 고급 필터·카메라 실험

이상치 필터 파라미터 실험 · 카메라 프로파일 수정

outlier.ts/LocationOutlierFilter.kt의 임계값(최대 속도·최대 이탈 거리·시간 창)을 바꿔 가며 걸러지는 점 수가 어떻게 변하는지 관찰한다. 또는 camera.ts의 무빙 프로파일(줌 알파·컨텍스트 비율)을 손봐 새로운 카메라 느낌을 만든다. 함께 있는 *.test.ts로 회귀를 확인한다. 배우는 것: 파라미터가 결과 영상에 미치는 영향, 테스트로 안전하게 실험하는 법.

LEVEL 5 · 도전 기능 추가

새 오버레이/출력 포맷 추가하거나 웹앱 빌드·배포

web/에서 pnpm install && pnpm build로 빌드해 GitHub Pages(또는 로컬)로 띄운다. 이어 overlay.ts/renderer.ts에 새 오버레이(예: 총 이동 거리·방문 도시 수 표시)를 얹거나, video.tsVIDEO_FORMATS에 새 해상도 프리셋을 추가해 본다. 배우는 것: 렌더러·인코더 파이프라인에 실제로 손을 대며 온디바이스 비디오 생성의 끝단을 경험하기.

9관련 기술 심화 학습 로드맵

"이 레포를 '읽고 확장하는 사람'이 되기 위한 6주 코스"
주차주제무엇을 · 왜
1주위치 데이터 기초구글 타임라인 내보내기 포맷, 위경도·E7·geo:, 시각(ISO/오프셋) 파싱. timeline.ts/TimelineParser.kt부터. 지저분한 입력을 표준형으로.
2주지도 투영·타일웹 메르카토르 project(), 줌/타일 좌표(z/x/y), 슬리피 맵. geo.ts·TileRepository.kt. 지도 앱의 근간.
3주데이터 정제이상치(excursion) 판별 heuristic, 정렬·중복 제거·경로 보간. outlier.ts. "도메인 지식으로 거르기".
4주애니메이션·카메라거리 기반 타이밍, 대권 보간, 카메라 무빙 프로파일, 꼬리 페이드. animation.ts·camera.ts·TimelinePainter.kt.
5주온디바이스 인코딩WebCodecs VideoEncoder vs 안드로이드 MediaCodec, H.264 코덱 문자열/레벨, muxing. video.ts·Mp4Exporter.kt.
6주앱화·프라이버시PWA(service worker)·포그라운드 서비스·권한 최소화·다국어(i18n). "예쁜 결과 + 데이터 주권"의 마무리.
추천 학습 순서
"파이썬 원형"으로 뼈대를 먼저, "세 구현 비교"는 나중에

세 구현을 한꺼번에 보면 압도적이다. 하지만 알고리즘의 뼈대는 하나뿐이고, 그게 가장 짧고 선형적으로 담긴 곳이 visualizer.py다. 이 한 파일로 "파싱→필터→투영→카메라→렌더→인코딩"의 큰 그림을 먼저 잡은 뒤, 같은 단계가 코틀린·타입스크립트에서 어떻게 다시 쓰였는지 비교하면 훨씬 빠르다. 원형으로 개념을, 이식본으로 플랫폼 차이를 — 이 순서가 이 레포에선 특히 효율적이다.

10핵심 키워드 사전

문서·코드에서 반복되는 용어들
용어
Timeline.json (타임라인 파일)
구글 지도에서 내보낸 내 위치 기록 파일. 2024년 말부터 클라우드가 아니라 폰에 저장되며, 폰의 설정/지도 앱에서 직접 내보낸다. 이 앱의 유일한 입력이며, 어디로도 업로드되지 않는다.
용어
Journey (이동 경로)
영상에 그려지는 애니메이션 경로와 그 최종 전체 그림(Journey overview)을 가리키는 이 제품의 표준 용어. "선택한 날짜 범위"는 Journey라고 부르지 않는다(용어 표준에서 구분).
용어
GeoPoint · 정규화
파서가 온갖 입력을 통일하는 표준 좌표(위도·경도·시각). 시간순 정렬·중복 제거를 거친 GeoPoint 리스트가 이후 모든 단계의 공통 입력이 된다.
용어
E7 좌표 · semanticSegments
E7은 위경도에 1e7을 곱해 정수로 저장하는 표기(예: 37.5665° → 375665000). semanticSegments는 예전 타임라인 내보내기의 최상위 구조. 파서는 이런 변형들을 모두 받아 준다.
용어
웹 메르카토르(Web Mercator) 투영
둥근 지구의 (위도, 경도)를 지도 평면 좌표 (x, y) ∈ [0,1]로 바꾸는 웹 지도 표준 방식. 위도는 ±85.05°로 제한한다. 구글·OSM 등 대부분의 웹 지도가 쓴다.
용어
지도 타일 · 슬리피 맵(XYZ)
지도를 줌 레벨별로 256×256 조각(z/x/y.png)으로 잘라 필요한 부분만 받아 붙이는 방식. 이 앱은 CARTO의 light_all 타일을 쓰고, 2단계 캐시(메모리+디스크)로 재요청을 줄인다.
용어
이상치 필터 · excursion(튐)
짧은 시간에 멀리 갔다가 사람이 낼 수 없는 속도로 되돌아오는 점들의 무리를 물리 조건으로 판별해 제거하는 보수적 필터. 원본은 건드리지 않고 걸린 개수만 보고한다.
용어
대권(great-circle) 보간
지구 표면 두 점을 잇는 최단 곡선(비행 항로). 점 사이가 멀 때 위경도를 3차원 벡터로 바꿔 그 곡선을 따라 중간점을 만들어, 목적지로 "순간이동"하지 않고 부드럽게 쓸고 가게 한다.
용어
MediaCodec / MediaMuxer
안드로이드 내장 저수준 미디어 API. MediaCodec이 프레임을 H.264로 하드웨어 인코딩하고, MediaMuxer가 그 스트림을 MP4 컨테이너로 묶는다. 외부 FFmpeg 없이 OS 기능만으로 영상 생성.
용어
WebCodecs / mediabunny
브라우저에서 저수준 인코딩을 가능하게 하는 표준 API가 WebCodecs(VideoEncoder). mediabunny는 그 출력 스트림을 MP4로 muxing하는 순수 JS 라이브러리. 둘로 파일 업로드 없이 브라우저 안에서 MP4를 만든다.
용어
포그라운드 서비스(Foreground Service)
안드로이드에서 사용자가 앱을 벗어나도 계속 돌며 알림을 띄우는 백그라운드 작업 방식. 수 분 걸리는 인코딩을 여기서 돌려, 화면을 꺼도·다른 앱을 써도 진행이 유지된다.
용어
CARTO · OpenStreetMap
OpenStreetMap은 오픈 지도 데이터, CARTO는 그 데이터로 만든 지도 타일을 제공하는 서비스. 이 앱의 유일한 네트워크 연결 대상(지도 배경)이며, 위치 기록 파일 자체는 전송되지 않는다.

11참고 링크

원본을 직접 확인하고 싶을 때