User Manual

Everything you need to run Krebf on your WordPress site. (v1.0.9)

About this software

Krebf is a JavaScript port of Fredrik Ramsberg's Ruby Z-machine interpreter. The original Ruby source lives at github.com/fredrikr/krebf and is the authoritative reference for any interpreter behaviour question.

Contact:

Contents

  1. Installation
  2. Adding story files
  3. The [krebf] shortcode
  4. URL parameters (?game=)
  5. The games dropdown
  6. Themes
  7. Admin settings
  8. Playing a story
  9. Save slots
  10. Transcripts
  11. External URLs
  12. Auto-updates
  13. Frequently asked questions
  14. Troubleshooting

1. Installation

From the plugin zip

  1. Download krebf.zip.
  2. In WordPress: Plugins → Add New → Upload Plugin.
  3. Choose the zip, click Install Now, then Activate.

Manual install via SFTP

  1. Upload the krebf/ folder into /wp-content/plugins/ on your server.
  2. Go to Plugins → Installed Plugins and activate Krebf Z-Machine Player.

What activation does

2. Adding story files

The runtime location for your story files is:

wp-content/uploads/krebf-games/

Drop your .z3, .z5, .z8 (etc.) files in that directory using SFTP, SSH, or your hosting provider's file manager. The filename becomes the slug:

File on diskURL slugDropdown label
zork1.z3zork1Zork 1
hitchhikers.z5hitchhikersHitchhikers
a-mind-forever-voyaging.z4a-mind-forever-voyagingA Mind Forever Voyaging
trinity.z4trinityTrinity

Supported extensions

.z1 .z2 .z3 .z4 .z5 .z7 .z8 .dat .story — anything else is ignored when listing and refused when requested. Maximum file size is 512 KB (Z-machine spec's hard ceiling for v8 stories).

3. The [krebf] shortcode

Drop this into any post, page, or block-based layout:

[krebf]

That gives you the full player: welcome screen, games dropdown, upload button, save/restore/transcript controls. The visitor picks a game, or you link to the page with a URL parameter (see next section).

Attributes

AttributeDefaultPurpose
game (none) A slug from your games folder, or an https://… URL. Auto-loads on page open. Overridden by a ?game= URL parameter if the visitor arrives with one.
height 720px CSS height for the player container. Accepts px, em, rem, %, vh, vw, ch.
width 100% CSS width. Same unit set as height.

Examples

[krebf]
[krebf game="zork1"]
[krebf game="zork1" height="800px"]
[krebf game="https://example.com/cloak.z5"]

One per page

The interpreter uses module-level state — only one player runs per page load. If you place [krebf] twice, the first copy is active and the second becomes inert scenery.

4. URL parameters

On any page containing the shortcode, you can preselect the story with:

https://your-site.example/play/?game=zork1
https://your-site.example/play/?game=trinity
https://your-site.example/play/?game=https%3A%2F%2Fifarchive.org%2F...

Two forms are recognised:

Priority

When multiple sources say "load a game", Krebf picks in this order: (1) the ?game= URL parameter, (2) the shortcode's game="" attribute, (3) the site-wide default set in admin settings.

In the top-right of the player sits a select list labelled "— choose a story —". Krebf populates it automatically by scanning your games folder. Pretty titles are derived from the filenames (underscores and dashes become spaces, words are capitalised).

Because the dropdown is filled server-side from the already-sanitised file list, visitors only ever see filenames and human-readable titles; the absolute server path never leaves the host.

Refreshing the list

Add or remove files in the games folder and the next page load will reflect it. There is no caching layer to bust; the plugin scans the directory on each render.

6. Themes

As of v1.0.1, the player ships with four selectable visual themes:

Pick the site-wide default under Settings → Krebf → Appearance. Override per-embed with the theme="" shortcode attribute:

[krebf theme="green"]
[krebf theme="paperwhite" game="zork1"]
[krebf theme="inherit"]

When the chosen theme is Inherit, Krebf doesn't enqueue Google Fonts — useful on privacy-conscious or air-gapped sites that decline external font requests.

7. Admin settings

Visit Settings → Krebf in the WordPress admin.

Theme

Amber CRT, green phosphor, paperwhite, or inherit (see the Themes section above). Per-embed [krebf theme="…"] still overrides this.

Games directory

Where your story files live. Empty means "use the default under wp-content/uploads/krebf-games/". You can set a custom absolute path, but it must sit somewhere inside wp-content/ — anything else is silently refused.

Allow external URLs

Off by default. Turning this on enables the ?game=https://… form of URL parameter. Even when enabled, several safeguards remain active: host allow-list (see below), SSRF IP filtering, 512 KB size cap, 10-second timeout, Z-machine signature check.

Allowed hosts

One hostname per line. Leave empty to permit any public host (still protected by the SSRF checks). To restrict to the IF Archive, for example, enter:

ifarchive.org
*.ifarchive.org

A leading *. matches any subdomain. An empty list means "anything not blocked by the SSRF defences is fine".

Default game

Optional. If a visitor reaches a [krebf] page with no ?game= on the URL and no game="" attribute in the shortcode, the default game is loaded instead. Useful when you have one "featured" title per site.

8. Playing a story

The player window divides into three bands:

Type commands at the prompt and press Enter. Standard IF verbs apply: north, take lantern, read letter, inventory, look, examine object. In-game meta-commands save, restore, undo, quit, verbose all work.

Special keys

KeyAction
EnterSubmit the typed command.
EscSends ZSCII 27 (games that handle it treat it as "cancel").
↑ ↓ ← →In single-character input mode (map puzzles, etc.) these map to ZSCII arrow codes 129–132.
F1F12Sent as ZSCII codes 133–144 when a story uses read_char.

9. Save slots

Clicking Save opens a dialog prompting for a slot name. A timestamp-based default is pre-filled. Names are free-form, and re-using a name overwrites the earlier slot.

Saves live in localStorage under the key prefix krebf_save_ — they are scoped to the browser profile and origin, not to any WordPress user account. A private browsing window sees an empty slot list by design.

Restore lists every save that came from the currently loaded story file. You can delete individual slots via the icon.

Saves are local to the browser

Clearing browser data, switching devices, or using incognito mode will leave saves inaccessible. For long plays, use the in-game save verb regularly and consider downloading a transcript (see below) as an out-of-band backup of your progress.

10. Transcripts

The Transcript button downloads every line of output the game has produced in the current session as a plain .txt file. Useful for preserving a playthrough, sharing walkthroughs, or citing from an academic essay.

Krebf also honours the in-game transcript stream (output_stream 2 in Z-machine terms). Many Infocom games expose this as a meta-command — type transcript or script to toggle it. The TRANS LED lights when the stream is active.

11. External URLs

When Allow external URLs is enabled, a link of the form:

https://your-site.example/play/?game=https%3A%2F%2Fifarchive.org%2Fif-archive%2Fgames%2Fzcode%2Fminizork.z3

causes the server to:

  1. Resolve the hostname and verify every A/AAAA record falls within a public IP range — 127.x.x.x, 10.x, 172.16–31.x, 192.168.x, 169.254.x, ::1, fc00::/7, etc. are rejected before any HTTP is attempted.
  2. Check the host against your allow-list (if non-empty).
  3. Fetch via wp_safe_remote_get with a 10-second timeout.
  4. Refuse HTML responses (common phishing vector).
  5. Verify the first byte of the body is 1–8 (a real Z-machine version number).
  6. Stream the verified bytes to the browser as application/octet-stream.

End result: the visitor loads any publicly-hosted Z-code story you allow, and your server bears the cost of the download; the browser never makes a cross-origin request of its own.

12. Auto-updates

From v1.0.9 onwards, the plugin checks https://www.callapple.org/krebf-updates/krebf.json twice a day for new releases. When a newer version is available it appears on the standard Plugins screen with the same yellow notice and one-click update button as any plugin hosted on .org.

How it works

The plugin hooks the pre_set_site_transient_update_plugins filter and injects its own update record. The remote endpoint serves a small JSON document with the current version, a download URL, and the sections the “View details” lightbox renders (description, changelog, installation). Cached for 12 hours; the cache clears automatically when an update completes.

Forcing an immediate check

The plugin row on Plugins → Installed Plugins has a Check for updates link that wipes the cache and asks WordPress to re-poll right now. Useful after a release announcement.

Disabling auto-updates

WordPress's standard auto-update opt-in applies. On Plugins → Installed Plugins, the Krebf row has an Enable auto-updates link if you want unattended updates. Leave it untoggled for manual updates only — the plugin still tells you when one is available.

Privacy

The update poll sends a generic User-Agent (Krebf/1.0.x (+WordPress; updater)) and nothing else — no site URL, no admin email, no install metrics. The endpoint returns the same JSON document to every requestor.

Air-gapped sites

If your server can't reach the public internet, the update checks will fail silently every 12 hours and time out at 10 seconds. There's no impact on the player; you'll just need to upgrade by manually uploading new releases.

13. Frequently asked questions

Why doesn't version 6 work?

V6 is Infocom's graphical branch (Journey, Shogun, Zork Zero, Arthur). It requires a window system and pixel fonts that the Ruby source this plugin was ported from never implemented. The other eight versions handle everything Infocom shipped in text mode, plus every modern Inform 6/7 output.

Will it run Blorb files?

Raw .zblorb isn't yet parsed — you'd need to extract the Z-code chunk first. On the roadmap.

Does it work on mobile?

Yes. The virtual keyboard pops up when the command line is focused. Long sessions on a small screen are inherently awkward for parser-based games, but nothing is broken — saves, scrolling, and transcripts all behave.

Can I style it to match my theme?

Yes — three ways, in increasing order of intrusiveness: (1) Set the plugin theme to Inherit (Settings → Krebf) so the player borrows your site’s colours and fonts. (2) Use a per-embed theme attribute: [krebf theme="paperwhite"]. (3) Override the --krebf-* CSS variables from your theme’s stylesheet; see the Technical Reference for the full list.

Does it send any data anywhere?

No. No telemetry, no analytics, no phone-home. Story files come from your server; saves live in the visitor's browser; transcripts download straight to disk. The only outbound requests are optional external URL fetches the visitor explicitly triggers.

14. Troubleshooting

The dropdown is empty

The games folder is unreadable or contains no matching files. Check:

"Story not found" on ?game=slug

Most often a filename mismatch. zork1.z3 matches ?game=zork1 but not ?game=Zork1 (filenames are case-sensitive on Linux hosts). Verify the actual filename on disk.

"This URL is not permitted"

External URLs disabled, the host isn't on your allow-list, or the target resolves to a private IP. Enable the feature in Settings, add the host, and confirm it's publicly addressable.

Story loads, but garbled output

Most likely a truly exotic Z-code variant or a file corrupted in transit. Try loading the file in another interpreter (Frotz, Bocfel, Gargoyle) to confirm; if those also fail, the file itself is bad.

Conflict with another plugin

All Krebf styles are scoped under .krebf-root and all JavaScript is inside an IIFE, so conflicts should be rare. If you spot one, it's most likely another plugin's stylesheet using aggressive * { } or button { } rules that win on specificity. Bump Krebf's specificity with a theme override:

.krebf-root .krebf-btn {
  /* your overrides */
}

See the Technical Reference for architectural detail, REST endpoints, hook catalogue, and the interpreter's internal structure.