Loading Assets
The Cavalry Web Player and API is currently in beta and so subject to change.
Supported Asset Types
| Type | API Method |
|---|---|
| Image | replaceImageAsset() |
| Font | replaceFontAsset() |
| CSV | replaceCSVAsset() |
| Excel | replaceExcelAsset() |
| SVG | replaceSVGAsset() |
| Google Sheets | replaceGoogleSheet() |
Module
First instantiate the module by importing the CavalryWasm.js JavaScript module.
const CavalryModule = await import("./wasm-lib/CavalryWasm.js");
const Module = await CavalryModule.default(
// `locateFile` is required for the module to load the wasm files
{ locateFile: (path) => `./wasm-lib/${path}` }
);
Virtual File System
When passing file paths into the various methods, the player will look for the files in the virtual file system.
Write assets to the virtual file system with FS.writeFile.
Module.FS.writeFile("my-image.png", Uint8Array)
Use fetch to request an asset from a URL. The data can then be read with Response.bytes, though browser support is limited. For better browser support use Response.arrayBuffer and convert it to a Uint8Array.
const filename = "my-image.png"
const response = await fetch(`/url/to/${filename}`)
// Limited browser support
// const asset = await response.bytes()
const asset = await response.arrayBuffer()
Module.FS.writeFile(filename, new Uint8Array(asset))
Replace Assets
Assets can be replaced at runtime. The assetId (e.g., asset#2) matches the asset ID in the Cavalry scene file.
// Replace an image asset
const filename = "new-image.png"
const response = await fetch(filename);
const imageData = await response.arrayBuffer();
Module.FS.writeFile(filename, new Uint8Array(imageData));
player.replaceImageAsset(filename, "asset#2");
player.render(surface);
// Replace a CSV asset
const filename = "data.csv"
const response = await fetch(filename);
const csvData = await response.arrayBuffer();
Module.FS.writeFile(filename, new Uint8Array(csvData));
player.replaceCSVAsset(filename, "asset#3");
player.render(surface);
Fonts
Fonts need to be loaded for the player to pick them up.
// Before loading the scene with `MakeWithPath`
Module.loadFont(filename, assetId);
Replace a font asset if preferred. This does not unload the existing font and does not change the font for any Text Shapes that are using it.
player.replaceFontAsset(filename, assetId);
Google Sheets
Google Sheets are loaded automatically. Use replaceGoogleSheet to replace a Google Sheet asset at runtime.
Set the Google Sheet's sharing permissions to "Anyone with the link" to avoid errors.
const sheetId = "UNIQUE_ID_OF_GOOGLE_SHEET"
const url = `https://docs.google.com/spreadsheets/d/${sheetId}`
player.replaceGoogleSheet(url, assetId);
Pending Assets
When a scene is loaded via MakeWithPath, its assets will be in the Module.pendingAssets array.
The assets can be loaded by looping over the array.
const player = Module.Cavalry.MakeWithPath("scene.cv");
const assets = Module.pendingAssets
for (const { type, filename, assetId } of assets) {
// Assumes the resource has the same filename
// as the asset in the scene
const response = await fetch(`/url/to/${filename}`);
const data = await response.arrayBuffer();
Module.FS.writeFile(filename, new Uint8Array(data));
switch (type) {
case "image":
player.replaceImageAsset(filename, assetId);
break;
case "font":
// Fonts need to be loaded
module.loadFont(filename, assetId);
// Replace the font asset if preferred
player.replaceFontAsset(filename, assetId);
break;
case "csv":
player.replaceCSVAsset(filename, assetId);
break;
case "svg":
player.replaceSVGAsset(filename, assetId);
break;
case "excel":
player.replaceExcelAsset(filename, assetId);
break;
default:
console.warn(
`Unexpected asset type "${type}" for ${filename} (${assetId})`
);
return;
}
}
const canvas = document.getElementById("canvas")
const { width, height } = player.getSceneResolution()
const surface = module.makeWebGLSurfaceFromElement(canvas, width, height)
player.render(surface);
Global Event
When a scene is loaded via MakeWithPath, the cavalryAutoLoadAsset event fires for each asset.
Listen to this event as an alternative to Module.pendingAssets.
Make sure the callback function has access to Module, player and surface.
window.addEventListener("cavalryAutoLoadAsset", async (event) => {
const { assetId, filename, type } = event.detail
const response = await fetch(`/url/to/${filename}`);
const data = await response.arrayBuffer();
Module.FS.writeFile(filename, new Uint8Array(data));
switch (type) {
case "image":
player.replaceImageAsset(filename, assetId);
break;
case "font":
// Fonts need to be loaded
Module.loadFont(filename, assetId);
// Replace the font asset if preferred
player.replaceFontAsset(filename, assetId);
break;
case "csv":
player.replaceCSVAsset(filename, assetId);
break;
case "svg":
player.replaceSVGAsset(filename, assetId);
break;
case "excel":
player.replaceExcelAsset(filename, assetId);
break;
default:
console.warn(`Unexpected asset type "${type}" for ${assetId} (${filename})`);
return;
}
player.render(surface);
})