そのWeb演出、Claude Codeで作れます。クリエイティブWeb表現のプロンプト集 #03 Generative Topography
株式会社グルーヴサインの米沢です。
AIコーディングでクリエイティブなWeb表現を実際に作り、そのプロンプトごと公開していく「PROMPT → WEB」の第3回です。
PROMPT → WEB #003
Generative Topography
INTRODUCTION
ブラウザで絵を描く方法は、大きく3つあります。
- WebGL ── GPUを使う。3Dや大量の粒子に強い(#01 Generative Particle Journey)
- Canvas 2D ── CPUでピクセルを塗る。文字や図形に素直(#02 Kinetic Typography)
- SVG ── ベクターの「線」を、DOMの要素として扱う
このシリーズは毎回まったく別の技術と別のデザインで作ると決めています。1回目がWebGL、2回目がCanvas 2Dでしたので、今回は3つ目の SVG です。
SVGは、ロゴやアイコンの入れ物として使われることが多い技術です。しかしSVGの本質は「線そのものをデータとして持てること」にあります。拡大しても劣化せず、CSSやJavaScriptから1本ずつ操作でき、印刷にも耐える。この性質が最も似合う題材は何かと考えて、地形図の等高線にしました。
作ったのは、ジェネラティブに生成された地形の等高線が、製図機(プロッタ)のように左から描き出されていく表現です。色は宇宙でも紙でもなく、墨色の地に銅から金へのグラデーション。測量図のような、静かで理知的な方向を狙いました。
RESULT
まず現物です。下のボタンを押してみてください。
クリックすると、この画面の上で Generative Topography が再生されます(何度でも再生可能)。ESC または CLOSE で終了します。
記事の上に暗い画面が広がり、等高線が左から描かれていきます。操作は2つあります。
- カーソルを動かす(スマホは画面をなぞる) ── その位置の地形が隆起し、等高線が再計算されます。同時にカーソルが「熱源」になり、近くの線は白熱した金色に、遠くの線は冷えた青灰色に変わります。
- クリックする(スマホはタップ) ── そこから衝撃波が走ります。閃光のリングが広がり、その峰で等高線が圧縮されて金色の帯になり、内側には波の谷ができて地面が沈みます。熱も一緒に押し広がります。
地形そのものもゆっくり変化し続けるので、同じ絵は二度と出ません。ESC または CLOSE で終了します。
画像でも動画でもなく、その場で計算してSVGの線を引いています。この演出をClaude Codeに作らせるためのプロンプトは、記事の後半でそのまま公開しています。
WHAT WE MADE
技術的に分解すると、次のようになります。
- 描画はSVGのみ ──
<canvas>もWebGLも使わず、<path>要素のd属性を毎フレーム書き換えています。 - 3Dノイズによる標高場 ── 値ノイズを3オクターブ重ねたfbmで、自然な起伏を生成。3軸目に時間を使うことで、地形がなめらかに変化し続けます。
- マーチングスクエア法による等高線抽出 ── 標高のデータから「高さがちょうど◯◯の場所」を線として取り出します(後述)。
- プロッタ風の描き出し ──
clipPathの矩形を左から広げ、描画ヘッドの線を走らせています。 - ポインタによる隆起 ── カーソル位置を中心にガウシアンの山を標高場へ加算。等高線が実際に計算し直されるため、山ができて線が密集します。
- カーソルに追従する色温度 ── カーソルを中心とした放射グラデーションを、等高線全体の「線の色」として与えています。中心が白熱、外周が冷えた青灰色。後述しますが、これはSVGでしか書けない類の実装です。
- クリックで走る衝撃波 ── 時間とともに半径が広がり振幅が減衰するリングを標高場に加算します。峰の内側に谷を作ることで、地面が持ち上がって沈む実際の衝撃波に近い挙動になります。さらに閃光のリング(
<circle>1つ)を峰に重ね、熱の半径も一時的に押し広げています。 - 測量図の意匠 ── 5本ごとの計曲線(太い線)、外周の目盛り、等幅フォントの計器表示。
HOW IT WORKS
この作品の心臓は マーチングスクエア法 です。名前は難しそうですが、考え方は驚くほど単純です。
まず画面を格子に区切り、各交点の「標高」を計算しておきます。そして格子の1マスごとに、4つの角のうちどれが基準の高さを超えているかを見ます。超えていれば1、超えていなければ0。4つの角なので、組み合わせは2の4乗=16通りしかありません。
この16通りそれぞれについて「線をどう引くか」は決まっています。たとえば左上の角だけが基準を超えているなら、線は左辺と上辺を斜めに横切る。あとは、その辺のどのあたりを通るかを線形補間で求めるだけです。
// 1マス分の処理(イメージ)
let idx = 0;
if (a > level) idx |= 8; // 左上
if (b > level) idx |= 4; // 右上
if (c > level) idx |= 2; // 右下
if (d > level) idx |= 1; // 左下
if (idx === 0 || idx === 15) continue; // 全部同じ側 → 線は通らない
// 辺のどこを通るかは線形補間で求める
const top = x0 + cell * ((level - a) / (b - a));
switch (idx) {
case 1: case 14: 線を引く(左, 下); break;
case 2: case 13: 線を引く(下, 右); break;
case 3: case 12: 線を引く(左, 右); break;
// …16通り分
}
これを高さを変えて13回繰り返せば、13本の等高線群ができあがります。天気図の等圧線も、医療画像の輪郭抽出も、原理は同じものです。
SVGでの実装上のコツは、1本の高さにつき <path> 要素を1つだけ使うことです。線分ごとに要素を作るとDOMが数千個に膨れ上がって重くなりますが、d 属性の中に M…L… を並べれば、1要素で何百本もの線分を持てます。毎フレーム更新するのは13個の属性だけ。SVGでもこの規模ならなめらかに動きます。
色温度は、グラデーションを「線の色」にする
カーソルの周りだけ色を変えたい。素直に考えると、線を1本ずつ、カーソルからの距離に応じて塗り分けることになります。しかし線分は数千本あるので、その方法では現実的な速度が出ません。
SVGには、もっと良い手があります。グラデーションを、塗りではなく「線の色」として指定できるのです。
<radialGradient id="heat" gradientUnits="userSpaceOnUse" cx="640" cy="360" r="800">
<stop offset="0" stop-color="#fffaf0"/> <!-- 中心:白熱 -->
<stop offset="0.34" stop-color="#e88f3c"/> <!-- 琥珀 -->
<stop offset="1" stop-color="#4d7280"/> <!-- 外周:冷えた青灰 -->
</radialGradient>
<!-- 等高線をまとめたグループに、線の色として指定する -->
<g stroke="url(#heat)"> … 13本のpath … </g>
gradientUnits="userSpaceOnUse" を指定すると、グラデーションは図形ごとではなく画面の座標系で解決されます。つまり、画面全体に一枚の熱分布が敷かれ、線はその上を通過する場所の色で描かれる ── という状態になります。
あとはカーソルが動くたびに cx と cy を書き換えるだけ。属性2つの更新で、画面上の数千本の線の色が一斉に変わります。 これはCanvasやWebGLでは(シェーダを書くか、線ごとに色を計算するかして)もっと手間のかかる部分で、SVGの構造がそのまま効いてくる場所です。衝撃波を出したときに r を一時的に広げれば、熱が押し広がるような演出にもなります。
THE PROMPT
ここが本題です。上のデモを作るためにClaude Codeへ渡せる、汎用プロンプト全文を掲載します。右上の COPY ボタンでそのままコピーできます。色やラベルを置き換えれば、自分用になります。
あなたはCreative Codingとデータビジュアライゼーションに精通したフロントエンドエンジニアです。
「Generative Topography」=ジェネラティブに生成された地形の等高線が、
製図機のように描かれていくWeb表現を、SVG で実装してください。
(canvas も WebGL も使わない。ベクター線が主役なので SVG を選ぶ)
# 置き換える変数
- BRAND_NAME = "GROOVESIGN"
- BG_COLOR = "#0a0c0b" // 暖かみのある墨色(青紫の宇宙にしない)
- HEAT_RAMP = 中心から外へ: "#fffaf0" → "#ffcf7a" → "#e88f3c" → "#9c6a4a" → "#4d7280"
(白熱 → 金 → 琥珀 → 枯茶 → 冷えた青灰)
- ACCENT_COLOR = "#e9a94a" // 目盛り・計器表示
- LABEL = "GENERATIVE TOPOGRAPHY"
# ビジュアル / クリエイティブディレクション
- 測量図・製図のような、静かで理知的な佇まい
- 線は髪の毛のように細く(1.0px)、4本ごとに計曲線として太く(1.7px)
- 標高が高い線ほど不透明に(0.5 → 0.95)
- 外周に目盛り、隅に等幅フォントの小さなラベルと計器表示を置く
- 発光・ブルーム・粒子・glassmorphism・rainbow は使わない(前作と差別化)
# 地形の生成
- 3D値ノイズを3オクターブ重ねた fbm で標高場をつくる
- 3軸目に時間を渡し、地形がゆっくり変化し続けるようにする
- 画面を格子(デスクトップ20px / モバイル28px間隔)に区切り、各交点の標高を配列に持つ
# 等高線の抽出(マーチングスクエア法)
- 標高を13段階に分け、各段階ごとに等高線を求める
- 各セルの4隅が基準値を超えているかで16通りに分岐し、辺上の交点を線形補間で求める
- 鞍点(case 5 と 10 の曖昧ケース)はセル中央の平均値で分岐を決める
- 【重要】1つの高さにつき <path> 要素は1つだけ。d 属性に "M…L…" を連結する
(線分ごとに要素を作らない。DOM が膨らんで重くなる)
# アニメーション / インタラクション
- 起動時、clipPath の矩形を左から広げて等高線を描き出す(easeOutCubic, 約1.6秒)
- 描画ヘッド(細い縦線)を、広がる境界に沿って走らせ、完了後にフェードアウト
- ポインタ(マウス/タッチ)位置を中心に exp(-d^2/2R^2) のガウシアンを標高へ加算し、
地形を隆起させる。ポインタ追従は補間してなめらかに
- 【色温度】ポインタを中心とする radialGradient(gradientUnits="userSpaceOnUse")を
HEAT_RAMP で定義し、等高線グループの stroke に url(#...) で指定する。
ポインタが動いたら cx/cy を書き換えるだけで画面全体の色温度が変わるようにする
(線を1本ずつ塗り分けない。SVGの構造を使って安く実現すること)
- 【衝撃波】クリック/タップで、時間とともに半径が広がり振幅が減衰するリングを標高へ加算する。
峰だけでなく内側に谷を作ると、地面が持ち上がって沈む本物らしい挙動になる:
amp * ( exp(-dr^2/2w^2) - 0.55*exp(-(dr+1.9w)^2/2w^2) ) // dr = 距離 - 半径
・リングの中心は「クリックした座標」に固定する(カーソルに追従させない)
・峰に重ねて閃光の輪(circle を1つ、半径を広げながら線を細く・薄くする)を走らせる
・同時にグラデーションの r を一時的に大きく広げ、熱が押し広がるように見せる
・同時に有効なリングは4本まで
・遠いセルは矩形で粗く枝刈りしてから距離を計算する(毎フレームの計算量を抑える)
- 等高線の再計算は最大45fps程度に制限する(低速端末の保険)
# 実装要件
- position: fixed の全画面オーバーレイとして被せ、通常ページに影響させない
- viewBox を画面サイズに合わせ、リサイズ・画面回転で格子とレイアウトを再計算する
- マウスとタッチの両方に対応
- モバイルでは格子を粗く、等高線の本数を減らす
# 堅牢性 / 品質
- CLOSE ボタンと ESC で必ず終了できる
- prefers-reduced-motion では、アニメーションを行わず静止した一枚の地形図を表示する
- SVG が生成できない等の失敗時はエラーを出さず自動でスキップ
- JavaScript が失敗しても本体ページは必ず表示される Progressive Enhancement
- 終了時に requestAnimationFrame を停止し、イベントリスナ(mouse/touch/resize/key)を
すべて解除、SVG を DOM から除去(何度実行してもリークしないこと)
- production 品質。共通のオーバーレイ/CLOSE/後始末は再利用できる形に分離する
# アクセシビリティ
- CLOSE は button 要素。ESC で閉じられる。オーバーレイに aria-label
- 装飾なので SVG には aria-hidden を付ける
- 動きが苦手な人向けに prefers-reduced-motion を尊重
まず標高場の生成とマーチングスクエア法による等高線描画を作り、次に描き出しの
アニメーション、ポインタの隆起、目盛りと計器表示、の順に組み上げ、
モバイル・reduced motion・後始末・本番ビルド確認まで進めてください。
弊社がこのデモを作った際も、この粒度から始めました。マーチングスクエア法の実装自体は、ほぼ一発で動きます。時間をかけたのは、等高線の本数(多いと図が潰れる)、線の細さ、隆起の強さといった図としての読みやすさの調整でした。
CUSTOMIZE
- 地形の性格を変える ── ノイズの周波数(
FREQ)を下げると、なだらかで大きな山に。上げると細かく複雑な地形になります。 - 等高線の本数 ── 13本前後が図として読みやすい上限です。増やすほど密度は上がりますが、潰れて模様になります。
- 色温度のランプ ──
HEAT_RAMPのstopを差し替えるだけで、全体の印象が変わります。暖色→寒色をやめて単色の濃淡にすれば、より製図らしい静かな佇まいになります。 - 熱の広がり ── グラデーションの半径。小さくすると手元だけが灯り、大きくすると画面全体がゆるやかに色づきます。
- 隆起の強さと範囲 ── ガウシアンの高さと半径。強くすると火山のように、弱くすると丘のように反応します。
- 衝撃波 ── 伝わる速さ、リングの太さ、減衰の速さ、そして谷の深さ。谷を浅くすると穏やかな波紋に、深くすると爆発のような迫力が出ます。遅く太くすれば重い地響き、速く細くすれば鋭い衝撃になります。
- 止める ── 時間軸を固定すれば、動かない一枚の地形図になります。背景画像としてはこちらの方が上品かもしれません。
PERFORMANCE
SVGは「要素数が増えると重くなる」技術です。実運用では次の点に気をつけました。
- 要素数を増やさない ── 前述の通り、1つの高さにつき
<path>は1つ。数千の線分を13要素にまとめています。 - 属性の更新回数を減らす ── 毎フレーム書き換えるのは13個の
d属性と、グラデーションのcx/cy/rだけ。計器表示のテキストは0.12秒に1回しか更新しません。 - 遠いセルは計算しない ── 衝撃波のリングは細いので、影響範囲の外は矩形で粗く枝刈りしてから距離を求めます。これがないと、リングが増えるほど平方根と指数関数の呼び出しが跳ね上がります。
- 計算量を実測する ── 1920×1080・等高線13本・衝撃波4本が同時に走る最悪条件で、標高場の生成と等高線抽出は1フレームあたり約6.3msでした。60fpsの予算(16.7ms)には収まっています。感覚ではなく、実際に測って確かめるべき部分です。
- 計算量の上限を決める ── 格子は最大160×110に制限。モバイルでは格子を粗く、線の本数も減らします。
- 再計算の頻度を抑える ── 等高線の再計算は約45fpsで頭打ちにしています。地形はゆっくり動くため、体感は変わりません。
- 後始末 ── 終了時にrequestAnimationFrameを停止し、全リスナを解除してSVGをDOMから除去。何度開閉してもリークしません。
WHAT AI DID / WHAT HUMAN DIRECTION MATTERS
マーチングスクエア法は、名前を知っていても、16通りの分岐と鞍点の処理を正確に書くのは面倒な部類のアルゴリズムです。そこはAIが確実に埋めてくれます。 「SVGでマーチングスクエア法の等高線を」と伝えれば、動く土台はすぐ立ち上がります。
一方で、任せきりにできない部分もはっきりしています。
- そもそも「SVGで等高線」という題材を選ぶこと
- 等高線を何本にするか(多いほど情報量は増えるが、図は死ぬ)
- 線の細さと色の幅 ── 測量図に見えるか、ただの模様に見えるかの分かれ目
- 隆起の強さ ── 強すぎると玩具っぽく、弱すぎると気づかれない
- 「1要素にまとめる」「グラデーションを線の色にする」という設計判断(これは見た目ではなく、動くかどうかを決める)
最初に出てきた実装は、線が細かすぎて画面が金色の砂嵐のようになりました。本数を減らし、線を細くし、色の幅を狭める。 引き算です。
一方で、足すべきものもありました。単色の線画のままでは、正確ではあっても、少し寂しい。「カーソルで色温度が変わったらどうか」という一言から、熱源のグラデーションと衝撃波が加わって、ようやく作品として立ちました。どこを削り、どこに一つだけ足すか。 手が速くなった分、この判断の比重はむしろ上がっています。
AIは実装の坂道をなだらかにしてくれる。ただ、どこで止めるかを決めるのは、やはり人の仕事です。3回続けて、同じ結論に辿り着いています。
NEXT
第1回は粒子(WebGL)、第2回は文字(Canvas 2D)、第3回は線(SVG)。ブラウザの主要な描画技術を、ひと通り違う表情で使ったことになります。
次回はまた別の素材 ── 物理シミュレーション、画像処理、あるいは音(Web Audio)といった方向を考えています。一覧で見たときに「毎回違う驚きがある」状態を目指します。
今回のプロンプトも丸ごとコピーして使えます。自社の言葉と色に置き換えて、ぜひ一度Claude Codeに渡してみてください。
レガシーPHPシステムの保守・引き継ぎのご相談を受け付けています。
初回のご相談・ヒアリングは無料です。