Skip to main content

argent-screenshot-diff

Capture stable before/after screenshots on an iOS simulator or Android emulator and pixel-diff them into evidence. Use when asked for a visual regression check, a screenshot diff, a before/after visual comparison, or when a visible mobile UI change needs pixel proof — including the executed screenshot-diff that a Tamagui conversion batch requires.

설치로 이동

소스 정보

저장소
Uniswap/interface
최근 소스 활동
2026년 9월 23일 19:07
감지된 SKILL.md 언어
영어
스타
5,529
포크
5,355

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
argent-screenshot-diff
description
Capture stable before/after screenshots on an iOS simulator or Android emulator and pixel-diff them into evidence. Use when asked for a visual regression check, a screenshot diff, a before/after visual comparison, or when a visible mobile UI change needs pixel proof — including the executed screenshot-diff that a Tamagui conversion batch requires.
## 1. Use the first-party `screenshot-diff` tool `screenshot-diff` is a real first-party argent MCP tool, and it is the preferred path for every diff in this skill. Hand-rolling a pixel diff is the fallback (§ 5), not the default. | Parameter | Required | Notes | | --- | --- | --- | | `udid` | **yes** | iOS UUID or Android adb serial, same as every other argent tool | | `outputDir` | **yes** | Where the diff artifacts are written | | `baselinePath`, `currentPath` | mode A | Two PNGs you already saved to disk | | `captureBaseline`, `captureCurrent` | mode B | The tool captures live from the device instead | | `rotation` | no | The same rotation parameter `screenshot` takes | Supply **either** the saved-PNG pair **or** the live-capture flags — the two modes are alternatives, not additions. Returns `{ summary, diffPath, contextDiffPath }`: the comparison summary plus two written artifacts, the diff image and a context diff. **It excludes the fixed status-bar band from both the pixel and the OCR comparison.** That alone is reason to prefer it over anything hand-rolled. The clock, battery percentage and signal indicators differ between any two captures taken seconds apart, and on a full-screen mobile capture they are the single most common source of false positives. With this tool you neither crop them out nor explain them away in review. **Load the schema before your first call** — deferred tools in this environment expose only their name until you load them. ToolSearch for `screenshot-diff`, read the parameter names and return shape off the schema, and use those. The table above was transcribed from a session with the argent server connected rather than verified in the session that wrote this skill, so treat the loaded schema as the authority wherever the two disagree. **Never invent a tool signature.** If ToolSearch cannot load it, the tool is not available to your session — take the § 5 fallback and say so in your report. --- ## 2. Prerequisites and their limits From `apps/mobile/CLAUDE.md`: ```bash bun add -g @swmansion/argent # one-time per machine; puts `argent` on PATH ``` - **Argent does not build or install the app for you** — it drives whatever is already on the sim. Get the build you intend to compare installed and running first via `argent-react-native-app-workflow`. - **Argent owns the simulator.** Do not mix `xcrun simctl install/launch/terminate` with argent calls — sim state corruption is real, and a corrupted sim silently poisons a diff. - **Do not run `argent init`** — skills and config are already committed. `argent update` only when intentionally refreshing. - **Android**: run `adb -s <serial> reverse tcp:8081 tcp:8081` before the app starts, or Metro is unreachable and you will capture a red screen. - **At session end**: call `stop-all-simulator-servers`. Get a `udid` per `argent-ios-simulator-setup` (iOS, UUID-shaped) or `argent-android-emulator-setup` (Android, adb serial). Tool names are identical on both platforms. --- ## 3. The headless constraint — state it, do not paper over it **A headless or CI agent session cannot drive a local simulator or emulator.** There is no sim to attach to, no Xcode/`xctrace`, no emulator, and no display. This was the blocking finding on INFRA-3096 and it has not changed. Everything below is the **argent-driven local-device path**, and that path needs a **locally attached simulator, emulator, or device** in a session running on a developer machine: argent's MCP server drives a local sim/emulator or an attached device, and a headless session has no argent binary, no argent MCP server, and no device. If you are headless, do **not** stage a diff and imply it ran. `tamagui-conversion` is explicit: *a staged-but-unrun diff is not evidence.* Instead do one of: 1. **Hand off.** Stage the comparison surface (§ 4), commit it, and write the exact runnable steps — udid selection, story names, `scale: 1.0`, the `screenshot-diff` call and its `outputDir`, and the state matrix — into the Linear issue and PR body so a human-run session executes it verbatim. 2. **Record the obligation.** Comment on the issue that the executed diff is outstanding, with the commit the diff must be run against. An unmet obligation on the record beats a fabricated verdict. 3. **Substitute, with sign-off.** If no legacy twin exists there is nothing to diff at all — substitute self-contained behavioral tests plus **explicit requester sign-off** (the `tamagui-conversion` rule). ### Remote devices — the blockers above are narrower than "you need a developer machine" Those blockers are about driving **argent**. They are not a claim that on-device visual evidence is impossible without a local simulator. **AWS Device Farm runs real remote devices and needs no local sim and no macOS host**, so it is a plausible route to the underlying evidence goal — before/after captures from a real device, taken to a pixel diff. What that route carries: - **Whether argent can target a Device Farm device is untested.** Do not claim it can and do not claim it cannot; if you need argent specifically, treat it as an open question to verify. - **The build must embed a dev-mode bundle**, because Storybook is `__DEV__`-only (§ 8) — a bundled production build cannot show the staged stories at all. - **Android-only absent a macOS host**, since an iOS build needs one. **The INFRA-3096 "declined" note is narrower than it reads.** A Device Farm pass was declined there — but on a batch with **zero converted files**, where the objection was to diffing a batch in which nothing had changed ("staged evidence with extra steps"), not to Device Farm as a capture mechanism. That is a reading of INFRA-3096 comment `fe4db9f3`; check it yourself before citing it either way. Whichever capture route you use, "executed, never staged" is unchanged — the diff must actually run, against changed code. --- ## 4. Staging the comparison — the canonical pattern The repo practice this skill formalizes: put both sides in **one Storybook file** rendering the **identical state matrix at identical screen positions**, so a diff of the two stories measures nothing but the component. Pattern files: - `apps/mobile/src/components/mycelium/SegmentedControlMigration.stories.tsx` (#37202) — the template. `Legacy` and `Rebuilt` stories render the exact same matrix at the exact same positions; `SideBySide` stacks both per state for eyeballing. - `apps/mobile/src/components/mycelium/ShimmerMigration.stories.tsx` — carries a hard-won caveat. Rules that fall out of those two files: | Case | Stage it as | Why | | --- | --- | --- | | Static states | Standalone `Legacy` + `Rebuilt` stories, identical positions | Diffable pair, nothing else varies | | **Animated** states | `SideBySide`, both mounts **simultaneous** | Separate mounts start their animation clocks at different times — an out-of-phase row looks frozen or broken when both implementations are correct. Phase-lock or do not diff. | | No legacy twin | Not diffable at all | Behavioral tests + requester sign-off instead | Identical positions is not a nicety. Any offset makes the whole panel differ and the diff is worthless. --- ## 5. Capture and diff — the procedure Get a `udid` from `list-devices`, stage both sides per § 4, and settle per § 6. Then: 1. Navigate to the `Legacy` story. Settle, then `screenshot` with **`scale: 1.0`**, persisted to disk. 2. Navigate to `Rebuilt` — same route, same scroll offset, no device rotation between captures. 3. Settle, then `screenshot` with `scale: 1.0`, persisted to disk. 4. Call `screenshot-diff` with `udid`, an `outputDir`, and the two files as `baselinePath` / `currentPath`. 5. Read `summary`, then open `diffPath` and `contextDiffPath` and actually look at them (§ 7). ### `scale: 1.0` is mandatory for anything you feed to a diff `screenshot` **downscales to 30% of native resolution by default** to save context (`argent-device-interact` § 7). `scale` accepts `0.01`–`1.0`. > A 30% capture has thrown away the pixels you are measuring: it invents resampling differences that read as regressions, and it hides real one-pixel border and anti-aliasing shifts. A diff run at the default scale is not evidence. ```json { "udid": "<UDID>", "scale": 1.0 } ``` If `screenshot` returns an inline image rather than a file path, you need the bytes on disk before `baselinePath` / `currentPath` will accept them. **Load the tool's schema with ToolSearch and read its actual return shape** — do not assume either form. ### The live-capture mode `captureBaseline` / `captureCurrent` (§ 1) let `screenshot-diff` take the shots itself instead of you saving PNGs. Read the schema for how the two are sequenced before relying on it: the staged-story pattern in § 4 requires **navigating between the two captures**, and a before/after across a code change requires a rebuild between them. Prefer the saved-PNG pair whenever anything has to happen in between. ### Fallback — only when `screenshot-diff` will not load For a session with no argent MCP server connected, or an argent version predating the tool. Capture the pair exactly as above, then diff the PNGs yourself: `labs/workbench` already carries the engine as devDeps (`pixelmatch` 7.2.0, `pngjs` 7.0.0), and `labs/workbench/scripts/visual/compare.ts` is a working reference for the pixelmatch call, padding, and flag arithmetic — reuse it rather than reaching for a new dependency. You then own the two jobs the first-party tool does for you: masking the status-bar band, and picking thresholds (§ 7). --- ## 6. Determinism — eliminate false positives before you diff A flaky diff is worse than no diff: it trains reviewers to ignore the artifact. Fix all of these before capturing. - **Kill animation.** Disable animations in the app, or use a `SideBySide` phase-locked mount for anything that moves. Never diff a mid-transition frame. - **Pin the device.** Same simulator model **and** same OS version for before and after. A different sim is a different renderer. - **Pin the position.** Identical scroll offset, orientation, and safe-area insets. Do not rotate between captures. - **Settle before capture.** Wait for the screen to be static — no spinner, no skeleton, no in-flight image load. If the returned screenshot shows a transitional frame, retake with `screenshot` (the `argent-test-ui-flow` recovery pattern). - **Same content.** No live data, no timestamps, no randomized ordering, no avatar that loads from the network. - **Same theme.** Diff light against light and dark against dark, as separate pairs. --- ## 7. Reading the result ### With `screenshot-diff` (the primary path) `summary` is the judgement surface; `diffPath` and `contextDiffPath` are the artifacts. - **Read `summary`, then corroborate it against the images.** A summary you did not check against the diff image is a claim, not a verdict. - **The contract in § 1 exposes no threshold, sensitivity, or flagging parameter** — so there is nothing to tune, and this skill will not recommend a number for it. Do not invent one. If the schema you load exposes a knob § 1 does not list, use it and record the value you passed. - **Calibrate with a no-change control pair.** Capture the same story twice with nothing changed and diff it. Whatever the tool reports on that pair is the floor for this device, this OS version, this screen — a real pair must clear it visibly. With no tunable threshold, this control is the calibration. - **Status-bar drift is already excluded** (§ 1), so anything reported is real content, not a clock tick. **How the harness numbers below translate: they mostly do not.** Stated plainly so nobody tries to reconcile them: | Harness concept | Counterpart in `screenshot-diff` | | --- | --- | | `--pixel-threshold` (per-pixel color sensitivity) | **None exposed.** The tool decides its own sensitivity | | `--flag-ratio` (`diffPixels / totalPixels`) | **None exposed.** The tool does not take a flagging rule from you | | `--min-diff-pixels` (absolute floor) | **None exposed** | | Manual status-bar masking | **Built in** — excluded from pixel *and* OCR comparison | | Diff PNG output | `diffPath`, plus `contextDiffPath` | | Flag verdict computed by you | `summary`, computed by the tool | Three of the harness's four knobs have no counterpart. That is not a gap to paper over with an invented mapping — it means the judgement moves from *choosing numbers* to *reading `summary` against a control pair and looking at the diff image*. ### Fallback thresholds — hand-rolled `pixelmatch` only Everything below applies to the § 5 fallback, not to `screenshot-diff`. **Established precedent** — `labs/workbench/scripts/visual/README.md`, the web harness. A pair is flagged when **both** conditions hold: ``` diffPixels / totalPixels > 0.005 # relative ratio (--flag-ratio) AND diffPixels > 250 # absolute floor (--min-diff-pixels) ``` with a per-pixel color sensitivity of `0.1` (`--pixel-threshold`, passed to pixelmatch). **Why two conditions, so you can adapt rather than cargo-cult:** the ratio alone over-fires on small panels. On a ~6–10k-pixel panel, sub-perceptual anti-aliasing noise (the harness's documented case: translucent-token compositing rendering text a few 8-bit steps apart) is ~120–180 px — under 250 absolute, but *over* 0.005 relative. The absolute floor absorbs exactly that. Meanwhile a genuinely broken color repaints most of a panel at high delta and trips both conditions comfortably. The two-condition rule buys you a wide, empty band between noise and real breakage. **Starting recommendations for mobile** (mine, not established — tune and record what you used): - Keep `pixel-threshold` at `0.1`. It is the sensitivity that was validated against real token-compositing noise, and it is platform-independent. - Keep the `0.005` ratio. - **Raise the absolute floor** above 250. Mobile captures at `scale: 1.0` are far larger than a workbench panel, and native text rasterization is noisier than Chromium's — 250 px will fire on nothing. Scale the floor with panel area: the web value is ~2.5–4% of a 6–10k-px panel, so start there and calibrate against a **no-change control pair** (capture the same story twice, unchanged; that number is your noise floor, and your threshold goes above it). - Any pair you had to raise a threshold to pass is **not** green — investigate it. Record what you ran alongside the verdict — `screenshot-diff` and which mode, or the fallback and its thresholds. A verdict without its mechanism is unreproducible. --- ## 8. The Storybook tension — real, and reconcilable This diff practice needs **Storybook**. But `apps/mobile/CLAUDE.md` mandates `NODE_ENV=production` for agent/CLI Metro precisely *because* dev-mode bundles Storybook and the app boots into Storybook UI, "breaking agent-driven interaction flows": ```bash bun nx run mobile:start:production # the normal agent default — Storybook OFF ``` Both are correct; they are different jobs. Reconcile by **choosing the mode for the task, deliberately and out loud**: | Task | Metro mode | Storybook | | --- | --- | --- | | Driving real app screens, flows, QA, profiling | `mobile:start:production` | off (required) | | **Screenshot-diffing a staged story matrix** | dev Metro (`NODE_ENV` unset) | on (required) | So: a screenshot-diff session runs dev Metro *on purpose*, and booting into Storybook UI is the desired outcome, not the failure the CLAUDE.md rule warns about. Consequences to hold onto: - **Do not do both in one Metro session.** Finish the diff, then restart Metro in production mode before any app-flow work — and say in your report which mode each artifact came from. - `NODE_ENV` applies at **JS-bundle time**. For a device build with no Metro dev server the flag goes on the build command, so a bundled production build cannot show Storybook at all — what you need is a **dev-mode bundle**, and how you get one depends on the route (§ 3): dev Metro against a local simulator, or a dev-mode-bundled build on a remote device. - A reviewer seeing Storybook chrome in your evidence should not read it as a broken setup. Label the captures as Storybook stories. --- ## 9. Recording the evidence An executed diff is only evidence once it is **on the record**. Post to both the Linear issue and the PR: 1. **Before/after images** per state — legacy, rebuilt, and the diff PNG. Never commit the images into the repo (the web harness's rule: report JSON is committed, images are gitignored); attach them to the issue/PR instead. 2. **Video for motion.** Static screenshots cannot prove an animation. Channel convention (Thomas's rule, carried in `tamagui-conversion`) is before/after screenshots **plus video for anything animated**. 3. **Provenance**: device model, OS version, platform, Metro mode, and the **commit SHA** the diff ran against. A diff against uncommitted work is not reproducible — the web harness refuses a dirty tree for exactly this reason. 4. **The diff mechanism** (§ 7) — `screenshot-diff` and its mode, or the fallback with the thresholds you used and any deviation from the defaults and why. 5. **A verdict per state**, not one aggregate. `pass` / `flagged` / `known drift (reason)`. Enumerate the full matrix so a reviewer can see nothing was quietly skipped. 6. **Captured from where.** Visual evidence must come from a deployed preview or the workbench — never local dev — for web. For mobile the equivalent is the installed build at a named commit, stated explicitly. Say plainly whether the diff **ran**. "Staged" and "executed" are different claims and reviewers rely on the difference. --- ## Related Skills | Skill | When to use | | --- | --- | | `argent-device-interact` | The `screenshot` tool itself, `scale`, rotation, gestures, troubleshooting (§ 7 is the screenshot reference) | | `argent-test-ui-flow` | Navigating to the staged stories; the settle/retake recovery pattern before capture | | `argent-ios-simulator-setup` | Booting an iOS simulator, getting a UDID | | `argent-android-emulator-setup` | Booting an Android emulator, getting an adb serial, `adb reverse` | | `argent-create-flow` | Record the navigate-and-capture sequence as a flow so before/after captures are byte-for-byte reproducible via `flow-execute` — this removes interaction variance, the largest source of diff noise | | `argent-react-native-app-workflow` | Getting the build installed and Metro running before any capture | | `tamagui-conversion` | The migration contract that requires an executed diff as the mobile proof artifact |
GitHub에서 보기