Concept & Inspiration
Concept: “Neon Truchet Tapestry” is an interactive, audio-reactive simulation that merges the logic of a Cyclic Cellular Automaton (CCA) with the geometric aesthetics of Truchet tiles. Instead of traditional grid cells shifting colors, the cell states dictate the rotation angles of glowing line segments. The grid is heavily influenced by live audio input: microphone volume dictates the system’s “entropy” (randomizing cells) and stroke weight, while the spectral centroid (pitch/treble) drives the maximum number of allowable states, shattering the geometry into more complex patterns as the sound changes.
Inspiration: The primary inspiration for this piece stems from the desire to visualize sound through structured geometric evolution. I drew inspiration from classical cyclic cellular automata models (where adjacent states “consume” each other in a toroidal loop) and combined it with cymatics—the visual representation of sound frequencies. Using rotational tiling patterns creates a tapestry-like effect that feels both highly structured and uniquely chaotic when disturbed by noise.
Code Highlight
I am particularly proud of the dynamic state sanitation logic required to bridge the audio analysis with the cellular automaton ruleset. Because the spectral centroid of the audio constantly changes the maxStates variable, the grid can easily break if existing cells are left with state values that suddenly exceed the new maximum.
I spent hours debugging frozen arrays before writing this fail-safe loop, which ensures seamless mathematical wrapping:
// louder = more chaos/entropy in the grid
let entropyChance = map(smoothedVol, 0.01, 0.3, 0.0, 0.5);
entropyChance = constrain(entropyChance, 0, 0.8);
// more treble = more cell states = more complex patterns
let targetStates = floor(map(spectralCentroid, 0, 4000, 4, 10));
maxStates = constrain(targetStates, 4, 10);
// IMPORTANT: sanitize the whole grid after changing maxStates
// if we dont do this, cells can have values >= maxStates which
// breaks the CA logic downstream. spent like 2 hours debuging this :(
for (let x = 0; x < cols; x++) {
for (let y = 0; y < rows; y++) {
if (grid[x][y] >= maxStates) {
grid[x][y] = grid[x][y] % maxStates; // wrap it back into range
}
}
}
Embedded Sketch [please open in Web Editor and give mic permissions]
Milestones and Challenges
The process involved bridging traditional grid rendering with dynamic geometry. Here are two major milestones from the development process that you can run to grab screenshots for your documentation.
Milestone 1: Establishing the Base Cyclic Automaton
The first challenge was getting the cyclic cellular automaton logic to function properly on a toroidal grid (wrapping around the edges) before adding any audio or line drawing. This proved that the neighbor-counting and state-advancing math worked.

Milestone 2: Converting States to Rotation (The Truchet Effect)
The second major milestone was moving away from filled rectangles and mapping the cell states to rotation angles. The challenge here was using push() and pop() properly alongside translate() to ensure each line rotated accurately around its own center without breaking the rest of the canvas.

Reflection and Future Work
Combining real-time user data (audio) with a rigid cellular automaton ruleset yielded highly satisfying results. Standard cellular automata can often fall into stagnant loops, but mapping volume to a random entropy variable continuously breathes life back into the canvas, keeping the visual output dynamic and engaging.
Future Improvements:
-
Interactive Mouse Brushes: Adding a feature where clicking and dragging across the canvas forces cells into a specific state, giving users manual, tactile control over the pattern generation alongside the audio.
-
GUI Integration: Utilizing a library like dat.gui to create on-screen sliders so users can manually tweak the neighbor threshold, resolution (res), or fade alpha, experimenting with how the parameters impact the visual outcome in real-time.
-
3D WebGL Implementation: Transitioning the 2D rotating lines into 3D rotating planes or cubes to give the geometry depth and explore the automata logic on a z-axis.