Skip to content

platformatic/destino

Destino

Destino runs Doom in a terminal using Node.js, node:ffi, and OpenTUI.

The Doom engine is built from doomgeneric as a native shared library. Node.js owns the application loop, forwards terminal input to Doom, reads Doom's framebuffer through FFI, and asks OpenTUI to render it as terminal graphics.

Sound is delegated to DoomGeneric's SDL2 audio backend through SDL2_mixer; Node.js only coordinates the process and does not synthesize or mix audio itself.

Architecture

The project is split into a small native platform layer and a JavaScript runtime:

  1. src/native/main.c implements the platform callbacks required by doomgeneric, including input, timing, frame readiness, and framebuffer access.
  2. src/engine.js loads the Doom shared library through node:ffi and exposes a small JavaScript wrapper around the native functions.
  3. src/input.js parses terminal keyboard input, including Kitty keyboard protocol events, and maps configured keys to Doom key codes.
  4. src/opentui.js loads OpenTUI's native library and renders Doom's framebuffer into the terminal.
  5. src/index.js wires everything together and runs Doom at 35 Hz.

Rendering is pull-based: Doom marks a frame ready, JavaScript pulls the native framebuffer, scales it into a reusable buffer, and passes that buffer to OpenTUI. This avoids C-to-JS callbacks in the frame path.

Requirements

You need:

  1. A Node.js build with node:ffi support.
  2. cmake, clang, pkg-config and unzip.
  3. SDL2_mixer development files.
  4. doomgeneric sources under deps/doomgeneric.
  5. A Doom-compatible WAD, such as freedoom1.wad from Freedoom.
  6. An SF2 sound font, such as GeneralUser GS.
  7. A terminal with Kitty keyboard protocol support, used for reliable key press and release events.

Installation

Automatic

This is only supported on macOS or Ubuntu Linux.

npm install
npm run dependencies

Manual

Install NPM dependencies:

npm install

On macOS, install native dependencies with:

brew install clang pkg-config sdl2_mixer

On Linux install SDL2, SDL2_Mixer, clang, pkg-config and unzip according to your distribution package manager.

Download runtime assets and doomgeneric locally:

mkdir -p deps
cd deps
curl -sSL -o doomgeneric.zip https://github.com/ozkl/doomgeneric/archive/refs/heads/master.zip
curl -sSL -o freedoom.zip https://github.com/freedoom/freedoom/releases/download/v0.13.0/freedoom-0.13.0.zip
curl -sSL -o GeneralUser.sf2 https://github.com/mrbumpy409/GeneralUser-GS/raw/refs/heads/main/GeneralUser-GS.sf2

unzip doomgeneric.zip
mv doomgeneric-master doomgeneric
unzip freedoom.zip
mv freedoom-0.13.0 freedoom
rm *.zip
cd ..

Building

Build the native Doom library:

npm run build

Building a SEA executable

Destino can be packaged as a Node.js Single Executable Application (SEA) on macOS.

First install dependencies and build the native library:

npm install
npm run dependencies
npm run build

Then build the executable:

npm run sea

This bundles the JavaScript entry point, native libraries, WAD files, and SF2 sound font into dist/destino. The SEA config also enables --experimental-ffi automatically, so the executable can be run directly:

./dist/destino

Running the game

Destino reads configuration from destino.json in the current directory by default. If the file does not exist, it creates one and exits.

Run once to generate the config:

/path/to/node --experimental-ffi src/index.js

Update wadPath and sf2Path if they were not detected automatically, then run again:

/path/to/node --experimental-ffi src/index.js

You can also pass a custom config path as the first argument:

/path/to/node --experimental-ffi src/index.js ./foo.json

Controls are configured in destino.json. Press Ctrl+C to exit.

Default keybindings:

Action Keys
Move forward w, up
Move backward s, down
Turn left a, left
Turn right d, right
Strafe left q, ,
Strafe right e, .
Fire space, ctrl
Use enter
Menu escape
Pause p
Confirm enter
Abort escape
Quit confirm y
Quit abort n

License

Destino is distributed as GPL-3.0-or-later because the Doom binding links with the GPL-licensed Doom engine sources. See LICENSE.

Files that do not directly bind to, build, or embed the Doom engine are licensed under the MIT License and carry an SPDX-License-Identifier: MIT header. See LICENSE-MIT.

The files that directly bind to or build the Doom engine carry an SPDX-License-Identifier: GPL-3.0-or-later header.

About

Doom terminal demo based on Node.js, doomgeneric and OpenTUI

Resources

License

GPL-3.0, MIT licenses found

Licenses found

GPL-3.0
LICENSE
MIT
LICENSE-MIT

Code of conduct

Stars

Watchers

Forks

Packages

 
 
 

Contributors