Using user uploaded files to load and add a Spine object

Hi all, been a bit stuck for a week now so thought I’d turn to the forums. I have a current Phaser scene I’m working on, very simple layout where a Spine animation is displayed in the center of the page. On the left is an animation select dropdown (animations are grabbed from a JS script I’ve done when reading the Spine Json file). Beneath that are an input (to upload 3 files, a .png, an .atlas, and a .json) and 2 buttons (1 button to upload files, code below. 2nd button that restarts the scene to use the new user uploaded files. I pass a keyName variable in the restart function. This keyName is the name of my folder since the folders all follow the same format of keyName.atlas, keyName.json and keyName.png)

  async uploadFiles() {
    if (this.fileInputControl.files.length !== 3) {
      alert('You are required to upload 3 files. Ensure you have one .atlas, one .json, and one .png file');
      return;
    }

    const files = Array.from(this.fileInputControl.files);
    const atlasFile = files.find(file => file.name.endsWith('.atlas'));
    const jsonFile = files.find(file => file.name.endsWith('.json'));
    const pngFile = files.find(file => file.name.endsWith('.png'));

    if (!atlasFile || !jsonFile || !pngFile) {
      alert('The uploaded files must include one .atlas file, one .json file, and one .png file');
      return;
    }
    
      // Wrap the FileReader in a Promise
      const readAsText = (file) => {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = (event) => resolve(event.target.result);
          reader.onerror = (error) => reject(error);
          reader.readAsText(file);
        });
      };
    
      const readAsDataURL = (file) => {
        return new Promise((resolve, reject) => {
          const reader = new FileReader();
          reader.onload = (event) => resolve(event.target.result);
          reader.onerror = (error) => reject(error);
          reader.readAsDataURL(file);
        });
      };
    
      try {
        const results = await Promise.all([
          readAsText(atlasFile),
          readAsText(jsonFile),
          readAsDataURL(pngFile)
        ]);
    
        console.log('Atlas file content:', results[0]);
        console.log('JSON file content:', results[1]);
        console.log('PNG file content:', results[2]);
    
        console.log('Files uploaded:', atlasFile, jsonFile, pngFile);
        this.fileLoaded = true;
      } catch (error) {
        console.error('Error reading files:', error);
      }
    }

My code works perfectly fine if I have the folders I’m uploading already in my assets/spine/%folderName% file path since I load my spine object like below

  loadSpineObject() {
    this.load.spine({
      key: this.keyName,
      jsonURL: `./assets/spine/${this.keyName}/${this.keyName}.json`,
      atlasURL: `./assets/spine/${this.keyName}/${this.keyName}.atlas`,
      preMultipliedAlpha: false,
    });
  }

The problem arises if I try upload the 3 files from a folder that is not already in this path. Obviously this poses an issue as my end goal is to host this online for my company for anyone to upload any of the required 3 files.

This JS code below is similar to what I want to happen, just with a Spine folder instead of an image

EDIT: I should probably add in my loader here, code as below

  loadSpineObject() {
    this.load.spine({
      key: this.keyName,
      jsonURL: `../assets/spine/${this.keyName}/${this.keyName}.json`,
      atlasURL: `../assets/spine/${this.keyName}/${this.keyName}.atlas`,
      preMultipliedAlpha: false,
    });
  }
  addSpineObject() { //keyName param?
    const spineObject = this.add.spine(
      400,
      300,
      this.keyName,
      [this.selectedAnimation],
      true
    );

    animationSelect.addEventListener("change", () => {
      this.selectedAnimation = this.changeAnimation();
      spineObject.setAnimation(0, this.selectedAnimation, true);
    });
  }

  /**
   * Changes the Spine object.
   */
  changeSpineObject() {
    const selectedFiles = this.fileInputControl.files;
    this.keyName = selectedFiles?.[0]?.name.split(".")[0];
    this.scene.restart({ keyName: this.keyName });
  }

:wave:

What do you see logged for results[0] etc.?

I guess you will have to adapt SpineFile#addToCache().

In Phaser v3.80 it looks like you’ll be able to call load.spine(…) with data URIs.

@samme with results[0] I see all the atlas file data, results[1] shows the json data and results[2] shows the png data (as dataURL)