@flemo/devtools 0.7.0 → 0.8.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 +7 -5
- package/dist/hud.d.ts +14 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +369 -347
- package/dist/noop.d.ts +1 -1
- package/dist/noop.mjs +5 -7
- package/dist/panel/styles.d.ts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.mjs +394 -372
- package/dist/surface.d.ts +0 -8
- package/package.json +2 -2
package/dist/index.mjs
CHANGED
|
@@ -174,7 +174,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
174
174
|
}), oe = (e) => e.some((e) => {
|
|
175
175
|
let t = e.getAttribute(m);
|
|
176
176
|
return t !== null && L.has(t);
|
|
177
|
-
}),
|
|
177
|
+
}), R = (e) => `${e.transform}/${e.opacity}`, se = (e, t, n) => {
|
|
178
178
|
e.releasedFrames += 1;
|
|
179
179
|
let r = !1, i = !1;
|
|
180
180
|
for (let n of t) {
|
|
@@ -188,7 +188,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
188
188
|
}
|
|
189
189
|
}
|
|
190
190
|
let a = n.style;
|
|
191
|
-
a && a.animation !== "" && e.lastPose.get(n) !==
|
|
191
|
+
a && a.animation !== "" && e.lastPose.get(n) !== R(a) && (r = !0);
|
|
192
192
|
}
|
|
193
193
|
if (!(e.releasedFrames < re)) {
|
|
194
194
|
if (r) {
|
|
@@ -201,17 +201,17 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
201
201
|
}
|
|
202
202
|
e.stalledFrames += 1, e.stallRunMs += n, e.stallRunMs > e.longestStallMs && (e.longestStallMs = e.stallRunMs);
|
|
203
203
|
}
|
|
204
|
-
},
|
|
204
|
+
}, z = (e, t) => {
|
|
205
205
|
let n = t.style;
|
|
206
206
|
if (!n || n.animation === "") return;
|
|
207
207
|
e.evidence.inlineSuppression = !0;
|
|
208
|
-
let r =
|
|
208
|
+
let r = R(n), i = e.lastPose.get(t);
|
|
209
209
|
i !== void 0 && i !== r && (e.evidence.inlineAdvance = !0), e.lastPose.set(t, r);
|
|
210
|
-
},
|
|
210
|
+
}, B = (e, t) => {
|
|
211
211
|
for (let n of t) {
|
|
212
212
|
let t = n.getAnimations, r = e.clocks.get(n);
|
|
213
213
|
if (r !== void 0 && r.playState !== "finished") {
|
|
214
|
-
r.playState === "running" && (e.evidence.compiledAnimation = !0),
|
|
214
|
+
r.playState === "running" && (e.evidence.compiledAnimation = !0), z(e, n);
|
|
215
215
|
continue;
|
|
216
216
|
}
|
|
217
217
|
if (typeof t == "function") try {
|
|
@@ -220,40 +220,40 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
220
220
|
typeof t == "string" && t.startsWith("flemo-") && (e.clocks.set(n, r), r.playState === "running" && (e.evidence.compiledAnimation = !0));
|
|
221
221
|
}
|
|
222
222
|
} catch {}
|
|
223
|
-
|
|
223
|
+
z(e, n);
|
|
224
224
|
}
|
|
225
|
-
},
|
|
225
|
+
}, ce = (e) => ({
|
|
226
226
|
sampledFrames: e.releasedFrames,
|
|
227
227
|
stalledFrames: e.stalledFrames,
|
|
228
228
|
longestStallMs: ie(e.longestStallMs),
|
|
229
229
|
pausedAfterRelease: e.pausedAfterRelease,
|
|
230
230
|
holdReassertedAtMs: e.holdReassertedAtMs,
|
|
231
231
|
tailFrames: e.tailFrames
|
|
232
|
-
}),
|
|
232
|
+
}), V = 200, H = (e) => {
|
|
233
233
|
let t = [];
|
|
234
234
|
for (let n of e) for (let e of Array.from(n.querySelectorAll("img"))) t.push(e);
|
|
235
235
|
return t;
|
|
236
|
-
},
|
|
237
|
-
let t = new Set(
|
|
236
|
+
}, le = (e) => {
|
|
237
|
+
let t = new Set(H(e).filter((e) => !e.complete));
|
|
238
238
|
return {
|
|
239
239
|
tracked: t,
|
|
240
240
|
loadingAtStart: t.size,
|
|
241
241
|
addedDuringFlight: 0,
|
|
242
242
|
held: /* @__PURE__ */ new Set()
|
|
243
243
|
};
|
|
244
|
-
},
|
|
245
|
-
if (!(e.tracked.size >=
|
|
244
|
+
}, ue = (e, t, n) => {
|
|
245
|
+
if (!(e.tracked.size >= V)) for (let r of Array.from(n)) {
|
|
246
246
|
if (!(r instanceof Element) || !t.some((e) => e === r || e.contains(r))) continue;
|
|
247
247
|
let n = r instanceof HTMLImageElement ? [r] : Array.from(r.querySelectorAll("img"));
|
|
248
248
|
for (let t of n) if (!(t.complete || e.tracked.has(t))) {
|
|
249
|
-
if (e.tracked.size >=
|
|
249
|
+
if (e.tracked.size >= V) return;
|
|
250
250
|
e.tracked.add(t), e.addedDuringFlight += 1;
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
-
},
|
|
253
|
+
}, de = (e, t) => {
|
|
254
254
|
for (let n of t) for (let t of Array.from(n.querySelectorAll(`img[${h}]`))) e.held.add(t);
|
|
255
255
|
for (let t of e.tracked) t.hasAttribute("data-flemo-img-hold") && e.held.add(t);
|
|
256
|
-
},
|
|
256
|
+
}, fe = (e) => {
|
|
257
257
|
let t = 0, n = 0;
|
|
258
258
|
for (let r of e.tracked) r.complete && (t += 1, e.held.has(r) || (n += 1));
|
|
259
259
|
return {
|
|
@@ -263,12 +263,12 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
263
263
|
heldDuringFlight: e.held.size,
|
|
264
264
|
completedUnheld: n
|
|
265
265
|
};
|
|
266
|
-
},
|
|
266
|
+
}, pe = [
|
|
267
267
|
"DevTools must be CLOSED while judging motion. An open inspector serializes requests and repaints its own panels on the same machine; the 2026-08 campaign's entire residual 'stutter' was this, and it is invisible to every in-page metric.",
|
|
268
268
|
"No screen recording or display capture while judging. A capture client forces WindowServer to composite every vsync, which SUPPRESSES the symptom — a capture that looks smooth proves nothing about the uncaptured session.",
|
|
269
269
|
"Judge with real input (a finger, a mouse). Synthetic dispatch — evaluate().click() and friends — never fires pointerdown, so it bypasses the swipe/gesture machinery that a real navigation goes through.",
|
|
270
270
|
"Establish the viewing configuration before believing any verdict: device emulation off, which physical display, its refresh rate and HiDPI scaling, Low Power Mode. Ask for a photo of the setup if it is not certain."
|
|
271
|
-
],
|
|
271
|
+
], U = (e) => Math.round(e * 10) / 10, me = (e) => {
|
|
272
272
|
if (e.length === 0) return {
|
|
273
273
|
count: 0,
|
|
274
274
|
medianGapMs: 0,
|
|
@@ -278,11 +278,11 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
278
278
|
let t = [...e].sort((e, t) => e - t);
|
|
279
279
|
return {
|
|
280
280
|
count: e.length,
|
|
281
|
-
medianGapMs:
|
|
282
|
-
maxGapMs:
|
|
281
|
+
medianGapMs: U(t[Math.floor(t.length / 2)]),
|
|
282
|
+
maxGapMs: U(t[t.length - 1]),
|
|
283
283
|
over30Count: e.filter((e) => e >= 30).length
|
|
284
284
|
};
|
|
285
|
-
},
|
|
285
|
+
}, he = (e, t = []) => {
|
|
286
286
|
let n = [...e, ...t];
|
|
287
287
|
return {
|
|
288
288
|
...n.length === 0 ? {
|
|
@@ -293,18 +293,18 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
293
293
|
let e = [...n].sort((e, t) => e - t);
|
|
294
294
|
return {
|
|
295
295
|
count: n.length,
|
|
296
|
-
medianGapMs:
|
|
297
|
-
maxGapMs:
|
|
296
|
+
medianGapMs: U(e[Math.floor(e.length / 2)]),
|
|
297
|
+
maxGapMs: U(e[e.length - 1])
|
|
298
298
|
};
|
|
299
299
|
})(),
|
|
300
|
-
longGaps: n.filter((e) => e >= 30).map(
|
|
301
|
-
held:
|
|
302
|
-
released:
|
|
300
|
+
longGaps: n.filter((e) => e >= 30).map(U),
|
|
301
|
+
held: me(e),
|
|
302
|
+
released: me(t)
|
|
303
303
|
};
|
|
304
|
-
},
|
|
304
|
+
}, ge = (e) => {
|
|
305
305
|
let t = e.inlineSuppression || e.inlineAdvance;
|
|
306
306
|
return t && e.compiledAnimation ? "mixed" : t ? "inline" : e.compiledAnimation ? "compiled" : "unknown";
|
|
307
|
-
},
|
|
307
|
+
}, _e = (e) => e === "PUSHING" ? "PUSH" : e === "POPPING" ? "POP" : e === "REPLACING" ? "REPLACE" : null, ve = (e) => {
|
|
308
308
|
let t = /^matrix3d\(([^)]+)\)$/.exec(e.trim());
|
|
309
309
|
if (t) {
|
|
310
310
|
let e = t[1].split(",").map((e) => Number(e.trim()));
|
|
@@ -316,7 +316,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
316
316
|
return e.length === 6 && Number.isFinite(e[4]) ? e[4] : null;
|
|
317
317
|
}
|
|
318
318
|
return null;
|
|
319
|
-
},
|
|
319
|
+
}, W = (e) => {
|
|
320
320
|
if (e) return [];
|
|
321
321
|
let t = [];
|
|
322
322
|
for (let [e, n] of [[h, "image reveal hold"], [g, "arrival hold"]]) {
|
|
@@ -324,7 +324,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
324
324
|
r > 0 && t.push(`${r} × ${n} (${e}) still marked at rest`);
|
|
325
325
|
}
|
|
326
326
|
return t;
|
|
327
|
-
},
|
|
327
|
+
}, ye = (e, t) => {
|
|
328
328
|
let n = [], r = !1, i = window.visualViewport?.width ?? window.innerWidth ?? 0;
|
|
329
329
|
return e.forEach((e, t) => {
|
|
330
330
|
if (!(e instanceof HTMLElement) || !e.isConnected) return;
|
|
@@ -336,27 +336,27 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
336
336
|
if (o === "none") return;
|
|
337
337
|
let s = e.getAttribute(p) === "true", c = `screen[${t}]${s ? " (active)" : ""}`;
|
|
338
338
|
if (e.style.transform !== "" && e.style.transform !== "none" && n.push(`${c} transform=${e.style.transform}`), e.style.opacity !== "" && e.style.opacity !== "1" && n.push(`${c} opacity=${e.style.opacity}`), s && e.getAttribute("data-flemo-status") === "COMPLETED" && i > 0) {
|
|
339
|
-
let e =
|
|
339
|
+
let e = ve(a);
|
|
340
340
|
e !== null && Math.abs(e) >= i * .5 && (r = !0);
|
|
341
341
|
}
|
|
342
342
|
}), {
|
|
343
343
|
residualInlineTransforms: n,
|
|
344
344
|
offViewportAtRest: r,
|
|
345
|
-
orphanedHolds:
|
|
345
|
+
orphanedHolds: W(t)
|
|
346
346
|
};
|
|
347
|
-
},
|
|
347
|
+
}, be = E.map((e) => `[${b}="${e}"]`).join(","), xe = A(d), Se = (e) => Math.round(e * 10) / 10, Ce = (e) => {
|
|
348
348
|
let t = e.getAttribute(x);
|
|
349
349
|
return t === null || t === "" ? null : t;
|
|
350
|
-
},
|
|
350
|
+
}, we = (e) => {
|
|
351
351
|
let t = e.getAttribute(b);
|
|
352
352
|
return t !== null && E.includes(t);
|
|
353
|
-
},
|
|
353
|
+
}, Te = () => {
|
|
354
354
|
try {
|
|
355
355
|
return document.querySelector("style[data-flemo-morph-sheet]")?.sheet?.cssRules.length ?? 0;
|
|
356
356
|
} catch {
|
|
357
357
|
return 0;
|
|
358
358
|
}
|
|
359
|
-
},
|
|
359
|
+
}, Ee = (e) => {
|
|
360
360
|
let t = {
|
|
361
361
|
registered: 0,
|
|
362
362
|
pairable: /* @__PURE__ */ new Set(),
|
|
@@ -366,17 +366,17 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
366
366
|
ghosts: 0,
|
|
367
367
|
ghostBornAt: /* @__PURE__ */ new Map(),
|
|
368
368
|
shortestGhostLifeMs: null,
|
|
369
|
-
sheetRulesAtStart:
|
|
369
|
+
sheetRulesAtStart: Te()
|
|
370
370
|
}, n = new Set(e), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map();
|
|
371
371
|
for (let e of Array.from(document.querySelectorAll(A(b)))) {
|
|
372
372
|
t.registered += 1;
|
|
373
|
-
let a =
|
|
373
|
+
let a = Ce(e);
|
|
374
374
|
if (a === null) continue;
|
|
375
|
-
if (
|
|
375
|
+
if (we(e)) {
|
|
376
376
|
t.flew.add(a);
|
|
377
377
|
continue;
|
|
378
378
|
}
|
|
379
|
-
let o = e.closest(
|
|
379
|
+
let o = e.closest(xe);
|
|
380
380
|
if (o !== null && !n.has(o)) continue;
|
|
381
381
|
let s = o, c = r.get(a);
|
|
382
382
|
c || r.set(a, c = /* @__PURE__ */ new Set()), c.add(s);
|
|
@@ -389,27 +389,27 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
389
389
|
r && [...r.values()].some((e) => e > 1) && t.duplicated.add(e);
|
|
390
390
|
}
|
|
391
391
|
return t;
|
|
392
|
-
},
|
|
393
|
-
if (t.hasAttribute("data-flemo-morph-camera") && (e.camera = !0), !
|
|
394
|
-
let n =
|
|
392
|
+
}, De = (e, t) => {
|
|
393
|
+
if (t.hasAttribute("data-flemo-morph-camera") && (e.camera = !0), !we(t)) return;
|
|
394
|
+
let n = Ce(t);
|
|
395
395
|
n !== null && e.flew.add(n);
|
|
396
|
-
},
|
|
397
|
-
for (let r of Array.from(t.addedNodes)) if (r instanceof Element) for (let t of
|
|
398
|
-
for (let r of Array.from(t.removedNodes)) if (r instanceof Element) for (let t of
|
|
396
|
+
}, Oe = (e, t, n) => {
|
|
397
|
+
for (let r of Array.from(t.addedNodes)) if (r instanceof Element) for (let t of ke(r)) e.ghostBornAt.has(t) || (e.ghosts += 1, e.ghostBornAt.set(t, n));
|
|
398
|
+
for (let r of Array.from(t.removedNodes)) if (r instanceof Element) for (let t of ke(r)) {
|
|
399
399
|
let r = e.ghostBornAt.get(t);
|
|
400
400
|
if (r === void 0) continue;
|
|
401
401
|
e.ghostBornAt.delete(t);
|
|
402
402
|
let i = n - r;
|
|
403
403
|
(e.shortestGhostLifeMs === null || i < e.shortestGhostLifeMs) && (e.shortestGhostLifeMs = i);
|
|
404
404
|
}
|
|
405
|
-
},
|
|
405
|
+
}, ke = (e) => [...e.hasAttribute("data-flemo-morph-ghost") ? [e] : [], ...Array.from(e.querySelectorAll(A(w)))], Ae = (e) => {
|
|
406
406
|
let t = e.shortestGhostLifeMs;
|
|
407
407
|
return t === null || t >= 34 ? [] : [{
|
|
408
408
|
kind: "ghost-cut",
|
|
409
|
-
atMs:
|
|
410
|
-
detail: `a morph ghost was removed ${
|
|
409
|
+
atMs: Se(t),
|
|
410
|
+
detail: `a morph ghost was removed ${Se(t)}ms after it was created (under one frame) — the departing content it stands for was never presented; this is the first-frame blade signature`
|
|
411
411
|
}];
|
|
412
|
-
},
|
|
412
|
+
}, je = (e, t) => {
|
|
413
413
|
let n = [...e.pairable].sort(), r = [...e.flew].sort(), i = new Set(r), a = t ? {
|
|
414
414
|
strandedRoles: 0,
|
|
415
415
|
strandedStandIns: 0,
|
|
@@ -417,11 +417,11 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
417
417
|
layerResidue: 0,
|
|
418
418
|
leaked: 0
|
|
419
419
|
} : {
|
|
420
|
-
strandedRoles: document.querySelectorAll(
|
|
420
|
+
strandedRoles: document.querySelectorAll(be).length,
|
|
421
421
|
strandedStandIns: document.querySelectorAll(A(C)).length,
|
|
422
422
|
strandedGhosts: document.querySelectorAll(A(w)).length,
|
|
423
423
|
layerResidue: Array.from(document.querySelectorAll(A(S))).reduce((e, t) => e + t.childElementCount, 0),
|
|
424
|
-
leaked: Math.max(0,
|
|
424
|
+
leaked: Math.max(0, Te() - e.sheetRulesAtStart)
|
|
425
425
|
};
|
|
426
426
|
return {
|
|
427
427
|
registered: e.registered,
|
|
@@ -437,21 +437,19 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
437
437
|
layerResidue: a.layerResidue,
|
|
438
438
|
duplicatedKeys: [...e.duplicated].sort()
|
|
439
439
|
};
|
|
440
|
-
},
|
|
441
|
-
key:
|
|
442
|
-
storage: "session",
|
|
443
|
-
kind: "opt-in-diagnostic",
|
|
444
|
-
values: "\"on\" / \"off\"",
|
|
445
|
-
fallback: "off",
|
|
446
|
-
effect: "arms this flight recorder in the playground (?devtools=on)"
|
|
447
|
-
}, {
|
|
448
|
-
key: Ne,
|
|
440
|
+
}, Me = "flemo:devtools-panel-height", Ne = [{
|
|
441
|
+
key: Me,
|
|
449
442
|
storage: "session",
|
|
450
443
|
kind: "production-state",
|
|
451
444
|
values: "a pixel height",
|
|
452
445
|
fallback: "(the panel's default height)",
|
|
453
446
|
effect: "the drawer height this panel was last dragged to"
|
|
454
|
-
}],
|
|
447
|
+
}], Pe = [], Fe = [...Pe, ...Ne], G = [
|
|
448
|
+
{
|
|
449
|
+
key: "flemo:devtools",
|
|
450
|
+
storage: "session",
|
|
451
|
+
retiredWith: "the playground's opt-in. `<FlemoDevtools />` mounts unconditionally and a production build resolves it to the inert entry, so there is nothing to arm (2026-09-07)"
|
|
452
|
+
},
|
|
455
453
|
{
|
|
456
454
|
key: "flemo:sixty",
|
|
457
455
|
storage: "session",
|
|
@@ -572,53 +570,53 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
572
570
|
storage: "session",
|
|
573
571
|
retiredWith: "the Low Power Mode release-latency probe (2026-08-22)"
|
|
574
572
|
}
|
|
575
|
-
],
|
|
573
|
+
], Ie = "(retired — the library no longer reads this)", Le = (e) => {
|
|
576
574
|
try {
|
|
577
575
|
let t = e === "session" ? sessionStorage : localStorage;
|
|
578
576
|
return t.length, t;
|
|
579
577
|
} catch {
|
|
580
578
|
return null;
|
|
581
579
|
}
|
|
582
|
-
},
|
|
580
|
+
}, Re = (e, t) => {
|
|
583
581
|
try {
|
|
584
582
|
return e ? e.getItem(t) : null;
|
|
585
583
|
} catch {
|
|
586
584
|
return null;
|
|
587
585
|
}
|
|
588
|
-
},
|
|
589
|
-
let e = {}, t =
|
|
590
|
-
for (let r of
|
|
591
|
-
let i =
|
|
586
|
+
}, ze = new Set(Fe.map((e) => e.key)), Be = new Set(G.map((e) => e.key)), Ve = () => {
|
|
587
|
+
let e = {}, t = Le("session"), n = Le("local");
|
|
588
|
+
for (let r of Fe) {
|
|
589
|
+
let i = Re(r.storage === "session" ? t : n, r.key);
|
|
592
590
|
i !== null && (e[r.key] = i);
|
|
593
591
|
}
|
|
594
|
-
for (let r of
|
|
595
|
-
let t =
|
|
596
|
-
t !== null && (e[`${r.key} (${a}) ${
|
|
592
|
+
for (let r of G) for (let [i, a] of [[t, "sessionStorage"], [n, "localStorage"]]) {
|
|
593
|
+
let t = Re(i, r.key);
|
|
594
|
+
t !== null && (e[`${r.key} (${a}) ${Ie}`] = t);
|
|
597
595
|
}
|
|
598
596
|
for (let [r, i] of [[t, "sessionStorage"], [n, "localStorage"]]) if (r) try {
|
|
599
597
|
for (let t = 0; t < r.length; t += 1) {
|
|
600
598
|
let n = r.key(t);
|
|
601
|
-
!n || !n.startsWith("flemo:") ||
|
|
599
|
+
!n || !n.startsWith("flemo:") || ze.has(n) || Be.has(n) || (e[`${n} (${i}, unknown key)`] = r.getItem(n) ?? "");
|
|
602
600
|
}
|
|
603
601
|
} catch {}
|
|
604
602
|
return e;
|
|
605
|
-
},
|
|
603
|
+
}, He = (e) => {
|
|
606
604
|
let t = [];
|
|
607
605
|
for (let [n, r] of Object.entries(e)) if (n.includes("(retired — the library no longer reads this)")) {
|
|
608
|
-
let e = n.slice(0, n.indexOf(" (")), i =
|
|
606
|
+
let e = n.slice(0, n.indexOf(" (")), i = G.find((t) => t.key === e);
|
|
609
607
|
t.push(`${n}=${r} — RETIRED residue: this key went with ${i?.retiredWith ?? "a removed feature"}. The library never reads it, so it cannot explain anything you are seeing. Safe to delete; it is listed only so it does not read as an unexplained lead.`);
|
|
610
608
|
continue;
|
|
611
609
|
}
|
|
612
610
|
return t;
|
|
613
|
-
},
|
|
611
|
+
}, Ue = "flemo:devtools-trace", We = () => {
|
|
614
612
|
try {
|
|
615
613
|
let e = sessionStorage;
|
|
616
614
|
return e.length, e;
|
|
617
615
|
} catch {
|
|
618
616
|
return null;
|
|
619
617
|
}
|
|
620
|
-
},
|
|
621
|
-
let n =
|
|
618
|
+
}, Ge = (e, t) => {
|
|
619
|
+
let n = We();
|
|
622
620
|
if (!n) return;
|
|
623
621
|
let r = e.slice(-10);
|
|
624
622
|
for (; r.length > 0;) {
|
|
@@ -629,23 +627,23 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
629
627
|
});
|
|
630
628
|
if (e.length <= 64e3) {
|
|
631
629
|
try {
|
|
632
|
-
n.setItem(
|
|
630
|
+
n.setItem(Ue, e);
|
|
633
631
|
} catch {}
|
|
634
632
|
return;
|
|
635
633
|
}
|
|
636
634
|
r = r.slice(1);
|
|
637
635
|
}
|
|
638
|
-
|
|
639
|
-
},
|
|
636
|
+
Ke();
|
|
637
|
+
}, Ke = () => {
|
|
640
638
|
try {
|
|
641
|
-
|
|
639
|
+
We()?.removeItem(Ue);
|
|
642
640
|
} catch {}
|
|
643
|
-
},
|
|
644
|
-
let t =
|
|
641
|
+
}, qe = (e) => {
|
|
642
|
+
let t = We();
|
|
645
643
|
if (!t) return null;
|
|
646
644
|
let n = null;
|
|
647
645
|
try {
|
|
648
|
-
n = t.getItem(
|
|
646
|
+
n = t.getItem(Ue);
|
|
649
647
|
} catch {
|
|
650
648
|
return null;
|
|
651
649
|
}
|
|
@@ -654,14 +652,14 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
654
652
|
try {
|
|
655
653
|
r = JSON.parse(n);
|
|
656
654
|
} catch {
|
|
657
|
-
return
|
|
655
|
+
return Ke(), null;
|
|
658
656
|
}
|
|
659
|
-
return !r || r.version !== e || !Array.isArray(r.flights) ? (
|
|
657
|
+
return !r || r.version !== e || !Array.isArray(r.flights) ? (Ke(), null) : {
|
|
660
658
|
savedAt: typeof r.savedAt == "string" ? r.savedAt : "",
|
|
661
659
|
flights: r.flights,
|
|
662
660
|
note: "These flights were recorded by the page instance BEFORE the last full load. They are kept apart from the live ones because they may have come from a different build."
|
|
663
661
|
};
|
|
664
|
-
},
|
|
662
|
+
}, Je = 12, Ye = 20, Xe = 40, Ze = 500, Qe = 200, $e = (e) => {
|
|
665
663
|
let t = e.rafCadence.medianGapMs;
|
|
666
664
|
if (t === null) return {
|
|
667
665
|
id: "display-cadence",
|
|
@@ -669,17 +667,17 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
669
667
|
detail: "the idle frame cadence could not be sampled, so the display's rate is unknown"
|
|
670
668
|
};
|
|
671
669
|
let n = { medianIdleFrameMs: t };
|
|
672
|
-
return t <
|
|
670
|
+
return t < Je ? {
|
|
673
671
|
id: "display-cadence",
|
|
674
672
|
status: "ok",
|
|
675
673
|
detail: `idle frames arrive every ${t}ms — a display above 60Hz. Frame budgets in this report are still quoted against 60Hz (a gap of 30ms or more)`,
|
|
676
674
|
metrics: n
|
|
677
|
-
} : t <=
|
|
675
|
+
} : t <= Ye ? {
|
|
678
676
|
id: "display-cadence",
|
|
679
677
|
status: "ok",
|
|
680
678
|
detail: `idle frames arrive every ${t}ms — a 60Hz clock`,
|
|
681
679
|
metrics: n
|
|
682
|
-
} : t <=
|
|
680
|
+
} : t <= Xe ? {
|
|
683
681
|
id: "display-cadence",
|
|
684
682
|
status: "violated",
|
|
685
683
|
detail: `idle frames arrive every ${t}ms — the page is being served roughly HALF rate. On iOS this is Low Power Mode, whose main-thread ceiling is ~30Hz while the compositor keeps 60: motion judged here is judged against a clock no transition can beat, and the ceiling is not a library defect. Turn it off, or judge elsewhere`,
|
|
@@ -690,7 +688,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
690
688
|
detail: `idle frames arrive every ${t}ms — the page is barely being served frames at all while idle. Something outside the transition owns this machine; no motion verdict taken here means anything`,
|
|
691
689
|
metrics: n
|
|
692
690
|
};
|
|
693
|
-
},
|
|
691
|
+
}, et = (e) => {
|
|
694
692
|
if (!e.environment.observation.longTasks) return {
|
|
695
693
|
id: "machine-idle",
|
|
696
694
|
status: "unknown",
|
|
@@ -701,7 +699,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
701
699
|
idleLongTaskMs: n,
|
|
702
700
|
worstIdleTaskMs: r
|
|
703
701
|
};
|
|
704
|
-
return n >=
|
|
702
|
+
return n >= Ze || r >= Qe ? {
|
|
705
703
|
id: "machine-idle",
|
|
706
704
|
status: "violated",
|
|
707
705
|
detail: `${t} long task(s) totalling ${n}ms ran while NO navigation was in flight (worst ${r}ms). Something else on this page or this machine was busy, and a motion verdict taken under someone else's load measures the load. A whole tremble campaign was invalidated by exactly this, with a build running in another window`,
|
|
@@ -712,7 +710,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
712
710
|
detail: `${t} idle long task(s), ${n}ms total — the page was quiet between navigations`,
|
|
713
711
|
metrics: i
|
|
714
712
|
};
|
|
715
|
-
},
|
|
713
|
+
}, tt = (e) => {
|
|
716
714
|
let { trusted: t, synthetic: n, pointerTypes: r } = e.input;
|
|
717
715
|
return n > 0 ? {
|
|
718
716
|
id: "real-input",
|
|
@@ -739,7 +737,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
739
737
|
synthetic: n
|
|
740
738
|
}
|
|
741
739
|
};
|
|
742
|
-
},
|
|
740
|
+
}, nt = (e) => e.input.pointerTypes.includes("touch") ? {
|
|
743
741
|
id: "touch-path",
|
|
744
742
|
status: "ok",
|
|
745
743
|
detail: "at least one navigation was driven by touch"
|
|
@@ -751,7 +749,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
751
749
|
id: "touch-path",
|
|
752
750
|
status: "unknown",
|
|
753
751
|
detail: "no touch-driven navigation was recorded on a touch-capable device. The swipe and pointer-capture paths are only reached by a finger; a build that had broken them outright once passed every automated layer green because every probe used a mouse"
|
|
754
|
-
},
|
|
752
|
+
}, rt = [
|
|
755
753
|
{
|
|
756
754
|
id: "devtools-closed",
|
|
757
755
|
status: "unknown",
|
|
@@ -767,7 +765,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
767
765
|
status: "unknown",
|
|
768
766
|
detail: "which physical display this window is on, its refresh rate and scaling, cannot be read from the page. Establish it with the user before believing any verdict"
|
|
769
767
|
}
|
|
770
|
-
],
|
|
768
|
+
], it = (e) => {
|
|
771
769
|
let { environment: t } = e, n = [];
|
|
772
770
|
return n.push(t.emulationSuspected ? {
|
|
773
771
|
id: "device-emulation",
|
|
@@ -777,7 +775,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
777
775
|
id: "device-emulation",
|
|
778
776
|
status: "ok",
|
|
779
777
|
detail: "no device-emulation signature on this session"
|
|
780
|
-
}), n.push(
|
|
778
|
+
}), n.push($e(t)), n.push(e.documentHidden || e.wentHidden ? {
|
|
781
779
|
id: "page-foreground",
|
|
782
780
|
status: "violated",
|
|
783
781
|
detail: e.documentHidden ? "this document is HIDDEN right now — a backgrounded page is throttled to a fraction of its frames" : "this document was hidden at least once while recording; any flight that ran then was throttled"
|
|
@@ -785,7 +783,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
785
783
|
id: "page-foreground",
|
|
786
784
|
status: "ok",
|
|
787
785
|
detail: "the document stayed visible throughout"
|
|
788
|
-
}), n.push(
|
|
786
|
+
}), n.push(et(e)), n.push(t.developmentHints.length > 0 ? {
|
|
789
787
|
id: "build-mode",
|
|
790
788
|
status: "violated",
|
|
791
789
|
detail: `development-server globals are present (${t.developmentHints.join(", ")}). A development build is a different program: unminified, double-invoking, and hot-reload instrumented. A day of ladder measurements once turned out to be measuring the build itself`
|
|
@@ -793,7 +791,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
793
791
|
id: "build-mode",
|
|
794
792
|
status: "unknown",
|
|
795
793
|
detail: "no development-server global was found. That is consistent with a production build but does not prove one — confirm how this page was built"
|
|
796
|
-
}), n.push(
|
|
794
|
+
}), n.push(tt(e)), n.push(nt(e)), n.push(t.reducedMotion ? {
|
|
797
795
|
id: "reduced-motion",
|
|
798
796
|
status: "violated",
|
|
799
797
|
detail: "this session prefers reduced motion, so the transitions under test are being suppressed or shortened. Whatever is on screen is not the motion being judged"
|
|
@@ -801,8 +799,8 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
801
799
|
id: "reduced-motion",
|
|
802
800
|
status: "ok",
|
|
803
801
|
detail: "reduced motion is not requested"
|
|
804
|
-
}), [...n, ...
|
|
805
|
-
},
|
|
802
|
+
}), [...n, ...rt];
|
|
803
|
+
}, at = 2e3, ot = 40, st = (e) => Math.round(e * 10) / 10, ct = (e) => typeof e.animationName == "string" && e.animationName.startsWith("flemo-"), lt = (e) => e instanceof Element ? `<${e.tagName.toLowerCase()}>${e.getAttribute("data-flemo-screen") === null ? "" : " (screen)"}` : "an unidentified node", ut = (e) => {
|
|
806
804
|
if (typeof document > "u") return {
|
|
807
805
|
detach: () => {},
|
|
808
806
|
sawAnimationEvent: () => !1,
|
|
@@ -813,18 +811,18 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
813
811
|
})
|
|
814
812
|
};
|
|
815
813
|
let t = [], n = !1, r = (t) => {
|
|
816
|
-
|
|
814
|
+
ct(t) && (n = !0, e.onAnimationStart(performance.now()));
|
|
817
815
|
}, i = (t) => {
|
|
818
|
-
|
|
816
|
+
ct(t) && (n = !0, e.onHit({
|
|
819
817
|
kind: "animation-cancel",
|
|
820
818
|
atMs: performance.now(),
|
|
821
|
-
detail: `${t.animationName} was CANCELLED on ${
|
|
819
|
+
detail: `${t.animationName} was CANCELLED on ${lt(t.target)} — the element was re-parented, re-styled or removed mid-flight. A cancelled animation loses its start time, and whatever restarts it is free to overwrite the authored delay`
|
|
822
820
|
}));
|
|
823
821
|
}, a = (t) => {
|
|
824
|
-
|
|
822
|
+
ct(t) && (n = !0, t.elapsedTime === 0 && e.onHit({
|
|
825
823
|
kind: "zero-length-animation-end",
|
|
826
824
|
atMs: performance.now(),
|
|
827
|
-
detail: `${t.animationName} reported animationend with elapsedTime 0 on ${
|
|
825
|
+
detail: `${t.animationName} reported animationend with elapsedTime 0 on ${lt(t.target)} — the animation ended without ever running. Anything landing on this event lands before the motion it was waiting for`
|
|
828
826
|
}));
|
|
829
827
|
}, o = (e) => {
|
|
830
828
|
let n = e.pointerType ?? "";
|
|
@@ -832,7 +830,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
832
830
|
atMs: performance.now(),
|
|
833
831
|
trusted: e.isTrusted === !0,
|
|
834
832
|
pointerType: n === "" ? e.type : n
|
|
835
|
-
}), t.length >
|
|
833
|
+
}), t.length > ot && t.splice(0, t.length - ot);
|
|
836
834
|
}, s = {
|
|
837
835
|
capture: !0,
|
|
838
836
|
passive: !0
|
|
@@ -843,7 +841,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
843
841
|
},
|
|
844
842
|
sawAnimationEvent: () => n,
|
|
845
843
|
inputBetween: (e, n) => {
|
|
846
|
-
let r = e -
|
|
844
|
+
let r = e - at, i = t.filter((e) => e.atMs >= r && e.atMs <= n), a = i.filter((e) => e.trusted).length, o = new Set(i.map((e) => e.pointerType));
|
|
847
845
|
return {
|
|
848
846
|
trusted: a,
|
|
849
847
|
synthetic: i.length - a,
|
|
@@ -851,22 +849,22 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
851
849
|
};
|
|
852
850
|
}
|
|
853
851
|
};
|
|
854
|
-
},
|
|
852
|
+
}, dt = (e, t) => ({
|
|
855
853
|
kind: e.kind,
|
|
856
|
-
atMs:
|
|
854
|
+
atMs: st(e.atMs - t),
|
|
857
855
|
detail: e.detail
|
|
858
|
-
}),
|
|
856
|
+
}), ft = (e) => {
|
|
859
857
|
/* v8 ignore next -- unreachable: deriveVerdict returns before this on an
|
|
860
858
|
empty flight list, so nothing ever asks for the median of nothing. */
|
|
861
859
|
if (e.length === 0) return 0;
|
|
862
860
|
let t = [...e].sort((e, t) => e - t);
|
|
863
861
|
return t[Math.floor(t.length / 2)];
|
|
864
|
-
},
|
|
862
|
+
}, pt = (e) => {
|
|
865
863
|
let t = [], n = e.preconditions.filter((e) => e.status === "violated");
|
|
866
864
|
if (n.length > 0 && t.push(`NOT EVIDENCE: ${n.length} judging precondition(s) failed — ${n.map((e) => e.id).join(", ")}. Everything below was measured under those conditions; fix them and measure again before drawing a conclusion from it.`), e.flights.length === 0) return t.push("No flights were recorded. Either no navigation happened while the recorder was attached, or it attached after the one you meant to measure — the recorder only sees flights that start after it does."), t;
|
|
867
865
|
e.observation.animationEvents || t.push("The animation channel observed NOTHING across this whole session: not one flemo keyframe reported a start, an end or a cancel, though flights were recorded. Treat every animation-derived field here as unmeasured rather than as clean — a probe that never fires reads exactly like a page with nothing to report.");
|
|
868
866
|
let r = e.flights, i = r.reduce((e, t) => Math.max(e, t.frameSamples.released.maxGapMs), 0), a = r.filter((e) => e.anomalies.length > 0).length;
|
|
869
|
-
t.push(`${r.length} flight(s) recorded. Median duration ${
|
|
867
|
+
t.push(`${r.length} flight(s) recorded. Median duration ${ft(r.map((e) => e.durationMs))}ms, worst frame gap during visible motion ${i}ms, ${a} flight(s) carrying at least one anomaly.`);
|
|
870
868
|
let o = r.filter((e) => e.motion.longestStallMs >= 48);
|
|
871
869
|
o.length > 0 && t.push(`${o.length} flight(s) STOPPED MOVING mid-flight (longest ${Math.max(...o.map((e) => e.motion.longestStallMs))}ms). Frames kept arriving; the picture did not change. Look at the hold and the animation's play state, not at the frame budget.`);
|
|
872
870
|
let s = r.filter((e) => e.morphs.skipped.length > 0);
|
|
@@ -882,7 +880,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
882
880
|
t.push(`${l.length} tripwire hit(s) across the session (${e.join(", ")}). These are one-frame events reported by the browser itself, not sampled — read the flights' \`tripwires\` arrays for the exact animations.`);
|
|
883
881
|
}
|
|
884
882
|
return r.filter((e) => e.frameSamples.released.over30Count > 0).length === 0 && a === 0 && n.length === 0 && t.push("No flight dropped a frame during visible motion (nothing at or over 30ms) and no anomaly fired. Under the preconditions above, this session is clean — what remains is in `blindSpots`, and none of it is reachable from page code."), t;
|
|
885
|
-
},
|
|
883
|
+
}, mt = "3", ht = new Set(O), gt = new Set(k), _t = A(d), vt = 2e3, yt = 1e3, bt = 4e3, K = (e) => Math.round(e * 10) / 10, xt = null, St = () => ({
|
|
886
884
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
887
885
|
version: "3",
|
|
888
886
|
verdict: ["No DOM was available, so nothing could be observed. The recorder ran inert."],
|
|
@@ -900,15 +898,15 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
900
898
|
previousSession: null,
|
|
901
899
|
anomalies: [],
|
|
902
900
|
blindSpots: [...c],
|
|
903
|
-
judgingProtocol: [...
|
|
904
|
-
}),
|
|
905
|
-
if (
|
|
901
|
+
judgingProtocol: [...pe]
|
|
902
|
+
}), Ct = (e = {}) => {
|
|
903
|
+
if (xt) return xt;
|
|
906
904
|
if (typeof window > "u" || typeof document > "u") return {
|
|
907
905
|
detach: () => {},
|
|
908
|
-
report:
|
|
906
|
+
report: St,
|
|
909
907
|
mark: () => null
|
|
910
908
|
};
|
|
911
|
-
let n = e.maxFlights ?? 50, r = e.log ?? !1, i = e.installGlobal ?? !0, a = e.persist ?? !0, l =
|
|
909
|
+
let n = e.maxFlights ?? 50, r = e.log ?? !1, i = e.installGlobal ?? !0, a = e.persist ?? !0, l = Ve(), d = performance.now(), h = a ? qe("3") : null, g = {
|
|
912
910
|
medianGapMs: null,
|
|
913
911
|
sampleCount: 0
|
|
914
912
|
};
|
|
@@ -919,10 +917,10 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
919
917
|
try {
|
|
920
918
|
typeof PerformanceObserver < "u" && PerformanceObserver.supportedEntryTypes?.includes("longtask") && (S = new PerformanceObserver((e) => {
|
|
921
919
|
for (let t of e.getEntries()) x.push({
|
|
922
|
-
startMs:
|
|
923
|
-
durationMs:
|
|
920
|
+
startMs: K(t.startTime),
|
|
921
|
+
durationMs: K(t.duration)
|
|
924
922
|
});
|
|
925
|
-
x.length >
|
|
923
|
+
x.length > yt && x.splice(0, x.length - yt);
|
|
926
924
|
}), S.observe({
|
|
927
925
|
type: "longtask",
|
|
928
926
|
buffered: !0
|
|
@@ -930,50 +928,50 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
930
928
|
} catch {
|
|
931
929
|
S = null;
|
|
932
930
|
}
|
|
933
|
-
let C = [], w = 0, E = null, D = null, O = [], k = !1, j = !1, M = document.visibilityState === "hidden", N = 0, P = () => Array.from(document.querySelectorAll(
|
|
934
|
-
let t = Array.from(document.querySelectorAll(A(y))).filter((e) =>
|
|
931
|
+
let C = [], w = 0, E = null, D = null, O = [], k = !1, j = !1, M = document.visibilityState === "hidden", N = 0, P = () => Array.from(document.querySelectorAll(_t)).filter((e) => ht.has(e.getAttribute("data-flemo-status") ?? "")), te = () => E !== null || P().length > 0, F = (e) => {
|
|
932
|
+
let t = Array.from(document.querySelectorAll(A(y))).filter((e) => ht.has(e.getAttribute("data-flemo-bar-status") ?? "") || e.getAttribute("data-flemo-bar-riding") === "true").length, n = Array.from(document.querySelectorAll(A(v))).filter((e) => ht.has(e.getAttribute("data-flemo-status") ?? "")).length, r = Array.from(document.querySelectorAll(A(_))).filter((e) => ht.has(e.getAttribute("data-flemo-status") ?? "")).length;
|
|
935
933
|
return {
|
|
936
934
|
screens: e.length,
|
|
937
935
|
bars: t,
|
|
938
936
|
decorators: n,
|
|
939
937
|
parts: r
|
|
940
938
|
};
|
|
941
|
-
}, I =
|
|
939
|
+
}, I = ut({
|
|
942
940
|
onHit: (e) => {
|
|
943
941
|
let t = E;
|
|
944
|
-
t && t.tripwires.push(
|
|
942
|
+
t && t.tripwires.push(dt(e, t.t0Ms));
|
|
945
943
|
},
|
|
946
944
|
onAnimationStart: (e) => {
|
|
947
945
|
let t = E;
|
|
948
|
-
!t || t.firstAnimationAtMs !== null || (t.firstAnimationAtMs =
|
|
946
|
+
!t || t.firstAnimationAtMs !== null || (t.firstAnimationAtMs = K(e - t.t0Ms));
|
|
949
947
|
}
|
|
950
948
|
}), re = (e) => {
|
|
951
949
|
let t = /* @__PURE__ */ new Set();
|
|
952
950
|
for (let n of e.elements) {
|
|
953
951
|
let e = n.getAttribute("data-flemo-status") ?? "";
|
|
954
|
-
|
|
952
|
+
ht.has(e) && t.add(e);
|
|
955
953
|
}
|
|
956
954
|
return [...t];
|
|
957
955
|
}, L = () => {
|
|
958
956
|
let e = E;
|
|
959
957
|
if (!e || k) return;
|
|
960
958
|
let t = performance.now(), n = e.frames;
|
|
961
|
-
if (n.lastFrameAt !== null && n.heldGaps.length + n.releasedGaps.length <
|
|
959
|
+
if (n.lastFrameAt !== null && n.heldGaps.length + n.releasedGaps.length < vt) {
|
|
962
960
|
let r = t - n.lastFrameAt, i = oe(e.elements);
|
|
963
|
-
(i ? n.heldGaps : n.releasedGaps).push(r), i || (
|
|
961
|
+
(i ? n.heldGaps : n.releasedGaps).push(r), i || (se(n, e.elements, r), n.releasedFrames === 1 && de(e.images, e.elements));
|
|
964
962
|
}
|
|
965
|
-
if (n.lastFrameAt = t,
|
|
966
|
-
O = [...e.elements],
|
|
963
|
+
if (n.lastFrameAt = t, B(n, e.elements), t - e.t0Ms > 1e4) {
|
|
964
|
+
O = [...e.elements], H(t, re(e));
|
|
967
965
|
return;
|
|
968
966
|
}
|
|
969
967
|
e.rafId = requestAnimationFrame(L);
|
|
970
968
|
}, ie = (e) => {
|
|
971
969
|
let t = performance.now();
|
|
972
970
|
w += 1;
|
|
973
|
-
let n = e.find((e) => e.getAttribute("data-flemo-active") === "true") ?? e[0], r =
|
|
971
|
+
let n = e.find((e) => e.getAttribute("data-flemo-active") === "true") ?? e[0], r = _e(n.getAttribute("data-flemo-status") ?? "") ?? "PUSH", i = null;
|
|
974
972
|
for (let t of e) {
|
|
975
973
|
let e = t.getAttribute(m);
|
|
976
|
-
if (e !== null &&
|
|
974
|
+
if (e !== null && gt.has(e)) {
|
|
977
975
|
i = e;
|
|
978
976
|
break;
|
|
979
977
|
}
|
|
@@ -991,61 +989,61 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
991
989
|
holdReleasedAtMs: null,
|
|
992
990
|
firstAnimationAtMs: null,
|
|
993
991
|
frames: ae(),
|
|
994
|
-
images:
|
|
995
|
-
morphs:
|
|
992
|
+
images: le(e),
|
|
993
|
+
morphs: Ee(e),
|
|
996
994
|
tripwires: [],
|
|
997
995
|
rafId: null
|
|
998
|
-
},
|
|
999
|
-
},
|
|
996
|
+
}, B(E.frames, E.elements), E.rafId = requestAnimationFrame(L);
|
|
997
|
+
}, R = (e, t) => {
|
|
1000
998
|
let n = 2, r = () => {
|
|
1001
999
|
if (k) return;
|
|
1002
1000
|
if (--n, n > 0) {
|
|
1003
1001
|
requestAnimationFrame(r);
|
|
1004
1002
|
return;
|
|
1005
1003
|
}
|
|
1006
|
-
let i =
|
|
1004
|
+
let i = ye(t, te());
|
|
1007
1005
|
e.landing.residualInlineTransforms = i.residualInlineTransforms, e.landing.offViewportAtRest = i.offViewportAtRest, e.landing.orphanedHolds = i.orphanedHolds;
|
|
1008
1006
|
};
|
|
1009
1007
|
requestAnimationFrame(r);
|
|
1010
|
-
},
|
|
1008
|
+
}, z = (e, t) => {
|
|
1011
1009
|
let n = 2, r = () => {
|
|
1012
1010
|
if (!k) {
|
|
1013
1011
|
if (--n, n > 0) {
|
|
1014
1012
|
requestAnimationFrame(r);
|
|
1015
1013
|
return;
|
|
1016
1014
|
}
|
|
1017
|
-
e.morphs =
|
|
1015
|
+
e.morphs = je(t.morphs, te());
|
|
1018
1016
|
}
|
|
1019
1017
|
};
|
|
1020
1018
|
requestAnimationFrame(r);
|
|
1021
|
-
},
|
|
1019
|
+
}, V = (e, t, n, r) => ({
|
|
1022
1020
|
id: r ? `${e.id} (in flight)` : e.id,
|
|
1023
1021
|
...e.routerId === void 0 ? {} : { routerId: e.routerId },
|
|
1024
1022
|
...e.bucket === null ? {} : { bucket: e.bucket },
|
|
1025
1023
|
kind: e.kind,
|
|
1026
1024
|
t0: {
|
|
1027
|
-
ms:
|
|
1025
|
+
ms: K(e.t0Ms),
|
|
1028
1026
|
iso: e.t0Iso
|
|
1029
1027
|
},
|
|
1030
1028
|
t1: {
|
|
1031
|
-
ms:
|
|
1029
|
+
ms: K(t),
|
|
1032
1030
|
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
1033
1031
|
},
|
|
1034
|
-
durationMs:
|
|
1035
|
-
driver:
|
|
1032
|
+
durationMs: K(t - e.t0Ms),
|
|
1033
|
+
driver: ge(e.frames.evidence),
|
|
1036
1034
|
participants: e.participants,
|
|
1037
1035
|
holds: {
|
|
1038
1036
|
kind: e.holdKind,
|
|
1039
1037
|
releasedAtMs: e.holdReleasedAtMs
|
|
1040
1038
|
},
|
|
1041
|
-
frameSamples:
|
|
1039
|
+
frameSamples: he(e.frames.heldGaps, e.frames.releasedGaps),
|
|
1042
1040
|
motion: {
|
|
1043
|
-
...
|
|
1041
|
+
...ce(e.frames),
|
|
1044
1042
|
firstAnimationAtMs: e.firstAnimationAtMs
|
|
1045
1043
|
},
|
|
1046
|
-
images:
|
|
1047
|
-
morphs:
|
|
1048
|
-
tripwires: [...e.tripwires, ...
|
|
1044
|
+
images: fe(e.images),
|
|
1045
|
+
morphs: je(e.morphs, !0),
|
|
1046
|
+
tripwires: [...e.tripwires, ...Ae(e.morphs)],
|
|
1049
1047
|
input: I.inputBetween(e.t0Ms, t),
|
|
1050
1048
|
longTasks: [],
|
|
1051
1049
|
holdLongTasks: [],
|
|
@@ -1056,29 +1054,29 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1056
1054
|
orphanedHolds: []
|
|
1057
1055
|
},
|
|
1058
1056
|
anomalies: []
|
|
1059
|
-
}),
|
|
1057
|
+
}), H = (e, t) => {
|
|
1060
1058
|
let i = E;
|
|
1061
1059
|
/* v8 ignore next -- unreachable: both callers hold a flight. sampleFrame
|
|
1062
1060
|
returns at its own top when `current` is null, and evaluate only calls
|
|
1063
1061
|
this inside `if (current && ...)`. The narrowing stays for the type. */
|
|
1064
1062
|
if (!i) return;
|
|
1065
|
-
|
|
1066
|
-
let a =
|
|
1067
|
-
C.push(a), C.length > n && C.splice(0, C.length - n), t.length === 0 && (
|
|
1068
|
-
},
|
|
1063
|
+
de(i.images, i.elements), E = null, i.rafId !== null && cancelAnimationFrame(i.rafId);
|
|
1064
|
+
let a = V(i, e, t, !1);
|
|
1065
|
+
C.push(a), C.length > n && C.splice(0, C.length - n), t.length === 0 && (R(a, i.elements), z(a, i)), r && console.info(`[flemo devtools] ${a.id} ${a.kind} driver=${a.driver} ${a.durationMs}ms screens=${a.participants.screens}`);
|
|
1066
|
+
}, U = (e) => {
|
|
1069
1067
|
let t = E;
|
|
1070
1068
|
if (!t || !(e.target instanceof Element)) return;
|
|
1071
1069
|
let n = e.target.getAttribute(m);
|
|
1072
|
-
if (n !== null &&
|
|
1073
|
-
let e =
|
|
1070
|
+
if (n !== null && gt.has(n) && t.holdKind === null && (t.holdKind = n), n !== null && gt.has(n) && t.holdReleasedAtMs !== null && t.frames.holdReassertedAtMs === null) {
|
|
1071
|
+
let e = K(performance.now() - t.t0Ms);
|
|
1074
1072
|
t.frames.holdReassertedAtMs = e, t.tripwires.push({
|
|
1075
1073
|
kind: "hold-reassert",
|
|
1076
1074
|
atMs: e,
|
|
1077
1075
|
detail: "an animation hold was re-asserted after this flight had already released it — the motion pauses here while every timing metric stays clean"
|
|
1078
1076
|
});
|
|
1079
1077
|
}
|
|
1080
|
-
(n === "false" || n === null) && e.oldValue !== null &&
|
|
1081
|
-
},
|
|
1078
|
+
(n === "false" || n === null) && e.oldValue !== null && gt.has(e.oldValue) && t.holdReleasedAtMs === null && !oe(t.elements) && (t.holdReleasedAtMs = K(performance.now() - t.t0Ms));
|
|
1079
|
+
}, me = () => {
|
|
1082
1080
|
let e = P();
|
|
1083
1081
|
if (O.length > 0) {
|
|
1084
1082
|
if (e.some((e) => O.includes(e))) return;
|
|
@@ -1089,18 +1087,18 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1089
1087
|
return;
|
|
1090
1088
|
}
|
|
1091
1089
|
if (E && e.length === 0) {
|
|
1092
|
-
|
|
1090
|
+
H(performance.now(), []);
|
|
1093
1091
|
return;
|
|
1094
1092
|
}
|
|
1095
|
-
if (E) for (let t of e) E.elements.includes(t) || (E.elements.push(t),
|
|
1096
|
-
},
|
|
1093
|
+
if (E) for (let t of e) E.elements.includes(t) || (E.elements.push(t), ue(E.images, E.elements, t.querySelectorAll("img")), E.participants = F(E.elements));
|
|
1094
|
+
}, ve = null, W = null, be = () => {
|
|
1097
1095
|
let e = document.documentElement;
|
|
1098
1096
|
if (!e) return !1;
|
|
1099
1097
|
let t = new MutationObserver((e) => {
|
|
1100
1098
|
if (k) return;
|
|
1101
1099
|
let t = performance.now();
|
|
1102
|
-
for (let n of e) n.type === "attributes" ? n.attributeName === "data-flemo-anim-hold" ?
|
|
1103
|
-
|
|
1100
|
+
for (let n of e) n.type === "attributes" ? n.attributeName === "data-flemo-anim-hold" ? U(n) : E && (n.attributeName === "data-flemo-morph" || n.attributeName === "data-flemo-morph-camera") && n.target instanceof Element && De(E.morphs, n.target) : (E && Oe(E.morphs, n, t), E && n.addedNodes.length > 0 && ue(E.images, E.elements, n.addedNodes));
|
|
1101
|
+
me();
|
|
1104
1102
|
});
|
|
1105
1103
|
try {
|
|
1106
1104
|
t.observe(e, {
|
|
@@ -1119,30 +1117,30 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1119
1117
|
} catch {
|
|
1120
1118
|
return !1;
|
|
1121
1119
|
}
|
|
1122
|
-
return
|
|
1120
|
+
return ve = t, me(), !0;
|
|
1123
1121
|
};
|
|
1124
|
-
if (!
|
|
1122
|
+
if (!be()) {
|
|
1125
1123
|
let e = () => {
|
|
1126
|
-
|
|
1124
|
+
W = null, k || be();
|
|
1127
1125
|
};
|
|
1128
|
-
|
|
1126
|
+
W = e, document.addEventListener("DOMContentLoaded", e, { once: !0 });
|
|
1129
1127
|
}
|
|
1130
|
-
let
|
|
1131
|
-
document.visibilityState === "hidden" && (M = !0, a && E === null &&
|
|
1128
|
+
let xe = () => {
|
|
1129
|
+
document.visibilityState === "hidden" && (M = !0, a && E === null && Ge(C, "3"));
|
|
1132
1130
|
};
|
|
1133
|
-
document.addEventListener("visibilitychange",
|
|
1134
|
-
let
|
|
1135
|
-
N = 0, !k && (E === null &&
|
|
1131
|
+
document.addEventListener("visibilitychange", xe);
|
|
1132
|
+
let Se = () => {
|
|
1133
|
+
N = 0, !k && (E === null && Ge(C, "3"), N = window.setTimeout(Se, bt));
|
|
1136
1134
|
};
|
|
1137
|
-
a && (N = window.setTimeout(
|
|
1138
|
-
let
|
|
1135
|
+
a && (N = window.setTimeout(Se, bt));
|
|
1136
|
+
let Ce = (e) => {
|
|
1139
1137
|
let t = x.filter((t) => t.startMs + t.durationMs >= e.t0.ms - 120 && t.startMs <= e.t1.ms), n = e.holds.kind === null ? e.t0.ms : e.holds.releasedAtMs === null ? e.t1.ms : e.t0.ms + e.holds.releasedAtMs;
|
|
1140
1138
|
return {
|
|
1141
1139
|
released: t.filter((e) => e.startMs + e.durationMs > n),
|
|
1142
1140
|
held: t.filter((e) => e.startMs + e.durationMs <= n)
|
|
1143
1141
|
};
|
|
1144
|
-
},
|
|
1145
|
-
let t =
|
|
1142
|
+
}, we = (e) => x.filter((t) => t.startMs >= d && !e.some((e) => t.startMs + t.durationMs >= e.t0.ms && t.startMs <= e.t1.ms)), Te = (e) => {
|
|
1143
|
+
let t = Ce(e), n = {
|
|
1146
1144
|
...e,
|
|
1147
1145
|
longTasks: t.released,
|
|
1148
1146
|
holdLongTasks: t.held,
|
|
@@ -1169,12 +1167,12 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1169
1167
|
morphs: n.morphs,
|
|
1170
1168
|
tripwires: n.tripwires
|
|
1171
1169
|
}), n;
|
|
1172
|
-
},
|
|
1173
|
-
let e = C.map(
|
|
1170
|
+
}, ke = () => {
|
|
1171
|
+
let e = C.map(Te), n = E;
|
|
1174
1172
|
if (!n) return e;
|
|
1175
1173
|
let r = performance.now(), i = r - n.t0Ms > t;
|
|
1176
|
-
return [...e,
|
|
1177
|
-
},
|
|
1174
|
+
return [...e, Te(V(n, r, i ? re(n) : [], !0))];
|
|
1175
|
+
}, Me = (e) => {
|
|
1178
1176
|
let t = /* @__PURE__ */ new Set(), n = 0, r = 0;
|
|
1179
1177
|
for (let i of e) {
|
|
1180
1178
|
n += i.input.trusted, r += i.input.synthetic;
|
|
@@ -1185,21 +1183,21 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1185
1183
|
synthetic: r,
|
|
1186
1184
|
pointerTypes: [...t].sort()
|
|
1187
1185
|
};
|
|
1188
|
-
},
|
|
1189
|
-
let e =
|
|
1186
|
+
}, Ne = () => {
|
|
1187
|
+
let e = Ve(), t = { ...e };
|
|
1190
1188
|
for (let [n, r] of Object.entries(l)) n in e || (t[`${n} (at attach, since cleared)`] = r);
|
|
1191
|
-
let n =
|
|
1189
|
+
let n = He(t), r = ne(g, I.sawAnimationEvent()), i = ke(), a = E, o = it({
|
|
1192
1190
|
environment: r,
|
|
1193
|
-
idleLongTasks:
|
|
1191
|
+
idleLongTasks: we(i),
|
|
1194
1192
|
observedMs: performance.now() - d,
|
|
1195
1193
|
wentHidden: M,
|
|
1196
1194
|
documentHidden: document.visibilityState === "hidden",
|
|
1197
|
-
input:
|
|
1195
|
+
input: Me(i)
|
|
1198
1196
|
});
|
|
1199
1197
|
return {
|
|
1200
1198
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1201
1199
|
version: "3",
|
|
1202
|
-
verdict:
|
|
1200
|
+
verdict: pt({
|
|
1203
1201
|
preconditions: o,
|
|
1204
1202
|
flights: i,
|
|
1205
1203
|
observation: r.observation
|
|
@@ -1220,37 +1218,37 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1220
1218
|
flightAnomalies: i.map((e) => e.anomalies)
|
|
1221
1219
|
}),
|
|
1222
1220
|
blindSpots: [...c],
|
|
1223
|
-
judgingProtocol: [...
|
|
1221
|
+
judgingProtocol: [...pe]
|
|
1224
1222
|
};
|
|
1225
|
-
},
|
|
1223
|
+
}, Pe = (e) => (D = e === null || e === "" ? null : e, D), Fe = () => {
|
|
1226
1224
|
if (!k) {
|
|
1227
|
-
if (k = !0,
|
|
1225
|
+
if (k = !0, ve?.disconnect(), W !== null && (document.removeEventListener("DOMContentLoaded", W), W = null), document.removeEventListener("visibilitychange", xe), I.detach(), S?.disconnect(), window.clearTimeout(N), N = 0, E?.rafId != null && cancelAnimationFrame(E.rafId), E = null, j) {
|
|
1228
1226
|
let e = window;
|
|
1229
1227
|
e.flemo?.__flemoDevtools === !0 && delete e.flemo;
|
|
1230
1228
|
}
|
|
1231
|
-
|
|
1229
|
+
xt = null;
|
|
1232
1230
|
}
|
|
1233
|
-
},
|
|
1234
|
-
detach:
|
|
1235
|
-
report:
|
|
1236
|
-
mark:
|
|
1231
|
+
}, G = {
|
|
1232
|
+
detach: Fe,
|
|
1233
|
+
report: Ne,
|
|
1234
|
+
mark: Pe
|
|
1237
1235
|
};
|
|
1238
1236
|
if (i) {
|
|
1239
1237
|
let e = window, t = e.flemo;
|
|
1240
1238
|
(t === void 0 || t?.__flemoDevtools === !0) && (e.flemo = {
|
|
1241
1239
|
__flemoDevtools: !0,
|
|
1242
|
-
report:
|
|
1243
|
-
flights:
|
|
1244
|
-
mark:
|
|
1245
|
-
detach:
|
|
1240
|
+
report: Ne,
|
|
1241
|
+
flights: ke,
|
|
1242
|
+
mark: Pe,
|
|
1243
|
+
detach: Fe
|
|
1246
1244
|
}, j = !0);
|
|
1247
1245
|
}
|
|
1248
|
-
return
|
|
1249
|
-
},
|
|
1246
|
+
return xt = G, G;
|
|
1247
|
+
}, wt = O.map((e) => A(d) + j(f, e)).join(","), Tt = () => document.querySelector(wt) !== null, Et = "\n:host {\n all: initial;\n color-scheme: dark;\n}\n* { box-sizing: border-box; }\n.root {\n --bg: #14161a;\n --bg-soft: #1b1e24;\n --line: #2b3038;\n --fg: #e6e9ef;\n --fg-dim: #99a1b0;\n --accent: #7cc4ff;\n --warn: #ffb454;\n --bad: #ff6b6b;\n font: 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n color: var(--fg);\n}\n@media (prefers-color-scheme: light) {\n .root {\n --bg: #ffffff;\n --bg-soft: #f4f6f9;\n --line: #dde1e8;\n --fg: #1a1d22;\n --fg-dim: #5c6472;\n --accent: #0b6bcb;\n --warn: #a35a00;\n --bad: #c2261f;\n }\n}\n", Dt = (e) => {
|
|
1250
1248
|
let t = document.createElement("div");
|
|
1251
1249
|
t.setAttribute(D, ""), t.style.position = "fixed", t.style.top = "0", t.style.left = "0", t.style.width = "0", t.style.height = "0", t.style.zIndex = "2147483000";
|
|
1252
1250
|
let n = t.attachShadow({ mode: "open" }), r = document.createElement("style");
|
|
1253
|
-
r.textContent = e, n.appendChild(r);
|
|
1251
|
+
r.textContent = Et + e, n.appendChild(r);
|
|
1254
1252
|
let i = document.createElement("div");
|
|
1255
1253
|
return i.className = "root", n.appendChild(i), {
|
|
1256
1254
|
host: t,
|
|
@@ -1270,10 +1268,10 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1270
1268
|
},
|
|
1271
1269
|
ownsRecorder: !1
|
|
1272
1270
|
} : {
|
|
1273
|
-
recorder:
|
|
1271
|
+
recorder: Ct(),
|
|
1274
1272
|
ownsRecorder: !0
|
|
1275
1273
|
};
|
|
1276
|
-
}, At = "http://www.w3.org/2000/svg",
|
|
1274
|
+
}, At = "http://www.w3.org/2000/svg", q = (e, t, n) => {
|
|
1277
1275
|
let r = document.createElement(e);
|
|
1278
1276
|
return t !== void 0 && (r.className = t), n !== void 0 && (r.textContent = n), r;
|
|
1279
1277
|
}, jt = (e, t) => {
|
|
@@ -1284,13 +1282,13 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1284
1282
|
for (; e.firstChild !== null;) e.removeChild(e.firstChild);
|
|
1285
1283
|
}, Nt = (e, t) => {
|
|
1286
1284
|
e.textContent !== t && (e.textContent = t);
|
|
1287
|
-
},
|
|
1285
|
+
}, J = (e) => e == null || e === "" ? "—" : String(e), Y = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e)}ms` : "—", Pt = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e * 10) / 10}ms` : "—", X = (e) => typeof e == "number" && Number.isFinite(e) ? String(e) : "—", Ft = (e) => e === !0 ? "yes" : e === !1 ? "no" : "—", It = (e) => {
|
|
1288
1286
|
let t = e?.environment;
|
|
1289
1287
|
if (!t) return "—";
|
|
1290
1288
|
let n = t.viewport, r = n && typeof n.width == "number" && typeof n.height == "number" ? `${Math.round(n.width)}×${Math.round(n.height)}` : "—";
|
|
1291
1289
|
return [
|
|
1292
|
-
|
|
1293
|
-
`dpr ${
|
|
1290
|
+
J(t.engine),
|
|
1291
|
+
`dpr ${J(t.devicePixelRatio)}`,
|
|
1294
1292
|
r,
|
|
1295
1293
|
`rAF ${Pt(t.rafCadence?.medianGapMs)}`
|
|
1296
1294
|
].join(" · ");
|
|
@@ -1299,43 +1297,43 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1299
1297
|
if (!Array.isArray(t)) return null;
|
|
1300
1298
|
let n = t.filter((e) => typeof e == "number" && Number.isFinite(e));
|
|
1301
1299
|
return n.length >= 2 ? n : null;
|
|
1302
|
-
}, zt = "\n
|
|
1303
|
-
let i =
|
|
1304
|
-
i.appendChild(
|
|
1305
|
-
},
|
|
1306
|
-
let n =
|
|
1307
|
-
return n.appendChild(
|
|
1308
|
-
},
|
|
1309
|
-
e.appendChild(
|
|
1300
|
+
}, zt = "\n.toggle {\n position: fixed;\n bottom: 12px;\n z-index: 2147483000;\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n padding: 6px 10px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg);\n color: var(--fg);\n font: inherit;\n cursor: pointer;\n}\n.toggle:hover { background: var(--bg-soft); }\n.toggle[data-corner=\"bottom-right\"] { right: 12px; }\n.toggle[data-corner=\"bottom-left\"] { left: 12px; }\n.mark { font-weight: 700; letter-spacing: 0.04em; }\n.count {\n padding: 0 6px;\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n}\n.dot {\n width: 7px;\n height: 7px;\n border-radius: 50%;\n background: var(--bad);\n}\n.dot[hidden] { display: none; }\n.panel {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2147482999;\n display: flex;\n flex-direction: column;\n max-width: 100%;\n border-top: 1px solid var(--line);\n background: var(--bg);\n overflow: hidden;\n}\n.panel[hidden] { display: none; }\n.grip {\n flex: 0 0 6px;\n height: 6px;\n background: var(--line);\n cursor: ns-resize;\n touch-action: none;\n}\n.head {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 8px;\n padding: 8px 10px;\n border-bottom: 1px solid var(--line);\n}\n.env { color: var(--fg-dim); }\n.spacer { flex: 1 1 auto; }\n.act {\n padding: 4px 8px;\n border: 1px solid var(--line);\n border-radius: 4px;\n background: var(--bg-soft);\n color: var(--fg);\n font: inherit;\n cursor: pointer;\n}\n.chips {\n display: flex;\n flex-wrap: wrap;\n gap: 6px;\n flex: 1 1 100%;\n}\n.chips:empty { display: none; }\n.chip {\n padding: 2px 8px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n max-width: 100%;\n overflow-wrap: anywhere;\n}\n/* The verdict reads as prose, not as a tag: it is a sentence about the whole\n session and it is the first thing anybody should read. */\n.chip.lead {\n border-color: var(--fg);\n color: var(--fg);\n white-space: normal;\n max-width: 100%;\n line-height: 1.5;\n}\n.chip.warn { border-color: var(--warn); color: var(--warn); }\n.chip.bad { border-color: var(--bad); color: var(--bad); }\n.body {\n display: flex;\n flex: 1 1 auto;\n min-height: 0;\n}\n.list {\n flex: 0 0 40%;\n max-width: 340px;\n min-width: 180px;\n overflow: auto;\n border-right: 1px solid var(--line);\n}\n.row {\n display: flex;\n align-items: center;\n gap: 8px;\n width: 100%;\n padding: 6px 10px;\n border: 0;\n border-bottom: 1px solid var(--line);\n background: none;\n color: var(--fg);\n font: inherit;\n text-align: left;\n cursor: pointer;\n}\n.row[aria-selected=\"true\"] { background: var(--bg-soft); }\n.row .kind { font-weight: 700; }\n.row .driver { color: var(--accent); }\n.row .dur, .row .screens { color: var(--fg-dim); }\n.row .n {\n margin-left: auto;\n padding: 0 6px;\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n}\n.row .n.bad { background: var(--bad); color: #fff; }\n.detail { flex: 1 1 auto; overflow: auto; padding: 8px 10px; }\n.section { margin: 0 0 10px; }\n.section > h2 {\n margin: 0 0 4px;\n font: inherit;\n font-weight: 700;\n color: var(--fg-dim);\n text-transform: uppercase;\n letter-spacing: 0.06em;\n}\n.kv { display: flex; gap: 8px; }\n.kv > .k { flex: 0 0 34%; max-width: 180px; color: var(--fg-dim); }\n.kv > .v { flex: 1 1 auto; overflow-wrap: anywhere; }\n/* A value that IS the finding — a stall, a re-asserted hold, an orphan. */\n.kv > .v.bad { color: var(--bad); }\n.li { overflow-wrap: anywhere; }\n.li.bad { color: var(--bad); }\n.dim { color: var(--fg-dim); }\n.spark { display: block; width: 100%; height: 28px; }\n.foot { border-top: 1px solid var(--line); padding: 6px 10px; color: var(--fg-dim); }\n.foot summary { cursor: pointer; }\n.foot .li { margin-top: 4px; }\n", Bt = 48, Z = (e, t, n, r) => {
|
|
1301
|
+
let i = q("div", "kv");
|
|
1302
|
+
i.appendChild(q("span", "k", t)), i.appendChild(q("span", r ? `v ${r}` : "v", n)), e.appendChild(i);
|
|
1303
|
+
}, Q = (e, t) => {
|
|
1304
|
+
let n = q("section", "section");
|
|
1305
|
+
return n.appendChild(q("h2", void 0, t)), e.appendChild(n), n;
|
|
1306
|
+
}, $ = (e, t, n = "li") => {
|
|
1307
|
+
e.appendChild(q("div", n, t));
|
|
1310
1308
|
}, Vt = (e, t) => {
|
|
1311
1309
|
Mt(e);
|
|
1312
|
-
for (let n of t?.verdict ?? []) e.appendChild(
|
|
1313
|
-
for (let n of t?.preconditions ?? []) n?.status === "violated" && e.appendChild(
|
|
1314
|
-
for (let n of t?.overrides?.warnings ?? []) e.appendChild(
|
|
1315
|
-
for (let n of t?.anomalies ?? []) e.appendChild(
|
|
1316
|
-
for (let [n, r] of Object.entries(t?.overrides?.active ?? {})) e.appendChild(
|
|
1310
|
+
for (let n of t?.verdict ?? []) e.appendChild(q("span", "chip lead", J(n)));
|
|
1311
|
+
for (let n of t?.preconditions ?? []) n?.status === "violated" && e.appendChild(q("span", "chip bad", `${n.id}: ${J(n.detail)}`));
|
|
1312
|
+
for (let n of t?.overrides?.warnings ?? []) e.appendChild(q("span", "chip warn", J(n)));
|
|
1313
|
+
for (let n of t?.anomalies ?? []) e.appendChild(q("span", "chip bad", J(n)));
|
|
1314
|
+
for (let [n, r] of Object.entries(t?.overrides?.active ?? {})) e.appendChild(q("span", "chip", `${n}=${String(r)}`));
|
|
1317
1315
|
}, Ht = (e, t, n, r) => {
|
|
1318
1316
|
if (Mt(e), t.length === 0) {
|
|
1319
|
-
|
|
1317
|
+
$(e, "no flights recorded yet — navigate once", "li dim");
|
|
1320
1318
|
return;
|
|
1321
1319
|
}
|
|
1322
1320
|
for (let i = t.length - 1; i >= 0; --i) {
|
|
1323
|
-
let a = t[i], o =
|
|
1324
|
-
s.type = "button", s.setAttribute("data-flight-id", o), s.setAttribute("aria-selected", String(o === n)), s.appendChild(
|
|
1321
|
+
let a = t[i], o = J(a?.id), s = q("button", "row");
|
|
1322
|
+
s.type = "button", s.setAttribute("data-flight-id", o), s.setAttribute("aria-selected", String(o === n)), s.appendChild(q("span", "kind", J(a?.kind))), s.appendChild(q("span", "driver", J(a?.driver))), s.appendChild(q("span", "dur", Y(a?.durationMs))), s.appendChild(q("span", "screens", `${X(a?.participants?.screens)} scr`));
|
|
1325
1323
|
let c = a?.anomalies?.length ?? 0;
|
|
1326
|
-
s.appendChild(
|
|
1324
|
+
s.appendChild(q("span", c > 0 ? "n bad" : "n", String(c))), s.addEventListener("click", () => r(o)), e.appendChild(s);
|
|
1327
1325
|
}
|
|
1328
1326
|
}, Ut = (e, t, n) => {
|
|
1329
1327
|
if (!n) {
|
|
1330
|
-
|
|
1328
|
+
Z(e, t, "—");
|
|
1331
1329
|
return;
|
|
1332
1330
|
}
|
|
1333
1331
|
let r = [
|
|
1334
|
-
`${
|
|
1332
|
+
`${X(n.count)} frames`,
|
|
1335
1333
|
`median ${Pt(n.medianGapMs)}`,
|
|
1336
1334
|
`max ${Pt(n.maxGapMs)}`
|
|
1337
1335
|
];
|
|
1338
|
-
typeof n.over30Count == "number" && r.push(`>30ms ×${n.over30Count}`),
|
|
1336
|
+
typeof n.over30Count == "number" && r.push(`>30ms ×${n.over30Count}`), Z(e, t, r.join(" · "));
|
|
1339
1337
|
}, Wt = (e) => {
|
|
1340
1338
|
let t = Math.max(...e), n = t > 0 ? t : 1, r = 100 / (e.length - 1), i = e.map((e, t) => `${Math.round(t * r * 10) / 10},${Math.round((27 - e / n * 26) * 10) / 10}`).join(" "), a = jt("svg", {
|
|
1341
1339
|
class: "spark",
|
|
@@ -1353,96 +1351,96 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1353
1351
|
}, Gt = (e, t) => {
|
|
1354
1352
|
let n = t.longTasks ?? [], r = t.holdLongTasks ?? [];
|
|
1355
1353
|
if (n.length === 0 && r.length === 0) {
|
|
1356
|
-
|
|
1354
|
+
$(e, "none", "li dim");
|
|
1357
1355
|
return;
|
|
1358
1356
|
}
|
|
1359
|
-
let i = (e) => `${
|
|
1360
|
-
for (let t of n)
|
|
1361
|
-
for (let t of r)
|
|
1357
|
+
let i = (e) => `${Y(e?.startMs)} + ${Y(e?.durationMs)}`;
|
|
1358
|
+
for (let t of n) $(e, i(t), "li bad");
|
|
1359
|
+
for (let t of r) $(e, `${i(t)} (absorbed by hold)`, "li dim");
|
|
1362
1360
|
}, Kt = (e, t) => {
|
|
1363
1361
|
if (Mt(e), !t) {
|
|
1364
|
-
|
|
1362
|
+
$(e, "select a flight", "li dim");
|
|
1365
1363
|
return;
|
|
1366
1364
|
}
|
|
1367
|
-
let n =
|
|
1368
|
-
|
|
1369
|
-
let r =
|
|
1365
|
+
let n = Q(e, "timing");
|
|
1366
|
+
Z(n, "id", J(t.id)), Z(n, "kind / driver", `${J(t.kind)} · ${J(t.driver)}`), Z(n, "router", J(t.routerId)), Z(n, "t0", J(t.t0?.iso)), Z(n, "duration", Y(t.durationMs)), Z(n, "participants", `${X(t.participants?.screens)} screens · ${X(t.participants?.bars)} bars · ${X(t.participants?.decorators)} decorators · ${X(t.participants?.parts)} parts`), Z(n, "hold", `${J(t.holds?.kind)} · released ${Y(t.holds?.releasedAtMs)}`);
|
|
1367
|
+
let r = Q(e, "frames");
|
|
1370
1368
|
Ut(r, "held (absorbed)", t.frameSamples?.held), Ut(r, "released (visible)", t.frameSamples?.released);
|
|
1371
1369
|
let i = Rt(t.frameSamples);
|
|
1372
1370
|
i && r.appendChild(Wt(i));
|
|
1373
|
-
let a =
|
|
1374
|
-
|
|
1371
|
+
let a = Q(e, "motion (did it move)"), o = t.motion?.longestStallMs, s = t.motion?.holdReassertedAtMs;
|
|
1372
|
+
Z(a, "released frames", X(t.motion?.sampledFrames)), Z(a, "stalled frames", X(t.motion?.stalledFrames), (t.motion?.stalledFrames ?? 0) > 0 ? "bad" : void 0), Z(a, "longest stall", Y(o), (o ?? 0) >= Bt ? "bad" : void 0), Z(a, "paused after release", Ft(t.motion?.pausedAfterRelease), t.motion?.pausedAfterRelease === !0 ? "bad" : void 0), Z(a, "hold re-asserted", s == null ? "no" : Y(s), typeof s == "number" ? "bad" : void 0), Z(a, "first animation", t.motion?.firstAnimationAtMs === null || t.motion?.firstAnimationAtMs === void 0 ? "not observed" : `+${Y(t.motion.firstAnimationAtMs)} after t0`);
|
|
1375
1373
|
let c = t.morphs;
|
|
1376
1374
|
if (c) {
|
|
1377
|
-
let t =
|
|
1378
|
-
|
|
1375
|
+
let t = Q(e, "shared elements");
|
|
1376
|
+
Z(t, "registered", X(c.registered)), Z(t, "pairable / flew", `${X(c.pairable?.length)} · ${X(c.flew?.length)}`);
|
|
1379
1377
|
let n = c.skipped ?? [];
|
|
1380
|
-
|
|
1378
|
+
Z(t, "did not fly", n.length === 0 ? "none" : n.join(", "), n.length > 0 ? "bad" : void 0);
|
|
1381
1379
|
let r = c.duplicatedKeys ?? [];
|
|
1382
|
-
r.length > 0 &&
|
|
1380
|
+
r.length > 0 && Z(t, "duplicate keys in one screen", r.join(", "), "bad"), Z(t, "camera", Ft(c.camera)), Z(t, "ghosts", X(c.ghosts));
|
|
1383
1381
|
let i = (c.strandedRoles ?? 0) + (c.strandedStandIns ?? 0) + (c.strandedGhosts ?? 0) + (c.layerResidue ?? 0) + (c.leakedSheetRules ?? 0);
|
|
1384
|
-
|
|
1382
|
+
Z(t, "residue at rest", i === 0 ? "clean" : `${X(c.strandedRoles)} roles · ${X(c.strandedStandIns)} stand-ins · ${X(c.strandedGhosts)} ghosts · ${X(c.layerResidue)} in layer · ${X(c.leakedSheetRules)} rules`, i > 0 ? "bad" : void 0);
|
|
1385
1383
|
}
|
|
1386
1384
|
let l = t.tripwires ?? [];
|
|
1387
1385
|
if (l.length > 0) {
|
|
1388
|
-
let t =
|
|
1389
|
-
for (let e of l)
|
|
1386
|
+
let t = Q(e, "tripwires (one-frame events)");
|
|
1387
|
+
for (let e of l) $(t, `+${Y(e.atMs)} ${e.kind}: ${e.detail}`, "li bad");
|
|
1390
1388
|
}
|
|
1391
1389
|
let u = t.input;
|
|
1392
1390
|
if (u) {
|
|
1393
|
-
let t =
|
|
1394
|
-
|
|
1391
|
+
let t = Q(e, "what drove it");
|
|
1392
|
+
Z(t, "input", `${X(u.trusted)} trusted · ${X(u.synthetic)} synthetic`, u.synthetic > 0 ? "bad" : void 0), Z(t, "pointer types", u.pointerTypes?.join(", ") || "none observed");
|
|
1395
1393
|
}
|
|
1396
|
-
let d =
|
|
1397
|
-
|
|
1398
|
-
let g =
|
|
1399
|
-
if (_.length === 0)
|
|
1400
|
-
else for (let e of _)
|
|
1401
|
-
|
|
1394
|
+
let d = Q(e, "images"), f = t.images?.completedDuringFlight ?? 0, p = t.images?.heldDuringFlight ?? 0, m = t.images?.completedUnheld, h = typeof m == "number" ? m > 0 : f > p;
|
|
1395
|
+
Z(d, "loading at t0", X(t.images?.loadingAtStart)), Z(d, "added mid-flight", X(t.images?.addedDuringFlight)), Z(d, "completed mid-flight", X(t.images?.completedDuringFlight), h ? "bad" : void 0), Z(d, "held by the engine", X(t.images?.heldDuringFlight)), Z(d, "completed without hold", X(m), h ? "bad" : void 0), Gt(Q(e, "long tasks"), t);
|
|
1396
|
+
let g = Q(e, "landing"), _ = t.landing?.residualInlineTransforms ?? [];
|
|
1397
|
+
if (_.length === 0) Z(g, "inline residue", "clean");
|
|
1398
|
+
else for (let e of _) Z(g, "inline residue", J(e));
|
|
1399
|
+
Z(g, "off-viewport at rest", Ft(t.landing?.offViewportAtRest));
|
|
1402
1400
|
let v = t.landing?.stuckStatuses ?? [];
|
|
1403
|
-
|
|
1401
|
+
Z(g, "stuck statuses", v.length === 0 ? "none" : v.join(", "));
|
|
1404
1402
|
let y = t.landing?.orphanedHolds ?? [];
|
|
1405
|
-
if (y.length === 0)
|
|
1406
|
-
else for (let e of y)
|
|
1407
|
-
let b =
|
|
1403
|
+
if (y.length === 0) Z(g, "orphaned holds", "none");
|
|
1404
|
+
else for (let e of y) Z(g, "orphaned holds", J(e), "bad");
|
|
1405
|
+
let b = Q(e, "anomalies"), x = t.anomalies ?? [];
|
|
1408
1406
|
if (x.length === 0) {
|
|
1409
|
-
|
|
1407
|
+
$(b, "none", "li dim");
|
|
1410
1408
|
return;
|
|
1411
1409
|
}
|
|
1412
|
-
for (let e of x)
|
|
1410
|
+
for (let e of x) $(b, J(e), "li bad");
|
|
1413
1411
|
}, qt = (e, t) => {
|
|
1414
1412
|
Mt(e);
|
|
1415
|
-
for (let n of t ?? [])
|
|
1413
|
+
for (let n of t ?? []) $(e, J(n));
|
|
1416
1414
|
}, Jt = 320, Yt = 2e3, Xt = 120, Zt = "Copy report JSON", Qt = () => {}, $t = null, en = (e = {}) => {
|
|
1417
1415
|
if ($t) return $t;
|
|
1418
1416
|
if (typeof document > "u") return { detach: Qt };
|
|
1419
|
-
let { recorder: t, ownsRecorder: n } = kt(e.recorder), { host: r, root: i } = Dt(zt), a =
|
|
1417
|
+
let { recorder: t, ownsRecorder: n } = kt(e.recorder), { host: r, root: i } = Dt(zt), a = q("button", "toggle");
|
|
1420
1418
|
a.type = "button", a.setAttribute("data-corner", e.position ?? "bottom-right"), a.setAttribute("aria-label", "flemo devtools");
|
|
1421
|
-
let o =
|
|
1422
|
-
s.hidden = !0, a.appendChild(
|
|
1423
|
-
let c =
|
|
1419
|
+
let o = q("span", "count", "0"), s = q("span", "dot");
|
|
1420
|
+
s.hidden = !0, a.appendChild(q("span", "mark", "flemo")), a.appendChild(o), a.appendChild(s);
|
|
1421
|
+
let c = q("section", "panel");
|
|
1424
1422
|
c.hidden = !0;
|
|
1425
|
-
let l =
|
|
1423
|
+
let l = q("div", "grip");
|
|
1426
1424
|
l.setAttribute("role", "separator"), l.setAttribute("aria-label", "Resize flemo devtools panel");
|
|
1427
|
-
let u =
|
|
1425
|
+
let u = q("header", "head"), d = q("div", "env", "—"), f = q("button", "act", Zt);
|
|
1428
1426
|
f.type = "button";
|
|
1429
|
-
let p =
|
|
1427
|
+
let p = q("button", "act", "Close");
|
|
1430
1428
|
p.type = "button";
|
|
1431
|
-
let m =
|
|
1429
|
+
let m = q("button", "act", "Detach");
|
|
1432
1430
|
m.type = "button";
|
|
1433
|
-
let h =
|
|
1431
|
+
let h = q("button", "act", "A/B: off");
|
|
1434
1432
|
h.type = "button";
|
|
1435
|
-
let g =
|
|
1436
|
-
u.appendChild(d), u.appendChild(
|
|
1437
|
-
let _ =
|
|
1433
|
+
let g = q("div", "chips");
|
|
1434
|
+
u.appendChild(d), u.appendChild(q("div", "spacer")), u.appendChild(h), u.appendChild(f), u.appendChild(p), u.appendChild(m), u.appendChild(g);
|
|
1435
|
+
let _ = q("div", "body"), v = q("div", "list"), y = q("div", "detail");
|
|
1438
1436
|
_.appendChild(v), _.appendChild(y);
|
|
1439
|
-
let b =
|
|
1440
|
-
x.appendChild(
|
|
1441
|
-
let S =
|
|
1437
|
+
let b = q("div", "foot"), x = q("details");
|
|
1438
|
+
x.appendChild(q("summary", void 0, "What this cannot see"));
|
|
1439
|
+
let S = q("div");
|
|
1442
1440
|
x.appendChild(S), b.appendChild(x), c.appendChild(l), c.appendChild(u), c.appendChild(_), c.appendChild(b), i.appendChild(a), i.appendChild(c);
|
|
1443
1441
|
let C = !1, w = e.initialOpen === !0, T = null, E = "", D = "", O = "", k = !1, A = 0, j = 0, M = -1, N = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], P = (e) => Math.min(Math.max(e, Xt), Math.max(Xt, window.innerHeight * .9)), ee = () => {
|
|
1444
1442
|
try {
|
|
1445
|
-
let e = sessionStorage.getItem(
|
|
1443
|
+
let e = sessionStorage.getItem(Me);
|
|
1446
1444
|
if (e === null) return null;
|
|
1447
1445
|
let t = Number.parseFloat(e);
|
|
1448
1446
|
return Number.isFinite(t) ? t : null;
|
|
@@ -1451,7 +1449,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1451
1449
|
}
|
|
1452
1450
|
}, te = (e) => {
|
|
1453
1451
|
try {
|
|
1454
|
-
sessionStorage.setItem(
|
|
1452
|
+
sessionStorage.setItem(Me, String(Math.round(e)));
|
|
1455
1453
|
} catch {}
|
|
1456
1454
|
}, F = P(ee() ?? window.innerHeight * .4);
|
|
1457
1455
|
c.style.height = `${Math.round(F)}px`;
|
|
@@ -1481,7 +1479,7 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1481
1479
|
l !== D && (D = l, Kt(y, a)), k || (k = !0, qt(S, e?.blindSpots));
|
|
1482
1480
|
};
|
|
1483
1481
|
function L() {
|
|
1484
|
-
C ||
|
|
1482
|
+
C || Tt() || re();
|
|
1485
1483
|
}
|
|
1486
1484
|
function ie() {
|
|
1487
1485
|
A = 0, L(), ae();
|
|
@@ -1491,117 +1489,141 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1491
1489
|
}
|
|
1492
1490
|
let oe = () => {
|
|
1493
1491
|
window.clearTimeout(A), ae();
|
|
1494
|
-
},
|
|
1492
|
+
}, R = (e) => {
|
|
1495
1493
|
w = e, oe(), L();
|
|
1496
1494
|
};
|
|
1497
|
-
a.addEventListener("click", () =>
|
|
1495
|
+
a.addEventListener("click", () => R(!w)), p.addEventListener("click", () => R(!1)), m.addEventListener("click", () => H()), h.addEventListener("click", () => {
|
|
1498
1496
|
M = M + 1 >= N.length ? -1 : M + 1;
|
|
1499
1497
|
let e = M === -1 ? null : N[M];
|
|
1500
1498
|
t.mark(e), Nt(h, `A/B: ${e ?? "off"}`), O = "", L();
|
|
1501
1499
|
});
|
|
1502
|
-
let
|
|
1500
|
+
let se = () => {
|
|
1503
1501
|
if (!C) {
|
|
1504
|
-
if (
|
|
1505
|
-
window.clearTimeout(j), j = window.setTimeout(
|
|
1502
|
+
if (Tt()) {
|
|
1503
|
+
window.clearTimeout(j), j = window.setTimeout(se, Jt);
|
|
1506
1504
|
return;
|
|
1507
1505
|
}
|
|
1508
|
-
Nt(f, "Copied ✓"), window.clearTimeout(j), j = window.setTimeout(
|
|
1506
|
+
Nt(f, "Copied ✓"), window.clearTimeout(j), j = window.setTimeout(z, 1200);
|
|
1509
1507
|
}
|
|
1510
1508
|
};
|
|
1511
|
-
function
|
|
1512
|
-
if (
|
|
1513
|
-
j = window.setTimeout(
|
|
1509
|
+
function z() {
|
|
1510
|
+
if (Tt()) {
|
|
1511
|
+
j = window.setTimeout(z, Jt);
|
|
1514
1512
|
return;
|
|
1515
1513
|
}
|
|
1516
1514
|
j = 0, Nt(f, Zt);
|
|
1517
1515
|
}
|
|
1518
|
-
let
|
|
1516
|
+
let B = (e) => {
|
|
1519
1517
|
if (C) return;
|
|
1520
|
-
if (
|
|
1521
|
-
window.clearTimeout(j), j = window.setTimeout(() =>
|
|
1518
|
+
if (Tt()) {
|
|
1519
|
+
window.clearTimeout(j), j = window.setTimeout(() => B(e), Jt);
|
|
1522
1520
|
return;
|
|
1523
1521
|
}
|
|
1524
|
-
let t =
|
|
1522
|
+
let t = q("textarea");
|
|
1525
1523
|
t.value = e, t.setAttribute("aria-hidden", "true"), t.style.position = "fixed", t.style.opacity = "0", t.style.pointerEvents = "none", document.body.appendChild(t), t.select();
|
|
1526
1524
|
let n = document;
|
|
1527
1525
|
try {
|
|
1528
1526
|
n.execCommand?.("copy");
|
|
1529
1527
|
} catch {}
|
|
1530
|
-
t.remove(),
|
|
1528
|
+
t.remove(), se();
|
|
1531
1529
|
};
|
|
1532
1530
|
f.addEventListener("click", () => {
|
|
1533
1531
|
let e = JSON.stringify(I(), null, 2), t = navigator.clipboard;
|
|
1534
1532
|
if (t && typeof t.writeText == "function") {
|
|
1535
|
-
t.writeText(e).then(
|
|
1533
|
+
t.writeText(e).then(se, () => B(e));
|
|
1536
1534
|
return;
|
|
1537
1535
|
}
|
|
1538
|
-
|
|
1536
|
+
B(e);
|
|
1539
1537
|
});
|
|
1540
|
-
let
|
|
1538
|
+
let ce = (e) => {
|
|
1541
1539
|
F = P(window.innerHeight - e.clientY), c.style.height = `${Math.round(F)}px`;
|
|
1542
|
-
},
|
|
1543
|
-
window.removeEventListener("pointermove",
|
|
1540
|
+
}, V = () => {
|
|
1541
|
+
window.removeEventListener("pointermove", ce), window.removeEventListener("pointerup", V), te(F);
|
|
1544
1542
|
};
|
|
1545
1543
|
l.addEventListener("pointerdown", (e) => {
|
|
1546
|
-
e.preventDefault(), window.addEventListener("pointermove",
|
|
1544
|
+
e.preventDefault(), window.addEventListener("pointermove", ce), window.addEventListener("pointerup", V);
|
|
1547
1545
|
});
|
|
1548
|
-
function
|
|
1549
|
-
C || (C = !0, window.clearTimeout(A), A = 0, window.clearTimeout(j), j = 0, window.removeEventListener("pointermove",
|
|
1546
|
+
function H() {
|
|
1547
|
+
C || (C = !0, window.clearTimeout(A), A = 0, window.clearTimeout(j), j = 0, window.removeEventListener("pointermove", ce), window.removeEventListener("pointerup", V), r.remove(), n && t.detach(), $t = null);
|
|
1550
1548
|
}
|
|
1551
1549
|
document.body.appendChild(r), L(), ae();
|
|
1552
|
-
let
|
|
1553
|
-
return $t =
|
|
1554
|
-
}, tn = 500, nn = 450, rn = "\n
|
|
1550
|
+
let le = { detach: H };
|
|
1551
|
+
return $t = le, le;
|
|
1552
|
+
}, tn = 500, nn = 450, rn = "flemo:devtools-hud-hidden", an = "\n.dock {\n position: fixed;\n display: flex;\n flex-direction: column;\n align-items: flex-end;\n gap: 6px;\n max-width: calc(100vw - 16px);\n}\n.dock[data-edge^=\"top\"] {\n top: max(8px, env(safe-area-inset-top));\n /* The control sits nearest the edge the dock is anchored to, whichever that\n is, so it does not MOVE when the readout it hides collapses under it. A\n control that walks across the screen as you use it is one you have to look\n for, and the whole point of it is to be found with a thumb. */\n flex-direction: column-reverse;\n}\n.dock[data-edge^=\"bottom\"] { bottom: max(12px, env(safe-area-inset-bottom)); }\n.dock[data-edge=\"top\"],\n.dock[data-edge=\"bottom\"] {\n left: 50%;\n transform: translateX(-50%);\n align-items: center;\n}\n.dock[data-edge$=\"-left\"] {\n left: max(12px, env(safe-area-inset-left));\n align-items: flex-start;\n}\n.dock[data-edge$=\"-right\"] { right: max(12px, env(safe-area-inset-right)); }\n.hud {\n max-width: 100%;\n padding: 6px 10px;\n border: 1px solid var(--line);\n border-radius: 10px;\n background: var(--bg);\n color: var(--fg);\n font-weight: 500;\n white-space: pre;\n text-align: left;\n overflow-x: auto;\n -webkit-user-select: none;\n user-select: none;\n touch-action: manipulation;\n /* No transition and no keyframe anywhere in this sheet: the readout must\n never be a moving thing on a screen whose motion is under test. */\n}\n.hud[hidden] { display: none; }\n.hud[data-alarm=\"true\"] { border-color: var(--bad); color: var(--bad); }\n.hud[data-blocked=\"true\"] { border-color: var(--warn); color: var(--warn); }\n/* The panel's toggle, in the opposite corner: same pill, same mark-and-chip,\n so the two controls read as one instrument rather than two. */\n.eye {\n display: flex;\n align-items: center;\n gap: 6px;\n margin: 0;\n padding: 6px 10px;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--bg);\n color: var(--fg);\n font: inherit;\n cursor: pointer;\n -webkit-user-select: none;\n user-select: none;\n touch-action: manipulation;\n}\n.eye:hover { background: var(--bg-soft); }\n.mark { font-weight: 700; letter-spacing: 0.04em; }\n.state {\n padding: 0 6px;\n border-radius: 999px;\n background: var(--bg-soft);\n color: var(--fg-dim);\n}\n", on = (e) => Math.round(e * 10) / 10, sn = (e) => {
|
|
1555
1553
|
if (!e) return "flemo no flight yet";
|
|
1556
1554
|
let t = e.frameSamples?.released, n = e.anomalies?.length ?? 0;
|
|
1557
|
-
return `${e.kind} ${Math.round(e.durationMs)}ms gap ${
|
|
1558
|
-
},
|
|
1555
|
+
return `${e.kind} ${Math.round(e.durationMs)}ms gap ${on(t?.maxGapMs ?? 0)} drop ${t?.over30Count ?? 0}` + (n > 0 ? ` !${n}` : " ok") + (e.bucket ? ` [${e.bucket}]` : "");
|
|
1556
|
+
}, cn = (e, t) => {
|
|
1559
1557
|
let n = [], r = (e?.preconditions ?? []).filter((e) => e.status === "violated");
|
|
1560
|
-
if (r.length > 0 && n.push(`BLOCKED ${r.map((e) => e.id).join(" ")}`), !t) return n.push(`rAF ${
|
|
1558
|
+
if (r.length > 0 && n.push(`BLOCKED ${r.map((e) => e.id).join(" ")}`), !t) return n.push(`rAF ${on(e?.environment?.rafCadence?.medianGapMs ?? 0)}ms`), n;
|
|
1561
1559
|
let i = t.frameSamples;
|
|
1562
|
-
n.push(`frames n${i?.released?.count ?? 0} med ${
|
|
1560
|
+
n.push(`frames n${i?.released?.count ?? 0} med ${on(i?.released?.medianGapMs ?? 0)} max ${on(i?.released?.maxGapMs ?? 0)}`), n.push(`motion stall ${on(t.motion?.longestStallMs ?? 0)}ms tail ${t.motion?.tailFrames ?? 0} start +${t.motion?.firstAnimationAtMs ?? "?"}ms`), n.push(`hold ${t.holds?.kind ?? "none"} rel ${t.holds?.releasedAtMs ?? "-"}ms task ${t.longTasks?.length ?? 0}`);
|
|
1563
1561
|
let a = t.morphs;
|
|
1564
1562
|
a && (a.pairable.length > 0 || a.flew.length > 0) && n.push(`morph ${a.flew.length} flew` + (a.camera ? " cam" : "") + (a.skipped.length > 0 ? ` SKIPPED ${a.skipped.length} (${a.skipped.join(",")})` : ""));
|
|
1565
1563
|
let o = t.input;
|
|
1566
1564
|
o && n.push(`input ${o.pointerTypes.join("/") || "none"}` + (o.synthetic > 0 ? ` SYNTHETIC ${o.synthetic}` : ""));
|
|
1567
1565
|
for (let e of t.anomalies ?? []) n.push(`! ${e.slice(0, 120)}`);
|
|
1568
1566
|
return n;
|
|
1569
|
-
},
|
|
1570
|
-
|
|
1567
|
+
}, ln = () => {
|
|
1568
|
+
try {
|
|
1569
|
+
return sessionStorage.getItem(rn) === "1";
|
|
1570
|
+
} catch {
|
|
1571
|
+
return !1;
|
|
1572
|
+
}
|
|
1573
|
+
}, un = (e) => {
|
|
1574
|
+
try {
|
|
1575
|
+
sessionStorage.setItem(rn, e ? "1" : "0");
|
|
1576
|
+
} catch {}
|
|
1577
|
+
}, dn = null, fn = (e = {}) => {
|
|
1578
|
+
if (dn) return dn;
|
|
1571
1579
|
if (typeof document > "u") return { detach: () => {} };
|
|
1572
|
-
let { recorder: t, ownsRecorder: n } = kt(e.recorder), r = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], { host: i, root: a } = Dt(
|
|
1573
|
-
|
|
1574
|
-
let
|
|
1580
|
+
let { recorder: t, ownsRecorder: n } = kt(e.recorder), r = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], { host: i, root: a } = Dt(an);
|
|
1581
|
+
i.style.zIndex = "2147482998";
|
|
1582
|
+
let o = document.createElement("div");
|
|
1583
|
+
o.className = "dock", o.setAttribute("data-edge", e.position ?? "bottom-right");
|
|
1584
|
+
let s = document.createElement("div");
|
|
1585
|
+
s.className = "hud", s.setAttribute("role", "status"), s.textContent = "flemo attaching";
|
|
1586
|
+
let c = document.createElement("button");
|
|
1587
|
+
c.className = "eye", c.type = "button";
|
|
1588
|
+
let l = document.createElement("span");
|
|
1589
|
+
l.className = "mark", l.textContent = "hud";
|
|
1590
|
+
let u = document.createElement("span");
|
|
1591
|
+
u.className = "state", c.appendChild(l), c.appendChild(u), o.appendChild(s), o.appendChild(c), a.appendChild(o);
|
|
1592
|
+
let d = !1, f = e.initialExpanded === !0, p = e.initialHidden ?? ln(), m = -1, h = 0, g = 0, _ = !1, v = "", y = () => {
|
|
1575
1593
|
try {
|
|
1576
1594
|
return t.report();
|
|
1577
1595
|
} catch {
|
|
1578
1596
|
return null;
|
|
1579
1597
|
}
|
|
1580
|
-
},
|
|
1581
|
-
if (
|
|
1582
|
-
let e =
|
|
1583
|
-
|
|
1584
|
-
let i = r.join("\n"), a = (e?.preconditions ?? []).some((e) => e.status === "violated"),
|
|
1585
|
-
i !==
|
|
1586
|
-
},
|
|
1587
|
-
|
|
1588
|
-
},
|
|
1589
|
-
|
|
1598
|
+
}, b = () => {
|
|
1599
|
+
if (d || p || Tt()) return;
|
|
1600
|
+
let e = y(), t = e?.flights ?? [], n = t[t.length - 1], r = [sn(n)];
|
|
1601
|
+
f && r.push(...cn(e, n));
|
|
1602
|
+
let i = r.join("\n"), a = (e?.preconditions ?? []).some((e) => e.status === "violated"), o = (n?.anomalies?.length ?? 0) > 0;
|
|
1603
|
+
i !== v && (v = i, s.textContent = i), s.setAttribute("data-alarm", o ? "true" : "false"), s.setAttribute("data-blocked", a ? "true" : "false");
|
|
1604
|
+
}, x = () => {
|
|
1605
|
+
h = 0, b(), h = window.setTimeout(x, tn);
|
|
1606
|
+
}, S = (e) => {
|
|
1607
|
+
p = e, s.hidden = e, u.textContent = e ? "show" : "hide", c.setAttribute("data-hidden", e ? "true" : "false"), c.setAttribute("aria-label", e ? "show the flemo readout" : "hide the flemo readout"), c.setAttribute("aria-expanded", e ? "false" : "true"), window.clearTimeout(h), h = 0, !e && (v = "", b(), h = window.setTimeout(x, tn));
|
|
1608
|
+
}, C = () => {
|
|
1609
|
+
m = m + 1 >= r.length ? -1 : m + 1, t.mark(m === -1 ? null : r[m]), v = "", b();
|
|
1590
1610
|
};
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1611
|
+
s.addEventListener("pointerdown", () => {
|
|
1612
|
+
_ = !1, window.clearTimeout(g), g = window.setTimeout(() => {
|
|
1613
|
+
_ = !0, C();
|
|
1594
1614
|
}, nn);
|
|
1595
|
-
}),
|
|
1596
|
-
window.clearTimeout(
|
|
1597
|
-
}),
|
|
1598
|
-
|
|
1599
|
-
|
|
1615
|
+
}), s.addEventListener("pointerup", () => {
|
|
1616
|
+
window.clearTimeout(g), g = 0, !_ && (f = !f, v = "", b());
|
|
1617
|
+
}), s.addEventListener("pointercancel", () => window.clearTimeout(g)), c.addEventListener("click", () => {
|
|
1618
|
+
S(!p), un(p);
|
|
1619
|
+
});
|
|
1620
|
+
let w = () => {
|
|
1621
|
+
d || (d = !0, window.clearTimeout(h), h = 0, window.clearTimeout(g), g = 0, i.remove(), n && t.detach(), dn = null);
|
|
1600
1622
|
};
|
|
1601
|
-
document.body.appendChild(i),
|
|
1602
|
-
let
|
|
1603
|
-
return
|
|
1604
|
-
},
|
|
1623
|
+
document.body.appendChild(i), S(p);
|
|
1624
|
+
let T = { detach: w };
|
|
1625
|
+
return dn = T, T;
|
|
1626
|
+
}, pn = 1200, mn = 2, hn = () => [...document.querySelectorAll(`[${d}]`)], gn = (e) => ve(getComputedStyle(e).transform) ?? 0, _n = (e) => {
|
|
1605
1627
|
let t = [];
|
|
1606
1628
|
for (let n of e) {
|
|
1607
1629
|
let e = n;
|
|
@@ -1611,22 +1633,22 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1611
1633
|
}
|
|
1612
1634
|
}
|
|
1613
1635
|
return t;
|
|
1614
|
-
},
|
|
1636
|
+
}, vn = (e) => e.length === 0 ? 0 : e.reduce((e, t) => e + t, 0) / e.length, yn = (e) => Math.round(e * 100) / 100, bn = (e) => {
|
|
1615
1637
|
/* v8 ignore next -- SSR guard: there is nothing to watch without a document. */
|
|
1616
1638
|
if (typeof document > "u") return { detach: () => {} };
|
|
1617
1639
|
let t = e.now ?? (() => performance.now()), n = e.schedule ?? ((e) => {
|
|
1618
1640
|
requestAnimationFrame(e);
|
|
1619
1641
|
}), r = () => {
|
|
1620
|
-
let r =
|
|
1642
|
+
let r = hn();
|
|
1621
1643
|
if (r.length === 0) return;
|
|
1622
|
-
let i = Math.max(...r.map((e) => Math.abs(
|
|
1623
|
-
if (i <
|
|
1644
|
+
let i = Math.max(...r.map((e) => Math.abs(gn(e))));
|
|
1645
|
+
if (i < mn) return;
|
|
1624
1646
|
let a = t(), o = [], s = () => {
|
|
1625
|
-
let r =
|
|
1647
|
+
let r = hn();
|
|
1626
1648
|
if (o.push({
|
|
1627
1649
|
t: Math.round(t() - a),
|
|
1628
|
-
x: r.map((e) =>
|
|
1629
|
-
animations:
|
|
1650
|
+
x: r.map((e) => yn(gn(e))),
|
|
1651
|
+
animations: _n(r)
|
|
1630
1652
|
}), t() - a < 1200) {
|
|
1631
1653
|
n(s);
|
|
1632
1654
|
return;
|
|
@@ -1638,13 +1660,13 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1638
1660
|
let t = Math.abs(u[e] - u[e - 1]);
|
|
1639
1661
|
t > 0 && d.push(t);
|
|
1640
1662
|
}
|
|
1641
|
-
let f =
|
|
1663
|
+
let f = vn(d.slice(0, 3)), p = vn(d.slice(-3));
|
|
1642
1664
|
e.onRelease({
|
|
1643
1665
|
samples: o,
|
|
1644
|
-
travelAtReleasePx:
|
|
1645
|
-
biggestStepPx:
|
|
1646
|
-
openingStepPx:
|
|
1647
|
-
closingStepPx:
|
|
1666
|
+
travelAtReleasePx: yn(i),
|
|
1667
|
+
biggestStepPx: yn(Math.max(0, ...d)),
|
|
1668
|
+
openingStepPx: yn(f),
|
|
1669
|
+
closingStepPx: yn(p),
|
|
1648
1670
|
eased: d.length > 3 && p < f * .5,
|
|
1649
1671
|
teleported: Math.max(0, ...d) > i * .5
|
|
1650
1672
|
});
|
|
@@ -1660,4 +1682,4 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
|
1660
1682
|
} };
|
|
1661
1683
|
};
|
|
1662
1684
|
//#endregion
|
|
1663
|
-
export { c as BLIND_SPOTS,
|
|
1685
|
+
export { c as BLIND_SPOTS, Pe as CORE_FLAGS, Ne as DEVTOOLS_OWNED_FLAGS, Fe as FLAG_REGISTRY, pe as JUDGING_PROTOCOL, e as LONG_GAP_MS, i as MID_FLIGHT_TASK_MS, n as OPENING_WINDOW_LEAD_MS, r as OPENING_WINDOW_TAIL_MS, Me as PANEL_HEIGHT_KEY, mt as REPORT_SCHEMA_VERSION, G as RETIRED_FLAGS, Ie as RETIRED_MARKER, a as STALL_MS, t as STUCK_STATUS_MS, pn as SWIPE_PROBE_MS, Ue as TRACE_KEY, fn as attachDevtoolsHud, en as attachDevtoolsPanel, Ct as attachFlightRecorder, bn as attachSwipeProbe, ne as captureEnvironment, ge as classifyDriver, Ke as clearTrace, he as computeFrameStats, me as computePhaseStats, o as deriveFlightAnomalies, He as deriveOverrideWarnings, it as derivePreconditions, s as deriveReportAnomalies, pt as deriveVerdict, N as detectEngine, F as developmentHints, P as isEmulationSuspected, _e as kindFromStatus, qe as loadTrace, ve as parseTranslateX, ee as sampleRafCadence, Ge as saveTrace, Ve as snapshotOverrides, u as summariseBuckets };
|