[FEAT] README hero screenshot generated from a seeded iOS simulator - #481
Merged
Merged
Conversation
Adds the platform-independent halves of the README hero screenshot pipeline: - `xtask screenshot-seed` fetches the CC0 photos pinned by SHA-256 in `xtask/screenshot/seed.toml` into a verified cache. It then normalizes each one (upright, long edge 2048 px, RGB ICC kept, EXIF reduced to a capture date) into a byte-reproducible seed set, and prints its digest. Capture dates are relative to an anchor day, so section headers read as recent dates of the current year. - `xtask screenshot-compose` keeps the capture's own screen mask, adds a soft drop shadow, pads onto a transparent canvas, and writes a deterministic PNG. `image` (jpeg + png only) is admitted as a build-tooling dependency; product media stays with Rawshift.
`mise run screenshot-ios` (macOS only) seeds the photos, builds the app,
and erases a dedicated "Capsule README" simulator (iPhone 17 Pro, newest
iOS 26.x). It then grants Photos access, imports the seed set, sets the
timeline to 3 columns, and pins the canonical 9:41 status bar. Light and
dark are each captured once the screen is stable, using Apple's alpha
screen mask, and composited into images/readme-hero-{light,dark}.png.
Each run starts from an erased simulator, so re-running is safe. Devices
left behind by an older runtime are deleted. On other hosts the task
fails with a message instead of skipping silently, because it is only
ever invoked explicitly.
A centred <picture> directly under the title shows the light or dark hero to match the reader's GitHub theme, at 360 px wide. The empty "Screenshots" TODO section is removed. The translated READMEs are regenerated to match, and each locale's translation data drops the orphaned heading. The images come from `mise run screenshot-ios`.
The <picture> at the top of each README references
images/readme-hero-{light,dark}.png, but the files were never
committed, so the hero rendered as a broken image. These are the
1536x2952 captures produced by `mise run screenshot-ios`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
This PR adds
mise run screenshot-ios, which generates the README hero image (a real screenshot of the iOS Library timeline, filled with a curated CC0 photo set). The README now leads with that image, centred under the title as a<picture>that serves the light or dark variant to match the reader's GitHub theme.Pipeline
xtask screenshot-seedruns anywhere and is unit-tested.curl. Each is verified against the SHA-256 pinned inxtask/screenshot/seed.tomland cached intarget/screenshot/cache/. The first run downloads about 335 MB; later runs use the cache.mise-tasks/screenshot-iosruns on macOS.Capsule READMEsimulator (iPhone 17 Pro, newest iOS 26.x).--mask=alphaonce two consecutive frames match.xtask screenshot-composeruns anywhere and is unit-tested. It keeps Apple's screen mask and the capture's colour profile, adds a soft drop shadow, and writes a deterministic PNG on a transparent canvas.Design decisions
<picture>.## ScreenshotsTODO section is removed.One deviation from the approved plan. Capture dates are stored as offsets from the run date, not as absolute timestamps. The app titles sections against the real clock ("Sat, September 12" in the current year; "September 12, 2025" otherwise), so absolute dates would drift into year-suffixed headers over time. The cost is that a run on a different day re-dates the headers. A future
--anchoris rejected, and a run in early January warns when some sections would carry a year suffix.Changed paths
xtask/src/screenshot.rs,xtask/src/screenshot/{manifest,seed,capture_exif,compose}.rsxtask/src/main.rstracing(stderr,RUST_LOG, defaultinfo)xtask/screenshot/seed.tomlxtask/Cargo.toml,Cargo.toml,Cargo.lockimage(jpeg and png only) as a workspace dependency; enablestoml_edit'sserdefeature; adds dev-dependencieskamadak-exifandtempfile; setsopt-level = 3forimage,zune-jpeg,pngandfdeflatein the dev profile. Lockfile changes only add packages; no existing package's version movescapsule-docs/.../design/dependencies.mdmise-tasks/screenshot-ioscapsule-swift/README.mdREADME.md,README.*.md(12)<picture>after the H1; Screenshots section removed; translations regeneratedxtask/translations/readme/*.json(12)Validation (Linux, at
747e4959)cargo nextest run -p xtask: 114 passed, including 32 new screenshot tests.mise run format-check-rust,lint-check-rust,architecture-check,license-check,translate-readme-check,i18n-check,i18n-guard,check-md: all pass. Clippy was also run pedantic over xtask's test targets: clean.shellcheck mise-tasks/screenshot-ios: clean. The script avoids bash-4-only syntax, since macOS ships bash 3.2.1a1e6544…71d17(anchor 2026-09-23). The run after the review fixes produced the same digest.mise run screenshot-iosexits 1 with a clear message, as designed.cargo deny check advisoriesreports 14 advisories. All are pre-existing and in crates this PR does not touch (libcrux, AES-GCM, h2, rustls via jsonwebtoken, proc-macro-error2); none of the added crates appears in any advisory tree. The advisory check is not part of the repo's gate map.CI at
747e4959Passed: Rust tests, all four Rust cross builds, iOS "Build & test Capsule.app" (macos-26), Markdown, Docs, Vision, and commit lint.
Failed, all pre-existing. The same
ci.ymljobs also fail onmasterat070e84d2(run 33572237092), each for an environment reason this PR does not touch:build-check-wasmthen fails because the runner lacks thewasm32-unknown-unknowntarget (E0463: can't find crate for core)bun install: "lockfile had changes, but lockfile is frozen". This PR changes no web filesCoverage gaps
xcodebuildproduct path, runtime and device-type resolution,simctl privacy/addmedia/status_bar/io --mask=alpha, and whethersimctl spawn … defaults write … -int 3reaches the app's defaults (if it doesn't, the grid stays at 5 columns).CurlFetcheris exercised only by the live run above; the cache logic around it is tested through a fake fetcher.Open questions for the reviewer
opt-level = 3overrides add some compile time tocheck-rustruns that build xtask. Is that acceptable?Related Issues
N/A
Contributor Checklist