How to embed NES ROM on Itch.io
Moderator: Moderators
How to embed NES ROM on Itch.io
I put together a little tutorial on how to embed your NES games in browser on Itch.io. Hopefully others can get some benefit out of it!
http://www.matthughson.com/2020/07/17/n ... n-itch-io/
One thing I am not happy with is the lack of controller support. If any more experience web people want to try adding that, I would love to add it to the tutorial!
I think it looks like it just needs to be added to this file: https://github.com/bfirsh/jsnes/blob/ma ... s-embed.js.
You can see it in action here:
https://mhughson.itch.io/from-below
http://www.matthughson.com/2020/07/17/n ... n-itch-io/
One thing I am not happy with is the lack of controller support. If any more experience web people want to try adding that, I would love to add it to the tutorial!
I think it looks like it just needs to be added to this file: https://github.com/bfirsh/jsnes/blob/ma ... s-embed.js.
You can see it in action here:
https://mhughson.itch.io/from-below
Last edited by Goose2k on Fri Jul 17, 2020 2:06 pm, edited 1 time in total.
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
Looks like there is a JS gamepad API
https://developer.mozilla.org/en-US/doc ... amepad_API
Seems like you could use this to poll a controller and hook it into jsnes.Controller.BUTTON_whatever... You should take a stab at it! Maybe i'll try later tonight...
Re: How to embed NES ROM on Itch.io
Yah, that's exactly what I was thinking!Controllerhead wrote: ↑Fri Jul 17, 2020 1:29 pmLooks like there is a JS gamepad API
https://developer.mozilla.org/en-US/doc ... amepad_API
If you give it a shot, let me know!!
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
Ok! So i got this working =)
You can play it here:
http://www.nesblast.com/jsnes
Right now my demo:
- Detects a Joystick
- Switches to Joystick when detected
- All controls and axis deadzone are customizable
- Saves keyboard and joystick controls in a cookie in JSON
- Code might be somewhat legible
I used this article / demo and borrowed heavily from it:
http://beej.us/blog/data/javascript-gamepad/
Anyway, i attached the source files to this post. I would DIF them against the JSNES embed example to see what i did. Also feel free to F12 the page and go though the code / debugger, and let me know if you have any questions as far as porting it over into your tutorial, or anything really. All of the code is vanilla JS / HTML, so i hope it is readable and clear what it does. This was fun! Enjoy.
You can play it here:
http://www.nesblast.com/jsnes
Right now my demo:
- Detects a Joystick
- Switches to Joystick when detected
- All controls and axis deadzone are customizable
- Saves keyboard and joystick controls in a cookie in JSON
- Code might be somewhat legible
I used this article / demo and borrowed heavily from it:
http://beej.us/blog/data/javascript-gamepad/
Anyway, i attached the source files to this post. I would DIF them against the JSNES embed example to see what i did. Also feel free to F12 the page and go though the code / debugger, and let me know if you have any questions as far as porting it over into your tutorial, or anything really. All of the code is vanilla JS / HTML, so i hope it is readable and clear what it does. This was fun! Enjoy.
- Attachments
-
- JSNES_joystick_demo.zip
- (6.26 KiB) Downloaded 131 times
Re: How to embed NES ROM on Itch.io
Oh wow! That sounds amazing! I'm out all day today but I'll hopefully be able to try it tonight.
Re: How to embed NES ROM on Itch.io
It works well! Probably needs a more sophisticated configuration panel, but I was able to play Metroid (after swapping A and B) without any issues at all! With a RetroUSB and running in full screen, it's pretty damn close to the real thing; all you'd really need is Blargg's or Bisqwit's NTSC filter from there.
For accuracy, I wonder how complicated it would be to cross-compile the Mesen core to Wasm?
For accuracy, I wonder how complicated it would be to cross-compile the Mesen core to Wasm?
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
Not bad considering i slogged it out in one night =)
You mean JSNES or the joystick support i added? What would you add? JSNES itself has no configuration whatsoever lol. I was thinking about deep diving into JSNES and seeing if i could contribute some features. I've built it before and already fixed the embed demo on github and that got merged. I have done some JS / Canvas stuff in the past too, so, what would you like to see? Maybe i'll fork it and goto town. I do have other projects i'm working on currently, so, it wouldn't be a priority for me, but, it might make a fun sidequest.
Mesen is a truly wonderful emulator for accuracy and development; and has some incredible features. That said, it is kind of a resource hog. It also uses C, C++, C#, and a few libraries; it's complicated. I don't know the ins and outs of compiling with emscripten or however you would even go about that. If you did even get it to compile, i have some serious doubts about how well it would run in a browser... FCEUX might be a better candidate for wasm, it's much more efficient and uses more mature features of C and C++, so i'd imagine if you were crazy enough to take on such a task, i might go that route.
Re: How to embed NES ROM on Itch.io
I meant the joystick support. It works 100% perfectly, but it could use some UXD, like using a diagram of the NES controller, or auto-configuring for common controllers (like the USB NES RetroPad). Basically just spit and polish; the bones are perfectControllerhead wrote: ↑Sat Jul 18, 2020 10:08 am You mean JSNES or the joystick support i added? What would you add?
Mesen's core, including the video filters, is all C++; only the GUI and some helper utilities are in C#. There's a lot even in the core library that wouldn't need to be there for a simple web-based player - Lua, 7-Zip, the debugger, HD packs... Probably it's possible to strip it down to the bare bones, compile to Wasm, connect the input to the Gamepad API, the video to Canvas, and the audio to the Web Audio API. In theory, it should run almost as fast as native in browsers that support Wasm!Controllerhead wrote: ↑Sat Jul 18, 2020 10:08 am Mesen is a truly wonderful emulator for accuracy and development; and has some incredible features. That said, it is kind of a resource hog. It also uses C, C++, C#, and a few libraries; it's complicated. I don't know the ins and outs of compiling with emscripten or however you would even go about that. If you did even get it to compile, i have some serious doubts about how well it would run in a browser... FCEUX might be a better candidate for wasm, it's much more efficient and uses more mature features of C and C++, so i'd imagine if you were crazy enough to take on such a task, i might go that route.
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
This demo, which is what it is, a demo, isn't really meant to be public facing or a finished product. I mean, there isn't an ounce of CSS on that entire page =p I also only have one joypad, an Adaptoid N64 USB controller adapter circa '99. It still works after 20 years! I don't know how i could go about adding controller support to controllers i don't have. I think taking 30 seconds to customize your controller and having it save in a cookie is way more than adequate.rox_midge wrote: ↑Sat Jul 18, 2020 11:30 amit could use some UXD, like using a diagram of the NES controller, or auto-configuring for common controllers (like the USB NES RetroPad).Controllerhead wrote: ↑Sat Jul 18, 2020 10:08 am You mean JSNES or the joystick support i added? What would you add?
My work here is done. That's about all i can ask for =)
I'm not really interested in pursuing this further. I only did this quick little one off thing out of curiousity and to help someone else. I'm not really a UX dude naturally. "Programmer art" is about all i can muster. I can't even draw a stick figure straight lol. One of the reasons i am targeting the NES is that it isn't art intensive visually. The cycle counting / byte conserving / 6502 ASM @ 1.7 Mhz aspect is a fun challenge. I thrive on engines and bones. And Music, i can do that =) Love me some chiptunes! Anyway, if someone else wants to jazz this thing up, be my guest! I'd be happy to help.
Bruhhhhh if you can get Mesen to run on a browser that would be epic! You seem to know way more than i do about it. Clearly you are the chosen one. Go forth my son and compileth!rox_midge wrote: ↑Sat Jul 18, 2020 11:30 am Mesen's core, including the video filters, is all C++; only the GUI and some helper utilities are in C#. There's a lot even in the core library that wouldn't need to be there for a simple web-based player - Lua, 7-Zip, the debugger, HD packs... Probably it's possible to strip it down to the bare bones, compile to Wasm, connect the input to the Gamepad API, the video to Canvas, and the audio to the Web Audio API. In theory, it should run almost as fast as native in browsers that support Wasm!
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
Oh wow. This is awesome!
At first glance, this appears far superior to JSNES. it runs with silky smooth graphics and audio where JSNES is a bit jittery. WebGL is so much smoother than JS Canvas. FCEUX has amazing accuracy and compatibility. Joystick seems to work. I'll have to play with it some more, and i'm not sure how cranky WebGL will be with embedding it in a page, but i think i'll be using this for any future plans personally. I did not know this existed; i'm glad i do now. Thanks for the link!
...you know, i figured FCEUX would be a good target for emscripten heh. It is!
Re: How to embed NES ROM on Itch.io
I just gave it a go, and when I try to fun locally with the files you provided I get this error:
Since your zip didn't include jsnes.min.js, I had to use the version I got from git a few days ago.
Are we running against different versions of the emulator or something maybe?
357850: Unable to get property 'frame' of undefined or null reference
nes-embed.js (65,3)
Code: Select all
function audio_callback(event){
var dst = event.outputBuffer;
var len = dst.length;
var didFrame = false
if(playAudio){
// Attempt to avoid buffer underruns.
if(audio_remain() < AUDIO_BUFFERING){
nes.frame() // ISSUE IS HERE I THINK
didFrame = true
}
Are we running against different versions of the emulator or something maybe?
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
Oops! Maybe. I was playing with stuff. Here is my source!
Try loading this though instead of my source. It should work, i don't think i changed anything that would break it.
Code: Select all
<script type="text/javascript" src="https://unpkg.com/jsnes/dist/jsnes.min.js"></script>
Try my build, i guess, and let me know!
- Attachments
-
- src.zip
- (193.42 KiB) Downloaded 127 times
Re: How to embed NES ROM on Itch.io
Sorry, it's been a while and I ended up just implementing gamepad support myself based on this article (https://developer.mozilla.org/en-US/doc ... amepad_API).
You can find a zip of an example, used for From Below. This is what is uploaded here: https://mhughson.itch.io/from-below
Excerpt nes-embed.js:
You can find a zip of an example, used for From Below. This is what is uploaded here: https://mhughson.itch.io/from-below
Excerpt nes-embed.js:
Code: Select all
/////////////////////
// GAMEPAD SUPPORT
//
// Based on documentation here: https://developer.mozilla.org/en-US/docs/Web/API/Gamepad_API/Using_the_Gamepad_API
/////////////////////
var haveEvents = 'ongamepadconnected' in window;
var controllers = {};
// Once the presses a button on one of the controllers, this will store
// the index of that controller so that only that controller is checked
// each frame. This is to avoid additional controllers triggering key_up
// events when they are just sitting there inactive.
var cur_controller_index = -1;
function connecthandler(e) {
addgamepad(e.gamepad);
}
function addgamepad(gamepad) {
controllers[gamepad.index] = gamepad;
requestAnimationFrame(updateStatus);
}
function disconnecthandler(e) {
removegamepad(e.gamepad);
}
function removegamepad(gamepad) {
delete controllers[gamepad.index];
}
// Check all controllers to see if player has pressed any buttons.
// If they have, store that as the current controller.
function findController()
{
var i = 0;
var j;
for (j in controllers)
{
var controller = controllers[j];
for (i = 0; i < controller.buttons.length; i++)
{
var val = controller.buttons[i];
var pressed = val == 1.0;
if (typeof(val) == "object")
{
pressed = val.pressed;
val = val.value;
}
if (pressed)
{
cur_controller_index = j;
}
}
}
}
function updateStatus()
{
if (!haveEvents)
{
scangamepads();
}
// If a controller has not yet been chosen, check for one now.
if (cur_controller_index == -1)
{
findController();
}
// Allow for case where controller was chosen this frame
if (cur_controller_index != -1)
{
var i = 0;
var j;
var controller = controllers[cur_controller_index];
for (i = 0; i < controller.buttons.length; i++)
{
var val = controller.buttons[i];
var pressed = val == 1.0;
if (typeof(val) == "object")
{
pressed = val.pressed;
val = val.value;
}
var player = 1 //parseInt(j,10) + 1;
if (pressed)
{
var callback = nes.buttonDown;
switch(i)
{
case 12: // UP
callback(player, jsnes.Controller.BUTTON_UP); break;
case 13: // Down
callback(player, jsnes.Controller.BUTTON_DOWN); break;
case 14: // Left
callback(player, jsnes.Controller.BUTTON_LEFT); break;
case 15: // Right
callback(player, jsnes.Controller.BUTTON_RIGHT); break;
case 1: // 'A'
callback(player, jsnes.Controller.BUTTON_A); break;
case 0: // 'B'
callback(player, jsnes.Controller.BUTTON_B); break;
case 8: // Select
callback(player, jsnes.Controller.BUTTON_SELECT); break;
case 9: // Start
callback(player, jsnes.Controller.BUTTON_START); break;
}
}
else
{
var callback = nes.buttonUp;
switch(i)
{
case 12: // UP
callback(player, jsnes.Controller.BUTTON_UP); break;
case 13: // Down
callback(player, jsnes.Controller.BUTTON_DOWN); break;
case 14: // Left
callback(player, jsnes.Controller.BUTTON_LEFT); break;
case 15: // Right
callback(player, jsnes.Controller.BUTTON_RIGHT); break;
case 1: // 'A'
callback(player, jsnes.Controller.BUTTON_A); break;
case 0: // 'B'
callback(player, jsnes.Controller.BUTTON_B); break;
case 8: // Select
callback(player, jsnes.Controller.BUTTON_SELECT); break;
case 9: // Start
callback(player, jsnes.Controller.BUTTON_START); break;
}
}
// var axes = d.getElementsByClassName("axis");
// for (i = 0; i < controller.axes.length; i++)
// {
// var a = axes[i];
// a.innerHTML = i + ": " + controller.axes[i].toFixed(4);
// a.setAttribute("value", controller.axes[i] + 1);
// }
}
}
requestAnimationFrame(updateStatus);
}
function scangamepads() {
var gamepads = navigator.getGamepads ? navigator.getGamepads() : (navigator.webkitGetGamepads ? navigator.webkitGetGamepads() : []);
for (var i = 0; i < gamepads.length; i++) {
if (gamepads[i]) {
if (gamepads[i].index in controllers) {
controllers[gamepads[i].index] = gamepads[i];
} else {
addgamepad(gamepads[i]);
}
}
}
}
window.addEventListener("gamepadconnected", connecthandler);
window.addEventListener("gamepaddisconnected", disconnecthandler);
if (!haveEvents) {
setInterval(scangamepads, 500);
}
- Attachments
-
- from_below_2020_09_16_v_1_0_0.zip
- (21.68 KiB) Downloaded 67 times
- Controllerhead
- Posts: 314
- Joined: Tue Nov 13, 2018 4:58 am
- Location: $4016
- Contact:
Re: How to embed NES ROM on Itch.io
Well i'm glad you got something you're happy with up and running!
I did take into account having an analog input for movement, and implemented a (crude) axis deadzone slider. You may want to consider that. If i remember correctly, the API returns a number between 0 and 1.
I did take into account having an analog input for movement, and implemented a (crude) axis deadzone slider. You may want to consider that. If i remember correctly, the API returns a number between 0 and 1.