Add brightness option and run/dry wrapper scripts

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
April John 2026-10-16 14:38:55 +02:00
commit 0ff391bfa1
5 changed files with 38 additions and 6 deletions

View file

@ -11,7 +11,9 @@ stairs show. On exit it sends a black frame. The stairs power must be on
nix-shell --run "python treppe_gl.py shaders/flow.glsl"
nix-shell --run "python treppe_gl.py shaders/pulse.glsl --dry-run"
Options: `--host`, `--port`, `--fps`, `--dry-run` (send nothing),
Wrappers: `./treppe-run.sh <shader> [brightness]` and `./treppe-dry.sh <shader> [brightness]` (dry run, nothing is sent).
Options: `--brightness 0-100` (scales output, default 100), `--host`, `--port`, `--fps`, `--dry-run` (send nothing),
`--no-window` (headless), `--white {extract,alpha,off}`.
Shaders define `mainImage(out vec4 fragColor, in vec2 fragCoord)` and may

View file

@ -59,3 +59,12 @@ def test_udp_loopback():
tx = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
tx.sendto(t.BLACK_FRAME, rx.getsockname())
assert rx.recv(2048) == t.BLACK_FRAME
def test_brightness_scales_and_clamps():
px = np.array([[1.0, 0.5, 0.25, 1.0]] + [[0, 0, 0, 0]] * 15)
half = t.to_rgbw(px, "extract", 50)[0]
np.testing.assert_allclose(half, [0.375, 0.125, 0.0, 0.125])
assert t.to_rgbw(px, "extract", 0).max() == 0
np.testing.assert_allclose(t.to_rgbw(px, "extract", 500),
t.to_rgbw(px, "extract", 100))

8
treppe-dry.sh Executable file
View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Usage: treppe-dry.sh <shader.glsl> [brightness 0-100, default 100]
set -euo pipefail
here=$(dirname "$(realpath "$0")")
[ $# -ge 1 ] || { echo "usage: $0 <shader.glsl> [brightness 0-100]" >&2; exit 2; }
shader=$(realpath "$1")
cd "$here"
exec nix-shell --run "python treppe_gl.py '$shader' --brightness ${2:-100} --dry-run"

8
treppe-run.sh Executable file
View file

@ -0,0 +1,8 @@
#!/usr/bin/env bash
# Usage: treppe-run.sh <shader.glsl> [brightness 0-100, default 100]
set -euo pipefail
here=$(dirname "$(realpath "$0")")
[ $# -ge 1 ] || { echo "usage: $0 <shader.glsl> [brightness 0-100]" >&2; exit 2; }
shader=$(realpath "$1")
cd "$here"
exec nix-shell --run "python treppe_gl.py '$shader' --brightness ${2:-100}"

View file

@ -35,23 +35,26 @@ WHITE_MODES = ("extract", "alpha", "off")
# --- Protocol --------------------------------------------------------------
def to_rgbw(pixels, white="extract"):
def to_rgbw(pixels, white="extract", brightness=100.0):
"""
Convert float RGBA pixels (STEPS x 4, 0..1) to RGBW (STEPS x 4).
extract: w = min(r, g, b), subtracted from r, g, b
alpha: the shader's alpha channel is the white value
off: w = 0
brightness (0..100, percent) scales the result linearly.
"""
scale = np.float32(min(max(brightness, 0.0), 100.0) / 100.0)
px = np.clip(np.asarray(pixels, dtype=np.float32), 0.0, 1.0)
rgb = px[:, :3]
if white == "extract":
w = rgb.min(axis=1, keepdims=True)
return np.hstack([rgb - w, w])
return np.hstack([rgb - w, w]) * scale
if white == "alpha":
return np.hstack([rgb, px[:, 3:4]])
return np.hstack([rgb, px[:, 3:4]]) * scale
if white == "off":
return np.hstack([rgb, np.zeros((len(px), 1), dtype=np.float32)])
return np.hstack([rgb, np.zeros((len(px), 1), dtype=np.float32)]) * scale
raise ValueError("unknown white mode: {}".format(white))
@ -380,7 +383,7 @@ def run(args):
last = now
pixels = renderer.render_strip(t, dt, frame)
rgbw = to_rgbw(pixels, args.white)
rgbw = to_rgbw(pixels, args.white, args.brightness)
if sock:
sock.sendto(encode_frame(rgbw), target)
@ -414,6 +417,8 @@ def parse_args(argv=None):
p.add_argument("--port", type=int, default=PORT_DEFAULT)
p.add_argument("--fps", type=float, default=60.0)
p.add_argument("--white", choices=WHITE_MODES, default="extract")
p.add_argument("--brightness", type=float, default=100.0,
help="0..100 percent, scales what is sent (default 100)")
p.add_argument("--dry-run", action="store_true",
help="do not send anything over the network")
p.add_argument("--no-window", dest="window", action="store_false",