├── make_release.sh ├── .github └── workflows │ └── default.yml └── README.md /make_release.sh: -------------------------------------------------------------------------------- 1 | #! /bin/bash 2 | 3 | # Setup build dirs 4 | rootdir=$(pwd)'/buildout/' 5 | mkdir -p ${rootdir}{data,js,emulatorjstmp} 6 | 7 | ## Grab frontend blobs 8 | # Custom cores 9 | wget https://github.com/linuxserver/libretro-cores/archive/master.tar.gz 10 | tar xf \ 11 | master.tar.gz -C \ 12 | ${rootdir} --strip-components=1 13 | rm -f ${rootdir}/{README.md,master.tar.gz} 14 | # Grab logic from emulatorjs 15 | wget https://github.com/linuxserver/emulatorjs/archive/${GITHUB_TAG}.tar.gz \ 16 | -O ${rootdir}/emulatorjstmp/emulatorjs.tar.gz 17 | tar xf \ 18 | ${rootdir}/emulatorjstmp/emulatorjs.tar.gz -C \ 19 | ${rootdir}/emulatorjstmp/ --strip-components=1 20 | mv \ 21 | ${rootdir}/emulatorjstmp/frontend/js/libretro.js \ 22 | ${rootdir}/js/ 23 | rm -Rf ${rootdir}/emulatorjstmp/ 24 | # Make tarball for release 25 | cd ${rootdir} 26 | tar -czf libretrojs.tar.gz * 27 | mv libretrojs.tar.gz ../ 28 | -------------------------------------------------------------------------------- /.github/workflows/default.yml: -------------------------------------------------------------------------------- 1 | name: libretrojs 2 | on: [workflow_dispatch] 3 | 4 | jobs: 5 | build-latest: 6 | name: Build Latest 7 | runs-on: ubuntu-latest 8 | container: 9 | image: alpine:latest 10 | steps: 11 | - uses: actions/checkout@v2 12 | with: 13 | ref: master 14 | 15 | - name: Setup Build env 16 | run: | 17 | apk add p7zip zip bash curl 18 | export GITHUB_TAG=$(curl -sX GET "https://api.github.com/repos/linuxserver/emulatorjs/releases/latest" | awk '/tag_name/{print $4;exit}' FS='[""]') 19 | echo "GITHUB_TAG=$GITHUB_TAG" >> $GITHUB_ENV 20 | 21 | - name: Build release 22 | env: 23 | GITHUB_TAG: ${{ env.GITHUB_TAG }} 24 | run: | 25 | ./make_release.sh 26 | 27 | - name: Create Release 28 | uses: actions/create-release@v1 29 | env: 30 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 31 | with: 32 | tag_name: ${{ env.GITHUB_TAG }} 33 | release_name: ${{ env.GITHUB_TAG }} 34 | draft: false 35 | prerelease: false 36 | 37 | - name: Upload Assets 38 | uses: svenstaro/upload-release-action@v2 39 | with: 40 | file: libretrojs.tar.gz 41 | overwrite: true 42 | prerelease: false 43 | release_name: ${{ env.GITHUB_TAG }} 44 | repo_token: ${{ secrets.GITHUB_TOKEN }} 45 | tag: ${{ env.GITHUB_TAG }} 46 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LibretroJS 2 | 3 | This repository collects the assets used in [https://github.com/linuxserver/emulatorjs](https://github.com/linuxserver/emulatorjs) and publishes releases that can be embedded into any website. 4 | 5 | # Example 6 | ``` 7 | 8 |
9 | 19 | ``` 20 | 21 | Simply extract the release into the root of your webserver and try this test page for the `snes9x` emulator. 22 | 23 | # Supported emulators 24 | 25 | * 81- [https://github.com/libretro/81-libretro](https://github.com/libretro/81-libretro) 26 | * atari800- [https://github.com/libretro/libretro-atari800](https://github.com/libretro/libretro-atari800) 27 | * bluemsx- [https://github.com/libretro/blueMSX-libretro](https://github.com/libretro/blueMSX-libretro) 28 | * fceumm- [https://github.com/libretro/libretro-fceumm](https://github.com/libretro/libretro-fceumm) 29 | * fuse- [https://github.com/libretro/fuse-libretro](https://github.com/libretro/fuse-libretro) 30 | * gambatte- [https://github.com/libretro/gambatte-libretro](https://github.com/libretro/gambatte-libretro) 31 | * gearboy- [https://github.com/libretro/Gearboy](https://github.com/libretro/Gearboy) 32 | * genesis_plus_gx- [https://github.com/libretro/Genesis-Plus-GX](https://github.com/libretro/Genesis-Plus-GX) 33 | * gw- [https://github.com/libretro/gw-libretro](https://github.com/libretro/gw-libretro) 34 | * handy- [https://github.com/libretro/libretro-handy](https://github.com/libretro/libretro-handy) 35 | * mame2003_plus- [https://github.com/libretro/mame2003-plus-libretro](https://github.com/libretro/mame2003-plus-libretro) 36 | * mednafen_ngp- [https://github.com/libretro/beetle-ngp-libretro](https://github.com/libretro/beetle-ngp-libretro) 37 | * mednafen_pce_fast- [https://github.com/libretro/beetle-pce-fast-libretro](https://github.com/libretro/beetle-pce-fast-libretro) 38 | * mednafen_psx- [https://github.com/libretro/beetle-psx-libretro](https://github.com/libretro/beetle-psx-libretro) 39 | * mednafen_vb- [https://github.com/libretro/beetle-vb-libretro](https://github.com/libretro/beetle-vb-libretro) 40 | * mednafen_wswan- [https://github.com/libretro/beetle-wswan-libretro](https://github.com/libretro/beetle-wswan-libretro) 41 | * melonds- [https://github.com/libretro/melonDS](https://github.com/libretro/melonDS) 42 | * melonds_threaded- [https://github.com/libretro/melonDS](https://github.com/libretro/melonDS) 43 | * mupen64plus_next - [https://github.com/libretro/mupen64plus-libretro-nx](https://github.com/libretro/mupen64plus-libretro-nx) 44 | * o2em- [https://github.com/libretro/libretro-o2em](https://github.com/libretro/libretro-o2em) 45 | * prboom- [https://github.com/libretro/libretro-prboom](https://github.com/libretro/libretro-prboom) 46 | * prosystem- [https://github.com/libretro/prosystem-libretro](https://github.com/libretro/prosystem-libretro) 47 | * snes9x- [https://github.com/libretro/snes9x](https://github.com/libretro/snes9x) 48 | * stella2014- [https://github.com/libretro/stella2014-libretro](https://github.com/libretro/stella2014-libretro) 49 | * tyrquake- [https://github.com/libretro/libretro-tyrquake](https://github.com/libretro/libretro-tyrquake) 50 | * vba_next- [https://github.com/libretro/vba-next](https://github.com/libretro/vba-next) 51 | * vecx- [https://github.com/libretro/libretro-vecx](https://github.com/libretro/libretro-vecx) 52 | * virtualjaguar- [https://github.com/libretro/virtualjaguar-libretro](https://github.com/libretro/virtualjaguar-libretro) 53 | * yabause- [https://github.com/libretro/yabause](https://github.com/libretro/yabause) 54 | * yabause_threaded- [https://github.com/libretro/yabause](https://github.com/libretro/yabause) 55 | 56 | # Variables and usage 57 | 58 | ## Supported variables 59 | * EJS_player- The id of the div you want the libretro canvas to render into. 60 | * EJS_gameUrl- The full URL to the game to load. 61 | * EJS_core- The libretro core to use. 62 | * EJS_biosUrl- Bios URL will be loaded into libretro's system directory, a zip file will be unzipped into this directory. 63 | * EJS_onGameStart- Run a custom function after the game is started. 64 | 65 | ## Basic setup 66 | 67 | The user of the game can bring up the libretro menu by pressing F1 on a keyboard or start+select+L+R on a controller. 68 | You can define scripts to run after startup by using the onGameStart option, IE to go fullscreen on load: 69 | 70 | ``` 71 | EJS_onGameStart = function() { 72 | Module.requestFullscreen(false); 73 | } 74 | ``` 75 | 76 | The core can be interacted with while running using the `Module` as seen above to go fullscreen, there are other commands that can be sent also one of the most important being `Module._cmd_savefiles()` this will force an sram dump of the users save data on supported games/cores. You will want to tie this to an unload or hashchange event on your webpage to ensure the user does not need to go into the menu and manually trigger this action. Some other commands are: 77 | 78 | ``` 79 | _cmd_load_state() 80 | _cmd_save_state() 81 | _cmd_savefiles() 82 | _cmd_take_screenshot() 83 | ``` 84 | 85 | Everything is stored in browser storage using an indexDB there is no integrated logic for downloading the files from the browser, but this can easily be built by interacting with the `fs` directly in the browser. 86 | All of the code is open, feel free to modify it to your needs, but do not come here for support, none will be provided. These repositories are simply for development participation only. 87 | 88 | # Bios files for cores 89 | 90 | These can be loaded as is no need to extract or modify them, they will be unzipped to the system directory before core load. 91 | i 92 | * atari800- [https://gateway.pinata.cloud/ipfs/QmXMs7meQMTpKxVbRGPX6b5Lj4Yh4iJhP69K5MbXqM23vS?filename=atari800.zip](https://gateway.pinata.cloud/ipfs/QmXMs7meQMTpKxVbRGPX6b5Lj4Yh4iJhP69K5MbXqM23vS?filename=atari800.zip) 93 | * bluemsx- [https://gateway.pinata.cloud/ipfs/QmUeCQ3vWxe7F1FZzspLSAvHE42cqoo5xEGK3FdEv5pbUp?filename=msx.zip](https://gateway.pinata.cloud/ipfs/QmUeCQ3vWxe7F1FZzspLSAvHE42cqoo5xEGK3FdEv5pbUp?filename=msx.zip) 94 | * bluemsx- [https://gateway.pinata.cloud/ipfs/QmUeCQ3vWxe7F1FZzspLSAvHE42cqoo5xEGK3FdEv5pbUp?filename=msx.zip](https://gateway.pinata.cloud/ipfs/QmUeCQ3vWxe7F1FZzspLSAvHE42cqoo5xEGK3FdEv5pbUp?filename=msx.zip) 95 | * fceumm- [https://gateway.pinata.cloud/ipfs/QmPk9EKQ2aRVHJX91PTJfmfBDiHRzeWuZExT36BAk2sNZL?filename=nes.zip](https://gateway.pinata.cloud/ipfs/QmPk9EKQ2aRVHJX91PTJfmfBDiHRzeWuZExT36BAk2sNZL?filename=nes.zip) 96 | * fuse- [https://gateway.pinata.cloud/ipfs/QmYutEB17S7d9gjkPPZj6YGV9XKWZNC3Uoaycxj3352dVh?filename=spectrum.zip](https://gateway.pinata.cloud/ipfs/QmYutEB17S7d9gjkPPZj6YGV9XKWZNC3Uoaycxj3352dVh?filename=spectrum.zip) 97 | * gambatte- [https://gateway.pinata.cloud/ipfs/QmYXjcLTGdtG9JtDGVg42cWFkW6feYufRPQYGSe6ifESY8?filename=gb.zip](https://gateway.pinata.cloud/ipfs/QmYXjcLTGdtG9JtDGVg42cWFkW6feYufRPQYGSe6ifESY8?filename=gb.zip) 98 | * gearboy- [https://gateway.pinata.cloud/ipfs/QmYXjcLTGdtG9JtDGVg42cWFkW6feYufRPQYGSe6ifESY8?filename=gb.zip](https://gateway.pinata.cloud/ipfs/QmYXjcLTGdtG9JtDGVg42cWFkW6feYufRPQYGSe6ifESY8?filename=gb.zip) 99 | * genesis_plus_gx- [https://gateway.pinata.cloud/ipfs/Qmct6NWgAbSvWW9XenBfJ8U15GiwEgDLNFKhCnhL6TFiad?filename=sega.zip](https://gateway.pinata.cloud/ipfs/Qmct6NWgAbSvWW9XenBfJ8U15GiwEgDLNFKhCnhL6TFiad?filename=sega.zip) 100 | * handy- [https://gateway.pinata.cloud/ipfs/QmTaUUheMwLj5JqTqiZLzUfdUBj9xWikyZY4s72RGfKb9d?filename=lynxboot.img](https://gateway.pinata.cloud/ipfs/QmTaUUheMwLj5JqTqiZLzUfdUBj9xWikyZY4s72RGfKb9d?filename=lynxboot.img) 101 | * mednafen_pce_fast- [https://gateway.pinata.cloud/ipfs/QmVZuSTmjWBbFvsgkV7fp4R1ZmjveK9Fap4Nxi6DhbpZPT?filename=pce.zip](https://gateway.pinata.cloud/ipfs/QmVZuSTmjWBbFvsgkV7fp4R1ZmjveK9Fap4Nxi6DhbpZPT?filename=pce.zip) 102 | * mednafen_psx- [https://gateway.pinata.cloud/ipfs/QmfQTsRzaE4T9LUWnKara8KVyXmoUn2RXzmSHYtDYN8Jr6?filename=psx.zip](https://gateway.pinata.cloud/ipfs/QmfQTsRzaE4T9LUWnKara8KVyXmoUn2RXzmSHYtDYN8Jr6?filename=psx.zip) 103 | * melonds- [https://gateway.pinata.cloud/ipfs/QmciBpXM6i1nPSyjKv7tJYmWS7NGXtfKX2EtFmTJ4iomas?filename=nds.zip](https://gateway.pinata.cloud/ipfs/QmciBpXM6i1nPSyjKv7tJYmWS7NGXtfKX2EtFmTJ4iomas?filename=nds.zip) 104 | * o2em- [https://gateway.pinata.cloud/ipfs/QmcXRfDzhsEnWnMykpVwQc86kZXKXgbWMKuXf3HNzXnWKN?filename=odyssey2.zip](https://gateway.pinata.cloud/ipfs/QmcXRfDzhsEnWnMykpVwQc86kZXKXgbWMKuXf3HNzXnWKN?filename=odyssey2.zip) 105 | * prboom- [https://gateway.pinata.cloud/ipfs/QmaYzUXDqtjYDhveavbyh34EtJsfa8smuQayvfHKDoruBE?filename=prboom.wad](https://gateway.pinata.cloud/ipfs/QmaYzUXDqtjYDhveavbyh34EtJsfa8smuQayvfHKDoruBE?filename=prboom.wad) 106 | * prosystem- [https://gateway.pinata.cloud/ipfs/QmcHsJd8dzc4gKwd3cmibFBAgBw3X7pswzdLsWSBG8Ngs7?filename=atari7800.zip](https://gateway.pinata.cloud/ipfs/QmcHsJd8dzc4gKwd3cmibFBAgBw3X7pswzdLsWSBG8Ngs7?filename=atari7800.zip) 107 | * snes9x- [https://gateway.pinata.cloud/ipfs/Qme4WxcE38pAZePr3jbHp4h3c9Bu23K7Gt7PNkVHU4x14e?filename=snes.zip](https://gateway.pinata.cloud/ipfs/Qme4WxcE38pAZePr3jbHp4h3c9Bu23K7Gt7PNkVHU4x14e?filename=snes.zip) 108 | * vba_next- [https://gateway.pinata.cloud/ipfs/QmYtDaErc2RzWBYLmcwfKD81NSVjqBsGD6cJCk3kNzDyuk?filename=gba.zip](https://gateway.pinata.cloud/ipfs/QmYtDaErc2RzWBYLmcwfKD81NSVjqBsGD6cJCk3kNzDyuk?filename=gba.zip) 109 | * yabause- [https://gateway.pinata.cloud/ipfs/QmWfQo5YDDx7w4PRHFCLUcWWuhiD6L42h2AGm3RojJwXKo?filename=saturn.zip](https://gateway.pinata.cloud/ipfs/QmWfQo5YDDx7w4PRHFCLUcWWuhiD6L42h2AGm3RojJwXKo?filename=saturn.zip) 110 | 111 | # Rom Hacks Support 112 | Retroarch supports [Softpatching](https://docs.libretro.com/guides/softpatching/), which will apply a patchfile to the base rom on launch. In order to leverage this feature you will need to prepare a custom zip file ending with the file extension ".patchzip". Lets take a popular hack "Invictus" as an example for snes. You will need to create a zip file named "Invictus.smc.patchzip" (note the two file extensions with smc indicating the extension of the base rom) containing the following files: 113 | 114 | * Invictus.smc - base rom file to be patched in this case SMW. 115 | * Invictus.bps - Patch file to be applied. 116 | 117 | Multiple patch files can be applied as long as they follow this naming scheme ending in the order to be loaded IE: 118 | 119 | * Invictus.smc - base rom file to be patched in this case SMW. 120 | * Invictus.bps - First patch file to be applied. 121 | * Invictus.bps1 - Second patch file to be applied. 122 | 123 | # MAME roms with chds 124 | 125 | mame_2003_plus roms need to be **full non-merged** roms in order to function. These are the zips that contain everything from the bios, to parent, to clones. In order to get games with chd files to load we have a custom file format that can be loaded by the extension ".multizip". To create this file simply zip the rom zip and the chd file (no folders) into a single file. IE if you had the file kinst.zip and the folder kinst/kinst.chd simply move the kinst.zip file into the kinst folder and create the archive using `zip kinst.multizip kinst.zip kinst.chd`. This multizip file will be unpacked before the emulator is loaded into the directory it is looking for the files. 126 | 127 | # Threaded emulators 128 | 129 | Some emulators might have a threaded option, in order for these to function on the client they need to have specific security headers set on the actual web host of the files so `SharedArrayBuffer` can be used in the clientside browser. They also need to be served from an HTTPS endpoint as these are the sandboxing requirements for modern browsers. 130 | 131 | In Nodejs: 132 | 133 | ``` 134 | app.use(function(req, res, next) { 135 | res.header("Cross-Origin-Embedder-Policy", "require-corp"); 136 | res.header("Cross-Origin-Opener-Policy", "same-origin"); 137 | next(); 138 | }); 139 | ``` 140 | 141 | In NGINX: 142 | 143 | ``` 144 | add_header Cross-Origin-Opener-Policy same-origin; 145 | add_header Cross-Origin-Embedder-Policy require-corp; 146 | ``` 147 | 148 | # Code Reference 149 | 150 | The source code these cores are build against is located [HERE](https://github.com/thelamer/retrostash). 151 | --------------------------------------------------------------------------------