C64 Doors
March 17, 2026 · View on GitHub
Draft — This document was generated by AI and may not have been reviewed for accuracy.
C64 Doors are WebDoors that run Commodore 64 programs inside a jsc64 emulator embedded directly in the browser. They require no additional server-side components beyond PHP — no bridge, no DOSBox, no Node.js.
Table of Contents
- How It Works
- Creating a C64 Door
- Supported File Types
- Configuration Reference
- D64 Disk Images
- Enabling the Door
How It Works
Each C64 Door is a WebDoor whose index.php includes the shared
_c64engine/player.php template. The engine:
- Authenticates the user and checks the door is enabled.
- Reads the game file (PRG, ROM, BIN, or D64) from the door's directory.
- Base64-encodes the program bytes and embeds them directly in the HTML page.
- Boots the jsc64 C64 emulator (Kernal, BASIC, and Character ROMs are in
public_html/vendor/jsc64/js/assets/). - After the 2-second BASIC boot, writes the program bytes into emulated memory and executes them.
No API calls are made at runtime — the program data travels with the page load.
Creating a C64 Door
File Structure
public_html/webdoors/
└── mygame/
├── webdoor.json ← door manifest
├── index.php ← sets $c64Config, includes the engine
└── mygame.prg ← the game (or .d64, .rom, .bin)
Copy public_html/webdoors/_c64example/ as a starting point, rename the
folder to your game's slug, and replace game.prg with your actual file.
index.php
<?php
$c64Config = [
'door_id' => 'mygame', // must match webdoor.json "id"
'title' => 'My C64 Game', // shown in the loading spinner
'prg' => 'mygame.prg', // file in the same directory as index.php
];
require __DIR__ . '/../_c64engine/player.php';
That's the entire index.php. The engine resolves prg relative to the door's
own directory automatically.
webdoor.json
{
"webdoor_version": "1.0",
"game": {
"id": "mygame",
"name": "My C64 Game",
"version": "1.0",
"author": "Author Name",
"description": "Short description shown in the games list.",
"entry_point": "index.php"
},
"requirements": {
"min_host_version": "1.0",
"features": []
},
"config": {
"credits_cost_per_session": 0
}
}
game.id must match door_id in index.php. The folder name is
conventionally the same value.
Supported File Types
The engine detects the file type from the extension and handles it automatically:
| Extension | Handling |
|---|---|
.prg | Standard C64 PRG — reads the 2-byte load address from the file header |
.p00 | P00 container — strips 26-byte header, then reads as PRG |
.d64 | C64 floppy disk image — extracts PRG files; loads the first one by default |
.rom | Raw cartridge ROM — loaded at $8000 (32768) |
.bin | Raw binary — loaded at $8000 (32768) |
| other | Treated as PRG (2-byte header read) |
Use load_address in $c64Config to override the default for any extension
(see Configuration Reference).
Configuration Reference
All keys for $c64Config:
| Key | Type | Required | Description |
|---|---|---|---|
door_id | string | Yes | Door identifier — must match webdoor.json id |
title | string | Yes | Game title shown in the loading spinner |
prg | string | One of these | Filename of a PRG/ROM/BIN in the door's directory |
d64 | string | One of these | Filename of a D64 in the door's directory |
prg_path | string | One of these | Absolute path to a PRG/ROM/BIN |
d64_path | string | One of these | Absolute path to a D64 |
prg_name | string | No | PRG name to auto-select from a D64 (default: first entry) |
load_address | int | No | Override load address; file loaded as raw binary with no header |
prg vs prg_path: Use prg for files that live next to index.php —
it's the shortest form. Use prg_path only when the file lives outside the
door's directory.
load_address example — loading a cartridge at a non-standard address:
$c64Config = [
'door_id' => 'mygame',
'title' => 'My Game',
'prg' => 'mygame.rom',
'load_address' => 0xC000, // override auto-detected \$8000 default
];
D64 Disk Images
A D64 door can contain a whole floppy's worth of programs. By default the
engine loads the first PRG found in the disk directory. Use prg_name to
select a specific one:
$c64Config = [
'door_id' => 'mygame',
'title' => 'My Game',
'd64' => 'mygame.d64',
'prg_name' => 'LOADER', // exact name as it appears in the D64 directory
];
PRG names in D64 images are uppercase — check them using the file preview in the BBS file browser, which shows the disk directory.
A .d64 file may also be passed via the prg key; the engine recognises the
extension and handles it correctly.
Enabling the Door
C64 Doors are WebDoors and go through the same activation flow:
- Drop the door folder into
public_html/webdoors/. - In the BBS admin panel go to WebDoors and click Refresh.
- Find the new door in the list and click Enable.
- Adjust credits cost if desired and save.
The door will appear in the WebDoors section of the BBS for all logged-in users.