Copy link to clipboard
Copied
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
Try this v1.0 code. Revisions can be made if needed.
EDIT: 22nd September, code updated to v1.2!
/*
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
...
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
...
Copy link to clipboard
Copied
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);
}
Find more inspiration, events, and resources on the new Adobe Community
Explore Now