ブログ |

PROMPT → WEB
#012
LINKAGE
CLAUDE CODE × CANVAS 2D / CONSTRAINT SOLVER

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

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

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

PROMPT → WEB #012

Linkage

INTRODUCTION

前回(#11)の最後に、次はスクロール連動か「リンク機構」と書きました。今回はリンク機構です。

リンク機構は、棒をピンでつないだだけの仕掛けです。歯車もばねも使いません。それでも、棒の長さの組み合わせしだいで、回転が往復になり、往復が首振りになり、ときには歩く脚になります。

その中でも、昔から機械屋を悩ませてきた問題があります。回転から、まっすぐな動きを作ることです。

円を描くのは簡単です。ピンを1本立てて棒を回せば、先端は円を描きます。ところが直線は、ガイドレールのような「まっすぐなもの」を最初から用意しない限り、棒とピンだけでは簡単に作れません。18世紀の終わりに蒸気機関を改良していたジェームズ・ワットは、ピストン棒をまっすぐ押すためにこの問題に取り組み、近似の答えを見つけました。後年、自分のどの発明よりも誇りに思っている、と息子に書き送ったと伝えられています。

今回は、この「回転を直線にする」機構を4つ並べました。

RESULT

まず現物です。下のボタンを押してみてください。

クリックすると、この画面の上で Linkage が再生されます(何度でも再生可能)。ESC または CLOSE で終了します。

工作機械のような緑灰色の塗装の上で、鋼の棒と真鍮のピンでできた機構がモーターで動いています。橙の線が「直線になっている区間」、細い破線がその横に置いた理想の直線(10mmごとの目盛り付き)です。操作は2つです。

左下の銘板には、出力点が理想の直線からいま何mmずれているかと、その機構で起こりうる最大のずれが表示されます。左上は、機構を解いている計算の様子(未知数の数、反復回数、残差)です。しばらく触らずにいると、またモーターで動き出します。ESC または CLOSE で終了します。

WHAT WE MADE

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

HOW IT WORKS

1. 機構を「点と距離」だけで書く

たとえばワットの平行運動機構は、次のように定義しています。

const watt = {
  fixed:  { A: { x: -100, y: 25 }, D: { x: 100, y: -25 } },   // 地面に留まる点
  driver: { pivot: 'A', tip: 'B', r: 100, mode: 'rocker' },    // モーターがつながる腕
  links:  [['B', 'C', 50], ['D', 'C', 100]],                   // 2点の距離(mm)
  derived: [{ name: 'P', a: 'B', b: 'C', t: 0.5 }],            // BC の中点が出力
};

入力の腕の角度を決めると、点Bの位置が決まります。残る未知数は点Cの座標(x, y)の2つで、拘束も「BCは50mm」「DCは100mm」の2本。未知数と拘束の数が同じになるので、解が決まります。

ヤンセン機構は脚1本に棒が11本あり、4本脚にすると自由に動く点が20個、未知数が40個、拘束が40本になります。それでも書き方は同じで、拘束の行が増えるだけです。

2. 全部まとめてニュートン法で解く

拘束はすべて「2点の距離の2乗 − 長さの2乗 = 0」という形をしています。これを未知数で微分したもの(ヤコビ行列)を作り、ずれが小さくなる方向へ一歩ずつ寄せていきます。

// f_k = |p_a - p_b|^2 - L_k^2 を 0 にしたい。
// (J^T J + λI) dx = -J^T f を解いて dx だけ動かす。残差が増えたら λ を大きくしてやり直す
for (const link of links) {
  const dx = pa.x - pb.x, dy = pa.y - pb.y;
  f[k] = (dx * dx + dy * dy - L * L) / (L * L);   // 長さの違う棒を同じ重みで扱うため正規化
  // この行で値を持つのは、点aと点bの x, y の4つだけ
  J[k][a.x] =  2 * dx / (L * L);  J[k][a.y] =  2 * dy / (L * L);
  J[k][b.x] = -2 * dx / (L * L);  J[k][b.y] = -2 * dy / (L * L);
}

前のフレームの位置から解き始めると、ほとんどの場合3〜5回の反復で、拘束のずれが 1e-14 以下(長さの2乗に対する相対値)まで縮みます。浮動小数点で表せる精度の限界です。

λ(減衰)は、機構が伸びきって固まる直前のような「解きにくい姿勢」で、一歩が大きくなりすぎるのを抑える役目です。普段はほぼ0で、純粋なニュートン法として動きます。

3. 拘束を満たす形は、1つではない

作っていて一番面白かったのがここです。

ポースリエ=リプキン機構には、ひし形が入っています。ひし形の4辺の長さが決まっていても、「左に開いたひし形」と「右に開いたひし形」は、どちらも拘束を完全に満たします。 数学的にはどちらも正解です。でも、機械として動いている途中で、ひし形が勝手に裏返ることはありません。

そこで、「毎フレーム、機構を開いたときと同じ初期位置から解く」とどうなるかを測ってみました。

ポースリエ=リプキン機構を360コマ分、毎回同じ初期位置から解いた場合
  拘束をすべて満たした:       360 / 360
  そのうち、裏返った形だった:  163 / 360(45%)

半分近くのコマで、計算は「正解」を返しているのに、機構は裏返っています。

対策は単純で、前のフレームの位置から解き始めることです。今の位置のすぐ近くにある解にたどり着くので、裏返った解には跳びません。入力の角度が少しずつしか変わらない限り、機構は一つながりに動き続けます。

ただし「少しずつ」には限度があります。前の位置から、入力をいきなり大きく回して解いた場合も測りました。

入力を一度に動かした角度    10°     30°     60°     90°
ポースリエ=リプキン        0/72   36/72   72/72   72/72
ヤンセン                    0/72    0/72    0/72    8/72
ワット・ホーケン              0       0       0       0

ポースリエ=リプキン機構は、30°一気に回すと半分、60°以上では毎回裏返りました。そこでデモでは、入力を一度に2°までしか動かしません。カーソルを素早く大きく振ったときは、2°ずつに刻んで、そのたびに解き直しています。

ちなみに、ホーケン機構とヤンセン機構を一回転させて元の角度に戻したときの位置のずれは、5e-14 mm でした。一周のあいだに一度も別の形へ跳んでいない、ということです。

4. 本当に、まっすぐなのか

直線を作る機構なので、どれくらいまっすぐかは測って見せたいと考えました。機構を開いた瞬間に入力を一周(往復する機構は端から端まで)先に回して出力点の軌跡を求め、直線区間でのずれを計算しています。

機構                  行程       直線からの最大のずれ
ワット                51.4 mm    0.06 mm(行程の 0.12%)
ホーケン             185.1 mm    0.69 mm(行程の 0.37%)回転の約6割が直線
ヤンセン(接地)     101.3 mm    0.53 mm(行程の 0.52%)
ポースリエ=リプキン 138.7 mm    0.000000000000028 mm

ポースリエ=リプキン機構だけ、桁が違います。これは近似ではないからです。

この機構は、固定点Oからの距離が OA × OP = 一定 になるように点AとPを結びつける「反転」という操作を、棒で作っています(ひし形の辺を s、長い腕を L とすると OA × OP = L² − s²)。そして点Aを「点Oを通る円」の上で動かすと、反転した点Pは必ず直線の上を動きます。 今回の寸法では 104² − 44² = 8880、Aの円の半径が40mmなので、Pは x = 8880 ÷ 80 = 111mm の縦線の上を動きます。

計算結果のずれ 2.8e-14 mm は、浮動小数点の丸め誤差です。銘板の「いま」の値も、ほとんどの瞬間で0か、その程度の値を示します。160年以上前の数学の答えが、棒とピンの計算でそのまま確かめられるのは、作っていて気持ちのいい瞬間でした。

5. ヤンセン機構の「聖なる数」

ヤンセン機構は、オランダのテオ・ヤンセンが、風で砂浜を歩く彫刻「ストランドビースト」のために探し出した寸法です。

a 38.0  b 41.5  c 39.3  d 40.1  e 55.8  f 39.4  g 36.7
h 65.7  i 49.0  j 50.0  k 61.9  l  7.8  m 15.0

この13個の数で、クランクの回転が「地面をまっすぐ蹴って、足を持ち上げて前に戻す」動きになります。デモでは、左右に鏡写しの脚を置き、半回転ずらした2組目を奥に重ねて4本脚にしています。奥の組は少し暗く描いています。

脚が4本になっても、ソルバーの側は何も変わりません。拘束が40本に増えるだけです。

IN THE REAL WORLD

4つの機構は、教科書の中の図ではありません。それぞれに、生まれた理由と、その後の行き先があります。

ワット ── 蒸気機関から、車のサスペンションへ

ワット以前の蒸気機関は、ピストンが大きな天秤(ビーム)を引くだけでした。引くだけなら、ピストン棒とビームを鎖でつなげば済みます。ところがワットは、ピストンが押すときにも引くときにも仕事をする機関を作ろうとしていました。鎖では押せません。ビームの先は円を描くのに、ピストン棒はまっすぐ押し返さなければならない。その食い違いを埋めるために考えたのが、平行運動機構です。

この機構は、いまも形を変えて生きています。自動車の後輪の車軸を、左右にずれないように押さえる「ワットリンク」です。中点が縦の直線上を動くという性質が、「車軸は上下には動いてよいが、横には動いてほしくない」という要求に、そのまま当てはまります。

ホーケン ── チェビシェフの歩く機械の親戚

ホーケン機構は、ロシアの数学者チェビシェフが考えた「ラムダ機構」と、まったく同じ曲線を描きます。棒の組み方は違うのに同じ曲線を描く、四節リンクの「兄弟(コグネイト)」の関係です。

チェビシェフはこのラムダ機構を脚にして、1878年のパリ万国博覧会に歩く機械を出品しています。歩行機械の、ごく初期の例の一つです。

ホーケン機構の直線区間は、出力点がほぼ一定の速さで進むのも特徴です。回転を「一定の速さの往路」と「素早い戻り」に分けられるので、物を送る仕組みや、歩く機械の脚を設計するときに、いまもよく参照されます。

ポースリエ=リプキン ── 「作れない」と思われていた直線

ワットから80年近く、近似ではない直線を描くリンク機構は見つかりませんでした。チェビシェフ自身、そんな機構は存在しないのではないかと考えていたと言われます。

1864年、フランスの陸軍の技術将校だったポースリエが、その答えを発表しました。1871年には、チェビシェフのもとで学んでいたリプキンが、独立に同じ機構を見つけています。

この機構は、イギリスの数学者シルベスターが1874年の講演で紹介したことで広く知られるようになりました。模型を手にしたケルビン卿が「こんなに美しいものは見たことがない」と言って、なかなか手放そうとしなかった、という逸話が伝えられています。

ただ、機械の部品としては、主役になりませんでした。関節が多いぶん、わずかな摩擦やがたが積み重なるからです。精密な直線運動には、やがて精度の高いレール(直線案内)が使われるようになります。それでもこの機構は数学の側で大きな仕事をしました。シルベスターの講演から2年後の1876年、イギリスのケンプが「棒とピンだけで、どんな代数曲線でも描ける」ことを示します。直線は、その最初の一歩だったわけです。

ヤンセン ── コンピュータが探した「聖なる数」

テオ・ヤンセンは、大学で物理を学んだあと画家になり、1990年から「ストランドビースト(砂浜の生き物)」と呼ぶ、風で歩く彫刻を作り続けています。

13個の「聖なる数」は、ヤンセンが手で計算して決めたものではありません。コンピュータの中で脚の寸法を少しずつ変え、足先がうまく地面を蹴るものを残していく進化のシミュレーションで探し出した、とヤンセン自身が語っています。今回のデモで測った「接地区間のずれ 0.53mm」は、その探索が見つけた答えの質でもあります。

日本では、学研の『大人の科学マガジン』がミニチュアの組み立てキットにしたことで、手のひらの上でこの脚の動きを確かめられるようになりました。脚で歩く仕組みは、砂地や凸凹の地面を進むロボットの研究でも参照されています。

蒸気機関のピストン棒から、砂浜を歩く彫刻まで。230年以上にわたる「まっすぐ」への試行錯誤が、デモの4枚の銘板に並んでいます。

THE PROMPT

ここが本題です。上のデモを作るためにClaude Codeへ渡せる、汎用プロンプト全文を掲載します。右上の COPY ボタンでそのままコピーできます。

あなたは機構学と数値計算とCreative Codingに精通したフロントエンドエンジニアです。
「Linkage」= 回転を直線に変えるリンク機構を4つ、Canvas 2D で動かしてください。
機構は「点と、点どうしの距離の拘束」だけで定義し、すべて同じ汎用の拘束ソルバーで解く。
(物理エンジン・幾何ライブラリは使わない。機構ごとに交点の式を手で解かない)

# 置き換える変数
- PAINT  = "#9fb2a7"  // 工作機械のハンマートーン塗装(明るい緑灰色)
- STEEL  = "#dde2e1" / STEEL_EDGE = "#5f6b68"   // 鋼の棒
- BRASS  = "#c99c40"                            // 真鍮のピン
- BASE   = "#55655d"                            // 固定点の台座
- SIGNAL = "#e8622c"                            // 安全色の橙(入力の腕と直線区間だけに使う)
- LABEL  = "LINKAGE"

# 機構の定義(データ)
- fixed: 固定点 / driver: 入力の腕(回転の中心・先端・長さ・crank=一回転 か rocker=min..max 往復)
- links: [点a, 点b, 長さmm] の配列 / derived: 他の2点から決まる点(P = a + t(b-a)。延長線上の点など)
- bodies: 描画する部品(2点の棒 / 3点の剛体板 / 入力の円盤)と重ね順
- 自由度1の機構では、入力を決めると「拘束の数 = 未知数の数」になる。一致しなければ起動時にエラーにする

# 拘束ソルバー(最重要)
- f_k = (|p_a - p_b|^2 - L_k^2) / L_k^2 を全拘束について 0 にする(長さで正規化して重みを揃える)
- ニュートン法 + レーベンバーグ・マーカート減衰: (J^T J + λI) dx = -J^T f を解く。
  残差が下がれば採用して λ を 1/10、上がれば λ を10倍してやり直す。収束判定は相対残差 1e-14
- ヤコビ行列は1行に非ゼロが4つ(点a・点bの x,y)しかない。J^T J はその4要素どうしの積だけで足し込む
  (全要素で計算すると、未知数40のヤンセン機構で3倍以上遅い)
- 連立方程式はコレスキー分解で解く。作業用配列は使い回す(毎回確保しない)
- 【罠】拘束を満たす形は複数ある(ひし形の裏返しなど)。毎回同じ初期位置から解くと、
  ポースリエ=リプキン機構では約半分のフレームで裏返った解に収束する。
  必ず「前のフレームの位置」から解くこと
- 【罠】入力を一度に大きく動かすと、前の位置からでも裏返る(ポースリエ=リプキンは30°で半分)。
  入力の変化は2°ごとに刻み、そのたびに解き直す(連続法)

# 4つの機構(単位 mm、y は上向き)
1. ワットの平行運動機構: 固定点 A(-100,25), D(100,-25)。入力 AB=100(±26°往復)。
   DC=100, BC=50。出力は BC の中点。直線区間は入力 ±15°(縦の直線)
2. ホーケン機構: 固定点 O(0,0), Q(80,0)。クランク OB=40(一回転)。BC=100, QC=100。
   出力 P は BC の延長上 BP=200(P = B + 2(C-B))。C は上側で組み立てる。直線区間は軌跡の下端(横の直線)
3. ポースリエ=リプキン機構: 固定点 O(0,0), Q(40,0)。入力 QA=40(±64°往復。A は O を通る円上)。
   OB=OD=104、ひし形 AB=AD=PB=PD=44。P は x=111 の直線上を厳密に動く(OA×OP = 104²−44²)
4. ヤンセン機構: 寸法 a38 b41.5 c39.3 d40.1 e55.8 f39.4 g36.7 h65.7 i49 j50 k61.9 l7.8 m15(×2倍してmm)。
   クランク中心X、固定点Z=(-a,-l)。拘束: KY=j, ZY=b, KW=k, ZW=c, YV=e, ZV=d, VU=f, WU=g, WT=i, UT=h。
   三角形 Z-Y-V と W-U-T は剛体の板として描く。足先 T が出力。
   左右に鏡写しの脚(固定点 Z'=(a,-l))を同じクランクピンにつなぎ、半回転ずらした2組目を奥に置いて4本脚にする。
   鏡写しの脚と2組目の初期位置は、脚1本だけの系を連続法で目的の角度まで回して作る

# 直線区間の解析(機構を初めて開いたときに一度だけ)
- 入力を一周(rocker は min→max)360分割で回して、出力点の軌跡と全点の範囲を求める
- 直線区間: 範囲が指定されていればそれを使い、無ければ軌跡の下端から全体の大きさの0.8%以内
- 向きを固定した最良の直線の位置は (最大+最小)/2、最大のずれは (最大-最小)/2
- 画面: 軌跡の全周は細い破線、直線区間は橙の太線。理想の直線を点線で引き、10mmごとに目盛り。
  ヤンセン機構は直線のかわりに地面の線を画面の端から端まで引き、その下を淡く塗る

# 描画(工作機械の質感)
- 地: PAINT に、起動時に一度だけ焼いたハンマートーンのむら(明暗の小さな放射グラデ)を pattern で重ねる。
  【罠】端でつなぐために複製を ±size ずらして描くとき、グラデーションは座標に固定されるので、
  図形ではなく translate で座標系ごとずらすこと(でないと継ぎ目が出る)
- 棒: 影(右下にずらした半透明)→ 縁 → 地 → 上辺の照り(光は左上から)。両端は丸。
  剛体板は角を丸めた多角形に肉抜きの穴。入力の腕だけ橙の帯
- ピン: 真鍮の放射グラデ。固定点: 斜線入りの台座とボルト。クランクは円盤(棒の奥に描く)
- 出力点は橙の丸。直線区間にいる間は少し大きく
- 左下に銘板(DOM): 番号・英名・和名・考案者と年・ひとこと説明・
  「直線からのずれ いま ○ mm / 最大 ○ mm(行程の○%)/ 行程 ○ mm」。表示は1秒に4回だけ書き換える
- 左上に等幅の小さな表示: 未知数・拘束の数・反復回数・解くのにかかった µs・残差

# 操作
- カーソルの方向(入力軸のまわりの角度)を、入力の腕の目標にする。crank は最短の向きへ回り、rocker は範囲で止める
- 入力は目標へ指数的に寄せ、速度は毎秒540°で頭打ち
- 2.4秒操作が無ければモーター駆動(crank は一定速度、rocker は正弦で往復)。手を離した角度から跳ねずに続ける
- クリック/タップで次の機構(0.3秒で消して入れ替え、0.4秒で出す)。動かしながら離したときはタップ扱いにしない

# 品質要件(production)
- 全画面オーバーレイ。CLOSE ボタンと ESC で終了。多重起動を防ぐ
- レスポンシブ: 機構の範囲を、銘板の高さを除いた画面に収まる倍率で配置。狭い画面では銘板の余白を広く取る。
  devicePixelRatio は最大2でクランプ。canvas に touch-action:none
- setPointerCapture は例外を投げることがあるので try で囲む
- prefers-reduced-motion: アニメーションせず、ヤンセン機構を1枚だけ描いて静止させる(操作のヒントも出さない)
- 終了時に requestAnimationFrame を停止し、全リスナを解除し、CanvasをDOMから除去する
- Canvas 2D が使えない環境では静かに何もしない。本文の閲覧を妨げない

CUSTOMIZE

PERFORMANCE

WHAT AI DID / WHAT HUMAN DIRECTION MATTERS

ニュートン法も、ヤコビ行列も、コレスキー分解も、AIにとっては教科書どおりの仕事です。4つの機構の寸法も、ヤンセンの13個の数も、聞けばすぐに出てきます。動くものを作るまでは、驚くほど速く進みます。

ただ、今回効いた判断は、どれもコードの外側にありました。

AIは、拘束を満たす答えを一瞬で返してくれます。でも、その答えが「機械として正しい答え」かどうかは、別の問題でした。今回は、正解が2つあるときに、どちらを選ぶべきかを決めることが、作品のほとんどだったように思います。

NEXT

粒子、文字、線、物理、計算、製版、音、分割、光と影、作図、視点、そして今回の拘束。

入力の軸で、まだ手をつけていないのがスクロールです。CUSTOMIZE にも書いたとおり、今回の機構もスクロールで動かせます。次回はいよいよ、読み進めることそのものを入力にする表現を考えています。

今回のプロンプトも丸ごとコピーして使えます。棒の長さを少し変えて、Claude Codeに渡してみてください。ほんの数mmの違いで、直線が崩れたり、また戻ったりするのは、眺めていると時間を忘れます。

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

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

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