## 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.

```js
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`.

```js
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](https://developer.mozilla.org/en-US/docs/Web/API/Response/bytes). For better browser support use `Response.arrayBuffer` and convert it to a `Uint8Array`.

```js
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.

```js
// 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);
```

```js
// 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.

```js
// 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.

```js
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.

```js
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.

```js
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`](/content/docs/web-player/loading-assets/#pending-assets/index.html).

note

Make sure the callback function has access to `Module`, `player` and `surface`.

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