OPEN SOURCE · ANDROID · WEB
One home for stable releases, fresh snapshots, interactive tools, and open projects built under the Kitsune banner.
List generated from folders in /docs.
ADict Library
Kitsune DB
Kitsune NET
KitsuneScript
README preview from GitHub (main / configured branch).
A modern Node.js Ultima Online shard, browser client, compatibility bridge, asset pipeline, and administration suite. NodeUO preserves the classic binary UO boundary while adding an independently negotiated JSON protocol for features shared only by the NodeUO server and client.
Current release: v1.0.0 · NodeUO JSON protocol package: 2.1.0
This repository does not include game files. You generate runtime assets locally from your own legal Ultima Online Classic installation.
NodeUO 1.0 is the first tagged, end-to-end release of the complete workspace:
scripting, AI, combat, crafting, skills, magic, housing, boats, quests, vendors, death, ghosts, and world-generation workflows;
NodeUO interfaces, including visual-novel NPC interaction;
binary protocol and the TCP/WebSocket bridge;
enhanced engines and Classic UO gump fallbacks for the other ninety-four;
live operations, and the transactional ISO world editor;
rollback paths, performance budgets, and automated compatibility audits.
Application releases follow semantic versioning from the root package.json. The private @uo/nodeuo-protocol package is versioned independently because its schema evolves without changing the product or classic UO wire version. See [CHANGELOG.md](CHANGELOG.md) for release notes.
This project is prepared for public source distribution.
make the corresponding source code available to the community under the same license terms.
world saves, accounts, passwords, shard secrets, or private player data.
AGPL-3.0-or-later.CONTRIBUTING.md.LICENSE.| Area | Technology | Role |
|---|---|---|
| Server | Node.js, ESM, ws | Shard runtime, world state, accounts, persistence, scripts, gameplay systems |
| Client | Vite, PixiJS v8, WebGL | Browser UO client for the project WebSocket flow and bridge flow |
| Scripts | JavaScript ESM + Script API | Commands, items, mobiles, NPCs, AI, skills, spells, quests, spawns |
| Extractor | Node.js + sharp | MUL/UOP to PNG/JSON/bin assets, optional KTX2/Basis output |
| Control Panel | Electron | Start/stop server, client, bridge, extractor, tools, and logs |
| Bridge | Node.js TCP/WebSocket | Browser client to raw TCP ServUO/RunUO/OSI-style shard |
The priority is functional coverage against ServUO and ClassicUO behavior without copying their architecture one-to-one. Reference projects are used for parity, protocol behavior, and bug fixing; the runtime design should stay native to this repository.
Main rules:
_inventory, _movement, _spatial, and registry helpers.
pipeline are built for the web.
for VRAM/decode if you generate it with toktx.
code.
apps/server owns the engine and world indexes.apps/scripts owns gameplay content.api.game, api.lifecycle, api.systems,.ktx2 is an optional faster pathtemplates/ is reference material for audits and bug fixes, not runtimeapps/
client/ Vite + PixiJS browser client
server/ shard, world engine, net handlers, persistence, systems
scripts/ gameplay content and server scripting API consumers
bridge/ WebSocket <-> raw TCP bridge for external shards
control-panel/ Electron launcher with logs and tool buttons
packages/
protocol/ UO binary protocol, packets, Huffman/shared helpers
extractor/ asset pipeline: MUL/UOP -> client assets
tools/
run-control-panel.bat main Windows GUI launcher
run-control-panel.sh main Linux/macOS GUI launcher
bats/ Windows command launchers
sh/ Linux/macOS command launchers
audit/ ServUO/ClassicUO audits and coverage maps
docs/
README.md documentation index
server-scripting.md guide for the current server Script API
templates/
ClassicUO/ServUO reference code, for comparison only
saves/
world.sqlite world and account database (SQLite WAL)
auxiliary JSON files houses, map edits and small subsystem state
>=22.23 (Node 24.18.0 LTS recommended; pinned in .nvmrc / .node-version)9.12.0 through Corepack or a global install.bat launchers or Linux/macOS .sh launcherstoktx) for .ktx2 generationBasic check:
node -v
corepack enable
pnpm -v
Recommended Windows path:
tools\run-control-panel.bat
Recommended Linux/macOS path:
chmod +x tools/run-control-panel.sh tools/sh/*.sh
tools/run-control-panel.sh
The Control Panel can:
toktx tooling;Terminal path for Linux/macOS:
pnpm install
UO_SRC="/path/to/Ultima Online Classic" tools/sh/extract-assets.sh
tools/sh/run-server.sh
tools/sh/run-client.sh
Terminal path for Windows:
pnpm install
$env:UO_SRC="C:\Program Files (x86)\Electronic Arts\Ultima Online Classic"
tools\bats\extract-assets.bat
tools\bats\run-server.bat
tools\bats\run-client.bat
The development client normally runs at:
http://localhost:5173
The project WebSocket server normally runs at:
ws://127.0.0.1:2593/game
A full extraction creates:
apps/client/public/assets/
That directory contains art/gump/anim/static atlases, map chunks, statics, tiledata, hues, multi data, lights, fonts, cliloc, and manifests.
Common commands:
pnpm extract
pnpm extract:ktx2:tool:check
pnpm extract:ktx2:tool:install
pnpm extract:ktx2
pnpm extract generates PNG/JSON/bin fallback assets. pnpm extract:ktx2 converts existing PNG atlases to .ktx2 when toktx is available. The client tries KTX2 where present and falls back to PNG when the parser or file is not available.
KTX2 is mainly useful for large texture atlases: smaller transfer, lower VRAM use, and faster GPU upload after transcoding. PNG remains the required fallback and the easiest format for debugging.
| Scenario | Windows | Linux/macOS |
|---|---|---|
| GUI launcher | tools\run-control-panel.bat | tools/run-control-panel.sh |
| Browser client + project server | tools\bats\run-all.bat | tools/sh/run-all.sh |
| WebSocket server only | tools\bats\run-server.bat | tools/sh/run-server.sh |
| WebSocket server + raw TCP for ClassicUO | tools\bats\run-server-tcp.bat | tools/sh/run-server-tcp.sh |
| WebSocket server + TCP + admin panel | tools\bats\run-server-admin.bat | tools/sh/run-server-admin.sh |
| Vite client only | tools\bats\run-client.bat | tools/sh/run-client.sh |
| Browser client through bridge to an external shard | tools\bats\run-client-bridge.bat host:port | tools/sh/run-client-bridge.sh host:port |
| Bridge only | tools\bats\run-bridge.bat host:port | tools/sh/run-bridge.sh host:port |
Default ports:
| Service | Port |
|---|---|
| Browser client Vite | 5173 |
| Project WebSocket server | 2593 |
| Raw TCP listener | 2594 |
| Bridge | 2595 |
| Admin panel | 2596 |
| Command | Purpose |
|---|---|
pnpm install | install monorepo dependencies |
pnpm server | start the server with node --watch |
pnpm client | start the Vite dev server |
pnpm build | build workspaces that define a build script |
pnpm test | run workspace tests |
pnpm lint | run ESLint for the repository |
pnpm extract | extract assets from UO MUL/UOP files |
pnpm extract:ktx2 | generate .ktx2 files next to PNG atlases |
pnpm client:perf-smoke | run the client performance smoke test |
pnpm client:profile | capture a client profile |
pnpm audit:servuo | audit server functionality against ServUO |
pnpm audit:servuo:map:check | check the ServUO coverage map |
apps/server is the runtime engine:
quests, economy, events;
Architectural rule: the engine should not contain concrete game content when that content can live in apps/scripts. The engine exposes APIs, indexes, and safe operations; scripts register content and behavior.
apps/scripts/src is the gameplay layer:
the admin authoring/operations workbenches;
apps/scripts/src/data.The canonical guide for the current API is:
docs/server-scripting.md
When the shard is running, the same guides are available as a searchable, responsive workbench under Admin → Docs (http://localhost:2596/docs). The page also exposes the gump model, configuration taxonomy, examples and a live inventory of the active scripts package.
The old pattern of scanning world.items or world.mobiles directly is an exception. New code should use:
api.game for gameplay operations and indexed reads;api.lifecycle for hot-reload-safe commands, events, and timers;api.systems for engine domains;_inventory.js, _movement.js, _spatial.js, and _entities.js;defineScript() for simple modules.apps/client is a web implementation of the UO client:
gumps, animation, and performance budgets.
Useful checks after renderer changes:
pnpm --filter @uo/client run smoke:roof
pnpm --filter @uo/client run smoke:light
pnpm --filter @uo/client build
Full client smoke:
pnpm --filter @uo/client run smoke
The project supports three practical configurations:
browser client -> project WebSocket server
ClassicUO/Razor -> project raw TCP server
browser client -> WebSocket bridge -> external ServUO/RunUO raw TCP shard
This lets the browser client evolve without abandoning protocol compatibility, and it lets the server be tested with native clients.
Local saves live in:
saves/world.sqlite
saves/world.sqlite-wal
saves/world.sqlite-shm
The server keeps gameplay state in memory and commits only dirty entities in batched SQLite transactions on a persistence worker. The -wal and -shm files are part of a live database; use a graceful shutdown/checkpoint or the admin backup operation instead of copying only world.sqlite while running. The first SQLite boot imports legacy accounts plus player characters and their complete inventory/pet chains, but intentionally discards legacy NPCs and generated world objects. A new shard therefore starts clean and is populated explicitly with createworld. When the account table is empty, set UO_BOOTSTRAP_ADMIN_PASSWORD (and optionally UO_ADMIN_USER) to create the first durable Admin account; the server never invents a default password.
Locally generated assets live in:
apps/client/public/assets/
These paths are environment data. Do not treat them as source-of-truth review material unless you are intentionally testing persistence migration or the asset pipeline.
| Document | Role |
|---|---|
QUICKSTART.md | short setup and launch guide |
CONTRIBUTING.md | contribution, testing, and licensing rules |
CHANGELOG.md | version history and release highlights |
LICENSE | full AGPL license text |
CODE_OF_CONDUCT.md | behavior rules for the public project |
docs/README.md | repository documentation index |
docs/server-scripting.md | current server scripting rules |
docs/scripting/gumps.md | server/client gumps and JSON authoring |
docs/scripting/configuration.md | config identity and data publishing |
docs/game-systems/authoring-tutorial.md | tutorial for activity authoring, scripting, compatibility, and publishing |
Admin /docs | searchable Scriptbook rendered from the canonical Markdown files |
tools/README.md | launchers, Control Panel, bridge, and environment variables |
apps/server/src/content/ARCHITECTURE.md | engine vs scripts split |
apps/server/src/systems/README.md | systems layer overview |
Before a larger change:
git status --short
pnpm test
After server changes:
pnpm --filter @uo/server test
After client changes:
pnpm --filter @uo/client build
pnpm --filter @uo/client run smoke:client-perf
After script changes:
pnpm --filter @uo/server test
pnpm audit:servuo:map:check
After asset pipeline changes:
pnpm extract:ktx2:tool:check
pnpm --filter @uo/extractor run ktx2:dry-run
Before opening a pull request:
CONTRIBUTING.md;AGPL-3.0-or-later.facade exists.
use api.game.item.move, api.game.mobile.move, or api.game.mobile.teleport.
batching, caches, atlases, lazy loading, dirty regions, and fixed-row virtual lists are preferred.
code.
world.items or world.mobiles in hot paths when an indexeditem.parent or mob.x/y/z/map directly from gameplay code;api.lifecycle.templates/ is for audits, comparisons, and bug fixing; it is not runtimeProject code is licensed as AGPL-3.0-or-later. The intent is simple: you may use, copy, host, and modify the project, but project changes should return to the community under the same terms when distributed or offered over a network.
This repository does not distribute Ultima Online files. Asset extraction requires your own legal copy of the UO client. Original code in this repository is a separate implementation; for any files ported from or based on external projects, respect the licenses noted in headers, history, and documentation.