1仕組みと動作原理
デフォルトのルートは「ページ内でのコード合成」:アニメーションページの <script> にテンプレートを貼り付け、BGMと映像で同一の BPM/SECTIONS/EVENTS を共有することで、各アクションの音が完全に同一フレーム上に着地する(キー不要、音声ファイル不要)。
Paste `templates/score.js` into the animation page's `<script>`, before the live-preview block at the bottom (the starter marks the spot), and set:
音楽が映像に追従する仕組みは手動の位置合わせではなくテンポマップ:各シーンに整数の小節(約70〜110 bpm)を割り当てることで、すべてのカットが自然に強拍へ着地する。
- **Tempo map.** Each scene gets a whole number of bars (tempo flexes per scene, roughly 70-110 bpm), so every cut lands on a downbeat.
カットは音量ではなく和声によって示す(シーンは属和音へ向かい、カットで主和音に着地)。また、音量を上げてはいけない理由を実測値で明示:+7〜10 dB の急変はユーザーに驚き(不快感)を与え、+3〜5 dB と和声変化の組み合わせこそがクリーンなカットとして認識される。
- **Mark cuts with harmony, not volume.** Each scene walks home to the dominant (G) and the cut arrives on the tonic (C). A loud accent on a cut (bass + bright chime at once) reads as a jump scare: users flagged a +7 to +10 dB jump as startling; +3 to +5 dB with a chord change reads as a clean edit.
自動検証により「アライメント」と「驚愕防止」を2つのフェイルセーフ判定基準に落とし込む:直近の強いアタック音へのオフセットと突入時の音量急変をイベント単位でレポートし、オフセットが ±100 ms を超えれば OFF-BEAT、音量跳ね上がりが +6 dB を超えれば STARTLE と判定。冒頭1秒と末尾のフェードアウトはスキップする。
It fails on OFF-BEAT (more than ±100 ms, ~3 frames) or STARTLE (more than +6 dB versus the second before). The opening second and the final fade are skipped (no "before" to compare against; a fade-out is not a cut).
非自作の音楽を使用する場合はアプローチを逆転させ、映像を音楽に合わせる:レンダリング、ミックス、チェック実行を経て、レポートされたオフセットに従ってページ側 SCENES のシーン境界を移動して再レンダリングする。シーン関数はローカル時間のみを受け取るため、境界を移動してもシーンコード自体は変更不要であり、このイテレーションループは非常に軽量である。
With music you don't control, reverse the direction: **the picture follows the music.**
対応能力の境界を明示:コード合成はオルゴール、ピアノ風の撥弦音、パッド、ベル、軽めのパーカッションを得意とし、リアルなボーカル/オーケストラ/ジャンル特化型のプロダクションは不可。必要に応じて AI 音楽や既存の楽曲へ切り替える。
Synthesized in code: music box, piano-like plucks, pads, bells, soft percussion are fine. Realistic voices, orchestras and genre production are not; use AI music or a real track for those.
AI 音楽ルートにはユーザー提供の API キーが必要であり、エージェントが外部生成サービス(OpenRouter 上の Lyria)へ直接 curl を実行して音楽の説明を送信する。これは本スキル内で認証情報を読み取り素材を外部送信する唯一のブランチであり、「要求された場合のみ」と位置づけられている。
Use when the user wants something richer than a synthesized score. Needs an API key.
2コア機能
3外部依存関係
| Kind | Dependency / Endpoint |
|---|---|
| cli | ffmpeg / ffprobe(分析视频与音频:抽灰度帧、抽 PCM;AI 支路里还用于混音) |
| api | OpenRouter 上的 Lyria(可选 AI 音乐生成,stream:true 收 base64 音频) |
| api | 该端点的凭证:从环境变量读取并放入 Authorization 头(仅 AI 音乐支路) |
| package | 兄弟 skill javascript-animation 的 render.mjs(离线渲染 SCORE 为 WAV 并 mux 进 MP4) |
| network | Web Audio API(浏览器内置,用于合成与离线渲染;非外部服务) |
4推奨統制措置と判定根拠
- scripts/: ローカルスクリプトまたはコマンドの実行: node scripts/sync-check.mjs piece.mp4 [--cues-file piece.cues.json] [--tol
- 网络端点: 外部ネットワークアクセスの宣言: https://openrouter.ai/api/v1/chat/completions —— AI 音楽ブランチのみ(ユーザーから明確に要求された場合)、Authori
- 本地工作目录: ファイルの読み書きと成果物の出力: 素材および中間生成物:bgm.mp3(curl ストリーミング音声をディスク保存)、piece_music.mp4(ffmpeg によるミックス出力)
5二重目の独立検証
- [ok] $OPENROUTER_API_KEY 是否真的被读取并外发(橙档判定关键) — references/ai-music.md 原文给出 `curl -s -N https://openrouter.ai/api/v1/chat/completions -H "Authorization: Bearer $OPENROUTER_API_KEY" …`,且开头写明 'Needs an API key.';端点与凭证同处一条可复制命令,调用点真实存在。
- [ok] 该支路是否真的是「可选、非默认」(避免过度判级) — SKILL.md 正文写 'Don't ask the user to choose a music source up front.',并把 AI 音乐放在 '## Other sources (only when asked)' 段下;默认段标题为 '## Default: synthesize it in the page (no key, no files)'。触发条件为用户显式要求。
- [ok] sync-check 的判据是否与文档一致(能力声明可信度) — 代码内 TOL = Number(opt('--tol', 100)) / 1000 对应 ±100ms;`const jump = 20 * Math.log10(rms(v.t, v.t + .3) / ref), startle = jump > 6;` 对应 +6 dB;无音轨时 console.error 并 process.exit(1);与 SKILL.md 逐条吻合,无夸大。
- [ok] 模板是否真的与画面共享数据(而非各自维护时间) — groove.js 头注释给出 schema(sections/events/kit/harmony/key)并写 'The picture reads the same BPM / SECTIONS / EVENTS, so sound and image can't drift apart.';score.js 同样由 cues(即 window.CUES)切段并做小节取整。声明与实现一致。
- [ok] 是否有比橙更高的行为(红档特征) — 全仓扫描 `sandbox|automationcontrolled|no-verify|stealth|bypass|ignoreHTTPSErrors|dangerously` 零命中;curl 未使用 -k/--insecure,无绕防护动作,无任意代码执行面(模板是页面内 Web Audio 代码)。
- [ok] 确定性声明(每次渲染一致)是否可在模板代码内定位 — score.js 的混响脉冲用固定种子 LCG 生成并注释 'deterministic noise tail (seeded, so every render is identical)';groove.js 同样用 `let s = 99 + c` 起手的 LCG 与固定种子噪声缓冲。声明属实。
6結論
7cd2fd4b7c5af0a2…