OpenTrailPaper
LilyGO T5S3 4.7" E-Paper PRO용 오픈소스 자전거 컴퓨터 펌웨어, 오프라인 지도·GPX 경로·FIT 기록·블루투스 센서 지원
초경량 달리기 대회 일정 캘린더 개막·마감·추첨일을 확인하고 다음 행동을 파악하세요
A living calendar of trail ultra registrations. Track opening dates, closing deadlines, and lottery draws for UTMB, Western States, Hardrock, and more — sorted by what needs action next.
스포츠·피트니스GitHub @Corresita온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
아직 감지된 업데이트가 없습니다. GitHub 릴리스가 나오면 여기에 보입니다.
Know the day registration opens. Every lottery draw, every deadline that matters — for the trail ultras you're chasing.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다.
README 전문 보기 ↗Never miss a trail ultra registration.
Live Site: racereminder.run
Race Reminder tracks 81 ultra-trail races — the full UTMB World Series calendar (65 events), the World Trail Majors, and independent classics like Western States, Hardrock, and the US 200-milers (Cocodona, Tahoe, Bigfoot, Moab) — with race dates, registration windows, entry methods (lottery vs. first come, first served), and index requirements in one clean calendar.
Popular ultra-trail races sell out within days (sometimes hours) of registration opening, and every race has its own rules: UTMB Mont-Blanc runs a Running Stones lottery, Hong Kong 100 uses a ballot, Eiger Ultra-Trail is first come, first served. Keeping track of all these windows by hand means missed races. Race Reminder puts every window in one place — and emails you when the ones you care about open.
.ics) so you can subscribe from Apple/Google Calendar/api/notify (endpoint ready; schedule not yet created)scripts/scrape.ts syncs official UTMB sites every 2 hours)Want to use the app? Just visit racereminder.run — no setup needed. The steps below are for developing or contributing.
npm install
npm run dev
Open http://localhost:3000.
Only needed to actually send reminder emails — everything else works without configuration:
RESEND_API_KEY=re_... # from https://resend.com; without it, notify runs dry
EMAIL_FROM="Race Reminder <[email protected]>" # a sender verified in Resend (optional)
race-reminder/
├── app/
│ ├── page.tsx # Server component: loads races, renders the page
│ ├── components/
│ │ └── race-browser.tsx # Client component: tabs, filters, subscribe buttons
│ └── api/
│ └── subscribe/route.ts # POST/DELETE subscription endpoint
├── lib/
│ ├── deriveStatus.ts # Facts → status derivation (the core logic)
│ └── subscriptions.ts # Subscriber storage shared by API + notifier
├── scripts/
│ ├── scrape.ts # Checks races against official UTMB sites
│ └── notify.ts # Emails subscribers when registration opens
└── data/
├── races.json # The race database (facts only)
└── subscriptions.json # Subscribers (gitignored, created on first use)
npm run dev # Start the dev server
npm run build # Production build
npm run lint # ESLint
npm run scrape # Diff every UTMB race against its official site (dry run)
npm run scrape -- --write # Apply the changes to data/races.json
npm run notify # Email subscribers whose races just opened (dry run without RESEND_API_KEY)
| Method | Endpoint | Description |
|---|---|---|
| POST | /api/subscribe | Subscribe an email to a race ({email, raceId}) |
| DELETE | /api/subscribe | Remove a subscription ({email, raceId}) |
Subscriptions are stored in data/subscriptions.json (gitignored — it contains email addresses). scripts/notify.ts reads them, derives each race's status, and emails subscribers whose race has an open window — at most once per race edition.
Race data lives in data/races.json. The file stores facts only — status is derived at runtime by lib/deriveStatus.ts from the facts plus the current time. Each race record looks like:
{
"id": "utmb-mont-blanc",
"name": "UTMB Mont-Blanc",
"series": "utmb-world-series",
"country": "France",
"raceDate": "2026-08-28T06:00:00+02:00",
"registrationOpens": null,
"registrationCloses": "2026-01-15T23:59:59+01:00",
"registrationType": "lottery",
"entryRequirement": "UTMB Index 100M + Running Stones",
"distancesKm": [15, 40, 60, 101, 145, 174, 300],
"officialUrl": "https://montblanc.utmb.world/"
}
registrationOpens / registrationCloses are null when the organizer has not announced them yet (TBA in the UI). registrationType is fcfs, lottery, or qualification; lottery races may carry a lotteryDrawDate. The only manually stored status is soldOut: true — code cannot know a race sold out. Everything else (open, closing soon, closed, completed, next edition) is a conclusion, not a field.
| Source | Coverage | Data provided |
|---|---|---|
| utmb.world event calendar | 65 UTMB World Series races | Names, dates, countries, distances, official sites |
Official race sites (via npm run scrape) | UTMB subdomains | Event dates, per-distance registration status |
| Manual curation | World Trail Majors + WSER/Hardrock + registration windows | Registration windows, entry requirements, lottery details |
Note: Dates are manually curated and may lag official announcements. Always confirm on the official race website before booking flights.
__NEXT_DATA__ JSON embedded in UTMB race sitesThe research, design decisions, and lessons learned behind this project are documented in PROJECT_JOURNEY.md. The page's information architecture — every UI block, its data, and its display rules — lives in DESIGN.md.
Data corrections are the most valuable contribution right now — if you spot a wrong date or a missing race, open a PR against data/races.json.
git checkout -b fix/eiger-2027-dates)