Skip to content

Read project data and export JSON

Choose the right data format: a project to merge, scene geometry, or JSON for a Minecraft integration.

A plugin can add the contents of a saved project, read scene geometry, or prepare JSON for a Minecraft integration. Choose the format based on what you need to do with the result. These three representations are not interchangeable.

Download the complete project-data.js example. After installation, a button with a JSON icon appears in the toolbar. It opens a window with three actions. While one action is running, the other buttons and fields are disabled. Test importing on a copy of your project.

Three different tasks

Task Method Result
Add objects from another project and continue editing mergeContent(content, decode) Objects are added to the current scene
Pass visible geometry to your own analyzer or exporter getMeshes() Temporary THREE.Mesh objects containing a geometry snapshot
Obtain data for creating a model and playing animations in Minecraft await exportToJSON(fullProject, version) A game export object, or false if the export cannot proceed

editorAPI has no general-purpose getProject() method that returns all editable state. To merge content, use a project file or its original JSON string. Serializing a mesh snapshot or a game export does not create a BDEngine project file.

Merging projects, reading meshes, and exporting use editorAPI. The internal window.editor is used to check the current project before importing and to read the selected Minecraft version index. There is currently no public getter for the selected version. Check these dependencies on internal interfaces after editor updates.

Add the contents of a project

Pass a .bdengine or .bdstudio file as an ArrayBuffer with decode: true. Reading a file is asynchronous: capture the original project before arrayBuffer() and check that it has not changed before starting the import:

async function mergeProjectFile(file) {
// Internal editor fields: check these after editor updates.
const editor = window.editor;
const api = window.editorAPI;
if (!editor?.objects || !editor.history) {
throw new Error('The project is not ready yet.');
}
const root = editor.objects;
const history = editor.history;
const historyGeneration = history._generation;
const loadGeneration = editor._projectLoadGeneration;
const content = await file.arrayBuffer();
if (
window.editor !== editor ||
editor.objects !== root ||
editor.history !== history ||
history._generation !== historyGeneration ||
editor._projectLoadGeneration !== loadGeneration
) {
throw new Error('The project changed while the file was being read. Try importing again.');
}
await api.mergeContent(content, true);
}

Here, file is the user-selected File from an input[type=file] element. The check detects replacement of the editor, project root, or history, as well as the start of a new project load. If the original project has changed, the example does not call mergeContent: repeat the action in the intended project. Once merging has started, the editor performs its own checks that the project is still current.

Closing the window does not cancel an operation in progress. In the complete example, task state is shared across window openings and retained when the script is manually run again. If you reopen the window while a file is being read or imported, its controls remain disabled until the operation finishes. Running the script again does not start a second import in parallel; the result appears in the current window.

The editor detects supported project containers and their resources. Do not unpack a modern project file as an arbitrary ZIP or discard its embedded resources. For a project JSON string that has already been decoded, use decode: false:

await window.editorAPI.mergeContent(projectJsonText, false);

This must be a string in the project format, not an object produced by JSON.parse. Server API JSON is not suitable: its structure and purpose are different.

The method adds content to the current scene. The current implementation has restrictions on imported structure blocks, which the editor reports in its interface. Handled errors are also shown there. The editorAPI.mergeContent() wrapper does not return the internal method’s boolean result, so undefined after await indicates neither success nor failure. Check the scene and notifications.

Accepted inputs are detailed in the mergeContent reference.

Get temporary geometry

getMeshes() returns a snapshot of visible meshes. Mesh manager instances are expanded into individual Mesh objects; bounding boxes, light gizmos, and meshes inside lights are excluded. This is not the editor’s object tree: the number of meshes does not necessarily match the number of entries in the object list.

const meshes = window.editorAPI.getMeshes();
try {
console.log('Meshes in the snapshot:', meshes.length);
// Read meshes here. Do not add them back to the project to duplicate it.
} finally {
for (const mesh of meshes) {
mesh.removeFromParent();
mesh.geometry.dispose();
const materials = Array.isArray(mesh.material) ? mesh.material : [mesh.material];
materials.forEach(material => material.dispose());
}
}

In the current implementation, geometries and materials are cloned for the snapshot. Material textures may still be shared with the editor: do not call dispose() on map, alphaMap, or other snapshot textures. The code above releases only the geometries and materials created for the snapshot after use.

The world transform has already been copied into mesh.matrix, and matrixAutoUpdate is disabled. Do not treat these meshes’ position, rotation, and scale values as the project’s original editable transforms. Request a new snapshot after the scene changes. See the getMeshes contract.

Get export JSON

Specify the export mode and the target Minecraft version index:

// Reading an internal editor setting: check this after editor updates.
const version = window.editor.settingsEditor.exportMine.commandVersion;
const data = await window.editorAPI.exportToJSON(false, version);
if (data === false) {
console.log('No export was produced. Check the editor notification.');
} else {
console.log(data.version, data.type);
}
  • fullProject: true requests an export through Animator and switches the editor to that mode if needed. false does not switch an already open Animator back to model editing. The result therefore also depends on the current mode: in Animator, even false can produce type: "full". For a model export, switch to model editing first. This does not guarantee support for every feature of a regular datapack.
  • version is a numeric index in the editor’s version list, not a string such as "1.21.4" or a JSON schema version. If omitted, the API selects the latest supported index, even if the user previously chose a different version.
  • The method changes the type and selected version in the export window, updates it, and displays it to the user. It is not a background getter without side effects.
  • Use await, check for false, and handle exceptions. For example, unfinished HeadPaint textures block the export.

The complete example reads the selected index on each button click, saves the returned object to bde-export.json, and does not send it to a server. It does not publish the export or create a temporary ID.

In the returned object, fields such as version, type, passengers, datapack, and meta are at the root when present in that export. There is no content wrapper, and strings retain the [BDESERVERTAG] marker. Do not add the HTTP wrapper or treat this data as an editable project.

Signature: exportToJSON. Result format: JSON structure and differences between sources.

Verify with a test scene

  1. Save your original work. Create a separate project with one block display.
  2. Open the example window and count the meshes. Clicking again should not add objects to the scene; the counter reports temporary geometry.
  3. Choose a small saved project to merge. Check the added objects and notifications, then undo the import using the editor’s history.
  4. Switch projects while the file is being read. The import should stop with a message; objects from the file must not be added to the new project.
  5. Close and reopen the example window during an operation. Its buttons and fields should remain disabled until the operation finishes. Also check this when manually running the script again: the new window receives the result and enables its controls when the operation is complete.
  6. Switch to model editing and choose the required Minecraft version in the export window. Download the example’s JSON with fullProject unchecked and check version and type.
  7. In a separate scene, add an animation and repeat with the checkbox selected. Check fields against the scene’s contents rather than expecting every optional field to be present.

Real structure blocks, separate group origins, and other regular datapack features do not become available simply because a plugin calls the API. Before implementing a consumer, read the game JSON export limitations.

The example’s contracts were checked against publicFunctions.js, editor.js, utils.js, RenderRT.js, RenderRTCore.js, command.js, and Export.js. This checks the implementation; running an arbitrary exported project in Minecraft requires separate testing of your integration.