CLI tool
jpd002/Play- avatar
jpd002/Play-

Play! and the awkward part of emulating a console without its firmware

Play! - PlayStation2 Emulator

2,687 stars373 forksC++NOASSERTION

At a glance

What is it?
A C++ PlayStation 2 emulator with a built-in high-level BIOS, arcade dongle support, and an iOS story that is mostly about how to get just-in-time compilation enabled.
Who is it for?
Play! sits in an unusual position among emulators because it refuses the most famous input to the problem. Emulation usually starts with firmware you do not have the right to distribute, and Play! removes that step entirely by carrying its own high-level BIOS, which means the repository is the whole project and there is no companion file you are expected to go find.
Can I use it commercially?
Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
Is it still maintained?
Yes. The repository last received commits 34 days ago.
What is it written in?
Mainly C++, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 24, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An emulator that refuses to need a BIOS image

Every PlayStation 2 emulator faces the same awkward opening move. The console shipped with firmware that the manufacturer never released, and the community's answer has traditionally been to ask users to supply a BIOS dump they obtained from elsewhere. Play! takes the other route and carries a built-in high-level emulation BIOS, which means an external BIOS file is not merely optional but impossible, since there is no path in the emulator that reads one.

That single design decision explains most of what is distinctive about the project. A high-level BIOS is one written against an interface rather than transliterated from real hardware, which is why it is legally clean to ship and why it can be changed without keeping cycle accuracy for a component nobody has. It also means compatibility is entirely the emulator's own responsibility, so the repository carries its own configuration surface: `GameConfig.xml` and `ee_functions.xml` sit at the root as data the build reads, and `arcadedefs/` holds per-county arcade definitions.

The repository is a C++ project with 2,687 stars, 373 forks and 270 open issues, last pushed on 2026-09-03. Compatibility reporting is deliberately pushed out to a separate repository, the Compatibility Tracker, and the README instructs users to open issues there rather than in the main one. The API reports no recognised licence identifier even though a `License.txt` sits in the tree, so the terms are whatever that file says rather than a standard SPDX name.

Running from a download or from a build directory

There are two ways in, and the README puts the easy one first. The Actions page carries build artifacts per system, so a user without a compiler can click the build category, open the most recent successful run and download the file under Artifacts. The README is explicit that a build that failed should be tested again later if newer fixes exist, which is a reasonable instruction for anyone reaching for a nightly.

The command line surface is small enough to read in a minute, and the Windows, macOS and Linux builds all share it:

code
--disc "disc image path" : Boots a disc image.
--elf "elf file path" : Boots a ELF file.
--arcade "arcade id" : Boots an arcade game.
--state "slot number" : Loads a state from slot number.
--fullscreen : Starts the emulator in fullscreen mode.

Building from source needs submodules, and the clone command says so explicitly rather than leaving you to discover it:

code
git clone --recurse-submodules https://github.com/jpd002/Play-.git
cd Play-

The documented Windows path runs through CMake and Qt, and the generator string is worth reading closely because it encodes the current toolchain rather than an old one. Qt6 or Qt5 has to be installed first, and the build directory is created by hand before the generator is invoked, with a comment noting that omitting `-G` produces 32-bit projects. The tree also carries `CMakePresets.json`, `CMakeLists.txt` at the root and a `build_cmake/` directory, so the CMake configuration is not confined to the Windows instructions. There are also `installer_macos/`, `installer_win32/`, `installer_ios/`, `installer_android/`, `installer_unix/` and a `build_retro/` directory alongside `js/`, which is the experimental web build.

The iOS path turns on whether JIT is enabled

This is the part of the README with the most consequences per line, and it is worth reading in order because the failure mode is blunt. Play! uses just-in-time code generation to speed up emulation, and iOS does not permit it by default. The stated requirements are a device on iOS 13 or earlier, or an arm64e device on iOS 14.2 or 14.3, together with a jailbroken device. The README then draws a line under its own instructions in bold: if you launch a game without JIT enabled, you will get a crash.

That is not a graceful degradation. A crash on launch is what a user sees when the requirement is unmet, so anyone trying this on an ordinary current iPhone is looking at an immediate failure rather than a slow one. There are documented workarounds, and the order they appear in reflects how much friction each one costs.

The first is a guide to enabling JIT through other means, which is linked rather than written out. The second is AltServer, and Play! implements automatic JIT activation through it, provided AltServer is running on the same network as the device, with the setting available in the emulator's Settings menu. The third is building the emulator yourself, launching it under Xcode's debugger, and then using the Detach button in the Debug section so the debugger's authorisation stays attached to the app process until the app ends. That last detail is the useful part: detaching means the JIT entitlement remains without keeping Xcode tethered to the device.

Game discovery on a jailbroken device works differently from the rest of the platform. Rather than a file picker, the emulator walks every bootable file under `/private/var/mobile` and its subdirectories, and the README links two Apple support documents for the non-jailbroken case.

Arcade support means dongles, light guns and drums

Namco System 2x6 hardware needs a dongle image alongside the disc, and Play! handles it with a directory convention rather than a dialog. The required files go into an `arcaderoms` subdirectory of the Play! data files directory, laid out so each arcade title has a zip paired with a folder of its own contents:

code
arcaderoms/
  bldyr3b.zip
  bldyr3b/
    bldyr3b.chd
  tekken4.zip
  tekken4/
    tef1dvd0.chd

The mapping section then assigns arcade-specific actions to ordinary controller buttons, which is the pragmatic part of emulating a cabinet with dedicated hardware. Service and Coin go to SELECT, and Test is L3 and R3 together. Light gun games map the trigger to CIRCLE and the pedal to TRIANGLE, with the mouse cursor supplying the gun's position and mouse buttons remappable to either face button. Time Crisis 3 needs a one-time calibration through the service menu, reached by holding the Test buttons, then I/O Test, then Gun Initialize, then the pedal to shoot at the centre.

Taiko no Tatsujin gets the four drum surfaces on the shoulder buttons, left men and fuchi on L1 and L2 and the right pair on R1 and R2. Driving games use the analog sticks as a wheel and pedals: left stick X plus and minus for steering, left stick Y plus for the gas, right stick X plus for the brake. These are the kind of mappings that tell you the arcade support came from people actually playing the cabinets rather than from a feature list.

Most broken installs turn out to be an image format problem

The troubleshooting section addresses exactly one failure, and the reason it gets that much space is that the error it produces is misleading. When a disc image fails to open, the cause is often that the dump is not in the format the emulator expects rather than that it is broken. Play! expects CDVD images compressed with chdman's createcd or createdvd commands, and anything else produces an error that reads like corruption.

The diagnostic is a metadata check, because CDVD and HDD images both use the CHD container and are told apart by what is inside:

code
chdman info -i image.chd

`CHT2` in the output means the image is a CDVD image and is fine. `GDDD` means it is an HDD image that has been handed to the emulator as a disc, so it needs converting. The README also notes that you can tell which kind a game wants by looking inside the associated arcadedef file for cdvd or hdd settings, which is a faster route than converting and failing.

The conversion is three commands, and the ordering matters because the second one reads the file the first one has just renamed:

code
mv image.chd image.chd.orig
chdman extracthd -i image.chd.orig -o image.iso
chdman createcd -i image.iso -o image.chd

This is the single most useful thing in the README for anyone whose first attempt failed, and it is also a good illustration of how narrow the emulator's real requirements are. It wants a specific container type produced by a specific tool, and it will not infer the difference.

What the tree says about how the project is built and shipped

The repository root is a build and release engineering document. Beyond the code in `Source/`, there are separate CI scripts for macOS that import a certificate and notarise the build, a `.gitlab-ci.yml` alongside a `.github/` directory, and a `.clang-format` that means the C++ style is enforced by a file rather than by convention. `UiDesign.md` and `Settings.md` sit next to the source, so the interface decisions are documented in the same place as the code.

The installer directories are the clearest statement of scope, one per target: macOS, Windows, iOS, Android and Unix. `build_android/` and `build_retro/` add two more build configurations, and `js/` is the source for the web emulator the README links at playjs.purei.org, which it labels experimental. `deps/` and `.gitmodules` explain why the clone command needs the recurse-submodules flag.

What is absent is as informative. No releases are published through the API, no example configuration is offered, and there is no Docker or package-manager distribution in the tree. A user gets binaries from the Actions artifacts or builds from source; there is no third path. With 270 open issues on the main repository and a separate compatibility tracker taking per-game reports, the load is divided on purpose: emulator bugs here, game breakage there.

Editorial conclusion

Play! sits in an unusual position among emulators because it refuses the most famous input to the problem. Emulation usually starts with firmware you do not have the right to distribute, and Play! removes that step entirely by carrying its own high-level BIOS, which means the repository is the whole project and there is no companion file you are expected to go find. What remains are the ordinary engineering problems, and they are the same ones you would meet anywhere: a build system that spans five platforms, an image format that trips people up more than the emulator does, and input devices that a console controller was never designed to carry. The CHD conversion path in the troubleshooting section is the highest-value thing in the README, because a dump in the wrong container produces an error message that reads like a corrupt file rather than a format mismatch. Read the compatibility tracker before filing anything in the main repository, since the 270 open issues there are mostly not where per-game breakage belongs.

Frequently asked questions

Can an iPhone run PS2 emulation?

Play! builds for iOS, but it needs just-in-time compilation enabled, which iOS does not permit by default. The documented path is a device on iOS 13 or earlier, or an arm64e device on iOS 14.2 or 14.3, with a jailbreak. AltServer running on the same network can activate JIT automatically, or you can launch a self-built version under Xcode's debugger and press Detach so the entitlement outlives the debugger session.

Is there a PS2 emulator that actually works?

Play! is one, and its compatibility is documented separately in the Play-Compatibility repository rather than in the main issue tracker. The README instructs you to open a new issue in the compatibility tracker when a specific game fails. The emulator carries its own high-level BIOS, so there is no firmware image to source before anything will boot.

Does Play! need a PS2 BIOS file?

No, and it will not accept one. Play! uses a built-in high-level emulation BIOS, so using an external BIOS file is neither necessary nor possible. This is the main reason the project is straightforward to install compared with emulators that expect the user to supply firmware.

Why does Play! fail to open my CHD image?

The image is usually the wrong type rather than corrupt. Run chdman info -i image.chd and look at the metadata: CHT2 means a CDVD image, which is what the emulator expects, while GDDD means an HDD image that must be converted with extracthd followed by createcd. The README also notes that a game's arcadedef file records whether it wants cdvd or hdd.

How do I build Play! on Windows?

Create a build directory, run CMake against the root CMakeLists.txt with a Visual Studio generator and a Qt prefix path, then build the Release configuration. Qt6 or Qt5 must be installed beforehand, and the generator flag matters because omitting it produces 32-bit projects. Opening the project in Qt Creator and pointing it at the CMakeLists.txt is the route the README calls easiest.

Official sources

  1. Issues
  2. jpd002/Play- on GitHub
  3. Project website
  4. README
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/jpd002-play.svg)](https://hysenlabs.com/projects/jpd002-play)