Digital Illustration

Offset text shadows with Scriptographer

Scriptographer is a plugin that provides a handy way to access Adobe Illustrator’s built in javascriptability. I’ve been looking for a reason to use it for a while, and found it today while manually repeating the same task ad nauseam. This is by no means the coolest use of script in illustrator (check out the gallery of scripts for that – http://scriptographer.org/gallery/), but it’s a nice way to automate a repetitive task, whilst also providing some control parameters. It also seems like an easy intro to the plugin’s use, which I’ve documented here lest someone might find it useful.

The effect we’re creating is the offset type shadow, beloved of sign painters:

In Illustrator, we’ll turn a text object from this:

To this:

Here’s the finished script, (text_shadow.js, 4KB). Make sure you have Scriptographer installed, then drag this into your scripts directory (usually created in User/documents/Scriptographer Scripts). To make your own, open the Scriptographer panel in Illustrator, and click the New Script button to create a file, and to open it in a text editor.

The effect looks simple, but in Illustrator, here is the sequence of commands you need to carry out to make it:

  1. Copy the text object, and paste in front of the original twice, to end up with three, stacked copies of the text.
  2. Offset the top layer.
  3. Send this offset layer backwards so that it’s in the middle of the three layers.
  4. Select the top two versions of the text, and create outlines of them.
  5. Convert each newly vectorised text block into a compound path.
  6. Using the pathfinder tool, subtract the front object from the back object.
  7. Offset the text shadow object that is created.

In reality, this can be done pretty quickly, but to adjust the offset values of the shadow the object needs to be remade. You could make the end result more editable by using a clipping mask instead of the pathfinder. Still, it’s more complicated that you’ll want it to be if you’re doing this often, or if you quickly want to try out different shadow sizes and offset positions.

The Script

Having broken down the steps that we’d carry out using the Illustrator interface, we can go about recreating each with code. To recap, we need to:

  1. Get the selected object.
  2. Triplicate it.
  3. Covert two copies to outlines.
  4. Move one of them.
  5. Make the outline copies into compound paths.
  6. Cut one from the other.
  7. Offset the new shadow object that is created.

1.
Get the first object that’s been selected on the canvas.

var obj = document.selectedItems.first;

This line shows us a little of Illustrator’s object hierarchy. We’re looking in the current document, getting an array of items that are currently selected, and getting the first one.

2.
We could duplicate the object using the clone method:

var objCopy = obj.clone();

2 & 3
But we can skip cloning the object, and combine steps 2 & 3 by directly creating the outlines of the original text, and assigning them to new variables:

var objCopy1 = obj.createOutline();
var objCopy2 = obj.createOutline();

4.
Move the first of the copies (which is in the middle of the stack), by creating a new point and adding it to its position attribute:

objCopy1.position += new Point(5, 5);

5.
If we cut one object from the other now, we’ll end up with one arbitrary piece of a letter. To ensure the action treats each vectorised word as a single shape, we need to make them into compound paths. The function expects an array of objects that it’ll tie together, but for our purposes we need only pass it a the single outlined word copy:

var compoundFront = CompoundPath([objCopy1]);
var compoundBack = CompoundPath([objCopy2]);

6.
To make our final shadow shape, we declare a new variable, shadow, and use Pathfinder.backMinusFront(). The Scriptographer pathfinder reference lists all the available functions (http://scriptographer.org/reference/ai/pathfinder). There are lots of optional details that can be set, but here we’re just going to pass it an array of the two objects:

var shadow = Pathfinder.backMinusFront([compoundFront, compoundBack]);

7.
Finally, we just need to move the shadow object away from the original text object (which remains unchanged by this script):

shadow.position += new Point(5,5);

8.
We’ll likely also want to move the shadow object so it’s behind the original text.

shadow.moveBelow(obj);

Parameterisation

In this example, we’ve hard coded both how large the shadow object is (in step four), and how far we place it from the object (in step seven). One of Scriptographer’s strongest features is the ease with which interface windows can be made, letting us change parameters at run time.

The Scriptographer interface tutorials are a great place to start:
Creating palette windows
Interface components

By declaring an object for values and another for components, you can script a window which looks like this:

var values = {
    color: '#727272',
    xSize: '2',
    ySize: '2',
    xOffset: '2',
    yOffset: '2',
    knockOut: false
};

var components = {
	color: {
		type: 'color', label: 'Color'
	},
	ruler1: {
        type: 'ruler'
    },
	xSize: {
		type: 'number', label: 'x width', range: [-100, 100]
	},
	ySize: {
		type: 'number', label: 'y width', range: [-100, 100]
	},
	ruler2: {
        type: 'ruler'
    },
	xOffset: {
		type: 'number', label: 'x offset', range: [-100, 100]
	},
	yOffset: {
		type: 'number', label: 'y offset', range: [-100, 100]
	},
	ruler3: {
        type: 'ruler'
    },
    knockOut: {
    	type: 'boolean', label: 'Knockout Front'
    },
    ruler4: {
        type: 'ruler'
    },
	button: {
		type: 'button', label: 'Run Script',
		value:'make shadow',
		onClick: function() {
			textShadow();
		}
	}
};

var palette = new Palette('Shadow', components, values);

To make the button run the script, wrap everything we wrote in steps 1-7 in a function called textShadow.

Reference the values for the shadow size and offset as values.xSize, values.ySize, values.xOffset and values.yOffset.

Rulers in the components object just add a line to the interface to help divide elements.

I’ve added a boolean value for ‘knockout’, which allows you to select whether or not to cut the original front object from the final shadow once it’s been moved. This could be handy if using transparencies in the front text. This uses a lot of code we used before in making the original shadow:

if(values.knockOut){
	var compFront = CompoundPath([obj.createOutline()]);
	var compBack = CompoundPath([shadow]);
	var finalObj = Pathfinder.backMinusFront([compBack, compFront]);
}

Finally, the color value can be used to set the final shadow colour. This was trickier that it seemed. Once we have a compound path, we need to loop through all the children within it, setting their color:

for(var j=0; j

Download the final script. (text_shadow.js, 4KB)

Have a look in the file – I've also wrapped some of the code into a loop to apply the shadow to all selected text objects.