From 212e349b192b97c7a42b278b640cca1556d8e186 Mon Sep 17 00:00:00 2001 From: archipelago Date: Mon, 17 Aug 2026 09:05:33 -0400 Subject: [PATCH] refine(wallet): the balance readout scans as one column, not a barcode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seeing it on the node settled the shape. Two rows of per-cell delays read as a dense flicker — closer to a progress bar than a display, and short enough against the row's text to look like an underline. Three rows laid out column-first fixes both: the three cells of a column now share a delay, so the lit column travels across as a single scan line, and at 11px the matrix sits with the text rather than under it. Verified in a real browser against the live node with the balance RPCs held open: five placeholders, five distinct rail colours (white, orange, yellow, purple, blue), 42 cells each, all animating, each announcing what it is waiting for — and no "0 sats" anywhere on screen while the calls were in flight. They gave way to real figures on arrival, with Lightning's genuine 0 correctly shown as a figure rather than left shimmering. Co-Authored-By: Claude Opus 5 (1M context) --- docker/lnd-ui/index.html | 10 +++--- neode-ui/src/components/BalanceAmount.vue | 35 ++++++++++++------- .../__tests__/BalanceAmount.test.ts | 12 +++++-- 3 files changed, 38 insertions(+), 19 deletions(-) diff --git a/docker/lnd-ui/index.html b/docker/lnd-ui/index.html index bc31a5ae..c5cf8da5 100644 --- a/docker/lnd-ui/index.html +++ b/docker/lnd-ui/index.html @@ -196,8 +196,8 @@ not a loading state, and it is the one number that frightens people. It inherits currentColor, so each tile shimmers in its own rail colour. */ - .bal-pixels { display: inline-grid; grid-template-columns: repeat(14, 4px); grid-auto-rows: 4px; gap: 1px; vertical-align: 0.15em; } - .bal-pixels i { width: 4px; height: 4px; border-radius: 0.5px; background: currentColor; opacity: 0.16; animation: bal-pixel-scan 1.4s ease-in-out infinite; } + .bal-pixels { display: inline-grid; grid-auto-flow: column; grid-template-rows: repeat(3, 4px); grid-auto-columns: 4px; gap: 1px; vertical-align: 0.1em; } + .bal-pixels i { width: 4px; height: 4px; border-radius: 0.5px; background: currentColor; opacity: 0.16; animation: bal-pixel-scan 1.6s ease-in-out infinite; } @keyframes bal-pixel-scan { 0%, 70%, 100% { opacity: 0.16; } 25% { opacity: 1; } 45% { opacity: 0.42; } } @media (prefers-reduced-motion: reduce) { .bal-pixels i { animation: none; opacity: 0.35; } } .bg-green { background: #4ade80; } .bg-yellow { background: #facc15; } .bg-red { background: #f87171; } @@ -1083,9 +1083,11 @@ // 28 cells = 14 columns x 2 rows, delays staggered so the lit column // travels across the matrix. + // 14 columns x 3 rows, laid out column-first so the three cells of a + // column share a delay and the lit column scans across as one line. const BAL_PIXELS = '' + - Array.from({ length: 28 }, function (_, i) { - return ''; + Array.from({ length: 42 }, function (_, i) { + return ''; }).join('') + ''; // Render a balance, or the pixel readout when it is not known yet. diff --git a/neode-ui/src/components/BalanceAmount.vue b/neode-ui/src/components/BalanceAmount.vue index ae8bf6c7..caaf3cb2 100644 --- a/neode-ui/src/components/BalanceAmount.vue +++ b/neode-ui/src/components/BalanceAmount.vue @@ -34,9 +34,18 @@ const props = withDefaults( { suffix: 'sats', label: 'balance' }, ) -// 14 columns × 2 rows. Enough to read as a matrix rather than a spinner, and -// close to the width of a five-figure sat amount. -const CELLS = 28 +// 14 columns × 3 rows, laid out column-first so all three cells of a column +// share a delay and the lit column travels across as a single scan line — +// that is what makes it read as a readout rather than a progress bar. +const COLUMNS = 14 +const ROWS = 3 +const CELLS = COLUMNS * ROWS +const STEP_MS = 55 + +/** Delay for cell `i` (1-based), constant within a column. */ +function cellDelay(i: number): string { + return `${Math.floor((i - 1) / ROWS) * STEP_MS}ms` +} /** * Built as one string rather than interpolated around a ` @@ -67,12 +76,15 @@ const display = computed(() => {