A Message Drifts
This series continues my explorations of the ways meaning can emerge from randomness. Each image is created using algorithmic systems that create the elements. There is an alphabet of symbols, a message generator and several approaches to glitch aesthetics. The result could be meaningful, or could be nonsense.
This article unpacks the components of the system: how the symbols are placed and distorted, how the sentences are constructed, and how variation is managed across the 3001 outputs. It also explores the underlying questions of what happens when randomness is shaped into something that feels like a message and how building these systems could enable meaning to reach us.
A Message Drifts test output
A Message Drifts test output
A Message Drifts test output
A Message Drifts test output
Symbolic
A Message Drifts began with the idea of a grid of symbols. Here are a couple of the very first ‘Work In Progress’ outputs I created when I started the project.
Early work in progress
Early work in progress
The final piece has an “alphabet” of 16 symbol options.
Symbol alphabet
Each of the symbols is defined by a short function that lays out its basic points and offers some level of variety within the way it is produced. For example, the next image contains different variations of the same symbol.
Variety within symbols
After creating the basic paths, I run them through a class I created called NaturalLine. I have been using this same class in different projects for a while. It adds extra points in to a path and jitters them using Perlin Noise, creating a more nuanced and natural effect.
In the images below you can see a close up of these natural lines, compared to a version where I simply drew the original input paths. It’s a subtle difference but makes the whole image seem more organic.
Natural lines
Original inputs
Most of the symbols are positioned on an angle, which is defined by a Perlin Noise field. This creates a cohesive flow over the image.
In the first image below you can see the effects of this flow field, while in the second you can see how it would look if the symbols were angled randomly. I didn’t include the option for random angling in the final piece because I felt the momentum created in the aligned image better matched my ideas for the project.
Symbols positioned on angles defined by flow field
Symbols positioned on random angles
One of the symbols in the first image below is particularly effective with the flow field effect, as the symbol is larger and extends out of its grid cell location. The symbols shown in the second image below are not affected by angles, and always appear upright.
Symbols positioned on angles defined by flow field
Upright symbols
There are four symbols which always appear aligned horizontally or vertically, but which can be extended beyond their grid cell location: a rectangle, a sin wave, a triangle wave (zig zag) and a square wave. The waves are always extended out across a few cell locations, while the rectangle can either extend or sit within one cell as a square.
Square / rectangle symbol
Sin wave symbol
Triangle wave symbol
Square wave symbol
Each image has a different distribution of symbols. In some outputs, each symbol in the alphabet is given a likelihood of being chosen. The likelihood for any given symbol could be zero, so each output has a different selection of symbols with different distributions. There are also some outputs which use a curated selection of symbols.
In the first image below, there are only two symbol types while the second image has many different symbols.
A Message Drifts test output
A Message Drifts test output
Grid
The symbols are arranged in a grid, which can have margins of different sizes and types. In the example images below, I’ve turned off some additional features so the grid edges appear more clearly.
No margin
Solid margin
Margin is solid at the top and uneven at the bottom
Margin is uneven at top and bottom
Symbols can also be jittered away from their original positions, using a Perlin Noise field, in a few different ways. Here’s a direct comparison using the same seed (again, with some other features turned off)
No position adjustment
Gentle
Mixed chaos
Smooth chaos
Scattered positions
Glow
You might have noticed that everything in the images is glowing! The library I’m using in JavaScript (p5js) has a built in blur filter feature, but it is extremely slow and doesn’t offer a lot of control over the results.
Instead of using that, I create the glow by drawing extra iterations of the content at a lower opacity. Every line or shape is drawn multiple extra times at slightly larger sizes than the original, with lower and lower opacity at the larger sizes.
The first image below is an unedited close up of an output. In the second image, to visualise what’s going on, I adjusted the glow effect so instead of 20 extra versions of each symbol, there are only 4 and they appear clearly.
Glow close up
Adjusted glow close up
Messages
Vitally, each image in the series contains a short message.
These sentences are generated, not using AI, but with an algorithm I wrote. The algorithm first selects a sentence template, from a set of about 40 possibilities. Here are a few examples.
[
["nouns", " are ", "adj", " and ", "adj"],
["nouns", " are ", "adj", " and ", "adverb", " ", "adj"],
["noun", " is ", "adj", " and ", "adverb", " ", "adj"],
["nouns", " ", "verb_plur_prep", " ", "nouns"],
["nouns", " ", "adverb", " ", "verb_plur_prep", " ", "nouns"],
["There is ", "noun", " in ", "adj", " ", "noun"],
];
The algorithm then populates the sentence with the appropriate parts of speech, chosen randomly from my curated word lists. As the words are added, various grammatical rules are applied so that the sentence flows correctly.
(The following outputs have been cropped to focus on the sentence)
Sentence with a preposition
Prepositions
This image’s sentence is formed using the following structure:
["nouns", " ", "verb_plur_prep", " ", "nouns"]
The verb list contains words like “see”, “analyse” and “think”.
Some of these words could slot into the sentence by themselves. For example: “Molecules see phenomena” or “Molecules analyse phenomena”. But we can’t really say “Molecules think phenomena”.
Some verbs are linked with a preposition from this list
this.preps = [
"", "with", "into", "in", "to",
"for", "about", "on", "from", "as",
"by", "through", "towards", "onto",
"at", "within", "of", "between",
"across", "among", "over", "like"
]
“Molecules think phenomena” then becomes “Molecules think about phenomena”.
Conjugated verb
Single and plural nouns
Words in the noun list come with information on how to handle their pluralisation.
Most nouns can be used as plural or singles. Single nouns have information about what article should be used, for example “A memory”, “The void”, or simply “time”.
Some nouns cannot be pluralised, for example “weather”, “balance” and “faith”.
Verbs are also conjugated into two separate lists, to work with singular or plural nouns. For example we’d say “A memory conceals…” but “Memories conceal…”
Sentence with an adverb
Adverbs
I recently added adverbs to my grammar algorithms, opening up a new set of sentence structures.
All of my adjectives, e.g. “phenomenological”, “anecdotal”, “cryptic” now come with information on how to turn them into adverbs. I.e. some need “-ly” added, some it’s “-ally” and so on.
This means I can now not only describe nouns as cryptic, but also describe actions as being done cryptically.
If you’d like to read more about how I generate sentences, I have a whole article about it here.
Handwriting
Perhaps you’ve noticed that the messages look handwritten. I coded a version of my handwriting which I’ve used in several projects now.
I started by defining just a few points for each letter’s paths, and including a 2-3 options for each letter. I based these paths on my own handwriting.
Here’s how a message looks with just the initial points that define each letter.
Initial letter points
Next, the letter paths are curved, using Chaikin’s curve algorithm, and joined together, so they look like this:
Letters curved and joined into words
Lastly, the word paths are turned into shapes, so they can be given different weights along the path. The paths are slightly thicker towards the bottom of the letters. The paths are also tilted, for an italic effect, and the glow is added.
“Handwritten” text
If you’re interesting in more on this topic, I have two articles which go into more depth about how I coded my handwriting.
The first article is about my initial implementation, in which I had individual letters rather than joined up or cursive writing, but it does go into detail about Chaikin’s curve algorithm and turning the paths into shapes.
In the second article I go into detail about how I coded my own handwriting, including joining the letters together into natural paths.
Glitching out (features)
At this point, we have created a grid of glowing symbols and a mysterious message. WIth just this, here’s how the outputs would be looking:
Image with no additional features
Image with no additional features
To develop the project further, I incorporated glitch aesthetics.
Repetition
The gridded symbols can be duplicated. There are different methods for the positioning of the duplicates. Here are some examples:
“Long” - lines in horizontal and vertical directions
“All directions” - horizontal, vertical and diagonal lines
“Smudge” - shorter lines with symbols closer together
“Up and down” - positions jittered along the lines
“Wander” - smooth wandering waves
“On the spot” - smattered around the original location
Stretch
Symbols can be stretched horizontally, vertically or radially. The lines created as they are stretched can be manipulated in different ways.
Here are some examples.
Radial - no jitter
Vertical - gentle jitter
Horizontal - mega jitter
Vertical - small jitter
Radial - tiny jitter
Vertical - wide smooth jitter
Passing Lines
Additional flowing or jagged lines can be added to the image, passing through the grid. These are adapted from an element I have used before, in my project Tiny Endless Things.
There are several different aesthetics available for these lines, here are some examples:
jaggy
light
many squiggles
messy
small
smooth
swoop
Every output has at least one of the features - repetition, stretching or additional lines. Many have two of them, repetition and stretching, or repetition and lines. Stretching and the additional lines cannot be combined as stretching the symbols also creates lines of a sort, and so combining them created clashes.
Repetition and lines
Repetition and stretching
Large symbols
An additional subtle feature is the chance for symbols to be enlarged. Around 1in 10 outputs have this possibility turned on, but only certain symbols can be enlarged.
Output with enlarged symbols
Output with enlarged symbols
Option Management
I have a couple of functions I use to make choices from sets of options. One returns a choice completely at random and one returns a choice with different weightings of likelihood taken into account.
// equal choice
function ecx(options){
return options[int(rand(options.length))];
}
// weighted choice
function wcx(options) {
let opt = [];
for (let o of options){
for (let i = 0; i < o[1]; i++){
opt.push(o[0]);
}
}
return opt[int(rand(opt.length))];
}
The equal weighting option chooser is simply passed an array of options, while the weighted option chooser is passed an array that contains inner arrays which contain the option and a number to define how each option should be weighted.
For example, here is the options array for the functions:
sx.features = wcx([[["repeat"], 2], [["stretch"], 2], [["lines"], 1], [["repeat", "stretch"], 9], [["repeat", "lines"], 5]])
Given 1900 outputs the options would be distributed roughly like so:
200 repeat only
200 stretch only
100 lines only
900 repeat and stretch
500 repeat and lines
Where options affect each other, I tend to set them up in groups. For example, here are three of the six options for the way repeated symbols can be laid out.
op.repeatOptions = [
[{
name: "on the spot",
on: true,
glitchChance: 0.12,
glitchDistances: [3, 1],
directions: [1, 0],
jitter: 30,
alpha: {
start: 60,
end: 20
},
numRepeats: () => {
return rand(10, 19);
}
},1],
[{
name: "smudge",
on: true,
glitchChance: 0.1,
glitchDistances: [3, 8],
directions: [1, 0],
alpha: {
start: 60,
end: 10
},
numRepeats: () => {
return rand(20, 60);
}
}, 2],
[{
name: "wander",
on: true,
glitchChance: 0.1,
glitchDistances: [15],
directions: ecx([[1, 0], [0], [1]]),
noise: {
res: 0.003,
dist: 100
},
alpha: {
start: 60,
end: 0
},
numRepeats: () => {
return rand(20, 50);
}
}, 1],
]
It would be possible to randomly generate values for each of these settings individually (glitchChance, glitchDistances, directions) etc. But by grouping them together, I create notably different sets of outcomes and ensure that the combinations always work together.
As an example - in an output where repeats are done using the “smudge” settings, each symbol will be repeated between 20 and 60 times, while an output with “on the spot” settings will repeat each symbol between 10 and 19 times.
This level of control is important. For example, when repeating symbols “on the spot”, it can become blocky if they are repeated as many as 60 times, but if the “smudge” option repeated symbols only up to 19 times, we don’t get nice long trails of smudgy repeats.
“on the spot” with too many repeats
“smudge” with too few repeats
There are also some layers of additional randomness within the options. For example, in the “wander” option, the direction of the repeats can be horizontal [0], vertically [1], or both [0, 1]. The choice of available directions is made once for the whole image and then each symbol that is repeated then makes a choice from those options, therefore either all going horizontally, all vertically or some of each.
There is also variety within the images - for example, every symbol that is repeated calls the function for numRepeats individually, so each set of repeat is different.
Collisions
As in many of my projects, there is a system for managing collisions between elements. First of all, symbols need to give way so that the messages can be read. Additionally, due to the way symbols are moved from their original gridded positions, stretched, repeated and enlarged, they can collide with each other. Some of these collisions are desired but not all.
There are several different settings for the amount of collisions allowed, which also vary depending on the element type (e.g. repeated and stretched items are generally allowed more collisions than originals) and the grid size. Some outputs also naturally have more collisions than others due to the grid layout, symbol types and features.
None
Spaced
Mid
Many
I explored several different ways of clearing space for the text, including removing entire symbols, moving them away from the text, fading their opacity and cutting away parts of the symbol.
In the end I settled on a combination of the latter two methods.
Symbols making way for text
If symbols did not make way for text
In the live code outputs, it’s possible to hit the “a” key to see all elements including those which have been removed (although it does not replace points which have been cut away from the text), and to hit "d” for debug mode, which illustrates the locations of the collision detection points.
In debug mode, most collision points appear in green, while the points for elements which have been removed appear in red and those which have areas cut away for the text appear in yellow.
Output
All elements
Debug mode
Palettes
Here are the 20 palettes available!
Colours can be laid out in three ways
Random colour layout
Perlin noise colour layout
Gradient colour layout
Concept
Ideally, these images appear as if they are transmissions, arriving from somewhere. The question of authorship runs through all generative work - as generative artists we relinquish control to the systems we have created and to randomness. In this piece in particular, I hope that question is near to the surface. The combination of organic aesthetics like the handwriting and digital aesthetics like the glitch, glow and repetition point to this mystery. Where did these communications originate from - myself as the artist, the system I created, or something else?
You know that the words are chosen at random and there is no logical reason they should say anything significant. Yet the messages are suggestive of meaning and, if you choose to interpret them with sincerity, then value can be found.
We exist in a universe where we are frequently left to our own interpretations of meaning, without any intrinsic or prescribed purpose. I find randomness to create an abundant supply of suggested meaning, of hints and signs and clues which we can construe as we wish. I believe strongly that using systems to generate random “nonsense” can create a surface on which to find things that resonate and mean something to us. More quietly, I question, if the universe was to directly send a message, might it use a system such as this?
A Message Drifts test output
A Message Drifts test output