@mudlet/mudlet-web 0.3.0 β†’ 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,150 +1,150 @@
1
- <div align="center">
2
-
3
- # πŸ—ΊοΈ Mudlet Web
4
-
5
- ### Mudlet in your browser β€” the full Mudlet Lua scripting stack, running entirely client-side.
6
-
7
- [![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=white)](https://react.dev)
8
- [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
9
- [![Vite](https://img.shields.io/badge/Vite-8-646CFF?logo=vite&logoColor=white)](https://vite.dev)
10
- [![Lua 5.1](https://img.shields.io/badge/Lua-5.1%20(WASM)-000080?logo=lua&logoColor=white)](https://www.lua.org)
11
-
12
- *No installs. No native dependencies. Open a tab and play.*
13
-
14
- </div>
15
-
16
- ---
17
-
18
- ## What is Mudlet Web?
19
-
20
- **Mudlet Web** is a browser edition of [Mudlet](https://www.mudlet.org/), the [MUD](https://en.wikipedia.org/wiki/Multi-user_dungeon) (Multi-User Dungeon) client. It speaks the full telnet protocol stack that modern MUDs use, renders rich ANSI output, and runs **real Lua scripting** compiled to WebAssembly β€” with an API built for **drop-in compatibility** with Mudlet packages, maps, and profiles.
21
-
22
- If you have Mudlet scripts, triggers, aliases, or maps, Mudlet Web aims to run them unchanged β€” anywhere you have a web browser. It is not a rewrite of desktop Mudlet and doesn't replace it: some things a native client can do simply aren't available inside a browser sandbox (see [Limitations](#️-limitations--known-constraints)).
23
-
24
- ## ✨ Features
25
-
26
- ### πŸ”Œ Connectivity
27
- - **Direct WebSocket** connections to MUDs that expose a `ws(s)://` endpoint.
28
- - **Telnet via proxy** — connect to any classic `host:port` MUD through the bundled telnet→WebSocket proxy.
29
- - Full protocol support: **GMCP**, **MSDP**, **MSSP**, **MCCP** (compression), **MSP** (sound), telnet **CHARSET**, **TTYPE/MTTS**, and GA/EOR prompt detection.
30
-
31
- ### πŸ“œ Mudlet Lua scripting
32
- - A complete **Lua 5.1** runtime (WASM) with Mudlet-native globals β€” `send`, `echo`/`cecho`/`decho`/`hecho`, `tempTimer`, `tempTrigger`, `tempAlias`, and [hundreds more](docs/MUDLET_API.md).
33
- - **Triggers, aliases, timers, keybindings, and buttons** organized in Mudlet-style folder trees.
34
- - **PCRE regex** powered by `pcre2-wasm` β€” the same engine flavour as desktop Mudlet.
35
- - Bundled Mudlet standard library: Geyser GUI toolkit, the generic mapper, string/table utilities, and the `db:*` database API.
36
- - A built-in **CodeMirror** script editor with autocompletion for the entire API surface.
37
-
38
- ### πŸ—ΊοΈ Maps & GUI
39
- - Renders **Mudlet binary maps** with a built-in viewer and editor.
40
- - **Geyser** mini-consoles, labels, gauges, and command lines as pixel-positioned overlays.
41
- - A **custom dock/float window system** β€” split, tab, dock to any edge, or tear off into free-floating windows.
42
-
43
- ### πŸ’Ύ Storage & persistence
44
- - A **per-profile virtual filesystem** (ZenFS) backed by IndexedDB β€” or linked to a **real folder on your disk** via the File System Access API, with two-way sync.
45
- - An in-browser **SQLite** database for the Mudlet `db:*` API.
46
- - **Session logging** to IndexedDB, browsable and exportable.
47
- - Install Mudlet **packages and modules** (`.mpackage` / `.zip` / XML) β€” including browsing the public Mudlet package repository.
48
-
49
- ### 🎨 Polish
50
- - Multiple themes (dark, light, amber, sky), custom fonts, configurable colors and backgrounds.
51
- - Text-to-speech, sound, and video playback wired to Mudlet's media APIs.
52
-
53
- ## πŸš€ Getting Started
54
-
55
- ### Prerequisites
56
- - [Node.js](https://nodejs.org/) 20+ and [yarn](https://yarnpkg.com/).
57
-
58
- ### Run the client
59
-
60
- ```bash
61
- git clone <repo-url> mudlet-web
62
- cd mudlet-web
63
- yarn
64
- yarn dev
65
- ```
66
-
67
- Open the printed local URL (usually `http://localhost:5173`) in your browser, then create a connection on the start screen.
68
-
69
- ### Run the telnet proxy (for `host:port` MUDs)
70
-
71
- The browser cannot open raw TCP sockets, so connecting to a classic telnet MUD needs the small bundled proxy:
72
-
73
- ```bash
74
- cd proxy
75
- yarn
76
- yarn start # listens on ws://localhost:3001 by default
77
- ```
78
-
79
- Then choose **MUD (host:port)** mode when creating a connection. Servers that expose a native WebSocket endpoint don't need the proxy β€” use **WebSocket** mode and point it straight at the `ws(s)://` URL.
80
-
81
- ## πŸ› οΈ Development
82
-
83
- ```bash
84
- yarn dev # Start the Vite dev server
85
- yarn build # Type-check + production build
86
- yarn preview # Preview the production build
87
- yarn typecheck # Type-check only (src + tests)
88
- yarn test # Run the Vitest suite
89
- yarn test:watch # Vitest in watch mode
90
- ```
91
-
92
- Production builds deploy to **GitHub Pages** automatically on push to `master`.
93
-
94
- ## 🧱 Architecture at a glance
95
-
96
- ```
97
- MudClient (WebSocket β€” direct or via telnet proxy)
98
- β†’ telnet/protocol parsing (GMCP Β· MSDP Β· MSSP Β· MCCP Β· MSP Β· CHARSET Β· TTYPE)
99
- β†’ MudSession.events (a typed EventBus β€” the spine of the app)
100
- β”œβ”€ ScriptingEngine β†’ LuaRuntime (WASM) + alias/trigger/timer/key engines
101
- β”œβ”€ React UI (output area, dock/float panels, toolbar)
102
- └─ SessionLogger (persists output to IndexedDB)
103
- ```
104
-
105
- | Layer | Lives in | Notes |
106
- |---|---|---|
107
- | **Connection** | `src/mud/connection`, `src/mud/protocol` | Telnet over binary WebSocket frames |
108
- | **Scripting** | `src/scripting` | wasmoon Lua 5.1, Mudlet-native API, bundled Mudlet Lua |
109
- | **UI / Windows** | `src/ui` | Custom dock/float layout, CodeMirror editor, overlays |
110
- | **Maps** | `src/map`, `MapPanel` | Mudlet binary map reader/renderer/editor |
111
- | **Storage** | `src/storage`, `src/scripting/vfs`, `src/db` | Zustand + per-profile VFS + SQLite + IndexedDB logs |
112
- | **Import** | `src/import` | Mudlet XML & package install/export |
113
-
114
- A deeper tour of the internals lives in [`CLAUDE.md`](./CLAUDE.md); the full Mudlet API implementation status is tracked in [`MUDLET_API.md`](docs/MUDLET_API.md).
115
-
116
- ## 🏷️ Branded builds
117
-
118
- Mudlet Web is also published as an npm library for shipping a **white-label client for one specific MUD** β€” your own name, login screen, theme, toolbar, and bundled Lua packages, without forking the repo. See [`docs/BRANDED_BUILDS.md`](docs/BRANDED_BUILDS.md) for the setup guide, or [embervale-web](https://github.com/Delwing/embervale-web) for a live example.
119
-
120
- > The package is published as [`@mudlet/mudlet-web`](https://www.npmjs.com/package/@mudlet/mudlet-web). It was previously `@delwing/mudix` (now deprecated) β€” the app root export was renamed `MudixApp` β†’ `MudletWebApp` with the move.
121
-
122
- ## ⚠️ Limitations & known constraints
123
-
124
- Mudlet Web runs inside a browser sandbox, which trades some of desktop Mudlet's native reach for zero-install portability. Worth knowing before you switch:
125
-
126
- - **Telnet MUDs need the proxy.** Browsers can't open raw TCP sockets, so classic `host:port` MUDs are reachable only through the bundled telnet→WebSocket proxy. Servers with a native `ws(s)://` endpoint connect directly.
127
- - **One profile per tab.** There's no desktop-Mudlet-style multi-profile tabbing *within* a tab β€” you open one connection per browser tab (`loadProfile()` and in-tab profile switching are no-op stubs). You can still run **different profiles in separate tabs**: each profile is locked to a single tab (opening the same one elsewhere shows a "waiting" screen until the first tab releases it), every profile's data is isolated in its own filesystem, and profiles can signal each other across tabs via Mudlet's `raiseGlobalEvent`.
128
- - **Storage is browser-scoped.** Profiles, scripts, maps, and logs live in the browser's IndexedDB/localStorage for the app's origin. Clearing site data wipes them β€” unless you **link a real disk folder** for that profile (see below). Different browsers/machines don't share state automatically.
129
- - **Disk-folder linking is Chromium-only.** The "link a folder on disk" feature uses the File System Access API, which Firefox and Safari don't implement. Those browsers fall back to IndexedDB-only storage.
130
- - **Secure context required.** The VFS service worker (which serves profile images/fonts/CSS) needs HTTPS or `localhost`.
131
- - **Clipboard access is best-effort.** The browser's OS clipboard is asynchronous and gated on a user gesture (and a secure context), whereas desktop Mudlet's `getClipboardText`/`setClipboardText` are synchronous. Mudlet Web keeps a session-local text-clipboard mirror as the authoritative value and syncs it to the real OS clipboard opportunistically β€” so `setClipboardText` may not reach the system clipboard without a user gesture, and `getClipboardText` returns the last value Mudlet Web knows about (an external copy made elsewhere shows up on the *next* call, once the async read completes). This mirror is separate from the rich-text buffer used by `copy()`/`paste()`.
132
- - **Some Mudlet APIs are stubbed or partial.** Anything fundamentally native is bound as a warning-emitting no-op so imported packages still load, but does nothing: **Discord** Rich Presence, **IRC** client, OS `spawn`/subprocess, and the system dictionary. A few synchronous Mudlet calls (`invokeFileDialog`, `getImageSize`) don't map cleanly onto the browser's async pickers/loaders and are still in progress. See [`MUDLET_API.md`](docs/MUDLET_API.md) for the per-function status (βœ… / ⚠️ / 🚧 / ❌).
133
- - **The main window is the viewport.** Calls like `setMainWindowSize` are no-ops β€” the browser window is the main window.
134
- - **The Lua↔JS boundary has a per-call cost.** Each crossing between the Lua VM and JS is cheap individually but adds up β€” a script that makes thousands of tiny boundary calls in a tight loop (e.g. iterating every room in a large area one `getRoom*` call at a time) will feel noticeably slower than in native Mudlet. The hot paths you actually hit constantly (line/trigger processing, GMCP) are batched and stay fast; prefer bulk/batched APIs over per-item calls when you can.
135
-
136
- ## 🀝 Contributing
137
-
138
- When adding a Mudlet API function, implement the JS-side method in `ScriptingAPI`, bind the Lua global in `LuaRuntime`, and add the autocomplete entry in `luaCompletions.ts`. Run `yarn typecheck` and `yarn test` before opening a PR.
139
-
140
- ## License
141
-
142
- Mudlet Web is licensed under the **GNU General Public License, version 2 or (at your option) any later version** β€” see [LICENSE](./LICENSE). This matches [Mudlet](https://github.com/Mudlet/Mudlet)'s license (GPL-2.0-or-later): Mudlet Web bundles Mudlet's Lua runtime files (`src/scripting/lua/mudlet-lua/` β€” LuaGlobal, Geyser, the generic mapper, DB utilities, and more), copyright the Mudlet contributors, so every distribution is a combined work with that GPL code.
143
-
144
- Lua scripts and packages that Mudlet Web merely *runs* (your profile scripts, installed `.mpackage`s, branded-build packages) are separate works and are not required to be GPL β€” the same way the Mudlet ecosystem treats its packages.
145
-
146
- Mudlet Web also bundles **Bitstream Vera Sans Mono** (`src/assets/fonts/bitstream-vera-sans-mono/`) as the default console output and command-line font, matching Mudlet's own default console typeface. It's under the separate, permissive [Bitstream Vera license](src/assets/fonts/bitstream-vera-sans-mono/COPYRIGHT.TXT) (free redistribution and embedding; just don't sell the font standalone or rename a modified copy while keeping "Bitstream"/"Vera" in the name).
147
-
148
- <div align="center">
149
- <sub>Built with React, TypeScript, and a lot of WebAssembly. Happy MUDding. πŸ‰</sub>
150
- </div>
1
+ <div align="center">
2
+
3
+ # πŸ—ΊοΈ Mudlet Web
4
+
5
+ ### Mudlet in your browser β€” the full Mudlet Lua scripting stack, running entirely client-side.
6
+
7
+ [![React](https://img.shields.io/badge/React-19-61DAFB?logo=react&logoColor=white)](https://react.dev)
8
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?logo=typescript&logoColor=white)](https://www.typescriptlang.org)
9
+ [![Vite](https://img.shields.io/badge/Vite-8-646CFF?logo=vite&logoColor=white)](https://vite.dev)
10
+ [![Lua 5.1](https://img.shields.io/badge/Lua-5.1%20(WASM)-000080?logo=lua&logoColor=white)](https://www.lua.org)
11
+
12
+ *No installs. No native dependencies. Open a tab and play.*
13
+
14
+ </div>
15
+
16
+ ---
17
+
18
+ ## What is Mudlet Web?
19
+
20
+ **Mudlet Web** is a browser edition of [Mudlet](https://www.mudlet.org/), the [MUD](https://en.wikipedia.org/wiki/Multi-user_dungeon) (Multi-User Dungeon) client. It speaks the full telnet protocol stack that modern MUDs use, renders rich ANSI output, and runs **real Lua scripting** compiled to WebAssembly β€” with an API built for **drop-in compatibility** with Mudlet packages, maps, and profiles.
21
+
22
+ If you have Mudlet scripts, triggers, aliases, or maps, Mudlet Web aims to run them unchanged β€” anywhere you have a web browser. It is not a rewrite of desktop Mudlet and doesn't replace it: some things a native client can do simply aren't available inside a browser sandbox (see [Limitations](#️-limitations--known-constraints)).
23
+
24
+ ## ✨ Features
25
+
26
+ ### πŸ”Œ Connectivity
27
+ - **Direct WebSocket** connections to MUDs that expose a `ws(s)://` endpoint.
28
+ - **Telnet via proxy** — connect to any classic `host:port` MUD through the bundled telnet→WebSocket proxy.
29
+ - Full protocol support: **GMCP**, **MSDP**, **MSSP**, **MCCP** (compression), **MSP** (sound), telnet **CHARSET**, **TTYPE/MTTS**, and GA/EOR prompt detection.
30
+
31
+ ### πŸ“œ Mudlet Lua scripting
32
+ - A complete **Lua 5.1** runtime (WASM) with Mudlet-native globals β€” `send`, `echo`/`cecho`/`decho`/`hecho`, `tempTimer`, `tempTrigger`, `tempAlias`, and [hundreds more](docs/MUDLET_API.md).
33
+ - **Triggers, aliases, timers, keybindings, and buttons** organized in Mudlet-style folder trees.
34
+ - **PCRE regex** powered by `pcre2-wasm` β€” the same engine flavour as desktop Mudlet.
35
+ - Bundled Mudlet standard library: Geyser GUI toolkit, the generic mapper, string/table utilities, and the `db:*` database API.
36
+ - A built-in **CodeMirror** script editor with autocompletion for the entire API surface.
37
+
38
+ ### πŸ—ΊοΈ Maps & GUI
39
+ - Renders **Mudlet binary maps** with a built-in viewer and editor.
40
+ - **Geyser** mini-consoles, labels, gauges, and command lines as pixel-positioned overlays.
41
+ - A **custom dock/float window system** β€” split, tab, dock to any edge, or tear off into free-floating windows.
42
+
43
+ ### πŸ’Ύ Storage & persistence
44
+ - A **per-profile virtual filesystem** (ZenFS) backed by IndexedDB β€” or linked to a **real folder on your disk** via the File System Access API, with two-way sync.
45
+ - An in-browser **SQLite** database for the Mudlet `db:*` API.
46
+ - **Session logging** to IndexedDB, browsable and exportable.
47
+ - Install Mudlet **packages and modules** (`.mpackage` / `.zip` / XML) β€” including browsing the public Mudlet package repository.
48
+
49
+ ### 🎨 Polish
50
+ - Multiple themes (dark, light, amber, sky), custom fonts, configurable colors and backgrounds.
51
+ - Text-to-speech, sound, and video playback wired to Mudlet's media APIs.
52
+
53
+ ## πŸš€ Getting Started
54
+
55
+ ### Prerequisites
56
+ - [Node.js](https://nodejs.org/) 20+ and [yarn](https://yarnpkg.com/).
57
+
58
+ ### Run the client
59
+
60
+ ```bash
61
+ git clone <repo-url> mudlet-web
62
+ cd mudlet-web
63
+ yarn
64
+ yarn dev
65
+ ```
66
+
67
+ Open the printed local URL (usually `http://localhost:5173`) in your browser, then create a connection on the start screen.
68
+
69
+ ### Run the telnet proxy (for `host:port` MUDs)
70
+
71
+ The browser cannot open raw TCP sockets, so connecting to a classic telnet MUD needs the small bundled proxy:
72
+
73
+ ```bash
74
+ cd proxy
75
+ yarn
76
+ yarn start # listens on ws://localhost:3001 by default
77
+ ```
78
+
79
+ Then choose **MUD (host:port)** mode when creating a connection. Servers that expose a native WebSocket endpoint don't need the proxy β€” use **WebSocket** mode and point it straight at the `ws(s)://` URL.
80
+
81
+ ## πŸ› οΈ Development
82
+
83
+ ```bash
84
+ yarn dev # Start the Vite dev server
85
+ yarn build # Type-check + production build
86
+ yarn preview # Preview the production build
87
+ yarn typecheck # Type-check only (src + tests)
88
+ yarn test # Run the Vitest suite
89
+ yarn test:watch # Vitest in watch mode
90
+ ```
91
+
92
+ Production builds deploy to **GitHub Pages** automatically on push to `master`.
93
+
94
+ ## 🧱 Architecture at a glance
95
+
96
+ ```
97
+ MudClient (WebSocket β€” direct or via telnet proxy)
98
+ β†’ telnet/protocol parsing (GMCP Β· MSDP Β· MSSP Β· MCCP Β· MSP Β· CHARSET Β· TTYPE)
99
+ β†’ MudSession.events (a typed EventBus β€” the spine of the app)
100
+ β”œβ”€ ScriptingEngine β†’ LuaRuntime (WASM) + alias/trigger/timer/key engines
101
+ β”œβ”€ React UI (output area, dock/float panels, toolbar)
102
+ └─ SessionLogger (persists output to IndexedDB)
103
+ ```
104
+
105
+ | Layer | Lives in | Notes |
106
+ |---|---|---|
107
+ | **Connection** | `src/mud/connection`, `src/mud/protocol` | Telnet over binary WebSocket frames |
108
+ | **Scripting** | `src/scripting` | wasmoon Lua 5.1, Mudlet-native API, bundled Mudlet Lua |
109
+ | **UI / Windows** | `src/ui` | Custom dock/float layout, CodeMirror editor, overlays |
110
+ | **Maps** | `src/map`, `MapPanel` | Mudlet binary map reader/renderer/editor |
111
+ | **Storage** | `src/storage`, `src/scripting/vfs`, `src/db` | Zustand + per-profile VFS + SQLite + IndexedDB logs |
112
+ | **Import** | `src/import` | Mudlet XML & package install/export |
113
+
114
+ A deeper tour of the internals lives in [`CLAUDE.md`](./CLAUDE.md); the full Mudlet API implementation status is tracked in [`MUDLET_API.md`](docs/MUDLET_API.md).
115
+
116
+ ## 🏷️ Branded builds
117
+
118
+ Mudlet Web is also published as an npm library for shipping a **white-label client for one specific MUD** β€” your own name, login screen, theme, toolbar, and bundled Lua packages, without forking the repo. See [`docs/BRANDED_BUILDS.md`](docs/BRANDED_BUILDS.md) for the setup guide, or [embervale-web](https://github.com/Delwing/embervale-web) for a live example.
119
+
120
+ > The package is published as [`@mudlet/mudlet-web`](https://www.npmjs.com/package/@mudlet/mudlet-web). It was previously `@delwing/mudix` (now deprecated) β€” the app root export was renamed `MudixApp` β†’ `MudletWebApp` with the move.
121
+
122
+ ## ⚠️ Limitations & known constraints
123
+
124
+ Mudlet Web runs inside a browser sandbox, which trades some of desktop Mudlet's native reach for zero-install portability. Worth knowing before you switch:
125
+
126
+ - **Telnet MUDs need the proxy.** Browsers can't open raw TCP sockets, so classic `host:port` MUDs are reachable only through the bundled telnet→WebSocket proxy. Servers with a native `ws(s)://` endpoint connect directly.
127
+ - **One profile per tab.** There's no desktop-Mudlet-style multi-profile tabbing *within* a tab β€” you open one connection per browser tab (`loadProfile()` and in-tab profile switching are no-op stubs). You can still run **different profiles in separate tabs**: each profile is locked to a single tab (opening the same one elsewhere shows a "waiting" screen until the first tab releases it), every profile's data is isolated in its own filesystem, and profiles can signal each other across tabs via Mudlet's `raiseGlobalEvent`.
128
+ - **Storage is browser-scoped.** Profiles, scripts, maps, and logs live in the browser's IndexedDB/localStorage for the app's origin. Clearing site data wipes them β€” unless you **link a real disk folder** for that profile (see below). Different browsers/machines don't share state automatically.
129
+ - **Disk-folder linking is Chromium-only.** The "link a folder on disk" feature uses the File System Access API, which Firefox and Safari don't implement. Those browsers fall back to IndexedDB-only storage.
130
+ - **Secure context required.** The VFS service worker (which serves profile images/fonts/CSS) needs HTTPS or `localhost`.
131
+ - **Clipboard access is best-effort.** The browser's OS clipboard is asynchronous and gated on a user gesture (and a secure context), whereas desktop Mudlet's `getClipboardText`/`setClipboardText` are synchronous. Mudlet Web keeps a session-local text-clipboard mirror as the authoritative value and syncs it to the real OS clipboard opportunistically β€” so `setClipboardText` may not reach the system clipboard without a user gesture, and `getClipboardText` returns the last value Mudlet Web knows about (an external copy made elsewhere shows up on the *next* call, once the async read completes). This mirror is separate from the rich-text buffer used by `copy()`/`paste()`.
132
+ - **Some Mudlet APIs are stubbed or partial.** Anything fundamentally native is bound as a warning-emitting no-op so imported packages still load, but does nothing: **Discord** Rich Presence, **IRC** client, OS `spawn`/subprocess, and the system dictionary. A few synchronous Mudlet calls (`invokeFileDialog`, `getImageSize`) don't map cleanly onto the browser's async pickers/loaders and are still in progress. See [`MUDLET_API.md`](docs/MUDLET_API.md) for the per-function status (βœ… / ⚠️ / 🚧 / ❌).
133
+ - **The main window is the viewport.** Calls like `setMainWindowSize` are no-ops β€” the browser window is the main window.
134
+ - **The Lua↔JS boundary has a per-call cost.** Each crossing between the Lua VM and JS is cheap individually but adds up β€” a script that makes thousands of tiny boundary calls in a tight loop (e.g. iterating every room in a large area one `getRoom*` call at a time) will feel noticeably slower than in native Mudlet. The hot paths you actually hit constantly (line/trigger processing, GMCP) are batched and stay fast; prefer bulk/batched APIs over per-item calls when you can.
135
+
136
+ ## 🀝 Contributing
137
+
138
+ When adding a Mudlet API function, implement the JS-side method in `ScriptingAPI`, bind the Lua global in `LuaRuntime`, and add the autocomplete entry in `luaCompletions.ts`. Run `yarn typecheck` and `yarn test` before opening a PR.
139
+
140
+ ## License
141
+
142
+ Mudlet Web is licensed under the **GNU General Public License, version 2 or (at your option) any later version** β€” see [LICENSE](./LICENSE). This matches [Mudlet](https://github.com/Mudlet/Mudlet)'s license (GPL-2.0-or-later): Mudlet Web bundles Mudlet's Lua runtime files (`src/scripting/lua/mudlet-lua/` β€” LuaGlobal, Geyser, the generic mapper, DB utilities, and more), copyright the Mudlet contributors, so every distribution is a combined work with that GPL code.
143
+
144
+ Lua scripts and packages that Mudlet Web merely *runs* (your profile scripts, installed `.mpackage`s, branded-build packages) are separate works and are not required to be GPL β€” the same way the Mudlet ecosystem treats its packages.
145
+
146
+ Mudlet Web also bundles **Bitstream Vera Sans Mono** (`src/assets/fonts/bitstream-vera-sans-mono/`) as the default console output and command-line font, matching Mudlet's own default console typeface. It's under the separate, permissive [Bitstream Vera license](src/assets/fonts/bitstream-vera-sans-mono/COPYRIGHT.TXT) (free redistribution and embedding; just don't sell the font standalone or rename a modified copy while keeping "Bitstream"/"Vera" in the name).
147
+
148
+ <div align="center">
149
+ <sub>Built with React, TypeScript, and a lot of WebAssembly. Happy MUDding. πŸ‰</sub>
150
+ </div>