この記事はTiDB Advent Calendar 2023 の二日目です。
二日目にして早くもTiDBそのものの記事ではないゆるふわ記事です。
ピンちゃんとは
ピンちゃんとは、TiDBの普及のためにPingCAP日本法人が作ったゆるキャラの名前です。公式ではないので公式サイトには出てこないのですが、プレゼン資料などではたまに使われており(たとえばここ)その何を考えているのか分からないつぶらな瞳で多くのTiDBユーザーを虜にしています。
鯛はTiDBのTiからきており、体が赤ではなくグレーなのはTiDBのもともとの由来であるチタニウムを意識していたと聞いています。
数年前にAsakusa Frameworkの屋形船を動かすコマンドラインツールを作ったので、その二番煎じインスパイアでこのピンちゃんを動かそうというのがこの記事になります。
Ascii Art化の挫折
早速ピンちゃんの下絵を元にアスキーアートを作ろうと思ったのですが、これがかなり難航しました。。。というか挫折しました。ピンちゃんの扇のあたりを動かそうと思ったのですが、扇を表現するのが難しいのと、そもそも縦に長くてターミナルで表示すると妙に間延びした感じになるのです。別の手を考えます。
┌─────────────┐
│======== =│
│===== ====│
│== === =│
│ == =│
********** │==== == =│
*************** │==== == =│
************************** └─────────────┘
**************** **********
*************** *** ***** *
************* ** *** ***
*********** ** .─────. ***** **
********* ** ╱ *** ╲ ** ***
**************** ( * * ) ******
****** `. *** ,' ((( *
******** *** * `───' (( * ****==
* ***** ** ((( *** =
** * * (( * **=
* ****** ** (( * **
*** ** ^^ ****** ((' ******
** ** ^^^^ *** ****( **
* ***** ^^ *** **** **** **
* * ** * ** **
** * ******* *** ** **
**** **** *** ** ** **
* * ^^ * *** **
** * ^^ ^ (( **
** *** ^ ^^^^ (( **
***** * ^^ ( ** **
*** * ( ***** ***
** *** ^ ( ** **
* * ^^^^^ (( *** *
*** *** ^ (( ** * *
**** ** ( ** ** *
***** ^ ((* ** **
*** ^^^ '* * ***
**** * * ******
**** * *****
********** ****** **
* ****** **
******** *****
***********
Gifアニメをターミナルで表示する
普通にGifアニメや、最近ならAIで動画を生成すれば、、、とおも思ったのですが、やっぱり普段使っている環境で素早く見れてこそのマスコット(?)なので、ターミナルに表示することにこだわりたいと思います。
ASCIIエスケープコードでカラーも表示できますから、これを使って画像をターミナルに表示するコマンドは世の中に存在するだろうと思って調べると、やはりあります。色々ありましたが、ここではgoで実装されたimgcat を使います。Gifアニメの表示にも対応しています。
MacOSの場合、インストールはbrewで出来ます。
brew install danielgatis/imgcat/imgcat
何をしているかソースを見てみましょう。実際に画面に出力しているのは main.goのescapeです。ここでは下記のように元画像をy軸二行ずつ処理して、1行目を背景色、2行目を前景色として表示しています。
for y := 0; y < maxY; y += 2 {
go func(y int) {
var sb strings.Builder
for x := 0; x < maxX; x++ {
r, g, b, a := f.At(x, y).RGBA()
if a>>8 < 128 {
sb.WriteString(ANSI_BG_TRANSPARENT_COLOR)
} else {
sb.WriteString(fmt.Sprintf(ANSI_BG_RGB_COLOR, r>>8, g>>8, b>>8))
}
r, g, b, a = f.At(x, y+1).RGBA()
if a>>8 < 128 {
sb.WriteString(ANSI_FG_TRANSPARENT_COLOR)
} else {
sb.WriteString(fmt.Sprintf(ANSI_FG_RGB_COLOR, r>>8, g>>8, b>>8))
}
}
sb.WriteString(ANSI_RESET)
sb.WriteString("\n")
c <- &data{y / 2, sb.String()}
}(y)
}
ANSI_BG_* や ANSI_FG_* の定義を見てみると、ASCIIエスケープコードでそれらを指定していることがわかります。さらにFGでは "▄" を前景色で描画しているのがわかります。そのため、余白部分が背景色の色、"▄"が前景色で描画されます。
これで描画の準備は整ったので、あとはアニメGifを用意してコマンドに渡すだけです。アニメGifを作るのが何気に一番手間のかかるところです。
そしてできたのがこちら。ターミナルの録画には、t-recを利用しました。はからずもTiDBのように、go製ツールとrust製ツールを利用しています。
味があって良いですよね!?
おまけ
手っ取り早く生成AIで動く動画つくっちゃえば...という気持ちもあったので、RunWay でピンちゃんごと動画を作るのにチャレンジしました。画像そのまま使っちゃうとなんかチートだなという気がしたので、「野球帽をかぶった鯛が扇を持って踊る動画」みたいなプロンプトで生成にチャレンジしたのですが、、、
「アニメ調でかわいらしく、扇を振る感じで」を追加したらそっちじゃねーよって感じになりました。
改めて「鯛に野球帽をかぶらせて扇をふらせる」という謎の発想に感心しました。