Simple Book Workflow Templates

This document contains the following programs to get you started: 

  • Ultra-simple p5.js text generator -- generates a JSON file containing some rudimentary "poems".
  • Ultra-simple Basil.js typesetter -- loads the JSON file into InDesign and lays out the poems.


Ultra-simple p5.js text generator

Here is an ultra-simple text generator, written in p5.js, which exports a JSON of random "poems" (using the saveJSON() function) when the user presses a button. Once you have this working, you can start to add more sophisticated text-generation techniques, using the resources (like RiTa, etc.) described here.

// This p5.js program generates an array of nonsense "poems", 
// and then exports these poems as objects in a JSON file. 
// Golan Levin, November 2018

var myPoemsArray = [];

// A "Poem" object consists of a title and a body text
class Poem {
  constructor(title, text) {
    this.title = title;
    this.text = text;
  }
}

function setup() {
  createCanvas (300, 100); 
  background(200); 
  
  var words1 = ["Foamy", "Fancy", "Funky", "Freaky", "Flappy", "Forky"];
  var words2 = ["Bagel", "Booger", "Bunting", "Bumper", "Banter", "Blip"];
  var vowels = "aeiou";
  var consonants = "bcdfgjklmnprstvxz";

  // Generate some random-ass poems.
  var nPoems = 5;
  var nIters = 20;
  for (var i = 0; i < nPoems; i++) {

    var aTitle = ""; // Generate the title from two random words.
    aTitle += words1 [floor(random(6))] + " ";
    aTitle += words2 [floor(random(6))];
    
    var aText = ""; // Generate the text from random characters.
    for (var j = 0; j < nIters; j++) {
      aText += consonants.charAt(floor(random() * consonants.length));
      if (j == 0) {
        aText = aText.toUpperCase();
      }
      aText += vowels.charAt(floor(random() * vowels.length));
      if (j == (nIters - 1)) {
        aText += ".";
      } else if (random() < 0.30) {
        aText += " ";
      }
    }

    // Construct the i'th Poem object, and add it to the Poem array.
    var aPoem = new Poem(aTitle, aText);
    myPoemsArray[i] = aPoem;
  }

  // Create a JSON Object, fill it with the Poems.
  var myJsonObject = {};
  myJsonObject.poems = myPoemsArray;

  // Make a button. When you press it, it will save the JSON.
  createButton('SAVE POEMS BUTTON')
    .position(10, 10)
    .mousePressed(function() {
      saveJSON(myJsonObject, 'myPoems.json');
    });
}

When you click the button, it generates JSON files and downloads them to your computer. The JSON files look like the following:

{
  "poems": [
    {
      "title": "Freaky Bunting",
      "text": "Nixepa mi de fugi nemo poduxeda ku ji vaxu kokoko."
    },
    {
      "title": "Foamy Blip",
      "text": "Vasadekufezibecu jefe kivu sucizosusicuku fu."
    },
    {
      "title": "Forky Banter",
      "text": "Rurejoga pivasazicu kidose fazibamamufi toxe."
    },
    {
      "title": "Freaky Bagel",
      "text": "Ki tetafu linitagi lorumepepu fovo noka retixi."
    },
    {
      "title": "Fancy Booger",
      "text": "Ninunifokosisojopa ra lokuzuboke surugubomi."
    }
  ]
}


Ultra-simple Basil.js Typesetter

The Basil.js program below loads the "myPoems.json" file generated by the program above. It then automatically lays out the poems in that JSON file, one per page, in Adobe InDesign. Here is a .zip archieve containing the complete Basil/InDesign project discussed here: SimplePoemBook

Since the layout is automatic, we are able to perform some typographic tricks. For example, we give each word its own random color; we automatically underline the first word of each poem; and we gradually shrink the letters as we go, giving each letter a unique size. There's a handy cheat sheet for these typographic options here.

#include "../../bundle/basil.js";
// Version for basil.js v.1.1.0
// Golan Levin, November 2018

//--------------------------------------------------------
function setup() {
 
  // Load a JSON file containing your book's content. This is expected
  // to be located in the "data" folder adjacent to your .indd and .jsx. 
  var jsonString = b.loadString("myPoems.json");

  // Clear the document at the very start. 
  b.clear (b.doc());

  // Parse the JSON file into the jsonData array
  var jsonData = b.JSON.decode( jsonString );
  var poems = jsonData.poems; 
  b.println("Number of poems: " + poems.length);

  // Initialize some variables for element placement positions.
  // Remember that the units are "points", 72 points = 1 inch.
  var inch = 72;

  var titleW = inch * 5.0;
  var titleH = inch * 0.5;
  var titleX = (b.width / 2) - (titleW / 2); // centered 
  var titleY = inch * 1.0;

  var textX = inch * 1.0; 
  var textY = inch * 2.5;
  var textW = inch * 4.0;
  var textH = inch * 5.0;

  // Loop over every element of the book content array
  // (Here assumed to be separate pages)
  for (var i = 0; i < poems.length; i++) {

    //----------------------------
    // Format and display the "title" field.
    b.noStroke(); 
    b.fill(0,0,0);
    b.textSize(30);
    b.textFont("Helvetica","Bold"); 
    b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN );
    b.text(poems[i].title, titleX,titleY,titleW,titleH);

    //----------------------------
    // Format and display the poem's "text" field. 
    // This time, let's do some typographic tricks.
    // See: 
    // http://basiljs.ch/wp-content/uploads/2013/03/basiljs_b_typo_cheatsheet_v0_2.pdf
    b.textFont("Times New Roman","Regular"); 
    b.textAlign(Justification.LEFT_ALIGN, VerticalJustification.TOP_ALIGN );
    
    // Get the text of the i'th poem
    var poemText = poems[i].text;
    
    // Create an InDesign TextFrame from this text
    var thePoemTextFrame = b.text(poemText, textX,textY,textW,textH);
    
    // Fetch the individual words in this TextFrame; 
    // Underline the first (0'th) word. 
    var poemWords = b.words (thePoemTextFrame);
    b.typo(poemWords[0],'underline', true);

    // Give each word its own (random) color.
    var poemLines = b.lines (thePoemTextFrame);
    for (var w=0; w<poemWords.length; w++){
      var wthWord = poemWords[w];
      var wordR = b.random(0, 180); 
      var wordG = b.random(0, 180); 
      var wordB = b.random(0, 180); 
      b.typo(wthWord,'fillColor', b.color(wordR, wordG, wordB));
    }

    // Fetch the individual characters in this TextFrame; 
    // Give each character its own type size, gradually
    // shrinking the characters as we go. 
    var poemChars = b.characters (thePoemTextFrame);
    var nPoemChars = poemChars.length; 
    for (var c=0; c<nPoemChars; c++){
      var cthChar = poemChars[c];
      var charSize = b.map(c, 0, nPoemChars, 40, 18); 
      b.typo(cthChar, "pointSize", charSize); 
    }

    //----------------------------
    // Create the next page. 
    if (i < (poems.length-1)){ 
      b.addPage(); } 
    } 

    // Ensure that there are an even 
    // number of pages in the document. 
    if ((poems.length % 2) > 0){
      b.addPage();
    }
}

// This makes it all happen:
b.go();