---
title: "BRZ: Bruce Archive Format"
section: "File Formats"
route: /formatbrz
account: {accountId}
bruce_api: https://{accountId}.api.nextspace.host
guardian_api: https://guardian.nextspace.host
---
# BRZ: Bruce Archive Format

A `.brz` file is a Nextspace archive format that packages an Assembly. It is a hierarchy of Entities at a single root Entity node for export, import, and interchange between systems. It carries the Entity attribute values, parent-child hierarchy with transforms, and embedded 3D geometry (GLB).

BRZ files are produced by an [Export BRZ](/apiexportbrz) job and consumed by the [Import Assembly](/apiimportassembly) endpoint.

## Container format

A BRZ file is a standard ZIP archive containing exactly one entry: a SQLite database named `model.db`. A ".db" file renamed to ".brz" is not considered valid.

```text
archive.brz
└── model.db
```

## Complete schema

The following is the exact creation script and schema explanation to use for new BRZ files. Copy-paste this to initialise a valid v7 database before inserting any data.

```sql
PRAGMA application_id = 1112687682;
PRAGMA user_version = 7;

-- Attribute definitions.
-- One row per distinct attribute that Entities in this archive can carry.
CREATE TABLE Attribute (
    id          INTEGER PRIMARY KEY,
    -- Dot-separated grouping path, e.g. "dimensions.physical".
    -- "Bruce" is reserved for internal use. Never create custom attributes under it.
    category    TEXT,
    name        TEXT,
    -- 0=STRING  1=NUMERIC  2=BOOLEAN  3=TIMESTAMP  4=DATE
    dataType    INT,
    -- Optional regex validation pattern. NULL or empty if no validation is needed.
    pattern     TEXT,
    displayName TEXT,
    description TEXT
);

-- One row per Entity.
-- Keep hierarchy minimal. Prefer direct geometry-bearing Entities for key parts (e.g. DOOR, WALL_EAST, NAS).
-- Avoid unnecessary wrapper or grouping nodes.
-- It is preferred for leaf-nodes to have geometry, and parent nodes to be mostly organizational.
CREATE TABLE Entity (
    -- Local auto-increment. Used for all FK references within this file only.
    internalID  INTEGER PRIMARY KEY,
    name        TEXT,
    -- 0 = regular Entity instance, 1 = prototype definition (deprecated, don't create new prototypes).
    prototype   BOOLEAN,
    -- UUID from the source system. Used for identity matching after an export from Nextspace.
    -- Leave as NULL for generated files that aren't coming from Nextspace.
    ID          TEXT,
    -- References "EntityType.internalid".
    -- Leave as NULL if no defined Entity Types are being brought in.
    typeid      INTEGER,
    -- Optional geohash string for spatial indexing.
    -- Leave as NULL if not applicable.
    geohash     TEXT,
    -- Optional WGS84 geographic position.
    -- Leave as NULL if not applicable (ie: Entities are relatively positioned within the Assembly).
    longitude   DOUBLE PRECISION,
    latitude    DOUBLE PRECISION,
    altitude    DOUBLE PRECISION
);

-- Attribute values for Entities. One row per attribute value per Entity.
-- Populate only the value column that matches the attribute dataType; leave the others NULL.
-- STRING/BOOLEAN/TIMESTAMP/DATE values under ~240 chars -> StringValue.
-- STRING values over ~240 chars -> LongTextValue.
-- NUMERIC values (and booleans as 0.0/1.0) -> NumericValue.
CREATE TABLE EntityAttribute (
    -- References "Entity.internalID".
    entityID      BIGINT,
    -- References "Attribute.id".
    AttributeID   BIGINT,
    StringValue   TEXT,
    LongTextValue TEXT,
    NumericValue  DOUBLE PRECISION
);

-- One row per GLB geometry asset.
-- The binary data must be zlib-compressed (RFC 1950); the importer always decompresses before use.
-- GLB geometry MUST use Y-up (the glTF standard). ParentRelationship transforms must also be in Y-up to match.
-- See the "GLB requirements" section below for mandatory content rules.
CREATE TABLE Geometry (
    id           INTEGER PRIMARY KEY,
    -- e.g. "model/gltf-binary"
    type         TEXT,
    -- UUID from the source system.
    -- Leave as NULL for generated files that aren't coming from Nextspace.
    persistentID TEXT,
    -- Deprecated field.
    -- Always set this to NULL for generated files as it'll prioritize checking filepath over data.
    filepath     TEXT,
    -- Vertex / face / line counts. Set to 0 if unknown.
    nverts       INT,
    nfaces       INT,
    nlines       INT,
    -- Axis-aligned bounding box of the geometry in its local space.
    minx         DOUBLE PRECISION,
    miny         DOUBLE PRECISION,
    minz         DOUBLE PRECISION,
    maxx         DOUBLE PRECISION,
    maxy         DOUBLE PRECISION,
    maxz         DOUBLE PRECISION,
    -- Uncompressed byte size of the GLB.
    size         DOUBLE PRECISION,
    -- CRC32 of the uncompressed GLB bytes. Used by the server for deduplication.
    hash         INTEGER,
    -- Hash algorithm version. Always 1 (CRC32).
    hashVersion  SMALLINT,
    -- Zlib-compressed GLB bytes (RFC 1950: 2-byte zlib header + DEFLATE payload + 4-byte checksum).
    -- Must not be stored uncompressed or as raw DEFLATE without the zlib wrapper.
    -- In Python use: zlib.compress(glb_bytes).
    -- In Node.js use: zlib.deflateSync(glbBuffer) (use deflateSync, NOT deflateRawSync).
    data         VARBINARY
);

-- Defines the parent-child hierarchy and the local transform of each child.
-- Every non-root Entity must have exactly one row here.
-- Shallow hierarchies are recommended. If a part is in the BOM, attach geometry to that Entity directly.
CREATE TABLE ParentRelationship (
    -- Both reference "Entity.internalID".
    parentID    BIGINT,
    childID     BIGINT,
    -- Zero-based ordering index among siblings.
    childNumber INT,
    -- Local translation in Y-up space (matching the GLB coordinate system).
    -- e.g. px = right, py = up, pz = toward viewer.
    px          DOUBLE PRECISION,
    py          DOUBLE PRECISION,
    pz          DOUBLE PRECISION,
    -- Local rotation as a unit quaternion. Identity = (0, 0, 0, 1).
    qx          DOUBLE PRECISION,
    qy          DOUBLE PRECISION,
    qz          DOUBLE PRECISION,
    qw          DOUBLE PRECISION,
    -- Local scale per axis. Identity = (1, 1, 1).
    sx          DOUBLE PRECISION,
    sy          DOUBLE PRECISION,
    sz          DOUBLE PRECISION
);

-- Links instance Entities to their prototype.
-- Only needed when multiple Entities share the same geometric definition.
-- Deprecated and not needed for newly generated files.
CREATE TABLE PrototypeRelationship (
    -- Both reference "Entity.internalID".
    instanceID  BIGINT,
    prototypeID BIGINT
);

-- Optional material references for a geometry row.
-- Can be left empty for generated files.
-- Simple explicit materials are recommended over vertex colors alone.
-- Window/glazing (and similar) materials should be mostly transparent.
CREATE TABLE GeometryMaterial (
    id                INTEGER PRIMARY KEY,
    -- References "Geometry.id".
    geometryID        BIGINT,
    -- Material slot path within the GLB.
    path              TEXT,
    materialReference TEXT
);

-- Alternative to embedding geometry in "Geometry.data": points to a downloadable URL instead.
-- Only populate this if "Geometry.data" is NULL (e.g. for very large assets).
-- Can be left empty for generated files that embed geometry directly.
CREATE TABLE GeometryRemoteURL (
    -- References "Geometry.id".
    geometryID BIGINT PRIMARY KEY,
    url        TEXT
);

-- Not read by the current importer. Can be left empty.
CREATE TABLE EntityRemoteURL (
    -- References "Entity.internalID".
    entityID BIGINT PRIMARY KEY,
    url      TEXT
);

-- Metadata about the account that exported this file.
-- Leave empty if generating files outside of Nextspace.
CREATE TABLE AccountSettings (
    accountID   TEXT,
    accountName TEXT,
    -- e.g. "prod", "uat", "dev".
    environment TEXT
);

-- Generic key/value store.
-- Leave empty if generating files outside of Nextspace.
CREATE TABLE Parameter (
    name  TEXT PRIMARY KEY,
    value TEXT
);

-- Defines the root Entity of the assembly.
-- At least one row is required; the importer uses this to locate the top of the hierarchy.
CREATE TABLE Component (
    id           INTEGER PRIMARY KEY,
    name         TEXT,
    -- References "Entity.internalID" of the root entity.
    rootEntityID BIGINT
);

-- Associates Entities with geometry at specific levels of detail.
-- Add one row per Entity that has geometry.
-- LODs should be marked with LODCategory = "GLB" and LODGroup = "DEFAULT".
CREATE TABLE EntityLOD (
    id          INTEGER PRIMARY KEY,
    -- References "Entity.internalID".
    entityID    BIGINT,
    -- References "Geometry.id".
    geometryID  BIGINT,
    -- 0 = highest detail.
    level       INT,
    -- "GLB" for primary geometry. "BOUNDS" for a bounding-box proxy mesh.
    LODCategory TEXT,
    -- Optional grouping label. NULL is fine.
    LODGroup    TEXT
);

-- Entity Type definitions used by Entities in this archive.
CREATE TABLE EntityType (
    -- Local auto-increment. Used for FK references within this file only.
    internalid     INTEGER PRIMARY KEY,
    -- UUID from the source system. Used for identity matching after an export from Nextspace.
    -- Leave as NULL for generated files that aren't coming from Nextspace.
    id             TEXT,
    name           TEXT,
    description    TEXT,
    -- 1 = reject attributes not in this schema on import. 0 = allow extras.
    isStrictSchema INTEGER
);

-- Maps attributes to Entity Types, forming a typed schema.
CREATE TABLE SchemaAttribute (
    id              INTEGER PRIMARY KEY,
    -- References "EntityType.internalid".
    typeID          INTEGER,
    -- References "Attribute.id".
    attributeID     INTEGER,
    -- Display ordering index.
    attributeNumber INTEGER
);

-- Required indexes.
CREATE UNIQUE INDEX IDX_Geometry_FilePath   ON Geometry (filepath);
CREATE UNIQUE INDEX UIDX_Geometry_Material  ON GeometryMaterial (geometryID, path);
CREATE        INDEX IDX_Geometry_Hash       ON Geometry (hash);
CREATE UNIQUE INDEX IDX_Entity_ID           ON Entity (ID);
```

## Inserting geometry correctly

The most common mistake when generating BRZ files is populating the `Geometry.filepath` column. When that column is non-empty the importer tries to read a file from disk instead of reading the embedded blob, which silently drops all geometry. Always set `filepath` to `NULL`.

```sql
-- Correct: filepath is NULL, data contains zlib-compressed GLB bytes.
INSERT INTO Geometry (
    id, type, persistentID,
    filepath,   -- MUST be NULL
    nverts, nfaces, nlines,
    minx, miny, minz, maxx, maxy, maxz,
    size, hash, hashVersion,
    data
) VALUES (
    1, 'model/gltf-binary', NULL,
    NULL,       -- No filename
    24, 12, 0,
    -1.0, -1.0, 0.0, 1.0, 1.0, 2.5,
    2048, 305419896, 1,
    X'789C...'  -- zlib.compress(glb_bytes)
);

-- Then link the Entity to this Geometry via EntityLOD:
INSERT INTO EntityLOD (id, entityID, geometryID, level, LODCategory, LODGroup)
VALUES (1, 2, 1, 0, 'GLB', 'DEFAULT');
```

## GLB requirements

Each GLB embedded in the Geometry table must satisfy the following rules. Missing any of these will cause import failures, Tileset generation crashes, or models rendering incorrectly.

| Requirement | Description |
| --- | --- |
| At least one material | Every GLB must define at least one material using pbrMetallicRoughness. A simple default is fine (e.g. baseColorFactor [0.8, 0.8, 0.8, 1.0]). GLBs with zero materials will crash the Tileset generator. |
| Material reference on every primitive | The material index on each mesh primitive must be set. Omitting it produces undefined behaviour in downstream processing tools. |
| Vertex normals (NORMAL) | Every mesh primitive must include a NORMAL accessor alongside POSITION. Without normals, lighting is broken and some processing tools may crash. |
| Indexed triangles (mode 4) | Primitives must use indexed triangle mode. Non-indexed geometry or other modes (lines, points) are not reliably supported. |
| Y-up orientation | Geometry must be authored in Y-up space per the glTF specification. +X = right, +Y = up, −Z = forward. The Nextspace viewer (CesiumJS) expects Y-up and automatically converts to its internal Z-up scene coordinate system. Geometry authored in Z-up will appear sideways. |
| Single-node structure | A single scene containing one root node with one child mesh node is the recommended GLB structure. Multi-node GLBs work but single-node is preferred for stable importer and Tileset generation behaviour. |

### Minimal valid material example

```json
// Inside the glTF JSON of each GLB:
{
  "materials": [
    {
      "pbrMetallicRoughness": {
        "baseColorFactor": [0.8, 0.8, 0.8, 1.0],
        "metallicFactor": 0.0,
        "roughnessFactor": 0.9
      }
    }
  ],
  "meshes": [
    {
      "primitives": [
        {
          "attributes": { "POSITION": 0, "NORMAL": 1 },
          "indices": 2,
          "material": 0
        }
      ]
    }
  ]
}
```

## Positioning and placement

The `ParentRelationship` transform (px/py/pz, quaternion, scale) is **relative to the parent Entity**, not world-absolute. The importer converts each row into a 4×4 matrix stored on the child Entity. At render time the viewer computes the world matrix by chaining transforms up the hierarchy: `world = parent.world × child.local`.

No collision detection, gravity, or snap-to-surface logic is applied. Objects will float, intersect, or sink if their translations are not computed from their actual geometry bounds.

### Flat vs. nested hierarchies

In a **flat hierarchy** (every Entity is a direct child of the root), the root typically has an identity transform, so each child's px/py/pz values are effectively world-space coordinates.

In a **nested hierarchy** (e.g. monitor is a child of desk), each child is positioned relative to its parent. A monitor at `py = 0.76` under a desk means "0.76 m above the desk's local origin", not 0.76 m above the world floor.

### Recommended mesh origin convention

For generated assets, place each mesh origin at the **centre of its base contact surface** so that `miny = 0` for floor-standing objects. This simplifies placement: in a flat hierarchy, `py` is the world-space Y of the surface the object rests on.

### Placement from bounds

To place a child so its base sits on a surface, use the Geometry bounding box:

```text
child.py = surface_y - child.miny
```

In a flat hierarchy, `surface_y` is the world-space Y of the support surface. In a nested hierarchy it is the parent-local Y of the support surface (e.g. the parent's `maxy`). If meshes follow the `miny = 0` convention, the formula simplifies to `py = surface_y`.

### Worked example (flat hierarchy)

All Entities below are children of the root Entity (1). Because the root has an identity transform, px/py/pz are world positions.

```sql
-- Root Entity (1) has identity transform.
-- All children are parented directly to it.

-- Floor slab: miny = 0, maxy = 0.05.
-- Rests at world origin.
INSERT INTO ParentRelationship VALUES
    (1, 2, 0,   0.0, 0.0, 0.0,   0,0,0,1,   1,1,1);

-- Desk: miny = 0, maxy = 0.76.
-- Rests on the floor surface (floor.maxy = 0.05).
INSERT INTO ParentRelationship VALUES
    (1, 3, 1,   0.0, 0.05, 0.0,   0,0,0,1,   1,1,1);

-- Monitor: miny = 0, maxy = 0.41.
-- Rests on the desk surface (desk.py + desk.maxy = 0.05 + 0.76 = 0.81).
INSERT INTO ParentRelationship VALUES
    (1, 4, 2,   0.0, 0.81, 0.0,   0,0,0,1,   1,1,1);

-- Chair: miny = 0, maxy = 1.0.
-- Rests on the floor surface, offset sideways.
INSERT INTO ParentRelationship VALUES
    (1, 5, 3,   -0.6, 0.05, 0.4,   0,0,0,1,   1,1,1);
```

---

Urls on this page are resolved for account `{accountId}`.
Site index: https://docs.nextspace.host/llms.txt · whole site in one file: https://docs.nextspace.host/llms-full.txt
Human-readable version of this page: https://docs.nextspace.host/formatbrz
