This guide documents the maintainer workflow for importing documentation screenshots into the managed screenshot library under src/content/docs/img/screenshots/.
Use npm run screenshots:scan-metadata when you want to:
- recursively inventory a screenshot folder without moving files
- capture width, height, timestamps, size, extension, and MIME type in a stable JSON report
- preflight a batch before running the heavier
screenshots:syncimport path - diagnose whether a staging batch contains corrupted or unsupported image files
Use this workflow when you want to:
- import an existing docs screenshot into the managed screenshot library
- generate
metadata.jsonwith ImgBin analysis results - rebuild
src/content/docs/img/screenshots/manifest.json - switch Markdown or MDX content to use managed screenshot paths
In short:
screenshots:scan-metadata= read-only inventory and progress-visible preflightscreenshots:sync= managed import, analysis, manifest rebuild, and staging cleanup
The screenshot-management-optimization change uses this existing workflow to absorb legacy screenshots into src/content/docs/img/screenshots/.
- In scope for this backlog pass:
quick-start/create-project(6screenshots)quick-start/create-proposal-session(26screenshots)installation/install-desktop(14screenshots, including1currently unreferenced legacy file)ai-compose-commit(3screenshots)monospecs(3screenshots)
- Affected docs pages to re-check after sync:
src/content/docs/quick-start/create-first-project.mdxsrc/content/docs/quick-start/proposal-session.mdxsrc/content/docs/installation/desktop.mdxsrc/content/docs/guides/ai-compose-commit.mdxsrc/content/docs/guides/monospecs.mdxsrc/content/docs/en/quick-start/create-first-project.mdxsrc/content/docs/en/quick-start/proposal-session.mdxsrc/content/docs/en/installation/desktop.mdxsrc/content/docs/en/guides/ai-compose-commit.mdx
- Known exception recorded during inventory:
- Historical inventory found one missing legacy source,
img/ai-compose-commit/✓ 处理完成.png;src/content/docs/en/guides/ai-compose-commit.mdxwas switched to text-only confirmation instead of keeping a broken image reference
- Historical inventory found one missing legacy source,
- Explicitly out of scope for this backlog pass:
src/content/docs/img/product-overview/**illustrations, which are managed as static documentation artwork rather than screenshot assets
This change does not introduce a new import script, a new metadata rule, or a parallel migration process. It only reuses the current staging/import/review flow documented on this page.
Current execution result for screenshot-management-optimization:
71legacy screenshots were imported or refreshed intosrc/content/docs/img/screenshots/13Markdown or MDX pages were updated to use managed screenshot pathssrc/content/docs/img/screenshots/manifest.jsonnow contains71published screenshot entries- All checked
metadata.jsonfiles currently reportstatus.recognition = succeeded
Remaining follow-up items after this backlog pass:
src/content/docs/img/product-overview/**illustrations still use legacy paths by design and remain outside the managed screenshot workflowsrc/content/docs/img/installation/install-desktop/向导01-04,选择配置好的AgentCLI.pngis now preserved as a managed asset for historical completeness, but there is still no active page reference pointing to it
- Run commands from
repos/docs - Ensure
@hagicode/imgbinis installed inrepos/docs(recommended), orrepos/imgbin/dist/cli.jsexists as a fallback - Ensure the
codexCLI is installed and available inPATH - Ensure
repos/docs/.envcontains valid analysis settings - Ensure the checked-in ImgBin analysis context file exists at
repos/docs/prompts/screenshot-analysis-context.txt, unless you plan to override it explicitly
Recommended repos/docs/.env keys:
IMGBIN_ANALYSIS_PROVIDER=codex
IMGBIN_CODEX_MODEL=lemon/gpt-5.4
IMGBIN_CODEX_BASE_URL=http://localhost:36129/v1
IMGBIN_ANALYSIS_TIMEOUT_MS=180000
SCREENSHOT_ANALYSIS_CONTEXT_FILE=./prompts/screenshot-analysis-context.txtscreenshots:sync always resolves an analysis context file before it launches ImgBin recognition. The precedence is deterministic:
--analysis-context-file <path>SCREENSHOT_ANALYSIS_CONTEXT_FILE- the checked-in default
./prompts/screenshot-analysis-context.txt
The command validates the resolved file before any import or refresh work begins. If the file is missing or empty after trimming whitespace, the run fails immediately instead of letting ImgBin fail later in the batch.
Keep the context file focused on durable screenshot semantics:
- common docs screenshot domains such as installation, settings, sessions, project setup, confirmations, and editor-like panels
- bilingual UI clues that remain stable across many screenshots
- evidence-first instructions that tell recognition to trust visible pixels over assumptions
Do not put one-off guidance into the shared context file:
- ticket-specific debugging notes
- temporary campaign wording or branch-specific UI guesses
- assumptions that only apply to one screenshot batch
- model-specific hacks that are likely to become stale
Put screenshots into a staging tree that mirrors the intended docs category:
repos/docs/
├── screenshot-staging/
│ └── quick-start/
│ └── create-project/
│ └── step1-click-new-project-button.png
└── src/content/docs/img/screenshots/
└── quick-start/
└── create-project/
└── step1-click-new-project-button/
├── original.png
└── metadata.json
Generated manifest:
src/content/docs/img/screenshots/manifest.json
Keep screenshot-staging/.gitkeep committed so the default staging directory exists even when the queue is empty.
Run this before sync when you only need a quick inventory or when you want to confirm the batch is healthy before ImgBin analysis:
npm run screenshots:scan-metadata -- --input ./screenshot-staging --output ./artifacts/screenshot-report.jsonReport shape:
{
"summary": {
"generatedAt": "2026-03-14T09:30:00.000Z",
"inputDirectory": "screenshot-staging",
"outputPath": "artifacts/screenshot-report.json",
"supportedExtensions": [".jpg", ".jpeg", ".png", ".webp"],
"scannedFileCount": 3,
"successCount": 3,
"failureCount": 0
},
"entries": [
{
"relativePath": "ai-compose-commit/trigger-button.png",
"fileName": "trigger-button.png",
"extension": ".png",
"mimeType": "image/png",
"sizeBytes": 290816,
"createdAt": "2026-03-14T09:00:00.000Z",
"modifiedAt": "2026-03-14T09:00:00.000Z",
"width": 1440,
"height": 900
}
],
"failures": []
}Expected progress log example:
[screenshots:scan-metadata] starting scan
[screenshots:scan-metadata] input: ./screenshot-staging
[screenshots:scan-metadata] discovered 3 supported screenshot files
[screenshots:scan-metadata] [1/3] scanning ai-compose-commit/trigger-button.png
[screenshots:scan-metadata] [1/3] ok 1440x900 284 KB
[screenshots:scan-metadata] [2/3] scanning ai-compose-commit/confirm-dialog.png
[screenshots:scan-metadata] [2/3] ok 1440x900 301 KB
[screenshots:scan-metadata] [3/3] scanning monospecs/select-repository.png
[screenshots:scan-metadata] [3/3] ok 1728x1117 512 KB
[screenshots:scan-metadata] wrote report to ./artifacts/screenshot-report.json
[screenshots:scan-metadata] completed: 3 succeeded, 0 failed
If repos/docs/.env is configured, the sync command now loads it automatically and creates a workspace-local .tmp directory when TMPDIR, TMP, and TEMP are not already set:
npm run screenshots:syncThe command resolves ImgBin in this order:
--imgbinIMGBIN_EXECUTABLEfromrepos/docs/.envor the shell- installed
repos/docs/node_modules/@hagicode/imgbin - fallback
../imgbin/dist/cli.js
The command resolves the analysis context in this order:
--analysis-context-fileSCREENSHOT_ANALYSIS_CONTEXT_FILE./prompts/screenshot-analysis-context.txt
At startup, screenshots:sync prints the resolved analysis context file so CI logs can confirm which file was actually used.
After a successful sync, the docs screenshot library also refreshes its ImgBin search index so future imgbin search runs can immediately match recognized titles, tags, descriptions, and imported source paths.
After screenshot files are imported, the repository-level Compress images GitHub Actions workflow may further optimize supported bitmap files on commit.
- Target formats:
png,jpg,jpeg,webp - Typical affected paths:
src/content/docs/img/**, includingsrc/content/docs/img/screenshots/** - Out of scope for the workflow:
metadata.json,manifest.json, prompt files, slug directories, and other non-bitmap assets
This follow-up compression does not replace the responsibilities of screenshots:sync. Maintainers still need screenshots:sync to:
- create or refresh managed screenshot directories
- generate
metadata.json - rebuild
src/content/docs/img/screenshots/manifest.json - preserve the slug and category layout used by docs references
In other words, screenshots:sync manages screenshot identity and metadata, while the repository workflow may only shrink the binary image payload afterward.
- Copy the screenshot into
screenshot-staging/<category>/... - Change directory to
repos/docs - Run the recommended command
- Verify the managed asset directory was created
- Verify
metadata.jsonandmanifest.json - Confirm the successfully processed staging file was removed
- Update docs content to reference the managed screenshot path
When a screenshot batch is already imported, treat the checked-in metadata as the primary source for page planning instead of re-reading the image manually every time.
- Find the candidate assets in
src/content/docs/img/screenshots/manifest.jsonor the nearbymetadata.jsonfiles. - Record a route plan before writing prose:
- Chinese route, for example
/adventure-team-introduction - English mirror route, for example
/en/adventure-team-introduction - section name that owns each screenshot
- Chinese route, for example
- Write the MDX page with the managed screenshot path, usually
.../original.png. - Keep the screenshot-to-section mapping in maintainer notes, change artifacts, or planning docs instead of the published page when the public docs should stay reader-focused.
- Add related links only after the page body is stable, so navigation changes stay minimal and reviewable.
Each screenshot-backed feature doc should still preserve the same five mapping fields somewhere reviewable for maintainers, even if they do not appear in the published page:
slugtitlerelativeSourcePathsectionroute
These fields are enough for a maintainer to jump from a rendered page back to:
- the managed asset directory under
src/content/docs/img/screenshots/** - the checked-in
metadata.json - the original staging filename recorded by
relativeSourcePath
Use checked-in metadata first. Fall back to existing ImgBin search results only when one of these is true:
- the screenshot title is too generic to decide which page owns it
- multiple screenshots appear to describe the same feature and you need extra semantic clues
- a maintainer is triaging a screenshot that has not been wired into docs yet
If you use ImgBin search as a fallback, copy the conclusion back into planning notes, the related OpenSpec change, or another checked-in maintainer artifact so the next maintainer does not need to repeat the search.
Before writing, create a small inventory like this in your notes or change proposal:
slug |
Intended page | section |
Why |
|---|---|---|---|
screenshot-a1e8035a |
/adventure-team-introduction |
成员与编组面板 |
Hero roster grid and loadout details explain the roster workspace |
screenshot-11d59f8f |
/adventure-team-introduction |
协作流程与副本推进 |
Dungeon proposal cards and roster editor show the team workflow |
guide1-language |
/quick-start/wizard-setup |
步骤 1:语言 |
Language settings and sidebar progress anchor the first wizard step |
This keeps feature pages bilingual, screenshot-backed, and easy to maintain when metadata changes later.
When processing a large legacy backlog, split the work into small, reviewable batches instead of staging every file at once.
Recommended batches for this repository:
quick-start/create-projectquick-start/create-proposal-sessioninstallation/install-desktopai-compose-commit+monospecs
For each batch:
- Copy only that batch into
screenshot-staging/ - Run the recommended sync command
- Review the generated or refreshed
metadata.jsonfiles - Confirm
src/content/docs/img/screenshots/manifest.jsonincludes the successful items - Update the affected Markdown or MDX references before moving to the next batch
This makes it easier to isolate failures, retry only the relevant files, and confirm page-level rendering before the next batch starts.
Source screenshot:
src/content/docs/img/quick-start/create-project/step1-click-new-project-button.png
Stage the file:
mkdir -p screenshot-staging/quick-start/create-project
cp src/content/docs/img/quick-start/create-project/step1-click-new-project-button.png \
screenshot-staging/quick-start/create-project/Run the import:
npm run screenshots:syncExpected CLI output:
Scanned 1 staged screenshot.
Per-file results:
- ✓ quick-start/create-project/step1-click-new-project-button.png [quick-start/create-project/step1-click-new-project-button]: imported -> src/content/docs/img/screenshots/quick-start/create-project/step1-click-new-project-button
Manifest entries: N
Completed without failures.
Verify these files exist:
src/content/docs/img/screenshots/<category>/<slug>/original.pngsrc/content/docs/img/screenshots/<category>/<slug>/metadata.jsonsrc/content/docs/img/screenshots/manifest.json
After a successful import or refresh:
- the processed screenshot file is removed from
screenshot-staging/... - failed screenshots remain in staging so they can be retried later
Manifest entries expose a static image path like:
img/screenshots/quick-start/create-project/step1-click-new-project-button/original.png
From a docs file such as src/content/docs/quick-start/create-first-project.mdx, the Markdown relative path is:
The helper at src/utils/screenshot-manifest.js can also resolve manifest entries into Markdown-ready paths.
Check these fields in metadata.json:
titledescriptiontagsstatus.recognitionpaths.originalextra.docsScreenshot.categoryextra.docsScreenshot.relativeSourcePath
status.recognition must be succeeded for the screenshot to appear in the generated manifest.
For backlog processing, also verify:
extra.docsScreenshot.categoryextra.docsScreenshot.categorySegmentsextra.docsScreenshot.relativeSourcePathextra.docsScreenshot.duplicateStrategy
Re-running the workflow for the same category and slug will:
- reuse the existing managed directory
- refresh
original.*andmetadata.json - remove the newly staged source file after a successful refresh
- avoid creating uncontrolled duplicate directories
Expected summary text for a rerun:
refreshed-existing
This is the expected path when legacy screenshots were already imported once and you need to refresh the original image, metadata, or manifest entry.
Show help:
npm run screenshots:sync -- --helpPreview without writing:
npm run screenshots:sync -- --dry-runScan metadata only:
npm run screenshots:scan-metadata -- --input ./screenshot-staging --output ./artifacts/screenshot-report.jsonForce one category:
npm run screenshots:sync -- --category quick-startReindex after import:
npm run screenshots:sync -- --reindexOverride the analysis context for one run:
npm run screenshots:sync -- --analysis-context-file ./prompts/experimental-context.txtIncrease the timeout in repos/docs/.env or your shell environment:
IMGBIN_ANALYSIS_TIMEOUT_MS=180000Verify:
../imgbin/dist/cli.jsexists- or
@hagicode/imgbinis installed inrepos/docs - or
IMGBIN_EXECUTABLEpoints to a valid executable
Verify:
repos/docs/prompts/screenshot-analysis-context.txtexists and is not blank- or
SCREENSHOT_ANALYSIS_CONTEXT_FILEpoints to a real non-empty file - or your
--analysis-context-fileoverride path is correct
If this is a one-off batch, prefer a CLI override. If the missing file should be the repository default, restore or fix repos/docs/prompts/screenshot-analysis-context.txt so CI and local runs stay aligned.
Verify repos/docs/.env contains:
IMGBIN_ANALYSIS_PROVIDER=codexIMGBIN_CODEX_MODEL=lemon/gpt-5.4IMGBIN_CODEX_BASE_URL=http://localhost:36129/v1
The sync command now auto-creates .tmp and exports TMPDIR / TMP / TEMP to that workspace-local directory by default. If you still need to override it, set one of these values in repos/docs/.env or your shell:
TMPDIR=/custom/workspace/tmpCheck metadata.json:
status.recognitionmust besucceeded
Failed recognition results do not enter the manifest.
This usually means the sync command has moved into ImgBin analysis, import, or another batch step that does not emit per-file logs as frequently as the lightweight scanner.
Use this preflight path first:
- Run
npm run screenshots:scan-metadata -- --input ./screenshot-staging --output ./artifacts/screenshot-report.json - Confirm the scan reports the expected file count, dimensions, and timestamps
- Fix any corrupted files reported in
failuresbefore retryingscreenshots:sync - Re-run
screenshots:synconly after the scan output looks healthy
The metadata scan command is intentionally the faster, more observable command for confirming that the batch itself is sane; the sync command still owns managed import, AI analysis, and manifest rebuild.
Also check the startup line that reports analysis context:. If it points at the wrong file, fix the CLI flag or environment override before retrying.
Use the existing retry path instead of inventing a parallel fix:
- Leave the failed file in
screenshot-staging/if the sync command already preserved it - Review the partial managed asset directory if one was created
- Re-run the same batch after correcting the source image or environment issue
- If the source file itself is missing, record the affected docs page and leave it for manual follow-up
Do not change the workflow rules just to handle one backlog item. This change is specifically about replaying the current process against old screenshots.
- Match staging categories to docs sections when possible
- Use step-oriented filenames such as
step1-click-new-project-button.png - Review generated
title,alt, andtagsbefore updating docs references - Prefer managed screenshot paths over direct legacy
img/...paths for newly processed assets - During backlog cleanup, keep a short written note of processed batches, pages updated, and any remaining missing source files
Validated in this repository:
- first-time import of real docs screenshots
- rerun refresh of existing managed screenshots
- manifest generation
- Markdown path resolution through the manifest helper
Current limitation:
- if you override the temp directory, it still needs to live on a filesystem that permits the import move/rename flow