This is a dynamic version (which may be further developed) of a piece first published in Run Run Run (ed. Nick Monfort, New York: Bad Quarto, 2025, p. 8). It loads its minimal text-generating code as its own supply text. In the node.js
version, the JavaScript file itself is loaded locally. At the moment, this version uses a copy of text for the two generating functions of the code module, as displayed here:
John Cayley, July 2025
function saying (whatIAmGenerating) {
const recognitions=[["="," being "],["RegExp","regular expression"],["replace",
"memory"],["[^\\w]"," "],["([A-Z])"," $1"],["const ","constantly "],["function",
"saying"],["match","archive"],["aeiou","breathing"],["split","language"],["floor",
"ground"],["length","extension"],["case","sayable"],["set","horizon"],["Timeout",
"ceasing"],[" +"," "]]
const moving=(qualities,here,there)=> qualities=qualities.replace(new RegExp(here,"g"),there)
function continualMovement(theLifeWorldReading,recognitions) {
for(const reading of recognitions) {
theLifeWorldReading=moving(theLifeWorldReading,reading[0],reading[1])}
return theLifeWorldReading}
function expressing (imagining) {
let writing = []
for (const images of imagining) {
if (images.match(/[aeiou]/)) writing.push(images)}
return writing}
whatIAmGenerating=continualMovement(whatIAmGenerating,recognitions)
whatIAmGenerating=expressing(whatIAmGenerating.split(" "))
return whatIAmGenerating}
function thinkingOfWords (lastWord, nothing, whatIAmGenerating) {
return new Promise((resolve) => {
function overAndOver() {
let thoughts = whatIAmGenerating[Math.floor(Math.random() *
whatIAmGenerating.length)].toLowerCase();
if (thoughts !== lastWord) {
resolve([enclosing(thoughts), thoughts]);
} else {
setTimeout(overAndOver, 0);}}
overAndOver();});}
To experiment with an entirely standalone node.js
version (that represents a slight revision of the piece in Run Run Run) just copy and paste the code below into a file that must be named ‘saying.js’ (because it loads itself as supply text). With node.js
installed on your system, open a terminal, navigate to the folder with the saying.js file, then run with:
> node saying.js
Each execution will generate a number of words proportionate to the length of the preprocessed code.
const theSayable=require('fs')
let whatIAmGenerating=theSayable.readFileSync("saying.js",'utf-8')
let thinking=0,movements="",dwelling=""
const recognitions=[["="," being "],["RegExp",
"regular expression"],["stdout","saying"],["replace",
"replacing"],["write","writing"],["[^\\w]"," "],
["([A-Z])"," $1"],["const ","constantly "],["fs","memory"
],["File","archive"],["aeiou","vowels"],["utf","language"],
["floor","ground"],["length","extension"],[" +"," "]]
const moving=(qualities,here,there)=>
qualities=qualities.replace(new RegExp(here,"g"),there)
function continualMovement(theLifeWorldReading,recognitions){
for(const reading of recognitions){
theLifeWorldReading=moving(theLifeWorldReading,reading[0],reading[1])}
return theLifeWorldReading}
function expressing(imagining){
let writing=[]
for(const images of imagining){
if(images.match(/[aeiou]/))writing.push(images)}
return writing}
whatIAmGenerating=continualMovement(whatIAmGenerating,recognitions)
whatIAmGenerating=expressing(whatIAmGenerating.split(" "))
let horizon=whatIAmGenerating.length
while(thinking++ <horizon){
do{movements=whatIAmGenerating[Math.floor(Math.random()*horizon)]}
while(dwelling==movements)
dwelling=movements
process.stdout.write(movements+" ")}