.arkdelta Format Specification

Version 3.0 · ArkMap Studio · Isithunzi · 2026
File extension: .arkdelta · MIME type: application/json · Encoding: UTF-8
Table of Contents
  1. Overview
  2. Top-Level Structure
  3. meta Object
  4. Base Identity
  5. Canonical Serialization & Checksums
  6. Symbolic IDs (sid)
  7. Operations
  8. Log Compaction
  9. Optional Signatures
  10. Validation Rules
  11. Apply Semantics
  12. Versioning & Compatibility
  13. Complete Example
  14. Format Changelog

1. Overview

The .arkdelta format is a JSON-based edit delta format for Arkadia MUD maps. It records a sequence of editing operations performed in ArkMap Studio on top of a known base map version, so the same set of changes can be re-applied later onto a newer upstream map release.

The typical workflow: a user downloads a map, makes local fixes in edit mode, and saves them as a .arkdelta file ("overlay" / kalka). When a fresh map version is released, the user downloads it, loads the overlay, and the changes are re-applied onto the new base.

Key design goals:

Relationship to .arkmap: A delta never stores a full map — only operations. The base identity is the hierarchical file checksum of the .arkmap canonical form of the map that was loaded when the edits were made (including the reduced-information variant derived from a Mudlet .dat file, where base identity is the file checksum of that derived .arkmap form). The checksum algorithm is the one defined by the .arkmap spec (currently v4 — XXH3-64, 16-hex); deltas written against older map checksum generations (CRC-32 8-hex, or v3 16-hex from ArkMap Studio v1.44.x) never match re-saved maps, so the base gate always reports a mismatch for them (informational dialog — the user may continue; see §4 and §11).

2. Top-Level Structure

{
  "format":         "arkdelta",  // REQUIRED — magic string, must be exactly "arkdelta"
  "format_version": 3,            // REQUIRED — integer, format version (currently 3)
  "meta":          { ... },      // REQUIRED — base identity, provenance, bookkeeping (see §3)
  "ops":           [ ... ],      // REQUIRED — ordered array of operation objects (see §7)
  "checksums":     { ... }       // REQUIRED — XXH3-64 checksums, optional signature (see §5, §9)
}
Unified envelope (format version 3): the envelope keys format, format_version and checksums live at the top level in both map formats (.arkmap and .arkdelta). The format_version counters are independent — each format bumps its own counter on its own breaking changes.
Breaking change (format version 3): files written in format version 2 (magic and version inside meta) are refused by conforming readers as an unsupported format version. There is no migration path — re-create the overlay from the edit log.

Keys at every level are serialized in sorted order (see §5). The file is produced by buildDelta() from the editor's full edit log and consumed by validateDeltaText() + applyDelta().

Closed top level: the top-level key set is closed — exactly the five keys shown above. Readers refuse files carrying any other top-level key. (Unlike meta, which is open, unknown top-level keys were historically covered by no checksum, so they cannot pass silently.)

3. meta Object

FieldTypeReqDescription
ops_countintegerREQNumber of operations; must equal ops.length
baseobjectREQBase identity (see §4); may be empty if the base could not be identified
app_versionstringREQArkMap Studio version that produced the file (informational)
authorstringOPTAuthor nickname, chosen by the user (for humans). Canonical form: lowercase, characters a-z and 0-9 only (1–32 characters) — case is insignificant everywhere, including key derivation. Added in format version 3. See the signature rules in §9 — author fields require a signature.
author_idstringOPTAuthor fingerprint (for machines): the first 16 lowercase hex characters of SHA-256 over the raw bytes of author_pubkey. Added in format version 3.
author_pubkeystringOPTAuthor's Ed25519 public key, 64 lowercase hex characters (32 bytes). Covered by checksums.file, so it cannot be swapped without invalidating the file checksum. Added in format version 3.
createdstringOPTCreation timestamp, ISO 8601. Informational. Added in format version 3.

The magic string and format version moved to the top-level envelope in format version 3 (see §2); they no longer appear inside meta.

Open meta: meta is an open object — readers MUST ignore unknown meta keys (forward compatibility). Operations, in contrast, are strict (see §10).
Threat model: the author fields and the optional signature prove continuity of identity — that the same key holder (nick cryptographically bound to a key) produced several overlays. A public nickname registry (§9, "Public registry") additionally binds a nick to exactly one key — first come, first served, with owner-initiated permanent revocation — so a signed file can be checked against the registry for nick ownership and revocation. The registry still does not prove any real-world identity: a registered nick proves only that its holder derived the matching key first. User interfaces should always show nick and fingerprint, never the nick alone. The registry is also not a trust or moderation layer: registration is uncurated, and a signature — registered or not — does not make the content safe: an overlay can carry executable commands in payloads regardless of who signed it — the "operations with commands" review category (§11) remains the primary defense.

4. Base Identity

meta.base identifies the map variant the delta was created against:

FieldTypeReqDescription
crcstringREQFile checksum (hex) of the canonical .arkmap form of the base map — the hierarchical file checksum as defined by the .arkmap spec §15 (algorithm v4: XXH3-64, 16 lowercase hex characters)
versionstringOPTMap version, copied from meta.user_data.version when present
revisionstringOPTSource revision (commit SHA), copied from meta.user_data.revision when present
areasobjectOPTPer-area base checksums: map of area ID (string key) → the v4 area checksum (16 lowercase hex) of that area in the base map, as defined by the .arkmap spec §15. Added in format version 3; recorded at map load time together with crc.

base.areas enables per-area risk classification when reviewing an overlay against a different base: an operation touching an area whose checksum still matches the base is green (applies onto unchanged ground), an area whose checksum differs is yellow (the area moved under the overlay — review advised), and an area absent from the current map (or a delta without base.areas) falls back to the binary whole-file comparison (red / unknown). Absent base.areas, behavior is exactly the binary base match of older files.

The base checksum is computed once, at map load time — not at export time. The v4 engine computes it read-only (no cloning: the canonical encoding is independent of key order and in-memory ordering, and excludes the internal room.area field), reusing the checksums already computed during load verification — one computation per load.

Why at load: the base identity must describe the map the user started from, not the map after edits. Computing it at load keeps it stable no matter what the session does afterwards.

On load of a delta, the application compares base.crc with the identity of the currently loaded map and informs the user whether the base matches ("baza zgodna") or differs ("kalka z innej wersji mapy"). A mismatch is not an error — applying onto a newer upstream version is the primary use case.

5. Canonical Serialization & Checksums

The file is serialized with the same canonical JSON writer as .arkmap (stableStringify): object keys sorted lexicographically at every level, no insignificant whitespace beyond the fixed pretty-print layout, UTF-8 encoding. The full canonical rules are those of the .arkmap specification (§16) — in particular, arrays of primitives with at most 8 elements are written inline on a single line (e.g. [255, 0, 0]), arrays of objects use the standard multi-line layout, and undefined values are omitted.

Checksums use XXH3-64 (seed 0; 16 lowercase hex characters) over the UTF-8 bytes of the canonical serialization — the same hash family as the .arkmap checksum engine (format_version 3; format_version 2 used XXH3-64 as well, format_version 1 used CRC-32, 8 hex):

FieldTypeDescription
checksums.filestringXXH3-64 of the canonical form of { format, format_version, meta, ops } — the whole file minus the checksums object itself. Because the checksums object is by definition outside this input, extra keys inside it (e.g. sig, §9) never affect the checksum and require no exclusion rules.
checksums.opsarray<string>Per-operation XXH3-64 of the canonical form of each op, in order; used to localize corruption
checksums.sigstringOptional Ed25519 signature over the file checksum — see §9. Readers unaware of signatures ignore it.

Unicode normalization: the checksum input is the raw UTF-8 byte stream of the canonical serialization — 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.

Tamper handling: if checksums.file does not match, the file is refused. The per-op checksums are then used to name the offending operations precisely (e.g. „op #17, #23 nie zgadza się z sumą kontrolną"). The per-op array is diagnostic only — it is not itself an integrity gate.

6. Symbolic IDs (sid)

Objects created by the delta (rooms, areas, labels) do not exist in the base map, so they have no meaningful numeric IDs. In the file they are identified by symbolic IDs:

sid := "d:" N        // N ≥ 1, decimal, no leading zeros — regex: /^d:[1-9][0-9]*$/

Rules:

On apply, each sid receives a fresh numeric ID from a monotonically increasing counter starting at max(existing IDs)+1 (per area for labels), and every reference is translated through the sid map.

7. Operations

Each entry in ops:

{
  "seq":     1,          // REQUIRED — 1-based, contiguous, in application order
  "type":    "ADD_ROOM", // REQUIRED — one of the 25 operation types below
  "target":  { ... },     // REQUIRED — object identity the op applies to
  "payload": { ... },     // REQUIRED — operation data
  "label":   "..."        // REQUIRED (may be "") — human-readable description, as in undo history
}

Room objects embedded in payloads (e.g. ADD_ROOM.payload.room) follow the .arkmap omission convention: empty containers and default values are omitted, and the internal area field never appears.

Room operations

typetargetpayloadNotes
ADD_ROOMroomId (sid), areaIdroom — full room object (id = sid)Fresh numeric ID on apply
DELETE_ROOMroomId, areaIdroom — snapshot at deletion time (informational)Incoming exits are recomputed from live state on apply
EDIT_ROOMroomIdbefore, after — full room snapshotsFull-state replace, same semantics as undo entries
EDIT_EXITroomIdbefore, after — full room snapshotsAs EDIT_ROOM; distinct type for history labels
PAINT_BATCH— (empty)changes: array of { roomId, beforeEnv, beforeSymbol, afterEnv, afterSymbol }Batch recolor; rooms missing on apply are skipped individually
MOVE_ROOMroomIdfromX, fromY, fromZ, toX, toY, toZCoordinates in map cells
MOVE_ROOM_TO_AREAroomIdfromAreaId, toAreaId

Exit operations

typetargetpayloadNotes
ADD_EXITsourceId, dirtargetId, bidirectionalRefused by the editor guard when dir is occupied on apply
DELETE_EXITroomId, direxitId (optional, informational)
DELETE_SPECIAL_EXITroomIdcmd, targetId (optional)Also removes attached custom line / lock / door / weight

Area operations

typetargetpayloadNotes
ADD_AREAareaId (sid)area — area object without rooms/labelsFresh numeric ID on apply
DELETE_AREAareaIdname (informational)Rooms and cross-area exits are cleaned from live state on apply
EDIT_AREAareaIdname, user_data, beforeName, beforeUserData

Custom line / suppressor operations

typetargetpayloadNotes
ADD_CLroomId, dircl — custom line object
EDIT_CLroomId, dirbefore, after
DELETE_CLroomId, dircl (optional, informational)
ADD_SUPPRESSORroomId, dir— (empty)Suppressor = empty red custom line
DELETE_SUPPRESSORroomId, dircl (optional, informational)
AUTO_FIX_SUPPRESSORS— (empty)added: array of { roomId, dir, cl }, removed: array of { roomId, dir }Batch form; entries whose room is missing on apply are dropped

Label operations

typetargetpayloadNotes
ADD_LABELareaIdlabel — full label object (id = sid)Fresh per-area ID on apply
EDIT_LABELareaId, labelIdbefore, after
DELETE_LABELareaId, labelIdlabel — snapshot (informational)
MOVE_LABELareaId, labelIdfromX, fromY, toX, toY
RESIZE_LABELareaId, labelIdfromX, fromY, fromW, fromH, toX, toY, toW, toH

Color operations

typetargetpayloadNotes
EDIT_ENV_COLORenvIdoldColor, newColor — RGB arrays or null
Waypoints: route waypoints are viewer state, not map data — they never appear in a delta.

8. Log Compaction

Producers MUST apply deterministic log compaction before serialization. The same edit log always produces the same file. Compaction rules (per object identity, order-preserving):

  1. A chain of EDIT_ROOM / EDIT_EXIT operations on the same room collapses to one operation: the first before, the last after; if the collapsed before equals after, the operation vanishes.
  2. An ADD_ROOM / ADD_AREA / ADD_LABEL followed by edits or moves of the same sid folds into a single ADD with the final state; likewise ADD_CL + EDIT_CL.
  3. A chain of MOVE_ROOM operations keeps the first from* and the last to*.
  4. EDIT_ENV_COLOR operations per envId collapse to the first oldColor and the last newColor.
  5. An ADD + DELETE pair on the same object vanishes.
  6. PAINT_BATCH entries per roomId collapse to the first before and the last after; batches may be merged.
Reference-safety condition: a chain may be collapsed only if no intervening operation references the object (dependency graph over references in target/payload; the chain must be contiguous in the dependency sense, not necessarily in seq adjacency).

After compaction, seq values are renumbered contiguously (validation already requires this), and the merged operation takes the label of its last component.

Compaction is a producer-side rule: validators MUST NOT reject uncompacted files. Two deliberate consequences, stated for the record: applied overlays enter the undo history at the compacted granularity, and intermediate-state guard refusals that would have occurred in the uncompacted log simply do not occur.

Determinism, precisely: byte-identical output holds for the same edit log compacted by the same producer version. The informational provenance fields (meta.created — a timestamp; signature material when signing is enabled) legitimately differ between two builds of the same log and are excluded from any byte-identity comparison.

9. Optional Signatures

An overlay 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.

What is signed

The signature is an Ed25519 signature over the UTF-8 byte string "arkdelta-v3:" + canonicalSerialization(whole object minus checksums.sig) — the domain prefix followed by the canonical form (§5) of the entire envelope, with only the sig key excluded from checksums. It is stored as checksums.sig — 128 lowercase hex characters (64 bytes). The payload therefore binds the content, the metadata (including the author fields), every checksum entry, and any unknown top-level keys a lenient reader might otherwise keep. The canonical serialization is the same deterministic, key-sorted form used for the file itself, so the payload is well-defined regardless of byte-level key order in the file. Storing the signature inside checksums keeps it outside every checksum input by construction — no circularity, and unsigned files are completely unaffected.

Keys and fingerprint

The signer's public key is stored in meta.author_pubkey (Ed25519, 32 bytes, lowercase hex). Because meta is covered by checksums.file, the key cannot be swapped without invalidating the file checksum. The fingerprint meta.author_id is the first 16 lowercase hex characters of SHA-256 over the raw public-key bytes. How the key pair is generated or stored is implementation-defined (ArkMap Studio derives it deterministically via PBKDF2-SHA256 from a user-held recovery code of 3–6 words — default 3 — from a frozen 2048-word list, salted with the canonical nick — see the user manual); the format defines only the field semantics.

Producer rule

A producer that writes any author field (author, author_id, author_pubkey) MUST sign the file (write checksums.sig). Author fields without a signature are an anomaly: a reader reports them as a declaration without proof and treats the authorship as unverified.

Reader policy

What a signature proves: continuity of identity — the same key holder produced the overlay. With the public registry (below) it can additionally be checked for nick ownership and revocation. It still does not prove real-world identity (registration is uncurated) and it does not vouch for content safety (see the threat model in §3).

Public registry

Signers MAY register their nick in the public ArkMap identity registry, binding the canonical nick to their public key. The registry data lives in a public GitHub repository (Isithunzi000/arkadia-arkmap-identity-registry), one JSON document per nick at entries/<nick>.json, readable by any client over plain HTTPS (no authentication). Writes are only accepted through an unauthenticated-but-proof-gated gateway (https://arkmap-identity-registry.vercel.app/api):

A registry entry records version, nick, author_id, pubkey, registered_at, register_sig, and the revocation fields above. The format of entries is versioned by version (currently 1). Public reads are served through a CDN cache, so a fresh registration or revocation becomes visible to readers within a few minutes (eventual, not instantaneous, consistency); readers MAY cache entries per session.

Registry-aware reader policy

Registry checks are never a load gate: they refine how authorship is reported, and an unreachable registry (offline, blocked, down) must leave the reader fully functional — local signature verification still runs and the registry dimension is reported as unavailable. For a file carrying author fields with a signature that verifies locally, a registry-aware reader reports one of:

For a declaration without proof (author fields without a signature), a registry mismatch or revoked result escalates the report from "unproven" to "conflicting with the registry — treat as false"; a match leaves it unproven (anyone can type a registered nick into an unsigned file).

10. Validation Rules

Validation is fail-closed: any violation refuses the whole file with a list of diagnostics; nothing is loaded. Checks run in this order:

  1. Size limit — file larger than 8 MiB is refused.
  2. JSON — the file must parse as a single JSON object.
  3. Magic — top-level format must be "arkdelta".
  4. Version — top-level format_version must equal 3 (an unknown or older version — including 1 and 2 — is refused loudly and advises updating ArkMap Studio).
  5. Top-level whitelist — keys other than format, format_version, meta, ops, checksums at the top level are refused.
  6. Nesting depth — meta and every operation are scanned before any checksum computation; a structure nested deeper than 60 levels is refused. (Checksum computation serializes recursively — the guard turns a potential stack overflow into a controlled, precise refusal.)
  7. File checksum — checksums.file must match the canonical form of { format, format_version, meta, ops }; on mismatch, per-op checksums localize the corrupted operations by seq.
  8. Operation count — at most 5000 operations; meta.ops_count must equal ops.length.
  9. Sequence — seq values must be 1-based and contiguous. Uncompacted logs are legal — compaction (§8) is a producer-side rule only.
  10. Schema — type must be one of the 25 known types; target/payload must be objects carrying the required fields per type (§7). Operations are strict: unknown keys inside an operation are refused. (meta, in contrast, is open — unknown meta keys are ignored.)
  11. Directions — any target.dir must be a valid direction (n, ne, e, se, s, sw, w, nw, up, down, in, out).
  12. Key sanitization — the keys __proto__, constructor, prototype are forbidden anywhere in an operation.
  13. sid integrity — define-before-use and no duplicate definitions (§6).
  14. Signature consistency — not a refusal gate: author fields without checksums.sig are reported as a declaration without proof; an invalid checksums.sig over an intact checksums.file is a loud warning, and the file still loads (see §9).

11. Apply Semantics

Applying a delta replays the operations in seq order onto the currently loaded map:

Base mismatch: applying onto a different map version is supported by design — operations whose targets no longer exist are skipped with reasons, everything else applies. Geometry review tooling (review window, ghost preview, collision autopositioning) is layered on top of this clean apply path.

12. Versioning & Compatibility

13. Complete Example

A delta with three operations: a new area, a new room inside it, and an exit from an existing room (100) into the new room. (Whitespace abridged; real files use the canonical writer.)

{
  "checksums": {
    "file": "ae01c59324adaedf",
    "ops": [ "37d3379e985f615d", "262f00d7717c507b", "037fd1e6593fac81" ]
  },
  "format": "arkdelta",
  "format_version": 3,
  "meta": {
    "app_version": "v1.51.0",
    "base": { "areas": { "1": "aaaabbbbccccdddd" }, "crc": "3f8a21c0b7d4e5f6", "revision": "0123456789abcdef0123456789abcdef01234567", "version": "0.205.0" },
    "ops_count": 3
  },
  "ops": [
    { "label": "Dodanie obszaru \"Nowy obszar\"",
      "payload": { "area": { "id": "d:1", "name": "Nowy obszar" } },
      "seq": 1, "type": "ADD_AREA",
      "target": { "areaId": "d:1" } },
    { "label": "Dodanie pokoju \"Polana\"",
      "payload": { "room": { "env": 262, "id": "d:2", "name": "Polana", "x": 12, "y": -4, "z": 0 } },
      "seq": 2, "type": "ADD_ROOM",
      "target": { "areaId": "d:1", "roomId": "d:2" } },
    { "label": "Dodanie wyjścia #100 n",
      "payload": { "bidirectional": true, "targetId": "d:2" },
      "seq": 3, "type": "ADD_EXIT",
      "target": { "dir": "n", "sourceId": 100 } }
  ]
}

A signed variant of the same overlay would additionally carry author, author_id, author_pubkey and created in meta, and sig in checksums (see §9). The checksum values above are the real hashes of the example content under the v3 checksum rule (§5), pinned by the test suite (tests/g6_crosscheck.js) so the example can never drift from the implementation.

On apply onto a map whose highest room ID is 6400 and highest area ID is 120: the area becomes 121, the room becomes 6401, and room 100 gains exit n → 6401 (with the reverse s → 100 on the new room, because bidirectional).

14. Format Changelog

VersionDateChanges
12026-08Initial format — ArkMap Studio v1.6.0
22026-08Checksums migrated from CRC-32 (8 hex) to XXH3-64 (16 hex) over the same canonical serialization — unified with the .arkmap checksum engine; base identity follows .arkmap alg v4 (ArkMap Studio v1.45.0). Version 1 files are refused loudly (no migration path — re-create the delta).
32026-08Breaking (ArkMap Studio v1.51.0): unified envelope with .arkmap — format and format_version moved from meta to the top level; checksums.file now covers { format, format_version, meta, ops }. New: per-area base checksums meta.base.areas (§4) with green/yellow/red risk classification; normative producer-side log compaction (§8); optional provenance fields author/author_id/author_pubkey/created (§3) with optional Ed25519 signatures checksums.sig (§9) — author fields require a signature; validation documents the nesting-depth guard (§10) and the open-meta / strict-ops asymmetry (§12); Unicode hashing pinned (raw UTF-8 bytes, producers SHOULD emit NFC). Version 2 files are refused as an unsupported format version — no migration path (re-create the overlay).
32026-08Additive / normative refinement (ArkMap Studio v1.52.0): signature payload redefined as "arkdelta-v3:" + the canonical serialization of the whole object minus checksums.sig (was: the file checksum alone). Signatures written by v1.51.0 do not verify under the new payload and are reported as invalid — re-save the overlay to re-sign (no legacy verification path). Top-level key whitelist added to validation (§10); recovery code word count 3–6 (default 3) with canonical nick (lowercase a-z/0-9) feeding the key-derivation salt; public identity registry with proof-of-possession registration and permanent owner revocation (§9 "Public registry").