Photo Metadata
Jacky's Photography keeps generated camera metadata in the builder manifest and keeps human-written copy in content/photo-descriptions.json. The sidecar file is merged into the manifest during pnpm run build:manifest, so editorial descriptions can improve search, alt text, detail pages, and social sharing without hand-editing generated manifest output.
Sidecar Shape
content/photo-descriptions.json is versioned JSON for editorial photo metadata. Each entry is matched by storage key, normalized without a leading photos/ prefix.
{
"version": 1,
"photos": [
{
"key": "随手/20260508120000.jpg",
"title": "Window Light",
"descriptions": {
"zh-CN": "一束光落在窗边,给日常留下安静的边缘。",
"en": "A quiet window-lit frame from an ordinary afternoon."
},
"tags": ["window", "light", "daily", "color"],
"aiContext": {
"currentTitle": "",
"dateTaken": "2026-05-08T12:00:00.000Z",
"camera": "FUJIFILM X-T5",
"lens": "FUJIFILM XF35mmF1.4 R",
"categoryTags": ["随手"]
}
}
]
}
Field behavior:
keyidentifies the photo by manifests3Keyafter path normalization.titlereplaces the generated title when it is non-empty.descriptions.zh-CNanddescriptions.enare the maintained localized descriptions.tagsare merged into generated tags while preserving order and removing duplicates.aiContextis helper context from the current manifest and is not merged into the public manifest.
The current editorial convention is to keep manual tags short and focused, usually no more than four tags per photo.
Sync Workflow
Run the builder first so apps/web/src/data/photos-manifest.json reflects the current photo set:
pnpm run build:manifest
Then sync the sidecar file:
pnpm run photos:descriptions:sync
The sync script reads apps/web/src/data/photos-manifest.json, creates missing sidecar entries, preserves existing title, descriptions, and tags, and refreshes aiContext from the latest manifest data. packages/data/src/photos-manifest.json is only a symlink to this generated file, so do not edit either manifest path by hand.
Use pruning only when old sidecar entries should be removed:
pnpm run photos:descriptions:sync -- --prune
After editing titles, descriptions, or tags, run the builder again:
pnpm run build:manifest
Manifest Merge
builder.config.ts registers plugins/builder/photo-descriptions.ts. The plugin runs before the manifest is saved:
- Missing
content/photo-descriptions.jsonis allowed; the build skips manual metadata. - Sidecar keys are normalized by removing leading slashes and an optional
photos/prefix. - Matching entries can update
title,descriptions, fallbackdescription, andtags. descriptionfalls back todescriptions["zh-CN"], thendescriptions.en.- Manual tags are appended after existing tags and deduplicated.
The public manifest therefore exposes both:
interface PhotoInfo {
description: string
descriptions?: Record<string, string>
}
description remains the compatibility field. descriptions is used by localized UI and SEO behavior.
Location Privacy
This site intentionally publishes the exact GPS coordinates stored in photo EXIF. Production builds emit those coordinates in the public, content-hashed full manifest, and the map downloads that manifest to place photos at their precise locations. Coordinates are not blurred or rounded; this is a deliberate publication policy for Jacky's Photography.
Deployers who do not accept that policy must add a builder-stage sanitizer that removes the complete GPS field set before the manifest is saved and before the web build runs. Disabling or hiding the map is not sufficient because the full manifest remains a directly downloadable public asset. After sanitizing, verify both the generated source manifest and the emitted assets/photos-manifest.<hash>.json before deployment.
Frontend Usage
The web app resolves descriptions through apps/web/src/lib/photo-description.ts:
- Chinese locales prefer the exact locale, then
zh-CN, thenen. - English locales prefer the exact locale, then
en, thenzh-CN. - Other locales try the exact locale, base language,
en, thenzh-CN. - Alt text falls back from localized description to title, then photo ID.
Current consumers include:
- masonry thumbnails and manifest cards through localized alt text
- command palette photo search across every available description
- photo detail route meta via
usePageMeta - map markers and cluster thumbnails through localized alt text
- static per-photo build output through
photo-page-meta
SEO Output
During production builds, apps/web/plugins/vite/photo-page-meta.ts reads the manifest and writes an HTML file for each photo at:
photos/<photo-id>/index.html
Each generated page keeps the SPA shell but replaces page metadata with photo-specific values:
<title>meta[name="description"]link[rel="canonical"]og:type,og:url,og:title,og:description,og:imagetwitter:url,twitter:title,twitter:description,twitter:image
The sitemap plugin also includes photo detail URLs, so the generated metadata is available to crawlers and social link unfurlers before the client app hydrates.
| Created At | |
| Last Modified |