Skip to content

Client Web Development

Kit Oliynyk edited this page Nov 2, 2026 · 3 revisions

TL;DR: The web client (mudjs) is a React and Vite app that speaks the JSON WebSocket protocol to the game. Work happens on the dreamland branch, npm run dev gives a hot-reloading copy on port 3000 that connects to the live game, and a push to dreamland rebuilds and publishes the client. The master branch is a frozen generic client for other MUDs. Use when: you change the web client, run it locally, point it at another server, or ship a client change. Source of truth: mudjs/package.json, mudjs/vite.config.js, mudjs/src/websock.js, mudjs/.drone.yml, mudjs/scripts/hooks/pre-push Verified: 2026-11-02 against mudjs 990bf6d (default branch dreamland), dreamland_code 88da8302

What it is

mudjs is the browser client served at https://dreamland.rocks/play. It is public: github.com/dreamland-mud/mudjs, GPL-3.0. Players get a terminal with clickable output, side panels (location, group, affects, quest, who, weather), a graph map with search, chat frames, a help sheet, settings with aliases, macros, triggers and sounds, and a login roster. The wire format is described in Client-Web-Protocol.

Stack, from package.json: React 18, Redux, Vite 6, MUI 5, Bootstrap 4 and jQuery (the terminal and tag code is still jQuery), Monaco for the script editor, d3 and three for the map. The project needs Node 20.19 or newer (sass and its dependencies require it), the deploy uses 22.

Two branches exist:

Branch State Use
dreamland Default. All work lands here. Tight integration with the DreamLand protocol. The game's client.
master Frozen since 2018. Small generic client, no game-specific protocol. A base for another MUD, see Use it for another MUD.

Run it locally

git clone https://github.com/dreamland-mud/mudjs.git
cd mudjs
npm install
npm run dev

Vite serves on port 3000 under the base path /play/, so open http://localhost:3000/play/. Edits hot-reload. By default the client connects to the public game server, so you play on the real game with a real character. Create a throwaway character if you only test the UI.

package-lock.json is ignored by git. The deploy build runs npm install --legacy-peer-deps, so use the same flag if npm install complains about peer dependencies.

The dev server proxies four paths (vite.config.js):

Path Goes to
/api http://localhost:4000 (a local API, if you run one)
/maps, /help, /data https://dreamland.rocks (map JSON, help dumps, site data)

Map graph files can be staged locally: put them under dev-maps/graph/ (git-ignored) and the dev server serves them at /maps/graph/ before the proxy. A missing file falls through to the proxy, and the map shows its ASCII fallback if there is no data at all.

If the page loads and the socket never connects, check whether an ad blocker is active on the page. They are known to block the WebSocket.

Choose the server

The server address is the wsUrl constant at the top of src/websock.js:

  • Default: the public game server.
  • Open the page with #build in the address to connect to the build server (the sandbox where builders and scripters work). Ask the team for a builder character first, see Building.
  • Local play is not supported through this client. The web client expects the full nanny dialogue of the live server, which a stock local server does not provide, and the client source says the local WebSocket on 1234 stalls at login. Use telnet on port 9000 (or the backdoor on 9001) for a server on your machine, see Local-Setup.

Build

npm run build     # writes build/
npm run preview   # serve build/ locally

The output goes to build/, not Vite's default dist/. Every build stamps an id into the bundle and into build/version.json. A running client polls that file every three minutes and reloads itself into the new build once the player has been idle for 15 seconds and is not in a fight (src/autoupdate.js). Until then a dismissable banner offers an immediate update.

Ship a change

  1. Branch from dreamland, change, open a pull request against dreamland. Commit messages and PR text are English.

  2. Install the pre-push hook once. It runs npm run build before every push and skips itself when node_modules is missing:

    ln -sf ../../scripts/hooks/pre-push .git/hooks/pre-push

    Bypass one push with git push --no-verify.

  3. A push to dreamland triggers the project's CI (.drone.yml). It resets the deploy checkout to the branch head, runs npm install --legacy-peer-deps and npm run build, and reports success or failure to the team chat. The built files are the live client. There is no staging step, so a broken merge breaks /play until the next good push.

  4. .travis.yml (Node 14, plain build) is legacy and no longer matches the Vite version. .gitpod.yml (build and python3 -m http.server) is also old and was not re-tested (unverified).

Code map

src/ at the top level holds single-purpose modules, src/components/ the React views.

Path What
websock.js, telnet.js Socket, reconnect, resume, keepalive, KOI8 decoding and telnet bytes.
store.js, prompt.js, react-hooks.js Redux store and the merged prompt object (window.mudprompt).
manip.js, ansi2html.js Turn output tags and ANSI colours into elements.
input.js, aliases.js, macros.js, triggers.js, settings.js, sound.js The command line and the player's scripting layer.
i18n.js, langsync.js Interface language (en, ru, ua) taken from the prompt.
components/terminal.jsx Output area. Live region for screen readers.
components/mapper/ The graph mapper (rooms, z-layers, search, path finding).
components/windowletsPanel/ Side panels.
components/settings/ Settings dialog and its pages.
components/sysCommands/ The client-side # commands (#help lists them).
components/chat/, components/helpSheet/ Chat frames and the help sheet.

Interface strings live in i18n.js in three languages. Game text arrives from the server already in the player's language, so do not translate it in the client.

Accessibility rules apply to every change: the terminal output is a polite live region, panels repeat information that is also in the text, and nothing may exist only as an icon or colour. See Accessibility.

Use it for another MUD

The simple route is the frozen master branch. Your server needs WebSocket support. If it speaks plain telnet, put websockify in front of it:

websockify :4321 :9000

Then set wsUrl in the page that loads the client, for example ws://yourmud.com:4321. The host must match the host that serves the page. The first thing the master client sends after connecting is a codepage digit. DreamLand's codepage menu uses 7 for UTF-8. Change the digit to whatever your MUD expects. This route is not tested on any other MUD (unverified).

The dreamland branch is not generic: it expects the DreamLand RPC events, the nanny dialogue and the prompt object, and it refuses to connect unless the server sends the matching version string.

See also

Clone this wiki locally