Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Changelog 26.05.0 - May 2025

### Stackbit 1248 Vertical Layout
Added vertical layout option for Stackbit 1248 backup display, allowing users to choose between Standard (horizontal) and Vertical (transposed) grid orientations.

### Migrate UR encoding to uUR MicroPython C module
Switch from the pure-Python urtypes and foundation-ur-py packages to the new uUR C module, allowing faster UR QR codes decoding with a smaller RAM footprint.

Expand Down
6 changes: 5 additions & 1 deletion docs/getting-started/usage/navigating-the-main-menu.en.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,11 +96,15 @@ Display the BIP39 mnemonic word numbers (1-2048) in decimal, hex, or octal forma

<img src="../../../img/maixpy_m5stickv/backup-stackbit-250.png" align="right" class="m5stickv">
<img src="../../../img/maixpy_amigo/backup-stackbit-300.png" align="right" class="amigo">

This metal backup format represents the BIP39 mnemonic word's numbers (1-2048). Each of the four digits is converted to a sum of 1, 2, 4 or 8. This option does not print even if a printer driver is set.
<div style="clear: both"></div>
<img src="../../../img/maixpy_m5stickv/backup-stackbit-vertical-250.png" align="right" class="m5stickv">
<img src="../../../img/maixpy_amigo/backup-stackbit-vertical-300.png" align="right" class="amigo">
Vertical layout transposes the grid, with rows = weights (1,2,4,8) and columns = digits.

<div style="clear: both"></div>


- **Tinyseed**

<img src="../../../img/maixpy_m5stickv/backup-tiny-seed-250.png" align="right" class="m5stickv">
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 2 additions & 0 deletions i18n/translations/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Einige Knoten sind nicht gehärtet:",
"Spend (%d):": "Ausgabe (%d):",
"Spend:": "Ausgaben:",
"Standard": "Standard",
"Standard mode": "Standardmodus",
"Static": "Statisch",
"Stats for Nerds": "Statistiken für Nerds",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Wert %S außerhalb des Bereichs: [ %s, %s]",
"Verifying…": "Überprüfung…",
"Version": "Version",
"Vertical": "Vertikal",
"Via Camera": "Via Kamera",
"Via D20": "Via D20",
"Via D6": "Via D6",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/es-MX.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Algunos nodos no están endurecidos:",
"Spend (%d):": "Gastos (%d):",
"Spend:": "Gasto:",
"Standard": "Estándar",
"Standard mode": "Modo estándar",
"Static": "Estático",
"Stats for Nerds": "Estadísticas para Entendidos",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Valor %s fuera del rango: [ %s, %s]",
"Verifying…": "Verificando…",
"Version": "Versión",
"Vertical": "Vertical",
"Via Camera": "Desde Cámara",
"Via D20": "Vía D20",
"Via D6": "Vía D6",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Certains nœuds ne sont pas durcis :",
"Spend (%d):": "Dépense (%d) :",
"Spend:": "Dépense :",
"Standard": "Standard",
"Standard mode": "Mode standard",
"Static": "Statique",
"Stats for Nerds": "Statistiques pour les geeks",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Valeur %s hors de portée: [%s, %s]",
"Verifying…": "Vérification…",
"Version": "Version",
"Vertical": "Vertical",
"Via Camera": "Par caméra",
"Via D20": "Via D20",
"Via D6": "Via D6",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/ja-JP.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "一部のノードは硬化されていません:",
"Spend (%d):": "支出(%d):",
"Spend:": "支出:",
"Standard": "標準",
"Standard mode": "標準モード",
"Static": "静止画",
"Stats for Nerds": "オタクのための統計",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "値%sが範囲外です: [ %s, %s]",
"Verifying…": "認証中…",
"Version": "バージョン",
"Vertical": "縦向き",
"Via Camera": "カメラ経由",
"Via D20": "D20経由",
"Via D6": "D6経由",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/ko-KR.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "일부 노드가 경화되지 않습니다:",
"Spend (%d):": "Spend (%d):",
"Spend:": "지출:",
"Standard": "표준",
"Standard mode": "표준 모드",
"Static": "Static",
"Stats for Nerds": "전문가를 위한 통계",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "%s는 [%s, %s] 범위를 벗어났습니다",
"Verifying…": "확인…",
"Version": "버전",
"Vertical": "세로",
"Via Camera": "카메라",
"Via D20": "20면체 주사위",
"Via D6": "일반 주사위",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/nl-NL.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Sommige knooppunten zijn niet gehard:",
"Spend (%d):": "Uitgaven (%d):",
"Spend:": "Uitgaven:",
"Standard": "Standaard",
"Standard mode": "Standaardmodus",
"Static": "Statisch",
"Stats for Nerds": "Statistieken voor nerds",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Waarde %s is buiten bereik: [%s, %s]",
"Verifying…": "Controleren…",
"Version": "Versie",
"Vertical": "Verticaal",
"Via Camera": "Via camera",
"Via D20": "Via D20",
"Via D6": "Via D6",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/pt-BR.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Alguns nós não são hardened:",
"Spend (%d):": "Gastos (%d):",
"Spend:": "Gasto:",
"Standard": "Padrão",
"Standard mode": "Modo padrão",
"Static": "Estático",
"Stats for Nerds": "Estatísticas para nerds",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Valor %s fora do intervalo: [%s, %s]",
"Verifying…": "Checando…",
"Version": "Versão",
"Vertical": "Vertical",
"Via Camera": "Pela Câmera",
"Via D20": "Via D20",
"Via D6": "Via D6",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/ru-RU.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Некоторые узлы не укреплены:",
"Spend (%d):": "Расход (%d):",
"Spend:": "Расход:",
"Standard": "Стандартный",
"Standard mode": "Стандартный режим",
"Static": "Static / Статическое оборудование",
"Stats for Nerds": "Статистика для Гиков",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Значение %s вне диапозона: [%s, %s]",
"Verifying…": "Верификация…",
"Version": "Версия",
"Vertical": "Вертикальный",
"Via Camera": "С Помощью Камеры",
"Via D20": "С Помощью D20",
"Via D6": "С Помощью D6",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/tr-TR.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Bazı düğümler sertleştirilmemiş:",
"Spend (%d):": "Harcama (%d):",
"Spend:": "Harcama:",
"Standard": "Standart",
"Standard mode": "Standart Mod",
"Static": "Statik",
"Stats for Nerds": "İnekler İçin İstatistikler",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "%s değeri aralık dışında: [%s, %s]",
"Verifying…": "Doğrulanıyor…",
"Version": "Sürüm",
"Vertical": "Dikey",
"Via Camera": "Kamera Aracılığıyla",
"Via D20": "D20 Aracılığıyla",
"Via D6": "D6 Aracılığıyla",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/vi-VN.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "Một số nút không được làm cứng:",
"Spend (%d):": "Chi tiêu (%d):",
"Spend:": "Chi tiêu:",
"Standard": "Tiêu chuẩn",
"Standard mode": "Chế độ Tiêu chuẩn",
"Static": "Tĩnh",
"Stats for Nerds": "Số liệu thống kê cho Mọt sách",
Expand Down Expand Up @@ -331,6 +332,7 @@
"Value %s out of range: [%s, %s]": "Giá trị %s ngoài phạm vi: [ %s, %s]",
"Verifying…": "Xác minh…",
"Version": "Phiên Bản",
"Vertical": "Dọc",
"Via Camera": "Qua máy ảnh",
"Via D20": "Qua xúc xắc 20 mặt",
"Via D6": "Qua xúc xắc 6 mặt",
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/zh-CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@
"Some nodes are not hardened:": "有些节点未硬化:",
"Spend (%d):": "花费 (%d):",
"Spend:": "花费",
"Standard": "标准",
"Standard mode": "标准模式",
"Static": "Static 静态?",
"Stats for Nerds": "极客统计数据",
Expand Down Expand Up @@ -330,6 +331,7 @@
"User's Data": "用户数据",
"Value %s out of range: [%s, %s]": "值 %s 超出范围:[ %s,%s ]",
"Verifying…": "验证中…",
"Vertical": "垂直",
"Version": "版本",
"Via Camera": "通过摄像头",
"Via D20": "通过 D20",
Expand Down
14 changes: 14 additions & 0 deletions simulator/sequences/home-options.txt
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,23 @@ press BUTTON_A
press BUTTON_B
press BUTTON_A

screenshot backup-stackbit-menu.png

press BUTTON_B
press BUTTON_A

screenshot backup-stackbit-vertical.png

x2 press BUTTON_A
press_amigo_only BUTTON_A
x2 press BUTTON_B
press BUTTON_A

screenshot backup-stackbit.png

x2 press BUTTON_A
x2 press BUTTON_B
press BUTTON_A
press BUTTON_B
press BUTTON_A

Expand Down
75 changes: 74 additions & 1 deletion src/krux/pages/home_pages/mnemonic_backup.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,19 @@ def display_seed_qr(self, binary=False):
return seed_qr_view.display_qr()

def stackbit(self):
"""Displays which numbers 1248 user should punch on 1248 steel card"""
"""Displays layout selection submenu for Stackbit 1248 backup"""
submenu = Menu(
self.ctx,
[
(t("Standard"), self._stackbit_standard),
(t("Vertical"), self._stackbit_vertical),
],
)
submenu.run_loop()
return MENU_CONTINUE

def _stackbit_standard(self):
"""Displays Stackbit 1248 in standard (horizontal) format — 6 words per page"""
from ..stack_1248 import Stackbit

stackbit = Stackbit(self.ctx)
Expand All @@ -198,6 +210,67 @@ def stackbit(self):
self.ctx.display.clear()
return MENU_CONTINUE

def _stackbit_vertical(self):
"""Dispatches to the grouped or minimal layout based on the current device"""
if kboard.has_minimal_display:
return self._stackbit_vertical_compact()
return self._stackbit_vertical_default()

def _stackbit_vertical_default(self):
"""Draws vertical Stackbit 1248 layout with 2 words per group, 4 words per page"""
from ..stack_1248 import Stackbit

stackbit = Stackbit(self.ctx)
words = self.ctx.wallet.key.mnemonic.split(" ")
total_words = len(words)

words_per_group = 2

groups_per_page = 2
block_h = 7 * FONT_HEIGHT + 2
group_gap = max(2, FONT_HEIGHT // 4)

word_index = 1
while word_index <= total_words:
self.ctx.display.draw_hcentered_text("Stackbit 1248")
y_offset = 2 * FONT_HEIGHT
for _ in range(groups_per_page):
if word_index > total_words:
break
group = []
for _ in range(words_per_group):
if word_index > total_words:
break
group.append((word_index, words[word_index - 1]))
word_index += 1
stackbit.export_1248_vertical_grouped(y_offset, group)
y_offset += block_h + group_gap
self.ctx.input.wait_for_button()
self.ctx.display.clear()
return MENU_CONTINUE
Comment thread
bitcoisas marked this conversation as resolved.

def _stackbit_vertical_compact(self):
"""Draws compact Stackbit 1248 layout for M5StickV, 6 words per page"""
from ..stack_1248 import Stackbit

stackbit = Stackbit(self.ctx)
words = self.ctx.wallet.key.mnemonic.split(" ")
total_words = len(words)
words_per_page = 6
word_index = 0

while word_index < total_words:
self.ctx.display.draw_hcentered_text("Stackbit 1248")
page_words = []
for _ in range(words_per_page):
if word_index < total_words:
page_words.append((word_index + 1, words[word_index]))
word_index += 1
stackbit.export_1248_vertical_compact(page_words, 2 * FONT_HEIGHT)
self.ctx.input.wait_for_button()
self.ctx.display.clear()
return MENU_CONTINUE
Comment thread
bitcoisas marked this conversation as resolved.

def tiny_seed(self):
"""Displays the seed in Tinyseed format"""
from ..tiny_seed import TinySeed
Expand Down
Loading
Loading