React + JSX runtime for PlayStation 4 homebrew. It renders a real React tree
through Embedded React, runs JavaScript on QuickJS and presents a 1920×1080
framebuffer with sceVideoOut — no OpenGL or shader compilation.
The default build produces a single installable package:
PS4-React-Starter.pkg.
- 1920×1080 presentation with two linear VideoOut buffers and vsync pacing.
- React 18 + JSX/TSX bundled with esbuild and executed by QuickJS.
- Controller input (D-pad, sticks, Cross/Circle, L1/R1, L2/R2, Options).
- Audio through
sceAudioOut(48 kHz stereo) and a real-time mixer. - Networking with libcurl + mbedTLS:
Httprequests andDownloads. - Remote images (PNG/JPEG) with an in-memory and disk cache.
- Archives (ZIP, TAR, 7z) through libarchive, with ZIP/TAR creation, extraction and inspection.
- Runtime text shaping for CJK, Arabic and Indic scripts with HarfBuzz and SheenBidi; apps package only the Noto fonts they use.
- Native filesystem under
/app0,/dataand/download0. - PKG installation and removal through the BGFT install service via
Packages.install/Packages.uninstall, with progress and errors. Apps that use it are packaged with"privileged": true(IV0000/gde). - Payload delivery to GoldHEN's BinLoader with ELF and size checks.
- Server-Sent Events through
Sse.connectwith bounded event queues. - WebSocket text client (
ws:///wss://) with polling, ping/pong and close. - Music playback: MP3 and OGG Vorbis decoding, 48 kHz resampling, local files and HTTP(S) streams, ID3/Vorbis metadata, MP3/OGG album art, playlists and crossfade on the mixer's two music decks.
- Video playback through
sceAvPlayer(local MP4/H.264 + AAC, NV12 with pitch/crop, ARGB blit at 30 fps for 480p, audio through the mixer on a dedicated thread). 720p/1080p and the GPU texture path are pending. - GPU presentation through Piglet/OpenGL ES (
"gpu": true) using Sony's precompiled texmap shaders, with the software VideoOut path as fallback. An opt-in Vulkan/RADV build (PS4SX2 SDK) hosts the complete React runtime and presents the UI at 1080p60 through a Vulkan texture; video frames are uploaded as Y/UV textures and composed on the GPU. - Multi-controller input with one pad per logged-in user and
useGamepad(playerIndex); any pad navigates the UI. - Device information (model, firmware, CPU frequency/temperature, SoC temperature, free flexible memory) and user enumeration.
- Save data through
sceSaveDataand the system on-screen keyboard throughsceImeDialog. - PKG packaging validated with
PkgTool.Coreand a load-image checker. - Dev hot reload over TCP when the build enables
-DPS4_REACT_DEV_SERVER=ON.
See ROADMAP.md for the implementation plan, current status and checklist.
Building on Windows uses WSL2 and a PacBrew rootfs with the OpenOrbis toolchain and runtime libraries. The same steps work on Linux with the toolchain installed.
- Windows 10/11 + WSL2 (Ubuntu 22.04/24.04), or Linux.
- PacBrew rootfs containing:
- OpenOrbis PS4 toolchain (
clang,create-fself,create-gp4,PkgTool.Core); - runtime libraries: libcurl, mbedTLS, libarchive, bzip2, zlib, libpng;
- HarfBuzz 14.6 source at
/workspace/harfbuzz(the Linux/CI build downloads it automatically).
- OpenOrbis PS4 toolchain (
- Node.js 20+ and npm.
- Python 3, CMake, Git,
curl,xz.
The first build fetches QuickJS-ng 0.15.0 and Embedded React at the revision in
dependencies.lock.json, applies the pinned engine
patches and builds HarfBuzz for the PS4.
.\tools\build_ps4.ps1On Linux, use the shell entry point:
./tools/build_ps4.shOutput:
build/PS4-React-Starter.pkg
The command builds only that package. -NoPackage produces the ELF/SELF without
packaging. -DevServer enables the TCP hot-reload receiver for local
development. The GitHub Actions workflow is
.github/workflows/build.yml.
samples/ contains small apps for the native APIs. Build one with:
.\tools\build_ps4.ps1 -Sample counter
# -> build/PS4-React-counter.pkgOn Linux, build one sample with:
./tools/build_ps4.sh --sample counterBuild every sample into samples-pkg/:
.\tools\build_samples.ps1./tools/build_samples.shEach sample's app.json supplies its title and Title ID. See
samples/README.md for the list and ideas.
Install a development build on the console with the receiver enabled:
.\tools\build_ps4.ps1 -DevServer./tools/build_ps4.sh --dev-serverThen, on the workstation, point the watcher at the console's IP:
node tools/dev_server.mjs --host 192.168.1.50
# sample:
node tools/dev_server.mjs --host 192.168.1.50 --sample counterThe console listens on TCP port 9001, validates each ERHR frame with CRC-32 and reloads the JavaScript bundle in the running title. Assets (images, fonts, sounds) are still compiled into the PKG; rebuild and reinstall when they change. The receiver is off in release builds.
- Copy
PS4-React-Starter.pkgto a USB drive or/data/pkg. - On the PS4, open GoldHEN → Install Package and select the file.
- Launch PS4 React Starter.
Title ID: CUSA99059.
The runtime log is written to /data/PS4React/react.log (fallback /temp0).
| Input | Action |
|---|---|
| D-pad / left stick | Move focus |
| Cross | Confirm |
| Circle | Back |
| L1 / R1 | Previous / next page |
| L2 / R2 | Previous / next section |
| L3 / R3 / touchpad | Exposed as actions |
| Options | Exit |
JavaScript reaches the host through @ps4-react/core.
| API | Purpose |
|---|---|
Http.request |
HTTP/HTTPS request with headers, method and abort signal |
Downloads.enqueue |
Download to a file with ranges, resume and completion receipts |
<Image> |
Local baked assets and remote PNG/JPEG decoding |
Archives.extract |
ZIP, TAR and 7z extraction with a destination directory |
Archives.create |
Create ZIP or TAR archives from files and directories |
Sound |
Play baked WAV clips with volume and pan |
Notifications / Users / DeviceInfo |
Notifications, users and device information |
FileSystem |
Read, write, list, rename and inspect files |
Controller / useGamepad |
Light bar, vibration and per-player pad state (playerIndex 0..3) |
Packages.install |
Install a PKG through BGFT; requires a privileged app |
Packages.uninstall |
Remove a title through sceAppInstUtil; requires a privileged app |
Payloads |
Check GoldHEN BinLoader and send an ELF payload to 127.0.0.1:9090 |
Sse |
Server-Sent Events stream with event polling and cancellation |
WebSocket |
ws/wss text client with polling, ping/pong and close |
Music |
Local and HTTP(S) MP3/OGG playback, seek (local), metadata, playlists and crossfade |
Video |
Local MP4/H.264 playback through sceAvPlayer; pause/resume/seek/stop |
SaveData |
Mount, unmount and delete PS4 save data; repairBroken recovers a broken directory |
Keyboard.prompt |
Open the system on-screen keyboard |
Dialog |
System message dialogs (alert, confirm and progress) |
AppState |
App lifecycle state and system events (resume, URL open, focus) |
Fonts / BackHandler / Power / Linking |
Text language, exit, keep-awake and URLs |
BrowserCapture is not part of the PS4 runtime. Opus, album art and system BGM
are pending. Video currently targets 480p on the software path; the Vulkan
build can present the UI and video frames through Y/UV textures, while
720p/1080p decoding and HDR remain pending.
Save data and the system keyboard are available from the same import:
import {SaveData, Keyboard, FileSystem} from '@ps4-react/core';
const save = SaveData.mount({dirName: 'settings', title: 'My App', repairBroken: true});
FileSystem.writeFile(`${save.path}/settings.json`, '{"name":"Player"}', {sync: true});
const result = await Keyboard.prompt({title: 'Player name', value: 'Player'}).done;
console.log(result.text);The settings sample in samples/ demonstrates both APIs.
Paths:
/app0— read-only package contents (the PKG root);/download0— writable application data, mapped to/data/PS4React;/cache0— image and cache data.
app/ React starter application (JSX, assets, sounds)
samples/ Example apps built with -Sample <name>
assets/ PKG icons and CA bundle
native/ps4/ PS4 host: VideoOut, input, audio, network, images,
archives, text shaping and packaging glue
runtime/js/ React runtime and focus/navigation components
tools/ build, bundling, packaging and load-image validation
patches/ pinned Embedded React patches
.github/workflows/ GitHub Actions build
Validated on PS4 hardware:
- VideoOut 1920×1080 at ~60 fps;
- React/QuickJS starter with focus and input;
- big-app PKG registration (
CATEGORY=gd) and a dlmalloc heap over mapped system flexible memory, replacing the stock libc heap that fails on retail; - clean Options exit through
sceKernelGetAppInfoandsceSystemServiceKillApp, with save-data unmount before the system suspends the title; sceAudioOutmixer and interface sounds;- HTTPS requests (IPv4, CA bundle in
/app0); - downloads to
/download0with completion receipts and resume; - remote PNG decode at 256×256;
- ZIP extraction with two entries;
- Japanese, Simplified Chinese and Arabic shaping at 59.9 fps;
- PS4 save-data mount and broken-directory recovery, with JSON persistence
through the
settingssample; - the system on-screen keyboard feeding text back into React;
- system message dialogs (
Dialog.alert/Dialog.confirm) with Cross confirm and input suppression while a dialog or the keyboard is open; - background/active lifecycle with save-data unmount/remount across the PS button and resume;
- app relaunch through
BackHandler.exitApp({relaunch: true})withsceSystemServiceLoadExec.
Known limitations:
- RAR/RAR5 extraction is not available yet; ZIP/TAR/7z are supported.
- Opus, album art and system BGM are not implemented yet.
- Video playback uses the software decoder and CPU NV12 conversion on the
default build (480p30). The Vulkan build uploads Y/UV textures instead; AAC
audio is validated, while 720p/1080p and hardware decoding are pending. Video
apps close through
sceSystemServiceLoadExec("exit", nullptr)becauseKillApp's suspend waits for a decoder GPU submit that never completes. Packagesrequires an app packaged with"privileged": true; it loads the internal AppInstUtil/BGFT sysmodules and installs through BGFT. Validated on the target PS4 5.05/GoldHEN console; large and invalid PKGs are untested.Payloads.isAvailablereads GoldHEN's config: a bare TCP connect to port 9090 can stop BinLoader's accept loop. UsePayloads.sendas the real test.- Runtime text shaping needs the app to package the Noto fonts it uses.
- Hot reload only replaces JavaScript; asset changes require a new PKG.
The project is GPL-3.0-or-later with the attribution term in
LICENSE-ATTRIBUTION. Third-party notices are in
NOTICE and licenses/.