Repository navigation
Releases: trygentic/damnationx
Release list
DamnationX 1.6.0 beta 3
DamnationX 1.6.0 beta 3 adds running, fixes browser chat rendering, and refreshes the HD warrior sprite selection. You need your own DIABDAT.MPQ or the shareware spawn.mpq; neither is included.
Downloads
DamnationX-1.6.0-beta.3-macos-arm64.zip: Apple Silicon desktop app for macOS 26 or later. It is ad hoc signed; on first launch, right-click the app and choose Open.DamnationX-1.6.0-beta.3-web.zip: self-hosted browser build. Serve it over HTTPS or localhost and use a WebGPU-capable browser. Self-hosted browser multiplayer remains unavailable.SHA256SUMS.txt: checksums for both archives.
The optional HD art pack and Diablo II: Resurrected sound files are not distributed here. The game can load or import them from copies you provide.
Changes
- Added a Run button and stamina bar, enabled by default in single-player games. You can hide the button in Gameplay settings. Enemies pursuing a running player speed up too; attack and spell timing remain unchanged. Multiplayer running remains disabled pending network state synchronization.
- Fixed chat history text containing braces and wrapped on-screen chat coloring, including narrow browser layouts.
- Improved HD warrior body clip selection for equipment variants and town walking, with classic art fallback when a matching HD clip is unavailable.
- Added native WebGPU build paths for Windows and Linux and an optional Android SDL3/Vulkan target. These targets have source and CI entry points, but this release does not include Windows, Linux, or Android binaries; device builds are still being validated.
The browser and macOS builds passed. Player, animation, and HD sprite tests passed. The macOS archive was checked for bundled libraries and signature integrity; the browser archive contains no proprietary game data.
DamnationX 1.6.0 beta 2
This beta is about frame rate. With the HD pack on, players reported 35 FPS where they got 55 without it, plus stutters down to 15 FPS. This release fixes most of that. You still need your own DIABDAT.MPQ; the README explains where to put it.
Downloads
DamnationX-1.6.0-beta.2-macos-arm64.zip: the desktop game for Apple Silicon Macs running macOS 26 or later. The app isn't signed by Apple, so the first launch needs right-click > Open.DamnationX-1.6.0-beta.2-web.zip: the browser build, for hosting yourself. A self-hosted copy plays single player only.
There are no Windows or Linux builds yet.
Results
Measured in Chrome on an Apple M4 Max at 1920x1080, walking through Cathedral level 1 with the whole HD pack on, then comparing beta.1 against this build:
| beta.1 | beta.2 | |
|---|---|---|
| FPS with vertical sync (the default) | 54 | 60, locked |
| FPS with frame rate control off | 68 | 155 |
| Frame time with frame rate control off | 14.6 ms | 6.5 ms |
| Frames over 25 ms, from town into the first 30 s of level 1 (vertical sync) | 72 | 20 |
On the macOS app, the HD floor went from 4 to 7 ms of CPU per frame down to about 0.3 ms. Frames over 25 ms across a run from town to the Catacombs dropped from 18 to 2.
We haven't tested on Linux, Firefox or AMD GPUs yet, so reports from those setups help a lot.
What was slow, and what we changed
Ray tracing was not the problem
The first guess was the ray-traced lighting. It isn't heavy: the GPU lighting pass costs about 0.5 ms per frame at 1080p, and the whole GPU frame about 2 ms. Turning ray tracing off doesn't help in dungeons either, because dungeons always use the hybrid lighting path.
The time went to the CPU, mostly to how the HD pack stores and uploads its art. DamnationX still draws the original game into a 256-colour frame on the CPU and builds the HD image on top of it, so any HD work done per pixel, every frame, adds up quickly at 1080p. On the web it runs as WebAssembly on one thread, which makes it worse.
The HD floor
This was the biggest cost. Each frame, the HD floor marked every floor pixel on the CPU with which tile and floor variant it belonged to. It looked for blood, bones and shadows, and checked which floor pixels something else had drawn over. Then it uploaded all of that as an 8-byte-per-pixel texture: about 15 to 17 MB every frame at 1080p. In the browser that copy also has to cross into the GPU process. On the desktop it overflowed Dawn's upload buffer, so each frame allocated and zero-filled a fresh staging buffer, which caused stalls of 17 to 115 ms.
The floor tiles sit on Diablo's fixed isometric grid, so the shaders now work out each pixel's tile from its screen position, the zoom and one reference tile, and read the floor variant and light level from a 112x112 per-tile table. The CPU only keeps one bit per pixel: should this pixel show the HD floor? To find pixels drawn over the floor, the capture swaps each floor pixel's palette index with its neighbouring shade. When the frame is presented, the code compares the frame against that capture 8 bytes at a time, and the shaders undo the swap wherever they show the classic colour. Blood, bone and shadow detection now runs as small GPU compute passes over 4x4 blocks with the same thresholds as before. Floor work also stops on loading screens.
The floor's upload went from about 15 MB to 0.27 MB per frame. In the town, river banks and tree bases used to be drawn three times per frame to find their floor pixels; that result is now cached per piece. With only the HD floor on, the town dropped from 39 to 100 FPS on the desktop (vertical sync on a 100 Hz display).
Stutters while HD art loads (browser)
Every stutter frame we recorded in the browser had an HD sprite image being decoded. In the first 35 seconds of level 1, the game downloaded about 394 MB of sprite sheets, decoded each one at full size, then shrank it to a quarter in a second step on the main thread. That second step blocked up to 30 ms for the largest warrior sheet.
Now one createImageBitmap call decodes and resizes each image, off the main thread. At most three images decode at once, and the game takes in about one finished image per frame. Main-thread time spent decoding in the first 30 seconds of level 1 went from about 900 ms to about 12 ms, and frames over 25 ms in that window dropped from 35 to 44 down to 9 to 12. We checked that the output pixels match the old path exactly, including the HD fonts, whose red channel holds exact palette indexes.
A fixed 4 ms wait in every browser frame
At the end of each frame, the browser build gave control back to the browser with emscripten_sleep(1). That runs on setTimeout, which browsers stretch to at least 4 ms when it repeats, so every web frame lost about 5 ms doing nothing, with or without HD. The wait now follows the Frame Rate Control setting:
- Vertical sync waits for the browser's next display frame (
requestAnimationFrame). The old code ignored this setting and ran uncapped. - None resumes as soon as the browser is free, through a
MessageChannelmessage, while still giving the browser a display frame often enough to draw the canvas and handle input. - An FPS limit sleeps only for the rest of the frame.
- A hidden tab still slows down to save CPU.
HD tiles and sprites streaming in
- HD tile pages are up to 64 MiB each, and each one was uploaded to the GPU in a single call, so entering the town cost 15 to 41 ms frames. They now upload in 2 MiB slices, at most 8 MiB per frame, and the classic art stays on screen until a page is complete.
- Sprite uploads are split up the same way. Monsters nearest the player load first, and preloading never evicts art that is already loaded.
- On the desktop, the sprite memory budget now depends on the GPU (768 MiB for integrated, 1 GiB for discrete) instead of a flat 256 MiB. In the Catacombs, the old budget evicted and reloaded about 200 sprites in the first 10 seconds; now it evicts none. The browser keeps 256 MiB.
- GPU pipelines are compiled in the background on the title screen. Before, the first town frame and the first dungeon frame stalled for 180 to 330 ms while they compiled.
- The game used to check all 1,787 HD sprites every frame for loading progress; it now only checks the ones still loading. Tile lookups use a dense per-position table instead of a hash map.
HD UI
On the first frame of every level, the HD UI rebuilt its colour lookup tables for the new palette on the CPU, which took 11 to 15 ms. A GPU compute shader now builds them, with the same integer maths, and we checked that the results match exactly. Tracking which UI panels and text the game draws now costs about half as much per frame.
Sprite lighting maps on level entry
The first frame of a level could take over 40 ms in the browser even though sprite normal-map generation has a 1.5 ms budget per frame. The cause was a one-time table build that ran inside the first job, before any budget check. That table is now built while the level loads, and the budget is checked before each job.
Fixes
- Broken HD text: if an HD font sheet fails to upload, or its palette indexes come out wrong (for example, because the browser applied colour management to it), the game now keeps the original Diablo text. Before, the original text was hidden even when the HD sheet hadn't loaded properly, which could leave text broken or missing. We couldn't reproduce the Firefox report here, so please tell us if you still see it.
- HD sprites that fail to upload to the GPU now fall back to the original art.
- A broken HD UI shader now falls back to the original UI instead of stopping the renderer.
Also in beta.1, not listed there
Beta.1 already included a first round of dungeon frame rate work, which its notes didn't mention:
- The HD Cathedral floor pass went from about 16 ms to under 2 ms per frame.
- The HD tile, sprite and UI passes now only scan and upload the parts of the screen they cover.
- The game no longer converts the whole view to colour on the CPU in dungeons, since the GPU builds that image itself.
- The lighting pass only considers lights that can reach each 8x8 block of pixels, and skips pixels that can never be lit.
In our tests that took Cathedral level 1 at 1080p from 24 to 56 FPS. The changes above build on it.
DamnationX 1.6.0 beta 1
First public beta of DamnationX. You need your own DIABDAT.MPQ to play. The README explains where to put it.
Downloads
DamnationX-1.6.0-beta.1-macos-arm64.zip: the desktop game for Apple Silicon Macs running macOS 26 or later. The app isn't signed by Apple, so the first launch needs right-click > Open.DamnationX-1.6.0-beta.1-web.zip: the browser build, for hosting yourself. A self-hosted copy plays single player only.
In this release
- Multi Player uses the new lobby server at
lobby.damnationx.net. - You can replace Diablo's sounds with the ones from your own Diablo II or Diablo II: Resurrected. Pick a pack in Settings > Audio > Sound Pack. Importing now switches to the pack straight away. Before, the game kept the original sounds until you selected the pack again.
- If a browser build doesn't include the Diablo II sound importer, the import dialog now says so instead of reporting a missing sound map.
There are no Windows or Linux builds yet.