ClaudeMods
☰
KO
● 0 명 접속 중 · 조회 0 회
후원프로젝트 제출
GitHub 저장소 · 작성자 KilimcininKorOglu

idle-art

모델이 작업하는 동안 프롬프트 위에 ASCII 애니메이션(매트릭스 비, 불, 수족관, 고양이 또는 가져온 GIF)을 그리는 Claude Code 플러그인입니다. 표시 전용이며 비용이 없습니다.

KilimcininKorOglu@KilimcininKorOglu

KilimcininKorOglu/claude-code-mods/tree/main/plugins/idle-art

번역 완료

이 mod 소개

idle-art는 긴 턴 동안 프롬프트 위 공간에 ASCII 애니메이션을 표시합니다. 기본 제공 장면 네 가지(매트릭스 비, 불, 수족관, 고양이)와 함께 /idle-art import를 통해 사용자가 가져온 GIF를 문자 클립으로 변환할 수 있습니다. AbovePrompt ui.render 훅을 사용하고 그리기 스레드에서 약 60fps로 실행됩니다. 표시 전용이므로 모델에 아무것도 전달되지 않고 토큰을 사용하지 않으며 프롬프트 캐시도 건드리지 않습니다. 설정과 클립은 mod store에 저장되고 2초 이내에 창 간 동기화됩니다. 마켓플레이스 저장소를 통해 설치하며 function hooks에는 Claude Code 2.1.288+가 필요합니다.

설치

먼저 작성자의 README에서 marketplace와 플러그인 이름을 확인하세요. 저장소 구조에 따라 명령어가 달라질 수 있습니다.

claude plugin marketplace add KilimcininKorOglu/claude-code-mods
claude plugin install idle-art
원문 / README

idle-art

While you wait out a long turn, all that moves above the prompt is a spinner. This mod fills that space with an ASCII animation while the model works. Four scenes are built in: matrix rain, fire, an aquarium and a cat. You can add your own: /idle-art import turns a GIF into a character clip and keeps it for every project. Display only: nothing reaches the model, so the mod costs no tokens and does not touch the prompt cache.

What it shows

The picture appears 3 seconds into a turn, so a short turn shows nothing, and it goes away when the turn ends. By default each turn draws a scene at random from the built-in scenes and your saved clips, never the one shown before. A long turn moves on to another at random: a built-in scene after 20 seconds, the cat and a clip at the end of their first round or loop that ends after 20 seconds, so a long clip plays through once and a short one repeats until then. A scene you chose by name stays for the whole turn, and choosing one while a turn draws changes the picture at once.

● Brewing… (5s)
         .:   .                 ,
                   ,   ::,,,
    ::;;:;    ;;::;          .
     ,  ;:+ :*;++++      , ,,
    :::*oO;*:;*:+:  :+++,::**o ++:, :
  ;,,   ;,;+;+::+;,;+:**+**,;  ;  ,
 :  +;*:+**o*;;;;*+**:,*:;;***o:,::;;
:,::;oOoO*ooOOO#oO*o*O*o**OOOoOo;+;,

| Scene | What moves | |---|---| | matrix | Streams of half-width katakana and digits fall in green, a bright head over a fading trail; glyphs under a trail flicker. | | fire | Heat rises from a hidden row under the band and cools on the way up, drawn from . to @ and from dark red to pale yellow. | | aquarium | A school of fish of four shapes crosses both ways, bubbles rise from them and from the sand and grow, tall seaweed sways on the sand, and the surface ripples on the top row. | | cat | A garden: two kittens play back and forth on the grass, one on each side, a ball of yarn rolls at their feet, and a butterfly drifts over them. A big cat walks in slowly to the middle, head first, sits and blinks, and says meow; then its tricks in a new order each round: it rolls on the ground and back, jumps three times, purrs with a heart floating up, and looks left and right. It says MEOW!, walks out slowly to the right and comes round again. Each word stands in a speech bubble over its head. A round takes about 38 seconds, and random waits for the cat to walk out before it moves on. |

● Brewing… (8s)
                 .------.
                ( meow )
                 '------'
                /
           /\_/\
          ( o.o )
           > ^ <
           (_|_)~

The band takes at most 8 rows, fewer when the terminal has less room, and the terminal's whole width; a clip stands in its middle. It draws nothing in a band under 3 rows. It draws on the terminal only, and gives way to a survey. The scenes draw about 60 frames a second, and each moves by the time that passed, so the rain, the fish and the cat glide a step on every frame. The fire's heat changes ten times a second, and a clip changes at its own frame delays.

Your own GIFs

/idle-art import ~/Downloads/kitty.gif kitty

The mod reads the GIF, decodes every frame with its own delay and transparency, and turns each frame into characters: every cell takes the mean colour of its pixels, rounded to six levels a channel so neighbouring cells share a colour, and a glyph from .:-=+*#%@ by its brightness, spread over the clip's own darkest to brightest cell. A cell mostly transparent stays blank. The picture keeps its shape and fills the 8 rows of the band, at most 100 columns wide; a cell counts as twice as tall as wide. The clip then plays in the middle of the band, each frame for its own delay, in a loop.

● Brewing… (6s)
    ....=*******++=+***+====-....
    ....=******=----=*#=====-....
    ....-+++++*==+----===---:....
    ....:--=###++*=-:-=-:---:....
    ....-+#%#%*--==-:-:-==--:....
    ....+**#*++-:-:---::::--:....
    ....-====+-=:--:::::.:-+-....
    ....:-=*++*+++=-:-=--=-=-....

A clip is kept under 90,000 characters, because that is what one drawing may hand the drawing thread. A longer clip keeps every other frame, each kept frame showing for the time of both, and does so again until it fits; the answer says how many frames stayed. The clips live in the mod's store, which holds 4 MiB in all, so about forty clips fit; a clip that does not fit is refused with the reason.

A name is lowercase letters, digits and dashes, starts with a letter or digit, is up to 24 characters (a capital letter is lowered), and cannot be a built-in scene or a word the command reads. Importing under a saved name replaces that clip. A path starting with ~ is under your home directory, and a relative path is under the session's directory. A path may hold spaces: the last word is the name.

Command

/idle-art                          the state: on or off, the style, the delay
/idle-art on | off                 draw or stop drawing
/idle-art <scene or clip>          always draw that one: matrix, fire, aquarium, cat, or a saved clip
/idle-art random                   a new scene or clip each turn and every 20 seconds or so (the default)
/idle-art delay <n>                wait n seconds into a turn, 0 to 60 (default 3)
/idle-art import <gif path> <name> turn a GIF into a clip and keep it under that name
/idle-art list                     the built-in scenes and the saved clips
/idle-art remove <name>            delete a saved clip; a style set to it goes back to random
/idle-art help

The settings and the clips stay in the mod's store, shared by every project and every window, and survive updates. Each window reads them again at each /idle-art command, at each turn's start, and every 2 seconds while a turn runs, so an on, an off, a style, a delay or a clip set in another window shows here within 2 seconds in a running turn, and at the next turn otherwise. Two windows that import at the same time keep both clips.

How it draws

An AbovePrompt ui.render hook mounts a Client element while isWorking is true. The Client runs hooks/scene.tsx on the drawing thread: a 16 ms surface.every tick advances the scene by 16 ms and asks for the next frame, so no hook runs per frame. Measured on 2.1.283, the frame clock keeps that rate: the cat, which walks 5 cells a second, moved 5 cells in each second of a live band. Each built-in scene is a pure module under hooks/art/ that answers a grid of cells; a saved clip reaches the drawing thread in the Client's props and plays from hooks/clip.ts. A row draws as one Text per run of one colour. The hooks module picks the scene and a random seed when the band first shows a working turn, a $.clock.after timer redraws the band once the delay has passed, and the main loop's turn.complete ends the turn, so the next one picks again. While a turn runs, a $.clock.every timer reads the settings and the clip names again every 2 seconds, and a turn.start hook reads them at each turn's start, so the draw itself never reads the store. The clips load again only when the stored names or the stamp an import or a remove writes changed, because one read of the store takes longer as the whole store grows: 0.28 ms for a small store and 3.1 ms for one of 3.5 MB, measured on 2.1.283. Under random the drawing thread counts a scene's time itself, and once it has run it posts the scene's name with surface.post; the ui.message hook picks the next scene and answers with its props, which the running instance takes in place. A message that names a scene no longer showing changes nothing, so a late or repeated post cannot skip one. No clip travels to the drawing thread before its turn to show, because one clip may take most of the 100,000 characters a Client's props hold. The GIF decoder in hooks/gif.ts is written for this mod and needs no tool on the machine.

Install

claude plugin marketplace add KilimcininKorOglu/claude-code-mods
claude plugin install idle-art@kilimcininkoroglu-mods

Function hooks are early access. Claude Code 2.1.288 and later load them by default, so there is nothing to switch on.

Load it from a local checkout for one session:

claude --plugin-dir plugins/idle-art

After installing

Restart Claude Code, or run /reload-plugins in an open session. The mod is on after an install; /idle-art off turns it off.

What it can reach

Validated with claude plugin validate on Claude Code 2.1.283:

❯ ./register.tsx hooks: session.start, ui.render{component=AbovePrompt}, ui.message, turn.start, turn.complete, command.run{command=idle-art}
❯ ./register.tsx calls: $.clock.after (via beginTurn), $.clock.every (via beginTurn), $.clock.now (via sceneFor), $.command.register, $.env.get (via resolvePath), $.fs.exists (via readGifBytes), $.fs.read (via readGifBytes), $.fs.stat (via readGifBytes), $.process.spawn (via streamedStdout), $.session.cwd (via resolvePath), $.store.delete (via removeClip), $.store.get (via clipsMark, loadClips, loadConfig, writeClipNames), $.store.set (via importGif, removeClip, setting, writeClipNames), $.ui.invalidate (via beginTurn, setting, sync), $.ui.log (via rereadOrStop), $.ui.resolve
❯ ./register.tsx env writes: nothing
❯ ./register.tsx env reads: HOME
❯ ./register.tsx surface modules: hooks/scene.tsx

Reach L2, runs base64 to read a GIF over 4 MiB.

1. Reads:    the band's props (working, survey, rows, columns) and the clock; its settings and clips from the store, at each command, at each turn's start and every 2 seconds while a turn runs; the GIF a /idle-art import names, once, when it is 32 MiB or smaller; HOME and the session's directory to resolve that path
2. Runs:     base64 -i <path> for a GIF over 4 MiB, once per import; no fork; one timer per turn for the delay, one that reads the settings every 2 seconds while a turn runs, and the drawing thread's 16 ms tick while the band shows
3. Sends:    nothing; no network call and nothing to the model
4. Persists: the on/off state, the style, the delay, each imported clip, and a stamp of the last import or remove in the mod's store
5. Hostile input: a GIF is untrusted bytes: the decoder bounds every read by the file's length, refuses a broken code stream or a missing color table, stops at 500 frames, and an import that fails keeps nothing; a stored clip of the wrong shape is skipped at load; the command takes a fixed word list, a whole number from 0 to 60, and a clip name of lowercase letters, digits and dashes

Limits

  • 8 rows is a small canvas: a GIF becomes about 30 columns by 8 rows at the usual 2:1 shape, enough for a silhouette or a motion, not for detail.
  • A GIF of up to 4 MiB is read with $.fs.read. A larger one, up to 32 MiB, is read through base64 -i <path> piece by piece, because $.fs.read refuses a file over 4 MiB and $.process.run cuts its output at 4 MiB (measured on 2.1.283). The bytes that come back must match the file's size, or the import is refused.
  • Each frame is reduced to its cells as it is decoded, so a large GIF holds one frame of pixels at a time. A GIF stops at 500 frames.
  • A long GIF loses frames to the 90,000-character limit; its motion stays as long, but steps more coarsely.
  • The terminal draws the colours with its own palette; a terminal without true colour shows the nearest of its 256 colours.
  • matrix draws half-width katakana. A font without those glyphs draws a replacement character.

Development

make install     # eslint, typescript-eslint, typescript
make lint        # complexity limit 10, the build fails above it
make typecheck   # needs .claude/types/ from /plugin-types
make validate
make test        # claude plugin test

비슷한 프로젝트