跪拜 Guibai
← Back to the summary

A Typhoon Tracker Built in One Sleepless Night Is Now Open for Anyone to Harden

This is a co-building guide for developers, designers, and weather enthusiasts. It's also a ramble about why I made this.

Repository: https://github.com/Trade-Offf/typhoon-bavi-tracker Live: https://chinaupdated.com


1. Origin

On the night Super Typhoon Bavi approached, I couldn't sleep.

Not out of fear, but because after a day of grinding as a corporate drone, my brain was fried. Lying in bed, I habitually opened my phone to check the typhoon situation. The more I scrolled, the more confused I got:

After twenty minutes of scrolling, I hadn't figured out a single piece of information, but I did learn three kinds of "typhoon outfits" and two "typhoon BGM" tracks. Lying in my rented apartment, only three questions remained in my head:

  1. Where is the typhoon now, and how strong is it?
  2. How long until it reaches my home?
  3. What exactly should I do right now?

Just these three questions. I searched through every app on my phone, and not a single one could answer them clearly in one place.

So I got up, opened my computer, and used Claude Fable 5 to hammer out the idea bit by bit. After putting the track data from four agencies—the China Meteorological Administration (CMA), the Japan Meteorological Agency (JMA), the US Joint Typhoon Warning Center (JTWC), and the Taiwan Central Weather Administration (CWA)—onto the same map, many things became clear at a glance. For example, at this moment, the predicted landfall points from several agencies are converging near Wenzhou.

Then I added a few more things:

This website was made purely for myself: no ads, no data collection, all data sources are official. For disaster prevention decisions, please rely on official warnings (do not believe or spread rumors).

There was only one thought while making this: If the people around me can know a little earlier, they can feel a little more at ease.

If you have friends in Jiangsu, Zhejiang, or Shanghai, feel free to forward it to them. If you're a developer, keep reading—I'll lay out how it works, where it's still rough, and how you can help.


2. What It Looks Like

Pictures first, then the tech talk.

A Moving Map on Open

01-overview-city-countdown.png

The observed path is colored by the national standard's six-level intensity scale, "burning" from the deep ocean to the coastal waters. A list of city countdowns hangs on the left, with the most urgent ones at the top. A warning banner at the top tells you who is in the most danger right now.

Click on a City You Care About

02-city-popup.png

The camera flies over, and a small card pops up: when the wind circle is expected to arrive, the closest distance in kilometers, and what to do now. A share link is also ready for you—?city=Wenzhou, send it to a friend in Wenzhou, and it opens directly focused on their home.

Four Agencies' Forecasts, Side by Side

Screenshot 2026-07-07 12.09.07.png

The forecast dotted lines from the four agencies—China, Japan, the US, and Taiwan—can be toggled on and off independently. Forecasts inherently have disagreements; the divergence itself is information. The tighter the four lines converge, the more certain the path; the more they spread out, the more you need to stay alert.

News and Guides, All at Hand

03-news-panel.png

04-guide-panel.png

News is from a media perspective, faster than official bulletins, but please use your own judgment. The guide is static content, covering everything from "48 hours before landfall" to "safety checks afterward." Emergency numbers are all listed—in a real moment of panic, no one has the patience to search again.


3. How It Works

The architecture is almost embarrassingly simple: one Cloudflare Worker, a bunch of pure functions, no database, no server.

┌─────────────────────────────────────────────────────────────┐
│  User Browser (MapLibre GL + TypeScript)                      │
│  · Path replay / Wind circle animation / City markers / HUD / Deep-link sharing │
└──────────────────────────┬──────────────────────────────────┘
                           │ /api/typhoon/:id  /api/news
┌──────────────────────────▼──────────────────────────────────┐
│  Cloudflare Worker (Edge Proxy + Cache + Disaster Recovery)   │
│  · normalize.ts  Dual-source normalization                    │
│  · news.ts       RSS feed aggregation                         │
│  · Cache: Typhoon 5min / News 10min                           │
└──────────┬─────────────────────────────┬────────────────────┘
           │                             │
   Zhejiang Water Resources      Google/Bing News RSS
   Dept. API (Primary)
   CMA NMC (Backup)

But the simplicity is intentional. In the face of a disaster, the simpler the system, the more reliable it is. There's no database to crash, no server to wake up and restart in the middle of the night. If one edge node goes down, there's another. The first thing a disaster prevention tool must do is not fall over itself.

The same thinking guided the tech choices:

Layer Choice Why
Edge Compute Cloudflare Workers Zero ops, global CDN, accessible in China
Frontend Map MapLibre GL Open-source, flexible, no Google dependency
Basemap Amap Satellite + CN labels Stable domestic CDN, Chinese labels, compliant
Build Vite + TypeScript Fast, with type safety net
Data No database Origin returns full track; edge cache is enough

Directory Overview

worker/
  index.ts       # Routing, edge caching, dual-source disaster recovery
  normalize.ts   # CMA/ZJ data → TyphoonData (pure function)
  news.ts        # RSS parsing, aggregation, and snapshot merging (pure function)

src/
  app.ts         # Entry: playback control, HUD, sharing, countdown refresh
  map.ts         # MapLibre layers, city markers, wind circle animation
  impact.ts      # City impact countdown algorithm (pure function)
  geo.ts         # Spherical distance, wind circle polygon, track interpolation
  guide.ts       # Emergency guide content
  news.ts        # News panel rendering
  mobile.ts      # Mobile layout: top live strip + bottom 3-drawer panel
  slogan.ts      # Positive energy slogan carousel

A few habits kept while coding:

A Pitfall I Stepped Into, Shared with You

I fell for a trap once with the news aggregation. The original logic was to overwrite the cached snapshot on each fetch. One time, Google was rate-limited and Bing happened to return only 1 result. This meager result wiped out the previously accumulated 30-item complete snapshot. When a user opened the page, the news panel had only a single lonely entry.

After the fix, the refresh logic was changed to a merge: new items take priority, historical items are deduplicated and fill in the gaps, and within a seven-day window, the data only grows, never shrinks. This lesson is worth writing down here: For a disaster prevention tool, a single bad fetch should never destroy the accumulation already built.


4. How to Get Started?

git clone [email protected]:Trade-Offf/typhoon-bavi-tracker.git
cd typhoon-bavi-tracker
npm install
npm run dev          # Vite dev server
npm run typecheck    # TypeScript check
npm run preview      # Build + wrangler local Worker simulation

When running vite dev locally, /api/typhoon proxies to the Zhejiang Water Resources Department interface. To see the full Worker behavior (caching, disaster recovery, news aggregation), use npm run preview.


5. These Tasks, Waiting for You

The directions below are sorted by "how much more they can help a person," not by technical difficulty. In this project, adding a city is more valuable than swapping a framework.

Directly Enhance Disaster Prevention Value

Direction Description Where to Modify
Add a city Add { name, lng, lat } to the CITIES array. That's it. src/impact.ts
10/12-level wind circle countdown Extend computeImpacts to return multi-level ETAs. src/impact.ts
Sort cities by location navigator.geolocation + distance sorting. src/app.ts
Multi-typhoon switching Change TYPHOON_ID to a route parameter—typhoons come every year, this site shouldn't live just for Bavi. src/app.ts · worker/index.ts
Localized guides Provincial flood prevention rules, shelters. You know your city better than I do. src/guide.ts

Experience & Dissemination

Direction Description
i18n Traditional Chinese / English For residents of Hong Kong, Macau, Taiwan, and foreign nationals.
Warning level integration Connect to CMA warning signals.
PWA offline cache The last data before disconnection, viewable offline—network loss is most common during typhoons.
Dynamic share card generation Real-time rendering of OG images based on city countdown.

Data Source Expansion (Requires Compliance Assessment)

Source Current Status Idea
Xiaohongshu (RED) Anti-scraping, cannot fetch anonymously Requires user authorization or official API.
Weibo Requires visitor Cookie Implement cautiously on Worker side, mind the ToS.
Local weather bureaus Most have public interfaces Add a fetcher module in worker/.

Performance To-Dos (Welcome to Claim)


6. How to Submit an MR

The process is standard: Fork, branch, self-test, send a PR:

git checkout -b feat/your-feature-name
npm run typecheck   # Must pass
npm run build       # Must pass
npm run preview     # Run Worker + frontend locally to verify

A few small conventions:

For example:

feat(impact): add Xiamen, Quanzhou city countdowns

- Added southern Fujian coastal cities to the CITIES array
- Verification: open /?city=Xiamen to see the countdown popup

During review, I'll look at type safety, dependency size, and data source timeouts and disaster recovery. But one rule outweighs all code standards:

Every line of text in this project might be read late at night by someone worried about their family. We provide certainty, not anxiety; convey urgency, not panic. The disclaimer must remain: the countdown is an estimate, and disaster prevention decisions should be based on official warnings.


7. Why Open Source

Disaster prevention information should not be locked in anyone's server—including mine.

This project was born on a sleepless night, but it shouldn't belong only to that night. Typhoons come every year, data sources will expire, city lists will become outdated, and guides will need updating. One person's passion cannot sustain something that needs to exist long-term; only a community can.

After open-sourcing, things become imaginable: a data source goes down, someone submits a fix within half an hour; a friend in Fujian adds Fujian's shelters; someone forks and deploys it to their own domain. Even if chinaupdated.com disappears one day, the code remains and can still help in an emergency.

People who write code often doubt whether what they make has meaning. But disaster prevention gives a rare, clear answer—

A technologist's idealism is sometimes just writing a piece of code so that one more person can see danger ahead of time.

Every bug you fix might be the last refresh a user grabs before the network cuts out; every city you add has real people living behind it. There are no KPIs here, no growth curves, just a simple metric: did someone, because of it, reinforce their windows early, stock up on water, or move their elderly parents to safety?

Welcome to Star, Fork, raise an Issue, submit an MR. One person's strength is limited, but many hands make light work, always illuminating a little more of the road ahead.

The typhoon will pass, the code will remain. May it be better the next time it is needed.


Appendix

The custom domain is configured in the routes section of wrangler.jsonc, currently bound to chinaupdated.com and www.chinaupdated.com.

Screenshot Index

File Description
docs/screenshots/01-overview-city-countdown.png Overview: Amap basemap + city list + warning bar
docs/screenshots/02-city-popup.png Click city: countdown popup + action suggestion
docs/screenshots/03-news-panel.png Real-time news: multi-source media reports
docs/screenshots/04-guide-panel.png Emergency guide: five-section checklist
docs/screenshots/05-forecast-compare.png Four-agency forecast path comparison
Comments

Top 7 of 11 from juejin.cn, machine-translated. The original thread is authoritative.

nuIi

Bug: Style is not done loading. at cn._checkLoaded (maplibre-wqmL2Hxp.js:796:86493) at cn.addSource (maplibre-wqmL2Hxp.js:796:91133) at Yo.addSource (maplibre-wqmL2Hxp.js:800:109763) at Gt.setupLayers (index-C1flaEsg.js:2:6218) at index-C1flaEsg.js:107:3324 at s (index-C1flaEsg.js:2:5974)

HiSt

Got it, I'll take a look after work. Probably a sporadic network issue. Gotta be a beast of burden for a while longer [downcast]

向日葵武士

There really is a bug crawling around [dog with eye-roll]

雨飞飞雨

I want to try it right now, deploy it quickly.

HiSt

https://chinaupdated.com/ , it's live online. Can't you open it?

雨飞飞雨  → HiSt

[grin] Just saw it.

七仔哥们儿

OP is fast. Did you have a server before? How can you be this fast? Even with AI assistance, it's still incredibly fast.

yuanchen

Don't you know about a real-time typhoon path website developed in Zhejiang? But yours has some unique features, more information.

二狗API中转站

Can't open it. It keeps showing 'Fetching Bavi real-time observation data...'

申君健2486418277202

The above is an ops doc. Talk about the tech stack. What engineering template is this, and how to deploy it on Cloudflare?

HiSt

Some ramblings: https://www.bilibili.com/video/BV148Ms6MET9/?spm_id_from=333.1387.homepage.video.card_click&vd_source=0bcafb665fe6140f5a86a181137e5c7d