mesurer-solid 0.1.2 → 0.1.3-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2840,7 +2840,30 @@ var Gn = "mesurer:capture-bridge-ping", Kn = "mesurer:capture-bridge-request", q
2840
2840
  command: Er,
2841
2841
  icon: Ar,
2842
2842
  active: C,
2843
- hidden: () => !w().toolEnabled
2843
+ hidden: () => !w().toolEnabled,
2844
+ menu: {
2845
+ label: "Screenshot options",
2846
+ items: [
2847
+ {
2848
+ id: "copy",
2849
+ label: "Auto-copy",
2850
+ checked: () => w().copy,
2851
+ run: () => T({ copy: !w().copy })
2852
+ },
2853
+ {
2854
+ id: "download",
2855
+ label: "Auto-download",
2856
+ checked: () => w().download,
2857
+ run: () => T({ download: !w().download })
2858
+ },
2859
+ {
2860
+ id: "measurements",
2861
+ label: "Include measurements",
2862
+ checked: () => w().includeMeasurements,
2863
+ run: () => T({ includeMeasurements: !w().includeMeasurements })
2864
+ }
2865
+ ]
2866
+ }
2844
2867
  }), t.settings.register({
2845
2868
  id: "screenshot",
2846
2869
  label: "Screenshot",
@@ -2885,7 +2908,7 @@ var Gn = "mesurer:capture-bridge-ping", Kn = "mesurer:capture-bridge-request", q
2885
2908
  S = !0, y += 1, u.removeEventListener("pointerdown", L), u.removeEventListener("pointermove", R), u.removeEventListener("pointerup", z), u.removeEventListener("pointercancel", B), i.removeEventListener("keydown", V, !0), v && i.clearTimeout(v), ee.dispose(), O(), cr(i), a.finishCapture(), a.dispose(), o.dispose();
2886
2909
  });
2887
2910
  }
2888
- }), Rr = "0.1.2", zr = wr, Br = xr, Vr = Sr, Hr = Cr, Ur = 4, Wr = dr, Gr = (e, t) => Xn(e, t), Kr = (e = /* @__PURE__ */ new Date()) => Zn(e), qr = (e, t, n, r) => Yn(e, t, n, r), Jr = (e, t, n) => Jn(e, t, n), Yr = (e, t) => ur(e, t), Xr = (e) => cr(e), Zr = (e = {}) => ({
2911
+ }), Rr = "0.1.3-beta.0", zr = wr, Br = xr, Vr = Sr, Hr = Cr, Ur = 4, Wr = dr, Gr = (e, t) => Xn(e, t), Kr = (e = /* @__PURE__ */ new Date()) => Zn(e), qr = (e, t, n, r) => Yn(e, t, n, r), Jr = (e, t, n) => Jn(e, t, n), Yr = (e, t) => ur(e, t), Xr = (e) => cr(e), Zr = (e = {}) => ({
2889
2912
  ...Lr(e),
2890
2913
  version: Rr
2891
2914
  }), Qr = (e) => $n(e);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mesurer-solid",
3
- "version": "0.1.2",
3
+ "version": "0.1.3-beta.0",
4
4
  "description": "Framework-agnostic UI measurement and inspection tools for browser apps and coding agents.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -15,6 +15,10 @@
15
15
  "types": "./dist/index.d.ts",
16
16
  "import": "./dist/index.js"
17
17
  },
18
+ "./arrange": {
19
+ "types": "./dist/arrange.d.ts",
20
+ "import": "./dist/arrange.js"
21
+ },
18
22
  "./core": {
19
23
  "types": "./dist/core.d.ts",
20
24
  "import": "./dist/core.js"
@@ -1,35 +1,36 @@
1
1
  ---
2
2
  name: mesurer-ui
3
- description: Use Mesurer when implementing, reviewing, debugging, or fixing frontend UI in a browser. Load for visual alignment, spacing, sizing, layout, CSS, responsive work, design/Figma implementation, screenshots, pixel discrepancies, or human Mesurer selections/measurements/guides/annotations. Treat Mesurer context as the output of every meaningful visual inspection: consume existing human context before editing, acquire a selection when needed, and obtain fresh context again before claiming completion.
3
+ description: Use Mesurer when implementing, reviewing, debugging, or fixing frontend UI in a browser. Load for visual alignment, spacing, sizing, layout, CSS, responsive work, design/Figma implementation, screenshots, pixel discrepancies, human Mesurer selections/measurements/guides/annotations, or Arrange intents. Consume existing human visual intent before editing and obtain fresh rendered evidence before claiming completion.
4
4
  ---
5
5
 
6
6
  # Mesurer UI workflow
7
7
 
8
- Mesurer is **shared visual state between the person reviewing a page and the coding agent editing it**. The page is the integration boundary.
8
+ Mesurer is shared visual state between the person reviewing a page and the coding agent editing it. The rendered page is the integration boundary.
9
9
 
10
10
  There is no Mesurer MCP, WebMCP, ACP, chat-delivery daemon, session router, or Send-to-agent callback in the normal workflow. Use the browser/evaluation channel the harness already owns and read `window.__MESURER__` directly.
11
11
 
12
- The critical behavioral contract is:
12
+ The central rule is:
13
13
 
14
- > **When Mesurer is available, expect structured context back.** Do not merely open, highlight, or inspect with Mesurer and then continue from memory. A meaningful visual step should produce `MesurerContextV1`, `MesurerReviewV1`, or an equally focused Mesurer measurement that the agent actually consumes.
14
+ > A meaningful Mesurer step must return evidence the agent actually consumes.
15
+
16
+ That evidence may be `MesurerContextV1`, `MesurerReviewV1`, an Arrange intent/review, or a focused low-level measurement. Do not merely draw a highlight and continue from memory.
15
17
 
16
18
  ```text
17
19
  human visual intent or agent UI change
18
- → identify affected rendered targets
19
- → Mesurer selection / annotation / workspace
20
- → structured context comes back to the agent
21
- → agent reasons from exact rendered evidence
22
- → source edit
23
- → render settles
24
- → fresh Mesurer context/review comes back
25
- → agent iterates until evidence supports completion
20
+ → preserve existing Mesurer state
21
+ → consume Arrange / annotation / selection evidence
22
+ → reason from exact rendered state
23
+ → edit normal source
24
+ → wait for the real render
25
+ → compare fresh rendered state with the human intent
26
+ → iterate until the evidence supports completion
26
27
  ```
27
28
 
28
- ## 1. Preserve existing human state
29
+ ## 1. Reuse the live Mesurer instance
29
30
 
30
- Never reinject, dispose, or replace Mesurer just because this skill loaded. The person may already have selected elements, placed guides, measured gaps, held distances, enabled rulers/X-ray, created annotations, or kept a screenshot thumbnail/viewer open. That state is part of the user's message.
31
+ Never reinject, dispose, or replace Mesurer just because this skill loaded. The person may already have selected elements, placed guides, measured gaps, held distances, enabled rulers/X-ray, created annotations, arranged elements into a desired layout, or kept a screenshot thumbnail/viewer open. That state is part of the user's message.
31
32
 
32
- Start by discovering the current page:
33
+ Discover the current page first:
33
34
 
34
35
  ```js
35
36
  const hasMesurer = Boolean(
@@ -44,28 +45,28 @@ if (hasMesurer) {
44
45
 
45
46
  If Mesurer exists, use that exact instance. Do not evaluate the injector again and do not call `dispose()`.
46
47
 
47
- If Mesurer is absent, inject the packaged classic payload through the browser JavaScript-evaluation primitive the harness already owns. The installed skill contains `assets/inject-script.js`; in this repository the development artifact is `packages/mesurer/dist/inject-script.js`; an installed npm package exposes `mesurer-solid/inject-script`.
48
+ If Mesurer is absent, inject the packaged classic payload through the JavaScript-evaluation primitive the harness already owns. The installed skill contains `assets/inject-script.js`; this repository builds `packages/mesurer/dist/inject-script.js`; the npm package exposes `mesurer-solid/inject-script`.
48
49
 
49
50
  Do not add Mesurer to application source, create another browser, create a second CDP connection, start a Mesurer server, or change the application build merely to inspect a page the harness already controls.
50
51
 
51
- The injector defaults to reusing a live injected instance. `window.__MESURER_CONFIG__ = { reuseExisting: false }` is an explicit destructive replacement option for tests/tooling. Do not use it while consuming human review state.
52
+ The injector reuses a live injected instance by default. `window.__MESURER_CONFIG__ = { reuseExisting: false }` is an explicit destructive replacement option for tests/tooling. Do not use it while consuming human review state.
52
53
 
53
- Normal injection keeps the optional human screenshot plugin disabled. If the task explicitly needs that camera tool, configure it before the first injection:
54
+ Normal injection keeps the optional human screenshot plugin disabled. If the task specifically needs that camera tool, configure it before first injection:
54
55
 
55
56
  ```js
56
57
  window.__MESURER_CONFIG__ = { screenshot: true }
57
58
  ```
58
59
 
59
- The first-party Chrome extension enables screenshot capture automatically. Do not replace/reinject a live instance merely to enable screenshots unless the user specifically asks for that change; preserve current review state first.
60
+ Do not replace/reinject a live instance merely to enable screenshots. Preserve current human state first.
60
61
 
61
- After a first injection:
62
+ After first injection or discovery:
62
63
 
63
64
  ```js
64
65
  await window.__MESURER__.ready()
65
66
  const capabilities = window.__MESURER__.capabilities()
66
67
  ```
67
68
 
68
- The context surface includes:
69
+ The context-oriented surface includes:
69
70
 
70
71
  ```text
71
72
  context
@@ -75,15 +76,120 @@ review
75
76
  capturePlan
76
77
  ```
77
78
 
78
- `select` is an agent/harness primitive, not a human toolbar action. The visible context controls remain Copy Context, Copy Selection, and Add Note. The optional screenshot plugin is a separate camera tool/service; it does not create a screenshot-delivery capability on `window.__MESURER__`.
79
+ When the first-party Arrange plugin is mounted, capabilities also reports:
80
+
81
+ ```text
82
+ arrange
83
+ ```
84
+
85
+ Arrange adds:
86
+
87
+ ```text
88
+ arrangements
89
+ arrange
90
+ showArrange
91
+ arrangeCapturePlan
92
+ reviewArrange
93
+ ```
94
+
95
+ The optional screenshot plugin remains a separate human tool/service. It is not a screenshot-delivery capability on `window.__MESURER__`.
96
+
97
+ ## 2. Consume Arrange before source edits
98
+
99
+ Arrange represents explicit human layout intent. If `capabilities.capabilities.arrange` is true, inspect it before replacing the human selection or editing source:
100
+
101
+ ```js
102
+ const arrangements = await window.__MESURER__.arrangements()
103
+ ```
104
+
105
+ For a relevant intent:
106
+
107
+ ```js
108
+ const intent = await window.__MESURER__.arrange(arrangeId)
109
+ ```
110
+
111
+ An Arrange intent contains exact targets plus Before and Desired geometry. Treat Desired as the requested visual outcome, not as an implementation prescription.
112
+
113
+ For example, a target moving `96px` right does **not** mean production code should receive `transform: translateX(96px)`. Inspect the surrounding layout and implement the appropriate source-level change: flex/grid alignment, gap, margin, sizing, placement, component structure, or another semantic layout rule.
114
+
115
+ ### Capture Before and Desired before HMR
116
+
117
+ Arrange can reconstruct both states while the original source-rendered page is still present. If the harness can capture screenshots, capture both before editing source.
118
+
119
+ ```js
120
+ await window.__MESURER__.showArrange(arrangeId, "before")
121
+ const beforePlan = await window.__MESURER__.arrangeCapturePlan(arrangeId, "before")
122
+
123
+ await window.__MESURER__.prepareCapture()
124
+ try {
125
+ // Use the current browser harness screenshot primitive with beforePlan.
126
+ } finally {
127
+ await window.__MESURER__.finishCapture()
128
+ }
129
+
130
+ await window.__MESURER__.showArrange(arrangeId, "desired")
131
+ const desiredPlan = await window.__MESURER__.arrangeCapturePlan(arrangeId, "desired")
132
+
133
+ await window.__MESURER__.prepareCapture()
134
+ try {
135
+ // Capture the Desired state with the same harness.
136
+ } finally {
137
+ await window.__MESURER__.finishCapture()
138
+ }
139
+ ```
140
+
141
+ The user should not need to export or attach these images. The coding harness already owns screenshot bytes; Mesurer owns the reproducible visual states and capture geometry.
142
+
143
+ Retain:
144
+
145
+ - the Arrange id;
146
+ - target selectors/fingerprints;
147
+ - Before geometry;
148
+ - Desired geometry and offsets;
149
+ - the Before screenshot when available;
150
+ - the Desired screenshot when available.
151
+
152
+ Do this **before** source changes or HMR can alter the baseline.
153
+
154
+ ### Verify the real implementation against Desired
155
+
156
+ After source changes and a stable render, switch Arrange to Live. Live removes Arrange's temporary visual preview so the page shows only what the application source actually produces.
157
+
158
+ ```js
159
+ await window.__MESURER__.stable()
160
+ await window.__MESURER__.showArrange(arrangeId, "live")
161
+ const review = await window.__MESURER__.reviewArrange(arrangeId)
162
+ ```
163
+
164
+ `reviewArrange()` reports exact current-vs-Desired rectangle deltas and whether the targets match within tolerance. If it says the result is still off, continue editing.
165
+
166
+ A typical loop is:
167
+
168
+ ```text
169
+ Before Desired Live
170
+ x 120 → x 284 x 276
171
+ remaining +8px
172
+
173
+ edit source
174
+ ↓
175
+ wait for stable render
176
+ ↓
177
+ Live x 284
178
+ ↓
179
+ matched ✓
180
+ ```
181
+
182
+ If review reports `stale` or `partial`, do not silently transfer the intent to a different element. Resolve target identity conservatively or ask the user to reselect/rearrange if ambiguity remains.
79
183
 
80
- ## 2. Context acquisition is mandatory for visual work
184
+ Do not clear, overwrite, or discard a human Arrange intent merely to make validation pass.
81
185
 
82
- Use this precedence order whenever Mesurer is available.
186
+ ## 3. Acquire ordinary context in the right order
83
187
 
84
- ### A. Existing human selection or annotation → consume it first
188
+ After preserving any relevant Arrange intent, use this order for the rest of the visual evidence.
85
189
 
86
- Always preserve and read existing human evidence before changing selection yourself.
190
+ ### A. Existing human selection or annotation
191
+
192
+ Read it before changing selection yourself:
87
193
 
88
194
  ```js
89
195
  const workspace = await window.__MESURER__.context()
@@ -97,7 +203,7 @@ try {
97
203
  }
98
204
  ```
99
205
 
100
- For each relevant annotation:
206
+ For a relevant annotation:
101
207
 
102
208
  ```js
103
209
  const annotationContext = await window.__MESURER__.context({
@@ -105,31 +211,29 @@ const annotationContext = await window.__MESURER__.context({
105
211
  })
106
212
  ```
107
213
 
108
- Treat annotation notes as human intent. Treat selection, guides, distances, measurements, geometry, computed styles, and screenshots as evidence supporting that intent.
109
-
110
- Do not overwrite a meaningful human selection until you have read and retained its context in the current task.
214
+ Treat annotation notes and Arrange Desired state as human intent. Treat selection, guides, distances, measurements, exact geometry, computed styles, and screenshots as evidence supporting that intent.
111
215
 
112
- ### B. No relevant selection + target is ambiguous → ask the user to select it
216
+ Do not overwrite a meaningful human selection until its context has been retained in the current task.
113
217
 
114
- If the user's request refers to something visually ambiguous and you cannot confidently identify the intended rendered element or region, do not guess.
218
+ ### B. No relevant selection and the target is ambiguous
115
219
 
116
- Ask the user to select the intended element(s) or drag the intended region with Mesurer. Once they do, immediately read:
220
+ Ask the user to select the intended element(s) or region with Mesurer. Then immediately read:
117
221
 
118
222
  ```js
119
223
  const selection = await window.__MESURER__.context({ scope: "selection" })
120
224
  ```
121
225
 
122
- A selection is the answer to “what exactly do you mean?” Do not require the user to create an annotation unless a durable note/baseline would actually help.
226
+ Do not guess merely to avoid asking for a selection.
123
227
 
124
- ### C. No relevant selection + agent knows the exact rendered targets → select them yourself
228
+ ### C. The agent knows the exact rendered target
125
229
 
126
- When you know exactly which rendered elements correspond to the UI you are changing or just changed, use `select()` instead of asking the user to do unnecessary work.
230
+ Select it yourself:
127
231
 
128
232
  ```js
129
233
  const context = await window.__MESURER__.select("#pricing-card")
130
234
  ```
131
235
 
132
- For several exact targets:
236
+ For multiple targets:
133
237
 
134
238
  ```js
135
239
  const context = await window.__MESURER__.select([
@@ -138,19 +242,13 @@ const context = await window.__MESURER__.select([
138
242
  ])
139
243
  ```
140
244
 
141
- `select()` does three things as one visual operation:
142
-
143
- 1. switches Mesurer to Select and visibly highlights the exact rendered targets;
144
- 2. makes those elements the live Mesurer selection;
145
- 3. **returns selection-scoped `MesurerContextV1` after the selection settles**.
245
+ `select()` switches Mesurer to Select, visibly highlights the exact targets, makes them the live selection, waits for the selection to settle, and returns selection-scoped `MesurerContextV1`.
146
246
 
147
- Use the returned object. Do not call `select()` only for the highlight and ignore its context.
247
+ Use the returned object. Do not call `select()` only for the highlight.
148
248
 
149
- `select()` is intentionally strict. Every selector must resolve to exactly one page target. Missing, invalid, or ambiguous selectors throw. Refine the selector or ask the user to select the intended target rather than guessing.
249
+ Every supplied selector must resolve to exactly one page target. Missing, invalid, or ambiguous selectors throw. Refine the selector or ask the user to select the target rather than guessing.
150
250
 
151
- Prefer exact selectors already obtained from `context()`, `inspect()`, stable IDs/test IDs, or a uniquely identified rendered node. Do not use a broad selector such as `.card` when it matches many elements unless you intentionally refine each target.
152
-
153
- ## 3. Understand the context you receive
251
+ ## 4. Read rendered context, not source assumptions
154
252
 
155
253
  `MesurerContextV1` is JSON-safe and uses `viewport-css-px` coordinates. Relevant fields include:
156
254
 
@@ -179,20 +277,20 @@ visualContext
179
277
  distances[]
180
278
  ```
181
279
 
182
- Mesurer's rendered values are the source of truth. Prefer them over estimating from screenshots or assuming CSS declarations equal browser output.
280
+ Mesurer's rendered values are the source of truth. Prefer them over screenshot estimates or source-level assumptions.
183
281
 
184
282
  Examples:
185
283
 
186
284
  - left edges differ by `4px` → the targets are not aligned;
187
- - rendered horizontal gap is `37px` → do not claim `24px` merely because CSS contains `gap: 24px`;
188
- - width is `318px` → do not report `320px` from design intent until the browser actually measures it;
189
- - overflow flags are true → the rendered document/component is overflowing even if source math looked correct.
285
+ - rendered gap is `37px` → do not claim `24px` because CSS contains `gap: 24px`;
286
+ - rendered width is `318px` → do not report `320px` until the browser measures it;
287
+ - overflow flags are true → the rendered component is overflowing even if source math looked correct.
190
288
 
191
- ## 4. Multi-selection is relational context
289
+ ## 5. Treat multi-selection as relational evidence
192
290
 
193
- When several elements are selected, do not summarize them as “3 selected” or inspect only the first target. Their relationship is usually the point.
291
+ When several elements are selected, inspect every relevant target and their relationships. Do not summarize the state as only “3 selected.”
194
292
 
195
- For every selected target, consume:
293
+ For each target, consume:
196
294
 
197
295
  ```text
198
296
  selector / identity / text / accessibility
@@ -204,52 +302,39 @@ layout: display / position / flex / grid / gap / transform / overflow
204
302
  scroll/client dimensions and overflow flags
205
303
  ```
206
304
 
207
- Then recover the useful relationships between targets. Start with `selection.visualContext.distances`; for a pair not represented there, use the exact selectors returned by context:
305
+ Start with `selection.visualContext.distances`; for a needed pair not represented there:
208
306
 
209
307
  ```js
210
308
  const pair = window.__MESURER__.distance(selectorA, selectorB)
211
309
  ```
212
310
 
213
- For a small selection, report all useful unique pair relationships. For a large repeated set, focus on adjacent/repeated/user-relevant relationships rather than generating useless O(n²) output.
311
+ For a small selection, report useful unique pair relationships. For a large repeated set, focus on adjacent/repeated/user-relevant relationships rather than dumping O(n²) pairs.
214
312
 
215
- A valid read can look like:
313
+ ## 6. Preserve the baseline before editing
216
314
 
217
- ```text
218
- Card A: 320 × 180
219
- Card B: 320 × 180
220
- Card C: 320 × 180
221
- A → B horizontal gap: 24px
222
- B → C horizontal gap: 24px
223
- A/B top-edge delta: 0px
224
- ```
315
+ If the human supplied selection, measurements, an annotation, or Arrange state, retain the relevant baseline before source changes or HMR can replace nodes.
225
316
 
226
- Only claim numbers you actually read.
227
-
228
- ## 5. Before editing, retain the baseline you need
229
-
230
- If the human supplied a selection, workspace measurement, or annotation, capture its relevant context before source changes or HMR can replace nodes.
231
-
232
- For a durable human annotation:
317
+ Annotation:
233
318
 
234
319
  ```js
235
320
  const before = await window.__MESURER__.context({ annotation: annotationId })
236
321
  ```
237
322
 
238
- For live selection:
323
+ Live selection:
239
324
 
240
325
  ```js
241
326
  const before = await window.__MESURER__.context({ scope: "selection" })
242
327
  ```
243
328
 
244
- Store the needed selectors, dimensions, relationships, and intent inside the current agent task.
329
+ Arrange: capture the intent plus Before/Desired states as described above.
245
330
 
246
- Do not mutate human guides, measurements, held distances, annotations, or screenshot preview/viewer state merely to make your implementation appear correct.
331
+ Do not mutate human guides, measurements, held distances, annotations, Arrange history, or screenshot preview/viewer state merely to make the implementation appear correct.
247
332
 
248
- ## 6. Edit the real implementation
333
+ ## 7. Edit the real implementation
249
334
 
250
- Make the smallest source change that addresses the rendered issue. Use the project's normal edit/build/dev-server workflow.
335
+ Make the smallest source change that addresses the rendered issue. Use the project's normal source, build, and dev-server workflow.
251
336
 
252
- Mesurer does not own source edits, browser navigation, or the dev server. Do not create Mesurer-specific infrastructure.
337
+ Mesurer does not own source edits, navigation, or the dev server. Do not create Mesurer-specific infrastructure for those jobs.
253
338
 
254
339
  After HMR/render:
255
340
 
@@ -257,33 +342,37 @@ After HMR/render:
257
342
  await window.__MESURER__.stable()
258
343
  ```
259
344
 
260
- ## 7. Fresh context is part of completion
345
+ ## 8. Fresh rendered evidence is part of completion
261
346
 
262
- For meaningful visual work, do not stop at lint/typecheck/tests/build. Before finalizing, obtain **fresh Mesurer evidence for the affected rendered UI**.
347
+ Lint, typecheck, tests, and build are implementation checks. They do not prove a visual result.
263
348
 
264
- Use the strongest available path.
349
+ Use the strongest applicable completion path.
265
350
 
266
- ### Human annotation exists
351
+ ### Arrange intent
267
352
 
268
353
  ```js
269
354
  await window.__MESURER__.stable()
270
- const review = await window.__MESURER__.review(annotationId)
355
+ await window.__MESURER__.showArrange(arrangeId, "live")
356
+ const review = await window.__MESURER__.reviewArrange(arrangeId)
271
357
  ```
272
358
 
273
- `review()` returns baseline, current context, target status, exact before/current/delta metrics, and missing evidence.
359
+ Continue until the live source-rendered geometry matches Desired within the expected tolerance, and use a fresh screenshot when visual composition matters.
274
360
 
275
- ### Human selection still represents the changed UI
361
+ ### Human annotation
276
362
 
277
363
  ```js
278
364
  await window.__MESURER__.stable()
279
- const after = await window.__MESURER__.context({ scope: "selection" })
365
+ const review = await window.__MESURER__.review(annotationId)
280
366
  ```
281
367
 
282
- Re-check the same dimensions and relationships you recorded before editing.
368
+ ### Still-relevant human selection
283
369
 
284
- ### Agent made the UI change and knows the affected rendered targets
370
+ ```js
371
+ await window.__MESURER__.stable()
372
+ const after = await window.__MESURER__.context({ scope: "selection" })
373
+ ```
285
374
 
286
- Proactively highlight them and get context back:
375
+ ### Agent-known changed targets
287
376
 
288
377
  ```js
289
378
  await window.__MESURER__.stable()
@@ -293,69 +382,48 @@ const after = await window.__MESURER__.select([
293
382
  ])
294
383
  ```
295
384
 
296
- This is the preferred completion path when there was no human selection. It leaves the changed UI visibly selected for the user and returns exact evidence to the agent in the same operation.
297
-
298
- ### The affected target is now ambiguous
299
-
300
- Ask the user to select the intended result, then read the resulting selection context. Do not manufacture confidence from a guessed selector.
301
-
302
- A visual task is not complete merely because `select()` drew an outline. **Consume the returned context and reason from it.**
303
-
304
- ## 8. Human screenshots and agent screenshot evidence are different paths
305
-
306
- Mesurer now has an optional first-party screenshot plugin for human capture, while coding-agent verification can continue to use the outer harness's screenshot primitive. Do not conflate the two.
307
-
308
- ### Human screenshot plugin
385
+ If target identity is ambiguous after the change, ask the user to select the intended result. Do not manufacture confidence from a guessed selector.
309
386
 
310
- When enabled, `mesurer.screenshot` adds a camera tool. The person drags a viewport region and Mesurer captures a real PNG with CSS-to-bitmap scaling so Retina/HiDPI crops remain accurate. It temporarily hides control chrome from the captured pixels and then restores the previous presentation.
387
+ ## 9. Human screenshots and agent screenshots are different paths
311
388
 
312
- The plugin supports persisted automatic copy/download preferences, best-effort clipboard/download outputs, a persistent draggable thumbnail with native image right-click behavior, click-to-open larger viewer with Copy/Save/Close controls, and short capture-status feedback.
389
+ The optional `mesurer.screenshot` plugin gives the person a camera tool. It can copy/download a HiDPI-aware PNG and keep a draggable preview/viewer. Do not treat it as an agent-delivery transport or destroy a human preview unless the task explicitly requires it.
313
390
 
314
- Normal browser injection opts in before injection:
315
-
316
- ```js
317
- window.__MESURER_CONFIG__ = { screenshot: true }
318
- ```
319
-
320
- Source-mounted applications import `screenshotPlugin` from `mesurer-solid/screenshot`. Normal browsers use `getDisplayMedia()` and reuse a live capture stream; the first-party Chrome extension enables the plugin automatically and uses `chrome.tabs.captureVisibleTab()` through its isolated-world bridge, so its camera path does not open the screen-share chooser.
321
-
322
- The screenshot plugin is a human tool/service, not a chat or agent-delivery channel. Do not infer a `screenshots` capability on `window.__MESURER__`, and do not close or replace an existing human preview unless the task explicitly requires it.
323
-
324
- ### Agent verification screenshots
325
-
326
- For ordinary coding-agent verification, use the current harness/browser's real screenshot primitive so the harness controls the exact viewport, timing, and artifact. Mesurer supplies geometry and clean capture scope/presentation:
391
+ For normal coding-agent verification, the outer harness owns screenshot bytes. Mesurer supplies exact scope and clean presentation:
327
392
 
328
393
  ```js
329
394
  const plan = await window.__MESURER__.capturePlan({ scope: "selection" })
330
395
  await window.__MESURER__.prepareCapture()
331
396
  try {
332
- // Use the current harness/browser's real screenshot primitive.
397
+ // Use the current harness/browser screenshot primitive.
333
398
  } finally {
334
399
  await window.__MESURER__.finishCapture()
335
400
  }
336
401
  ```
337
402
 
403
+ Arrange follows the same ownership model through `arrangeCapturePlan()`. The important difference is that Arrange can deliberately present Before, Desired, or Live before the harness captures.
404
+
338
405
  Use both signals:
339
406
 
340
407
  ```text
341
- Mesurer context → exact geometry, styles, distances, overflow
342
- real screenshot → composition, hierarchy, clipping, color, visual judgment
408
+ Mesurer context/review → exact geometry, styles, distances, overflow
409
+ real screenshot → composition, hierarchy, clipping, color, visual judgment
343
410
  ```
344
411
 
345
- Screenshots from either path do not replace exact Mesurer measurements; Mesurer numbers do not replace visual judgment. Only use the screenshot plugin itself as the automation target when the task is specifically to test or modify that feature.
412
+ Screenshots do not replace exact Mesurer measurements, and Mesurer numbers do not replace visual judgment.
346
413
 
347
- ## 9. HMR and stale-target rules
414
+ ## 10. HMR and stale-target rules
348
415
 
349
- Annotations keep the exact live node while it remains connected and rebind conservatively after DOM replacement. If an annotation reports `stale` or `partial`, do not silently transfer human intent to a different element.
416
+ Annotations and Arrange intents rebind conservatively after DOM replacement. If review reports `stale` or `partial`, do not silently bind human intent to a different element.
350
417
 
351
- An unsaved selection can disappear when HMR replaces nodes. Preserve initial context before editing. After the render, use the original exact selectors when still valid, `select()` the known replacement targets when unambiguous, or ask the user to reselect when identity is uncertain.
418
+ An unsaved selection can disappear when HMR replaces nodes. Preserve initial context before editing. After render, use original exact selectors when still valid, `select()` known replacement targets when unambiguous, or ask the user to reselect when identity is uncertain.
352
419
 
353
- ## 10. Completion standard
420
+ ## 11. Completion standard
354
421
 
355
- A visual completion statement should be grounded in fresh rendered evidence, for example:
422
+ A valid visual completion statement is grounded in fresh rendered evidence, for example:
356
423
 
357
424
  ```text
358
- - selected cards now measure 320px wide
425
+ - Arrange Live now matches Desired within 1px
426
+ - selected cards measure 320px wide
359
427
  - rendered horizontal gap is 24px
360
428
  - selected top edges differ by 0px
361
429
  - component horizontal overflow is false
@@ -372,13 +440,11 @@ tests passed
372
440
  build passed
373
441
  ```
374
442
 
375
- Those are implementation checks, not rendered proof.
376
-
377
- If Mesurer is available and you could identify the affected UI, finishing without fresh Mesurer context is a workflow failure.
443
+ If Mesurer is available and the affected UI can be identified, finishing without fresh Mesurer evidence is a workflow failure.
378
444
 
379
- ## 11. Low-level helpers
445
+ ## 12. Low-level helpers
380
446
 
381
- Use these for focused questions when scoped context/review is not enough:
447
+ Use these only when scoped context/review is not enough:
382
448
 
383
449
  ```js
384
450
  await window.__MESURER__.ready()
@@ -392,24 +458,27 @@ await window.__MESURER__.state()
392
458
  await window.__MESURER__.stable()
393
459
  ```
394
460
 
395
- Prefer `context()`, `select()`, and `review()` for human-in-the-loop work because they preserve visual meaning and produce context that can be carried directly into the agent's reasoning.
461
+ Prefer `arrangements()`, `context()`, `select()`, `reviewArrange()`, and `review()` for human-in-the-loop work because they preserve visual meaning and return evidence that can be carried directly into reasoning.
396
462
 
397
- ## 12. Do not do these things
463
+ ## 13. Do not do these things
398
464
 
399
465
  - do not look for an MCP/WebMCP tool;
400
466
  - do not start a local feedback server;
401
467
  - do not discover chat/thread/session IDs;
402
468
  - do not route Mesurer through ACP or another delivery protocol;
403
469
  - do not recreate Send-to-agent;
404
- - do not treat the screenshot plugin as an agent-delivery transport;
470
+ - do not treat screenshot capture as an agent-delivery transport;
405
471
  - do not create another browser/CDP connection when the harness already controls the page;
406
472
  - do not reinject over live human Mesurer state;
407
473
  - do not overwrite human selection before reading it;
474
+ - do not clear or alter human Arrange history to make validation pass;
475
+ - do not implement Arrange offsets as production transforms unless the source layout genuinely calls for that;
476
+ - do not capture only Desired after source editing; preserve Before and Desired first when screenshot comparison matters;
408
477
  - do not close/destroy a human screenshot preview merely to clean up agent state;
409
478
  - do not use `select()` with a knowingly ambiguous selector;
410
479
  - do not ask the user to select something the agent can identify exactly itself;
411
- - do not guess when the intended target really is ambiguous—ask the user to select it;
412
- - do not ignore the context returned by `select()`;
480
+ - do not guess when the intended target really is ambiguous;
481
+ - do not ignore context returned by `select()`;
413
482
  - do not alter human measurements/guides to make validation pass;
414
483
  - do not infer exact geometry from screenshots when Mesurer reports the number;
415
484
  - do not claim visual completion from source/build output alone.
@@ -422,7 +491,8 @@ existing agent harness
422
491
  existing rendered page
423
492
  ↕
424
493
  window.__MESURER__
425
- ↳ context() / select() / review()
494
+ ↳ arrangements() / context() / select()
495
+ ↳ reviewArrange() / review()
426
496
  ```
427
497
 
428
- **Context is the output.**
498
+ **Rendered evidence is the output.**