.arkmap · MIME type: application/json · Encoding: UTF-8
The .arkmap format is a JSON-based file format for storing MUD map data. It is designed as the canonical format for ArkMap Studio, a web-based map viewer and editor for the Arkadia MUD game world.
Key design goals:
.dat format (version 20) — converting .dat → .arkmap → .dat produces a byte-identical result for files already in the canonical Qt layout (i.e. written by ArkMap Studio); files written by external tools are preserved semantically but normalized on import (see §19){
"format": "arkmap", // REQUIRED — magic string, must be exactly "arkmap"
"format_version": 2, // REQUIRED — integer, format version (currently 2)
"meta": { ... }, // REQUIRED — metadata object (see §3)
"colors": { ... }, // REQUIRED — color palette object (see §4)
"areas": [ ... ], // REQUIRED — array of Area objects (see §5)
"checksums": { ... }, // optional — XXH3-64 checksums, added by ArkMap Studio on save (see §15)
"transports": { ... } // optional — transport lines, arkmap-transports v1 (see §21)
}
| Field | Type | Required | Description |
|---|---|---|---|
format | string | YES | Must be "arkmap". Used to identify file type. |
format_version | integer | YES | Format version. Currently 2. Increment on breaking changes. Renamed from version (format version 1) — see §24. |
meta | object | YES | Map-level metadata. See §3. |
colors | object | YES | Environment color definitions. See §4. |
areas | array | YES | Array of Area objects. See §5. |
checksums | object | optional | Hierarchical XXH3-64 checksums. Moved from meta.checksums (format version 1) to the top level in format version 2. See §15. |
transports | object | optional | Transport lines (ships, coaches, portals) — a universal, MUD-agnostic arkmap-transports v1 document. Not preserved in .dat export. See §21. |
format, format_version, and checksums live at the top level in both formats (.arkmap and .arkdelta), so a generic dispatcher can identify file type and version without knowing the per-format meta layout. The format_version counters of .arkmap and .arkdelta are independent sequences; equal numbers carry no cross-format meaning.version instead of format_version, checksums under meta.checksums) are refused by conforming readers as an unsupported format version.{
"map_name": "Arkadia",
"symbol_font": { /* Font object */ },
"symbol_font_fudge_factor": 1.0,
"use_only_map_font": false,
"user_data": { /* optional string→string map (see §14) */ },
"app_version": "v1.51.0", /* optional, informational — writer's version */
"accepted_dir_issues": [ /* optional, .arkmap-only — direction-validator acceptances */ ]
}
| Field | Type | Required | Description |
|---|---|---|---|
map_name | string | YES | Display name of the map (e.g. "Arkadia") |
symbol_font | Font | YES | Font used for rendering room symbols on the map |
symbol_font_fudge_factor | number | YES | Mudlet's font size scaling factor (typically 1.0) |
use_only_map_font | boolean | YES | If true, only use symbol_font; false = allow fallback |
room_id_hash | object (string → integer) | optional | Mudlet's mRoomIdHash: contributor name → starting room ID, used by multi-contributor map merging (crowdmap). Preserved through .dat round-trips. Omit if empty. Added in spec v1.1. |
user_data | UserData | optional | Map-level key-value metadata. May contain version, revision, map_sync_version etc. |
app_version | string | optional | Version of ArkMap Studio that wrote the file. Informational; ignored by validation. Mirrors the .arkdelta bookkeeping field. Covered by checksums.meta (see §15). Added in spec v2.0. |
author | string | optional | Author nickname (for humans). Canonical form: lowercase, characters a-z and 0-9 only (1–32 characters) — case is insignificant everywhere, including key derivation. Requires a signature — see §23. Additive extension: does not change the format version. |
author_id | string | optional | Author fingerprint (for machines): the first 16 lowercase hex characters of SHA-256 over the raw bytes of author_pubkey. |
author_pubkey | string | optional | Author's Ed25519 public key, 64 lowercase hex characters (32 bytes). Covered by checksums.meta and by the signature, so it cannot be swapped without invalidating both. |
created | string | optional | Creation timestamp, ISO 8601. Informational — self-declared by the producer. |
accepted_dir_issues | array of strings | optional | .arkmap-only — Acceptances for the direction validator (intentional team_follow_link / dir_bind mismatches marked as OK). Each entry is a key string "type:roomId:value", parsed by splitting on the first two colons (the value may itself contain :). The key embeds the numeric room ID, so it becomes stale when room IDs are renumbered (e.g. crowdmap merge) — acceptable, because acceptances are soft UX state. Written only when the validator's acceptance store is set to "file". Serialized sorted lexicographically (see §16). Not preserved in .dat export. See §14. |
{
"env_colors": { "258": 34, "272": 248 },
"custom_env_colors": { "258": [0, 179, 0], "301": [255, 114, 14] }
}
| Field | Type | Required | Description |
|---|---|---|---|
env_colors | object | optional | Map of envId (string key) → ANSI palette index (integer 0–255). Lower priority than custom_env_colors. |
custom_env_colors | object | optional | Map of envId (string key) → Color array. These override env_colors and the ANSI palette. |
custom_env_colors[envId] — direct RGB, highest priorityenv_colors[envId] → ANSI 256-color palette lookup (explicit override)ARKADIA_ENVS, 51 entries covering all known Arkadia envIds) — overrides implicit ANSI for Arkadia-specific envIds (200+). Applied only when the loaded map is detected as an Arkadia map (map-level user_data.map_sync_version present, "arkadia" in the map/file name, or ≥2 signature envIds >255 in use); maps from other MUDs skip this layer entirely and render from the ANSI palette plus their own env_colors / custom_env_colors — matching the official Mudlet renderer behavior.If none of the four layers provides a color for a given envId, the room renders with the Mudlet default color (rgb(114,1,0)).
The env_colors mapping and the implicit ANSI layer resolve indices to RGB using the standard xterm-256 palette:
n = i − 16, channel levels = [0, 95, 135, 175, 215, 255], RGB = [levels[⌊n/36⌋ mod 6], levels[⌊n/6⌋ mod 6], levels[n mod 6]]v = 8 + (i − 232) × 10, RGB = [v, v, v]color_table assignment in map-exporter.lua.An ordered array of Area objects. Must be sorted by id ascending for deterministic serialization.
{
"id": 7,
"name": "Miasto",
"rooms": [ /* Room objects */ ],
"labels": [ /* Label objects — optional */ ],
"grid_mode": false, // optional, default false
"is_zone": false, // optional, default false
"zone_area_ref": 0, // optional, default 0
"pos": [0, 0, 0], // optional, area position on overview
"user_data": { ... } // optional
}
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | YES | Unique area ID. Can be negative (Mudlet's Default Area is -1). |
name | string | YES | Display name of the area. |
rooms | array | YES | Array of Room objects. Sorted by id ascending. |
labels | array | optional | Array of Label objects. Sorted by id ascending. |
grid_mode | boolean | optional | Mudlet grid mode flag. Default: false. Omit if false. |
is_zone | boolean | optional | Zone flag. Default: false. Omit if false. |
zone_area_ref | integer | optional | Reference to parent zone area. Omit if 0. |
pos | [number, number, number] | optional | Area position on Mudlet's overview map [x, y, z]. Omit if [0,0,0]. |
user_data | UserData | optional | Area-level metadata. |
{
"id": 12847,
"x": 15,
"y": -3,
"z": 0,
"env": 272,
"name": "Skrzyżowanie dróg",
"weight": 1,
"symbol": "K",
"locked": false,
"hash": "abc123def456",
"exits": { "n": 12840, "e": 12848 },
"stubs": ["sw"],
"doors": { "n": "closed" },
"exit_weights": { "e": 3 },
"exit_locks": ["n"],
"special_exits": { "wejdz do jaskini": 15001 },
"special_exit_locks": ["wejdz do jaskini"],
"custom_lines": { /* see §10 */ },
"user_data": { "zone": "handlowa" },
"notes": "Tu jest kowal",
"tags": ["shop", "blacksmith"]
}
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | YES | Globally unique room ID (across all areas). |
x | integer | YES | X coordinate (east is positive). |
y | integer | YES | Y coordinate (north/up is positive — note: Mudlet negates Y for display). |
z | integer | YES | Z coordinate (level/floor). |
env | integer | YES | Environment ID. Determines room color via the color resolution chain (§4). |
name | string | optional | Room name. Omit if empty string. |
weight | integer ≥ 1 | optional | Pathfinding cost. Default: 1. Omit if 1. |
symbol | string | optional | Room symbol displayed on map (e.g. "P", "K", "[]"). Omit if empty. No length limit (Mudlet has none). ArkMap Studio fits the symbol font to the room square; symbols too long to stay legible are not drawn. Short symbols (1–2 chars) are recommended for readability. |
locked | boolean | optional | Room locked flag (Mudlet isLocked). Locked rooms are skipped by pathfinding (not traversed through, but can be a destination). Omit if false. |
hash | string | optional | Mudlet room database hash (mpRoomDbHashToRoomId). Omit if not present. |
hidden | boolean | optional | Hidden room — not drawn and skipped by pathfinding. In .dat (v20) there is no native field, so it round-trips through userData as system.hidden = "1" (readers accept both the flag and the userData key). Omit if false. |
exits | object | optional | Standard exits. See §7. |
stubs | array of strings | optional | Stub directions — exits without a known target. Sorted alphabetically. |
doors | object | optional | Door data. See §8. |
exit_weights | object | optional | Per-exit pathfinding weights. See §7. |
exit_locks | array of strings | optional | Locked exit directions. Sorted alphabetically. |
special_exits | object | optional | Special exits. See §9. |
special_exit_locks | array of strings | optional | Locked special exit commands. Sorted alphabetically. |
custom_lines | object | optional | Custom drawn lines. See §10. |
user_data | UserData | optional | Room-level key-value metadata. |
notes | string | optional | .arkmap-only — Free-form notes. Not preserved in .dat export. Omit if empty. |
tags | array of strings | optional | .arkmap-only — Tags/labels. Not preserved in .dat export. Omit if empty array. |
"weight" entirely when the value is 1, rather than writing "weight": 1.Exits use short direction strings as keys. The complete set of 12 valid directions:
| Short | Long (Mudlet) | Index | Screen vector [dx, dy] |
|---|---|---|---|
n | north | 1 | [0, -1] |
ne | northeast | 2 | [1, -1] |
nw | northwest | 3 | [-1, -1] |
e | east | 4 | [1, 0] |
w | west | 5 | [-1, 0] |
s | south | 6 | [0, 1] |
se | southeast | 7 | [1, 1] |
sw | southwest | 8 | [-1, 1] |
up | up | 9 | [0, 0] |
down | down | 10 | [0, 0] |
in | in | 11 | [0, 0] |
out | out | 12 | [0, 0] |
.arkmap and Mudlet .dat files north = positive Y (see §6). The display layer negates Y; the data model never does.Maps direction → target room ID. Keys are short direction strings; values are integers (room IDs). Only existing exits are listed.
{ "n": 12840, "e": 12848, "up": 12900 }
Per-exit pathfinding cost overrides. Keys must be valid direction strings that exist in exits or special_exits. Values are integers ≥ 1. A weight of 1 is allowed and meaningful: in Mudlet's .dat an absent weight entry means weight 0, so explicit 1s are preserved across .dat round-trips (both from import and from the editor). In ArkMap Studio's own routing an absent weight falls back to the target room's weight.
{ "e": 3 }
Directions where an exit is "hinted" but the target room is unknown. Sorted alphabetically. May coexist with entries in exits (Mudlet allows this).
["sw", "w"]
Directions where the exit is programmatically locked (distinct from doors). Sorted alphabetically. Locked exits are ignored by the pathfinder.
Maps direction string → door type string.
{ "n": "closed", "e": "locked" }
| Value | Mudlet int | Description |
|---|---|---|
"open" | 1 | Door exists but is open |
"closed" | 2 | Door is closed (can be opened) |
"locked" | 3 | Door is locked (requires key) |
exits or stubs. Mudlet allows doors to exist independently of exits.Maps command string → target room ID. The command is a text string used in the MUD client (e.g. "wejdz do jaskini").
{
"special_exits": { "wejdz do jaskini": 15001, "przejdz most": 15042 },
"special_exit_locks": ["wejdz do jaskini"]
}
special_exit_locks is an array of command strings that are locked. Each value must exist as a key in special_exits.
"0command" (unlocked) or "1command" (locked) strings mapped by target room ID. The .arkmap format decomposes this into separate special_exits and special_exit_locks fields for clarity.doors, exit_weights, and custom_lines key namespace with standard exits. Avoid using standard direction names (n, ne, e, se, s, sw, w, nw, up, down, in, out) as special exit commands when a normal exit exists in the same direction — this will cause metadata conflicts.Custom lines are hand-drawn polylines on the map that replace the default straight-line exit connections. They are keyed by direction (for standard exits) or command string (for special exits).
"custom_lines": { "e": { "points": [[15.5, -3.0], [16.0, -2.5], [16.5, -3.0]], "color": [255, 0, 0], "style": "dash", "arrow": true }, "w": { "points": [], "color": [255, 0, 0] } }
| Field | Type | Required | Description |
|---|---|---|---|
points | array of [number, number] | YES | Waypoints of the polyline. Each element must be a 2-element array [x, y]. Coordinates are in map units (same as room x/y). On .dat import coordinates are rounded to 4 decimal places (see §19) — a sub-pixel difference, invisible when rendered. Empty array ([]) = empty custom line (hides the default exit line). |
color | Color | optional | Line color. Default: [255, 0, 0] (red). |
style | string | optional | Line style. Default: "solid". Omit if "solid". |
arrow | boolean | optional | Show arrowhead at the end of the polyline. Rendered in both view and edit mode. Omit if false. |
Custom lines are rendered as polylines starting from the room center (room.x, room.y), then through each waypoint in order. A custom line with 1 waypoint draws a single segment from room center to that point. The points array contains only waypoints — the room center is implicit and not stored in points.
| Value | Mudlet int | Description |
|---|---|---|
"solid" | 1 | Continuous line (default) |
"dash" | 2 | Dashed line |
"dot" | 3 | Dotted line |
"dash_dot" | 4 | Alternating dash-dot |
"dash_dot_dot" | 5 | Alternating dash-dot-dot |
"points": []) is an empty custom line — it hides the default exit line. This is an intentional Mudlet design feature, not data corruption. Empty custom lines must be preserved through all conversions.An empty custom line hides the default exit line that Mudlet would normally draw from this room in the given direction. It is needed when the opposite room has a custom line pointing here — without it, both lines would be drawn (a double line).
Example: Room A (id=100) has custom line e → Room B (id=101). Room B should have an empty custom line: "w": { "points": [], "color": [255,0,0] } to hide the default westward line.
Custom line keys must reference existing exits or special exits. The key must appear in either exits or special_exits of the same room.
Only custom line entries with a points array (including empty arrays, i.e. suppressors) are represented in .arkmap. Style/arrow/color entries for directions without a points entry — possible in .dat, where these are separate maps — are dropped on import (see §19).
Labels are text annotations or image overlays on the map, associated with an area.
{
"id": 3,
"x": 12.5,
"y": -4.2,
"z": 0,
"width": 8.0,
"height": 1.5,
"text": "Wyspa Miłości",
"fg_color": [200, 200, 100],
"bg_color": [0, 0, 0, 50],
"no_scaling": false,
"show_on_top": true,
"pixmap": null
}
| Field | Type | Required | Description |
|---|---|---|---|
id | integer | YES | Label ID, unique within the area. The same ID may exist in different areas. |
x | number | YES | X position in map coordinates. |
y | number | YES | Y position in map coordinates. |
z | integer | YES | Z level. |
width | number | YES | Width in map units. |
height | number | YES | Height in map units. |
text | string | YES | Label text. May be empty for image-only labels. |
fg_color | Color | YES | Foreground (text) color. |
bg_color | Color | YES | Background color. Alpha channel supported for transparency. |
no_scaling | boolean | optional | If true, label size is fixed regardless of zoom. Omit if false. |
show_on_top | boolean | optional | If true, label renders above rooms. Omit if false. |
pixmap | string | null | optional | Base64-encoded image data (Mudlet QPixMap). Null or omit for text labels. |
Represents a Qt QFont, serialized as JSON. Used for meta.symbol_font.
{
"family": "Bitstream Vera Sans Mono",
"point_size": -1,
"pixel_size": 10,
"style_hint": 7,
"weight": 50,
"style_setting": false,
"underline": false,
"strike_out": false,
"fixed_pitch": true
}
| Field | Type | Required | Description |
|---|---|---|---|
family | string | YES | Font family name. |
point_size | number | YES | Point size (-1 if pixel_size is used). |
pixel_size | number | YES | Pixel size (-1 if point_size is used). |
style_hint | integer | YES | Qt QFont::StyleHint enum value. |
weight | integer | YES | Font weight (50 = normal, 75 = bold). |
style_setting | boolean | YES | Style setting flag. |
underline | boolean | YES | Underline flag. |
strike_out | boolean | YES | Strikeout flag. |
fixed_pitch | boolean | YES | Fixed pitch flag. |
| Field | Type | Default | Description |
|---|---|---|---|
style | string | "" | Font style string. |
style_strategy | integer | 0 | Qt style strategy. |
stretch | integer | 100 | Font stretch (100 = normal). |
letter_spacing | number | 0 | Letter spacing. |
word_spacing | number | 0 | Word spacing. |
hinting_preference | integer | 0 | Qt hinting preference. |
capital | integer | 0 | Capitalization mode. |
kerning | boolean | true | Kerning enabled. Only include if false. |
overline | boolean | false | Overline flag. |
style_oblique | boolean | false | Oblique style flag. |
ignore_pitch | boolean | false | Ignore pitch flag. |
letter_spacing_is_absolute | boolean | false | If true, letter_spacing is in pixels (not percentage). |
Colors are represented as JSON arrays:
[r, g, b] — 3 integers, each 0–255[r, g, b, a] — 4 integers, each 0–255 (alpha: 0 = transparent, 255 = opaque)Use RGB (3 elements) when alpha is 255 (fully opaque). Use RGBA (4 elements) only when alpha < 255. This keeps files compact.
[0, 128, 0] // RGB green, alpha implied 255 [255, 0, 0, 128] // RGBA semi-transparent red
A user_data field is a flat JSON object mapping string keys to string values. No nested objects, no arrays, no numeric values.
{ "version": "3.15.0", "revision": "abc123def456" }
Available at three levels: meta.user_data (map-level), area.user_data (area-level), and room.user_data (room-level).
Although user_data is a generic string→string map, ArkMap Studio and the Arkadia toolchain assign meaning to a set of reserved keys. They remain ordinary string values — any conforming reader may ignore them — but editors that understand them should preserve their formats verbatim. Unless noted otherwise, these are room-level keys.
Edited through the Skrypty tab of the room panel. All survive .dat round-trips (stored as Mudlet user_data).
| Key | Value format | Description |
|---|---|---|
gps | JSON array (as string) | GPS entries — a JSON-encoded array of objects, each with gps_string_lines (array of strings), room_id (target room) and area_name. Any additional fields (e.g. within_room_ids, line_delta) are preserved verbatim. |
bind | commands joined by # | Room command bind, internal form (e.g. otworz drzwi#wejdz). |
bind_printable | commands joined by ; | Human-readable form of bind (e.g. otworz drzwi;wejdz). Kept in sync with bind — the latter is bind_printable with ; replaced by #. |
drinkable | "true" | Marks the room as a watering hole (wodopój). Absent or empty = not drinkable. |
gate | string | Gate command for the room (e.g. uderz w brame). |
walk_pre_cmd | string | Auto-traversal command issued before walking through the room. |
walk_post_cmd | string | Auto-traversal command issued after walking through the room. |
dir_bind | dir=cmd pairs joined by & | Direction → command binds (e.g. down=odsun prycze#d). Each pair splits on the first =; surrounding whitespace is trimmed. A pair with a direction but an empty command is reported by the direction validator as an empty bind. |
team_follow_link | label*dir pairs joined by # | Team-follow links (e.g. ścieżka do lasku*e). Each pair splits on the first * (1:1 with the arkadia-web client — the label therefore cannot contain *). A direction that is not an existing exit of the room is reported by the direction validator as a mismatch (rozjazd). |
Set through the room panel's Podstawowe tab. Stored as user_data, so they round-trip through .dat as opaque strings that Mudlet itself ignores.
| Key | Value format | Description |
|---|---|---|
room.ui_borderColor | Qt color string | Custom room outline color (the Obrys option). When present together with a thickness, the room is drawn with a colored border instead of the default outline. |
room.ui_borderThickness | "1"–"10" | Custom room outline thickness in pixels. Clamped to the 1–10 range. |
system.fallback_hidden | "true" | Marks the room as hidden. Rendering of hidden rooms follows the active "Ukryte pokoje" view mode (faded / dashed / shown / hidden). |
| Key | Value format | Description |
|---|---|---|
system.fallback_symbol_color | #rrggbb | Per-room symbol color fallback. Mudlet .dat versions < 21 have no native per-room symbol-color field, so the color is carried here. On v20 export the room's symbol color is written into this key; on import it is read back from it. |
These keys are injected by the source map (Arkadia mapping scripts / Mudlet) and are not written or interpreted by ArkMap Studio. They are preserved verbatim across both .arkmap and .dat round-trips.
| Key | Value format | Description |
|---|---|---|
internal_id | string (e.g. "i1fd75c220") | Source-generated unique room identifier. Present on every room in Arkadia maps (distinct from the numeric room.id). Opaque to ArkMap Studio. |
description | string (may be multi-line) | Free-form room description carried by the source map (e.g. shop price tables). Present on a subset of rooms. Newlines are stored escaped within the string value. |
These keys commonly appear in meta.user_data and are written/read by ArkMap Studio:
| Key | Description |
|---|---|
version | Map release version string (e.g. "3.15.0"). |
revision | Map revision / commit hash. |
map_sync_version | Mudlet map-sync version marker. |
user_data keys — any key not listed above is preserved verbatim. The reserved keys above are conventions layered on top of the generic string→string contract; they never change the underlying type.ArkMap Studio computes hierarchical XXH3-64 checksums on save and stores them in the top-level checksums object (moved out of meta in format version 2 — see §2). Every hashed value is first serialized with the canonical binary encoding — a deterministic, JSON-independent byte format whose normative reference is tests/checksums/CANONICAL_V4.md in the project repository. Checksums are optional — a file without checksums is valid.
"checksums": { "alg": "v4", "file": "a1b2c3d4e5f60718", "meta": "f0e1d2c3b4a59687", "areas": { "7": "e5f6a7b8c9d0e1f2", "12": "c9d0e1f2a3b4c5d6" }, "rooms": { "12847": "1a2b3c4d5e6f7a8b", "12848": "5e6f7a8b9c0d1e2f" }, "transports": { "hash": "…", "lines": { "Wyzima - Novigrad": "…" } }, /* optional — transport line sums (see §21) */ "sig": "3f4a…" /* optional — author signature, 128 lowercase hex (see §23) */ }
"r4". Default values are omitted from the encoding (weight: 1, locked: false, hidden: false, empty strings and empty containers), internal fields (area) are excluded, and custom line defaults are normalized (style: "solid" → omit, arrow: false → omit). The upstream hash field (e.g. "45:28:0:Wyzima") is covered when present. This ensures hash stability regardless of in-memory representation."a4" + the canonical encoding of the area attributes (id, name, the optional grid_mode/is_zone/zone_area_ref/pos fields when present, labels sorted by id — with full label color channels including alpha, count-prefixed —, user_data with keys in UTF-8 byte order) + the rollup of raw 8-byte little-endian room hashes sorted by room ID. Because the area's own fields and its id are part of the input, two empty areas are distinguishable."f4" + the canonical encoding of the map-level colors tables (env_colors, custom_env_colors; numeric keys in ascending numeric order) + the rollup of raw 8-byte little-endian area hashes sorted by area ID.checksums.meta, added in format version 2) = XXH3-64 (seed 0) of the canonical binary encoding of the entire meta object, domain prefix "m4" (see the Meta object encoding section of CANONICAL_V4.md — keys in UTF-8 byte order, recursive). The two roles are deliberately separate: checksums.file is the map's identity — it excludes meta by design, so metadata edits (notes, acceptances, book-keeping) never change it; checksums.meta is the metadata's integrity — it detects external edits to meta without disturbing the identity hash. Keeping meta integrity separate is also what allows .arkdelta base matching (§4 of the .arkdelta spec) to rely on checksums.file alone.All hash values are stored as 16-character lowercase hexadecimal strings. The canonical encoding fixes every cross-platform ambiguity: integers are little-endian i32, floats are little-endian f64 with -0 normalized to +0 and every NaN (or non-number) normalized to the canonical quiet-NaN 7ff8000000000000, strings are length-prefixed UTF-8, and map keys follow a fixed domain order (direction keys in n,ne,e,se,s,sw,w,nw,up,down,in,out order; other keys in UTF-8 byte order; numeric keys in ascending numeric order).
Unicode normalization: strings are hashed as their raw UTF-8 bytes exactly as they appear in the file — verifiers MUST NOT normalize before hashing. Producers SHOULD emit strings in Unicode Normalization Form C (NFC) so that semantically identical text hashes identically across tools.
alg)"v4" is the only algorithm ArkMap Studio writes (since v1.45.0) and the only one it verifies. The retired generations — legacy v1 (no alg field), "v2" ("a2:"/"f2:" prefixed rollups) and "v3" (canonical binary, v1.44.x) — are no longer produced or verified; the formulas are frozen history.
Verifiers MUST dispatch on alg: "v4" → v4 formulas; any other value (including absent) → report an algorithm mismatch (loud, never a silent skip — a silently skipped stale file would be indistinguishable from a file without checksums). Re-saving the file upgrades its checksums to v4.
checksums.transports)When the map embeds a transport document (map.transports), saving additionally signs it into checksums.transports = { hash, lines }: hash covers the whole document, lines holds one sum per line keyed by line name — so verification pinpoints exactly which line was modified (badLines), added unsigned (missingLines) or removed leaving an orphaned sum (extraLines). Unlike room/area/meta sums, transport sums use the canonical JSON encoding (deterministic stableStringify — keys sorted at every level, absent keys omitted), hashed as XXH3-64 of its UTF-8 bytes; the canonical document sorts lines by name (array order is not semantic) while preserving leg order (leg order is semantic). Transport integrity is an auxiliary, informational signal (same class as metaOk): it never affects file identity and is reported separately from map-data sums. Re-saving after removing transports clears the orphaned sums.
On load, recompute from bottom up — using the algorithm recorded in alg (see Algorithm versioning above) — and compare. Mismatches indicate the file was modified externally (hand-edited JSON, merge conflict resolution, etc.). Mismatches are warnings, not fatal errors. Verification never throws on malformed data (it reports a verification error and defers to structural validation), and it also reports dictionary inconsistencies: rooms or areas missing their checksum entry, and orphaned checksum entries without a matching object. Dictionary-inconsistency reporting applies to the areas and rooms dictionaries only; unrecognized top-level keys inside the checksums object itself (e.g. keys introduced by a newer spec) are ignored, not reported — verifiers must remain forward-compatible with the envelope.
hash); area hashes additionally cover the area's own in-scope attributes (id, name, user_data, labels with full color channels, and the optional grid_mode, is_zone, zone_area_ref and pos fields — inside the scope since v4); the file hash additionally covers the colors tables; the meta hash covers the entire meta object. Transport line sums (checksums.transports) are signed and verified separately (canonical JSON encoding — see §21). The file key is still a rollup (hash of area hashes + colors), not a hash of the entire document byte stream; v4 dropped the redundant global room rollup (rooms are already rolled up through their areas).For git-friendly output, .arkmap files use stable JSON serialization:
, separator — e.g. [255, 0, 0], [32.7281, -7.9983]areas sorted by id ascendingrooms within each area sorted by id ascendinglabels within each area sorted by id ascendingstubs, exit_locks, special_exit_locks sorted alphabeticallymeta.accepted_dir_issues sorted lexicographically (UTF-8 byte order of the key strings)id; stubs and exit locks alphabetically) is also applied when exporting to Mudlet .dat, so two .dat exports of the same logical map are byte-identical regardless of how the in-memory map was edited.A conforming implementation should validate the following rules:
format must be "arkmap"format_version must be 2meta, colors, areas must be presentchecksums, if present, must be an object; meta.checksums is not a recognized location (format version 1 layout — rejected by rule 2)meta, areas, rooms, labels, colors) must not cause rejection — readers preserve them verbatim and writers re-emit them (see §1); only the rules in this list may reject or warn. Unknown top-level keys are additionally reported at load (an informational note listing them) and are covered by the optional signature (§23)meta.room_id_hash, if present, must be an object mapping contributor names (strings) to starting room IDs (integers)doors, exit_weights, custom_lines)"open", "closed", "locked""solid", "dash", "dot", "dash_dot", "dash_dot_dot"[number, number] pairs (empty array = empty custom line)name and symbol must be strings (if present)locked must be boolean (if present)user_data keys and values must be stringsdoors, exit_weights, custom_lines must be objects (not arrays) if presentspecial_exit_locks must be an array if presentformat or a missing/wrong format_version are fatal errors. There is no migration path and no backward compatibility: files written in format version 1 (with version: 1 and meta.checksums) are refused as an unsupported format version.This section documents rendering conventions that implementations should follow for visual compatibility with Mudlet and Delwing.
Custom lines are drawn as polylines starting from the room center, then through each waypoint in order. Arrowheads (when arrow: true) are rendered in both view and edit modes. Custom lines with an empty points array (empty custom lines) are not drawn but may be indicated with a ⊘ symbol at the room edge.
Rooms with envIds not resolved by any color layer render with the Mudlet default color rgb(114, 1, 0) (dark brownish-red). This applies to all visual contexts: canvas, minimap, room panel swatch, env color dialog, and palette chips. The legend and palette chips refresh dynamically after map load to reflect any custom_env_colors overrides.
The .arkmap format is designed for lossless conversion to/from Mudlet's binary map.dat format. ArkMap Studio reads versions 17–22 and always writes version 20 (the Arkadia MUD standard). Round-trip conversion .dat → .arkmap → .dat produces byte-identical output for version 20 input files that are already in the canonical Qt layout — in practice, files previously written by ArkMap Studio (verified with SHA-256). Files written by external tools (e.g. Mudlet itself or Arkadia mapping scripts) are preserved semantically but not byte-identically: their content is normalized on import as listed below. Files in other versions (17–19, 21–22) are read correctly but re-written as version 20, so the output will differ structurally.
ArkMap Studio always writes .dat files in the canonical layout (see §16). When importing a .dat file produced by external tools, the following normalizations are applied. They do not change the meaning of the map:
TRoom::audit), which removes them as well.None currently known — as of spec v1.1, all previously identified data-loss cases (mRoomIdHash, exit weights equal to 1, orphan custom line attributes) have been addressed; the normalizations listed above are the only intentional differences from the source file.
.arkmap uses short strings; .dat uses 1-based indices (see §7 table). Convert using the direction table.
.arkmap uses strings; .dat uses integers: open=1, closed=2, locked=3.
.arkmap uses strings; .dat uses integers: solid=1, dash=2, dot=3, dash_dot=4, dash_dot_dot=5.
.dat stores special exits as QMap<int targetRoomId, QList<QString>> where each string is prefixed with "0" (unlocked) or "1" (locked). .arkmap decomposes this into special_exits + special_exit_locks.
Important: Mudlet negates Y for per-area bounds: min_y = -max(room.y), max_y = -min(room.y). The .arkmap format stores Y as-is (positive = north). Implementations must negate Y when computing area bounds for .dat export.
Mudlet uses QColor (spec, r, g, b, alpha, pad). .arkmap uses [r, g, b] or [r, g, b, a]. When alpha is 255, omit it. When converting to QColor, set spec=1 (RGB), pad=0.
QFont bit flags are decomposed into boolean fields in .arkmap. See §12 for the mapping.
These fields are exclusive to the .arkmap format and are not preserved when exporting to Mudlet .dat:
| Field | Location | Description |
|---|---|---|
notes | Room object | Free-form text notes for a room. |
tags | Room object | Array of string tags for filtering/categorization. |
checksums | top-level object | XXH3-64 integrity checksums (auto-generated by ArkMap Studio on save; top-level envelope key since format version 2 — see §15). |
transports | top-level object | Transport lines document (arkmap-transports v1) — universal routing data, signed per line via checksums.transports. See §21. |
app_version | meta object | Version of ArkMap Studio that wrote the file (informational). |
accepted_dir_issues | meta object | Direction-validator acceptances, written only when the validator's acceptance store is "file" (see §14). |
Implementations that only handle .dat conversion can safely ignore these fields. When reading a .arkmap file for .dat export, these fields should be silently dropped.
transports)A map may embed a transport document describing named transport lines — ships, coaches, portals, anything that moves the player between non-adjacent rooms. The format is universal: it describes routing data for any map of any MUD; game-specific content is just data on top of the same schema. The document may also live as a standalone sidecar JSON (same schema) for tools that keep routing data out of the map file.
{
"format": "arkmap-transports", // REQUIRED — magic string
"version": 1, // REQUIRED — schema version
"lines": [
{
"name": "Wyzima - Novigrad ferry", // REQUIRED, unique — lines are keyed by name
"board": ["wsiadz na statek", "wejdz na statek"], // REQUIRED — boarding commands (aliases)
"exit": "zejdz ze statku", // REQUIRED — disembark command
"legs": [ // REQUIRED, ordered — the ride sequence
{ "from": 729, "to": 3760, "time": 23, "label": "Bialy Most" },
{ "from": 3760, "to": 729, "time": 18, "label": "Wyzima" }
]
}
]
}
| Field | Type | Required | Description |
|---|---|---|---|
name | string | YES | Unique line name (duplicate names are a validation error — lines are keyed by name). |
board | array of strings | YES | Commands that board the line; the first is canonical, the rest are aliases. |
exit | string | YES | Command that disembarks. |
legs[].from / to | positive integer | YES | Room ids of the boarding / arrival stops. |
legs[].time | number (seconds) | optional | Measured travel time; when absent, routing cost assumes 60 s (TRANSPORT_DEFAULT_TIME). |
legs[].label | string | optional | Human-readable stop name. |
name.Σ leg times · ratio + boarding penalty, one penalty per ride, so a direct crossing beats transfers. Reference cost model: normal ratio 0.5 / penalty 30, aggressive ratio 0.1 / penalty 10..arkmap validation (§17) does not inspect transports (unknown top-level keys are preserved untouched); the document is validated separately against the arkmap-transports v1 schema (validateTransports in the arkmap npm package).checksums.transports — see §15.transports has no .dat counterpart and is dropped on .dat export (see §20).A minimal but valid .arkmap file with one area containing two rooms:
{
"areas": [
{
"id": 1,
"name": "Test Area",
"rooms": [
{
"env": 272,
"exits": {
"e": 2
},
"id": 1,
"name": "Start Room",
"x": 0,
"y": 0,
"z": 0
},
{
"env": 258,
"exits": {
"w": 1
},
"id": 2,
"name": "Forest",
"symbol": "T",
"x": 1,
"y": 0,
"z": 0
}
]
}
],
"checksums": {
"alg": "v4",
"areas": { "1": "202da9297d3fa8c6" },
"file": "5d03008d88f80d3c",
"meta": "81b665ced34bce7a",
"rooms": { "1": "8e006383da3c0aa8", "2": "fa11ba21960714e5" }
},
"colors": {
"custom_env_colors": {
"258": [0, 179, 0],
"272": [128, 128, 128]
}
},
"format": "arkmap",
"format_version": 2,
"meta": {
"map_name": "Test Map",
"symbol_font": {
"family": "Bitstream Vera Sans Mono",
"fixed_pitch": true,
"pixel_size": 10,
"point_size": -1,
"strike_out": false,
"style_hint": 7,
"style_setting": false,
"underline": false,
"weight": 50
},
"symbol_font_fudge_factor": 1.0,
"use_only_map_font": false
}
}
areas, checksums, colors, format, format_version, meta). Within each room, keys are also sorted. This is the deterministic serialization format. The checksum values above are the real v4 hashes of the example content — cross-verified against two independent implementations (the ArkMap Studio encoder and the reference Python oracle) and pinned by the test suite (tests/g6_crosscheck.js), so the example can never drift from the specification text.A map file exists in exactly one of two states: anonymous (no author fields, no signature) or signed (author fields plus a valid signature). There is no third state — see the anomaly rule below. The scheme mirrors the .arkdelta signature (§9 of the .arkdelta spec): the same field names, the same key type, the same payload construction — only the domain prefix differs (arkmap-v2: versus arkdelta-v3:).
The signature is an Ed25519 signature over the UTF-8 byte string "arkmap-v2:" + canonicalSerialization(whole object minus checksums.sig) — the domain prefix followed by the deterministic serialization (§16) of the entire envelope, with only the sig key excluded from checksums. The payload therefore binds the content (areas/rooms), the colors tables, the metadata (including the author fields), every checksum entry, and any unknown top-level keys preserved under the forward-compatibility rule (§17). It is stored as checksums.sig — 128 lowercase hex characters (64 bytes). Storing the signature inside checksums keeps it outside every checksum input by construction — no circularity, and unsigned files are completely unaffected.
A producer that writes any author field (author, author_id, author_pubkey, created) MUST sign the file (write checksums.sig) and MUST recompute checksums.meta after writing the author fields, so the meta hash covers them. Author fields without a signature are an anomaly: readers report them as a declaration without proof and treat the authorship as unverified.
checksums.sig is present, readers that support signatures SHOULD verify it against meta.author_pubkey. An invalid signature over an intact checksum hierarchy is a loud warning, not a refusal: the file loads, authorship is treated as unverified.sig), claimed (author fields without sig — declaration without proof), valid (sig verifies; the reader additionally compares author_id against the fingerprint of author_pubkey and reports a mismatch), invalid (sig does not verify — loud warning).checksums and meta are ignored (§17).format_version.Signers MAY register their nick in the public ArkMap identity registry — one nick bound to exactly one key, with owner-initiated permanent revocation (tombstone). The registry, its gateway, and the registry-aware reader policy (match / missing / mismatch / revoked / offline) are specified once in §9 of the .arkdelta spec ("Public registry") and apply unchanged to map signatures — the registry binds identities, not file formats. Registry checks are never a load gate; an unreachable registry only marks the registry dimension unavailable.
| Version | Date | Changes |
|---|---|---|
1 | 2026 | Initial release. Full Mudlet .dat v20 compatibility. Extensions: notes, tags, checksums. |
1 | 2026 | Additive, non-breaking: documented reserved user_data keys (Arkadia mechanics, room UI, Mudlet system — §14); added optional meta.accepted_dir_issues (.arkmap-only, direction-validator acceptances). |
1 | 2026 | Documentation only (no format change): documented source pass-through keys internal_id and description (§14.1); clarified checksum scope — room/area graph only, not whole-document (§15). |
1 | 2026 | Documentation only (no format change): terminology update — "exit suppressor" renamed to "empty custom line"; validator label updated to "double line". |
1 | 2026 | Additive normative (no format change): algorithm versioning — meta.checksums records "alg": "v2"; verifiers MUST dispatch on alg (absent = frozen legacy v1 formulas; unknown = skip silently) (§15). |
1 | 2026 | Additive normative (no format change): checksum engine v3 — meta.checksums records "alg": "v3" (XXH3-64 over canonical binary encoding, 16-hex values); v1/v2 formulas retired — treated as unknown algorithms and skipped silently (§15). |
1 | 2026 | Normative correction (ArkMap Studio v1.44.1): the v3 area encoding gained user_data (UTF-8 byte-ordered keys, key+value strings), restoring the v2 area scope. Files written by v1.44.0 (v3 without area user_data in scope) recompute under the corrected encoding — no v3 files existed outside the project mirror at the time of the correction (§15). |
1 | 2026 | Additive normative (no format change; ArkMap Studio v1.45.0): checksum engine v4 — meta.checksums records "alg": "v4" (domain prefixes r4/a4/f4; label colors with all channels incl. alpha; area grid_mode/is_zone/zone_area_ref/pos in scope; room hash in scope; redundant global room rollup dropped). v3 retired — any non-v4 alg is a loudly reported mismatch, never a silent skip; verification never throws and reports missing/orphaned entries (§15). |
2 | 2026 | Breaking (ArkMap Studio v1.51.0): unified envelope with .arkdelta — version renamed to format_version (now 2); checksums moved from meta.checksums to the top level; new checksums.meta entry (meta integrity, domain prefix m4 — checksums.file remains the meta-independent identity hash); optional meta.app_version; meta.accepted_dir_issues parsing pinned (split on first two colons) and serialization pinned (sorted lexicographically); Unicode hashing pinned (raw UTF-8 bytes, producers SHOULD emit NFC); preserve-unknown-keys rule stated normatively (§17). Version 1 files are refused as an unsupported format version — there is no migration path. |
2 | 2026 | Additive (no format change; ArkMap Studio v1.52.0): optional author signatures — meta.author/author_id/author_pubkey/created and checksums.sig (Ed25519 over "arkmap-v2:" + the canonical serialization of the whole object minus checksums.sig), mirroring the .arkdelta §9 scheme; unknown top-level keys are reported at load (§17); nick canonical form pinned (lowercase a-z/0-9); public identity registry (nick bound to one key, owner-initiated permanent revocation) (§23). |
2 | 2026 | Additive (no format change): optional top-level transports field — a universal, MUD-agnostic arkmap-transports v1 document (named transport lines with boarding/disembark commands and timed legs) — and its per-line integrity sums checksums.transports ({ hash, lines }, canonical JSON encoding, informational class like meta; §15, §21). Reference implementation: arkmap npm package (validateTransports / addTransportChecksums / verifyTransportChecksums / buildTransportEdges). |
.arkmap Format Specification v2 · ArkMap Studio · Isithunzi · AGPL-3.0 License · 2026