The runway where all gtfs.zone projects take off from
  • TypeScript 82.4%
  • HTML 13.9%
  • CSS 2.8%
  • Shell 0.6%
  • Dockerfile 0.3%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Max Katz-Christy b36dce4f29
All checks were successful
Vulnerability scan / vuln-scan (push) Successful in 7s
docs: fix manager repo, release steps and license in README and package.json
2026-09-30 21:37:13 +02:00
.forgejo/workflows ci: check out from the public Forgejo URL in the vuln scan 2026-09-30 20:01:17 +02:00
.github/workflows ci: add osv-scanner vulnerability gate on GitHub and Forgejo Actions 2026-09-30 19:49:43 +02:00
docs refactor(copy): scheduled feed vocabulary and link param 2026-08-26 10:03:29 +02:00
public feat(seo): GTFS in the title, structured data, and a PNG social card 2026-09-27 01:19:38 +02:00
scripts ci: add osv-scanner vulnerability gate on GitHub and Forgejo Actions 2026-09-30 19:49:43 +02:00
src refactor(content): name the GitHub link github instead of mirror 2026-09-30 19:19:18 +02:00
.cz.toml chore(release): bump version 0.7.0 -> 0.8.0 2026-09-27 01:19:59 +02:00
.dockerignore Build and publish a site image instead of copying into a shared volume 2026-08-18 01:44:45 +02:00
.gitignore feat: replace zola site with vite single page 2026-08-15 03:17:49 +02:00
.pre-commit-config.yaml build: default pre-commit 2026-03-10 15:03:01 +01:00
CHANGELOG.md chore(release): bump version 0.7.0 -> 0.8.0 2026-09-27 01:19:59 +02:00
CLAUDE.md docs: replace the superseded plan docs with one current plan 2026-08-16 14:39:15 +02:00
CURRENT_PLAN.md docs: replace the superseded plan docs with one current plan 2026-08-16 14:39:15 +02:00
Dockerfile Build and publish a site image instead of copying into a shared volume 2026-08-18 01:44:45 +02:00
index.html feat(seo): GTFS in the title, structured data, and a PNG social card 2026-09-27 01:19:38 +02:00
LICENSE.txt chore: apply bare-chassis copier template 2026-04-17 00:54:07 +02:00
nginx.conf fix(nginx): return 404 for unknown paths instead of the homepage 2026-09-27 01:19:38 +02:00
package.json docs: fix manager repo, release steps and license in README and package.json 2026-09-30 21:37:13 +02:00
pnpm-lock.yaml chore(deps): update dependencies within range 2026-09-30 19:27:37 +02:00
pnpm-workspace.yaml feat: replace zola site with vite single page 2026-08-15 03:17:49 +02:00
postcss.config.js feat: replace zola site with vite single page 2026-08-15 03:17:49 +02:00
README.md docs: fix manager repo, release steps and license in README and package.json 2026-09-30 21:37:13 +02:00
tsconfig.json feat: replace zola site with vite single page 2026-08-15 03:17:49 +02:00
vite.config.ts feat(seo): GTFS in the title, structured data, and a PNG social card 2026-09-27 01:19:38 +02:00

landing-zone

The gtfs.zone homepage. Deployed to https://gtfs.zone.

A scroll-driven single page: Vite, TypeScript, Tailwind v4, DaisyUI, and d3 for the scene geometry. No framework.

Commands

pnpm install
pnpm dev         # http://localhost:8080
pnpm build
pnpm typecheck
pnpm bake                          # re-bake public/data/network-night.json from MBTA
pnpm bake ./path/to/feed.zip
pnpm bake <source> --types=0,1     # keep only those GTFS route_types

The committed geometry is MBTA rapid transit (--types=0,1): 16 routes, 86 stations, 25 KB, with the agency's own route colors.

Themes

One page, two themes, switched by the moon toggle in the top right. The control is the same swap swap-rotate markup and the same theme-controller contract used by the editor and the visualizer, and it shares their theme localStorage key.

  • night dark, glowing strokes, continuous vehicles
  • light warm paper, hairlines, grid, snapping vehicles

Both themes draw the same real GTFS geometry, so the toggle changes how the site looks, never what it shows. The differences are exactly two things: the CSS token set (src/styles/tokens-*.css) and the VariantConfig in src/main.ts.

Scenes bake palette values into DOM attributes when they mount, so a theme change tears every scene down and remounts it (stopEngine() in src/engine/scene.ts). Window-level listeners are installed once and survive the swap.

The products

The page treats the first two as peers, and links both everywhere.

Tool URL Repo
Editor https://edit.gtfs.zone coloring-book
Visualizer https://viz.rt.gtfs.zone test-track
Manager https://manage.rt.gtfs.zone yard-master
Feed map https://list.gtfs.zone globe-of-contents

How it fits together

  • src/page.html is the body markup. A small Vite plugin inlines it into index.html.
  • The same plugin expands <!-- @feeds editor --> and <!-- @feeds visualizer --> from src/content/feeds.ts, so the editor chips and the visualizer chips are built from one feed list.
  • It then stamps target="_blank" rel="noopener noreferrer" onto every external anchor and fails the build if one escapes. Nobody has to remember the rule per-anchor.
  • src/content/links.ts is the canonical URL table. src/content/copy.ts holds the prose and imports its hrefs from there.
  • Motion is a pure function of scroll offset. Every scene's render(p) is idempotent and depends only on p. Time-based ambient motion uses p.elapsed and a deterministic seed.
  • One rAF loop drives everything (src/engine/ticker.ts). Offscreen scenes do not render. The background network is the one exception and always renders.

Sections and scenes

Section Scene
Hero hero-map (persistent background)
What is GTFS? none, text only
GTFS Schedule timetable
GTFS Realtime realtime-phone
The editor editor-tools, editor-cta
The visualizer visualizer-inspector
The manager alert-broadcast
Publish publish
Open source none, static SVG glyphs
Get in touch none

Releasing

Deploys are triggered by tags, not by pushes to main. Push to main freely; nothing ships until a tag exists.

cz bump          # updates package.json + CHANGELOG.md, commits, tags vX.Y.Z
git push origin main --tags
git push github main --tags

cz bump refuses to run off main. The v* tag fires .forgejo/workflows/build.yml, which typechecks, builds, pushes the image by digest and records that digest in deploy-gtfs-rt/sites/kustomization.yaml; ArgoCD rolls it out.

History

docs/VERIFICATION.md records what was checked against the deployed products.