{
  "_comment": "The Store app reads this from https://snailos.org/apps/index.json, and downloads each file from https://snailos.org/apps/<file>. Upload this file and every published file beside it — the .lua apps and the .art packs some of them carry. Every field is a flat scalar because that is what xt_json.h extracts without holding the document: an object nested inside an array element comes back empty. `category` groups the rows; the Store makes a section per distinct value, in the order the values first appear here. ARRAY ORDER IS THE ORDER ON SCREEN; there is no rank field, because a number beside an ordering is two orderings that can disagree. AN APP IS NOT ALWAYS ONE FILE: `also` names one more file to download from the same directory and land beside `file`, which is how an app declares its art pack. It is a single name rather than a list because an array inside an element also comes back empty; omit it or leave it \"\" for anything that is one file. The Store stages the whole set to .part and renames nothing until all of it has arrived, so a failed download leaves no half-app in the launcher. Every app is Lua and the launcher holds sixteen card apps. THREE FIELDS FEED THE APP'S OWN PAGE, which firmware 1.13 opens from the list. `author` is who made it, shown as \"by <author>\"; up to 23 characters. `version` is an opaque string of up to 11 characters compared only for INEQUALITY: the device records the version it installed, and shows UPDATE whenever this file says something different — so any changed string, in any format, publishes an update, and \"newer\" is decided here rather than parsed there. Never re-upload changed files under an unchanged version, because devices that hold that version will not offer the update. `size` is the set's total bytes (file plus also) as a decimal string, so the page can say what a download costs before the radio is raised; omit it and the line is simply not shown. These eight fields are every field the device's extractor can capture (XT_JSON_FIELDS is 8), so the next field added must displace one. `featured` is no longer read: it flagged the storefront grid, and the flat list that replaced the storefront cannot promote an entry without moving it, which is what array order is for. Field width limits on the device: name 27, file and also 31, desc 119 (shown whole on the app page; the list shows two lines), category 19.",
  "apps": [
    {
      "name": "Billy's Blackjack",
      "file": "billy.lua",
      "also": "billy.art",
      "category": "Games",
      "author": "Snail",
      "version": "1.3",
      "size": "16975",
      "desc": "One deck and a dealer who talks. Double down on the first two cards; blackjack pays three to two."
    },
    {
      "name": "Snake",
      "file": "snake.lua",
      "also": "",
      "category": "Games",
      "author": "Snail",
      "version": "1.5",
      "size": "16990",
      "desc": "The snake crawls on its own and the arrows steer. Eat, grow, and keep off the walls and your tail."
    },
    {
      "name": "Cascade",
      "file": "cascade.lua",
      "also": "",
      "category": "Games",
      "author": "Snail",
      "version": "1.5",
      "size": "17282",
      "desc": "Seven tetrominoes, line clears and a next-piece preview. Gravity takes a row every three seconds."
    },
    {
      "name": "Stocks",
      "file": "stocks.lua",
      "also": "",
      "category": "Connected",
      "author": "Snail",
      "version": "1.7",
      "size": "24423",
      "soon": "1",
      "desc": "A watchlist you edit on the device, then one symbol a screen: price, day range, volume, averages and RSI."
    }
  ]
}
