argent-lens
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePrerequisite — feature flag. This workflow is gated behind theflag (off by default). Runargent-lensonce before using it. Ifargent enable argent-lens/propose_variantcome back not-found, the flag is off — enable it and retry.await_user_selection
前置条件——功能标志。此工作流受标志限制(默认关闭)。使用前需运行一次argent-lens。如果argent enable argent-lens/propose_variant返回未找到,则说明标志未开启——请启用后重试。await_user_selection
1. Overview
1. 概述
You implement several candidate designs, capture each one running on the device, and stage them with . Each proposed element shows up as a floating card next to the live simulator stream in the Argent Lens window (a native window that opens automatically), connected by a thin line to the real element. The human picks per element, optionally pins free-form comments to elements, and presses Complete selection. is the single blocking call that returns their decision.
propose_variantawait_user_selectionThe golden rule: one variant = one real, distinct screenshot. A proposal is only useful if its shows the variant actually rendered on the device, captured AFTER that specific variant was applied. Never propose a variant you have not built and seen on screen, and never point two variants at the same file path — if two captures end up byte-identical you have not actually changed anything and the Argent Lens degenerates to identical thumbnails. Plan → build → navigate → screenshot → propose, repeated for every variant of every element, then await once.
previewImage你需要实现多个候选设计,捕获每个设计在设备上运行的画面,并通过进行提交。每个提交的元素会作为浮动卡片显示在Argent Lens窗口(自动打开的原生窗口)中的实时模拟器流旁边,通过细线连接到对应的实际元素。用户可为每个元素做出选择,还可选择为元素添加自由格式的评论,然后点击完成选择。是唯一的阻塞调用,会返回用户的决策结果。
propose_variantawait_user_selection黄金法则:一个变体对应一张真实、独特的截图。只有当展示了该变体在设备上实际渲染的画面(且是应用该特定变体后捕获的),提案才有意义。绝不要提交你未在屏幕上构建和查看过的变体,也绝不要让两个变体指向同一个文件路径——如果两次捕获的内容字节完全相同,说明你并未做出任何实际更改,Argent Lens会显示相同的缩略图。按照规划→构建→导航→截图→提交的流程,针对每个元素的每个变体重复执行,最后调用一次等待方法。
previewImage2. Tools
2. 工具
| Tool | Blocking? | Purpose |
|---|---|---|
| No | Stage ONE variant for ONE element. Call once per variant. Keep working. |
| Yes | Call ONCE after every variant is staged. Parks until the human is done. |
propose_variantelementmatch{ by: "text"|"label"|"identifier"|"role", value }udidvariant{ name, summary, code?, filePath?, previewImage?, frame? }elementelementAlways pass (the same simulator/emulator id you screenshotted and described with). The preview window then streams that device directly — the human never has to pick a simulator. Set it on the first of a round; later calls may omit it (the last value wins).
udidpropose_variant| 工具名称 | 是否阻塞 | 用途 |
|---|---|---|
| 否 | 为单个元素提交一个变体。每个变体调用一次。可继续执行其他操作。 |
| 是 | 在所有变体提交完成后调用一次。会暂停执行直到用户完成选择。 |
propose_variantelementmatch{ by: "text"|"label"|"identifier"|"role", value }udidvariant{ name, summary, code?, filePath?, previewImage?, frame? }elementelement务必传入(即你截图并描述的模拟器/模拟器ID)。预览窗口随后会直接流式传输该设备的画面——用户无需手动选择模拟器。在一轮提交的第一个中设置该参数;后续调用可省略(最后传入的值会生效)。
udidpropose_variant3. Workflow
3. 工作流
Resolve a simulator/emulator first ( / ) and, for React Native, to run the app and reload the bundle. Argent shows the staged variants in a native preview window that opens automatically on the user's screen; you don't open or display anything yourself. Just stage variants and call , and the window appears on its own.
argent-ios-simulator-setupargent-android-emulator-setupargent-react-native-app-workflowawait_user_selection首先启动模拟器/模拟器(/),对于React Native项目,使用运行应用并重新加载包。Argent会在用户屏幕上自动打开的原生预览窗口中显示已提交的变体;你无需手动打开或显示任何内容。只需提交变体并调用,窗口就会自动弹出。
argent-ios-simulator-setupargent-android-emulator-setupargent-react-native-app-workflowawait_user_selectionStep 0 — Plan the variants
步骤0——规划变体
Decide, before touching code, exactly which elements you are redesigning and the distinct variants for each. Write them down (e.g. "Search field: Filled / Outlined / Pill" — "Primary CTA: Solid / Gradient"). Each variant must be a single, self-contained change you can apply, screenshot, and revert independently. Vague or overlapping variants produce useless proposals.
在编写代码之前,明确你要重新设计的元素以及每个元素的独特变体。将它们记录下来(例如:“搜索框:填充式/轮廓式/胶囊式”——“主CTA:纯色/渐变”)。每个变体必须是可独立应用、截图和还原的单一独立变更。模糊或重叠的变体无法产生有用的提案。
Step 1 — Get a precise matcher
步骤1——获取精确匹配器
For each element, run (or for RN) on the screen where it lives and read its exact / / . Pass that as so the floating card's connector anchors to the right element:
describedebugger-component-treelabelidentifierrolematch- Stable testID / accessibilityIdentifier → (most reliable)
{ by: "identifier", value: "search-input" } - Exact a11y label →
{ by: "label", value: "Search" } - Otherwise → (fuzzy contains; the default if
{ by: "text", value: "Search" }is omitted)match
Omitting defaults to , which is fine only when the element's visible text is unique.
match{ by: "text", value: element }对于每个元素,在其所在屏幕上运行(或针对RN使用),读取其确切的//。将其作为参数传入,以便浮动卡片的连接线锚定到正确的元素:
describedebugger-component-treelabelidentifierrolematch- 稳定的testID/accessibilityIdentifier → (最可靠)
{ by: "identifier", value: "search-input" } - 精确的无障碍标签 →
{ by: "label", value: "Search" } - 其他情况 → (模糊匹配包含内容;如果省略
{ by: "text", value: "Search" }则默认使用此方式)match
省略参数会默认使用,仅当元素的可见文本唯一时才适用。
match{ by: "text", value: element }Step 2 — For each variant: build → navigate → screenshot → propose
步骤2——针对每个变体:构建→导航→截图→提交
Loop over every variant of every element:
- Build the variant. Implement that one variant in code.
- Apply it on the device. Reload the RN bundle () or rebuild as needed so the running app shows this variant.
debugger-reload-metro - Navigate to it. Drive the app () to the screen where the element is visible — a screenshot is only meaningful if the element is actually on screen.
argent-device-interact - Screenshot. Call and pass the returned file path straight through as
screenshot. NEVER hand-crop, resize, re-encode, or copy the screenshot to another folder (e.g. avariant.previewImageintocrop.py): that double-crops against the preview window's own cropping and writes the image somewhere the server won't serve it ("No preview"). Capture the whole screen — the preview window crops it for you using/tmp/variants/(step 5). The path you got back must be a NEW file; if you suspect the device froze or the variant didn't apply (you see no visible change vs. the previous capture), diff with the previous path (variant.frame) before proposing — byte-identical captures mean the variant is not on screen yet. Fix that before proposing, never propose anyway.shasum -a 256 - Propose. Call with
propose_variant,element,match(the device you captured on), andudidset to that screenshot path. The tool auto-captures the crop frame: it describes the device at propose time and matches the element, so each thumbnail crops to its own current layout — as long as the variant is still on screen when you callvariant.previewImage(propose right after the screenshot, before reverting). You may passpropose_variant(the matched node's normalizedvariant.framein 0..1 from a{x, y, width, height}on THIS variant) to override the auto-capture — useful when the element can't stay on screen at propose time. Adddescribe(what changed and why) andsummary/codewhen useful.filePath - Revert. Roll the variant change back before building the next one — only one variant can be on screen at a time. Keep going; does not block.
propose_variant
previewImagehttp(s)data:遍历每个元素的每个变体:
- 构建变体。在代码中实现该变体。
- 在设备上应用。重新加载RN包()或按需重新构建,使运行中的应用显示该变体。
debugger-reload-metro - 导航到目标页面。通过操作应用,导航到元素可见的屏幕——只有当元素在屏幕上可见时,截图才有意义。
argent-device-interact - 截图。调用并将返回的文件路径直接作为
screenshot传入。绝不要手动裁剪、调整大小、重新编码或复制截图到其他文件夹(例如使用variant.previewImage保存到crop.py):这会与预览窗口自身的裁剪功能冲突,且图片会被保存到服务器无法访问的位置(显示“无预览”)。捕获整个屏幕——预览窗口会使用/tmp/variants/(步骤5)自动裁剪图片。你获取的路径必须是新文件;如果你怀疑设备冻结或变体未应用(与上一次捕获相比无可见变化),在提交前对比两个路径的哈希值(variant.frame)——字节完全相同的捕获说明变体尚未显示在屏幕上。请先修复问题再提交,不要直接提交。shasum -a 256 - 提交。调用,传入
propose_variant、element、match(你捕获截图的设备),并将udid设置为该截图路径。工具会自动捕获裁剪框:它会在提交时描述设备并匹配元素,因此每个缩略图会根据当前布局自动裁剪——只要在调用variant.previewImage时变体仍显示在屏幕上(截图后立即提交,不要先还原)。你也可以传入propose_variant(通过对该变体执行variant.frame得到的匹配节点的标准化describe,取值范围0..1)来覆盖自动捕获——当元素在提交时无法保持在屏幕上时非常有用。可添加{x, y, width, height}(变更内容及原因),必要时添加summary/code。filePath - 还原。在构建下一个变体之前,回滚当前变体的变更——同一时间屏幕上只能显示一个变体。继续执行;不会阻塞。
propose_variant
previewImagehttp(s)data:Step 3 — Await the human's decision (once)
步骤3——等待用户决策(仅一次)
After every variant for every element is staged, call exactly once. It returns:
await_user_selection- — apply
{ status: "completed", selections: [{ element, chosenVariant, comment? }], unselected, annotations: [{ target, match, comment }], globalComment }for each element; skip elements inchosenVariant. Treat eachunselectedentry (inspector comments the human pinned to elements) andannotationsas a change request.globalComment - —
{ status: "pending", proposedElements }elapsed, not an error. Proposals are still live; calltimeoutSecondsagain.await_user_selection - — you called it before any
{ status: "no_proposals" }. Stage variants first.propose_variant
在所有元素的所有变体提交完成后,精确调用一次。它会返回:
await_user_selection- ——为每个元素应用
{ status: "completed", selections: [{ element, chosenVariant, comment? }], unselected, annotations: [{ target, match, comment }], globalComment };跳过chosenVariant中的元素。将每个unselected条目(用户固定到元素的检查器评论)和annotations视为变更请求。globalComment - ——
{ status: "pending", proposedElements }超时,并非错误。提案仍然有效;可再次调用timeoutSeconds。await_user_selection - ——你在未提交任何
{ status: "no_proposals" }的情况下调用了该方法。请先提交变体。propose_variant
Step 4 — Apply the outcome
步骤4——应用结果
Implement the chosen variant for every selected element, address every annotation/comment, and report what you applied and what was skipped. If the human commented but skipped a variant, the comment still matters — act on it.
为每个选中的元素实现选定的变体,处理所有注释/评论,并报告你应用的内容和跳过的内容。如果用户对某个变体添加了评论但未选择该变体,该评论仍然有效——请据此执行。
4. Rules
4. 规则
- At least two variants per element. A choice needs alternatives — every element you propose must have ≥2 distinct variants (call at least twice for it). If you only have one look for an element, either produce a real alternative or don't propose that element at all; a lone variant isn't a choice.
propose_variant - Build before you propose. Every must be a screenshot of that variant actually running on the device. No mockups, no guesses, no proposing un-built ideas.
previewImage - Distinct screenshot per variant. Reusing a path across two variants — or capturing two paths whose bytes turn out identical — defeats the whole point of the Argent Lens. If you can't produce visibly different captures (e.g. the app is read-only, accessibility is broken so you can't navigate, the bundle won't hot-reload), STOP and tell the user instead of staging duplicates.
previewImage - One blocking call. never blocks — stage freely.
propose_variantis the only call that waits, and you call it once, last.await_user_selection - Anchor accurately. Pull matchers from ; a wrong
describemakes the card point at the wrong element or float unanchored.match - One variant on screen at a time. Apply → screenshot → revert before the next variant so screenshots never bleed together.
- is normal. On
pending, just await again — proposals persist across timeouts.pending - Re-proposing starts a fresh round. Calling after a round was consumed begins round N+1 and clears the previous round's elements; stage a full set each round.
propose_variant
- 每个元素至少两个变体。选择需要备选方案——你提交的每个元素必须有≥2个独特变体(针对该元素至少调用两次)。如果你只为某个元素设计了一种外观,要么生成一个真实的替代方案,要么不要提交该元素;单个变体无法构成选择。
propose_variant - 先构建再提交。每个必须是该变体在设备上实际运行的截图。禁止使用模型图、猜测图,禁止提交未构建的想法。
previewImage - 每个变体对应独特截图。在两个变体中重复使用路径——或者捕获两个字节完全相同的路径——会完全违背Argent Lens的初衷。如果你无法生成视觉上不同的截图(例如应用为只读、无障碍功能损坏导致无法导航、包无法热重载),请停止操作并告知用户,不要提交重复内容。
previewImage - 仅一次阻塞调用。永远不会阻塞——可自由提交。
propose_variant是唯一会等待的调用,且你只需在最后调用一次。await_user_selection - 准确锚定。从获取匹配器;错误的
describe会导致卡片指向错误的元素或无锚点浮动。match - 同一时间屏幕上仅显示一个变体。应用→截图→还原后再处理下一个变体,避免截图内容重叠。
- 是正常状态。当返回
pending时,只需再次等待——提案会在超时后保留。pending - 重新提交会开启新的一轮。在一轮提案被处理后调用会开启第N+1轮,并清除上一轮的元素;每一轮都需要提交完整的变体集。
propose_variant
5. Example
5. 示例
describe { udid } # read exact label/identifier
propose_variant { element: "Search field",
match: { by: "identifier", value: "search-input" },
variant: { name: "Outlined", summary: "1pt border, transparent fill",
previewImage: "/var/folders/.../search-outlined.png" } }
propose_variant { element: "Search field",
match: { by: "identifier", value: "search-input" },
variant: { name: "Pill", summary: "Fully rounded, filled grey",
previewImage: "/var/folders/.../search-pill.png" } }
propose_variant { element: "Primary CTA",
match: { by: "label", value: "Get started" },
variant: { name: "Gradient", summary: "Accent gradient fill",
previewImage: "/var/folders/.../cta-gradient.png" } }
await_user_selection {} # ONE blocking call → human picks
→ { status: "completed",
selections: [ { element: "Search field", chosenVariant: { name: "Pill" } },
{ element: "Primary CTA", chosenVariant: { name: "Gradient" } } ],
annotations: [ { target: "Tab bar", comment: "raise contrast" } ] }describe { udid } # 读取确切的标签/标识符
propose_variant { element: "Search field",
match: { by: "identifier", value: "search-input" },
variant: { name: "Outlined", summary: "1pt border, transparent fill",
previewImage: "/var/folders/.../search-outlined.png" } }
propose_variant { element: "Search field",
match: { by: "identifier", value: "search-input" },
variant: { name: "Pill", summary: "Fully rounded, filled grey",
previewImage: "/var/folders/.../search-pill.png" } }
propose_variant { element: "Primary CTA",
match: { by: "label", value: "Get started" },
variant: { name: "Gradient", summary: "Accent gradient fill",
previewImage: "/var/folders/.../cta-gradient.png" } }
await_user_selection {} # 唯一的阻塞调用 → 用户选择
→ { status: "completed",
selections: [ { element: "Search field", chosenVariant: { name: "Pill" } },
{ element: "Primary CTA", chosenVariant: { name: "Gradient" } } ],
annotations: [ { target: "Tab bar", comment: "raise contrast" } ] }→ apply Pill + Gradient, and raise tab-bar contrast.
→ 应用Pill和Gradient变体,并提高标签栏对比度。
undefinedundefined