This is a dynamic version (which may be further developed) of a piece first published in Run Run Run (ed. Nick Montfort, 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+" ")}