#Anatomy of a door
The manifest:
apimust be 1.slugis the unique lowercase id; it names the door's storage and its DOOR menu argument.entryis the PHP file to include;classis the fully qualified class it defines.- Install by uploading the folder to
data/doors/(ordoors/) and pressing Scan on the console Doors page.
#The lifecycle
The class implements three methods:
enterruns when the caller opens the door; return the opening frames.inputruns per keystroke, line, or editor payload, exactly like board screens. Check$in->kindforkey,lineoreditor, then read the matching field.- To exit, include
$c->exitDoor()in your returned frames; the board pops the caller back to the menu and callsleave.
#DoorContext: every service
| Call | Gives you |
|---|---|
| $c->out() | An ANSI builder: ->cls(),
->at(row, col), ->txt(), ->fg(),
->bg(), ->reset(), ->str(). |
| $c->pipe(s) | Render pipe codes in a string to ANSI. |
| $c->center(s) | Center a line on the 80-column screen. |
| $c->ansi(s) | Wrap a raw ANSI string as a frame. |
| $c->bell() | A terminal bell frame. |
| $c->hotkey() | Ask for single-key input mode. |
| $c->line(...) | Ask for line input mode, with a prompt and options. |
| $c->editor(...) | Ask for the full-screen editor. |
| $c->exitDoor() | The leave-the-door frame. |
| $c->user() | The caller row: id, handle, level. |
| $c->state | A per-visit scratch array, persisted between requests automatically. |
| $c->kv() | The door's private key/value store: get, set, del, all by prefix. |
| $c->table(...) | A private database table. See below. |
| $c->files() | A jailed folder under data/doorstore/<slug>/
for flat files. $c->path(name) resolves one file inside it. |
| $c->award(n) | Add to this caller's score for the board-wide DOOR CHAMPIONS ladder on the Stats screen. |
| $c->log(msg) | A line in the board events log, tagged with your slug. |
| $c->localStamp(...) | Format a UTC timestamp in the board timezone. |
| $c->boardRumors(n) | A few current board rumors, for flavor text. |
| $c->dropfile() | Path of the classic-style JSON drop file written for this session. |
#Storage: tables that scope themselves
A door never touches the board's tables. $c->table() creates and returns a
table named door_<slug>_<name> from a compact schema:
Column types: pk (auto id), int, text (add
'short' => true for indexable varchars), datetime. The third
argument lists indexes. The object then offers:
| insert(row) | Insert one row; returns the new id. insertMany(rows)
for a batch. |
| rows(...) | Select many, with where, order and limit. |
| one(where) | Select one row or null. |
| count(where) | Aggregate. sum(col, where) too. |
| update(set, where) | Update matching rows. |
| delete(where) | Delete matching rows. [] means all. |
The where grammar is an array: a bare column means equals, or suffix an operator inside the key.
Operators: =, !=, <, <=,
>, >=, IN, LIKE. Everything is a
prepared statement underneath; identifiers are validated, so injection has no doorway.
#The crash wall
Any uncaught exception or PHP error inside a door is caught by the board: the caller sees a short in-character apology and lands back at the menu, and the full error goes to the events log for you.
#The cron hook
If the folder has a cron.php, the board's daily tick includes it (each enabled
door, each day, wrapped in its own try/catch) with $doorCron in scope:
Make it idempotent: record the last day you ran in kv and return early on a
repeat. Star Merchant's cron.php is the worked example.
#The admin panel hook
If the folder has an admin.php, the console Doors page grows a panel link for it.
Your file renders inside the console page with $doorAdmin (kv and tables, plus the
db) and $csrfField to drop into every form you print. Handle your own POSTs at the
top, exactly like Star Merchant's panel does.
#The drop file
On entry the board writes a JSON drop file, with its path from $c->dropfile(),
carrying the board name and version, base URL, node, and the caller's id, handle and level. The
spiritual DOOR.SYS, for doors that want a file interface or external tooling.
#Learn from HILO, then ship
- Read
doors/hilo/door.php: about 120 lines using the state bag, kv, line mode and award. The SDK README atdoors/README.mdwalks it line by line. - Keep every visible row inside 80 columns; position with
at()rather than trailing on wraps. - Never touch superglobals or board tables. Everything you need arrives through the context.
- To distribute: zip the folder. Another sysop drops it in
data/doors/, presses Scan, done.