You ask Claude Code to build a chess game in the browser. You open the page: the board is there, the pieces are set up, a pawn obediently follows your mouse. You can play. But as a check, you drag it three squares forward at once - and it stays there. Then you try moving black twice in a row. The page doesn't object this time either.
Before these two moves, the project looked nearly done. Now it turns out the main part still doesn't work: nothing checks the rules. You could ask the agent to block that pawn move. But next you'd have to deal with turn order, check, castling, pawn promotion. After every fix, one question remains: which condition did you still miss?
This is a good point to stop and look for existing code for this job. Chess rules are already implemented in the chess.js library. You can hand it a move and get back a check result. Then your own code is only responsible for the glue: take the action from the board, run it through the library, and show the correct position of the pieces.
What's left is delivering the library to the browser and wiring it into the page. One way is to load it from a CDN link. Below we look at how this works and why a link showing up in the code doesn't yet mean the pawn has stopped moving wherever it likes.
What the library does
A library is someone else's code that you plug into your project so you don't have to write what's already written. chess.js is exactly that case: it knows how each piece moves, what check and castling are, can list every legal move from the current position, and can tell whether the game is over.
And here it's easy to fall into a trap: connect the library and expect the game to just work. It won't. The library keeps the rules and the game position in its own memory - it doesn't draw anything and has no idea the page even has a board.
| Who | What it's responsible for | What happens without it |
|---|---|---|
The chess.js library | the rules and the current game position: which moves are possible, whose turn it is, whether the game is over | no one checks moves; the board allows anything |
| Page interface | the board, pieces, dragging, square highlighting | nothing to play with: the rules exist, but there's nothing to act on them |
| Glue code | passes the move you made to the library and redraws the board based on its answer | the rules and the picture live separately and never affect each other |
Look at what happens on a normal move. You drag the pawn from e2 straight to e5. The interface sees the drag, the glue code asks the library "is this move allowed?", the library answers "no" - and the glue code sends the piece back to e2. If nobody asked that question, the pawn settles on e5 without any trouble: nothing stops the page from drawing it there.
Both branches end in the same action: the glue code displays the position from the library. After a legal move it's already the new one; after an illegal move it stays the same, which is why the piece goes back to its starting square.
That leads to a conclusion about how you phrase the request. The ask "connect chess.js" can be carried out to the letter - a loading line shows up, and that's it. What you need to ask for is the connection: a move from the board goes into the library, the library's answer decides whether to move the piece, and the position after the move comes from the library's state, not from wherever you released the mouse.
It's easy to mix them up, because you "connect" both. A skill changes the agent's own behavior - it extends its instructions, gives it a new capability. A library has nothing to do with the agent at all: it's code inside your application, and it runs in the user's browser. The agent can connect it, but afterward it works without the agent too.
How the browser gets the code through a CDN
The library file has to come from somewhere. You can download it and place it next to your page, or you can point to it in your page's code with a link to an external service. For this, people often use a CDN (Content Delivery Network). It's a network of servers that serve files to users from different locations. Images, stylesheets, and JavaScript libraries all get delivered through CDNs, among other things. In our example, the jsDelivr service serves the library file.
When you open the page, the browser reads its code and comes across the link to the library. It requests the file at that address, downloads it, and then runs the page's code that uses the library. The library runs in the user's browser. The CDN delivers its code; checking chess moves happens on your own device.
The frame in the diagram separates the browser from the external service. Once loaded, the library lives inside the page: the glue code talks to it right there. There's no need to send every move to the CDN.
For chess.js, the connection looks like this:
<script type="module">
import { Chess } from 'https://cdn.jsdelivr.net/npm/chess.js@1.4.0/+esm'
const chess = new Chess()
console.log(chess.fen())
// rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1
</script>Three details matter here. First, type="module". The library arrives as an ES module, and the only way to get Chess out of it is by importing it; a plain <script src="..."> tag won't parse this same file - it will fail on the export statement inside it. Some libraries also ship in an older, non-module form: there a plain tag is enough, and a global variable simply appears on the page. chess.js has no such build, so there's exactly one option.
The second detail is the version number right in the address, chess.js@1.4.0. The connection method and the method names come from the documentation for that exact version in the link. An address without a number will sooner or later point to a different file, and code written against the old documentation will break.
And the third detail, the easiest to miss, is the /+esm tail at the end of the address. That's not decoration - it's a request to the CDN to build the file specifically as a module: without it, the same address delivers a different build, and import won't find anything.
You can confirm the library actually loaded without building the whole game - add a couple of lines to the same <script type="module"> and open the browser console (the Console tab in dev tools, F12 or Ctrl+Shift+I):
// a white pawn can't go straight from e2 to e5
try {
chess.move('e5')
} catch (error) {
console.log('move rejected:', error.message) // Invalid move: e5
}
chess.move('e4') // but the library accepts this move
console.log(chess.turn()) // b, black's turnThe starting position in the console, the rejected move, and black's turn after e4 - that means the file made it and the rules are working. What's left is wiring them up to the board.
And one caveat, so you don't get the wrong idea. A CDN doesn't remove the dependence on the network. The browser can reuse the file from its cache, its own saved copy, so it doesn't have to download it again every time you open the page. But if there's no suitable copy and the CDN is unreachable, the library won't load and the game won't be able to work with its rules.
An error at this step is almost always in the connection itself: the wrong address, the wrong version, the wrong import form. Don't rewrite the line at random - ask the agent to check it and find exactly what's off. One short check instead of half an hour of trial and error.
How this works together with Claude Code
The request "connect the library through a CDN" leaves the agent several decisions to make: where to get the file, which version to pick, how to load it into this page, and how to confirm the result. It's better to spell out these decisions right in the request. Below are prompts for different situations; you don't have to send all of them in a row.
Choose the URL to load from
If the agent suggests a library, first ask it to work out how to connect it in your project. That way you'll have a specific address and an explanation of where it came from.
Look at how my page is set up and check whether chess.js is already connected.
Look in the library's docs and jsDelivr's for a CDN loading method that
works for the browser. Suggest a URL with a specific version and explain
the parts of the address. Give links to the documentation. Don't change
the code yet. If you couldn't check the documentation, say so.Look in the answer for a version number, a connection method, and a reason for the choice. Just "here's a working link" isn't enough: it doesn't tell you whether the agent checked the address against the documentation or whether the file fits your page.
Connect the library to the board
Once the address is chosen, give the agent a task with a visible result. For a simple HTML page, you can specify right away that you want to keep the existing way of running it.
Connect chess.js using the chosen CDN address with a pinned version.
Keep the existing way of running the page. Link the library to the
board: pass it every move and show the position from its state.
On an illegal move, return the piece to its starting square.
Show me where the connection was added and where the library's answer is handled.There are two separate results here: the browser got the library, and actions on the board started going through its rules. By asking to see both spots in the code, you can see exactly what the agent added.
Check the result in the browser
A link in the HTML only confirms that the file was edited. The next request helps check whether it actually loads and how the game behaves.
Open the page and check that chess.js loaded, in the Network tab
of dev tools. Check for errors in Console. Then, from the starting
position, try e2-e5: the move should be rejected, the pawn should stay on e2.
After that, play e2-e4: the move should go through, the turn should pass to black.
Report what you observed at each step. If you don't have access to a browser,
give me short verification steps and note that you didn't check it yourself.The Network tab shows the page's network requests; Console shows messages and errors from its code. If the file loaded but the pawn still goes to e5, the cause is in how the move is handled. Swapping the CDN link on its own won't fix that connection.
Sort out a loading error
If something fails, give the agent the exact error text from Console and the address of the failed request from Network. That way it can check a specific cause instead of trying links at random.
After connecting the library, the page throws an error.
Text from Console: [paste the message in full].
URL and request result in Network: [paste the address and status].
Check whether the file is reachable, whether its format fits our import,
and whether the names in the code match the documentation for the chosen version.
First name the cause based on this data, then make a minimal
fix and repeat the check. Don't change the CDN, the version, and the game code all at once.Replace the text in square brackets with your own data. If there's no request for the library in Network at all, say so: that's also a useful clue. After the fix, repeat the two-move check to make sure the whole connection works.
Plan for the CDN being unreachable
If the library fails to load, an active-looking board can create the false impression that you can still play. Ask the agent to make this state clear to the user.
Handle the case where chess.js fails to load from the CDN.
While the library isn't ready, don't allow any moves. On error, show
a clear message and a way to retry loading the page.
Check the behavior when the request to the CDN is blocked, and then
after the block is lifted. Account for the cache: simply cutting the network
may still leave a previously loaded copy available. Describe exactly how you tested the failure.It's easier to run this check separately from an ordinary game. In the end you should see two clear states: the library is available and moves are checked; the load failed and the page explains why you can't play yet.
GO TO FULL VERSION