From 16ac004d067490be4318e030c236f0015925d8ee Mon Sep 17 00:00:00 2001 From: jim kolpack Date: Thu, 1 Oct 2026 21:57:51 -0400 Subject: [PATCH] Add a calibration test image/script for visually checking zoom cropping dev/calibration.png is a synthetic grid (concentric color rings, corner markers, a crosshair) and dev/calibration_test.star runs it through the same zoom logic as the real _art_widget, so cropping can be checked visually without depending on what a live station happens to be playing. This is what was used to find and verify the centered-zoom fix. --- README.md | 15 ++++++++++++ dev/calibration.png | Bin 0 -> 1416 bytes dev/calibration_test.star | 50 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) create mode 100644 dev/calibration.png create mode 100644 dev/calibration_test.star diff --git a/README.md b/README.md index 5472ae4..b71db3a 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,21 @@ pixlet render subwave_nowplaying.star station_url=https://your-station.example.c pixlet serve subwave_nowplaying.star ``` +`dev/calibration_test.star` renders a synthetic test grid (`dev/calibration.png` +— concentric color rings, corner markers, a crosshair) through the exact same +zoom logic as the real `_art_widget`, to visually check cropping without +depending on what a live station happens to be playing: + +``` +pixlet render dev/calibration_test.star -o calib.gif +``` + +At rest you should see a thin, *even* sliver of magenta on all four edges; +as it zooms in, each corner marker should get clipped by the same amount. +If one side loses noticeably more than the others, the zoom isn't +centered. Keep its copy of the zoom math in sync with `_art_widget` if that +ever changes. + ## Deploy Upload `subwave_nowplaying.star` directly through your Tronbyt server's diff --git a/dev/calibration.png b/dev/calibration.png new file mode 100644 index 0000000000000000000000000000000000000000..d8b0b163378d32a5bce8ff6ee8ea5051be3a0aed GIT binary patch literal 1416 zcmeAS@N?(olHy`uVBq!ia0y~yV9Wqv4kn<;*Y_)5AD&LEhV?^OzUe_Pn~_*Z71#RgLvsp$rq;To5yUbSS5;c+}Cg5 z7H6NpNf$J?FYbZdnd|!BtN;9Yd%Ujy|IMdGlF2dauRAZ>|Km^E{^R@i{n~Q>v43MX z^NAMPAU}8g0{(ON>tyyGlKu7X+i5?2`#X8od;gT|pjYstrK_CT$?ImDZBJdit#$tE z!(Vshi2XnE`*iBr1(w%ppC8}$&ief$1|#v~_8@F5CU~NBG@u)xRU-sTO8i78yE#f59xt6 p<@Qy6;X6=&>?mW(A-W)Y#z=0bZT@GtcLGaT22WQ%mvv4FO#sxDG6w(v literal 0 HcmV?d00001 diff --git a/dev/calibration_test.star b/dev/calibration_test.star new file mode 100644 index 0000000..e4c657d --- /dev/null +++ b/dev/calibration_test.star @@ -0,0 +1,50 @@ +""" +Dev tool, not part of the deployed app: renders dev/calibration.png through +the exact same zoom logic as _art_widget in subwave_nowplaying.star, so you +can visually check how much margin gets cropped at rest and at full zoom, +and whether the crop is even on all sides. + +calibration.png is a 360x360 grid: concentric 10%-wide color rings (magenta +outermost, then yellow, then cyan) plus four corner markers (red TL, green +TR, blue BL, white BR) and a center crosshair. At rest, you should see a +thin, EVEN sliver of magenta on all four edges. As it zooms in, each corner +marker should get clipped by the same amount -- if one side/corner loses +noticeably more than the others, the zoom isn't centered. + +Usage: + pixlet render dev/calibration_test.star -o calib.gif + pixlet render dev/calibration_test.star zoom_scale=1.0 -o calib_rest.gif # rest only + +Keep ART_SIZE/ART_SLOT/the zoom math below in sync with the real +_art_widget if that ever changes. +""" + +load("render.star", "render") +load("animation.star", "animation") +load("calibration.png", CALIB = "file") + +ART_SIZE = 36 +ART_SLOT = 32 +ART_ZOOM_DURATION = 200 + +def _art_widget(art_bytes, zoom_scale): + art = render.Image(src = art_bytes, width = ART_SIZE, height = ART_SIZE) + top_scale = max(zoom_scale, 1.0) + shift = (1.0 - top_scale) * (ART_SIZE / 2.0) + zoom = animation.Transformation( + child = art, + duration = ART_ZOOM_DURATION, + keyframes = [ + animation.Keyframe(percentage = 0.0, transforms = [animation.Scale(1.0, 1.0), animation.Translate(0, 0)]), + animation.Keyframe(percentage = 0.5, transforms = [animation.Scale(top_scale, top_scale), animation.Translate(shift, shift)], curve = "ease_in_out"), + animation.Keyframe(percentage = 1.0, transforms = [animation.Scale(1.0, 1.0), animation.Translate(0, 0)], curve = "ease_in_out"), + ], + ) + return render.Box(width = ART_SLOT, height = ART_SLOT, child = zoom) + +def main(config): + zoom_scale = float(config.get("zoom_scale", "1.4")) + return render.Root(child = render.Row(children = [ + _art_widget(CALIB.readall(), zoom_scale), + render.Box(width = 32, height = 32, color = "#111111"), + ]))