idle-art
Uzun bir turn'de beklerken prompt'un üstünde yalnız dönen bir spinner vardır. Bu mod o boşluğa, model çalışırken ASCII bir animasyon çizer. Dört sahne yerleşik olarak gelir: matrix yağmuru, ateş, akvaryum ve bir kedi. Kendi animasyonlarını da ekleyebilirsin: /idle-art import bir GIF'i karakterlerden oluşan bir klibe çevirir ve bütün projelerde kullanılmak üzere saklar. Yalnız görüntüdür: modele hiçbir şey gitmez, bu yüzden mod token harcamaz ve prompt cache'e dokunmaz.
Ne gösterir
Resim bir turn'ün 3. saniyesinde çıkar, bu yüzden kısa bir turn hiçbir şey göstermez. Turn bitince resim kaybolur. Varsayılan olarak her turn, yerleşik sahneler ve kaydettiğin klipler arasından rastgele birini çizer ve bir önce gösterileni asla tekrar seçmez. Uzun bir turn, rastgele başka bir sahneye geçer. Yerleşik bir sahne 20 saniye sonra değişir. Kedi ve bir klip, 20 saniyeden sonra biten ilk turlarının ya da döngülerinin sonunda değişir: uzun bir klip bir kez baştan sona oynar, kısa bir klip o süre dolana kadar tekrar eder. Adıyla seçtiğin bir sahne bütün turn boyunca kalır. Bir turn çizilirken sahne seçersen resim hemen değişir.
● Brewing… (5s)
.: . ,
, ::,,,
::;;:; ;;::; .
, ;:+ :*;++++ , ,,
:::*oO;*:;*:+: :+++,::**o ++:, :
;,, ;,;+;+::+;,;+:**+**,; ; ,
: +;*:+**o*;;;;*+**:,*:;;***o:,::;;
:,::;oOoO*ooOOO#oO*o*O*o**OOOoOo;+;,
| Sahne | Ne hareket eder |
|---|---|
matrix |
Yarım genişlikte katakana ve rakamlardan oluşan akışlar yeşil renkte düşer. Her akışın parlak bir başı ve solan bir kuyruğu vardır. Kuyruğun altındaki karakterler titrer. |
fire |
Isı, band'in altındaki gizli bir satırdan yükselir ve yukarı çıktıkça soğur. . ile @ arasındaki karakterlerle, koyu kırmızıdan açık sarıya kadar çizilir. |
aquarium |
Dört şekilde bir balık sürüsü iki yönde de geçer. Balıklardan ve kumdan çıkan kabarcıklar yükseldikçe büyür. Kumun üstünde uzun yosunlar sallanır, en üst satırda su yüzeyi dalgalanır. |
cat |
Bir bahçe: iki yavru kedi çimenin üstünde, biri sağda biri solda, bir o yana bir bu yana oynar, ayaklarının dibinde bir yün yumağı yuvarlanır, üstlerinde bir kelebek uçar. Büyük bir kedi, kafası önde, yavaş yavaş yürüyerek ortaya gelir, oturur, göz kırpar ve meow der. Sonra her turda başka bir sırayla şebeklik yapar: yerde bir o yana bir bu yana yuvarlanır, üç kez zıplar, başından bir kalp yükselirken mırlar, sağa sola bakar. MEOW! der, sağa doğru yavaş yavaş yürüyüp sahneden çıkar ve yeniden gelir. Her söz, başının üstünde bir konuşma balonunda çıkar. Bir tur yaklaşık 38 saniye sürer. random, başka sahneye geçmeden önce kedinin sahneden çıkmasını bekler. |
● Brewing… (8s)
.------.
( meow )
'------'
/
/\_/\
( o.o )
> ^ <
(_|_)~
Band en fazla 8 satır kaplar ve terminalin tüm genişliğini kullanır. Terminalde daha az satır varsa daha alçak çizilir. Bir klip band'in ortasında durur. 3 satırdan kısa bir band'e hiçbir şey çizmez. Yalnız terminalde çizer ve açık bir anketin önünden çekilir. Sahneler saniyede yaklaşık 60 kare çizilir ve her biri geçen süre kadar ilerler. Böylece yağmur, balıklar ve kedi her karede bir adım kayar. Ateşin ısısı saniyede on kez değişir, bir klip de kendi kare sürelerine göre değişir.
Kendi GIF'lerin
/idle-art import ~/Downloads/kedi.gif kedi
Mod GIF'i okur ve her kareyi kendi süresi ve şeffaflığıyla çözer. Sonra her kareyi karakterlere çevirir. Her hücre, kapladığı piksellerin ortalama rengini alır; renk kanal başına altı seviyeye yuvarlanır, böylece komşu hücreler aynı rengi paylaşır. Hücrenin karakteri .:-=+*#%@ dizisinden parlaklığına göre seçilir. Parlaklık, klibin kendi en koyu ve en parlak hücresi arasına yayılır. Çoğu şeffaf olan bir hücre boş kalır. Resim şeklini korur ve band'in 8 satırını doldurur, en fazla 100 sütun genişliğinde. Bir hücre, genişliğinin iki katı yükseklikte sayılır. Klip band'in ortasında, her kare kendi süresi kadar gösterilerek döngü halinde oynar.
● Brewing… (6s)
....=*******++=+***+====-....
....=******=----=*#=====-....
....-+++++*==+----===---:....
....:--=###++*=-:-=-:---:....
....-+#%#%*--==-:-:-==--:....
....+**#*++-:-:---::::--:....
....-====+-=:--:::::.:-+-....
....:-=*++*+++=-:-=--=-=-....
Bir klip 90.000 karakterin altında tutulur, çünkü tek bir çizim, çizim thread'ine en fazla bu kadar veri verebilir. Daha uzun bir klip her iki kareden birini düşürür ve sığana kadar bunu tekrarlar. Kalan her kare, düşen karenin süresini de üstlenir. Cevap kaç karenin kaldığını söyler. Klipler mod'un store'unda durur. Store toplam 4 MiB tutar, bu da yaklaşık kırk klip eder. Sığmayan bir klip, sebebiyle birlikte reddedilir.
Klip adı küçük harf, rakam ve tire içerir, bir harf ya da rakamla başlar ve en fazla 24 karakterdir; büyük harfle yazılan ad küçük harfe çevrilir. Yerleşik bir sahnenin adı ya da komutun okuduğu bir kelime olamaz. Kayıtlı bir adla yeniden import etmek o klibi değiştirir. ~ ile başlayan bir yol ev dizinini gösterir. Göreli bir yol session'ın dizinine göre çözülür. Yolda boşluk olabilir: son kelime klibin adıdır.
Komut
/idle-art durum: açık ya da kapalı, stil, gecikme
/idle-art on | off çizimi aç ya da kapat
/idle-art <sahne ya da klip> her zaman onu çiz: matrix, fire, aquarium, cat ya da kayıtlı bir klip
/idle-art random her turn ve yaklaşık her 20 saniyede yeni bir sahne ya da klip (varsayılan)
/idle-art delay <n> turn'ün n. saniyesinde başla, 0 ile 60 arası (varsayılan 3)
/idle-art import <gif yolu> <ad> bir GIF'i klibe çevir ve o adla sakla
/idle-art list yerleşik sahneler ve kayıtlı klipler
/idle-art remove <ad> kayıtlı bir klibi sil; stil o klipse yeniden random olur
/idle-art help
Ayarlar ve klipler mod'un store'unda durur. Store bütün projelerde ve bütün pencerelerde ortaktır ve güncellemelerden sonra da kalır. Her pencere onları her /idle-art komutunda, her turn'ün başında ve bir turn çalışırken 2 saniyede bir yeniden okur. Böylece başka bir pencerede yapılan on, off, stil, gecikme ya da klip değişikliği çalışan bir turn'de 2 saniye içinde, yoksa sonraki turn'de burada da görünür. Aynı anda import eden iki pencere iki klibi de korur.
Nasıl çizer
AbovePrompt için bir ui.render hook'u, isWorking true olduğu sürece bir Client element mount eder. Client, hooks/scene.tsx modülünü çizim thread'inde çalıştırır. 16 ms'lik bir surface.every tick'i sahneyi 16 ms ilerletir ve sonraki frame'i ister. Bu yüzden frame başına hiçbir hook çalışmaz. 2.1.283 üzerinde ölçüldü: frame saati bu hızı tutuyor. Saniyede 5 hücre yürüyen kedi, canlı bir band'de her saniye 5 hücre ilerledi. Her yerleşik sahne hooks/art/ altında saf bir modüldür ve bir hücre grid'i döner. Kayıtlı bir klip çizim thread'ine Client'ın props değeriyle ulaşır ve hooks/clip.ts ile oynar. Bir satırdaki aynı renkli ardışık hücreler tek bir Text olarak çizilir. Hooks modülü, band çalışan bir turn'ü ilk gördüğünde sahneyi ve rastgele bir seed seçer. Gecikme dolunca bir $.clock.after timer'ı band'i yeniden çizdirir. Ana döngünün turn.complete olayı turn'ü bitirir, böylece sonraki turn yeniden seçer. Bir turn çalışırken bir $.clock.every timer'ı ayarları ve klip adlarını 2 saniyede bir yeniden okur, bir turn.start hook'u da onları her turn'ün başında okur. Böylece çizimin kendisi store'u hiç okumaz. Klipler yalnız store'daki adlar ya da bir import veya remove'un yazdığı damga değiştiğinde yeniden yüklenir, çünkü store'dan tek bir okuma store büyüdükçe uzar: 2.1.283 üzerinde küçük bir store için 0,28 ms, 3,5 MB'lık bir store için 3,1 ms ölçüldü. random modunda sahnenin süresini çizim thread'i kendisi sayar. Süre dolunca sahnenin adını surface.post ile gönderir. ui.message hook'u sıradaki sahneyi seçer ve onun props değerini döner, çalışan instance bunu yerinde alır. Artık gösterilmeyen bir sahneyi adlandıran mesaj hiçbir şeyi değiştirmez, böylece geç gelen ya da tekrarlanan bir mesaj bir sahneyi atlatamaz. Hiçbir klip, gösterilme sırası gelmeden çizim thread'ine gönderilmez, çünkü tek bir klip bir Client'ın props sınırı olan 100.000 karakterin büyük kısmını kaplayabilir. hooks/gif.ts içindeki GIF decoder'ı bu mod için yazıldı ve makinede başka bir araç gerektirmez.
Kurulum
claude plugin marketplace add KilimcininKorOglu/claude-code-mods
claude plugin install idle-art@kilimcininkoroglu-mods
Function hook'lar henüz early access aşamasında. Claude Code 2.1.288 ve üzerinde varsayılan olarak yüklenir, açılacak bir ayar yok.
Yerel bir checkout'tan tek session için yüklemek istersen:
claude --plugin-dir plugins/idle-art
Kurulumdan sonra
Claude Code'u yeniden başlat ya da açık bir session'da /reload-plugins çalıştır. Mod kurulumdan sonra açıktır. /idle-art off komutu onu kapatır.
Nereye uzanır
Claude Code 2.1.283 üzerinde claude plugin validate ile doğrulandı:
❯ ./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: 4 MiB'tan büyük bir GIF'i okumak için base64 çalıştırır.
1. Okur: band'in props değerlerini (çalışıyor mu, anket var mı, satır, sütun) ve saati; store'daki ayarları ve klipleri, her komutta, her turn'ün başında ve bir turn çalışırken 2 saniyede bir; /idle-art import komutunun verdiği GIF'i, 32 MiB veya daha küçükse, bir kez; bu yolu çözmek için HOME'u ve session'ın dizinini
2. Çalıştırır: 4 MiB'tan büyük bir GIF için import başına bir kez base64 -i <yol>; fork yok; turn başına gecikme için bir timer, bir turn çalışırken ayarları 2 saniyede bir okuyan bir timer, band görünürken çizim thread'inin 16 ms'lik tick'i
3. Gönderir: hiçbir şey; network çağrısı yok, modele bir şey gitmez
4. Saklar: mod'un store'unda açık/kapalı durumunu, stili, gecikmeyi, import edilen her klibi ve son import ya da remove'un damgasını
5. Düşman girdi: bir GIF güvenilmeyen byte'lardır: decoder her okumayı dosyanın uzunluğuyla sınırlar, bozuk bir kod akışını ya da eksik bir color table'ı reddeder, 500 karede durur; başarısız bir import hiçbir şey saklamaz; yanlış biçimdeki kayıtlı bir klip yüklenirken atlanır; komut sabit bir kelime listesi, 0 ile 60 arası bir tam sayı ve küçük harf, rakam ve tireden oluşan bir klip adı kabul eder
Sınırlar
- 8 satır küçük bir tuvaldir: bir GIF, alışılmış 2:1 oranda yaklaşık 30 sütun ve 8 satır olur. Bu bir siluet ya da hareket için yeterlidir, ayrıntı için yetmez.
- 4 MiB'a kadar bir GIF
$.fs.readile okunur. 32 MiB'a kadar daha büyük bir GIF,base64 -i <yol>ile parça parça okunur. Sebebi şu:$.fs.read4 MiB'tan büyük bir dosyayı reddeder,$.process.runda çıktısını 4 MiB'ta keser (2.1.283 üzerinde ölçüldü). Dönen byte'lar dosyanın boyutuyla aynı olmalıdır, değilse import reddedilir. - Her kare, çözülür çözülmez hücrelerine indirilir. Böylece büyük bir GIF bellekte aynı anda yalnız bir karenin piksellerini tutar. Bir GIF'ten en fazla 500 kare okunur.
- Uzun bir GIF, 90.000 karakter sınırı yüzünden kare kaybeder. Hareketi aynı sürede kalır, ama daha kaba adımlarla ilerler.
- Renkleri terminal kendi paletiyle çizer. True color desteklemeyen bir terminal, 256 rengi içinden en yakın olanı gösterir.
matrixyarım genişlikte katakana çizer. Bu karakterleri içermeyen bir font yerlerine yedek bir karakter çizer.
Geliştirme
make install # eslint, typescript-eslint, typescript
make lint # complexity sınırı 10; aşılırsa build kırılır
make typecheck # /plugin-types çıktısı olan .claude/types/ gerekir
make validate
make test # claude plugin test