@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/react.mjs
CHANGED
|
@@ -9,7 +9,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
9
9
|
"park",
|
|
10
10
|
"park-under",
|
|
11
11
|
"park-over"
|
|
12
|
-
], b = (e) => `[${e}]`, x = (e, t) => `[${e}="${t}"]`,
|
|
12
|
+
], b = (e) => `[${e}]`, x = (e, t) => `[${e}="${t}"]`, S = 1e4, C = (e) => {
|
|
13
13
|
let t = [], { t0Ms: n, driver: r, frameSamples: i, longTasks: a, holdLongTasks: o, landing: s } = e, c = n + (e.releasedAtMs ?? 0);
|
|
14
14
|
if (i.released.over30Count > 0) {
|
|
15
15
|
let e = r === "compiled" ? " (compiled/compositor flights can still present cleanly through main-thread gaps)" : "";
|
|
@@ -18,29 +18,29 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
18
18
|
for (let e of a) e.startMs <= c + 120 && e.startMs + e.durationMs >= c - 50 ? t.push(`long task ${Math.round(e.durationMs)}ms overlapped the visible-motion start (opening-swallow risk: the first presented frames of the transition may have been lost)`) : e.durationMs >= 100 && t.push(`long task ${Math.round(e.durationMs)}ms mid-flight`);
|
|
19
19
|
for (let e of o) e.durationMs >= 100 && t.push(`long task ${Math.round(e.durationMs)}ms absorbed by the hold (screen posed, not yet moving — the hold doing its job, not user-visible jank)`);
|
|
20
20
|
let { motion: l, images: u } = e;
|
|
21
|
-
l.holdReassertedAtMs !== null && t.push(`hold re-asserted ${l.holdReassertedAtMs}ms into the flight, after it had already released (an interleaved commit wrote the stale paused hold attribute over a running flight — the flemo 2026-08-18 release-race signature; the motion pauses while every timing metric stays clean)`), l.pausedAfterRelease && t.push("compiled animation reported playState=paused after its release (the flight was posed and then stopped mid-motion, not merely starved of frames)"), l.longestStallMs >= 48 && t.push(`motion stalled ${l.longestStallMs}ms mid-flight (${l.stalledFrames}/${l.sampledFrames} released frames advanced neither the animation clock nor the pose — freeze, or freeze-then-leap if the flight still landed on time)`), l.sampledFrames === 0 && e.releasedAtMs !== null && t.push("no released frames were sampled (the flight ended at or before its own hold release — the visible motion, if any, was never observed)"), u.completedUnheld > 0 && t.push(`${u.completedUnheld} image(s) finished loading mid-flight without a hold (${u.completedDuringFlight} completed, ${u.heldDuringFlight} held; ${u.loadingAtStart} were loading at t0, ${u.addedDuringFlight} arrived mid-flight) — each decode rasters on the moving layer and costs a present; this is the warm-side image-hold regression`), s.orphanedHolds.length > 0 && t.push(`hold markers left on the page at rest: ${s.orphanedHolds.join("; ")} (whatever they hide has no owner left to reveal it — the permanently-blank-avatar class)`), s.residualInlineTransforms.length > 0 && t.push(`residual inline style after COMPLETED: ${s.residualInlineTransforms.join("; ")} (landing cleanup failure — the landed scope belongs to the compiled rest rules)`), s.offViewportAtRest && t.push("screen resting at from-pose while COMPLETED+active (blank-viewport signature — the flemo PR #259 class: a residual pose left the landed screen parked off-viewport)"), s.stuckStatuses.length > 0 && t.push(`transitional status stuck >${
|
|
21
|
+
l.holdReassertedAtMs !== null && t.push(`hold re-asserted ${l.holdReassertedAtMs}ms into the flight, after it had already released (an interleaved commit wrote the stale paused hold attribute over a running flight — the flemo 2026-08-18 release-race signature; the motion pauses while every timing metric stays clean)`), l.pausedAfterRelease && t.push("compiled animation reported playState=paused after its release (the flight was posed and then stopped mid-motion, not merely starved of frames)"), l.longestStallMs >= 48 && t.push(`motion stalled ${l.longestStallMs}ms mid-flight (${l.stalledFrames}/${l.sampledFrames} released frames advanced neither the animation clock nor the pose — freeze, or freeze-then-leap if the flight still landed on time)`), l.sampledFrames === 0 && e.releasedAtMs !== null && t.push("no released frames were sampled (the flight ended at or before its own hold release — the visible motion, if any, was never observed)"), u.completedUnheld > 0 && t.push(`${u.completedUnheld} image(s) finished loading mid-flight without a hold (${u.completedDuringFlight} completed, ${u.heldDuringFlight} held; ${u.loadingAtStart} were loading at t0, ${u.addedDuringFlight} arrived mid-flight) — each decode rasters on the moving layer and costs a present; this is the warm-side image-hold regression`), s.orphanedHolds.length > 0 && t.push(`hold markers left on the page at rest: ${s.orphanedHolds.join("; ")} (whatever they hide has no owner left to reveal it — the permanently-blank-avatar class)`), s.residualInlineTransforms.length > 0 && t.push(`residual inline style after COMPLETED: ${s.residualInlineTransforms.join("; ")} (landing cleanup failure — the landed scope belongs to the compiled rest rules)`), s.offViewportAtRest && t.push("screen resting at from-pose while COMPLETED+active (blank-viewport signature — the flemo PR #259 class: a residual pose left the landed screen parked off-viewport)"), s.stuckStatuses.length > 0 && t.push(`transitional status stuck >${S / 1e3}s: ${s.stuckStatuses.join(", ")} (navigation queue lock or missed animationend — later navigations will be swallowed)`);
|
|
22
22
|
let { morphs: d, tripwires: f } = e;
|
|
23
23
|
for (let e of f) t.push(`tripwire ${e.kind} at +${e.atMs}ms: ${e.detail}`);
|
|
24
24
|
return d.skipped.length > 0 && t.push(`shared element(s) did not fly: ${d.skipped.join(", ")} (${d.pairable.length} pairable key(s), ${d.flew.length} flew) — both ends were registered on two different screens and neither was stamped with a flight role, so the pair was never made`), d.duplicatedKeys.length > 0 && t.push(`pairing key(s) used twice inside one screen: ${d.duplicatedKeys.join(", ")} (two ends under one screen are not a pair, so one of them can never fly — this is in the consuming app)`), d.strandedRoles > 0 && t.push(`${d.strandedRoles} morph element(s) still carry a flight role at rest (the stranded participant class: a role that outlives its flight stays in the layer and poisons the NEXT pairing, which is how one interrupted gesture turned into every later pop losing its camera)`), (d.strandedStandIns > 0 || d.strandedGhosts > 0 || d.layerResidue > 0) && t.push(`morph residue at rest: ${d.strandedStandIns} stand-in(s), ${d.strandedGhosts} ghost(s), ${d.layerResidue} element(s) left in a flight layer (a stand-in is a hole in the layout and a layer element is a corpse the next flight will pair against)`), d.leakedSheetRules > 0 && t.push(`${d.leakedSheetRules} morph keyframe rule(s) were left in the per-flight sheet (a flight that never landed keeps its keyframes; they accumulate for the life of the page)`), r === "unknown" && t.push("driver could not be classified (no running flemo-* CSSAnimation and no player inline-style signature observed — zero-duration flight, or the sampler attached after motion ended)"), t;
|
|
25
|
-
},
|
|
25
|
+
}, w = (e) => {
|
|
26
26
|
let t = [];
|
|
27
27
|
if (e.emulationSuspected) {
|
|
28
28
|
let n = /Win/i.test(e.platform) ? " (Windows touch hardware makes this signal ambiguous — confirm the DevTools device toolbar state)" : "";
|
|
29
29
|
t.push("DevTools device emulation suspected — the page composites to a rescaled surface, so visual reports from this session are untrustworthy; judge motion in a plain window or on a real device" + n);
|
|
30
30
|
}
|
|
31
|
-
return e.stuckFlightOpen && t.push(`a flight is still transitional after ${
|
|
32
|
-
},
|
|
31
|
+
return e.stuckFlightOpen && t.push(`a flight is still transitional after ${S / 1e3}s — the navigation queue is likely locked; subsequent navigations will be ignored`), e.flightAnomalies.some((e) => e.some((e) => e.includes("blank-viewport"))) && t.push("at least one flight landed with the blank-viewport signature (see that flight's anomalies)"), t;
|
|
32
|
+
}, T = [
|
|
33
33
|
"macOS Chrome present-pipeline pacing: on 120Hz ProMotion displays Chrome can present frames unevenly even when rAF cadence and this report read perfectly clean (Chromium issues 40062488 / 345275139; proven with a no-script pure-CSS control page that still juddered). Not diagnosable or fixable from page code.",
|
|
34
34
|
"Display-hardware effects: local dimming, backlight modulation, and panel overdrive alter perceived motion and are invisible to every web API.",
|
|
35
35
|
"Compositor-internal present skips: a frame can be produced on time (clean rAF, clean player gaps) yet dropped or delayed inside the compositor's present queue; only platform tools (about:tracing, Instruments) see that layer.",
|
|
36
36
|
"DevTools device emulation composites the page to a rescaled surface: every in-page instrument reads the pre-scale surface and reports clean while the eye watches the post-scale one, so emulated sessions grow shimmer/flash artifacts that do not exist in a plain window or on a real device."
|
|
37
|
-
],
|
|
37
|
+
], E = (e) => {
|
|
38
38
|
/* v8 ignore next -- unreachable: a group exists only because a flight was
|
|
39
39
|
put in it, so nothing ever asks for the median of nothing. */
|
|
40
40
|
if (e.length === 0) return 0;
|
|
41
41
|
let t = [...e].sort((e, t) => e - t);
|
|
42
42
|
return Math.round(t[Math.floor(t.length / 2)] * 10) / 10;
|
|
43
|
-
},
|
|
43
|
+
}, ee = (e) => {
|
|
44
44
|
let t = e.filter((e) => typeof e.bucket == "string");
|
|
45
45
|
if (t.length === 0) return [];
|
|
46
46
|
let n = /* @__PURE__ */ new Map();
|
|
@@ -51,31 +51,31 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
51
51
|
return [...n.entries()].map(([e, t]) => ({
|
|
52
52
|
bucket: e,
|
|
53
53
|
flights: t.length,
|
|
54
|
-
medianDurationMs:
|
|
55
|
-
medianReleasedGapMs:
|
|
54
|
+
medianDurationMs: E(t.map((e) => e.durationMs)),
|
|
55
|
+
medianReleasedGapMs: E(t.map((e) => e.frameSamples.released.medianGapMs)),
|
|
56
56
|
worstReleasedGapMs: t.reduce((e, t) => Math.max(e, t.frameSamples.released.maxGapMs), 0),
|
|
57
57
|
longGapCount: t.reduce((e, t) => e + t.frameSamples.released.over30Count, 0),
|
|
58
58
|
anomalyCount: t.reduce((e, t) => e + t.anomalies.length, 0),
|
|
59
59
|
stalledFlights: t.filter((e) => e.motion.stalledFrames > 0).length
|
|
60
60
|
})).sort((e, t) => e.bucket.localeCompare(t.bucket));
|
|
61
|
-
},
|
|
61
|
+
}, D = () => {
|
|
62
62
|
if (typeof navigator > "u") return null;
|
|
63
63
|
let e = navigator.userAgentData;
|
|
64
64
|
return !e || !Array.isArray(e.brands) ? null : e.brands.map((e) => ({
|
|
65
65
|
brand: String(e.brand ?? ""),
|
|
66
66
|
version: String(e.version ?? "")
|
|
67
67
|
}));
|
|
68
|
-
},
|
|
68
|
+
}, O = () => {
|
|
69
69
|
if (typeof navigator > "u") return "unknown";
|
|
70
|
-
let e =
|
|
70
|
+
let e = D();
|
|
71
71
|
if (e?.some((e) => /Chromium/i.test(e.brand))) return "blink";
|
|
72
72
|
let t = navigator.userAgent ?? "";
|
|
73
73
|
return /Firefox|FxiOS/i.test(t) ? "gecko" : e || /AppleWebKit/i.test(t) && !/Chrome|Chromium|Android/i.test(t) ? "webkit" : /Android/i.test(t) ? "blink" : "unknown";
|
|
74
|
-
},
|
|
75
|
-
if (typeof navigator > "u" ||
|
|
74
|
+
}, k = () => {
|
|
75
|
+
if (typeof navigator > "u" || O() !== "blink") return !1;
|
|
76
76
|
let e = navigator.platform ?? "";
|
|
77
77
|
return /Mac|Win|Linux/i.test(e) ? /Android/i.test(navigator.userAgent ?? "") && !/Mac|Win/i.test(e) ? /Linux (x86_64|i686)/i.test(e) : (navigator.maxTouchPoints ?? 0) > 0 : !1;
|
|
78
|
-
},
|
|
78
|
+
}, A = (e = 20) => new Promise((t) => {
|
|
79
79
|
let n = Number.isFinite(e) ? Math.max(1, Math.floor(e)) : 20;
|
|
80
80
|
if (typeof requestAnimationFrame != "function" || typeof performance > "u") {
|
|
81
81
|
t({
|
|
@@ -97,7 +97,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
97
97
|
requestAnimationFrame(a);
|
|
98
98
|
};
|
|
99
99
|
requestAnimationFrame(a);
|
|
100
|
-
}),
|
|
100
|
+
}), j = [
|
|
101
101
|
"__vite_plugin_react_preamble_installed__",
|
|
102
102
|
"__vite__",
|
|
103
103
|
"__NEXT_HMR_CB",
|
|
@@ -106,10 +106,10 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
106
106
|
"webpackHotUpdate",
|
|
107
107
|
"__REACT_REFRESH_RUNTIME__",
|
|
108
108
|
"$RefreshReg$"
|
|
109
|
-
],
|
|
109
|
+
], te = () => {
|
|
110
110
|
if (typeof window > "u") return [];
|
|
111
111
|
let e = [];
|
|
112
|
-
for (let t of
|
|
112
|
+
for (let t of j) try {
|
|
113
113
|
window[t] !== void 0 && e.push(t);
|
|
114
114
|
} catch {}
|
|
115
115
|
return e;
|
|
@@ -128,8 +128,8 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
128
128
|
}
|
|
129
129
|
return {
|
|
130
130
|
userAgent: n?.userAgent ?? "",
|
|
131
|
-
uaBrands:
|
|
132
|
-
engine:
|
|
131
|
+
uaBrands: D(),
|
|
132
|
+
engine: O(),
|
|
133
133
|
platform: n?.platform ?? "",
|
|
134
134
|
maxTouchPoints: n?.maxTouchPoints ?? 0,
|
|
135
135
|
devicePixelRatio: r?.devicePixelRatio ?? 1,
|
|
@@ -145,8 +145,8 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
145
145
|
visualViewportScale: r?.visualViewport?.scale ?? null,
|
|
146
146
|
rafCadence: e,
|
|
147
147
|
reducedMotion: i,
|
|
148
|
-
developmentHints:
|
|
149
|
-
emulationSuspected:
|
|
148
|
+
developmentHints: te(),
|
|
149
|
+
emulationSuspected: k(),
|
|
150
150
|
observation: {
|
|
151
151
|
longTasks: M(),
|
|
152
152
|
elementAnimations: typeof Element < "u" && typeof Element.prototype.getAnimations == "function",
|
|
@@ -251,10 +251,10 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
251
251
|
e.tracked.add(t), e.addedDuringFlight += 1;
|
|
252
252
|
}
|
|
253
253
|
}
|
|
254
|
-
},
|
|
254
|
+
}, R = (e, t) => {
|
|
255
255
|
for (let n of t) for (let t of Array.from(n.querySelectorAll(`img[${a}]`))) e.held.add(t);
|
|
256
256
|
for (let t of e.tracked) t.hasAttribute("data-flemo-img-hold") && e.held.add(t);
|
|
257
|
-
},
|
|
257
|
+
}, fe = (e) => {
|
|
258
258
|
let t = 0, n = 0;
|
|
259
259
|
for (let r of e.tracked) r.complete && (t += 1, e.held.has(r) || (n += 1));
|
|
260
260
|
return {
|
|
@@ -264,12 +264,12 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
264
264
|
heldDuringFlight: e.held.size,
|
|
265
265
|
completedUnheld: n
|
|
266
266
|
};
|
|
267
|
-
},
|
|
267
|
+
}, pe = [
|
|
268
268
|
"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.",
|
|
269
269
|
"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.",
|
|
270
270
|
"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.",
|
|
271
271
|
"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."
|
|
272
|
-
],
|
|
272
|
+
], z = (e) => Math.round(e * 10) / 10, me = (e) => {
|
|
273
273
|
if (e.length === 0) return {
|
|
274
274
|
count: 0,
|
|
275
275
|
medianGapMs: 0,
|
|
@@ -279,11 +279,11 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
279
279
|
let t = [...e].sort((e, t) => e - t);
|
|
280
280
|
return {
|
|
281
281
|
count: e.length,
|
|
282
|
-
medianGapMs:
|
|
283
|
-
maxGapMs:
|
|
282
|
+
medianGapMs: z(t[Math.floor(t.length / 2)]),
|
|
283
|
+
maxGapMs: z(t[t.length - 1]),
|
|
284
284
|
over30Count: e.filter((e) => e >= 30).length
|
|
285
285
|
};
|
|
286
|
-
},
|
|
286
|
+
}, he = (e, t = []) => {
|
|
287
287
|
let n = [...e, ...t];
|
|
288
288
|
return {
|
|
289
289
|
...n.length === 0 ? {
|
|
@@ -294,18 +294,18 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
294
294
|
let e = [...n].sort((e, t) => e - t);
|
|
295
295
|
return {
|
|
296
296
|
count: n.length,
|
|
297
|
-
medianGapMs:
|
|
298
|
-
maxGapMs:
|
|
297
|
+
medianGapMs: z(e[Math.floor(e.length / 2)]),
|
|
298
|
+
maxGapMs: z(e[e.length - 1])
|
|
299
299
|
};
|
|
300
300
|
})(),
|
|
301
|
-
longGaps: n.filter((e) => e >= 30).map(
|
|
302
|
-
held:
|
|
303
|
-
released:
|
|
301
|
+
longGaps: n.filter((e) => e >= 30).map(z),
|
|
302
|
+
held: me(e),
|
|
303
|
+
released: me(t)
|
|
304
304
|
};
|
|
305
|
-
},
|
|
305
|
+
}, ge = (e) => {
|
|
306
306
|
let t = e.inlineSuppression || e.inlineAdvance;
|
|
307
307
|
return t && e.compiledAnimation ? "mixed" : t ? "inline" : e.compiledAnimation ? "compiled" : "unknown";
|
|
308
|
-
},
|
|
308
|
+
}, _e = (e) => e === "PUSHING" ? "PUSH" : e === "POPPING" ? "POP" : e === "REPLACING" ? "REPLACE" : null, ve = (e) => {
|
|
309
309
|
let t = /^matrix3d\(([^)]+)\)$/.exec(e.trim());
|
|
310
310
|
if (t) {
|
|
311
311
|
let e = t[1].split(",").map((e) => Number(e.trim()));
|
|
@@ -317,7 +317,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
317
317
|
return e.length === 6 && Number.isFinite(e[4]) ? e[4] : null;
|
|
318
318
|
}
|
|
319
319
|
return null;
|
|
320
|
-
},
|
|
320
|
+
}, ye = (e) => {
|
|
321
321
|
if (e) return [];
|
|
322
322
|
let t = [];
|
|
323
323
|
for (let [e, n] of [[a, "image reveal hold"], [o, "arrival hold"]]) {
|
|
@@ -325,7 +325,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
325
325
|
r > 0 && t.push(`${r} × ${n} (${e}) still marked at rest`);
|
|
326
326
|
}
|
|
327
327
|
return t;
|
|
328
|
-
},
|
|
328
|
+
}, be = (e, t) => {
|
|
329
329
|
let n = [], i = !1, a = window.visualViewport?.width ?? window.innerWidth ?? 0;
|
|
330
330
|
return e.forEach((e, t) => {
|
|
331
331
|
if (!(e instanceof HTMLElement) || !e.isConnected) return;
|
|
@@ -337,27 +337,27 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
337
337
|
if (s === "none") return;
|
|
338
338
|
let c = e.getAttribute(r) === "true", l = `screen[${t}]${c ? " (active)" : ""}`;
|
|
339
339
|
if (e.style.transform !== "" && e.style.transform !== "none" && n.push(`${l} transform=${e.style.transform}`), e.style.opacity !== "" && e.style.opacity !== "1" && n.push(`${l} opacity=${e.style.opacity}`), c && e.getAttribute("data-flemo-status") === "COMPLETED" && a > 0) {
|
|
340
|
-
let e =
|
|
340
|
+
let e = ve(o);
|
|
341
341
|
e !== null && Math.abs(e) >= a * .5 && (i = !0);
|
|
342
342
|
}
|
|
343
343
|
}), {
|
|
344
344
|
residualInlineTransforms: n,
|
|
345
345
|
offViewportAtRest: i,
|
|
346
|
-
orphanedHolds:
|
|
346
|
+
orphanedHolds: ye(t)
|
|
347
347
|
};
|
|
348
|
-
},
|
|
348
|
+
}, xe = g.map((e) => `[${u}="${e}"]`).join(","), Se = b(t), Ce = (e) => Math.round(e * 10) / 10, B = (e) => {
|
|
349
349
|
let t = e.getAttribute(d);
|
|
350
350
|
return t === null || t === "" ? null : t;
|
|
351
|
-
},
|
|
351
|
+
}, we = (e) => {
|
|
352
352
|
let t = e.getAttribute(u);
|
|
353
353
|
return t !== null && g.includes(t);
|
|
354
|
-
},
|
|
354
|
+
}, Te = () => {
|
|
355
355
|
try {
|
|
356
356
|
return document.querySelector("style[data-flemo-morph-sheet]")?.sheet?.cssRules.length ?? 0;
|
|
357
357
|
} catch {
|
|
358
358
|
return 0;
|
|
359
359
|
}
|
|
360
|
-
},
|
|
360
|
+
}, Ee = (e) => {
|
|
361
361
|
let t = {
|
|
362
362
|
registered: 0,
|
|
363
363
|
pairable: /* @__PURE__ */ new Set(),
|
|
@@ -367,17 +367,17 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
367
367
|
ghosts: 0,
|
|
368
368
|
ghostBornAt: /* @__PURE__ */ new Map(),
|
|
369
369
|
shortestGhostLifeMs: null,
|
|
370
|
-
sheetRulesAtStart:
|
|
370
|
+
sheetRulesAtStart: Te()
|
|
371
371
|
}, n = new Set(e), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map();
|
|
372
372
|
for (let e of Array.from(document.querySelectorAll(b(u)))) {
|
|
373
373
|
t.registered += 1;
|
|
374
|
-
let a =
|
|
374
|
+
let a = B(e);
|
|
375
375
|
if (a === null) continue;
|
|
376
|
-
if (
|
|
376
|
+
if (we(e)) {
|
|
377
377
|
t.flew.add(a);
|
|
378
378
|
continue;
|
|
379
379
|
}
|
|
380
|
-
let o = e.closest(
|
|
380
|
+
let o = e.closest(Se);
|
|
381
381
|
if (o !== null && !n.has(o)) continue;
|
|
382
382
|
let s = o, c = r.get(a);
|
|
383
383
|
c || r.set(a, c = /* @__PURE__ */ new Set()), c.add(s);
|
|
@@ -390,27 +390,27 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
390
390
|
r && [...r.values()].some((e) => e > 1) && t.duplicated.add(e);
|
|
391
391
|
}
|
|
392
392
|
return t;
|
|
393
|
-
},
|
|
394
|
-
if (t.hasAttribute("data-flemo-morph-camera") && (e.camera = !0), !
|
|
395
|
-
let n =
|
|
393
|
+
}, De = (e, t) => {
|
|
394
|
+
if (t.hasAttribute("data-flemo-morph-camera") && (e.camera = !0), !we(t)) return;
|
|
395
|
+
let n = B(t);
|
|
396
396
|
n !== null && e.flew.add(n);
|
|
397
|
-
},
|
|
398
|
-
for (let r of Array.from(t.addedNodes)) if (r instanceof Element) for (let t of
|
|
399
|
-
for (let r of Array.from(t.removedNodes)) if (r instanceof Element) for (let t of
|
|
397
|
+
}, Oe = (e, t, n) => {
|
|
398
|
+
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));
|
|
399
|
+
for (let r of Array.from(t.removedNodes)) if (r instanceof Element) for (let t of ke(r)) {
|
|
400
400
|
let r = e.ghostBornAt.get(t);
|
|
401
401
|
if (r === void 0) continue;
|
|
402
402
|
e.ghostBornAt.delete(t);
|
|
403
403
|
let i = n - r;
|
|
404
404
|
(e.shortestGhostLifeMs === null || i < e.shortestGhostLifeMs) && (e.shortestGhostLifeMs = i);
|
|
405
405
|
}
|
|
406
|
-
},
|
|
406
|
+
}, ke = (e) => [...e.hasAttribute("data-flemo-morph-ghost") ? [e] : [], ...Array.from(e.querySelectorAll(b(m)))], Ae = (e) => {
|
|
407
407
|
let t = e.shortestGhostLifeMs;
|
|
408
408
|
return t === null || t >= 34 ? [] : [{
|
|
409
409
|
kind: "ghost-cut",
|
|
410
|
-
atMs:
|
|
411
|
-
detail: `a morph ghost was removed ${
|
|
410
|
+
atMs: Ce(t),
|
|
411
|
+
detail: `a morph ghost was removed ${Ce(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`
|
|
412
412
|
}];
|
|
413
|
-
},
|
|
413
|
+
}, je = (e, t) => {
|
|
414
414
|
let n = [...e.pairable].sort(), r = [...e.flew].sort(), i = new Set(r), a = t ? {
|
|
415
415
|
strandedRoles: 0,
|
|
416
416
|
strandedStandIns: 0,
|
|
@@ -418,11 +418,11 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
418
418
|
layerResidue: 0,
|
|
419
419
|
leaked: 0
|
|
420
420
|
} : {
|
|
421
|
-
strandedRoles: document.querySelectorAll(
|
|
421
|
+
strandedRoles: document.querySelectorAll(xe).length,
|
|
422
422
|
strandedStandIns: document.querySelectorAll(b(p)).length,
|
|
423
423
|
strandedGhosts: document.querySelectorAll(b(m)).length,
|
|
424
424
|
layerResidue: Array.from(document.querySelectorAll(b(f))).reduce((e, t) => e + t.childElementCount, 0),
|
|
425
|
-
leaked: Math.max(0,
|
|
425
|
+
leaked: Math.max(0, Te() - e.sheetRulesAtStart)
|
|
426
426
|
};
|
|
427
427
|
return {
|
|
428
428
|
registered: e.registered,
|
|
@@ -438,21 +438,19 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
438
438
|
layerResidue: a.layerResidue,
|
|
439
439
|
duplicatedKeys: [...e.duplicated].sort()
|
|
440
440
|
};
|
|
441
|
-
},
|
|
442
|
-
key:
|
|
443
|
-
storage: "session",
|
|
444
|
-
kind: "opt-in-diagnostic",
|
|
445
|
-
values: "\"on\" / \"off\"",
|
|
446
|
-
fallback: "off",
|
|
447
|
-
effect: "arms this flight recorder in the playground (?devtools=on)"
|
|
448
|
-
}, {
|
|
449
|
-
key: Ne,
|
|
441
|
+
}, Me = "flemo:devtools-panel-height", Ne = [{
|
|
442
|
+
key: Me,
|
|
450
443
|
storage: "session",
|
|
451
444
|
kind: "production-state",
|
|
452
445
|
values: "a pixel height",
|
|
453
446
|
fallback: "(the panel's default height)",
|
|
454
447
|
effect: "the drawer height this panel was last dragged to"
|
|
455
|
-
}],
|
|
448
|
+
}], V = [
|
|
449
|
+
{
|
|
450
|
+
key: "flemo:devtools",
|
|
451
|
+
storage: "session",
|
|
452
|
+
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)"
|
|
453
|
+
},
|
|
456
454
|
{
|
|
457
455
|
key: "flemo:sixty",
|
|
458
456
|
storage: "session",
|
|
@@ -573,53 +571,53 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
573
571
|
storage: "session",
|
|
574
572
|
retiredWith: "the Low Power Mode release-latency probe (2026-08-22)"
|
|
575
573
|
}
|
|
576
|
-
],
|
|
574
|
+
], Pe = "(retired — the library no longer reads this)", Fe = (e) => {
|
|
577
575
|
try {
|
|
578
576
|
let t = e === "session" ? sessionStorage : localStorage;
|
|
579
577
|
return t.length, t;
|
|
580
578
|
} catch {
|
|
581
579
|
return null;
|
|
582
580
|
}
|
|
583
|
-
},
|
|
581
|
+
}, Ie = (e, t) => {
|
|
584
582
|
try {
|
|
585
583
|
return e ? e.getItem(t) : null;
|
|
586
584
|
} catch {
|
|
587
585
|
return null;
|
|
588
586
|
}
|
|
589
|
-
},
|
|
590
|
-
let e = {}, t =
|
|
591
|
-
for (let r of
|
|
592
|
-
let i =
|
|
587
|
+
}, Le = new Set(Ne.map((e) => e.key)), Re = new Set(V.map((e) => e.key)), ze = () => {
|
|
588
|
+
let e = {}, t = Fe("session"), n = Fe("local");
|
|
589
|
+
for (let r of Ne) {
|
|
590
|
+
let i = Ie(r.storage === "session" ? t : n, r.key);
|
|
593
591
|
i !== null && (e[r.key] = i);
|
|
594
592
|
}
|
|
595
|
-
for (let r of
|
|
596
|
-
let t =
|
|
597
|
-
t !== null && (e[`${r.key} (${a}) ${
|
|
593
|
+
for (let r of V) for (let [i, a] of [[t, "sessionStorage"], [n, "localStorage"]]) {
|
|
594
|
+
let t = Ie(i, r.key);
|
|
595
|
+
t !== null && (e[`${r.key} (${a}) ${Pe}`] = t);
|
|
598
596
|
}
|
|
599
597
|
for (let [r, i] of [[t, "sessionStorage"], [n, "localStorage"]]) if (r) try {
|
|
600
598
|
for (let t = 0; t < r.length; t += 1) {
|
|
601
599
|
let n = r.key(t);
|
|
602
|
-
!n || !n.startsWith("flemo:") ||
|
|
600
|
+
!n || !n.startsWith("flemo:") || Le.has(n) || Re.has(n) || (e[`${n} (${i}, unknown key)`] = r.getItem(n) ?? "");
|
|
603
601
|
}
|
|
604
602
|
} catch {}
|
|
605
603
|
return e;
|
|
606
|
-
},
|
|
604
|
+
}, Be = (e) => {
|
|
607
605
|
let t = [];
|
|
608
606
|
for (let [n, r] of Object.entries(e)) if (n.includes("(retired — the library no longer reads this)")) {
|
|
609
|
-
let e = n.slice(0, n.indexOf(" (")), i =
|
|
607
|
+
let e = n.slice(0, n.indexOf(" (")), i = V.find((t) => t.key === e);
|
|
610
608
|
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.`);
|
|
611
609
|
continue;
|
|
612
610
|
}
|
|
613
611
|
return t;
|
|
614
|
-
},
|
|
612
|
+
}, H = "flemo:devtools-trace", Ve = () => {
|
|
615
613
|
try {
|
|
616
614
|
let e = sessionStorage;
|
|
617
615
|
return e.length, e;
|
|
618
616
|
} catch {
|
|
619
617
|
return null;
|
|
620
618
|
}
|
|
621
|
-
},
|
|
622
|
-
let n =
|
|
619
|
+
}, He = (e, t) => {
|
|
620
|
+
let n = Ve();
|
|
623
621
|
if (!n) return;
|
|
624
622
|
let r = e.slice(-10);
|
|
625
623
|
for (; r.length > 0;) {
|
|
@@ -630,23 +628,23 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
630
628
|
});
|
|
631
629
|
if (e.length <= 64e3) {
|
|
632
630
|
try {
|
|
633
|
-
n.setItem(
|
|
631
|
+
n.setItem(H, e);
|
|
634
632
|
} catch {}
|
|
635
633
|
return;
|
|
636
634
|
}
|
|
637
635
|
r = r.slice(1);
|
|
638
636
|
}
|
|
639
|
-
|
|
640
|
-
},
|
|
637
|
+
Ue();
|
|
638
|
+
}, Ue = () => {
|
|
641
639
|
try {
|
|
642
|
-
|
|
640
|
+
Ve()?.removeItem(H);
|
|
643
641
|
} catch {}
|
|
644
|
-
},
|
|
645
|
-
let t =
|
|
642
|
+
}, We = (e) => {
|
|
643
|
+
let t = Ve();
|
|
646
644
|
if (!t) return null;
|
|
647
645
|
let n = null;
|
|
648
646
|
try {
|
|
649
|
-
n = t.getItem(
|
|
647
|
+
n = t.getItem(H);
|
|
650
648
|
} catch {
|
|
651
649
|
return null;
|
|
652
650
|
}
|
|
@@ -655,14 +653,14 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
655
653
|
try {
|
|
656
654
|
r = JSON.parse(n);
|
|
657
655
|
} catch {
|
|
658
|
-
return
|
|
656
|
+
return Ue(), null;
|
|
659
657
|
}
|
|
660
|
-
return !r || r.version !== e || !Array.isArray(r.flights) ? (
|
|
658
|
+
return !r || r.version !== e || !Array.isArray(r.flights) ? (Ue(), null) : {
|
|
661
659
|
savedAt: typeof r.savedAt == "string" ? r.savedAt : "",
|
|
662
660
|
flights: r.flights,
|
|
663
661
|
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."
|
|
664
662
|
};
|
|
665
|
-
},
|
|
663
|
+
}, Ge = 12, Ke = 20, qe = 40, Je = 500, Ye = 200, Xe = (e) => {
|
|
666
664
|
let t = e.rafCadence.medianGapMs;
|
|
667
665
|
if (t === null) return {
|
|
668
666
|
id: "display-cadence",
|
|
@@ -670,17 +668,17 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
670
668
|
detail: "the idle frame cadence could not be sampled, so the display's rate is unknown"
|
|
671
669
|
};
|
|
672
670
|
let n = { medianIdleFrameMs: t };
|
|
673
|
-
return t <
|
|
671
|
+
return t < Ge ? {
|
|
674
672
|
id: "display-cadence",
|
|
675
673
|
status: "ok",
|
|
676
674
|
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)`,
|
|
677
675
|
metrics: n
|
|
678
|
-
} : t <=
|
|
676
|
+
} : t <= Ke ? {
|
|
679
677
|
id: "display-cadence",
|
|
680
678
|
status: "ok",
|
|
681
679
|
detail: `idle frames arrive every ${t}ms — a 60Hz clock`,
|
|
682
680
|
metrics: n
|
|
683
|
-
} : t <=
|
|
681
|
+
} : t <= qe ? {
|
|
684
682
|
id: "display-cadence",
|
|
685
683
|
status: "violated",
|
|
686
684
|
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`,
|
|
@@ -691,7 +689,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
691
689
|
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`,
|
|
692
690
|
metrics: n
|
|
693
691
|
};
|
|
694
|
-
},
|
|
692
|
+
}, Ze = (e) => {
|
|
695
693
|
if (!e.environment.observation.longTasks) return {
|
|
696
694
|
id: "machine-idle",
|
|
697
695
|
status: "unknown",
|
|
@@ -702,7 +700,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
702
700
|
idleLongTaskMs: n,
|
|
703
701
|
worstIdleTaskMs: r
|
|
704
702
|
};
|
|
705
|
-
return n >=
|
|
703
|
+
return n >= Je || r >= Ye ? {
|
|
706
704
|
id: "machine-idle",
|
|
707
705
|
status: "violated",
|
|
708
706
|
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`,
|
|
@@ -713,7 +711,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
713
711
|
detail: `${t} idle long task(s), ${n}ms total — the page was quiet between navigations`,
|
|
714
712
|
metrics: i
|
|
715
713
|
};
|
|
716
|
-
},
|
|
714
|
+
}, Qe = (e) => {
|
|
717
715
|
let { trusted: t, synthetic: n, pointerTypes: r } = e.input;
|
|
718
716
|
return n > 0 ? {
|
|
719
717
|
id: "real-input",
|
|
@@ -740,7 +738,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
740
738
|
synthetic: n
|
|
741
739
|
}
|
|
742
740
|
};
|
|
743
|
-
},
|
|
741
|
+
}, $e = (e) => e.input.pointerTypes.includes("touch") ? {
|
|
744
742
|
id: "touch-path",
|
|
745
743
|
status: "ok",
|
|
746
744
|
detail: "at least one navigation was driven by touch"
|
|
@@ -752,7 +750,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
752
750
|
id: "touch-path",
|
|
753
751
|
status: "unknown",
|
|
754
752
|
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"
|
|
755
|
-
},
|
|
753
|
+
}, et = [
|
|
756
754
|
{
|
|
757
755
|
id: "devtools-closed",
|
|
758
756
|
status: "unknown",
|
|
@@ -768,7 +766,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
768
766
|
status: "unknown",
|
|
769
767
|
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"
|
|
770
768
|
}
|
|
771
|
-
],
|
|
769
|
+
], tt = (e) => {
|
|
772
770
|
let { environment: t } = e, n = [];
|
|
773
771
|
return n.push(t.emulationSuspected ? {
|
|
774
772
|
id: "device-emulation",
|
|
@@ -778,7 +776,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
778
776
|
id: "device-emulation",
|
|
779
777
|
status: "ok",
|
|
780
778
|
detail: "no device-emulation signature on this session"
|
|
781
|
-
}), n.push(
|
|
779
|
+
}), n.push(Xe(t)), n.push(e.documentHidden || e.wentHidden ? {
|
|
782
780
|
id: "page-foreground",
|
|
783
781
|
status: "violated",
|
|
784
782
|
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"
|
|
@@ -786,7 +784,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
786
784
|
id: "page-foreground",
|
|
787
785
|
status: "ok",
|
|
788
786
|
detail: "the document stayed visible throughout"
|
|
789
|
-
}), n.push(
|
|
787
|
+
}), n.push(Ze(e)), n.push(t.developmentHints.length > 0 ? {
|
|
790
788
|
id: "build-mode",
|
|
791
789
|
status: "violated",
|
|
792
790
|
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`
|
|
@@ -794,7 +792,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
794
792
|
id: "build-mode",
|
|
795
793
|
status: "unknown",
|
|
796
794
|
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"
|
|
797
|
-
}), n.push(
|
|
795
|
+
}), n.push(Qe(e)), n.push($e(e)), n.push(t.reducedMotion ? {
|
|
798
796
|
id: "reduced-motion",
|
|
799
797
|
status: "violated",
|
|
800
798
|
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"
|
|
@@ -802,8 +800,8 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
802
800
|
id: "reduced-motion",
|
|
803
801
|
status: "ok",
|
|
804
802
|
detail: "reduced motion is not requested"
|
|
805
|
-
}), [...n, ...
|
|
806
|
-
},
|
|
803
|
+
}), [...n, ...et];
|
|
804
|
+
}, nt = 2e3, rt = 40, it = (e) => Math.round(e * 10) / 10, at = (e) => typeof e.animationName == "string" && e.animationName.startsWith("flemo-"), ot = (e) => e instanceof Element ? `<${e.tagName.toLowerCase()}>${e.getAttribute("data-flemo-screen") === null ? "" : " (screen)"}` : "an unidentified node", st = (e) => {
|
|
807
805
|
if (typeof document > "u") return {
|
|
808
806
|
detach: () => {},
|
|
809
807
|
sawAnimationEvent: () => !1,
|
|
@@ -814,18 +812,18 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
814
812
|
})
|
|
815
813
|
};
|
|
816
814
|
let t = [], n = !1, r = (t) => {
|
|
817
|
-
|
|
815
|
+
at(t) && (n = !0, e.onAnimationStart(performance.now()));
|
|
818
816
|
}, i = (t) => {
|
|
819
|
-
|
|
817
|
+
at(t) && (n = !0, e.onHit({
|
|
820
818
|
kind: "animation-cancel",
|
|
821
819
|
atMs: performance.now(),
|
|
822
|
-
detail: `${t.animationName} was CANCELLED on ${
|
|
820
|
+
detail: `${t.animationName} was CANCELLED on ${ot(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`
|
|
823
821
|
}));
|
|
824
822
|
}, a = (t) => {
|
|
825
|
-
|
|
823
|
+
at(t) && (n = !0, t.elapsedTime === 0 && e.onHit({
|
|
826
824
|
kind: "zero-length-animation-end",
|
|
827
825
|
atMs: performance.now(),
|
|
828
|
-
detail: `${t.animationName} reported animationend with elapsedTime 0 on ${
|
|
826
|
+
detail: `${t.animationName} reported animationend with elapsedTime 0 on ${ot(t.target)} — the animation ended without ever running. Anything landing on this event lands before the motion it was waiting for`
|
|
829
827
|
}));
|
|
830
828
|
}, o = (e) => {
|
|
831
829
|
let n = e.pointerType ?? "";
|
|
@@ -833,7 +831,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
833
831
|
atMs: performance.now(),
|
|
834
832
|
trusted: e.isTrusted === !0,
|
|
835
833
|
pointerType: n === "" ? e.type : n
|
|
836
|
-
}), t.length >
|
|
834
|
+
}), t.length > rt && t.splice(0, t.length - rt);
|
|
837
835
|
}, s = {
|
|
838
836
|
capture: !0,
|
|
839
837
|
passive: !0
|
|
@@ -844,7 +842,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
844
842
|
},
|
|
845
843
|
sawAnimationEvent: () => n,
|
|
846
844
|
inputBetween: (e, n) => {
|
|
847
|
-
let r = e -
|
|
845
|
+
let r = e - nt, 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));
|
|
848
846
|
return {
|
|
849
847
|
trusted: a,
|
|
850
848
|
synthetic: i.length - a,
|
|
@@ -852,22 +850,22 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
852
850
|
};
|
|
853
851
|
}
|
|
854
852
|
};
|
|
855
|
-
},
|
|
853
|
+
}, ct = (e, t) => ({
|
|
856
854
|
kind: e.kind,
|
|
857
|
-
atMs:
|
|
855
|
+
atMs: it(e.atMs - t),
|
|
858
856
|
detail: e.detail
|
|
859
|
-
}),
|
|
857
|
+
}), lt = (e) => {
|
|
860
858
|
/* v8 ignore next -- unreachable: deriveVerdict returns before this on an
|
|
861
859
|
empty flight list, so nothing ever asks for the median of nothing. */
|
|
862
860
|
if (e.length === 0) return 0;
|
|
863
861
|
let t = [...e].sort((e, t) => e - t);
|
|
864
862
|
return t[Math.floor(t.length / 2)];
|
|
865
|
-
},
|
|
863
|
+
}, ut = (e) => {
|
|
866
864
|
let t = [], n = e.preconditions.filter((e) => e.status === "violated");
|
|
867
865
|
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;
|
|
868
866
|
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.");
|
|
869
867
|
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;
|
|
870
|
-
t.push(`${r.length} flight(s) recorded. Median duration ${
|
|
868
|
+
t.push(`${r.length} flight(s) recorded. Median duration ${lt(r.map((e) => e.durationMs))}ms, worst frame gap during visible motion ${i}ms, ${a} flight(s) carrying at least one anomaly.`);
|
|
871
869
|
let o = r.filter((e) => e.motion.longestStallMs >= 48);
|
|
872
870
|
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.`);
|
|
873
871
|
let s = r.filter((e) => e.morphs.skipped.length > 0);
|
|
@@ -883,7 +881,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
883
881
|
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.`);
|
|
884
882
|
}
|
|
885
883
|
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;
|
|
886
|
-
},
|
|
884
|
+
}, U = new Set(v), dt = new Set(y), ft = b(t), pt = 2e3, mt = 1e3, ht = 4e3, W = (e) => Math.round(e * 10) / 10, gt = null, _t = () => ({
|
|
887
885
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
888
886
|
version: "3",
|
|
889
887
|
verdict: ["No DOM was available, so nothing could be observed. The recorder ran inert."],
|
|
@@ -900,30 +898,30 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
900
898
|
comparison: [],
|
|
901
899
|
previousSession: null,
|
|
902
900
|
anomalies: [],
|
|
903
|
-
blindSpots: [...
|
|
904
|
-
judgingProtocol: [...
|
|
905
|
-
}),
|
|
906
|
-
if (
|
|
901
|
+
blindSpots: [...T],
|
|
902
|
+
judgingProtocol: [...pe]
|
|
903
|
+
}), vt = (e = {}) => {
|
|
904
|
+
if (gt) return gt;
|
|
907
905
|
if (typeof window > "u" || typeof document > "u") return {
|
|
908
906
|
detach: () => {},
|
|
909
|
-
report:
|
|
907
|
+
report: _t,
|
|
910
908
|
mark: () => null
|
|
911
909
|
};
|
|
912
|
-
let t = e.maxFlights ?? 50, a = e.log ?? !1, o = e.installGlobal ?? !0, d = e.persist ?? !0, f =
|
|
910
|
+
let t = e.maxFlights ?? 50, a = e.log ?? !1, o = e.installGlobal ?? !0, d = e.persist ?? !0, f = ze(), p = performance.now(), m = d ? We("3") : null, g = {
|
|
913
911
|
medianGapMs: null,
|
|
914
912
|
sampleCount: 0
|
|
915
913
|
};
|
|
916
|
-
|
|
914
|
+
A().then((e) => {
|
|
917
915
|
g = e;
|
|
918
916
|
});
|
|
919
917
|
let _ = [], v = null;
|
|
920
918
|
try {
|
|
921
919
|
typeof PerformanceObserver < "u" && PerformanceObserver.supportedEntryTypes?.includes("longtask") && (v = new PerformanceObserver((e) => {
|
|
922
920
|
for (let t of e.getEntries()) _.push({
|
|
923
|
-
startMs:
|
|
924
|
-
durationMs:
|
|
921
|
+
startMs: W(t.startTime),
|
|
922
|
+
durationMs: W(t.duration)
|
|
925
923
|
});
|
|
926
|
-
_.length >
|
|
924
|
+
_.length > mt && _.splice(0, _.length - mt);
|
|
927
925
|
}), v.observe({
|
|
928
926
|
type: "longtask",
|
|
929
927
|
buffered: !0
|
|
@@ -931,59 +929,59 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
931
929
|
} catch {
|
|
932
930
|
v = null;
|
|
933
931
|
}
|
|
934
|
-
let y = [], x = 0,
|
|
935
|
-
let t = Array.from(document.querySelectorAll(b(l))).filter((e) =>
|
|
932
|
+
let y = [], x = 0, E = null, D = null, O = [], k = !1, j = !1, te = document.visibilityState === "hidden", M = 0, re = () => Array.from(document.querySelectorAll(ft)).filter((e) => U.has(e.getAttribute("data-flemo-status") ?? "")), N = () => E !== null || re().length > 0, ie = (e) => {
|
|
933
|
+
let t = Array.from(document.querySelectorAll(b(l))).filter((e) => U.has(e.getAttribute("data-flemo-bar-status") ?? "") || e.getAttribute("data-flemo-bar-riding") === "true").length, n = Array.from(document.querySelectorAll(b(c))).filter((e) => U.has(e.getAttribute("data-flemo-status") ?? "")).length, r = Array.from(document.querySelectorAll(b(s))).filter((e) => U.has(e.getAttribute("data-flemo-status") ?? "")).length;
|
|
936
934
|
return {
|
|
937
935
|
screens: e.length,
|
|
938
936
|
bars: t,
|
|
939
937
|
decorators: n,
|
|
940
938
|
parts: r
|
|
941
939
|
};
|
|
942
|
-
}, P =
|
|
940
|
+
}, P = st({
|
|
943
941
|
onHit: (e) => {
|
|
944
|
-
let t =
|
|
945
|
-
t && t.tripwires.push(
|
|
942
|
+
let t = E;
|
|
943
|
+
t && t.tripwires.push(ct(e, t.t0Ms));
|
|
946
944
|
},
|
|
947
945
|
onAnimationStart: (e) => {
|
|
948
|
-
let t =
|
|
949
|
-
!t || t.firstAnimationAtMs !== null || (t.firstAnimationAtMs =
|
|
946
|
+
let t = E;
|
|
947
|
+
!t || t.firstAnimationAtMs !== null || (t.firstAnimationAtMs = W(e - t.t0Ms));
|
|
950
948
|
}
|
|
951
949
|
}), F = (e) => {
|
|
952
950
|
let t = /* @__PURE__ */ new Set();
|
|
953
951
|
for (let n of e.elements) {
|
|
954
952
|
let e = n.getAttribute("data-flemo-status") ?? "";
|
|
955
|
-
|
|
953
|
+
U.has(e) && t.add(e);
|
|
956
954
|
}
|
|
957
955
|
return [...t];
|
|
958
956
|
}, I = () => {
|
|
959
|
-
let e =
|
|
960
|
-
if (!e ||
|
|
957
|
+
let e = E;
|
|
958
|
+
if (!e || k) return;
|
|
961
959
|
let t = performance.now(), n = e.frames;
|
|
962
|
-
if (n.lastFrameAt !== null && n.heldGaps.length + n.releasedGaps.length <
|
|
960
|
+
if (n.lastFrameAt !== null && n.heldGaps.length + n.releasedGaps.length < pt) {
|
|
963
961
|
let r = t - n.lastFrameAt, i = oe(e.elements);
|
|
964
|
-
(i ? n.heldGaps : n.releasedGaps).push(r), i || (se(n, e.elements, r), n.releasedFrames === 1 &&
|
|
962
|
+
(i ? n.heldGaps : n.releasedGaps).push(r), i || (se(n, e.elements, r), n.releasedFrames === 1 && R(e.images, e.elements));
|
|
965
963
|
}
|
|
966
964
|
if (n.lastFrameAt = t, ce(n, e.elements), t - e.t0Ms > 1e4) {
|
|
967
|
-
|
|
965
|
+
O = [...e.elements], ye(t, F(e));
|
|
968
966
|
return;
|
|
969
967
|
}
|
|
970
968
|
e.rafId = requestAnimationFrame(I);
|
|
971
969
|
}, ue = (e) => {
|
|
972
970
|
let t = performance.now();
|
|
973
971
|
x += 1;
|
|
974
|
-
let n = e.find((e) => e.getAttribute("data-flemo-active") === "true") ?? e[0], r =
|
|
972
|
+
let n = e.find((e) => e.getAttribute("data-flemo-active") === "true") ?? e[0], r = _e(n.getAttribute("data-flemo-status") ?? "") ?? "PUSH", a = null;
|
|
975
973
|
for (let t of e) {
|
|
976
974
|
let e = t.getAttribute(i);
|
|
977
|
-
if (e !== null &&
|
|
975
|
+
if (e !== null && dt.has(e)) {
|
|
978
976
|
a = e;
|
|
979
977
|
break;
|
|
980
978
|
}
|
|
981
979
|
}
|
|
982
|
-
|
|
980
|
+
E = {
|
|
983
981
|
id: `flight-${x}`,
|
|
984
982
|
kind: r,
|
|
985
983
|
routerId: n.getAttribute("data-flemo-router") ?? void 0,
|
|
986
|
-
bucket:
|
|
984
|
+
bucket: D,
|
|
987
985
|
t0Ms: t,
|
|
988
986
|
t0Iso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
989
987
|
elements: [...e],
|
|
@@ -993,60 +991,60 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
993
991
|
firstAnimationAtMs: null,
|
|
994
992
|
frames: ae(),
|
|
995
993
|
images: de(e),
|
|
996
|
-
morphs:
|
|
994
|
+
morphs: Ee(e),
|
|
997
995
|
tripwires: [],
|
|
998
996
|
rafId: null
|
|
999
|
-
}, ce(
|
|
1000
|
-
},
|
|
997
|
+
}, ce(E.frames, E.elements), E.rafId = requestAnimationFrame(I);
|
|
998
|
+
}, z = (e, t) => {
|
|
1001
999
|
let n = 2, r = () => {
|
|
1002
|
-
if (
|
|
1000
|
+
if (k) return;
|
|
1003
1001
|
if (--n, n > 0) {
|
|
1004
1002
|
requestAnimationFrame(r);
|
|
1005
1003
|
return;
|
|
1006
1004
|
}
|
|
1007
|
-
let i =
|
|
1005
|
+
let i = be(t, N());
|
|
1008
1006
|
e.landing.residualInlineTransforms = i.residualInlineTransforms, e.landing.offViewportAtRest = i.offViewportAtRest, e.landing.orphanedHolds = i.orphanedHolds;
|
|
1009
1007
|
};
|
|
1010
1008
|
requestAnimationFrame(r);
|
|
1011
|
-
},
|
|
1009
|
+
}, me = (e, t) => {
|
|
1012
1010
|
let n = 2, r = () => {
|
|
1013
|
-
if (!
|
|
1011
|
+
if (!k) {
|
|
1014
1012
|
if (--n, n > 0) {
|
|
1015
1013
|
requestAnimationFrame(r);
|
|
1016
1014
|
return;
|
|
1017
1015
|
}
|
|
1018
|
-
e.morphs =
|
|
1016
|
+
e.morphs = je(t.morphs, N());
|
|
1019
1017
|
}
|
|
1020
1018
|
};
|
|
1021
1019
|
requestAnimationFrame(r);
|
|
1022
|
-
},
|
|
1020
|
+
}, ve = (e, t, n, r) => ({
|
|
1023
1021
|
id: r ? `${e.id} (in flight)` : e.id,
|
|
1024
1022
|
...e.routerId === void 0 ? {} : { routerId: e.routerId },
|
|
1025
1023
|
...e.bucket === null ? {} : { bucket: e.bucket },
|
|
1026
1024
|
kind: e.kind,
|
|
1027
1025
|
t0: {
|
|
1028
|
-
ms:
|
|
1026
|
+
ms: W(e.t0Ms),
|
|
1029
1027
|
iso: e.t0Iso
|
|
1030
1028
|
},
|
|
1031
1029
|
t1: {
|
|
1032
|
-
ms:
|
|
1030
|
+
ms: W(t),
|
|
1033
1031
|
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
1034
1032
|
},
|
|
1035
|
-
durationMs:
|
|
1036
|
-
driver:
|
|
1033
|
+
durationMs: W(t - e.t0Ms),
|
|
1034
|
+
driver: ge(e.frames.evidence),
|
|
1037
1035
|
participants: e.participants,
|
|
1038
1036
|
holds: {
|
|
1039
1037
|
kind: e.holdKind,
|
|
1040
1038
|
releasedAtMs: e.holdReleasedAtMs
|
|
1041
1039
|
},
|
|
1042
|
-
frameSamples:
|
|
1040
|
+
frameSamples: he(e.frames.heldGaps, e.frames.releasedGaps),
|
|
1043
1041
|
motion: {
|
|
1044
1042
|
...le(e.frames),
|
|
1045
1043
|
firstAnimationAtMs: e.firstAnimationAtMs
|
|
1046
1044
|
},
|
|
1047
|
-
images:
|
|
1048
|
-
morphs:
|
|
1049
|
-
tripwires: [...e.tripwires, ...
|
|
1045
|
+
images: fe(e.images),
|
|
1046
|
+
morphs: je(e.morphs, !0),
|
|
1047
|
+
tripwires: [...e.tripwires, ...Ae(e.morphs)],
|
|
1050
1048
|
input: P.inputBetween(e.t0Ms, t),
|
|
1051
1049
|
longTasks: [],
|
|
1052
1050
|
holdLongTasks: [],
|
|
@@ -1057,51 +1055,51 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1057
1055
|
orphanedHolds: []
|
|
1058
1056
|
},
|
|
1059
1057
|
anomalies: []
|
|
1060
|
-
}),
|
|
1061
|
-
let r =
|
|
1058
|
+
}), ye = (e, n) => {
|
|
1059
|
+
let r = E;
|
|
1062
1060
|
/* v8 ignore next -- unreachable: both callers hold a flight. sampleFrame
|
|
1063
1061
|
returns at its own top when `current` is null, and evaluate only calls
|
|
1064
1062
|
this inside `if (current && ...)`. The narrowing stays for the type. */
|
|
1065
1063
|
if (!r) return;
|
|
1066
|
-
|
|
1067
|
-
let i =
|
|
1068
|
-
y.push(i), y.length > t && y.splice(0, y.length - t), n.length === 0 && (
|
|
1069
|
-
},
|
|
1070
|
-
let t =
|
|
1064
|
+
R(r.images, r.elements), E = null, r.rafId !== null && cancelAnimationFrame(r.rafId);
|
|
1065
|
+
let i = ve(r, e, n, !1);
|
|
1066
|
+
y.push(i), y.length > t && y.splice(0, y.length - t), n.length === 0 && (z(i, r.elements), me(i, r)), a && console.info(`[flemo devtools] ${i.id} ${i.kind} driver=${i.driver} ${i.durationMs}ms screens=${i.participants.screens}`);
|
|
1067
|
+
}, xe = (e) => {
|
|
1068
|
+
let t = E;
|
|
1071
1069
|
if (!t || !(e.target instanceof Element)) return;
|
|
1072
1070
|
let n = e.target.getAttribute(i);
|
|
1073
|
-
if (n !== null &&
|
|
1074
|
-
let e =
|
|
1071
|
+
if (n !== null && dt.has(n) && t.holdKind === null && (t.holdKind = n), n !== null && dt.has(n) && t.holdReleasedAtMs !== null && t.frames.holdReassertedAtMs === null) {
|
|
1072
|
+
let e = W(performance.now() - t.t0Ms);
|
|
1075
1073
|
t.frames.holdReassertedAtMs = e, t.tripwires.push({
|
|
1076
1074
|
kind: "hold-reassert",
|
|
1077
1075
|
atMs: e,
|
|
1078
1076
|
detail: "an animation hold was re-asserted after this flight had already released it — the motion pauses here while every timing metric stays clean"
|
|
1079
1077
|
});
|
|
1080
1078
|
}
|
|
1081
|
-
(n === "false" || n === null) && e.oldValue !== null &&
|
|
1082
|
-
},
|
|
1079
|
+
(n === "false" || n === null) && e.oldValue !== null && dt.has(e.oldValue) && t.holdReleasedAtMs === null && !oe(t.elements) && (t.holdReleasedAtMs = W(performance.now() - t.t0Ms));
|
|
1080
|
+
}, Se = () => {
|
|
1083
1081
|
let e = re();
|
|
1084
|
-
if (
|
|
1085
|
-
if (e.some((e) =>
|
|
1086
|
-
|
|
1082
|
+
if (O.length > 0) {
|
|
1083
|
+
if (e.some((e) => O.includes(e))) return;
|
|
1084
|
+
O = [];
|
|
1087
1085
|
}
|
|
1088
|
-
if (!
|
|
1086
|
+
if (!E && e.length > 0) {
|
|
1089
1087
|
ue(e);
|
|
1090
1088
|
return;
|
|
1091
1089
|
}
|
|
1092
|
-
if (
|
|
1093
|
-
|
|
1090
|
+
if (E && e.length === 0) {
|
|
1091
|
+
ye(performance.now(), []);
|
|
1094
1092
|
return;
|
|
1095
1093
|
}
|
|
1096
|
-
if (
|
|
1097
|
-
},
|
|
1094
|
+
if (E) for (let t of e) E.elements.includes(t) || (E.elements.push(t), L(E.images, E.elements, t.querySelectorAll("img")), E.participants = ie(E.elements));
|
|
1095
|
+
}, Ce = null, B = null, we = () => {
|
|
1098
1096
|
let e = document.documentElement;
|
|
1099
1097
|
if (!e) return !1;
|
|
1100
1098
|
let t = new MutationObserver((e) => {
|
|
1101
|
-
if (
|
|
1099
|
+
if (k) return;
|
|
1102
1100
|
let t = performance.now();
|
|
1103
|
-
for (let n of e) n.type === "attributes" ? n.attributeName === "data-flemo-anim-hold" ?
|
|
1104
|
-
|
|
1101
|
+
for (let n of e) n.type === "attributes" ? n.attributeName === "data-flemo-anim-hold" ? xe(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 && L(E.images, E.elements, n.addedNodes));
|
|
1102
|
+
Se();
|
|
1105
1103
|
});
|
|
1106
1104
|
try {
|
|
1107
1105
|
t.observe(e, {
|
|
@@ -1120,30 +1118,30 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1120
1118
|
} catch {
|
|
1121
1119
|
return !1;
|
|
1122
1120
|
}
|
|
1123
|
-
return
|
|
1121
|
+
return Ce = t, Se(), !0;
|
|
1124
1122
|
};
|
|
1125
|
-
if (!
|
|
1123
|
+
if (!we()) {
|
|
1126
1124
|
let e = () => {
|
|
1127
|
-
|
|
1125
|
+
B = null, k || we();
|
|
1128
1126
|
};
|
|
1129
|
-
|
|
1127
|
+
B = e, document.addEventListener("DOMContentLoaded", e, { once: !0 });
|
|
1130
1128
|
}
|
|
1131
|
-
let
|
|
1132
|
-
document.visibilityState === "hidden" && (
|
|
1129
|
+
let Te = () => {
|
|
1130
|
+
document.visibilityState === "hidden" && (te = !0, d && E === null && He(y, "3"));
|
|
1133
1131
|
};
|
|
1134
|
-
document.addEventListener("visibilitychange",
|
|
1135
|
-
let
|
|
1136
|
-
M = 0, !
|
|
1132
|
+
document.addEventListener("visibilitychange", Te);
|
|
1133
|
+
let ke = () => {
|
|
1134
|
+
M = 0, !k && (E === null && He(y, "3"), M = window.setTimeout(ke, ht));
|
|
1137
1135
|
};
|
|
1138
|
-
d && (M = window.setTimeout(
|
|
1139
|
-
let
|
|
1136
|
+
d && (M = window.setTimeout(ke, ht));
|
|
1137
|
+
let Me = (e) => {
|
|
1140
1138
|
let t = _.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;
|
|
1141
1139
|
return {
|
|
1142
1140
|
released: t.filter((e) => e.startMs + e.durationMs > n),
|
|
1143
1141
|
held: t.filter((e) => e.startMs + e.durationMs <= n)
|
|
1144
1142
|
};
|
|
1145
|
-
},
|
|
1146
|
-
let t =
|
|
1143
|
+
}, Ne = (e) => _.filter((t) => t.startMs >= p && !e.some((e) => t.startMs + t.durationMs >= e.t0.ms && t.startMs <= e.t1.ms)), V = (e) => {
|
|
1144
|
+
let t = Me(e), n = {
|
|
1147
1145
|
...e,
|
|
1148
1146
|
longTasks: t.released,
|
|
1149
1147
|
holdLongTasks: t.held,
|
|
@@ -1156,7 +1154,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1156
1154
|
morphs: { ...e.morphs },
|
|
1157
1155
|
tripwires: [...e.tripwires]
|
|
1158
1156
|
};
|
|
1159
|
-
return n.anomalies =
|
|
1157
|
+
return n.anomalies = C({
|
|
1160
1158
|
t0Ms: n.t0.ms,
|
|
1161
1159
|
t1Ms: n.t1.ms,
|
|
1162
1160
|
driver: n.driver,
|
|
@@ -1170,12 +1168,12 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1170
1168
|
morphs: n.morphs,
|
|
1171
1169
|
tripwires: n.tripwires
|
|
1172
1170
|
}), n;
|
|
1173
|
-
},
|
|
1174
|
-
let e = y.map(
|
|
1171
|
+
}, Pe = () => {
|
|
1172
|
+
let e = y.map(V), t = E;
|
|
1175
1173
|
if (!t) return e;
|
|
1176
|
-
let n = performance.now(), r = n - t.t0Ms >
|
|
1177
|
-
return [...e,
|
|
1178
|
-
},
|
|
1174
|
+
let n = performance.now(), r = n - t.t0Ms > S;
|
|
1175
|
+
return [...e, V(ve(t, n, r ? F(t) : [], !0))];
|
|
1176
|
+
}, Fe = (e) => {
|
|
1179
1177
|
let t = /* @__PURE__ */ new Set(), n = 0, r = 0;
|
|
1180
1178
|
for (let i of e) {
|
|
1181
1179
|
n += i.input.trusted, r += i.input.synthetic;
|
|
@@ -1186,21 +1184,21 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1186
1184
|
synthetic: r,
|
|
1187
1185
|
pointerTypes: [...t].sort()
|
|
1188
1186
|
};
|
|
1189
|
-
},
|
|
1190
|
-
let e =
|
|
1187
|
+
}, Ie = () => {
|
|
1188
|
+
let e = ze(), t = { ...e };
|
|
1191
1189
|
for (let [n, r] of Object.entries(f)) n in e || (t[`${n} (at attach, since cleared)`] = r);
|
|
1192
|
-
let n =
|
|
1190
|
+
let n = Be(t), r = ne(g, P.sawAnimationEvent()), i = Pe(), a = E, o = tt({
|
|
1193
1191
|
environment: r,
|
|
1194
|
-
idleLongTasks:
|
|
1192
|
+
idleLongTasks: Ne(i),
|
|
1195
1193
|
observedMs: performance.now() - p,
|
|
1196
|
-
wentHidden:
|
|
1194
|
+
wentHidden: te,
|
|
1197
1195
|
documentHidden: document.visibilityState === "hidden",
|
|
1198
|
-
input:
|
|
1196
|
+
input: Fe(i)
|
|
1199
1197
|
});
|
|
1200
1198
|
return {
|
|
1201
1199
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1202
1200
|
version: "3",
|
|
1203
|
-
verdict:
|
|
1201
|
+
verdict: ut({
|
|
1204
1202
|
preconditions: o,
|
|
1205
1203
|
flights: i,
|
|
1206
1204
|
observation: r.observation
|
|
@@ -1212,46 +1210,46 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1212
1210
|
warnings: n
|
|
1213
1211
|
},
|
|
1214
1212
|
flights: i,
|
|
1215
|
-
comparison:
|
|
1213
|
+
comparison: ee(i),
|
|
1216
1214
|
previousSession: m,
|
|
1217
|
-
anomalies:
|
|
1215
|
+
anomalies: w({
|
|
1218
1216
|
emulationSuspected: r.emulationSuspected,
|
|
1219
1217
|
platform: r.platform,
|
|
1220
1218
|
stuckFlightOpen: a !== null && performance.now() - a.t0Ms > 1e4,
|
|
1221
1219
|
flightAnomalies: i.map((e) => e.anomalies)
|
|
1222
1220
|
}),
|
|
1223
|
-
blindSpots: [...
|
|
1224
|
-
judgingProtocol: [...
|
|
1221
|
+
blindSpots: [...T],
|
|
1222
|
+
judgingProtocol: [...pe]
|
|
1225
1223
|
};
|
|
1226
|
-
},
|
|
1227
|
-
if (!
|
|
1228
|
-
if (
|
|
1224
|
+
}, Le = (e) => (D = e === null || e === "" ? null : e, D), Re = () => {
|
|
1225
|
+
if (!k) {
|
|
1226
|
+
if (k = !0, Ce?.disconnect(), B !== null && (document.removeEventListener("DOMContentLoaded", B), B = null), document.removeEventListener("visibilitychange", Te), P.detach(), v?.disconnect(), window.clearTimeout(M), M = 0, E?.rafId != null && cancelAnimationFrame(E.rafId), E = null, j) {
|
|
1229
1227
|
let e = window;
|
|
1230
1228
|
e.flemo?.__flemoDevtools === !0 && delete e.flemo;
|
|
1231
1229
|
}
|
|
1232
|
-
|
|
1230
|
+
gt = null;
|
|
1233
1231
|
}
|
|
1234
|
-
},
|
|
1235
|
-
detach:
|
|
1236
|
-
report:
|
|
1237
|
-
mark:
|
|
1232
|
+
}, H = {
|
|
1233
|
+
detach: Re,
|
|
1234
|
+
report: Ie,
|
|
1235
|
+
mark: Le
|
|
1238
1236
|
};
|
|
1239
1237
|
if (o) {
|
|
1240
1238
|
let e = window, t = e.flemo;
|
|
1241
1239
|
(t === void 0 || t?.__flemoDevtools === !0) && (e.flemo = {
|
|
1242
1240
|
__flemoDevtools: !0,
|
|
1243
|
-
report:
|
|
1244
|
-
flights:
|
|
1245
|
-
mark:
|
|
1246
|
-
detach:
|
|
1247
|
-
},
|
|
1241
|
+
report: Ie,
|
|
1242
|
+
flights: Pe,
|
|
1243
|
+
mark: Le,
|
|
1244
|
+
detach: Re
|
|
1245
|
+
}, j = !0);
|
|
1248
1246
|
}
|
|
1249
|
-
return
|
|
1250
|
-
},
|
|
1247
|
+
return gt = H, H;
|
|
1248
|
+
}, yt = v.map((e) => b(t) + x(n, e)).join(","), G = () => document.querySelector(yt) !== null, bt = "\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", xt = (e) => {
|
|
1251
1249
|
let t = document.createElement("div");
|
|
1252
1250
|
t.setAttribute(_, ""), t.style.position = "fixed", t.style.top = "0", t.style.left = "0", t.style.width = "0", t.style.height = "0", t.style.zIndex = "2147483000";
|
|
1253
1251
|
let n = t.attachShadow({ mode: "open" }), r = document.createElement("style");
|
|
1254
|
-
r.textContent = e, n.appendChild(r);
|
|
1252
|
+
r.textContent = bt + e, n.appendChild(r);
|
|
1255
1253
|
let i = document.createElement("div");
|
|
1256
1254
|
return i.className = "root", n.appendChild(i), {
|
|
1257
1255
|
host: t,
|
|
@@ -1271,71 +1269,95 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1271
1269
|
},
|
|
1272
1270
|
ownsRecorder: !1
|
|
1273
1271
|
} : {
|
|
1274
|
-
recorder:
|
|
1272
|
+
recorder: vt(),
|
|
1275
1273
|
ownsRecorder: !0
|
|
1276
1274
|
};
|
|
1277
|
-
}, wt = 500, Tt = 450, Et = "\n
|
|
1275
|
+
}, wt = 500, Tt = 450, Et = "flemo:devtools-hud-hidden", Dt = "\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", K = (e) => Math.round(e * 10) / 10, Ot = (e) => {
|
|
1278
1276
|
if (!e) return "flemo no flight yet";
|
|
1279
1277
|
let t = e.frameSamples?.released, n = e.anomalies?.length ?? 0;
|
|
1280
|
-
return `${e.kind} ${Math.round(e.durationMs)}ms gap ${
|
|
1281
|
-
},
|
|
1278
|
+
return `${e.kind} ${Math.round(e.durationMs)}ms gap ${K(t?.maxGapMs ?? 0)} drop ${t?.over30Count ?? 0}` + (n > 0 ? ` !${n}` : " ok") + (e.bucket ? ` [${e.bucket}]` : "");
|
|
1279
|
+
}, kt = (e, t) => {
|
|
1282
1280
|
let n = [], r = (e?.preconditions ?? []).filter((e) => e.status === "violated");
|
|
1283
|
-
if (r.length > 0 && n.push(`BLOCKED ${r.map((e) => e.id).join(" ")}`), !t) return n.push(`rAF ${
|
|
1281
|
+
if (r.length > 0 && n.push(`BLOCKED ${r.map((e) => e.id).join(" ")}`), !t) return n.push(`rAF ${K(e?.environment?.rafCadence?.medianGapMs ?? 0)}ms`), n;
|
|
1284
1282
|
let i = t.frameSamples;
|
|
1285
|
-
n.push(`frames n${i?.released?.count ?? 0} med ${
|
|
1283
|
+
n.push(`frames n${i?.released?.count ?? 0} med ${K(i?.released?.medianGapMs ?? 0)} max ${K(i?.released?.maxGapMs ?? 0)}`), n.push(`motion stall ${K(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}`);
|
|
1286
1284
|
let a = t.morphs;
|
|
1287
1285
|
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(",")})` : ""));
|
|
1288
1286
|
let o = t.input;
|
|
1289
1287
|
o && n.push(`input ${o.pointerTypes.join("/") || "none"}` + (o.synthetic > 0 ? ` SYNTHETIC ${o.synthetic}` : ""));
|
|
1290
1288
|
for (let e of t.anomalies ?? []) n.push(`! ${e.slice(0, 120)}`);
|
|
1291
1289
|
return n;
|
|
1292
|
-
},
|
|
1293
|
-
|
|
1290
|
+
}, At = () => {
|
|
1291
|
+
try {
|
|
1292
|
+
return sessionStorage.getItem(Et) === "1";
|
|
1293
|
+
} catch {
|
|
1294
|
+
return !1;
|
|
1295
|
+
}
|
|
1296
|
+
}, jt = (e) => {
|
|
1297
|
+
try {
|
|
1298
|
+
sessionStorage.setItem(Et, e ? "1" : "0");
|
|
1299
|
+
} catch {}
|
|
1300
|
+
}, Mt = null, Nt = (e = {}) => {
|
|
1301
|
+
if (Mt) return Mt;
|
|
1294
1302
|
if (typeof document > "u") return { detach: () => {} };
|
|
1295
|
-
let { recorder: t, ownsRecorder: n } = Ct(e.recorder), r = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], { host: i, root: a } = xt(
|
|
1296
|
-
|
|
1297
|
-
let
|
|
1303
|
+
let { recorder: t, ownsRecorder: n } = Ct(e.recorder), r = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], { host: i, root: a } = xt(Dt);
|
|
1304
|
+
i.style.zIndex = "2147482998";
|
|
1305
|
+
let o = document.createElement("div");
|
|
1306
|
+
o.className = "dock", o.setAttribute("data-edge", e.position ?? "bottom-right");
|
|
1307
|
+
let s = document.createElement("div");
|
|
1308
|
+
s.className = "hud", s.setAttribute("role", "status"), s.textContent = "flemo attaching";
|
|
1309
|
+
let c = document.createElement("button");
|
|
1310
|
+
c.className = "eye", c.type = "button";
|
|
1311
|
+
let l = document.createElement("span");
|
|
1312
|
+
l.className = "mark", l.textContent = "hud";
|
|
1313
|
+
let u = document.createElement("span");
|
|
1314
|
+
u.className = "state", c.appendChild(l), c.appendChild(u), o.appendChild(s), o.appendChild(c), a.appendChild(o);
|
|
1315
|
+
let d = !1, f = e.initialExpanded === !0, p = e.initialHidden ?? At(), m = -1, h = 0, g = 0, _ = !1, v = "", y = () => {
|
|
1298
1316
|
try {
|
|
1299
1317
|
return t.report();
|
|
1300
1318
|
} catch {
|
|
1301
1319
|
return null;
|
|
1302
1320
|
}
|
|
1303
|
-
},
|
|
1304
|
-
if (
|
|
1305
|
-
let e =
|
|
1306
|
-
|
|
1307
|
-
let i = r.join("\n"), a = (e?.preconditions ?? []).some((e) => e.status === "violated"),
|
|
1308
|
-
i !==
|
|
1309
|
-
},
|
|
1310
|
-
|
|
1311
|
-
},
|
|
1312
|
-
|
|
1321
|
+
}, b = () => {
|
|
1322
|
+
if (d || p || G()) return;
|
|
1323
|
+
let e = y(), t = e?.flights ?? [], n = t[t.length - 1], r = [Ot(n)];
|
|
1324
|
+
f && r.push(...kt(e, n));
|
|
1325
|
+
let i = r.join("\n"), a = (e?.preconditions ?? []).some((e) => e.status === "violated"), o = (n?.anomalies?.length ?? 0) > 0;
|
|
1326
|
+
i !== v && (v = i, s.textContent = i), s.setAttribute("data-alarm", o ? "true" : "false"), s.setAttribute("data-blocked", a ? "true" : "false");
|
|
1327
|
+
}, x = () => {
|
|
1328
|
+
h = 0, b(), h = window.setTimeout(x, wt);
|
|
1329
|
+
}, S = (e) => {
|
|
1330
|
+
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, wt));
|
|
1331
|
+
}, C = () => {
|
|
1332
|
+
m = m + 1 >= r.length ? -1 : m + 1, t.mark(m === -1 ? null : r[m]), v = "", b();
|
|
1313
1333
|
};
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1334
|
+
s.addEventListener("pointerdown", () => {
|
|
1335
|
+
_ = !1, window.clearTimeout(g), g = window.setTimeout(() => {
|
|
1336
|
+
_ = !0, C();
|
|
1317
1337
|
}, Tt);
|
|
1318
|
-
}),
|
|
1319
|
-
window.clearTimeout(
|
|
1320
|
-
}),
|
|
1321
|
-
|
|
1322
|
-
|
|
1338
|
+
}), s.addEventListener("pointerup", () => {
|
|
1339
|
+
window.clearTimeout(g), g = 0, !_ && (f = !f, v = "", b());
|
|
1340
|
+
}), s.addEventListener("pointercancel", () => window.clearTimeout(g)), c.addEventListener("click", () => {
|
|
1341
|
+
S(!p), jt(p);
|
|
1342
|
+
});
|
|
1343
|
+
let w = () => {
|
|
1344
|
+
d || (d = !0, window.clearTimeout(h), h = 0, window.clearTimeout(g), g = 0, i.remove(), n && t.detach(), Mt = null);
|
|
1323
1345
|
};
|
|
1324
|
-
document.body.appendChild(i),
|
|
1325
|
-
let
|
|
1326
|
-
return
|
|
1327
|
-
},
|
|
1346
|
+
document.body.appendChild(i), S(p);
|
|
1347
|
+
let T = { detach: w };
|
|
1348
|
+
return Mt = T, T;
|
|
1349
|
+
}, Pt = "http://www.w3.org/2000/svg", q = (e, t, n) => {
|
|
1328
1350
|
let r = document.createElement(e);
|
|
1329
1351
|
return t !== void 0 && (r.className = t), n !== void 0 && (r.textContent = n), r;
|
|
1330
|
-
},
|
|
1331
|
-
let n = document.createElementNS(
|
|
1352
|
+
}, Ft = (e, t) => {
|
|
1353
|
+
let n = document.createElementNS(Pt, e);
|
|
1332
1354
|
for (let [e, r] of Object.entries(t)) n.setAttribute(e, r);
|
|
1333
1355
|
return n;
|
|
1334
|
-
},
|
|
1356
|
+
}, It = (e) => {
|
|
1335
1357
|
for (; e.firstChild !== null;) e.removeChild(e.firstChild);
|
|
1336
|
-
},
|
|
1358
|
+
}, Lt = (e, t) => {
|
|
1337
1359
|
e.textContent !== t && (e.textContent = t);
|
|
1338
|
-
}, J = (e) => e == null || e === "" ? "—" : String(e), Y = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e)}ms` : "—",
|
|
1360
|
+
}, J = (e) => e == null || e === "" ? "—" : String(e), Y = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e)}ms` : "—", Rt = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e * 10) / 10}ms` : "—", X = (e) => typeof e == "number" && Number.isFinite(e) ? String(e) : "—", zt = (e) => e === !0 ? "yes" : e === !1 ? "no" : "—", Bt = (e) => {
|
|
1339
1361
|
let t = e?.environment;
|
|
1340
1362
|
if (!t) return "—";
|
|
1341
1363
|
let n = t.viewport, r = n && typeof n.width == "number" && typeof n.height == "number" ? `${Math.round(n.width)}×${Math.round(n.height)}` : "—";
|
|
@@ -1343,65 +1365,65 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1343
1365
|
J(t.engine),
|
|
1344
1366
|
`dpr ${J(t.devicePixelRatio)}`,
|
|
1345
1367
|
r,
|
|
1346
|
-
`rAF ${
|
|
1368
|
+
`rAF ${Rt(t.rafCadence?.medianGapMs)}`
|
|
1347
1369
|
].join(" · ");
|
|
1348
|
-
},
|
|
1370
|
+
}, Vt = (e, t) => `${t ?? ""}#${e.map((e) => `${e?.id ?? ""}|${e?.kind ?? ""}|${e?.driver ?? ""}|${Math.round(e?.durationMs ?? 0)}|${e?.participants?.screens ?? 0}|${e?.anomalies?.length ?? 0}`).join(",")}`, Ht = (e) => {
|
|
1349
1371
|
let t = e?.released?.gaps;
|
|
1350
1372
|
if (!Array.isArray(t)) return null;
|
|
1351
1373
|
let n = t.filter((e) => typeof e == "number" && Number.isFinite(e));
|
|
1352
1374
|
return n.length >= 2 ? n : null;
|
|
1353
|
-
},
|
|
1354
|
-
let i =
|
|
1355
|
-
i.appendChild(
|
|
1375
|
+
}, Ut = "\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", Wt = 48, Z = (e, t, n, r) => {
|
|
1376
|
+
let i = q("div", "kv");
|
|
1377
|
+
i.appendChild(q("span", "k", t)), i.appendChild(q("span", r ? `v ${r}` : "v", n)), e.appendChild(i);
|
|
1356
1378
|
}, Q = (e, t) => {
|
|
1357
|
-
let n =
|
|
1358
|
-
return n.appendChild(
|
|
1379
|
+
let n = q("section", "section");
|
|
1380
|
+
return n.appendChild(q("h2", void 0, t)), e.appendChild(n), n;
|
|
1359
1381
|
}, $ = (e, t, n = "li") => {
|
|
1360
|
-
e.appendChild(
|
|
1361
|
-
},
|
|
1362
|
-
|
|
1363
|
-
for (let n of t?.verdict ?? []) e.appendChild(
|
|
1364
|
-
for (let n of t?.preconditions ?? []) n?.status === "violated" && e.appendChild(
|
|
1365
|
-
for (let n of t?.overrides?.warnings ?? []) e.appendChild(
|
|
1366
|
-
for (let n of t?.anomalies ?? []) e.appendChild(
|
|
1367
|
-
for (let [n, r] of Object.entries(t?.overrides?.active ?? {})) e.appendChild(
|
|
1368
|
-
},
|
|
1369
|
-
if (
|
|
1382
|
+
e.appendChild(q("div", n, t));
|
|
1383
|
+
}, Gt = (e, t) => {
|
|
1384
|
+
It(e);
|
|
1385
|
+
for (let n of t?.verdict ?? []) e.appendChild(q("span", "chip lead", J(n)));
|
|
1386
|
+
for (let n of t?.preconditions ?? []) n?.status === "violated" && e.appendChild(q("span", "chip bad", `${n.id}: ${J(n.detail)}`));
|
|
1387
|
+
for (let n of t?.overrides?.warnings ?? []) e.appendChild(q("span", "chip warn", J(n)));
|
|
1388
|
+
for (let n of t?.anomalies ?? []) e.appendChild(q("span", "chip bad", J(n)));
|
|
1389
|
+
for (let [n, r] of Object.entries(t?.overrides?.active ?? {})) e.appendChild(q("span", "chip", `${n}=${String(r)}`));
|
|
1390
|
+
}, Kt = (e, t, n, r) => {
|
|
1391
|
+
if (It(e), t.length === 0) {
|
|
1370
1392
|
$(e, "no flights recorded yet — navigate once", "li dim");
|
|
1371
1393
|
return;
|
|
1372
1394
|
}
|
|
1373
1395
|
for (let i = t.length - 1; i >= 0; --i) {
|
|
1374
|
-
let a = t[i], o = J(a?.id), s =
|
|
1375
|
-
s.type = "button", s.setAttribute("data-flight-id", o), s.setAttribute("aria-selected", String(o === n)), s.appendChild(
|
|
1396
|
+
let a = t[i], o = J(a?.id), s = q("button", "row");
|
|
1397
|
+
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`));
|
|
1376
1398
|
let c = a?.anomalies?.length ?? 0;
|
|
1377
|
-
s.appendChild(
|
|
1399
|
+
s.appendChild(q("span", c > 0 ? "n bad" : "n", String(c))), s.addEventListener("click", () => r(o)), e.appendChild(s);
|
|
1378
1400
|
}
|
|
1379
|
-
},
|
|
1401
|
+
}, qt = (e, t, n) => {
|
|
1380
1402
|
if (!n) {
|
|
1381
1403
|
Z(e, t, "—");
|
|
1382
1404
|
return;
|
|
1383
1405
|
}
|
|
1384
1406
|
let r = [
|
|
1385
1407
|
`${X(n.count)} frames`,
|
|
1386
|
-
`median ${
|
|
1387
|
-
`max ${
|
|
1408
|
+
`median ${Rt(n.medianGapMs)}`,
|
|
1409
|
+
`max ${Rt(n.maxGapMs)}`
|
|
1388
1410
|
];
|
|
1389
1411
|
typeof n.over30Count == "number" && r.push(`>30ms ×${n.over30Count}`), Z(e, t, r.join(" · "));
|
|
1390
|
-
},
|
|
1391
|
-
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 =
|
|
1412
|
+
}, Jt = (e) => {
|
|
1413
|
+
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 = Ft("svg", {
|
|
1392
1414
|
class: "spark",
|
|
1393
1415
|
viewBox: "0 0 100 28",
|
|
1394
1416
|
preserveAspectRatio: "none",
|
|
1395
1417
|
"aria-hidden": "true"
|
|
1396
1418
|
});
|
|
1397
|
-
return a.appendChild(
|
|
1419
|
+
return a.appendChild(Ft("polyline", {
|
|
1398
1420
|
points: i,
|
|
1399
1421
|
fill: "none",
|
|
1400
1422
|
stroke: "currentColor",
|
|
1401
1423
|
"stroke-width": "1",
|
|
1402
1424
|
"vector-effect": "non-scaling-stroke"
|
|
1403
1425
|
})), a;
|
|
1404
|
-
},
|
|
1426
|
+
}, Yt = (e, t) => {
|
|
1405
1427
|
let n = t.longTasks ?? [], r = t.holdLongTasks ?? [];
|
|
1406
1428
|
if (n.length === 0 && r.length === 0) {
|
|
1407
1429
|
$(e, "none", "li dim");
|
|
@@ -1410,19 +1432,19 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1410
1432
|
let i = (e) => `${Y(e?.startMs)} + ${Y(e?.durationMs)}`;
|
|
1411
1433
|
for (let t of n) $(e, i(t), "li bad");
|
|
1412
1434
|
for (let t of r) $(e, `${i(t)} (absorbed by hold)`, "li dim");
|
|
1413
|
-
},
|
|
1414
|
-
if (
|
|
1435
|
+
}, Xt = (e, t) => {
|
|
1436
|
+
if (It(e), !t) {
|
|
1415
1437
|
$(e, "select a flight", "li dim");
|
|
1416
1438
|
return;
|
|
1417
1439
|
}
|
|
1418
1440
|
let n = Q(e, "timing");
|
|
1419
1441
|
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)}`);
|
|
1420
1442
|
let r = Q(e, "frames");
|
|
1421
|
-
|
|
1422
|
-
let i =
|
|
1423
|
-
i && r.appendChild(
|
|
1443
|
+
qt(r, "held (absorbed)", t.frameSamples?.held), qt(r, "released (visible)", t.frameSamples?.released);
|
|
1444
|
+
let i = Ht(t.frameSamples);
|
|
1445
|
+
i && r.appendChild(Jt(i));
|
|
1424
1446
|
let a = Q(e, "motion (did it move)"), o = t.motion?.longestStallMs, s = t.motion?.holdReassertedAtMs;
|
|
1425
|
-
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) >=
|
|
1447
|
+
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) >= Wt ? "bad" : void 0), Z(a, "paused after release", zt(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`);
|
|
1426
1448
|
let c = t.morphs;
|
|
1427
1449
|
if (c) {
|
|
1428
1450
|
let t = Q(e, "shared elements");
|
|
@@ -1430,7 +1452,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1430
1452
|
let n = c.skipped ?? [];
|
|
1431
1453
|
Z(t, "did not fly", n.length === 0 ? "none" : n.join(", "), n.length > 0 ? "bad" : void 0);
|
|
1432
1454
|
let r = c.duplicatedKeys ?? [];
|
|
1433
|
-
r.length > 0 && Z(t, "duplicate keys in one screen", r.join(", "), "bad"), Z(t, "camera",
|
|
1455
|
+
r.length > 0 && Z(t, "duplicate keys in one screen", r.join(", "), "bad"), Z(t, "camera", zt(c.camera)), Z(t, "ghosts", X(c.ghosts));
|
|
1434
1456
|
let i = (c.strandedRoles ?? 0) + (c.strandedStandIns ?? 0) + (c.strandedGhosts ?? 0) + (c.layerResidue ?? 0) + (c.leakedSheetRules ?? 0);
|
|
1435
1457
|
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);
|
|
1436
1458
|
}
|
|
@@ -1445,11 +1467,11 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1445
1467
|
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");
|
|
1446
1468
|
}
|
|
1447
1469
|
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;
|
|
1448
|
-
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),
|
|
1470
|
+
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), Yt(Q(e, "long tasks"), t);
|
|
1449
1471
|
let g = Q(e, "landing"), _ = t.landing?.residualInlineTransforms ?? [];
|
|
1450
1472
|
if (_.length === 0) Z(g, "inline residue", "clean");
|
|
1451
1473
|
else for (let e of _) Z(g, "inline residue", J(e));
|
|
1452
|
-
Z(g, "off-viewport at rest",
|
|
1474
|
+
Z(g, "off-viewport at rest", zt(t.landing?.offViewportAtRest));
|
|
1453
1475
|
let v = t.landing?.stuckStatuses ?? [];
|
|
1454
1476
|
Z(g, "stuck statuses", v.length === 0 ? "none" : v.join(", "));
|
|
1455
1477
|
let y = t.landing?.orphanedHolds ?? [];
|
|
@@ -1461,39 +1483,39 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1461
1483
|
return;
|
|
1462
1484
|
}
|
|
1463
1485
|
for (let e of x) $(b, J(e), "li bad");
|
|
1464
|
-
},
|
|
1465
|
-
|
|
1486
|
+
}, Zt = (e, t) => {
|
|
1487
|
+
It(e);
|
|
1466
1488
|
for (let n of t ?? []) $(e, J(n));
|
|
1467
|
-
},
|
|
1468
|
-
if (
|
|
1469
|
-
if (typeof document > "u") return { detach:
|
|
1470
|
-
let { recorder: t, ownsRecorder: n } = Ct(e.recorder), { host: r, root: i } = xt(
|
|
1489
|
+
}, Qt = 320, $t = 2e3, en = 120, tn = "Copy report JSON", nn = () => {}, rn = null, an = (e = {}) => {
|
|
1490
|
+
if (rn) return rn;
|
|
1491
|
+
if (typeof document > "u") return { detach: nn };
|
|
1492
|
+
let { recorder: t, ownsRecorder: n } = Ct(e.recorder), { host: r, root: i } = xt(Ut), a = q("button", "toggle");
|
|
1471
1493
|
a.type = "button", a.setAttribute("data-corner", e.position ?? "bottom-right"), a.setAttribute("aria-label", "flemo devtools");
|
|
1472
|
-
let o =
|
|
1473
|
-
s.hidden = !0, a.appendChild(
|
|
1474
|
-
let c =
|
|
1494
|
+
let o = q("span", "count", "0"), s = q("span", "dot");
|
|
1495
|
+
s.hidden = !0, a.appendChild(q("span", "mark", "flemo")), a.appendChild(o), a.appendChild(s);
|
|
1496
|
+
let c = q("section", "panel");
|
|
1475
1497
|
c.hidden = !0;
|
|
1476
|
-
let l =
|
|
1498
|
+
let l = q("div", "grip");
|
|
1477
1499
|
l.setAttribute("role", "separator"), l.setAttribute("aria-label", "Resize flemo devtools panel");
|
|
1478
|
-
let u =
|
|
1500
|
+
let u = q("header", "head"), d = q("div", "env", "—"), f = q("button", "act", tn);
|
|
1479
1501
|
f.type = "button";
|
|
1480
|
-
let p =
|
|
1502
|
+
let p = q("button", "act", "Close");
|
|
1481
1503
|
p.type = "button";
|
|
1482
|
-
let m =
|
|
1504
|
+
let m = q("button", "act", "Detach");
|
|
1483
1505
|
m.type = "button";
|
|
1484
|
-
let h =
|
|
1506
|
+
let h = q("button", "act", "A/B: off");
|
|
1485
1507
|
h.type = "button";
|
|
1486
|
-
let g =
|
|
1487
|
-
u.appendChild(d), u.appendChild(
|
|
1488
|
-
let _ =
|
|
1508
|
+
let g = q("div", "chips");
|
|
1509
|
+
u.appendChild(d), u.appendChild(q("div", "spacer")), u.appendChild(h), u.appendChild(f), u.appendChild(p), u.appendChild(m), u.appendChild(g);
|
|
1510
|
+
let _ = q("div", "body"), v = q("div", "list"), y = q("div", "detail");
|
|
1489
1511
|
_.appendChild(v), _.appendChild(y);
|
|
1490
|
-
let b =
|
|
1491
|
-
x.appendChild(
|
|
1492
|
-
let
|
|
1493
|
-
x.appendChild(
|
|
1494
|
-
let
|
|
1512
|
+
let b = q("div", "foot"), x = q("details");
|
|
1513
|
+
x.appendChild(q("summary", void 0, "What this cannot see"));
|
|
1514
|
+
let S = q("div");
|
|
1515
|
+
x.appendChild(S), b.appendChild(x), c.appendChild(l), c.appendChild(u), c.appendChild(_), c.appendChild(b), i.appendChild(a), i.appendChild(c);
|
|
1516
|
+
let C = !1, w = e.initialOpen === !0, T = null, E = "", ee = "", D = "", O = !1, k = 0, A = 0, j = -1, te = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], M = (e) => Math.min(Math.max(e, en), Math.max(en, window.innerHeight * .9)), ne = () => {
|
|
1495
1517
|
try {
|
|
1496
|
-
let e = sessionStorage.getItem(
|
|
1518
|
+
let e = sessionStorage.getItem(Me);
|
|
1497
1519
|
if (e === null) return null;
|
|
1498
1520
|
let t = Number.parseFloat(e);
|
|
1499
1521
|
return Number.isFinite(t) ? t : null;
|
|
@@ -1502,7 +1524,7 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1502
1524
|
}
|
|
1503
1525
|
}, re = (e) => {
|
|
1504
1526
|
try {
|
|
1505
|
-
sessionStorage.setItem(
|
|
1527
|
+
sessionStorage.setItem(Me, String(Math.round(e)));
|
|
1506
1528
|
} catch {}
|
|
1507
1529
|
}, N = M(ne() ?? window.innerHeight * .4);
|
|
1508
1530
|
c.style.height = `${Math.round(N)}px`;
|
|
@@ -1513,66 +1535,66 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1513
1535
|
return null;
|
|
1514
1536
|
}
|
|
1515
1537
|
}, ae = (e) => {
|
|
1516
|
-
e !==
|
|
1538
|
+
e !== T && (T = e, P());
|
|
1517
1539
|
}, oe = () => {
|
|
1518
1540
|
let e = ie(), t = e?.flights ?? [];
|
|
1519
|
-
|
|
1541
|
+
Lt(o, String(t.length));
|
|
1520
1542
|
let n = t.some((e) => (e?.anomalies?.length ?? 0) > 0);
|
|
1521
|
-
if (s.hidden = !n, c.hidden = !
|
|
1522
|
-
|
|
1543
|
+
if (s.hidden = !n, c.hidden = !w, !w) return;
|
|
1544
|
+
Lt(d, Bt(e));
|
|
1523
1545
|
let r = JSON.stringify([
|
|
1524
1546
|
e?.overrides?.warnings ?? [],
|
|
1525
1547
|
e?.anomalies ?? [],
|
|
1526
1548
|
e?.overrides?.active ?? {}
|
|
1527
1549
|
]);
|
|
1528
|
-
r !==
|
|
1529
|
-
let i =
|
|
1530
|
-
i !==
|
|
1531
|
-
let a = t.find((e) => e?.id ===
|
|
1532
|
-
l !==
|
|
1550
|
+
r !== D && (D = r, Gt(g, e)), T === null && t.length > 0 && (T = t[t.length - 1]?.id ?? null);
|
|
1551
|
+
let i = Vt(t, T);
|
|
1552
|
+
i !== E && (E = i, Kt(v, t, T, ae));
|
|
1553
|
+
let a = t.find((e) => e?.id === T) ?? null, l = JSON.stringify(a);
|
|
1554
|
+
l !== ee && (ee = l, Xt(y, a)), O || (O = !0, Zt(S, e?.blindSpots));
|
|
1533
1555
|
};
|
|
1534
1556
|
function P() {
|
|
1535
|
-
|
|
1557
|
+
C || G() || oe();
|
|
1536
1558
|
}
|
|
1537
1559
|
function se() {
|
|
1538
|
-
|
|
1560
|
+
k = 0, P(), F();
|
|
1539
1561
|
}
|
|
1540
1562
|
function F() {
|
|
1541
|
-
|
|
1563
|
+
k = window.setTimeout(se, w ? Qt : $t);
|
|
1542
1564
|
}
|
|
1543
1565
|
let ce = () => {
|
|
1544
|
-
window.clearTimeout(
|
|
1566
|
+
window.clearTimeout(k), F();
|
|
1545
1567
|
}, le = (e) => {
|
|
1546
|
-
|
|
1568
|
+
w = e, ce(), P();
|
|
1547
1569
|
};
|
|
1548
|
-
a.addEventListener("click", () => le(!
|
|
1549
|
-
|
|
1550
|
-
let e =
|
|
1551
|
-
t.mark(e),
|
|
1570
|
+
a.addEventListener("click", () => le(!w)), p.addEventListener("click", () => le(!1)), m.addEventListener("click", () => fe()), h.addEventListener("click", () => {
|
|
1571
|
+
j = j + 1 >= te.length ? -1 : j + 1;
|
|
1572
|
+
let e = j === -1 ? null : te[j];
|
|
1573
|
+
t.mark(e), Lt(h, `A/B: ${e ?? "off"}`), D = "", P();
|
|
1552
1574
|
});
|
|
1553
1575
|
let I = () => {
|
|
1554
|
-
if (!
|
|
1555
|
-
if (
|
|
1556
|
-
window.clearTimeout(
|
|
1576
|
+
if (!C) {
|
|
1577
|
+
if (G()) {
|
|
1578
|
+
window.clearTimeout(A), A = window.setTimeout(I, Qt);
|
|
1557
1579
|
return;
|
|
1558
1580
|
}
|
|
1559
|
-
|
|
1581
|
+
Lt(f, "Copied ✓"), window.clearTimeout(A), A = window.setTimeout(ue, 1200);
|
|
1560
1582
|
}
|
|
1561
1583
|
};
|
|
1562
1584
|
function ue() {
|
|
1563
|
-
if (
|
|
1564
|
-
|
|
1585
|
+
if (G()) {
|
|
1586
|
+
A = window.setTimeout(ue, Qt);
|
|
1565
1587
|
return;
|
|
1566
1588
|
}
|
|
1567
|
-
|
|
1589
|
+
A = 0, Lt(f, tn);
|
|
1568
1590
|
}
|
|
1569
1591
|
let de = (e) => {
|
|
1570
|
-
if (
|
|
1571
|
-
if (
|
|
1572
|
-
window.clearTimeout(
|
|
1592
|
+
if (C) return;
|
|
1593
|
+
if (G()) {
|
|
1594
|
+
window.clearTimeout(A), A = window.setTimeout(() => de(e), Qt);
|
|
1573
1595
|
return;
|
|
1574
1596
|
}
|
|
1575
|
-
let t =
|
|
1597
|
+
let t = q("textarea");
|
|
1576
1598
|
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();
|
|
1577
1599
|
let n = document;
|
|
1578
1600
|
try {
|
|
@@ -1590,31 +1612,31 @@ var t = "data-flemo-screen", n = "data-flemo-status", r = "data-flemo-active", i
|
|
|
1590
1612
|
});
|
|
1591
1613
|
let L = (e) => {
|
|
1592
1614
|
N = M(window.innerHeight - e.clientY), c.style.height = `${Math.round(N)}px`;
|
|
1593
|
-
},
|
|
1594
|
-
window.removeEventListener("pointermove", L), window.removeEventListener("pointerup",
|
|
1615
|
+
}, R = () => {
|
|
1616
|
+
window.removeEventListener("pointermove", L), window.removeEventListener("pointerup", R), re(N);
|
|
1595
1617
|
};
|
|
1596
1618
|
l.addEventListener("pointerdown", (e) => {
|
|
1597
|
-
e.preventDefault(), window.addEventListener("pointermove", L), window.addEventListener("pointerup",
|
|
1619
|
+
e.preventDefault(), window.addEventListener("pointermove", L), window.addEventListener("pointerup", R);
|
|
1598
1620
|
});
|
|
1599
|
-
function
|
|
1600
|
-
|
|
1621
|
+
function fe() {
|
|
1622
|
+
C || (C = !0, window.clearTimeout(k), k = 0, window.clearTimeout(A), A = 0, window.removeEventListener("pointermove", L), window.removeEventListener("pointerup", R), r.remove(), n && t.detach(), rn = null);
|
|
1601
1623
|
}
|
|
1602
1624
|
document.body.appendChild(r), P(), F();
|
|
1603
|
-
let
|
|
1604
|
-
return
|
|
1625
|
+
let pe = { detach: fe };
|
|
1626
|
+
return rn = pe, pe;
|
|
1605
1627
|
};
|
|
1606
1628
|
//#endregion
|
|
1607
1629
|
//#region src/react.ts
|
|
1608
|
-
function
|
|
1630
|
+
function on({ recorder: t, hud: n = !0, panel: r = !0, hudPosition: i = "bottom-right", panelPosition: a = "bottom-left", initialOpen: o = !1, buckets: s } = {}) {
|
|
1609
1631
|
let c = s?.join("\0");
|
|
1610
1632
|
return e(() => {
|
|
1611
1633
|
let e = [];
|
|
1612
|
-
return r && e.push(
|
|
1634
|
+
return r && e.push(an({
|
|
1613
1635
|
recorder: t,
|
|
1614
1636
|
position: a,
|
|
1615
1637
|
initialOpen: o,
|
|
1616
1638
|
buckets: s
|
|
1617
|
-
}).detach), n && e.push(
|
|
1639
|
+
}).detach), n && e.push(Nt({
|
|
1618
1640
|
recorder: t,
|
|
1619
1641
|
position: i,
|
|
1620
1642
|
buckets: s
|
|
@@ -1632,4 +1654,4 @@ function tn({ recorder: t, hud: n = !0, panel: r = !0, hudPosition: i = "top", p
|
|
|
1632
1654
|
]), null;
|
|
1633
1655
|
}
|
|
1634
1656
|
//#endregion
|
|
1635
|
-
export {
|
|
1657
|
+
export { on as FlemoDevtools, on as default };
|