Unofficial · Bring your own game

Soul of Darkness on the web

A browser runtime that plays Gameloft's 2008 J2ME action platformer from your own copy of the game. It runs the original code on desktop and phone, with no emulator and no Java at runtime.

No game included. This project contains no Gameloft code, graphics, music, text or game files, and this site does not host the game. Soul of Darkness is © 2008 Gameloft SA. This project is not affiliated with or endorsed by Gameloft. You need your own copy of the game to play. The player reads the file you choose directly in your browser: it is never uploaded anywhere.

What it is

The original game is a J2ME MIDlet: Java bytecode written for the MIDP 2.0 phone APIs. Browsers don't have those APIs, so this project:

Compiles, not emulates

The game's unmodified bytecode is translated to JavaScript, either in your browser when you open your file, or ahead of time with TeaVM. Java's exact integer maths, bounds checks and exceptions are preserved.

Reimplements the phone

The ~50 MIDP methods the game uses are rebuilt on web APIs: a pixel-exact software renderer, PNG decoding, saves, audio and input.

Plays like a web game

Keyboard controls, a touch joystick and buttons for phones, whole-pixel scaling, and optional smoothing plus LCD/CRT screen effects.

Play in the browser

Open the player and choose your copy of SoulOfDarkness_HTC_P3450_EN_IGPL_EU_101_S8000.jar (v1.0.1, 240×320 touch build). The page unzips it and compiles the game's bytecode to JavaScript right there, then starts it. Nothing is sent to a server; the site only hosts the runtime. You can optionally keep the file in your browser's storage so you don't have to choose it again.

Other builds show a warning and may not work. Saves stay in that browser.

Build it yourself

You need JDK 11+, Maven 3.9+, Node.js 18+, and your own copy of SoulOfDarkness_HTC_P3450_EN_IGPL_EU_101_S8000.jar (v1.0.1, 240×320 touch build). The build checks the file's SHA-256 and rejects other versions.

git clone https://github.com/Jubayer-cmd/sod-web-port.git
cd sod-web-port
cp /path/to/your/SoulOfDarkness.jar game/SoulOfDarkness.jar
mvn -q package
node serve.mjs            # open http://localhost:8240/

On your phone

node serve.mjs --lan      # prints http://<your-LAN-IP>:8240/

Open the printed address on a phone connected to the same Wi-Fi. On iPhone, use Share → Add to Home Screen to play full screen.

Your build contains the game, so keep it to yourself: don't host, upload or share dist/.

Controls

ActionKeyboardTouch
MoveA D / ← →drag the joystick sideways
JumpW / Space / ↑joystick up, or Jump
Diagonal jumpQ / Ejoystick up-left / up-right
CrouchS / ↓joystick down
AttackJ (or Z)Attack
MagicK (or X)Magic
Switch weaponL (or C)Switch
OK / Next (hold to fill the bar on the upgrade screen)EnterOK
PausePOK during play
Back / weapon upgradeEsc / UBack

How it works

In the browser (play/):
your game.jar ─▶ unzip ─▶ class files ─▶ jvm/compiler.js ─▶ JavaScript functions
                                         jvm/cldc.js + jvm/midp.js (Java & phone APIs)

Ahead of time (local build):
your game.jar ─▶ original classes + data ─┐
                                         ├─ TeaVM ─▶ dist/sod.js (plain JavaScript)
MIDP 2.0 layer (this repo) ──────────────┘               │
                                                         ▼
host.js      canvas · input · text · WebAudio · localStorage
display.js   WebGL2: Scale2x → sharp-bilinear → LCD / CRT
controls.js  drag joystick + buttons      midi.js  MIDI synth

Pixel-exact graphics

A software renderer handles MIDP clipping, all 8 sprite transforms and alpha, then the GPU scales the result.

Same input timing as a phone

Input is delivered on the game thread before each frame, and every press lasts at least one frame, because the game checks the keys once per frame.

Context-aware OK

Enter is the phone's OK soft key, except on the upgrade screen, which only fills its bar while Fire is held.

Smooth 60 fps motion

The game updates 20 times a second. The player records each frame as draw calls, tracks sprites, tiles and the camera between frames, and redraws in-between positions on every screen refresh. Game speed is unchanged; switch to Original 20 fps for the lowest input delay.

Pause and resume

Hiding and showing the page arrive on a separate thread, so the game pauses when you switch tabs and picks up again when you come back.

Status

The in-browser player is tested in Chrome on macOS through boot, menus, story, level 1 gameplay and the upgrade screen, at the game's full 20 frames per second. The local TeaVM build is tested in Chrome on macOS: boot, menus, story, level 1 gameplay, keyboard, mouse and touch, saves, sound, tab switching, all display modes, and the phone layouts in emulated screen sizes. Typical frame cost is 2–7 ms of the game's 50 ms frame budget.

Not yet tested on physical phones. The music is a simple synth. The game's own tutorial screens still show phone controls. Only build v1.0.1 is supported.

Legal

This project's own source code is released under the MIT License. That license covers only the code in this repository. Soul of Darkness, its code, graphics, music, text and trademarks belong to Gameloft SA. None of it is included here, and nothing here grants any right to it. This is an independent, non-commercial compatibility project for people who already own the game, and it does not bypass any copy protection. Rights holders with a concern can open an issue on the repository.