framefields-render について
framefields-render は、framefields を使う開発者やクリエイター向けのヘッドレスレンダリングガイドです。Node.js での検証と動画出力を扱い、型チェックやフレーム確認からプレビュー、全体のエンコードへ順に進めます。
主な機能
- 01Node.js でのヘッドレスレンダリング
- 02型と実行時スキーマの検証
- 03単一フレームとフレームグリッドの描画
- 04Vitest によるピクセル・レイアウトテスト
- 05プレビューと MP4 / WebM 出力
活用シーン
- 01全体のエンコード前にキーフレームのレイアウトを確認
- 02フレームグリッドでアニメーションやトランジションを点検
- 03色、透明度、境界ボックスのレンダリングテスト
- 04コンポジションのプレビューを通じたフィードバック収集
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ gatewai-dev/ framefields --skill framefields-renderインストール後、Claude Code で/framefields-renderを入力して読み込まれたか確認します。
詳細
framefields-render
セットアップ
framefields npm パッケージからすべてをインポートします。プロジェクトでまだ framefields をセットアップしていない場合は、まず framefields スキルに従ってください(インストール、プロジェクトのひな形作成、最初のレンダリング)。
概要
framefields は、ネイティブ WebGPU(Dawn)を基盤として Node.js 上でヘッドレスにレンダリングし、FFmpeg でエンコードします。動作する場合はハードウェアエンコーダー(NVENC、VideoToolbox)を使用し、それ以外の場合はソフトウェアエンコーダーを使用します。ブラウザー、Puppeteer、Chromium は実行しません。
動画のレンダリングはリソースを大量に消費し、ネイティブ GPU パイプラインはワーカープール内で非同期に実行されるため、framefields のワークフローでは、動画全体のレンダリングを開始する前に、低コストの中間生成物を確認する厳格な検証手順を設けています。
5 段階の検証手順
必ず順番どおりに進めてください。手順 1 または 2 でレイアウトやタイミングのバグを見つければ数秒で済みますが、30 秒の 4K 動画をレンダリングした後に見つけると、何分も無駄になります。
手順 1:静的型チェックとスキーマ検証
GPU を使う前に、TypeScript の型を検証し、厳格なランタイムスキーマに照らしてコンポジションを解析します。
import { CompositorProgramSchema } from "framefields";
// 1. Compile spec
const spec = comp.toSpec();
// 2. Validate against strict schema
const parsed = CompositorProgramSchema.safeParse(spec);
if (!parsed.success) {
console.error("Schema validation failed:", parsed.error.format());
process.exit(1);
}
// 3. Lint: things that render without error but not as intended
for (const d of comp.lint()) console.log(`${d.severity} ${d.code}: ${d.message}`);
プロジェクトの型をチェックします。
npx tsc --noEmit -p .
現在の CLI で初期化したプロジェクトでは、pnpm check によって型チェックとドキュメントのプリフライトが実行されます。別のエントリーポイントの場合は、pnpm exec framefields check src/film.ts --export buildFilm --json を実行してください。エクスポートは Composition、または Composition を返すビルダーです。インポート時にプロジェクトコードが実行されるため、ビルダー内でのレンダリング、生成、書き込みは避けてください。CLI は別プロセスで実行し、ビルダーのログを stderr に送り、バージョン付きの JSON 結果を stdout に 1 つ書き出します。エラーがあるとコマンドは失敗し、--warnings-as-errors を指定すると警告がある場合も失敗します。--timeout 60000 はワーカーの実行時間を制限します。
pnpm check:render は GPU 検証を追加し、フレームと 3 点のグリッドを output/check に出力します。--output <dir> を指定すると出力先を変更できます。このスモークチェックは、対象を絞ったピクセルアサーションや動画の QA の代わりにはなりません。GPU チェックが失敗した場合、または利用できない場合は、失敗として報告されます。この SDK バージョンから生成されたタイミング、グリッド、プリフライトの型宣言を確認するには、pnpm exec framefields api を使用してください。
手順 2:単一フレームの確認(renderFrame)
主要なキーフレーム(例:開始、動きのピーク、終了)を個別にレンダリングし、PNG ファイルとしてディスクに保存して、配置、タイポグラフィ、色、不透明度を確認します。
import fs from "node:fs/promises";
import path from "node:path";
import { HeadlessMediaRenderer } from "framefields";
const renderer = new HeadlessMediaRenderer();
// Render frame 45 (1.5s at 30fps)
const pngBuffer = await comp.renderFrame({
frame: 45,
renderer,
});
await fs.writeFile("output/frame-45.png", pngBuffer);
frame と atMs の両方を指定した場合、フレームフックも含めて atMs が優先されます。フレームインデックスは、0 以上の安全な整数でなければなりません。小数のタイムスタンプと FPS はサポートされています。コンポジションの FPS が基準となるため、レンダリングまたはグリッドの FPS に異なる値を指定するとエラーになります。メディアパイプラインでは、引き続きレンダリング FPS を選択できます。
手順 3:モーションとレイアウトの安定性をコンタクトシートで確認(renderFrameGrid)
動画全体をエンコードせずにイージングカーブ、カット位置、キネティックスイープ、テキストの折り返しを検証するには、連続したフレームのグリッド画像を生成します。
import fs from "node:fs/promises";
import { renderFrameGrid } from "framefields";
// Samples frames across the intro sweep (frames 0 to 60)
const gridPng = await comp.renderFrameGrid({
frames: [0, 6, 12, 18, 24, 30, 36, 42, 48, 54, 60],
columns: 4,
cellWidth: 480, // Downscaled thumbnail size for rapid visual scanning
showLabels: true, // frame number and timestamp under each cell
});
await fs.writeFile("output/intro-grid.png", gridPng);
コンタクトシートですぐに確認できる問題:
- モーションの引っかかりや、イージング減速の滑らかさの欠如。
- キーフレームの境界をまたぐテキストの切れや、折り返し位置の急な変化。
- レイヤーの z-index の誤りや、カットのトランジションの欠落。
グリッドのフレーム範囲は終点を含みますが、コンポジションの再生時間の終点は含みません。自動サンプリングは、エクスポートされるフレーム数(max(1, round(durationMs * fps / 1000)))より前で停止します。診断用に、明示的なポイントでエクスポート範囲を超えてサンプリングすることもできます。サンプルの順序と重複は保持されます。フレーム間隔は正の安全な整数、タイムスタンプ間隔は有限の正数でなければなりません。サンプル数の上限はポイントの生成中にチェックされます(デフォルトは 64、最大 120)。無効または上限を超えるリクエストは、大きなリストが作成される前に失敗します。ラベルは実際に選択されたフレームを示し、タイムスタンプは表示用にのみフォーマットされます。
手順 4:Vitest によるプログラム上の適合性プローブ
ピクセルの色、透明度、またはレイアウトのバウンディングボックスを検証する、自動化されたヘッドレスの vitest テストを作成します。
import { describe, it, expect } from "vitest";
import { HeadlessMediaRenderer } from "framefields";
import { buildFilm } from "../film.js";
describe("Hero Scene Conformance", () => {
it("renders non-black title text on frame 30", async () => {
const comp = await buildFilm();
const renderer = new HeadlessMediaRenderer();
const png = await comp.renderFrame({ frame: 30, renderer });
expect(png.length).toBeGreaterThan(1000);
// Use skia-canvas or pixel probes to assert color at target coordinates
});
});
ステップ 4.5:エクスポート前にユーザーに確認してもらう(preview)
人が確認に参加する場合は、最終レンダリングに時間をかける前に、構成を確認してもらいましょう。startPreview は、サウンドトラック、波形付きのタイムライン、コマ送り機能を備えたローカルホストのプレーヤーを提供します。ページは構成独自のコードを読み込み、ブラウザー内で WebGPU を使ってリアルタイムにレンダリングします。すべてのフレームを時間内に描画できないデバイスでは一部のフレームがスキップされますが、音声の速度は維持されます。サーバーが提供するのは、そのコード、プロジェクトのファイル、そしてエクスポートエンジンがミックスしたサウンドトラックだけです。構成をビルドするモジュールを指定してください。
import { startPreview } from "framefields";
const session = await startPreview(
{ entry: new URL("./film.ts", import.meta.url), export: "buildFilm" },
{ title: "Launch film" },
);
console.log(`Preview at ${session.url}`);
await session.closed; // keep the process alive while the user watches
- エクスポートは
Compositionを返す関数(非同期でもかまいません)、またはComposition自体です。ブラウザーがこれを呼び出すため、その中のビルド時の Node コードはシンプルに保つ必要があります。node:path、fileURLToPath(import.meta.url)、同期的なfs読み込み(JSON、テキスト)はシム経由で動作します。書き込みはスキップされます。絶対パスで参照されるアセットは、エントリを含むプロジェクト(最も近い.gitまたはpackage.jsonがある場所)に限り、サーバーから読み込まれます。その範囲外に置いたアセット(共有フォントフォルダーなど)には、1 つ以上のパスを指定してrootを渡してください。 - バックグラウンドで実行し、出力を確認してください。 スクリプトを、実行環境で許可される最長のタイムアウトを指定してバックグラウンドコマンドとして起動し、ユーザーに URL を伝えてチャットでフィードバックを求めてください。コマンドの出力(
[framefields preview]で始まる標準エラー出力)には、ページが開いたタイミング、ページ上で発生したエラー(ビルドエラー、例外を投げたフレーム、読み込みに失敗したフォントやレンダラー、WebGPU がない場合など、それぞれ一度ずつ)、停止した理由が示されます。フィルムが描画されたと思い込まず、ページが開いた後に出力を確認してください。logはこれらの行をリダイレクトするか、出力しないようにします。session.closedは停止理由("idle"、"replaced"、"closed")で解決します。 - ループ全体でタブは 1 つだけです。 ポートはプロジェクトディレクトリごとに固定されています。プレビューを再度実行すると(変更を加えた後など)、すでに実行中のプレビューに切り替わり、開いたままのタブは自動的に再接続して新しいバージョンを読み込みます。その際、表示していた時点も維持されます。ユーザーに何かを再度開くよう頼まないでください。ユーザーがタブを閉じると、約 5 秒後にプレビューも自動的に停止します(再読み込みでは停止しません。遅延時間は
idleCloseMsで変更できます)。プレビューが停止した場合(タブを閉じた、時間制限に達した、またはユーザーが停止したなど)は、再度起動してください。 - 映像にピン留めされたメモは、ユーザーからの具体的なフィードバックです。 一時停止中に、ユーザーはフレームをクリックする(または範囲をドラッグする)と、変更内容を記入できます。メモにはフレーム、フレームに対する比率で表した位置(
x、y。範囲の場合はw、hも)、テキストが保持されます。各メモは出力に表示され(note 3 at 0:12.50 (frame 750), spot 42%,31%: …)、note-<id>.jpgのパスと位置を示すマーク付きフレームも表示されます。すべてのメモは.framefields/preview-notes/notes.jsonに保存されます(.framefieldsは git で自動的に無視されます。notesDirで保存先を変更でき、falseにするとメモを無効にできます)。メモに対応するには、notes.jsonを読み込み、未完了の各メモの画像を開いて対象を正確に確認し、時刻と位置からコード内のレイヤーを特定して変更を加え、プレビューを再度実行してください。タブにはメモが再び表示されるので、ユーザーは確認して完了済みにできます。自分でnotes.jsonに"done": trueを設定することもできます。ファイルを読み込めないチャットでは、Notes パネルの Copy ボタンから同じリストを取得できます。 - 特定の時点を指定してください。 URL の
#t=12.5はプレーヤーを 12.5 秒の位置で開きます(フレーム番号で指定する場合は#frame=750)。停止するとアドレスが再生ヘッドに追従するため、ユーザーに渡すリンクを意図した位置に合わせられます。 - クリック操作ではなく、スクリプトで操作してください。 ページ内で JavaScript(エージェントのブラウザー)を実行できる場合は、
window.framefieldsPreviewを使用します。await seek(seconds)またはawait seekFrame(n)は該当フレームが描画されると解決するため、その時点でスクリーンショットを撮影してください。play()とpause()は再生を操作し、notes()はメモの一覧を返します。state()は{ state: "loading" | "ready" | "error", error, frame, time, playing, buffering, audio, connected, playbackFps, renderMs, meta }を返します。<html data-preview="ready">は最初のフレームが描画されたことを示します。ブラウザーが非表示のタブの再生を制限するため、非表示のタブでは再生が一時停止します。 - ユーザーが見られる場所に表示してください。
startPreviewはページを配信して URL を返すだけです。アプリに内蔵ブラウザーがある場合は、そこで URL を開いてください。それ以外の場合はユーザーにリンクを渡すか、open: trueを指定して既定のブラウザーで開いてください(タブがすでに開いており、自動的に再接続する場合は開きません)。ページには WebGPU が必要です(最新の Chrome、Edge、または Safari)。 - どのデバイスでも、再生はリアルタイムで進みます。 再生時にはクロックに従って表示するフレームを描画し、間に合わなかったフレームはスキップします。そのためすぐに再生が始まり、音声の速度も維持されます。遅いデバイスでは表示されるフレーム数が少なくなります。ページにはタイムコードの横に、フィルム自体の
fpsとは別に、再生時に達したフレームレートが表示されます。state()はこれをplaybackFpsとして返し、renderMsは最後のフレームの描画にかかった時間を示します。一時停止中は、再生ヘッド位置の正確なフレームが描画されます。ビジョンエフェクトは、直前に描画されたフレームを基に各フレームを解析します。一時停止中は最大 20 秒先まで解析するため、その範囲は正確に再生されます。それ以降は、フレームをスキップするデバイスでは、最後に描画されたフレームに基づく切り抜きやトラッキングが表示されます。これらは一時停止中、または書き出しで確認してください。 - 音声には
renderVideoが多重化するものと同じミックスを使います(audio: falseにするとスキップされます)。再生ではサウンドトラックをクロックとして使います。フレームの処理に時間がかかる場合(動画シークや負荷の高いショットなど)、音声に追いつくよう映像が先に進みます。
ステップ 5:動画全体のエクスポート(renderVideo)
静止フレームとモーショングリッドを確認したら、最終的な MP4/WebM 動画をエンコードします。
import path from "node:path";
const result = await comp.renderVideo({
outputPath: "output/final-video.mp4",
quality: "high", // "draft" | "medium" | "high" | "lossless"
codec: "avc", // "avc" (H.264) | "hevc" (H.265) | "vp9" | "av1"
audioCodec: "aac",
concurrency: 4, // Parallel frame encoding threads
});
// Always invoke cleanup to release temporary frame cache and file handles
await result.cleanup?.();
レンダリング中にエンジンが出力を確認し、検出結果を result.qa として返すには、qa: true を渡します(下記の組み込み動画 QAを参照)。
GPU を使用しないレンダリング
エージェントは、GPU のないサンドボックスや CI ランナーで実行されることがよくあります。その場合、framefields は CPU でレンダリングし、テキスト、メディア、Lottie、エフェクト、3D、ビジョンのすべての機能で同じ出力を生成します。ビジョン推論も CPU に移行します。
- Linux: Mesa lavapipe をインストールします。
apt-get install -y libvulkan1 mesa-vulkan-drivers。Vulkan ドライバーがまったくない場合、何もレンダリングできません。 - Windows: Direct3D 12 の WARP レンダラーが組み込まれています。lavapipe(例:mesa-dist-win)も Vulkan 経由で動作します。
- macOS: VM を含め、常に Metal GPU が利用できます。framefields の WebGPU ビルドには Vulkan がないため、そこで lavapipe は使用されません。
- 確認方法:
await describeGpu()がsoftware: trueを返します。 - 速度の目安: Linux でのテストでは、Apple M1 Pro の GPU と比べて約 12 倍遅くなります(スモークプロジェクトの 3 本の動画では、49 秒に対して 9.7 分)。CPU コア数に応じて性能が変わります。フレーム、グリッド、短いエクスポートには問題ありません。最も時間がかかるのはビジョンレイヤーです。
- 長編動画: GPU マシンでレンダリングするか、プロジェクトをプッシュして framefields レンダーワーカーに送信します(Docker または RunPod を使用し、GPU 上で git コミットをレンダリングします。認証が必要な場合は、ユーザーに
FRAMEFIELDS_API_KEYをプロセス環境に設定してもらい、出力や埋め込みを行わずに使用してください)。プロジェクトのチェックリストとジョブ形式については、https://framefields.dev/docs/guides/render-service/ を参照してください。
本番環境向けレンダリングスクリプトのパターン
本番プロジェクトでは、CLI からのクイックなフレーム確認と全体のエクスポートの両方に対応できるよう、src/render.ts を構成します。
// src/render.ts
import fs from "node:fs/promises";
import path from "node:path";
import { HeadlessMediaRenderer, startPreview } from "framefields";
import { buildFilm } from "./film.js";
const OUT = path.resolve(import.meta.dirname, "../output");
const [mode = "video", ...args] = process.argv.slice(2);
if (mode === "preview") {
// The browser runs film.ts itself; no need to build the film here.
const session = await startPreview({ entry: new URL("./film.ts", import.meta.url), export: "buildFilm" });
console.log(`Preview at ${session.url}`);
await session.closed; // serves until its tab closes or the next preview replaces it
process.exit(0);
}
const comp = await buildFilm();
await fs.mkdir(OUT, { recursive: true });
if (mode === "frames") {
const renderer = new HeadlessMediaRenderer();
await fs.mkdir(path.join(OUT, "frames"), { recursive: true });
for (const f of args.map(Number)) {
const png = await comp.renderFrame({ frame: f, renderer });
const file = path.join(OUT, "frames", `f${String(f).padStart(4, "0")}.png`);
await fs.writeFile(file, png);
console.log(`Rendered frame: ${file}`);
}
} else {
const started = Date.now();
const result = await comp.renderVideo({
outputPath: path.join(OUT, "output.mp4"),
quality: "high",
});
await result.cleanup?.();
console.log(`Exported video: ${result.filePath} in ${((Date.now() - started) / 1000).toFixed(1)}s`);
}
// CRITICAL: Always explicitly exit process to prevent native WebGPU/mediabunny thread hangs
process.exit(0);
CLI の使用方法:
# Render specific keyframes for instant review:
tsx src/render.ts frames 0 18 36 72
# Live player for the user (run in the background; re-run after changes and the open tab reloads):
tsx src/render.ts preview
# Render full master video:
tsx src/render.ts
レンダリングの進行状況を確認する
renderVideo は、イベントごとに短い [framefields] 行を 1 行ずつ stderr に出力して、独自の進行状況をログに記録します。動画がどれだけ長くてもログは短く、エクスポート 1 回につき約 15 行です。
[framefields] Preparing 1800 frames (60.0s) at 1920x1080, 30 fps, h264
[framefields] Rendering 1800 frames
[framefields] Rendered 10% (180/1800 frames) · 41.2 fps · eta 39.3s
…
[framefields] Rendered 100% (1800/1800 frames) · 41.8 fps · in 43.1s
[framefields] Mixing audio
[framefields] Encoding 60.0s of audio (aac)
[framefields] Muxing mp4
[framefields] Done in 51.4s (14.2 MB): prepare 1.2s · render 43.1s · audio 3.2s · audio-encode 1.1s · mux 0.8s
- 最後のフレームの後も処理は続きます。 「Mixing audio」では、動画内のすべての音声クリップと動画クリップをデコードし、その後サウンドトラックをエンコードし、「Muxing」でファイルを書き込みます。クリップが多い場合や長い場合は時間がかかります。ハングではありません。
Done in …が表示されるまでお待ちください。 - 処理が静かな間は
Still …の行が表示されます。 例:Still mixing audio (42%, 3/7 clips: music.mp3), 1m 10s in this phase。10 秒後、30 秒後、70 秒後に表示され、その後は間隔が 5 分ずつ延びます。各行には、実行中のフェーズと経過時間が示されます。最後の行から間隔を大幅に超えても新しい行が届かない場合に限り、レンダリングが停止しています。途中で終了すると動画は残りません。 - 失敗時にはフェーズが示されます。 エラーとともに
Failed while mixing audio after 12.3sのように表示されます。 - 長時間のエクスポートは、ハーネスで許容される最長のタイムアウトを設定してバックグラウンドで実行し、ポーリングせずに完了後に出力を確認してください。
LOG_LEVEL=warnを設定するとこれらの行が表示されなくなり、LOG_LEVEL=debugを設定するとステージごとの詳細が追加されます。警告とエラーは[framefields] warn: …/error: …と表示されます。NODE_ENV=production(またはFRAMEFIELDS_LOG_FORMAT=json)の場合、行は代わりに stdout に pino JSON として出力され、テキストはmsgに含まれます。FRAMEFIELDS_LOG_FORMAT=textを設定すると短い行の形式になります。- 独自の進行状況を出力する場合、
onProgressは各イベントを{ phase, frame, totalFrames, elapsedMs, phaseProgress?, fps?, etaSec?, detail? }として受け取ります。phaseにはprepare、render(音声のみの出力では省略)、audio、audio-encode、mux、convert(GIF のみ)、doneが設定されます。
組み込みの動画 QA(renderVideo({ qa }))
エンジンは動画のレンダリング中に測定します。エンコーダー用に読み戻される各フレームと、ミックスされる音声を測定します。2 回目のデコード処理は不要で、数値はエンコードされた内容を正確に示します。
import { formatQaReport } from "framefields";
const result = await comp.renderVideo({
outputPath: "output/final-video.mp4",
qa: { targetLufs: -14 }, // or `qa: true` for defaults (no loudness target)
});
console.log(formatQaReport(result.qa!));
if (!result.qa!.passed) process.exitCode = 1; // fail CI / the agent loop
result.qa は構造化されているため、ログを解析するのではなく、これを使って分岐してください。
issues[].code | 重大度 | 意味 |
|---|---|---|
frames_missing | error | エンコードされたフレーム数がコンポジションのフレーム数より少ない |
black_frames | warning | 黒いフレームが minBlackSec(0.5 秒)以上続いています。startSec/endSec があります |
audio_clipping | warning | フルスケール以上のサンプルがあります |
loudness_off_target | warning | 統合ラウドネスが targetLufs から lufsTolerance(1 LU)を超えて外れています |
animation_truncated | warning | レイヤーのクリップ範囲を超えたキーフレームは再生されません。layerId があります |
frozen_video | info | 映像が minFrozenSec(2 秒)以上変化していません。タイトルカードを表示し続ける場合は問題ありません |
audio_silence | info | silenceDbfs(-60)を下回る無音が minSilenceSec(2 秒)以上続いています |
audio_silent | info | トラック全体が無音です |
invalid_gradient | error | 解析できない background/fill のグラデーション文字列です。何も描画されません |
unsupported_image_format | error | .json/.lottie のベクターアニメーション、動画、または音声ファイルを画像レイヤーが受け取っています |
unknown_color | warning | 色ではない色文字列です。透明として描画されます |
low_contrast_text | warning | 背景の単色に対するテキストのコントラスト比が 3:1 未満です(読みやすい色を提案します) |
offscreen_layer | warning | 静的な絶対位置指定のレイヤーがキャンバスの完全な外側にあります |
shadow_unsupported_light | warning | ポイントライトまたは環境光に castShadow が設定されています |
pbr_without_environment | info | roughness/metallic が設定されていますが、Layer.environment() がありません(物理ベースのシェーディングは行われません) |
multiple_shadow_lights | info | castShadow が設定されたライトが複数あります。影を落とすのは最初のライトだけです |
static_track | info | トラック上のすべてのキーフレームが同じ値を保持しています |
ドキュメントのチェックも、レンダリング前に単独で実行されます。comp.lint() は同じ { severity, code, message, layerId } エントリーを返します。Step 1 で、型チェックの直後に実行してください。
エラーまたは警告がある場合、passed は false になります。qa.audio.integratedLufs は ITU-R BS.1770 のラウドネスです(ストリーミングプラットフォームでは通常、約 -14 LUFS に正規化されます)。qa.audio.peakDbfs はサンプルピークです。
ffmpeg で完成ファイルを検査する
別の場所でレンダリングしたファイルを検査する場合や、以前のレンダリング結果と比較する場合は、ffmpeg/ffprobe で検査してください。
# 1. Check video and audio stream properties
ffprobe -v error -show_entries stream=codec_name,width,height,duration,r_frame_rate output/final-video.mp4
# 2. Detect unexpected black frames or dead transitions
ffmpeg -i output/final-video.mp4 -vf "blackdetect=d=0.5:pix_th=0.10" -f null -
# 3. Verify audio loudness levels (prevent clipping / silence)
ffmpeg -i output/final-video.mp4 -af "volumedetect" -f null -
よくあるレンダリング失敗のパターン
| 症状 | 根本原因 | 解決策 |
|---|---|---|
| フレーム全体が黒くレンダリングされる | フォントが登録されていない、または uniform に NaN が含まれている | Layer.text で使用するすべてのフォントが FontManager.register() で登録され、comp.fonts に列挙されていることを確認してください。すべてのシグナル出力が有限の数値であることも確認してください。 |
| メディアレイヤーが表示されない/空白になる | 入力ハンドルのバインドに誤りがある、または不透明度が 0 | メディアのパスが存在し、opacity > 0 であることを確認してください。エフェクトまたはセクションを使用している場合は、fit: "cover" と有効なコンテナー寸法が設定されていることを確認してください。 |
| 音声が早く途切れる | 音声レイヤーに durationFrames が設定されていない | Layer.audio() に durationFrames: totalFrames を明示的に設定してください。 |
単一の renderFrame でビジョンによる切り抜き/マスクが空になる | ビジョンは直前にレンダリングされたフレームを読み取るため、フレーム 0 にはフレームがありません | 同じ HeadlessMediaRenderer で 2 フレーム以上を連続してレンダリングし、最後のフレームを使用してください。renderVideo ではこれが自動的に処理されます。 |
| ビジョンによる切り抜きで被写体が二重に残像表示される | フレームが順不同でレンダリングされている(フレームグリッド、またはフレーム 3 から 48 にジャンプするなど)ため、切り抜きに別のフレームのピクセルが使われている | ビジョンレイヤーは、renderFrameGrid ではなく、フレームを順番にレンダリングするか、書き出した MP4 で確認してください。 |
Rendered 100% の後に出力が止まる | 音声をミックス、エンコード、または多重化している | ハングではありません。Still … の行と Done in … が表示されるまでお待ちください(レンダリングの進行状況を確認するを参照)。 |
Done in … の後にスクリプトがハングする | バックグラウンドのワーカースレッドプールが開いたままになっている | レンダリングスクリプトの末尾には必ず process.exit(0) を含めてください。 |
| Linux サーバーでレンダリングが非常に遅い | CPU アダプター(lavapipe)でフレームが描画されている | await describeGpu() で software: true と表示されます。GPU の Vulkan ドライバーを修正してください(vulkaninfo --summary)。 |
エンコーダーを開けない(h264_rkmpp、NVENC) | framefields 2.2 より前のバージョンでは、未検証のハードウェアエンコーダーを使用する | libx264 などにフォールバックする framefields 2.2 以降を使用するか、FRAMEFIELDS_HW_CODECS=off を設定してください。 |
| レンダーワーカーのジョブが失敗する | プロジェクトがレンダリング可能な状態ではない(ロックファイル、エクスポート、LFS) | ジョブの code と hint を確認してください。チェックリスト:https://framefields.dev/docs/guides/render-service/ |
| テキストの位置がずれている、または途切れて見える | レイアウトノードのボックスがテキスト文字列より小さい | 折り返し用の width を明示的に設定する(例:width: 1400)か、width: "fill" を使用してください。 |
| 色が薄く見える/端が暗くなる | 乗算済みアルファを使用しないアルファブレンディング | エンジンは乗算済みアルファで動作します。カスタムシェーダーでは srcFactor: "one" を使用してください。 |