Skip to main content

Loading Assets

Beta

The Cavalry Web Player and API is currently in beta and so subject to change.

Supported Asset Types

TypeAPI Method
ImagereplaceImageAsset()
FontreplaceFontAsset()
CSVreplaceCSVAsset()
ExcelreplaceExcelAsset()
SVGreplaceSVGAsset()
Google SheetsreplaceGoogleSheet()

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.

Sharing Permissions

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.

note

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);
})