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 to TimelineParser.kt. Rendering is performed by TimelinePainter.kt and related classes in render/. Video export runs through VideoExportService.kt, which uses Mp4Exporter.kt and VideoEncoderSupport.kt to 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 in web/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

  1. LaunchMainActivity.onCreate() (file MainActivity.kt) inflates the layout and registers UI callbacks.
  2. File selection – UI invokes TimelineSourceStore → reads the selected JSON into memory.
  3. ParsingTimelineParser.parse(json) builds TimelineModels and runs LocationOutlierFilter.filter() to clean data.
  4. RenderingTimelinePainter.draw(model) drives TimelineAnimation and RenderText to generate bitmap frames.
  5. Export – UI calls VideoExportService.export(model, settings). The service creates an Mp4Exporter instance, which streams frames to MediaCodec via VideoEncoderSupport.
  6. CompletionVideoExportState updates UI; the resulting .mp4 is 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

  1. Entryweb/index.html loads the Vite bundle; main.ts mounts the React root component.
  2. File picker – component reads the user‑selected Timeline.json via the File API.
  3. Parsing – imported TimelineParser.ts processes the JSON, applying the same outlier filter logic (mirrored from Kotlin).
  4. Preview – React renders a canvas driven by TimelinePainter.ts (client‑side animation).
  5. 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.
  6. 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/... and app/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 – LicenseLICENSE present (MIT).
  • Low – Dependency lockpnpm-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.