Retro-style boot splash screen for Micronuts, featuring the official Cashu nut logo in a tiled grid with alternating row-scrolling animation.
At boot, the display fills with a repeating grid of Cashu nut logos. Every other row scrolls in the opposite direction, creating a retro parallax / raster-style visual. Three distinct variants cycle every 3 seconds. Touch anywhere to exit the splash and continue into the normal firmware UI.
The official Cashu nut logo is vendored from the cashubtc/docs.cashu.space repository:
- Source file:
public/homepage/nut-logo.png - Vendored copy:
firmware/assets/nut-logo-original.png(707×809 RGBA) - License: Used with attribution per the Cashu project
The logo is not modified in any way — no recoloring, no anti-aliasing, no redesign. All resizing is done offline using nearest-neighbor interpolation to preserve pixel crispness.
From the original 707×809 logo, four tile masters are generated at different sizes:
| Name | Size | Use case |
|---|---|---|
| tiny | 21×24 | Dense grid, Variant A |
| small | 35×40 | Available for custom variants |
| medium | 56×64 | Brick layout, Variant B |
| large | 84×96 | Large logos, Variant C |
scripts/generate_assets.pyreadsfirmware/assets/nut-logo-original.png- Resizes to each target height using nearest-neighbor only (no smoothing)
- Composites the transparent logo onto black background
- Converts to RGB565 format (16-bit, little-endian)
- Writes:
- PNG masters →
firmware/assets/generated/nut-{size}.png - RGB565 binary →
firmware/assets/generated/nut-{size}.rgb565 - Rust source →
firmware/src/boot_splash_assets.rs
- PNG masters →
pip install Pillow
python3 scripts/generate_assets.pyThe generated boot_splash_assets.rs is checked into the repo so that normal firmware builds do not require Python or internet access.
- Tile: tiny (21×24)
- Speed: 3 px/frame
- Layout: Regular grid, tight spacing
- Feel: Fast retro wallpaper, dense texture
- Tile: medium (56×64)
- Speed: 2 px/frame (odd rows +1 px/frame extra)
- Layout: Brick stagger (odd rows offset by half a tile)
- Feel: Arcade title-card, brick-wall pattern
- Tile: large (84×96)
- Speed: 1 px/frame
- Layout: Regular grid, 8px per-row phase offset
- Feel: Slow, gentle wave motion, more breathing room
All variants share:
- Alternating row directions (even→right, odd→left)
- Seamless wraparound scrolling
- Black background, pixel-perfect 1:1 rendering
- ~30 FPS frame pacing
Edit the VARIANTS array in firmware/src/boot_splash.rs:
VariantConfig {
tile_index: 0, // Index into TILE_CATALOG (0=tiny, 1=small, 2=medium, 3=large)
speed: 3, // Pixels per frame (base speed for even rows)
brick_stagger: false, // Half-tile offset on odd rows
odd_row_speed_delta: 0, // Extra speed for odd rows
row_phase_step: 0, // Per-row phase offset in pixels (wave effect)
extra_gap: 0, // Additional gap between tiles (added to base 2px)
}VARIANT_DURATION_FRAMES: Frames per variant (default: 90 = 3 seconds at 30 FPS)TILE_GAP: Base gap between tiles (default: 2 pixels)- Frame pacing:
delay.delay_ms(33u32)inmain.rs(~30 FPS)
- Edit
TILE_CATALOGinscripts/generate_assets.py - Re-run
python3 scripts/generate_assets.py - Reference the new tile by index in your variant config
- Increase
NUM_VARIANTSinboot_splash.rs - Add a new
VariantConfigto theVARIANTSarray - Add the corresponding font glyph in
render_variant_indicator
- Tap anywhere: Exit splash immediately, continue boot
- Touch failure: If the FT6X06 controller doesn't initialize, the splash still runs with timeout-only exit (no brick)
- Auto-exit: After 2 full variant cycles (~18 seconds), the splash exits automatically
firmware/src/
├── boot_splash.rs # Animation engine (render_frame, blit_tile, state management)
├── boot_splash_assets.rs # Generated RGB565 tile data (const arrays)
├── main.rs # Integration point (splash loop before main loop)
└── lib.rs # Module declarations
firmware/assets/
├── nut-logo-original.png # Vendored official Cashu nut logo
├── generated/
│ ├── nut-tiny.png # 21×24 tile master
│ ├── nut-small.png # 35×40 tile master
│ ├── nut-medium.png # 56×64 tile master
│ ├── nut-large.png # 84×96 tile master
│ └── *.rgb565 # Binary RGB565 data (intermediate)
└── preview/
├── boot-splash-preview.gif # Animated preview
├── boot-splash-composite.png # All variants side by side
├── boot-splash-screenshot.png # Single screenshot for README
└── variant_*_frame_*.png # Key frames per variant
scripts/
├── generate_assets.py # Offline tile master generation
└── render_preview.py # Host-side preview renderer
The splash is parameterized by (width, height) passed to render_frame(). To adapt for a different display:
- Generate tile sizes appropriate for the new resolution
- Adjust
tile_indexin each variant's config - The rendering loop automatically adapts to fill any display size
To generate preview images locally:
pip install Pillow
python3 scripts/generate_assets.py # if not already done
python3 scripts/render_preview.pyOutput goes to firmware/assets/preview/. The CI workflow also generates these as artifacts on every push that touches splash-related files.