How to make a word game with AI
A word game is a dictionary with a keyboard attached. Decide where the words come from before you write the prompt, because a model asked to supply them will invent some of them.
Jump to a section
Settle the word list first. Everything else in a word game is a grid and a keyboard, and any model writes those without complaint. The words are the hard part, because a real English dictionary is far too large for a model to type out and far too useful to do without. So you choose: a short list you curate yourself, or a bigger one fetched once and kept.
A plain text list of English words runs to megabytes. Nothing a model writes into your file will be that. Ask anyway and one of three things happens. It writes out a short list and calls it a dictionary, it fetches a URL that may not exist, or it writes code against a variable nobody defined. All three look finished until somebody plays.
Four steps to a word game that accepts real words#
A curated list inside the file, or a larger file fetched on first load and kept. Pick one now. Changing your mind later rewrites the loading code and the failure path.
Read it properly, word by word. You are looking for things that are not words, and for anything you would not want shown to a stranger.
Pick real words that would never be the answer and try them. Each refusal is a hole in the allowed list, and that list is the one players feel.
Nearly every complaint about a word game is a missing entry. Add it and reload. Leave the rules alone until the lists are honest.
Build a guess the hidden word game as ONE self-contained .html file.
Canvas only, no frameworks, no images, no network requests.
TWO LISTS, and this is the part that matters:
ANSWERS is an array of ordinary five letter words the game may
choose as the hidden word. Write out as many as you can. Everyday
words only: no proper nouns, no abbreviations, nothing coarse.
ALLOWED is a Set holding every entry of ANSWERS plus every other
real five letter word you can write down. A typed guess is accepted
when ALLOWED has it. Never check a guess against ANSWERS.
If ALLOWED ends up shorter than you would like, write a comment at the
top of the file saying so. Do not quietly shorten it instead.
GUESSING: six attempts at the hidden word. After each one, mark every
letter as right letter right place, right letter wrong place, or
absent. Count the letters of the answer as you mark, so a letter that
occurs once there is only ever marked once in the guess.
REFUSED GUESS: shake the row, name the word that was not recognised,
and do not spend an attempt on it.
WORD OF THE DAY: derive the index into ANSWERS from today's date, so
every player gets the same word on the same day. Add a practice mode
that picks from ANSWERS at random instead.
KEYBOARD: draw your own keyboard on the canvas and tint each key once
its letter is settled. Physical keys work as well. Put
canvas { touch-action: none; } in the CSS so tapping a key cannot
scroll the page.
Advance any reveal or shake animation by the seconds elapsed since the
previous frame, with that number held to 0.05 at the very most. Put
every value worth changing, attempt count, word length, palette and
animation timings, in one CONFIG object at the top of the file.
The two list paragraphs are the article. Delete them and you get one list used for both jobs, which is the bug that makes a word game feel broken. Everything after WORD OF THE DAY is safe to reword. The CONFIG object is where you change word length, and changing it means replacing both lists.
Why the dictionary is the whole problem#
Think about what you are asking for. An open word list of the sort a crossword setter uses holds a very large number of entries and weighs megabytes as plain text. A model generating your file is writing it out token by token. It is not going to produce that, and it has no way to tell you it is not going to produce that.
The invented fetch is the worse of the two failures. Code that pulls a word list from a plausible looking address passes a read through and then does nothing on a machine where that address is wrong. You get an empty game with no error, because a fetch that fails on load tends to leave the board waiting rather than complaining.
So be explicit instead of hopeful. Tell the model to write the list out in full and to admit in a comment when the list it managed is thin. That one instruction turns a silent shortfall into a line you can read, which is the whole difference between a bug and a decision.
If you want a larger list than any model will type, fetch one yourself. Find a plain text word list, check the licence, and either paste it into the file or load it once and keep a copy in local storage. Then your game has one network call that happens once, and never again.
Two lists, not one#
Here is the mistake that makes an otherwise working word game feel rotten. One list does both jobs. The game picks its hidden word from that list, and it also checks typed guesses against it. Both jobs look like the same job. They are not.
The answer list wants to be small and kind. Nobody enjoys being asked to guess a word they have never read. So it holds common words, nothing coarse, no abbreviations, no names of places. You read it through once yourself, which you can only do if it is short.
The allowed list wants to be as big as you can make it. A player probing for letters will type a word they would never expect to be the answer, on purpose. If that gets refused they do not think the list is short. They think the game is broken, and they are close enough to right.
- Every answer is an allowed guess. Build the allowed set from the answer list plus the extras, never the other way round. Otherwise a player can be refused the word the game is holding.
- Normalise before you look up. Decide on upper case with accents stripped, apply it to both lists when they load and to every guess, and nothing else needs to think about it again.
- Use a Set. Membership of a Set is a hash lookup. Searching an array of many thousands of strings on every keystroke is work you have no reason to do.
- Log the refusals. When a guess is turned down, keep it. A short list of words real players tried is the most direct instruction you will ever get about what to add.
Four places the words can come from#
| Where the list lives | Suits | What it costs you |
|---|---|---|
| Written into the HTML file | Guessing games, anagrams | Typing, and a list that stays modest |
| Fetched once, then cached | Crosswords, long words, scoring | A loading state and an offline path |
| Generated offline and pasted | Anything, if you can run a script | A step you must repeat on every change |
| Asked of a model while playing | Nothing at all | A key in public, a wait, invented words |
The first two are real choices with real trade offs. The last one is the option a model will reach for if you do not rule it out.
The embedded list is the right default, and not only because it is simple. A single file with its words inside works with no connection, loads in one go, and cannot break because something else moved. That matters for a game somebody plays once from a link.
Fetching earns its keep when the list has to be long. A crossword or a scoring game needs breadth you will not type. Fetch it on first load, store the parsed set, and write the failure path first: a clear message and a retry, never a board that sits there empty.
Never ask a model for words while the game runs#
It is a tempting idea and it is wrong in four separate ways. A browser game that calls a model needs a key, and a key in a file anyone can open is a key anyone can use. That alone ends it.
The rest matter too. Every guess would wait on a round trip, and a word game lives on instant feedback. The rulings would not agree with each other, so the same word could be accepted in one round and refused in the next. And the generated answers would sometimes not be words, which is the fault you started out trying to avoid.
Use the model for the thing it is good at. Ask it to write the list, read what it wrote, correct it, and ship the corrected list. The model did the typing. You did the checking. The game that reaches a player checks against a fixed list that cannot change its mind.
Letter counting deserves a mention here because it is the other thing that gets quietly wrong. Marking a guess is not asking whether each letter appears in the answer. It is matching letters while crossing them off, so a letter that occurs once is only ever credited once. Scoring an anagram against a pool of tiles has the same shape.
🎮Games written by AI
Common questions#
Can AI make a word game?
Yes, and the mechanics come out quickly: grid, keyboard, letter marking, a shared daily word. The limit is the dictionary, because a real English list is megabytes and a model has to type whatever it gives you. Decide where the words come from and the rest is routine.
How big does the word list need to be?
Two different answers. The list the game picks from can be short, because you want common words only and you want to read it yourself. The list it accepts guesses from should be as long as you can get, because players type real words that would never be the answer.
Why does my word game reject real words?
Because it is checking guesses against the answer list. That list is small by design, so anything outside it gets refused even though it is a perfectly good word. Build a separate allowed set, seed it from the answers, and add every other real word you can find.
Should the game fetch a dictionary or embed one?
Embed it when a modest list will do, since a single file works offline and cannot break when something else moves. Fetch when you genuinely need breadth, do it once, cache the result, and write the failure message before you write the happy path.
Can I have the AI generate words while the game is running?
Not in a browser game. It needs a key that anyone reading your file can take, and it adds a wait to every guess. Its rulings also disagree between calls, and some of what it returns will not be a word. Generate the list once, check it, then ship the checked list.
How do I make everyone get the same word each day?
Derive the index into the answer list from the date rather than picking at random. Every player on that day lands on the same entry with no server involved. Keep a separate practice mode that picks randomly, so somebody can play more than once.
Where to go next#
When your own refused guesses have dried up, publish it. The page it gets shows which model wrote the code and the prompt behind it. A word game is also the kind of thing people send to one other person, which is how most of them end up being played.
The general method is in how to make a game with AI. For a game whose content has to be valid rather than merely varied, the puzzle guide covers authored levels and undo. For a game that teaches rather than tests, read the educational guide. Prompts for common faults live in the prompt guide, and the category list shows what people have already built.
Built something? Put it on Agent Games.
Publishing takes a file and a minute. Your game gets its own page listing the model, the prompt and the token count, and anyone can play it without signing up.
Read next