I've been trying to write a script that lets a user indicate two layers/groups, and then output the difference in position between them (of their topleft most points) like so:

var calculated_offset = [group.bounds[0].value - originGroup.bounds[0].value, group.bounds[1].value - originGroup.bounds[1].value];

Now, getting the first layer is fairly trivial: app.activeDocument.activeLayer;

But I can't think of a good way to let the user switch their selection, and then start the comparison.

I've written script for a dialog that requests for an exact match name, and then a recursive function to find the correct (grouped) layer, but the find function takes a long time, and a non-fuzzy search is terribly user-unfriendly.

I've also tried creating a new window, and then taking in a first and then a second selection, but since these modal dialogs are blocking windows, that fell flat.

Answers could include ideas to:

  • Let users select a second layer after being prompted
  • Implement a fast (< 4s at ~100 nested layers) (fuzzy) search
  • Access the multiple layers that the user has selected
  • Make the window non-blocking
  • An alternative way to get the offset between two layers

1 Answer 1


I don't think it's possible to ask user for a layer with JSX (unless you want to create some bizarre interface with ScriptUI)

However, are you familiar with ActionManager code? What you want would be much easier to achieve using it. You can get selected layers data using a script from this answer.

If you wouldn't want groups you could've just use AM bounds property BUT I haven't found a way to get bounds of layers inside the group, not the group itself — so in this script I'll use AM to get IDs, select the layers, get their bounds with DOM and then show the offset:

function main()
  var ids = getLayersIDs(); // getting ids of selected layers
  var bounds = [];

  if (ids.length != 2)
    alert('expected 2 selected layers, aborting');
    return false;

  //for each id
  for (var i = 0; i < ids.length; i++)
    // select the layer first
    // get layer bounds DOM property

  // caclulating offset
  // bounds[0] are bounds of the first layer, bounds[1] — second
  var offsetX = Math.abs(bounds[0][0] - bounds[1][0]);
  var offsetY = Math.abs(bounds[0][1] - bounds[1][1]);

  alert('offset X:' + offsetX + '\noffset Y: ' + offsetY );

  // this will get IDs of selected layers/groups
  function getLayersIDs()
    var lyrs = [];
    var lyr;
    var ref = new ActionReference();
    var desc;
    var tempIndex;
    var ref2;

    ref.putProperty(stringIDToTypeID("property"), stringIDToTypeID("targetLayers"));
    ref.putEnumerated(charIDToTypeID('Dcmn'), charIDToTypeID('Ordn'), charIDToTypeID('Trgt'));

    var targetLayers = executeActionGet(ref).getList(stringIDToTypeID("targetLayers"));
    for (var i = 0; i < targetLayers.count; i++)
      tempIndex = 0;
      ref2 = new ActionReference();
        ref2.putIndex(charIDToTypeID('Lyr '), targetLayers.getReference(i).getIndex());
          desc = executeActionGet(ref2);
          tempIndex = desc.getInteger(stringIDToTypeID("itemIndex")) - 1;
        catch (e)
          tempIndex = 0;
      catch (o)
        ref2.putIndex(charIDToTypeID('Lyr '), targetLayers.getReference(i).getIndex() + 1);
        desc = executeActionGet(ref2);
        tempIndex = desc.getInteger(stringIDToTypeID("itemIndex"));


    return lyrs;

  // this will select a layer by ID
  function selectById(id)
    var desc1 = new ActionDescriptor();
    var ref1 = new ActionReference();
    ref1.putIdentifier(charIDToTypeID('Lyr '), id);
    desc1.putReference(charIDToTypeID('null'), ref1);
    executeAction(charIDToTypeID('slct'), desc1, DialogModes.NO);
app.activeDocument.suspendHistory("temp", "main()");
  • Thanks! That worked like a charm. I've used AM a couple of times, but I try to avoid it whenever possible since the code it produces is so unreadable. It did exactly what I needed from it, though!
    – user162335
    Apr 10, 2021 at 23:00

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.