Files
ansible/roles/pi_slint_frontend/defaults/main.yml
Martin Bauer 2fb290b146 Build and install the native front-end on musicdolphin
slint-frontend/ in the app repo is a native front-end for the same backend, written
because the React UI is sluggish on this device. This installs it beside the web UI,
never instead of it: the systemd unit is installed but not enabled, so the device still
boots into the kiosk browser and the two can be compared on the same screen.

  systemctl start musikdelfin     # takes over the display
  systemctl stop  musikdelfin     # back to the browser underneath

Unlike pi_musicmouse, which builds the web front-end on the control machine and rsyncs
dist/, this builds on the device. A Rust binary is not portable, and the reason it has
to be built here rather than cross-compiled is worth writing down: these Pis run 32-bit
armhf Raspbian on a 64-bit kernel. `uname -m` says aarch64 and it is misleading;
`dpkg --print-architecture` says armhf and that is the one that matters. Cross-compiling
to armv7-unknown-linux-gnueabihf needs a sysroot, the devices carry no -dev packages to
build one from, and reconstructing one from the Debian archive means owning a glibc skew
risk indefinitely. Spending the device's own CPU once is the smaller liability. The
build is stamped with the commit it came from, so it only runs again when that changes.

The same fact rules out the Skia renderer that the app's own kiosk profile prefers:
rust-skia publishes no prebuilt binaries for armhf. This builds --features desktop -
winit, FemtoVG and the software renderer - and runs as an X client in the existing
session. Worth noting after the fact: the FemtoVG bug that makes Skia the upstream
recommendation (slint-ui/slint#11785, album covers drawn as solid black) was reported on
a Pi 5 with a 64-bit userland and does not reproduce here - covers render correctly.

Three things had to be found by running it rather than reading anything:

The X session belongs to `kiosk`, not root, so the launcher needs that user's cookie and
the unit runs as them. Without it winit fails with "could not initialize backend", which
says nothing about authorization.

winit and glutin dlopen every windowing and GL library they use, so none of them appear
in `ldd` and the binary links happily without them - then aborts on first run with
"Library libxkbcommon-x11.so could not be loaded". The runtime packages are listed
explicitly for that reason.

Raspbian ships no font containing the emoji the design uses as iconography, so the shelf
badges rendered as empty boxes until fonts-noto-color-emoji went in.

First build took 63 minutes: 570 crates, two jobs, nice'd, which bounds peak memory on
musicdolphin's 1.8 GB.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-21 00:44:54 +02:00

43 lines
2.3 KiB
YAML

---
# The native Slint front-end (slint-frontend/ in the app repo). Installed alongside the
# web UI, not instead of it: both talk to the same backend, so the two can be compared
# on the same screen.
# Built on the device rather than on the control machine, which is the opposite of what
# pi_musicmouse does for the web front-end - and for a reason. The Pis run 32-bit armhf
# Raspbian on a 64-bit kernel, so the target is armv7-unknown-linux-gnueabihf. Cross
# compiling to it needs a sysroot, and the device has no -dev packages to build one
# from, so the choice is between reconstructing one from the Debian archive (and
# owning a glibc-version skew risk forever) or spending the device's own CPU once.
# A rebuild only happens when the commit changes - see the stamp below.
pi_slint_frontend_toolchain: stable
# Bounds peak memory during the build. musicdolphin has 4 cores but only 1.8 GB.
pi_slint_frontend_jobs: 2
# winit + FemtoVG + the software renderer. Deliberately not Skia: rust-skia ships no
# prebuilt binaries for armhf, so `kiosk` would mean compiling Skia from source on a
# Pi, which will not finish in any reasonable time and would not fit on the disk.
pi_slint_frontend_features: desktop
# Which backend the app is served by. Same machine as the kiosk browser uses.
pi_slint_frontend_server: "http://localhost:8080"
# Where the checkout lives. Shared with pi_musicmouse, which owns the checkout itself.
pi_slint_frontend_root: /opt/musicmouse/slint-frontend
# The user the kiosk's X session belongs to - the app has to run as them to reach the
# display. pi_kiosk owns this name; repeated here as a default so the role still works
# on a host where pi_kiosk has not run.
pi_slint_frontend_x_user: "{{ pi_kiosk_user | default('kiosk') }}"
# The device is a kiosk, so the window takes the whole screen. Set false to get a
# normal window - useful while pi_kiosk_mode is "debug" and you want the browser and
# this side by side on the same display.
pi_slint_frontend_fullscreen: true
# Slint's own frame-timing readout, for measuring rather than guessing. Empty to leave
# it off; "overlay,refresh_lazy" draws the numbers on screen and only counts frames
# that were actually rendered, which is the honest measure for a UI that idles.
pi_slint_frontend_debug_performance: ""