From cfc0bddb1f0be7bffc07946c8dab4b1039ab1dd3 Mon Sep 17 00:00:00 2001 From: Dejvino Date: Wed, 28 Oct 2026 15:33:07 +0100 Subject: [PATCH] =?UTF-8?q?Metabolism:=20browser=20fix=20=E2=80=94=20the?= =?UTF-8?q?=20arena=20stays=20a=20plain=20ArrayBuffer=20unless=20a=20regio?= =?UTF-8?q?n=20pool=20will=20share=20it;=20vite=20serves=20cross-origin-is?= =?UTF-8?q?olation=20headers=20so=20the=20browser=20can=20opt=20into=20SAB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- metabolism/src/sim/world.js | 10 +++++++++- metabolism/vite.config.js | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/metabolism/src/sim/world.js b/metabolism/src/sim/world.js index 3260c9e..a01255e 100644 --- a/metabolism/src/sim/world.js +++ b/metabolism/src/sim/world.js @@ -209,7 +209,15 @@ export class World { const fcSide0 = Math.max(16, Math.round(field / 2)); // the layout needs the coarse shape const spec = layout ?? arenaLayout(field, this.m, B0, fcSide0); this.layout = spec; - this.arena = sab ?? new SharedArrayBuffer((spec.bytes + 3) & ~3); + // The arena is shared ONLY when a region pool will actually spawn: + // browsers expose SharedArrayBuffer solely under cross-origin + // isolation, and the serial world must never require it. + const wantPool = !bare && workers > 1 && !!workerCtor() && + typeof SharedArrayBuffer !== 'undefined'; + if (!wantPool) workers = 0; + this.arena = sab ?? ((wantPool) + ? new SharedArrayBuffer((spec.bytes + 3) & ~3) + : new ArrayBuffer((spec.bytes + 3) & ~3)); { let off = 0; for (const it of spec.items) { it.offset = off; off += (it.bytes + 3) & ~3; } diff --git a/metabolism/vite.config.js b/metabolism/vite.config.js index 29c7440..3af11c0 100644 --- a/metabolism/vite.config.js +++ b/metabolism/vite.config.js @@ -142,4 +142,20 @@ function songBankPlugin() { export default defineConfig({ plugins: [songBankPlugin()], + // Cross-origin isolation: browsers expose SharedArrayBuffer only when + // both headers are present. The region pool needs it once the sim runs + // inside a browser worker; the demo is fully same-origin, so requiring + // corp costs nothing here. + server: { + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, + }, + preview: { + headers: { + 'Cross-Origin-Opener-Policy': 'same-origin', + 'Cross-Origin-Embedder-Policy': 'require-corp', + }, + }, }); \ No newline at end of file