Downloads
Everything you need to read, write, and validate MJPF. The example payloads are generated from the reference implementation, so they can never drift from the spec.
White paper
A typeset overview of the format, its transport, governance, attribution, and licence — a readable companion to the normative spec.
MJPF_WhitePaper_v1.2.0.pdf Current · proposed & originated by JSCBIZ · open, royalty-free specification
Earlier editions stay published, never rewritten (additive governance): MJPF_WhitePaper_v1.0.0.pdf
JSON Schema
Validate document structure before acting on it (the four normative checks still apply on top).
mjpf.schema.json
Draft 2020-12 · $id: https://mjpf.openmahj.org/schema/mjpf-1.3.0.json
Conformance vectors
Frozen input → output pairs: the exact canonical JSON and MJQR bytes for four documents, plus the first ten tiles dealt from a known seed. An implementation is conformant when it reproduces all of them byte for byte — and if your output differs, the vector is right and your implementation is wrong.
conformance-vectors.json Asserted against the reference implementation on every build, so they can't drift
Example payloads
Each example comes in two forms: the readable .mjpf.json document and its .mjqr.txt
transport code (base64 of raw-DEFLATE-compressed canonical JSON).
| Example | Kind | JSON | MJQR code |
|---|---|---|---|
| Deal challenge | deal |
example-deal.mjpf.json | .mjqr.txt |
| Deal + score-to-beat | deal |
example-challenge.mjpf.json | .mjqr.txt |
| Result report | result |
example-result.mjpf.json | .mjqr.txt |
| Full resume bundle | resume |
example-resume.mjpf.json | .mjqr.txt |
A deal, in full
This is the entire portable core — a seed, a rule set, an opponent tier. It fits in one QR code.
{
"format": "mjpf",
"spec": "1.3.0",
"kind": "deal",
"requires": [],
"uses": [],
"game": {
"seed": "12648430",
"ruleset": "riichi-lite",
"tier": "wizard",
"mode": "play",
"seats": 4,
"humanSeat": 0,
"recordSeat": 0,
"branchPointIndex": 0
},
"meta": { "app": "Mahjong Coach", "title": "Riichi deal challenge" }
}
…and the same deal as an MJQR transport code (264 bytes — well under one QR's budget):
PY67TgNBDEV/ZeV6iQJZIbQtFQUSghJRODPOjpN54Z0VeSj/jh0kuhmfe318gV2RhA1GSPu6gx4mTATjBbaC2YW3wrm9ZE9HGNc9hCVh/iDL6y8Vr1GoEU9aFHJF/D+UJdJMtliYXeC7yI00NmtghnGwF3nF9w+Pw9OwWStrTKKTHz6jeLj2cOBsEU8YFSdqaKdhrTp8xbAveeqeC7pwK7do57zfdJ11OhcwRsoT2TKh74WFVP75pfZKzuyrzcrUy/wHrr8=
Decode it: base64 → raw inflate (-15) → JSON. See Implement.
A challenge — "beat my score"
A deal plus the challenger's outcome. Note uses: ["result"] (advisory — an old reader still
plays the deal even if it ignores the score-to-beat).
{
"format": "mjpf", "spec": "1.3.0", "kind": "deal",
"requires": [], "uses": ["result"],
"game": { "seed": "12648430", "ruleset": "hongkong", "tier": "veryGood",
"mode": "play", "seats": 4, "humanSeat": 0, "recordSeat": 0, "branchPointIndex": 0 },
"result": { "won": true, "score": 96, "bySelfDraw": false, "turns": 14, "label": "Hong Kong · 8 faan" },
"meta": { "app": "Mahjong Coach", "title": "Beat my score" }
}
Reference implementation
The spec's source of truth in Swift, with a full test suite (envelope, semver gating, forward-compat, raw-DEFLATE, large-seed string round-trip, deal→game, resume==live):
MahjongKit/Sources/MahjongKit/Game/MJPF.swift— the reference codec.MahjongKit/Tests/MahjongKitTests/MJPFTests.swift— the tests (and the vector generator that produced the files on this page).MJPF_SPEC.md— the canonical spec.
Publication of these to a public repository is a project handoff step.