This project started with a simple yet poetic idea , visualizing lines from old Urdu poetry on screen, placing the main verse at the center and surrounding it with words from the next line, like floating thoughts. But then I began replacing those with some of my favorite Urdu song lyrics , the kind I really connect with , trying to merge different verses across songs to create something emotionally layered. That’s when I was reminded of Antakshari, a fun game many of us grew up playing. The rules are simple: one person sings a song, and the next person has to sing another song that starts with the last letter of the previous one. I loved the idea of using that structure as the basis for generative text. I initially wanted to build this fully in Urdu, but I realized it would be tricky to detect and match the last letter accurately in the script. So, I switched to English to get the logic working smoothly. Instead of full lyrics, I used individual words and for each word, the next one is chosen randomly from a list of possible options starting with the last letter. That means each run of the program generates a unique chain of words, but with a meaningful constraint just like Antakshari. I also added visual flair: a short delay between words, small random rotations and scaling for different text sizes so it wouldn’t look like a grid structure and feel a little unpredictable.
The two functions placeWord() and pickNextWord() were the heart of my sketch. I was particularly proud of how I used my prior knowledge of dictionaries to implement the words dictionary, which acts as a lookup system. It takes the last letter of the previous word and finds a list of possible next words starting with that letter. Then I randomly select one to create branching possibilities making the output different every time.
In placeWord(), I figured out how to make each word feel organic and unique by adding randomness to its angle and size using random(-PI/16, PI/16) and a scaling factor. I also calculated the text width dynamically so I could position the next word without overlap between words. These choices made the flow of words appear natural.
function placeWord(word) { let fontOriginalSize = 24; let wordMargin = 8; let angle = random(-PI / 16, PI / 16); let scaleFactor = random(0.9, 1.3); //find color from colormap let firstLetter = word.charAt(0).toLowerCase(); let wordColor = colorMap[firstLetter]; textSize(fontOriginalSize * scaleFactor); let wordWidth = textWidth(word); placedWords.push({ word: word, x: gridX, y: gridY + random(-3, 3), size: fontOriginalSize * scaleFactor, angle: angle, color: wordColor }); //move the horizontal position to right for next word gridX += wordWidth + wordMargin; //starts a new line/row if (gridX > width - 100) { gridX = 50; gridY += gridSpacing; } //canvas not filled checked by seeing if we reach bottom or not if (autoRun && gridY < height - 50) { pickNextWord(); lastPlacedWord = nextWord; setTimeout(() => placeWord(nextWord), 150); } } function pickNextWord() { let lastLetter = lastPlacedWord.charAt(lastPlacedWord.length - 1).toLowerCase(); //find the candidate words using lastletter and choose a random word let candidates = words[lastLetter]; nextWord = random(candidates); }
Here’s the sketch:
Eventually, I’d love to go back to my original vision and bring Urdu fully into the experience. That would mean figuring out last-letter detection in Urdu script and possibly integrating a calligraphic font to preserve the beauty of the language. If I can pull that off, the result would be a truly generative, Urdu Antakshari as a perfect blend of nostalgia, music, and generative text.