import jsnes from "jsnes"; var SCREEN_WIDTH = 256; var SCREEN_HEIGHT = 240; var FRAMEBUFFER_SIZE = SCREEN_WIDTH * SCREEN_HEIGHT; var framebuffer_u8, framebuffer_u32; var nes = new jsnes.NES({ onFrame: function (framebuffer_24) { for (var i = 0; i < FRAMEBUFFER_SIZE; i++) framebuffer_u32[i] = 0xff000000 | framebuffer_24[i]; postMessage(framebuffer_u8); }, }); var pressedKeys = {}; onmessage = (msg) => { if (msg.data.rom) { nes_load_url(msg.data.rom); return; } const keys = { up: jsnes.Controller.BUTTON_UP, down: jsnes.Controller.BUTTON_DOWN, left: jsnes.Controller.BUTTON_LEFT, right: jsnes.Controller.BUTTON_RIGHT, a: jsnes.Controller.BUTTON_A, b: jsnes.Controller.BUTTON_B, start: jsnes.Controller.BUTTON_START, select: jsnes.Controller.BUTTON_SELECT, }; for (let i = 0; i < Object.keys(keys).length; i++) { const key = Object.keys(keys)[i]; const val = keys[key]; if (pressedKeys[key] && !msg.data.keys[key]) { // key was pressed and no longer is pressed nes.buttonUp(1, val); } else if (!pressedKeys[key] && msg.data.keys[key]) { // key was not pressed but now it is nes.buttonDown(1, val); } } pressedKeys = msg.data.keys; }; function nes_init() { // Allocate framebuffer array. var buffer = new ArrayBuffer(SCREEN_WIDTH * SCREEN_HEIGHT * 4); framebuffer_u8 = new Uint8ClampedArray(buffer); framebuffer_u32 = new Uint32Array(buffer); } function nes_boot(rom_data) { nes.loadROM(rom_data); } function nes_load_url(path) { nes_init(); var req = new XMLHttpRequest(); req.open("GET", path); req.overrideMimeType("text/plain; charset=x-user-defined"); req.onerror = () => console.log(`Error loading ${path}: ${req.statusText}`); req.onload = function () { if (this.status === 200) { nes_boot(this.responseText); function doit() { setTimeout(() => { doit(); nes.frame(); }, 1000.0 / 60); } doit(); } else if (this.status === 0) { // Aborted, so ignore error } else { req.onerror(); } }; req.send(); }