# Project Files (.babylonproj)

> A single-file project bundle that composes a Smart Asset map, an Override Manager registry, and a companion .babylon for user-created scene content. Authored through the Inspector V2 Project Authoring pane.

Source: https://doc.babylonjs.com/toolsAndResources/inspectorv2/projectFile

## Overview

A `.babylonproj` file is a single-file project bundle for a Babylon scene. It packages three layers in one zip:

1. A **Smart Asset map** — the registry of external assets the scene references ([Smart Assets](https://doc.babylonjs.com/features/featuresDeepDive/importers/smartAssets)).
2. The **Override Manager** state — declarative property diffs applied after load ([Override Manager](./overrideManager)).
3. A **companion `.babylon`** — meshes, lights, cameras, transform nodes, and materials that are *not* tracked by any smart asset (i.e. user-created scene content), plus a small side table mapping material texture slots back to SAM-tracked textures.

Together these three layers let a project capture both *external content* (glTF models, environment maps, textures) and *local authoring* (a sphere the user built, a PBR material, a camera placement) in a portable, declarative bundle. Reopening the project rebuilds the scene from the same external sources and reapplies the captured overrides on top.

`.babylonproj` is the save format produced by the **Project Authoring** pane in Inspector V2.

## Working with project files in the Inspector

Open Inspector V2 against any scene and look for the **Project Authoring** pane in the right-hand pane toolbar (cube icon). It contains three sections:

- **Project File** — Save the current scene as `scene.babylonproj`, or load an existing one.
- **Assets** — The Smart Asset list. Drop glTFs, OBJs, `.babylon` files, or textures here to register and load them under stable keys. Each row supports reload, unload, and remove.
- **Override Summary** — A live list of every property override currently in the [Override Manager](./overrideManager) registry.

The authoring loop is:

1. Drag external assets into the **Assets** section (or call `RegisterSmartAsset` / `LoadSmartAssetAsync` from code).
2. Build any user content directly in the scene — code, `MeshBuilder`, materials you author yourself, cameras and lights you place.
3. Tweak properties through the **Properties** pane. Each edit is captured as an [override](./overrideManager).
4. Click **Save Project (.babylonproj)** to download the bundle.
5. Reopen it later with **Load Project (.babylonproj)** in any session — the assets reload from their original URLs, your local content comes back from the companion `.babylon`, and your overrides reapply on top.

## File format

A `.babylonproj` is a standard zip archive with the following layout:

```
project.json
__project_locals__.babylon          (only if the scene has user-created objects)
assets/<key>.<ext>                  (bundled local blobs, e.g. user-dragged files)
```

### `project.json`

```jsonc
{
    "version": 2,
    "assets": {
        "boombox": { "url": "BoomBox/BoomBox.gltf" },
        "albedo":  { "url": "assets/albedo.png", "type": "texture" },
        "__project_locals__": { "url": "__project_locals__.babylon" }
    },
    "overrides": [
        { "targetType": "materials", "targetName": "paintMat",
          "targetIndex": 0, "propertyPath": "albedoColor", "value": [1, 0, 0] }
    ],
    "companionBindings": {
        "paintMat": { "albedoTexture": "albedo" }
    }
}
```

- **`assets`** is the [Smart Asset map](https://doc.babylonjs.com/features/featuresDeepDive/importers/smartAssets#declarative-asset-maps), extended with one reserved key (`__project_locals__`) that points at the companion `.babylon` inside the zip.
- **`overrides`** is the serialized [Override Manager](./overrideManager) registry.
- **`companionBindings`** records which texture slot on which user-authored material should be reattached to which SAM-tracked texture after load. This is what lets a `PBRMaterial` the user built reference a SAM texture without embedding texture bytes inside the companion `.babylon`.

Remote URLs (`http://`, `https://`) in the asset map are stored as references and **not** bundled into the zip. Local content (`blob:` and `data:` URIs — typically files the user dragged in) is fetched, written into `assets/`, and the entry's URL is rewritten to a relative path. On load, the loader recreates blob URLs for each bundled file and feeds them back through the Smart Asset Manager.

### Companion `.babylon` and texture bindings

The companion `.babylon` is generated by `SceneSerializer.SerializeMesh` from the subset of scene content that is **not** owned by any external smart asset — every user-created `Mesh`, `Light`, `Camera`, `TransformNode`, and standalone `Material`.

Before the companion is written, every serialized material is walked for `*Texture` slots that resolve to a SAM-tracked texture. Each such slot is removed from the serialized material data and recorded in `companionBindings` instead. After the companion loads on the next open, the project loader walks `companionBindings` and reattaches each slot to the SAM texture by key — without ever needing to embed texture bytes or refer to a now-defunct `blob:` URL.

If there are no user-created objects at all, the companion `.babylon` is omitted and the `__project_locals__` entry is not added to the asset map.

## Code API

The same operations the Project Authoring pane performs are available as exported functions on `@babylonjs/inspector-v2/projects/projectFile`:

| Function | Purpose |
| --- | --- |
| `SaveProjectFileAsync(scene)` | Produces a `Blob` containing the `.babylonproj` zip. |
| `LoadProjectFileAsync(scene, file)` | Loads a `.babylonproj` zip into the scene. |
| `SerializeProject(scene, baseUrl?)` | Lower-level: returns an `IProjectBundle` (the JSON document + an optional companion blob), useful for serving the JSON over a network without zipping. |
| `LoadProjectAsync(scene, source, rootUrl?)` | Lower-level: load from a URL, `File`, or pre-parsed `ISerializedProject` JSON object. |
| `DeserializeProject(data)` | Validate a parsed JSON document against the v2 schema. |

The zip layer uses [fflate](https://github.com/101arrowz/fflate), loaded via dynamic `import()` so the dependency stays out of the main inspector bundle and zip/unzip runs in a Web Worker instead of blocking the UI thread.

```ts
import { SaveProjectFileAsync, LoadProjectFileAsync } from "@babylonjs/inspector-v2/projects/projectFile";
import { Tools } from "@babylonjs/core";

// Save
const blob = await SaveProjectFileAsync(scene);
Tools.Download(blob, "scene.babylonproj");

// Load
await LoadProjectFileAsync(scene, fileFromInputElement);
```

`LoadProjectAsync` and `LoadProjectFileAsync` both follow the same sequence: clear the existing smart-asset registry and dispose user-owned scene content, register every asset entry, `LoadAllSmartAssetsAsync`, then load the companion `.babylon` (so its bindings can find the now-loaded textures), then apply overrides. The active render loop is paused for the duration of the swap so disposing the camera mid-frame can't kill the loop with a "No camera defined" exception.

## What round-trips, and what doesn't

Anything tracked by [Smart Assets](https://doc.babylonjs.com/features/featuresDeepDive/importers/smartAssets) round-trips by URL (or, for local files, by being bundled into the zip). User-created `Mesh` geometry, `Material`s (Standard / PBR / Multi / Node), texture-slot bindings to SAM textures, `Light`s, `Camera`s, `TransformNode`s, and scene/material image processing all round-trip via the companion `.babylon`. Property overrides on any of the above are reapplied last.

Things that **don't** round-trip today:

- `PostProcess` attachments to cameras (post-processes attach to a specific camera instance, which is disposed and recreated on load).
- `AdvancedDynamicTexture` GUI controls (not part of the `.babylon` format).
- Audio (`Sound` / `AudioEngine` state).
- Particle systems with live runtime state and baked vertex animations.
- Complex shader-driven content like Gaussian Splatting (the mesh round-trips, but its companion utility materials get duplicated on each load cycle).
- Skeleton animation playback state.

If a scene "looks different after load," it is almost always one of the items above rather than camera or mesh state drift.

## Related

- [Smart Assets](https://doc.babylonjs.com/features/featuresDeepDive/importers/smartAssets) — the registry of external assets that the project's `assets` layer is built on.
- [Override Manager](./overrideManager) — the property-diff registry that the project's `overrides` layer is built on.

## Further reading

- [Smart Assets](https://doc.babylonjs.com/features/featuresDeepDive/importers/smartAssets)
- [Override Manager](https://doc.babylonjs.com/toolsAndResources/inspectorv2/overrideManager)
