Local Doors — Native v86 Emulation
Native DOS Emulation via v86
ENiGMA½ includes a built-in x86/DOS emulator powered by v86 — a JavaScript x86 emulator that runs entirely within Node.js. The v86_door module boots a FreeDOS disk image and bridges COM1 directly to the user’s connection, with no external emulator installed on the server.
The emulator runs in a dedicated worker thread, so it does not block ENiGMA½’s event loop. Each active session gets its own isolated emulator instance.
How It Works
- ENiGMA½ generates the appropriate drop file for the user (DORINFO, DOOR.SYS, etc.)
- The drop file is written into a small in-memory FAT12 floppy image — no temp files on disk
- v86 boots the op-supplied FreeDOS disk image from the hard drive (
C:) - The drop file floppy is mounted as
A:in FreeDOS - The door’s
AUTOEXEC.BATcopies the drop file fromA:and launches the game - COM1 serial I/O is bridged directly between v86 and the user’s connection
- When the door exits and FreeDOS powers off, the session ends cleanly
Prerequisites
BIOS Files
v86 requires SeaBIOS and a VGA BIOS image. The ENiGMA½ installer (misc/install.sh) downloads these automatically to misc/v86_bios/. To download manually:
mkdir -p misc/v86_bios
curl -fL https://github.com/copy/v86/raw/master/bios/seabios.bin -o misc/v86_bios/seabios.bin
curl -fL https://github.com/copy/v86/raw/master/bios/vgabios.bin -o misc/v86_bios/vgabios.bin
Disk Image
You need a raw FreeDOS disk image (.img) with your door game pre-installed. Raw .img images are fully compatible between QEMU, DOSBox-X, and v86 — set up your image with QEMU or DOSBox-X, then point v86_door at it on the production server.
Configuration
| Item | Required | Description |
|---|---|---|
name |
Door name. Used as a key for tracking concurrent sessions. | |
image |
Path to the raw FreeDOS disk image (.img). |
|
dropFileType |
Drop file to generate and inject onto the A: floppy: DORINFO, DOOR, or DOOR32. Omit if the door needs no drop file. |
|
runBatch |
Multi-line batch script written to A:\RUN.BAT at runtime. Supports variable substitution. See One Image, Multiple Doors. |
|
nodeMax |
Max concurrent sessions. 0 = unlimited. |
|
tooManyArt |
Art spec to display when nodeMax is exceeded. |
|
memoryMb |
Guest RAM in MB. Default: 64. |
|
biosPath |
Path to SeaBIOS image. Default: misc/v86_bios/seabios.bin. |
|
vgaBiosPath |
Path to VGA BIOS image. Default: misc/v86_bios/vgabios.bin. |
Drop File Filenames on A:
dropFileType |
Filename on A:
|
|---|---|
DORINFO |
DORINFOx.DEF (x = node-based suffix per spec) |
DOOR |
DOOR.SYS |
DOOR32 |
door32.sys |
runBatch Variables
When runBatch is set, ENiGMA replaces the following variables before writing RUN.BAT:
| Variable | Description | Example |
|---|---|---|
{dropFile} |
Drop file filename | DORINFO1.DEF |
{node} |
Node number | 1 |
{baud} |
Baud rate | 57600 |
Example Menu Entries
Single-player door (PimpWars):
doorPimpWars: {
desc: Playing PimpWars
module: v86_door
config: {
name: PimpWars
image: /path/to/images/freedos_doors.img
dropFileType: DORINFO
nodeMax: 1
tooManyArt: DOORMANY
runBatch:
'''
@ECHO OFF
C:\FOSSIL\X00.SYS
COPY A:\{dropFile} C:\DOORS\PW\
CD C:\DOORS\PW
PW.EXE {node}
ECHO Returning to BBS, please wait... > COM1
'''
}
}
Multi-node door with shared game state (TradeWars 2002):
doorTradeWars2002: {
desc: TradeWars 2002
module: v86_door
config: {
name: TradeWars2002
image: /path/to/images/tw2002.img
dropFileType: DORINFO
nodeMax: 4
tooManyArt: DOORMANY
runBatch:
'''
@ECHO OFF
C:\FOSSIL\X00.SYS
C:\FREEDOS\BIN\SHARE.COM
COPY A:\{dropFile} C:\DOORS\TW2\{dropFile}
CD C:\DOORS\TW2
TW2.EXE
C:\FREEDOS\BIN\FDAPM POWEROFF
'''
}
}
ANSI color with DORINFO: ENiGMA½ sets the DORINFO graphics field to
2(ANSI color), which is the value required by RBBS-mode doors such as TradeWars 2002. A value of1enables IBM high-bit characters but not color in strict RBBS mode.
Image Preparation
Your disk image must contain:
- A working FreeDOS installation
- Your door game(s) installed (e.g.
C:\DOORS\PIMPWARS\) - Optionally, a FOSSIL driver such as X00 — required by most classic DOS doors
- An
AUTOEXEC.BAT(orFDAUTO.BAT) that callsA:\RUN.BATand powers off
AUTOEXEC.BAT Convention
Set up your image’s AUTOEXEC.BAT once. ENiGMA writes RUN.BAT to A: at runtime with the door-specific launch commands:
CALL A:\RUN.BAT
ECHO Shutting down, please wait... > COM1
FDAPM POWEROFF
-
CALL A:\RUN.BAT— executes the per-door launch script ENiGMA injects at runtime -
ECHO ... > COM1— sends a message to the user’s terminal while FreeDOS shuts down (can take a few seconds) -
FDAPM POWEROFF— shuts FreeDOS down cleanly; placed after the CALL so it always fires even if the door crashes
One Image, Multiple Doors
Because RUN.BAT is generated at runtime, a single FreeDOS image can host multiple doors. Each door has its own menu entry pointing at the same image path with a different runBatch:
doorPimpWars: {
module: v86_door
config: {
name: PimpWars
image: /path/to/images/freedos_doors.img
dropFileType: DORINFO
nodeMax: 1
runBatch:
'''
COPY A:\{dropFile} C:\DOORS\PW\
C:\FOSSIL\X00.SYS
CD C:\DOORS\PW
PW.EXE {node}
ECHO Returning to BBS, please wait... > COM1
'''
}
}
doorSmurfCombat: {
module: v86_door
config: {
name: SmurfCombat
image: /path/to/images/freedos_doors.img // same image
dropFileType: DOOR
nodeMax: 1
runBatch:
'''
COPY A:\{dropFile} C:\DOORS\SMURF\
C:\FOSSIL\X00.SYS
CD C:\DOORS\SMURF
SMURF.EXE {node}
ECHO Returning to BBS, please wait... > COM1
'''
}
}
All concurrent sessions for the same image path share a single in-memory disk buffer (SharedArrayBuffer). Guest writes from one session are immediately visible to others — exactly as they would be with a real shared disk. Use
nodeMax: 1for single-player doors that have no locking. For multi-node games that rely on file/record locking (e.g. TradeWars 2002), load a FOSSIL-aware SHARE driver (C:\FOSSIL\X00.SYSplusC:\FREEDOS\BIN\SHARE.COM) inrunBatch— the game handles concurrent access the same way it would on a real BBS.
FOSSIL Driver
Most classic DOS doors use the FOSSIL serial interface for COM1 I/O. If your door fails to start or falls back to local mode, a FOSSIL driver is needed. X00 works well with v86.
Load it from runBatch (per-door, recommended) rather than FDCONFIG.SYS (global):
C:\FOSSIL\X00.SYS
Or in FDCONFIG.SYS if all doors on the image need it:
DEVICE=C:\FOSSIL\X00.SYS
Creating and Configuring Images with oputil v86
ENiGMA½ ships two oputil subcommands for working with disk images without needing QEMU or DOSBox-X installed on the server:
oputil.js v86 console <image.img> Boot and wire COM1 to this terminal (interactive)
oputil.js v86 desktop <image.img> Boot in a full VGA browser session
console — best for doors that output entirely through COM1 (most doors). Use CTTY COM1 in the image’s FDAUTO.BAT to redirect all I/O. Ctrl+] exits and saves changes back to the image file automatically.
desktop — boots the image in a small local HTTP server and opens your browser to a full VGA canvas. Use this for setup programs that write directly to VGA (e.g. door configuration wizards). Click Save Image to write changes back to the image file on the server — no browser download dialog appears.
# Interactive COM1 terminal
node core/oputil/oputil_main.js v86 console /path/to/tw2002.img
# Full VGA browser session (opens browser automatically)
node core/oputil/oputil_main.js v86 desktop /path/to/tw2002.img --port 18086
See also: oputil.js fat for listing and copying files into images without booting them.
Creating the Image with QEMU
# Create a 500MB raw image
qemu-img create -f raw freedos_mygame.img 500M
# Install FreeDOS (boot from CD)
qemu-system-i386 -hda freedos_mygame.img -cdrom FD14CD.iso -boot d
# Boot into FreeDOS to install your door
qemu-system-i386 -hda freedos_mygame.img
# Transfer files from host using QEMU's vfat driver — files appear on D:
qemu-system-i386 -hda freedos_mygame.img -hdb fat:/path/to/door/files
DOSBox-X is a graphical alternative for image setup on Windows, macOS, and Linux. See the DOSBox-X documentation for imgmount.
FreeDOS Boot Configuration for Fast Startup
For ~5 second boot times, configure FreeDOS to use Emergency Mode (no memory managers, no networking). In FDCONFIG.SYS:
MENUDEFAULT=5,0
Ensure the 5? config block loads your FOSSIL driver:
5?DEVICE=C:\FOSSIL\X00.SYS
5?SHELL=C:\FreeDOS\BIN\COMMAND.COM C:\FreeDOS\BIN /E:1024 /P=C:\FDAUTO.BAT
See Also
- Local Doors
- External DOS Emulators
- Scripts & Native Binaries
- v86 — upstream JavaScript x86 emulator
