Skip to main content
Known Participant
January 14, 2026
Question

Distribute layers with fixed inserted space

  • January 14, 2026
  • 3 replies
  • 129 views

Hello everyone,
I'm trying to create a JavaScript script for Photoshop with the following goal:
To distribute several selected layers horizontally or vertically using a fixed pixel spacing, for example:
If I give a horizontal spacing of 15 pixels, then I want the following:
(width of Layer 1) + 15px + (width of Layer 2) + 15px + (width of Layer 3)
Something equivalent to the "Distribute Horizontally" function of the Move tool, but allowing me to enter the exact pixel value in an EditText field for horizontal and another for vertical, with Layer 1 as the reference point, all through a ScriptUI.

Move.png

 

3 replies

Stephen Marsh
Community Expert
Community Expert
January 16, 2026

Take a look at the following script from Paul Riggott:

 

https://raw.githubusercontent.com/Paul-Riggott/PS-Scripts/refs/heads/master/Distribute%20Layers.jsx

 

//Row, Column or Grid can be selected and distributed.
#target photoshop
if(documents.length) app.activeDocument.suspendHistory('Distribute Layers', 'main()'); 
function main(){
var selectedLayers = getSelectedLayersIdx();
if(selectedLayers.length <3){
    alert("Not enough layers selected!");
    return;
    }
var boundsList=[];
var tempbnds=[];
showFX(false);
for(var a=0;a<selectedLayers.length;a++){
	var LB =getLayerBoundsByIndex(selectedLayers[a] );
	boundsList.push([[selectedLayers[a]],[LB[0]],[LB[1]],[LB[2]],[LB[3]]]);
	tempbnds=[];
	}
showFX(true);
boundsList.sort(function(a,b){return a[2]-b[2];}); 
var row1=[]; var row2=[]; var row3=[]; var row4=[]; var row5=[];
var row6=[]; var row7=[]; var row8=[]; var row9=[]; var row10=[];
var row11=[]; var row12=[]; var row13=[]; var row14=[]; var row15=[];
var row16=[]; var row17=[]; var row18=[]; var row19=[]; var row20=[];
var arrayNumber =1;
var TOP =Number(boundsList[0][2]);
for(var f =0;f<boundsList.length;f++){
	if(TOP > (boundsList[f][2]-50) && boundsList[f][2] < (boundsList[f][2]+50)){
		eval("row" +arrayNumber).push(boundsList[f]);
		}else{
            TOP =Number(boundsList[f][2]);
			arrayNumber++;
			eval("row" +arrayNumber).push(boundsList[f]);
		}
}
for(var d=0;d<arrayNumber;d++){
	eval("row" +(d+1)).sort(function(a,b){return a[1]-b[1];}); 
	}
if((row1.length*arrayNumber) != boundsList.length){
	alert("Unable to distribute this selection of layers!");
	return;
	}
for(var l=0;l<arrayNumber;l++){
var leftAnchor =Number(eval("row"+(l+1))[0][3]);
var spacingA =(Number(eval("row"+(l+1))[eval("row"+(l+1)).length-1][1])) - (Number(eval("row"+(l+1))[0][3]));
for(var a = 1;a<eval("row"+(l+1)).length-1;a++){
    var layerWidth = Number(eval("row"+(l+1))[a][3]) - Number(eval("row"+(l+1))[a][1]);
    spacingA = spacingA - layerWidth;
}
spacingA = spacingA/((eval("row"+(l+1)).length)-1);

for(var a = 1;a<eval("row"+(l+1)).length;a++){
makeActiveByIndex(Number(eval("row"+(l+1))[a][0]),false);
var Width = Number(eval("row"+(l+1))[a][3]) - Number(eval("row"+(l+1))[a][1]);
var shiftPixels = (leftAnchor+spacingA) - Number(eval("row"+(l+1))[a][1]);
activeDocument.activeLayer.translate(UnitValue(shiftPixels,'px') ,0);
leftAnchor +=(Width+spacingA);
	}
}
for(var v=0;v<row1.length;v++){
var topAnchor = Number(eval("row1")[v][4]);
var TopToBottom =(Number(eval("row"+(arrayNumber))[v][4])) - (Number(row1[v][2]));
var totalMasks =0;
for(var m = 0;m<arrayNumber;m++){
    var Height = Number(eval("row"+(m+1))[v][4]) - Number(eval("row"+(m+1))[v][2]);
    totalMasks +=Height;
    }
var SpacingB = (TopToBottom-totalMasks)/(arrayNumber-1);
for(var z = 1;z<arrayNumber-1;z++){
    makeActiveByIndex(Number(eval("row"+(z+1))[v][0]),false);
    var Height = (Number(eval("row"+(z+1))[v][4])) - (Number(eval("row"+(z+1))[v][2]));
    var shiftPixels =( topAnchor+SpacingB) - Number(eval("row"+(z+1))[v][2]);
    activeDocument.activeLayer.translate(0, UnitValue(shiftPixels,'px') );
    topAnchor += (Height+SpacingB);
    }
}
for(var a in selectedLayers){
    makeActiveByIndex(Number(selectedLayers[a]),false,true);
}
}
function selectLayerByIdx(idx, add) {
	var ref = new ActionReference();
	ref.putIndex(charIDToTypeID('Lyr '), idx);
	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 makeActiveByIndex( idx, visible,add ){ 
    if(add == undefined) add=false;
    var desc = new ActionDescriptor(); 
      var ref = new ActionReference(); 
      ref.putIndex(charIDToTypeID( "Lyr " ), idx) 
      desc.putReference( charIDToTypeID( "null" ), ref ); 
      if(add) desc.putEnumerated(stringIDToTypeID('selectionModifier'), stringIDToTypeID('selectionModifierType'), stringIDToTypeID('addToSelection'));
      desc.putBoolean( charIDToTypeID( "MkVs" ), visible ); 
   executeAction( charIDToTypeID( "slct" ), desc, DialogModes.NO ); 
};
function getSelectedLayersIdx(){ 
      var selectedLayers = new Array; 
      var ref = new ActionReference(); 
      ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
      var desc = executeActionGet(ref); 
      if( desc.hasKey( stringIDToTypeID( 'targetLayers' ) ) ){ 
         desc = desc.getList( stringIDToTypeID( 'targetLayers' )); 
          var c = desc.count 
          var selectedLayers = new Array(); 
          for(var i=0;i<c;i++){ 
            try{ 
               activeDocument.backgroundLayer; 
               selectedLayers.push(  desc.getReference( i ).getIndex() ); 
            }catch(e){ 
               selectedLayers.push(  desc.getReference( i ).getIndex()+1 ); 
            } 
          } 
       }else{ 
         var ref = new ActionReference(); 
         ref.putProperty( charIDToTypeID("Prpr") , charIDToTypeID( "ItmI" )); 
         ref.putEnumerated( charIDToTypeID("Lyr "), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") ); 
         try{ 
            activeDocument.backgroundLayer; 
            selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))-1); 
         }catch(e){ 
            selectedLayers.push( executeActionGet(ref).getInteger(charIDToTypeID( "ItmI" ))); 
         } 
      } 
      return selectedLayers; 
 };
function getLayerBoundsByIndex( idx ) { 
    var ref = new ActionReference(); 
    ref.putProperty( charIDToTypeID("Prpr") , stringIDToTypeID( "bounds" )); 
    ref.putIndex( charIDToTypeID( "Lyr " ), idx );
    var desc = executeActionGet(ref).getObjectValue(stringIDToTypeID( "bounds" ));
    var bounds = [];
    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('left')));
    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('top')));
    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('right')));
    bounds.push(desc.getUnitDoubleValue(stringIDToTypeID('bottom'))); 
    return bounds;
};
function showFX(FX) {
    var desc48 = new ActionDescriptor();
        var ref34 = new ActionReference();
        ref34.putProperty( charIDToTypeID('Prpr'), charIDToTypeID('lfxv') );
        ref34.putEnumerated( charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt') );
    desc48.putReference( charIDToTypeID('null'), ref34 );
        var desc49 = new ActionDescriptor();
        desc49.putBoolean( charIDToTypeID('lfxv'), FX );
    desc48.putObject( charIDToTypeID('T   '), charIDToTypeID('lfxv'), desc49 );
    try{
    executeAction( charIDToTypeID('setd'), desc48, DialogModes.NO );
    }catch(e){}
};

 

Or perhaps here:

 

https://community.adobe.com/t5/photoshop-ecosystem-discussions/photoshop-distribution-by-custom-width-parameters/m-p/15141411

 

Delta2487Author
Known Participant
January 17, 2026

@ExUSA  @jane-e   @Stephen Marsh  Thanks for the help. Chuck Uebele's script works as I want, but it has two issues. It adds one extra pixel to the horizontal setting; for example, if I enter 15, it gives me 16, which isn't a big problem. The other issue is that it automatically opens the script editor (ExtendScript Toolkit). I don't know if there's a solution.

Legend
January 15, 2026

I don't have time to write a script but you can use layer.bounds which returns a bounding rectangle and then calculate spacing by adding the desired padding. Run this snippet on a multilayer PSD file to see how that works.

 

try{
	var layerRef = null;
	var dims = '';
	for(var a = 0; a < app.activeDocument.layers.length; a++){
    		layerRef = app.activeDocument.layers[a];
    		dims = dims + '\r' + layerRef.bounds.toString();
    		}
	Window.alert(dims);
	}
catch(e){
	Window.alert (e + ' ' + e.line.toString());
	}

 

jane-e
Community Expert
Community Expert
January 15, 2026

@Delta2487 

 

I see that none of our scripters have chimed in yet, although they still might. Can you show us what your code looks like so far?

Illustrator has Distribute Spacing built into the panel — it requires setting a key object first. I'd love to see this in Photoshop, but PS does not have a key object.

 

What I do if I want 15 pixels is use a shape or rectangular marquee with a fixed width of 15 and move it between the objects. You can also insert guides  (View > Guides > New Guide) to assist with precise positioning.

 

I noticed that you checked all of the topics, but not all platforms have scripting capibilities. What device are you using? This might change our answer.

janee_0-1768485939209.png

Jane