teardown は何をしますか?
1つの機械、1つのページ。訪問者は機械が動くのを見て、ボタンを押すと、その部分が開き、周囲のゲージに実際の数値が表示されます。何もしなければ、ページはカーソルと共に自動でツアーします。同じコードで、ツアーの映像を同じタイムライン上のスコアと共にフレームごとに録画します。
SKILL_DIR は、このファイルがあるフォルダです(Cursorインストールの場合、通常は ~/.cursor/skills/teardown、~/.agents/skills/teardown、またはプロジェクト内の .cursor/skills/teardown)。ビルドとレンダリングは実行元フォルダの ./teardown-out に出力されます。
最初の実行
cd "$SKILL_DIR" && npm install && npx playwright install chromium
ページに必要なものはこれだけです。動画には ffmpeg がPATHに、スコアにはPython 3(標準ライブラリのみ)が必要です。FFMPEG、PYTHON、CHROMIUM を設定して他のバイナリを指定できます。
3つのサンプル
1つビルドして、HTMLを開き、ボタンを押してください。新しい機械を始めるときは、最も近いものをコピーしてください。
| 機械 | 駆動方法 | 盗む価値あり | |
|---|---|---|---|
v8-* | ガラスライナー付きクロスプレーンV8:追跡するシリンダー内でチャージが燃焼し、バルブがカム上でリフトし、8つのピストンが正確なスライダークランクから動きます。 | クランク角度。点火順序1-8-4-3-6-5-7-2、インジケーター線図用のチャンバー圧力モデル。 | カットアウェイモード(ガラス、断面、ソリッド)、シリンダーセレクターとしての点火順序、クランクに同期したライブチャート。 |
cessna-* | セスナ337メインランディングギアが離陸時に機体に格納され、着陸時に降りる機構。 | ストローク0..1:201mmのラックが32歯のピニオン(モジュール4mm)を正確に180°回転させる。 | 1自由度で機構全体をポーズ制御、時間の関数としての飛行フェーズ、モデルの下で回転する滑走路。 |
strandbeest-* | テオ・ヤンセンのストランドビースト、1つのクランクシャフトに20脚、砂の上を横方向に歩行。 | 風。クランク速度は風から積分され、すべての関節はヤンセンの11リンク長から円交差によって導かれる。 | 67行の正確なリンケージソルバー、インスタンス化されたチューブ、足跡、全20脚の接触チャート。 |
各サンプルは3つのフォルダに分かれています:<name>-shared/ は機械、<name>-film/ は録画されたツアー、<name>-live/ は操作可能なページを保持します。
node "$SKILL_DIR/sims/build.mjs" v8-live # → teardown-out/dist/v8-live.html、オフライン、約800KB
node "$SKILL_DIR/sims/build.mjs" # 6つすべて
機械の構成方法
機械ごとに1つのフォルダに、役割ごとにファイルを分割します。サンプルは以下に従っています:
| ファイル | 役割 |
|---|---|
kin.js / gear.js / jansen.js | 数学。実際の寸法と実単位で、1つの入力(クランク角、ストローク、風力)とそれに依存するすべてのポーズと読み出し。内部にthree.jsはありません。 |
engine.js / gear.js / beast.js | ジオメトリ。コードから構築:旋盤加工部品、チューブ、インスタンス化されたリンク。update(input) でポーズ設定。 |
stage.js | スタジオ、ライト、影、ポスト処理(GTAO、ブルーム)。frame(state, cam) で1フレームを描画。 |
console.js | オーバーレイ:固定1600x900 CSSレイアウトのパネル、チャート、トグル、リーダー付きコールアウト。update(state) でフレームの状態から再描画。 |
film.js | オペレーターの動き(ビュー、アイソレート、カットアウェイ、スロットル)の SCRIPT と、時間の純関数としての render(t)。 |
live.js | 同じ機械をリアルタイムで:ボタン、スライダー、オービット、ズーム、キー。入力がない場合は film.js のスクリプトをカーソル付き自動ツアーとして再生。クリック、ドラッグ、ホイール、キーのいずれかで制御を取得し、25秒間操作がなければ制御を戻す。 |
score.py | フィルムのタイムライン上のサウンド。 |
SKILL_DIR 外の機械の場合は、main.js を含むフォルダを作成し、名前でキットをインポート:import {runSim} from 'teardown-kit/runtime.js'。node "$SKILL_DIR/sims/build.mjs" ./my-machine でビルドします。
成功を決めるルール
- 基準から始め、想像から始めない。 写真、マニュアルの断面図、実物のクリップ。それに照らしてフレームごとに比較する。文章から発明された機械は毎回一般的にしか見えない。同じモデルが実物を再構築するには、一致する目標が必要。
- 実数、1つのソース。 最初に実際の寸法を入手(ボア、ストローク、歯数、リンク長)。すべてのゲージ、チャート、ラベルは部品をポーズ設定する同じ関数から読み取るため、画面上で動きと矛盾するものは何もない。1つ手計算で確認:セスナでは、32歯×4mmモジュールは128mmのピッチ円直径で、その半円周が201mmのストローク。
- 1つの入力がすべてを駆動。 クランク角、ストローク、または風力からポーズ設定する。手動でキーフレームを設定しないため、フィルム、ライブページ、スコアがずれることはない。
- 動作する部分を開く。 アイソレート、カット、X線表示。内部に入るカメラは10回のオービットより価値がある。
- ライトスタジオ、1つのアクセント。 淡い背景はフィードで読みやすい。暗い背景は最初の1秒を見失う。アクセントは変化しているものを示す。淡い背景の白に近い部分には、インクの輪郭または暗めの地面を与える。
- メカニズムに合わせてカメラを選ぶ。 平面リンケージを正面から見ると格子状に見える。脊椎に沿った3/4ビューはすべての脚を読みやすくする。
- 衝突は数値で修正。 部品が別の部品を突き抜ける場合、パラメータブロックでスケールまたは移動する。カメラで隠してはいけない。
ライブページのルール
- 統合GPUでテスト。 デスクトップカードで60fpsのページが、ラップトップの内蔵GPUでは15fpsに低下する可能性がある。サンプルは品質層(
live.jsのTIERS)を持つ:AOなし、低ピクセル比、小さいシャドウマップ、パネルは1フレームおきに再描画。最初に高価なシェーダーを見つける:頂点ごとに5回計算される変位は、すべての層を合わせたよりもコストがかかる。 - シェーダーをウォームアップ。
kit/warm.jsは最初のフレームの前にすべてのプログラムを並列コンパイルするため、最初の描画時にページがフリーズすることはない。 - ページを1MB未満に保つ。 リンククローラー(X、Slack)はHTMLから共有カードを読み取り、15MBのページでは諦める。大きなモデルはページの隣にファイルとして出力:
build.json→{"external": {"heavy.glb": "light.glb"}}。
render(t) コントラクト
import {runSim} from '../kit/runtime.js';
const DEFAULTS = {duration: 20, fps: 60, hud: {enabled: false}, director: {enabled: false}};
runSim(DEFAULTS, async ({cfg, canvas, capture}) => {
// シーンを構築し、状態を持つものを事前計算
return {render(t) { /* フレームtをスクラッチから描画 */ return {}; }, resize() {}};
});
render(t)は純粋関数:Math.randomなし(セットアップ時はkit/util.jsのrng(seed)を使用)、Dateなし、フレーム間で状態を引き継がない。キャプチャは任意のタイミングで呼び出す。- 独自のルールで動くもの(エージェント、パーティクル)はロード時に型付き配列に一度シミュレートされ、
renderは読み取りのみ行う。時間とともに積分される量(変化する風下でのストランドビーストのクランク)は、閉形式で積分されるか、ロード時に表形式で格納される。 - すべてのビートは
<name>-film/timeline.jsonに秒単位で格納される。スコアも同じファイルを読み取る。 - フレーム0はサムネイル。すでに機械が表示されている必要がある。
コマンド
node "$SKILL_DIR/sims/build.mjs" v8-film
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --stills beats --cols 4 --out teardown-out/v8-beats.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --still 12.5 --out teardown-out/v8-12.5.png
node "$SKILL_DIR/sims/capture.mjs" v8-film --size 1600x900 --dpr 1.2 --out teardown-out/v8-silent.mp4
python "$SKILL_DIR/run_sfx.py" "$SKILL_DIR/sims/v8-shared/score.py"
ffmpeg -y -i teardown-out/v8-silent.mp4 -i teardown-out/v8-score.wav -map 0:v -map 1:a -c:v copy -c:a aac -b:a 256k -shortest -movflags +faststart teardown-out/v8.mp4
node "$SKILL_DIR/wave.mjs" teardown-out/v8.mp4 --timeline "$SKILL_DIR/sims/v8-film/timeline.json"
--size はCSSレイアウト、--dpr はそれを乗算:1600x900を1.2倍で1920x1080になります。Captureは取得したGPUを表示します。ソフトウェアレンダラーは paths.mjs のGPUフラグが有効にならなかったことを意味します。
レビューループ
動画は見られません。フレームを見ることができます。現在のレンダリングのシートを読まずに機械が完了したと報告しないでください。
--stills beats:タイムラインビートごとに1タイル、その0.3秒後、それぞれt=でラベル付け。- 各タイルを以下のチェックリストに対して読む。
- 拡大:トランジションには
--stills every:0.2 --from A --to B、フルフレームには--still T。 - 修正、再ビルド、1に戻る。完全なパスで何も見つからなくなるまで。
- 最終:
node "$SKILL_DIR/sheet.mjs" --video <final.mp4> --timeline <timeline.json>も読み取る:エンコーダーが書き込んだものが表示される。
チェックリスト:
- 機構: 接触すべきすべての部品が接触している。何も貫通していない。パネルの数値がポーズと一致している。
- 構成: フレームごとに1つの焦点。重要なものは端から60ピクセル以内にない。ラベルは名前を付けた部品を覆わない。
- タイポグラフィ: 切り取られていない。主要な読み取り値は電話画面幅でも読める。
- 3D: ブルームはディテールを食いつぶす:エミッシブレイヤーを1.0未満に保つ。白に近い表面は飛ぶ。低照度下の光沢金属は筋状になる:大きな表面では粗さ ≥ 0.45、envMapIntensity ≈ 0.5。
- タイミング: 各状態は読むのに十分な長さ保持:短いフレーズで1秒、3語を超える場合は1語あたり0.25秒追加。
three.jsの罠(サンプルですでにヒット済み)
smoothstep(a, b, x)でa > bの場合、Windows(ANGLE/D3D)では0を返す。1.0 - smoothstep(b, a, x)と書く。ShadowMaterialや床から数ミリ上のデカールは、ポストプロセッシングレンダーターゲット内で深度テストを失う。polygonOffsetを与える。- ミラーマッピングで地面に配置されたクワッドは、裏面としてカリングされる。
DoubleSideを使用する。 - 1つのNaNピクセルがブルームを通じてフレーム全体を黒くする。シェーダー内のすべての
pow()のベースをクランプする。 - クリップされた(カットアウェイ)モデル上のGTAOは、
gtao.normalMaterialに同じクリッピングプレーンが必要。そうしないと、カットされた半分が淡いゴーストとして戻ってくる。
サウンド
sfx/ はすべてのサウンドを純粋なPython(48kHz、再現可能)で合成し、フィルムのタイムラインを読み取るため、サウンドがシンクからずれることはありません。python "$SKILL_DIR/run_sfx.py" --list でジェネレーターを表示。sample() は sfx/samples/ の録音済みCC0サウンドを追加します。sfx/score_kit.py には3つのスコアが使用するベッドとアクセントがあります:コードベッド、パワーストロークごとの柔らかいドスン、モーター、抗力下の空気。
- すべてのタイミングはタイムラインから来ており、入力された数字ではない。
- マスタリングは自動:−14 LUFS、トゥルーピーク ≤ −2 dBFS。
- アクセント、決してナレーションしない:連続した動きは無音のまま。各トーンサウンドに1つのキー。
テイスト、数字で
- イージング:出現
cubic-bezier(0.16, 1, 0.3, 1)、消失cubic-bezier(0.6, 0, 0.9, 0.35)で出現の半分の長さ、状態間cubic-bezier(0.65, 0, 0.35, 1)。線形は連続動画のみ。 - 機械はビューポートの60-70%を占める。ラベルは1080キャンバス上で34px以上。
- 1つのアクセント、そしてそれは意味を持つ:今動作している部分。
- 完全に静止しているものはない:1つの要素は常に動いている。
クレジット
Cursor移植: bugeng777/teardown-cursor(elvarofficial/teardown の移植、MIT)。キット、フレームキャプチャ、SFXエンジン、レビュールールは whaleyxbt/claude-motion(MIT)から。録音されたサンプルはFreesoundのCC0で、Barty-Bart/motion-graphics(MIT)でトリミング。ソースは sfx/samples/SOURCES.md にあり。