DES319 Typography IV: Basil.JS Spring 2019
Monday + Wednesday 9:00 – 11:40 a.m.
Course Description
Creative Coding and Typography. Using a scripting library - basil.js -, students will have the possibility of exploring traditional typographic features through programming. Basil.js is a tool to kick off interest in creative coding within Adobe InDesign, expand existing typographic knowledge, and open a path of further exploration and experimentation. → DES 319 Syllabus
Objectives & Goals
Manipulate advanced typographic features in digital environments. Write simple scripts and form your own algorithms.Create tools and define rules to generate typographic systems or systematic typographic manipulations.Develop logical and mathematical reasoning, applying it in the design process.
Technology
Important Information: We will be using the development branch of basil.js, the version 2.0! The 'b.' has been removed but the website, references & tutorials are still a work in progress... Any time you see a 'b.' in examples/tutorials/references, just remove it. Please just bare with me if there are any additional problems.
RESOURCES
Uselful Links Here are some of the main links you'll need: basil.js website // basil.js project basil.js *DEV* reference // list of all most basil.js functions and usage basil.js *DEV* tutorials // learn about things we don't have time for here! typo extended use // list from JONGWARE text properties for typo function JONGWARE // the motherload for InDesign scripting access BJS GITHUB // Basil.JS Development Repository
Cheat Sheets (©Ted Davis) basil.js cheatsheet v2 // 1 page reference to commonly used functions typo cheat-sheet // 2 pages of common type properties that typo can change
Uselful Books & Articles Gross, Benedikt. Bohnacker, Hartmut. Generative Design. Princeton Architectural Press, 2018. Reas, Casey. Form+Code in Design, Art and Architecture. P.A.P., 2010. Elam, Kimberly. Typographic Systems. P.A.P., 2007. Maeda, John. Design By Numbers. MIT Press, 1999.
Setup + Getting Started
Download the Basil.JS 2.0 Dev. Package (to "install" Basil.JS, just paste the basiljs folder into your root Documents folder)
02.10: Latest Basil.JS Source Code Version
Using Sublime Text 3
- Download Sublime Text 3;
- In Sublime Text, top navigation bar, go to "Tools", "Command Palette";
- Select "Package Control: Install Package";
- Choose "Run in inDesign"
- Under "Tools", there's a new option: "inDesign Tools", "Run in InDesign". Shortcut: Cmd+E / Ctrl+E The first time you run it, it will ask you to find desired version of InDesign.
Note: We still need to have ExtendScript Toolkit open in the background.
Using Visual Studio Code (MacOS Catalina users)
- Download Visual Studio Code;
- Open Extensions Menu (Cmd+Shift+X or Ctrl+Shift+X);
- Type and Install "Adobe Script Runner" and "Extendscript Debugger";
- On the bottom purple bar, select target application to Adobe inDesign;
- This step only needs to be done once.Press Ctrl/Cmd+K followed of Ctrl/Cmd+S to open the Keyboard Shortcut pages;Type Adobe After Effects, right click on it and "Remove Keybinding";Type Adobe inDesign, right click on it and "Add Keybinding";Press the command that you would like to save to run your scripts into inDesign (e.g. Cmd+R).
Note: This method only works if ExtendScript Toolkit is not installed.
Template
Each script starts with the following template. Please note that without including the first two lines of code, the library won't work. Paste it into a new document in your text editor (Sublime Text or Visual Studio Code):
- // @includepath ~/Documents/;%USERPROFILE%Documents;
- // @include basiljs/basil.js;
- function draw() {
- }
Hello WorldEvery programming language starts by saying hello to the world:
- println("hello world"); // says hello world in our console
- alert("hello world"); // prompts an hello world pop-up in inDesign
Setup Preferences A few helpful settings to consider:
- layer("myLayer"); // creates layer called 'myLayer' and draw our items there
- clear(layer("myLayer")); // clears all items on a layer - good to refresh the page when running the script
- units(IN); // sets units to inches (can use PTS, PX, MM)
- canvasMode(MARGIN); // sets 0,0 and width/height to our margins (PAGE, BLEED, ...)
Javascript Basics
VariablesVariables let us reference a value for usage throughout our code, usually placed multiple times, allowing us to change it on demand, and have each reference automatically updated.There are a handful of variable types, they all begin with var, can be named 'almost' anything you want, but avoid spaces and note they are caseSensitive in naming and usage:
- var myNumber = 14; // integer (whole number)
- var myFloat = 14.333; // float (decimal number)
- var myString = "Hi"; // string = text
- var myChar = 'a'; // single character
- var myBoolean = true; // boolean = true or false, used for if statements
Variables need to be declared the first time you use them with a 'var' at the front, afterwards you can change their value by simple setting them to equal a new value:
- var myText = "Hi";
- text text(myText,0,0,5,5);
- myText = "This is Basil.JS!";
- text(myText,0,5,5,5);
Combine variables (javascript automatically figures out how to join string + number):
- var myText = "Today is ";
- var date = weekday();
- text(myText+date,0,5,5,5);
If you are writing the same 'hard value' (ie. 50) multiple times, you should probably use a variable to save yourself time if later changing your mind. You also use them whenever parts of the code need to react to each other:
- var mySize = 10; // generate random value between 0 — 50
- ellipse(mySize, width-mySize,mySize,mySize) // use value to avoid edges + circle
We also use variables to let us reference any object we create. If we simply draw text with text(); – we have no way to talk to it. But making it a variable, we can then reference that object for further coding:
- var myText = text("Hi",0,0,5,5); // draw text frame
- typo(myText, "pointSize", random(1,20)); // change font size randomly between 1 and 20
The more variables you use, the more flexible your code will be!
If StatementsIt's very common to check values against each other and react accordingly. Is this value bigger than that one? Does this value equal this one? For that we use an 'if statement':
- var myRandom = random(100); // generates value between 0 – 100
- if(myRandom < 50){ // is the new value less than 50? » like flipping a coin
- // if so, run any code between these { brackets }
- }
There are a handful of ways we can ask these questions, they are known as conditionals:
- var a = 50;
- var c = 25;
- if(a == c){ // note the two ==, checks IF equal
- // do something if true
- }
- /* CONDITIONALS:
- a == c // equal
- a === c // equal and same data type (ie. number + number)
- a != c // not equal
- a > c // bigger than
- a < c // smaller than
- a >= c // bigger or equal
- a <= c // smaller or equal
- */
Once we asked that question, we can default to an 'else' (otherwise):
- var a = 25; // set a to value of 25
- if(a == 25){ // do this code if a EQUALS 25
- // do something if true
- } else{
- // do this code if not
- }
OR we can ask yet another question to catch the value in various values:
- var a = 2; // set a to value of 25
- if(a == 1){
- // do this code if a EQUALS 1
- } else if(a == 2){
- // do this code if a EQUALS 2
- } else if(a == 3){
- // do this code if a EQUALS 3
- } else{
- // do this code if none are true
- }
We can also combine these questions, to be more specific, known as AND/OR logic:
- var a = random(100);
- var c = random(100);
- if(a > 50 && c < 75){ // if BOTH are true
- // do this code
- }
- if(a > 50 || c < 75){ // if EITHER are true
- // do this code
- }
Think of if statements as filters. We don't want all code to run on all things. Maybe you want to check if some text == other_text, or in a loop, to see if you are on an even count for reacting to every-other iteration.
MathEven though we're designers, some math is good for us!Through practice you will get good at basic programmed math:
- var a = 10;
- var c = 5;
- var d = a + c;
- println(c);
- d = a - c;
- println(d);
- d = a * c;
- println(d);
- d = a / c;
- println(d);
- d = a * c + c/a - a;
- println(d);
Allow variables to grow:
- var a = 5;
- var c = 10;
- var d = 15;
- println(d);
- d += a; // adds 5 to the existing 15; // same as d = d + a;
- println(d);
- d += c; // adds 10 to the existing 20;
- println(d);
Percentages vs Fractions:
- var half = width * .5; // width/2 // 50%
- var quarter = width * .25; // width/4 // 25%
- var tenPercent = width * .1; // width/10 // 10%
- var third = width/3; // 1/3rd // 33.3333%
Rounding off:
- var a = 5.25;
- var c = 99.9;
- var d = round(c/a) // 5+ rounds up, 4- rounds down
- println(d);
- d = floor(c/a) // always rounds down
- println(d);
- d = ceil(c/a) // always rounds up
- println(d);
Modulor (%) — Usually used to determine even/odd (every other) within a loop:
- for(var i=0; i < 20; i++){
- if(i%2==0){
- // i went into it without leftovers = these are even numbers
- }
- }
Mapping:Map lets us scale the range (min, max) of value from an old (in) one to new (out) one. Think of a funnel - big at the top, small at the bottom.. scales pouring. This becomes especially useful while in a loop to automatically calculate increments.
- // map(inputVal, inMin, inMax, outMin, outMax);
- rectMode(CENTER);
- var loops = 20;
- for(var i = 0; i < loops; i++){
- var rx = map(i, 0, loops-1, 25, width);
- var ry = map(i, 0, loops-1, 25, height);
- var rs = map(i, 0, loops-1, 25, 5);
- var rc = map(i, 0, loops-1, 255, 0);
- fill(rc);
- var box = rect(rx,ry,rs,rs); // random horizontal position
- }
LoopsWhy draw one thing when you can draw 1,000,000?! Take advantage of the computer to create many objects instead of one.
For-loop abstraction:
- for(start; end; count){
- // run this code x looped times
- }
For-loop example:
- for(var i = 0; i < 50; i++){
- println(i); // outputs 0-19
- }
Drawing circles with for-loop:
- for(var i = 0; i < 50; i++){
- var rx = random(width); // random horizontal position
- var ry = random(height); // random vertical position
- var rs = random(0.1,2); // random size between 0.1 and 2
- var rc = random(255); // random grayscale value
- fill(rc);
- var circle = ellipse(rx,ry,rs,rs); // random horizontal position
- }
Loops within loops!? It's also common to place two loops within each other, so it does one looped task, multiple times, either to add a page, or for a grid. however we need to use different variable names within the loop to avoid overlap.
- var grid = 10; // random horizontal position
- for(var i = 0; i < grid; i++){
- for(var j = 0; j < grid; j++){
- var sw = width/grid;
- var sh = height/grid;
- var x = map(j, 0, grid-1, 0, width-sw);
- var y = map(i, 0, grid-1, 0, height-sh);
- var r = rect(x,y,sw,sh);
- }
- }
ArraysArray's are amazing for keeping track of a group of variables, objects, overall data. You can create an array from scratch:
- // an array is known by using [, ] structure:
- var someNumbers = [5,20,42,29,105]; // random horizontal position
- println(someNumbers); // list all items
- println("2nd Index: " + someNumbers[1]); // list 2nd index (0 = 1st index, 1 = 2nd index, etc.)
- println("Last Index: " + someNumbers[someNumbers.length-1]); // last index! arrayName.length = number of items in array.
- println("Random Index: " + someNumbers[round(random(someNumbers.length))]); // last index! arrayName.length = number of items in array.
It's typical to then process an array and do something with each value in it:
- var someNumbers = [1,3,2,4,.5]; // random horizontal position
- var previousSize= 0; // store previous value
- for(var i = 0; i < someNumbers.length; i++){
- println(someNumbers[i]);
- rect(0, previousSize, vals[i], vals[i]);
- previousSize += vals[i]; // add on previousSize (vertically)
- }
We can also add data to an array, either existing or from scratch:
- var myData = []; // empty array
- for(var i = 0; i < 15; i++){
- myData.push(random(1,100));
- }
- inspect(myData);
ObjectsObjects are similar to variables, but they can contain many other variables and functions. one analogy is a car with all its parts:
How to create an object from scratch:
- // an object is known by using {, } structure; Using name:value pairs (separated by a colon); Separate properties with a comma
- var car = {type:"Fiat", model:"500", color:"Black"};
- // use blank space to keep it organized
- var person = {
- firstName:"John",
- lastName:"Doe",
- age:50
- };
- inspect(car); // list all items
- println(car.type);
- println(car["type"]); // same as above
An object can go many levels deep, containing more objects or arrays of objects. Think of cars in a parking garage. an array of levels, each having an array of cars, each containing the details of that car. Here some pseudo code reaching a single car within a level of a garage:
- println(garage.level[2].cars[10].color);
Drawing Shapes
Basic ShapesHere are a handful of shapes we can draw to the canvas:
- // line(x1, y1, x2, y2);
- var myLine = line(0,height*.5, width, height*.25);
- // ellipse(x, y, width, height);
- var myEllipse = ellipse(width*.5,height*.5, 2, 2);
- // rect(x, y, width, height);
- var myRect = rect(width*.25,height*.25, 3, 3);
- // complex shape, path of points
- beginShape();
- vertex(1,1);
- vertex(3,5);
- vertex(2,4);
- vertex(7,2);
- // as many vertex(x, y); as you want
- var myShape = endShape();
Pre-Styling ShapesUsed to set the appearance before drawing any shapes:
- // color(R, G, B); = full color
- // color(150) = grayscale
- var myColor = color(200,0,0); // create a red color
- fill(200,0,0); // set color of fill directly
- fill(myColor); // use color() variable
- noFill(); // turns off fill = none
- stroke(0,0,200); // set color of stroke directly
- stroke(myColor); // use color() variable
- noStroke(); // turns off stroke = none
- strokeWeight(5); // sets thickness of stroke
- rectMode(CENTER); // draw rectangles from center out. default is CORNER = upper left
- var myShape = rect(2,2,5,5); // declare shapes after the style attributes
Post-Styling ShapesWe can change any property of a shape or pageItem using our new property() function:
- var myShape = rect(2,2,5,5); // can now talk to it as 'myShape'
- property(myShape, "fillColor", color(200,0,0)); // same as previous fill()
- property(myShape, "fillColor", "None"); // same as noFill()
- property(myShape, "strokeColor", color(0,0,200)); // same as stroke()
- property(myShape, "strokeColor", "None"); // same as noStroke()
- property(myShape, "strokeWeight", "5"); // same as strokeWeight
You can also set multiple properties at once by feeding it a javascript object:
- var myShape = rect(2,2,5,5);
- var myStyle = {
- strokeWeight:25,
- strokeColor:gradient(color(200,0,0),color(200,200,0)),
- fillColor:gradient(color(200,200,0),color(200,0,0)),
- }
- property(myShape,myStyle);
Adding Images
Local ImagesFirst save your indesign document and create a folder next to it called 'data'. Place some images in there, and load using a relative path:
- //imageMode(CENTER); // similar to rectMode();
- var img = image('image.jpg',0,0); // image(filename, xPos, yPos)
- var img = image('image.jpg',0,0,width,height); // additional params: width, height
- var img = image('image.jpg',obj); // place image into rectangle, ellipse, polygon
Now load an image anywhere on your computer using its absolute path:
- var imgPath = file('~/Pictures/image-example.jpg');
- var img = image(imgPath,0,0);
Remote ImagesFirst save your indesign document so the images can be downloaded — MacOs only 🙁
- var url = "https://raw.githubusercontent.com/basiljs/basil.js/master/lib/basil.png";
- // download image to a relative path (/data)
- download(url,"downloads/basil.png");
- var img = image("downloads/basil.png", 0, 0, width, height);
- // download image to an absolute path
- var newFile = file("~/Documents/basiljs/user/downloads/basil.png");
- download(url,newFile);
- var img = image(newFile, 0, 0);
FoldersWe can even load a whole folder of images! find one on your computer and adjust code:
- // point to folder of images + load them
- var imgsDir = folder("/Library/Desktop\ Pictures");
- var imgs = file(imgsDir, {filter: ["jpeg", "jpg"]}); // optional filetype filter
- println("imgs found: " + imgs.length);
- // loop through list and do something per image
- for(var i = 0; i < imgs; i++){
- var img = image(imgs[i], 0, 0, width, height);
- addPage();
- }
Image FittingFit the image within its frame using various fit() options:
- var img = image("photo.png", 0, 0, 10, 10);
- img.fit(FitOptions.FILL_PROPORTIONALLY);
- /*
- FitOptions.CONTENT_TO_FRAME
- FitOptions.CENTER_CONTENT
- FitOptions.PROPORTIONALLY
- FitOptions.FRAME_TO_CONTENT
- FitOptions.FILL_PROPORTIONALLY
- FitOptions.APPLY_FRAME_FITTING_OPTIONS
- */
Image Blend ModeEasily change the blendmode/effect of an image:
- var img = image("photo.png", 0, 0, 10, 10);
- var img2 = image("photo2.png", 0, 5, 10, 10);
- blendMode(img2, BlendMode.LIGHTEN);
- /*
- BlendMode.NORMAL
- BlendMode.MULTIPLY
- BlendMode.SATURATION
- BlendMode.OVERLAY
- ...
- */
ImageFrameTo adjust the actual image within the imageframe, we talk to its 'graphics'. Here we can center position the image, scaled at 25% of the frame:
- var img = image("photo.png", 0, 0, 10, 10);
- img.graphics[0].verticalScale = 25;
- img.graphics[0].horizontalScale = 25;
- img.fit((FitOptions.CENTER_CONTENT);
Drawing Type
TextFramethere's just one line of code needed to draw text and you've already learned it! It's up to you what text goes in there, where the box sits and how big it is.
- // text(string, x, y, width, height);
- var myText = text("Hello",0, 0, width, height); // full page textframe
- var myText2 = text("Hello",0, 0, 2, 2); // small textframe
- var myTextPath = text(LOREM,obj); // place text on path or in polygon
Pre-Styling TypeWe can set type styles before drawing our textframe:
- textFont("Georgia", "Bold"); // font family, comma, specific style
- textSize(50); // set font size
- textLeading(110); // set font leading
- textTracking(20); // set font tracking
- var myText = text("Hello! \n Goodbye!",0,0,width,height); // \n = new line
Post-Styling Typewe can also change the type after drawing it, by referencing its variable:
- var myText = text("Hello",0,0,5,5); // reference it as 'myText'
- typo(myText, "appliedFont", "Georgia Bold"); // change font family and style
- typo(myText, "pointSize", 50); // change font size
- typo(myText, "leading", 110); // change font leading
- typo(myText, "tracking", 20); // change font tracking
Once the type is stylized, you can resize the textFrame to match the content inside:
- text.fit(FitOptions.FRAME_TO_CONTENT);
There are MANY more things we can do to the type! Check out the typo cheatsheet!
Modifying Type
Splitting TypeOnce you have a newly generated or existing textFrame in selection, ie. 'sel', we can break it down into the following sections. Note: in some cases it's best to turn off hyphenation so it can find full words.
- typo(sel, "hyphenation", false);
Each line:
- lines(sel,function(obj,c){
- // 'obj' is each line
- // 'c' is counting each object 0..1..2..
- typo(obj, "pointSize", random(1,50));
- });
Each word:
- words(sel,function(obj,c){
- // 'obj' is each word
- // 'c' is counting each object 0..1..2..
- typo(obj, "pointSize", random(1,50));
- });
Each character:
- characters(sel,function(obj,c){
- // 'obj' is each character
- // 'c' is counting each object 0..1..2..
- typo(obj, "pointSize", random(1,50));
- });
Mapping TypeWe can make smooth transitions if we store how many objects there are and map values. This would work with any section above, simply change lines -> words -> characters. Explore the many possibilities of the typo() function 😊
- var objCount = characters(sel).length; // store how many there are
- characters(sel,functionobj,c{
- // 'obj' is each character
- // 'c' is counting each object 0..1..2..
- typo(sel, "strokeColor", color(0)); // set stroke to a color
- typo(sel, "strokeWeight", map(c, 0, objCount-1, 0, 10)); // smoothly change value
- });
Apply StylesIt's possible to apply character or paragraph styles to any text/textframe you are talking to:
- applyParagraphStyle(obj,"StyleName");
- applyCharacterStyle(obj,"StyleName");
- applyObjectStyle(obj,"StyleName");
Outline TypeLet's play with the points of each letter. Once we break it down by points, we'll need to study up on arrays + the basics. Note: this can slow down the render time of your script.
- // start with some text
- textSize(200);
- textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
- var tf = text("Hi",0,0,width,height);
- var outlines = createOutlines(tf);
- addPoints(outlines,5); // optionally increase amount of points
- property(outlines,"fillColor","None"); // optionally hide original outlines
- // get points (coordinates) from outline
- var pts = points(outlines); // // array of the outline points
- println(pts.length); // check how many points you have (.length = size of array)
- // loop through points
- for(var i = 0; i < pts.length; i++){
- // pts[i].x , pts[i].y = x , y coordinates of point!
- var s = random(0.25,2);
- ellipse(pts[i].x,pts[i].y,s,s);
- }
Selection + Modification of Items
Single SelectionIf we want to change/modify just one single item from our existing indesign document, once selected, use any of the 'post-style' attributes from the previous lessons. Simply click on the item before running the script.
- var sel = selection();
- //transform(sel, "position", [random(width), random(height)]);
Script label — open 'script label' window and give a name there:
- var sel = label("labelName"); // be sure the label has the same name, 'myObject'
- //transform(sel, "position", [random(width), random(height)]);
Multiple SelectionOr you might want to grab a group of objects and change them all. Once we select the items, we combine a function to cycle through each object. Within that loop, use the 'post-style' attributes to modify each object. Start by clicking on the item before running the script.
- selections(function(obj,c){
- // 'obj' is each item
- // 'c' is counting each object 0..1..2..
- // transform(obj, "size", [random(5), random(5)]);
- });
Script labels. Select multiple items and give the same script label, ie. 'box':
- selections("box",function(obj,c){
- // 'obj' is each item
- // 'c' is counting each object 0..1..2..
- // transform(obj, "size", [random(5), random(5)]);
- });
Select multiple objects in a specific layer:
- items(layer("shapes"),function(obj,c){
- // 'obj' is each item
- // 'c' is counting each object 0..1..2..
- // transform(obj, "size", [random(5), random(5)]);
- });
Modifying/Transforming ObjectsWe can change newly created items or existing and selected items in a handful of ways:
- transform(obj, "position", [2,0]); // only move the x position
- transform(obj, "position", [0,5]); // only move the y position
- transform(obj, "position", [width/2,height/2]); // move both x and y position
- transform(obj, "width", 5); // only change the width
- transform(obj, "height", 5); // only change the height
- transform(obj, "size", [5,5]); // change both width and height
- transform(obj, "rotation", 45); // change rotation of item
- transform(obj, "shearing", 15); // change shear of item
- // change reference/anchor point for any transformations
- referencePoint(CENTER); // set reference point (`TOP_LEFT`, `TOP_CENTER`, `TOP_RIGHT`, `CENTER_LEFT`, `CENTER`, `CENTER_RIGHT`, `BOTTOM_LEFT`, `BOTTOM_CENTER`, `BOTTOM_RIGHT`)
- transform(obj, "rotation", 45); // change rotation of item
Geometric BoundsGrab an items geometric bounds on the page (left, right, top, bottom, width, height):
- var bnd = bounds(sel); // sel should be your selected item
- //inspect(bounds); // shows us the available values in the console
- line(0,0, bnd.left, bnd.top);
- line(0,0, bnd.right, bnd.bottom);
- line(width,height, bnd.right, bnd.top);
- line(width,height, bnd.right, bnd.bottom);
Copy/Cut & PasteWe can easily duplicate or remove/clear unnecessary items:
- var myCopy = duplicate(obj);
- // myCopy.fillColor = color(random(255));
- remove(obj); // deletes selected item
- clear(doc()); // clears entire document
- // clear(page()); // clears current page
- // clear(layer("myLayer")); // clears layed called 'myLayer'
Generative Transformations
RandomWe can take advantage of the computer's logic by letting it perform pseudo-random... Helping create things we would NEVER think of doing or trying!
- // random(high); // random value from 0 - high
- // random(low, high); // random value from low - high
- var randomX = random(width); // anywhere across width of page
- var randomY = random(height); // anywhere across height of page
- var circle = ellipse(randomX,randomY,2,2);
- var circle2 = ellipse(width/2,height/2,randomX, randomY);
50/50 ChanceFlip a coin to decide things by generating a random number and checking it's value.
- if(random(1) < .5){ // create random number to 1, if it's less than .5 = 50% chance
- // do something if it's true
- }else{
- // do something else if it's false
- }
Page ControlThere are plenty of things to do with InDesign pages:
- addPage(); // simply adds a new blank page
- var dupPage = duplicate(page());
- page(); // is the current page
- page(15); // jumps to specific page for working on
Generative BookWant 100 pages of generative shapes? it just takes a few lines of code:
- pageCount(1); // clear any previous pages
- noFill();
- var numPages = 100;
- for(var i = 0; i < numPages; i++){
- beginShape(); // start our shape
- for(var j = 0; j < 5; j++){
- // we add ## of points to the shape
- vertex(random(width),random(height));
- }
- endShape();
- addPage();
- }
Export Files
Export PDF or PNGYou must first save your inDesign document before exporting a PDF or PNG:
- savePDF(timestamp()+".pdf"); // exports file with current/latest PDF settings
- savePDF(timestamp()+".pdf", true); // brings up dialog box for PDF settings
- PNG
- savePNG(timestamp()+".png"); // exports file with current/latest PNG settings
- savePNG(timestamp()+".png", true); // brings up dialog box for PNG settings
Data Management & Vizualization
Data FileTypesBasil.js gets fancy when loading online data for data-viz + generative layouts.
The most common formats for passing data are:- CSV | comma, separated, values | from spreadsheet- JSON | javascript object notation | usually info from the web- XML | extensible markup language | older format, JSON basically replaced it
They'll contain an array of records, each with many properties.
APIAn API, or application program interface, is a programmable way that we can tap into the data of most online servies. youtube, facebook, instagram, google maps, twitter, etc etc. – all provided varying degrees of access to their databases. some require authentication (username + password) for doing automated actions to ones own account, other are available to the general public for meta/trending/statistical info via a key.
List for free APIs, ProgrammableWeb
New York Times API We'll use NYTimes Top Stories, it's well documented and free for 1,000 calls per day. Sign up here for free: NYTimes API
Load Data Remotely call the API for data as a string, then process it into a JSON object: (PC users, use this special function)
- var apiKey = "your api key"; // received by email after signing up
- var nytJSON = loadString("https://api.nytimes.com/svc/topstories/v2/home.json?api-key=" + apiKey);
- // var nytJSON = loadString("nytimes_comments.txt"); // offline json
- var nyt = JSON.parse(nytJSON); // decode json to object
- var data = nyt.results; // use data.length for # of results
- inspect(data[0]); // inspect is necessary for objects
Inspect returns:|-- abstract|-- byline|-- created_date|-- des_facet|-- geo_facet|-- item_type|-- kicker|-- material_type_facet|-- multimedia|-- org_facet|-- per_facet|-- published_date|-- section|-- short_url|-- subsection|-- title|-- updated_date|-- url
Read the Javascript Basics Objects section and use syntax of objectName.propertyName examples below are just for the first [0] result:
- // turn result into var
- var article = data[0];
- // title
- var artTitle = article.title;
- // abstract
- var artAbstract = article.abstract;
- // published date
- var artPub = article.published_date;
- // sections + subsection
- var artSection = article.section;
- var artSubsection = article.subsection;
- // url
- var artUrl = article.url;
Images:
- // image, array of various sizes
- var imgs = article.multimedia;
- // thumbnail image (75px)
- var thumb = article.multimedia[0].url;
- // hi-res image (> 1000px)
- var thumb = article.multimedia[4].url;
- // meta data
- var caption = article.multimedia[4].caption;
- var copyright = article.multimedia[4].copyright;
- var imgWidth = article.multimedia[4].width;
- var imgHeight = article.multimedia[4].height
Process DataIf any value is an array, use a loop to cycle through it:
- for(var i = 0; i < data.length; i++){
- var article = data[i]; // temp var to keep things clean
- textSize(map(i, 0, data.length, 10, 50)); // map text size based on count
- varmyHeadline = text(article.title, 0, 0, width, height); // draw text
- // only add page if not last
- if(i < data.length-1){
- addPage();
- }
- }
'multimedia' is an array of sizes from thumbnail [0] to hi-res [4] place in loop above right below declaring 'var article = ...' Be sure to save InDesign document first + might only works on MacOS...
- // only download if there are images
- if(article.multimedia.length > 0){
- download(article.multimedia[1].url, "img_"+i+".jpg");
- var pict = image("img_"+i+".jpg", 0, 0, width, height);
- }
Combine this with what we've covered so far in previous lessons! :-)
Assignment
Basil.JS Exercise: NYTimes API Brief
Basil.JS Exercise: 36 Days of Type Brief
Assignment Poster for Tomorrow 2020
Class Files
01.29: Javascript Basics Part 1
02.03: Javascript Basics Part 2
02.05: Javascript Basics Part 3
02.10: Type Manipulation
02.12: Images+Generative
02.19: Data Import
03.11: Type Outlines
Schedule (Subject to change at the instructor’s discretion)
Week 1 → 13 + 15 Jan. 2020 Course introduction; inDesign features: options and possibilities.
W2 → (20 Jan. M.L.K. Day) + 22 Jan. 2020Basil.JS setup: hello world.
W3 → 27 + 29 Jan. 2020Javascript basics: variables, if statements, math.
W4 → 03 + 05 Feb. 2020Javascript basics: loops, arrays, objects.
W5 → 10 + 12 Feb. 2020Basil.JS basics: drawing shapes, images and type.
W6 → 17 + 19 Feb. 2020Basil.JS typography: manipulating type.
W7 → 24 + 26 Feb. 2020Basil.JS Exercise: NYTimes API Brief.
W8 → 02 + 04 Mar. 2020Basil.JS Exercise: NYTimes API.
W9 → 09 + 11 Mar. 2020Basil.JS Exercise: 36 Days of Type.
W10 → 16 + 18 Mar. 2020 Spring Break.
W11 → 23 + 25 Mar. 2020Spring Break.
W12 → 30 Mar. + 01 Apr. 2020Basil.JS Exercise: 36 Days of Type. (ONL)
W13 → 06 + 08 Apr. 2020Assignment (T.B.C.) (ONL)
W14 → 13 + 15 Apr. 2020Assignment (T.B.C.) (ONL)
W15 → 20 + 22 Apr. 2020Assignment (T.B.C.) (ONL)
W16 → 27 + 29 Apr. 2020Final presentation + documentation + submission. (ONL)
Attendance + Grading
Students who are actively engaged in class sessions are more likely to be successful. You are expected to attend each class session and to be on time. If you are sick, especially contagious, do not come to class. This is an excused absence. Notify the instructor via e-mail. Students who accumulate 3 or more unexcused absences may be asked to withdraw from class and/or risk receiving a failing grade. After 2 unexcused absences your grade may be adjusted downward one letter grade for each additional absence. Students are required to attend class for its full duration. Valuable information, demonstrations, lectures and announcements typically take place at the start of class. Arriving on time and being prepared to work are essential factors for productivity. Being late, leaving early, or missing a critique will negatively impact your performance. Missing demonstrations or lectures will set you behind from the rest of the students. In case of an absence, it is your responsibility to make up any material introduced in class. All work must be received by the set deadlines. Late or incomplete work will not be accepted, except in extreme circumstances, with the instructor’s approval. Grading is based on the aesthetic quality and craft of the work, as evidenced in the finished pieces; the course of research and/or process of design exploration pursued to achieve the finished pieces, as evidenced by your work in process; attendance and class participation. Grading percentages: Project development/Research process/Sketches (60%); Final execution/Output (30%); In class participation and preparation (10%);
Acknowledgments
Special Thanks to Ted Davis & Basil.JS Development Team for all the documents, links and support that was necessary to put this website together.