Classic Ultima Online on Godot 4 .NET
GUO runs in a web browser. The same C# client as on the desktop logs in to a
shard, enters the world and plays. On 2026-09-27, in headless Chrome, it
created a character on the local dev shard, walked in Valoria with footstep
sounds, opened the backpack and moved an item. Firefox is verified as far as
the login screen. This page is the short version; the decision record is
ADR-0008 (Accepted, Amendment 1), and the how-to is tools/web/README.md.
Two things make it different from the other builds:
tools/godot_web,
kept apart from the pinned engine; its README gives the origin and the
SHA-256.launchers\web\doctor.bat REM what the web export needs, and what this PC has
launchers\web\export.bat REM export build\web\GUO.html with the community build (~10 min)
launchers\web\serve.bat REM the page + your install at /uo/, on 127.0.0.1 only
launchers\web\ws_bridge.bat REM the shard over WebSocket (a browser cannot open TCP)
launchers\web\smoke.bat REM export + serve + Chrome and Firefox + wait for the login screen
tools/godot_web/README.md: download
the 4.7.2 release zip, check its SHA-256, unzip it self-contained, put its
web templates in its own editor_data, and add a private .NET SDK with the
wasm workload. Do not run its install.bat: it writes into the same
template folder and NuGet feed as the pinned engine.UO_CLIENT_DATA,
UO_CLIENT_VERSION, UO_SHARD_HOST / UO_SHARD_PORT in
launchers\_shared\config.local.bat.launchers\web\doctor.bat should report no MISS.launchers\shard\run.bat REM the dev shard (or point UO_SHARD_HOST at another)
launchers\web\export.bat REM once per client change
launchers\web\ws_bridge.bat REM leave it running: ws://127.0.0.1:2594 -> the shard
launchers\web\serve.bat REM leave it running
Then open http://127.0.0.1:8060/GUO.html in Chrome or Firefox. Optional
page parameters: ?host=ws://...&port=... for another bridge, ?arg=--foo
for any client argument, ?data=uo/ for where the install is served (none
mounts nothing).
Off by default. Set UO_WEB_LAN=1 (or pass --lan) and serve and the
bridge listen on this PC’s private network address only, over https and
wss, and turn away connections from non-private addresses. A phone’s browser
needs the page on https, so serve makes a small certificate authority for
this PC that the phone installs once. UO_WEB_LAN_HOST names the address if
the wrong network card is picked. Steps: tools/web/README.md. Written from
that README, not run here.
| Chrome | Firefox | |
|---|---|---|
| Login screen | yes (52-58 s from a cold start, headless) | yes (213-235 s, headless) |
| Log in, relay, create a character | yes | not yet run |
| In the world: walk, sound, backpack, drag and drop | yes | not yet run |
The client reads about 230 MiB of the install to reach the login screen and about 370 MiB for a short session, out of 2.6 GB.
wss:// bridge
behind TLS; nothing is set up.docs/web/unblock-report.md).serve sends the headers; most static hosts do not.docs/web/2026-09-28_firefox_boot.md).serve):
with no install served, the first-run screen’s Choose folder opens the
browser’s folder picker, and the files are read where they are, never
uploaded. Works in Chrome and Firefox; in Firefox the tab does not
respond until the slow start finishes. The pick lasts for the visit: the next visit asks again.