Create a new path in UXP

I cannot for the life of me figure this one out. This is my 2nd or 3rd attempt and I am about to give up again.

I would like to be able to have some coordinates and create a shape layer from them. I am trying to recreate some custom shapes.

I tried the example code here with no luck:
https://developer.adobe.com/photoshop/uxp/2022/ps_reference/classes/pathpointinfo/
Perhaps it is because I am not using typescript, but I tried (and chatgpt tried) to convert it and still had no luck.

I tried to do it via batchplay and get an error that Make is not available. I tried both in and out of modal with no luck.

Here is one of the attempts I did with chatgpt:

const batchPlay = require('photoshop').action.batchPlay;

async function createPath(start, stop) {
    try {
        const app = require('photoshop').app;
        const activeDocument = app.activeDocument;

        if (!activeDocument) {
            throw new Error("No active document found.");
        }

        console.log("Active document ID: ", activeDocument.id);

        const activeLayers = activeDocument.activeLayers;

        if (!activeLayers || !activeLayers.length) {
            throw new Error("No active layer found.");
        }

        const activeLayerID = activeLayers[0].id;

        console.log("Active layer ID: ", activeLayerID);

        // Ensure no open modal states
        await batchPlay([{
            _obj: 'close',
            _target: [{ _ref: 'dialog', _enum: 'ordinal', _value: 'all' }]
        }], { synchronousExecution: true });

        // Switch to Standard mode (to avoid any modal states)
        await batchPlay([{
            _obj: 'modalState',
            _value: 0
        }], { synchronousExecution: true });

        const startPoint = {
            _obj: 'pathPoint',
            anchor: start,
            leftDirection: start,
            rightDirection: start,
            kind: { _enum: 'pointKind', _value: 'cornerPoint' }
        };

        const stopPoint = {
            _obj: 'pathPoint',
            anchor: stop,
            leftDirection: stop,
            rightDirection: stop,
            kind: { _enum: 'pointKind', _value: 'cornerPoint' }
        };

        const subPath = {
            _obj: 'subPath',
            operation: { _enum: 'shapeOperation', _value: 'add' },
            closedSubpath: false,
            points: [startPoint, stopPoint]
        };

        const pathDescriptor = {
            _obj: 'make',
            new: { _class: 'path' },
            from: {
                _obj: 'path',
                name: 'Line',
                subpaths: [subPath],
                kind: { _enum: 'pathKind', _value: 'workPath' }
            }
        };

        console.log("Creating path...");

        const result = await batchPlay([pathDescriptor], {
            synchronousExecution: true,
            modalBehavior: 'execute'
        });

        const setDescriptor = {
            _obj: 'set',
            _target: [{ _ref: 'path', _enum: 'ordinal', _value: 'targetEnum' }],
            to: { _name: 'Line' }
        };

        const namingResult = await batchPlay([setDescriptor], {
            synchronousExecution: true,
            modalBehavior: 'execute'
        });

        console.log("Path creation result: ", result);
        console.log("Path naming result: ", namingResult);
        console.log("Path created successfully.");

    } catch (error) {
        console.error("Error creating path:", error.message);
    }
}

// Execute the function
(async () => {
    try {
        await createPath([100, 100], [200, 200]);
    } catch (error) {
        console.error("Error in execution: ", error);
    }
})();

Any help would be appreciated.

Things are so complicated.

Firstly, did you wrap your code in executeAsModal?
without it, any application API doesn’t work at all on Photoshop.

https://developer.adobe.com/photoshop/uxp/2022/ps_reference/#detour—executeasmodal

Secondly, the example of code on this page doesn’t work but not because of without TypeScript.
I suppose the code on document may miss lead developers.
For example, PathPointInfo Constructor comes from app class. But it doesn’t write any requirement. so you have to add this.

const { app } = require("photoshop");
const startPoint = new app.PathPointInfo();

PathPointinfo constructor isn’t global object, That why it won’t work just calling like “new PathPointInfo();”

and some parts of classes and objects were also missed.

const { constants } = require("photoshop");
startPoint.kind = constants.PointKind.CORNERPOINT;

And overall. I confirmed the function works below on Photoshop 2024 Mac OS.

const { core, app, constants } = require("photoshop");
function drawLine(doc, start, stop) {
         const startPoint = new app.PathPointInfo();
         startPoint.anchor = start;
         startPoint.leftDirection = start;
         startPoint.rightDirection = start;
         startPoint.kind = constants.PointKind.CORNERPOINT;

         const stopPoint = new app.PathPointInfo();
         stopPoint.anchor = stop;
         stopPoint.leftDirection = stop;
         stopPoint.rightDirection = stop;
         stopPoint.kind = constants.PointKind.CORNERPOINT;

         const spi = new app.SubPathInfo();
         spi.closed = false;
         spi.operation = constants.ShapeOperation.SHAPEXOR;
         spi.entireSubPath = [startPoint, stopPoint];

         const line = doc.pathItems.add("Line", [spi]);
         const currentPathItem = app.activeDocument.pathItems.getByName("Line");
         await currentPathItem.strokePath(constants.ToolType.PENCIL);
     }

and still only there are few examples of UXP code on Internet.
Chatgpt hasn’t learnt well I think. Therefore it couldn’t generate code well I believe.

1 Like

I finally got it thanks to your help. Thank you!
I also had little things that seemed to mess it up and took forever to find, for instance I had the constants defined like this:

const { constants } = require("photoshop").constants;

removing the .constants got me going. :man_shrugging:

You can use plain JS objects intead of class instances. This will work as well if you keep property names without typo. The DOM team was shifting away from classes to plain JS objects. I think this would be changed too.

const startPoint = {
         anchor: start,
         leftDirection: start,
         rightDirection: start,
         kind: constants.PointKind.CORNERPOINT,
};
2 Likes