Back to all posts

Build an Accessible Tic Tac Toe Game with AI and Codex CLI

Build an accessible tic-tac-toe game with Codex CLI, React, and Vite while working with NVDA. This walkthrough covers project instructions, a focused prompt, test setup, command approvals, and manual screen-reader testing.

Watch the video

What I built

I wanted to see how far Codex CLI could get with one focused prompt and a small React starter project. I scaffolded the project with Vite, gave Codex instructions for working in the repository, and asked it to build a two-player tic-tac-toe game with screen-reader support.

I did the whole workflow with the NVDA screen reader on Windows 11. The project ran inside Ubuntu on WSL, I worked in VS Code, and I tested the finished game in Brave.

The result was a solid accessible first draft. The game used native buttons, announced each move and turn, gave every square a row-and-column label, and announced the winner. Codex also added five component tests and reported a clean lint and production build.

I called the game “fully accessible” in the original prompt and video title. That is a useful goal, but one NVDA test and five automated tests do not prove complete accessibility. In this article, I call it accessible and explain exactly what I tested.

Tools I used

This was my setup for the recording:

  • Windows 11
  • Ubuntu on WSL
  • NVDA
  • VS Code
  • Brave
  • Node.js and npm
  • Codex CLI
  • React and Vite

If you are new to Codex CLI, I have separate videos on installing Codex CLI and selecting a model and reasoning effort.

The finished project is available in the tic-tac-toe-ai GitHub repository.

Create the React project

I started in my React projects directory and created a folder for the game:

mkdir tic-tac-toe
cd tic-tac-toe

I already had a local Markdown file with my Vite setup notes, so I copied that file into the new directory. Then I opened the directory in VS Code:

code .

Before scaffolding the project, I checked my Node.js version and installed the current LTS release through nvm:

node -v
nvm install --lts

I created the Vite project in the current directory with:

npm create vite@latest . -- --template react

The period tells Create Vite to use the current directory, and --template react selects the React starter template. The interactive questions can change between releases. In my recording, I kept the existing setup-notes file, selected ESLint, and let the tool install the npm packages and start the development server.

Once the server was running, I opened the local address in Brave and confirmed that the default React counter worked. That gave me a known starting point before asking Codex to replace the starter interface.

Give Codex project instructions first

I kept the Vite server running and opened another terminal with Ctrl+Shift+grave. Then I started Codex:

codex

For this recording, I selected GPT-5.6 Sol with medium reasoning effort. Model availability can change, so check the current model list in Codex rather than treating that selection as a requirement.

My first request was not to build the game. I asked Codex to inspect the starter project and create an AGENTS.md file:

Good afternoon. Please start by analyzing the current project and creating an AGENTS.md file.

Codex documented the React and Vite versions, repository structure, npm commands, coding conventions, accessibility expectations, and verification steps. This gave the agent a local working contract before it touched the application.

I also created a directory for plans and a text file for the main prompt:

mkdir plan
echo > prompt.txt

Write a focused accessibility prompt

The prompt was intentionally small. It described the outcome I wanted and the rules that should shape the implementation.

Here is a cleaned version of what I typed in the video. I corrected the typing mistakes and changed “fully accessible” to “accessible” because the finished game still needs broader testing.

Facts are important throughout. Assumptions need to be flagged.

The goal is to create a professional tic-tac-toe game that is simple and accessible for
screen readers.

Use ARIA where it is appropriate. A live region should announce game information that would
otherwise only appear visually.

Any game-flow instruction also needs to be announced.

Rules for writing code:

1. Test-driven development is required.
2. Be Socratic about the goal and direction.
3. Keep it clean. Write modern code, prefer simple solutions, and do not look for unnecessary
   code to write.

The prompt did not describe every React component or CSS rule. It established the goal, accessibility requirements, and engineering constraints while leaving the implementation to Codex.

Save a clean starting point

Before sending the build request, I initialized Git and saved the starter project:

git init
git add .
git commit -m "Initial commit"
git branch -M main
git status

This gave me a clean baseline. If the generated work went in the wrong direction, I could inspect exactly what changed instead of trying to remember the original state.

Ask Codex to build the game

With AGENTS.md, prompt.txt, and the initial commit in place, I sent one short request:

Now please read prompt.txt and execute the application.

Codex interpreted “execute the application” as both implementing the prompt and launching the result. While it worked, it asked for permission to install the test dependencies:

npm install --save-dev vitest jsdom @testing-library/react @testing-library/user-event @testing-library/jest-dom

I read the command before approving it and chose the one-time approval. I did not select the option that would automatically approve every future command beginning with npm install.

There is an important distinction between two of those packages. Vitest is the test runner. jsdom provides a simulated browser-like DOM environment so the React component tests can run under Node.js. It is not another test runner.

The Codex interface reported 9 minutes and 2 seconds of work. Its handoff reported:

  • Five tests passed
  • ESLint passed
  • The production build passed
  • The HTTP smoke check passed
  • The dependency audit found no vulnerabilities

The source repository contains five tests covering the empty board, alternating moves, a win, a draw, and starting a new game.

What Codex added for accessibility

The useful part was not only that the game worked visually. Codex added several details that made the game understandable and operable with NVDA:

  • Each square is a native button.
  • Every square has an accessible name containing its row, column, and current state.
  • The board is a named group associated with the game instructions.
  • A polite, atomic live region announces the selected square, next turn, win, draw, and new game state.
  • Occupied squares and the finished board become unavailable.
  • Keyboard focus has a visible outline.
  • The CSS includes high-contrast text and game-mark colors and reduced-motion support.
  • The Play again button starts a fresh board and announces the new game.

For example, an empty square is announced as “Row 2, column 1: empty.” After selecting it, the status message includes the move and tells the player whose turn comes next.

Play the game with NVDA

Codex launched the finished application on a second local port. I copied the address from its handoff and opened it in Brave.

At the top of the page, NVDA announced the Tic Tac Toe heading, the instruction that X goes first, and the current game status. The board was exposed as a group named “Tic tac toe board.”

I used B and Shift+B to move between the square buttons. NVDA announced each square by row, column, and state, so I did not have to infer the board from its visual position.

I played these moves:

  1. X in row 2, column 1.
  2. O in row 2, column 2.
  3. X in row 3, column 1.
  4. O in row 3, column 3.
  5. X in row 1, column 1.

That gave X the first column. The live region announced the final move, said that X won, and instructed me to select Play again to start a new game.

After the board, NVDA found the Play again button and the keyboard instruction explaining that players can use Tab to move between available squares and Enter or Space to play.

What this result proves

This project shows that a coding agent can produce a useful accessible first draft when I give it a clear outcome, project rules, a test-driven-development requirement, and specific screen-reader requirements. The prompt did not need to prescribe every line of code, but it did need to say what success meant.

It does not mean I can ignore software fundamentals or accept the first result without checking it. I still needed to inspect the command approval, read the handoff, understand the test setup, and play the game with NVDA.

The next level of accessibility testing would include more browsers and screen readers, keyboard-only testing beyond the path I demonstrated, zoom and reflow checks, color and contrast checks, mobile layouts, and a review against the relevant WCAG criteria. The five component tests and one successful NVDA game are evidence of a good start, not proof that every user and configuration will work.

References