mcpField
B
build-wireframe-scan-reveal

build-wireframe-scan-reveal

github.com/mengtoデザイン・UI7.1k1.2k 回インストール3 日前に更新
リポジトリ

build-wireframe-scan-reveal について

一時的なワイヤーフレームスキャンで、3Dオブジェクトの実体表面を表示するデザインスキルです。シーンの導入演出向けに、ワールド空間の波面でワイヤーケージとソリッドメッシュを連動させます。

主な機能

  1. 01単一のスキャンでワイヤーと実体を連動
  2. 02両方の表現をワールド空間に配置
  3. 03遅延を伴う不均一なスキャン前線をアニメーション
  4. 04一時的なケージを除去してリソース解放
  5. 05リプレイと視差軽減状態に対応

活用シーン

  1. 01ワイヤーフレームを先行させて3D形状を表示
  2. 02スケールされたシーングループ間でスキャンを同期
  3. 03リプレイを設けつつ視差軽減用の静止画を維持

インストール

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

$npx skills add https://github.com/mengto/skills --skill build-wireframe-scan-reveal

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

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

agents/
openai.yaml
demo/
index.html
PROMPT.md

詳細

ワイヤーフレームのスキャンリビールを作成する

1 つのワールド空間の波面で、2 つの表現を制御します。先端ではトポロジーを描画し、その後ろではソリッドを維持し、最後に一時的なケージを取り除きます。ワイヤーフレームがページの恒久的なビジュアル表現なら technical-wireframe-info-layout を、制御するのが 3D の波ではなく DOM のスクロールなら animation-on-scroll を使います。

inner-green-3d.html から抽出した手法です。カードやテキストを通り抜けながら、プロシージャルな苔の根が成長するサーベイパルスを、円形のマスクに見えないようにする必要がありました。

2 つの表現を組み合わせる

同じソースジオメトリから、ソリッドメッシュと一時的な LineSegments ケージを作成します。両方のマテリアルで uScanOrigin、uScanRadius、時間を共有します。両方をワールド空間に保ちます。グループをスケーリングまたはネストするとローカル空間での距離が変わり、2 つの波面がずれてしまいます。

先端より遅れてソリッドを破棄し、ケージが先に見えるようにします。

uniform vec3 uScanOrigin;
uniform float uScanRadius;
uniform float uScanEnabled;

bool unscanned(vec3 worldPosition, float lag) {
  if (uScanEnabled < 0.5) return false;
  float wobble =
      sin(worldPosition.y * 0.011 + worldPosition.x * 0.007) * 36.0
    + sin(worldPosition.z * 0.021 + worldPosition.y * 0.013) * 17.0;
  return distance(worldPosition, uScanOrigin)
       > uScanRadius - lag + wobble;
}

// In the solid fragment shader:
if (unscanned(vWorldPosition, 520.0)) discard;

シルエットの外側、通常は左下に 1 つの原点を置きます。中央に置くとローディングリングのように見えます。2 つの長いサイン項は維持します。完全な円形の波面はクリップパスのように見え、高周波ノイズはエッジをきらつかせます。

ケージを波面に追従させる

各ラインフラグメントと同じ半径との距離を測定します。

float distanceFromOrigin = distance(vWorldPosition, uScanOrigin);
float rim = exp(-pow((distanceFromOrigin - uScanRadius) / 135.0, 2.0));
float trail = smoothstep(uScanRadius, uScanRadius - 950.0, distanceFromOrigin);
float alpha = (rim * 1.60 + trail * 0.34) * uWireOpacity;

加算ブレンディング、transparent: true、depthWrite: false、シーンのアクセントカラーを淡くした色を使います。オブジェクト越しにケージを見せる必要がない限り、深度テストは有効にしておきます。深度テストを無効にすると、密なトポロジーの背面が露出し、明るく判読しにくい球体になります。

1 つの制御役をアニメーションさせる

実装済みのタイミングを出発点として使います。

パラメーターデフォルト防止できる問題
duration3.4 sリビールが速すぎるとフラッシュのように見えます
半径のイージング1 - (1 - t)^1.35線形の移動では、視覚的に遠い角の手前で停滞します
ソリッドの遅延520 ワールド単位遅延がないと、ワイヤーと塗りつぶしが一度にワイプされます
リムの幅135 単位リムが狭いとエイリアスが発生し、広いと霧のようになります
ワイヤーの軌跡950 単位軌跡がないと、トポロジーを読み取る前に隠れてしまいます
ワイヤーのフェードsmoothstep(.72, 1, t)ケージが残り続けると、完成した表面と競合します
半径の到達距離シーンの対角線 × 1.3 + 900完了後も遠い角がクリップされたままになります

タイムラインの最初の 6% でケージを表示し、最後の 28% でフェードさせます。

const e = Math.min(1, elapsed / 3.4);
scanRadius.value = easeOutPow(e) * maxRadius;
wireOpacity.value = Math.min(1, e / 0.06) * (1 - smoothstep(0.72, 1, e));

完了時には破棄処理の分岐を無効にし、ケージを取り除いて、そのジオメトリとマテリアルを破棄します。透明度で隠すだけでは、ページの残りの表示期間中も重複したジオメトリとシェーダー処理が動き続けます。

スキャンを配置してサイズを調整する

レイアウトが確定し、親の行列が更新された後に maxRadius を計算します。ResizeObserver を使い、ルートのサイズが 0 の場合を処理し、カメラの投影を更新してから、原点と最遠到達距離を再計算します。フォントやレイアウトが確定する前に一度だけ測定すると、最後の角が表示されないままになります。

デモでは、見覚えのあるシーンを維持します。グレーグリーンの背景、下部の光だまり、白いエディトリアル風のテキスト、淡いカード、根の形をしたフォームを使います。こうした演出はデモに属します。再利用できる手法は、2 つの表現と共有する制御役だけです。

モーションとライフサイクルに配慮する

  • prefers-reduced-motion: reduce の場合は、ケージとソリッドの両方を表示した、半径約 62% のデザイン済み診断用静止画をレンダリングします。リプレイコントロールで静止画を再構成し、状態を通知します。シーンを隠してはいけません。
  • dt を 1/30 秒に制限します。非表示タブや画面外のセクションが再開したら、時間の基準をリセットします。
  • document.hidden の場合や、IntersectionObserver でセクションが画面外と判定された場合は一時停止します。
  • デバイスのピクセル比を 2 以下に制限します。
  • リプレイは、フォーカスが見える実際のボタンと aria-live ステータスで提供します。キャンバスが装飾目的の場合は、aria-hidden を設定します。
  • ティアダウン時には、フレームをキャンセルし、オブザーバーを切断し、リスナーを削除して、ジオメトリ、マテリアル、テクスチャ、レンダラーを破棄します。

コストを正直に伝える

一時的な第2の表現と、その線が覆う範囲が実際のコストです。半径の計算より、トポロジーの密度とオーバードローのほうが重要です。ワイヤーケージは導入時にのみ作成し、シルエットを保てる最も粗いエッジグラフを使い、スキャンが終わったらすぐに破棄してください。ケージの描画パスの前後で GPU のフレーム時間を計測せずに、パフォーマンスが向上すると主張しないでください。

検証

  • 1440×900 で、開始時、中間時、完了時の状態を元のものと比較します。
  • スケーリングされた子グループも含め、あらゆる場所でケージがソリッドより先行することを確認します。
  • 完了まで早送りし、クリッピングされた島状の部分が残っていないことを確認します。
  • 2 回再生し、フレームループとケージがそれぞれ 1 つだけ残ることを確認します。
  • スキャン中に 390×844 と 1440×900 へサイズ変更します。
  • Tab キーで再生ボタンに移動し、フォーカスが表示され、ステータスが更新されることを確認します。
  • ?reduced=1 またはシステムの視差効果を減らす設定をテストします。合成済みの静止画が表示され、半径が進まないことを確認します。
  • タブを非表示にしてから再表示し、ビューポートから出て再び入ります。時間が飛ばないことを確認します。
  • コンソールに問題がなく、完了後にケージのリソースが破棄されていることを確認します。

動作確認には demo/index.html を使い、再作成またはリミックスするには demo/PROMPT.md を使ってください。

コメント