qapture2 0.9.0 → 0.10.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.
- package/README.md +118 -248
- package/dist/bin/init.cjs +323 -60
- package/dist/{chunk-B22X5Y6U.js → chunk-5W5FS7JY.js} +391 -366
- package/dist/{chunk-5EWNGJ2N.cjs → chunk-R6WVHVXO.cjs} +391 -366
- package/dist/index.cjs +5 -5
- package/dist/index.d.cts +31 -0
- package/dist/index.d.ts +31 -0
- package/dist/index.js +1 -1
- package/dist/next.cjs +4 -4
- package/dist/next.js +1 -1
- package/dist/standalone.cjs +2 -2
- package/dist/standalone.js +1 -1
- package/package.json +4 -3
package/README.md
CHANGED
|
@@ -14,14 +14,9 @@ npm install qapture2
|
|
|
14
14
|
|
|
15
15
|
## Contents
|
|
16
16
|
|
|
17
|
-
- [What's new in v0.7 "Walk"](#whats-new-in-v07-walk)
|
|
18
|
-
- [What's new in v0.6 "Elbow Room"](#whats-new-in-v06-elbow-room)
|
|
19
|
-
- [What's new in v0.5 "Loop"](#whats-new-in-v05-loop)
|
|
20
|
-
- [What's new in v0.4 "Ledger"](#whats-new-in-v04-ledger)
|
|
21
|
-
- [Breaking Changes (v0.3.0 "Graphite")](#breaking-changes-v030-graphite)
|
|
22
17
|
- [Quick Start](#quick-start)
|
|
23
18
|
- [Steps to reproduce, recorded for you](#steps-to-reproduce-recorded-for-you)
|
|
24
|
-
- [Screenshots:
|
|
19
|
+
- [Screenshots: three engines](#screenshots-three-engines)
|
|
25
20
|
- [Saving to a folder](#saving-to-a-folder)
|
|
26
21
|
- [Where notes live, and what "storage full" means](#where-notes-live-and-what-storage-full-means)
|
|
27
22
|
- [Config Reference](#config-reference)
|
|
@@ -40,98 +35,10 @@ npm install qapture2
|
|
|
40
35
|
|
|
41
36
|
---
|
|
42
37
|
|
|
43
|
-
## What's new in v0.7 "Walk"
|
|
44
38
|
|
|
45
|
-
| | |
|
|
46
|
-
|---|---|
|
|
47
|
-
| **The Walk** | One guided sequence over either your test plan or your notes, with a **Take me there** button that actually navigates. Pressing a Guide step now walks from it. |
|
|
48
|
-
| **Walk the re-test queue** | Filter to Re-test, press Walk: each stop takes you to the page, lights up the spot, re-shoots it and takes your verdict. |
|
|
49
|
-
| **A link that starts it** | `?qa=walk:retest` opens the app with the re-test round already running — send that instead of instructions. |
|
|
50
|
-
| **"Doesn't apply"** | A third grade for plan steps that aren't relevant to this build. Removed from coverage totals rather than counted either way. |
|
|
51
|
-
| **Alt+1/2/3** | Set severity while typing a note. |
|
|
52
|
-
| **Session summary** | The export leads with "12 points · 5 bugs · 4 pages · over 38 minutes". |
|
|
53
|
-
|
|
54
|
-
**Two fixes from real use:** the widget could be hidden underneath an app's own high-z-index chrome (it now sits above everything, in its own stacking context, without ever swallowing a click), or removed outright by a framework clearing `<body>` (it now puts itself back). And the panel's open state, tab and walk position survive a reload — the notes always did, the *place in the work* didn't.
|
|
55
|
-
|
|
56
|
-
---
|
|
57
|
-
|
|
58
|
-
## What's new in v0.6 "Elbow Room"
|
|
59
|
-
|
|
60
|
-
| | |
|
|
61
|
-
|---|---|
|
|
62
|
-
| **Bulk actions** | Select many notes → mark them Open / Re-test / Verified, or delete them, in one pass with a single undo. |
|
|
63
|
-
| **Compact list** | One line per note, expanding in place — for when a session has thirty of them. |
|
|
64
|
-
| **Move the panel** | Dock it to the other edge, or collapse it to its header strip, so it stops covering the app you're testing. |
|
|
65
|
-
| **Whole-screen capture** | Grab everything visible without dragging a box across the screen. |
|
|
66
|
-
|
|
67
|
-
---
|
|
68
|
-
|
|
69
|
-
## What's new in v0.5 "Loop"
|
|
70
|
-
|
|
71
|
-
Not a breaking release. Notes from 0.3.x and 0.4.x read back unchanged.
|
|
72
|
-
|
|
73
|
-
| | |
|
|
74
|
-
|---|---|
|
|
75
|
-
| **Steps to reproduce, written for you** | Every note now carries what the tester clicked, typed into, toggled and navigated on the way to it. Never what they typed — see [below](#steps-to-reproduce-recorded-for-you). |
|
|
76
|
-
| **Draw on the screenshot** | Tap the shot, add an arrow / box / pen mark in one of four colours. Burned into the image, so it survives everywhere the screenshot goes. Never interrupts the capture flow. |
|
|
77
|
-
| **A capture shortcut** | `Alt+Shift+C` (`Option+Shift+C` on macOS) jumps straight into capture from anywhere; press again to back out. Configurable via `captureHotkey`. |
|
|
78
|
-
| **A re-test queue** | Note status is now Open → **Re-test** → Verified. "Re-test" is the state that tells a tester what to check on the next build, with a filter chip and a header badge so the queue can't be missed. |
|
|
79
|
-
| **Automatic backups** | A backup ZIP downloads every 5 notes, for everyone who can't use folder saving (Safari, Firefox, phones). Pauses itself while folder saving is on. |
|
|
80
|
-
| **Catches what you miss** | When the page throws an error or a request fails, Qapture offers a one-tap capture with the error already written in — the bug nobody reported because nobody saw it. |
|
|
81
|
-
| **Before / after on a re-test** | A note in the re-test queue gets a "Re-test now" button that re-shoots the same target, so "is it actually fixed?" is answered with a picture. |
|
|
82
|
-
| **Share (phones)** | Hands the campaign ZIP to the OS share sheet — WhatsApp, Mail, Files, AirDrop — because a "download" on a phone lands where nobody finds it. |
|
|
83
|
-
| **A welcome card** | Three lines, shown once, for someone who was just handed a beta link. |
|
|
84
|
-
|
|
85
|
-
---
|
|
86
|
-
|
|
87
|
-
## What's new in v0.4 "Ledger"
|
|
88
|
-
|
|
89
|
-
v0.4 is **not** a breaking release — every 0.3.x config, note and export keeps
|
|
90
|
-
working, and each new feature is off until someone turns it on.
|
|
91
|
-
|
|
92
|
-
| | |
|
|
93
|
-
|---|---|
|
|
94
|
-
| **Screenshots frame the right thing** | Capture mode's own scroll lock used `overflow:hidden`, which **unstuck every `position: sticky` header** just before the screenshot was rendered — measured at 20px of wrongness in a 40px capture, now 0.0px. See [Screenshots: two engines](#screenshots-two-engines). |
|
|
95
|
-
| **Pixel-exact capture (opt-in)** | A real photograph rather than a redraw — so canvas/WebGL, video, cross-origin iframes and exotic CSS all come out right. Taken the instant capture opens, then the screen is handed straight back: one frame per capture, nothing recording in between. Desktop browsers. |
|
|
96
|
-
| **Save straight to a folder** | Pick a QA folder once; every note is written to disk as it's saved, organised `Project / Campaign / notes + screenshots + REPORT.md`. See [Saving to a folder](#saving-to-a-folder). |
|
|
97
|
-
| **Storage that explains itself** | A real usage meter, WebP screenshots (~10× smaller), a request to stop the browser evicting your data, and a "drop screenshots, keep findings" recovery valve. |
|
|
98
|
-
| **A usable notes list** | Severity/status filter chips with counts, text search, and a "this page" toggle. |
|
|
99
|
-
| **Simple mode** | Hides Logins and Guide for a tester who was just handed a link. |
|
|
100
|
-
| **Minimized capture** | A small box next to your selection instead of the full card — type, Enter, move on. |
|
|
101
|
-
|
|
102
|
-
---
|
|
103
39
|
|
|
104
|
-
## Breaking Changes (v0.3.0 "Graphite")
|
|
105
40
|
|
|
106
|
-
**v0.3.0 is a breaking release.**
|
|
107
41
|
|
|
108
|
-
- **Custom themes are removed.** The widget now ships one fixed, self-contained
|
|
109
|
-
dark design ("Graphite") — there is no more per-project colour override. A
|
|
110
|
-
`theme` key left in `qa.config` is no longer read; `validateConfig` ignores
|
|
111
|
-
it and pushes this exact warning:
|
|
112
|
-
|
|
113
|
-
> theme: custom themes were removed in Qapture 0.3.0 — the widget now ships
|
|
114
|
-
> one fixed, self-contained design. The "theme" key is ignored; remove it
|
|
115
|
-
> from your qa.config to silence this warning.
|
|
116
|
-
|
|
117
|
-
Delete the `theme` block from your config — see the updated
|
|
118
|
-
[`examples/minimal.config.ts`](./examples/minimal.config.ts) and
|
|
119
|
-
[`examples/stitch-and-sell.config.ts`](./examples/stitch-and-sell.config.ts),
|
|
120
|
-
both of which had their `theme` block removed entirely. The `QaTheme` type
|
|
121
|
-
is still exported so old config objects keep type-checking, but it is
|
|
122
|
-
`@deprecated` and has no runtime effect — see [`QaTheme`](#qatheme-deprecated).
|
|
123
|
-
- **New:** a guided, step-by-step walkthrough over your journey ("test-along"),
|
|
124
|
-
severity + status on notes, a one-click "Copy as agent prompt", and an
|
|
125
|
-
undo-capable delete/clear system. See the sections below.
|
|
126
|
-
- **New, and worth reading if you care about privacy:** an (on-by-default,
|
|
127
|
-
opt-out) runtime context capture that records recent console errors and
|
|
128
|
-
failed network calls into each note. See
|
|
129
|
-
[Runtime Context Capture](#runtime-context-capture) and
|
|
130
|
-
[SECURITY.md § Runtime context capture](./SECURITY.md#runtime-context-capture).
|
|
131
|
-
|
|
132
|
-
Full details: [CHANGELOG.md](./CHANGELOG.md#030-graphite--unreleased).
|
|
133
|
-
|
|
134
|
-
---
|
|
135
42
|
|
|
136
43
|
## Quick Start
|
|
137
44
|
|
|
@@ -265,168 +172,124 @@ capture — no listener is installed at all. The complete guarantees are in
|
|
|
265
172
|
|
|
266
173
|
---
|
|
267
174
|
|
|
268
|
-
## Screenshots:
|
|
175
|
+
## Screenshots: three engines
|
|
176
|
+
|
|
177
|
+
Every engine crops the exact viewport rectangle you selected. They differ in
|
|
178
|
+
where the pixels come from, and that difference is the whole story.
|
|
269
179
|
|
|
270
|
-
|
|
271
|
-
|
|
180
|
+
| | Prompts you | Real pixels | Works in |
|
|
181
|
+
|---|---|---|---|
|
|
182
|
+
| **`native`** — local helper | never | yes | any browser, macOS |
|
|
183
|
+
| **`exact`** — browser screen capture | every capture | yes | Chromium, Safari, Firefox |
|
|
184
|
+
| **`dom`** — html2canvas redraw | never | no, a reconstruction | everywhere |
|
|
272
185
|
|
|
273
|
-
|
|
186
|
+
Qapture picks the best one available and tells you in the capture card which
|
|
187
|
+
one it used.
|
|
274
188
|
|
|
275
|
-
|
|
276
|
-
rasterises it. No permission prompt, works in every browser, and it is the
|
|
277
|
-
only option on Firefox, Safari and mobile.
|
|
189
|
+
### `native` — real screenshots, no prompt (recommended, macOS)
|
|
278
190
|
|
|
279
|
-
|
|
280
|
-
|
|
191
|
+
Run this next to your dev server and leave it going:
|
|
192
|
+
|
|
193
|
+
```bash
|
|
194
|
+
npx qapture2 shots
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
It drives `/usr/sbin/screencapture` — the binary behind Cmd+Shift+4. macOS
|
|
198
|
+
asks the terminal for Screen Recording permission **once**, and never again.
|
|
199
|
+
|
|
200
|
+
That single fact is why this engine exists. `getDisplayMedia`, which the
|
|
201
|
+
`exact` engine uses, prompts on *every* call by design; no flag or prior grant
|
|
202
|
+
changes it. Each prompt restarts the OS capture pipeline, which on a laptop is
|
|
203
|
+
heat and a machine that feels like it is recording continuously. The helper
|
|
204
|
+
takes a picture and exits — nothing is left running between shots.
|
|
205
|
+
|
|
206
|
+
The widget finds it automatically. Nothing to configure, and nothing to turn
|
|
207
|
+
on in Settings, because there is no prompt to opt into.
|
|
208
|
+
|
|
209
|
+
**What it will answer.** It binds to `127.0.0.1` only, so nothing off your
|
|
210
|
+
machine can reach it. It answers `http://localhost:*` and `http://127.0.0.1:*`
|
|
211
|
+
without being asked. Any other origin — a staging site you are testing
|
|
212
|
+
against, say — must be named explicitly:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
npx qapture2 shots --allow https://staging.example.com
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Origins not on that list get no CORS headers at all, so the browser blocks the
|
|
219
|
+
request before the page sees a reply. Add `--port 7018` (and `shotPort: 7018`
|
|
220
|
+
in your config) if 7017 is taken.
|
|
221
|
+
|
|
222
|
+
**If captures come back as wallpaper with no windows in them**, the permission
|
|
223
|
+
was not granted: System Settings → Privacy & Security → Screen Recording, tick
|
|
224
|
+
your terminal, restart it.
|
|
225
|
+
|
|
226
|
+
### `exact` — real pixels, at a prompt per screenful
|
|
227
|
+
|
|
228
|
+
The browser's own Screen Capture API. Turn it on from the capture hint bar
|
|
229
|
+
("Pixel-exact shots") or Settings; turning it on does not prompt, the first
|
|
230
|
+
capture does.
|
|
231
|
+
|
|
232
|
+
One grant covers several notes: "Save + next" (⌘/Ctrl + Shift + Enter) files
|
|
233
|
+
the note and puts you straight back to framing the same photograph. Worth
|
|
234
|
+
knowing in Safari, where the per-site Screen Sharing setting offers only *Ask*
|
|
235
|
+
and *Deny* — there is no *Allow*, so the only lever is needing fewer captures.
|
|
236
|
+
|
|
237
|
+
Chromium shares this tab directly (`preferCurrentTab`), so the frame *is* the
|
|
238
|
+
viewport — measured at 0.0px error. Safari and Firefox can only share a window
|
|
239
|
+
or a screen; see below for how the page is found inside that.
|
|
240
|
+
|
|
241
|
+
### `dom` — the fallback, works everywhere
|
|
242
|
+
|
|
243
|
+
html2canvas re-renders a clone of your DOM and rasterises it. No prompt, every
|
|
244
|
+
browser, and the only option on mobile. Because it is a reconstruction rather
|
|
245
|
+
than a photograph:
|
|
281
246
|
|
|
282
247
|
- `<canvas>` / WebGL, `<video>` and cross-origin `<iframe>` content cannot be
|
|
283
|
-
read and
|
|
248
|
+
read, and come out blank or approximated;
|
|
284
249
|
- CSS the cloner doesn't implement (some `backdrop-filter`, `mask`, exotic
|
|
285
250
|
gradients) renders differently;
|
|
286
|
-
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
raw `getBoundingClientRect()`, and a table column, a sidebar, a long form or a
|
|
322
|
-
wide toolbar routinely extends past the fold. You got a fragment. And when the
|
|
323
|
-
element started *above* the viewport, the crop slid down the page to fill its
|
|
324
|
-
height, so the screenshot was the right size showing the wrong content — a
|
|
325
|
-
failure with nothing on screen to reveal it.
|
|
326
|
-
|
|
327
|
-
Captures now render the union of the viewport and the selection, so an element
|
|
328
|
-
that leaves the screen in any direction is rendered whole, up to 4000px per
|
|
329
|
-
side (past a ~64 MB device-pixel render budget the scale drops, not the
|
|
330
|
-
framing). The exact engine can't photograph off-screen pixels, so there the
|
|
331
|
-
selection is trimmed to the visible part instead — cropped, never displaced.
|
|
332
|
-
`npm run element-capture-test` measures all four cases.
|
|
333
|
-
|
|
334
|
-
**v0.7.3 corrected the half of that which was wrong.** Chasing an element's
|
|
335
|
-
whole box is only right when the whole box is *drawn*. Inside a scroll
|
|
336
|
-
container it isn't: a dashboard scrolls an inner `overflow:auto` box, so a
|
|
337
|
-
3000px column inside a 700px box is 700px of pixels and 2300px of nothing.
|
|
338
|
-
0.7.2 rendered the nothing — measured at 23.3% element, 76.7% empty page, with
|
|
339
|
-
the real content squeezed from 1040px wide to 312px by the long-edge cap.
|
|
340
|
-
|
|
341
|
-
Captures are now clipped to what the browser actually paints: the element's box
|
|
342
|
-
intersected with every ancestor that clips it, on either axis, up to `<html>`.
|
|
343
|
-
The viewport is deliberately not a clipper, so a long form on an ordinary
|
|
344
|
-
scrolling page still captures in full. Same fixture after: 100% element, full
|
|
345
|
-
1040×1400. The hover outline is clipped identically, so what you highlight is
|
|
346
|
-
what you get.
|
|
347
|
-
|
|
348
|
-
### "The screenshot looks simulated"
|
|
349
|
-
|
|
350
|
-
Because by default it is. The DOM engine re-draws your page; fonts shift,
|
|
351
|
-
shadows and gradients flatten, `<canvas>` and video come out blank. From
|
|
352
|
-
v0.7.3 a redrawn capture says so under the preview and offers a one-tap **Use
|
|
353
|
-
real screenshots**, which grants tab-share and re-shoots the same selection
|
|
354
|
-
with the exact engine below.
|
|
355
|
-
|
|
356
|
-
**From v0.7.6 this works in Safari and Firefox too.** They have no tab capture,
|
|
357
|
-
but they can share a *window*, and Qapture works out where your page sits
|
|
358
|
-
inside that frame — by measuring, not by guessing at toolbar heights. On the
|
|
359
|
-
first capture the page is covered for a fifth of a second by a dark card with
|
|
360
|
-
four coloured corners; the engine photographs it, finds the corners and solves
|
|
361
|
-
for the mapping. That dark flash is the measurement. If it can't verify the
|
|
362
|
-
result it refuses the grant and falls back to redrawing, because a screenshot
|
|
363
|
-
of the wrong pixels is worse than no screenshot.
|
|
364
|
-
|
|
365
|
-
Chromium still takes the direct path (`preferCurrentTab`), unchanged and still
|
|
366
|
-
0.0px. Only iOS/iPadOS have no Screen Capture API at all, and there the card
|
|
367
|
-
says so.
|
|
368
|
-
|
|
369
|
-
**If your app draws anything with inline SVG, a `<canvas>`, or video, turn real
|
|
370
|
-
screenshots on.** A redraw will render an SVG chart as bare outlines and a
|
|
371
|
-
canvas as a blank box, every time, in any tool built this way.
|
|
372
|
-
|
|
373
|
-
### `exact` — opt-in, pixel-for-pixel
|
|
374
|
-
|
|
375
|
-
Uses the Screen Capture API to photograph **the viewport's real composited
|
|
376
|
-
pixels**, then crops your rectangle out arithmetically. Nothing is
|
|
377
|
-
re-rendered, so it cannot mis-frame, and everything above renders correctly
|
|
378
|
-
because it was never re-drawn in the first place.
|
|
379
|
-
|
|
380
|
-
**The photograph is taken when you open capture mode, not when you finish
|
|
381
|
-
dragging.** That ordering is the whole design, and it decides three things at
|
|
382
|
-
once:
|
|
383
|
-
|
|
384
|
-
- **Nothing keeps recording.** The stream is acquired, one frame is taken, and
|
|
385
|
-
the track is stopped — about a third of a second — so the browser's sharing
|
|
386
|
-
indicator blinks and goes. Before 0.8 the stream was held for the entire
|
|
387
|
-
session so it would only prompt once, which on Safari (where the only option
|
|
388
|
-
is sharing a window or a whole screen) meant the indicator stayed lit and the
|
|
389
|
-
capture pipeline kept running behind every page. One prompt per capture is
|
|
390
|
-
the price of not recording you between them.
|
|
391
|
-
- **You crop what you can see.** The still is shown under the capture scrim
|
|
392
|
-
while you frame, so a page that animates cannot move between the moment you
|
|
393
|
-
point at something and the moment it is cropped — and a hover state, an open
|
|
394
|
-
dropdown or a tooltip survives being framed instead of being dismissed by the
|
|
395
|
-
mouse moving to start the drag.
|
|
396
|
-
- **Whether this shot is a photograph or a redraw is settled before you
|
|
397
|
-
start.** A still is either held or it is not. Previously the exact engine
|
|
398
|
-
reached for a frame at the end, from a stream that could quietly have died,
|
|
399
|
-
and fell through to `dom` without saying so — which is why the same click
|
|
400
|
-
could photograph one time and redraw the next.
|
|
401
|
-
|
|
402
|
-
Everything else:
|
|
403
|
-
|
|
404
|
-
- **Turn it on** from the capture hint bar ("Pixel-exact shots") or Settings.
|
|
405
|
-
Turning it on does not prompt; the first capture does.
|
|
406
|
-
- **One prompt can cover several notes.** "Save + next" on the annotation card
|
|
407
|
-
(⌘/Ctrl + Shift + Enter) files the note and puts you back to framing the same
|
|
408
|
-
photograph. Worth knowing in **Safari**, where the per-site Screen Sharing
|
|
409
|
-
setting offers only *Ask* and *Deny* — there is no *Allow*, so every capture
|
|
410
|
-
prompts and the only lever is needing fewer captures. Three bugs on one
|
|
411
|
-
screen, one prompt.
|
|
412
|
-
- Nothing leaves the device — the frame is cropped locally and never uploaded.
|
|
251
|
+
- an element inside a scroll container is clipped to what is actually painted,
|
|
252
|
+
because the rest of it does not exist as pixels anywhere.
|
|
253
|
+
|
|
254
|
+
If a shot looks simulated rather than photographed, this is the engine that
|
|
255
|
+
took it — start the helper above and it will not be.
|
|
256
|
+
|
|
257
|
+
### How a photograph is aligned to the page
|
|
258
|
+
|
|
259
|
+
`native` and `exact`-on-Safari/Firefox both hand back a frame containing the
|
|
260
|
+
browser's toolbar, and maybe a whole desktop. Working out where the page sits
|
|
261
|
+
inside that by arithmetic (`outerHeight - innerHeight`, `screenX`,
|
|
262
|
+
`devicePixelRatio`) is a stack of guesses, and a wrong guess is a screenshot
|
|
263
|
+
confidently showing the *wrong pixels* — worse than no screenshot, because
|
|
264
|
+
nobody double-checks one that looks fine.
|
|
265
|
+
|
|
266
|
+
So Qapture measures instead. It covers the page with an opaque card carrying
|
|
267
|
+
four known colours at four known corners, photographs that, and solves for
|
|
268
|
+
scale and origin from where the colours landed. Toolbar height, pixel ratio
|
|
269
|
+
and monitor layout never enter the arithmetic, so they cannot be wrong in it.
|
|
270
|
+
You see a dark flash for a fifth of a second.
|
|
271
|
+
|
|
272
|
+
Two corners solve the mapping and the other two verify it. **A calibration
|
|
273
|
+
that cannot be verified is refused** — the frame is dropped and the capture
|
|
274
|
+
falls back to `dom`, visibly, rather than returning a confidently wrong image.
|
|
275
|
+
|
|
276
|
+
On the `native` path the measurement is cached against the window's geometry,
|
|
277
|
+
so that flash happens once a session rather than once a capture.
|
|
278
|
+
|
|
279
|
+
### Common to both photograph engines
|
|
280
|
+
|
|
281
|
+
- **The picture is taken when you enter capture mode, not when you finish
|
|
282
|
+
dragging.** You then crop a frozen still, so the page cannot move under you,
|
|
283
|
+
and a hover state, an open dropdown or a tooltip survives being framed
|
|
284
|
+
instead of being dismissed by the mouse moving to start the drag.
|
|
285
|
+
- Nothing leaves the device. The frame is cropped locally and never uploaded.
|
|
413
286
|
- The QA overlay is hidden for the captured frame, so the scrim, the selection
|
|
414
287
|
outline and the annotation card never appear in the image.
|
|
415
|
-
- **Chromium** shares this tab directly (`preferCurrentTab`), so the frame *is*
|
|
416
|
-
the viewport — measured at 0.0px error.
|
|
417
|
-
- **Safari and Firefox** have no tab capture, only a window or a screen. That
|
|
418
|
-
frame does contain the page, and Qapture finds it by *measuring*: it covers
|
|
419
|
-
the page with an opaque card carrying four known colours at four known
|
|
420
|
-
corners, photographs that, and solves for scale and origin from where the
|
|
421
|
-
colours landed. Toolbar height, pixel ratio and monitor layout all cancel
|
|
422
|
-
out. You see a dark flash for a fifth of a second. Two corners solve and the
|
|
423
|
-
other two verify — and a calibration that cannot be verified is **refused**,
|
|
424
|
-
falling back to `dom` rather than returning a confidently wrong image.
|
|
425
288
|
- The still belongs to the viewport it was taken in. Resize the window
|
|
426
|
-
mid-capture and the crop is refused
|
|
289
|
+
mid-capture and the crop is refused rather than guessed.
|
|
427
290
|
- Off-screen pixels do not exist in a photograph at any price, so a selection
|
|
428
|
-
|
|
429
|
-
|
|
291
|
+
running past the fold is trimmed to what was visible. `dom` re-renders and
|
|
292
|
+
has no such limit.
|
|
430
293
|
|
|
431
294
|
---
|
|
432
295
|
|
|
@@ -531,7 +394,8 @@ All fields are optional. Passing an empty object (or no config at all) produces
|
|
|
531
394
|
| Field | Type | Default | Description |
|
|
532
395
|
|---|---|---|---|
|
|
533
396
|
| `namespace` | `string` | `'qapture'` | Prefix for IndexedDB (`${namespace}-db`) and localStorage keys (`${namespace}:*`). Use a unique value per project to avoid storage collisions on the same origin. |
|
|
534
|
-
| `
|
|
397
|
+
| `shotPort` | `number` | `7017` | Where `npx qapture2 shots` is listening. Only needed if you started the helper on another port. |
|
|
398
|
+
| `theme` | `Partial<QaTheme>` (**deprecated, ignored**) | — | **Removed in v0.3.0.** `validateConfig` ignores this key (after pushing a warning) — the widget always renders the fixed Graphite design. Delete it from your config. |
|
|
535
399
|
| `brand` | `{ label?: string }` | `{ label: 'Qapture' }` | Panel heading label. |
|
|
536
400
|
| `loginField` | `{ en: string; ar?: string }` | `{ en: 'Username', ar: 'اسم المستخدم' }` | Display label for the login column in the Credentials tab. |
|
|
537
401
|
| `credentials` | `QaCredential[]` | `[]` | DEV/TEST/SEED login rows shown in the Credentials tab. |
|
|
@@ -540,8 +404,8 @@ All fields are optional. Passing an empty object (or no config at all) produces
|
|
|
540
404
|
| `rtl` | `boolean` | `false` | When `true`, the UI initialises in Arabic / RTL mode. |
|
|
541
405
|
| `visible` | `boolean \| undefined` | `undefined` | `true` = always show; `false` = always hide; `undefined` = dev-only (hidden in production). |
|
|
542
406
|
| `alwaysVisible` | `boolean` | `false` | When `true`, overrides `visible` and shows the panel even in production. |
|
|
543
|
-
| `hotkey` | `string` | `'shift+alt+q'` |
|
|
544
|
-
| `captureHotkey` | `string` | `'shift+alt+c'`
|
|
407
|
+
| `hotkey` | `string` | `'shift+alt+q'` | Keyboard shortcut that toggles the panel open/closed. |
|
|
408
|
+
| `captureHotkey` | `string` | `'shift+alt+c'` | Keyboard shortcut that jumps straight into capture mode. |
|
|
545
409
|
| `captureContext` | `boolean` | `true` | Whether to record ambient runtime context (recent console errors/warnings, uncaught errors, failed network calls, and an environment snapshot) into each note as it's captured. Set to `false` to disable entirely. See [Runtime Context Capture](#runtime-context-capture). |
|
|
546
410
|
|
|
547
411
|
### `QaTheme` (deprecated)
|
|
@@ -806,18 +670,24 @@ The CLI scaffolds `qa.config`, the agent skill, and `AGENTS.md` into any reposit
|
|
|
806
670
|
|
|
807
671
|
```bash
|
|
808
672
|
npx qapture2 init [target-dir] [--force]
|
|
673
|
+
npx qapture2 shots [--port 7017] [--allow <origin>]
|
|
809
674
|
npx qapture2 version
|
|
810
675
|
```
|
|
811
676
|
|
|
812
677
|
`target-dir` defaults to the current directory. `--force` overwrites existing `qa.config.*` and `qa.preamble.md` (SKILL.md is always refreshed regardless).
|
|
813
678
|
|
|
679
|
+
`shots` is the local screenshot helper — a loopback server that runs
|
|
680
|
+
`screencapture` so screenshots are real photographs and never prompt. macOS
|
|
681
|
+
only; see [Screenshots](#screenshots-three-engines). It is the one command
|
|
682
|
+
here that keeps running: leave it up while you test.
|
|
683
|
+
|
|
814
684
|
### What it detects and generates
|
|
815
685
|
|
|
816
686
|
| Step | What happens |
|
|
817
687
|
|---|---|
|
|
818
688
|
| Route detection | Scans `src/`, `app/`, `pages/` for route files; generates journey lanes with placeholder `'green'` steps for you to grade |
|
|
819
689
|
| Credential detection | Scans `.env.example` and seeder/seed files for test logins. **Never reads `.env`, `.env.local`, `.env.production`, or any real secrets file** — enforced by a hard blocklist |
|
|
820
|
-
| `qa.config.js` / `.ts` | Generated based on detections; contains TODO comments for manual grading. No `theme` block is emitted — v0.3.0 removed custom themes entirely (see
|
|
690
|
+
| `qa.config.js` / `.ts` | Generated based on detections; contains TODO comments for manual grading. No `theme` block is emitted — v0.3.0 removed custom themes entirely (see CHANGELOG) |
|
|
821
691
|
| `qa.preamble.md` | Starter preamble file; fill with project context and paste into `config.preamble` |
|
|
822
692
|
| `.claude/skills/qapture/SKILL.md` | Claude Code agent skill (always refreshed — this is a vendor artifact) |
|
|
823
693
|
| `AGENTS.md` | Idempotent merge with sentinel guards; safe to run repeatedly |
|