Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

Converting a bunch of artboards into separate Linked Smart Objects

Community Beginner ,
Sep 18, 2025 Sep 18, 2025

Hello all, 

I'm currently working on a huge file with numerous artboards. To lighten the file I'm converting each artboards into a smart object, into a linked smart object.

Since it's taking me some time to actually do it manually, I'm looking for a way to it automatedly create *linked smart objects* out of a selection. 

I'm on photoshop 2025 if that helps. 

 

Thanks for any help or clue 🙂

Arnault

TOPICS
Actions and scripting , Windows
411
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines

correct answers 2 Correct answers

Community Expert , Sep 18, 2025 Sep 18, 2025

@arnault_6305 

 

Try this v1.0 code. Revisions can be made if needed.

 

EDIT: 22nd September, code updated to v1.2!

 

Note: The linked smart object will have four guides indicating the original artboard bounds, which might be useful if you have content extending beyond the artboard edges.

 

/* 
Convert All Artboards Content to Separate Linked Smart Objects.jsx
Stephen Marsh
v1.0 - 19th September 2025: Initial release
v1.1 - 20th September 2025: Corrected the layer selection code to include gro
...
Translate
Community Expert , Sep 19, 2025 Sep 19, 2025

@arnault_6305 

 

Rather than processing all artboards, this new script only works on (multiple) selected artboards.

 

EDIT: 22nd September, code updated to v1.2!

 

/* 
Convert Selected Artboards Content to Separate Linked Smart Objects.jsx
Stephen Marsh
v1.0 - 19th September 2025: Revised to work on selected artboards instead of all top-level layerSets
v1.1 - 20th September 2025: Corrected the layer selection code to include groups
v1.2 - 22nd September 2025: Added a progress bar for the artboar
...
Translate
Adobe
Community Expert ,
Sep 19, 2025 Sep 19, 2025

@arnault_6305 

 

Rather than processing all artboards, this new script only works on (multiple) selected artboards.

 

EDIT: 22nd September, code updated to v1.2!

 

/* 
Convert Selected Artboards Content to Separate Linked Smart Objects.jsx
Stephen Marsh
v1.0 - 19th September 2025: Revised to work on selected artboards instead of all top-level layerSets
v1.1 - 20th September 2025: Corrected the layer selection code to include groups
v1.2 - 22nd September 2025: Added a progress bar for the artboard and .psb file processing loops
https://community.adobe.com/t5/photoshop-ecosystem-discussions/converting-a-bunch-of-artboards-into-separate-linked-smart-objects/m-p/15510949
Partly based on:
https://community.adobe.com/t5/photoshop-ecosystem-discussions/converting-to-linked-smart-object/m-p/13357539
Note: The linked smart object will have four guides indicating the original artboard bounds, which might be useful if you have content extending beyond the artboard edges.
*/

#target photoshop

app.activeDocument.suspendHistory("Convert Selected Artboard's Content to Separate Linked Smart Objects", "main()");

function main() {
    if (app.documents.length > 0) {
        var doc = app.activeDocument;
        var docName = doc.name.replace(/\.[^\.]+$/, '');

        ///// Process selected layers - from jazz-y (1st part) /////
        var s2t = stringIDToTypeID;
        (r = new ActionReference()).putProperty(s2t('property'), p = s2t('targetLayersIDs'));
        r.putEnumerated(s2t('document'), s2t('ordinal'), s2t('targetEnum'));
        var lrs = executeActionGet(r).getList(p),
            sel = new ActionReference();
        /////

        // 1st Progress Bar: Artboards
        var win1 = new Window("palette", "Processing Selected Artboards", undefined, {closeButton: false});
        win1.orientation = "column";
        win1.alignChildren = ["fill", "top"];
        win1.margins = 15;

        var txt1 = win1.add("statictext", undefined, "Processing artboards...");
        txt1.alignment = "fill";

        var progressBar1 = win1.add("progressbar", undefined, 0, lrs.count);
        progressBar1.preferredSize = [300, 20];

        win1.show();

        var processedCount = 0;

        ///// Process selected layers - from jazz-y (2nd part) ///// 
        for (var i = 0; i < lrs.count; i++) {
            sel.putIdentifier(s2t('layer'), p = lrs.getReference(i).getIdentifier(s2t('layerID')));
            (r = new ActionReference()).putIdentifier(s2t('layer'), p);
            (d = new ActionDescriptor()).putReference(s2t("target"), r);
            executeAction(s2t('select'), d, DialogModes.NO);
        /////

            var currentLayer = doc.activeLayer;

            txt1.text = "Artboard " + (i + 1) + " of " + lrs.count + " - " + currentLayer.name;
            progressBar1.value = i;
            win1.update();

            if (isArtboard() === true) {
                artboardBounds(currentLayer, doc);
                deselectAllLayers();

                var selectedCount = selectAllLayersInGroup(currentLayer);

                if (selectedCount > 0) {
                    var newSOName = docName + "_" + currentLayer.name;
                    convertToEmbeddedSmartObject(newSOName);
                    convertToLinkedSmartObject();
                    processedCount++;
                } else {
                    alert("No layers found in artboard: " + currentLayer.name);
                }
            } else {
                alert("Unexpected error: Are all selected layers artboards?");
                win1.close();
                return;
            }

            progressBar1.value = i + 1;
            win1.update();
        }
        /////

        win1.close();

        // 2nd Progress Bar: PSB files
        var psbFiles = getPSBFiles(doc);
        if (psbFiles.length > 0) {
            var win2 = new Window("palette", "Processing PSB Files", undefined, {closeButton: false});
            win2.orientation = "column";
            win2.alignChildren = ["fill", "top"];
            win2.margins = 15;

            var txt2 = win2.add("statictext", undefined, "Processing PSB files...");
            txt2.alignment = "fill";

            var progressBar2 = win2.add("progressbar", undefined, 0, psbFiles.length);
            progressBar2.preferredSize = [300, 20];

            win2.show();

            for (var i = 0; i < psbFiles.length; i++) {
                txt2.text = "File " + (i + 1) + " of " + psbFiles.length + " - " + decodeURI(psbFiles[i].name);
                progressBar2.value = i;
                win2.update();

                processSinglePSB(psbFiles[i]);

                progressBar2.value = i + 1;
                win2.update();
            }

            win2.close();
        }

        app.beep();
        alert(processedCount + " artboards" + (processedCount === 1 ? "" : "s") + " processed to linked smart objects.");

    } else {
        alert("A document must be open to use this script!");
    }
}


///// Helper Functions /////

function getPSBFiles(doc) {
    try {
        var docName = doc.name.replace(/\.[^\.]+$/, '');
        var assetsFolder = new Folder(doc.path + "/" + sanitiseName(docName) + "_Assets");
        if (!assetsFolder.exists) return [];
        return assetsFolder.getFiles("*.psb");
    } catch (e) {
        alert("Error finding saved .psb files: " + e.toString());
        return [];
    }
}

function processSinglePSB(f) {
    try {
        var openedDoc = app.open(f);
        app.activeDocument.activeLayer = app.activeDocument.layers["artboardBounds"];
        executeAction(stringIDToTypeID("newGuidesFromTarget"), undefined, DialogModes.NO);
        app.activeDocument.activeLayer.remove();
        openedDoc.close(SaveOptions.SAVECHANGES);
    } catch (e) {
        alert("Error opening " + f.name + ": " + e.toString());
    }
}

function selectAllLayersInGroup(group) {
    var selectedCount = 0;
    var childLayers = group.layers;
    for (var j = 0; j < childLayers.length; j++) {
        var layer = childLayers[j];
        if (layer.typename === "ArtLayer" || layer.typename === "LayerSet") {
            selectLayerById(layer.id, selectedCount > 0);
            selectedCount++;
        }
    }
    return selectedCount;
}

function isArtboard() {
    try {
        var d = new ActionDescriptor();
        var r = new ActionReference();
        r.putEnumerated(stringIDToTypeID('layer'), stringIDToTypeID('ordinal'), stringIDToTypeID('targetEnum'));
        var options = executeActionGet(r);
        return options.hasKey(stringIDToTypeID('artboard'));
    } catch (e) {}
}

function sanitiseName(name) {
    return name.replace(/[\/\\:\*\?"<>\|]/g, "_");
}

function selectLayerById(id, add) {
    var ref = new ActionReference();
    ref.putIdentifier(charIDToTypeID("Lyr "), id);
    var desc = new ActionDescriptor();
    desc.putReference(charIDToTypeID("null"), ref);
    if (add) {
        desc.putEnumerated(stringIDToTypeID("selectionModifier"),
            stringIDToTypeID("selectionModifierType"),
            stringIDToTypeID("addToSelection"));
    }
    desc.putBoolean(charIDToTypeID("MkVs"), false);
    executeAction(charIDToTypeID("slct"), desc, DialogModes.NO);
}

function deselectAllLayers() {
    try {
        var idselectNone = stringIDToTypeID("selectNoLayers");
        executeAction(idselectNone, undefined, DialogModes.NO);
    } catch (e) {
        app.activeDocument.activeLayer = app.activeDocument.layers[0];
    }
}

function convertToEmbeddedSmartObject(newName) {
    try {
        layerLock("protectNone");
        executeAction(stringIDToTypeID("newPlacedLayer"), undefined, DialogModes.NO);
        app.activeDocument.activeLayer.name = sanitiseName(newName);
    } catch (e) {
        alert("Error converting to smart object: " + e.toString());
    }
}

function layerLock(lockValue) {
    var idapplyLocking = stringIDToTypeID("applyLocking");
    var desc1113 = new ActionDescriptor();
    var idnull = charIDToTypeID("null");
    var ref514 = new ActionReference();
    var idLyr = charIDToTypeID("Lyr ");
    var idOrdn = charIDToTypeID("Ordn");
    var idTrgt = charIDToTypeID("Trgt");
    ref514.putEnumerated(idLyr, idOrdn, idTrgt);
    desc1113.putReference(idnull, ref514);
    var idlayerLocking = stringIDToTypeID("layerLocking");
    var desc1114 = new ActionDescriptor();
    var idprotectNone = stringIDToTypeID(lockValue);
    desc1114.putBoolean(idprotectNone, true);
    desc1113.putObject(idlayerLocking, idlayerLocking, desc1114);
    executeAction(idapplyLocking, desc1113, DialogModes.NO);
}

function convertToLinkedSmartObject() {
    var doc = app.activeDocument;
    var docName = doc.name.replace(/\.[^\.]+$/, '');
    var assetsFolder = new Folder(doc.path + "/" + sanitiseName(docName) + "_Assets");
    if (!assetsFolder.exists) {
        assetsFolder.create();
    }

    var baseName = sanitiseName(doc.activeLayer.name);
    var fileName = baseName + ".psb";
    var file = new File(assetsFolder.fsName + "/" + fileName);

    var counter = 1;
    while (file.exists) {
        var suffix = "_" + ("000" + counter).slice(-3);
        fileName = baseName + suffix + ".psb";
        file = new File(assetsFolder.fsName + "/" + fileName);
        counter++;
    }

    var idplacedLayerConvertToLinked = stringIDToTypeID("placedLayerConvertToLinked");
    var desc346 = new ActionDescriptor();
    var idnull = stringIDToTypeID("null");
    var ref49 = new ActionReference();
    var idlayer = stringIDToTypeID("layer");
    var idordinal = stringIDToTypeID("ordinal");
    var idtargetEnum = stringIDToTypeID("targetEnum");
    ref49.putEnumerated(idlayer, idordinal, idtargetEnum);
    desc346.putReference(idnull, ref49);
    var idusing = stringIDToTypeID("using");
    desc346.putPath(idusing, file);
    executeAction(idplacedLayerConvertToLinked, desc346, DialogModes.NO);
}

function artboardBounds(group, doc) {
    var boundsLayer = group.artLayers.add();
    boundsLayer.name = "artboardBounds";
    doc.activeLayer = boundsLayer;
    var fillColor = new SolidColor();
    fillColor.rgb.red = 127;
    fillColor.rgb.green = 127;
    fillColor.rgb.blue = 127;

    doc.selection.selectAll();
    doc.selection.fill(fillColor);
    doc.selection.deselect();

    boundsLayer.opacity = 0;
    boundsLayer.fillOpacity = 0;

    boundsLayer.move(group.layers[0], ElementPlacement.PLACEBEFORE);
}

 

Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines