Jacky's Photography

Jacky's Photography is a customized static photo gallery based on Afilmory. This repository contains the public source code for the React/Vite gallery, the photo-manifest builder, shared workspace packages, and this MDX documentation site published at docs.photo.jackyw.cn. The source photos live in the private Jackyhq/Photography-Photos repository and are checked out locally as photos/ only during builds.

Do not treat photos/ as reusable sample media. The originals, generated thumbnails, generated OG images, README preview image, and other media derived from Jackyhq's photos remain copyrighted personal works and are outside the open-source license.

What It Builds

The production output is a pure client-side SPA in apps/web/dist/. The site can run on static hosting because all photo data is generated before the frontend build.

The user-facing gallery includes:

  • responsive masonry browsing
  • WebGL photo viewing with DOM fallback
  • EXIF, histogram, camera, lens, GPS, HDR, Live Photo, and Fujifilm metadata
  • command palette search across titles, localized descriptions, tags, camera, and lens data
  • MapLibre location exploration for geotagged photos
  • localized alt text and photo descriptions
  • static per-photo HTML for /photos/:id
  • RSS, sitemap, PWA assets, and share metadata

Repository Layout

apps/web/                 # React 19 + Vite gallery SPA
packages/builder/         # Photo scanning, EXIF, thumbnails, manifest generation
packages/data/            # Runtime data loader and manifest symlink export
packages/docs/            # This Vite + React + MDX documentation site
packages/hooks/           # Shared React hooks
packages/sdk/             # Shared schemas/client helpers
packages/ui/              # Shared UI primitives
packages/utils/           # Shared utilities, RSS helpers, storage helpers
packages/webgl-viewer/    # WebGL image viewer
plugins/                  # Builder, ESLint, and Vite plugins
scripts/                  # Photo, docs, OG, favicon, and maintenance scripts
photos/                   # Local private photo checkout, ignored by Git

There is no packages/components/ package. App-specific UI should stay in apps/web/src; only broadly reusable primitives belong in packages/ui.

Manifest Flow

The builder writes the generated manifest to:

apps/web/src/data/photos-manifest.json

That file is ignored by Git. packages/data/src/photos-manifest.json is a tracked symlink to the generated file, so @afilmory/data and Vite build plugins read the same manifest without duplicating data.

The normal flow is:

  1. Check out Jackyhq/Photography-Photos into ./photos.
  2. Run pnpm run photos:standardize to rename and move incoming files.
  3. Run pnpm run build:manifest to scan photos, extract metadata, generate thumbnails, and write the manifest.
  4. Build the web app with pnpm build.
  5. Deploy apps/web/dist/.

Current Configuration

builder.config.ts uses the local storage provider against the private checkout:

import { defineBuilderConfig } from '@afilmory/builder'

export default defineBuilderConfig(() => ({
  storage: {
    provider: 'local',
    basePath: './photos',
    baseUrl: 'https://photos3.jackyw.cn/photos/',
    excludeRegex: '^incoming($|/.*)',
  },
  plugins: [new URL('plugins/builder/photo-descriptions.ts', import.meta.url).href],
}))

The photo-descriptions plugin merges human-written titles, zh-CN/en descriptions, and editorial tags from photo-descriptions.json.

Common Commands

pnpm dev
pnpm build
pnpm docs:dev
pnpm docs:build
pnpm run photos:standardize
pnpm run build:manifest
pnpm run photos:descriptions:sync
pnpm run lint:check
pnpm --filter web type-check
pnpm test
pnpm run test:e2e

pnpm dev and pnpm build run the web precheck, which calls the builder CLI before Vite starts or builds. CI can set AFILMORY_SKIP_MANIFEST_PRECHECK=true after an explicit manifest build to avoid doing the same work twice.

Deployment Summary

The GitHub Actions workflow checks out the private photo repository, rejects symlinks in that checkout, installs dependencies, runs linting, type checking, unit tests, photo standardization, manifest generation, web build, bundle budget checks, and Playwright E2E tests.

Non-PR deployments also commit standardized photo changes back to the private photo repository, sync published photos to Cloudflare R2 under the photos/ prefix, mirror apps/web/dist/ into Jackyhq/Photography-Web, and deploy the same output to GitHub Pages.

For manual metadata curation, see Photo Metadata. For loading and build performance details, see Performance. For storage-provider options, see Storage Providers.

Maintenance Notes

  • Do not hand-edit generated outputs such as apps/web/dist/, apps/web/public/thumbnails/, and apps/web/src/data/photos-manifest.json.
  • Keep .specstory/history/, .DS_Store, local dist/, and tool logs out of Git.
  • Keep docs lastModified values current when editing files under packages/docs/contents/.
  • Prefer existing workspace packages and local helper APIs over duplicate utilities.

License

Code is licensed under the repository license. Photo media and generated media derivatives remain copyrighted works owned by Jackyhq.

Created At
Last Modified