Coder Social home page Coder Social logo

arianrhodsandlot / nostalgist Goto Github PK

View Code? Open in Web Editor NEW
608.0 4.0 16.0 7.39 MB

A JavaScript library used for running emulators of retro consoles inside browsers.

Home Page: https://nostalgist.js.org

License: MIT License

TypeScript 96.87% JavaScript 2.43% HTML 0.67% CSS 0.04%
emscripten retroarch retroarch-wasm retroarch-web emulator atari atari2600 gb gba gbc

nostalgist's Introduction

Greetings 👋

Introduction

I'm @arianrhodsandlot, a frontend engineer committed to delivering clean, efficient, maintainable, high-quality code and user-friendly products.

You can find some of them that are open-source below, and feel free to raise any feedback.

My tech stack

Proficient / recently used

Expand to see details
  • Languages & runtimes

    CSS3 HTML5 JavaScript NodeJS TypeScript

  • Libraries & frameworks

    jQuery lodash NextJS Nuxt React Redux TailwindCSS Vue.js

  • Tools

    ESLint Git Jest NPM Playwright PNPM Prettier RollupJS Vite Vitest Webpack Yarn

Have ever used or worked with

Expand to see details
  • Languages & runtimes

    Bun C coffeescript json Less Markdown mermaid PHP Pug Python Ruby SASS Shell Script Stylus toml YAML
  • Libraries & frameworks

    Amp Angular.js Apache Echarts Astro axios backbonedotjs Bootstrap Bulma codeigniter cssmodules datefns dotenv ejs Electron.js esbuild Express.js Flask fontawesome Framer Motion handlebarsdotjs i18next iconify Jinja koa normalizedotcss NumPy Pandas postcss Preact PWA Radix UI Rails React Query React Router Svelte swiper swr WordPress
  • Tools

    avajs Babel bower chai cypress Docker editorconfig esbuild gitlfs Grunt Gulp Jupyter Notebook mocha mysql Nginx Nodemon pipx pm2 Poetry precommit puppeteer standardjs stylelint swc Vagrant

My toolbox

Expand to see details
  • Operating systems

    Chrome OS iOS Lineageos macOS Manjaro Windows 11
  • Browsers

    Edge Google Chrome Safari Vivaldi
  • Services & platforms

    Bitbucket ChatGPT Cloudflare Cloudflarepages CodePen feedly Figma GitHub Actions Github Pages GitHub Google jsdelivr MDN Web Docs OneDrive Stack Overflow Stackblitz Trello Vercel Wikipedia
  • Development softwares

    alacritty charles curl Gimp Gnu Image Manipulation Program homebrew iTerm2 sourcetree Starship tmux Vim Visual Studio Code Windows Terminal Zsh

nostalgist's People

Contributors

arianrhodsandlot avatar dagaiguanyu avatar epicnesstwo avatar gauztech avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

nostalgist's Issues

Failed to launch without user gesture.

This is a repo reproducing this question: https://github.com/daGaiGuanYu/show-me-bugs/tree/nostalgist240207

warn message in console:

The AudioContext was not allowed to start. It must be resumed (or created) after a user gesture on the page.

I don't know whether this can be fixed.
If not, it would be nice to mention it in the documentation.
Developer could show a dialog to tell users "rom download, start now?".
And user's clicking will offer a "user gesture", and this limit are gone.


I'm making a little APP (not completed):

  • load nes games from local and the internet.
  • Installable, and offline playing(not completed), and launching by clicking a nes file.

截屏2024-02-07 15 55 07
截屏2024-02-07 15 54 19

Access to game's memory

Hey, I could not manage to get access to rom's memory.
I think retroArch provides such feature, could we get this in Nostalgist?

Additional libretro cores compatible with Nostalgist

Hi. There are few more cores that work great with Nostalgist (in addition to the ones you have uploaded to https://github.com/arianrhodsandlot/retroarch-emscripten-build/tree/main/retroarch ):

Atari 400 / 800 / XE / XL series
https://github.com/libretro/libretro-atari800
(If you try to compile this one and encounter any errors let me know, I may have some uncommitted changes)

Atari 2600 / VCS
https://github.com/libretro/stella2014-libretro

Amstrad CPC series
https://github.com/libretro/libretro-crocods

To build the above - I cloned the projects and cd its directory, then
emmake make -f Makefile platform=emscripten
then changed the output filename to libretro_emscripten.bc and copied it to RetroArch directory, then (from this dir)
emmake make -f Makefile.emscripten LIBRETRO=corename -j all
(where corename is e.g. stella2014, atari800, crocods)

Apart from that, the EmulatorJS has a working Commodore Amiga core (that I cannot build at the moment due to emsdk issue?):
https://github.com/libretro/libretro-uae

Features: startPaused, getCurrentFrame and onFrame Event

Related to #4, Some useful tools for multiplayer and recording/playback would be related to knowing the frame.

  • { startPaused: true } starting paused would allow a group of players to prepare the games and start at relatively the same time.
  • getCurrentFrame() getting the current frame would be useful for knowing when a player did an action. Good for broadcasting actions to happen in the future or for recording the action to be played later
  • on("frame", ()=>{}) knowing what frame the player is on would be good commanding prepared actions. For my examples, the event happens before the buttons are read.

This might be more work than it's worth but it seems interesting

// Not working Example Multiplayer Client

const controller = new OnscreenController(document.querySelector("#OnscreenController"))

const connection = new WebSocket("/game-room/12345");

const nostalgist = await Nostalgist.launch({
  startPaused: true, // Needed so that all players start around the same time
  core: 'fceumm',
  rom: 'flappybird.nes',
})

await syncWithRoom(connection);
const frameOffset = await getFrameOffset(connection)

var startListener = (event)=>{
  const data = JSON.parse(event.data)
  if(data.action !== "start") return;
  connection.removeEventListener("message", startListener)
  nostalgist.resume();
}
connection.addEventListener("message", startListener)

const ACTIONS_TODO = {};

controller.addEventListener("button", (event)=>{
  const { button, toggleValue } = event.data
  const targetFrame = nostalgist.getFrame() + frameOffset;
  connection.send({
    targetFrame, button, toggleValue
  })
})


// Doesn't have to be event target. just simpler to use it for the example
nostalgist.addEventListener("frame", (event)=>{
  const currentFrame = event.frame;
  const todos = ACTIONS_TODO[currentFrame];
  if(todos === void 0) return;
  delete ACTIONS_TODO[currentFrame]
  todos.forEach((todo)=>{
    nostalgist.press(todo.player, todo.button, todo.toggleValue)
  });
})


connection.addEventListener("message", (event)=>{
  // Handle Input
  const data = JSON.parse(event.data);
  if(data.action !== "input") return;

  const { targetFrame, player, button, toggleValue } = data
  const currentFrame = nostalgist.getFrame()
  if(targetFrame <= currentFrame){
    nostalgist.exit();
    connection.send(JSON.stringify({
      action: "desync"
    }));
    alert("You are out of sync with the room")
    return;
  }
  if(!(targetFrame in ACTIONS_TODO)){
    ACTIONS_TODO[targetFrame] = []
  }
  ACTIONS_TODO[targetFrame].push({ player, button, toggleValue })
})
connection.addEventListener("message", (event)=>{
  const data = JSON.parse(event.data);
  if(data.action !== "desync") return;
  nostalgist.removeController(data.player)
})
// Not working Example Input Recording

const PLAYER = 0;

// Recording

function runRecorder(){
  const controller = new OnscreenController(document.querySelector("#OnscreenController"))

  const nostalgist = await Nostalgist.launch({
    startPaused: true, // Needed so that all players start around the same time
    core: 'fceumm',
    rom: 'flappybird.nes',
  })

  const transcript = [];

  controller.addEventListener("button", (event)=>{
    const { button, toggleValue } = event.data
    transcript.push({ frame: nostalgist.getFrame(), type: "button", button, toggleValue });
    nostalgist.press(PLAYER, button, toggleValue)
  })

  return new Promise((res)=>{
    nostalgist.addEventListener("exit", ()=>{
      transcript.push({ frame: nostalgist.getFrame(), type: "off" })
      res(transcript)
    })
  });
}


// Playback

function playTranscript(transcript){
  var transcriptOffset = 0;
  nostalgist.addEventListener("frame", (event)=>{
    const currentFrame = event.frame;
    for(transcriptOffset; transcriptOffset < transcript.length; transcriptOffset++){
      const action = transcript[transcriptOffset]
      if(action.frame > currentFrame) break;
      switch(action.type){
        case "button": {
          nostalgist.press(PLAYER, action.button, action.toggleValue);
          break;
        }
        case "exit":{
          nostalgist.pause();
          alert("recording finished");
          break;
        }
      }
    }
  })
}

Feature: External/Manual Inputs

Looks like a cool project. One thing I noticed in the instance methods is that there are no manual input methods. Granted, keyboard and gamepad may be enough to control/play the game but a developer might want to have "on screen" controls for things like mobile devices. In addition, a player might want to customize the inputs of a gamepad to their liking or have something like a turbo (when a player doesn't want to mash a button) or toggle (so you don't have to hold down the run button in mario)

If you want to point me in the direction of where the inputs are handled I wouldn't mind taking a look at what I can do

How can i use this?

I want host nostalgist.js on my pc so i can play games from localhost instead of the nostalgist.js website.
I also want to run this on a circuitpython device (it is an raspberry pi pico w).

Error when trying to load ROMs from external CORS-enabled server

Hi!
I think that there’s a bug that causes all rom imports from external CORS-enabled domains to fail. It's easy to reproduce this with Archive.org URLs - the Internet Archive allows cross-origin downloads (and they work fine when using EmulatorJS).
I think I can post a public domain / demoscene prod link (Game Boy) for reference :)

either
rom: 'https://archive.org/download/pouet_54175/oh.gb',
or
rom: 'https://archive.org/download/pouet_54175/oh.zip/oh.gb',
(plain http URLs can also be used on archive org)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.