Copy link to clipboard
Copied
I am pretty new to using scripts in Illustrator. I have a script that I would like to run in Illustrator. However, when I go to File > Scripts > Other Script and attempt to select my plain text file named SimplifyMeshToLines_Separated.jsx, the file is greyed out. If I save this file to the folder containing the Illustrator Scripts, it fails to show up in the list of Scripts. What am I doing wrong here? Thanks.
Hi @chadulus2, I've written a script that works with the idea I mentioned earlier—saving as an Illustrator version 8 file. It works because it reads the plain text coordinates directly from the saved file and then draws them into the document. Each patch of the mesh is a path item.
Give it a try and let me know if it helps in your case.
- Mark
/**
* @file Draw Geometry Of MeshItems.js
*
* Will add a path item for each patch
* of each mesh item in the document.
*
* Note: document must be...
Copy link to clipboard
Copied
Can you possibly share the jsx file?
Copy link to clipboard
Copied
Copy link to clipboard
Copied
I have tried a few things and seems to have gotten the script to actually work....well, whether it does what I want is another question, but at least I can get Illustrator to run the script.
Copy link to clipboard
Copied
Hi @chadulus2 did you get the script to give you the meshes geometry as normal path items? I tried it and it didn't work. In fact I don't think it *can* work because it uses "Expand" menu on the mesh which isn't available from the UI (or anywhere!). So, sadly, this script seems to be AI confabulation. By the way, we don't have access to the mesh's paths via scripting either so no help there. Maybe there is a way to export in some format—I notice we can get the coordinates from an .ai version 8 file, so it would be possible to script this with a bit of work.
- Mark
Copy link to clipboard
Copied
Hi Mark, thanks for giving that a try. No, I could not get it to work either. I also tried this one (see attached), but I am not sure this works either (it is actually still running on my machine after quite a bit of time). Are you aware of any method to "convert" a mesh into a simplified line drawing?
Copy link to clipboard
Copied
Hi @chadulus2, I've written a script that works with the idea I mentioned earlier—saving as an Illustrator version 8 file. It works because it reads the plain text coordinates directly from the saved file and then draws them into the document. Each patch of the mesh is a path item.
Give it a try and let me know if it helps in your case.
- Mark
/**
* @file Draw Geometry Of MeshItems.js
*
* Will add a path item for each patch
* of each mesh item in the document.
*
* Note: document must be saved before
* running script.
*
* @author m1b
* @version 2025-10-18
* @discussion https://community.adobe.com/t5/illustrator-discussions/greyed-out-script/m-p/15545562
*/
(function () {
var settings = {
drawAsPatches: false,
layerName: 'meshes',
showUI: true,
};
if (0 === app.documents.length)
return alert('Please open a document and try again.');
var doc = app.activeDocument;
if (!doc.saved)
return alert('Please save document and try again.');
if (settings.showUI) {
var result = ui(settings);
if (2 === result)
// user cancelled
return;
}
// how to draw the mesh geometry
settings.drawMesh = settings.drawAsPatches ? drawMeshAsPatches : drawMeshAsGridLines;
// save temp document as AI version 8 (plain text)
var original = doc.fullName;
var so = new IllustratorSaveOptions();
so.compatibility = Compatibility.ILLUSTRATOR8;
so.compressed = true;
var tempFile = File(Folder.temp + '/tmp.ai');
doc.saveAs(tempFile, so);
doc.close();
// restore original document
app.open(original);
doc = app.activeDocument;
// read the mesh coords
var meshes = readMeshData(tempFile);
// draw the meshes as path items
var pathItems = [];
// get a safe layer to draw to
var layer = getThing(doc, 'name', settings.layerName) || doc.layers.add();
layer.name = settings.layerName;
layer.visible = true;
layer.locked = false;
// draw the meshes
for (var i = 0; i < meshes.length; i++) {
var group = layer.groupItems.add();
group.name = 'mesh ' + (i + 1);
pathItems = pathItems.concat(settings.drawMesh(group, meshes[i]));
}
if (0 === pathItems.length)
alert('No mesh items found in document.');
})();
/**
* Extract MeshItem coordinates from an Illustrator v8 file.
* Will return an array containing mesh data for each mesh found.
* @author m1b
* @version 2025-10-18
* @param {File} file - the file to read.
* @returns {Array<Array<patch>>} - the mesh data objects.
*/
function readMeshData(file) {
const MATCH_PATCH_START = /%_\[([^\]]+)\] \/P X#/;
const MATCH_PATCH_END = /%_\/E X#/;
const MATCH_PATCH_COORDS = /%_\[([^\]]+)\] \/N X#/;
if (!file.exists)
return;
file.open('r');
var meshes = [];
var mesh;
var patch;
var line;
var match;
var coords;
while (!file.eof) {
line = file.readln();
match = line.match(MATCH_PATCH_START);
if (
null !== match
&& 2 === match.length
) {
// start new patch
patch = { name: match[1], rowIndex: -1, columnIndex: -1, points: [] };
var parts = patch.name.split(' ');
if (2 !== parts.length)
continue;
patch.rowIndex = Number(parts[0]);
patch.columnIndex = Number(parts[1]);
if (
isNaN(patch.rowIndex)
|| isNaN(patch.columnIndex)
)
continue;
if (
0 === patch.rowIndex
&& 0 === patch.columnIndex
) {
// start new mesh
mesh = [];
meshes.push(mesh);
}
mesh.push(patch);
continue;
}
if (!patch)
// nothing
continue;
var match = line.match(MATCH_PATCH_COORDS);
if (
null === match
|| 2 > match.length
) {
if (MATCH_PATCH_END.test(line))
// end of patch
patch = undefined;
// part of a patch, but not geometry;
continue;
}
var coords = match[1].split(' ');
// start new point
var numbers = [];
for (var i = 0; i < coords.length; i++) {
numbers.push(Number(coords[i]));
}
var len = numbers.length;
patch.points.push({
anchor: [numbers[len - 8], numbers[len - 7]],
leftDirection: [numbers[len - 3], numbers[len - 2]],
rightDirection: [numbers[len - 6], numbers[len - 5]],
});
}
return meshes;
};
/**
* Draws mesh patches.
* @author m1b
* @version 2025-10-18
* @param {Document|Layer|GroupItem} container - the location of the new path items.
* @param {Object} patches - patch objects { name:"", points:[] }.
* @returns {Array<PathItem>}
*/
function drawMeshAsPatches(container, patches) {
if (!container.hasOwnProperty('pathItems'))
throw new Error('drawMesh: bad `container` supplied.');
var pathItems = [];
for (var i = 0; i < patches.length; i++) {
var patch = patches[i];
var pathItem = drawPath(container, patch.points, patch.name);
pathItem.closed = true;
pathItems.push(pathItem);
}
return pathItems;
};
/**
* Draw mesh grid lines (rows and columns).
* @author m1b
* @version 2025-10-18
* @param {Document|Layer|GroupItem} [container] - the container to draw in.
* @param {Array<Object>} patches - array of patches {name: points:}.
* @returns {Array<PathItem>}
*/
function drawMeshAsGridLines(container, patches) {
var map = [];
var maxRow = 0;
var maxCol = 0;
// parse patch names
for (var i = 0; i < patches.length; i++) {
var p = patches[i];
if (!map[p.rowIndex])
map[p.rowIndex] = [];
map[p.rowIndex][p.columnIndex] = p;
if (p.rowIndex > maxRow)
maxRow = p.rowIndex;
if (p.columnIndex > maxCol)
maxCol = p.columnIndex;
}
var rowCount = maxRow + 1;
var columnCount = maxCol + 1;
// draw the lines
var pathItems = [];
var linePts = [];
/* ------------------ *
* HORIZONTAL LINES *
* ------------------ */
for (var r = 0; r < rowCount; r++) {
for (var c = 0; c < columnCount; c++) {
var patch = map[r][c];
if (!linePts[c]) {
linePts[c] = [];
}
if (!linePts[c + 1]) {
linePts[c + 1] = [];
}
if (0 === c) {
// right side of patch
if (0 === r)
linePts[c][r] = {
anchor: patch.points[0].anchor,
leftDirection: patch.points[0].leftDirection,
rightDirection: patch.points[0].rightDirection,
pointType: PointType.CORNER,
};
else
// fix join
linePts[c][r].rightDirection = patch.points[0].rightDirection;
linePts[c][r + 1] = {
anchor: patch.points[1].anchor,
leftDirection: patch.points[1].leftDirection,
rightDirection: patch.points[1].rightDirection,
pointType: PointType.CORNER,
};
}
// left side of patch
if (0 === r)
linePts[c + 1][r] = {
anchor: patch.points[3].anchor,
leftDirection: patch.points[3].rightDirection,
rightDirection: patch.points[3].leftDirection,
pointType: PointType.CORNER,
};
else
// fix join
linePts[c + 1][r].rightDirection = patch.points[3].leftDirection;
linePts[c + 1][r + 1] = {
anchor: patch.points[2].anchor,
leftDirection: patch.points[2].rightDirection,
rightDirection: patch.points[2].leftDirection,
pointType: PointType.CORNER,
};
}
}
// draw horizontal lines
for (var i = 0; i < linePts.length; i++)
pathItems.push(drawPath(container, linePts[i], 'row ' + (i + 1)));
/* ----------------- *
* VERTICAL LINES *
* ----------------- */
var linePts = [];
for (var c = 0; c < columnCount; c++) {
for (var r = 0; r < rowCount; r++) {
var patch = map[r][c];
if (!linePts[r]) {
linePts[r] = [];
}
if (!linePts[r + 1]) {
linePts[r + 1] = [];
}
if (0 === r) {
// bottom edge of patch
if (0 === c)
linePts[r][c] = {
anchor: patch.points[0].anchor,
leftDirection: patch.points[0].rightDirection,
rightDirection: patch.points[0].leftDirection,
pointType: PointType.CORNER,
};
else
// fix join
linePts[r][c].rightDirection = patch.points[0].leftDirection;
linePts[r][c + 1] = {
anchor: patch.points[3].anchor,
leftDirection: patch.points[3].rightDirection,
rightDirection: patch.points[3].leftDirection,
pointType: PointType.CORNER,
};
}
// top edge of patch
if (0 === c)
linePts[r + 1][c] = {
anchor: patch.points[1].anchor,
leftDirection: patch.points[1].leftDirection,
rightDirection: patch.points[1].rightDirection,
pointType: PointType.CORNER,
};
else
// fix join
linePts[r + 1][c].rightDirection = patch.points[1].rightDirection;
linePts[r + 1][c + 1] = {
anchor: patch.points[2].anchor,
leftDirection: patch.points[2].leftDirection,
rightDirection: patch.points[2].rightDirection,
pointType: PointType.CORNER,
};
}
}
// draw vertical lines
for (var i = 0; i < linePts.length; i++)
pathItems.push(drawPath(container, linePts[i], 'column ' + (i + 1)));
return pathItems;
};
/**
* Draws a path of `points`;
* @author m1b
* @version 2025-10-18
* @param {Document|Layer|GroupItem} [container] - the container to draw in.
* @param {Array<PathPoints>} points - an array of points {anchor: leftDirection: rightDirection: pointType?:}.
* @param {String} [name] - the path item name (default: none).
* @returns {PathItem}
*/
function drawPath(container, points, name) {
var path = newEmptyPathItem(container, name);
for (var i = 0; i < points.length; i++) {
var p = path.pathPoints.add();
p.anchor = points[i].anchor;
p.leftDirection = points[i].leftDirection;
p.rightDirection = points[i].rightDirection;
p.pointType = points.pointType || PointType.CORNER;
}
return path;
};
/**
* Returns a new empty path item.
* @author m1b
* @version 2025-10-16
* @param {Document|Layer|GroupItem} container - the location of the new path items.
* @param {String} [name] - the name of the item (default: none).
* @returns {PathItem}
*/
function newEmptyPathItem(container, name) {
var item = container.pathItems.add();
item.name = name || '';
item.filled = false;
item.stroked = true;
return item;
};
/**
* Returns a thing with matching property.
* If `key` is undefined, evaluate the object itself.
* @author m1b
* @version 2024-04-21
* @param {Array|Collection} things - the things to look through.
* @param {String} [key] - the property name (default: undefined).
* @param {*} value - the value to match.
*/
function getThing(things, key, value) {
for (var i = 0, obj; i < things.length; i++)
if ((undefined == key ? things[i] : things[i][key]) == value)
return things[i];
};
/**
* User interface for this script. Will update the `settings` object.
* @author m1b
* @version 2025-10-18
* @param {Object} settings - the script settings.
* @returns {1|2}
*/
function ui(settings) {
var w = new Window("dialog { text:'Draw MeshItem Geometry' }");
var group = w.add('group {orientation:"column", alignment:["fill","fill"], alignChildren:["left","fill"], margins:[10,10,10,10] }');
var radioButtons = group.add('group {orientation:"row", margins:[10,10,10,10] }'),
asPatchesRadio = radioButtons.add('radiobutton {text:"Draw mesh as patches"}'),
asLinesRadio = radioButtons.add('radiobutton {text:"Draw mesh as lines"}');
var bottomUI = w.add('group {orientation:"row", alignment:["fill","top"], margins: [0,20,0,0] }'),
buttons = bottomUI.add('group {orientation:"row", alignment:["right","top"], alignChildren:"right" }'),
cancelButton = buttons.add('button', undefined, 'Cancel', { name: 'cancel' }),
drawButton = buttons.add('button', undefined, 'Draw', { name: 'ok' });
(settings.drawAsPatches ? asPatchesRadio : asLinesRadio).value = true;
drawButton.onClick = function () {
settings.drawAsPatches = asPatchesRadio.value;
w.close(1);
};
w.center();
return w.show();
};
Edit 2025-10-18: added capability to draw geometry as grid lines, as well as patches.
Copy link to clipboard
Copied
fantastic Mark!
Copy link to clipboard
Copied
Thanks! I did a bit of Carlos-style thinking outside the box! Well, except you would have done it somehow in just two lines! 😝
Copy link to clipboard
Copied
Copy link to clipboard
Copied
@chadulus2 FYI I updated the code so it can draw as grid lines as well as patches.
Find more inspiration, events, and resources on the new Adobe Community
Explore Now