(Some classes in the WebSDK do hold an asset member, which is an object responsible for handling files. An asset is an interface that provides access to its components (also commonly referred to as files). Through the asset interface, the WebSDK can request a files content as blobs or the location (url) of a file where it is publicly available.

Here are some public implementations of the IAsset interface:

  • StaticAsset

  • LocalStorageAsset

Each of them serves a different use case when handling files. If you are working with the SDK externally you will mostly only use the StaticAsset, but it might be that you encounter / need the other two in special cases.

Storing an asset

Sometimes you want to preserve an asset, so that you do not have to do an expensive computation via the compute server over and over again (e.g. persisting a personalised mannequin). You most likely want to store it on your blob storage or S3 bucket.

To get all components of an asset, iterate over all available asset keys. From there you can call your own storage interface implementation to store the resulting blobs.

It's important that the information of the asset key is not lost. If we later recreate the asset, getComponentKey(key) must be able to resolve to the same exact asset component!

const assetKeys = await asset.getKeys();
for (const assetKey of assetKeys) {
  const component = await asset.getComponent(assetKey);
  myStorage.store(assetKey, component);
}
CODE

Let’s say our myStorage.store(assetKey, component) stores every blob with a filename that equals its assetKey in some blob storage. Imagine it being myBlobStorage://assets/avatar-1/*.

In this case we can recreate the asset later via a StaticAsset:

const myAsset = new StaticAsset("myBlobStorage://assets/avatar-1");
CODE

Advanced static assets

In some cases it is not as simple as uploading a bunch of files to a remote folder. In this case the StaticAsset constructor can also take a custom IResourceProvider implementation.

Inside your resource provider implementation you can handle things like: Authentication, complex asset component path resolutions or API calls.

Let’s say we got this fictional IResourceProvider implementation:

type APIServicePictofitAsset {
  uid: string,
  componentUids: Array<string>,
}

type APIServiceFileDto = {
  uid: string,
  fileUrl: string,
  assetComponentKey: string
}

class MyCustomResourceProvider implements IResourceProvider {
  private _user: User;
  
  constructor(myUser: User) {
    this._user = myUser;
  }

  async requestURL(key: string, baseURL: string): Promise<string> {
    const apiService = new MyAPIService(this._user.getUUID(), this._user.getToken())
    apiService.auth()

    const assetDto = apiService.getPictofitAsset(baseURL) as APIServicePictofitAsset;
    const assetComponent = assetDto.componentUids.find((it) => it.assetComponentKey === key);
    const assetComponentDto = apiService.getPictofitAssetComponent(assetComponent.uid);
    return assetComponentDto.fileUrl;
  }
}
TYPESCRIPT

This is how an authenticated call to our CMS api might look like to access a file stored under a users profile.

If we then want to use this custom IResourceProvider in our asset, we just have to provide it as a second argument. The argument passed in first will be the handed through to the requestURL(key: string, baseURL: string) as the baseURL. So it does not have to actually be a valid url.

new StaticAsset("my-avatar-1", new MyCustomResourceProvider(myLoggedInUser));
CODE

Keeping assets in the browser storage

For the special case you might want to keep assets in the e.g. local or session storage of the browser, there is also a LocalStorageAsset .

To convert an existing asset into a LocalStorageAsset you may do the following:

const myAsset = myAvatar.asset;  
const myLocalStorageAsset = await LocalStorageAsset.createFromAsset(myAsset, "my-avatar-asset-1", window.sessionStorage);
const restoredAvatar = await virtualDressingRoom.createAvatar(myLocalStorageAsset);
CODE

In this example we take the asset of a generated avatar and create a new asset in the sessionStorage of our browser. Then we recreate the avatar from this new asset.

Creating an LocalStorageAsset does only make sense when the asset you create it from is created on the fly (via a compute server call maybe) and therefore stored in memory. Storing whole large StaticAssets may take up a lot of browser storage.

A good use case for using a LocalStorageAsset is for storing generated personalised mannequins.

If you have stored a LocalStorageAsset in a previous browser session in the e.g. local storage you can then just use the default constructor to create the asset object to handle it.

const myLocalStorageAsset = new LocalStorageAsset("my-avatar-asset-1", window.localStorage)
CODE

In cases where it might happen that the user clears his browser storage, you should check if the stored asset is valid: myLocalStorageAsset.isValid()

You can also cleanup a stored asset by calling: myLocalStorageAsset.cleanup(). This will release any occupied space by the asset.