Open-source project
sansan0/mao-map avatar
sansan0/mao-map

mao-map turns a historical chronology into a playable timeline map

📍 毛主席足迹地图 | Chairman Mao's Footprints Map - 交互式动态展示1893-1976年完整轨迹 | Interactive map showcasing Mao Zedong's journey (1893-1976). 星星之火,可以燎原 / A single spark can start a prairie fire.。底部为网友整理的毛泽东年谱,欢迎协作完善数据。

594 stars105 forksJavaScriptGPL-3.0

At a glance

What is it?
mao-map is an interactive map of Mao Zedong's travels from 1893 to 1976, built as a Vite web app with Tauri v2 clients for Windows, macOS and Android. Its real substance is the data: six historical periods, per-event sources, and a route model you can search and layer.
Who is it for?
mao-map fits anyone who wants to explore a long historical chronology as a sequence of places and journeys, and it fits contributors who want their corrections to become part of the record rather than a comment thread. It is a poor fit if you need citable academic sourcing, since the readme notes that records without a source are marked as such, and it is a poor fit offline, because the base map tiles need a network connection.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 10 days ago.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A chronology you scrub through, not a page you read

The project describes itself as an interactive map that condenses a life from 1893 to 1976 onto one dynamic map, with the stated aim of letting the history come alive and showing the key decisions and geographical marks along the way. The homepage link goes to a Quark share, and the online version is served from GitHub Pages.

What the app is, concretely, is a timeline player over a map. Clicking the play button walks through 83 years of the trajectory in chronological order, and dragging the timeline at the bottom jumps to a particular year to see what was happening then. The map itself has multi level markers whose style depends on how many times a place was visited and what kind of event it was, and clicking a marker opens a panel with the full list of historical events for that location. Clicking an event in that list highlights the corresponding movement path on the map.

The statistics panel keeps a running count of moves, provinces visited and international movements, and shows playback progress, age and event index, with charts for the trajectory as a whole.

So the value is in the interaction. A chronological list gives you the order of events; this gives you the geography of them, which is a different question and, for a life defined by long journeys, arguably the more revealing one. What the app cannot do is verify the history, and the project is honest about that: the event card shows the date, the place, the route and the source for the event, and records whose source has not been filled in are explicitly marked as such.

Two modes over one map, with a shared layout on every device

The interface has two modes and the same map underneath both.

The default is pure playback, using the paper, warm toned skin and a full screen map with a frosted glass playback bar along the bottom showing the current footprint, and the event description can be collapsed when it covers too much. The alternative is browsing, toggled from the top, where the timeline can be expanded or collapsed, the mobile version presents it as a drawer, the historical material is expanded on demand, and the map tools stay collapsed by default.

The cross platform point is worth stating because it is unusual for a project of this size. The HTML version, the Windows build, the macOS build and the Android build share the same interface structure, so the browse mode can show the timeline and the map side by side, while small screens and short windows collapse the timeline into a drawer.

Several details are about not losing the reader's place. Switching modes, switching skins or collapsing the description does not interrupt playback. Appearance, mode, collapsed state, period filter, route range, camera, speed, volume and the choice of built in song are all saved locally in the current browser or application and restored on reopen, with playback resuming paused rather than jumping ahead. Clearing site or application data clears those preferences, and locally uploaded music is used only for the current session.

That last pair of facts is the honest boundary of a client side app: the state lives on your machine, which is convenient and private, and which also means there is no sync between your desktop and your phone unless you move it yourself.

Search, layered routes and the period filter

The data model is where a project like this either holds up or does not, and the readme describes it in enough detail to judge.

Events are organised into six historical periods, from study and exploration through to the years of the new China. You can search by year, by event, by origin and destination, and by waypoint, and selecting a record synchronises the map and the timeline. Routes can be viewed in layers, switching between the cumulative footprints and the current trip, and there is a one click action to locate the current trip or to see the footprint range up to the current point in the playback.

Each event card carries the date, the place, the journey and the source for the event, which is the field that separates a serious reference from a nice animation. Records whose source has not been added are explicitly marked, so a reader can see which parts of the map rest on documentation and which do not.

On the desktop, the Tauri v2 build adds a system tray, so closing the window puts the app in the tray rather than quitting, and the tray menu offers always on top and start on boot. There is also a smart camera follow with three modes, smart with distance adapted framing, along the route, and off, and a single speed control that drives playback, path animation and camera follow together, which is the sort of detail that only matters if the two drift apart otherwise.

The PC keyboard shortcuts are minimal and useful: space for play and pause, the left and right arrows for the previous and next event, and Home and End.

Local development is vite, a node test runner and one Tauri command

The quick start is short, because the project is a static front end with an optional native shell.

bash
npm ci
npm run dev

The development server then serves the page at http://127.0.0.1:51420/. A separate path, /tauri.html, previews the shared client page structure, and the native window capabilities need the Tauri runtime, so they are not available in the plain browser.

The scripts in the package metadata show the whole toolchain, and they are worth reading because there is no framework layer between you and the browser.

json
  "scripts": {
    "dev": "vite",
    "build": "node scripts/build.js",
    "check:version": "node scripts/check-version.mjs",
    "test": "node --test scripts/ui.test.mjs",
    "icons:sync": "node scripts/sync-icons.mjs",
    "tauri": "tauri",
    "tauri:dev": "node scripts/dev.mjs",
    "tauri:build": "tauri build"
  },

The test command runs the Node test runner against a single script and, as the readme states, validates the DOM, the data, the interactions and the static asset paths, with no browser automation involved. jsdom is in the dev dependencies for that purpose, alongside the Tauri CLI, lucide-static and Vite.

Icons are handled rather than hand drawn. The interface uses Lucide's official SVGs, and scripts/sync-icons.mjs extracts the needed icons from a pinned version of lucide-static, with npm run icons:sync updating libs/lucide/. That directory ships with both the static web version and Tauri, so nothing is fetched from an icon CDN at runtime, and the upstream licence is kept in libs/lucide/LICENSE.

Deployment is a GitHub Pages concern as much as a Tauri one. Pages keeps using the root index.html with the assets, libs, data and i18n directories, and the two entry points share their page structure through assets/js/shell.js, with relative paths so a subdirectory deployment works.

The data is crowdsourced, and the map tiles need a network

Two limitations are stated in the readme and both are worth knowing before you plan around the project.

The first is network dependency. The base map tiles still require a network connection, and when they fail to load you can continue browsing the timeline and retry the tiles. So the application is not offline capable in the way an offline-first map viewer would be, even though all of the interesting data is local. The data directories, the i18n files and the libraries are shipped with the app; the geography underneath is not.

The second is the provenance of the events. The project is explicit that records without a completed source are marked as such, and it asks contributors to help complete the chronology, with contributions and bugs going through GitHub Issues as the single channel for tracking them.

The mechanism for that is a JSON array called userVerification, where each entry carries an optional username for attribution, an optional comment and an optional date. The intent is that a reader who spots a wrong date or a missing stop submits their research as an issue, the maintainer enters it, and the project says that when enough of these accumulate they will be rendered as scrolling comments over the map, in the style of a danmaku track.

That is an unusual but coherent design for a historical map. It acknowledges that the record is the fragile part, not the rendering, and it builds a path for a reader with better sources to fix it. What it does not offer is a citation trail for the history itself, so for academic use the map is a lead generator rather than a reference.

GPL-3.0, a busy release line and a client that keeps getting smaller

The licence is GPL-3.0, with the LICENSE file at the repository root, and the readme invites sharing and further creation under those terms.

The activity record is active. The repository is not archived, the last push was on 2026-10-13, and the tags show v2.4.0 on 2026-10-13, v2.3.0 on 2026-10-12 and v2.2.0 earlier in the year, with the project version in the package metadata matching 2.4.0. There is a check:version script and a version.json at the repository root, which suggests the version is kept in step with the data and the clients rather than bumped by hand.

The packaging is worth one more look because it explains the shape of the repository. The web version is a static site with no server side rendering, built with Vite from a root index.html, and the native clients are built by Tauri v2 from the src-tauri directory, which is why the same front end can be packaged as a Windows installer, a macOS DMG and an Android APK. The release assets are published on GitHub Releases, and the readme points at the latest release for all three platforms.

The alternative to this project is the text based chronology that the same maintainers compile, which the readme places at the bottom of the map. The difference in approach is the whole point. A chronicle is linear, citable and reliable, and you read it top to bottom. The map is exploratory, it relates events to place, and it lets you watch a route rather than read about one. For learning the shape of a life the map does something a list cannot, and for checking a date the chronicle is still the safer source.

Editorial conclusion

mao-map fits anyone who wants to explore a long historical chronology as a sequence of places and journeys, and it fits contributors who want their corrections to become part of the record rather than a comment thread. It is a poor fit if you need citable academic sourcing, since the readme notes that records without a source are marked as such, and it is a poor fit offline, because the base map tiles need a network connection. Check first that the events you care about carry a documented source, that the map tiles you expect are reachable from where you run it, and that the Tauri build works on your desktop before you rely on the native clients.

Frequently asked questions

How do I run mao-map locally?

Run npm ci and npm run dev, then open http://127.0.0.1:51420/. The /tauri.html path previews the shared client page structure, while the native window capabilities need the Tauri runtime.

What is mao-map built with?

A Vite based web front end with Tauri v2 for the Windows, macOS and Android clients. The package scripts include tauri:dev and tauri:build, and the dev dependencies are the Tauri CLI, jsdom, lucide-static and Vite.

Does mao-map work without an internet connection?

Not completely. The base map tiles still need a network connection, and if they fail to load you can keep browsing the timeline and retry the tiles. Locally uploaded music is only used for the current session.

How do I contribute a correction to the mao-map chronology?

Through GitHub Issues, which the readme names as the single channel for contributions and bugs. The project records crowd sourced research entries with a username, a comment and a date, which the maintainer enters into the data.

Official sources

  1. License: GPL-3.0
  2. Project website
  3. README
  4. Releases
  5. sansan0/mao-map on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/sansan0-mao-map.svg)](https://hysenlabs.com/projects/sansan0-mao-map)