game-maker / suite (push) Successful in 12m1s
Sounds follow the road fonts already paved: the file goes to the server content-addressed under its sha256, the project keeps a named asset that points at it, and nothing is ever re-encoded. The format is read from the file's own signature, not from what the browser claims - the same .m4a arrives as audio/mp4, audio/x-m4a or as nothing at all. Playing is two nodes. "Play sound" takes the asset and may raise or lower its volume; every call is its own voice, so two jumps in a row are two jumps heard. Its loop input is a choice of three - from the asset, on, off - because a checkbox has to spend one of its two positions on "not set" and would lose a case: an asset that loops could then never be played once. Below the graph core stays browser-free: NodeContext hands out an asset id, BehaviorSystem resolves it against the project and folds the asset's own volume and loop into the call, and only viewport/SoundLibrary knows about Web Audio. A run without a sink plays nothing instead of throwing. The CI browser is muted, so the ear is no witness: the debug hook counts started and stopped voices, and step 34 reads that counter.
42 lines
1.5 KiB
JavaScript
42 lines
1.5 KiB
JavaScript
import { spawn } from 'node:child_process';
|
||
|
||
const FLAGS = [
|
||
'--headless',
|
||
'--hide-scrollbars',
|
||
/**
|
||
* Measured (idle editor, 20 s): software WebGL 373% of a core at 8 fps, HD 630 via ANGLE/Vulkan 69% at
|
||
* 56 fps; no software fallback on purpose. `--use-angle=gl` and `--use-gl=egl` get no WebGL context at all.
|
||
*/
|
||
'--use-angle=vulkan',
|
||
'--ignore-gpu-blocklist',
|
||
'--enable-gpu',
|
||
'--enable-features=Vulkan',
|
||
// None of this serves a headless check, and its stderr was full of GCM sign-in retries.
|
||
'--disable-background-networking',
|
||
'--disable-sync',
|
||
'--disable-extensions',
|
||
'--no-first-run',
|
||
// Nothing is meant to be heard here – but the sounds still have to *run*, or the sound checks
|
||
// would be measuring a browser that refuses to start a voice rather than an editor that never
|
||
// asked for one. Muted plus autoplay-allowed is exactly that: it plays, silently.
|
||
'--mute-audio',
|
||
'--autoplay-policy=no-user-gesture-required',
|
||
];
|
||
|
||
/** Starts chromium with the CDP port open; `proc.stderr` carries its last words. */
|
||
export function launchBrowser({ port, width, height }) {
|
||
const proc = spawn(
|
||
'chromium',
|
||
// --no-sandbox: this container runs as root, where chromium refuses to start otherwise.
|
||
[
|
||
...FLAGS,
|
||
'--no-sandbox',
|
||
`--remote-debugging-port=${port}`,
|
||
`--window-size=${width},${height}`,
|
||
'about:blank',
|
||
],
|
||
{ stdio: ['ignore', 'ignore', 'pipe'] },
|
||
);
|
||
return { proc, stop: () => proc.kill('SIGTERM'), where: 'local chromium' };
|
||
}
|