A static photo gallery. Photos live in photos/originals/ (local only, gitignored). Running npm run photos:sync extracts EXIF, uploads to Cloudflare Images, and writes src/data/photos.json which the site renders at runtime.
- Enable Cloudflare Images on your Cloudflare account.
- In the Cloudflare Images dashboard, create three variants:
thumb— max 600w, fit: scale-downmedium— max 1600w, fit: scale-downfull— original, no transform
- Create a Cloudflare API token with scope Cloudflare Images: Edit.
- Copy
.env.exampleto.envand fill in:CLOUDFLARE_ACCOUNT_ID— from Cloudflare dashboard URLCLOUDFLARE_IMAGES_TOKEN— the API token from step 3VITE_CF_ACCOUNT_HASH— the hash inimagedelivery.net/<hash>/...URLs
- For Vercel deployment, add
VITE_CF_ACCOUNT_HASHto the project's build environment variables. - Node 20+ required.
- Drop photos into
photos/originals/(any of.jpg .jpeg .heic .png .webp). - Run
npm run photos:sync. The script uploads new photos, removes entries whose source files are gone (with confirmation), and updatessrc/data/photos.json. Commit the manifest. npm run devto preview locally.npm run buildto produce a static bundle.npm run typecheckto type-check without emitting.
npm run photos:sync -- --dry— show what would change, no API calls.npm run photos:sync -- --keep-orphans— don't prompt to delete manifest entries whose source files are missing (useful if you've moved the originals directory temporarily).