Skip to content

feat: a whole gallery of spinner packs - #3

Merged
noctaIO merged 2 commits into
masterfrom
claude/spinner-packs-feature-sioghd
Aug 7, 2026
Merged

noctaIO merged 2 commits into
masterfrom
claude/spinner-packs-feature-sioghd

Conversation

@noctaIO

@noctaIO noctaIO commented Aug 7, 2026

Copy link
Copy Markdown
Owner

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

claude added 2 commits August 6, 2026 18:02
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
@noctaIO
noctaIO merged commit 8dcc92d into master Aug 7, 2026
27 of 29 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants