« »

Modifying typography

How to change the appearance of InDesign text frames programatically. By Ted Davis

1. Getting started with type

Add basic text box

#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";

function draw() {

b.clear(b.doc()); // clears previous output, helpful during this tutorial

b.text('hello world', 0, 0, 150, 50); 
// this means b.text("your text", x, y, w, h);



Be sure to visit our reference section on b.text() and other typographic features if you want to know more about the functions.

Change type attributes

Add these one at a time before your text frame, as they will only effect text that comes after it.

b.textFont("Helvetica", "Regular"); 
// simply copy name as found when selecting fonts
// second string is optional if specifying font-weight


Overflowing text

If the font gets too big, you'll see that the type is now flowing past the bounds of the box, so let's resize it. In order to change the Text Frame we just built, we need to create it as a variable so that we can easily refer to it later. To do this, simply changing the following:

// b.text('hello world', 0, 0, 350, 50);
var myFrame = b.text('hello world', 0, 0, 350, 50);

Note the 'var myFrame = ' placed in front of our b.text() code.
We can now refer to it and resize it, by writing the following after our manipulations:


The bounding box is now as big as our page's width + height.

Styling those contents

Now that you can refer to your text frame, let's change further attributes inside using the all encompassing b.typo() function:

b.typo(myFrame,'strikeThru',true); // add strike through
b.typo(myFrame,'characterRotation',-45); // add strike through

Exercise 1

Download our cheat sheet dedicated to the b.typo function: basiljs_b_typo_cheatsheet_v0_1.pdf

Go through the list and pick additional properties to manipulate.
Suggestion: Add a longer text to your initial text frame to have more material to work with.

2. Linking Text Frames + Aligning Text

If creating a generative book across multiple pages, you'll surely want to know how to link text frames together.

Start with a new document and let's build two very generative text frames

#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";

function draw() {

b.clear(b.doc()); // clears previous output

var myFrame1 = b.text('this is frame 1', b.random(b.width), b.random(b.height), b.random(30,300), b.random(30,300));
var myFrame2 = b.text('this is frame 2', b.random(b.width), b.random(b.height), b.random(30,300), b.random(30,300));


To link these text boxes, you simply write the following after they have been created:

b.linkTextFrames(myFrame1, myFrame2);

If you saw the type leave myFrame2 and join myFrame1, then they have been properly linked.
Just to test out that it's working, try flowing some placeholder text through the two text frames:

b.typo(myFrame1, "contents", ""); // clear the current text
myFrame1.contents = TextFrameContents.placeholderText;

This should not only erase the existing contents of the two boxes, but then fill them entirely with Lorem Ipsum text.

Aligning Text

When setting the justification of type, there are two options: set it before you build your text frame or use b.typo() to set it afterwards.
Each can be set in the following way:

Before you generate the text frame

// var myFrame1 = b.text('this is frame 1', 30, 30, 300, 300);

After you've generated the text frame

// var myFrame1 = b.text('this is frame 1', 30, 30, 300, 300);
b.typo(myFrame1, "justification", Justification.CENTER_ALIGN);

Refer to the following list for setting various justifications:

  • Justification.AWAY_FROM_BINDING_SIDE
  • Justification.CENTER_ALIGN
  • Justification.CENTER_JUSTIFIED
  • Justification.FULLY_JUSTIFIED
  • Justification.LEFT_ALIGN
  • Justification.RIGHT_ALIGN
  • Justification.RIGHT_JUSTIFIED
  • Justification.TO_BINDING_SIDE

  • VerticalJustification.BOTTOM_ALIGN

  • VerticalJustification.CENTER_ALIGN
  • VerticalJustification.JUSTIFY_ALIGN
  • VerticalJustification.TOP_ALIGN

Note: vertical justification of a text frame should be done before generating it, also using the textAlign() function.

b.textAlign(Justification.FULLY_JUSTIFIED, VerticalJustification.CENTER_ALIGN);

Exercise 2

Generate an interesting composition of of text frames throughout the page or document and link them all together. Change each text frames justification to fit your composition. Use the b.typo() + "contents" function to replace your text within your composition with any larger body of text.

Hint: Be sure to create all new text boxes with at least one empty space as initial text (" "), because InDesign automatically removes a newly created empty text box, assuming it was a mistake.

3. Break it all apart

Manipulating the entire block is fun and all, but hardly demonstrates a reason to stop using the mouse and GUI of inDesign. It's when we break down and isolate each and every element within a text frame that the power of programming really begins to shine.

Working from a selection

As you begin to learn how to use basil.js, it may be helpful to revisit old projects that were designed by hand/mouse and manipulate the contents of objects by simply selecting them and running your code.

Incase you are not opening an old project, create a new document and place a new text frame across the entire page. Fill this text frame with placeholder type, and continue.

To begin let's get our selected text frame or text into something that we can refer to by code, a variable:

#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";

function draw() {
  selItems = b.selections()[0];  


This code is looking for an object or text that is selected and grabs the very first one [0], just incase multiple items were selected.

Next let's break the selection down and isolate every single word within the text. Todo this, we have two ways to walk forward. Both accomplish the exact same task, but approach it quite differently.

b.words(selItems, function(w, n){
  b.typo(w, "pointSize", n+1);

The snippet above is the most efficient way to cycle through all of the words, of mySel, build a special function, in which 'w' refers to each word and 'n' refers to their placement in order. The end result will be a growing cascade of type, using the words order to set it's size.

Think about how long that would take you with the mouse...!

var myWords = b.words(selItems);

for(var i = 0; i < myWords.length; i++){
  b.typo(myWords[i], "pointSize", i+1);


This second snippet is not as compact, but more flexible for further use. By using the b.words() function on it's on (not embedding a function like above), it allows you to create an array (or grouping) of objects to refer to later. Once we have our array called myWords, we use a for loop to also cycle through each of these words (it repeats until hitting the end or myWords.length). Within this loop, we do the exact same b.typo() function for the pointSize. So why is this one more useful? Because once we are done with our loop, we can easily refer to just one of these words and change/view/print it's contents.

Exercise 3

Explore the various ways of isolating content within your text frame:

  • b.paragraphs()
  • b.lines()
  • b.words()
  • b.characters()

and test different combinations of modifying the content based on b.typo() or other attributes as listed above.

4. Example - Website typo

Here is a quick script demonstrating how to recreate the headlines as seen on this website:

#includepath "~/Documents/;%USERPROFILE%Documents";
#include "basiljs/bundle/basil.js";

function draw() {
  selItems = b.selections();
  b.characters(selItems[0], function (ch,n) {

    // map font size range by the length of characters there are
    var shrinkText = b.map(n,0,selItems[0].characters.length,60, 20);

    b.typo(ch, 'appliedFont', 'Times New Roman\tBold');
    b.typo(ch, "pointSize", shrinkText);
    b.typo(ch,'underline', true);