August 3 2022
I have finally got this subdomain set up to a level I'm happy with. I also spent the hand-coding a friend's poem for an upcoming project. HTML! is! back! babey!~
I want to spend some time this afternoon reading and writing about the work on Reading Machines, a really cool project of web-based creative texts edited by Tiger Dingsun. There are so many interesting pieces on this site but I'll focus on this piece written by Tiger: I Never Believe it Until it Happens Again.
I Never Believe it Until it Happens Again
The poem begins with a prompt to start (through a click, not key-press). Once started, at the top of the screen a single word appears in a large font. The word changes frequently in time with a gentle synth melody. For each word, there is a small phonetic pronunciation provided just below it. This takes up maybe 20% of the vertical screen-space. Below, there is only blank space at first. As a new word appears at the top, a smaller copy of the word appears in this large blank space, flashing. On each synth tone, the placement of the small word on-screen changes. As the poem plays on, this space fills with more of these small words. The poem is organised into numbered sections, and as each new section begins the colour scheme changes.
The stream of words that appears at the top of the screen usually moves quite fast, creating a very immediate experience akin to a stream-of-consciousness style of writing. As I could follow it in this form, the narrator struggles to take action of their life amidst a string of bad luck: loneliness, separation, a hint of a betrayal. The title phrase appears at the beginning and also at the end, where it is accentuated with the refutation 'but it always. happens. again.' The phrase evokes from the speaker a kind of naive denial in the face of their misfortunes (or their mistakes). The sense of overwhelm the speaker feels is emulated both visually – the cluttered whirl of text accruing as the poem progresses – and aurally: the pronunciation guides below each words implies speech, but as I attempted to read aloud at the speed of the poem my reading stumbled over and over.
The text of the piece is of course, viewable in the source code. It appears as a single string in /script.js. While likely a single block for the purposes of the code that renders it on the page, I noticed that some sections frequently use capitalisation without full stops, especially section 3. This suggests to me the poem might have initially been written as a mixture of prose poetry and free verse. Assuming a linebreak at every capitalisation in section 3 would give this poem a very tall, slim shape, with thoughts flowing over lines in a style reminiscent of Eileen Myles.
In trying to get a broad understanding of what is happening at a code level as quickly as possible, I first looked at the rendered page through my browser inspector. The main elements of the piece are contained with a few div elements: in this post and others I'll use CSS selector notation to discuss the divs (# for div ID, . for div classes). I'll use the # symbol to denote the div IDs in this prose. The
#container holds all of the small words, which each have their own divs of class
.word, though there are some empty divs with class
.spacer (I'll get back to those). The other elements of note are container div
#bigwordframe, which contains the
#bigword div for the stream of words and the
#syllables div for the phonetic pronunciation.
As the poem runs, the text content inside of
#syllables is rapidly replaced – hence the stream of 'big words' on the page. The small
.word elements are given what seems to be randomised
animation-delay values as inline CSS. Looking at the
.word class, they are positioned
relative inside their
fixed container and have an animation:
animation: blink 0.5s linear infinite. So the height of each word is randomised, but how is their horizontal placement determined? I suspect the answer is in this block of CSS applied to
display: flex; flex-wrap: wrap; justify-content: space-between; align-items: flex-start; align-content: space-between; overflow: auto; word-break: break-all; word-wrap: break-word;
Without going into too much detail,
#container is a flexbox allowing its nested divs to be aligned according to the number of elements and the amount of space available. Once a threshold of words are placed – not sure how this happens, padding I assume? – the
overflow property kicks in and words begin appearing on a 'new line', for want of a better phrase. One neat benefit of this vs manually setting a randomised
left value for horizontal placement (in the way that
top is used for vertical placement) is that this allows the poem to function on multiple screen sizes without having any words appear off-screen, as far as I can tell. Neat!
Looking at the page source, I see Tiger is using jquery and a library called Tone.js, the latter controlling the audio elements of the piece. I'm less interested in unpacking exactly how Tone.js works in this piece, but at a high level I see a polysynth is declared near the beginning of the program and new notes are played each time the
displayWord function runs via the synth.triggerAttackRelease method. In Tiger's piece this method is selecting a note at random from an array of semitone intervals defined in the program. What's cool to me is there is a switch statement with a case to run at the start of each new numbered section in the poem – when this happens, a new range of semitone intervals is declared for the program to pick from. Thus, as the poem moves through the sections, the variety of notes played increases, adding additional sonic complexity that mirrors the increasing sense of overwhelm throughout the piece.
Tiger uses the split() method twice: first to split the single string that contains the text of the piece into individual words to be fed into the divs at some point during the
displayWord function, and again to split the phonemes of a word to insert into the
#syllables div. Tiger uses a language processing library called RiTa here, calling the RiTa.syllables() method to get the phonemes for each word. I have made use of the
split() method in many of my interactive web poems and I suspect it is likely a favourite for poet-coders working with words in the browser!
One final element I wanted to make note of stems from a question I had while reading the piece: what is the time interval for the changing of words? At times it feels very regular, but then there are some strange pauses throughout that I couldn't quite build a sense of familiarity with. Turns out, the length of time each word appears in the
#bigword div is decided by multiplying the number of syllables in the word by a set
var time = syllables_arr.length * speed. This is really clever to me as it means more verbose, and therefore more complex words, are likely to appear on screen for longer than the shorter words. In addition to this, an extra conditional statement is set up to run if the word ends in a full stop or question mark, in which case the time is set to a cool 1000 milliseconds. One of the great strengths of this piece is its sense of rhythm and musicality, established most obviously through the synth tones but reiterated subtly through the connection between syllable length and screen-time. It almost feels like a unvocalised slam poem, with a timing set to roughly mirror the speed at which the piece might be spoken aloud.
To wrap up, here are some key insights this analysis has given me about creative applications of HTML, CSS, JS:
- CSS flexbox is a valuable positioning system for semi-responsive poetry design
- If using the same CSS animation across many elements, randomising the
animation-delayvalues for each element can create a sense of chaos and dynamism
switchstatements can help group sets of changes (sound, colour, style) based on key inputs/conditions
- Connecting parameters within your poem to one another (e.g. syllable length, function speed, interval range, etc) might contribute to an implicit sense of harmony and cohesiveness to the reading experience - this needs more discussion/investigation...
Reflecting briefly on the length, structure and content of this analysis, I think if I was doing this more formally I'd need to condense it heaps. I'd also want to make more explicit the connections between what is happening at a code level, what effect that has on what plays out in the browser, and then ultimately what effect that has on what plays out in the mind of the reader. Code->Poem->Reading? Hmm.