[UXP/batchPlay] How to reproduce a Live Shape (arrow, keyOriginType:9) on a new layer?
Hi everyone,
I’m developing a UXP plugin that saves layer groups as templates and reapplies them to other documents. I’ve hit a wall trying to programmatically reproduce arrow shapes (and other non-rectangle/ellipse Live Shapes).
What I have
I can successfully read the arrow layer’s data via batchPlay GET:
keyOriginType: 9(arrow)vectorMask.pathComponentswith valid bézier data (percentUnit coordinates)- All subpath points, anchors, and control handles
The problem
I cannot recreate the arrow shape on a new layer. I’ve tried 14 different approaches over several weeks. Here’s a summary:
Approach A – make contentLayer with path data
// Tried with pathComponents, pathContents (_obj:"pathContents"),
// and pathContents (_obj:"pathClass")
await batchPlay([{
_obj: "make",
_target: [{ _ref: "contentLayer" }],
using: {
_obj: "contentLayer",
type: { _obj: "solidColorLayer", color: { ... } },
shape: { _obj: "path", pathComponents: [ /* arrow data */ ] }
}
}], {});
Result: No layer created (silent failure, no error thrown).
Approach B – Create shape layer → SET vectorMask
// 1. Create a rectangle shape layer
// 2. Set vectorMask with arrow path data
// 3. Clear keyOriginType with keyOriginType: []
await batchPlay([{
_obj: "set",
_target: [{ _ref: "path", _property: "vectorMask" }],
to: { _obj: "pathClass", pathComponents: [ /* arrow data */ ] }
}], {});
Result: Layer stays as rectangle. Even though a subsequent GET confirms the arrow path data is stored in vectorMask, PS continues to render the rectangle from keyOriginType:1. Clearing keyOriginType: [] has no visual effect.
Approach C – Fill layer → vectorMask
// Tried: addMask vectorMaskRevealAll → set vectorMask,
// set layer vectorMask directly,
// workPath → select → addMask vectorMaskFromCurrentPath
Result: Always renders as full-canvas fill. The vectorMask SET completes without error but never visually applies.
What works (but has limitations)
duplicate is the only method that successfully preserves the arrow shape:
await batchPlay([{
_obj: "duplicate",
_target: [{ _ref: "layer", _enum: "ordinal", _value: "targetEnum" }],
version: 5,
to: { _ref: "document", _id: destDocId }
}], {});
This works, but requires keeping the original layer alive somewhere as a “master copy,” which adds complexity to the template system.
My questions
-
Is there a correct batchPlay descriptor to create an arrow (or other non-rect/ellipse Live Shape) from scratch? If anyone has captured the descriptor via Alchemist or Actions panel → “Copy as JavaScript” when manually drawing an arrow, I’d love to see the structure.
-
Is
keyOriginTypefundamentally read-only for creation purposes? My testing suggests PS only establishes it during the internal shape-creation flow and ignores external SET attempts. -
Is
duplicatetruly the only reliable path? If so, any tips on controlling placement (parent group, position) after cross-document duplicate?
Any insights from the UXP/batchPlay community would be hugely appreciated. Thanks!
Environment: Photoshop 2025, UXP 8.x, macOS