Skip to main content
Known Participant
May 15, 2026
Answered

how to find start and end positions in path text using extendscript?

How to get start and end position value using extendscript in path text (any shapes)?

m1b
m1bCorrect answer
Community Expert
May 17, 2026

Hi ​@psar12345 I’ve had a good look into this and it wasn’t easy to understand (and AI didn’t know either, which means it probably isn’t documented). But after a lot of experimentation I now understand the T values properties of TextFrame and I’ve written a script that demonstrates how to get the two points where the start and end text handles intersect with the path.

Also look at the `polarity` of the `textPath` to determine if the text is inside (like your green above) or outside.

— Mark

/**
* @file Get Start And End of Path Text.js
*
* Demonstration of resolving the T values of a PATHTEXT type TextFrame to points.
* Note: The "start and end of path text" means the position [x,y] of the path-text specific handles on either side of the path text itself.
*
* @author m1b (bezier function by claude code)
* @version 2026-05-17
* @discussion https://community.adobe.com/questions-652/how-to-find-start-and-end-positions-in-path-text-using-extendscript-1561754?tid=1561754
*/
(function () {

var doc = app.activeDocument;
var item = doc.selection[0];

if (!item || !item.hasOwnProperty('textPath'))
return alert('Please select a text on a path object and try again.');

var pp = item.textPath.pathPoints;

// get the two points we want
var startPoint = getPointAtTValue(pp, item.startTValue, item.textPath.closed)
var endPoint = getPointAtTValue(pp, item.endTValue, item.textPath.closed)

// draw circles just to show the points
drawCircle(item.layer, startPoint, 2, { fillColor: (doc.swatches[7] || 0).color });
drawCircle(item.layer, endPoint, 2, { fillColor: (doc.swatches[4] || 0).color });

// I think you can use this to work out which side of a circle the text is on (POSITIVE means outside)
var textIsInsideCircle = (PolarityValues.NEGATIVE === item.textPath.polarity);

})();

/**
* Returns the document coordinates of a point at a given T value (arc length) along a path.
* Note: tValues can be arbitrarily large; the segment is determined by `floor(tValue) % segmentCount`.
* @author m1b
* @version 2026-05-17
* @param {PathPoints} pathPoints - Illustrator PathPoints collection.
* @param {Number} tValue - length from path start, in points.
* @param {Boolean} [closed] - whether the path is closed. Default: true.
* @returns {Array} [x, y] document coordinates.
*/
function getPointAtTValue(pathPoints, tValue, closed) {

closed = (closed !== false);

var count = pathPoints.length;
var segmentCount = closed ? count : count - 1;
var intPart = Math.floor(tValue);
var segIndex = closed ? intPart % segmentCount : Math.min(intPart, segmentCount - 1);
var localT = tValue - intPart;
var curr = pathPoints[segIndex];
var next = pathPoints[(segIndex + 1) % count];

return _evaluateCubicBezier(curr.anchor, curr.rightDirection, next.leftDirection, next.anchor, localT);

};

/**
* Evaluates a cubic Bézier segment at parameter t.
* @param {Array} p0 - [x, y] start anchor.
* @param {Array} p1 - [x, y] start right direction.
* @param {Array} p2 - [x, y] end left direction.
* @param {Array} p3 - [x, y] end anchor.
* @param {Number} t - parameter, 0–1.
* @returns {Array} [x, y] point on curve.
*/
function _evaluateCubicBezier(p0, p1, p2, p3, t) {

var mt = 1 - t;
var mt2 = mt * mt;
var t2 = t * t;
var a = mt2 * mt;
var b = 3 * mt2 * t;
var c = 3 * mt * t2;
var d = t2 * t;

return [
a * p0[0] + b * p1[0] + c * p2[0] + d * p3[0],
a * p0[1] + b * p1[1] + c * p2[1] + d * p3[1],
];

};

/**
* Draws and returns a circle.
* @author m1b
* @version 2025-07-09
* @param {Document|Layer|GroupItem} container - the container for the circle.
* @param {Array<Number>|PathPoint} c - center of circle [cx, cy].
* @param {Number} radius - radius of circle.
* @param {Object} [props] - object with properties to be applied to the circle.
* @returns {PathItem}
*/
function drawCircle(container, center, radius, props) {

if (!container.hasOwnProperty('pathItems'))
throw Error('drawCircle: bad `container` supplied.');

if (center.hasOwnProperty('anchor'))
center = center.anchor;

var circle = container.pathItems.ellipse(center[1] + radius, center[0] - radius, radius * 2, radius * 2);

if (props != undefined)
for (var key in props)
if (circle.hasOwnProperty(key))
circle[key] = props[key];

return circle;

};

 

6 replies

Hedda Gabler1
Participating Frequently
May 18, 2026

Illustrator scripting sadly doesn’t expose the actual start/end handles of Type on a Path directly.

Most people work around it by:

  • duplicating the text
  • creating outlines
  • reading the outline bounds to estimate start/end positions

So you’re probably not missing anything — it’s just a limitation of ExtendScript in Illustrator 😅

Translate
HeddaG
m1b
Community Expert
m1bCommunity ExpertCorrect answer
Community Expert
May 17, 2026

Hi ​@psar12345 I’ve had a good look into this and it wasn’t easy to understand (and AI didn’t know either, which means it probably isn’t documented). But after a lot of experimentation I now understand the T values properties of TextFrame and I’ve written a script that demonstrates how to get the two points where the start and end text handles intersect with the path.

Also look at the `polarity` of the `textPath` to determine if the text is inside (like your green above) or outside.

— Mark

/**
* @file Get Start And End of Path Text.js
*
* Demonstration of resolving the T values of a PATHTEXT type TextFrame to points.
* Note: The "start and end of path text" means the position [x,y] of the path-text specific handles on either side of the path text itself.
*
* @author m1b (bezier function by claude code)
* @version 2026-05-17
* @discussion https://community.adobe.com/questions-652/how-to-find-start-and-end-positions-in-path-text-using-extendscript-1561754?tid=1561754
*/
(function () {

var doc = app.activeDocument;
var item = doc.selection[0];

if (!item || !item.hasOwnProperty('textPath'))
return alert('Please select a text on a path object and try again.');

var pp = item.textPath.pathPoints;

// get the two points we want
var startPoint = getPointAtTValue(pp, item.startTValue, item.textPath.closed)
var endPoint = getPointAtTValue(pp, item.endTValue, item.textPath.closed)

// draw circles just to show the points
drawCircle(item.layer, startPoint, 2, { fillColor: (doc.swatches[7] || 0).color });
drawCircle(item.layer, endPoint, 2, { fillColor: (doc.swatches[4] || 0).color });

// I think you can use this to work out which side of a circle the text is on (POSITIVE means outside)
var textIsInsideCircle = (PolarityValues.NEGATIVE === item.textPath.polarity);

})();

/**
* Returns the document coordinates of a point at a given T value (arc length) along a path.
* Note: tValues can be arbitrarily large; the segment is determined by `floor(tValue) % segmentCount`.
* @author m1b
* @version 2026-05-17
* @param {PathPoints} pathPoints - Illustrator PathPoints collection.
* @param {Number} tValue - length from path start, in points.
* @param {Boolean} [closed] - whether the path is closed. Default: true.
* @returns {Array} [x, y] document coordinates.
*/
function getPointAtTValue(pathPoints, tValue, closed) {

closed = (closed !== false);

var count = pathPoints.length;
var segmentCount = closed ? count : count - 1;
var intPart = Math.floor(tValue);
var segIndex = closed ? intPart % segmentCount : Math.min(intPart, segmentCount - 1);
var localT = tValue - intPart;
var curr = pathPoints[segIndex];
var next = pathPoints[(segIndex + 1) % count];

return _evaluateCubicBezier(curr.anchor, curr.rightDirection, next.leftDirection, next.anchor, localT);

};

/**
* Evaluates a cubic Bézier segment at parameter t.
* @param {Array} p0 - [x, y] start anchor.
* @param {Array} p1 - [x, y] start right direction.
* @param {Array} p2 - [x, y] end left direction.
* @param {Array} p3 - [x, y] end anchor.
* @param {Number} t - parameter, 0–1.
* @returns {Array} [x, y] point on curve.
*/
function _evaluateCubicBezier(p0, p1, p2, p3, t) {

var mt = 1 - t;
var mt2 = mt * mt;
var t2 = t * t;
var a = mt2 * mt;
var b = 3 * mt2 * t;
var c = 3 * mt * t2;
var d = t2 * t;

return [
a * p0[0] + b * p1[0] + c * p2[0] + d * p3[0],
a * p0[1] + b * p1[1] + c * p2[1] + d * p3[1],
];

};

/**
* Draws and returns a circle.
* @author m1b
* @version 2025-07-09
* @param {Document|Layer|GroupItem} container - the container for the circle.
* @param {Array<Number>|PathPoint} c - center of circle [cx, cy].
* @param {Number} radius - radius of circle.
* @param {Object} [props] - object with properties to be applied to the circle.
* @returns {PathItem}
*/
function drawCircle(container, center, radius, props) {

if (!container.hasOwnProperty('pathItems'))
throw Error('drawCircle: bad `container` supplied.');

if (center.hasOwnProperty('anchor'))
center = center.anchor;

var circle = container.pathItems.ellipse(center[1] + radius, center[0] - radius, radius * 2, radius * 2);

if (props != undefined)
for (var key in props)
if (circle.hasOwnProperty(key))
circle[key] = props[key];

return circle;

};

 

Translate
CarlosCanto
Community Expert
Community Expert
May 17, 2026

Love it, thanks for sharing.

Translate
m1b
Community Expert
Community Expert
May 16, 2026

Hi ​@psar12345 what do you mean, the start and end position? Can you show an X on the two points you would like to locate?

Translate
psar12345Author
Known Participant
May 16, 2026

I try to get starting and ending position text. also i try to get whether it is clockwise or antoclockwise direction.

Translate