@drakulavich/zapara 0.7.3 → 0.7.4

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/CHANGELOG.md CHANGED
@@ -5,6 +5,16 @@ All notable changes to this project are documented here. The format follows
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [0.7.4] - 2026-09-26
9
+
10
+ ### Changed
11
+ - On a high-density screen, `zapara card` draws the picture at its final size
12
+ instead of at double size and scaling it down. The PNG render on a Mac went
13
+ from about 3.4 s to 1.6 s. The picture is the same.
14
+
15
+ ### Fixed
16
+ - `--verbose` no longer counts the wait at `open it? [Y/n]` in the `total` row.
17
+
8
18
  ## [0.7.3] - 2026-09-26
9
19
 
10
20
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@drakulavich/zapara",
3
- "version": "0.7.3",
3
+ "version": "0.7.4",
4
4
  "description": "Cognitive load index for people driving Claude Code, computed locally from transcripts",
5
5
  "license": "MIT",
6
6
  "author": "Anton Yakutovich",
package/src/image.ts CHANGED
@@ -41,9 +41,19 @@ export async function renderCard(html: string, out: string, timeoutMs = 15_000):
41
41
  try {
42
42
  bytes = await Promise.race([
43
43
  (async () => {
44
- const view = new Bun.WebView({ width: WIDTH, height: HEIGHT, backend: BACKEND });
44
+ // WebKit draws at the screen's density: at 2x, a 2400-wide viewport made a
45
+ // 4800-wide shot, 2.2 s of a 3 s render. The viewport and the page's zoom
46
+ // (2 in cardHtml) shrink by the density, so the shot is 2400 wide already.
47
+ // Headless Chrome (or Edge) shoots at 1x and cannot evaluate before a navigate.
48
+ let dpr = 1;
49
+ if (BACKEND === "webkit") {
50
+ const probe = new Bun.WebView({ width: 1, height: 1, backend: BACKEND });
51
+ try { dpr = await probe.evaluate<number>("devicePixelRatio"); } finally { probe.close(); }
52
+ }
53
+ const view = new Bun.WebView({ width: Math.round(WIDTH / dpr), height: Math.round(HEIGHT / dpr), backend: BACKEND });
45
54
  try {
46
55
  await view.navigate("data:text/html;charset=utf-8," + encodeURIComponent(html));
56
+ await view.evaluate(`document.documentElement.style.zoom = "${2 / dpr}"`);
47
57
  while (!(await view.evaluate<boolean>(READY))) await Bun.sleep(50);
48
58
  const shot = await view.screenshot({ encoding: "buffer", format: "png" });
49
59
  const image = new Bun.Image(shot);
package/src/index.ts CHANGED
@@ -236,6 +236,7 @@ async function card(a: Args, timing?: Timing): Promise<number> {
236
236
  }
237
237
  if (timing) timing.render = { format: target.path.slice(target.path.lastIndexOf(".") + 1).toLowerCase(), ms: performance.now() - t };
238
238
  console.log(`${data.name}: ${sentenceText(data.sentence)}\nwrote ${target.label}`);
239
+ if (timing) timing.totalMs = performance.now(); // the wait for an answer is not zapara's time
239
240
  if (process.stdin.isTTY && process.stdout.isTTY && process.platform !== "win32") {
240
241
  process.stdout.write("open it? [Y/n] ");
241
242
  let answer: string | null = null;
@@ -256,7 +257,7 @@ function timingLines(t: Timing): string {
256
257
  + row("read", `${plural(t.read, "file")}, ${(t.bytes / 1e6).toFixed(1)} MB, ${READERS} at a time`, t.readMs)
257
258
  + row("analyze", "", t.analyzeMs)
258
259
  + (t.render ? row("render", t.render.format, t.render.ms) : "")
259
- + row("total", "", performance.now());
260
+ + row("total", "", t.totalMs ?? performance.now());
260
261
  }
261
262
 
262
263
  if (import.meta.main) {
package/src/report.ts CHANGED
@@ -6,7 +6,7 @@ import type { Day, Transcript } from "./types.ts";
6
6
 
7
7
  export type ReportOptions = { projects: string; to: string; days: number; now?: Date };
8
8
  // What --verbose prints about a run: counts and milliseconds, never a path.
9
- export type Timing = ScanStats & { inWindow: number; read: number; bytes: number; scanMs: number; readMs: number; analyzeMs: number; render?: { format: string; ms: number } };
9
+ export type Timing = ScanStats & { inWindow: number; read: number; bytes: number; scanMs: number; readMs: number; analyzeMs: number; render?: { format: string; ms: number }; totalMs?: number };
10
10
 
11
11
  // Reading one file at a time left the disk idle between files: 1.6 GB took 5.4 s
12
12
  // sequentially and 0.9 s in parallel. The cap keeps open files well under the limit.