feat(terminal): add WebGL renderer toggle in settings

Adds a 'WebGL Renderer' toggle to Settings > Appearance (desktop). WebGL
stays on by default; users can turn it off to force the DOM renderer when
they hit GPU glitches, without needing the ?nowebgl URL param. Explicit
opt-in (or ?webgl=force) clears a stale auto-fallback marker. Mobile skip
and the long-task auto-fallback safety net are unchanged.

The device/param/sticky/pref interaction is factored into a pure,
unit-tested shouldSkipWebGL() helper in constants.js.
This commit is contained in:
Kevin Crawley
2026-07-01 20:41:38 -05:00
parent b7ff54b2ec
commit bf36eb0db4
6 changed files with 138 additions and 8 deletions
+76
View File
@@ -215,4 +215,80 @@ describe('WebGL longtask auto-fallback', () => {
expect(result).toBeNull();
});
});
describe('shouldSkipWebGL — renderer toggle + fallback precedence', () => {
type Input = {
deviceType?: string;
noWebglParam?: boolean;
forceParam?: boolean;
stickyDisabled?: boolean;
userPrefEnabled?: boolean;
};
const run = async (input: Input): Promise<{ skip: boolean; clearSticky: boolean }> =>
page.evaluate(
(i) =>
(
window as unknown as {
shouldSkipWebGL: (x: unknown) => { skip: boolean; clearSticky: boolean };
}
).shouldSkipWebGL(i),
input
);
it('exposes shouldSkipWebGL on window', async () => {
const t = await page.evaluate(
() => typeof (window as unknown as { shouldSkipWebGL?: unknown }).shouldSkipWebGL
);
expect(t).toBe('function');
});
it('mobile always skips, even when the user opted in', async () => {
expect(await run({ deviceType: 'mobile', userPrefEnabled: true })).toEqual({
skip: true,
clearSticky: false,
});
});
it('explicit opt-out skips without touching the sticky marker', async () => {
expect(await run({ deviceType: 'desktop', userPrefEnabled: false, stickyDisabled: false })).toEqual({
skip: true,
clearSticky: false,
});
});
it('?nowebgl is a one-shot opt-out (sticky untouched)', async () => {
expect(await run({ deviceType: 'desktop', noWebglParam: true })).toEqual({
skip: true,
clearSticky: false,
});
});
it('explicit opt-in enables and clears a stale sticky marker', async () => {
expect(await run({ deviceType: 'desktop', userPrefEnabled: true, stickyDisabled: true })).toEqual({
skip: false,
clearSticky: true,
});
});
it('?webgl=force enables and clears the sticky marker', async () => {
expect(await run({ deviceType: 'desktop', forceParam: true, stickyDisabled: true })).toEqual({
skip: false,
clearSticky: true,
});
});
it('untouched default respects an active sticky marker', async () => {
expect(await run({ deviceType: 'desktop', stickyDisabled: true })).toEqual({
skip: true,
clearSticky: false,
});
});
it('untouched default enables WebGL when nothing is disabling it', async () => {
expect(await run({ deviceType: 'desktop', stickyDisabled: false })).toEqual({
skip: false,
clearSticky: false,
});
});
});
});