No. 002 · puzzles · experiments · growing

Birthday crosswords made of private jokes

Five arrow-word grids for Lo's birthday, built from 157 words only his friends would get. Notes from writing my own generator, and why every grid still had to be rewritten by hand.

13 min read
grids
5
own words
157
filler words
~62,000
grid shapes
7,358
code
~13.6k lines
print
A5 booklet
the booklet, open at grids three and four. Illustrative mockup.
Fig. 01 · the booklet, open at grids three and four. Illustrative mockup.

It was Lo’s birthday, and he loves solving puzzles. So I thought: why not make him a crossword of his own, full of private jokes and the names of people we know?

I assumed it would be easy. I remembered seeing plenty of crossword generators online, the kind where you type a few words and get a grid back. Little did I know. What I wanted was not a crossword, not everything about it can be automated, and the part that can’t turned out to be the fun part.

Arrow words are not crosswords

The puzzle Lo solves is the mots fléchés, the arrow-word grid. There is no numbered list of clues beside it. Each clue is written inside a cell of the grid itself, with a small arrow pointing to where the answer goes. It is the common format in French-speaking countries, much less so in the United States, and that is why I found so little written about how to generate one.

Part of an arrow-word grid. Clue cells point to the words BOUGIE and FÊTE, and a highlighted clue points down to the two letters L and O.

Fig. 02 · How an arrow word works. The clue sits in a cell and points at its answer.

Why the grid itself is the hard part

I thought the difficulty would be finding words that cross. It is, but there is a problem before that one. In a crossword, the clues sit in a list beside the grid, so the grid only has to hold letters. In an arrow word, every clue takes up a cell, and that cell has to touch the first letter of its word.

That one rule decides most of the shape. Try it:

This sheet can be filled.

Long words have to be broken, and the only tool is another clue cell. Each one costs a letter, has to point at a word, and must not strand the letters around it. 5 more cells, and this sheet can be filled. Now press any cell and watch how fast it stops working.

Words without a clue cell
0
Words over 6 letters
0
Clue cells pointing at nothing
0
Letters left in no word
0

A crossword would spend no cells on clues. This sheet spends 11 of 48.

Three things follow, and each of them cost me an evening to understand.

The margin is not yours. A word that starts against the top or left edge has nowhere to put its clue. So the first row and the first column alternate: clue, letter, clue, letter. Every clue cell there carries two clues and points two ways, often around a corner.

Every clue cell has to earn its place. It costs a letter, it holds two clues at most, and if it points at nothing it is a hole in the page. Placing one to fix a word usually breaks the word next to it.

So you cannot draw a shape and hope. A shape that obeys all of this can still be impossible to fill, because its words are too long or cross too tightly. That is why I stopped inventing shapes and started collecting them from grids that people had already solved.

I did learn a few things along the way. The people who make these grids are called verbicrucistes. The people who solve them are cruciverbistes, which is the word I had been using for both. There are companies whose whole business is producing grids, including a French one that supplies most of the websites offering free puzzles [name it?]. And the really hard grids, the ones with a reputation, are still made by hand.

The format is also having a moment. What gave me the idea in the first place was an Instagram ad for Grillé, a brand started by two women, Louise and Dior, who decided to publish their own booklets. Their clues mix pop references, humour and traps, a long way from the definitions I remembered from my grandparents’ magazines. Their site says they have sold more than 50,000 booklets. One magazine filed them under holiday pastimes.

The Grillé home page: a booklet of arrow words being filled in with a red pencil on a checked tablecloth, beside a Scrabble board, under the headline Les mots fléchés, bons pour le coeur, beaux pour les yeux.
Fig. 03 · The Grillé home page. Screenshot from grille.fr.Full size (opens in a new tab)

So the plan became: the same thing, for an audience of one.

Thirty words is not enough

I started with the dictionary. I built a small tool where I could type a word and a simple definition: a private joke, a nickname, a place, the name of someone we both know.

I ran out at around thirty. That is the first thing nobody tells you. Thirty words feels like a lot when you are writing them down, and it is nowhere near enough. A grid has dozens of slots of very specific lengths, and the words have to cross each other. You need at least a hundred before the grids start to make sense and still feel personal.

Two things got me there.

Asking for more ideas. I fed my list to Claude, ChatGPT and Gemini and asked what else could belong on it. They don’t know Lo, but they are good at noticing what a list implies: if these three words are here, what about the fourth?

Playing other people’s grids. Solving arrow words on puzzle sites gave me shapes, and it gave me material. You can take an existing word with its definition and bend it to your own story. The word stays. The clue becomes about him.

I ended up with 157 words.

Length turned out to matter as much as number. A grid is built mostly from short words, and the things I wanted to say about Lo were rarely two letters long.

A grid is mostly short words.Share of words by number of letters.
  • Slots in the five finished grids (228)
  • My own words (157)

Letters in the word

Show the numbers
LettersSlots in the gridsMy own words
24515
36437
45444
52527
61619
7139
8104
911
1001

Almost half the slots in my finished grids hold a word of two or three letters. Only a third of my own words were that short. So part of the list had to be written for the grid, not for the joke: initials, nicknames, the two letters of a name.

I won’t give the answers here, because they are his. But the clues give the flavour. Dort en soirée: falls asleep at parties. Pour taguer un pote: for tagging a friend. Tournée au pub: a round at the pub. OMG à Liège: what you say instead, in Liège. Each of those is one person, or one evening, that everyone around the table would recognise.

[Add one or two with their answer and the story behind them, if you are happy to share.]

The words that fill the gaps

A grid made only of private jokes is a list, not a puzzle. Most of the words in a real grid are ordinary ones, and they need ordinary clues.

So I loaded existing dictionaries to act as fillers: about 35,000 words that already came with crossword-style definitions, and about 27,000 more from Lexique, a database of French words. My own 157 sit in a separate dictionary that the solver treats differently.

I also needed shapes. Where the clue cells go decides whether a grid can be filled at all, and published grids are designed by people who know that. I collected 7,358 distinct shapes from real grids and kept only the pattern of each one: this cell is a clue, that cell is a letter.

A solver, in one Saturday

Most of the code was written in a single day. I started on a Saturday afternoon and stopped around midnight.

I built it with Claude. I also kept Gemini and ChatGPT open the whole time, not to write code but to challenge the plans I was making. Before each big step I would hand them the plan and ask what was wrong with it. They disagreed with each other often enough to be useful.

The order of operations is simple to describe:

  1. Pick a shape whose slot lengths suit my words.
  2. Place as many of my words as possible.
  3. Fill everything else from the big dictionaries.
  4. Do it again with another shape and another random seed, and keep the best attempt.

The first solver was greedy. It always filled the most constrained slot next, chose the word that left the most options for the slots crossing it, and refused any word that would leave a crossing with nothing to put in it. It never went back on a decision. When it got stuck, it started over.

That got further than I expected, and then it stopped improving. The next few hours were a sequence of small discoveries.

Short attempts beat one long one. Cutting the time budget into two-second attempts and keeping the fullest grid filled 22 slots out of 31, against 18 for a single long run.

Local search does not work here. I tried a finisher that repairs conflicts one at a time. It plateaued at around fifteen broken slots and never converged, however long it ran. I removed it.

My shape scoring was backwards. The score I used to pick a shape turned out to be negatively correlated with how well that shape actually filled. I had been choosing the worst candidates with confidence. After recalibrating it, the generator lands on shapes that fill at 72 to 81 percent.

A real constraint solver changes the result. Late in the evening I tried OR-Tools, Google’s constraint solver, behind a switch. It beat the greedy solver on five shapes out of six. On a real run with my own dictionary it placed 16 of my words where the greedy one had placed 7.

Sixteen private jokes in one grid, instead of seven. That was the number I had been chasing all day.

I ran both solvers again for this article, with the dictionary as it is today. The gap is smaller now that the word list has grown, and it is still there.

Same words, same time limit, two solvers.Each square is one cell of an 11 by 9 grid. Letters are hidden.
  • My words
  • Filler words
  • Clue cells
  • Left empty
  • Blocked

Greedy solver

11 of my words26 of 35 words filled

Constraint solver

15 of my words30 of 35 words filled

An early generated grid. A wide black band runs down the left side and across the top, and only a handful of clue cells are filled in.
Fig. 04 · An early attempt from that Saturday. Every cell the solver could not use became a black block.Full size (opens in a new tab)

Not a single grid survived untouched

Here is what I did not expect. There was not one grid I generated that I didn’t rework by hand.

I deleted words. I added others. And more than anything, I had fun taking a word the solver had placed, a perfectly ordinary one, and writing a new definition for it that was funnier than the one in the dictionary. A filler word with the right clue becomes a private joke too.

As generated, 30 MayThe first birthday grid as the generator produced it: plain grey clue cells, some clue text cut off at the cell edge, no title treatment.
After the second passA finished grid titled Gravé dans la roche, with a portrait in the centre (blurred here), arrows on every clue cell and clues rewritten as private jokes.
Fig. 05 · What the machine gave me, and what I gave Lo after reworking the words and laying the page out in Figma. They are different grids, and the difference is the point.

Across the five finished grids, 68 of the 161 ordinary words carry a clue that is not the dictionary’s. A few were only shortened to fit the cell. Most were rewritten.

  • DÉRAPAGEDictionary clue: Glissade à skisPrinted clue: Micro resté ouvertA skid on skis, turned into a microphone left on.
  • DÉÇUEDictionary clue: Pas satisfaite de ce qu'elle a obtenuPrinted clue: Mais pas étonnéeDisappointed. But not surprised.
  • ATDictionary clue: Symbole chimique de l'astatePrinted clue: Pour taguer un poteThe chemical symbol for astatine, turned into what you type to tag a friend.
  • EXPERTDictionary clue: Référence en la matièrePrinted clue: De MiamiAn authority on the subject, turned into a television series.
  • IADictionary clue: Intelligence artificiellePrinted clue: GPTThe one clue that got shorter.
Five of the rewrites. The word is the dictionary's. The clue is mine.

So the generator was never going to be the product. The editor was.

The editor with a grid in the centre and a slot panel on the right. A yellow box explains that no word fits the pattern, names the three letters imposed by crossing words, and lists two crossing slots as unfillable.
Fig. 06 · The editor, asked why nothing fits. It names the letters that block the word and the crossings that are the real cause. This grid uses public words only.Full size (opens in a new tab)
Most of the evening’s work went into the tools I needed for that second pass:

  • Force a word in, repair around it. Put the word where I want it and let the solver rebuild only the neighbourhood.
  • Lock and re-roll. Keep the words I like and regenerate everything else.
  • See before placing. Hovering a candidate previews it on the grid, with clashes in red.
  • Ask why. When a slot has no candidates, the editor says which crossing is to blame.
  • Split a stuck slot. Turn one impossible long word into two shorter ones by adding a clue cell.
  • Review every clue in one list. All the definitions of a grid on one screen, with the missing ones counted.
The editor with a four letter slot selected. The panel on the right shows its pattern, a field for the clue, a tone selector and one candidate word.
Fig. 07 · A slot with one letter missing, and the only word that fits.Full size (opens in a new tab)

There is also a button that proposes clues in a chosen tone: classic, funny, pop culture, trap, or poetic. It is a good source of first drafts.

One word, five tones

BOUGIE

Elle éclaire sans ampouleIt gives light without a bulb.Elle fond pour ton anniversaireShe melts for your birthday.Elton John en chante une dans le ventElton John sings about one in the wind.Se souffle sans tricherYou can blow it out without cheating. In French, to blow also means to whisper an answer.Petite flamme qui compte les annéesA small flame that counts the years.

These five were written for this article, one in each tone the tool offers. They are not output from the tool.

The ones that made Lo laugh were the ones I rewrote. [True? Or did a generated one land?]

Printing them

An arrow-word grid has to look like one. The clue text has to fit a cell a few millimetres wide, and the arrows have to sit on the edge of the cell, pointing at the right row or column. When a single cell carries two clues, one across and one down, each needs its own band and its own arrow. That took more attempts than the solver did.

The tool’s job ends at the grid. It exports each one as an SVG, a drawing made of shapes and text rather than pixels, so nothing is lost when it changes size. I imported those into Figma and did the final layout there by hand: a title for each grid, the type, and a photo in the middle.

The booklet also got a cover, in the style of the puzzle magazines you find at a newsstand. Limited edition, June 2026, “un moment de pure relaxation”.

The Figma file: a red magazine-style cover titled Mots fléchés, a blank page, and five grids in a row, each with its own title and a blurred portrait in the centre.
Fig. 08 · The whole booklet in Figma: a cover and five grids. Faces are blurred here.Full size (opens in a new tab)

Then I printed it myself, as an A5 booklet. Five grids, small enough to fit in a bag, and the only copy in existence.

[What happened when he got it? Did he solve them, how long did it take, what did he say?]

What I’d tell someone trying this

The dictionary is the gift. The software is a way to arrange it. The hours that mattered were the ones spent remembering things about a friend.

Get to a hundred words before writing any code. Under that, no solver will help you.

Let the machine do the first eighty percent, and keep the rest for yourself. Filling a grid is a search problem. Deciding what is funny is not.

Build the editor, not just the generator. Every grid needed a second pass. The tools for that pass are the ones I used most.

Stop the software where a design tool starts. I did not need my own page layout. Exporting a clean drawing and finishing in Figma was faster, and it looked better.

One for you

This one has no private jokes, so anyone can solve it. It is the small sheet from earlier in the article, filled in, and in English, which almost nobody does with arrow words. Choose a cell and type. Press the same cell again to turn the corner.

Choose a cell to see its clue.