What went into a themed crossword generator from idea to working app
I got hooked on crossword apps on my phone, but kept running into the same issues: recycled clues, vague hints, and answers that felt like a stretch just to avoid repeating a previous puzzle. There's no way to pick a topic you're actually interested in, and no guarantee the grid is valid at every intersection.
Claude (Anthropic's AI) generates the themed word list and clues. I send it a structured prompt with the theme, grid size constraints, and rules about clue quality. It returns a JSON array of answers and clues, which the placement engine then arranges into a valid crossword. The AI handles the creative part (coming up with clever, fair clues that actually relate to the theme), while the algorithm handles the structural part (making sure every letter intersection is valid).
For multi-word answers, the app automatically calculates the word count indicator. If the answer is "BACK HOME," the clue displays (4,4) at the end. If it's "HERE I AM," you see (4,1,2). This is computed from the display form of the answer, not hardcoded by the AI.
This was the real engineering challenge. Generating words is easy. Placing them in a valid crossword grid where every intersection checks out is a constraint satisfaction problem.
Words are sorted longest-first. The first word goes horizontally near the center. For each subsequent word, the engine scans every cell of every placed word looking for matching letters to create perpendicular intersections. It validates bounds, letter conflicts, unintended parallel adjacency, and word boundaries. Multiple shuffled orderings are tried, and the densest valid layout wins.
Every crossing must produce real letters in both directions. No word can accidentally extend into another. No parallel words can touch without a proper crossing. The cell before and after each word must be empty. These constraints are checked for every candidate position of every word.
The app is a single self-contained HTML file with React loaded via CDN. No build step, no bundler, no framework overhead. The Cloudflare Worker acts as a proxy so the API key stays server-side. The crossword placement engine is ~200 lines of pure JavaScript with no dependencies.
Difficulty settings that control clue obscurity. A timer and scoring system. Saving puzzle state so you can close the tab and come back. A "hint" button that reveals a single letter instead of the whole puzzle. Pre-generated puzzle packs for offline play.