BeamNG.Earth
A 1:1 scale streamed Earth for BeamNG.drive: real elevation and satellite imagery, floating origin, LOD streaming from a companion server
Single-player browser tech demo for the mmorpg repository: the shared Rust zone simulation runs in the page through WebAssembly.
GamesRust · TypeScriptGitHub @moenarch-gamesConnection unstableOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
No updates detected yet. GitHub releases will appear here.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Loading the full README. The saved excerpt is shown below.
Server-authoritative MMORPG foundation that scales by distributing zone ownership, with deterministic physics and a separate client presentation layer.Read the full README ↗Server-authoritative MMORPG foundation that scales by distributing zone ownership, with deterministic physics and a separate client presentation layer.
The native Rust client now connects to the standalone zone host and renders server-authoritative multiplayer movement through wgpu. The GitHub Pages demo runs the same Rust zone simulation in the page as a local single-player WASM host; in a development setup, browser tabs can instead join a zone host together over WebTransport. The in-memory control plane and fenced runtime establish tested contracts; they are not yet a production distributed fleet. See the architecture capability map for implemented behavior and deployment prerequisites.
Decision history and stable cross-references: MMORPG Decision Atlas. The atlas distinguishes implemented behavior from agreed but unimplemented design.
| Concern | Authority |
|---|---|
| Zone-local gameplay rules and interest policy | mmorpg-core |
| Collision and physical movement | Rapier (rapier3d, embedded in mmorpg-core, #271) |
| Command/snapshot wire encoding | mmorpg-protocol |
| Session ticks, reconnects, replay/recovery, WebTransport | game-server |
| Zone placement, lease fencing, host routing, handoff metadata | mmorpg-control-plane |
| Durable character records and exclusive character leases | mmorpg-characters (file entries for development/LAN, browser localStorage entries; optional PostgreSQL adapter) |
Adapter from a zone simulation into game-server | mmorpg-game-server |
| Presentation scenery: props, roads, water, relief, terrain grid (clients only) | mmorpg-scenery |
| Native graphics | mmorpg-client: wgpu/winit adapter over pinned 3d-lab mesh/camera models |
| Browser graphics | pinned 3d-lab browser renderer |
| Browser zone host (single-player demo) | mmorpg-wasm: thin wasm-bindgen adapter over mmorpg-core and mmorpg-protocol |
| Runtime input semantics | input-bindings (browser and native action runtime; browser/native Settings compose character-scoped profiles and explicit conflict repairs, #41) |
| User-facing settings | settings (shared JSON catalog; browser @moritzbrantner/settings-browser and native settings-core, #41) |
| Asset normalization/provenance | asset-tooling (future content slice) |
| Social systems | social-service where its existing authority fits |
| Runtime/performance evidence | runtime-profiler integration, without moving gameplay truth |
The MMO repository composes those foundations. It should not grow substitutes for them.
The rendering and asset adoption record distinguishes active external components, in-house foundations, and unintegrated character capabilities with source-backed evidence.
control plane
zone directory / placement
leases + fencing epochs
/ \
/ \
v v
zone host A zone host B
┌────────────┐ ┌────────────┐
client ────────▶│ game-server│ │ game-server│◀──────── client
│ MatchHost │ │ MatchHost │
│ zone 10 │ │ zone 11 │
└─────┬──────┘ └─────┬──────┘
v v
mmorpg-core mmorpg-core
| |
v v
Rapier (core) Rapier (core)
A zone is a single-writer authoritative simulation. A host may own many zones and the fleet may contain many hosts. Cross-zone movement transfers authority at a deterministic boundary using a unique transfer ID plus source/destination lease epochs. Two hosts must never concurrently own the same zone epoch.
This deliberately avoids shared mutable physics across machines. Horizontal scale comes from more zones, more zone hosts, bounded per-zone populations, player-scoped interest projections, and later evidence-driven zone splitting.
The workspace provides:
KinematicCharacterController, #271);game-server::GameSimulation adapter;ZoneId to game-server::MatchId;3d-lab renderer;The control-plane implementation in this slice is a reference model, not yet a production distributed consensus system. Host registration is placement eligibility only: a missed heartbeat blocks new assignment to that host but does not revoke an already-issued zone lease. Existing lease deadlines and fencing epochs remain the authority boundary. The model makes ownership, liveness-sensitive placement, epoch fencing and handoff idempotence executable alongside the optional PostgreSQL directory and durable host adapter and any future orchestration infrastructure.
The native client uses wgpu 30.0.1 + winit 0.30.13, shared Rust world geometry, and the existing WebTransport protocol. W/S run and backpedal, A/D strafe relative to a third-person orbit camera (drag to orbit, wheel to zoom), Space jumps (held, it swims up in deep water; X swims down), Shift dodge-rolls (#516), the left mouse button swings where the character faces and hits everything in its arc (#517; a drag still orbits), a right click selects the specific visible creature or NPC, Tab cycles attackable creatures and N cycles NPCs, 1–8 use the class abilities (offensive ones fire where the character faces), a Warden holds Z for the shield guard (move the mouse up or down for the high or low lane; the unit frame shows the zone's guard) (without --class warden|ranger|arcanist the window opens a local character roster with a turntable preview, kept under the platform config directory), B/C/L toggle bags, character and quest log, Escape cancels a cast or closes panels and R releases a dead spirit; the client only sends intent and the GPU renders interpolated player-visible snapshots of players, creatures and NPCs with their facing. An egui interface shows unit/target frames, the action bar with cooldowns, minimap, quest tracker/log, quest and vendor windows, bags, character pane, loot and chat, plus world-space nameplates, NPC quest markers and floating combat text; every control sends an existing command. E opens the selected NPC’s existing quest/vendor context (otherwise it uses the door in reach; Enter chats): Up/Down browses every quest, stock offer and bag slot, 1 accepts/turns in or buys, 2 sells, Left/Right chooses a quest reward, H pages authored dialogue/objectives, and Escape closes the context or cancels an armed click. The zone validates range, quest state and transactions. Multiple client processes can join the same zone.
python3 scripts/smoke-native.py --window
This builds the client and host, creates disposable development TLS credentials, checks server readiness, verifies an actual GPU frame, opens a window for 120 frames, and shuts everything down. Requires Python 3, OpenSSL and a supported graphics backend. Omit --window for the offscreen GPU check.
For persistent interactive play, see native setup and controls. Tauri is a possible future launcher shell; the gameplay window uses a native GPU surface. See the decision.
Start the complete local native development environment with:
./scripts/dev-native.sh
The launcher fetches the latest merged source and fast-forwards safely before building, then watches local Rust, shader, scenery and build-input edits and restarts the host and client. Each restart resets the disposable zone. Local edits and commits are preserved; an update that needs manual integration stops with an explanation. Use --no-update to work offline or intentionally run your current checkout, and --no-watch for a single interactive launch. Requires Python 3 in addition to Cargo, Git, curl and OpenSSL; see native development.
The standalone HTML editor has been removed. For optional development-only Outpost placement editing, install Blender 5.2.2 LTS and run bash scripts/dev-blender.sh open. Move, add, duplicate or delete houses and decorative props in Blender, then save/close and run bash scripts/dev-blender.sh export. The exporter invokes the existing Rust collision/scenery validator before writing content/greyhaven/outpost-layout.json; rebuild the game to consume the changes. Blender is not a Cargo/Bun or runtime dependency.
See Blender layout authoring for supported objects, coordinate mapping, exact version and limitations. The editable source is the existing repository JSON, not the generated .blend file.
web/ is the GitHub Pages client. It runs the shared Rust zone simulation in the page as a local single-player zone host (ADR 0002): the mmorpg-wasm crate compiles mmorpg-core and mmorpg-protocol to WebAssembly and builds the same ZoneSimulation and content revision as mmorpg-zone-host (zone 1, Greyhaven Vale). There is one implementation of the movement and combat rules; the browser owns none.
! (available), ? (ready) and grey ? (in progress) float over quest givers. Givers need you within 5 m; only the zone accepts, credits and rewards quests. Start with Marshal Elden Greywatch west of the spawn plaza.Building the page or the native client first needs the asset-tooling bundles: scripts/fetch-bundles.sh downloads the selected character/equipment downloads of the rolling humanoid-ranger-male release, the rolling kit, prop, animal and sound releases and the immutable greyhaven-inn-v1 inn into the ignored web/public/ (re-running it keeps a download while its release is unchanged; rolling releases are read live and unpinned, so it refreshes them after an upload). Native builds also need scripts/prepare-ranger-native.sh; see the shared Ranger loading path and browser example. Building the page requires the Rust toolchain from rust-toolchain.toml (with the wasm32-unknown-unknown target) and the wasm-bindgen CLI at the crate's exact version: cargo install wasm-bindgen-cli --version =0.2.129 --locked. bun run build and bun run dev first sync browser dependencies from the committed lockfile, then compile the module. bun test also compiles the module before its WASM tests. The generated bindings are ignored build output. After vite build, web/scripts/build-asset-cache.ts writes dist/asset-cache.json (every static file's SHA-256) and the service worker dist/sw.js (#410): on return visits the built page reuses downloaded WASM, chunks and bundle files from Cache Storage while the deployed manifest still names their revision, revalidates pages and the manifest on every navigation, stores a download only when its bytes match, and falls back to the network when storage is unavailable. Open the page with ?reset-cache to drop it. Update the Git checkout explicitly to build newer source; these scripts do not change source revisions or dependency pins.
The standalone host, the native client and the browser's WASM local host share the Rust Greyhaven Vale content (mmorpg_core::greyhaven_vale). Snapshot schema/wire version 15 carries the viewer's own state (with class, resource, cast, cooldowns, auras and melee range), its target's target, cast and auras, the self sheet (bag, equipment, stat totals and the quest log with completed quests and quest-NPC markers), bounded feedback events, heard chat lines and emotes and compact, priority-ordered unit records within a one-datagram byte budget, and command wire version 9 carries Move, Jump, SelectTarget, StartAttack, StopAttack, ReleaseSpirit, MoveItem, death-fenced Loot, UseAbility, CancelCast, ChooseClass, EquipItem, UnequipItem, BuyItem, SellItem, Chat, Emote, AcceptQuest, CompleteQuest and AbandonQuest; v14 and earlier snapshots, v8 and earlier commands and old recovery bundles require an explicit migration decision. See the wire specification.
The opt-in broadleaf comparison shows current and proposed scenery at the same real game camera; default art stays unchanged pending owner feedback.
The browser Warden hotbar uses four owner-approved painted icons from asset-tooling, with build-time content checks and separate gameplay/UI overlays.
The browser also offers the first Battle Royale PvP activity: temporary max-level builds, real hosted MMORPG combat, results and between-life reconfiguration. Pages serves the client; a compatible Battle Royale host runs the match.
The same page can join a real zone host instead of its local zone, over WebTransport with the game-server session protocol: the browser counterpart of the native client, and the transport swap ADR 0002 kept open. It is a development and self-hosting mode; the GitHub Pages build stays offline.
./scripts/dev-browser-online.sh
The launcher reuses or creates the ECDSA P-256 development certificate under target/dev-tls/ (valid for 10 days; WebTransport certificate hashes allow at most 14), starts mmorpg-zone-host for zone 1 on UDP port 4433 (status on TCP port 8080) and Vite on 127.0.0.1:5173, and prints a URL to open in two tabs of a Chromium-based browser. Ctrl-C stops both processes, --check verifies the setup and exits, and MMORPG_DEV_TRANSPORT_PORT, MMORPG_DEV_STATUS_PORT and MMORPG_DEV_WEB_PORT override the ports. It shares the certificate and ports with ./scripts/dev-native.sh, so run one of them at a time; a native client can join the launcher's zone with the second-player command.
?server=https://<host>:<port>/game/matches/zone-<id>&certHash=<base64 SHA-256 of the DER certificate> joins that host; without certHash the host needs a publicly trusted certificate. A build with VITE_ZONE_SERVER and VITE_ZONE_CERT_HASH offers the same through a Play online checkbox on the character screen, unchecked by default; the default remains the local WASM zone. The address must be a canonical admission route: credentials, queries, fragments and resume routes are refused, and an invalid address disables entry with the reason instead of falling back to the local zone.OnlineZoneSource (web/src/world/online-zone-source.ts) reads the welcome (player, tick rate, connection epoch, reconnect token), sends command frames with strictly increasing sequences, reassembles and verifies snapshot frames and fragments per connection (web/src/session/, a port of the pinned SnapshotReassembler), and decodes projections with the same decoder as the local zone. Movement is held intent the page resends every 50 ms, like the native client; a jump or any other discrete intent is resent byte for byte until a projection acknowledges it, and no later command overtakes it meanwhile, so the host's stale-sequence rule cannot drop it unseen.ChooseClass. With MMORPG_CHARACTER_DIR, the selected character instead claims its durable server record before entering; explicit Characters/Exit commits and releases it. Closing a tab abruptly retains its latest periodic commit. Appearance remains presentation-only.python3 scripts/smoke-browser-online.py proves it end to end with the production bundle: it starts a real host with a disposable certificate on OS-selected ports, opens two Chromium pages in online mode, runs one character and checks the other page sees it move in its own decoded projections, then closes the running page and checks its unit disappears after the host's one-second grace.
On the host computer, use its actual LAN IPv4 address (for example 192.168.1.20):
./scripts/dev-browser-online.sh --lan 192.168.1.20
The launcher runs one authoritative Greyhaven zone host (UDP 4433) and serves the browser game over HTTPS on that LAN interface (TCP 5173). The printed link names the correct LAN WebTransport endpoint and its pinned development certificate hash. Other computers on the same network open that link in a Chromium-based browser; they do not need the Rust toolchain or a copy of the game source. Each player selects Enter World to join the same zone. --check also works with --lan to verify server readiness and the HTTPS page before playing.
The page uses a self-signed development HTTPS certificate. On each device, trust the host's certificate target/dev-tls/cert.pem for this locally controlled server (or explicitly accept the browser's certificate warning where supported) before using the shared link. Never distribute key.pem. The launcher includes the LAN IP in the short-lived certificate's subject alternative names, regenerating the pair if the IP changes. Open firewall access for TCP 5173 (HTTPS page) and UDP 4433 (WebTransport) only to trusted LAN peers; do not forward the ports to the internet. The server has anonymous sessions and no public authentication or production durability.
You can also connect a native client from another LAN computer to this host (or to one running ./scripts/dev-native.sh) by copying only the public certificate cert.pem to that computer and supplying its LAN endpoint:
cargo run --locked -p mmorpg-client -- \
--url https://192.168.1.20:4433/game/matches/zone-1 \
--certificate ./cert.pem
For a host-only check without a browser, the native zone host is already available as mmorpg-zone-host; no separate LAN gameplay server is needed. The ordinary ./scripts/dev-browser-online.sh (without --lan) stays bound to loopback and uses HTTP for local development. The GitHub Pages demo remains local single-player.
The first scaling unit is the zone:
game-server::MatchRuntime drives that zone;MatchHost;The initial MAX_PLAYERS_PER_ZONE is a safety bound, not a performance claim. Capacity changes require deterministic workload evidence. Large cities, raids, or crowded world events should eventually be handled by measured spatial/instance partitioning rather than silently increasing one process's bound.
The starter progression rules define the shared XP curve and level-difference kill rewards. The zone awards and projects durable XP; the browser displays its XP bar and level-up feedback from that state.
Starter inventory rules define the immutable item catalog and atomic 16-slot bags. Player-owned bags, queued moves and recoverable self sheets are implemented; the browser displays those slots and sends split/move/merge intent through its Bags panel.
Starter loot rules define validated weighted rewards and deterministic rolling. Core generates corpse rewards once, fences claims by owner/death/reach, and atomically credits money and bags with replay/recovery coverage. The browser Loot window displays the complete selected-corpse sheet, sends the fenced claim and shows refusals.
Use lightweight CQRS/CQS at service boundaries: commands mutate authoritative durable state; queries read it. Do not introduce event sourcing by default. Zone hot loops must not synchronously depend on a distributed database. mmorpg-characters is the durable character boundary (#30): a versioned CharacterRecord captured from and admitted into a zone, stored with an exclusive lease held by one zone at one control-plane epoch; every commit names its lease and fails closed once a newer epoch of the zone or a release superseded it. Its development backend is a directory of atomically replaced, OS-locked entry files; the optional PostgreSQL backend follows TECH-002, and development/LAN zone-host admission is available with MMORPG_CHARACTER_DIR. Zone checkpoint storage is a separate upcoming boundary.
The PostgreSQL/S3 host now suspends empty zones and cold-restores them on admission, with a bounded 30-second default grace and frozen gameplay time. Development file hosts and the browser-local host remain resident.
rapier3d: =0.36.1 (crates.io, default features)physics-engine: git rev ae64adbdb2d1af74f89f5befe287a8029eeaa072, optional in mmorpg-core behind the test/bench-only physics-ab feature (physics backend A/B); never in production or WASM buildsgame-server: a3cdf8c8bf915167988de2ef5e1f9b39cf847d133d-lab (three-d-core, three-d-camera, three-d-projective, three-d-animation and the browser @moritzbrantner/three-d-renderer, kept on one commit): 235774615f1367065093deb6988f5217bdf4d7e145042e56be120b438096e774027637cac0280075cargo fmt --all -- --check
cargo clippy --workspace --all-targets --all-features --locked -- -D warnings
cargo test --workspace --all-features --locked
cargo build --workspace --all-features --locked
mmorpg-core, mmorpg-protocol and mmorpg-wasm must keep compiling for WebAssembly:
cargo build -p mmorpg-core -p mmorpg-protocol -p mmorpg-wasm --target wasm32-unknown-unknown --locked
For the browser client, from web/ using the latest Bun (needs the pinned wasm-bindgen CLI above):
bun install --frozen-lockfile
bun test
bun run build
Committed Rust and Bun lockfiles make local and CI resolution reproduce the same dependency graphs. Rust and browser tests both consume fixtures/protocol/player-snapshot-v22.hex, fixtures/protocol/commands-v12.hex and the game-server session frames in fixtures/protocol/session-frames-v3.hex.
The browser's online mode has its own end-to-end check against a real zone host (needs cargo, OpenSSL, a built web/dist and Playwright Chromium, like scripts/smoke-browser.py):
python3 scripts/smoke-browser-online.py
Do not launch competing processes for the same zones: this binary does not acquire control-plane leases yet.
Provide a TLS certificate and key, then start one process hosting one or more zones:
MMORPG_ZONE_IDS=10,11 \
MMORPG_CERT_PEM=cert.pem \
MMORPG_KEY_PEM=key.pem \
MMORPG_RECOVERY_DIR=recovery/zone-host \
cargo run --locked -p mmorpg-game-server --bin mmorpg-zone-host
The host uses one WebTransport listener (port 4433 by default) and routes sessions under /game/matches/zone-<id>. Operational HTTP status is exposed separately on port 8080:
/healthz reports process liveness;/readyz reports whether at least one hosted zone can accept sessions;/status reports host capacity and per-zone readiness;/matches/zone-<id>/readyz and /matches/zone-<id>/status expose a single zone's operational projection.MMORPG_CHARACTER_DIR=target/dev-characters enables unauthenticated development/LAN
character claims from both clients. The host owns exclusive character leases and
commits outside the tick; a second process cannot open the same local directory.
Clients persist globally distinct online IDs for their local roster slots. This
mode uses whole-host graceful recovery at MMORPG_RECOVERY_DIR, or by default
<character-directory>/zone-recovery, reacquires restored leases before serving,
and commits final records from stopped recovery before releasing them. Content or
schema incompatibility fails closed; choose an explicit development reset or
migration rather than silently discarding saved data. Production authentication,
fleet ownership and strong reward journaling remain separate work.
See the admission decision.
When MMORPG_RECOVERY_DIR is set, graceful SIGINT/SIGTERM shutdown writes one atomic recovery bundle for the complete configured zone set. Restarting with the same zones restores simulation, command-sequence, and reconnect state, then consumes the old bundle. A missing zone, an extra zone, or corrupt recovery data fails startup closed instead of partially restoring a host. Durable crash recovery remains a separate persistence boundary.
These endpoints consume game-server host state and never mutate or redefine zone gameplay authority. Configuration is explicit through MMORPG_ZONE_IDS, MMORPG_PORT, MMORPG_STATUS_PORT, MMORPG_CERT_PEM, MMORPG_KEY_PEM, MMORPG_RECOVERY_DIR, MMORPG_CHARACTER_DIR, MMORPG_ROUTE_PREFIX, MMORPG_RECONNECT_GRACE_TICKS, and MMORPG_DRAIN_GRACE_MS; recovery is opt-in, while invalid configured values fail startup instead of silently falling back.
The saved grass authoring package freezes accepted Outpost placements and reproduces their exclusion-mask filtering through pinned asset-tooling. Both clients consume its saved selection through shared scenery.
The saved relief authoring package freezes the Outpost heightfield and reproduces its saved flatten coverage through the same pinned producer. Both clients consume the saved result through shared scenery.
See docs/ARCHITECTURE.md and ROADMAP.md.
Mode hosts can seed temporary max-level character builds without exporting arena outcomes to durable characters.
Opt-in dedicated-zone combat is documented in PvP combat. Ordinary Greyhaven play stays safe; the first playable Battle Royale mode remains separate integration work.
mmorpg-scenery (props, relief terrain, water) plus creature and NPC bodies (procedural models in the browser, low-poly box-built models in the native client);!/? NPC markers, all in core and recovered exactly; a scripted Warden completes the first three quests on the hosted content;/y yells it to 60 m, Escape returns to the world. /wave, /bow, /cheer, /laugh and /point emote to players within 20 m. You may speak or emote once per second; the zone delivers every line and emote, including your own, and they are not saved.input-bindings to an MMORPG-owned action catalog (web/src/input/game-controls.ts): the left stick moves, A jumps (held, it swims up), R3 swims down, B dodge-rolls (#516; it closes an open panel or cancels a running cast instead), X swings the weapon (#517), Y releases the spirit, RB targets next, the d-pad uses ability slots 1–4 and holding LT raises the Warden's shield guard, aimed high or low with the right stick (#156); open bags, the character pane, loot or the vendor form a non-blocking overlay that claims Escape while movement falls through, and leaving the world, focusing a control, opening Settings, blur or a hidden tab release held movement. Mapped game keys (Space, Tab, arrows, F3, …) suppress cancelable browser defaults only while the game owns input; text fields, the Settings dialog, Shift+Tab and Ctrl/Cmd shortcuts keep their browser behavior, and a mouse click on a HUD or panel button hands focus back to the world so Space still jumps. Settings (on character selection and in the world toolbar) is a modal over the shared settings session with field of view, look sensitivity, vertical look inversion and reduced motion (exact entry, global search, category navigation, confirmed category/global resets, and portable User-profile preview/import/export), plus the shared input-bindings workbench for the selected character's own key bindings, which apply and save on each confirmed change. Settings pauses the browser-local zone; an online zone keeps running with the player's input blocked. The page enters with the character's class and sex and encodes command wire v14 with strictly increasing sequences and resends the current intent like the native client.web/src/input/touch-layout.ts), so the zone validates the same intents; the touch layout is not yet rebindable.WorldSource seam (web/src/world/) advances fixed 60 Hz ticks from a bounded accumulator and hands presentation only encoded player-scoped projections, decoded by the same web/src/replication.ts the online source uses. Canonical state never reaches rendering. The online mode swaps in a WebTransport source behind the same seam.mmorpg_presentation::audio, exported as UnitPresenter.takeAudio) through the shared game-audio wasm package on Web Audio, from asset-tooling's CC0 combat-sounds bundle (web/public/sounds/combat-sounds, fetched by scripts/fetch-bundles.sh). Audio unlocks on the first click, key or touch and suspends while the tab is hidden; Settings → Audio sets master, effects and interface volume and mute. Without Web Audio or the bundle the page is silent and every visual telegraph is unchanged (native details).scenery() export of the WASM module (format v3), which maps the same mmorpg-scenery Greyhaven Vale the native client draws. The browser builds it as a stylised low-poly valley: relief terrain in biome tones with smooth roads, plaza and shore, snow-capped distant ranges softened by renderer fog, procedural models for every prop (keep, timber-framed houses, palisade, windmill, camp, cliffs, oak, pine and birch trees, grass, flowers, reeds …) with shared instance geometry for repeated trees, grass and rocks and static batches for structures, a translucent lake, and a renderer sky with a matching CSS backdrop. Structures' walls are their exact core colliders. Players are animated humanoids with class gear; other players share a neutral look: projections carry each player's class and sex as its appearance code, which the browser does not draw yet. A circular minimap shows the subzone name, roads, water, buildings and units.Idle_Shield_Loop clip), and wolves, vermin and boars animated Quaternius CC0 animals (Atlas 6.3.6), as in the native client; humanoid creatures and NPCs use the procedural models. Ranger humanoids also use the bundle’s authored takeoff, airborne and landing clips from the projected vertical-motion cue, shared by both clients; their roots remain at the projected body position. Imported models load on demand, with the procedural low-poly models (quadruped animals with a trot, compact humanoids; unknown templates fall back to a box) shown while a model loads, with the disposition colour (hostile, neutral, friendly) as an accent that their minimap dots share; corpses lie down. Tab or a right click (a right drag still turns) selects, the left mouse button, gamepad X or the touch Attack pill swings where the character faces and hits everything in a 100° arc in reach, targeted or not (#517), 1–8 (or a click on the action bar) use the chosen class's abilities (offensive ones fire where the character faces, heals and buffs land on the selected friend or yourself), Escape cancels a cast and R releases a dead spirit. A Warden's directed Heroic Strike is a separate bindable action (default G): hold it, move the pointer left/right and up (high) or down (low), and release to swing; the zone resolves which creature the sweep physically reaches (or a whiff) and the client draws the arc at the aimed height. Blur, Settings, an open panel or a click cancel the held aim without a strike; the Heroic Strike slot shows the working binding as a compact hint and in its tooltip, or says it is unbound. The Warden's shield guard is another bindable held action (default Z): hold it and move the pointer up (high) or down (low) to pick the lane; the zone blocks matching creature blows from the front and shield side, slows movement while the guard is up, suspends it in the air, and a heavy charging blow breaks it for 1.5 s before the held lane returns. A lane indicator beside the screen centre shows the zone's guard (steel while protecting, dim while suspended, red while broken), blocks and breaks flash at the lane and float Block / Guard broken text, and the most recent of guard and directed strike owns the pointer (pressing one cancels the other without a strike). A directed strike commits the Warden to a 0.2 s recovery: a guard pressed during it is held and protects as soon as the recovery ends. Warden melee is movement-dependent (Atlas 5.2.69–5.2.70): charging at the target deals +20% melee damage, an airborne (overhead) blow +35% while the airborne Warden takes +25% creature melee damage, a planted Warden takes −10% and one backing or strafing away deals −15%; melee pressed during the short landing recovery waits and fires when it ends. The status line names the current stance. A directed Heroic Strike that damages a creature opens the Warden's first combo: Shield Bash pressed during the 0.2 s impact or the following 0.6 s window hits exactly that creature (whatever is selected) and may ignore only the slash's global cooldown; the status line announces the open combo. The action bar (bottom centre) shows the class kit (up to eight abilities) with keybinds and glyph icons; hover, right-click or long-press a slot for its tooltip (cost, range, cast time, cooldown, description). Slots tint blue without enough resource, turn the keybind red when the target is out of range, sweep radially over a cooldown (seconds from 2 s) or the global cooldown, highlight while casting and grey out with their unlock level until learned. The player frame shows health, the class resource (rage red, focus amber, mana blue) and buff and debuff icons with time left; the target frame shows the target's health, auras and cast; a cast bar sits above the action bar (channels drain backwards, with an Interrupted flash). Floating combat text shows damage, heals (green), Absorb, smaller periodic damage and interrupts, and the status lines give readable messages for every error code. Names and numbers come from the module's versioned catalog() export and the decoded projection; range and descriptions are presentation facts held in web/src/world/units/ability-presentation.ts. Nameplates follow in a later step.mmorpg-characters record and lease rules zone hosts use, and its level, XP, copper, bags, equipment, quests, health, cooldowns and position are committed every five seconds, when the page is hidden and on leaving, then resumed on the next visit; the roster shows its committed level. One tab plays a character at a time (Web Locks); a reloaded page's newer local zone epoch fences the page it replaces. The world is saved beside them (Atlas 3.3.8): the local zone's checkpoint without players resumes on the next visit, one world per browser and one tab at a time; a saved world from another version is reset with a notice. There is no handoff, shared world or multiplayer authority, and browser storage is a development adapter.