Skip to content

Let the screensaver pin one ttfx effect via shell.json - #11732

Open
buddha9 wants to merge 1 commit into
omacom:quattrofrom
buddha9:screensaver-fixed-effect
Open

buddha9 wants to merge 1 commit into
omacom:quattrofrom
buddha9:screensaver-fixed-effect

Conversation

@buddha9

@buddha9 buddha9 commented Sep 13, 2026

Copy link
Copy Markdown

Summary

  • The screensaver has always picked a random ttfx effect (beams, matrix, fireworks, ...) each cycle, with no way to stick to one you like.
  • Adds an optional idle.screensaverEffect key to shell.json. When set, it constrains ttfx's --random-effect selection to that one effect via --include-effects; an unrecognized name falls back to random and sends a notification saying why.
  • New hidden helper bin/omarchy-screensaver-effect resolves and validates the configured effect, kept separate from bin/omarchy-screensaver so the logic is unit-testable without touching the live screensaver loop (mirrors how IdleModel.js is split out from Service.qml).
  • Docs updated in manual/13-toggles-idle-screensaver.md, docs/omarchy-shell.md, and the bundled omarchy agent skill's plugins.md.

Test plan

  • test/shell.d/screensaver-effect-test.sh (new): unset falls back to random silently, a valid effect resolves and is passed through, an invalid effect falls back to random and notifies.
  • ./test/all run locally — no new failures (5 pre-existing failures in this sandbox are all due to a missing omarchy-pkgs checkout or environment-specific rendering/locale issues, unrelated to this change).
  • Manual check on a real Omarchy install: set "screensaverEffect": "matrix" in ~/.config/omarchy/shell.json, trigger the screensaver (Super + Esc), confirm it always renders the matrix digital-rain effect instead of a random pick.

🤖 Generated with Claude Code

The screensaver has always picked a random ttfx effect (beams, matrix,
fireworks, ...) each cycle, with no way to keep one you like. Add an
optional idle.screensaverEffect key to shell.json that constrains
ttfx's --random-effect selection to a single named effect; an
unrecognized name falls back to random and notifies why.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@omarchybot omarchybot added the enhancement New feature or request label Sep 27, 2026
@llstrk

llstrk commented Sep 30, 2026

Copy link
Copy Markdown

Automated AI review

Community review: Independent automated community review, unaffiliated with the Omarchy team, intended to help prepare PRs for their review.

Outcome: An option-like screensaverEffect such as -R or --help passes validation and leaves the screensaver relaunching a failing ttfx command, with no notification.

Option-like effect names pass the --help check

ttfx "$effect" --help exits 0 for any value-less top-level flag (-R, --help, --version, --no-color), because clap acts on --help as soon as it sees it. The screensaver then runs --include-effects -R, which ttfx rejects (exit 2), so the loop relaunches it and shows the usage error, not the animation. Impact: the documented fallback with a notification does not happen for these values; it needs a user-typed option-like name, and a key press still exited it in sandbox runs.

Suggested change: Check the name's shape first, e.g. if [[ $effect =~ ^[a-z]+$ ]] && ttfx "$effect" --help ... (all 37 effect names match).

Reproducer (fails at 5b8c958)

Reproducer: an option-like idle.screensaverEffect passes the --help check but breaks the ttfx command

Reviewed head: 5b8c9584fed2b346aca2bfcbaf19f9c9048099b7. The same result was reproduced on quattro 8b4eae66da2938ba9559f103b18dbf85cdf28a70 with this PR merged.

ttfx used: 0.3.2. Omarchy's package currently builds 0.5.0; src/cli.rs and src/effects/mod.rs are identical in the two tags, and both lock clap 4.6.6.

Test case

Save as test/shell.d/screensaver-effect-optionlike-test.sh. It follows the style of the PR's screensaver-effect-test.sh, but it uses the real ttfx rather than a stub:

#!/bin/bash

set -euo pipefail

source "$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)/base-test.sh"

require_command jq
require_command ttfx

test_tmp=$(mktemp -d)
trap 'rm -rf "$test_tmp"' EXIT

stub_bin="$test_tmp/bin"
mkdir -p "$stub_bin"

notify_log="$test_tmp/notify.log"
cat >"$stub_bin/omarchy-notification-send" <<STUB
#!/bin/bash
printf '%s\n' "\$*" >>"$notify_log"
STUB
chmod +x "$stub_bin/omarchy-notification-send"

mkdir -p "$test_tmp/home/.config/omarchy"

# Uses the real ttfx: "-R" is not an effect, but `ttfx -R --help` prints the
# top-level help and exits 0, so the --help probe accepts it.
cat >"$test_tmp/home/.config/omarchy/shell.json" <<'JSON'
{
  "version": 1,
  "idle": { "screensaver": 150, "lock": 300, "screensaverEffect": "-R" }
}
JSON

effect=$(HOME="$test_tmp/home" OMARCHY_PATH="$ROOT" PATH="$stub_bin:$PATH" \
  "$ROOT/bin/omarchy-screensaver-effect")

[[ -z $effect ]] || fail "screensaver effect falls back to random for an option-like name" "helper printed: $effect"
grep -q -- '-R' "$notify_log" 2>/dev/null || fail "screensaver effect notifies about an option-like name"
pass "screensaver effect falls back to random and notifies for an option-like name"

Commands and actual output at the reviewed head

The commands ran from a copy of the repository root. The second-to-last command is the helper's --help check, which runs once per screensaver instance. The last command is the ttfx call that bin/omarchy-screensaver then makes on every loop iteration, with a local screensaver.txt in place of ~/.config/omarchy/branding/screensaver.txt.

$ ttfx --version
ttfx 0.3.2

$ bash test/shell.d/screensaver-effect-optionlike-test.sh
helper printed: -R
not ok - screensaver effect falls back to random for an option-like name
exit: 1

$ bash test/shell.d/screensaver-effect-test.sh
ok - screensaver effect defaults to random when unset
ok - screensaver effect resolves a configured effect
ok - screensaver effect falls back to random and notifies for an unknown effect
exit: 0

$ ttfx -R --help >/dev/null; echo $?
0

$ ttfx -i screensaver.txt --frame-rate 120 --canvas-width 0 --canvas-height 0 --reuse-canvas --anchor-canvas c --anchor-text c --random-effect --include-effects -R --no-eol --no-restore-cursor
error: a value is required for '--include-effects <INCLUDE_EFFECTS>...' but none was supplied

For more information, try '--help'.
exit: 2

With a suggested guard

This is the one-line change that was tested:

@@ -14,7 +14,7 @@
 # Every ttfx effect is also its own subcommand, so this doubles as validation:
 # an effect name that isn't real fails --help instead of ttfx erroring later,
 # inside the screensaver's restart loop, with no easy way to surface why.
-if ttfx "$effect" --help >/dev/null 2>&1; then
+if [[ $effect =~ ^[a-z]+$ ]] && ttfx "$effect" --help >/dev/null 2>&1; then
   printf '%s\n' "$effect"
 else
   omarchy-notification-send -g ⚠️ "Unknown screensaver effect \"$effect\" in shell.json, using random effects"

Actual output of the same commands with that change applied. The PR's own test still passes:

$ ttfx --version
ttfx 0.3.2

$ bash test/shell.d/screensaver-effect-optionlike-test.sh
ok - screensaver effect falls back to random and notifies for an option-like name
exit: 0

$ bash test/shell.d/screensaver-effect-test.sh
ok - screensaver effect defaults to random when unset
ok - screensaver effect resolves a configured effect
ok - screensaver effect falls back to random and notifies for an unknown effect
exit: 0

$ ttfx -R --help >/dev/null; echo $?
0

$ ttfx -i screensaver.txt --frame-rate 120 --canvas-width 0 --canvas-height 0 --reuse-canvas --anchor-canvas c --anchor-text c --random-effect --include-effects -R --no-eol --no-restore-cursor
error: a value is required for '--include-effects <INCLUDE_EFFECTS>...' but none was supplied

For more information, try '--help'.
exit: 2
Details

Verified

  • All 37 ttfx effect names pass the check, and each then runs alone on every cycle under the screensaver's flags. Case variants, whitespace, lists and unknown names fall back to random effects with a notification.
  • Config lookup matches bin/omarchy-shell-config: the user shell.json when non-empty, otherwise the defaults file. A missing, empty or invalid-JSON file falls back to random silently.
  • The helper runs once per screensaver launch, before the loop. The loop and its exit paths are unchanged.
  • The new test passes at the head and with quattro merged, and fails without the helper. Full test/shell shows the same 15 failures on quattro with and without this PR.

Optional notes

  • Test coverage: a copy of bin/omarchy-screensaver with the helper call removed still passes all three new assertions, because they call the helper directly. Asserting the ttfx arguments from a stubbed screensaver run would catch that.

Related open PRs


Review information

Test scope: Source and sandbox tests with real ttfx 0.3.2 (same CLI source as packaged 0.5.0), at 5b8c958; not run on a live desktop.

AI process: Opus 5.5 Medium coordination and synthesis, Opus 5.5 Xhigh technical review and final fact check, GPT 6 Sol Xhigh search for related issues, Opus 5.5 Medium editorial check.

Opt out: To stop receiving these reviews, reply to this comment saying so.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants