ブログ |

PROMPT → WEB
#003
GENERATIVE TOPOGRAPHY
CLAUDE CODE × SVG / MARCHING SQUARES

そのWeb演出、Claude Codeで作れます。クリエイティブWeb表現のプロンプト集 #03 Generative Topography

株式会社グルーヴサインの米沢です。

AIコーディングでクリエイティブなWeb表現を実際に作り、そのプロンプトごと公開していく「PROMPT → WEB」の第3回です。

PROMPT → WEB #003

Generative Topography

INTRODUCTION

ブラウザで絵を描く方法は、大きく3つあります。

このシリーズは毎回まったく別の技術と別のデザインで作ると決めています。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

技術的に分解すると、次のようになります。

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

PERFORMANCE

SVGは「要素数が増えると重くなる」技術です。実運用では次の点に気をつけました。

WHAT AI DID / WHAT HUMAN DIRECTION MATTERS

マーチングスクエア法は、名前を知っていても、16通りの分岐と鞍点の処理を正確に書くのは面倒な部類のアルゴリズムです。そこはAIが確実に埋めてくれます。 「SVGでマーチングスクエア法の等高線を」と伝えれば、動く土台はすぐ立ち上がります。

一方で、任せきりにできない部分もはっきりしています。

最初に出てきた実装は、線が細かすぎて画面が金色の砂嵐のようになりました。本数を減らし、線を細くし、色の幅を狭める。 引き算です。

一方で、足すべきものもありました。単色の線画のままでは、正確ではあっても、少し寂しい。「カーソルで色温度が変わったらどうか」という一言から、熱源のグラデーションと衝撃波が加わって、ようやく作品として立ちました。どこを削り、どこに一つだけ足すか。 手が速くなった分、この判断の比重はむしろ上がっています。

AIは実装の坂道をなだらかにしてくれる。ただ、どこで止めるかを決めるのは、やはり人の仕事です。3回続けて、同じ結論に辿り着いています。

NEXT

第1回は粒子(WebGL)、第2回は文字(Canvas 2D)、第3回は線(SVG)。ブラウザの主要な描画技術を、ひと通り違う表情で使ったことになります。

次回はまた別の素材 ── 物理シミュレーション、画像処理、あるいは音(Web Audio)といった方向を考えています。一覧で見たときに「毎回違う驚きがある」状態を目指します。

今回のプロンプトも丸ごとコピーして使えます。自社の言葉と色に置き換えて、ぜひ一度Claude Codeに渡してみてください。

レガシーPHPシステムの保守・引き継ぎのご相談を受け付けています。
初回のご相談・ヒアリングは無料です。

無料相談・お問い合わせはこちら

株式会社グルーヴサイン 代表取締役 米沢忠司。PHP開発歴約20年。他社開発システムの保守・引き継ぎを主力に、2007年の設立から19期目。