Creating materials in the PC Editor

I’m using a JSON file to create materials within the editor. The files contains about 17 materials so I loop through each one and use the editor hooks to create it.

My problem is that although 17 materials are created, changing the material’s name and adding a texture only works once.

The code should explain it better, but firing the event ‘assets:add’ with editor.once() changes the first material’s name/diffuseMap, and using editor.on() changes all of them but to the same values.

const createMaterial = (folderName, textureName, materialName) => {
	const folder = findAssetType(folderName, 'folder');
	const texture = findAssetType(textureName, 'texture');'assets:create:material', { parent: folder[1] });
	editor.once('assets:add', asset => {
	    asset.set('name', materialName);
	    asset.set('data.diffuseMap', texture[1].get('id'));

What I’m looking for is to either get the material that’s created by'assets:create:material', { parent: folder[1] }); or a way to wait until the event has fired and executed. Are there Promises in here at all?



In the end I created two separate buttons within the UI (I’m building a Chrome plugin). One creates a load of New Materials, the other applies textures to those materials. Not perfect but good enough for our needs.

Things I tried was forcing a hard wait, a while loop for searching for the new asset, moving the editor.once() call to before the call to create the asset, and creating a load of new materials before immediately applying textures.

None of these worked. It looks like there needs to be a stop in JS execution so that the New Materials can be found by'assets:findOne', a => a.get('type') == 'material' && a.get('name') == 'New Material');.


Another update on this. I managed to crack it in the end.

Instead of creating a New Material, then applying a texture, I do it all before creating the material:

// taken from editor.js, line 39,278
const createMaterialApplyTexture = (materialName, textureId, parent, colours, tiling) => {
    var asset = {
        name: materialName,
        type: 'material',
        source: false,
        preload: true,
        parent: parent,
        scope: {
            type: 'project',

    // overwrite the defaults (provided by'schema:material:getDefaultData'))
    // with the texture, tiling and colour values = textureId; = true; = [colours.r, colours.g, colours.b]; = [tiling.x, tiling.y];'assets:create', asset);

This method does away with two separate buttons to create the materials then apply the textures. I was using'assets:create:material'), but using the above is much easier.

I have over 50 projects to create, each with 50 - 200 entities and associated materials to create. All the data are in JSON files. This function saves us days in setup time.

1 Like