Skip to content

.paq Specification

.paq is a file format we use to ship asset packs. It is a ZIP archive with a specific predefined content structure and .paq extension. We use the .paq extension for a better user experience with the Blender's file selector.

engon is able to install any .paq file that follows the given structure and automatically displays all found assets in the browser. Alternatively a folder containing extracted .paq file with .pack-info can be registered into the browser using search paths. Check search paths for more information. This is a good option for development, as you don't have to archive the contents into .paq each time.

Specification is up to date with engon 1.4.0

This specification was written based on engon 1.4.0. engon is always backwards compatible and will load the index even from previous versions. Packs made according to this specification will load in all future engon versions.

.paq file structure

pack_name.paq
├── blends/
├── previews/
├── textures/ [optional]
├── fonts/ [optional]
├── sequences/ [optional]
├── icons/
│   ├── vendor.png [optional]
│   └── pack.png [optional]
├── index.json
└── pack_name.pack-info
Field Description
blends/ Directory with .blend files, can contain nested folders for categories. Can contain arbitrary .blends, but he ones referenced in index.json can be spawned and have to follow Asset Conventions.
previews/ Directory with .png preview images for the assets, ideally the folder structure matches the blends/, but it's not a hard requirement.
textures/ Optional Directory with texture files used by the assets.
fonts/ Optional Directory with .ttf files used by the assets.
sequences/ Optional directory with sequence files named according to Blender's naming convention.
icons/ Optional directory with .png icon files for the pack and vendor.
index.json One or more JSON files containing metadata and information about the assets. See index.json.
pack_name.pack-info JSON like file containing information about the asset pack. See .pack-info.
Recommended folder structure

This folder structure is what we use and we recommend it based on our experience. However any other structure will most likely work as well as long as the paths in index.json are relative to the root of the pack.

Packaging to .paq

To create a .paq out of your folder hierarchy use your favorite tool to create a ZIP archive of the contents and rename the .zip to .paq.

Paths have to be relative and encapsulated

In order to ship a pack with all dependencies without missing textures, libraries and dependencies, all the paths have to be made relative within the .paq hierarchy.

If the .paq is shipped with textures pointing to some local directory using absolute path, then this path will most likely not be available on the user's device, as the pack can be installed in arbitrary location.

.pack-info file

Contains information about the given pack. Structure:

{
    "full_name": "pack_name",
    "version": [1, 0, 0],
    "vendor": "vendor_name",
    "engon_features": ["aquatiq"],
    "min_engon_version": [1, 3, 0],
    "index_paths": ["index.json"],
    "file_id_prefix": "/pack_name",
    "pack_icon": "icons/pack_icon.png",
    "vendor_icon": "icons/vendor_icon.png"
}
Field Description
full_name Full name of the asset pack.
version Version of the asset pack in [major, minor, patch] format according to semantic versioning.
vendor Name of the vendor providing the asset pack.
engon_features A list of engon features to enable when the asset pack is installed (can be empty, this is mostly tied to polygoniq features).
min_engon_version The minimum version of engon required to use the asset pack.
index_paths A list of paths to index.json files within the asset pack.
file_id_prefix A prefix used to make sure file paths are unique within our addon.
pack_icon Optional path to the icon for the pack ("null" for empty)
vendor_icon Optional path to the icon for the vendor ("null" for empty).

index.json

This is the heart of the asset pack. It provides information about assets, categories and other. Minimal working set of fields is:

{
    "asset_data": {
        "$ASSET_DATA_ID": {
            "dependency_files": [
                "$FILE_ID_PREFIX:ROOT_RELPATH_TO_DEPENDENCY",
                ...
            ],
            "primary_blend_file": "$FILE_ID_PREFIX:ROOT_RELPATH_TO_BLEND",
            "type": "$ASSET_DATA_TYPE"
        },
        ...
    },
    "asset_metadata": {
        "$ASSET_ID": {
            "title": "$ASSET_TITLE",
            "type": "$ASSET_DATA_TYPE",
            "preview_file: "$FILE_ID_PREFIX:$ROOT_RELPATH_TO_PREVIEW.png",
            "numeric_parameters": {...},
            "tags": {...},
            "text_parameters": {
                "bpy.data.version": "$BPY_DATA_VERSION",
                "mapr_asset_id": "$ASSET_ID",
                ...
            },
            "vector_parameters": {...}
        },
        ...
    },
    "category_metadata": {
        "/": {
            "title": "$CATEGORY_TITLE"
        },
        "$CATEGORY_PATH": {
            "title": "$CATEGORY_TITLE"
        },
        "$CATEGORY_PATH": {
            "title": "$CATEGORY_TITLE"
        },
        ...
    },
    "child_asset_data": {
        "$ASSET_ID": [
            "$ASSET_DATA_ID",
            ...
        ],
        ...
    },
    "child_assets": {
        "$CATEGORY_PATH": [
            "$ASSET_ID",
            ...
        ],
        ...
    },
    "child_categories": {
        "$CATEGORY_PATH": [
            "$CATEGORY_PATH",
            ...
        ]
    }
}
Field Description
$ASSET_ID Unique identifier for the asset. Use UUID version 4 according to RFC4122 in string representation. For example, we use uuid.uuid4().
$ASSET_DATA_ID Unique identifier for the asset data. Use UUID version 4 according to RFC4122 in string representation. For example, we use uuid.uuid4(). For most use-cases, every asset will have exactly one $ASSET_ID and exactly one $ASSET_DATA_ID. We don't support spawning multiple $ASSET_DATA_IDs yet.
$FILE_ID_PREFIX Prefix used for all paths within mapr index. Has to start with / and end with :. This should be equal to the prefix provided in .pack-info file. For example /botaniq:
$ROOT_RELPATH_TO_DEPENDENCY Relative path from the root of the pack to the dependency file - can be other .blend, .jpg, .png or anything that Blender allows as dependency.
$ROOT_RELPATH_TO_BLEND Relative path from the root of the pack to the primary .blend file - the file where we spawn the asset from.
$ASSET_DATA_TYPE Type of the asset data. Values: {blender_model, blender_world, blender_geometry_nodes, blender_particle_system, blender_material, blender_scene}
$ASSET_TITLE Title of the asset - this will be displayed in the browser
$ROOT_RELPATH_TO_PREVIEW.png Relative path from the root of the pack to the preview image .png file.
$BPY_DATA_VERSION Version of the Blender data in string representation, e.g "3.6.13" - This is the version of the Blender data - run bpy.data.version in Blender's console to obtain it. This value is different from the Blender version.
$CATEGORY_TITLE Title of the category - this will be displayed in the browser.
$CATEGORY_PATH Path to the category, has to start with root (/).
Example index.json
{
    "asset_data": {
        "57626a41-dafe-4464-a9c0-5f544eb7135e": {
            "dependency_files": [
                "/botaniq:blends/models/bq_Library_Materials.blend",
                "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_A_spring-summer.blend",
                "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_D_spring-summer.blend",
                "/botaniq:textures/bq_Leaf_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Leaf_Ivy_Normal.jpg",
                "/botaniq:textures/bq_Stem_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Stem_Ivy_Normal.jpg"
            ],
            "primary_blend_file": "/botaniq:blends/particles/vines/bq_pps_Vines_Basic_A_spring-summer.blend",
            "type": "blender_particle_system"
        },
        "8097b7aa-5ba7-4f4d-bd51-19cbe8edee63": {
            "dependency_files": [
                "/botaniq:blends/models/bq_Library_Materials.blend",
                "/botaniq:textures/bq_Leaf_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Leaf_Ivy_Normal.jpg",
                "/botaniq:textures/bq_Stem_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Stem_Ivy_Normal.jpg"
            ],
            "primary_blend_file": "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_A_spring-summer.blend",
            "type": "blender_model"
        },
        "d6007dde-6539-41bb-88d7-bf8a5f57acd2": {
            "dependency_files": [
                "/botaniq:blends/models/bq_Library_Materials.blend",
                "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_A_spring-summer.blend",
                "/botaniq:textures/bq_Leaf_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Leaf_Ivy_Normal.jpg",
                "/botaniq:textures/bq_Stem_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Stem_Ivy_Normal.jpg"
            ],
            "primary_blend_file": "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_D_spring-summer.blend",
            "type": "blender_model"
        },
        "dcd46b6b-39c5-48cb-acf1-7bc573093369": {
            "dependency_files": [
                "/botaniq:blends/models/bq_Library_Materials.blend",
                "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_A_spring-summer.blend",
                "/botaniq:blends/models/vine/bq_Vine_Vitis-vinifera_D_spring-summer.blend",
                "/botaniq:textures/bq_Leaf_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Leaf_Ivy_Normal.jpg",
                "/botaniq:textures/bq_Stem_Ivy_Diffuse.png",
                "/botaniq:textures/bq_Stem_Ivy_Normal.jpg"
            ],
            "primary_blend_file": "/botaniq:blends/geonodes/vines/bq_Vines_Vitis-vinifera_A_spring-summer.blend",
            "type": "blender_geometry_nodes"
        }
    },
    "asset_metadata": {
        "8a29aacb-7494-46c0-83a4-d46257b30003": {
            "numeric_parameters": {},
            "preview_file": "/botaniq:previews/particles/vines/bq_pps_Vines_Basic_A_spring-summer.png",
            "tags": [
                "Spring",
                "Summer",
                "variant starter",
                "variant lite",
                "variant full"
            ],
            "text_parameters": {
                "bpy.data.version": "3.6.13",
                "copyright": "(c) 2018- polygoniq xyz s.r.o.",
                "license": "Royalty Free",
                "mapr_asset_id": "8a29aacb-7494-46c0-83a4-d46257b30003",
                "polygoniq_addon": "botaniq"
            },
            "title": "pps Vines Basic A spring summer",
            "type": "blender_particle_system",
            "vector_parameters": {
                "introduced_in": [
                    6,
                    2,
                    0
                ]
            }
        },
        "b3276bc7-f444-4138-a03f-56c8acb5b03a": {
            "numeric_parameters": {
                "depth": 0.09522026777267456,
                "height": 0.11390715092420578,
                "image_count": 4,
                "material_count": 2,
                "object_count": 1,
                "triangle_count": 44,
                "triangle_count_applied": 44,
                "width": 0.047646842896938324
            },
            "preview_file": "/botaniq:previews/models/vine/bq_Vine_Vitis-vinifera_A_spring-summer.png",
            "tags": [
                "Spring",
                "Summer",
                "variant starter",
                "variant lite",
                "variant full"
            ],
            "text_parameters": {
                "bpy.data.version": "3.6.13",
                "bq_animation_type": "Wind-Simple",
                "class": "Magnoliopsida",
                "class_en": "Dicots",
                "conservation_status": "0 - Least concern (LC)",
                "copyright": "(c) 2018- polygoniq xyz s.r.o.",
                "family": "Vitaceae",
                "family_en": "Grape family",
                "genus": "Vitis",
                "genus_en": "Grapevines",
                "license": "Royalty Free",
                "mapr_asset_id": "b3276bc7-f444-4138-a03f-56c8acb5b03a",
                "model_detail": "Low-poly",
                "order": "Vitales",
                "order_en": "Grapes and allies",
                "polygoniq_addon": "botaniq",
                "species": "Vitis vinifera",
                "species_en": "Wine grape"
            },
            "title": "Vine Vitis vinifera A spring summer",
            "type": "blender_model",
            "vector_parameters": {
                "introduced_in": [
                    6,
                    2,
                    0
                ]
            }
        },
        "cd6b5586-2460-4e95-ae3e-b1cbebb1fc00": {
            "numeric_parameters": {},
            "preview_file": "/botaniq:previews/geonodes/vines/bq_Vines_Vitis-vinifera_A_spring-summer.png",
            "tags": [
                "Drawable",
                "Spring",
                "Summer",
                "variant lite",
                "variant full"
            ],
            "text_parameters": {
                "bpy.data.version": "3.6.13",
                "class": "Magnoliopsida",
                "class_en": "Dicots",
                "conservation_status": "0 - Least concern (LC)",
                "copyright": "(c) 2018- polygoniq xyz s.r.o.",
                "family": "Vitaceae",
                "family_en": "Grape family",
                "genus": "Vitis",
                "genus_en": "Grapevines",
                "license": "Royalty Free",
                "mapr_asset_id": "cd6b5586-2460-4e95-ae3e-b1cbebb1fc00",
                "order": "Vitales",
                "order_en": "Grapes and allies",
                "polygoniq_addon": "botaniq",
                "species": "Vitis vinifera",
                "species_en": "Wine grape"
            },
            "title": "Vines Vitis vinifera A spring summer",
            "type": "blender_geometry_nodes",
            "vector_parameters": {
                "introduced_in": [
                    7,
                    0,
                    0
                ]
            }
        },
        "dde8edeb-0509-43e4-b4ad-8af939bf141d": {
            "numeric_parameters": {
                "depth": 0.14925122261047363,
                "height": 0.15415030717849731,
                "image_count": 4,
                "material_count": 2,
                "object_count": 1,
                "triangle_count": 136,
                "triangle_count_applied": 136,
                "width": 0.12670491635799408
            },
            "preview_file": "/botaniq:previews/models/vine/bq_Vine_Vitis-vinifera_D_spring-summer.png",
            "tags": [
                "Spring",
                "Summer",
                "variant starter",
                "variant lite",
                "variant full"
            ],
            "text_parameters": {
                "bpy.data.version": "3.6.13",
                "bq_animation_type": "Wind-Simple",
                "class": "Magnoliopsida",
                "class_en": "Dicots",
                "conservation_status": "0 - Least concern (LC)",
                "copyright": "(c) 2018- polygoniq xyz s.r.o.",
                "family": "Vitaceae",
                "family_en": "Grape family",
                "genus": "Vitis",
                "genus_en": "Grapevines",
                "license": "Royalty Free",
                "mapr_asset_id": "dde8edeb-0509-43e4-b4ad-8af939bf141d",
                "model_detail": "Low-poly",
                "order": "Vitales",
                "order_en": "Grapes and allies",
                "polygoniq_addon": "botaniq",
                "species": "Vitis vinifera",
                "species_en": "Wine grape"
            },
            "title": "Vine Vitis vinifera D spring summer",
            "type": "blender_model",
            "vector_parameters": {
                "introduced_in": [
                    6,
                    2,
                    0
                ]
            }
        }
    },
    "category_metadata": {
        "/": {
            "title": "all"
        },
        "/botaniq": {
            "title": "botaniq"
        },
        "/botaniq/vine": {
            "title": "Vine"
        },
        "/botaniq/vines": {
            "title": "Vines"
        }
    },
    "child_asset_data": {
        "8a29aacb-7494-46c0-83a4-d46257b30003": [
            "57626a41-dafe-4464-a9c0-5f544eb7135e"
        ],
        "b3276bc7-f444-4138-a03f-56c8acb5b03a": [
            "8097b7aa-5ba7-4f4d-bd51-19cbe8edee63"
        ],
        "cd6b5586-2460-4e95-ae3e-b1cbebb1fc00": [
            "dcd46b6b-39c5-48cb-acf1-7bc573093369"
        ],
        "dde8edeb-0509-43e4-b4ad-8af939bf141d": [
            "d6007dde-6539-41bb-88d7-bf8a5f57acd2"
        ]
    },
    "child_assets": {
        "/botaniq/vine": [
            "b3276bc7-f444-4138-a03f-56c8acb5b03a",
            "dde8edeb-0509-43e4-b4ad-8af939bf141d"
        ],
        "/botaniq/vines": [
            "8a29aacb-7494-46c0-83a4-d46257b30003",
            "cd6b5586-2460-4e95-ae3e-b1cbebb1fc00"
        ]
    },
    "child_categories": {
        "/": [
            "/botaniq"
        ],
        "/botaniq": [
            "/botaniq/vine",
            "/botaniq/vines"
        ]
    }
}

Asset Conventions

Each asset is stored in a primary .blend file. Individual $ASSET_DATA_TYPEs assume different structure of the contents of the .blend, so we can spawn the asset consistently. All the datablocks marked as required for the data type need to be local in the .blend file so they are reachable in the API.

Spawning the asset to the scene mostly requires the relevant datablock to have the same name as the basename of the .blend without extension - e.g. bq_Vine_Vitis-vinifera_D_spring-summer.blend contains collection bq_Vine_Vitis-vinifera_D_spring-summer.blend.

Asset Data Type Requirements
blender_model Collection (bpy.data.collections) with the same name as the filename of the blend without extension is loaded from the file.
blender_world First world (bpy.data.worlds) is loaded.
blender_geometry_nodes Object (bpy.data.objects) with the same name as the filename of the blend without extension is loaded. This object has a modifier with the geometry nodes setup.
blender_particle_system All particle systems (bpy.data.particles) are loaded from the .blend file. Dependencies of the particle system like individual instanced assets are loaded automatically by Blender.
blender_material First material (bpy.data.materials) is loaded, or if no material is found, we try to find a mesh with the same name as the filename without extensions and load first material from it.
blender_scene First scene (bpy.data.scenes) is loaded.