Instant Celtic Art

Scripting InDesign to create patterns

Adobe InDesign is a magical tool for creating art, and one interesting approach is using the wonderful exposure to automation that InDesign provides. Rather than droning on incessantly about why and how this is so great, let me offer you a simple example of how beautiful art can be created easily with some simple scripting and minor manual adjustment to the results of the scripts.

The scripts for this and other cool art are available here. By simply copying the .jsx files to the appropriate folder as described here, you are ready get started auto-generating art.

To get an idea of the sort of design aesthetic our code is going to mimic, you can google Celtic knot patterns. We are using the “NINA” script written by Olav Martin Kvern, built on an algorithm by Matt Freedman — for more about NINAs, see

Assuming you’ve put the scripts in the right place, from within InDesign you can Choose Window>Utilities>Scripts and you should be able to find them in the scripts panel. Double-clicking on the NINA script should invoke the following dialog:

Dialog for entering parameters to the NINA script

Set the following parameters:

  • Number of iterations: 800
  • a_pulse: 7
  • b_pulse: 10

Don’t change anything else for now: just click “OK”.

Without moving the path you’ve created, create another one with the following parameters:

  • Number of iterations: 800
  • a_pulse: 8
  • b_pulse: 11

At this point, you should have two paths on top of each other looking something like this:

Results of running the script twice

Select the two paths and create a compound path by choosing Object>Paths>Make Compound Path. Apply a fill (in this example, black) and a stroke (in this example, 3 point Cyan). Voila! Instant “celtic knotwork” design.

function myDrawNina(myNumberOfLines, a_pulse, b_pulse, myLength, myClosedPath){

var cur_x, cur_y;

var myAnchor = new Array(2);

var myArray = new Array;

//Rather than draw the entire path point-by-point, we’ll fill an array and then

//use it to fill in all of the point locations at once using the entirePath property.

//Fill in the Array “myArray” with a list of coordinates.

for (var myCounter = 0; myCounter < myNumberOfLines; myCounter++){

cur_x = (Math.cos((-2 * Math.PI * a_pulse * myCounter) / myNumberOfLines) + Math.cos((-2 * Math.PI * b_pulse * myCounter) / myNumberOfLines)) * myLength;

cur_y = (Math.sin((-2 * Math.PI * a_pulse * myCounter) / myNumberOfLines) + Math.sin((-2 * Math.PI * b_pulse * myCounter) / myNumberOfLines)) * myLength;

myAnchor = [cur_x, cur_y];



app.activeDocument.viewPreferences.horizontalMeasurementUnits = MeasurementUnits.points;

app.activeDocument.viewPreferences.verticalMeasurementUnits = MeasurementUnits.points;

var myPage = app.activeWindow.activePage;

var myGraphicLine = myPage.graphicLines.add();

myGraphicLine.move(undefined, [“1p”,”1p”]);

var myPath = myGraphicLine.paths.item(0);

//Now set the entire path to the contents of the array.

myPath.entirePath = myArray;

if(myClosedPath == true){

myPath.pathType = PathType.closedPath;



myPath.pathTYpe = PathType.openPath;


//Label the graphic line with the parameters used to create it.

myGraphicLine.label = “number_of_lines = “ + myNumberOfLines + “, a_pulse = “ + a_pulse + “, b_pulse = “ + b_pulse;


Experiment! Try different parameters, rotate the same path and overlay it on itself before making the compound path, try the other scripts… who says an algorithm doesn’t have a soul?