Tachibana

Documentación › Compilación de navegador

Compilación WebAssembly (navegador)

Phosphoric compila a WebAssembly mediante Emscripten: el emulador completo (CPU 6502, memoria, VIA, PSG, ULA, teclado, casete, disco) funciona en una pestaña, renderizado en un <canvas>, audio por Web Audio, teclado por el DOM — reutilizando la ruta SDL2 existente (puerto SDL de Emscripten).

Requisitos

Emscripten SDK activo (emcc en el PATH):

git clone https://github.com/emscripten-core/emsdk
cd emsdk && ./emsdk install latest && ./emsdk activate latest
source ./emsdk_env.sh

Compilar y ejecutar

make wasm
(cd web && python3 -m http.server 8000)
# abrir http://localhost:8000/phosphoric.html

make wasm produce en web/: phosphoric.html (página + canvas), phosphoric.js, phosphoric.wasm y phosphoric.data (las ROM de roms/ precargadas en el sistema de archivos virtual). La página arranca el Atmos (-r /roms/basic11b.rom); haz clic en la pantalla para el foco de teclado y el audio.

Despliegue: assets necesarios + CSP

La página carga su lógica (definición de Module, UI, teclado, arrastrar y soltar) desde web/shell.js — un archivo externo que hay que desplegar junto a phosphoric.html/.js/.wasm/.data. shell.js está versionado (fuente) y referenciado por phosphoric.html mediante <script src="shell.js">.

Esta externalización hace el paquete compatible con una Content-Security-Policy estricta. Un host que sirva la página bajo script-src 'self' 'wasm-unsafe-eval' bloquearía un <script> inline (script-src-elem) → Module nunca definido → Module.canvas undefined → error fatal en createContext WebGL. Al externalizar todo el JS (y reemplazar el atributo inline oncontextmenu del canvas por un listener del DOM), phosphoric.html no tiene ningún script/manejador inline: funciona bajo CSP estricta igual que bajo una permisiva (GitHub Pages).

CSP mínima requerida

Content-Security-Policy: script-src 'self' 'wasm-unsafe-eval'

⚠️ No quitar 'wasm-unsafe-eval': bajo un script-src 'self' desnudo, la compilación WebAssembly se rechaza y el emulador no arranca. Tras la corrección de externalización, no se necesitan ni 'unsafe-inline' ni hash/nonce — solo el token WASM.

Un bloqueo script-src-elem cuya fuente sea sandbox eval code (y no phosphoric.html) proviene de una extensión del navegador, no de Phosphoric: la página no inyecta ningún script inline ni eval. Sin efecto sobre el emulador.

Interfaz (página web)

La página muestra un raíl de iconos vertical a la izquierda (estilo JOric) y el teclado ORIC en overlay:

CTRL+T y otros acordes: el navegador reserva ciertos atajos (CTRL+T = nueva pestaña) a nivel del SO. Usa la tecla CTRL del teclado virtual: escribe la matriz ORIC mediante una llamada C directa, así que el navegador no la intercepta.

Sirve los archivos por HTTP (no file://): el navegador se niega a cargar un .wasm desde el sistema de archivos local.

Detalles técnicos

Fidelidad — verificado

La salida WASM es idéntica byte a byte a la compilación nativa con entradas idénticas: un arranque Atmos headless compilado a WASM y ejecutado bajo Node.js produce la misma captura PPM exacta que el binario nativo (probado a 2M y 5M ciclos). El determinismo de ciclo exacto del núcleo se preserva a través de la compilación WebAssembly.

El renderizado en navegador también se validó: la página cargada en Chromium headless muestra la pantalla de arranque Atmos correcta, y la entrada de teclado funciona (escribir PRINT 6*7 + RETURN muestra 42) — arranque de ROM → inyección de teclado → ejecución BASIC → renderizado, enteramente en el navegador.

Reproducido de docs/wasm.md (versión de referencia actualizada en GitHub).

← Documentación · Abrir el emulador →