Source: threejs-examples/ExportToGLTF.1.js

/**
 * @file
 *
 * Summary.
 *
 * <p>Class for exporting a scene or a model to a file in GLTF format.</p>
 *
 * @since 10/03/2025
 * @author {@link https://krotalias.github.io Paulo Roma}
 * @copyright © 2025 Paulo R Cavalcanti
 * @license {@link https://opensource.org/license/mit MIT License}
 * @see <a href="/cwdc/13-webgl/threejs-examples/ExportToGLTF.1.js">source</a>
 * @see <a href="https://threejs.org/examples/#misc_exporter_gltf">threejs example</a>
 */

import * as TextureUtils from "three/addons/utils/WebGLTextureUtils.js";
import { GLTFExporter } from "three/addons/exporters/GLTFExporter.js";

/**
 * Class for exporting to a file (scene.gltf or scene.glb) in gltf format.
 */
export class ExportToGLTF {
  /**
   * Create a GLTFExporter object and an anchor HTMLElement.
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement Document: createElement() method}
   * @see {@link https://threejs.org/docs/#examples/en/exporters/GLTFExporter GLTFExporter}
   */
  constructor() {
    this.gltfExporter = new GLTFExporter().setTextureUtils(TextureUtils);

    this.link = document.createElement("a");
    this.link.style.display = "none";
    document.body.appendChild(this.link); // Firefox workaround, see #6594
  }

  /**
   * Export the scene to GLTF format.
   * @param {THREE.Object3D} input the scene to export.
   * @param {Object} params {@link https://threejs.org/docs/#examples/en/exporters/GLTFExporter.parse GLTFExporter.parse} options.
   * @property {boolean} [params.trs=false] export position, rotation and scale instead of matrix per node.
   * @property {boolean} [params.onlyVisible=true] export only visible objects.
   * @property {boolean} [params.binary=false] export in binary (.glb) format, returning an ArrayBuffer.
   * @property {number} [params.maxTextureSize=infinity] restricts the image maximum size (both width and height) to the given value.
   * @property {Array<AnimationClip>} [params.animations=null] a List of animations to be included in the export.
   * @property {boolean} [params.includeCustomExtensions=false] export custom glTF extensions defined on an object's userData.gltfExtensions property.
   *
   * @see {@link https://threejs.org/docs/#examples/en/exporters/GLTFExporter GLTFExporter}
   */
  exportGLTF(input, params) {
    let trs, onlyVisible, binary, maxTextureSize;
    const options = params
      ? ({ trs, onlyVisible, binary, maxTextureSize } = params)
      : undefined;

    this.gltfExporter
      .parseAsync(input, options)
      .then((result) => {
        if (result instanceof ArrayBuffer) {
          this.saveArrayBuffer(result, "scene.glb");
        } else {
          const output = JSON.stringify(result, null, 2);
          console.log(output);
          this.saveString(output, "scene.gltf");
        }
      })
      .catch((error) => {
        console.log("An error happened during parsing", error);
      });
  }

  /**
   * Save a blob to a file, which is a file-like object of immutable, raw data;
   * they can be read as text or binary data, or converted into a ReadableStream
   * so its methods can be used for processing the data.
   * @param {Blob} blob a file-like object of immutable, raw data.
   * @param {string} filename file name.
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob Blob}
   */
  save(blob, filename) {
    this.link.href = URL.createObjectURL(blob);
    this.link.download = filename;
    this.link.click();

    // URL.revokeObjectURL( url ); breaks Firefox...
  }

  /**
   * Save a string to a file.
   * @param {string} text Blob as JSON string.
   * @param {string} filename file name.
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob Blob}
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify JSON.stringify()}
   */
  saveString(text, filename) {
    this.save(new Blob([text], { type: "text/plain" }), filename);
  }

  /**
   * Save an array buffer to a file.
   * @param {ArrayBuffer} buffer Blob as binary data.
   * @param {string} filename file name.
   * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Blob Blob}
   */
  saveArrayBuffer(buffer, filename) {
    this.save(
      new Blob([buffer], { type: "application/octet-stream" }),
      filename,
    );
  }
}