0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ElectronとTypeScriptベースのVRChatの写真を使ったフレンド関係Viewerを作ってみた

Last updated at Posted at 2025-02-03

main.png

Electronを活用したデスクトップアプリケーション、JavaScriptベースのフロントエンド、そしてTypeScriptベースのバックエンドを組み合わせ、VRChatの写真を解析・メタデータを抽出した上で友達ネットワークを可視化するフルスタックアプリケーションを作ってみました。

ダウンロードやSource Codeに関しては下記のリンクを確認してください。


1. 使用技術スタックと開発環境

バックエンド

  • 言語/フレームワーク: TypeScript, Node.js, Express
    → バックエンドAPIサーバーはExpress/RESTful APIをベースに構築され、TypeScriptの強力な型検査とモジュールシステムにより、安定したコード構造が保たれています。
  • ファイルシステム操作: Node.js組み込みモジュール(fs, path)および fs-extra
    → 画像ディレクトリの探索、メタデータファイルの読み書き作業を行います。
  • HTTPリクエスト処理および外部連携: node-fetch, form-data
    → 画像アップロード時に外部一時ファイルホスティングサービス(tmpfiles.org)と連携します。
  • リアルタイム進捗状況更新: Server-Sent Events (SSE)
    → メタデータ生成作業の進捗状況をリアルタイムでクライアントにストリーミングします。

フロントエンド

  • 言語/ライブラリ: JavaScript, HTML, CSS, d3.js
    → VRChatの友達ネットワークの可視化は、d3.jsのforce simulationを活用して実装され、ユーザーとのインタラクション(検索、スライダー、ズーム、ドラッグなど)をサポートします。
  • UIフレームワークとスタイリング: CSS
  • 通信: fetch API, EventSource (SSE)
    → バックエンドとのデータ通信や、リアルタイムの進捗状況更新に使用されます。
  • Electronレンダラープロセス
    → Electron内でHTML/CSS/JavaScriptで作成されたフロントエンドが、デスクトップアプリケーションとして動作します。

2. バックエンド:画像メタデータのパースとAPIサーバー

2-1. 画像メタデータのパース

バックエンドの主要機能のひとつは、VRChatの写真(PNGファイル)内に含まれるメタデータを抽出することです。写真には、PNG標準のiTXtチャンクを利用してJSON形式のメタデータが埋め込まれています。
主要な実装ロジックは src/utils/pngParser.ts に実装され、以下の手順でメタデータを抽出します。

  1. PNG形式の検証: PNGファイルのシグネチャ(137,80,78,71,13,10,26,10)を確認します。
  2. チャンクのパース: ファイルデータを順次読み込み、各チャンクの長さ、タイプ、データ、CRC値をパースします。
  3. iTXtチャンクの抽出とパース: iTXtチャンクが存在する場合、そのチャンクからテキストデータを抽出し、JSONとしてパースします。
    もしiTXtチャンクが存在しない場合は、デフォルトで現在の時刻とファイル名を含む空のメタデータオブジェクトを返します。

pngParser.ts 主要コードスニペット

private extractMetadata(data: Buffer): any {
  if (!this.isPNG(data)) {
    throw new Error("Invalid PNG format");
  }

  const chunks = this.parseChunks(data);
  const iTXtChunk = chunks.find(chunk => chunk.type === "iTXt");

  if (!iTXtChunk) {
    return {
      timestamp: new Date().toISOString(),
      filename: path.basename(this.filePath),
      metadata: {}
    };
  }

  try {
    const metadata = this.parseITXtChunk(iTXtChunk.data);
    return {
      ...JSON.parse(metadata),
      timestamp: new Date().toISOString(),
      filename: path.basename(this.filePath)
    };
  } catch (error) {
    throw new Error(`Failed to parse metadata: ${error instanceof Error ? error.message : "Unknown error"}`);
  }
}

2-2. メタデータの構造と含まれる情報

メタデータはPNGファイルのiTXtチャンク内にJSON文字列として保存されます。一般的に含まれる情報は以下の通りです:

  • timestamp: メタデータ生成時刻(バックエンドでデフォルト値として追加)
  • filename: 元のPNGファイル名
  • metadata: ユーザーまたはシステムによって挿入された追加情報
    → 例として、VRChat内での友達関係を表現するためのfriend ID、友達間の相互作用回数、タグ情報などが含まれる可能性があります。

この構造により、バックエンドは各JSONファイルを読み込み、VRChatの友達ネットワークデータに変換し、d3.jsによる可視化に必要なノードとリンクのデータを生成できます。

2-3. APIサーバーとSSEによる進捗状況更新

バックエンドのExpressサーバーは、さまざまなAPIエンドポイントを提供しています。代表的なエンドポイントは以下の通りです:

  • /api/metadata/generate: PNGファイルをスキャンし、メタデータを生成する作業を開始し、SSEを通じて "start"、"progress"、"complete" などのイベントをストリーミングします。
  • /api/metadata/date-range, /api/metadata/filter: メタデータファイルの日付範囲を計算したり、特定期間内のファイルのみをフィルタリングします。
  • /api/upload/image: クライアントから送信されたBase64画像データを外部ホスティングサービスにアップロードします。

SSEを使用したリアルタイム更新により、ユーザーはメタデータ生成作業の進捗状況を確認し、必要に応じて作業を中断することが可能です。


3. フロントエンド:VRChat友達ネットワークの可視化

3-1. データの可視化とd3.js

フロントエンドでは、d3.jsを利用して友達ネットワークを可視化します。主要な実装は public/js/network-visualization.js にあり、force simulationを通じてノードとリンクの物理的な配置を計算します。
例えば、以下のコードでは各ノードの大きさと色は出現回数(友達関係の頻度など)に基づいて決定され、リンクは関係強度により線の太さと透明度が調整されます。

ネットワーク可視化コードスニペット

const simulation = d3.forceSimulation(filteredNodes)
  .force('link', d3.forceLink(currentLinks)
    .id(d => d.id)
    .distance(d => 200 / (d.strength || 1)))
  .force('charge', d3.forceManyBody().strength(d => -500 * Math.sqrt(d.count)))
  .force('collide', d3.forceCollide().radius(d => Math.sqrt(d.count) * 10 + 20))
  .force('x', d3.forceX(width / 2).strength(0.03))
  .force('y', d3.forceY(height / 2).strength(0.03));

3-2. UIとインタラクション機能

フロントエンドはElectronのレンダラープロセス内で動作し、ユーザーとの多様なインタラクションをサポートします。

  • 検索機能: 特定の友達名でノードをハイライトし、関連するリンクのみを強調表示します。
  • 日付スライダー: メタデータの日付範囲に基づいてフィルタリングし、特定期間のデータのみを可視化します。
  • 共有およびエクスポート: SVGエクスポートやPNG変換を通じて生成されたネットワークグラフを外部に共有可能にします。
  • ローディングオーバーレイと進捗状況表示: メタデータ生成作業中は、ローディングスピナーとともに現在の進捗状況をリアルタイムでユーザーに表示します。
0
2
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
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?