0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

GitHubプロフィール上で文字が動く!?毛筆で書き順どおりに書くOSSを公開した話

0
Last updated at Posted at 2026-09-29

GitHub のプロフィール README に、今日の日付を毛筆で書き順どおりに書いていくアニメーションを置けるようにしました。
GitHub Action として公開しているので、ワークフローを 1 つ足すだけで誰でも使えます。

今日の日付

きっかけ

昔、自分のプロフィールに「今日の漢字」という日付の画像を置いていたのですが、
配信元のサービスが止まって 404 になっていました。
作り直すなら、ただ文字が出るのではなく筆で書いているように見せたいと思ったのが始まりです。

できること

一期一会 十二月二十九日
任意の文字 + 添え書き + 落款 西暦の日付
  • 漢字・ひらがな・カタカナなら何でも書けます(字形と書き順はその場で取得)
  • 今日の日付モード(令和 / 西暦、タイムゾーン指定)
  • 小さな添え書きと、朱色の落款(はんこ)
  • テーマは washi(和紙)、sumi(墨)、背景なしの clear / clear-dark

使い方

プロフィール用リポジトリ(<ユーザー名>/<ユーザー名>)に、このワークフローを置くだけです。

.github/workflows/fude.yml
name: fude
on:
  schedule:
    - cron: "5 15 * * *" # 毎日 0:05 (JST)
  workflow_dispatch:

permissions:
  contents: write

jobs:
  write:
    runs-on: ubuntu-latest
    steps:
      - uses: q0v0p/fude@v1
        with:
          theme: sumi
          output: dist/today.svg

      - name: output ブランチへ置く
        working-directory: dist
        run: |
          git init -q -b output
          git config user.name "github-actions[bot]"
          git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
          git add . && git commit -q -m "fude"
          git push -f "https://x-access-token:${{ github.token }}@github.com/${{ github.repository }}.git" output

README からはこう参照します。

<img src="https://raw.githubusercontent.com/<ユーザー名>/<ユーザー名>/output/today.svg" width="480"/>

生成物は output ブランチに上書きで push しているので、main の履歴が毎日のコミットで埋まりません。

好きな言葉を書くだけなら、手元で一度作ってコミットしても OK です。

pip install fonttools
python fude.py --text "一期一会" --sub "いちごいちえ" --seal 縁 --theme sumi -o ichigo.svg

仕組み

1. 字形は毛筆フォント、書き順は KanjiVG

最初は KanjiVG の書き順データ(1 画ずつの中心線)をそのまま線で描いていました。
書き順は完璧なのですが、線の太さが一定なのでペン習字にしか見えません。

そこで役割を分けました。

  • 見える形: 毛筆体フォント Yuji Boku の輪郭(入り・はね・払い・かすれがある)
  • 書く順番: KanjiVG の中心線

KanjiVG の線を**太い筆(マスク)**として 1 画ずつ伸ばしていき、その下にあるフォントの輪郭を現していきます。
こうすると、形は毛筆のまま、書き順どおりに書かれていくように見えます。

<mask id="m0">
  <!-- KanjiVG の 1 画。太い白線として伸びていく -->
  <path class="st" pathLength="1" d="M31.5,24.5c1.12,1.12 ..."/>
  ...
</mask>
<!-- 毛筆フォントの輪郭をマスク越しに見せる -->
<path class="ink" mask="url(#m0)" d="..."/>

KanjiVG もフォントも 109×109 の枠に揃えてあるので、座標変換なしで重なります。
マスクの線だけでは筆の輪郭を覆いきれない部分があるので、1 文字書き終えたらマスクを全面に開いて仕上げています。

2. pathLength="1" で線の長さを気にしない

線を伸ばすアニメーションの定番は stroke-dasharray と stroke-dashoffset ですが、
普通は線の長さを事前に知っておく必要があります。

pathLength="1" を付けると、どんな線でも長さが 1 として扱われるので、
全部の画を同じ CSS で動かせます。

.st {
  stroke-dasharray: 1 2;
  stroke-dashoffset: 1; /* 1 → 0 で書き終わり */
}

3. 筆の緩急

全部の画が同じ速さだと機械的に見えるので、

  • 画の長さ(パスの端点をつないだ折れ線で近似)に比例した時間をかける
  • cubic-bezier(.55,0,.35,1) で、入りでためて、送りで速く、収筆でゆるめる

ようにしています。細かいことですが、これで一気に「書いている」感じが出ました。

4. README の <img> の中で動かすための制約

GitHub の README では、SVG は <img> として(しかもプロキシ経由で)表示されます。そのため、

  • JavaScript は動かない → CSS アニメーションだけで作る
  • 外部のフォントや画像は読めない → 字形はパスとして SVG に埋め込む

という制約があります。fude の出力は完全に 1 ファイルで閉じた SVG なので、そのまま動きます。
ループは、全体の周期を決めて各画の @keyframes をパーセントで書き出すことで実現しています。

5. 地味にハマったところ

  • 画像キャッシュ: raw.githubusercontent.com は 5 分ほどキャッシュします。テーマを変えたのにプロフィールが変わらない……というときは、出力ファイル名を変えるとすぐ反映されます
  • スケジュール実行の自動停止: 公開リポジトリの schedule は、60 日間動きがないと止まります。ワークフローの最後で gh workflow enable を呼んで延命しています
  • Windows の zoneinfo: Windows の Python には tz データベースがなく Asia/Tokyo が引けません。+09:00 のような時差表記も受け付けるようにしました

ライセンス

  • コード: MIT
  • 書き順データ: KanjiVG © Ulrich Apel(CC BY-SA 3.0)。生成した SVG もこれに従います(クレジットは SVG 内に埋め込み済み)
  • 字形: Yuji Boku(SIL Open Font License 1.1)

おわりに

プロフィール README にちょっと和の要素を足したい方は、ぜひ使ってみてください。
気に入ってもらえたら ⭐ をもらえると励みになります!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?