ENES
Play with my files
ENES
Play with my files

The references to source files and binary offsets you'll see here are the provenance of each claim: they say where it comes from. The engine is published under GPL-3.0-or-later at github.com/kokoima/openu5, so you can go and look them up one by one.

3 · Experience improvements

Touch controls, tapping the map to walk, save slots, Spanish, the scrollable log, and the developer console, and the atlas your browser builds.

Every point in this document is confirmed against the code, not inferred.


Contents

  1. Tapping the map to walk ✨
  2. Touch controls: the deck ✨
  3. Multiple save slots ✨
  4. Spanish ✨
  5. The scrollable log ✨
  6. The developer console ✨
  7. The atlas your browser builds ✨

1 · Tapping the map to walk

✨ ADDED · By tapping or clicking a cell in the viewport · Code: game/src/ui/autowalk.ts, game/src/core/world/pathfind.ts, skin/fiel/skin.ts (intent emission)

You tap a cell in the viewport and the party walks there, along the same code path an arrow key takes.

Before

Arrow keys, one step per press. Without a keyboard — that is, on a phone — you were left with the D-pad on the button deck, one tap per tile.

Now

You tap a cell in the viewport and the party walks there. One step every 140 ms, following the path computed by A* (findPath) over the active map and respecting the means of transport (on foot, horse, carpet, skiff, ship: the same transport the engine uses).

The design decision that makes it safe

Every step goes through game.move(dir) and applyEvents — exactly the same path as an arrow-key press. There is no parallel route that teleports, and no shortcut that skips the turn's events. That is the difference between "a convenience" and "a second implementation of movement that drifts out of sync".

And it is cancelled by:

Trade-offs


2 · Touch controls: the deck

✨ ADDED · On its own, where the pointer is coarse (pointer: coarse) · Code: game/src/ui/touch.ts (single source for the button deck), skin/portrait/deck-ancho.ts (CSS), deck-nativo.ts (behaviour)

A touch deck with every command in the game, censused against the binary, that fires as the finger lifts and appears when the pointer is coarse.

Touch deck, split layout

The deck appears when the pointer is coarse (pointer: coarse) — the pointer is measured, not the user agent. And that is not a criterion picked for this: it is the same predicate that brings up the split layout and that the skin uses to decide its mobile fit. Tying them guarantees that the split layout and the buttons that make it usable always appear together.

Buttons, derived from the tables in the code on 2026-08-16 (the figures are checked by game/tests/dungeon-botonera.test.ts, so they cannot go stale again):

SheetButtons
World (WORLD_BUTTONS)25
Utility (UTIL_BUTTONS)3
Dungeon (DUNGEON_BUTTONS)18
Combat (COMBAT_BUTTONS)13

Complete against the original, not against memory

The deck did not come from a list written from memory: it was censused against the binary's real dispatcher (kernel_cmd_dispatch @0x3178, case by case, plus the 'F'..'L' jump table at 0x3490), and the contextual sheets against the arena's own turn loop and the dungeon's per-location gate. Every command the original accepts has a button — lighting a torch at night in the open, attacking in a town or viewing a gem no longer require a physical keyboard.

The price, stated: the commands the census added go at the end of the grid, so as not to move the buttons that existing deck users had memorised under their thumb. Attack and Ignite torch, among the most frequent, sit below the fold.

The trigger, as the finger lifts

Buttons decide on pointerup, not on touch: it is a tap only if the finger moved no more than 10 px (≈ the Android/iOS touch slop), and if the browser keeps the gesture for its native pan, it does not count. Swiping to see more commands no longer presses the button underneath. The only exception is the D-pad, which stays on pointerdown: walking wants immediate response and repeat-on-hold, and it does not live in a scrollable area.

The ☰ button: the SYSTEM menu one tap away

The deck with the SYSTEM menu open

The deck's ☰ opens the SYSTEM menu directly — the same surface as F10 and the ⚙ button. There used to be an intermediate five-entry popover here and it was retired after being measured: reaching the saves, the video or the keys always took two taps, and the first one decided nothing. Its entries live in the menu itself today: Switch pad side (moves the D-pad; the default is right, "for right-handers", deck-nativo.ts:ladoGuardado) and Split layout (portrait) — the same toggle as the ▤ discussed in 2 · Layouts §4.

The hint that there is more below

The commands below the fold were invisible: "it does not look like there is more". The solution is a chevron with a gradient on the relevant edge when there is content out of view (ui/scroll-hint.ts). Both overlays carry pointer-events: none, so they never steal a tap.

Trade-off: measuring the pointer also over-fires

Tying yourself to pointer: coarse is right — the user agent lies, and a bespoke criterion would leave the split layout without its buttons — but it has a cost worth knowing: a laptop with a touchscreen reports coarse. That user has a keyboard and a mouse, and still gets the deck and the split layout by default.

It is not a fault of the predicate: it is that "are there fingers?" and "is this a phone?" are not the same question, and only the first one can be measured. The way out exists and is one click away — the deck's ▤, or the ⚙ → Video checkbox — and the preference beats the default in both directions, so whoever turns it off stays off. But the first launch on that machine looks like a phone.


3 · Multiple save slots

✨ ADDED · Code: game/src/core/persistence.ts, ui/savepanel.ts · F5

Named, unlimited slots, with export and import, instead of the original's single SAVED.GAM.

Before

The original had a single SAVED.GAM. It is stated in the first line of the docstring of persistence.ts, and it is the reason the panel exists.

Now

Save panel with two slots

Named slots, unlimited, each with its place, its turn and its date, plus Load and Delete buttons. Below: name and Save, plus Export, Export .GAM and Import.

The four decisions behind it

  1. localStorage, not OPFS. OPFS would be cleaner for large blobs, but its API is asynchronous and still uneven across browsers. localStorage is synchronous, universal and more than enough for a serialised GameState.
  2. A light index kept separately. The index lives in u5clone:saves and each full save in u5clone:save:<id>, so that listing the slots does not force deserialising every state.
  3. It never throws on a full quota. The soak test found that an uncaught QuotaExceededError in the boot autosave left the game half-initialised — a boot zombie. Now saveGame returns {ok:false, reason:"quota"} and the caller decides: a message to the user on a manual save, silence and a log on the autosave.
  4. A rotating 3-slot autosave (autosave-1/2/3, round-robin) so one autosave does not overwrite the previous one.

The bridge back to the original, which is the elegant part

"Journey Onward" still works. The original's title menu reloads SAVED.GAM verbatim; here SAVED.GAM = the slot with the highest timestamp, whether an autosave or a manual save. With none, it starts a new game — just like the default SAVED.GAM that shipped on the disk. The multi-slot feature is added without breaking the 1988 flow.

Exporting in the 1988 format

"Export .GAM" produces a SAVED.GAM + SAVED.OOL + sidecar in the original disk format, from a 4192-byte template. You can take a game out of the port and — in principle — carry it to the real game.

Trade-offs


4 · Spanish

✨ ADDED · Code: game/src/i18n/ · Switched live with the 🌐 / ES button

The whole game text in Spanish, as a substitution table over the English of the transcription, switchable live.

SpanishEnglish
console in Spanishconsole in English

The model, which is what makes it safe

English is the floor of the replica, not "one more language": every piece of text comes byte-exact from the binary, and all the guards (pixeldiff, Grand Tour, approved-strings) are anchored against it. A language other than English is a parallel substitution table, keyed by the original English string, resolved at a single choke point (t()):

That last property is what makes translating a byte-for-byte replica not a risk: what is missing does not break, it shows in English.

Where the table lives, and why there

In src/i18n/ (versioned source), not in game/assets/. assets/ is material extracted from the binary and kept out of git; the language table is newly authored content and belongs under version control.

Status, measured on 2026-08-04

MetricValue
Entries in es.json4 000
Marked as reviewed (reviewed: true)3 994
Language quotes« … »

There is a separate layer for the shell (menus, panels: authored text, not from the binary) with its own ts() function.

Trade-offs


5 · The scrollable log

✨ ADDED · Wheel or drag over the console · Code: game/src/skin/fiel/skin.ts (ConsoleScrollback, consoleScrollLines, consoleScrollToLive)

The console keeps a scrollback: wheel or drag to reread what scrolled off, with the >HISTORY< band of the 1988 frame.

Before

The original's console shows the last lines and nothing more. What scrolls off the top is gone: there is no way to re-read what an NPC said three turns ago.

Now

Live consoleHistory mode
live consolehistory mode

Wheel or drag over the console area and you enter history mode. Notice the band that appears in the chrome: >HISTORY<, with the same band brackets as the rest of the 1988 frame. It is not a modern scrollbar stuck on top; it is an indicator drawn in the skin's own language.

You leave by returning to the bottom or with any key: you never get stuck in the past while the game waits for a command.

The details that keep it out of the way

Trade-off

The history belongs to the session, not the save: it is skin state, not GameState. Reloading the page loses it.


6 · The developer console

✨ ADDED · ` ` key or F4, or ⚙ → "Debug (QA)" · Code: game/src/debug/ (panel, section registry, window.__u5debug` facade), gate in game/src/main.ts

The project's own debug panel, open to everyone: edit almost any field of your game — and editing marks the save as touched, forever.

Before

The original ships nothing like this. Cheating a 1988 game meant editing SAVED.GAM byte by byte with an external tool, with no safety net: one wrong byte and the save does not load.

Now

The very panel the port is debugged with travels in the published game, enabled by default (the emergency exit is ?debug=0 in the URL). It is a side drawer with a field search box and an accordion of sections: point-and-click teleport with a map picker, party and stats, resources and inventory, the Britannia clock, quest flags, NPCs, moonstones, transports. It writes directly into live state without consuming the engine's RNG — editing does not desync the game's determinism.

On mobile there is no backquote and no F4: the entry point is ⚙ → "Debug (QA)" → "Open debug menu", always available.

The debug drawer open over the game's right-hand edge, with a DEBUG header, a field filter box, three shortcuts — max everything, best gear for everyone, full party at maximum — and a teleport section with a clickable map of Britannia and selectors for location, floor and dungeon

The drawer over the game's right-hand edge, on the desktop.

The SYSTEM menu on a phone: first the game's key reminder, and below it four collapsible entries — privacy, atlas help, close the menu, and Debug (QA), which opens the debug menu with the backquote key or F4 —, with the touch command keyboard taking up the last thirdThe same debug drawer on a phone, filling nearly the whole width, with the field filter, the three shortcuts, the teleport map and, at the foot, a red button to enter the dungeon through the real flow, marked as random

On the phone: the way in through ⚙ → «Debug (QA)» and the same drawer, full width.

Trade-off

It is deliberate and visible: editing marks the save. The first mutation that goes through the panel stamps a persistent mark into the save (it travels with it and survives save/load) and lights a discreet on-screen tag — ⚑ EDITED. Opening the panel and looking does not mark; editing does, and the mark cannot be removed from the panel itself. A touched game stays distinguishable from a cleanly played one — by design.

The same screen with the drawer open, and now a badge with a small flag and the word EDITED in the bottom-left cornerThe game without the drawer, the whole party panel visible — Avatar, Shamino and Iolo with their gold —, the food and gold counters at 9999, and the badge with the small flag and the word EDITED fixed in the bottom-left corner

The same screen before and after closing the drawer: the ⚑ EDITED badge stays.


7 · The atlas your browser builds

✨ ADDED · ⚙ → "Help · Atlas & guide", or straight to /companion · Code: docs/manual/companion/byo-runtime.mjs (the client-side build), menu probe in game/src/ui/shell/companion.ts

A full guide — walkthrough, bestiary, spell and reagent tables, navigable maps — that stores none of the game's data: the maps, the interiors and the portraits are drawn by your browser, from your copy.

Before

The original shipped its documentation in the box: the cloth map, the spell book and the Book of Lore. Anyone playing from a digital copy today rarely has any of that at hand, and what circulates online are scans of material nobody is entitled to hand out.

Now

The port brings its own atlas, served at /companion and linked from inside the game at SYSTEM → Help · Atlas & guide. The link only appears if the probe answers, so it never leads to a page that is not there.

What is inside is split in two halves, and the split is the whole point:

Supply nothing and the atlas does not break: it still hands you the written half in full, and marks the sections that need data with a door to /byo instead of a blank page.

The companion atlas in the browser: on the left an index with the book's sections, and on the right the map of Britannia drawn tile by tile over blue sea, with filter checkboxes by kind of place and coloured markers over towns, dungeons, castles, lighthouses, shrines and moongates

The atlas with a copy supplied: the map is drawn by the browser, tile by tile.

The atlas table of the eight reagents: one row per reagent with its colour, its domain and the towns where it is sold with price and stock, and below a note about the five towns that sell them. In the index on the left, the map, places, characters and companions entries appear dimmedThe atlas on a phone screen: a top bar with the menu button and the magnifier, and below it the whole map of Britannia with its coloured markers and the legend split over two lines

The half the project writes — here, the eight reagents — needs no copy of yours; on the right, the atlas on the phone.

Trade-off

Two of them, both deliberate: