Repository navigation
feat: a whole gallery of spinner packs - #3
Merged
Merged
Conversation
Turns the two-mode toy into a pack system: 23 word packs, 36 animations and 12 colour themes, mixed and matched, browsed in a live-animating TUI. Adding a pack used to mean editing four places — VERBS, menu()'s options, --set's choices tuple and apply_selected's if/else — and there was no way to undo an apply. So this starts with a registry and hangs everything off it. - PACKS/SPINNERS/THEMES registries; resolve_verbs() handles static, meta and live packs behind one interface, collapsing the old branch into a dispatch - 21 new word packs (british, scottish, eldritch, pirate, corporate, noir, wizard, genz, zen and more), each rated sfw/mild/nsfw so --sfw and the gallery's `s` key can filter. Roughly half are work-safe - 36 animations, from braille to moon phases to progress bars. Tests enforce equal frame widths per set — mixed widths make the verb jitter each tick - 12 themes defined once in RGB; the 256-cube, 16-colour and curses-pair paths are all derived. NO_COLOR, TERM=dumb and pipes emit zero escapes - the gallery: every pack animating in its own glyphs and colour, search over names and verbs, category/SFW filters, wall mode, and a 56-column preview of exactly what Claude Code will draw - backup and restore: the first apply stashes your previous spinnerVerbs and never overwrites it, so --restore returns your settings byte for byte - user packs from ~/.claude/spinner-packs/*.json, with --import/--export. A bad verb or unknown theme costs you that verb or a fallback, not the pack - new flags: --list/--json, --pack, --spinner, --theme, --random, --mix, --wall, --search, --sfw, --no-color, --restore, --import, --export. Every old flag still works; --set verbs|news|toggle maps onto the registry Fixes along the way: `spin.py --verbs | head` died with an unhandled BrokenPipeError; fit() asserted rather than giving up when a wide glyph left no room for text at all; normalize_items turned a null feed entry into the headline "None". The layout draws against a two-method screen interface with curses and plain-text backends, so all 118 tests — including the TUI at fourteen window sizes — run without a terminal. README tables and the SVG art are generated from the registries and CI fails if either drifts. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0178aR5Qr3iyREMrJ84rzGu3
The themes were decoration. apply_pack wrote exactly one thing to Claude Code
— spinnerVerbs — so the animation and theme you picked only ever drove this
program's own previews.
Claude Code's spinner colour is reachable, via a custom theme file whose
`claude` token is documented as "primary brand accent, used for the spinner".
So picking a pack now also writes ~/.claude/themes/obscene-spinner.json:
{"name": "obscene-spinner (Void)", "base": "dark",
"overrides": {"claude": "#9d4edd", "claudeShimmer": "#c495eb"}}
Only those two tokens are ever written. `overrides` is documented as additive,
so every other colour in the user's interface falls through to the base preset
untouched. Select it once in /theme; after that the same file is rewritten on
every apply and Claude Code hot-reloads it, so the colour follows the pack
live. Nothing here pokes at the theme *preference*, which has no documented
settings key — asking for one /theme run beats guessing at an undocumented one.
claudeShimmer is derived rather than taken straight from the theme's accent:
the docs define it as the lighter half of the gradient, and half our themes
run bright -> dark (void, blood, deep, matrix), so handing over `accent`
unexamined would invert the animation. shimmer_for() picks whichever of the
accent and a lightened frame is genuinely brighter; a test asserts the
invariant for all twelve.
Also fixes a claim I shouldn't have shipped. The gallery's detail pane is
labelled "as Claude Code will draw it" but drew whichever animation you were
previewing — and Claude Code's glyph is not configurable, so it always draws
braille. The box now shows braille in the pack's real colour, with a line
under it naming what leaves this program (verbs + colour) and what doesn't
(the animation). The list rows and --pack/--wall previews still animate.
- backup_once() now also captures any theme file already at our slug, keeping
its write-once discipline; --restore hands a hand-written one back byte for
byte, or removes ours outright
- new flags: --theme-base (default dark; it sets the rest of the UI too, so
the tool prints which it wrote), --no-theme, --print-theme
- --status reports the active colour and where it came from, and says plainly
that it only applies once /theme has the theme selected
- the generated theme table gains each theme's spinner colour
22 new tests: payload schema and shimmer luminance for every theme, the
pre-existing-file backup path, --no-theme, --print-theme, and a check that the
preview box shows braille whatever --spinner is set to. 140 total, still
stdlib-only.
Verified: file contents, atomicity, and the full apply/restore round-trip
against a scratch HOME. Not verified here: that the spinner visibly changes
colour — this container has no interactive Claude Code session.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0178aR5Qr3iyREMrJ84rzGu3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Turns the two-mode toy into a pack system: 23 word packs, 36 animations and
12 colour themes, mixed and matched, browsed in a live-animating TUI.
Adding a pack used to mean editing four places — VERBS, menu()'s options,
--set's choices tuple and apply_selected's if/else — and there was no way to
undo an apply. So this starts with a registry and hangs everything off it.
live packs behind one interface, collapsing the old branch into a dispatch
wizard, genz, zen and more), each rated sfw/mild/nsfw so --sfw and the
gallery's
skey can filter. Roughly half are work-safeequal frame widths per set — mixed widths make the verb jitter each tick
paths are all derived. NO_COLOR, TERM=dumb and pipes emit zero escapes
names and verbs, category/SFW filters, wall mode, and a 56-column preview
of exactly what Claude Code will draw
never overwrites it, so --restore returns your settings byte for byte
A bad verb or unknown theme costs you that verb or a fallback, not the pack
--wall, --search, --sfw, --no-color, --restore, --import, --export.
Every old flag still works; --set verbs|news|toggle maps onto the registry
Fixes along the way:
spin.py --verbs | headdied with an unhandledBrokenPipeError; fit() asserted rather than giving up when a wide glyph left
no room for text at all; normalize_items turned a null feed entry into the
headline "None".
The layout draws against a two-method screen interface with curses and
plain-text backends, so all 118 tests — including the TUI at fourteen window
sizes — run without a terminal. README tables and the SVG art are generated
from the registries and CI fails if either drifts.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_0178aR5Qr3iyREMrJ84rzGu3