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.