mcpField
S
shaders-cursor-ripples

shaders-cursor-ripples

github.com/boraoztuncデザイン・UI43495 回インストール11 週間前に更新
リポジトリ

shaders-cursor-ripples について

shaders-cursor-ripples は、ページ画像に CursorRipples のシェーダー効果を適用する開発スキルです。ポインターに反応する画像の歪みを実装する際に、遅延読み込み、静的画像へのフォールバック、WebGPU の確認、視差効果の軽減への対応を示します。

主な機能

  1. 01画像へのポインター連動リップル適用
  2. 02React、Vue、Svelte、Solid に対応
  3. 03シェーダーモジュールの遅延読み込み
  4. 04アクセシブルな静的画像フォールバック
  5. 05WebGPU と視差効果の軽減への対応

活用シーン

  1. 01ページ内メディアへのポインター連動歪みの追加
  2. 02WebGPU 非対応時も画像を表示
  3. 03従来のスポットライト式画像リビールの置き換え

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/boraoztunc/skills --skill shaders-cursor-ripples

インストール後、Claude Code で/shaders-cursor-ripplesを入力して読み込まれたか確認します。

同梱ファイルREFERENCES.md

詳細

Shaders カーソルリップル

基本契約

  1. 既存のページ、コンテンツ、セマンティック画像を維持します。
  2. shaders をインストールし、使用中のフレームワーク用サブパスからインポートします。
  3. 1 つの Shader キャンバスを通して元画像を描画します。
  4. ImageTexture の後に CursorRipples を配置し、この画像を後処理します。
  5. ルートに toneMapping="aces" を維持します。
  6. カーソルの追跡は Shaders に任せます。独自のスポットライト座標、放射状マスク、重複するリビール画像、ポインターアニメーションループは削除します。
  7. アクセシブルな読み込み時および WebGPU 非対応時のフォールバックとして、キャンバスの下に実際の画像を 1 枚配置します。
  8. モーション低減が有効な場合と WebGPU 非対応の場合は、シェーダーを無効にします。
  9. 初期ページバンドルがライブラリで肥大化しないよう、シェーダーコードを遅延読み込みします。

ユーザーがシェーダーエフェクトのみを求めている場合は、参考例のリボン、ブロブ、グロー、タイポグラフィ、レイアウト、コピー、色、アイデンティティをそのまま使わないでください。Shaders の Water コンポーネントで代用しないでください。CursorRipples はインタラクティブな画像変位エフェクトです。

編集前の確認

  • 実際のメディアラッパー、画像 URL、クロップ、オーバーレイ、z-index、既存のモーションを確認します。
  • ラッパーのレンダリング幅と高さがゼロでないことを確認します。
  • data-reveal-hover、mask-image: radial-gradient、重複画像、requestAnimationFrame、手動のポインターリスナーなど、古いリビールコードを検索します。
  • シェーダーキャンバスと競合しない限り、無関係な視差効果や出現時のモーションは維持します。
  • パッケージが変更されている可能性がある場合は、インストール済みの shaders のバージョンと最新のフレームワーク API を確認します。

インストール

npm install shaders

shaders/react、shaders/vue、shaders/svelte、または shaders/solid からインポートします。Vite プロジェクトでは、shaders を optimizeDeps.exclude に絶対に追加しないでください。CommonJS の依存関係には Vite の事前バンドルが必要です。通常、optimizeDeps の設定は必要ありません。

これは有料の非 OSS 依存関係です。 shaders パッケージには独自の 「Shader Effects License Agreement」が同梱されており、npm では license: None と報告されます。つまり、 権利の付与は支払いを条件とします。MIT/Apache ライセンスではなく、 無料の推移的依存関係として扱うことはできません。有料依存関係を利用する商用リリースの前にライセンスを確認し、 有料依存関係を利用できないプロジェクトでは webgl-laser または独自実装のシェーダーを 使用してください。

必須の構成

以下のコンポーネント順序と値を維持します。

<Shader toneMapping="aces">
  <ImageTexture url={imageUrl} objectFit="cover" />
  <CursorRipples decay={7.3} radius={0.6} />
</Shader>

intensity、chromaticSplit、edges を調整する前に、これをベースラインとして使用します。ユーザーが参考例の生成アートワークを明示的に求めていない限り、SolidColor、Blob、Form3D、GaborNoise、Glow、その他のジェネレーターを追加しないでください。

React では、assets/react/cursor-ripple-shader.tsx と assets/react/cursor-ripple-media.css をコピーして調整します。

クライアントとフォールバックのパターン

ブラウザーで WebGPU が利用可能で、モーションが許可されていることを確認してから、シェーダーをマウントします。

const CursorRippleShader = lazy(() => import("./cursor-ripple-shader"));

const [shaderEnabled, setShaderEnabled] = useState(false);
const [shaderReady, setShaderReady] = useState(false);

useEffect(() => {
  const reduceMotion = window.matchMedia("(prefers-reduced-motion: reduce)");

  const sync = () => {
    const enabled = "gpu" in navigator && !reduceMotion.matches;
    setShaderEnabled(enabled);
    if (!enabled) setShaderReady(false);
  };

  sync();
  reduceMotion.addEventListener("change", sync);
  return () => reduceMotion.removeEventListener("change", sync);
}, []);

ラッパー内にセマンティック画像を残し、その上に遅延読み込みしたシェーダーを重ねます。

<figure className="cursor-ripple-media">
  <img
    className="cursor-ripple-media__fallback"
    src={imageUrl}
    alt={meaningfulAlt}
    width={width}
    height={height}
  />

  {shaderEnabled ? (
    <Suspense fallback={null}>
      <CursorRippleShader
        imageUrl={imageUrl}
        ready={shaderReady}
        onReady={() => setShaderReady(true)}
      />
    </Suspense>
  ) : null}
</figure>

Next.js では、ssr: false を指定した動的インポートも有効です。シェーダーで onReady が呼び出されるまでフォールバックを非表示にしないでください。WebGPU の初期化に失敗した場合でも、ページの内容を判読可能な状態に保ち、必要な情報をすべて表示する必要があります。

レイヤーのルール

  • メディアラッパーに position: relative、明確なサイズ、overflow: hidden、isolation: isolate を設定します。
  • フォールバックを z-index 0、キャンバスを z-index 1 にします。
  • position: absolute; inset: 0; width: 100%; height: 100% でラッパー全体を埋めます。
  • Shaders はグローバルにリッスンし、キャンバスの境界を使ってポインター座標を変換するため、シェーダーレイヤーに pointer-events: none を設定します。
  • アクセシブルな名前はフォールバック画像が担うため、シェーダーラッパーに aria-hidden="true" を設定します。
  • エフェクトが操作を妨げないよう、コピー、リンク、コントロールはキャンバスより上に配置します。
  • フォールバックと ImageTexture で同じクロップを維持します。全画面メディアには objectFit="cover" を使用します。

失敗したスポットライトパターンの削除

古い実装は隠したままにせず、削除してください。

  • 2枚目の表示画像
  • 放射状の mask-image とカスタム表示変数
  • ポインター位置に連動するスモークやぼかしのオーバーレイ
  • コンポーネント内でポインターをイージングする requestAnimationFrame
  • フラッシュライト専用に作られた pointerenter、pointermove、pointerleave、およびリサイズ関連の処理
  • 廃止した表示レイヤーを参照する coarse-pointer ルール

両方のシステムを残すと、座標のずれ、GPU 負荷の増加、紛らわしいフォールバックが発生します。

パフォーマンスとモーション

  • WebGPU のチェック後にシェーダーモジュールを遅延読み込みします。
  • メディアパネル用のシェーダーキャンバスは1つだけにします。
  • ライブラリの onReady コールバックを使って、短時間の不透明度の切り替えを行います。
  • テレメトリが不要な場合は disableTelemetry を使用します。
  • キャンバスのサイズはアニメーションさせず、視差が必要な場合はサイズが安定した親要素をアニメーションさせます。
  • prefers-reduced-motion: reduce の場合は、シェーダーを無効化するかアンマウントします。
  • タッチレイアウトでも静的画像を使いやすくし、エフェクト内に重要な情報を配置しないでください。

検証

プロジェクトの lint、プロダクションビルド、レンダリングテスト、git diff --check を実行します。その後、実際のブラウザーで次の点を検証します。

  1. canvas[data-renderer="shaders"] が1つだけ存在することを確認します。
  2. シェーダーが ready クラスに到達し、フォールバック画像が表示されたままであることを確認します。
  3. メディア内の複数の位置にポインターを移動します。切り離された円が現れず、歪みがその軌跡に沿って動く必要があります。
  4. リンクとコントロールがクリックできることを確認します。
  5. コンソールにエラーや警告がないことを確認します。
  6. WebGPU が利用できない場合や、動きを減らす設定が有効な場合も、静的画像が表示されたままであることを確認します。
  7. 古い data-reveal-hover レイヤーや放射状マスクレイヤーが存在しないことを確認します。
  8. キャンバスの初期化後に、モバイルとデスクトップでの切り抜きを確認します。

失敗の診断

  • キャンバスは存在するが空白になる: ラッパーの寸法がゼロではないこと、画像 URL が同一オリジンであるか CORS で読み取れることを確認します。
  • 画像は描画されるが波紋が出ない: CursorRipples を ImageTexture の後に置きます。子要素/入力サーフェスが必要です。
  • 波紋の位置がずれる: 手動のポインター変換を削除し、変換された祖先要素によってキャンバスの境界が変わっていないか確認します。
  • SSR 中にページがクラッシュする: シェーダーをクライアント専用の遅延読み込みコンポーネントに移します。
  • 読み込み時に画像がちらつく: フォールバックを維持し、onReady の後にのみシェーダーをフェードインさせます。
  • 初期バンドルが大きくなる: Shaders のインポートが遅延モジュール内だけにあることを確認します。
  • エフェクトがボタン操作を妨げる: キャンバスをポインターイベントを透過するようにし、コントロールをより高いスタッキングレイヤーに置きます。

引き継ぎ

影響を受けるメディア、Shaders パッケージのバージョン、フォールバックの動作、動きを減らす設定時の動作、ビルド/テストの結果、実際の操作による検証結果を報告します。ローカルでエフェクトが正常に動作する状態と、公開済みのデプロイを区別してください。

コメント