machine について
machine は、機械の構造や動作原理を示す 3D 表示と映像を作るスキルです。1 行の説明から実寸の部品と物理計算を含む自立型 HTML ページを構成し、映像も出力します。
主な機能
- 01自立型 three.js ページの生成
- 02実寸に基づく部品の構築
- 03断面・分解・X 線表示
- 04方程式による数値と動作の計算
- 05規定構成の機械映像の作成
活用シーン
- 01ターボファンのインタラクティブな展示
- 02内部構造と部品の組み立ての表示
- 03スライダー入力による動作変化の提示
- 04故障と計算された影響の表現
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ airsuphq/ machine-skill --skill machineインストール後、Claude Code で/machineを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
README.mdLICENSECHANGELOG.md.gitignoreCONTRIBUTING.mdLAUNCH.mdV2-IDEAS.mdpackage.json.github/REPO.mdevals/evals.jsonexamples/compressor.htmlrocket-engine.htmlturbofan.htmlrefinery-pump.htmlfilm/README.mdreply.htmllaunch.htmlkit/template.htmllab-kit.jsreferences/solvers.mdscripts/inline.mjsshot.mjsrecord.mjspinkscan.mjsscripts/lib/browser.mjsguard.mjsserve.mjspng.mjs詳細
Machine Skill
製品スタジオが撮影し、エンジニアが説明するように機械を作ります。実物を実物大で、実際の素材を使い、整ったスタジオセットに置き、実際の方程式で動かします。1 行入力すれば、HTML ファイル 1 つと動画が 1 つのコマンドで出力されます。
出力は常に次のとおりです。
<name>.html:単体で完結する 1 ページ(jsDelivr の three.js 0.170、キットをインライン化)。ディスク上、任意の静的ホスト、または iframe 内で開けます。- 動画:
node scripts/record.mjs <name>.html out/<name>.mp4 --music freepd:<Category>/<Name>。
まず examples/ を開いてください。すべての例は、ページ冒頭の 1 行から作られています。examples/turbofan.html がリファレンスです。何か書き始める前に、最初から最後まで読んでください。
求める水準
始める前に、視聴者が 3 秒後に目にするフレームを思い描いてください。実物の機械を撮影したスタジオ製品写真のように、最初から見える必要があります。正しいシルエットとプロポーション、金属らしく見える金属、紙の床に落ちる柔らかな影、浮いているものも、クリッピングしているものも、仮のものもない状態です。その後、機械が動き、画面上の数値はすべて計算されます。
次のいずれかに当てはまる間は、完成ではありません。
- 整備士があるはずだと思う部品が欠けている(燃焼器に燃料ノズルがない、時計に脱進機がない、エンジンにバルブがない)
- 何かが浮いている、交差している、または接合部に目立つ継ぎ目や隙間がある
- 金属であるべき素材がプラスチックのように見える、またはすべてが同じグレーに見える
- 画面上の数値がソルバーで計算されず、手入力されている
- カットアウェイが中身の詰まっていない殻だけを見せており、断面が実体として描かれていない
- 動画の最初のフレームが美しくない
ワークフロー
1. 実際の機械を調べる(5 分、コードなし)
機械のスクリプトの先頭にあるコメントブロックに、知っていること(可能であればウェブで調べた情報も)を書き留めます。
- 実際の寸法:シルエットを決める 5~10 個の部品について、単位はメートル(ターボファン:ファン直径 2.85 m、全長 4.9 m、ナセル最大直径 3.44 m)。
- 部品一覧:組み立て順に、それぞれの素材も記載します。部品名は 15~40 個を目安にします。繰り返し使われる部品(ブレード、歯、ボルト、コイル)も個別に数えます。
- 物理:機械が動く仕組みを、実際に計算する 3~6 個の方程式として記述します。実際の定数と運転点も含めます(ターボファン:ブレイトンサイクル、離陸時 N1 100%、OPR 42、T4 1,750 K、約 330 kN)。
- 1 つの数値:視聴者が気にする主役の数値です(推力、トルク、1 時間あたりの拍数、流量、出力)。大きなセリフ体の数値表示と細いバーで示します。
- 入力:視聴者が操作したい入力です。スライダーを 1 つ用意します(スロットル、風速、rpm、ポンプ速度、挽き目)。
- 故障:エンジニアが懸念する故障と、ソルバーが予測する結果です(ファンブレードの脱落による不釣り合い荷重、レッドラインを超えたときのバルブフロート、ポンプのストール、過圧)。アニメーションではなく、計算された結果でなければなりません。
2. テンプレートからページを作成する
kit/template.html を <name>.html にコピーします。このテンプレートには、インポートマップ(バージョンが [email protected] に固定されています)、フォント、キットを配置する目印付きブロック、そして記入する 4 つのセクションがあります。
const { THREE, Lab, MAT, GEO, heatGlow, clamp, lerp, approach, fmt } = window.LabKit
const lab = new Lab({ prompt, no, title, sub, size, view, cut }) // 1. the lab
// 2. the parts lab.mesh(GEO..., MAT..., { name, pos, explode, xray, count })
// 3. the solver lab.hero(...); lab.slider(...); lab.onTick((dt, lab) => { ... lab.setHero(...) })
// 4. break, explain, film lab.breakIt(...); lab.how(...); lab.autoFilm(...); lab.start()
コピーしたらすぐに、node <skill dir>/scripts/inline.mjs <name>.html を実行します。これにより、キットが目印付きブロックに貼り付けられ、ページは保存場所にかかわらず単体で完結するファイルになります(テンプレート内の src="../kit/lab-kit.js" は、このリポジトリ内でのみ解決されます)。その後、2 つ目のスクリプトブロックに機械のコードを書きます。
3. ジオメトリ:実寸の実体部品
機械固有の座標系でメートル単位を使い、Y 軸を上向きにします。ground を設定しない場合、床は y = 0 です。size には実際の最長寸法を設定します。キットが表示スケールを調整して、すべての機械がセット上で同じサイズになるようにし、スケールバーには実寸が表示されます。
- 回転部品(シャフト、ディスク、ケーシング、ノズル、コーン、スピナー、ピストン、ベゼル):閉じたプロファイルで
GEO.lathe([[r, y], ...])を使います。壁にはGEO.shell(profile, thickness)、チューブにはGEO.tube(rOut, rIn, h)、面取りディスクにはGEO.disc(r, h)を使います。角はシャープなまま保たれ、曲面には自動でスムーズシェーディングが適用されます。 - ブレードとベーン:
GEO.rotor({ count, axis, r0, r1, chord, thick, camber, twist, pitch, sweep })は、実際のキャンバーとねじりを備えた翼型(NACA 厚さ)の閉じた立体を生成し、円周上に配置します。chord、thick、camber には[root, tip]配列を使います。 - ギア:
GEO.gear({ teeth, module, width, bore, helix, spokes, rim })を使います。2 つのギアは、中心距離(z1 + z2) * module / 2でかみ合わせ、歯数比の逆比で回転させ、半歯分ずらします。 - パイプ、ホース、ワイヤー:
GEO.pipe(points, r)(閉じており、両端にキャップ付き)を使います。構造に沿ってポート間に配線し、部品を貫通させないでください。 - 締結具:すべてのフランジに
GEO.bolts(n, R, size, h)を使います。スプリングにはGEO.spring(R, wire, turns, len)、ボックスにはGEO.rbox(w, h, d, r)(常に丸みを付け、角を鋭くしない)を使います。穴のあるプレートにはGEO.extrude(shape, depth)を使います。 - 質量と慣性はジオメトリから求められます。
GEO.volume(geo)で体積と重心を取得し、実際の密度を掛けてください。
きれいに仕上げるためのルール:
- すべての部品を閉じた立体にします(lathe のプロファイルは閉じ、シェルには厚みを付け、パイプにはキャップを付けます)。これにより、断面表示で切断面が立体として描画されます。開いたサーフェスは切断時に中空に見えます。
- 目に見える交差も、浮いている部品もなくします。 各部品を支持部に接触させます(フランジは面に接し、シャフトはベアリング内を通り、支柱は床まで届くようにします)。接合部は拡大表示で確認してください。
- 視線が集まる箇所を細かく作り込みます:フランジのボルト円、面取り、リップ、銘板、燃料ライン、ハーネスなどを追加します。大きな平面には、継ぎ目、パネルライン、またはテクスチャ仕上げを加えます。
- 機械にベースを付けます:床に脚が接するスタンド、クレードル、台座、ベンチ、またはマウントを用意します。実際の機械が宙に浮いていることはほとんどありません。
- 予算:三角形は最大約 70 万、メッシュは最大 200 個です。繰り返しの静的部品は
GEO.merge/GEO.ringで結合し、可動グループは分離したままにします。
4. マテリアル:単一のグレーにしない
MAT.* プリセットを使います。これらには実測された反射率が設定されており、鋼、チタン、アルミニウム、真鍮、銅の違いが並べたときにも分かります。各プリセットでは、オーバーライド(color、roughness、clearcoat、その他すべての MeshPhysicalMaterial フィールド)と finish(微細な粗さのテクスチャ:lathe 部品の turned リング、brushed の筋目、cast の斑点、smudge、knurl)を指定できます。
| 用途 | プリセット |
|---|---|
| シャフト、ディスク、機械加工部品 | MAT.steel、MAT.stainless、MAT.chrome |
| ハウジング、鋳物 | MAT.aluminium、MAT.castIron、MAT.steelDark |
| ブレード、航空宇宙部品 | MAT.titanium、MAT.inconel(heatGlow と併用) |
| 継手、配線 | MAT.brass、MAT.copper、MAT.gold |
| 塗装された本体 | MAT.paint({ color })、MAT.satin、MAT.anodised({ color }) |
| ポリマー | MAT.plastic、MAT.rubber、MAT.carbon |
| 窓、結晶 | MAT.glass、MAT.sapphire、MAT.ruby、MAT.enamel |
| 光、炎、高温ガス | MAT.glow、heatGlow(material, kelvin) |
工業デザイナーのように配色を選びます。金属を主体に、塗装色は 1~2 色まで、アクセントカラーは多くても 1 色にします。高温部品は、ソルバーの温度に応じて発光します(material.userData.heat.value = T)。
5. ソルバー:実数値以外は使わない
入力と状態から、表示するすべての数値を算出する小さな純粋関数を作成し、実際の単位と実際の定数を使います。動力学の積分には approach(一次遅れ:回転数の上昇、熱容量)または rk4(ばね、脱進機、振り子)を使います。そして、その結果で動きを制御します。ソルバーが算出した rpm でシャフトを回転させ、ソルバーが算出した流量で粒子を動かし、ソルバーが算出した温度で金属を加熱します。
- ヒーロー表示は1つ:
lab.hero({ label, unit, max })の後、毎ティックlab.setHero(value, { state, sub, bad })を呼び出します。stateは2~3語(回転上昇中、離陸、チョーク流など)にします。subは、追加の数値を2つか3つ含む1行にします。 - スライダーは1つ:
lab.slider({ id, label, min, max, value, unit, ends })。機械に本当に必要な場合に限り、2つ目を追加します。 - ラベルは、断面平面上の座標を指定して静止部品に取り付けます:
lab.label(obj, 'HP turbine', { at: [x, y, z], value: () => '12,979 rpm' })。 lab.how(words, equations)で「How it is computed」を埋めます。モデルを平易な言葉で説明し、コードに書かれたとおりの方程式を示します。簡略化した箇所も説明します。- 動きが速すぎて見えない場合(2,700 rpm のファンなど)は、速度を落として表示し、そのことを
howに記載します(「回転表示は1:60」)。数値は決して遅くしません。 - ステップ1で書き留めた公開データと照らし合わせて、動作点が妥当かを確認します。約20%以上ずれている場合は、数値ではなくモデルを修正します。
6. 流れ、熱、エフェクト
lab.flow({ paths, count, length, color, parent }):実際の流路から作成したパスに沿って流れるストリークです(ダクト内の空気、ポンプを通る血液、パック内の水など)。.speedはソルバーの値を設定し、.opacityはlab.state.cutに基づいて設定して、カットアウェイ内部に表示されるようにします。計算した量(温度、圧力)に応じて色を付けます。lab.plume({ radius, length, dir, color: 'rocket' | 'jet', shocks }):マッハダイヤモンドを伴う排気です。.powerはソルバーの値を設定します。- 破損には
lab.sparks.emit(worldPos, n, speed)とlab.shed(mesh, v, w)を使います。火花は重力で落下して跳ね返り、放出された部品は剛体となって床に着地します。
7. モード(キット側で用意されるため、設定だけ行います)
- 分解:各
lab.add/lab.meshには、親の座標系でメートル単位のexplode: [dx, dy, dz]を指定します。部品を組み立て軸に沿って動かし、外殻は最も遠くに配置し、コアはその場に保ちます。移動中に部品どうしが交差してはいけません。 - カットアウェイ:Lab に
cut: { a, b, center, reach }を指定します。aとbは取り除く領域の方向です。a = [0,0,1], b = [0,1,0]とすると、手前かつ上方向の四分の一が取り除かれます(軸を持つものに最適です)。b = aでは半分が取り除かれます。すべての閉じた立体に、ハッチングを薄く施した断面が自動的に描画されます。 - X線:外装ケースに
xray: 'shell'を指定すると、細いエッジを残してガラス状になり、稼働中のコアが見えるようになります。 - スローモーション、ラベル、一時停止は最初から使えます(キーは S、L、Space)。操作できるのはマウスでの回転、スライダー、ボタンです。
- 破損:
lab.breakIt({ label, run(lab), reset(lab) })を使います。runでソルバーの状態を変化させ(ブレードの脱落、バルブの固着、シールの破損など)、ソルバーでその結果を計算します。ヒーロー表示(bad: true)と、火花、破片、または揺れで表現します。
8. 批評家の目で確認する(必須)
作成した画像をすべてレンダリングし、実際に読んで確認します。次のスクリプトを使います:
node scripts/shot.mjs <name>.html out/review.png # the first look
node scripts/shot.mjs <name>.html out/cut.png --js "lab.toggle('cut', true); lab.toggle('labels', true)"
node scripts/shot.mjs <name>.html out/near.png --js "lab.setView({ az: 70, el: 8, dist: 0.8, target: [x, y, z] })"
node scripts/shot.mjs <name>.html out/film --film 1,4,8,12,17,22,26 # film stills
少なくとも4回レビューします。各回で、全体表示、ラベル付きカットアウェイ、分解表示、接合部のクローズアップ2枚、そして映画のスチルを確認します。記憶にある実際の製品写真と照らし合わせ、プロポーション、部品数、素材、光の当たり方を比べます。問題点を列挙し、修正して、再度レンダリングします。問題点がなくなるまで続けます。ショットスクリプトには fps、部品数、三角形数が出力されます。インタラクティブ時のフレームレートは30以上を維持します。
9. 映像
lab.autoFilm({ runBeat, runSub, breakBeat, breakSub, sliderTo }) は、マシンから標準の28秒のストーリーを作成します。番号付きのビートと、次の編集用キャプションが含まれます。
- ひとつの文で概要を伝えます(プロンプトバーに文字が自動入力されます)。
- Claude がマシンを組み立てます(部品が組み立て順に飛んできて、カウンターが「84 of 3,597 parts」まで増えます)。
- マシンが動作します(カーソルがスライダーをドラッグし、ソルバーの計算結果に応じてメインの数値が上がります)。
- 内部を切り開きます(断面のキャップと、リアルタイムの値を表示するラベル)。
- 分解します(分解表示)。
- 壊します(カーソルが破損ボタンをクリックし、ソルバーが故障箇所を判定します)。
ループ再生され、最後のカメラキーから最初に戻ります。独自の映像を作るには、lab.film('name', { len, assemble, shots, events }) を使います。ショットはカメラキー { t, az, el, dist, target, fov }、イベントは { t, beat: ['07', 'Bold sentence.', 'Grey sentence.'], set: { cut: 1 }, slider: { id, to, dur }, cursor: { to: 'slider:id:0.8' | 'button:break' | [x, y], click: true }, do(lab) {} } です。
録画(Node 18+、Chromium を含む Playwright、ffmpeg が必要です):
node scripts/record.mjs <name>.html out/<name>.mp4 --music freepd:Classical/Easy_Lemon
node scripts/record.mjs <name>.html out/<name>-portrait.mp4 --w 1080 --h 1350
ページは映像モード(?film=1)で動作します。時計はレコーダーが進めたときだけ進むため、すべてのフレームが完全に描画され、何度録画しても映像は同じになります。レコーダーは、停止したヘッドレス GPU が返すことのあるマゼンタ色のフレームがないか、すべてのスクリーンショットを確認し、完成した映像もスキャンします。ピンク色のフレームがひとつでもある場合、ゼロ以外の終了コードで終了します。FreePD の音楽は CC0 ですが、曲のクレジットは記載してください。
画面上のテキスト
このページはダッシュボードではなく、編集的な表現を重視しています。プロンプトバー、イタリック体の副題が付いたセリフ体のタイトル、イタリック体の単位と細いバーを添えた大きな数値ひとつ、補足の数値が並ぶ1行、そしてスライダーひとつで構成されています。優れたキャプションのように、短く、具体的に、誇張せずに書いてください。単位は実際に使われるものを、数値との間にスペースを入れて記載します(338 kN、1,750 K、4.2 L/min)。桁区切りも入れてください。ビートのキャプションは、太字の文とグレーの文で構成します。
引き渡し時に伝えること
HTML ファイルのパス、映像のコマンド、公開されている数値と比較してソルバーが到達する動作点、簡略化した箇所を伝えてください。次のマシンも提案してください。