Spoon-Book

For my generative book, I chose to make a bad design student. The school of design teaches a required course for its freshman students called Placing, in which students produce photo essays. I wrote an algorithm that would generate these essays by taking other students' essays (with their permission) as source material for a markov chain. The resulting essays are a mish-mosh of all sorts of different content that addresses the same assignment (every time the code is run it produces an essay that addresses one of the four assignments given in Placing). These essays do not make much sense, but they tend to contain gems of crazy, nonsensical sentences or outlandish claims about society that are the result of multiple different sentences from the source material being put together in a strange way.

After the text is generated and saved into a JSON file, it is fed through a Basil.js script that places the resulting text onto different pages and pairs each paragraph with a photograph randomly pulled from a collection of photos used in students' essays for that particular assignment.

The code for the text generator is just a Markov chain with no additional logic added to it. I spent some time experimenting with the n-value for the chain because I was trying to find a balance between sentences that were more or less grammatical and not simply lifting full sentences directly from the source material. The code generates a random number of sentences between a range of 60 to 75. It then splits the resulting text into paragraphs of 5 sentences each.

The Basil.js script creates a title page for the book, then lays out two generated Placing essays (I select these essays by hand). Each page of the laid out essay features an image paired with one paragraph.

I'm not totally satisfied with the results. I would have liked the essays to be a little more interesting. At this point, they are more or less just a random set of random sentences that happen to focus on the same general topic. The essays are not random enough to be funny, but they don't make enough sense to be interesting for other reasons. I might be able to it more interesting by increasing the dataset or by having some sort of logical decision making in the code to focus the sentences a little more.

 
 

var lines = [], markov, data = [], x = 160, y = 240;
 
var paragraphs = [];
 
var essay;
 
class Paragraph {
    constructor(title, text) {
        this.title = title;
        this.text = text;
    }
}
 
function preload() {
    var essayNum = int(random(4));
    switch(essayNum) {
    case 0 :
        essay = "Stuff";
        data[0] = loadStrings('src/Essays/stuff_delgado.txt');
        data[1] = loadStrings('src/Essays/stuff_vzhou.txt');
        data[2] = loadStrings('src/Essays/stuff_carpenter.txt');
        break;
    case 1 :
        essay = "Nature";
        data[0] = loadStrings('src/Essays/nature_delgado.txt');
        data[1] = loadStrings('src/Essays/nature_fang.txt');
        data[2] = loadStrings('src/Essays/nature_carpenter.txt');
        break;
    case 2 :
        essay = "Neighborhood";
        data[0] = loadStrings('src/Essays/neighborhood_carpenter_fan_zhang.txt');
        data[1] = loadStrings('src/Essays/neighborhood_cho_fang_nishizaki.txt');
        //data[2] = loadStrings('src/Essays/stuff_carpenter.txt');
        break;
    default :
        essay = "Trash";
        data[0] = loadStrings('src/Essays/trash_delgado_powell.txt');
        data[1] = loadStrings('src/Essays/trash_choe_fang.txt');
        data[2] = loadStrings('src/Essays/trash_carpenter_ezhou.txt');
        break;
 
    }
}
 
function setup() {
    createCanvas(500, 3500);
    textFont('times', 16);
    textAlign(LEFT);
 
    lines = ["click to (re)generate!"];
 
    // create a markov model w' n=4
    markov = new RiMarkov(3);
 
    // load text into the model
 
    for(var i = 0; i < data.length; i++) {
        markov.loadText(data[i].join(' '));
    }
 
    drawText();
}
 
function drawText() {
    background(250);
 
    if(lines.length <= 1) {
        text(lines.join(' '), x, y, 400, 400);
    }
 
    for(var i = 0; i < lines.length; i++) {
        var line = [lines[i]];
        text(line.join(' '), x, y + (i * 410), 400, 400 + (i * 410));
    }
}
 
function keyTyped() {
    if(key === ' ') {
        x = y = 50;
        var essayLength = int(random(75, 100));//int(random(4, 9));
        var fullEssay = markov.generateSentences(essayLength);
        for(var i = 0; i < int(essayLength / 10); i++) {
            lines[i] = "";
            if((i + 1) * 10 > essayLength) {
                for(var j = i * 10; j < essayLength; j++) {
                    lines[i] = lines[i].concat(' ', fullEssay[j]);
                }
            } else {
                lines[i] = "";
                for(var j = i * 10; j < (i + 1) * 10; j++) {
                    lines[i] = lines[i].concat(' ', fullEssay[j]);
                }
            }
        }
 
        var newParagraph = new Paragraph(essay, lines);
        paragraphs[0] = newParagraph;
        drawText();
 
        var output = {};
        output.paragraphs = paragraphs;
        createButton('SAVE PARAGRAPHS')
            .position(450, 3450)
            .mousePressed(function() {
                saveJSON(output, 'essay.json');
            });
    }
}

 

 

#include "../../bundle/basil.js";
 
var numPages;
 
var neighborNums = [48, 40, 33];
var neighborNames = ["carpenter_fan_zhang", "cho_fang_nishizaki", "gersing_kim_powell"];
 
var natureNums = [5, 13, 6, 6, 5];
var natureNames = ["carpenter", "delgado", "fang", "powell", "zhai"];
 
var stuffNums = [8, 9, 2, 8, 19, 7];
var stuffNames = ["carpenter", "delgado", "fang", "powell", "vzhou", "zhai"];
 
var trashNums = [13, 12, 15, 6, 5];
var trashNames = ["carpenter_ezhou", "choe_fang", "choi_zhai", "delgado_powell", "zhai_vzhou"];
 
var usedImages = [];
 
function setup() {
	var jsonString2 = b.loadString("neighborhood/essay (18).json");
	var jsonString1 = b.loadString("stuff/essay (44).json");
 
	b.clear (b.doc());
 
	var jsonData1 = b.JSON.decode( jsonString1 );
	var paragraphs1 = jsonData1.paragraphs;
	var jsonData2 = b.JSON.decode( jsonString2 );
	var paragraphs2 = jsonData2.paragraphs;
	b.println("paragraphs: " + paragraphs1.length + "+" + paragraphs2.length);
 
	var inch = 72;
 
	var titleW = inch * 5.0;
	var titleH = inch * 0.5;
	var titleX = (b.width / 2) - (titleW / 2);
	var titleY = inch;
 
	var paragraphX = inch / 2.0;
	var paragraphY = (b.height / 2.0) + (inch * 1.5);
	var paragraphW = b.width - inch;
	var paragraphH = (b.height / 2.0) - (inch * 2.0);
 
	var imageX = inch / 2.0;
	var imageY = inch / 2.0;
	var imageW = b.width - (inch);
	var imageH = (b.height * 0.5) + inch;
 
	numPages = 0;
	usedImages.push("");
 
 
	//first page of book
	//newPage();
	numPages++;
 
	b.fill(0);
	b.textSize(52);
	b.textFont("Archivo Black", "Regular");
	b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
	b.text("Plagiarizing:", inch / 2.0, b.height / 2.0 - inch, b.width - inch, inch);
 
	b.fill(0);
	b.textSize(20);
	b.textFont("Archivo", "Bold");
	b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
	b.text("A reinterpretation of other people's photo-essays from Placing", inch / 2.0, b.height / 2.0, 
		b.width - inch, inch);
 
 
	//introduce first essay
	newPage();
	b.fill(0);
	b.textSize(36);
	b.textFont("Archivo Black", "Regular");
	b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
	b.text(paragraphs1[0].title + "ing", inch / 2.0, b.height - inch * 2, 
		b.width - inch, inch);
 
	b.noStroke();
	var coverImageName = imageName(paragraphs1[0].title);
	var coverImage = b.image(coverImageName, inch / 2.0, 
		inch  / 2.0, b.width - inch, (b.height / 2.0) + (2 * inch));
	coverImage.fit(FitOptions.PROPORTIONALLY);
 
	for(var i = 0; i &lt; paragraphs1[0].text.length; i++) {
		newPage();
		b.fill(0);
		b.textSize(12);
		b.textFont("Archivo", "Regular");
		b.textAlign(Justification.LEFT_ALIGN, VerticalJustification.TOP_ALIGN);
		b.text("\t" + paragraphs1[0].text[i].substring(1), paragraphX, paragraphY, 
			paragraphW, paragraphH);
 
		b.noStroke();
		var imgName = imageName(paragraphs1[0].title);
		var img = b.image(imgName, imageX, imageY, imageW, imageH);
		img.fit(FitOptions.PROPORTIONALLY);
	};
 
	if(numPages % 2 == 0) {
		newPage();
	}
 
	//Second Photo Essay
	newPage();
	b.fill(0);
	b.textSize(36);
	b.textFont("Archivo Black", "Regular");
	b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
	b.text(paragraphs2[0].title + "ing", inch / 2.0, b.height - inch * 2, 
		b.width - inch, inch);
 
	usedImages = [""];
 
	b.noStroke();
	coverImageName = imageName(paragraphs2[0].title);
	coverImage = b.image(coverImageName, inch / 2.0, inch  / 2.0, b.width - inch, 
		(b.height / 2.0) + (2 * inch));
	coverImage.fit(FitOptions.PROPORTIONALLY);
 
	for(var i = 0; i &lt; paragraphs2[0].text.length; i++) {
		newPage();
		b.fill(0);
		b.textSize(12);
		b.textFont("Archivo", "Regular");
		b.textAlign(Justification.LEFT_ALIGN, VerticalJustification.TOP_ALIGN);
		b.text("\t" + paragraphs2[0].text[i].substring(1), paragraphX, paragraphY, 
			paragraphW, paragraphH);
 
		b.noStroke();
		var imgName = imageName(paragraphs2[0].title);
		var img = b.image(imgName, imageX, imageY, imageW, imageH);
		img.fit(FitOptions.PROPORTIONALLY);
	};
 
	//give credit to original authors and photographs
	newPage();
	b.fill(0);
	b.textSize(14);
	b.textFont("Archivo", "Bold");
	b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
	b.text(paragraphs1[0].title + "ing", inch / 2.0, (b.height / 2.0) - (inch * 1.5), 
		b.width - inch, inch / 2.0);
 
	var authors = generateCredits(paragraphs1[0].title);
 
	b.textSize(12);
	b.textFont("Archivo", "Regular");
	b.textAlign(Justification.LEFT_ALIGN, VerticalJustification.TOP_ALIGN);
	b.text("Original text and photos by:", inch / 2.0, (b.height / 2.0) - inch, 
		b.width - inch, 14.4);
	b.text(authors.join(", "), inch, (b.height / 2.0) - inch + 14.4, 
		b.width - (inch * 1.5), inch - 14.4);
 
 
	b.textSize(14);
	b.textFont("Archivo", "Bold");
	b.textAlign(Justification.CENTER_ALIGN, VerticalJustification.CENTER_ALIGN);
	b.text(paragraphs2[0].title + "ing", inch / 2.0, (b.height / 2.0), 
		b.width - inch, inch / 2.0);
 
	authors = generateCredits(paragraphs2[0].title);
 
	b.textSize(12);
	b.textFont("Archivo", "Regular");
	b.textAlign(Justification.LEFT_ALIGN, VerticalJustification.TOP_ALIGN);
	b.text("Original text and photos by:", inch / 2.0, 
		(b.height / 2.0) + (inch * 0.5), b.width - inch, 14.4);
	b.text(authors.join(", "), inch, (b.height / 2.0) + (inch * 0.5) + 14.4, 
		b.width - (inch * 1.5), inch - 14.4);
 
	if(numPages % 2 != 0) {
		newPage();
	}
}
 
function newPage() {
	b.addPage();
	numPages++;
}
 
function imageName(assignment) {
	var fileName = "";
	while(usedImagesIncludes(fileName)){
		if(assignment == "Neighborhood") {	
			var i = b.floor(b.random(neighborNames.length));
			fileName = neighborNames[i] + b.floor(b.random(neighborNums[i]) + 1);
		} else if(assignment == "Nature") {	
			var i = b.floor(b.random(natureNames.length));
			fileName = natureNames[i] + b.floor(b.random(natureNums[i]) + 1);
		} else if(assignment == "Trash") {	
			var i = b.floor(b.random(trashNames.length));
			fileName = trashNames[i] + b.floor(b.random(trashNums[i]) + 1);
		} else {
			var i = b.floor(b.random(stuffNames.length));
			fileName = stuffNames[i] + b.floor(b.random(stuffNums[i]) + 1);	
		}
	}
	usedImages.push(fileName);
	return "images/" + assignment + "/" + fileName + ".jpg";
}
 
function usedImagesIncludes(fileName) {
	for(var i = 0; i &lt; usedImages.length; i++) {
		if(usedImages[i] == fileName)
			return true;
	}
	return false;
}
 
function generateCredits(assignment) {
	if(assignment == "Neighborhood") {	
		return ["Sebastian Carpenter", "Danny Cho", "Sophia Fan", "Alice Fang", "Margot Gersing",
				"Jenna Kim", "Julia Nishizaki", "Michael Powell", "Jean Zhang"];
	} else if(assignment == "Nature") {	
		return ["Sebastian Carpenter", "Daniela Delgado", "Alice Fang", 
				"Michael Powell", "Sabrina Zhai"];
	} else if(assignment == "Trash") {	
		return ["Sebastian Carpenter", "Eunice Choe", "Julie Choi", "Daniela Delgado", "Alice Fang", 
				"Mimi Jiao", "Michael Powell", "Sabrina Zhai", "Emily Zhou"];
	} else {
		return ["Sebastian Carpenter", "Daniela Delgado", "Michael Powell", 
				"Sabrina Zhai", "Vicky Zhou"];	
	}
}
 
b.go();