@aura3d/debug 4.0.7 → 4.1.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/dist/index.d.ts CHANGED
@@ -28,4 +28,6 @@ export { buildAxesHelper, buildBoundsHelper, buildCameraFrustumHelper, buildDire
28
28
  export type { AxesHelperOptions, BoundsHelperOptions, CameraFrustumHelperOptions, DebugColor, DebugVec3, DirectionalLightHelperOptions, GridHelperOptions, SkeletonHelperJoint } from "./SceneHelpers.js";
29
29
  export { ReportExporter } from "./ReportExporter.js";
30
30
  export type { DebugReport } from "./ReportExporter.js";
31
+ export { DEFAULT_HEAL_LADDER, DEFAULT_HEAL_STORAGE_KEY, createBlackFrameWatch, formatEngineSection, formatGpuProbe, healParams, healRungName, healStage, installDiagnosticsPanel, installSafetyNet, isBlackFrame, probeGpu, resolveQualitySwitches } from "./safety/index.js";
32
+ export type { BlackFrameWatch, BlackFrameWatchOptions, DiagnosticsAppLike, DiagnosticsPanelHandle, DiagnosticsPanelOptions, GpuProbe, HealRung, QualitySwitches, ResolveQualitySwitchesOptions, SafetyNet, SafetyNetOptions, SafetyReport, SafetySettings } from "./safety/index.js";
31
33
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/debug/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AACvF,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AACxG,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAClF,YAAY,EAAE,sBAAsB,EAAE,MAAM,wBAAwB,CAAC;AACrE,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AACxF,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAC3F,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACtH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,YAAY,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,mBAAmB,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AACzF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,YAAY,EAAE,WAAW,EAAE,gBAAgB,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AACxG,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAC1E,YAAY,EAAE,kBAAkB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,oBAAoB,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AACvE,YAAY,EAAE,8BAA8B,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AACjI,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,iBAAiB,EACjB,mBAAmB,EACnB,0BAA0B,EAC1B,UAAU,EACV,SAAS,EACT,6BAA6B,EAC7B,iBAAiB,EACjB,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../packages/debug/src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -13,4 +13,5 @@ export { DebugOverlay } from "./DebugOverlay.js";
13
13
  export { DebugLineCanvasRenderer } from "./DebugLineCanvasRenderer.js";
14
14
  export { buildAxesHelper, buildBoundsHelper, buildCameraFrustumHelper, buildDirectionalLightHelper, buildGridHelper, buildSkeletonHelper } from "./SceneHelpers.js";
15
15
  export { ReportExporter } from "./ReportExporter.js";
16
+ export { DEFAULT_HEAL_LADDER, DEFAULT_HEAL_STORAGE_KEY, createBlackFrameWatch, formatEngineSection, formatGpuProbe, healParams, healRungName, healStage, installDiagnosticsPanel, installSafetyNet, isBlackFrame, probeGpu, resolveQualitySwitches } from "./safety/index.js";
16
17
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/debug/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../packages/debug/src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAEvD,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,2BAA2B,CAAC;AAEvF,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAElF,OAAO,EAAE,uBAAuB,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAExF,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAE7D,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAE1E,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,OAAO,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAEvE,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,wBAAwB,EACxB,2BAA2B,EAC3B,eAAe,EACf,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAW3B,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAErD,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,qBAAqB,EACrB,mBAAmB,EACnB,cAAc,EACd,UAAU,EACV,YAAY,EACZ,SAAS,EACT,uBAAuB,EACvB,gBAAgB,EAChB,YAAY,EACZ,QAAQ,EACR,sBAAsB,EACvB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * Black-frame self-heal. Some GPU/driver combinations present a frame that is entirely black while the engine reports
3
+ * draw calls. When that persists the page reloads itself one rung down a compatibility ladder (each rung switches off
4
+ * one more optional stage) and records the rung, so a player still gets a picture and the diagnostics panel shows which
5
+ * rung fixed it. Opt-in only: nothing here runs unless `installSafetyNet` (or `createBlackFrameWatch`) is called.
6
+ */
7
+ export interface HealRung {
8
+ readonly name: string;
9
+ readonly params: Readonly<Record<string, string>>;
10
+ }
11
+ export declare const DEFAULT_HEAL_LADDER: readonly HealRung[];
12
+ export declare const DEFAULT_HEAL_STORAGE_KEY = "aura3d-safety-heal-stage";
13
+ type StorageLike = Pick<Storage, "getItem" | "setItem">;
14
+ /** Current rung (0 = full quality) from session storage, so a reload continues down the ladder. */
15
+ export declare function healStage(storage?: Pick<Storage, "getItem"> | undefined, ladder?: readonly HealRung[], storageKey?: string): number;
16
+ /** Query parameters implied by rung `stage` (cumulative); callers merge them under the author's explicit parameters. */
17
+ export declare function healParams(stage: number, ladder?: readonly HealRung[]): Record<string, string>;
18
+ export declare function healRungName(stage: number, ladder?: readonly HealRung[]): string;
19
+ /** True when every sampled texel of a downscaled frame is (almost) black. */
20
+ export declare function isBlackFrame(rgba: ArrayLike<number>): boolean;
21
+ export interface BlackFrameWatchOptions {
22
+ readonly enabled: boolean;
23
+ readonly ladder?: readonly HealRung[];
24
+ readonly storageKey?: string;
25
+ /** Shortens the detection window (tests only); production uses 20 frames then 23 consecutive black samples. */
26
+ readonly fastFrames?: number;
27
+ /** Reads a downscaled RGBA probe of the canvas. Defaults to a 16x16 2D canvas copy. */
28
+ readonly readProbe?: (canvas: HTMLCanvasElement) => ArrayLike<number> | undefined;
29
+ readonly storage?: StorageLike;
30
+ readonly currentUrl?: () => string;
31
+ /** Navigates to the next rung. Defaults to `location.replace`. */
32
+ readonly navigate?: (url: string) => void;
33
+ readonly log?: (code: string, message: string) => void;
34
+ }
35
+ export interface BlackFrameWatch {
36
+ /** Call right after a frame was drawn, in the same task (before the browser composites it). */
37
+ sample(framesDrawn: number): void;
38
+ readonly stage: number;
39
+ readonly rung: string;
40
+ /** True once the watch decided to reload one rung down. */
41
+ readonly escalated: boolean;
42
+ }
43
+ export declare function createBlackFrameWatch(canvas: HTMLCanvasElement, options: BlackFrameWatchOptions): BlackFrameWatch;
44
+ export {};
45
+ //# sourceMappingURL=blackFrame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blackFrame.d.ts","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/blackFrame.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,eAAO,MAAM,mBAAmB,EAAE,SAAS,QAAQ,EAOlD,CAAC;AAEF,eAAO,MAAM,wBAAwB,6BAA6B,CAAC;AAKnE,KAAK,WAAW,GAAG,IAAI,CAAC,OAAO,EAAE,SAAS,GAAG,SAAS,CAAC,CAAC;AAUxD,mGAAmG;AACnG,wBAAgB,SAAS,CACvB,OAAO,GAAE,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,GAAG,SAAyB,EAC7D,MAAM,GAAE,SAAS,QAAQ,EAAwB,EACjD,UAAU,GAAE,MAAiC,GAC5C,MAAM,CAGR;AAED,wHAAwH;AACxH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,SAAS,QAAQ,EAAwB,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAInH;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,GAAE,SAAS,QAAQ,EAAwB,GAAG,MAAM,CAErG;AAED,6EAA6E;AAC7E,wBAAgB,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,GAAG,OAAO,CAM7D;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,+GAA+G;IAC/G,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;IAC7B,uFAAuF;IACvF,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,iBAAiB,KAAK,SAAS,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAClF,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,MAAM,CAAC;IACnC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,WAAW,eAAe;IAC9B,+FAA+F;IAC/F,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2DAA2D;IAC3D,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAiBD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,iBAAiB,EAAE,OAAO,EAAE,sBAAsB,GAAG,eAAe,CAwCjH"}
@@ -0,0 +1,109 @@
1
+ export const DEFAULT_HEAL_LADDER = [
2
+ { name: "no-aa", params: { aa: "0" } },
3
+ { name: "no-post", params: { post: "0" } },
4
+ { name: "aces-tone", params: { tm: "aces" } },
5
+ { name: "no-env", params: { env: "0" } },
6
+ { name: "no-shadow", params: { shadow: "0" } },
7
+ { name: "low-quality", params: { quality: "low", sky: "1" } }
8
+ ];
9
+ export const DEFAULT_HEAL_STORAGE_KEY = "aura3d-safety-heal-stage";
10
+ const DEFAULT_FRAMES_NEEDED = 45;
11
+ const BLACK_MAX_CHANNEL = 4;
12
+ const PROBE_SIZE = 16;
13
+ function safeStorage() {
14
+ try {
15
+ return globalThis.sessionStorage;
16
+ }
17
+ catch {
18
+ return undefined;
19
+ }
20
+ }
21
+ /** Current rung (0 = full quality) from session storage, so a reload continues down the ladder. */
22
+ export function healStage(storage = safeStorage(), ladder = DEFAULT_HEAL_LADDER, storageKey = DEFAULT_HEAL_STORAGE_KEY) {
23
+ const raw = Number(storage?.getItem(storageKey) ?? "0");
24
+ return Number.isInteger(raw) && raw >= 0 && raw <= ladder.length ? raw : 0;
25
+ }
26
+ /** Query parameters implied by rung `stage` (cumulative); callers merge them under the author's explicit parameters. */
27
+ export function healParams(stage, ladder = DEFAULT_HEAL_LADDER) {
28
+ const merged = {};
29
+ for (const rung of ladder.slice(0, Math.max(0, stage)))
30
+ Object.assign(merged, rung.params);
31
+ return merged;
32
+ }
33
+ export function healRungName(stage, ladder = DEFAULT_HEAL_LADDER) {
34
+ return stage <= 0 ? "full" : ladder[Math.min(stage, ladder.length) - 1].name;
35
+ }
36
+ /** True when every sampled texel of a downscaled frame is (almost) black. */
37
+ export function isBlackFrame(rgba) {
38
+ if (rgba.length < 4)
39
+ return false;
40
+ for (let i = 0; i + 2 < rgba.length; i += 4) {
41
+ if (rgba[i] > BLACK_MAX_CHANNEL || rgba[i + 1] > BLACK_MAX_CHANNEL || rgba[i + 2] > BLACK_MAX_CHANNEL)
42
+ return false;
43
+ }
44
+ return true;
45
+ }
46
+ function defaultProbe() {
47
+ let ctx;
48
+ return (canvas) => {
49
+ if (ctx === undefined) {
50
+ const probe = document.createElement("canvas");
51
+ probe.width = PROBE_SIZE;
52
+ probe.height = PROBE_SIZE;
53
+ ctx = probe.getContext("2d", { willReadFrequently: true });
54
+ }
55
+ if (!ctx)
56
+ return undefined;
57
+ ctx.drawImage(canvas, 0, 0, PROBE_SIZE, PROBE_SIZE);
58
+ return ctx.getImageData(0, 0, PROBE_SIZE, PROBE_SIZE).data;
59
+ };
60
+ }
61
+ export function createBlackFrameWatch(canvas, options) {
62
+ const ladder = options.ladder ?? DEFAULT_HEAL_LADDER;
63
+ const storageKey = options.storageKey ?? DEFAULT_HEAL_STORAGE_KEY;
64
+ const storage = options.storage ?? safeStorage();
65
+ const minFrames = options.fastFrames ?? 20;
66
+ const samplesNeeded = Math.max(2, Math.ceil((options.fastFrames ?? DEFAULT_FRAMES_NEEDED) / 2));
67
+ const stage = healStage(storage, ladder, storageKey);
68
+ const readProbe = options.readProbe ?? defaultProbe();
69
+ const log = options.log ?? ((code, message) => console.warn(`${code}: ${message}`));
70
+ const currentUrl = options.currentUrl ?? (() => location.href);
71
+ const navigate = options.navigate ?? ((url) => location.replace(url));
72
+ let consecutive = 0;
73
+ let escalated = false;
74
+ if (stage > 0)
75
+ log("SAFETY_COMPAT_MODE", `rung ${stage} (${healRungName(stage, ladder)}) after a black frame was detected`);
76
+ return {
77
+ stage,
78
+ rung: healRungName(stage, ladder),
79
+ get escalated() {
80
+ return escalated;
81
+ },
82
+ sample(framesDrawn) {
83
+ if (!options.enabled || escalated || framesDrawn < minFrames || framesDrawn % 2 !== 0)
84
+ return;
85
+ let black;
86
+ try {
87
+ const data = readProbe(canvas);
88
+ if (!data)
89
+ return;
90
+ black = isBlackFrame(data);
91
+ }
92
+ catch {
93
+ return;
94
+ }
95
+ consecutive = black ? consecutive + 1 : 0;
96
+ if (consecutive < samplesNeeded || stage >= ladder.length)
97
+ return;
98
+ escalated = true;
99
+ storage?.setItem(storageKey, String(stage + 1));
100
+ const url = new URL(currentUrl());
101
+ for (const [key, value] of Object.entries(healParams(stage + 1, ladder)))
102
+ if (!url.searchParams.has(key))
103
+ url.searchParams.set(key, value);
104
+ log("SAFETY_BLACK_FRAME", `reloading at rung ${stage + 1} (${healRungName(stage + 1, ladder)})`);
105
+ navigate(url.toString());
106
+ }
107
+ };
108
+ }
109
+ //# sourceMappingURL=blackFrame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blackFrame.js","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/blackFrame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * On-screen GPU diagnostics panel: renderer string, WebGL limits and extensions, canvas size, WebGPU presence, engine
3
+ * draw calls, shader compile/link failures, WebGL context loss and the last console errors. Intended for real-device
4
+ * bug reports ("open the page with ?diag=1 and send a screenshot"). Nothing is installed until the function is called,
5
+ * and `dispose()` restores every patched browser prototype and console method.
6
+ */
7
+ export interface DiagnosticsAppLike {
8
+ /** `AuraApp.diagnostics()` shape; only these members are read. */
9
+ diagnostics?(): {
10
+ readonly backend?: unknown;
11
+ readonly drawCalls?: unknown;
12
+ readonly fps?: unknown;
13
+ readonly warnings?: readonly string[];
14
+ readonly errors?: readonly string[];
15
+ } | undefined;
16
+ }
17
+ export interface DiagnosticsPanelOptions {
18
+ readonly app?: DiagnosticsAppLike;
19
+ readonly title?: string;
20
+ readonly maxLines?: number;
21
+ /** Extra lines appended to the engine section (the safety net adds its rung and switches here). */
22
+ readonly extraLines?: () => readonly string[];
23
+ /** Update period in ms. */
24
+ readonly refreshMs?: number;
25
+ }
26
+ export interface DiagnosticsPanelHandle {
27
+ readonly lines: readonly string[];
28
+ refresh(): void;
29
+ dispose(): void;
30
+ }
31
+ export interface GpuProbe {
32
+ readonly renderer: string;
33
+ readonly limits: string;
34
+ readonly extensions: string;
35
+ readonly webgpu: boolean;
36
+ readonly dpr: number;
37
+ }
38
+ export declare function probeGpu(): GpuProbe | {
39
+ readonly error: string;
40
+ };
41
+ export declare function formatGpuProbe(probe: GpuProbe | {
42
+ readonly error: string;
43
+ }): string;
44
+ /** Pure formatter for the engine section so it can be unit tested without a browser. */
45
+ export declare function formatEngineSection(app: DiagnosticsAppLike | undefined, canvases: ReadonlyArray<{
46
+ id?: string;
47
+ width: number;
48
+ height: number;
49
+ clientWidth: number;
50
+ clientHeight: number;
51
+ }>): string;
52
+ export declare function installDiagnosticsPanel(options?: DiagnosticsPanelOptions): DiagnosticsPanelHandle;
53
+ //# sourceMappingURL=diagnosticsPanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnosticsPanel.d.ts","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/diagnosticsPanel.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,WAAW,kBAAkB;IACjC,kEAAkE;IAClE,WAAW,CAAC,IAAI;QAAE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;QAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,GAAG,SAAS,CAAC;CAC9L;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,GAAG,CAAC,EAAE,kBAAkB,CAAC;IAClC,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,mGAAmG;IACnG,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,SAAS,MAAM,EAAE,CAAC;IAC9C,2BAA2B;IAC3B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;IAClC,OAAO,IAAI,IAAI,CAAC;IAChB,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;CACtB;AAID,wBAAgB,QAAQ,IAAI,QAAQ,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAehE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,QAAQ,GAAG;IAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAGnF;AAED,wFAAwF;AACxF,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,kBAAkB,GAAG,SAAS,EAAE,QAAQ,EAAE,aAAa,CAAC;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,CAAC,GAAG,MAAM,CAgBnM;AAED,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CAsErG"}
@@ -0,0 +1,117 @@
1
+ const EXTENSIONS = ["EXT_color_buffer_float", "OES_texture_float_linear", "WEBGL_multi_draw", "EXT_disjoint_timer_query_webgl2"];
2
+ export function probeGpu() {
3
+ try {
4
+ const gl = document.createElement("canvas").getContext("webgl2");
5
+ if (!gl)
6
+ return { error: "webgl2: unavailable" };
7
+ const info = gl.getExtension("WEBGL_debug_renderer_info");
8
+ return {
9
+ renderer: String(info ? gl.getParameter(info.UNMASKED_RENDERER_WEBGL) : gl.getParameter(gl.RENDERER)),
10
+ limits: `maxTex ${gl.getParameter(gl.MAX_TEXTURE_SIZE)} units ${gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)} samples ${gl.getParameter(gl.MAX_SAMPLES)} fragUniforms ${gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)} varyings ${gl.getParameter(gl.MAX_VARYING_VECTORS)}`,
11
+ extensions: EXTENSIONS.map((name) => `${name.replace(/^(EXT|OES|WEBGL)_/, "")}:${gl.getExtension(name) ? "y" : "n"}`).join(" "),
12
+ webgpu: "gpu" in navigator,
13
+ dpr: globalThis.devicePixelRatio ?? 1
14
+ };
15
+ }
16
+ catch (error) {
17
+ return { error: `webgl2 probe failed: ${String(error.message)}` };
18
+ }
19
+ }
20
+ export function formatGpuProbe(probe) {
21
+ if ("error" in probe)
22
+ return probe.error;
23
+ return `gpu: ${probe.renderer}\n${probe.limits}\n${probe.extensions} navigator.gpu:${probe.webgpu ? "y" : "n"} dpr ${probe.dpr}`;
24
+ }
25
+ /** Pure formatter for the engine section so it can be unit tested without a browser. */
26
+ export function formatEngineSection(app, canvases) {
27
+ const parts = [];
28
+ try {
29
+ const report = app?.diagnostics?.();
30
+ if (report) {
31
+ if (report.backend !== undefined)
32
+ parts.push(`backend=${String(report.backend)}`);
33
+ if (report.drawCalls !== undefined)
34
+ parts.push(`drawCalls=${String(report.drawCalls)}`);
35
+ if (report.fps !== undefined)
36
+ parts.push(`fps=${Number(report.fps).toFixed(0)}`);
37
+ for (const warning of (report.warnings ?? []).slice(0, 3))
38
+ parts.push(`warn:${String(warning).slice(0, 80)}`);
39
+ for (const error of (report.errors ?? []).slice(0, 3))
40
+ parts.push(`error:${String(error).slice(0, 80)}`);
41
+ }
42
+ }
43
+ catch {
44
+ parts.push("diagnostics() threw");
45
+ }
46
+ const sizes = canvases.map((c) => `${c.id || "canvas"} ${c.width}x${c.height} (css ${c.clientWidth}x${c.clientHeight})`).join("; ");
47
+ return `engine: ${parts.join(" ") || "no diagnostics exposed"}\ncanvas: ${sizes}`;
48
+ }
49
+ export function installDiagnosticsPanel(options = {}) {
50
+ const lines = [];
51
+ const maxLines = options.maxLines ?? 14;
52
+ const restore = [];
53
+ const push = (line) => {
54
+ lines.push(line.slice(0, 220));
55
+ while (lines.length > maxLines)
56
+ lines.shift();
57
+ };
58
+ const originalError = console.error;
59
+ const originalWarn = console.warn;
60
+ console.error = (...args) => { push(`error: ${args.map(String).join(" ")}`); originalError.apply(console, args); };
61
+ console.warn = (...args) => { push(`warn: ${args.map(String).join(" ")}`); originalWarn.apply(console, args); };
62
+ restore.push(() => { console.error = originalError; console.warn = originalWarn; });
63
+ const onError = (event) => push(`uncaught: ${event.message}`);
64
+ const onRejection = (event) => push(`rejection: ${String(event.reason?.message ?? event.reason)}`);
65
+ window.addEventListener("error", onError);
66
+ window.addEventListener("unhandledrejection", onRejection);
67
+ restore.push(() => { window.removeEventListener("error", onError); window.removeEventListener("unhandledrejection", onRejection); });
68
+ const proto = globalThis.WebGL2RenderingContext?.prototype;
69
+ if (proto) {
70
+ const compile = proto.compileShader;
71
+ const link = proto.linkProgram;
72
+ proto.compileShader = function (shader) {
73
+ compile.call(this, shader);
74
+ if (!this.getShaderParameter(shader, this.COMPILE_STATUS))
75
+ push(`SHADER COMPILE FAILED: ${(this.getShaderInfoLog(shader) ?? "").replace(/\s+/g, " ")}`);
76
+ };
77
+ proto.linkProgram = function (program) {
78
+ link.call(this, program);
79
+ if (!this.getProgramParameter(program, this.LINK_STATUS))
80
+ push(`PROGRAM LINK FAILED: ${(this.getProgramInfoLog(program) ?? "").replace(/\s+/g, " ")}`);
81
+ };
82
+ restore.push(() => { proto.compileShader = compile; proto.linkProgram = link; });
83
+ }
84
+ const getContext = HTMLCanvasElement.prototype.getContext;
85
+ HTMLCanvasElement.prototype.getContext = function (...args) {
86
+ const context = getContext.apply(this, args);
87
+ if (context && !this.__auraSafetyWatched) {
88
+ this.__auraSafetyWatched = true;
89
+ this.addEventListener("webglcontextlost", () => push("WEBGL CONTEXT LOST"));
90
+ }
91
+ return context;
92
+ };
93
+ restore.push(() => { HTMLCanvasElement.prototype.getContext = getContext; });
94
+ const panel = document.createElement("pre");
95
+ panel.setAttribute("data-aura3d-safety-panel", "");
96
+ panel.style.cssText = "position:fixed;left:8px;top:8px;z-index:2147483001;max-width:min(720px,calc(100vw - 16px));margin:0;padding:6px 9px;border-radius:6px;background:rgba(0,0,0,.78);color:#9dffb0;font:400 11px/1.35 ui-monospace,Menlo,monospace;white-space:pre-wrap;pointer-events:none";
97
+ document.body.appendChild(panel);
98
+ restore.push(() => panel.remove());
99
+ const staticInfo = formatGpuProbe(probeGpu());
100
+ const refresh = () => {
101
+ const canvases = Array.from(document.querySelectorAll("canvas"));
102
+ const extra = options.extraLines?.() ?? [];
103
+ panel.textContent = `${options.title ?? "Aura3D diagnostics"}\n${staticInfo}\n${formatEngineSection(options.app, canvases)}${extra.length ? `\n${extra.join("\n")}` : ""}\n${lines.length ? lines.join("\n") : "no errors captured"}`;
104
+ };
105
+ refresh();
106
+ const timer = setInterval(refresh, options.refreshMs ?? 1000);
107
+ restore.push(() => clearInterval(timer));
108
+ return {
109
+ lines,
110
+ refresh,
111
+ dispose() {
112
+ for (const undo of restore.reverse())
113
+ undo();
114
+ }
115
+ };
116
+ }
117
+ //# sourceMappingURL=diagnosticsPanel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"diagnosticsPanel.js","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/diagnosticsPanel.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import { type BlackFrameWatchOptions, type HealRung } from "./blackFrame.js";
2
+ import { type DiagnosticsAppLike } from "./diagnosticsPanel.js";
3
+ import { type QualitySwitches } from "./switches.js";
4
+ export * from "./blackFrame.js";
5
+ export * from "./diagnosticsPanel.js";
6
+ export * from "./switches.js";
7
+ export interface SafetyNetOptions {
8
+ /** Must be true (or an options object) for anything to run: the safety net is never on by default. */
9
+ readonly safety: boolean | SafetySettings;
10
+ readonly canvas?: HTMLCanvasElement;
11
+ readonly app?: DiagnosticsAppLike;
12
+ /** Query string to read switches from; defaults to `location.search`. */
13
+ readonly search?: string | URLSearchParams;
14
+ }
15
+ export interface SafetySettings {
16
+ /** Reload one rung down when the canvas stays black. Default true; `?heal=0` still wins. */
17
+ readonly selfHeal?: boolean;
18
+ /** Show the diagnostics panel. Default: only when the URL has `?diag=1`. */
19
+ readonly panel?: boolean | "query";
20
+ readonly ladder?: readonly HealRung[];
21
+ readonly watch?: Pick<BlackFrameWatchOptions, "fastFrames" | "readProbe" | "storage" | "currentUrl" | "navigate" | "storageKey" | "log">;
22
+ }
23
+ export interface SafetyReport {
24
+ readonly enabled: boolean;
25
+ readonly stage: number;
26
+ readonly rung: string;
27
+ readonly escalated: boolean;
28
+ readonly switches: QualitySwitches;
29
+ readonly panel: boolean;
30
+ }
31
+ export interface SafetyNet {
32
+ /** Switches in force (explicit URL parameters, then the black-frame rung's parameters). */
33
+ readonly switches: QualitySwitches;
34
+ /** Call after every presented frame with the running frame count. */
35
+ sample(framesDrawn: number): void;
36
+ /** What the safety net did; also exposed as `globalThis.__AURA_SAFETY__` while installed. */
37
+ report(): SafetyReport;
38
+ dispose(): void;
39
+ }
40
+ /**
41
+ * Opt-in runtime safety net for real-device failures: quality URL switches, black-frame self-heal and the diagnostics panel.
42
+ * Returns an inert handle (switches still parsed) unless `safety` is truthy. Reports through stable console codes
43
+ * (`SAFETY_COMPAT_MODE`, `SAFETY_BLACK_FRAME`), `report()` and the panel; `AuraApp.diagnostics()` is a read-only snapshot,
44
+ * so the safety net does not write into it.
45
+ */
46
+ export declare function installSafetyNet(options: SafetyNetOptions): SafetyNet;
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAA6F,KAAK,sBAAsB,EAAE,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AACxK,OAAO,EAA2B,KAAK,kBAAkB,EAA+B,MAAM,uBAAuB,CAAC;AACtH,OAAO,EAA0B,KAAK,eAAe,EAAE,MAAM,eAAe,CAAC;AAE7E,cAAc,iBAAiB,CAAC;AAChC,cAAc,uBAAuB,CAAC;AACtC,cAAc,eAAe,CAAC;AAE9B,MAAM,WAAW,gBAAgB;IAC/B,sGAAsG;IACtG,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,cAAc,CAAC;IAC1C,QAAQ,CAAC,MAAM,CAAC,EAAE,iBAAiB,CAAC;IACpC,QAAQ,CAAC,GAAG,CAAC,EAAE,kBAAkB,CAAC;IAClC,yEAAyE;IACzE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;CAC5C;AAED,MAAM,WAAW,cAAc;IAC7B,4FAA4F;IAC5F,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,4EAA4E;IAC5E,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;IACnC,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,sBAAsB,EAAE,YAAY,GAAG,WAAW,GAAG,SAAS,GAAG,YAAY,GAAG,UAAU,GAAG,YAAY,GAAG,KAAK,CAAC,CAAC;CAC1I;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,SAAS;IACxB,2FAA2F;IAC3F,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,qEAAqE;IACrE,MAAM,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,6FAA6F;IAC7F,MAAM,IAAI,YAAY,CAAC;IACvB,OAAO,IAAI,IAAI,CAAC;CACjB;AAID;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,gBAAgB,GAAG,SAAS,CA8CrE"}
@@ -0,0 +1,61 @@
1
+ import { createBlackFrameWatch, DEFAULT_HEAL_LADDER, healRungName, healStage } from "./blackFrame.js";
2
+ import { installDiagnosticsPanel } from "./diagnosticsPanel.js";
3
+ import { resolveQualitySwitches } from "./switches.js";
4
+ export * from "./blackFrame.js";
5
+ export * from "./diagnosticsPanel.js";
6
+ export * from "./switches.js";
7
+ const NOOP_REPORT = (switches) => ({ enabled: false, stage: 0, rung: "full", escalated: false, switches, panel: false });
8
+ /**
9
+ * Opt-in runtime safety net for real-device failures: quality URL switches, black-frame self-heal and the diagnostics panel.
10
+ * Returns an inert handle (switches still parsed) unless `safety` is truthy. Reports through stable console codes
11
+ * (`SAFETY_COMPAT_MODE`, `SAFETY_BLACK_FRAME`), `report()` and the panel; `AuraApp.diagnostics()` is a read-only snapshot,
12
+ * so the safety net does not write into it.
13
+ */
14
+ export function installSafetyNet(options) {
15
+ const settings = typeof options.safety === "object" ? options.safety : {};
16
+ const enabled = options.safety !== false && options.safety !== undefined;
17
+ const ladder = settings.ladder ?? DEFAULT_HEAL_LADDER;
18
+ const stage = enabled ? healStage(settings.watch?.storage, ladder, settings.watch?.storageKey) : 0;
19
+ const switches = resolveQualitySwitches({ search: options.search, healStage: stage, ladder });
20
+ if (!enabled) {
21
+ return { switches, sample() { }, report: () => NOOP_REPORT(switches), dispose() { } };
22
+ }
23
+ let watch;
24
+ if (options.canvas && settings.selfHeal !== false) {
25
+ watch = createBlackFrameWatch(options.canvas, { enabled: switches.heal, ladder, ...settings.watch });
26
+ }
27
+ const showPanel = settings.panel === true || ((settings.panel === undefined || settings.panel === "query") && switches.diag);
28
+ const report = () => ({
29
+ enabled: true,
30
+ stage: watch?.stage ?? stage,
31
+ rung: watch?.rung ?? healRungName(stage, ladder),
32
+ escalated: watch?.escalated ?? false,
33
+ switches,
34
+ panel: showPanel
35
+ });
36
+ let panel;
37
+ if (showPanel && typeof document !== "undefined") {
38
+ panel = installDiagnosticsPanel({
39
+ ...(options.app ? { app: options.app } : {}),
40
+ title: "Aura3D safety net (?diag=1)",
41
+ extraLines: () => {
42
+ const r = report();
43
+ const off = ["post", "shadow", "env", "sky", "aa"].filter((key) => !switches[key]);
44
+ return [`safety: rung ${r.stage} (${r.rung})${r.escalated ? " reloading" : ""} off:[${off.join(",")}] quality:${switches.quality} tm:${switches.toneMapping} heal:${switches.heal ? "on" : "off"}`];
45
+ }
46
+ });
47
+ }
48
+ const g = globalThis;
49
+ g.__AURA_SAFETY__ = report;
50
+ return {
51
+ switches,
52
+ sample: (framesDrawn) => watch?.sample(framesDrawn),
53
+ report,
54
+ dispose() {
55
+ panel?.dispose();
56
+ if (g.__AURA_SAFETY__ === report)
57
+ delete g.__AURA_SAFETY__;
58
+ }
59
+ };
60
+ }
61
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { type HealRung } from "./blackFrame.js";
2
+ /**
3
+ * Quality URL switches shared by every game: `?post=0 ?shadow=0 ?env=0 ?sky=0 ?aa=0 ?quality=low ?tm=aces ?heal=0 ?diag=1`.
4
+ * Parsing is pure; a game decides what each switch changes in its own options. Rung parameters from the black-frame
5
+ * ladder are merged UNDER explicit parameters, so an author's URL always wins.
6
+ */
7
+ export interface QualitySwitches {
8
+ readonly post: boolean;
9
+ readonly shadow: boolean;
10
+ readonly env: boolean;
11
+ readonly sky: boolean;
12
+ readonly aa: boolean;
13
+ readonly heal: boolean;
14
+ readonly diag: boolean;
15
+ readonly quality: "default" | "low";
16
+ readonly toneMapping: "default" | "aces";
17
+ /** The merged query parameters actually used (explicit + ladder). */
18
+ readonly params: Readonly<Record<string, string>>;
19
+ }
20
+ export interface ResolveQualitySwitchesOptions {
21
+ readonly search?: string | URLSearchParams;
22
+ /** Black-frame ladder rung currently in force (0 = none). */
23
+ readonly healStage?: number;
24
+ readonly ladder?: readonly HealRung[];
25
+ }
26
+ export declare function resolveQualitySwitches(options?: ResolveQualitySwitchesOptions): QualitySwitches;
27
+ //# sourceMappingURL=switches.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switches.d.ts","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/switches.ts"],"names":[],"mappings":"AAAA,OAAO,EAAmC,KAAK,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAEjF;;;;GAIG;AACH,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,OAAO,EAAE,SAAS,GAAG,KAAK,CAAC;IACpC,QAAQ,CAAC,WAAW,EAAE,SAAS,GAAG,MAAM,CAAC;IACzC,qEAAqE;IACrE,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,eAAe,CAAC;IAC3C,6DAA6D;IAC7D,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,MAAM,CAAC,EAAE,SAAS,QAAQ,EAAE,CAAC;CACvC;AAED,wBAAgB,sBAAsB,CAAC,OAAO,GAAE,6BAAkC,GAAG,eAAe,CAmBnG"}
@@ -0,0 +1,23 @@
1
+ import { DEFAULT_HEAL_LADDER, healParams } from "./blackFrame.js";
2
+ export function resolveQualitySwitches(options = {}) {
3
+ const raw = options.search ?? (typeof location === "undefined" ? "" : location.search);
4
+ const query = raw instanceof URLSearchParams ? new URLSearchParams(raw) : new URLSearchParams(raw);
5
+ for (const [key, value] of Object.entries(healParams(options.healStage ?? 0, options.ladder ?? DEFAULT_HEAL_LADDER))) {
6
+ if (!query.has(key))
7
+ query.set(key, value);
8
+ }
9
+ const off = (key) => query.get(key) !== "0";
10
+ return {
11
+ post: off("post"),
12
+ shadow: off("shadow"),
13
+ env: off("env"),
14
+ sky: off("sky"),
15
+ aa: off("aa"),
16
+ heal: off("heal"),
17
+ diag: query.get("diag") === "1",
18
+ quality: query.get("quality") === "low" ? "low" : "default",
19
+ toneMapping: query.get("tm") === "aces" ? "aces" : "default",
20
+ params: Object.fromEntries(query.entries())
21
+ };
22
+ }
23
+ //# sourceMappingURL=switches.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"switches.js","sourceRoot":"","sources":["../../../../../packages/debug/src/safety/switches.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,UAAU,EAAiB,MAAM,iBAAiB,CAAC;AA4BjF,MAAM,UAAU,sBAAsB,CAAC,UAAyC,EAAE;IAChF,MAAM,GAAG,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,OAAO,QAAQ,KAAK,WAAW,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IACvF,MAAM,KAAK,GAAG,GAAG,YAAY,eAAe,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,eAAe,CAAC,GAAG,CAAC,CAAC;IACnG,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,IAAI,mBAAmB,CAAC,CAAC,EAAE,CAAC;QACrH,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;IAC7C,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,GAAW,EAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,GAAG,CAAC;IAC7D,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;QACjB,MAAM,EAAE,GAAG,CAAC,QAAQ,CAAC;QACrB,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC;QACf,GAAG,EAAE,GAAG,CAAC,KAAK,CAAC;QACf,EAAE,EAAE,GAAG,CAAC,IAAI,CAAC;QACb,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC;QACjB,IAAI,EAAE,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,GAAG;QAC/B,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS;QAC3D,WAAW,EAAE,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS;QAC5D,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;KAC5C,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@aura3d/debug",
3
- "version": "4.0.7",
3
+ "version": "4.1.0",
4
4
  "type": "module",
5
5
  "dependencies": {
6
- "@aura3d/animation": "4.0.7",
7
- "@aura3d/rendering": "4.0.7",
8
- "@aura3d/physics": "4.0.7"
6
+ "@aura3d/animation": "4.1.0",
7
+ "@aura3d/physics": "4.1.0",
8
+ "@aura3d/rendering": "4.1.0"
9
9
  },
10
10
  "exports": {
11
11
  ".": {