Concrete Poems
Last updated: Feb 26, 2021
Starting from the example code, I decided I wanted to try making the Frost poem about the two roads diverging in a wood, into a pair of paths, that might mimic the two in the poem. They wander across the page with some random parameters and two different fixed colors, so they may be told apart.
import numpy as np
def interp(p1, p2, n=10):
p1 = np.array(p1)
p2 = np.array(p2)
pts = []
for i in range(n):
pt = (p2 * (i/(n-1))) + (p1 * (1-(i/(n-1))))
pts.append(tuple(pt))
return pts
interp((0, 0), (5, 21), n=5)
import random
import math
from IPython.display import display, HTML
def show_html(src):
return display(HTML(src), metadata=dict(isolated=True))
html_src = """
<body>
<p style="height: 240px; background-image: url(https://i.giphy.com/media/OmK8lulOMQ9XO/giphy-downsized.gif);">Hello!</h1>
</body>
</html>
"""
# show_html(html_src)
html_tmpl = """<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{title}</title>
<style>
html {{ min-height: 50em; overflow: scroll; }}
</style>
</head>
<body>
{content}
</body>
</html>"""
def mkdiv(content, **kwargs):
if 'position' not in kwargs:
kwargs['position'] = 'absolute'
style_str = ' '.join([": ".join((k.replace('_', '-'), v))+";" for k, v in kwargs.items()])
return f"<div style='{style_str}'>{content}</div>"
src = open("frost.txt").read()
divs = []
pts = interp((0, 0), (14,12), n=25)
pts2 = interp((0, 0), (14,12), n=25)
x1 = 14
y1 = 12
x2 = 14
y2 = 12
point1 = (0,0)
point2 = (14,12)
point3 = (0,0)
point4 = (14,12)
for i in range(29):
pts += interp(point1, point2, n=40)
point1 = point2
x1 = random.randrange(x1-16, x1+20)
y1 = random.randrange(y1-20, y1+24)
point2 = (x1, y1)
pts += interp(point2, (200,200), n=len(src))
for i in range(len(src)):
ch = src[i]
pt = pts[i]
this_div = mkdiv(ch,
color="#f5a142",
top=f"{pt[1]}%",
left=f"{pt[0]}%",
font_size="10pt")
divs.append(this_div)
for i in range(29):
pts2 += interp(point3, point4, n=40)
point3 = point4
x2 = random.randrange(x1-12, x1+26)
y2 = random.randrange(y1-14, y1+29)
point4 = (x2, y2)
pts2 += interp(point4, (200,200), n=len(src))
for i in range(len(src)):
ch = src[i]
pt = pts2[i]
this_div = mkdiv(ch,
color="#eb4034",
top=f"{pt[1]}%",
left=f"{pt[0]}%",
font_size="10pt")
divs.append(this_div)
html_src = html_tmpl.format(title="characters along lines", content="".join(divs))
show_html(html_src)
Here are several results of this program:
Over on my 100 Days Project Instagram account, I’ve been doing some work inspired by the concrete poetry we’ve been looking at, but using Three.js, I’m trying to bring a degree of interactivity to the work. The most recent one, I was interested in the stroke and fill properties of the text bitmaps HTML will let you generate, so I put them on separate planes with similar text. On scroll, one moves up and the other down. After starting with a test string, I put in the text “one the other both / not neither nor” because I think it highlights the addition/exception/subtraction the stroke and fill letters are already beginniing to touch on. This is one of my favorites so far.
I also did one that was inspired by the R.P. Draper piece topspin, trying to capture—with the scrollwheel/trackpad—another dimension of the experience of playing tennis. I also gave the text a tennis-ball yellow lighting setup.
This third one is a concretization(?) of a W.B. Yeats poem, The Wheel. Here the scrollwheel allows you to move through the poem, which appears as though written on a set of literal wheels.
I also liked this one, which is almost entirely about form. Here, letters fall when typed by the user. The text is arbitrary and user-controlled, but falls in such a way as to be difficult to read. The three-dimensional letter forms, falling like dead balloons, are almost all that is left.