Vibresia について
Vibresia は、Mac で再生中の音楽をリアルタイムの映像にする macOS 用ビジュアライザーで、独自の映像表現も作成できます。付属のローカル MCP サーバーにより、AI エージェントが映像を記述し、コンパイルを確認して結果を見られます。
主な機能
- 01再生中の音楽をリアルタイムのシーンに変換
- 02独自の GLSL ビジュアライゼーションを作成
- 03リンクでビジュアライゼーションを共有
- 04ローカル MCP サーバーをエージェントから利用
- 05ビジュアライゼーションのコンパイルと確認
活用シーン
- 01音楽再生に合わせた動く映像の作成
- 02特定の音楽スタイルに合わせたシーンの制作
- 03オリジナルの映像表現をリンクで共有
- 04エージェントによるシェーダーの作成と反復確認
MCP 対応
アプリには、標準入出力で JSON-RPC を使うローカル MCP サーバーが付属します。エージェントはツールで映像表現を作成し、コンパイルを確認して画像を見られ、変更はアプリに反映されます。
設定
リモートサーバーはインストール不要です。クライアントを選んで設定をコピーするか、ワンクリックで導入できます。
https://vibresia.com/mcpclaude mcp add --transport http com-vibresia-music-visualizer https://vibresia.com/mcp{"mcpServers":{"com-vibresia-music-visualizer":{"type":"http","url":"https://vibresia.com/mcp"}}}Cursor で開く{"servers":{"com-vibresia-music-visualizer":{"type":"http","url":"https://vibresia.com/mcp"}}}VS Code で開く{"mcpServers":{"com-vibresia-music-visualizer":{"type":"http","url":"https://vibresia.com/mcp"}}}{"mcpServers":{"com-vibresia-music-visualizer":{"serverUrl":"https://vibresia.com/mcp"}}}コマンドはターミナルで実行し、JSON は各クライアントの MCP 設定に貼り付けて再起動します。認可が必要なサーバーは初回接続時にログインを求めます。
ツール
詳細
Vibresia
音楽に合わせて動くビジュアルの世界を楽しめる、無料の macOS アプリです。Mac で再生中の音声を聴き取り、ネオンの波形から、楽器の音を聴くとステージを歩き始めるピクセルアートのバンドまで、リアルタイムのシーンに変換します。自分で世界を作ることも、AI アシスタントに作ってもらうこともできます。
ウェブサイトとインストール: https://vibresia.com
curl -fsSL https://vibresia.com/install.sh | bash
AI アシスタントに「https://vibresia.com から vibresia をインストールして」と頼むこともできます。
気に入ったら、コーヒーをごちそうしてください。
バグを見つけた場合やアイデアがある場合は、Issue を作成してください。プルリクエストも大歓迎です。特に、新しい vibescape をお待ちしています。CONTRIBUTING.mdをご覧ください。
リポジトリの構成
| パス | 内容 |
|---|---|
VisualiserMac/ | macOS アプリ(Swift、SwiftUI、OpenGL)です。READMEをご覧ください。 |
site/ | ランディングページ、インストーラー(install.sh)、AI 向けインストール手順(install.md、llms.txt)です。 |
site/analytics.js | ランディングページの匿名のページビュー/クリック計測です。 |
site/github.js | GitHub API から取得する変更履歴とオープン Issue です。画面をスクロールして表示範囲に入ると取得されます。 |
worker/index.js | Cloudflare Worker です。./site を配信し、/download(リダイレクトと Discord 通知)を処理します。 |
worker/share.test.js | 共有 vibescape エンドポイントのテストです。 |
migrations/ | D1 スキーマです。テーブルは 1 つで、共有 vibescape ごとに 1 行です。 |
site/sitemap.xml、site/robots.txt | Google に通知する内容です。URL は 1 つです。プレーンテキストのエージェント向けページはクロール可能なままにし、リストには載せていません。 |
site/_headers、site/_redirects | Cloudflare のレスポンスヘッダー(キャッシュ、セキュリティ)と正規パスへのリダイレクトです。 |
scripts/check-vibescapes.sh | ランディングページに vibescape が掲載されていない場合、または構造化データのバージョンが古い場合に失敗します。 |
scripts/check-posthog.sh | サイトとアプリの送信先が異なる PostHog プロジェクトの場合に失敗します。 |
scripts/check-no-webhook-leak.sh | Discord の Webhook URL、通知トークン、共有トークンがリポジトリ内のどこかにある場合に失敗します。 |
wrangler.toml | Worker(および Worker 経由の site/)を Cloudflare にデプロイします。 |
開発
cd VisualiserMac
./build-app.sh debug # build/Vibresia.app
open build/Vibresia.app
カスタム vibescape とローカル MCP サーバー
vibescape はフラグメントシェーダーです。1 つの関数 vec3 render(vec2 p, float t) を用意すれば、ユニフォームやヘルパーなどはアプリがすべて提供します。
Vibresia にはローカルのMCPサーバーが付属しているため、AI エージェントはコードを手作業でコピーしなくても、vibescape を作成し、コンパイルを確認し、画像を見て、再度試すことができます。
claude mcp add vibresia -- "/Applications/Vibresia.app/Contents/MacOS/Vibresia" --mcp
これは --mcp を付けて実行する同じバイナリで、標準入力経由で JSON-RPC をやり取りします。ウィンドウもポートもなく、分析も行いません。アプリと同じファイルを読み書きするため、エージェントが作成した vibescape は 1 秒以内にアプリに表示されます。提供されるツールについては、VisualiserMac/README.mdをご覧ください。
バージョン番号
ビルドバージョンにはビルド日を使うため、番号を更新する必要はありません。
MAJOR.MINOR.PATCH
MAJOR は 2026 年からの経過年数、MINOR は月、PATCH は月内の日付とその日のビルド番号です。0.10.201 は 2026 年 10 月 20 日の最初のビルドを表します。
VisualiserMac/version.sh がバージョンを算出し、build-app.sh がアプリに埋め込みます。release.sh はリリースにタグを付ける前に VisualiserMac/VERSION とランディングページに記録するため、アプリ、サイト、git タグのバージョンは常に一致します。
ランディングページの分析
site/analytics.js は約180行の PostHog クライアントです。SDK、セッションリプレイ、Cookie は使わず、アプリと同じ PostHog プロジェクトにデータを送信し、surface プロパティ(web と mac_app)で区別します。
イベント:$pageview、demo_played、vibescape_card_viewed(スクロールして表示された vibescape カード)、download_clicked、install_command_copied(ask-ai または curl。異なるユーザー層なので、この内訳は注目に値します)、coffee_clicked(配置別)、outbound_clicked。
本番環境に触れずにイベントを確認するには、meta タグをローカルの受け口に向けます。
python3 - <<'PY'
p='site/index.html'; s=open(p).read()
open(p,'w').write(s.replace('https://us.i.posthog.com">','http://127.0.0.1:8099">'))
PY
(cd site && python3 -m http.server 8098) # then open http://127.0.0.1:8098
フッターにはワンクリックでオプトアウトする機能があり、Do Not Track にも対応しています。どちらの場合も、ページからのデータ送信はすべて停止します。
ダウンロード通知(Discord)
すべてのダウンロードは Worker の /download を経由し、最新の GitHub リリースへ 302 リダイレクトするとともに、Discord に埋め込みメッセージを投稿します。ページからではなくサーバー側で処理する理由は2つあります。HTML 内の Webhook URL は公開されてしまうこと、そして最後まで完了しなかったクリックはダウンロードとは言えないことです。
埋め込みメッセージには、ダウンロード元、都市/国(Cloudflare のジオロケーション情報)、リファラー、ブラウザー、そのブラウザーで以前にダウンロードしたことがあるかどうかが含まれます。
npx wrangler secret put DISCORD_WEBHOOK_URL # once; the webhook URL in Discord
npx wrangler deploy
curl https://vibresia.com/api/health # {"discord":"configured"}
アプリのエラー。 Webhook をアプリに含めることはできません(アプリのバンドル内にあるため、誰でも読めてしまいます)。そのため、アプリはこのサイトの POST /api/notify に投稿し、Worker が転送します。共有トークンを2つ目のシークレットとして設定し、同じ値をアプリに埋め込みます。
npx wrangler secret put NOTIFY_TOKEN # any random string
REPORT_TOKEN=<the same string> ./build-app.sh release
次の3種類の通知が届きます:audio_error(音声ソースが失敗した、または途中で途切れた場合のエラー。スタックトレースでは決して分からない障害です)、source_failure、app_crash(先頭のスタックフレームを含みます)。権限の確認を拒否するのはユーザーの選択であり、障害ではないため、報告されません。
2種類の音声レポートは、アプリ内の切り替え設定の対象外です。ユーザーがそのソースを明示的に選択しており、入力が機能しない問題はほかの方法では分からないためです。app_crash は対象です。PostHog へのクラッシュ情報のアップロードとともに送信されますが、この送信には「Share anonymous usage」が有効になっている必要があるため、これをオフにすると両方とも停止します。送信されるのはアプリの状態(vibescape、ジャンル、エラーテキスト)であり、音声やトラック名は含まれません。エラーには独自のクールダウンが設定されており(1分あたり1件、1時間あたり60件)、インストールに問題があってもチャンネルが通知であふれることはありません。また、DISCORD_ERRORS_ENABLED = "false" にすると、ダウンロード通知に影響を与えずにエラー通知を無効化できます。
ローカルでは、(gitignore 対象の).dev.vars で Webhook の送信先をスタブにします。
npx wrangler dev --port 8787
curl -s 'http://127.0.0.1:8787/download?src=hero&seen=0' -A 'Mozilla/5.0'
npm test # 13 tests, no network
注意事項:
- Webhook URL と通知トークンは、どちらも認証情報です。
scripts/check-no-webhook-leak.shは、どちらかがリポジトリ内に見つかると失敗します。delphina でも同じ問題があり、数十個のリリースタグに埋め込まれてしまいました。漏えいした場合は、Discord で Webhook を再作成し、wrangler secret putで新しいものを登録してください。 - ボットとリンクプレビューは除外されます。ボタンをダブルクリックしても投稿は1回のみです(5秒のデバウンス、1時間あたり30件)。また、投稿はタイムアウトと1回の再試行を伴って
ctx.waitUntil経由で行われます。そのため、Discord がダウンしてもダウンロードが遅くなったり、失敗したりすることはありません。 wrangler.tomlでDISCORD_NOTIFICATIONS_ENABLEDを"false"に設定して再デプロイすると、通知を無効にできます。いずれの場合もサイトは引き続き動作します。install.shは引き続き GitHub から直接ダウンロードするため、スクリプトによるインストールでは通知は送信されません。
共有されたビブスケープ
カスタムのビブスケープ、つまり誰かが作成したものは、以前は次のリンクにペイロードとして含まれていました:vibresia.com/share/?d=<base64 of the deflated shader>。バックエンドが一切なくても機能するため、この方式が採用されていました。しかし、リンクは約370文字あり、サーバーは末尾にスラッシュを追加するために307を返していました。WhatsAppのリンクプレビュークローラーはこれに追従しなかったため、プレビューは空白になり、チャットではリンクが壊れているように見えていました。
現在はペイロードを保存し、リンクを短くしています:
POST /api/share {payload, name, author, image, key} → {"url": "https://vibresia.com/s/k3f9x2"}
GET /s/k3f9x2 the share page, with the payload inlined
GET /og/k3f9x2.jpg a picture of this vibescape
- 同じビブスケープには常に同じリンクが割り当てられます。 以前は共有のたびに新規作成されていたため、新しい行、新しいID、新しいURLができ、同じビブスケープを2回共有するとリンクも2つになり、誰かから送られてきたものを再共有すると3つ目のリンクができていました。アプリはビブスケープの内容(名前、作者、URL、シェーダー)をハッシュ化して送信します。Workerはそのハッシュに一致する共有と、同じペイロードを持つ共有を探し、別のものを作成するのではなく、見つかった行を返します。
key列には部分ユニークインデックスがあるため、2台のデバイスから同時に共有しても、同じ1行にまとまります。 - リンクから届いたビブスケープは、届いたときのリンクを保持します。 ページは共有IDをディープリンクに含め、アプリはそれをビブスケープとともに記憶します。共有すると、そのリンクがそのまま使われます。あなたに送った人がそのリンクを送ってくれたのだから、あなたが送る相手にも同じリンクが届くべきです。ビブスケープを編集するとハッシュが変わり、独自のリンクが割り当てられます。
- 画像には作成者が表示されます。 アプリはアップロードする画像にVibresiaのマークとクレジットを入れます。サイトに組み込まれている画像も同じコードで描画されます。
VisualiserMac/Sources/VibresiaBrandをご覧ください。
ギャラリー
vibresia.com/vibescapesには、組み込みのビブスケープと、ユーザーが共有したビブスケープが、新しい順に1つのリストで表示されます。
ビブスケープを共有すると、誰でも開けるリンクが作成されます。ギャラリーはそれとは異なり、ビブスケープを一覧表示するため、掲載されたものは誰でも見つけられ、名前と作者も公開されます。共有シートにはそのことが表示され、デフォルトでオンになっているチェックボックスもあります。
- アプリが確認します。
POST /api/shareはpublicを受け取り、共有シートには名前の横にチェックボックスがあります。 - Workerが保存します。
is_public列に保存し、/vibescapes(ページ)と/api/gallery(同じ内容のJSON)で一覧を提供します。カードはサーバー側で作成されるため、ページはJavaScriptなしで動作し、クローラーにもリストが表示されます。 - 組み込みのビブスケープも含まれます。 初めて登場した日、つまりビブスケープに初めて言及したコミットの日付が付けられ、ユーザーが作成した共有と並べ替えられます。
scripts/generate-share-pages.pyがその日付を割り出し、共有マニフェストに書き込みます。カードには、共有用のフレーム付き画像ではなく、ほかのすべてのカードと同じ、加工されていない静止画を使用します。 - ギャラリーができる前に作成された共有は含まれません。 それらについては選択肢が提示されたことがなく、確認せずに公開すれば、誰かの名前をサイトのトップページに掲載することになります。チェックボックスをオンにして再共有すると、ギャラリーに掲載されます。
管理画面
vibresia.com/admin はリンクされておらず、サイトマップにも含まれていません。トークンを入力すると、ギャラリーに表示されているものも非表示のものも含め、すべての共有が一覧表示されます。それぞれに対して、次の3つの操作を行えます。
- 非表示にするとギャラリーから取り除かれますが、リンクは引き続き機能します。共有内容に問題はないものの、一覧には表示すべきでない場合に適しています。
- 表示にすると、ギャラリーに戻ります。
- 削除すると、行とリンクが削除されます。画像と名前も削除されます。元に戻せないため、最初に確認を求めます。
トークンは ADMIN_TOKEN という名前の Worker シークレットで、共有トークンとは別のものです。共有トークンはアプリ内に含まれているため、誰でもバンドルから読み取れます。このトークンはサーバーの外に出ることはなく、公開インターネットとギャラリーの間を隔てる唯一のものです。このページでは sessionStorage に保存するため、そのタブ内にだけ存在し、ほかの場所には保存されません。
npx wrangler secret put ADMIN_TOKEN
- Workers KV ではなく D1。 KV は結果整合性です。共有から10秒後にリンクを開いても、書き込みを認識していないエッジに接続されて404になる可能性があります。機能が使われたまさにその時に失敗することになります。D1 は SQLite ベースで強整合性があるため、リンクは作成された瞬間から機能します。無料で、1日あたり100,000行を書き込み、5,000,000行を読み取り、5 GBを保存できます。共有はペイロードと約120 KBの画像を含む1行です。
- ページはリダイレクト先ではなく、直接配信されます。 プレビュー用クローラーが追従しなかったのはリダイレクトでした。Worker は
/share/を取得し、その共有固有の部分、つまりタイトル、説明、保存された画像を指すog:imageを書き換えます。クローラーはページの JavaScript を実行しないため、HTML 自体が正しくなければなりません。 - 画像は vibescape です。 アプリは共有ページが静止画を描画するのと同じタイミング(6秒後なので、時間に応じて変化するものはすべて通常の状態に達しています)に、1200x630で画像をレンダリングします。そのため、チャットのプレビューには受信者が受け取る画像が表示されます。
- 長いリンクも引き続き機能します。 ペイロードがリンクに含まれているため、保存は不要です。サイトに接続できない場合、アプリはこの方式にフォールバックします。共有がネットワークに依存してはなりません。
エンドポイントにはトークンが必要ですが、これはロックではなく、速度を落とすためのものです。アプリ内に含まれているため、誰でもバンドルから読み取れます。防止するのは、スクリプトが共有を作成し、1日の書き込みクォータを使い切ることです。
npx wrangler secret put SHARE_TOKEN # once; the same value goes in VisualiserMac/.env
npx wrangler d1 migrations apply vibresia-shares --remote
node scripts/backfill-share-payload-hashes.mjs
順序が重要です。 マイグレーションでは Worker が共有を検索するために使う列を追加し、バックフィルでは列が存在する前に作成された共有のハッシュを埋めます。まずマイグレーションを実行し、次にバックフィルを実行してから、Worker をデプロイしてください。Worker はマイグレーションされていないデータベースでも動作し、以前と同様に共有をそれぞれ個別に保存する方式にフォールバックします。ただし、同じリンクを再利用する動作には新しい列が必要です。
SHARE_TOKEN は NOTIFY_TOKEN と同じ種類の認証情報なので、ツリーに含まれると scripts/check-no-webhook-leak.sh が失敗します。
公開 MCP サーバー
https://vibresia.com/mcp — リモートの Model Context Protocol サーバーです。ブラウザーで動作するエージェントは、アプリをインストールせず、GPU がどこにもなくても vibescape を作成できます。
これはアプリ内蔵のローカルサーバーと同じ考え方ですが、Mac が必要な機能は省いています。描画はできないため、プレビューの表示やシェーダーのコンパイル確認はできず、Mac で再生中の音楽を認識することもできません。できるのは、vibescape を作成し、lint を実行して、リンクを返すことです。
- 描画するのはブラウザーです。 シェーダーは Worker では実行できませんが、共有ページでは WebGL を使って vibescape をリアルタイムに描画します。そのため、ツールが返すリンクを開けば、すでに世界が動いています。アプリの有無にかかわらず、誰でも利用できます。
- 作成と共有は別々の操作です。
create_vibescapeは共有用のものを作成し、非公開リストにします。share_vibescapeはそれを公開ギャラリーに掲載します。共有のためのものなので、公開ギャラリーに掲載するのが適切です。 - 認証は不要です。 どちらのディレクトリにも掲載されており、アカウントを必要とするサーバーでは、本来利用してもらうための機能から利用者を締め出してしまいます。書き込みはアドレスごとにレート制限され、非公開リストに保存されるため、悪用によるコストを抑えられ、ギャラリーにも影響しません。
/.well-known/mcp.jsonは、MCP レジストリが読み取るディスカバリーファイルであり、そのドメインが、申告したサーバーを所有していることを証明する仕組みでもあります。
scripts/check-mcp-reference.py は、vibescape リファレンスの2つのコピー(アプリ版とウェブサイト版)に差異がある場合、リリースを失敗させます。これにより、エージェントがどちらに問い合わせても、異なる情報を伝えられることはありません。
npx wrangler secret put SHARE_TOKEN # only for the app's own sharing
python3 scripts/check-mcp-reference.py # and --write to copy the app's text over
変更履歴と未解決の課題
ランディングページの両セクションは、内容を埋め込むのではなく、実行時に api.github.com から読み込みます。そのため、デプロイの合間に情報が古くなることはありません。これを確実にするため、次の3つの対策を講じています。
- キャッシュ —
sessionStorageに15分間保存します。GitHub の未認証 API では、1時間あたりのリクエスト数が IP ごとに60回までであり、訪問者全員が同じ枠を使うことになるためです。 - 遅延読み込み — セクションが表示範囲に入ったときに取得を開始します。
- 障害で停止しない — GitHub がダウンしている場合、リクエストがレート制限された場合、または JSON の構造が変わった場合は、セクションにその旨を表示し、リポジトリへのリンクを残します。Issue のタイトルは、誰かがテキストボックスに入力した内容そのものであるため、
innerHTMLではなくtextContentを使って表示します。
SEO
- サイトマップを送信するには、Search Consoleで一度送信します —
https://vibresia.com/sitemap.xml。サイトをデプロイした後は再送信してください。lastmodも含まれています。 - 構造化データは、
index.html内のSoftwareApplicationとOrganizationのJSON-LDです。バージョンはビルド日付なので、手動で更新する必要はありません —VisualiserMac/version.sh --writeを実行すると、index.htmlとVisualiserMac/VERSIONの両方に書き込まれます。また、両者に食い違いがある場合、scripts/check-vibescapes.shがリリースを失敗させます。 - Cloudflareの
vibresia.comゾーンで**「Always Use HTTPS」を有効にします**。Worker独自のhttp:からhttps:へのリダイレクトも同じ役割を果たしますが、ゾーン設定を使うことで、重複したコンテンツがそもそも配信されないようにできます。古いaudiovane.minithlabs.com名はリダイレクト用に引き続きWorkerに紐付けられています — 詳しくは下記の注記を参照してください。 - 古いドメインはリダイレクト先であり、別のサイトではありません。
audiovane.minithlabs.comは同じWorkerに紐付けられており、パスを維持したままvibresia.comへ301リダイレクトします。そのため、古いインストールコマンドや古いリンクも引き続き動作します。これを機能させるには、DNSが引き続きCloudflareを指している必要があります。ドメイン変更で引き継げないものが一つあります。分析のオプトアウト設定はブラウザーのlocalStorageに保存され、オリジンごとに分かれているため、古いサイトで分析をオプトアウトした人は、新しいサイトでもう一度設定する必要があります。 - Workerはカスタムドメインではなく、ルートで紐付けられています。
vibresia.comはWorkerの作成前にCloudflareに向けられていたため、そのDNSレコードはCloudflareが作成したものではありません。カスタムドメインではそれらのレコードを所有する必要があり、上書きが拒否されます。ルートを使うと、DNSには手を加えずにホスト名をWorkerに紐付けられます。同じ理由でrun_worker_firstも有効になっています。リダイレクトはWorkerで決定されるため、エッジから直接配信されたアセットはリダイレクトを通らないからです。 - キャッシュはCloudflareのデフォルト設定(
max-age=0, must-revalidate)です。site/_headersのCache-Controlルールはこれを置き換えるのではなく、追加するため、この方法では変更できません。再訪時には5.9MBを再ダウンロードする代わりに、ETagによる304で再検証されます。重要なのはこの点です。 - ページは単一の静的ファイルで、H1が1つ、説明的なaltテキスト付きの遅延読み込み画像が16枚あり、フレームワークは使っていません。このまま維持してください — これらを導入する前のローカル計測では、LCPは約0.08秒、CLSは約0.005でした。
動画のエクスポート
共有シートを使うと、vibescapeの直近10秒間を音楽付きの動画としてDownloadsに保存できます。
映像には、アプリ独自のレンダラーを使います。ウィンドウで描画中のものと同じ描画を、アプリの時計の直近10秒間にわたって記録するため、vibescapeそのものを映像にします。映像を撮影するのではありません。音声には、アプリが聞いていたものの直近10秒間を使うため、実際に流れていた音楽がそのまま記録されます。
クリップの長さは、アプリが取得できた音声の長さになります。10秒間の音楽があれば10秒間のクリップになり、10秒未満しかなければその分だけになります。クリップを作成するには、アプリが何かを再生中の状態で聞いている必要があります。
./build/Vibresia.app/Contents/MacOS/Vibresia --export-video band /tmp/out.mp4
曲とジャンル
アプリが再生中の曲を特定できる場合、バンドのジャンルはその曲から判定されます。方法は2つあり、並行して使えます。
- **曲名による判定。**Apple MusicとSpotifyはどちらも、曲が切り替わると曲名とアーティスト名を含む通知を送ります。アプリは曲をAppleの公開カタログで検索し、カタログに登録されたジャンルを取得します。そのため、波形から推測するのではなく、その曲に合わせてステージが選ばれます。
VisualiserMac/Sources/VisualiserMac/Audio/SongIdentifier.swift - **音を聞き取って判定。**ShazamKitは音のシグネチャをShazamのカタログと照合します。この方法は、通知を送るプレーヤーだけでなく、ブラウザーや映画など、音を出すあらゆるものに対応します。
VisualiserMac/Sources/VisualiserMac/Audio/ShazamIdentifier.swift
現在リリースに含まれているのは1つ目の方法です。2つ目の方法は、Shazamのカタログとの照合をアプリに許可する必要があり、その許可は開発者ポータルでアプリの識別子に対してShazamKitサービスが有効かどうかによって決まるため、フラグで無効になっています。
ShazamKit に必要なものと、デフォルトで有効になっていない理由
Apple は、プロビジョニングプロファイルで署名されたアプリに com.apple.developer.shazamkit エンタイトルメントを発行します。このアプリは Developer ID 証明書で署名され、公証されているため、エンタイトルメントは署名に手動で宣言する必要があります。ただし、チームに付与されていないエンタイトルメントを宣言すると、ビルドが一致しないのではなく、アプリが起動しなくなります。macOS はプロセスを強制終了します。
$ SHAZAMKIT=1 ./build-app.sh debug && ./build/Vibresia.app/Contents/MacOS/Vibresia
Killed (exit 137)
エンタイトルメントなしでは同じアプリが実行されますが、マッチ結果は com.apple.ShazamCore error 102、つまり「許可されていない」であり、「見つからない」ではありません。
そのため、エンタイトルメントはオプトイン方式(SHAZAMKIT=1)になっており、開発者ポータルで com.minithlabs.visualiser の ShazamKit サービスが有効になり、かつ Apple が Developer ID 署名への使用を許可した場合にのみ、有効にする価値があります。
この調査用コードは引き続き残してあります。この疑問にはフォーラムへの投稿ではなく、答えを出す価値があるためです。
./build/Vibresia.app/Contents/MacOS/Vibresia --shazam-spike
マシンの外に送信されるもの
音声が外部に送信されることはありません。音声はローカルで解析され、ローカルで描画されます。また、バンドのステージはシェーダーが音声をどのように処理するかに基づいて描画されます。
音楽アプリが再生中の曲を知らせる場合、外部に送信されるのは曲の 名前 です。曲名とアーティスト名は Apple の公開カタログで検索されます。これは iTunes Store で行われる検索と同じものです。それ以外の情報は送信されず、アカウントも関与しません。カタログから返されるのはジャンルで、その後の判断はローカルで行われます。
検索結果を照合するには、曲名とアーティスト名の両方が一致する必要があります。カタログは「Redbone」の「Me and Your Mama」を喜んで返しますが、アーティストが同じでも曲は別です。曲が間違っていれば、ステージのジャンルも間違ってしまうため、明らかに正しい曲だと判断できない結果は使用せずに破棄します。カタログに曲が登録されていない場合、アプリは従来どおり音声ヒューリスティックにフォールバックするため、何も失われません。
音楽アプリを使わずに検索を試すには、次のようにします。
./build/Vibresia.app/Contents/MacOS/Vibresia --song-lookup "bad guy" "Billie Eilish"
バンドの調整
VisualiserMac/Tests/band-fixtures.yaml には、ジャンルと演奏者のラベルが付いた YouTube 動画が記載されています。scripts/band-eval.py は、Vibresia が聴いている間に Chrome で各動画を再生し、スコアカード(ジャンルは正しいか、ステージに正しいミュージシャンがいるか)を出力します。また、調整用に検出器の特徴量とジャンルごとのスコアを VisualiserMac/Tests/eval-results/ に保存します。Vibresia には、まずシステムオーディオの使用許可が必要です。実行中はほかの音声をオフにしてください。
scripts/band-eval.py --check # validate the fixtures file
scripts/band-eval.py # run them all (about a minute each)
scripts/band-eval.py --only jazz
リリース
- 新しいビブスケープを
site/index.htmlに追加します(data-vibescape="<case name>"を持つカード)。 VisualiserMac/release.shはサイトの両方のチェックを実行し、日付からバージョンを決定してVisualiserMac/VERSIONとランディングページに記録した後、ビルドし、Vibresia.appを ZIP 化して GitHub リリースv<VERSION>を公開します。インストーラーとアプリのアップデート確認は、常に最新のリリースを使用します。キーチェーンに Developer ID 証明書がある場合は、その一環としてリリースを公証します。バンドルに再度署名すると公証が無効になるため、ビルド後、ZIP 化する前にチケットをアプリにステープルします。署名と公証を参照してください。- サイトまたはワーカーに変更があった場合は
npx wrangler deployを実行し、続けてサイトマップを再送信します。クローン後、初回のデプロイではnpx wrangler secret put DISCORD_WEBHOOK_URLが必要です(ダウンロード通知を参照)。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。