@mauricode/token-derby 2.13.0 → 2.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.js CHANGED
@@ -152,48 +152,52 @@ function hatById(id) {
152
152
  }
153
153
  var HATS = [
154
154
  // ── COMMON (18) ────────────────────────────────────────────────────────
155
- { id: "flat_cap", name: "Flat Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...........", "....AAAA...", "...AAAAAA..", "..AAAAAAA.."], variants: [{ A: "#8B6914" }, { A: "#12301b" }, { A: "#aab5cb" }, { A: "#bdcbaa" }] },
156
- { id: "bucket_hat", name: "Bucket Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "...AAAAA...", "...AAAAA...", ".AAAAAAAAA."], variants: [{ A: "#CC2200", Q: "#FFFFFF" }, { A: "#0007cc", Q: "#FFFFFF" }, { A: "#becc00", Q: "#4d3dc7" }, { A: "#cc00c5", Q: "#d6d6dc" }] },
157
- { id: "beanie", name: "Beanie", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#4A7C59" }, { A: "#b21f35" }, { A: "#ec9418" }, { A: "#3a17e6" }] },
158
- { id: "stetson", name: "Stetson", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AA.AA...", "...AAAAA...", "...AAAAA...", "A..AAAAA..A", "AAAAAAAAAAA", "AAAAAAAAAAA"], variants: [{ A: "#C49A00" }, { A: "#272004" }, { A: "#040404" }, { A: "#373606" }] },
159
- { id: "party_hat", name: "Party Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "....AQA....", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FF69B4", Q: "#FFD700" }, { A: "#c46bff", Q: "#ff000d" }, { A: "#fdff6b", Q: "#0400ff" }, { A: "#6bff97", Q: "#05050a" }] },
160
- { id: "fez", name: "Fez", rarity: "common", width: 11, anchor_x: 22, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....Q......", "....AAA....", "....AAA....", "....AAA...."], variants: [{ A: "#CC0000", Q: "#8B0000" }, { A: "#CC0000", Q: "#f5e5e5" }, { A: "#CC0000", Q: "#f1e209" }, { A: "#CC0000", Q: "#0956f1" }] },
161
- { id: "sailor_hat", name: "Sailor Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "..AAAAAAA..", "..QQQQQQQ..", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#000080" }, { A: "#FFFFFF", Q: "#c0c0ed" }, { A: "#FFFFFF", Q: "#00000a" }, { A: "#FFFFFF", Q: "#0505ef" }] },
162
- { id: "newsboy_cap", name: "Newsboy Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA..", "..AAAAAA..."], variants: [{ A: "#5C4033", Q: "#3D2B1F" }, { A: "#e96020", Q: "#131211" }, { A: "#342c28", Q: "#131211" }, { A: "#0a0300", Q: "#ddab78" }] },
163
- { id: "tam_o_shanter", name: "Tam O'Shanter", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "....AAA....", "..AAAAAAA..", "..AAAAAAA..", "...AAAAA..."], variants: [{ A: "#006400", Q: "#FF0000" }, { A: "#ff0000", Q: "#016400" }] },
164
- { id: "trucker_cap", name: "Trucker Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAQQ....", "...AAQQ....", "..AAQQQAA..", "..AAQQQAA.."], variants: [{ A: "#2196F3", Q: "#FFFFFF" }, { A: "#f41fe3", Q: "#FFFFFF" }, { A: "#1ff45f", Q: "#FFFFFF" }] },
165
- { id: "hard_hat", name: "Hard Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#FFD600" }, { A: "#d74c1d" }] },
166
- { id: "chef_toque", name: "Chef's Toque", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AAAAA...", "..AAQAQAA..", "...AQAQA...", "...AQAQA...", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FFFFFF", Q: "#f9f9f9" }] },
167
- { id: "bobble_hat", name: "Bobble Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....Q.....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#C62828", Q: "#FFFFFF" }, { A: "#293bc7", Q: "#FFFFFF" }, { A: "#29c775", Q: "#231f1f" }, { A: "#a529c7", Q: "#d50707" }] },
168
- { id: "cowboy_hat", name: "Cowboy Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "A.AAAAAAA.A", ".AAAAAAAAA."], variants: [{ A: "#8B4513" }, { A: "#0a0400" }, { A: "#956c50" }] },
169
- { id: "baseball_cap", name: "Baseball Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#1565C0" }, { A: "#8515c1" }, { A: "#15c157" }, { A: "#ef2d0b" }] },
170
- { id: "tinfoil_hat", name: "Tinfoil Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#B0BEC5" }, { A: "#6a6c6c" }] },
171
- { id: "dunce_cap", name: "Dunce Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....Q.....", "....QAQ....", "...QAAAQ...", "...QAAAQ...", "..QAAAAAQ..", "..AAAAAAA.."], variants: [{ A: "#F8F8F8", Q: "#F44336" }] },
172
- { id: "mini_top_hat", name: "Mini Top Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#212121" }, { A: "#626060" }] },
155
+ { id: "flat_cap", name: "Flat Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...........", "....AAAA...", "...AAAAAA..", "..AAAAAAA.."], variants: [{ A: "#8B6914" }, { A: "#12301b" }, { A: "#aab5cb" }, { A: "#bdcbaa" }], rollable: true },
156
+ { id: "bucket_hat", name: "Bucket Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "...AAAAA...", "...AAAAA...", ".AAAAAAAAA."], variants: [{ A: "#CC2200", Q: "#FFFFFF" }, { A: "#0007cc", Q: "#FFFFFF" }, { A: "#becc00", Q: "#4d3dc7" }, { A: "#cc00c5", Q: "#d6d6dc" }], rollable: true },
157
+ { id: "beanie", name: "Beanie", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#4A7C59" }, { A: "#b21f35" }, { A: "#ec9418" }, { A: "#3a17e6" }], rollable: true },
158
+ { id: "stetson", name: "Stetson", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AA.AA...", "...AAAAA...", "...AAAAA...", "A..AAAAA..A", "AAAAAAAAAAA", "AAAAAAAAAAA"], variants: [{ A: "#C49A00" }, { A: "#272004" }, { A: "#040404" }, { A: "#373606" }], rollable: true },
159
+ { id: "party_hat", name: "Party Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "....AQA....", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FF69B4", Q: "#FFD700" }, { A: "#c46bff", Q: "#ff000d" }, { A: "#fdff6b", Q: "#0400ff" }, { A: "#6bff97", Q: "#05050a" }], rollable: true },
160
+ { id: "fez", name: "Fez", rarity: "common", width: 11, anchor_x: 22, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....Q......", "....AAA....", "....AAA....", "....AAA...."], variants: [{ A: "#CC0000", Q: "#8B0000" }, { A: "#CC0000", Q: "#f5e5e5" }, { A: "#CC0000", Q: "#f1e209" }, { A: "#CC0000", Q: "#0956f1" }], rollable: true },
161
+ { id: "sailor_hat", name: "Sailor Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...QQQQQ...", "..AAAAAAA..", "..QQQQQQQ..", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#000080" }, { A: "#FFFFFF", Q: "#c0c0ed" }, { A: "#FFFFFF", Q: "#00000a" }, { A: "#FFFFFF", Q: "#0505ef" }], rollable: true },
162
+ { id: "newsboy_cap", name: "Newsboy Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA..", "..AAAAAA..."], variants: [{ A: "#5C4033", Q: "#3D2B1F" }, { A: "#e96020", Q: "#131211" }, { A: "#342c28", Q: "#131211" }, { A: "#0a0300", Q: "#ddab78" }], rollable: true },
163
+ { id: "tam_o_shanter", name: "Tam O'Shanter", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "....AAA....", "..AAAAAAA..", "..AAAAAAA..", "...AAAAA..."], variants: [{ A: "#006400", Q: "#FF0000" }, { A: "#ff0000", Q: "#016400" }], rollable: true },
164
+ { id: "trucker_cap", name: "Trucker Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAQQ....", "...AAQQ....", "..AAQQQAA..", "..AAQQQAA.."], variants: [{ A: "#2196F3", Q: "#FFFFFF" }, { A: "#f41fe3", Q: "#FFFFFF" }, { A: "#1ff45f", Q: "#FFFFFF" }], rollable: true },
165
+ { id: "hard_hat", name: "Hard Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#FFD600" }, { A: "#d74c1d" }], rollable: true },
166
+ { id: "chef_toque", name: "Chef's Toque", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...AAAAA...", "..AAQAQAA..", "...AQAQA...", "...AQAQA...", "...AQAQA...", "...AAAAA..."], variants: [{ A: "#FFFFFF", Q: "#f9f9f9" }], rollable: true },
167
+ { id: "bobble_hat", name: "Bobble Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....Q.....", "...AAAAA...", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#C62828", Q: "#FFFFFF" }, { A: "#293bc7", Q: "#FFFFFF" }, { A: "#29c775", Q: "#231f1f" }, { A: "#a529c7", Q: "#d50707" }], rollable: true },
168
+ { id: "cowboy_hat", name: "Cowboy Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "A.AAAAAAA.A", ".AAAAAAAAA."], variants: [{ A: "#8B4513" }, { A: "#0a0400" }, { A: "#956c50" }], rollable: true },
169
+ { id: "baseball_cap", name: "Baseball Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "...AAAAA...", "..AAAAAA...", "..AAAAAAA..", "..AAAAAAAAA"], variants: [{ A: "#1565C0" }, { A: "#8515c1" }, { A: "#15c157" }, { A: "#ef2d0b" }], rollable: true },
170
+ { id: "tinfoil_hat", name: "Tinfoil Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA.."], variants: [{ A: "#B0BEC5" }, { A: "#6a6c6c" }], rollable: true },
171
+ { id: "dunce_cap", name: "Dunce Cap", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....Q.....", "....QAQ....", "...QAAAQ...", "...QAAAQ...", "..QAAAAAQ..", "..AAAAAAA.."], variants: [{ A: "#F8F8F8", Q: "#F44336" }], rollable: true },
172
+ { id: "mini_top_hat", name: "Mini Top Hat", rarity: "common", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...AAAAA...", "...AAAAA...", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#212121" }, { A: "#626060" }], rollable: true },
173
173
  // ── RARE (10) ──────────────────────────────────────────────────────────
174
- { id: "bicorne", name: "Bicorne", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AAAQQQQ..", "..AAAAAAA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#1A237E", Q: "#FFD700" }, { A: "#01052d", Q: "#544803" }] },
175
- { id: "viking_helmet", name: "Viking Helmet", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..A.AAA.A..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#9E9E9E", Q: "#8D6E63" }, { A: "#dcdbdb", Q: "#bf3908" }] },
176
- { id: "jesters_cap", name: "Jester's Cap", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "...AAAAA...", "...AAAAA..."], variants: [{ A: "#E53935", Q: "#FFD600" }, { A: "#e5a434", Q: "#0040ff" }, { A: "#34e537", Q: "#eeff00" }, { A: "#e234e5", Q: "#00ff40" }] },
177
- { id: "plague_doctor", name: "Plague Doctor Beak", rarity: "rare", width: 11, anchor_x: 24, rows: ["...........", "...........", "...........", "...........", "....QQQ....", "...QAAAQQ..", "...QQQQQQQ.", "..QQQQQ.QQQ", "..QQQQ....Q", "..QQQQ....."], variants: [{ A: "#F5F5F5", Q: "#795548" }, { A: "#e1dbdb", Q: "#080707" }] },
178
- { id: "morion", name: "Conquistador Morion", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "...QQQQQ...", "...QAAAQ...", ".A..AAA..A.", "..AAQQQAA.."], variants: [{ A: "#B0BEC5", Q: "#FFD600" }, { A: "#0a4768", Q: "#e6c10a" }] },
179
- { id: "shako", name: "Shako", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "........Q..", "........Q..", "........Q..", "........Q..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#45464f", Q: "#00ff2a" }, { A: "#45464f", Q: "#ff4d00" }, { A: "#45464f", Q: "#ff0019" }, { A: "#45464f", Q: "#fff700" }] },
180
- { id: "centurion_helm", name: "Centurion Helm", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "....QQQ....", "...QQQQQQ..", "..QQQQQQQQ.", ".QQ..A...Q.", ".Q..AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#2f3131", Q: "#C62828" }] },
181
- { id: "papal_mitre", name: "Papal Mitre", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....QQQ....", "...QQQQQ...", "...QAAAQ...", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }] },
182
- { id: "headdress", name: "Headdress", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#FF8F00", Q: "#1565C0" }] },
183
- { id: "sombrero", name: "Sombrero", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "...AQAQA...", "AAAAAAAAAAA"], variants: [{ A: "#F57F17", Q: "#BF360C" }, { A: "#f8b377", Q: "#3e1204" }, { A: "#d6f877", Q: "#04133e" }, { A: "#d6f877", Q: "#04133e" }] },
174
+ { id: "bicorne", name: "Bicorne", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AAAQQQQ..", "..AAAAAAA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#1A237E", Q: "#FFD700" }, { A: "#01052d", Q: "#544803" }], rollable: true },
175
+ { id: "viking_helmet", name: "Viking Helmet", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..A.AAA.A..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#9E9E9E", Q: "#8D6E63" }, { A: "#dcdbdb", Q: "#bf3908" }], rollable: true },
176
+ { id: "jesters_cap", name: "Jester's Cap", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "...AAAAA...", "...AAAAA..."], variants: [{ A: "#E53935", Q: "#FFD600" }, { A: "#e5a434", Q: "#0040ff" }, { A: "#34e537", Q: "#eeff00" }, { A: "#e234e5", Q: "#00ff40" }], rollable: true },
177
+ { id: "plague_doctor", name: "Plague Doctor Beak", rarity: "rare", width: 11, anchor_x: 24, rows: ["...........", "...........", "...........", "...........", "....QQQ....", "...QAAAQQ..", "...QQQQQQQ.", "..QQQQQ.QQQ", "..QQQQ....Q", "..QQQQ....."], variants: [{ A: "#F5F5F5", Q: "#795548" }, { A: "#e1dbdb", Q: "#080707" }], rollable: true },
178
+ { id: "morion", name: "Conquistador Morion", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....Q.....", "...QQQQQ...", "...QAAAQ...", ".A..AAA..A.", "..AAQQQAA.."], variants: [{ A: "#B0BEC5", Q: "#FFD600" }, { A: "#0a4768", Q: "#e6c10a" }], rollable: true },
179
+ { id: "shako", name: "Shako", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "........Q..", "........Q..", "........Q..", "........Q..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#45464f", Q: "#00ff2a" }, { A: "#45464f", Q: "#ff4d00" }, { A: "#45464f", Q: "#ff0019" }, { A: "#45464f", Q: "#fff700" }], rollable: true },
180
+ { id: "centurion_helm", name: "Centurion Helm", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "....QQQ....", "...QQQQQQ..", "..QQQQQQQQ.", ".QQ..A...Q.", ".Q..AAA....", "...AAAAA...", "..AAAAAAA..", "..AAAAAAA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#2f3131", Q: "#C62828" }], rollable: true },
181
+ { id: "papal_mitre", name: "Papal Mitre", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "....QQQ....", "...QQQQQ...", "...QAAAQ...", "..AAAAAAA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }], rollable: true },
182
+ { id: "headdress", name: "Headdress", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", "...........", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "...QQQQQ..."], variants: [{ A: "#FF8F00", Q: "#1565C0" }], rollable: true },
183
+ { id: "sombrero", name: "Sombrero", rarity: "rare", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "...AQAQA...", "AAAAAAAAAAA"], variants: [{ A: "#F57F17", Q: "#BF360C" }, { A: "#f8b377", Q: "#3e1204" }, { A: "#d6f877", Q: "#04133e" }, { A: "#d6f877", Q: "#04133e" }], rollable: true },
184
184
  // ── EPIC (6) ───────────────────────────────────────────────────────────
185
- { id: "papal_tiara", name: "Papal Tiara", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "....QQ.....", "...QQQQQ...", "...QAAQQ...", "...QQQQQ...", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }, { A: "#b18e10", Q: "#f3f3f1" }] },
186
- { id: "samurai_kabuto", name: "Samurai Kabuto", rarity: "epic", width: 11, anchor_x: 23, rows: ["....Q...Q..", "....QQ.QQ..", ".....QQQ...", ".......Q...", "...AAAAQ...", "..AAAAAQQ..", "..AAAAAQQ..", ".AAAAAAAQ..", "AAAAAAAAQ..", "AAAAAAAAQ.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#050505", Q: "#C62828" }, { A: "#675f5f", Q: "#c4c729" }] },
187
- { id: "gladiator_galea", name: "Gladiator Galea", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "....QQQQQQ.", "...QQQQQ...", "...QQQQQ...", "...QAAA....", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#ffe907", Q: "#C62828" }] },
188
- { id: "pharaoh_nemes", name: "Pharaoh Nemes", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "..AAAAAAA..", "..AAQAQAA..", "..QAQAQAQ..", "..QAQAQAQ..", "..QQAAAQQ..", "..QQAAAAA..", "...QAQA...."], variants: [{ A: "#FFD700", Q: "#1565C0" }, { A: "#8d342a", Q: "#63686e" }] },
189
- { id: "spartan_helmet", name: "Spartan Helmet", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "........Q..", ".......QQ..", ".....QQQQ..", "....QQQQQ..", "..QQQQQQ...", ".QQQAA.....", "QQAAAAAAA..", "Q.AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#B71C1C" }, { A: "#B0BEC5", Q: "#b2b51c" }, { A: "#B0BEC5", Q: "#b5611c" }] },
190
- { id: "conquistador_full", name: "Conquistador Helm", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA..", "...AQQQA...", "...AQQQA..."], variants: [{ A: "#B0BEC5", Q: "#FFD700" }, { A: "#B0BEC5", Q: "#0040ff" }, { A: "#B0BEC5", Q: "#36123b" }] },
185
+ { id: "papal_tiara", name: "Papal Tiara", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "....QQ.....", "...QQQQQ...", "...QAAQQ...", "...QQQQQ...", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#FFFFFF", Q: "#FFD700" }, { A: "#b18e10", Q: "#f3f3f1" }], rollable: true },
186
+ { id: "samurai_kabuto", name: "Samurai Kabuto", rarity: "epic", width: 11, anchor_x: 23, rows: ["....Q...Q..", "....QQ.QQ..", ".....QQQ...", ".......Q...", "...AAAAQ...", "..AAAAAQQ..", "..AAAAAQQ..", ".AAAAAAAQ..", "AAAAAAAAQ..", "AAAAAAAAQ.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#050505", Q: "#C62828" }, { A: "#675f5f", Q: "#c4c729" }], rollable: true },
187
+ { id: "gladiator_galea", name: "Gladiator Galea", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "....QQQQQQ.", "...QQQQQ...", "...QQQQQ...", "...QAAA....", "..AAAAAAA..", "..AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#C62828" }, { A: "#ffe907", Q: "#C62828" }], rollable: true },
188
+ { id: "pharaoh_nemes", name: "Pharaoh Nemes", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "..AAAAAAA..", "..AAQAQAA..", "..QAQAQAQ..", "..QAQAQAQ..", "..QQAAAQQ..", "..QQAAAAA..", "...QAQA...."], variants: [{ A: "#FFD700", Q: "#1565C0" }, { A: "#8d342a", Q: "#63686e" }], rollable: true },
189
+ { id: "spartan_helmet", name: "Spartan Helmet", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "........Q..", ".......QQ..", ".....QQQQ..", "....QQQQQ..", "..QQQQQQ...", ".QQQAA.....", "QQAAAAAAA..", "Q.AAAAAAA..", "..AQQQQQA.."], variants: [{ A: "#B0BEC5", Q: "#B71C1C" }, { A: "#B0BEC5", Q: "#b2b51c" }, { A: "#B0BEC5", Q: "#b5611c" }], rollable: true },
190
+ { id: "conquistador_full", name: "Conquistador Helm", rarity: "epic", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", ".....A.....", "....AAA....", "...AAAAA...", "..AAAAAAA..", "...AQQQA...", "...AQQQA..."], variants: [{ A: "#B0BEC5", Q: "#FFD700" }, { A: "#B0BEC5", Q: "#0040ff" }, { A: "#B0BEC5", Q: "#36123b" }], rollable: true },
191
191
  // ── LEGENDARY (5) ──────────────────────────────────────────────────────
192
- { id: "rainbow_crown", name: "Rainbow Crown", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", ".....A.....", "....AAA....", "....AQA....", "....AAA....", "...AAQAA...", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA.."], colors: { A: "#FFD700", Q: "#553f3f" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF"], fps: 8 } },
193
- { id: "inferno_cap", name: "Inferno Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "....AAA....", "...AAAAA...", "....AAA....", ".....Q.....", "A....Q....A", "A...QQQ...A", ".A..QQQ..A.", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF4500", Q: "#FFD700" }, animation: { type: "cycle", frames: ["#FF0000", "#FF2200", "#FF4500", "#FF6600", "#FF8C00", "#FFA500"], fps: 12 } },
194
- { id: "void_hood", name: "Void Hood", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...AAA.....", "..AAAAAA...", ".AAAAAAA...", ".AAAAAAAA..", "AAAAAAAAA..", "AAAAQQQAA..", "AAAAQQQAA.."], colors: { A: "#1A0033", Q: "#d9cfe3" }, animation: { type: "cycle", frames: ["#0D0019", "#1A0033", "#2D004D", "#3D0066", "#2D004D", "#1A0033"], fps: 3 } },
195
- { id: "prismatic_jester", name: "Prismatic Jester", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "..Q.Q.Q.Q..", "Q..A.A.A..Q", ".Q.A.A.A.Q.", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF0000", Q: "#0000FF" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF", "#FF00FF", "#00FFFF"], fps: 15 } },
196
- { id: "aurora_helm", name: "Aurora Helm", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...QQQQQ...", "...QQQQQ...", "..AAAAAAA..", "..AAAAAAA..", "..AQAAAQA..", "..AQAAAQA.."], colors: { A: "#00CED1", Q: "#00FF7F" }, animation: { type: "cycle", frames: ["#0000FF", "#0066FF", "#00BFFF", "#00CED1", "#00FF7F", "#7CFC00", "#00FF7F", "#00CED1"], fps: 4 } }
192
+ { id: "rainbow_crown", name: "Rainbow Crown", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", ".....A.....", "....AAA....", "....AQA....", "....AAA....", "...AAQAA...", "...AAAAA...", "..AAAQAAA..", "..AAAAAAA.."], colors: { A: "#FFD700", Q: "#553f3f" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF"], fps: 8 }, rollable: true },
193
+ { id: "inferno_cap", name: "Inferno Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "....AAA....", "...AAAAA...", "....AAA....", ".....Q.....", "A....Q....A", "A...QQQ...A", ".A..QQQ..A.", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF4500", Q: "#FFD700" }, animation: { type: "cycle", frames: ["#FF0000", "#FF2200", "#FF4500", "#FF6600", "#FF8C00", "#FFA500"], fps: 12 }, rollable: true },
194
+ { id: "void_hood", name: "Void Hood", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...AAA.....", "..AAAAAA...", ".AAAAAAA...", ".AAAAAAAA..", "AAAAAAAAA..", "AAAAQQQAA..", "AAAAQQQAA.."], colors: { A: "#1A0033", Q: "#d9cfe3" }, animation: { type: "cycle", frames: ["#0D0019", "#1A0033", "#2D004D", "#3D0066", "#2D004D", "#1A0033"], fps: 3 }, rollable: true },
195
+ { id: "prismatic_jester", name: "Prismatic Jester", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "..Q.Q.Q.Q..", "Q..A.A.A..Q", ".Q.A.A.A.Q.", "..AQAQAQA..", "..AQAQAQA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA..", "..AAAAAAA.."], colors: { A: "#FF0000", Q: "#0000FF" }, animation: { type: "cycle", frames: ["#FF0000", "#FF7F00", "#FFFF00", "#00FF00", "#0000FF", "#8B00FF", "#FF00FF", "#00FFFF"], fps: 15 }, rollable: true },
196
+ { id: "aurora_helm", name: "Aurora Helm", rarity: "legendary", width: 11, anchor_x: 23, rows: ["...........", "...........", "...........", "...........", "...QQQQQ...", "...QQQQQ...", "..AAAAAAA..", "..AAAAAAA..", "..AQAAAQA..", "..AQAAAQA.."], colors: { A: "#00CED1", Q: "#00FF7F" }, animation: { type: "cycle", frames: ["#0000FF", "#0066FF", "#00BFFF", "#00CED1", "#00FF7F", "#7CFC00", "#00FF7F", "#00CED1"], fps: 4 }, rollable: true },
197
+ // Claim-only: awarded by an admin, never from a roll. Only the A channel cycles,
198
+ // so the inset motif shifts colour while the cap body stays a static rust brown.
199
+ // The body colour is kept out of the frame list so the motif never merges into it.
200
+ { id: "contributor_cap", name: "Contributor Cap", rarity: "legendary", width: 11, anchor_x: 23, rows: [".....Q.....", "....QQQ....", "...QQQQQ...", "..QAAAQQQ..", "..QQAQQQQ..", ".QQQAQAAQQ.", ".QQQAQAQAQ.", ".QQQQQAQAQ.", ".QQQQQAAQQ.", ".QQQQQQQQQ."], colors: { A: "#21138b", Q: "#6f2801" }, animation: { type: "cycle", frames: ["#FF8C42", "#E0457B", "#8B5CF6", "#3B82F6", "#22D3EE", "#34D399", "#A3E635", "#FBBF24"], fps: 6 }, rollable: false }
197
201
  ];
198
202
 
199
203
  // ../shared/dist/series-transform.js
@@ -821,8 +825,8 @@ var HEARTBEAT_RETRY_DELAYS_MS = [1e3, 2e3, 4e3, 8e3, 15e3];
821
825
  // src/version.ts
822
826
  import { createRequire } from "module";
823
827
  function readVersion() {
824
- if ("2.13.0".length > 0) {
825
- return "2.13.0";
828
+ if ("2.13.1".length > 0) {
829
+ return "2.13.1";
826
830
  }
827
831
  try {
828
832
  const req = createRequire(import.meta.url);
@@ -1024,6 +1028,12 @@ function equipHat(stableHorseId, body) {
1024
1028
  function createWebSession() {
1025
1029
  return request("POST", "/web-sessions", void 0, void 0);
1026
1030
  }
1031
+ function probeClaim(code) {
1032
+ return request("GET", `/claims/${encodeURIComponent(code)}`, void 0, void 0);
1033
+ }
1034
+ function redeemClaim(code, body) {
1035
+ return request("POST", `/claims/${encodeURIComponent(code)}/redeem`, body, void 0);
1036
+ }
1027
1037
 
1028
1038
  // src/commands/stable-create.ts
1029
1039
  async function stableCreateCommand() {
@@ -1163,7 +1173,7 @@ import { render as render3 } from "ink";
1163
1173
  import { useState as useState3 } from "react";
1164
1174
  import { Box as Box5, Text as Text5, useInput as useInput2 } from "ink";
1165
1175
  import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
1166
- function HorsePicker({ horses, onPick, onCancel }) {
1176
+ function HorsePicker({ horses, onPick, onCancel, prompt = "Pick a horse to race:" }) {
1167
1177
  const [idx, setIdx] = useState3(0);
1168
1178
  useInput2((input, key) => {
1169
1179
  if (key.escape) {
@@ -1191,7 +1201,7 @@ function HorsePicker({ horses, onPick, onCancel }) {
1191
1201
  ] });
1192
1202
  }
1193
1203
  return /* @__PURE__ */ jsxs3(Box5, { flexDirection: "column", children: [
1194
- /* @__PURE__ */ jsx5(Text5, { children: "Pick a horse to race:" }),
1204
+ /* @__PURE__ */ jsx5(Text5, { children: prompt }),
1195
1205
  horses.map((h, i) => /* @__PURE__ */ jsxs3(Box5, { flexDirection: "column", children: [
1196
1206
  /* @__PURE__ */ jsx5(Box5, { flexDirection: "row", children: /* @__PURE__ */ jsxs3(Text5, { children: [
1197
1207
  i === idx ? "\u25BA" : " ",
@@ -2789,30 +2799,108 @@ function runNpmUpgrade(spawnImpl) {
2789
2799
  }
2790
2800
 
2791
2801
  // src/commands/roll.ts
2802
+ import React14 from "react";
2803
+ import { render as render6 } from "ink";
2804
+
2805
+ // src/ui/RollHorsePicker.tsx
2806
+ import { useState as useState6 } from "react";
2807
+ import { Box as Box9, Text as Text9, useInput as useInput4 } from "ink";
2808
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
2809
+ function RollHorsePicker({ horses, onPick, onCancel }) {
2810
+ const [idx, setIdx] = useState6(0);
2811
+ useInput4((input, key) => {
2812
+ if (key.escape) {
2813
+ onCancel();
2814
+ return;
2815
+ }
2816
+ if (horses.length === 0) return;
2817
+ if (key.upArrow) {
2818
+ setIdx((idx - 1 + horses.length) % horses.length);
2819
+ return;
2820
+ }
2821
+ if (key.downArrow) {
2822
+ setIdx((idx + 1) % horses.length);
2823
+ return;
2824
+ }
2825
+ if (key.return) {
2826
+ onPick(horses[idx]);
2827
+ return;
2828
+ }
2829
+ });
2830
+ return /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", children: [
2831
+ /* @__PURE__ */ jsx9(Text9, { children: "Pick a horse to roll for:" }),
2832
+ horses.map((h, i) => /* @__PURE__ */ jsxs7(Box9, { flexDirection: "column", children: [
2833
+ /* @__PURE__ */ jsx9(Box9, { flexDirection: "row", children: /* @__PURE__ */ jsxs7(Text9, { children: [
2834
+ i === idx ? "\u25BA" : " ",
2835
+ " ",
2836
+ h.name,
2837
+ " ",
2838
+ /* @__PURE__ */ jsxs7(Text9, { color: "cyan", children: [
2839
+ "[Lvl. ",
2840
+ levelFromXp(h.xp),
2841
+ "]"
2842
+ ] }),
2843
+ " ",
2844
+ /* @__PURE__ */ jsxs7(Text9, { color: "yellow", children: [
2845
+ "\u2014 ",
2846
+ h.pending,
2847
+ " roll",
2848
+ h.pending === 1 ? "" : "s"
2849
+ ] })
2850
+ ] }) }),
2851
+ /* @__PURE__ */ jsxs7(Box9, { flexDirection: "row", children: [
2852
+ /* @__PURE__ */ jsx9(Text9, { children: " " }),
2853
+ /* @__PURE__ */ jsx9(HorseSprite, { sprite: MINI_SPRITE, colors: h.colors })
2854
+ ] })
2855
+ ] }, h.stable_horse_id)),
2856
+ /* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { dimColor: true, children: "\u2191/\u2193 choose \xB7 Enter pick \xB7 Esc cancel" }) })
2857
+ ] });
2858
+ }
2859
+
2860
+ // src/ui/prompt.ts
2861
+ async function promptYesNo(question) {
2862
+ resetStdinAfterInk();
2863
+ const readline6 = await import("readline/promises");
2864
+ const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
2865
+ const a = (await rl.question(question)).trim().toLowerCase();
2866
+ rl.close();
2867
+ return a === "" || a === "y" || a === "yes";
2868
+ }
2869
+ function resetStdinAfterInk() {
2870
+ if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
2871
+ process.stdin.setRawMode(false);
2872
+ }
2873
+ while (process.stdin.read() !== null) {
2874
+ }
2875
+ process.stdin.pause();
2876
+ process.stdin.ref();
2877
+ }
2878
+
2879
+ // src/ui/reveal.ts
2792
2880
  import React13 from "react";
2793
2881
  import { render as render5 } from "ink";
2794
2882
 
2795
2883
  // src/ui/RollReveal.tsx
2796
- import { useState as useState7, useEffect as useEffect4, useMemo } from "react";
2797
- import { Box as Box10, Text as Text10 } from "ink";
2884
+ import { useState as useState8, useEffect as useEffect4, useMemo } from "react";
2885
+ import { Box as Box11, Text as Text11 } from "ink";
2798
2886
 
2799
2887
  // src/ui/HatSprite.tsx
2800
- import { useEffect as useEffect3, useState as useState6 } from "react";
2801
- import { Box as Box9, Text as Text9 } from "ink";
2802
- import { jsx as jsx9 } from "react/jsx-runtime";
2888
+ import { useEffect as useEffect3, useState as useState7 } from "react";
2889
+ import { Box as Box10, Text as Text10 } from "ink";
2890
+ import { jsx as jsx10 } from "react/jsx-runtime";
2803
2891
  function HatSprite({ hat, variant, centerIn }) {
2804
2892
  const colors = hatColorsFor2(hat, variant ?? 0);
2805
2893
  const grid = makeHatGrid(hat, colors, centerIn);
2806
2894
  const lines = hexGridToHalfBlocks(grid);
2807
- return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx9(Text9, { children: line }, i)) });
2895
+ return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: lines.map((line, i) => /* @__PURE__ */ jsx10(Text10, { children: line }, i)) });
2808
2896
  }
2809
2897
  function AnimatedHatSprite({ hat, variant, centerIn }) {
2810
2898
  if (hat.rarity !== "legendary") {
2811
- return /* @__PURE__ */ jsx9(HatSprite, { hat, variant, centerIn });
2899
+ return /* @__PURE__ */ jsx10(HatSprite, { hat, variant, centerIn });
2812
2900
  }
2813
2901
  const frames = hat.animation.frames;
2814
2902
  const fps = hat.animation.fps;
2815
- const [idx, setIdx] = useState6(0);
2903
+ const [idx, setIdx] = useState7(0);
2816
2904
  useEffect3(() => {
2817
2905
  if (frames.length <= 1) return;
2818
2906
  const interval = setInterval(
@@ -2822,7 +2910,7 @@ function AnimatedHatSprite({ hat, variant, centerIn }) {
2822
2910
  return () => clearInterval(interval);
2823
2911
  }, [frames.length, fps]);
2824
2912
  const framed = { ...hat, colors: { ...hat.colors, A: frames[idx] } };
2825
- return /* @__PURE__ */ jsx9(HatSprite, { hat: framed, variant, centerIn });
2913
+ return /* @__PURE__ */ jsx10(HatSprite, { hat: framed, variant, centerIn });
2826
2914
  }
2827
2915
  function hatColorsFor2(hat, variantIdx) {
2828
2916
  if (hat.rarity === "legendary") return hat.colors;
@@ -2849,7 +2937,7 @@ function makeHatGrid(hat, colors, centerIn) {
2849
2937
  }
2850
2938
 
2851
2939
  // src/ui/RollReveal.tsx
2852
- import { jsx as jsx10 } from "react/jsx-runtime";
2940
+ import { jsx as jsx11 } from "react/jsx-runtime";
2853
2941
  var RESET3 = "\x1B[0m";
2854
2942
  var BOX_COLOR = "#E5C76B";
2855
2943
  var TIER_PALETTE = {
@@ -2918,7 +3006,7 @@ var BOX_EMPTY = [
2918
3006
  ""
2919
3007
  ].map(pad);
2920
3008
  function GiftBox({ frame, color }) {
2921
- return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: frame.map((line, i) => /* @__PURE__ */ jsx10(Text10, { children: line ? ansiFg(color) + line + RESET3 : line }, i)) });
3009
+ return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: frame.map((line, i) => /* @__PURE__ */ jsx11(Text11, { children: line ? ansiFg(color) + line + RESET3 : line }, i)) });
2922
3010
  }
2923
3011
  function spawnParticles(tier, count, cx, cy) {
2924
3012
  const palette = TIER_PALETTE[tier];
@@ -2941,7 +3029,7 @@ function ConfettiBurst({ tier }) {
2941
3029
  const cx = Math.floor(SCENE_W / 2);
2942
3030
  const cy = Math.floor(SCENE_H / 2);
2943
3031
  const particles = useMemo(() => spawnParticles(tier, 36, cx, cy), [tier, cx, cy]);
2944
- const [tick, setTick] = useState7(0);
3032
+ const [tick, setTick] = useState8(0);
2945
3033
  useEffect4(() => {
2946
3034
  const i = setInterval(() => setTick((t) => t + 1), 70);
2947
3035
  return () => clearInterval(i);
@@ -2954,13 +3042,13 @@ function ConfettiBurst({ tier }) {
2954
3042
  grid[y][x] = ansiFg(p.color) + p.char + RESET3;
2955
3043
  }
2956
3044
  }
2957
- return /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx10(Text10, { children: row.join("") }, y)) });
3045
+ return /* @__PURE__ */ jsx11(Box11, { flexDirection: "column", children: grid.map((row, y) => /* @__PURE__ */ jsx11(Text11, { children: row.join("") }, y)) });
2958
3046
  }
2959
3047
  var CLOSED_HOLD_MS = 3e3;
2960
3048
  function RollReveal({ outcome, onDone }) {
2961
3049
  const isNoHat = outcome.kind === "no_hat";
2962
3050
  const isLegendary = outcome.kind !== "no_hat" && outcome.hat.rarity === "legendary";
2963
- const [phase, setPhase] = useState7("closed");
3051
+ const [phase, setPhase] = useState8("closed");
2964
3052
  useEffect4(() => {
2965
3053
  const timers = [];
2966
3054
  timers.push(setTimeout(() => setPhase("open1"), CLOSED_HOLD_MS));
@@ -2975,95 +3063,18 @@ function RollReveal({ outcome, onDone }) {
2975
3063
  }
2976
3064
  return () => timers.forEach(clearTimeout);
2977
3065
  }, [isNoHat, isLegendary, onDone]);
2978
- if (phase === "closed") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_CLOSED, color: BOX_COLOR });
2979
- if (phase === "open1") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_OPENING_1, color: BOX_COLOR });
2980
- if (phase === "open2") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_OPENING_2, color: BOX_COLOR });
2981
- if (phase === "empty") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
3066
+ if (phase === "closed") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_CLOSED, color: BOX_COLOR });
3067
+ if (phase === "open1") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_OPENING_1, color: BOX_COLOR });
3068
+ if (phase === "open2") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_OPENING_2, color: BOX_COLOR });
3069
+ if (phase === "empty") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
2982
3070
  if (phase === "burst" && outcome.kind !== "no_hat") {
2983
- return /* @__PURE__ */ jsx10(ConfettiBurst, { tier: outcome.hat.rarity });
3071
+ return /* @__PURE__ */ jsx11(ConfettiBurst, { tier: outcome.hat.rarity });
2984
3072
  }
2985
- if (outcome.kind === "no_hat") return /* @__PURE__ */ jsx10(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
2986
- return outcome.hat.rarity === "legendary" ? /* @__PURE__ */ jsx10(AnimatedHatSprite, { hat: outcome.hat, centerIn: { w: SCENE_W, h: SCENE_H } }) : /* @__PURE__ */ jsx10(HatSprite, { hat: outcome.hat, variant: outcome.variant, centerIn: { w: SCENE_W, h: SCENE_H } });
2987
- }
2988
-
2989
- // src/ui/RollHorsePicker.tsx
2990
- import { useState as useState8 } from "react";
2991
- import { Box as Box11, Text as Text11, useInput as useInput4 } from "ink";
2992
- import { jsx as jsx11, jsxs as jsxs7 } from "react/jsx-runtime";
2993
- function RollHorsePicker({ horses, onPick, onCancel }) {
2994
- const [idx, setIdx] = useState8(0);
2995
- useInput4((input, key) => {
2996
- if (key.escape) {
2997
- onCancel();
2998
- return;
2999
- }
3000
- if (horses.length === 0) return;
3001
- if (key.upArrow) {
3002
- setIdx((idx - 1 + horses.length) % horses.length);
3003
- return;
3004
- }
3005
- if (key.downArrow) {
3006
- setIdx((idx + 1) % horses.length);
3007
- return;
3008
- }
3009
- if (key.return) {
3010
- onPick(horses[idx]);
3011
- return;
3012
- }
3013
- });
3014
- return /* @__PURE__ */ jsxs7(Box11, { flexDirection: "column", children: [
3015
- /* @__PURE__ */ jsx11(Text11, { children: "Pick a horse to roll for:" }),
3016
- horses.map((h, i) => /* @__PURE__ */ jsxs7(Box11, { flexDirection: "column", children: [
3017
- /* @__PURE__ */ jsx11(Box11, { flexDirection: "row", children: /* @__PURE__ */ jsxs7(Text11, { children: [
3018
- i === idx ? "\u25BA" : " ",
3019
- " ",
3020
- h.name,
3021
- " ",
3022
- /* @__PURE__ */ jsxs7(Text11, { color: "cyan", children: [
3023
- "[Lvl. ",
3024
- levelFromXp(h.xp),
3025
- "]"
3026
- ] }),
3027
- " ",
3028
- /* @__PURE__ */ jsxs7(Text11, { color: "yellow", children: [
3029
- "\u2014 ",
3030
- h.pending,
3031
- " roll",
3032
- h.pending === 1 ? "" : "s"
3033
- ] })
3034
- ] }) }),
3035
- /* @__PURE__ */ jsxs7(Box11, { flexDirection: "row", children: [
3036
- /* @__PURE__ */ jsx11(Text11, { children: " " }),
3037
- /* @__PURE__ */ jsx11(HorseSprite, { sprite: MINI_SPRITE, colors: h.colors })
3038
- ] })
3039
- ] }, h.stable_horse_id)),
3040
- /* @__PURE__ */ jsx11(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx11(Text11, { dimColor: true, children: "\u2191/\u2193 choose \xB7 Enter pick \xB7 Esc cancel" }) })
3041
- ] });
3073
+ if (outcome.kind === "no_hat") return /* @__PURE__ */ jsx11(GiftBox, { frame: BOX_EMPTY, color: BOX_COLOR });
3074
+ return outcome.hat.rarity === "legendary" ? /* @__PURE__ */ jsx11(AnimatedHatSprite, { hat: outcome.hat, centerIn: { w: SCENE_W, h: SCENE_H } }) : /* @__PURE__ */ jsx11(HatSprite, { hat: outcome.hat, variant: outcome.variant, centerIn: { w: SCENE_W, h: SCENE_H } });
3042
3075
  }
3043
3076
 
3044
- // src/commands/roll.ts
3045
- function pendingFor(horse) {
3046
- const level = levelFromXp(horse.xp);
3047
- const lastRolled = horse.last_rolled_level ?? Math.max(1, level - 1);
3048
- return level - lastRolled;
3049
- }
3050
- async function promptYesNo(question) {
3051
- resetStdinAfterInk();
3052
- const readline6 = await import("readline/promises");
3053
- const rl = readline6.createInterface({ input: process.stdin, output: process.stdout });
3054
- const a = (await rl.question(question)).trim().toLowerCase();
3055
- rl.close();
3056
- return a === "" || a === "y" || a === "yes";
3057
- }
3058
- function resetStdinAfterInk() {
3059
- if (process.stdin.isTTY && typeof process.stdin.setRawMode === "function") {
3060
- process.stdin.setRawMode(false);
3061
- }
3062
- while (process.stdin.read() !== null) {
3063
- }
3064
- process.stdin.pause();
3065
- process.stdin.ref();
3066
- }
3077
+ // src/ui/reveal.ts
3067
3078
  async function runReveal(outcome) {
3068
3079
  await new Promise((resolve) => {
3069
3080
  const app = render5(React13.createElement(RollReveal, {
@@ -3075,6 +3086,13 @@ async function runReveal(outcome) {
3075
3086
  }));
3076
3087
  });
3077
3088
  }
3089
+
3090
+ // src/commands/roll.ts
3091
+ function pendingFor(horse) {
3092
+ const level = levelFromXp(horse.xp);
3093
+ const lastRolled = horse.last_rolled_level ?? Math.max(1, level - 1);
3094
+ return level - lastRolled;
3095
+ }
3078
3096
  async function rollCommand() {
3079
3097
  let stable;
3080
3098
  try {
@@ -3092,7 +3110,7 @@ async function rollCommand() {
3092
3110
  return 0;
3093
3111
  }
3094
3112
  const picked = await new Promise((resolve) => {
3095
- const app = render5(React13.createElement(RollHorsePicker, {
3113
+ const app = render6(React14.createElement(RollHorsePicker, {
3096
3114
  horses: eligible,
3097
3115
  onPick: (h) => {
3098
3116
  app.unmount();
@@ -3174,6 +3192,105 @@ No hat this time. +${result.xp_awarded} XP toward your next level.
3174
3192
  }
3175
3193
  }
3176
3194
 
3195
+ // src/commands/claim.ts
3196
+ import React15 from "react";
3197
+ import { render as render7 } from "ink";
3198
+ async function claimCommand(token) {
3199
+ if (!token) {
3200
+ console.error("Usage: token-derby claim <token>");
3201
+ return 2;
3202
+ }
3203
+ try {
3204
+ await probeClaim(token);
3205
+ } catch (e) {
3206
+ if (e instanceof ApiError) {
3207
+ console.error(`Error: ${e.code} ${e.message}`);
3208
+ return 1;
3209
+ }
3210
+ throw e;
3211
+ }
3212
+ let stable;
3213
+ try {
3214
+ stable = await listStable();
3215
+ } catch (e) {
3216
+ if (e instanceof ApiError) {
3217
+ console.error(`Error: ${e.code} ${e.message}`);
3218
+ return 1;
3219
+ }
3220
+ throw e;
3221
+ }
3222
+ if (stable.horses.length === 0) {
3223
+ console.error("No horses in your stable. Run `token-derby stable create` first.");
3224
+ return 1;
3225
+ }
3226
+ console.log("\n\u{1F381} A cosmetic has been awarded to you.\n");
3227
+ const picked = await new Promise((resolve) => {
3228
+ const app = render7(React15.createElement(HorsePicker, {
3229
+ horses: stable.horses,
3230
+ prompt: "Which horse should receive it?",
3231
+ onPick: (h) => {
3232
+ app.unmount();
3233
+ resolve(h);
3234
+ },
3235
+ onCancel: () => {
3236
+ app.unmount();
3237
+ resolve(null);
3238
+ }
3239
+ }));
3240
+ });
3241
+ if (!picked) {
3242
+ console.log("Cancelled. Your token is unspent.");
3243
+ return 0;
3244
+ }
3245
+ let result;
3246
+ try {
3247
+ result = await redeemClaim(token, { stable_horse_id: picked.stable_horse_id });
3248
+ } catch (e) {
3249
+ if (e instanceof ApiError) {
3250
+ console.error(`Error: ${e.code} ${e.message}`);
3251
+ return 1;
3252
+ }
3253
+ throw e;
3254
+ }
3255
+ const outcome = (() => {
3256
+ if (result.result === "hat") {
3257
+ const hat3 = hatById(result.collected.id);
3258
+ return hat3 ? { kind: "hat", hat: hat3, variant: result.collected.variant } : null;
3259
+ }
3260
+ const hat2 = hatById(result.hat_id);
3261
+ return hat2 ? { kind: "duplicate", hat: hat2, variant: result.variant } : null;
3262
+ })();
3263
+ if (!outcome) {
3264
+ console.error("Server returned an unknown hat id \u2014 catalog mismatch.");
3265
+ return 1;
3266
+ }
3267
+ await runReveal(outcome);
3268
+ if (result.result === "hat") {
3269
+ const hat2 = hatById(result.collected.id);
3270
+ const variantSuffix2 = hat2.rarity !== "legendary" && result.collected.variant !== void 0 ? ` #${result.collected.variant + 1}` : "";
3271
+ console.log(`
3272
+ \u2728 ${hat2.name}${variantSuffix2} [${hat2.rarity.toUpperCase()}]
3273
+ `);
3274
+ if (await promptYesNo("Equip now? [Y/n] ")) {
3275
+ try {
3276
+ await equipHat(picked.stable_horse_id, { hat_index: result.hat_index });
3277
+ console.log(`Equipped on ${picked.name}.`);
3278
+ } catch (e) {
3279
+ if (e instanceof ApiError) {
3280
+ console.error(`Equip failed: ${e.code} ${e.message}`);
3281
+ } else throw e;
3282
+ }
3283
+ }
3284
+ return 0;
3285
+ }
3286
+ const hat = hatById(result.hat_id);
3287
+ const variantSuffix = result.variant !== void 0 ? ` #${result.variant + 1}` : "";
3288
+ console.log(`
3289
+ ${picked.name} already has ${hat?.name ?? result.hat_id}${variantSuffix}. +${result.xp_awarded} XP.
3290
+ `);
3291
+ return 0;
3292
+ }
3293
+
3177
3294
  // src/commands/org-join.ts
3178
3295
  async function orgJoinCommand(token) {
3179
3296
  if (!token) {
@@ -3299,6 +3416,8 @@ Races:
3299
3416
  Cosmetics:
3300
3417
  token-derby roll Spend a pending roll to try for a hat.
3301
3418
  Earn rolls by leveling up horses.
3419
+ token-derby claim <token> Redeem a claim token for a cosmetic
3420
+ awarded to you by an admin.
3302
3421
 
3303
3422
  Environment:
3304
3423
  token-derby env Show the active environment (prod|staging)
@@ -3354,6 +3473,7 @@ async function main() {
3354
3473
  if (cmd === "join") return joinCommand(argv[1], argv.slice(2));
3355
3474
  if (cmd === "end") return endCommand(argv[1]);
3356
3475
  if (cmd === "roll") return rollCommand();
3476
+ if (cmd === "claim") return claimCommand(argv[1]);
3357
3477
  if (cmd === "web") return webCommand();
3358
3478
  console.error(`Unknown command: ${cmd}`);
3359
3479
  console.error(HELP);