The Problem
Users who export Google Maps Timeline data have no simple way to turn the raw JSON into a visual travel story. The file is large, contains outliers, and requires custom rendering and video encoding, which most users cannot perform manually.
What This Does
The repo ships two front‑ends that consume a Timeline.json file and produce an animated MP4 of the user’s journeys.
- Android app – Kotlin source lives under
app/src/main/java/dev/mahlernim/timelinevisualizer/.MainActivity.kt(entry point) launches the UI, lets the user pick a JSON file, and delegates parsing toTimelineParser.kt. Rendering is performed byTimelinePainter.ktand related classes inrender/. Video export runs throughVideoExportService.kt, which usesMp4Exporter.ktandVideoEncoderSupport.ktto write the final file.
- Web app – The static site starts at
web/index.html, which loads the bundle produced by Vite (web/src/main.ts). The TypeScript entry point bootstraps a React UI (React is listed in the dependency graph) and calls the same core logic that lives inweb/src/(e.g.,TimelineParser.ts). After preview, the browser‑based encoder (Safari 16.4+ H.264) creates the MP4 client‑side.
Both front‑ends share the same data model (model/TimelineModels.kt for Android, analogous TS types for web) and filtering logic (LocationOutlierFilter.kt / its TS counterpart) to discard noisy GPS points before rendering.
How It Is Wired
Android flow
- Launch –
MainActivity.onCreate()(fileMainActivity.kt) inflates the layout and registers UI callbacks. - File selection – UI invokes
TimelineSourceStore→ reads the selected JSON into memory. - Parsing –
TimelineParser.parse(json)buildsTimelineModelsand runsLocationOutlierFilter.filter()to clean data. - Rendering –
TimelinePainter.draw(model)drivesTimelineAnimationandRenderTextto generate bitmap frames. - Export – UI calls
VideoExportService.export(model, settings). The service creates anMp4Exporterinstance, which streams frames toMediaCodecviaVideoEncoderSupport. - Completion –
VideoExportStateupdates UI; the resulting.mp4is stored in the app’s private files (videos/directory).
The Android side is a linear pipeline; the only hub is VideoExportService, which coordinates parsing, rendering, and encoding. No network I/O occurs.
Web flow
- Entry –
web/index.htmlloads the Vite bundle;main.tsmounts the React root component. - File picker – component reads the user‑selected
Timeline.jsonvia the File API. - Parsing – imported
TimelineParser.tsprocesses the JSON, applying the same outlier filter logic (mirrored from Kotlin). - Preview – React renders a canvas driven by
TimelinePainter.ts(client‑side animation). - Export – when the user clicks “Create MP4”, the browser calls the Web‑Codecs API (Safari’s H.264 encoder) through
Mp4Exporter.ts, streaming frames directly to a Blob. - Download – the Blob is offered as a downloadable file; no server is involved.
The web side’s central coordinator is the React component that calls TimelineParser, TimelinePainter, and Mp4Exporter. All heavy work stays in the client, keeping the repo server‑free.
How To Use It
# Clone the repo
git clone https://github.com/moses-y/google-timeline-visualizer
cd google-timeline-visualizer
# ---------- Android ----------
# Build and install the APK (requires Java 17+ and Android SDK)
./gradlew :app:assembleDebug # produces app/build/outputs/apk/debug/app-debug.apk
# Transfer the APK to a device and install, or use:
adb install app/build/outputs/apk/debug/app-debug.apk
# ---------- Web ----------
# Install Node dependencies with pnpm (pnpm is declared in package.json)
pnpm install --dir web
# Run a dev server
pnpm --dir web dev # starts Vite on http://localhost:5173
# For a production build
pnpm --dir web build
# Serve the `dist/` folder with any static server (e.g., `python -m http.server`)
# Both front‑ends expect a local `Timeline.json` file; no additional config files,
# environment variables, or API keys are required.
The Android UI also offers a “Restore Google Maps Timeline” link that opens the system settings page for exporting a fresh JSON file.
Real‑World Use
A travel blogger exports Timeline.json from Google Maps on their phone, opens the Android app, selects a month‑long vacation, tweaks the title template (TitleTemplate.kt), and taps “Create MP4”. The app produces a 30‑second video that the blogger uploads to social media directly from the device.
Code Health & Issues
- Low – Test coverage – 47 unit tests under
app/src/test/java/...andapp/src/androidTest/...cover parsing, rendering, and export logic. - Low – CI – GitHub Actions workflows (
.github/workflows/*.yml) run lint, unit tests, and web validation on every push. - Low – License –
LICENSEpresent (MIT). - Low – Dependency lock –
pnpm-lock.yaml(implied) and Gradle version catalogs keep third‑party versions pinned. - No secrets or hard‑coded credentials found.
- Documentation (
README.md,docs/) is comprehensive and includes platform‑specific usage notes.
The Bottom Line
The repository delivers a well‑tested, dual‑platform solution for turning Google Maps Timeline data into shareable videos, with clear separation between parsing, rendering, and encoding. Build and run steps are straightforward, but the project is limited to Android and modern Safari browsers; there is no backend or cross‑platform CLI. Engineers looking to extend the visualizer (e.g., adding custom map styles or server‑side batch processing) have a clean code base to start from.