inconvergent
Screenshot of a Boxtype level

Boxtype—Level Encoding (Devlog Part 2)

Introduction & Context

This post describes how levels in Boxtype are encoded in the URL. You may want to look at first: It has many screenshots in it.

Encoding Requirements & Comments

  • Encode levels in a single URL parameter.
  • Compress & base64 encode a stringified envelope that contains the level.
  • Include level hash ["46fd5f03"] as integrity check.
  • EDN as envelope format.
  • Include an encoding flag [:b1].
  • Hash calculated from a string constructed from the same information as the envelope. But with a salt and some modifications. envelope. So hashing scheme does not depend on the envelope format.
  • This could be hard to implement in languages where MurmurHash & LZString are unavailable?
  • Encoding scheme doesn't have any obvious ways to encoded dynamic components.
  • Not the most (space) efficient approach.

Level Encoding

Here is an EDN encoded envelope that contains a playable level:

[:b1 "46fd5f03" 0 800 800 "slippery" -1 590 635 "-9:7
5:10:4:i:3|10:15:3:9|13:19:12:3|14:15:24:3:l:3|19:49:
2:22|1:2:3:7::1|1:31:12:3|1:41:3:7|21:50:6:6|21:69:4:
2|22:57:4:11::1|24:2:17:3:s:3|25:19:3:6|26:37:5:3|27:
49:2:12|29:19:41:3::3|29:53:12:3|2:75:6:4::7|30:57:10
:4:p:2|30:75:10:4::7|31:30:11:10::3|33:40:3:7|36:25:4
:5|38:40:3:4|41:52:5:10|42:35:9:3::f|46:1:29:3|46:58:
9:3|46:5:14:3::3|47:53:4:4:r|49:67:19:4|52:53:3:5|56:
47:10:3::3|57:29:5:4:e|5:41:7:7:y|63:29:10:7|64:39:13
:3::3|66:26:3:3|66:36:3:3|68:58:5:4::1|69:75:5:4::7|6
:24:7:3|6:27:3:4|70:9:9:3|72:46:7:3|72:49:2:3|75:72:4
:7::2|76:12:3:3|76:1:3:3|77:27:9:3::f|77:49:2:22|7:2:
11:3::1|7:59:8:3|9:66:6:5::x|9:75:20:4"]

;; boxes: 55; len: 684

Some of this has been mentioned already. But:

  • "0 800 800": integer for feature flags, and the level width/height.
  • "slippery": target phrase.
  • -1: the number of allowed manual rotations (infinite).
  • 590 635: spawn coordinates.
  • "-9:75:10:4:i:3|10...: custom box encoding. Trailing zero of the first four integers has been has been stripped.

Url Parameter

Finally the envelope is compressed & base64 encoded. A URL looks like this:

https://boxtype.app?w=
NoLgRgjABARALANgGYBMCsSAMBmGVNQAcmBxBMAzgDYCWADnQKYBO
AnngLTRoCcBC2NLA48QAdjQgImEHBA0Q2AD7Spk7CB4qNEURABMil
XIiT9cjVSO7Zow-v0qQhjWJBSn2CFJdO431yV9bzQZBBAEIO8EUTl
HBxA0NxNvD3NnKTcNCiN9SRsNSP1w7Dd1IOS7HyC9WID3ZX1RNB1f
QwkI2XcxJWwZJKkZOTpnXpkO1TlxXoCZCG9VI2wNOBlA7HC8rrRew
lk12SV-RMN8zCOXSVENECQj8O8mo0REvev7xKkLBqOyla7mEdRAg3
DY4Eo0KcNBodmhwnBQQcjAMnpI5IwIbJvG43KwlAJnHpxviLHpoT8
EJsSkZKYpqcoEHs0Eyuh4YuJJGjuvjnHIsjz9FlDmIZKJ3mJDC9+R
LbBllB0ZXz3I4xA8XEZVVJFBq3ILNNrbkoxJUMg4jRl5gaIObeCA9
spgeFwpIQAAPJSiDr6IYwAC6QA

;; boxes: 55; len: 503; box.dens: 9.1

Intermission

There may or may not be a part three in this series coming.

Thank you for reading!


  • LZString does both.
  • Using MurmurHash.
  • The box encoding has this format: xy-position:width:height:char:prop|.... Where char & props are optional.