Web Player API
Cavalry Web Player と API は現在ベータ版のため、変更される可能性があります。
Cavalry Web Player は、Web ブラウザで Cavalry シーンを再生および操作するために使用できます。このドキュメントでは、完全な統合ガイドと API リファレンスを提供します。
Web Player は 2 つの主要部分で構成されています。
- WebAssembly ランタイム
- JavaScript モジュール
JavaScript モジュールは、Web Player をインスタンス化するために使用されます。Web Player は 4 つの側面で構成されています。
- Module — インポートされた
CavalryWasmモジュールのインスタンス - Player — 再生、アセット管理などを制御する Cavalry プレーヤー(Cavalry のスクリプト API に類似)
- Canvas — ビューポートとして機能する
canvas要素 - Surface — シーンを
canvasにレンダリングする WebGL サーフェス
// Import the Cavalry moduleconst wasm = await import("../wasm-lib/CavalryWasm.js")// Initialise the moduleconst Module = await wasm.default({ // `locateFile` is required for the module to load the wasm files locateFile: (path) => `../wasm-lib/${path}`, print: (text) => console.log(text), printErr: (text) => console.error(text),})// Load a scene fileconst response = await fetch("scene.cv")const sceneData = await response.arrayBuffer()Module.FS.writeFile("scene.cv", new Uint8Array(sceneData))// Create a player instanceconst player = Module.Cavalry.MakeWithPath("scene.cv")// Read the scene resolutionconst scene = player.getSceneResolution()const canvas = document.getElementById("canvas")canvas.width = scene.widthcanvas.height = scene.height// Set up a rendering surfaceconst surface = Module.makeWebGLSurfaceFromElement( canvas, scene.width, scene.height,)// Render the current frameplayer.render(surface)// Use `requestAnimationFrame` for efficient playbacklet animationFrameId = 0const runPlaybackLoop = () => { const tick = (timestamp) => { // `tick` advances the frame based on the elapsed time const status = player.tick(surface, timestamp); // Optionally update the UI when a frame changes if (status.frameChanged) { console.log("Frame", status.currentFrame); } animationFrameId = requestAnimationFrame(tick) } animationFrameId = requestAnimationFrame(tick)}runPlaybackLoop()player.play()// To stop playback// player.stop();// cancelAnimationFrame(animationFrameId);Module
「Module」という見出しのセクション以下の方法でモジュールをインポートします:
// Import the Cavalry moduleconst wasm = await import("../wasm-lib/CavalryWasm.js")// Initialise the moduleconst Module = await wasm.default({ // `locateFile` is required for the module to load the wasm files locateFile: (path) => `../wasm-lib/${path}`, // Logs diagnostic data to the console print: (text) => console.log(text), // Logs errors to the console printErr: (text) => console.error(text),})makeWebGLSurface(canvasId:string, width:number, height:number) → SkSurface
「makeWebGLSurface(canvasId:string, width:number, height:number) → SkSurface」という見出しのセクション指定された canvas 要素を使用して WebGL2 コンテキストと Skia サーフェスを初期化します。
パラメータ:
canvasId: canvas HTML 要素の ID。width: レンダリングサーフェスの幅。height: レンダリングサーフェスの高さ。
戻り値: WebGL コンテキストにバインドされた Skia SkSurface。
const surface = Module.makeWebGLSurface("canvas", 800, 600);makeWebGLSurfaceFromElement(canvas:emscripten::val, width:number, height:number) → SkSurface
「makeWebGLSurfaceFromElement(canvas:emscripten::val, width:number, height:number) → SkSurface」という見出しのセクション指定された canvas 要素を使用して WebGL2 コンテキストと Skia サーフェスを初期化します。
パラメータ:
canvas: canvas HTML 要素。width: レンダリングサーフェスの幅。height: レンダリングサーフェスの高さ。
戻り値: WebGL コンテキストにバインドされた Skia SkSurface。
const surface = Module.makeWebGLSurfaceFromElement(canvas, canvas.width, canvas.height);loadFont(path:string, alias?:string) → string
「loadFont(path:string, alias?:string) → string」という見出しのセクション仮想ファイルシステムからランタイムフォントレジストリにフォントを読み込みます。
パラメータ:
path: 仮想ファイルシステム内のフォントファイル(例:.ttf、.otf、.woff、.woff2)へのパス。alias(オプション): フォントを登録するカスタム名。指定された場合、フォントは内部ファミリー名の代わりにこのエイリアスで登録されます。これは外部の命名システム(例:CSS font-family 名)と一致させるのに便利です。
戻り値: 登録されたファミリー名(エイリアスが指定された場合はエイリアス、それ以外はフォントの内部ファミリー名)。
// Load font using its internal family nameModule.FS.writeFile("Montserrat.ttf", fontBytes);const familyName = Module.loadFont("Montserrat.ttf", "");// familyName = "Montserrat" (from font's internal name)// Load font with a custom aliasModule.FS.writeFile("AC-Compacta.woff", fontBytes);const familyName = Module.loadFont("AC-Compacta.woff", "my-custom-id");// familyName = "my-custom-id"// Use the alias with other font APIsconst styles = player.getFontStyles("my-custom-id");player.setAttributeFont("textShape#1", "font", { font: "my-custom-id", style: "Regular" });getFontMetadata(familyName:string) → FontMetadata
「getFontMetadata(familyName:string) → FontMetadata」という見出しのセクション読み込まれたフォントの詳細なメタデータを取得します。利用可能なすべてのスタイルと CSS 互換の値が含まれます。
パラメータ:
familyName: 登録されたファミリー名(loadFont()またはqueryFonts()から取得)。
戻り値: フォント名のバリアントとスタイル情報を含む FontMetadata オブジェクト。
// Load a fontconst familyName = Module.loadFont("Inter.ttf", "");// Get metadataconst metadata = Module.getFontMetadata(familyName);console.log("Family:", metadata.registeredFamily);console.log("Styles:", metadata.styles);// Use style info for CSS mappingmetadata.styles.forEach(style => { console.log(`${style.name}: weight=${style.weight}, slant=${style.slant}`);});// Output: "Regular: weight=400, slant=normal"// Output: "Bold: weight=700, slant=normal"// Output: "Italic: weight=400, slant=italic"loadFontData(url:string)
「loadFontData(url:string)」という見出しのセクション指定された URL からフォントデータを読み込み、ランタイムフォントレジストリに登録します。
パラメータ:
url(文字列): フォントデータを取得する URL。
// Load a font from a URLModule.loadFontData("/url/to/font.ttf");Cavalry
「Cavalry」という見出しのセクション以下の方法でインスタンスを作成します:
const player = Module.Cavalry.Make("scene.cv");pendingAssets
「pendingAssets」という見出しのセクションMakeWithPath でシーンが読み込まれると、そのアセットは pendingAssets 配列に格納されます。その後、配列をループしてアセットを読み込むことができます。
実装例については、アセットの読み込み を参照してください。
const player = Module.Cavalry.MakeWithPath("scene.cv");console.log(Module.pendingAssets)specialHTMLTargets
「specialHTMLTargets」という見出しのセクションこのオブジェクトに canvas 要素を追加すると、CavalryWasm モジュールは canvas が Shadow DOM にある場合でもそれを見つけることができます。
Shadow DOM を参照してください。
const id = "my-canvas"const canvas = document.createElement("canvas")canvas.id = idModule.specialHTMLTargets[id] = canvasMake(scenePath?:string) → Cavalry
「Make(scenePath?:string) → Cavalry」という見出しのセクション新しい Cavalry クラスのインスタンスを構築して返します。
パラメータ:
scenePath(オプション): 仮想ファイルシステム内のシーンファイルへのパス。後方互換性のためデフォルトは"scene.cv"です。
// Load default scene.cvconst player = Module.Cavalry.Make();// Load a specific scene fileconst player = Module.Cavalry.Make("myAnimation.cv");MakeWithPath(scenePath:string) → Cavalry
「MakeWithPath(scenePath:string) → Cavalry」という見出しのセクション新しい Cavalry クラスのインスタンスを構築して返します。
Make の代替メソッドです。
パラメータ:
scenePath: 仮想ファイルシステム内のシーンファイルへのパス。
// Load a specific scene fileconst player = Module.Cavalry.MakeWithPath("scene.cv");render(surface:SkSurface)
「render(surface:SkSurface)」という見出しのセクション現在のフレームを指定された WebGL Skia サーフェスにレンダリングします。
player.render(surface);getSceneResolution() → Resolution
「getSceneResolution() → Resolution」という見出しのセクション現在のコンポジションの解像度を取得します。
戻り値: Resolution 型のオブジェクト。
const resolution = player.getSceneResolution();console.log(resolution.width, resolution.height);replaceImageAsset(filePath:string, assetId:string)
「replaceImageAsset(filePath:string, assetId:string)」という見出しのセクションassetId の画像アセットを指定されたパスの画像に置き換えます。
Module.FS.writeFile("image.png", imageBytes);player.replaceImageAsset("image.png", "asset#2");player.render(surface);replaceImageAssetData(assetId:string, image:string)
「replaceImageAssetData(assetId:string, image:string)」という見出しのセクションassetId の画像アセットを仮想ファイルシステム内の画像に置き換えます。
player.replaceImageAssetData("asset#2", "test.png");player.render(surface);replaceFontAsset(filePath:string, assetId:string)
「replaceFontAsset(filePath:string, assetId:string)」という見出しのセクションassetId のフォントアセットを仮想ファイルシステム内のフォントに置き換えます。
player.replaceFontAsset("font.ttf", "asset#2");player.render(surface);replaceCSVAsset(filePath:string, assetId:string)
「replaceCSVAsset(filePath:string, assetId:string)」という見出しのセクションassetId の CSV アセットを指定されたパスの CSV に置き換えます。
軽量で高速な Web CSV パーサーは、Cavalry 自体に同梱されている大規模でフル機能のパーサーに比べて基本的なものです。現在、カスタム区切り文字と引用符はサポートされていません。CSV ファイルで問題が発生した場合はお知らせください。
Module.FS.writeFile("test.csv", csvBytes);player.replaceCSVAsset("text.csv", "asset#2");player.render(surface);replaceCSVAssetData(assetId:string, csvData:string)
「replaceCSVAssetData(assetId:string, csvData:string)」という見出しのセクションassetId の CSV アセットを CSV データに置き換えます。
注意 — 軽量で高速な Web CSV パーサーは、Cavalry 自体に同梱されている大規模でフル機能のパーサーに比べて基本的なものです。現在、カスタム区切り文字と引用符はサポートされていません。CSV ファイルで問題が発生した場合はお知らせください。
player.replaceCSVAssetData("asset#2", "test.csv");player.render(surface);replaceExcelAsset(filePath:string, assetId:string)
「replaceExcelAsset(filePath:string, assetId:string)」という見出しのセクションassetId の Excel アセットを仮想ファイルシステム内の Excel アセットに置き換えます。
player.replaceExcelAsset("sheet.xlsx", "asset#2");player.render(surface);replaceExcelAssetData(assetId:string, csvData:string)
「replaceExcelAssetData(assetId:string, csvData:string)」という見出しのセクションassetId の CSV アセットを CSV データに置き換えます。
player.replaceExcelAssetData("asset#2", "test.csv");player.render(surface);replaceSVGAsset(filePath:string, assetId:string)
「replaceSVGAsset(filePath:string, assetId:string)」という見出しのセクションassetId の SVG アセットを仮想ファイルシステム内の SVG アセットに置き換えます。
player.replaceExcelAsset("image.svg", "asset#2");player.render(surface);replaceSVGAssetData(assetId:string, svgData:string)
「replaceSVGAssetData(assetId:string, svgData:string)」という見出しのセクションassetId の SVG アセットを SVG データに置き換えます。
player.replaceExcelAssetData("asset#2", "image.svg");player.render(surface);replaceGoogleSheet(sheetUrl:string, assetId:string)
「replaceGoogleSheet(sheetUrl:string, assetId:string)」という見出しのセクションGoogle Sheets は自動的に読み込まれます。replaceGoogleSheet を使用して、ランタイム時に Google Sheet アセットを置き換えます。
エラーを避けるために、Google Sheet の共有権限を「リンクを知っている全員」に設定してください。
const sheetId = "UNIQUE_ID_OF_GOOGLE_SHEET"const url = `https://docs.google.com/spreadsheets/d/${sheetId}`player.replaceGoogleSheet(url, assetId);getActiveComp() → string
「getActiveComp() → string」という見出しのセクション現在アクティブなコンポジションの ID を返します。
const compId = player.getActiveComp();getInConnection(layerId:string, attrId:string) → string
「getInConnection(layerId:string, attrId:string) → string」という見出しのセクションAttribute への入力接続を返します。対象の Attribute に入力がない場合は空文字列が返されます。
const path = player.getInConnection("basicShape#2", "scale");disconnect(fromLayerId:string, fromAttrId:string, toLayerId:string, toAttrId:string)
「disconnect(fromLayerId:string, fromAttrId:string, toLayerId:string, toAttrId:string)」という見出しのセクションAttribute 間の接続を解除します。接続が解除されると空文字列を返します。
player.disconnect("basicShape#2", "position", "basicShape#2", "scale");const path = player.getInConnection("basicShape#2", "scale"); console.log("Connection for Scale Attribute after disconnect is", path);setCompTimeMultiplier(multiplier:number)
「setCompTimeMultiplier(multiplier:number)」という見出しのセクションコンポジションのタイム乗数を設定します。2.0 に設定すると、コンポジションは 2 倍の速度で再生されます。
player.setCompTimeMultiplier(0.5);setActiveComp(compId:string)
「setActiveComp(compId:string)」という見出しのセクションID でアクティブなコンポジションを設定します。コンポジションが見つからない場合は警告がログに記録されます。
setAttributeViaStringify(layerId:string, jsonString:string)
「setAttributeViaStringify(layerId:string, jsonString:string)」という見出しのセクションJSON 文字列を渡してレイヤー上の 1 つ以上の Attribute を設定します。
パラメータ:
layerId: 変更するレイヤーの ID。jsonString: Attribute 名を値にマッピングする JSON 文字列。
const color = JSON.stringify({ backgroundColor: { r: 255, g: 0, b: 128 } });player.setAttributeViaStringify(player.getActiveComp(), color);player.render(surface);const playbackStep = JSON.stringify({ playbackStep: 2 });player.setAttributeViaStringify(player.getActiveComp(), playbackStep);setAttribute(layerId:string, attrId:string, value:any)
「setAttribute(layerId:string, attrId:string, value:any)」という見出しのセクションレイヤー上の Attribute を設定します。値の型は自動的に検出され、適切な C++ 型に変換されます。
パラメータ:
layerId: 変更するレイヤーの ID。attrId: 変更する Attribute。value: 設定する値。サポートされる型:- 数値: Attribute の型に基づいて自動的に
double、int、またはenumとして検出 - 文字列: text および richText Attribute 用
- ブール値: boolean Attribute 用
- 配列: 2D ベクトル用
[x, y]、3D ベクトル用[x, y, z]、色用[r, g, b]または[r, g, b, a] - オブジェクト: ベクトル用
{x, y}または{x, y, z}、色用{r, g, b}または{r, g, b, a}
- 数値: Attribute の型に基づいて自動的に
// Numbers (auto-detected as double, int, or enum based on attribute type)player.setAttribute("textShape#1", "fontSize", 24.5);player.setAttribute("duplicator#1", "count", 10);player.setAttribute("dropdown#1", "alignment", 2);// Stringsplayer.setAttribute("textShape#1", "text", "Hello World!");// Booleansplayer.setAttribute("shape#1", "visible", true);// 2D vectors (array or object syntax)player.setAttribute("shape#1", "position", [100, 200]);player.setAttribute("shape#1", "scale", {x: 1.5, y: 2.0});// 3D vectors (array or object syntax)player.setAttribute("camera#1", "position", [10, 20, 30]);player.setAttribute("transform#1", "rotation", {x: 0, y: 45, z: 0});// Colours (array or object syntax, values 0-255)player.setAttribute("shape#1", "fillColor", [255, 0, 0, 255]);player.setAttribute("shape#1", "material.materialColor", {r: 128, g: 64, b: 255, a: 255});// Composition background colourplayer.setAttribute(player.getActiveComp(), "backgroundColor", {r: 30, g: 30, b: 30});getAttribute(layerId:string, attrId:string) → any
「getAttribute(layerId:string, attrId:string) → any」という見出しのセクションレイヤーから Attribute 値を取得します。戻り値の型は Attribute の型によって異なります。
パラメータ:
layerId: クエリするレイヤーの ID。attrId: 取得する Attribute。
戻り値: Attribute 値。戻り値の型:
- double/int/enum:
number - bool:
boolean - string/richText:
string - double2/int2:
[x, y]配列 - double3/int3:
[x, y, z]配列 - color:
{r, g, b, a}オブジェクト(値範囲 0-255)
// Numbersconst fontSize = player.getAttribute("textShape#1", "fontSize");const count = player.getAttribute("duplicator#1", "count");// Stringsconst text = player.getAttribute("textShape#1", "text");// Booleansconst isVisible = player.getAttribute("shape#1", "visible");// 2D vectors (returns array)const position = player.getAttribute("shape#1", "position");console.log(`Position: ${position[0]}, ${position[1]}`);// 3D vectors (returns array)const rotation = player.getAttribute("transform#1", "rotation");console.log(`Rotation: ${rotation[0]}, ${rotation[1]}, ${rotation[2]}`);// Colours (returns object)const color = player.getAttribute("shape#1", "material.materialColor");console.log(`Color: R=${color.r}, G=${color.g}, B=${color.b}, A=${color.a}`);// Convert colour to CSS hexconst hex = "#" + [color.r, color.g, color.b] .map(x => x.toString(16).padStart(2, "0")) .join("");getAttributeViaStringify(layerId:string, attrId:string) → string
「getAttributeViaStringify(layerId:string, attrId:string) → string」という見出しのセクション任意の Attribute 値を JSON 文字列として取得します。これは、特定のゲッターがない複雑な Attribute 型のためのフォールバックメソッドです。
パラメータ:
layerId: クエリするレイヤーの ID。attrId: 取得する Attribute。
戻り値: Attribute 値の JSON 文字列表現。
const jsonString = player.getAttributeViaStringify("basicShape#1", "customData");const data = JSON.parse(jsonString);getAttributeName(layerId:string, attrId:string) → string
「getAttributeName(layerId:string, attrId:string) → string」という見出しのセクションAttribute の名前を取得します。Attribute 名は、Cavalry 内で Attribute Editor の Attribute を右クリックし「Rename…」を選択して設定できます。
パラメータ:
layerId: クエリするレイヤーの ID。attrId: 取得する Attribute。
戻り値: Attribute の名前または Attribute ID。
const name = player.getAttributeName("basicShape#1", "position");getAttributeDefinition(layerId:string, attrId:string) → AttributeDefinition
「getAttributeDefinition(layerId:string, attrId:string) → AttributeDefinition」という見出しのセクションAttribute の型、制約、デフォルト値、構造などの詳細なメタデータを取得します。これは、Attribute の特性を理解する必要がある動的ユーザーインターフェースの構築に特に役立ちます。
パラメータ:
layerId: クエリするレイヤーの ID。attrId: 検査する Attribute。
戻り値: 包括的な Attribute メタデータを含む AttributeDefinition オブジェクト。
// Get definition for a numeric attribute with constraintsconst sizeDef = player.getAttributeDefinition("pixelateFilter#1", "size");console.log(`Type: ${sizeDef.type}`);console.log(`Default: ${sizeDef.defaultValue}`);console.log(`Min: ${sizeDef.numericInfo.hardMin}, Max: ${sizeDef.numericInfo.hardMax}`);// Use definition to create appropriate UIif (sizeDef.type === "int" && sizeDef.numericInfo.hasHardMin && sizeDef.numericInfo.hasHardMax) { // Create slider with proper min/max values const slider = document.createElement("input"); slider.type = "range"; slider.min = sizeDef.numericInfo.hardMin; slider.max = sizeDef.numericInfo.hardMax; slider.value = JSON.parse(sizeDef.defaultValue);}AttributeDefinition プロパティ:
interface AttributeDefinition { attrId: string; // Attribute id type: string; // Data type (int, double, bool, string, Color, etc.) prefix: string; // UI prefix text (e.g X, or R) placeholder: string; // UI placeholder text for string attributes defaultValue: string; // JSON-serialized default value isArray: boolean; // Whether this is an array attribute isCompound: boolean; // Whether this has child attributes isDynamic: boolean; // Whether this is dynamically created isAttrReadOnly: boolean; // Whether this is read-only allowsConstrainProportions: boolean; // Whether proportions can be constrained multiline: boolean; // Whether text should be multiline numericInfo: NumericInfo; // Numeric constraint information enumValues: number[]; // Enum option values children: AttributeDefinition[]; // Child attribute definitions}interface NumericInfo { hardMin: number; // Hard minimum constraint hardMax: number; // Hard maximum constraint softMin: number; // Soft minimum constraint softMax: number; // Soft maximum constraint step: number; // Step increment hasHardMin: boolean; // Whether hardMin is set hasHardMax: boolean; // Whether hardMax is set hasSoftMin: boolean; // Whether softMin is set hasSoftMax: boolean; // Whether softMax is set hasStep: boolean; // Whether step is set}getControlCentreAttributes(compId:string) → [string]
「getControlCentreAttributes(compId:string) → [string]」という見出しのセクション指定されたコンポジションのすべての Control Centre Attribute パスのリストを取得します。
パラメータ:
compId: クエリするコンポジションの ID(通常はgetActiveComp()から取得)。
戻り値: "layerId.attributeId" 形式の Attribute パスを表す文字列の配列。
// Get active composition and its control centre attributesconst activeComp = player.getActiveComp();const attributes = player.getControlCentreAttributes(activeComp);console.log("Control Centre Attributes:", attributes);// Output example: [ "pixelateFilter#1.size", "pixelateFilter#1.outline", "pixelateFilter#1.borderColor" ]// Generate dynamic UI for each Attributeattributes.forEach((attrPath) => { const [layerId, attrId] = attrPath.split("."); // Get attribute definition to determine UI type const definition = player.getAttributeDefinition(layerId, attrId); // Create appropriate control based on type switch (definition.type) { case "int": // Create integer input or slider break; case "bool": // Create checkbox break; case "color": // Create color picker break; // ... handle other types }});getFontAxisInfo(fontName:string, fontStyle:string) → FontAxisInfo
「getFontAxisInfo(fontName:string, fontStyle:string) → FontAxisInfo」という見出しのセクション指定されたフォントの可変フォント軸情報を取得します。可変フォントには、ウェイト、幅、スラントなどの調整可能な軸が含まれており、フォントの外観を細かく制御できます。このメソッドは、各利用可能な軸の名前、タグ、範囲、現在値などのメタデータを返します。
パラメータ:
fontName: フォントファミリー名(例:“Roboto”、“Inter”)。fontStyle: フォントのスタイル(例:“Regular”、“Bold”)。
戻り値: 各可変フォント軸に対応する FontAxisInfo オブジェクトの配列。フォントが可変フォントでないか軸がない場合は空の配列を返します。
// Query available fonts and their stylesconst fonts = player.queryFonts();const styles = player.getFontStyles(fonts[0]);// Get axis information for a variable fontconst axisInfo = player.getFontAxisInfo("Roboto Flex", "Regular");if (!axesInfo.length) { console.warn("This font has no variable axes (not a variable font)");} else { console.log(`Font has ${axisInfo.length} variable axes`); console.log(axisInfo) // Create sliders for each axis axisInfo.forEach(axis => { const slider = document.createElement("input"); slider.type = "range"; slider.min = axis.minValue; slider.max = axis.maxValue; slider.value = axis.currentValue; slider.addEventListener("input", (e) => { // Update font axis value when slider changes console.log(`${axis.axisName} set to ${e.target.value}`); }) })}fetchAndProcess(zipUrl:string) → Promise<void>
「fetchAndProcess(zipUrl:string) → Promise<void>」という見出しのセクションZIP ファイルを取得して処理し、その内容を展開してプレーヤー内に画像シーケンスアセットを作成します。
パラメータ:
zipUrl(文字列): 取得して処理する ZIP ファイルの URL。
await player.fetchAndProcess("/url/to/ImageSequence.zip");Web Player は、フレームタイミングとレンダリングを処理するネイティブ再生マネージャーを提供します。
再生モード
「再生モード」という見出しのセクション2 つの再生モードが利用可能です:
- Accurate(デフォルト): 実時間ベースのタイミングで、正しいタイミングを維持するためにフレームをスキップします。オーディオ同期とリアルタイム再生に最適です。
- Smooth: すべてのフレームを順番に表示しますが、複雑なシーンではリアルタイムより遅くなる場合があります。フレーム単位の正確なプレビューに最適です。
基本的な再生パターン
「基本的な再生パターン」という見出しのセクション// Start playbackplayer.play();// Run the playback loopfunction runPlaybackLoop() { const tick = (timestamp) => { if (!player.isPlaying()) { return; } const status = player.tick(surface, timestamp); // Update UI if needed if (status.frameChanged) { console.log(status) } requestAnimationFrame(tick); }; requestAnimationFrame(tick);}runPlaybackLoop();// Stop playbackplayer.stop();play()
「play()」という見出しのセクション現在のフレーム位置から再生を開始します。requestAnimationFrame ループを開始する前にこれを呼び出します。
player.play();runPlaybackLoop();stop()
「stop()」という見出しのセクション再生を停止します。現在のフレーム位置は保持されるため、再度 play() を呼び出すと停止した位置から再開されます。
player.stop();cancelAnimationFrame(animationFrameId);toggle()
「toggle()」という見出しのセクション再生状態を切り替えます。再生中なら停止、停止中なら再生を開始します。
player.toggle();console.log(player.isPlaying() ? "Stop" : "Play");isPlaying() → boolean
「isPlaying() → boolean」という見出しのセクション現在再生中かどうかを返します。
console.log("Playback is running?", player.isPlaying());tick(surface:SkSurface, timestampMs:number) → PlaybackStatus
「tick(surface:SkSurface, timestampMs:number) → PlaybackStatus」という見出しのセクション経過時間に基づいて再生を進め、現在のフレームをレンダリングします。これは requestAnimationFrame コールバックから呼び出す必要があります。
パラメータ:
surface: レンダリング先の Skia サーフェス。timestampMs:requestAnimationFrameからのタイムスタンプ(DOMHighResTimeStamp)。
戻り値: 現在の再生状態を含む PlaybackStatus オブジェクト。
const tick = (timestamp) => { if (!player.isPlaying()) { return; } const status = player.tick(surface, timestamp); if (status.frameChanged) { console.log("Frame", status.currentFrame); } requestAnimationFrame(tick);}setFrame(frame:number)
「setFrame(frame:number)」という見出しのセクション現在のフレームを設定します。フレーム番号は有効な再生範囲(getStartFrame() と getEndFrame() の間)に制限されます。
注意: 再生中の場合、フレームを設定する前に再生を停止し、必要に応じて再開してください。
// Seek to a specific frameconst wasPlaying = player.isPlaying();player.stop();player.setFrame(50);player.render(surface);if (wasPlaying) { player.play(); runPlaybackLoop();}getFrame() → number
「getFrame() → number」という見出しのセクション現在のフレーム番号を返します。
const currentFrame = player.getFrame();console.log("Current frame", currentFrame);getStartFrame() → number
「getStartFrame() → number」という見出しのセクション現在のコンポジションの再生範囲の開始フレームを返します。
const startFrame = player.getStartFrame();console.log(startFrame);getEndFrame() → number
「getEndFrame() → number」という見出しのセクション現在のコンポジションの再生範囲の終了フレームを返します。
const endFrame = player.getEndFrame();console.log(endFrame);getFPS() → number
「getFPS() → number」という見出しのセクション現在のコンポジションのフレームレート(FPS)を返します。
const fps = player.getFPS();console.log(`Scene runs at ${fps} FPS`);getActualFPS() → number
「getActualFPS() → number」という見出しのセクションアクティブな再生中に測定された再生 FPS を返します。これは 1 秒間のウィンドウで計算され、再生パフォーマンスの監視に使用できます。
const actualFps = player.getActualFPS();console.log(`${actualFps.toFixed(1)} FPS`);setPlaybackMode(mode:number)
「setPlaybackMode(mode:number)」という見出しのセクション再生モードを設定します。
パラメータ:
mode: Accurate モード(デフォルト)の場合は0、Smooth モードの場合は1。
// Use Smooth mode for frame-accurate previewplayer.setPlaybackMode(1);// Use Accurate mode for real-time playbackplayer.setPlaybackMode(0);getPlaybackMode() → number
「getPlaybackMode() → number」という見出しのセクション現在の再生モードを返します。0 = Accurate、1 = Smooth。
const mode = player.getPlaybackMode();console.log(mode === 0 ? "Accurate" : "Smooth");setLoop(loop:boolean)
「setLoop(loop:boolean)」という見出しのセクション終了フレームに達したときに再生をループするかどうかを設定します。
パラメータ:
loop: ループを有効にする場合はtrue(デフォルト)、終了時に停止する場合はfalse。
player.setLoop(false);isLooping() → boolean
「isLooping() → boolean」という見出しのセクション再生ループが有効かどうかを返します。
console.log("Playback will loop?", player.isLooping());incrementFrame()
「incrementFrame()」という見出しのセクション手動で次のフレームに進みます。これは手動フレーム制御のための低レベルメソッドです — ほとんどのユースケースでは、タイミングを自動的に処理する tick() を使用してください。
player.incrementFrame();player.render(surface);Resolution
「Resolution」という見出しのセクションinterface Resolution { width: number; height: number;}シーンまたはキャンバスの解像度を表します。
ColorRGBA
「ColorRGBA」という見出しのセクションinterface ColorRGBA { r: number; // Red component (0-255) g: number; // Green component (0-255) b: number; // Blue component (0-255) a: number; // Alpha component (0-255)}各成分が 0-255 の範囲の RGBA カラー値を表します。カラー Attribute の getAttribute() で返されます。
const color = player.getAttribute("shape#1", "fillColor");// Convert to CSS hex colourconst hex = "#" + [color.r, color.g, color.b] .map(x => x.toString(16).padStart(2, "0")) .join("");// Set a colour using an objectplayer.setAttribute("shape#1", "fillColor", {r: 255, g: 128, b: 0, a: 255});Double2
「Double2」という見出しのセクションinterface Double2 { x: number; // X component y: number; // Y component}倍精度の 2D ベクトルを表します。なお、getAttribute() は便宜上、2D ベクトルを配列 [x, y] として返します。
// getAttribute returns an array [x, y]const position = player.getAttribute("shape#1", "position");console.log(`Position: (${position[0]}, ${position[1]})`);// Set a new position using array syntaxplayer.setAttribute("shape#1", "position", [position[0] + 10, position[1] + 20]);// Or use object syntaxplayer.setAttribute("shape#1", "position", {x: 100, y: 200});Double3
「Double3」という見出しのセクションinterface Double3 { x: number; // X component y: number; // Y component z: number; // Z component}倍精度の 3D ベクトルを表します。なお、getAttribute() は便宜上、3D ベクトルを配列 [x, y, z] として返します。
// getAttribute returns an array [x, y, z]const cameraPos = player.getAttribute("camera#1", "position");console.log(`Camera at: (${cameraPos[0]}, ${cameraPos[1]}, ${cameraPos[2]})`);// Set camera position using array syntaxplayer.setAttribute("camera#1", "position", [ cameraPos[0], cameraPos[1], cameraPos[2] + 100]);// Or use object syntaxplayer.setAttribute("camera#1", "position", { x: 10, y: 20, z: 30 });FontMetadata
「FontMetadata」という見出しのセクションinterface FontMetadata { registeredFamily: string; // The name used for registration (use with getFontStyles) registeredStyle: string; // Default style name fullName: string; // Full font name from the font file preferredFamily: string; // Preferred family name (may differ from registeredFamily) preferredSubfamily: string; // Preferred subfamily name postscriptName: string; // PostScript name wwsFamilyName: string; // WWS (Weight Width Slope) family name styles: FontStyleInfo[]; // All available styles with CSS-compatible values}フォントの名前テーブルからの名前バリアントと利用可能なすべてのスタイルを含むフォントメタデータを格納します。getFontMetadata() で返されます。
const metadata = Module.getFontMetadata("Inter");console.log(metadata.registeredFamily); // "Inter"console.log(metadata.styles); // Array of FontStyleInfo objectsFontStyleInfo
「FontStyleInfo」という見出しのセクションinterface FontStyleInfo { name: string; // Style name (e.g., "Regular", "Bold Italic") weight: number; // CSS font-weight: 100-900 (400=normal, 700=bold) slant: string; // CSS font-style: "normal", "italic", or "oblique" width: number; // CSS font-stretch: 1-9 (5=normal, 3=condensed, 7=expanded)}CSS 互換の値を持つフォントスタイルを表します。これらの値を使用して Cavalry フォントスタイルを CSS プロパティにマッピングします。
const metadata = Module.getFontMetadata("Roboto");metadata.styles.forEach(style => { // Create CSS font-face rules or match styles console.log(`@font-face { font-family: "${style.name}"; font-weight: ${style.weight}; font-style: ${style.slant}; }`);});FontAxisInfo
「FontAxisInfo」という見出しのセクションinterface FontAxisInfo { axisName: string; // Human-readable name (e.g., "Weight", "Width") axisTag: string; // Four-character axis tag (e.g., "wght", "wdth") minValue: number; // Minimum allowed value for this axis maxValue: number; // Maximum allowed value for this axis defaultValue: number; // Default value for this axis currentValue: number; // Current value for this axis}可変フォント軸に関する情報を表します。可変フォントには複数の軸があり、フォントの外観を細かく制御できます。一般的な軸には、ウェイト(wght)、幅(wdth)、スラント(slnt)、光学サイズ(opsz)があります。
// Get variable font axis informationconst axisInfo = player.getFontAxisInfo("Inter", "Regular");console.log(axisInfo)PlaybackStatus
「PlaybackStatus」という見出しのセクションinterface PlaybackStatus { isPlaying: boolean; // Whether playback is currently active currentFrame: number; // The current frame number frameChanged: boolean; // Whether the frame changed since the last tick actualFPS: number; // Measured playback FPS}tick() によって返され、現在の再生状態に関する情報を提供します。frameChanged を使用して UI 要素を更新するタイミングを判断します。
const status = player.tick(surface, timestamp);if (status.frameChanged) { console.log(status.currentFrame); console.log("Frame", status.currentFrame);}if (status.actualFPS > 0) { console.log(`${status.actualFPS.toFixed(1)} FPS`)}PlaybackMode
「PlaybackMode」という見出しのセクションenum PlaybackMode { Accurate = 0, // Wall-clock based, skips frames to maintain timing Smooth = 1 // Shows every frame, may run slow}再生マネージャーがフレームを進める方法を定義します:
- Accurate(0): 経過した実時間に基づいて正しいフレームを計算します。レンダリングが遅い場合、正しいタイミングを維持するためにフレームがスキップされます。オーディオ同期に最適です。
- Smooth(1): 十分な時間が経過したときに 1 フレームずつ正確に進めます。フレームをスキップすることはありませんが、複雑なシーンでは再生がリアルタイムより遅くなる可能性があります。
// Check current modeconsole.log(player.getPlaybackMode());// Set to Smooth mode for frame-by-frame previewplayer.setPlaybackMode(1);// Set to Accurate mode for real-time playbackplayer.setPlaybackMode(0);Cavalry Web Player は、特定のアセット関連操作に対して自動的にイベントを発行します。これらのイベントにより、自動アセット読み込みやその他の統合シナリオが可能になります。
cavalryAutoLoadAsset
「cavalryAutoLoadAsset」という見出しのセクションイベントタイプ: CustomEvent
Cavalry Web Player が、Web サーバーから仮想ファイルシステムに読み込む必要がある画像またはフォントアセットをシーンファイル内で検出すると、自動的に発行されます。
イベント詳細:
interface CavalryAutoLoadAssetDetail { type: "image" | "font" | "csv" | "svg" | "excel" | "googlesheet"; assetId: string; // Asset ID from the scene file (e.g., "asset#2") filename: string; // Extracted filename (e.g., "3.jpg" or "font.ttf")}// Listen for automatic asset loading eventswindow.addEventListener("cavalryAutoLoadAsset", async (event) => { console.log("Auto-loading asset:", event.detail); const path = "/path/to/assets/" if (event.detail.type === "image") { const { assetId, filename } = event.detail; const response = await fetch(path + filename); if (!response.ok) { throw new Error(`Could not find image ${filename}`); } const imageData = await response.arrayBuffer(); // Write to virtual filesystem Module.FS.writeFile(filename, new Uint8Array(imageData)); // Load the asset player.replaceImageAsset(filename, assetId); // Re-render to show the image player.render(surface); console.log(`Auto-loaded image: ${filename} for ${assetId}`); } if (event.detail.type === "font") { const { assetId, filename } = event.detail; const response = await fetch(path + filename); if (!response.ok) { throw new Error(`Could not find font ${filename}`); } const fontData = await response.arrayBuffer(); // Write to virtual filesystem Module.FS.writeFile(filename, new Uint8Array(fontData)); // Load the font into the font registry Module.loadFont(filename); // Re-render to show font changes player.render(surface); console.log(`Auto-loaded font: ${filename} for ${assetId}`); }});仕組み:
- Cavalry シーン(.cv ファイル)が読み込まれると、Web Player はアセット定義をスキャンします
"type": "file"とサポートされる拡張子を持つファイルアセットがこのイベントをトリガーします:- 画像ファイル: png、jpg、jpeg、exr、webp
- フォントファイル: ttf、otf、woff、woff2
- イベントは、アプリケーションが処理するためのアセット ID と抽出されたファイル名を提供します
- イベントハンドラーは Web サーバーからファイルを取得し、仮想ファイルシステムに書き込む必要があります
- その後、適切な API を呼び出してアセットを読み込みます:
- 画像:
replaceImageAsset(filename, assetId) - フォント:
Module.loadFont(filename)
- 画像:
自動読み込み:
- Google Sheets アセット は自動的に処理され、このイベントは不要です
- 画像およびフォントアセット は Web サーバーから取得する必要があるため、JavaScript 処理が必要です
ファイルパス解決: Web Player は Cavalry の内部パスからファイル名を抽出します。例:
"@assets/image.jpg"→"image.jpg""@assets/Changa_One/ChangaOne-Regular.ttf"→"ChangaOne-Regular.ttf""subfolder/font.ttf"→"font.ttf"
イベントハンドラーは、ルートディレクトリ(./filename)や Assets フォルダ(./Assets/filename)などの一般的な場所を試す必要があります。
実装例:
- 画像読み込み:
src/wasm/cavalry-web-player/image-asset/の画像アセットデモを参照 - フォント読み込み:
src/wasm/cavalry-web-player/custom-font/のカスタムフォントデモを参照