GitHubのプロフィールにアニメーションを描く方法

この記事は、SYSKEN Advent Calendar 2024年12月22日の記事です。

はじめに

システム研究部のNotoです。

今年も残るところ80万秒程度となってきましたが皆様いかがお過ごしでしょうか?クリスマスが近づきイルミネーションが蔓延る昨今、研究室に落ちていたArduinoのテープライトでピカピカイルミネーションを作成したところ思いのほか愉快で楽しくなっている始末でございます。

常にゲーミングで面白さを探求している情報系高専生はGitHubのプロフィールもゴテゴテのピカピカになっているに違いません。そこで今回は、より楽しく愉快になるようGitHubのプロフィールにアニメーションを載せる方法を解説します。

作ったもの

GitHubプロフィールに動的なアニメーションを追加します。

  • GitHubのコントリビューション(活動記録)に合わせて波紋が広がるアニメーション
  • SVGを動的に生成して表示
  • 波紋の大きさはコントリビューション数に応じて変化
  • ランダムな位置に波紋が出現

完成品は以下のような感じです:

GitHub Contribution Animation

作り方

使用技術

  • Node.js
  • GitHub Actions
  • GitHub GraphQL API
  • SVG アニメーション

フォルダ構成

.
├── .github
│ └── workflows
│ └── animation.yml
├── script
│ └── generate-animation.js
├── package.json
└── README.md

ファイルの内容と役割

animation.yml

  • GitHub Actionsの設定ファイル
  • 24時間ごとにアニメーションを自動生成
  • GitHub Pagesへの自動デプロイを担当

generate-animation.js

  • アニメーションのSVGを生成するメインスクリプト
  • GitHub GraphQL APIを使用してコントリビューションデータを取得
  • 波紋アニメーションのSVGを生成

README.md

  • プロフィールページの表示内容
  • 生成したアニメーションの表示

手順

1. リポジトリの作成

  • ユーザー名と同じ名前のリポジトリを作成(例:username/username)
  • このリポジトリがGitHubプロフィールとして表示される

2. 必要なファイルの設置

  • 上記のフォルダ構成に従ってファイルを配置
  • package.jsonに必要な依存関係を追加

3. GitHub Actionsの設定

  • Personal Access Tokenの発行(repo権限必要)
  • リポジトリのSecretsにトークンを設定

4. GitHub Pagesの有効化

  • リポジトリの設定からGitHub Pagesを有効化
  • デプロイ元をgh-pagesブランチに設定

主要なコード

1. Rippleクラスの実装

class Ripple {
  constructor(x, y, contributionCount, duration, delay) {
    this.x = x;
    this.y = y;
    this.size = 20 + contributionCount * 3;  // コントリビューション数に応じてサイズを決定
    this.duration = duration;
    this.delay = delay;
    this.fillColor = "none";
    this.isMultiCircle = false;

    // ランダムに塗りつぶすかどうかを決定
    if(Math.floor(Math.random() * 2) > 0) {
        this.fillColor = "#4B9EF9";
    }

    // 大きな波紋の場合、複数の円を重ねる
    if (this.size >= 80 && this.fillColor === "none") {
      this.isMultiCircle = true;
    }
  }
}

2. GitHubのコントリビューションデータ取得

async function getContributions(username) {
  const query = `
    query($username: String!) {
      user(login: $username) {
        contributionsCollection {
          contributionCalendar {
            totalContributions
            weeks {
              contributionDays {
                contributionCount
                date
              }
            }
          }
        }
      }
    }
  `;

  const response = await graphqlWithAuth(query, { username });
  return response.user.contributionsCollection.contributionCalendar;
}

3. アニメーションの生成ロジック

async function generateAnimation() {
  const username = process.env.GITHUB_REPOSITORY.split('/')[0];
  const contributionData = await getContributions(username);
  const width = 800;
  const height = 400;
  const duration = 2; // 波紋が広がるまでの時間(秒)
  let delay = 0;

  // コントリビューションがある日のみ波紋を生成
  const ripples = contributionData.weeks.flatMap((week) =>
    week.contributionDays.filter(day => day.contributionCount > 0)
      .map((day) => {
        const { x, y } = getRandomPosition(width, height);
        delay += Math.random() * 0.3;  // 波紋の出現タイミングをずらす
        return new Ripple(x, y, day.contributionCount, duration, delay);
      })
  );

  // SVGの生成
  const rippleSVGs = ripples.map(ripple => ripple.toSVG()).join('');

  const svg = `
    <svg 
      viewBox="0 0 ${width} ${height}" 
      xmlns="http://www.w3.org/2000/svg"
      style="background: #0D1117">
      <rect width="100%" height="100%" fill="#0D1117"></rect>
      <g>${rippleSVGs}</g>
    </svg>
  `;
}

4. SVGアニメーションの実装

toSVG() {
  return `
    <circle
      cx="${this.x}"
      cy="${this.y}"
      r="0"
      fill="${this.fillColor}"
      stroke="#4B9EF9"
      stroke-width="1"
      opacity="0.8">
      <animate
        attributeName="r"
        begin="${this.delay}s"
        from="0"
        to="${this.size}"
        dur="${this.duration}s"
        fill="freeze"
        values="0; ${this.size}"
        keyTimes="0; 1" 
        keySplines="0 0.8 0.5 1"
        calcMode="spline"></animate>
      <animate
        attributeName="opacity"
        begin="${this.delay}s"
        from="0.8"
        to="0.2"
        dur="${this.duration}s"
        fill="freeze"></animate>
    </circle>
  `;
}

5. GitHub Actionsの設定詳細

name: Generate GitHub Animation
on:
  schedule:
    - cron: "0 */24 * * *"  # 24時間ごとに実行
  workflow_dispatch:  # 手動実行も可能
  push:
    branches:
      - main  # mainブランチへのプッシュでも実行

jobs:
  generate:
    permissions:
      contents: write  # リポジトリへの書き込み権限
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - name: Setup Node.js
        uses: actions/setup-node@v3
        with:
          node-version: '18'
      - name: Install dependencies
        run: npm install
      - name: Create Animation
        run: |
          mkdir -p dist
          npm run generate
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

これらのコードが組み合わさることで、GitHubの活動状況に基づいた動的なアニメーションが生成され、自動的にプロフィールページに反映する事ができるようになります。

おわりに

GitHubプロフィールをアニメーションで彩ることで、より魅力的な自己表現が可能になります。このような動的な要素を加えることで、プロフィールページが単なる情報の羅列ではなく、見る人の興味を引く展示になる事でしょう。

SVGアニメーションについては、より自分らしく楽しいものを作成しましょう!皆様も、ぜひ自分なりのアニメーションを作ってGitHubプロフィールを華やかにしてみてはいかがでしょうか。

参考資料


コメントを残す

メールアドレスが公開されることはありません。

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください