GLTF/GLB Export in ThreeJS: Disrupting Scene Hierarchy

I am exporting my scene using a very basic approach:

function save(blob, filename) {
  const link = document.createElement("a");
  link.href = URL.createObjectURL(blob); = filename;;

function saveString(text, filename) {
  save(new Blob([text], { type: "text/plain" }), filename);

function saveArrayBuffer(buffer, filename) {
  save(new Blob([buffer], { type: "application/octet-stream" }), filename);

const exporter = new GLTFExporter();
  function (result) {
    const name = `${modelName}.glb`;
    if (result instanceof ArrayBuffer) {
      saveArrayBuffer(result, name);
    } else {
      const output = JSON.stringify(result, null, 2);
      saveString(output, name);
  function (error) {
    binary: true,
    animations: [mixer.clipAction(model.animations[0]).getClip()],

But as can be understood from the title, the hierarchy in my scene is being disrupted. Typically, my objects are directly placed under the scene. However, during the export process, a new empty object is created, and all my objects are nested within it. I want to maintain the original structure of my scene.

further explanation:
I have a GLB file that I am importing into the scene using GLTFLoader . I want to make some modifications to it, such as renaming some objects. However, even if I don’t make any changes and export it, then import it back into three.js afterwards, the scene remains visually the same. The issue is that my objects (meshes) end up being placed under a new empty object (Object3D) instead of being directly part of the scene. And this process repeats itself. After multiple exports, my objects shift inside the object3D that is inside the object3D and goes on…





note: my scene contains animations that belong to objects.

Re-posting my reply from Stack Overflow:

Because glTF is not a three.js-specific format, its structures (nodes, meshes, primitives, …) are not 1:1 analogs of three.js structures (Scene, Group, Object3D, Mesh, …). three.js does the conversion in one direction during loading, and in another direction during export, with the goal of preserving the visual correctness of the scene.

Unfortunately, as you’ve found here, there’s no guarantee that the round-trip will reproduce the exact underlying structure of the original three.js scene. There are some other related implications – texture are recompressed, and might lose a little quality.

There might be other ways to go about this, depending on what you’re ultimately trying to do, but that might be better suited for a forum discussion than a Stack Overflow Q/A.

That being the case … can you say a bit more about what you’re trying to do? I think possible workarounds would depend on those details.

1 Like

I currently have 4000+ 3D models in GLB format. These models were exported in GLB format by the “3ds max babylon.js plugin.”


Each object within the model was properly named during the modeling process. However, there are some objects that were overlooked and misnamed. I am developing an interface to rename these objects.

In the API system of my website, the objects’ name of each model are entered correctly. This interface compares the names of the objects in the model with the information retrieved from the API and notifies the user if there is a problem. My current goal is to perform the renaming process of misnamed objects through the same interface and this is the final point I’ve reached.

I would be grateful for any ideas on what to do next after this point.

Can renaming objects be separated from displaying them in three.js? It is certainly possible to losslessly edit the file as you describe, but a round-trip through a three.js scene graph is not an easy way to do that. As mentioned above, changes to your textures may also be a problem.

If so, another option would be something like glTF Transform (

import { Document, WebIO } from '@gltf-transform/core';
import { ALL_EXTENSIONS } from '@gltf-transform/extensions';

// Configure I/O.
const io = new WebIO().registerExtensions(ALL_EXTENSIONS);

// Read from URL.
const document = await'path/to/model.glb');

// Rename something.
const scene = document.getRoot().listScenes()[0];
for (const childNode of scene.listChildren()) {

  const mesh = childNode.getMesh();
  if (mesh) {

// Write to byte array (Uint8Array).
const glb = await io.writeBinary(document);
1 Like

It would be great if ThreeJS could handle all of my problems, but as long as my problem gets solved, I don’t mind. I am not creating the most performant website anyway.

I spent some time using both libraries together to solve my problem, and in the end, I successfully managed to do it. Unlike ThreeJS, I appreciated that “gltf-transform” took care of the remaining tasks, such as renaming animation target objects properly, etc.

1 Like