@caperjs/core 0.6.0 → 0.7.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/build/index.d.mts +6 -0
- package/build/index.mjs +7 -0
- package/build/plugins/solid.mjs +30 -0
- package/cli/doctor.mjs +128 -0
- package/cli/doctor.test.mjs +154 -0
- package/extras/llms.txt +192 -4
- package/extras/skills/caper/SKILL.md +51 -3
- package/lib/{CaptionsPlugin-CDbGZrN9.js → CaptionsPlugin-Boj-gm3A.js} +5 -5
- package/lib/{CaptionsPlugin-CDbGZrN9.js.map → CaptionsPlugin-Boj-gm3A.js.map} +1 -1
- package/lib/{DataAdapter-BTlNzWqg.js → DataAdapter-Cra9dJ6W.js} +9 -9
- package/lib/{DataAdapter-BTlNzWqg.js.map → DataAdapter-Cra9dJ6W.js.map} +1 -1
- package/lib/{DebugRenderer-eSVpon4c.js → DebugRenderer-19S58S4h.js} +4 -4
- package/lib/{DebugRenderer-eSVpon4c.js.map → DebugRenderer-19S58S4h.js.map} +1 -1
- package/lib/{DevToolsPlugin-Ci6r9j-m.js → DevToolsPlugin-BTSkRsdS.js} +3 -3
- package/lib/{DevToolsPlugin-Ci6r9j-m.js.map → DevToolsPlugin-BTSkRsdS.js.map} +1 -1
- package/lib/{GSAPPlugin-C8zo-fyt.js → GSAPPlugin-BcL7vjyw.js} +5 -5
- package/lib/{GSAPPlugin-C8zo-fyt.js.map → GSAPPlugin-BcL7vjyw.js.map} +1 -1
- package/lib/{LayoutPlugin-Cs2lcXKb.js → LayoutPlugin-BDhSngz_.js} +26 -26
- package/lib/{LayoutPlugin-Cs2lcXKb.js.map → LayoutPlugin-BDhSngz_.js.map} +1 -1
- package/lib/ScreenDebugPlugin-C6pxs_3O.js +103 -0
- package/lib/ScreenDebugPlugin-C6pxs_3O.js.map +1 -0
- package/lib/{SpinePlugin-CLgSXBQm.js → SpinePlugin-CrQhaK6r.js} +2 -2
- package/lib/{SpinePlugin-CLgSXBQm.js.map → SpinePlugin-CrQhaK6r.js.map} +1 -1
- package/lib/{StatsPlugin-D_90U3BG.js → StatsPlugin-Cu625dmk.js} +2 -2
- package/lib/{StatsPlugin-D_90U3BG.js.map → StatsPlugin-Cu625dmk.js.map} +1 -1
- package/lib/{VoiceOverPlugin-CAE1dtOw.js → VoiceOverPlugin-D4rfHFyJ.js} +5 -5
- package/lib/{VoiceOverPlugin-CAE1dtOw.js.map → VoiceOverPlugin-D4rfHFyJ.js.map} +1 -1
- package/lib/caper.mjs +98 -97
- package/lib/caper.mjs.map +1 -1
- package/lib/{const-BTDpIdRO.js → const-BQ2iMCtc.js} +180 -180
- package/lib/{const-BTDpIdRO.js.map → const-BQ2iMCtc.js.map} +1 -1
- package/lib/core/Application.d.ts.map +1 -1
- package/lib/plugins/ScreenDebugPlugin.d.ts +22 -0
- package/lib/plugins/ScreenDebugPlugin.d.ts.map +1 -0
- package/lib/plugins/ScreenDebugPlugin.test.d.ts +2 -0
- package/lib/plugins/ScreenDebugPlugin.test.d.ts.map +1 -0
- package/lib/plugins/index.d.ts +2 -0
- package/lib/plugins/index.d.ts.map +1 -1
- package/lib/plugins/screenDebugFlag.d.ts +2 -0
- package/lib/plugins/screenDebugFlag.d.ts.map +1 -0
- package/lib/plugins/screenDebugFlag.test.d.ts +2 -0
- package/lib/plugins/screenDebugFlag.test.d.ts.map +1 -0
- package/lib/{registries-nN_hU44y.js → registries-BmDw_GV1.js} +244 -228
- package/lib/registries-BmDw_GV1.js.map +1 -0
- package/package.json +3 -3
- package/src/core/Application.ts +8 -0
- package/src/plugins/ScreenDebugPlugin.test.ts +61 -0
- package/src/plugins/ScreenDebugPlugin.ts +174 -0
- package/src/plugins/index.ts +2 -0
- package/src/plugins/screenDebugFlag.test.ts +45 -0
- package/src/plugins/screenDebugFlag.ts +26 -0
- package/src/version.ts +2 -2
- package/lib/registries-nN_hU44y.js.map +0 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@caperjs/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"title": "Caper",
|
|
5
5
|
"description": "An opinionated HTML game framework built on PixiJS v8",
|
|
6
6
|
"bin": {
|
|
@@ -98,7 +98,7 @@
|
|
|
98
98
|
"peerDependencies": {
|
|
99
99
|
"@pixi/sound": "^6.0.1",
|
|
100
100
|
"gsap": "^3.15.0",
|
|
101
|
-
"pixi.js": "8.
|
|
101
|
+
"pixi.js": "8.20.0",
|
|
102
102
|
"vite": "^8.0.7",
|
|
103
103
|
"workbox-window": "^7.4.0"
|
|
104
104
|
},
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"npm-run-all": "^4.1.5",
|
|
118
118
|
"oxc-parser": "^0.124.0",
|
|
119
119
|
"pixi-filters": "^6.1.2",
|
|
120
|
-
"pixi.js": "8.
|
|
120
|
+
"pixi.js": "8.20.0",
|
|
121
121
|
"prettier": "^3.2.5",
|
|
122
122
|
"rimraf": "^5.0.5",
|
|
123
123
|
"shelljs": "^0.8.5",
|
package/src/core/Application.ts
CHANGED
|
@@ -66,6 +66,7 @@ import { IFullScreenPlugin } from '../plugins/FullScreenPlugin';
|
|
|
66
66
|
import { type IGSAPPlugin } from '../plugins/GSAPPlugin';
|
|
67
67
|
import { ILookupPlugin } from '../plugins/LookupPlugin';
|
|
68
68
|
import { ITimerPlugin } from '../plugins/TimerPlugin';
|
|
69
|
+
import { shouldEnableScreenDebug } from '../plugins/screenDebugFlag';
|
|
69
70
|
import { Signal } from '../signals';
|
|
70
71
|
|
|
71
72
|
type App = AppTypeOverrides['App'];
|
|
@@ -1014,6 +1015,13 @@ export class Application extends PIXIPApplication implements IApplication {
|
|
|
1014
1015
|
namedExport: 'StatsPlugin',
|
|
1015
1016
|
});
|
|
1016
1017
|
}
|
|
1018
|
+
if (shouldEnableScreenDebug()) {
|
|
1019
|
+
await this.loadPlugin({
|
|
1020
|
+
id: 'screenDebug',
|
|
1021
|
+
module: () => import('../plugins/ScreenDebugPlugin'),
|
|
1022
|
+
namedExport: 'ScreenDebugPlugin',
|
|
1023
|
+
});
|
|
1024
|
+
}
|
|
1017
1025
|
if (this.config.useVoiceover) {
|
|
1018
1026
|
await this.loadPlugin({
|
|
1019
1027
|
id: 'voiceover',
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
vi.mock('../core', () => ({ coreFunctionRegistry: {}, coreSignalRegistry: {} }));
|
|
4
|
+
vi.mock('../core/Application', () => ({
|
|
5
|
+
Application: {
|
|
6
|
+
getInstance: () => ({
|
|
7
|
+
renderer: { canvas: null, width: 320, height: 480, resolution: 1 },
|
|
8
|
+
size: { width: 320, height: 480 },
|
|
9
|
+
resizer: { scale: 1, safeArea: { top: 0, right: 0, bottom: 0, left: 0 } },
|
|
10
|
+
}),
|
|
11
|
+
},
|
|
12
|
+
}));
|
|
13
|
+
|
|
14
|
+
import { ScreenDebugPlugin } from './ScreenDebugPlugin';
|
|
15
|
+
|
|
16
|
+
describe('ScreenDebugPlugin', () => {
|
|
17
|
+
let plugin: ScreenDebugPlugin;
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.useFakeTimers();
|
|
21
|
+
plugin = new ScreenDebugPlugin();
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
plugin.destroy();
|
|
26
|
+
vi.useRealTimers();
|
|
27
|
+
document.querySelectorAll('[data-caper-screen-debug]').forEach((node) => node.remove());
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('appends the overlay and populates metrics on a tick', () => {
|
|
31
|
+
plugin.initialize();
|
|
32
|
+
expect(document.querySelectorAll('[data-caper-screen-debug]')).toHaveLength(3);
|
|
33
|
+
|
|
34
|
+
vi.advanceTimersByTime(500);
|
|
35
|
+
|
|
36
|
+
const panel = document.querySelector('[data-caper-screen-debug="panel"]');
|
|
37
|
+
expect(panel?.textContent).toContain('inner ');
|
|
38
|
+
expect(panel?.textContent).toContain('standalone ');
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it('repopulates the panel from the interval tick, not just the initial call', () => {
|
|
42
|
+
plugin.initialize();
|
|
43
|
+
const panel = document.querySelector('[data-caper-screen-debug="panel"]')!;
|
|
44
|
+
panel.textContent = '';
|
|
45
|
+
|
|
46
|
+
vi.advanceTimersByTime(500);
|
|
47
|
+
|
|
48
|
+
expect(panel.textContent).toContain('inner ');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('removes every overlay node and clears its interval on destroy', () => {
|
|
52
|
+
const clearInterval = vi.spyOn(window, 'clearInterval');
|
|
53
|
+
plugin.initialize();
|
|
54
|
+
|
|
55
|
+
plugin.destroy();
|
|
56
|
+
|
|
57
|
+
expect(document.querySelectorAll('[data-caper-screen-debug]')).toHaveLength(0);
|
|
58
|
+
expect(clearInterval).toHaveBeenCalledOnce();
|
|
59
|
+
expect(vi.getTimerCount()).toBe(0);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import { Plugin } from './Plugin';
|
|
2
|
+
|
|
3
|
+
type TimelineEntry = { t: number; type: string; innerH: number; vvH: number };
|
|
4
|
+
|
|
5
|
+
export class ScreenDebugPlugin extends Plugin {
|
|
6
|
+
public readonly id = 'screenDebug';
|
|
7
|
+
|
|
8
|
+
private _panel: HTMLDivElement | null = null;
|
|
9
|
+
private _visibleBottom: HTMLDivElement | null = null;
|
|
10
|
+
private _canvasBottom: HTMLDivElement | null = null;
|
|
11
|
+
private _safeAreaProbe: HTMLDivElement | null = null;
|
|
12
|
+
private _startedAt = 0;
|
|
13
|
+
private _timeline: TimelineEntry[] = [];
|
|
14
|
+
private _initialVvH = 0;
|
|
15
|
+
|
|
16
|
+
public initialize(): void {
|
|
17
|
+
if (typeof document === 'undefined') {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
this._startedAt = performance.now();
|
|
22
|
+
this._initialVvH = window.visualViewport?.height ?? window.innerHeight;
|
|
23
|
+
|
|
24
|
+
this._panel = document.createElement('div');
|
|
25
|
+
this._panel.dataset.caperScreenDebug = 'panel';
|
|
26
|
+
this._panel.style.cssText =
|
|
27
|
+
'position:fixed;top:8px;left:8px;z-index:999999;pointer-events:none;font:10px/1.4 monospace;' +
|
|
28
|
+
'color:#9f9;background:rgba(0,0,0,.75);padding:6px 8px;border-radius:4px;max-width:86vw;white-space:pre;';
|
|
29
|
+
this._visibleBottom = this._makeMarker('red', 'visible-bottom');
|
|
30
|
+
this._canvasBottom = this._makeMarker('cyan', 'canvas-bottom');
|
|
31
|
+
document.body.append(this._panel, this._visibleBottom, this._canvasBottom);
|
|
32
|
+
|
|
33
|
+
this.listen(window, 'resize', () => this._onViewportEvent('resize'));
|
|
34
|
+
this.listen(window, 'orientationchange', () => this._onViewportEvent('orientationchange'));
|
|
35
|
+
if (window.visualViewport) {
|
|
36
|
+
this.listen(window.visualViewport, 'resize', () => this._onViewportEvent('vv.resize'));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const interval = window.setInterval(() => this._update(), 500);
|
|
40
|
+
this.addDisposer(
|
|
41
|
+
() => window.clearInterval(interval),
|
|
42
|
+
() => {
|
|
43
|
+
this._panel?.remove();
|
|
44
|
+
this._visibleBottom?.remove();
|
|
45
|
+
this._canvasBottom?.remove();
|
|
46
|
+
this._safeAreaProbe?.remove();
|
|
47
|
+
this._panel = this._visibleBottom = this._canvasBottom = this._safeAreaProbe = null;
|
|
48
|
+
},
|
|
49
|
+
);
|
|
50
|
+
this._update();
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private _makeMarker(color: string, name: string): HTMLDivElement {
|
|
54
|
+
const marker = document.createElement('div');
|
|
55
|
+
marker.dataset.caperScreenDebug = name;
|
|
56
|
+
marker.style.cssText =
|
|
57
|
+
`position:fixed;left:0;width:100%;height:2px;background:${color};` +
|
|
58
|
+
'z-index:999999;pointer-events:none;';
|
|
59
|
+
return marker;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
private _onViewportEvent(type: string): void {
|
|
63
|
+
const innerH = window.innerHeight;
|
|
64
|
+
const vvH = window.visualViewport?.height ?? innerH;
|
|
65
|
+
this._timeline.push({ t: performance.now() - this._startedAt, type, innerH, vvH });
|
|
66
|
+
if (this._timeline.length > 20) {
|
|
67
|
+
this._timeline.shift();
|
|
68
|
+
}
|
|
69
|
+
this._update();
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private _update(): void {
|
|
73
|
+
if (!this._panel || !this._visibleBottom || !this._canvasBottom) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const vv = window.visualViewport;
|
|
78
|
+
const canvas = this._getCanvas();
|
|
79
|
+
const canvasRect = canvas?.getBoundingClientRect();
|
|
80
|
+
const safeArea = this._measureSafeAreaCssPx();
|
|
81
|
+
const renderer = this._getRenderer();
|
|
82
|
+
const appSize = this._getAppSize();
|
|
83
|
+
const resizer = this._getResizer();
|
|
84
|
+
const r = (n: number) => Math.round(n * 10) / 10;
|
|
85
|
+
const viewportUnits = ['dvh', 'svh', 'lvh', 'vh'].map((unit) => `${unit} ${r(this._measureViewportUnit(unit))}`);
|
|
86
|
+
const events = this._timeline.map((event, index) => {
|
|
87
|
+
const prior = this._timeline[index - 1];
|
|
88
|
+
return `+${Math.round(event.t)}ms ${event.type} ${r(prior?.vvH ?? this._initialVvH)}→${r(event.vvH)}`;
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
this._panel.textContent = [
|
|
92
|
+
`inner ${window.innerWidth}x${window.innerHeight}`,
|
|
93
|
+
`client ${document.documentElement.clientHeight}`,
|
|
94
|
+
`vv ${vv ? `${r(vv.width)}x${r(vv.height)} scale ${vv.scale} offsetTop ${r(vv.offsetTop)}` : 'n/a'}`,
|
|
95
|
+
...viewportUnits,
|
|
96
|
+
`screen ${window.screen.width}x${window.screen.height}`,
|
|
97
|
+
`dpr ${window.devicePixelRatio}`,
|
|
98
|
+
`standalone ${window.matchMedia('(display-mode: standalone)').matches}`,
|
|
99
|
+
`env ${safeArea.top},${safeArea.right},${safeArea.bottom},${safeArea.left}`,
|
|
100
|
+
`canvas ${canvasRect ? `top ${r(canvasRect.top)} bottom ${r(canvasRect.bottom)} height ${r(canvasRect.height)}` : 'n/a'} style ${canvas?.style.height || 'n/a'}`,
|
|
101
|
+
`renderer ${renderer ? `${renderer.width}x${renderer.height} resolution ${renderer.resolution}` : 'n/a'}`,
|
|
102
|
+
`app.size ${appSize ? `${appSize.width}x${appSize.height}` : 'n/a'}`,
|
|
103
|
+
`resizer ${resizer ? `scale ${Math.round(resizer.scale * 1000) / 1000} safeArea ${JSON.stringify(resizer.safeArea)}` : 'n/a'}`,
|
|
104
|
+
...events,
|
|
105
|
+
].join('\n');
|
|
106
|
+
|
|
107
|
+
this._visibleBottom.style.top = `${(vv ? vv.offsetTop + vv.height : window.innerHeight) - 2}px`;
|
|
108
|
+
if (canvasRect) {
|
|
109
|
+
this._canvasBottom.style.top = `${canvasRect.bottom - 2}px`;
|
|
110
|
+
this._canvasBottom.style.display = 'block';
|
|
111
|
+
} else {
|
|
112
|
+
this._canvasBottom.style.display = 'none';
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private _measureViewportUnit(unit: string): number {
|
|
117
|
+
const probe = document.createElement('div');
|
|
118
|
+
probe.style.cssText = `position:fixed;height:100${unit};visibility:hidden;pointer-events:none;`;
|
|
119
|
+
document.body.appendChild(probe);
|
|
120
|
+
const height = probe.getBoundingClientRect().height;
|
|
121
|
+
probe.remove();
|
|
122
|
+
return height;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
private _measureSafeAreaCssPx(): { top: number; right: number; bottom: number; left: number } {
|
|
126
|
+
if (!this._safeAreaProbe) {
|
|
127
|
+
this._safeAreaProbe = document.createElement('div');
|
|
128
|
+
this._safeAreaProbe.style.cssText =
|
|
129
|
+
'position:fixed;top:0;left:0;width:0;height:0;visibility:hidden;pointer-events:none;' +
|
|
130
|
+
'padding-top:env(safe-area-inset-top, 0px);padding-right:env(safe-area-inset-right, 0px);' +
|
|
131
|
+
'padding-bottom:env(safe-area-inset-bottom, 0px);padding-left:env(safe-area-inset-left, 0px);';
|
|
132
|
+
document.body.appendChild(this._safeAreaProbe);
|
|
133
|
+
}
|
|
134
|
+
const style = getComputedStyle(this._safeAreaProbe);
|
|
135
|
+
return {
|
|
136
|
+
top: parseFloat(style.paddingTop) || 0,
|
|
137
|
+
right: parseFloat(style.paddingRight) || 0,
|
|
138
|
+
bottom: parseFloat(style.paddingBottom) || 0,
|
|
139
|
+
left: parseFloat(style.paddingLeft) || 0,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
private _getCanvas(): HTMLCanvasElement | null {
|
|
144
|
+
try {
|
|
145
|
+
return (this.app.renderer?.canvas as HTMLCanvasElement | undefined) ?? null;
|
|
146
|
+
} catch {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private _getRenderer(): { width: number; height: number; resolution: number } | null {
|
|
152
|
+
try {
|
|
153
|
+
return this.app.renderer ?? null;
|
|
154
|
+
} catch {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
private _getAppSize(): { width: number; height: number } | null {
|
|
160
|
+
try {
|
|
161
|
+
return this.app.size ?? null;
|
|
162
|
+
} catch {
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private _getResizer(): { scale: number; safeArea: unknown } | null {
|
|
168
|
+
try {
|
|
169
|
+
return this.app.resizer ?? null;
|
|
170
|
+
} catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
package/src/plugins/index.ts
CHANGED
|
@@ -13,6 +13,8 @@ export * from './LookupPlugin';
|
|
|
13
13
|
export * from './Plugin';
|
|
14
14
|
export * from './PopupManagerPlugin';
|
|
15
15
|
export * from './ResizerPlugin';
|
|
16
|
+
export * from './ScreenDebugPlugin';
|
|
17
|
+
export * from './screenDebugFlag';
|
|
16
18
|
export * from './SceneManagerPlugin';
|
|
17
19
|
export * from './TimerPlugin';
|
|
18
20
|
export * from './WebEventsPlugin';
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { shouldEnableScreenDebug } from './screenDebugFlag';
|
|
3
|
+
|
|
4
|
+
describe('shouldEnableScreenDebug', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
window.history.replaceState({}, '', '/');
|
|
7
|
+
window.localStorage.clear();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.restoreAllMocks();
|
|
12
|
+
window.history.replaceState({}, '', '/');
|
|
13
|
+
window.localStorage.clear();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it('enables and persists from the query string', () => {
|
|
17
|
+
window.history.replaceState({}, '', '/?caper-screen-debug=1');
|
|
18
|
+
expect(shouldEnableScreenDebug()).toBe(true);
|
|
19
|
+
expect(window.localStorage.getItem('caper:screen-debug')).toBe('1');
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it('disables and clears persistence from the query string', () => {
|
|
23
|
+
window.localStorage.setItem('caper:screen-debug', '1');
|
|
24
|
+
window.history.replaceState({}, '', '/?caper-screen-debug=0');
|
|
25
|
+
expect(shouldEnableScreenDebug()).toBe(false);
|
|
26
|
+
expect(window.localStorage.getItem('caper:screen-debug')).toBeNull();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('enables from a persisted key without a query value', () => {
|
|
30
|
+
window.localStorage.setItem('caper:screen-debug', '1');
|
|
31
|
+
expect(shouldEnableScreenDebug()).toBe(true);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it('stays disabled without a query value or persisted key', () => {
|
|
35
|
+
expect(shouldEnableScreenDebug()).toBe(false);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('falls back to the query value when localStorage throws', () => {
|
|
39
|
+
vi.spyOn(Storage.prototype, 'setItem').mockImplementation(() => {
|
|
40
|
+
throw new Error('unavailable');
|
|
41
|
+
});
|
|
42
|
+
window.history.replaceState({}, '', '/?caper-screen-debug=true');
|
|
43
|
+
expect(shouldEnableScreenDebug()).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
const queryKey = 'caper-screen-debug';
|
|
2
|
+
const storageKey = 'caper:screen-debug';
|
|
3
|
+
|
|
4
|
+
export function shouldEnableScreenDebug(): boolean {
|
|
5
|
+
if (typeof window === 'undefined') {
|
|
6
|
+
return false;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const value = new URLSearchParams(window.location.search).get(queryKey);
|
|
10
|
+
const enabledByQuery = value === '1' || value === 'true';
|
|
11
|
+
const disabledByQuery = value === '0' || value === 'false';
|
|
12
|
+
|
|
13
|
+
try {
|
|
14
|
+
if (enabledByQuery) {
|
|
15
|
+
window.localStorage.setItem(storageKey, '1');
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
if (disabledByQuery) {
|
|
19
|
+
window.localStorage.removeItem(storageKey);
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
return window.localStorage.getItem(storageKey) === '1';
|
|
23
|
+
} catch {
|
|
24
|
+
return enabledByQuery;
|
|
25
|
+
}
|
|
26
|
+
}
|
package/src/version.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// This file is auto-generated during the build process.
|
|
2
|
-
export const version: string = '0.
|
|
3
|
-
export const pixiVersion: string = '8.
|
|
2
|
+
export const version: string = '0.7.0';
|
|
3
|
+
export const pixiVersion: string = '8.20.0';
|