@flemo/devtools 0.4.0 → 0.6.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 +67 -15
- package/dist/__tests__/buckets.test.d.ts +1 -0
- package/dist/__tests__/hud.test.d.ts +1 -0
- package/dist/__tests__/imageProbe.test.d.ts +1 -0
- package/dist/__tests__/morphProbe.test.d.ts +1 -0
- package/dist/__tests__/persistence.test.d.ts +1 -0
- package/dist/__tests__/preconditions.test.d.ts +1 -0
- package/dist/__tests__/recorder.session.test.d.ts +1 -0
- package/dist/__tests__/tripwires.test.d.ts +1 -0
- package/dist/__tests__/verdict.test.d.ts +1 -0
- package/dist/anomalies.d.ts +3 -2
- package/dist/buckets.d.ts +2 -0
- package/dist/domProtocol.d.ts +22 -0
- package/dist/environment.d.ts +4 -1
- package/dist/flight.d.ts +40 -0
- package/dist/frameProbe.d.ts +53 -0
- package/dist/hud.d.ts +18 -0
- package/dist/imageProbe.d.ts +23 -0
- package/dist/index.d.ts +14 -5
- package/dist/index.mjs +1156 -613
- package/dist/landingProbe.d.ts +17 -0
- package/dist/morphProbe.d.ts +57 -0
- package/dist/noop.d.ts +11 -2
- package/dist/noop.mjs +346 -73
- package/dist/panel/index.d.ts +2 -0
- package/dist/panel/styles.d.ts +1 -1
- package/dist/persistence.d.ts +20 -0
- package/dist/preconditions.d.ts +14 -0
- package/dist/react.d.ts +31 -0
- package/dist/react.mjs +1635 -0
- package/dist/reactNoop.d.ts +4 -0
- package/dist/reactNoop.mjs +6 -0
- package/dist/recorder.d.ts +4 -1
- package/dist/sampling.d.ts +9 -11
- package/dist/surface.d.ts +30 -0
- package/dist/tripwires.d.ts +37 -0
- package/dist/types.d.ts +213 -16
- package/dist/verdict.d.ts +7 -0
- package/package.json +24 -6
package/dist/index.mjs
CHANGED
|
@@ -1,53 +1,80 @@
|
|
|
1
1
|
//#region src/anomalies.ts
|
|
2
|
-
var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = (e) => {
|
|
3
|
-
let n = [], { t0Ms: r, driver: i, frameSamples: a,
|
|
4
|
-
if (
|
|
2
|
+
var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = 48, o = (e) => {
|
|
3
|
+
let n = [], { t0Ms: r, driver: i, frameSamples: a, longTasks: o, holdLongTasks: s, landing: c } = e, l = r + (e.releasedAtMs ?? 0);
|
|
4
|
+
if (a.released.over30Count > 0) {
|
|
5
5
|
let e = i === "compiled" ? " (compiled/compositor flights can still present cleanly through main-thread gaps)" : "";
|
|
6
6
|
n.push(`main-thread rAF gap up to ${a.released.maxGapMs}ms ×${a.released.over30Count} during visible motion${e}`);
|
|
7
7
|
}
|
|
8
|
-
for (let e of
|
|
9
|
-
for (let e of
|
|
10
|
-
let { motion:
|
|
11
|
-
|
|
12
|
-
|
|
8
|
+
for (let e of o) e.startMs <= l + 120 && e.startMs + e.durationMs >= l - 50 ? n.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 && n.push(`long task ${Math.round(e.durationMs)}ms mid-flight`);
|
|
9
|
+
for (let e of s) e.durationMs >= 100 && n.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)`);
|
|
10
|
+
let { motion: u, images: d } = e;
|
|
11
|
+
u.holdReassertedAtMs !== null && n.push(`hold re-asserted ${u.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)`), u.pausedAfterRelease && n.push("compiled animation reported playState=paused after its release (the flight was posed and then stopped mid-motion, not merely starved of frames)"), u.longestStallMs >= 48 && n.push(`motion stalled ${u.longestStallMs}ms mid-flight (${u.stalledFrames}/${u.sampledFrames} released frames advanced neither the animation clock nor the pose — freeze, or freeze-then-leap if the flight still landed on time)`), u.sampledFrames === 0 && e.releasedAtMs !== null && n.push("no released frames were sampled (the flight ended at or before its own hold release — the visible motion, if any, was never observed)"), d.completedUnheld > 0 && n.push(`${d.completedUnheld} image(s) finished loading mid-flight without a hold (${d.completedDuringFlight} completed, ${d.heldDuringFlight} held; ${d.loadingAtStart} were loading at t0, ${d.addedDuringFlight} arrived mid-flight) — each decode rasters on the moving layer and costs a present; this is the warm-side image-hold regression`), c.orphanedHolds.length > 0 && n.push(`hold markers left on the page at rest: ${c.orphanedHolds.join("; ")} (whatever they hide has no owner left to reveal it — the permanently-blank-avatar class)`), c.residualInlineTransforms.length > 0 && n.push(`residual inline style after COMPLETED: ${c.residualInlineTransforms.join("; ")} (landing cleanup failure — the landed scope belongs to the compiled rest rules)`), c.offViewportAtRest && n.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)"), c.stuckStatuses.length > 0 && n.push(`transitional status stuck >${t / 1e3}s: ${c.stuckStatuses.join(", ")} (navigation queue lock or missed animationend — later navigations will be swallowed)`);
|
|
12
|
+
let { morphs: f, tripwires: p } = e;
|
|
13
|
+
for (let e of p) n.push(`tripwire ${e.kind} at +${e.atMs}ms: ${e.detail}`);
|
|
14
|
+
return f.skipped.length > 0 && n.push(`shared element(s) did not fly: ${f.skipped.join(", ")} (${f.pairable.length} pairable key(s), ${f.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`), f.duplicatedKeys.length > 0 && n.push(`pairing key(s) used twice inside one screen: ${f.duplicatedKeys.join(", ")} (two ends under one screen are not a pair, so one of them can never fly — this is in the consuming app)`), f.strandedRoles > 0 && n.push(`${f.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)`), (f.strandedStandIns > 0 || f.strandedGhosts > 0 || f.layerResidue > 0) && n.push(`morph residue at rest: ${f.strandedStandIns} stand-in(s), ${f.strandedGhosts} ghost(s), ${f.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)`), f.leakedSheetRules > 0 && n.push(`${f.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)`), i === "unknown" && n.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)"), n;
|
|
15
|
+
}, s = (e) => {
|
|
13
16
|
let n = [];
|
|
14
17
|
if (e.emulationSuspected) {
|
|
15
18
|
let t = /Win/i.test(e.platform) ? " (Windows touch hardware makes this signal ambiguous — confirm the DevTools device toolbar state)" : "";
|
|
16
19
|
n.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" + t);
|
|
17
20
|
}
|
|
18
21
|
return e.stuckFlightOpen && n.push(`a flight is still transitional after ${t / 1e3}s — the navigation queue is likely locked; subsequent navigations will be ignored`), e.flightAnomalies.some((e) => e.some((e) => e.includes("blank-viewport"))) && n.push("at least one flight landed with the blank-viewport signature (see that flight's anomalies)"), n;
|
|
19
|
-
},
|
|
22
|
+
}, c = [
|
|
20
23
|
"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.",
|
|
21
24
|
"Display-hardware effects: local dimming, backlight modulation, and panel overdrive alter perceived motion and are invisible to every web API.",
|
|
22
25
|
"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.",
|
|
23
26
|
"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."
|
|
24
|
-
],
|
|
27
|
+
], l = (e) => {
|
|
28
|
+
/* v8 ignore next -- unreachable: a group exists only because a flight was
|
|
29
|
+
put in it, so nothing ever asks for the median of nothing. */
|
|
30
|
+
if (e.length === 0) return 0;
|
|
31
|
+
let t = [...e].sort((e, t) => e - t);
|
|
32
|
+
return Math.round(t[Math.floor(t.length / 2)] * 10) / 10;
|
|
33
|
+
}, u = (e) => {
|
|
34
|
+
let t = e.filter((e) => typeof e.bucket == "string");
|
|
35
|
+
if (t.length === 0) return [];
|
|
36
|
+
let n = /* @__PURE__ */ new Map();
|
|
37
|
+
for (let e of t) {
|
|
38
|
+
let t = e.bucket, r = n.get(t);
|
|
39
|
+
r ? r.push(e) : n.set(t, [e]);
|
|
40
|
+
}
|
|
41
|
+
return [...n.entries()].map(([e, t]) => ({
|
|
42
|
+
bucket: e,
|
|
43
|
+
flights: t.length,
|
|
44
|
+
medianDurationMs: l(t.map((e) => e.durationMs)),
|
|
45
|
+
medianReleasedGapMs: l(t.map((e) => e.frameSamples.released.medianGapMs)),
|
|
46
|
+
worstReleasedGapMs: t.reduce((e, t) => Math.max(e, t.frameSamples.released.maxGapMs), 0),
|
|
47
|
+
longGapCount: t.reduce((e, t) => e + t.frameSamples.released.over30Count, 0),
|
|
48
|
+
anomalyCount: t.reduce((e, t) => e + t.anomalies.length, 0),
|
|
49
|
+
stalledFlights: t.filter((e) => e.motion.stalledFrames > 0).length
|
|
50
|
+
})).sort((e, t) => e.bucket.localeCompare(t.bucket));
|
|
51
|
+
}, d = "data-flemo-screen", f = "data-flemo-status", p = "data-flemo-active", m = "data-flemo-anim-hold", h = "data-flemo-img-hold", g = "data-flemo-held-arrival", _ = "data-flemo-part-name", v = "data-flemo-decorator", y = "data-flemo-bar", b = "data-flemo-morph", x = "data-flemo-morph-id", S = "data-flemo-morph-layer", C = "data-flemo-morph-stand-in", w = "data-flemo-morph-ghost", T = "data-flemo-morph-camera", E = ["enter", "exit"], D = "data-flemo-devtools-panel", O = [
|
|
25
52
|
"PUSHING",
|
|
26
53
|
"POPPING",
|
|
27
54
|
"REPLACING"
|
|
28
|
-
],
|
|
55
|
+
], k = [
|
|
29
56
|
"true",
|
|
30
57
|
"park",
|
|
31
58
|
"park-under",
|
|
32
59
|
"park-over"
|
|
33
|
-
],
|
|
60
|
+
], A = (e) => `[${e}]`, j = (e, t) => `[${e}="${t}"]`, M = () => {
|
|
34
61
|
if (typeof navigator > "u") return null;
|
|
35
62
|
let e = navigator.userAgentData;
|
|
36
63
|
return !e || !Array.isArray(e.brands) ? null : e.brands.map((e) => ({
|
|
37
64
|
brand: String(e.brand ?? ""),
|
|
38
65
|
version: String(e.version ?? "")
|
|
39
66
|
}));
|
|
40
|
-
},
|
|
67
|
+
}, N = () => {
|
|
41
68
|
if (typeof navigator > "u") return "unknown";
|
|
42
|
-
let e =
|
|
69
|
+
let e = M();
|
|
43
70
|
if (e?.some((e) => /Chromium/i.test(e.brand))) return "blink";
|
|
44
71
|
let t = navigator.userAgent ?? "";
|
|
45
72
|
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";
|
|
46
|
-
},
|
|
47
|
-
if (typeof navigator > "u" ||
|
|
73
|
+
}, P = () => {
|
|
74
|
+
if (typeof navigator > "u" || N() !== "blink") return !1;
|
|
48
75
|
let e = navigator.platform ?? "";
|
|
49
76
|
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;
|
|
50
|
-
},
|
|
77
|
+
}, ee = (e = 20) => new Promise((t) => {
|
|
51
78
|
let n = Number.isFinite(e) ? Math.max(1, Math.floor(e)) : 20;
|
|
52
79
|
if (typeof requestAnimationFrame != "function" || typeof performance > "u") {
|
|
53
80
|
t({
|
|
@@ -69,50 +96,348 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = (e) => {
|
|
|
69
96
|
requestAnimationFrame(a);
|
|
70
97
|
};
|
|
71
98
|
requestAnimationFrame(a);
|
|
72
|
-
}),
|
|
99
|
+
}), te = [
|
|
100
|
+
"__vite_plugin_react_preamble_installed__",
|
|
101
|
+
"__vite__",
|
|
102
|
+
"__NEXT_HMR_CB",
|
|
103
|
+
"__NEXT_HMR_LATENCY_CB",
|
|
104
|
+
"__webpack_hot_middleware_reporter__",
|
|
105
|
+
"webpackHotUpdate",
|
|
106
|
+
"__REACT_REFRESH_RUNTIME__",
|
|
107
|
+
"$RefreshReg$"
|
|
108
|
+
], F = () => {
|
|
109
|
+
if (typeof window > "u") return [];
|
|
110
|
+
let e = [];
|
|
111
|
+
for (let t of te) try {
|
|
112
|
+
window[t] !== void 0 && e.push(t);
|
|
113
|
+
} catch {}
|
|
114
|
+
return e;
|
|
115
|
+
}, I = () => {
|
|
73
116
|
try {
|
|
74
117
|
return typeof PerformanceObserver < "u" && Array.isArray(PerformanceObserver.supportedEntryTypes) && PerformanceObserver.supportedEntryTypes.includes("longtask");
|
|
75
118
|
} catch {
|
|
76
119
|
return !1;
|
|
77
120
|
}
|
|
78
|
-
},
|
|
79
|
-
let
|
|
121
|
+
}, ne = (e, t = !1) => {
|
|
122
|
+
let n = typeof navigator < "u" ? navigator : null, r = typeof window < "u" ? window : null, i = !1;
|
|
80
123
|
try {
|
|
81
|
-
|
|
124
|
+
i = r?.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? !1;
|
|
82
125
|
} catch {
|
|
83
|
-
|
|
126
|
+
i = !1;
|
|
84
127
|
}
|
|
85
128
|
return {
|
|
86
|
-
userAgent:
|
|
87
|
-
uaBrands:
|
|
88
|
-
engine:
|
|
89
|
-
platform:
|
|
90
|
-
maxTouchPoints:
|
|
91
|
-
devicePixelRatio:
|
|
129
|
+
userAgent: n?.userAgent ?? "",
|
|
130
|
+
uaBrands: M(),
|
|
131
|
+
engine: N(),
|
|
132
|
+
platform: n?.platform ?? "",
|
|
133
|
+
maxTouchPoints: n?.maxTouchPoints ?? 0,
|
|
134
|
+
devicePixelRatio: r?.devicePixelRatio ?? 1,
|
|
135
|
+
hardwareConcurrency: n?.hardwareConcurrency ?? 0,
|
|
92
136
|
screen: {
|
|
93
|
-
width:
|
|
94
|
-
height:
|
|
137
|
+
width: r?.screen?.width ?? 0,
|
|
138
|
+
height: r?.screen?.height ?? 0
|
|
95
139
|
},
|
|
96
140
|
viewport: {
|
|
97
|
-
width:
|
|
98
|
-
height:
|
|
141
|
+
width: r?.innerWidth ?? 0,
|
|
142
|
+
height: r?.innerHeight ?? 0
|
|
99
143
|
},
|
|
100
|
-
visualViewportScale:
|
|
144
|
+
visualViewportScale: r?.visualViewport?.scale ?? null,
|
|
101
145
|
rafCadence: e,
|
|
102
|
-
reducedMotion:
|
|
103
|
-
|
|
146
|
+
reducedMotion: i,
|
|
147
|
+
developmentHints: F(),
|
|
148
|
+
emulationSuspected: P(),
|
|
104
149
|
observation: {
|
|
105
|
-
longTasks:
|
|
150
|
+
longTasks: I(),
|
|
106
151
|
elementAnimations: typeof Element < "u" && typeof Element.prototype.getAnimations == "function",
|
|
107
|
-
|
|
152
|
+
animationEvents: t
|
|
108
153
|
}
|
|
109
154
|
};
|
|
110
|
-
},
|
|
155
|
+
}, re = 2, L = new Set(k), ie = (e) => Math.round(e * 10) / 10, ae = () => ({
|
|
156
|
+
heldGaps: [],
|
|
157
|
+
releasedGaps: [],
|
|
158
|
+
lastFrameAt: null,
|
|
159
|
+
evidence: {
|
|
160
|
+
compiledAnimation: !1,
|
|
161
|
+
inlineSuppression: !1,
|
|
162
|
+
inlineAdvance: !1
|
|
163
|
+
},
|
|
164
|
+
lastPose: /* @__PURE__ */ new Map(),
|
|
165
|
+
clocks: /* @__PURE__ */ new Map(),
|
|
166
|
+
lastClock: /* @__PURE__ */ new Map(),
|
|
167
|
+
releasedFrames: 0,
|
|
168
|
+
stalledFrames: 0,
|
|
169
|
+
tailFrames: 0,
|
|
170
|
+
stallRunMs: 0,
|
|
171
|
+
longestStallMs: 0,
|
|
172
|
+
pausedAfterRelease: !1,
|
|
173
|
+
holdReassertedAtMs: null
|
|
174
|
+
}), oe = (e) => e.some((e) => {
|
|
175
|
+
let t = e.getAttribute(m);
|
|
176
|
+
return t !== null && L.has(t);
|
|
177
|
+
}), se = (e) => `${e.transform}/${e.opacity}`, ce = (e, t, n) => {
|
|
178
|
+
e.releasedFrames += 1;
|
|
179
|
+
let r = !1, i = !1;
|
|
180
|
+
for (let n of t) {
|
|
181
|
+
let t = e.clocks.get(n);
|
|
182
|
+
if (t) {
|
|
183
|
+
t.playState === "paused" && (e.pausedAfterRelease = !0), t.playState !== "finished" && (i = !0);
|
|
184
|
+
let a = typeof t.currentTime == "number" ? t.currentTime : null;
|
|
185
|
+
if (a !== null) {
|
|
186
|
+
let t = e.lastClock.get(n);
|
|
187
|
+
t !== void 0 && a !== t && (r = !0), e.lastClock.set(n, a);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
let a = n.style;
|
|
191
|
+
a && a.animation !== "" && e.lastPose.get(n) !== se(a) && (r = !0);
|
|
192
|
+
}
|
|
193
|
+
if (!(e.releasedFrames < re)) {
|
|
194
|
+
if (r) {
|
|
195
|
+
e.stallRunMs = 0;
|
|
196
|
+
return;
|
|
197
|
+
}
|
|
198
|
+
if (!i && e.clocks.size > 0) {
|
|
199
|
+
e.tailFrames += 1, e.stallRunMs = 0;
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
e.stalledFrames += 1, e.stallRunMs += n, e.stallRunMs > e.longestStallMs && (e.longestStallMs = e.stallRunMs);
|
|
203
|
+
}
|
|
204
|
+
}, le = (e, t) => {
|
|
205
|
+
let n = t.style;
|
|
206
|
+
if (!n || n.animation === "") return;
|
|
207
|
+
e.evidence.inlineSuppression = !0;
|
|
208
|
+
let r = se(n), i = e.lastPose.get(t);
|
|
209
|
+
i !== void 0 && i !== r && (e.evidence.inlineAdvance = !0), e.lastPose.set(t, r);
|
|
210
|
+
}, ue = (e, t) => {
|
|
211
|
+
for (let n of t) {
|
|
212
|
+
let t = n.getAnimations, r = e.clocks.get(n);
|
|
213
|
+
if (r !== void 0 && r.playState !== "finished") {
|
|
214
|
+
r.playState === "running" && (e.evidence.compiledAnimation = !0), le(e, n);
|
|
215
|
+
continue;
|
|
216
|
+
}
|
|
217
|
+
if (typeof t == "function") try {
|
|
218
|
+
for (let r of t.call(n)) {
|
|
219
|
+
let t = r.animationName;
|
|
220
|
+
typeof t == "string" && t.startsWith("flemo-") && (e.clocks.set(n, r), r.playState === "running" && (e.evidence.compiledAnimation = !0));
|
|
221
|
+
}
|
|
222
|
+
} catch {}
|
|
223
|
+
le(e, n);
|
|
224
|
+
}
|
|
225
|
+
}, de = (e) => ({
|
|
226
|
+
sampledFrames: e.releasedFrames,
|
|
227
|
+
stalledFrames: e.stalledFrames,
|
|
228
|
+
longestStallMs: ie(e.longestStallMs),
|
|
229
|
+
pausedAfterRelease: e.pausedAfterRelease,
|
|
230
|
+
holdReassertedAtMs: e.holdReassertedAtMs,
|
|
231
|
+
tailFrames: e.tailFrames
|
|
232
|
+
}), R = 200, z = (e) => {
|
|
233
|
+
let t = [];
|
|
234
|
+
for (let n of e) for (let e of Array.from(n.querySelectorAll("img"))) t.push(e);
|
|
235
|
+
return t;
|
|
236
|
+
}, fe = (e) => {
|
|
237
|
+
let t = new Set(z(e).filter((e) => !e.complete));
|
|
238
|
+
return {
|
|
239
|
+
tracked: t,
|
|
240
|
+
loadingAtStart: t.size,
|
|
241
|
+
addedDuringFlight: 0,
|
|
242
|
+
held: /* @__PURE__ */ new Set()
|
|
243
|
+
};
|
|
244
|
+
}, pe = (e, t, n) => {
|
|
245
|
+
if (!(e.tracked.size >= R)) for (let r of Array.from(n)) {
|
|
246
|
+
if (!(r instanceof Element) || !t.some((e) => e === r || e.contains(r))) continue;
|
|
247
|
+
let n = r instanceof HTMLImageElement ? [r] : Array.from(r.querySelectorAll("img"));
|
|
248
|
+
for (let t of n) if (!(t.complete || e.tracked.has(t))) {
|
|
249
|
+
if (e.tracked.size >= R) return;
|
|
250
|
+
e.tracked.add(t), e.addedDuringFlight += 1;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}, me = (e, t) => {
|
|
254
|
+
for (let n of t) for (let t of Array.from(n.querySelectorAll(`img[${h}]`))) e.held.add(t);
|
|
255
|
+
for (let t of e.tracked) t.hasAttribute("data-flemo-img-hold") && e.held.add(t);
|
|
256
|
+
}, he = (e) => {
|
|
257
|
+
let t = 0, n = 0;
|
|
258
|
+
for (let r of e.tracked) r.complete && (t += 1, e.held.has(r) || (n += 1));
|
|
259
|
+
return {
|
|
260
|
+
loadingAtStart: e.loadingAtStart,
|
|
261
|
+
addedDuringFlight: e.addedDuringFlight,
|
|
262
|
+
completedDuringFlight: t,
|
|
263
|
+
heldDuringFlight: e.held.size,
|
|
264
|
+
completedUnheld: n
|
|
265
|
+
};
|
|
266
|
+
}, ge = [
|
|
111
267
|
"DevTools must be CLOSED while judging motion. An open inspector serializes requests and repaints its own panels on the same machine; the 2026-08 campaign's entire residual 'stutter' was this, and it is invisible to every in-page metric.",
|
|
112
268
|
"No screen recording or display capture while judging. A capture client forces WindowServer to composite every vsync, which SUPPRESSES the symptom — a capture that looks smooth proves nothing about the uncaptured session.",
|
|
113
269
|
"Judge with real input (a finger, a mouse). Synthetic dispatch — evaluate().click() and friends — never fires pointerdown, so it bypasses the swipe/gesture machinery that a real navigation goes through.",
|
|
114
270
|
"Establish the viewing configuration before believing any verdict: device emulation off, which physical display, its refresh rate and HiDPI scaling, Low Power Mode. Ask for a photo of the setup if it is not certain."
|
|
115
|
-
],
|
|
271
|
+
], B = (e) => Math.round(e * 10) / 10, V = (e) => {
|
|
272
|
+
if (e.length === 0) return {
|
|
273
|
+
count: 0,
|
|
274
|
+
medianGapMs: 0,
|
|
275
|
+
maxGapMs: 0,
|
|
276
|
+
over30Count: 0
|
|
277
|
+
};
|
|
278
|
+
let t = [...e].sort((e, t) => e - t);
|
|
279
|
+
return {
|
|
280
|
+
count: e.length,
|
|
281
|
+
medianGapMs: B(t[Math.floor(t.length / 2)]),
|
|
282
|
+
maxGapMs: B(t[t.length - 1]),
|
|
283
|
+
over30Count: e.filter((e) => e >= 30).length
|
|
284
|
+
};
|
|
285
|
+
}, _e = (e, t = []) => {
|
|
286
|
+
let n = [...e, ...t];
|
|
287
|
+
return {
|
|
288
|
+
...n.length === 0 ? {
|
|
289
|
+
count: 0,
|
|
290
|
+
medianGapMs: 0,
|
|
291
|
+
maxGapMs: 0
|
|
292
|
+
} : (() => {
|
|
293
|
+
let e = [...n].sort((e, t) => e - t);
|
|
294
|
+
return {
|
|
295
|
+
count: n.length,
|
|
296
|
+
medianGapMs: B(e[Math.floor(e.length / 2)]),
|
|
297
|
+
maxGapMs: B(e[e.length - 1])
|
|
298
|
+
};
|
|
299
|
+
})(),
|
|
300
|
+
longGaps: n.filter((e) => e >= 30).map(B),
|
|
301
|
+
held: V(e),
|
|
302
|
+
released: V(t)
|
|
303
|
+
};
|
|
304
|
+
}, ve = (e) => {
|
|
305
|
+
let t = e.inlineSuppression || e.inlineAdvance;
|
|
306
|
+
return t && e.compiledAnimation ? "mixed" : t ? "inline" : e.compiledAnimation ? "compiled" : "unknown";
|
|
307
|
+
}, ye = (e) => e === "PUSHING" ? "PUSH" : e === "POPPING" ? "POP" : e === "REPLACING" ? "REPLACE" : null, be = (e) => {
|
|
308
|
+
let t = /^matrix3d\(([^)]+)\)$/.exec(e.trim());
|
|
309
|
+
if (t) {
|
|
310
|
+
let e = t[1].split(",").map((e) => Number(e.trim()));
|
|
311
|
+
return e.length === 16 && Number.isFinite(e[12]) ? e[12] : null;
|
|
312
|
+
}
|
|
313
|
+
let n = /^matrix\(([^)]+)\)$/.exec(e.trim());
|
|
314
|
+
if (n) {
|
|
315
|
+
let e = n[1].split(",").map((e) => Number(e.trim()));
|
|
316
|
+
return e.length === 6 && Number.isFinite(e[4]) ? e[4] : null;
|
|
317
|
+
}
|
|
318
|
+
return null;
|
|
319
|
+
}, H = (e) => {
|
|
320
|
+
if (e) return [];
|
|
321
|
+
let t = [];
|
|
322
|
+
for (let [e, n] of [[h, "image reveal hold"], [g, "arrival hold"]]) {
|
|
323
|
+
let r = document.querySelectorAll(`[${e}]`).length;
|
|
324
|
+
r > 0 && t.push(`${r} × ${n} (${e}) still marked at rest`);
|
|
325
|
+
}
|
|
326
|
+
return t;
|
|
327
|
+
}, xe = (e, t) => {
|
|
328
|
+
let n = [], r = !1, i = window.visualViewport?.width ?? window.innerWidth ?? 0;
|
|
329
|
+
return e.forEach((e, t) => {
|
|
330
|
+
if (!(e instanceof HTMLElement) || !e.isConnected) return;
|
|
331
|
+
let a = "", o = "";
|
|
332
|
+
try {
|
|
333
|
+
let t = getComputedStyle(e);
|
|
334
|
+
a = t.transform ?? "", o = t.display ?? "";
|
|
335
|
+
} catch {}
|
|
336
|
+
if (o === "none") return;
|
|
337
|
+
let s = e.getAttribute(p) === "true", c = `screen[${t}]${s ? " (active)" : ""}`;
|
|
338
|
+
if (e.style.transform !== "" && e.style.transform !== "none" && n.push(`${c} transform=${e.style.transform}`), e.style.opacity !== "" && e.style.opacity !== "1" && n.push(`${c} opacity=${e.style.opacity}`), s && e.getAttribute("data-flemo-status") === "COMPLETED" && i > 0) {
|
|
339
|
+
let e = be(a);
|
|
340
|
+
e !== null && Math.abs(e) >= i * .5 && (r = !0);
|
|
341
|
+
}
|
|
342
|
+
}), {
|
|
343
|
+
residualInlineTransforms: n,
|
|
344
|
+
offViewportAtRest: r,
|
|
345
|
+
orphanedHolds: H(t)
|
|
346
|
+
};
|
|
347
|
+
}, Se = E.map((e) => `[${b}="${e}"]`).join(","), Ce = A(d), we = (e) => Math.round(e * 10) / 10, Te = (e) => {
|
|
348
|
+
let t = e.getAttribute(x);
|
|
349
|
+
return t === null || t === "" ? null : t;
|
|
350
|
+
}, Ee = (e) => {
|
|
351
|
+
let t = e.getAttribute(b);
|
|
352
|
+
return t !== null && E.includes(t);
|
|
353
|
+
}, De = () => {
|
|
354
|
+
try {
|
|
355
|
+
return document.querySelector("style[data-flemo-morph-sheet]")?.sheet?.cssRules.length ?? 0;
|
|
356
|
+
} catch {
|
|
357
|
+
return 0;
|
|
358
|
+
}
|
|
359
|
+
}, Oe = (e) => {
|
|
360
|
+
let t = {
|
|
361
|
+
registered: 0,
|
|
362
|
+
pairable: /* @__PURE__ */ new Set(),
|
|
363
|
+
duplicated: /* @__PURE__ */ new Set(),
|
|
364
|
+
flew: /* @__PURE__ */ new Set(),
|
|
365
|
+
camera: document.querySelector(A(T)) !== null,
|
|
366
|
+
ghosts: 0,
|
|
367
|
+
ghostBornAt: /* @__PURE__ */ new Map(),
|
|
368
|
+
shortestGhostLifeMs: null,
|
|
369
|
+
sheetRulesAtStart: De()
|
|
370
|
+
}, n = new Set(e), r = /* @__PURE__ */ new Map(), i = /* @__PURE__ */ new Map();
|
|
371
|
+
for (let e of Array.from(document.querySelectorAll(A(b)))) {
|
|
372
|
+
t.registered += 1;
|
|
373
|
+
let a = Te(e);
|
|
374
|
+
if (a === null) continue;
|
|
375
|
+
if (Ee(e)) {
|
|
376
|
+
t.flew.add(a);
|
|
377
|
+
continue;
|
|
378
|
+
}
|
|
379
|
+
let o = e.closest(Ce);
|
|
380
|
+
if (o !== null && !n.has(o)) continue;
|
|
381
|
+
let s = o, c = r.get(a);
|
|
382
|
+
c || r.set(a, c = /* @__PURE__ */ new Set()), c.add(s);
|
|
383
|
+
let l = i.get(a);
|
|
384
|
+
l || i.set(a, l = /* @__PURE__ */ new Map()), l.set(s, (l.get(s) ?? 0) + 1);
|
|
385
|
+
}
|
|
386
|
+
for (let [e, n] of r) {
|
|
387
|
+
n.size >= 2 && t.pairable.add(e);
|
|
388
|
+
let r = i.get(e);
|
|
389
|
+
r && [...r.values()].some((e) => e > 1) && t.duplicated.add(e);
|
|
390
|
+
}
|
|
391
|
+
return t;
|
|
392
|
+
}, ke = (e, t) => {
|
|
393
|
+
if (t.hasAttribute("data-flemo-morph-camera") && (e.camera = !0), !Ee(t)) return;
|
|
394
|
+
let n = Te(t);
|
|
395
|
+
n !== null && e.flew.add(n);
|
|
396
|
+
}, Ae = (e, t, n) => {
|
|
397
|
+
for (let r of Array.from(t.addedNodes)) if (r instanceof Element) for (let t of je(r)) e.ghostBornAt.has(t) || (e.ghosts += 1, e.ghostBornAt.set(t, n));
|
|
398
|
+
for (let r of Array.from(t.removedNodes)) if (r instanceof Element) for (let t of je(r)) {
|
|
399
|
+
let r = e.ghostBornAt.get(t);
|
|
400
|
+
if (r === void 0) continue;
|
|
401
|
+
e.ghostBornAt.delete(t);
|
|
402
|
+
let i = n - r;
|
|
403
|
+
(e.shortestGhostLifeMs === null || i < e.shortestGhostLifeMs) && (e.shortestGhostLifeMs = i);
|
|
404
|
+
}
|
|
405
|
+
}, je = (e) => [...e.hasAttribute("data-flemo-morph-ghost") ? [e] : [], ...Array.from(e.querySelectorAll(A(w)))], Me = (e) => {
|
|
406
|
+
let t = e.shortestGhostLifeMs;
|
|
407
|
+
return t === null || t >= 34 ? [] : [{
|
|
408
|
+
kind: "ghost-cut",
|
|
409
|
+
atMs: we(t),
|
|
410
|
+
detail: `a morph ghost was removed ${we(t)}ms after it was created (under one frame) — the departing content it stands for was never presented; this is the first-frame blade signature`
|
|
411
|
+
}];
|
|
412
|
+
}, Ne = (e, t) => {
|
|
413
|
+
let n = [...e.pairable].sort(), r = [...e.flew].sort(), i = new Set(r), a = t ? {
|
|
414
|
+
strandedRoles: 0,
|
|
415
|
+
strandedStandIns: 0,
|
|
416
|
+
strandedGhosts: 0,
|
|
417
|
+
layerResidue: 0,
|
|
418
|
+
leaked: 0
|
|
419
|
+
} : {
|
|
420
|
+
strandedRoles: document.querySelectorAll(Se).length,
|
|
421
|
+
strandedStandIns: document.querySelectorAll(A(C)).length,
|
|
422
|
+
strandedGhosts: document.querySelectorAll(A(w)).length,
|
|
423
|
+
layerResidue: Array.from(document.querySelectorAll(A(S))).reduce((e, t) => e + t.childElementCount, 0),
|
|
424
|
+
leaked: Math.max(0, De() - e.sheetRulesAtStart)
|
|
425
|
+
};
|
|
426
|
+
return {
|
|
427
|
+
registered: e.registered,
|
|
428
|
+
pairable: n,
|
|
429
|
+
flew: r,
|
|
430
|
+
skipped: n.filter((e) => !i.has(e)),
|
|
431
|
+
camera: e.camera,
|
|
432
|
+
ghosts: e.ghosts,
|
|
433
|
+
strandedRoles: a.strandedRoles,
|
|
434
|
+
strandedStandIns: a.strandedStandIns,
|
|
435
|
+
strandedGhosts: a.strandedGhosts,
|
|
436
|
+
leakedSheetRules: a.leaked,
|
|
437
|
+
layerResidue: a.layerResidue,
|
|
438
|
+
duplicatedKeys: [...e.duplicated].sort()
|
|
439
|
+
};
|
|
440
|
+
}, U = "flemo:devtools-panel-height", Pe = [{
|
|
116
441
|
key: "flemo:devtools",
|
|
117
442
|
storage: "session",
|
|
118
443
|
kind: "opt-in-diagnostic",
|
|
@@ -120,13 +445,13 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = (e) => {
|
|
|
120
445
|
fallback: "off",
|
|
121
446
|
effect: "arms this flight recorder in the playground (?devtools=on)"
|
|
122
447
|
}, {
|
|
123
|
-
key:
|
|
448
|
+
key: U,
|
|
124
449
|
storage: "session",
|
|
125
450
|
kind: "production-state",
|
|
126
451
|
values: "a pixel height",
|
|
127
452
|
fallback: "(the panel's default height)",
|
|
128
453
|
effect: "the drawer height this panel was last dragged to"
|
|
129
|
-
}],
|
|
454
|
+
}], Fe = [], W = [...Fe, ...Pe], G = [
|
|
130
455
|
{
|
|
131
456
|
key: "flemo:sixty",
|
|
132
457
|
storage: "session",
|
|
@@ -247,403 +572,535 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = (e) => {
|
|
|
247
572
|
storage: "session",
|
|
248
573
|
retiredWith: "the Low Power Mode release-latency probe (2026-08-22)"
|
|
249
574
|
}
|
|
250
|
-
],
|
|
575
|
+
], Ie = "(retired — the library no longer reads this)", Le = (e) => {
|
|
251
576
|
try {
|
|
252
577
|
let t = e === "session" ? sessionStorage : localStorage;
|
|
253
578
|
return t.length, t;
|
|
254
579
|
} catch {
|
|
255
580
|
return null;
|
|
256
581
|
}
|
|
257
|
-
},
|
|
582
|
+
}, Re = (e, t) => {
|
|
258
583
|
try {
|
|
259
584
|
return e ? e.getItem(t) : null;
|
|
260
585
|
} catch {
|
|
261
586
|
return null;
|
|
262
587
|
}
|
|
263
|
-
},
|
|
264
|
-
let e = {}, t =
|
|
265
|
-
for (let r of
|
|
266
|
-
let i =
|
|
588
|
+
}, ze = new Set(W.map((e) => e.key)), Be = new Set(G.map((e) => e.key)), Ve = () => {
|
|
589
|
+
let e = {}, t = Le("session"), n = Le("local");
|
|
590
|
+
for (let r of W) {
|
|
591
|
+
let i = Re(r.storage === "session" ? t : n, r.key);
|
|
267
592
|
i !== null && (e[r.key] = i);
|
|
268
593
|
}
|
|
269
|
-
for (let r of
|
|
270
|
-
let t =
|
|
271
|
-
t !== null && (e[`${r.key} (${a}) ${
|
|
594
|
+
for (let r of G) for (let [i, a] of [[t, "sessionStorage"], [n, "localStorage"]]) {
|
|
595
|
+
let t = Re(i, r.key);
|
|
596
|
+
t !== null && (e[`${r.key} (${a}) ${Ie}`] = t);
|
|
272
597
|
}
|
|
273
598
|
for (let [r, i] of [[t, "sessionStorage"], [n, "localStorage"]]) if (r) try {
|
|
274
599
|
for (let t = 0; t < r.length; t += 1) {
|
|
275
600
|
let n = r.key(t);
|
|
276
|
-
!n || !n.startsWith("flemo:") ||
|
|
601
|
+
!n || !n.startsWith("flemo:") || ze.has(n) || Be.has(n) || (e[`${n} (${i}, unknown key)`] = r.getItem(n) ?? "");
|
|
277
602
|
}
|
|
278
603
|
} catch {}
|
|
279
604
|
return e;
|
|
280
|
-
},
|
|
605
|
+
}, He = (e) => {
|
|
281
606
|
let t = [];
|
|
282
607
|
for (let [n, r] of Object.entries(e)) if (n.includes("(retired — the library no longer reads this)")) {
|
|
283
|
-
let e = n.slice(0, n.indexOf(" (")), i =
|
|
608
|
+
let e = n.slice(0, n.indexOf(" (")), i = G.find((t) => t.key === e);
|
|
284
609
|
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.`);
|
|
285
610
|
continue;
|
|
286
611
|
}
|
|
287
612
|
return t;
|
|
288
|
-
},
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
613
|
+
}, Ue = "flemo:devtools-trace", We = () => {
|
|
614
|
+
try {
|
|
615
|
+
let e = sessionStorage;
|
|
616
|
+
return e.length, e;
|
|
617
|
+
} catch {
|
|
618
|
+
return null;
|
|
619
|
+
}
|
|
620
|
+
}, Ge = (e, t) => {
|
|
621
|
+
let n = We();
|
|
622
|
+
if (!n) return;
|
|
623
|
+
let r = e.slice(-10);
|
|
624
|
+
for (; r.length > 0;) {
|
|
625
|
+
let e = JSON.stringify({
|
|
626
|
+
version: t,
|
|
627
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
628
|
+
flights: r
|
|
629
|
+
});
|
|
630
|
+
if (e.length <= 64e3) {
|
|
631
|
+
try {
|
|
632
|
+
n.setItem(Ue, e);
|
|
633
|
+
} catch {}
|
|
634
|
+
return;
|
|
635
|
+
}
|
|
636
|
+
r = r.slice(1);
|
|
637
|
+
}
|
|
638
|
+
Ke();
|
|
639
|
+
}, Ke = () => {
|
|
640
|
+
try {
|
|
641
|
+
We()?.removeItem(Ue);
|
|
642
|
+
} catch {}
|
|
643
|
+
}, qe = (e) => {
|
|
644
|
+
let t = We();
|
|
645
|
+
if (!t) return null;
|
|
646
|
+
let n = null;
|
|
647
|
+
try {
|
|
648
|
+
n = t.getItem(Ue);
|
|
649
|
+
} catch {
|
|
650
|
+
return null;
|
|
651
|
+
}
|
|
652
|
+
if (n === null) return null;
|
|
653
|
+
let r = null;
|
|
654
|
+
try {
|
|
655
|
+
r = JSON.parse(n);
|
|
656
|
+
} catch {
|
|
657
|
+
return Ke(), null;
|
|
658
|
+
}
|
|
659
|
+
return !r || r.version !== e || !Array.isArray(r.flights) ? (Ke(), null) : {
|
|
660
|
+
savedAt: typeof r.savedAt == "string" ? r.savedAt : "",
|
|
661
|
+
flights: r.flights,
|
|
662
|
+
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."
|
|
294
663
|
};
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
664
|
+
}, Je = 12, Ye = 20, Xe = 40, Ze = 500, Qe = 200, $e = (e) => {
|
|
665
|
+
let t = e.rafCadence.medianGapMs;
|
|
666
|
+
if (t === null) return {
|
|
667
|
+
id: "display-cadence",
|
|
668
|
+
status: "unknown",
|
|
669
|
+
detail: "the idle frame cadence could not be sampled, so the display's rate is unknown"
|
|
301
670
|
};
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
671
|
+
let n = { medianIdleFrameMs: t };
|
|
672
|
+
return t < Je ? {
|
|
673
|
+
id: "display-cadence",
|
|
674
|
+
status: "ok",
|
|
675
|
+
detail: `idle frames arrive every ${t}ms — a display above 60Hz. Frame budgets in this report are still quoted against 60Hz (a gap of 30ms or more)`,
|
|
676
|
+
metrics: n
|
|
677
|
+
} : t <= Ye ? {
|
|
678
|
+
id: "display-cadence",
|
|
679
|
+
status: "ok",
|
|
680
|
+
detail: `idle frames arrive every ${t}ms — a 60Hz clock`,
|
|
681
|
+
metrics: n
|
|
682
|
+
} : t <= Xe ? {
|
|
683
|
+
id: "display-cadence",
|
|
684
|
+
status: "violated",
|
|
685
|
+
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`,
|
|
686
|
+
metrics: n
|
|
687
|
+
} : {
|
|
688
|
+
id: "display-cadence",
|
|
689
|
+
status: "violated",
|
|
690
|
+
detail: `idle frames arrive every ${t}ms — the page is barely being served frames at all while idle. Something outside the transition owns this machine; no motion verdict taken here means anything`,
|
|
691
|
+
metrics: n
|
|
692
|
+
};
|
|
693
|
+
}, et = (e) => {
|
|
694
|
+
if (!e.environment.observation.longTasks) return {
|
|
695
|
+
id: "machine-idle",
|
|
696
|
+
status: "unknown",
|
|
697
|
+
detail: "this browser does not report long tasks, so the recorder cannot tell whether anything else was competing for the main thread"
|
|
698
|
+
};
|
|
699
|
+
let t = e.idleLongTasks.length, n = Math.round(e.idleLongTasks.reduce((e, t) => e + t.durationMs, 0)), r = Math.round(e.idleLongTasks.reduce((e, t) => Math.max(e, t.durationMs), 0)), i = {
|
|
700
|
+
idleLongTasks: t,
|
|
701
|
+
idleLongTaskMs: n,
|
|
702
|
+
worstIdleTaskMs: r
|
|
703
|
+
};
|
|
704
|
+
return n >= Ze || r >= Qe ? {
|
|
705
|
+
id: "machine-idle",
|
|
706
|
+
status: "violated",
|
|
707
|
+
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`,
|
|
708
|
+
metrics: i
|
|
709
|
+
} : {
|
|
710
|
+
id: "machine-idle",
|
|
711
|
+
status: "ok",
|
|
712
|
+
detail: `${t} idle long task(s), ${n}ms total — the page was quiet between navigations`,
|
|
713
|
+
metrics: i
|
|
714
|
+
};
|
|
715
|
+
}, tt = (e) => {
|
|
716
|
+
let { trusted: t, synthetic: n, pointerTypes: r } = e.input;
|
|
717
|
+
return n > 0 ? {
|
|
718
|
+
id: "real-input",
|
|
719
|
+
status: "violated",
|
|
720
|
+
detail: `${n} script-dispatched (untrusted) input event(s) drove this session. Synthetic dispatch never fires the gesture machinery a real navigation goes through, so a clean run proves nothing about a finger`,
|
|
721
|
+
metrics: {
|
|
722
|
+
trusted: t,
|
|
723
|
+
synthetic: n
|
|
724
|
+
}
|
|
725
|
+
} : t === 0 ? {
|
|
726
|
+
id: "real-input",
|
|
727
|
+
status: "unknown",
|
|
728
|
+
detail: "no input event preceded any recorded flight. These navigations were driven programmatically or by the browser's own back/forward, which is a different path from the one a user takes",
|
|
729
|
+
metrics: {
|
|
730
|
+
trusted: t,
|
|
731
|
+
synthetic: n
|
|
732
|
+
}
|
|
733
|
+
} : {
|
|
734
|
+
id: "real-input",
|
|
735
|
+
status: "ok",
|
|
736
|
+
detail: `${t} trusted input event(s) drove this session (${r.join(", ") || "type unreported"})`,
|
|
737
|
+
metrics: {
|
|
738
|
+
trusted: t,
|
|
739
|
+
synthetic: n
|
|
740
|
+
}
|
|
741
|
+
};
|
|
742
|
+
}, nt = (e) => e.input.pointerTypes.includes("touch") ? {
|
|
743
|
+
id: "touch-path",
|
|
744
|
+
status: "ok",
|
|
745
|
+
detail: "at least one navigation was driven by touch"
|
|
746
|
+
} : e.environment.maxTouchPoints === 0 ? {
|
|
747
|
+
id: "touch-path",
|
|
748
|
+
status: "unknown",
|
|
749
|
+
detail: "this device reports no touch points, so there is no touch path to exercise here"
|
|
750
|
+
} : {
|
|
751
|
+
id: "touch-path",
|
|
752
|
+
status: "unknown",
|
|
753
|
+
detail: "no touch-driven navigation was recorded on a touch-capable device. The swipe and pointer-capture paths are only reached by a finger; a build that had broken them outright once passed every automated layer green because every probe used a mouse"
|
|
754
|
+
}, rt = [
|
|
755
|
+
{
|
|
756
|
+
id: "devtools-closed",
|
|
757
|
+
status: "unknown",
|
|
758
|
+
detail: "whether an inspector is open cannot be seen from inside the page. An open one serializes requests and repaints its own panels on the same machine; a whole campaign's residual stutter was this and nothing else. Confirm it with the user"
|
|
759
|
+
},
|
|
760
|
+
{
|
|
761
|
+
id: "no-screen-capture",
|
|
762
|
+
status: "unknown",
|
|
763
|
+
detail: "whether the screen is being captured cannot be seen from inside the page. A capture client forces the compositor to present every vsync, which SUPPRESSES the symptom — a recording that looks smooth proves nothing about the uncaptured session"
|
|
764
|
+
},
|
|
765
|
+
{
|
|
766
|
+
id: "viewing-configuration",
|
|
767
|
+
status: "unknown",
|
|
768
|
+
detail: "which physical display this window is on, its refresh rate and scaling, cannot be read from the page. Establish it with the user before believing any verdict"
|
|
769
|
+
}
|
|
770
|
+
], it = (e) => {
|
|
771
|
+
let { environment: t } = e, n = [];
|
|
772
|
+
return n.push(t.emulationSuspected ? {
|
|
773
|
+
id: "device-emulation",
|
|
774
|
+
status: "violated",
|
|
775
|
+
detail: "DevTools device emulation is suspected (Blink on a desktop platform reporting touch points). 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" + (/Win/i.test(t.platform) ? ". Windows touch hardware makes this signal ambiguous — confirm the device toolbar state" : "")
|
|
776
|
+
} : {
|
|
777
|
+
id: "device-emulation",
|
|
778
|
+
status: "ok",
|
|
779
|
+
detail: "no device-emulation signature on this session"
|
|
780
|
+
}), n.push($e(t)), n.push(e.documentHidden || e.wentHidden ? {
|
|
781
|
+
id: "page-foreground",
|
|
782
|
+
status: "violated",
|
|
783
|
+
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"
|
|
784
|
+
} : {
|
|
785
|
+
id: "page-foreground",
|
|
786
|
+
status: "ok",
|
|
787
|
+
detail: "the document stayed visible throughout"
|
|
788
|
+
}), n.push(et(e)), n.push(t.developmentHints.length > 0 ? {
|
|
789
|
+
id: "build-mode",
|
|
790
|
+
status: "violated",
|
|
791
|
+
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`
|
|
792
|
+
} : {
|
|
793
|
+
id: "build-mode",
|
|
794
|
+
status: "unknown",
|
|
795
|
+
detail: "no development-server global was found. That is consistent with a production build but does not prove one — confirm how this page was built"
|
|
796
|
+
}), n.push(tt(e)), n.push(nt(e)), n.push(t.reducedMotion ? {
|
|
797
|
+
id: "reduced-motion",
|
|
798
|
+
status: "violated",
|
|
799
|
+
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"
|
|
800
|
+
} : {
|
|
801
|
+
id: "reduced-motion",
|
|
802
|
+
status: "ok",
|
|
803
|
+
detail: "reduced motion is not requested"
|
|
804
|
+
}), [...n, ...rt];
|
|
805
|
+
}, at = 2e3, ot = 40, st = (e) => Math.round(e * 10) / 10, ct = (e) => typeof e.animationName == "string" && e.animationName.startsWith("flemo-"), lt = (e) => e instanceof Element ? `<${e.tagName.toLowerCase()}>${e.getAttribute("data-flemo-screen") === null ? "" : " (screen)"}` : "an unidentified node", ut = (e) => {
|
|
806
|
+
if (typeof document > "u") return {
|
|
807
|
+
detach: () => {},
|
|
808
|
+
sawAnimationEvent: () => !1,
|
|
809
|
+
inputBetween: () => ({
|
|
810
|
+
trusted: 0,
|
|
811
|
+
synthetic: 0,
|
|
812
|
+
pointerTypes: []
|
|
813
|
+
})
|
|
814
|
+
};
|
|
815
|
+
let t = [], n = !1, r = (t) => {
|
|
816
|
+
ct(t) && (n = !0, e.onAnimationStart(performance.now()));
|
|
817
|
+
}, i = (t) => {
|
|
818
|
+
ct(t) && (n = !0, e.onHit({
|
|
819
|
+
kind: "animation-cancel",
|
|
820
|
+
atMs: performance.now(),
|
|
821
|
+
detail: `${t.animationName} was CANCELLED on ${lt(t.target)} — the element was re-parented, re-styled or removed mid-flight. A cancelled animation loses its start time, and whatever restarts it is free to overwrite the authored delay`
|
|
822
|
+
}));
|
|
823
|
+
}, a = (t) => {
|
|
824
|
+
ct(t) && (n = !0, t.elapsedTime === 0 && e.onHit({
|
|
825
|
+
kind: "zero-length-animation-end",
|
|
826
|
+
atMs: performance.now(),
|
|
827
|
+
detail: `${t.animationName} reported animationend with elapsedTime 0 on ${lt(t.target)} — the animation ended without ever running. Anything landing on this event lands before the motion it was waiting for`
|
|
828
|
+
}));
|
|
829
|
+
}, o = (e) => {
|
|
830
|
+
let n = e.pointerType ?? "";
|
|
831
|
+
t.push({
|
|
832
|
+
atMs: performance.now(),
|
|
833
|
+
trusted: e.isTrusted === !0,
|
|
834
|
+
pointerType: n === "" ? e.type : n
|
|
835
|
+
}), t.length > ot && t.splice(0, t.length - ot);
|
|
836
|
+
}, s = {
|
|
837
|
+
capture: !0,
|
|
838
|
+
passive: !0
|
|
839
|
+
};
|
|
840
|
+
return document.addEventListener("animationstart", r, s), document.addEventListener("animationcancel", i, s), document.addEventListener("animationend", a, s), document.addEventListener("pointerdown", o, s), document.addEventListener("click", o, s), {
|
|
841
|
+
detach: () => {
|
|
842
|
+
document.removeEventListener("animationstart", r, s), document.removeEventListener("animationcancel", i, s), document.removeEventListener("animationend", a, s), document.removeEventListener("pointerdown", o, s), document.removeEventListener("click", o, s);
|
|
843
|
+
},
|
|
844
|
+
sawAnimationEvent: () => n,
|
|
845
|
+
inputBetween: (e, n) => {
|
|
846
|
+
let r = e - at, i = t.filter((e) => e.atMs >= r && e.atMs <= n), a = i.filter((e) => e.trusted).length, o = new Set(i.map((e) => e.pointerType));
|
|
311
847
|
return {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
848
|
+
trusted: a,
|
|
849
|
+
synthetic: i.length - a,
|
|
850
|
+
pointerTypes: [...o].sort()
|
|
315
851
|
};
|
|
316
|
-
}
|
|
317
|
-
longGaps: n.filter((e) => e >= 30).map(L),
|
|
318
|
-
held: R(e),
|
|
319
|
-
released: R(t)
|
|
852
|
+
}
|
|
320
853
|
};
|
|
321
|
-
},
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
854
|
+
}, dt = (e, t) => ({
|
|
855
|
+
kind: e.kind,
|
|
856
|
+
atMs: st(e.atMs - t),
|
|
857
|
+
detail: e.detail
|
|
858
|
+
}), ft = (e) => {
|
|
859
|
+
/* v8 ignore next -- unreachable: deriveVerdict returns before this on an
|
|
860
|
+
empty flight list, so nothing ever asks for the median of nothing. */
|
|
861
|
+
if (e.length === 0) return 0;
|
|
862
|
+
let t = [...e].sort((e, t) => e - t);
|
|
863
|
+
return t[Math.floor(t.length / 2)];
|
|
864
|
+
}, pt = (e) => {
|
|
865
|
+
let t = [], n = e.preconditions.filter((e) => e.status === "violated");
|
|
866
|
+
if (n.length > 0 && t.push(`NOT EVIDENCE: ${n.length} judging precondition(s) failed — ${n.map((e) => e.id).join(", ")}. Everything below was measured under those conditions; fix them and measure again before drawing a conclusion from it.`), e.flights.length === 0) return t.push("No flights were recorded. Either no navigation happened while the recorder was attached, or it attached after the one you meant to measure — the recorder only sees flights that start after it does."), t;
|
|
867
|
+
e.observation.animationEvents || t.push("The animation channel observed NOTHING across this whole session: not one flemo keyframe reported a start, an end or a cancel, though flights were recorded. Treat every animation-derived field here as unmeasured rather than as clean — a probe that never fires reads exactly like a page with nothing to report.");
|
|
868
|
+
let r = e.flights, i = r.reduce((e, t) => Math.max(e, t.frameSamples.released.maxGapMs), 0), a = r.filter((e) => e.anomalies.length > 0).length;
|
|
869
|
+
t.push(`${r.length} flight(s) recorded. Median duration ${ft(r.map((e) => e.durationMs))}ms, worst frame gap during visible motion ${i}ms, ${a} flight(s) carrying at least one anomaly.`);
|
|
870
|
+
let o = r.filter((e) => e.motion.longestStallMs >= 48);
|
|
871
|
+
o.length > 0 && t.push(`${o.length} flight(s) STOPPED MOVING mid-flight (longest ${Math.max(...o.map((e) => e.motion.longestStallMs))}ms). Frames kept arriving; the picture did not change. Look at the hold and the animation's play state, not at the frame budget.`);
|
|
872
|
+
let s = r.filter((e) => e.morphs.skipped.length > 0);
|
|
873
|
+
if (s.length > 0) {
|
|
874
|
+
let e = [...new Set(s.flatMap((e) => e.morphs.skipped))];
|
|
875
|
+
t.push(`Shared elements did NOT fly on ${s.length} flight(s): ${e.join(", ")}. Both ends were registered on two different screens and neither was ever stamped with a flight role, so the pair was never made. This is silent by nature — nothing else on the page says it happened.`);
|
|
332
876
|
}
|
|
333
|
-
let
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
877
|
+
let c = [...new Set(r.flatMap((e) => e.morphs.duplicatedKeys))];
|
|
878
|
+
c.length > 0 && t.push(`Pairing key(s) used twice inside one screen: ${c.join(", ")}. Two ends under one screen are not a pair, so one of them can never fly. This is in the consuming app, not in the library.`);
|
|
879
|
+
let l = r.flatMap((e) => e.tripwires);
|
|
880
|
+
if (l.length > 0) {
|
|
881
|
+
let e = [...new Set(l.map((e) => e.kind))];
|
|
882
|
+
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.`);
|
|
337
883
|
}
|
|
338
|
-
return
|
|
339
|
-
},
|
|
340
|
-
|
|
884
|
+
return r.filter((e) => e.frameSamples.released.over30Count > 0).length === 0 && a === 0 && n.length === 0 && t.push("No flight dropped a frame during visible motion (nothing at or over 30ms) and no anomaly fired. Under the preconditions above, this session is clean — what remains is in `blindSpots`, and none of it is reachable from page code."), t;
|
|
885
|
+
}, mt = "3", ht = new Set(O), gt = new Set(k), _t = A(d), vt = 2e3, yt = 1e3, bt = 4e3, K = (e) => Math.round(e * 10) / 10, xt = null, St = () => ({
|
|
886
|
+
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
887
|
+
version: "3",
|
|
888
|
+
verdict: ["No DOM was available, so nothing could be observed. The recorder ran inert."],
|
|
889
|
+
environment: ne({
|
|
890
|
+
medianGapMs: null,
|
|
891
|
+
sampleCount: 0
|
|
892
|
+
}),
|
|
893
|
+
preconditions: [],
|
|
894
|
+
overrides: {
|
|
895
|
+
active: {},
|
|
896
|
+
warnings: ["no DOM available — recorder ran inert"]
|
|
897
|
+
},
|
|
898
|
+
flights: [],
|
|
899
|
+
comparison: [],
|
|
900
|
+
previousSession: null,
|
|
901
|
+
anomalies: [],
|
|
902
|
+
blindSpots: [...c],
|
|
903
|
+
judgingProtocol: [...ge]
|
|
904
|
+
}), Ct = (e = {}) => {
|
|
905
|
+
if (xt) return xt;
|
|
341
906
|
if (typeof window > "u" || typeof document > "u") return {
|
|
342
907
|
detach: () => {},
|
|
343
|
-
report:
|
|
344
|
-
|
|
345
|
-
version: "2",
|
|
346
|
-
environment: T({
|
|
347
|
-
medianGapMs: null,
|
|
348
|
-
sampleCount: 0
|
|
349
|
-
}),
|
|
350
|
-
overrides: {
|
|
351
|
-
active: {},
|
|
352
|
-
warnings: ["no DOM available — recorder ran inert"]
|
|
353
|
-
},
|
|
354
|
-
flights: [],
|
|
355
|
-
anomalies: [],
|
|
356
|
-
blindSpots: [...s],
|
|
357
|
-
judgingProtocol: [...E]
|
|
358
|
-
})
|
|
908
|
+
report: St,
|
|
909
|
+
mark: () => null
|
|
359
910
|
};
|
|
360
|
-
let n = e.maxFlights ?? 50, r = e.log ?? !1, i = e.installGlobal ?? !0,
|
|
911
|
+
let n = e.maxFlights ?? 50, r = e.log ?? !1, i = e.installGlobal ?? !0, a = e.persist ?? !0, l = Ve(), d = performance.now(), h = a ? qe("3") : null, g = {
|
|
361
912
|
medianGapMs: null,
|
|
362
913
|
sampleCount: 0
|
|
363
914
|
};
|
|
364
|
-
|
|
365
|
-
|
|
915
|
+
ee().then((e) => {
|
|
916
|
+
g = e;
|
|
366
917
|
});
|
|
367
|
-
let
|
|
918
|
+
let x = [], S = null;
|
|
368
919
|
try {
|
|
369
|
-
typeof PerformanceObserver < "u" && PerformanceObserver.supportedEntryTypes?.includes("longtask") && (
|
|
370
|
-
for (let t of e.getEntries())
|
|
371
|
-
startMs:
|
|
372
|
-
durationMs:
|
|
920
|
+
typeof PerformanceObserver < "u" && PerformanceObserver.supportedEntryTypes?.includes("longtask") && (S = new PerformanceObserver((e) => {
|
|
921
|
+
for (let t of e.getEntries()) x.push({
|
|
922
|
+
startMs: K(t.startTime),
|
|
923
|
+
durationMs: K(t.duration)
|
|
373
924
|
});
|
|
374
|
-
|
|
375
|
-
}),
|
|
925
|
+
x.length > yt && x.splice(0, x.length - yt);
|
|
926
|
+
}), S.observe({
|
|
376
927
|
type: "longtask",
|
|
377
928
|
buffered: !0
|
|
378
929
|
}));
|
|
379
930
|
} catch {
|
|
380
|
-
|
|
931
|
+
S = null;
|
|
381
932
|
}
|
|
382
|
-
let
|
|
383
|
-
let t = Array.from(document.querySelectorAll(
|
|
933
|
+
let C = [], w = 0, E = null, D = null, O = [], k = !1, j = !1, M = document.visibilityState === "hidden", N = 0, P = () => Array.from(document.querySelectorAll(_t)).filter((e) => ht.has(e.getAttribute("data-flemo-status") ?? "")), te = () => E !== null || P().length > 0, F = (e) => {
|
|
934
|
+
let t = Array.from(document.querySelectorAll(A(y))).filter((e) => ht.has(e.getAttribute("data-flemo-bar-status") ?? "") || e.getAttribute("data-flemo-bar-riding") === "true").length, n = Array.from(document.querySelectorAll(A(v))).filter((e) => ht.has(e.getAttribute("data-flemo-status") ?? "")).length, r = Array.from(document.querySelectorAll(A(_))).filter((e) => ht.has(e.getAttribute("data-flemo-status") ?? "")).length;
|
|
384
935
|
return {
|
|
385
936
|
screens: e.length,
|
|
386
937
|
bars: t,
|
|
387
938
|
decorators: n,
|
|
388
939
|
parts: r
|
|
389
940
|
};
|
|
390
|
-
},
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
loadingAtStart: e.imagesLoadingAtStart,
|
|
399
|
-
addedDuringFlight: e.imagesAddedDuringFlight,
|
|
400
|
-
completedDuringFlight: t,
|
|
401
|
-
heldDuringFlight: e.imagesHeld.size,
|
|
402
|
-
completedUnheld: n
|
|
403
|
-
};
|
|
404
|
-
}, j = (e) => {
|
|
405
|
-
let t = x;
|
|
406
|
-
if (!(!t || t.imagesTracked.size >= pe)) for (let n of Array.from(e)) {
|
|
407
|
-
if (!(n instanceof Element) || !t.elements.some((e) => e === n || e.contains(n))) continue;
|
|
408
|
-
let e = n instanceof HTMLImageElement ? [n] : Array.from(n.querySelectorAll("img"));
|
|
409
|
-
for (let n of e) if (!(n.complete || t.imagesTracked.has(n))) {
|
|
410
|
-
if (t.imagesTracked.size >= pe) return;
|
|
411
|
-
t.imagesTracked.add(n), t.imagesAddedDuringFlight += 1;
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
}, M = (e) => {
|
|
415
|
-
for (let t of e.elements) for (let n of Array.from(t.querySelectorAll(`img[${f}]`))) e.imagesHeld.add(n);
|
|
416
|
-
for (let t of e.imagesTracked) t.hasAttribute("data-flemo-img-hold") && e.imagesHeld.add(t);
|
|
417
|
-
}, N = (e, t) => {
|
|
418
|
-
e.releasedFrames += 1;
|
|
419
|
-
let n = !1, r = !1;
|
|
420
|
-
for (let t of e.elements) {
|
|
421
|
-
let i = e.clocks.get(t);
|
|
422
|
-
if (i) {
|
|
423
|
-
i.playState === "paused" && (e.pausedAfterRelease = !0), i.playState !== "finished" && (r = !0);
|
|
424
|
-
let a = typeof i.currentTime == "number" ? i.currentTime : null;
|
|
425
|
-
if (a !== null) {
|
|
426
|
-
let r = e.lastClock.get(t);
|
|
427
|
-
r !== void 0 && a !== r && (n = !0), e.lastClock.set(t, a);
|
|
428
|
-
}
|
|
429
|
-
}
|
|
430
|
-
let a = t.style;
|
|
431
|
-
if (a && a.animation !== "") {
|
|
432
|
-
let r = `${a.transform}/${a.opacity}`;
|
|
433
|
-
e.lastPose.get(t) !== r && (n = !0);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
if (!(e.releasedFrames < fe)) {
|
|
437
|
-
if (n) {
|
|
438
|
-
e.stallRunMs = 0;
|
|
439
|
-
return;
|
|
440
|
-
}
|
|
441
|
-
if (!r && e.clocks.size > 0) {
|
|
442
|
-
e.tailFrames += 1, e.stallRunMs = 0;
|
|
443
|
-
return;
|
|
444
|
-
}
|
|
445
|
-
e.stalledFrames += 1, e.stallRunMs += t, e.stallRunMs > e.longestStallMs && (e.longestStallMs = e.stallRunMs);
|
|
446
|
-
}
|
|
447
|
-
}, P = (e) => {
|
|
448
|
-
for (let t of e.elements) {
|
|
449
|
-
let n = t.style, r = t.getAnimations, i = e.clocks.get(t);
|
|
450
|
-
if (i !== void 0 && i.playState !== "finished") {
|
|
451
|
-
if (i.playState === "running" && (e.evidence.compiledAnimation = !0), n && n.animation !== "") {
|
|
452
|
-
e.evidence.playerSuppression = !0;
|
|
453
|
-
let r = `${n.transform}/${n.opacity}`, i = e.lastPose.get(t);
|
|
454
|
-
i !== void 0 && i !== r && (e.evidence.playerAdvance = !0), e.lastPose.set(t, r);
|
|
455
|
-
}
|
|
456
|
-
continue;
|
|
457
|
-
}
|
|
458
|
-
if (typeof r == "function") try {
|
|
459
|
-
for (let n of r.call(t)) {
|
|
460
|
-
let r = n.animationName;
|
|
461
|
-
typeof r == "string" && r.startsWith("flemo-") && (e.clocks.set(t, n), n.playState === "running" && (e.evidence.compiledAnimation = !0));
|
|
462
|
-
}
|
|
463
|
-
} catch {}
|
|
464
|
-
if (n && n.animation !== "") {
|
|
465
|
-
e.evidence.playerSuppression = !0;
|
|
466
|
-
let r = `${n.transform}/${n.opacity}`, i = e.lastPose.get(t);
|
|
467
|
-
i !== void 0 && i !== r && (e.evidence.playerAdvance = !0), e.lastPose.set(t, r);
|
|
468
|
-
}
|
|
469
|
-
}
|
|
470
|
-
}, ne = (e) => e.elements.some((e) => {
|
|
471
|
-
let t = e.getAttribute(H);
|
|
472
|
-
return t !== null && V.has(t);
|
|
473
|
-
}), re = () => {
|
|
474
|
-
let e = x;
|
|
475
|
-
if (!e || C) return;
|
|
476
|
-
let t = performance.now();
|
|
477
|
-
if (e.lastFrameAt !== null && e.heldGaps.length + e.releasedGaps.length < de) {
|
|
478
|
-
let n = t - e.lastFrameAt, r = ne(e);
|
|
479
|
-
(r ? e.heldGaps : e.releasedGaps).push(n), r || (N(e, n), e.releasedFrames === 1 && M(e));
|
|
480
|
-
}
|
|
481
|
-
if (e.lastFrameAt = t, P(e), t - e.t0Ms > 1e4) {
|
|
482
|
-
S = [...e.elements], W(t, L(e));
|
|
483
|
-
return;
|
|
941
|
+
}, I = ut({
|
|
942
|
+
onHit: (e) => {
|
|
943
|
+
let t = E;
|
|
944
|
+
t && t.tripwires.push(dt(e, t.t0Ms));
|
|
945
|
+
},
|
|
946
|
+
onAnimationStart: (e) => {
|
|
947
|
+
let t = E;
|
|
948
|
+
!t || t.firstAnimationAtMs !== null || (t.firstAnimationAtMs = K(e - t.t0Ms));
|
|
484
949
|
}
|
|
485
|
-
|
|
486
|
-
}, L = (e) => {
|
|
950
|
+
}), re = (e) => {
|
|
487
951
|
let t = /* @__PURE__ */ new Set();
|
|
488
952
|
for (let n of e.elements) {
|
|
489
953
|
let e = n.getAttribute("data-flemo-status") ?? "";
|
|
490
|
-
|
|
954
|
+
ht.has(e) && t.add(e);
|
|
491
955
|
}
|
|
492
956
|
return [...t];
|
|
493
|
-
},
|
|
957
|
+
}, L = () => {
|
|
958
|
+
let e = E;
|
|
959
|
+
if (!e || k) return;
|
|
960
|
+
let t = performance.now(), n = e.frames;
|
|
961
|
+
if (n.lastFrameAt !== null && n.heldGaps.length + n.releasedGaps.length < vt) {
|
|
962
|
+
let r = t - n.lastFrameAt, i = oe(e.elements);
|
|
963
|
+
(i ? n.heldGaps : n.releasedGaps).push(r), i || (ce(n, e.elements, r), n.releasedFrames === 1 && me(e.images, e.elements));
|
|
964
|
+
}
|
|
965
|
+
if (n.lastFrameAt = t, ue(n, e.elements), t - e.t0Ms > 1e4) {
|
|
966
|
+
O = [...e.elements], z(t, re(e));
|
|
967
|
+
return;
|
|
968
|
+
}
|
|
969
|
+
e.rafId = requestAnimationFrame(L);
|
|
970
|
+
}, ie = (e) => {
|
|
494
971
|
let t = performance.now();
|
|
495
|
-
|
|
496
|
-
let n = e.find((e) => e.getAttribute("data-flemo-active") === "true") ?? e[0], r =
|
|
972
|
+
w += 1;
|
|
973
|
+
let n = e.find((e) => e.getAttribute("data-flemo-active") === "true") ?? e[0], r = ye(n.getAttribute("data-flemo-status") ?? "") ?? "PUSH", i = null;
|
|
497
974
|
for (let t of e) {
|
|
498
|
-
let e = t.getAttribute(
|
|
499
|
-
if (e !== null &&
|
|
975
|
+
let e = t.getAttribute(m);
|
|
976
|
+
if (e !== null && gt.has(e)) {
|
|
500
977
|
i = e;
|
|
501
978
|
break;
|
|
502
979
|
}
|
|
503
980
|
}
|
|
504
|
-
|
|
505
|
-
id: `flight-${
|
|
981
|
+
E = {
|
|
982
|
+
id: `flight-${w}`,
|
|
506
983
|
kind: r,
|
|
507
984
|
routerId: n.getAttribute("data-flemo-router") ?? void 0,
|
|
985
|
+
bucket: D,
|
|
508
986
|
t0Ms: t,
|
|
509
987
|
t0Iso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
510
988
|
elements: [...e],
|
|
511
|
-
participants:
|
|
989
|
+
participants: F(e),
|
|
512
990
|
holdKind: i,
|
|
513
991
|
holdReleasedAtMs: null,
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
compiledAnimation: !1,
|
|
520
|
-
playerSuppression: !1,
|
|
521
|
-
playerAdvance: !1
|
|
522
|
-
},
|
|
523
|
-
lastPose: /* @__PURE__ */ new Map(),
|
|
524
|
-
clocks: /* @__PURE__ */ new Map(),
|
|
525
|
-
lastClock: /* @__PURE__ */ new Map(),
|
|
526
|
-
releasedFrames: 0,
|
|
527
|
-
tailFrames: 0,
|
|
528
|
-
stalledFrames: 0,
|
|
529
|
-
stallRunMs: 0,
|
|
530
|
-
longestStallMs: 0,
|
|
531
|
-
pausedAfterRelease: !1,
|
|
532
|
-
holdReassertedAtMs: null,
|
|
533
|
-
imagesTracked: new Set(k(e).filter((e) => !e.complete)),
|
|
534
|
-
imagesLoadingAtStart: 0,
|
|
535
|
-
imagesAddedDuringFlight: 0,
|
|
536
|
-
imagesHeld: /* @__PURE__ */ new Set(),
|
|
992
|
+
firstAnimationAtMs: null,
|
|
993
|
+
frames: ae(),
|
|
994
|
+
images: fe(e),
|
|
995
|
+
morphs: Oe(e),
|
|
996
|
+
tripwires: [],
|
|
537
997
|
rafId: null
|
|
538
|
-
},
|
|
539
|
-
},
|
|
540
|
-
let n =
|
|
541
|
-
if (
|
|
998
|
+
}, ue(E.frames, E.elements), E.rafId = requestAnimationFrame(L);
|
|
999
|
+
}, se = (e, t) => {
|
|
1000
|
+
let n = 2, r = () => {
|
|
1001
|
+
if (k) return;
|
|
1002
|
+
if (--n, n > 0) {
|
|
1003
|
+
requestAnimationFrame(r);
|
|
1004
|
+
return;
|
|
1005
|
+
}
|
|
1006
|
+
let i = xe(t, te());
|
|
1007
|
+
e.landing.residualInlineTransforms = i.residualInlineTransforms, e.landing.offViewportAtRest = i.offViewportAtRest, e.landing.orphanedHolds = i.orphanedHolds;
|
|
1008
|
+
};
|
|
1009
|
+
requestAnimationFrame(r);
|
|
1010
|
+
}, le = (e, t) => {
|
|
1011
|
+
let n = 2, r = () => {
|
|
1012
|
+
if (!k) {
|
|
542
1013
|
if (--n, n > 0) {
|
|
543
1014
|
requestAnimationFrame(r);
|
|
544
1015
|
return;
|
|
545
1016
|
}
|
|
546
|
-
|
|
1017
|
+
e.morphs = Ne(t.morphs, te());
|
|
547
1018
|
}
|
|
548
1019
|
};
|
|
549
1020
|
requestAnimationFrame(r);
|
|
550
|
-
},
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
1021
|
+
}, R = (e, t, n, r) => ({
|
|
1022
|
+
id: r ? `${e.id} (in flight)` : e.id,
|
|
1023
|
+
...e.routerId === void 0 ? {} : { routerId: e.routerId },
|
|
1024
|
+
...e.bucket === null ? {} : { bucket: e.bucket },
|
|
1025
|
+
kind: e.kind,
|
|
1026
|
+
t0: {
|
|
1027
|
+
ms: K(e.t0Ms),
|
|
1028
|
+
iso: e.t0Iso
|
|
1029
|
+
},
|
|
1030
|
+
t1: {
|
|
1031
|
+
ms: K(t),
|
|
1032
|
+
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
1033
|
+
},
|
|
1034
|
+
durationMs: K(t - e.t0Ms),
|
|
1035
|
+
driver: ve(e.frames.evidence),
|
|
1036
|
+
participants: e.participants,
|
|
1037
|
+
holds: {
|
|
1038
|
+
kind: e.holdKind,
|
|
1039
|
+
releasedAtMs: e.holdReleasedAtMs
|
|
1040
|
+
},
|
|
1041
|
+
frameSamples: _e(e.frames.heldGaps, e.frames.releasedGaps),
|
|
1042
|
+
motion: {
|
|
1043
|
+
...de(e.frames),
|
|
1044
|
+
firstAnimationAtMs: e.firstAnimationAtMs
|
|
1045
|
+
},
|
|
1046
|
+
images: he(e.images),
|
|
1047
|
+
morphs: Ne(e.morphs, !0),
|
|
1048
|
+
tripwires: [...e.tripwires, ...Me(e.morphs)],
|
|
1049
|
+
input: I.inputBetween(e.t0Ms, t),
|
|
1050
|
+
longTasks: [],
|
|
1051
|
+
holdLongTasks: [],
|
|
1052
|
+
landing: {
|
|
1053
|
+
residualInlineTransforms: [],
|
|
1054
|
+
offViewportAtRest: !1,
|
|
1055
|
+
stuckStatuses: n,
|
|
1056
|
+
orphanedHolds: []
|
|
1057
|
+
},
|
|
1058
|
+
anomalies: []
|
|
1059
|
+
}), z = (e, t) => {
|
|
1060
|
+
let i = E;
|
|
1061
|
+
/* v8 ignore next -- unreachable: both callers hold a flight. sampleFrame
|
|
1062
|
+
returns at its own top when `current` is null, and evaluate only calls
|
|
1063
|
+
this inside `if (current && ...)`. The narrowing stays for the type. */
|
|
576
1064
|
if (!i) return;
|
|
577
|
-
|
|
578
|
-
let a =
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
t0: {
|
|
583
|
-
ms: U(i.t0Ms),
|
|
584
|
-
iso: i.t0Iso
|
|
585
|
-
},
|
|
586
|
-
t1: {
|
|
587
|
-
ms: U(e),
|
|
588
|
-
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
589
|
-
},
|
|
590
|
-
durationMs: U(e - i.t0Ms),
|
|
591
|
-
driver: ae(i.evidence),
|
|
592
|
-
participants: i.participants,
|
|
593
|
-
holds: {
|
|
594
|
-
kind: i.holdKind,
|
|
595
|
-
releasedAtMs: i.holdReleasedAtMs
|
|
596
|
-
},
|
|
597
|
-
frameSamples: ie(i.heldGaps, i.releasedGaps),
|
|
598
|
-
motion: {
|
|
599
|
-
sampledFrames: i.releasedFrames,
|
|
600
|
-
stalledFrames: i.stalledFrames,
|
|
601
|
-
longestStallMs: U(i.longestStallMs),
|
|
602
|
-
pausedAfterRelease: i.pausedAfterRelease,
|
|
603
|
-
holdReassertedAtMs: i.holdReassertedAtMs,
|
|
604
|
-
tailFrames: i.tailFrames
|
|
605
|
-
},
|
|
606
|
-
images: A(i),
|
|
607
|
-
...a ? { playerGaps: a } : {},
|
|
608
|
-
longTasks: [],
|
|
609
|
-
holdLongTasks: [],
|
|
610
|
-
landing: {
|
|
611
|
-
residualInlineTransforms: [],
|
|
612
|
-
offViewportAtRest: !1,
|
|
613
|
-
stuckStatuses: t,
|
|
614
|
-
orphanedHolds: []
|
|
615
|
-
},
|
|
616
|
-
anomalies: []
|
|
617
|
-
};
|
|
618
|
-
y.push(o), y.length > n && y.splice(0, y.length - n), t.length === 0 && ce(o, i.elements), r && console.info(`[flemo devtools] ${o.id} ${o.kind} driver=${o.driver} ${o.durationMs}ms screens=${o.participants.screens}`);
|
|
619
|
-
}, ye = (e) => {
|
|
620
|
-
let t = x;
|
|
1065
|
+
me(i.images, i.elements), E = null, i.rafId !== null && cancelAnimationFrame(i.rafId);
|
|
1066
|
+
let a = R(i, e, t, !1);
|
|
1067
|
+
C.push(a), C.length > n && C.splice(0, C.length - n), t.length === 0 && (se(a, i.elements), le(a, i)), r && console.info(`[flemo devtools] ${a.id} ${a.kind} driver=${a.driver} ${a.durationMs}ms screens=${a.participants.screens}`);
|
|
1068
|
+
}, B = (e) => {
|
|
1069
|
+
let t = E;
|
|
621
1070
|
if (!t || !(e.target instanceof Element)) return;
|
|
622
|
-
let n = e.target.getAttribute(
|
|
623
|
-
n !== null &&
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
1071
|
+
let n = e.target.getAttribute(m);
|
|
1072
|
+
if (n !== null && gt.has(n) && t.holdKind === null && (t.holdKind = n), n !== null && gt.has(n) && t.holdReleasedAtMs !== null && t.frames.holdReassertedAtMs === null) {
|
|
1073
|
+
let e = K(performance.now() - t.t0Ms);
|
|
1074
|
+
t.frames.holdReassertedAtMs = e, t.tripwires.push({
|
|
1075
|
+
kind: "hold-reassert",
|
|
1076
|
+
atMs: e,
|
|
1077
|
+
detail: "an animation hold was re-asserted after this flight had already released it — the motion pauses here while every timing metric stays clean"
|
|
1078
|
+
});
|
|
1079
|
+
}
|
|
1080
|
+
(n === "false" || n === null) && e.oldValue !== null && gt.has(e.oldValue) && t.holdReleasedAtMs === null && !oe(t.elements) && (t.holdReleasedAtMs = K(performance.now() - t.t0Ms));
|
|
1081
|
+
}, V = () => {
|
|
1082
|
+
let e = P();
|
|
1083
|
+
if (O.length > 0) {
|
|
1084
|
+
if (e.some((e) => O.includes(e))) return;
|
|
1085
|
+
O = [];
|
|
629
1086
|
}
|
|
630
|
-
if (!
|
|
631
|
-
|
|
1087
|
+
if (!E && e.length > 0) {
|
|
1088
|
+
ie(e);
|
|
632
1089
|
return;
|
|
633
1090
|
}
|
|
634
|
-
if (
|
|
635
|
-
|
|
1091
|
+
if (E && e.length === 0) {
|
|
1092
|
+
z(performance.now(), []);
|
|
636
1093
|
return;
|
|
637
1094
|
}
|
|
638
|
-
if (
|
|
639
|
-
},
|
|
1095
|
+
if (E) for (let t of e) E.elements.includes(t) || (E.elements.push(t), pe(E.images, E.elements, t.querySelectorAll("img")), E.participants = F(E.elements));
|
|
1096
|
+
}, be = null, H = null, Se = () => {
|
|
640
1097
|
let e = document.documentElement;
|
|
641
1098
|
if (!e) return !1;
|
|
642
1099
|
let t = new MutationObserver((e) => {
|
|
643
|
-
if (
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
1100
|
+
if (k) return;
|
|
1101
|
+
let t = performance.now();
|
|
1102
|
+
for (let n of e) n.type === "attributes" ? n.attributeName === "data-flemo-anim-hold" ? B(n) : E && (n.attributeName === "data-flemo-morph" || n.attributeName === "data-flemo-morph-camera") && n.target instanceof Element && ke(E.morphs, n.target) : (E && Ae(E.morphs, n, t), E && n.addedNodes.length > 0 && pe(E.images, E.elements, n.addedNodes));
|
|
1103
|
+
V();
|
|
647
1104
|
});
|
|
648
1105
|
try {
|
|
649
1106
|
t.observe(e, {
|
|
@@ -652,412 +1109,498 @@ var e = 30, t = 1e4, n = 50, r = 120, i = 100, a = (e) => {
|
|
|
652
1109
|
attributes: !0,
|
|
653
1110
|
attributeOldValue: !0,
|
|
654
1111
|
attributeFilter: [
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
1112
|
+
f,
|
|
1113
|
+
p,
|
|
1114
|
+
m,
|
|
1115
|
+
b,
|
|
1116
|
+
T
|
|
658
1117
|
]
|
|
659
1118
|
});
|
|
660
1119
|
} catch {
|
|
661
1120
|
return !1;
|
|
662
1121
|
}
|
|
663
|
-
return
|
|
1122
|
+
return be = t, V(), !0;
|
|
664
1123
|
};
|
|
665
|
-
if (!
|
|
1124
|
+
if (!Se()) {
|
|
666
1125
|
let e = () => {
|
|
667
|
-
|
|
1126
|
+
H = null, k || Se();
|
|
668
1127
|
};
|
|
669
|
-
|
|
1128
|
+
H = e, document.addEventListener("DOMContentLoaded", e, { once: !0 });
|
|
670
1129
|
}
|
|
671
|
-
let
|
|
672
|
-
|
|
1130
|
+
let Ce = () => {
|
|
1131
|
+
document.visibilityState === "hidden" && (M = !0, a && E === null && Ge(C, "3"));
|
|
1132
|
+
};
|
|
1133
|
+
document.addEventListener("visibilitychange", Ce);
|
|
1134
|
+
let we = () => {
|
|
1135
|
+
N = 0, !k && (E === null && Ge(C, "3"), N = window.setTimeout(we, bt));
|
|
1136
|
+
};
|
|
1137
|
+
a && (N = window.setTimeout(we, bt));
|
|
1138
|
+
let Te = (e) => {
|
|
1139
|
+
let t = x.filter((t) => t.startMs + t.durationMs >= e.t0.ms - 120 && t.startMs <= e.t1.ms), n = e.holds.kind === null ? e.t0.ms : e.holds.releasedAtMs === null ? e.t1.ms : e.t0.ms + e.holds.releasedAtMs;
|
|
673
1140
|
return {
|
|
674
1141
|
released: t.filter((e) => e.startMs + e.durationMs > n),
|
|
675
1142
|
held: t.filter((e) => e.startMs + e.durationMs <= n)
|
|
676
1143
|
};
|
|
677
|
-
},
|
|
678
|
-
let
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
holdLongTasks: t.held,
|
|
683
|
-
landing: {
|
|
684
|
-
residualInlineTransforms: [...e.landing.residualInlineTransforms],
|
|
685
|
-
offViewportAtRest: e.landing.offViewportAtRest,
|
|
686
|
-
stuckStatuses: [...e.landing.stuckStatuses],
|
|
687
|
-
orphanedHolds: [...e.landing.orphanedHolds]
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
return n.anomalies = a({
|
|
691
|
-
t0Ms: n.t0.ms,
|
|
692
|
-
t1Ms: n.t1.ms,
|
|
693
|
-
driver: n.driver,
|
|
694
|
-
frameSamples: n.frameSamples,
|
|
695
|
-
playerGaps: n.playerGaps ?? null,
|
|
696
|
-
longTasks: n.longTasks,
|
|
697
|
-
holdLongTasks: n.holdLongTasks,
|
|
698
|
-
releasedAtMs: n.holds.releasedAtMs,
|
|
699
|
-
landing: n.landing,
|
|
700
|
-
motion: n.motion,
|
|
701
|
-
images: n.images
|
|
702
|
-
}), n;
|
|
703
|
-
}), r = x;
|
|
704
|
-
if (!r) return n;
|
|
705
|
-
let i = e - r.t0Ms > t, o = {
|
|
706
|
-
id: `${r.id} (in flight)`,
|
|
707
|
-
...r.routerId === void 0 ? {} : { routerId: r.routerId },
|
|
708
|
-
kind: r.kind,
|
|
709
|
-
t0: {
|
|
710
|
-
ms: U(r.t0Ms),
|
|
711
|
-
iso: r.t0Iso
|
|
712
|
-
},
|
|
713
|
-
t1: {
|
|
714
|
-
ms: U(e),
|
|
715
|
-
iso: (/* @__PURE__ */ new Date()).toISOString()
|
|
716
|
-
},
|
|
717
|
-
durationMs: U(e - r.t0Ms),
|
|
718
|
-
driver: ae(r.evidence),
|
|
719
|
-
participants: r.participants,
|
|
720
|
-
holds: {
|
|
721
|
-
kind: r.holdKind,
|
|
722
|
-
releasedAtMs: r.holdReleasedAtMs
|
|
723
|
-
},
|
|
724
|
-
frameSamples: ie(r.heldGaps, r.releasedGaps),
|
|
725
|
-
motion: {
|
|
726
|
-
sampledFrames: r.releasedFrames,
|
|
727
|
-
stalledFrames: r.stalledFrames,
|
|
728
|
-
longestStallMs: U(r.longestStallMs),
|
|
729
|
-
pausedAfterRelease: r.pausedAfterRelease,
|
|
730
|
-
holdReassertedAtMs: r.holdReassertedAtMs,
|
|
731
|
-
tailFrames: r.tailFrames
|
|
732
|
-
},
|
|
733
|
-
images: A(r),
|
|
734
|
-
longTasks: [],
|
|
735
|
-
holdLongTasks: [],
|
|
1144
|
+
}, Ee = (e) => x.filter((t) => t.startMs >= d && !e.some((e) => t.startMs + t.durationMs >= e.t0.ms && t.startMs <= e.t1.ms)), De = (e) => {
|
|
1145
|
+
let t = Te(e), n = {
|
|
1146
|
+
...e,
|
|
1147
|
+
longTasks: t.released,
|
|
1148
|
+
holdLongTasks: t.held,
|
|
736
1149
|
landing: {
|
|
737
|
-
residualInlineTransforms: [],
|
|
738
|
-
offViewportAtRest:
|
|
739
|
-
stuckStatuses:
|
|
740
|
-
orphanedHolds: []
|
|
1150
|
+
residualInlineTransforms: [...e.landing.residualInlineTransforms],
|
|
1151
|
+
offViewportAtRest: e.landing.offViewportAtRest,
|
|
1152
|
+
stuckStatuses: [...e.landing.stuckStatuses],
|
|
1153
|
+
orphanedHolds: [...e.landing.orphanedHolds]
|
|
741
1154
|
},
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
longTasks:
|
|
751
|
-
holdLongTasks:
|
|
752
|
-
releasedAtMs:
|
|
753
|
-
landing:
|
|
754
|
-
motion:
|
|
755
|
-
images:
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
let
|
|
1155
|
+
morphs: { ...e.morphs },
|
|
1156
|
+
tripwires: [...e.tripwires]
|
|
1157
|
+
};
|
|
1158
|
+
return n.anomalies = o({
|
|
1159
|
+
t0Ms: n.t0.ms,
|
|
1160
|
+
t1Ms: n.t1.ms,
|
|
1161
|
+
driver: n.driver,
|
|
1162
|
+
frameSamples: n.frameSamples,
|
|
1163
|
+
longTasks: n.longTasks,
|
|
1164
|
+
holdLongTasks: n.holdLongTasks,
|
|
1165
|
+
releasedAtMs: n.holds.releasedAtMs,
|
|
1166
|
+
landing: n.landing,
|
|
1167
|
+
motion: n.motion,
|
|
1168
|
+
images: n.images,
|
|
1169
|
+
morphs: n.morphs,
|
|
1170
|
+
tripwires: n.tripwires
|
|
1171
|
+
}), n;
|
|
1172
|
+
}, je = () => {
|
|
1173
|
+
let e = C.map(De), n = E;
|
|
1174
|
+
if (!n) return e;
|
|
1175
|
+
let r = performance.now(), i = r - n.t0Ms > t;
|
|
1176
|
+
return [...e, De(R(n, r, i ? re(n) : [], !0))];
|
|
1177
|
+
}, U = (e) => {
|
|
1178
|
+
let t = /* @__PURE__ */ new Set(), n = 0, r = 0;
|
|
1179
|
+
for (let i of e) {
|
|
1180
|
+
n += i.input.trusted, r += i.input.synthetic;
|
|
1181
|
+
for (let e of i.input.pointerTypes) t.add(e);
|
|
1182
|
+
}
|
|
1183
|
+
return {
|
|
1184
|
+
trusted: n,
|
|
1185
|
+
synthetic: r,
|
|
1186
|
+
pointerTypes: [...t].sort()
|
|
1187
|
+
};
|
|
1188
|
+
}, Pe = () => {
|
|
1189
|
+
let e = Ve(), t = { ...e };
|
|
1190
|
+
for (let [n, r] of Object.entries(l)) n in e || (t[`${n} (at attach, since cleared)`] = r);
|
|
1191
|
+
let n = He(t), r = ne(g, I.sawAnimationEvent()), i = je(), a = E, o = it({
|
|
1192
|
+
environment: r,
|
|
1193
|
+
idleLongTasks: Ee(i),
|
|
1194
|
+
observedMs: performance.now() - d,
|
|
1195
|
+
wentHidden: M,
|
|
1196
|
+
documentHidden: document.visibilityState === "hidden",
|
|
1197
|
+
input: U(i)
|
|
1198
|
+
});
|
|
761
1199
|
return {
|
|
762
1200
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
763
|
-
version: "
|
|
1201
|
+
version: "3",
|
|
1202
|
+
verdict: pt({
|
|
1203
|
+
preconditions: o,
|
|
1204
|
+
flights: i,
|
|
1205
|
+
observation: r.observation
|
|
1206
|
+
}),
|
|
764
1207
|
environment: r,
|
|
1208
|
+
preconditions: o,
|
|
765
1209
|
overrides: {
|
|
766
1210
|
active: t,
|
|
767
1211
|
warnings: n
|
|
768
1212
|
},
|
|
769
1213
|
flights: i,
|
|
770
|
-
|
|
1214
|
+
comparison: u(i),
|
|
1215
|
+
previousSession: h,
|
|
1216
|
+
anomalies: s({
|
|
771
1217
|
emulationSuspected: r.emulationSuspected,
|
|
772
1218
|
platform: r.platform,
|
|
773
1219
|
stuckFlightOpen: a !== null && performance.now() - a.t0Ms > 1e4,
|
|
774
1220
|
flightAnomalies: i.map((e) => e.anomalies)
|
|
775
1221
|
}),
|
|
776
|
-
blindSpots: [...
|
|
777
|
-
judgingProtocol: [...
|
|
1222
|
+
blindSpots: [...c],
|
|
1223
|
+
judgingProtocol: [...ge]
|
|
778
1224
|
};
|
|
779
|
-
},
|
|
780
|
-
if (!
|
|
781
|
-
if (
|
|
782
|
-
let e =
|
|
1225
|
+
}, Fe = (e) => (D = e === null || e === "" ? null : e, D), W = () => {
|
|
1226
|
+
if (!k) {
|
|
1227
|
+
if (k = !0, be?.disconnect(), H !== null && (document.removeEventListener("DOMContentLoaded", H), H = null), document.removeEventListener("visibilitychange", Ce), I.detach(), S?.disconnect(), window.clearTimeout(N), N = 0, E?.rafId != null && cancelAnimationFrame(E.rafId), E = null, j) {
|
|
1228
|
+
let e = window;
|
|
783
1229
|
e.flemo?.__flemoDevtools === !0 && delete e.flemo;
|
|
784
1230
|
}
|
|
785
|
-
|
|
1231
|
+
xt = null;
|
|
786
1232
|
}
|
|
787
|
-
},
|
|
788
|
-
detach:
|
|
789
|
-
report:
|
|
1233
|
+
}, G = {
|
|
1234
|
+
detach: W,
|
|
1235
|
+
report: Pe,
|
|
1236
|
+
mark: Fe
|
|
790
1237
|
};
|
|
791
1238
|
if (i) {
|
|
792
|
-
let e =
|
|
1239
|
+
let e = window, t = e.flemo;
|
|
793
1240
|
(t === void 0 || t?.__flemoDevtools === !0) && (e.flemo = {
|
|
794
1241
|
__flemoDevtools: !0,
|
|
795
|
-
report:
|
|
796
|
-
flights:
|
|
797
|
-
|
|
798
|
-
|
|
1242
|
+
report: Pe,
|
|
1243
|
+
flights: je,
|
|
1244
|
+
mark: Fe,
|
|
1245
|
+
detach: W
|
|
1246
|
+
}, j = !0);
|
|
799
1247
|
}
|
|
800
|
-
return
|
|
801
|
-
},
|
|
1248
|
+
return xt = G, G;
|
|
1249
|
+
}, wt = O.map((e) => A(d) + j(f, e)).join(","), Tt = () => document.querySelector(wt) !== null, Et = (e) => {
|
|
1250
|
+
let t = document.createElement("div");
|
|
1251
|
+
t.setAttribute(D, ""), t.style.position = "fixed", t.style.top = "0", t.style.left = "0", t.style.width = "0", t.style.height = "0", t.style.zIndex = "2147483000";
|
|
1252
|
+
let n = t.attachShadow({ mode: "open" }), r = document.createElement("style");
|
|
1253
|
+
r.textContent = e, n.appendChild(r);
|
|
1254
|
+
let i = document.createElement("div");
|
|
1255
|
+
return i.className = "root", n.appendChild(i), {
|
|
1256
|
+
host: t,
|
|
1257
|
+
root: i
|
|
1258
|
+
};
|
|
1259
|
+
}, Dt = () => {}, Ot = (e) => {
|
|
1260
|
+
if (e) return {
|
|
1261
|
+
recorder: e,
|
|
1262
|
+
ownsRecorder: !1
|
|
1263
|
+
};
|
|
1264
|
+
let t = window.flemo;
|
|
1265
|
+
return t?.__flemoDevtools === !0 && typeof t.report == "function" ? {
|
|
1266
|
+
recorder: {
|
|
1267
|
+
report: t.report,
|
|
1268
|
+
detach: Dt,
|
|
1269
|
+
mark: t.mark ?? (() => null)
|
|
1270
|
+
},
|
|
1271
|
+
ownsRecorder: !1
|
|
1272
|
+
} : {
|
|
1273
|
+
recorder: Ct(),
|
|
1274
|
+
ownsRecorder: !0
|
|
1275
|
+
};
|
|
1276
|
+
}, kt = "http://www.w3.org/2000/svg", q = (e, t, n) => {
|
|
802
1277
|
let r = document.createElement(e);
|
|
803
1278
|
return t !== void 0 && (r.className = t), n !== void 0 && (r.textContent = n), r;
|
|
804
|
-
},
|
|
805
|
-
let n = document.createElementNS(
|
|
1279
|
+
}, At = (e, t) => {
|
|
1280
|
+
let n = document.createElementNS(kt, e);
|
|
806
1281
|
for (let [e, r] of Object.entries(t)) n.setAttribute(e, r);
|
|
807
1282
|
return n;
|
|
808
|
-
},
|
|
1283
|
+
}, jt = (e) => {
|
|
809
1284
|
for (; e.firstChild !== null;) e.removeChild(e.firstChild);
|
|
810
|
-
},
|
|
1285
|
+
}, Mt = (e, t) => {
|
|
811
1286
|
e.textContent !== t && (e.textContent = t);
|
|
812
|
-
},
|
|
1287
|
+
}, J = (e) => e == null || e === "" ? "—" : String(e), Y = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e)}ms` : "—", Nt = (e) => typeof e == "number" && Number.isFinite(e) ? `${Math.round(e * 10) / 10}ms` : "—", X = (e) => typeof e == "number" && Number.isFinite(e) ? String(e) : "—", Pt = (e) => e === !0 ? "yes" : e === !1 ? "no" : "—", Ft = (e) => {
|
|
813
1288
|
let t = e?.environment;
|
|
814
1289
|
if (!t) return "—";
|
|
815
1290
|
let n = t.viewport, r = n && typeof n.width == "number" && typeof n.height == "number" ? `${Math.round(n.width)}×${Math.round(n.height)}` : "—";
|
|
816
1291
|
return [
|
|
817
|
-
|
|
818
|
-
`dpr ${
|
|
1292
|
+
J(t.engine),
|
|
1293
|
+
`dpr ${J(t.devicePixelRatio)}`,
|
|
819
1294
|
r,
|
|
820
|
-
`rAF ${
|
|
1295
|
+
`rAF ${Nt(t.rafCadence?.medianGapMs)}`
|
|
821
1296
|
].join(" · ");
|
|
822
|
-
},
|
|
1297
|
+
}, It = (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(",")}`, Lt = (e) => {
|
|
823
1298
|
let t = e?.released?.gaps;
|
|
824
1299
|
if (!Array.isArray(t)) return null;
|
|
825
1300
|
let n = t.filter((e) => typeof e == "number" && Number.isFinite(e));
|
|
826
1301
|
return n.length >= 2 ? n : null;
|
|
827
|
-
},
|
|
828
|
-
let i =
|
|
829
|
-
i.appendChild(
|
|
1302
|
+
}, Rt = "\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.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", zt = 48, Z = (e, t, n, r) => {
|
|
1303
|
+
let i = q("div", "kv");
|
|
1304
|
+
i.appendChild(q("span", "k", t)), i.appendChild(q("span", r ? `v ${r}` : "v", n)), e.appendChild(i);
|
|
830
1305
|
}, Q = (e, t) => {
|
|
831
|
-
let n =
|
|
832
|
-
return n.appendChild(
|
|
1306
|
+
let n = q("section", "section");
|
|
1307
|
+
return n.appendChild(q("h2", void 0, t)), e.appendChild(n), n;
|
|
833
1308
|
}, $ = (e, t, n = "li") => {
|
|
834
|
-
e.appendChild(
|
|
835
|
-
},
|
|
836
|
-
|
|
837
|
-
for (let n of t?.
|
|
838
|
-
for (let n of t?.
|
|
839
|
-
for (let
|
|
840
|
-
|
|
841
|
-
|
|
1309
|
+
e.appendChild(q("div", n, t));
|
|
1310
|
+
}, Bt = (e, t) => {
|
|
1311
|
+
jt(e);
|
|
1312
|
+
for (let n of t?.verdict ?? []) e.appendChild(q("span", "chip lead", J(n)));
|
|
1313
|
+
for (let n of t?.preconditions ?? []) n?.status === "violated" && e.appendChild(q("span", "chip bad", `${n.id}: ${J(n.detail)}`));
|
|
1314
|
+
for (let n of t?.overrides?.warnings ?? []) e.appendChild(q("span", "chip warn", J(n)));
|
|
1315
|
+
for (let n of t?.anomalies ?? []) e.appendChild(q("span", "chip bad", J(n)));
|
|
1316
|
+
for (let [n, r] of Object.entries(t?.overrides?.active ?? {})) e.appendChild(q("span", "chip", `${n}=${String(r)}`));
|
|
1317
|
+
}, Vt = (e, t, n, r) => {
|
|
1318
|
+
if (jt(e), t.length === 0) {
|
|
842
1319
|
$(e, "no flights recorded yet — navigate once", "li dim");
|
|
843
1320
|
return;
|
|
844
1321
|
}
|
|
845
1322
|
for (let i = t.length - 1; i >= 0; --i) {
|
|
846
|
-
let a = t[i], o =
|
|
847
|
-
s.type = "button", s.setAttribute("data-flight-id", o), s.setAttribute("aria-selected", String(o === n)), s.appendChild(
|
|
1323
|
+
let a = t[i], o = J(a?.id), s = q("button", "row");
|
|
1324
|
+
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`));
|
|
848
1325
|
let c = a?.anomalies?.length ?? 0;
|
|
849
|
-
s.appendChild(
|
|
1326
|
+
s.appendChild(q("span", c > 0 ? "n bad" : "n", String(c))), s.addEventListener("click", () => r(o)), e.appendChild(s);
|
|
850
1327
|
}
|
|
851
|
-
},
|
|
1328
|
+
}, Ht = (e, t, n) => {
|
|
852
1329
|
if (!n) {
|
|
853
1330
|
Z(e, t, "—");
|
|
854
1331
|
return;
|
|
855
1332
|
}
|
|
856
1333
|
let r = [
|
|
857
1334
|
`${X(n.count)} frames`,
|
|
858
|
-
`median ${
|
|
859
|
-
`max ${
|
|
1335
|
+
`median ${Nt(n.medianGapMs)}`,
|
|
1336
|
+
`max ${Nt(n.maxGapMs)}`
|
|
860
1337
|
];
|
|
861
1338
|
typeof n.over30Count == "number" && r.push(`>30ms ×${n.over30Count}`), Z(e, t, r.join(" · "));
|
|
862
|
-
},
|
|
863
|
-
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 =
|
|
1339
|
+
}, Ut = (e) => {
|
|
1340
|
+
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 = At("svg", {
|
|
864
1341
|
class: "spark",
|
|
865
1342
|
viewBox: "0 0 100 28",
|
|
866
1343
|
preserveAspectRatio: "none",
|
|
867
1344
|
"aria-hidden": "true"
|
|
868
1345
|
});
|
|
869
|
-
return a.appendChild(
|
|
1346
|
+
return a.appendChild(At("polyline", {
|
|
870
1347
|
points: i,
|
|
871
1348
|
fill: "none",
|
|
872
1349
|
stroke: "currentColor",
|
|
873
1350
|
"stroke-width": "1",
|
|
874
1351
|
"vector-effect": "non-scaling-stroke"
|
|
875
1352
|
})), a;
|
|
876
|
-
},
|
|
1353
|
+
}, Wt = (e, t) => {
|
|
877
1354
|
let n = t.longTasks ?? [], r = t.holdLongTasks ?? [];
|
|
878
1355
|
if (n.length === 0 && r.length === 0) {
|
|
879
1356
|
$(e, "none", "li dim");
|
|
880
1357
|
return;
|
|
881
1358
|
}
|
|
882
|
-
let i = (e) => `${
|
|
1359
|
+
let i = (e) => `${Y(e?.startMs)} + ${Y(e?.durationMs)}`;
|
|
883
1360
|
for (let t of n) $(e, i(t), "li bad");
|
|
884
1361
|
for (let t of r) $(e, `${i(t)} (absorbed by hold)`, "li dim");
|
|
885
|
-
},
|
|
886
|
-
if (
|
|
1362
|
+
}, Gt = (e, t) => {
|
|
1363
|
+
if (jt(e), !t) {
|
|
887
1364
|
$(e, "select a flight", "li dim");
|
|
888
1365
|
return;
|
|
889
1366
|
}
|
|
890
1367
|
let n = Q(e, "timing");
|
|
891
|
-
Z(n, "id",
|
|
1368
|
+
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)}`);
|
|
892
1369
|
let r = Q(e, "frames");
|
|
893
|
-
|
|
894
|
-
let i =
|
|
895
|
-
i && r.appendChild(
|
|
1370
|
+
Ht(r, "held (absorbed)", t.frameSamples?.held), Ht(r, "released (visible)", t.frameSamples?.released);
|
|
1371
|
+
let i = Lt(t.frameSamples);
|
|
1372
|
+
i && r.appendChild(Ut(i));
|
|
896
1373
|
let a = Q(e, "motion (did it move)"), o = t.motion?.longestStallMs, s = t.motion?.holdReassertedAtMs;
|
|
897
|
-
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",
|
|
898
|
-
let c =
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
let
|
|
910
|
-
if (
|
|
911
|
-
|
|
1374
|
+
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) >= zt ? "bad" : void 0), Z(a, "paused after release", Pt(t.motion?.pausedAfterRelease), t.motion?.pausedAfterRelease === !0 ? "bad" : void 0), Z(a, "hold re-asserted", s == null ? "no" : Y(s), typeof s == "number" ? "bad" : void 0), Z(a, "first animation", t.motion?.firstAnimationAtMs === null || t.motion?.firstAnimationAtMs === void 0 ? "not observed" : `+${Y(t.motion.firstAnimationAtMs)} after t0`);
|
|
1375
|
+
let c = t.morphs;
|
|
1376
|
+
if (c) {
|
|
1377
|
+
let t = Q(e, "shared elements");
|
|
1378
|
+
Z(t, "registered", X(c.registered)), Z(t, "pairable / flew", `${X(c.pairable?.length)} · ${X(c.flew?.length)}`);
|
|
1379
|
+
let n = c.skipped ?? [];
|
|
1380
|
+
Z(t, "did not fly", n.length === 0 ? "none" : n.join(", "), n.length > 0 ? "bad" : void 0);
|
|
1381
|
+
let r = c.duplicatedKeys ?? [];
|
|
1382
|
+
r.length > 0 && Z(t, "duplicate keys in one screen", r.join(", "), "bad"), Z(t, "camera", Pt(c.camera)), Z(t, "ghosts", X(c.ghosts));
|
|
1383
|
+
let i = (c.strandedRoles ?? 0) + (c.strandedStandIns ?? 0) + (c.strandedGhosts ?? 0) + (c.layerResidue ?? 0) + (c.leakedSheetRules ?? 0);
|
|
1384
|
+
Z(t, "residue at rest", i === 0 ? "clean" : `${X(c.strandedRoles)} roles · ${X(c.strandedStandIns)} stand-ins · ${X(c.strandedGhosts)} ghosts · ${X(c.layerResidue)} in layer · ${X(c.leakedSheetRules)} rules`, i > 0 ? "bad" : void 0);
|
|
1385
|
+
}
|
|
1386
|
+
let l = t.tripwires ?? [];
|
|
1387
|
+
if (l.length > 0) {
|
|
1388
|
+
let t = Q(e, "tripwires (one-frame events)");
|
|
1389
|
+
for (let e of l) $(t, `+${Y(e.atMs)} ${e.kind}: ${e.detail}`, "li bad");
|
|
1390
|
+
}
|
|
1391
|
+
let u = t.input;
|
|
1392
|
+
if (u) {
|
|
1393
|
+
let t = Q(e, "what drove it");
|
|
1394
|
+
Z(t, "input", `${X(u.trusted)} trusted · ${X(u.synthetic)} synthetic`, u.synthetic > 0 ? "bad" : void 0), Z(t, "pointer types", u.pointerTypes?.join(", ") || "none observed");
|
|
1395
|
+
}
|
|
1396
|
+
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;
|
|
1397
|
+
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), Wt(Q(e, "long tasks"), t);
|
|
1398
|
+
let g = Q(e, "landing"), _ = t.landing?.residualInlineTransforms ?? [];
|
|
1399
|
+
if (_.length === 0) Z(g, "inline residue", "clean");
|
|
1400
|
+
else for (let e of _) Z(g, "inline residue", J(e));
|
|
1401
|
+
Z(g, "off-viewport at rest", Pt(t.landing?.offViewportAtRest));
|
|
1402
|
+
let v = t.landing?.stuckStatuses ?? [];
|
|
1403
|
+
Z(g, "stuck statuses", v.length === 0 ? "none" : v.join(", "));
|
|
1404
|
+
let y = t.landing?.orphanedHolds ?? [];
|
|
1405
|
+
if (y.length === 0) Z(g, "orphaned holds", "none");
|
|
1406
|
+
else for (let e of y) Z(g, "orphaned holds", J(e), "bad");
|
|
1407
|
+
let b = Q(e, "anomalies"), x = t.anomalies ?? [];
|
|
1408
|
+
if (x.length === 0) {
|
|
1409
|
+
$(b, "none", "li dim");
|
|
912
1410
|
return;
|
|
913
1411
|
}
|
|
914
|
-
for (let e of
|
|
915
|
-
},
|
|
916
|
-
|
|
917
|
-
for (let n of t ?? []) $(e,
|
|
918
|
-
},
|
|
919
|
-
if (
|
|
920
|
-
if (typeof document > "u") return { detach:
|
|
921
|
-
let
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
let d = W("section", "panel");
|
|
937
|
-
d.hidden = !0;
|
|
938
|
-
let f = W("div", "grip");
|
|
939
|
-
f.setAttribute("role", "separator"), f.setAttribute("aria-label", "Resize flemo devtools panel");
|
|
940
|
-
let p = W("header", "head"), m = W("div", "env", "—"), h = W("button", "act", Le);
|
|
1412
|
+
for (let e of x) $(b, J(e), "li bad");
|
|
1413
|
+
}, Kt = (e, t) => {
|
|
1414
|
+
jt(e);
|
|
1415
|
+
for (let n of t ?? []) $(e, J(n));
|
|
1416
|
+
}, qt = 320, Jt = 2e3, Yt = 120, Xt = "Copy report JSON", Zt = () => {}, Qt = null, $t = (e = {}) => {
|
|
1417
|
+
if (Qt) return Qt;
|
|
1418
|
+
if (typeof document > "u") return { detach: Zt };
|
|
1419
|
+
let { recorder: t, ownsRecorder: n } = Ot(e.recorder), { host: r, root: i } = Et(Rt), a = q("button", "toggle");
|
|
1420
|
+
a.type = "button", a.setAttribute("data-corner", e.position ?? "bottom-right"), a.setAttribute("aria-label", "flemo devtools");
|
|
1421
|
+
let o = q("span", "count", "0"), s = q("span", "dot");
|
|
1422
|
+
s.hidden = !0, a.appendChild(q("span", "mark", "flemo")), a.appendChild(o), a.appendChild(s);
|
|
1423
|
+
let c = q("section", "panel");
|
|
1424
|
+
c.hidden = !0;
|
|
1425
|
+
let l = q("div", "grip");
|
|
1426
|
+
l.setAttribute("role", "separator"), l.setAttribute("aria-label", "Resize flemo devtools panel");
|
|
1427
|
+
let u = q("header", "head"), d = q("div", "env", "—"), f = q("button", "act", Xt);
|
|
1428
|
+
f.type = "button";
|
|
1429
|
+
let p = q("button", "act", "Close");
|
|
1430
|
+
p.type = "button";
|
|
1431
|
+
let m = q("button", "act", "Detach");
|
|
1432
|
+
m.type = "button";
|
|
1433
|
+
let h = q("button", "act", "A/B: off");
|
|
941
1434
|
h.type = "button";
|
|
942
|
-
let g =
|
|
943
|
-
|
|
944
|
-
let v =
|
|
945
|
-
v.
|
|
946
|
-
let
|
|
947
|
-
|
|
948
|
-
let
|
|
949
|
-
|
|
950
|
-
let
|
|
951
|
-
C.appendChild(W("summary", void 0, "What this cannot see"));
|
|
952
|
-
let te = W("div");
|
|
953
|
-
C.appendChild(te), S.appendChild(C), d.appendChild(f), d.appendChild(p), d.appendChild(b), d.appendChild(S), s.appendChild(c), s.appendChild(d);
|
|
954
|
-
let w = !1, T = e.initialOpen === !0, E = null, O = "", k = "", A = "", j = !1, M = 0, N = 0, P = (e) => Math.min(Math.max(e, Ie), Math.max(Ie, window.innerHeight * .9)), ne = () => {
|
|
1435
|
+
let g = q("div", "chips");
|
|
1436
|
+
u.appendChild(d), u.appendChild(q("div", "spacer")), u.appendChild(h), u.appendChild(f), u.appendChild(p), u.appendChild(m), u.appendChild(g);
|
|
1437
|
+
let _ = q("div", "body"), v = q("div", "list"), y = q("div", "detail");
|
|
1438
|
+
_.appendChild(v), _.appendChild(y);
|
|
1439
|
+
let b = q("div", "foot"), x = q("details");
|
|
1440
|
+
x.appendChild(q("summary", void 0, "What this cannot see"));
|
|
1441
|
+
let S = q("div");
|
|
1442
|
+
x.appendChild(S), b.appendChild(x), c.appendChild(l), c.appendChild(u), c.appendChild(_), c.appendChild(b), i.appendChild(a), i.appendChild(c);
|
|
1443
|
+
let C = !1, w = e.initialOpen === !0, T = null, E = "", D = "", O = "", k = !1, A = 0, j = 0, M = -1, N = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], P = (e) => Math.min(Math.max(e, Yt), Math.max(Yt, window.innerHeight * .9)), ee = () => {
|
|
955
1444
|
try {
|
|
956
|
-
let e = sessionStorage.getItem(
|
|
1445
|
+
let e = sessionStorage.getItem(U);
|
|
957
1446
|
if (e === null) return null;
|
|
958
1447
|
let t = Number.parseFloat(e);
|
|
959
1448
|
return Number.isFinite(t) ? t : null;
|
|
960
1449
|
} catch {
|
|
961
1450
|
return null;
|
|
962
1451
|
}
|
|
963
|
-
},
|
|
1452
|
+
}, te = (e) => {
|
|
964
1453
|
try {
|
|
965
|
-
sessionStorage.setItem(
|
|
1454
|
+
sessionStorage.setItem(U, String(Math.round(e)));
|
|
966
1455
|
} catch {}
|
|
967
|
-
}, F = P(
|
|
968
|
-
|
|
969
|
-
let I = () =>
|
|
1456
|
+
}, F = P(ee() ?? window.innerHeight * .4);
|
|
1457
|
+
c.style.height = `${Math.round(F)}px`;
|
|
1458
|
+
let I = () => {
|
|
970
1459
|
try {
|
|
971
|
-
return
|
|
1460
|
+
return t.report();
|
|
972
1461
|
} catch {
|
|
973
1462
|
return null;
|
|
974
1463
|
}
|
|
975
|
-
},
|
|
976
|
-
e !==
|
|
977
|
-
},
|
|
978
|
-
let e =
|
|
979
|
-
|
|
1464
|
+
}, ne = (e) => {
|
|
1465
|
+
e !== T && (T = e, L());
|
|
1466
|
+
}, re = () => {
|
|
1467
|
+
let e = I(), t = e?.flights ?? [];
|
|
1468
|
+
Mt(o, String(t.length));
|
|
980
1469
|
let n = t.some((e) => (e?.anomalies?.length ?? 0) > 0);
|
|
981
|
-
if (
|
|
982
|
-
|
|
1470
|
+
if (s.hidden = !n, c.hidden = !w, !w) return;
|
|
1471
|
+
Mt(d, Ft(e));
|
|
983
1472
|
let r = JSON.stringify([
|
|
984
1473
|
e?.overrides?.warnings ?? [],
|
|
985
1474
|
e?.anomalies ?? [],
|
|
986
1475
|
e?.overrides?.active ?? {}
|
|
987
1476
|
]);
|
|
988
|
-
r !==
|
|
989
|
-
let i =
|
|
990
|
-
i !==
|
|
991
|
-
let a = t.find((e) => e?.id ===
|
|
992
|
-
|
|
1477
|
+
r !== O && (O = r, Bt(g, e)), T === null && t.length > 0 && (T = t[t.length - 1]?.id ?? null);
|
|
1478
|
+
let i = It(t, T);
|
|
1479
|
+
i !== E && (E = i, Vt(v, t, T, ne));
|
|
1480
|
+
let a = t.find((e) => e?.id === T) ?? null, l = JSON.stringify(a);
|
|
1481
|
+
l !== D && (D = l, Gt(y, a)), k || (k = !0, Kt(S, e?.blindSpots));
|
|
993
1482
|
};
|
|
994
|
-
function
|
|
995
|
-
|
|
1483
|
+
function L() {
|
|
1484
|
+
C || Tt() || re();
|
|
996
1485
|
}
|
|
997
|
-
function
|
|
998
|
-
|
|
1486
|
+
function ie() {
|
|
1487
|
+
A = 0, L(), ae();
|
|
999
1488
|
}
|
|
1000
|
-
function
|
|
1001
|
-
|
|
1489
|
+
function ae() {
|
|
1490
|
+
A = window.setTimeout(ie, w ? qt : Jt);
|
|
1002
1491
|
}
|
|
1003
|
-
let
|
|
1004
|
-
window.clearTimeout(
|
|
1005
|
-
},
|
|
1006
|
-
|
|
1492
|
+
let oe = () => {
|
|
1493
|
+
window.clearTimeout(A), ae();
|
|
1494
|
+
}, se = (e) => {
|
|
1495
|
+
w = e, oe(), L();
|
|
1007
1496
|
};
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1497
|
+
a.addEventListener("click", () => se(!w)), p.addEventListener("click", () => se(!1)), m.addEventListener("click", () => z()), h.addEventListener("click", () => {
|
|
1498
|
+
M = M + 1 >= N.length ? -1 : M + 1;
|
|
1499
|
+
let e = M === -1 ? null : N[M];
|
|
1500
|
+
t.mark(e), Mt(h, `A/B: ${e ?? "off"}`), O = "", L();
|
|
1501
|
+
});
|
|
1502
|
+
let ce = () => {
|
|
1503
|
+
if (!C) {
|
|
1504
|
+
if (Tt()) {
|
|
1505
|
+
window.clearTimeout(j), j = window.setTimeout(ce, qt);
|
|
1013
1506
|
return;
|
|
1014
1507
|
}
|
|
1015
|
-
|
|
1508
|
+
Mt(f, "Copied ✓"), window.clearTimeout(j), j = window.setTimeout(le, 1200);
|
|
1016
1509
|
}
|
|
1017
1510
|
};
|
|
1018
|
-
function
|
|
1019
|
-
if (
|
|
1020
|
-
|
|
1511
|
+
function le() {
|
|
1512
|
+
if (Tt()) {
|
|
1513
|
+
j = window.setTimeout(le, qt);
|
|
1021
1514
|
return;
|
|
1022
1515
|
}
|
|
1023
|
-
|
|
1516
|
+
j = 0, Mt(f, Xt);
|
|
1024
1517
|
}
|
|
1025
|
-
let
|
|
1026
|
-
if (
|
|
1027
|
-
if (
|
|
1028
|
-
window.clearTimeout(
|
|
1518
|
+
let ue = (e) => {
|
|
1519
|
+
if (C) return;
|
|
1520
|
+
if (Tt()) {
|
|
1521
|
+
window.clearTimeout(j), j = window.setTimeout(() => ue(e), qt);
|
|
1029
1522
|
return;
|
|
1030
1523
|
}
|
|
1031
|
-
let t =
|
|
1524
|
+
let t = q("textarea");
|
|
1032
1525
|
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();
|
|
1033
1526
|
let n = document;
|
|
1034
1527
|
try {
|
|
1035
1528
|
n.execCommand?.("copy");
|
|
1036
1529
|
} catch {}
|
|
1037
|
-
t.remove(),
|
|
1530
|
+
t.remove(), ce();
|
|
1038
1531
|
};
|
|
1039
|
-
|
|
1040
|
-
let e = JSON.stringify(
|
|
1532
|
+
f.addEventListener("click", () => {
|
|
1533
|
+
let e = JSON.stringify(I(), null, 2), t = navigator.clipboard;
|
|
1041
1534
|
if (t && typeof t.writeText == "function") {
|
|
1042
|
-
t.writeText(e).then(
|
|
1535
|
+
t.writeText(e).then(ce, () => ue(e));
|
|
1043
1536
|
return;
|
|
1044
1537
|
}
|
|
1045
|
-
|
|
1538
|
+
ue(e);
|
|
1046
1539
|
});
|
|
1047
|
-
let
|
|
1048
|
-
F = P(window.innerHeight - e.clientY),
|
|
1049
|
-
},
|
|
1050
|
-
window.removeEventListener("pointermove",
|
|
1540
|
+
let de = (e) => {
|
|
1541
|
+
F = P(window.innerHeight - e.clientY), c.style.height = `${Math.round(F)}px`;
|
|
1542
|
+
}, R = () => {
|
|
1543
|
+
window.removeEventListener("pointermove", de), window.removeEventListener("pointerup", R), te(F);
|
|
1051
1544
|
};
|
|
1052
|
-
|
|
1053
|
-
e.preventDefault(), window.addEventListener("pointermove",
|
|
1545
|
+
l.addEventListener("pointerdown", (e) => {
|
|
1546
|
+
e.preventDefault(), window.addEventListener("pointermove", de), window.addEventListener("pointerup", R);
|
|
1054
1547
|
});
|
|
1055
|
-
function
|
|
1056
|
-
|
|
1548
|
+
function z() {
|
|
1549
|
+
C || (C = !0, window.clearTimeout(A), A = 0, window.clearTimeout(j), j = 0, window.removeEventListener("pointermove", de), window.removeEventListener("pointerup", R), r.remove(), n && t.detach(), Qt = null);
|
|
1057
1550
|
}
|
|
1058
|
-
document.body.appendChild(
|
|
1059
|
-
let fe = { detach:
|
|
1060
|
-
return
|
|
1551
|
+
document.body.appendChild(r), L(), ae();
|
|
1552
|
+
let fe = { detach: z };
|
|
1553
|
+
return Qt = fe, fe;
|
|
1554
|
+
}, en = 500, tn = 450, nn = "\n:host { all: initial; }\n.root { all: initial; }\n.hud {\n position: fixed;\n left: 50%;\n transform: translateX(-50%);\n max-width: calc(100vw - 16px);\n box-sizing: border-box;\n padding: 6px 10px;\n border-radius: 8px;\n background: #0b0f14;\n color: #e8f0f8;\n border: 1px solid #2b3a4a;\n font: 500 12px/1.45 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\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[data-edge=\"top\"] { top: max(8px, env(safe-area-inset-top)); }\n.hud[data-edge=\"bottom\"] { bottom: max(8px, env(safe-area-inset-bottom)); }\n.hud[data-alarm=\"true\"] { border-color: #ff6b6b; color: #ffd9d9; }\n.hud[data-blocked=\"true\"] { border-color: #ffb020; color: #ffe9c2; }\n", rn = (e) => Math.round(e * 10) / 10, an = (e) => {
|
|
1555
|
+
if (!e) return "flemo no flight yet";
|
|
1556
|
+
let t = e.frameSamples?.released, n = e.anomalies?.length ?? 0;
|
|
1557
|
+
return `${e.kind} ${Math.round(e.durationMs)}ms gap ${rn(t?.maxGapMs ?? 0)} drop ${t?.over30Count ?? 0}` + (n > 0 ? ` !${n}` : " ok") + (e.bucket ? ` [${e.bucket}]` : "");
|
|
1558
|
+
}, on = (e, t) => {
|
|
1559
|
+
let n = [], r = (e?.preconditions ?? []).filter((e) => e.status === "violated");
|
|
1560
|
+
if (r.length > 0 && n.push(`BLOCKED ${r.map((e) => e.id).join(" ")}`), !t) return n.push(`rAF ${rn(e?.environment?.rafCadence?.medianGapMs ?? 0)}ms`), n;
|
|
1561
|
+
let i = t.frameSamples;
|
|
1562
|
+
n.push(`frames n${i?.released?.count ?? 0} med ${rn(i?.released?.medianGapMs ?? 0)} max ${rn(i?.released?.maxGapMs ?? 0)}`), n.push(`motion stall ${rn(t.motion?.longestStallMs ?? 0)}ms tail ${t.motion?.tailFrames ?? 0} start +${t.motion?.firstAnimationAtMs ?? "?"}ms`), n.push(`hold ${t.holds?.kind ?? "none"} rel ${t.holds?.releasedAtMs ?? "-"}ms task ${t.longTasks?.length ?? 0}`);
|
|
1563
|
+
let a = t.morphs;
|
|
1564
|
+
a && (a.pairable.length > 0 || a.flew.length > 0) && n.push(`morph ${a.flew.length} flew` + (a.camera ? " cam" : "") + (a.skipped.length > 0 ? ` SKIPPED ${a.skipped.length} (${a.skipped.join(",")})` : ""));
|
|
1565
|
+
let o = t.input;
|
|
1566
|
+
o && n.push(`input ${o.pointerTypes.join("/") || "none"}` + (o.synthetic > 0 ? ` SYNTHETIC ${o.synthetic}` : ""));
|
|
1567
|
+
for (let e of t.anomalies ?? []) n.push(`! ${e.slice(0, 120)}`);
|
|
1568
|
+
return n;
|
|
1569
|
+
}, sn = null, cn = (e = {}) => {
|
|
1570
|
+
if (sn) return sn;
|
|
1571
|
+
if (typeof document > "u") return { detach: () => {} };
|
|
1572
|
+
let { recorder: t, ownsRecorder: n } = Ot(e.recorder), r = e.buckets && e.buckets.length > 0 ? e.buckets : ["A", "B"], { host: i, root: a } = Et(nn), o = document.createElement("div");
|
|
1573
|
+
o.className = "hud", o.setAttribute("data-edge", e.position ?? "top"), o.setAttribute("role", "status"), o.textContent = "flemo attaching", a.appendChild(o);
|
|
1574
|
+
let s = !1, c = e.initialExpanded === !0, l = -1, u = 0, d = 0, f = !1, p = "", m = () => {
|
|
1575
|
+
try {
|
|
1576
|
+
return t.report();
|
|
1577
|
+
} catch {
|
|
1578
|
+
return null;
|
|
1579
|
+
}
|
|
1580
|
+
}, h = () => {
|
|
1581
|
+
if (s || Tt()) return;
|
|
1582
|
+
let e = m(), t = e?.flights ?? [], n = t[t.length - 1], r = [an(n)];
|
|
1583
|
+
c && r.push(...on(e, n));
|
|
1584
|
+
let i = r.join("\n"), a = (e?.preconditions ?? []).some((e) => e.status === "violated"), l = (n?.anomalies?.length ?? 0) > 0;
|
|
1585
|
+
i !== p && (p = i, o.textContent = i), o.setAttribute("data-alarm", l ? "true" : "false"), o.setAttribute("data-blocked", a ? "true" : "false");
|
|
1586
|
+
}, g = () => {
|
|
1587
|
+
u = 0, h(), u = window.setTimeout(g, en);
|
|
1588
|
+
}, _ = () => {
|
|
1589
|
+
l = l + 1 >= r.length ? -1 : l + 1, t.mark(l === -1 ? null : r[l]), p = "", h();
|
|
1590
|
+
};
|
|
1591
|
+
o.addEventListener("pointerdown", () => {
|
|
1592
|
+
f = !1, window.clearTimeout(d), d = window.setTimeout(() => {
|
|
1593
|
+
f = !0, _();
|
|
1594
|
+
}, tn);
|
|
1595
|
+
}), o.addEventListener("pointerup", () => {
|
|
1596
|
+
window.clearTimeout(d), d = 0, !f && (c = !c, p = "", h());
|
|
1597
|
+
}), o.addEventListener("pointercancel", () => window.clearTimeout(d));
|
|
1598
|
+
let v = () => {
|
|
1599
|
+
s || (s = !0, window.clearTimeout(u), u = 0, window.clearTimeout(d), d = 0, i.remove(), n && t.detach(), sn = null);
|
|
1600
|
+
};
|
|
1601
|
+
document.body.appendChild(i), h(), u = window.setTimeout(g, en);
|
|
1602
|
+
let y = { detach: v };
|
|
1603
|
+
return sn = y, y;
|
|
1061
1604
|
};
|
|
1062
1605
|
//#endregion
|
|
1063
|
-
export {
|
|
1606
|
+
export { c as BLIND_SPOTS, Fe as CORE_FLAGS, Pe as DEVTOOLS_OWNED_FLAGS, W as FLAG_REGISTRY, ge as JUDGING_PROTOCOL, e as LONG_GAP_MS, i as MID_FLIGHT_TASK_MS, n as OPENING_WINDOW_LEAD_MS, r as OPENING_WINDOW_TAIL_MS, U as PANEL_HEIGHT_KEY, mt as REPORT_SCHEMA_VERSION, G as RETIRED_FLAGS, Ie as RETIRED_MARKER, a as STALL_MS, t as STUCK_STATUS_MS, Ue as TRACE_KEY, cn as attachDevtoolsHud, $t as attachDevtoolsPanel, Ct as attachFlightRecorder, ne as captureEnvironment, ve as classifyDriver, Ke as clearTrace, _e as computeFrameStats, V as computePhaseStats, o as deriveFlightAnomalies, He as deriveOverrideWarnings, it as derivePreconditions, s as deriveReportAnomalies, pt as deriveVerdict, N as detectEngine, F as developmentHints, P as isEmulationSuspected, ye as kindFromStatus, qe as loadTrace, be as parseTranslateX, ee as sampleRafCadence, Ge as saveTrace, Ve as snapshotOverrides, u as summariseBuckets };
|