The source of hyoban.cc: a personal site built with Astro and plain CSS, with posts, a calendar and map of Moments and trips, a search over both, and the pieces around it that record and serve them.
.
├─ apps/web/ the Astro site (@hyoban/web; its DESIGN.md describes how it looks)
├─ data/ the car's records, and a local copy of the API's (docs/data.md)
├─ apps/api/ Cloudflare Worker serving the records from D1 (@hyoban/api)
├─ apps/android/ Here, the Android app that reads and writes Moments (Gradle)
├─ apps/apple/ HereKit, the start of Here on iPhone, iPad and Mac (Swift)
├─ packages/data-spec/ the Zod schemas every side shares (@hyoban/data-spec)
├─ packages/trip-map/ the map page and trip player (@hyoban/trip-map)
├─ packages/drawer/ the calendar's and map's drawers (@hyoban/drawer)
├─ packages/design-tokens/ the app's design tokens, springs and icons
├─ scripts/ data, asset and media scripts, run as `vp run <name>`
└─ docs/ data.md, assets.md and deploy.md
Android app ──POST /v2/changes──▶ API Worker (D1 + R2) ──deploy hook──▶ site build
│ ▲ │
data:export │ │ data:push / data:import ▼
▼ │ hyoban.cc (static)
data/ (local copy, out of git)
- The API (
apps/api) keeps the Moments, places, trips and the trips' routes in a D1 database, and the photos and videos in theblog-imagesR2 bucket, served fromhttps://image.hyoban.cc. - Every request to the API needs a token. The Android app writes to it as one change
set (
POST /v2/changes) and reads it with its token. - The site is static. Its build reads the API's export with
MOMENTS_API_TOKEN, and fails without it. data/holds the car's records in git; the rest of it is a local copy of the API's thatvp run data:exportwrites for the scripts, which git leaves out. Edit records through the API, or push what you wrote withvp run data:push(docs/data.md).
FORKING.md says how to make it your own: who the site belongs to and where it
lives is all in site.config.json, which the site, scripts, API and app read, and a local
build without a token shows made-up records.
This is a pnpm workspace driven by Vite+ (vp); see AGENTS.md.
vp install
vp run dev # the site, from the API with MOMENTS_API_TOKEN in .env, else made-up records
vp check # format, lint and type check, packages and API included
vp test
vp run build # the static site into apps/web/dist/.env (see .env.example) may hold:
| Variable | Used for |
|---|---|
VITE_MAPBOX_TOKEN |
the map page's Mapbox tiles |
MAPBOX_STATIC_TOKEN |
the map pages' placeholders, if VITE_MAPBOX_TOKEN is URL-restricted |
MOMENTS_API_TOKEN |
building the site from the API, data:export and data:push |
CI |
set, the build draws every Moment's share card (slow; off locally) |
The scripts that upload to R2 use Wrangler's login, or CLOUDFLARE_API_TOKEN;
media:generate needs TMDB_API_TOKEN or TMDB_API_KEY.
To run the API locally, see apps/api; for the app,
apps/android, built with its own ./gradlew; for the Apple apps'
shared package, apps/apple, checked with swift test.
Everything runs on Cloudflare and deploys from main: Workers Builds builds the site on
every push and whenever the API takes a write it shows, and deploys the API when its
inputs change; GitHub Actions back up the data and the R2 bucket. The settings, secrets
and recovery steps are in docs/deploy.md.
The 3D car's speed mode, held down in the year review and the 20,000 km post, where a line
credits it (apps/web/src/car-model-speed.ts), follows GameMCU's
Xiaomi SU7 showroom: its tunnel of streaks, its reflections laid
crisp over the paint, its glossy floor and its camera.