Browser Checks
Essential browser checks before publishing. These cover HTML5 and WebAssembly (Unity/Godot).
Supported Browsers
- Latest stable versions of Chrome/Edge/Firefox desktop.
- Safari iOS/iPadOS 16+ (with specific audio/fullscreen constraints).
- Private mode / restricted profile: plan for graceful degradation.
Isolation (COOP/COEP) & Engines
For Unity/Godot (WebAssembly + threads/SharedArrayBuffer), check Strict Isolation in the game form.
The game will be served under https://games.voidrush.com/iso/<slug>/… with the headers:
Cross-Origin-Opener-Policy: same-origin and Cross-Origin-Embedder-Policy: require-corp.
Avoid any non-CORS CDN resources (COEP will block them).
Capability Detection (Ready-to-Use Snippet)
Run this early (before heavy loading) to display a clear help message if a core feature is missing.
function detectCapabilities() {
const canvas = document.createElement('canvas');
const webgl2 = !!canvas.getContext('webgl2');
const webgl1 = !!(canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
const wasm = typeof WebAssembly === 'object';
const sab = typeof SharedArrayBuffer === 'function';
const coi = self.crossOriginIsolated === true; // true if COOP/COEP active
const audio = !!(window.AudioContext || window.webkitAudioContext);
const idb = !!window.indexedDB;
const gamepad= 'getGamepads' in navigator;
return { webgl2, webgl1, wasm, sab, coi, audio, idb, gamepad };
}
function minimalGuard({ requireIsolation=false, requireWebGL=true }) {
const c = detectCapabilities();
// WebGL
if (requireWebGL && !c.webgl1) return { ok:false, reason:"WebGL unavailable" };
// Unity/Godot (WASM + threads)
if (requireIsolation) {
if (!c.wasm) return { ok:false, reason:"WebAssembly unavailable" };
if (!c.sab) return { ok:false, reason:"SharedArrayBuffer required" };
if (!c.coi) return { ok:false, reason:"Cross-origin isolated context required (COOP/COEP)" };
}
return { ok:true, reason:"OK" };
}
// Exemple usage:
// const g = minimalGuard({ requireIsolation:true, requireWebGL:true });
// if (!g.ok) showFatalOverlay(g.reason);
User Error Overlay
Show a readable message to players instead of a blank screen.
<div id="fatal-overlay" style="display:none;position:fixed;inset:0;background:#111;color:#fff;padding:24px;z-index:9999"></div>
<script>
function showFatalOverlay(msg){
const el = document.getElementById('fatal-overlay');
el.innerHTML = "<h2>Cannot Launch Game</h2><p>"+msg+
"</p><p>Try updating your browser, enabling WebGL/WebAssembly, or opening in Chrome/Edge/Firefox.</p>";
el.style.display = 'block';
}
</script>
Audio, Fullscreen & Controls
- Mobile Audio Unlocking: iOS requires a user gesture. Create the AudioContext on the first click.
let audioCtx;
function unlockAudio(){
if (!audioCtx) {
const AC = window.AudioContext || window.webkitAudioContext;
if (AC) audioCtx = new AC();
}
document.removeEventListener('pointerdown', unlockAudio);
}
document.addEventListener('pointerdown', unlockAudio, { once:true });
- Fullscreen: request it on user action (“Fullscreen” button).
- Keyboard/Mouse/Gamepad: test
navigator.getGamepads()and plan for a touch fallback.
Storage & Persistence
- Check
indexedDBandlocalStorage(private mode may restrict either).
async function storageCheck(){
if (!('indexedDB' in window)) return false;
try {
const db = await new Promise((ok, ko) => {
const r = indexedDB.open('vr_probe', 1);
r.onupgradeneeded = ()=> r.result.createObjectStore('s');
r.onsuccess = ()=> ok(r.result);
r.onerror = ()=> ko(r.error);
});
db.close();
return true;
} catch { return false; }
}
Performance & Stability
- Initial Budget: < 50 MB (initial download) for a good time-to-play.
- Avoid repeated JS errors: capture and aggregate.
- Pause the game when the tab is not visible.
document.addEventListener('visibilitychange', () => {
if (document.hidden) { window.game?.pause?.(); }
else { window.game?.resume?.(); }
});
// Optional: detect "long tasks" (>50ms) to diagnose janks
if ('PerformanceObserver' in window) {
try {
new PerformanceObserver((list) => {
for (const e of list.getEntries()) {
if (e.duration > 80) console.warn('Long task', Math.round(e.duration)+'ms', e.name||'');
}
}).observe({ entryTypes: ['longtask'] });
} catch {}
}
Network & CORS
- In isolated mode (Unity/Godot), all third-party resources must be served with correct CORS
(
Cross-Origin-Resource-Policy/Cross-Origin-Resource-Sharevia appropriateAccess-Control-Allow-Origin). - Prefer loading everything from the platform (same site) to avoid COEP blockages.
Validation Checklist
- WebGL1+ OK, WebAssembly OK (if WASM engine),
crossOriginIsolated= true for Unity/Godot. - No recurring JS errors or blocked assets (network): the Network tab must not display 403/404/blocked-by-client on essential assets.
- Audio starts after first click; fullscreen accessible; keyboard/touch/gamepad controls functional.
- Storage (IndexedDB/LocalStorage) accessible or proper fallback.
- Reasonable load time (initial bundle < 50 MB, no looping long task freeze).
Quick Integration (Example)
Integrate these safeguards before your main boot:
(async () => {
const guard = minimalGuard({ requireIsolation: /* true if Unity/Godot */ false, requireWebGL:true });
if (!guard.ok) { showFatalOverlay(guard.reason); return; }
if (!(await storageCheck())) console.warn('IndexedDB unavailable: save fallback (SDK Data Module recommended).');
// Here: start your game
// await startGame();
})();
Need examples of headers or embeds between voidrush.com and games.voidrush.com?
Consult the Requirements → Basic launch section and the Resources → Assets page.