Qwen3.8-27B-Fast
M4 Max 128 GB · llama.cpp · every run of this model · uwu · 2026-11-04
Race it: run Qwen3.8-27B-Fast on your computer and see the two side by side.
A full run: 50 tasks, 82 points
- Score
- 2,256 Silver#1 of 1 on M4 Max 128 GB · #1 among Apple silicon
- Tasks passed
- 49/50
- Points
- 79/82Harder tasks count 3
- Tokens
- 100,19128,721 read, 71,470 written, as the runner counted them
- Speed
- 23.4 tok/sAs the runner measured it; the site cannot check this.
- Writing speed
- 23.4 tok/sPrompt reading left out. As the runner measured it; the site cannot check this.
tok/s is tokens a second: how fast the model writes. A token is about three quarters of a word. How the score works.
This setup, checked
No other runs of Qwen3.8-27B-Fast on M4 Max 128 GB yet; the next one will be compared with this one.
- Summarizing 5/5
- Extracting 5/5
- Following instructions 5/5
- Reasoning 5/5
- Reading code 4/4
- Using tools 5/5
- Building pages 5/5
- Building games 3/4
- Building apps 4/4
- Writing code 3/3
- Fixing code 2/2
- Planning and data 3/3
Run details
Flag this run
Failed 1
Build SnakeFailed
3,342 tokens: 455 read, 2,887 written · 2 min 1 s · 24.3 tok/s
Build Snake as one web page on a 10 by 10 grid, playable with the arrow keys (one key press, one step), with the grid drawn on the page. In <script id="game">, define createGame() returning an object with step(dir) and state(). dir is "up", "down", "left" or "right". state() returns {snake, food, score, over}: snake is a list of [x, y] cells, head first; food is [x, y]; score is a number; over is a boolean. x is the column (0 to 9, left to right), y the row (0 to 9, top to bottom); up is y - 1. The rules, exactly: 1. The game starts with snake [[6, 3], [7, 3], [8, 3]], moving left, food at [8, 1], score 0. 2. step(dir): if dir is the opposite of the current direction it is ignored and the snake keeps going; otherwise dir becomes the current direction. The head moves one cell that way. 3. If the new head cell holds the food, the snake grows: its tail stays. Otherwise the tail cell is freed first. 4. If the new head is off the grid or on a cell of the snake (after rule 3), the game is over: over becomes true and nothing else changes. Once over, step does nothing. 5. Eating adds 1 to the score, and the next food goes to the first empty cell in reading order (row by row from the top, left to right) after the new head's cell, wrapping from [9, 9] to [0, 0]. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and plays the game through createGame(). Wire the page in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Snake</title> <style> body { font-family: monospace; background: #1b1b2f; color: #e0e0e0; display: flex; flex-direction: column; align-items: center; padding-top: 24px; } h1 { font-size: 20px; margin: 0 0 8px; } #score { margin-bottom: 12px; font-size: 16px; } #board { display: grid; grid-template-columns: repeat(10, 32px); grid-template-rows: repeat(10, 32px); gap: 2px; background: #10101c; padding: 4px; border: 2px solid #444466; } .cell { background: #2a2a44; } .cell.snake { background: #4caf50; } .cell.head { background: #a5d6a7; } .cell.food { background: #ff5252; } #msg { margin-top: 12px; height: 20px; font-size: 16px; color: #ff8a80; } .hint { margin-top: 6px; font-size: 12px; color: #8888aa; } </style> </head> <body> <h1>Snake</h1> <div id="score">Score: 0</div> <div id="board"></div> <div id="msg"></div> <div class="hint">Arrow keys: one press, one step</div> <script id="game"> function createGame() { const DELTAS = { up: [0, -1], down: [0, 1], left: [-1, 0], right: [1, 0] }; const OPPOSITE = { up: 'down', down: 'up', left: 'right', right: 'left' }; const snake = [[6, 3], [7, 3], [8, 3]]; let dir = 'left'; let food = [8, 1]; let score = 0; let over = false; function step(d) { if (over) return; if (d !== OPPOSITE[dir]) dir = d; const head = snake[0]; const nx = head[0] + DELTAS[dir][0]; const ny = head[1] + DELTAS[dir][1]; if (nx < 0 || nx > 9 || ny < 0 || ny > 9) { over = true; return; } const eating = (nx === food[0] && ny === food[1]); const body = snake.slice(1); if (!eating) body.pop(); // tail freed first const bodyWithHead = [[nx, ny]].concat(body); if (bodyWithHead.slice(1).some(function (c) { return c[0] === nx && c[1] === ny; })) { over = true; return; } snake.length = 0; snake.push.apply(snake, bodyWithHead); if (eating) { score += 1; let i = (ny * 10 + nx + 1) % 100; for (let k = 0; k < 100; k++) { const fx = i % 10; const fy = Math.floor(i / 10); const occupied = snake.some(function (c) { return c[0] === fx && c[1] === fy; }); if (!occupied) { food = [fx, fy]; return; } i = (i + 1) % 100; } } } function state() { return { snake: snake.map(function (c) { return [c[0], c[1]]; }), food: [food[0], food[1]], score: score, over: over }; } return { step: step, state: state }; } </script> <script> (function () { const game = createGame(); const board = document.getElementById('board'); const scoreEl = document.getElementById('score'); const msgEl = document.getElementById('msg'); const cells = []; for (let i = 0; i < 100; i++) { const d = document.createElement('div'); d.className = 'cell'; board.appendChild(d); cells.push(d); } function render() { const s = game.state(); cells.forEach(function (c) { c.className = 'cell'; }); s.snake.forEach(function (cell, i) { cells[cell[1] * 10 + cell[0]].className = 'cell ' + (i === 0 ? 'head' : 'snake'); }); cells[s.food[1] * 10 + s.food[0]].classList.add('food'); scoreEl.textContent = 'Score: ' + s.score; msgEl.textContent = s.over ? 'Game over' : ''; } const KEYMAP = { ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right' }; document.addEventListener('keydown', function (e) { if (KEYMAP[e.key]) { e.preventDefault(); game.step(KEYMAP[e.key]); render(); } }); render(); })(); </script> </body> </html> ```
What it built
Pages and games, as the model wrote them, each in a sandbox. On a computer, click a game and use the arrow keys.
-
Build 2048Keeps a game's rules across many moves.Passed · 4.4k tokens · 24.8 tok/s
-
Build SnakeRuns a game where a snake grows and the game ends on a crash.Failed · 3.3k tokens · 24.3 tok/s
-
Box-pushing puzzleShows whether a model can follow the push rules exactly across a whole level, counting steps and pushes as the rules say.Passed · 9.7k tokens · 23.1 tok/s
-
MinesweeperShows whether a model keeps the rules of a small game exact: where an empty area stops spreading, what a flag does to the count, and what a win or a loss reveals.Passed · 6k tokens · 20 tok/s
-
A small websiteLays out a small website with a menu and a footer.Passed · 2.4k tokens · 22.3 tok/s
-
A pricing table with a toggleSwitches every price between monthly and yearly with one button.Passed · 2.1k tokens · 24.9 tok/s
-
An accessible sign-up formChecks a sign-up form and labels each of its fields.Passed · 1.6k tokens · 25.3 tok/s
-
A to-do app that remembersKeeps data across a reload.Passed · 1.7k tokens · 25.3 tok/s
-
A bar chart in SVGDraws data to scale.Passed · 1.2k tokens · 24.4 tok/s
-
Step sequencerShows whether a model can keep a beat in time, step by step.Passed · 10k tokens · 23.3 tok/s
-
Grow a branching plantThis shows whether a model can apply a branching rewrite rule exactly, over four rounds of growth.Passed · 5.4k tokens · 20.8 tok/s
-
Falling sandShows whether a model can follow exact falling rules, cell by cell and frame by frame.Passed · 7.2k tokens · 23.8 tok/s
-
Focus timerShows whether a model keeps a focus timer exact through pauses, skips and resets.Passed · 4.5k tokens · 23.9 tok/s
Scored tasks
Summarizing 5 of 5
One-sentence summaryPassed
1,389 tokens: 108 read, 1,281 written · 51 s · 25.3 tok/s
Summarize this in one sentence of at most 30 words. Starting December 17, the Newbury Rise Public Library will open at 6:30 a.m. instead of 10:35 a.m. on weekdays. The change follows a survey in which 57% of respondents asked for earlier hours. Weekend hours stay the same. The library will hire three part-time staff to cover the extra time, paid for by a state grant.
Following a survey, the Newbury Rise Public Library will open weekdays at 6:30 a.m. instead of 10:35 a.m. starting December 17, with three part-time staff funded by a state grant.
Meeting notes in three bulletsPassed
730 tokens: 195 read, 535 written · 22 s · 25.1 tok/s
Summarize these meeting notes as exactly three bullet points, each at most 20 words. Keep only the decisions and ownership changes that matter. Output only the bullet points. Weekly sync, design team. Present: Wren, Kim, Lucas, Sam. - Lucas reported that the payment provider fixed the login bug; no action needed. - The launch date moves from November 20 to November 26 because the app store review is slow. - Sam showed the new onboarding screens. Everyone liked them. Small copy changes only. - The marketing budget of $15,000 was approved by finance on Sunday. - Wren will own end-to-end testing from now on; Kim hands over the test plan by Friday. - Next sync is moved to Monday at 09:15. - Coffee machine on floor 3 is broken again.
- Launch date moved from November 20 to November 26 due to slow app store review. - Wren now owns end-to-end testing; Kim hands over the test plan by Friday. - Finance approved the $15,000 marketing budget.
Review sentiment and complaintPassed
358 tokens: 119 read, 239 written · 11 s · 24.1 tok/s
Read this product review and answer in exactly this format: Sentiment: <positive, negative or mixed> Complaint: <the main complaint in a few words> I've used this toaster every day for a month. Honestly, it toasts evenly every time and it heats up in seconds. But the crumb tray that came in the box cracked after two weeks, and support took 10 days to reply. I bought a replacement crumb tray myself. Would I buy it again? Probably, but I'm annoyed.
Sentiment: mixed Complaint: Crumb tray cracked and slow customer support response
Faithful summary of a studyPassed
963 tokens: 137 read, 826 written · 37 s · 23 tok/s
Summarize this in at most 50 words. Keep the key numbers. Do not add anything the text does not say. In a randomized trial, 250 adults with episodic migraine took either Dravex or a placebo for 12 weeks. Those on Dravex had 4.0 fewer headache days per month on average, compared with 0.6 fewer days for placebo. Dizziness was the most common side effect, reported by 12% of the drug group. The authors note the trial lasted only 12 weeks and call for longer studies before any recommendation is made.
In a randomized 12-week trial, 250 adults with episodic migraine took Dravex or placebo. Dravex reduced headache days by 4.0 per month versus 0.6 for placebo. Dizziness affected 12% of the drug group. Authors call for longer studies before recommendations.
Action items from an email threadPassed
595 tokens: 217 read, 378 written · 16 s · 25.1 tok/s
List every action item in this email thread that someone has committed to do, as lines of the form "- <owner>: <action>". Leave out offers that were declined and things that turned out not to be needed. Output only the list. From: Yara Hi all, quick recap of what's still open for the team away day. I'll send the revised contract to the hotel by Saturday. From: Pablo I can book the venue for the dinner if that helps? From: Jules Thanks Pablo, but I'll book the venue myself since I already spoke to them. Also, no need to change the logo on the badges, it's fine as is. From: Ines I'll update the budget sheet with the new hotel price tonight. From: Yara Great. Oh, and I'll email the caterer about the vegetarian options. Pablo, could you just double-check the date on the invitations? Actually never mind, I checked them this morning, they're correct.
- Yara: Send the revised contract to the hotel by Saturday - Jules: Book the venue for the dinner - Ines: Update the budget sheet with the new hotel price - Yara: Email the caterer about the vegetarian options
Extracting 5 of 5
Fields from an email as JSONPassed
233 tokens: 121 read, 112 written · 5 s · 24.5 tok/s
Extract these fields from the email as a JSON object with exactly these keys: "name" (the sender's full name), "company", "meeting_date" (YYYY-MM-DD) and "attendees" (a number). Output only the JSON. Hello! This is Yara Mensah from Kestrel Analytics. We'd love to visit your workshop. Could we meet on the 11th of September 2026, any time after lunch? We'll be four people in total, including me. Best, Yara
{"name":"Yara Mensah","company":"Kestrel Analytics","meeting_date":"2026-09-11","attendees":4}Every email address, oncePassed
430 tokens: 143 read, 287 written · 12 s · 24.8 tok/s
List every email address written out in full in this text (like name@example.com), one per line, in the order they first appear, without duplicates. Leave out any inbox the text says is closed. Output only the addresses. Contacts for the conference: write to info@cedar-summit.org for general questions, or to speakers@cedar-summit.org if you are presenting. Our designer (eli.f@pixelhouse.co) made the poster. Billing questions: billing@cedar-summit.org. Again, presenters use speakers@cedar-summit.org. Please don't write to jo at cedar dot org, that inbox is closed.
info@cedar-summit.org speakers@cedar-summit.org eli.f@pixelhouse.co billing@cedar-summit.org
A list as CSVPassed
411 tokens: 106 read, 305 written · 13 s · 24.9 tok/s
Convert this shopping list to CSV with the header row item,qty,price. Write prices as plain numbers without a currency sign. Output only the CSV. Butter (250 g) - 12 @ $5.05 Bananas - 11 @ $1.80 Bread loaf - 23 @ $6.40 Cheddar (200 g) - 20 @ $2.05
item,qty,price Butter (250 g),12,5.05 Bananas,11,1.80 Bread loaf,23,6.40 Cheddar (200 g),20,2.05
The real deadlinePassed
168 tokens: 99 read, 69 written · 3 s · 24.8 tok/s
What is the final submission deadline? Answer with the date only, in YYYY-MM-DD format. The call for papers opened on 9 January 2026. Drafts were originally due September 20, but the committee extended the final submission deadline to 26 October 2026. Reviews are due by 26 October, and results will be announced on November 7, 2026.
2026-10-26
Warnings and errors from a logPassed
603 tokens: 278 read, 325 written · 14 s · 25.2 tok/s
From this log, return a JSON array with one object per WARN or ERROR line, in order, each with the keys "time" (HH:MM:SS), "level" and "message". Output only the JSON. 2025-05-23 09:03:48 INFO server started on port 8080 2025-05-23 09:08:50 WARN config key "retries" is deprecated 2025-05-23 09:13:00 INFO user kim logged in 2025-05-23 09:14:47 ERROR database connection lost 2025-05-23 09:15:59 INFO retrying in 30s 2025-05-23 09:17:04 INFO database reconnected 2025-05-23 09:19:09 DEBUG cache hit ratio 0.91 2025-05-23 09:23:29 ERROR payment webhook returned 504
[{"time":"09:08:50","level":"WARN","message":"config key \"retries\" is deprecated"},{"time":"09:14:47","level":"ERROR","message":"database connection lost"},{"time":"09:23:29","level":"ERROR","message":"payment webhook returned 504"}]
Following instructions 5 of 5
Exactly one wordPassed
59 tokens: 21 read, 38 written · 2 s · 25 tok/s
Reply with exactly the word Stopped and nothing else.
Stopped
Three lowercase linesPassed
592 tokens: 88 read, 504 written · 24 s · 21.6 tok/s
Write exactly three lines about a hospital. Use the word hospital in every line. Start every line with the letter d, and do not use any of these words: station, river, barn, crater, volcano, lighthouse, summer, canyon, palace or quarry. Every line must be entirely lowercase, and the third line must end with a question mark. Output only the three lines.
doctors at the hospital work tirelessly to save lives down the hallway, the hospital feels like a second home did you know that the hospital has been open for decades?
Exact JSON shapePassed
222 tokens: 62 read, 160 written · 7 s · 24.9 tok/s
Return a JSON object with exactly two keys: "words", a list of exactly 4 different lowercase words that each start with the letter o and use only the plain letters a to z, and "count", the number 4. Output only the JSON.
{"words":["one","orange","ocean","olive"],"count":4}Sort a listPassed
240 tokens: 43 read, 197 written · 8 s · 24.6 tok/s
Sort these words alphabetically, ignoring case. Output only the sorted words, on one line separated by commas: peach, bean, Orange, papaya, Wheat.
bean, Orange, papaya, peach, Wheat
A name with three rulesPassed
680 tokens: 71 read, 609 written · 29 s · 21.9 tok/s
Suggest a product name for a solar-powered bike. Rules: exactly two words, both capitalized, using only the plain letters A to Z, the first word starts with the letter L, the second word starts with the letter C, and the letter y must not appear anywhere. Output only the name.
Light Cruiser
Reasoning 5 of 5
Unit pricePassed
298 tokens: 52 read, 246 written · 13 s · 20.1 tok/s
A shop sells pencils at 5 for $2.75. How much do 14 pencils cost, in dollars? Work it out, then end with a line "ANSWER: <number>".
To find the cost of 14 pencils, I'll first determine the price per pencil. **Step 1: Find the cost per pencil.** 5 pencils cost $2.75, so one pencil costs: $2.75 ÷ 5 = $0.55 **Step 2: Calculate the cost of 14 pencils.** 14 × $0.55 = $7.70 ANSWER: 7.70
Day and datePassed
615 tokens: 66 read, 549 written · 22 s · 24.9 tok/s
Today is Saturday, 4 July 2026. What day of the week, and what date, is it 34 days from today? Work it out, then end with a line "ANSWER: <day of the week>, <YYYY-MM-DD>".
# Finding the Date 34 Days from Saturday, 4 July 2026 ## Step 1: Work out the date - **4 July 2026** + 34 days - Days remaining in July after the 4th: 31 − 4 = **27 days** (brings us to 31 July) - Days left to count: 34 − 27 = **7 days** into August - Date: **7 August 2026** ## Step 2: Work out the day of the week - 34 days ÷ 7 = 4 weeks and **6 days** remainder - Advance 6 days from Saturday: | +1 | +2 | +3 | +4 | +5 | +6 | |----|----|----|----|----|----| | Sun | Mon | Tue | Wed | Thu | **Fri** | So 34 days after Saturday is a **Friday**. ANSWER: Friday, 2026-08-07
Who owns each petPassed
716 tokens: 160 read, 556 written · 23 s · 25.1 tok/s
Five people, Hal, Ivy, Ana, Dee and Gus, each own exactly one of these pets: a cat, a dog, a fish, a bird and a rabbit. Each pet has one owner. Clues: - Dee owns the bird. - Ivy owns the rabbit. - Ana owns the dog or the fish. - Ana owns the cat or the dog. - Gus owns the fish or the rabbit. Who owns each pet? Work it out, then end with a line "ANSWER: <owner of the cat>, <owner of the dog>, <owner of the fish>, <owner of the bird>, <owner of the rabbit>", with the five names in that order, separated by commas.
Looking at the clues: 1. **Dee owns the bird.** 2. **Ivy owns the rabbit.** Now I need to figure out Ana. From clue 3, Ana owns the **dog or fish**. From clue 4, Ana owns the **cat or dog**. The only pet that appears in both possibilities is the **dog**, so Ana owns the dog. From clue 5, Gus owns the **fish or rabbit**. Since Ivy already has the rabbit, Gus must own the **fish**. That leaves **Hal** with the **cat**. **Verification:** - Dee = bird ✓ - Ivy = rabbit ✓ - Ana = dog (satisfies "dog or fish" and "cat or dog") ✓ - Gus = fish (satisfies "fish or rabbit") ✓ - Hal = cat (only one left) ✓ ANSWER: Hal, Ana, Gus, Dee, Ivy
Arrival timePassed
181 tokens: 60 read, 121 written · 5 s · 25 tok/s
A train leaves at 13:10 and the trip takes 3 hours. At what time does it arrive? Work it out, then end with a line "ANSWER: <HH:MM>" in 24-hour time.
The train departs at 13:10. Adding 3 hours to that: 13:10 + 3:00 = 16:10 The train arrives at 16:10. ANSWER: 16:10
Filling a tankPassed
360 tokens: 84 read, 276 written · 12 s · 24.7 tok/s
A tank holds 69 liters and starts empty. Pipe A adds 16 liters an hour, pipe B adds 12 liters an hour, and a drain takes 5 liters an hour out of it. With all three open, how many hours until the tank is full? Work it out, then end with a line "ANSWER: <number>".
## Setting Up the Problem **Tank capacity:** 69 liters (starts empty) **Rates (all three open simultaneously):** - Pipe A: +16 L/hr - Pipe B: +12 L/hr - Drain: −5 L/hr ## Calculating the Net Rate Net rate = 16 + 12 − 5 = **23 liters per hour** ## Finding the Time Time = Volume ÷ Net rate Time = 69 ÷ 23 = **3 hours** ## Verification After 3 hours: 23 × 3 = 69 liters ✓ (tank is exactly full) ANSWER: 3
Reading code 4 of 4
What does it printPassed
508 tokens: 84 read, 424 written · 21 s · 20.9 tok/s
What numbers does this Python program print, in order? Work it out, then end with a line "ANSWER: <numbers, separated by commas>". def f(xs): return sorted(xs)[::-1][:2] print(f([33, 35, 38, 48, 14, 41]))Let me trace through the program: 1. `f([33, 35, 38, 48, 14, 41])` is called. 2. `sorted(xs)` → `[14, 33, 35, 38, 41, 48]` 3. `sorted(xs)[::-1]` → `[48, 41, 38, 35, 33, 14]` (reversed) 4. `sorted(xs)[::-1][:2]` → `[48, 41]` (first two elements) 5. `print([48, 41])` outputs: `[48, 41]` ANSWER: 48, 41
Trace a loopPassed
914 tokens: 93 read, 821 written · 35 s · 24 tok/s
What does this Python program print? Work it out, then end with a line "ANSWER: <output>". def g(n): total = 0 for i in range(1, n + 1): if i % 4 == 0 or i % 8 == 0: total += i return total print(g(75))Looking at this program, I need to trace through the function `g(n)` with `n = 75`. The function sums all numbers `i` from 1 to 75 where `i % 4 == 0` **or** `i % 8 == 0`. **Key observation:** Any number divisible by 8 is *also* divisible by 4. So the condition `i % 8 == 0` is redundant — the effective condition is simply `i % 4 == 0`. So I need the sum of all multiples of 4 from 1 to 75: 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 68, 72 That's 18 terms (since ⌊75/4⌋ = 18). Sum = 4 × (1 + 2 + 3 + … + 18) = 4 × (18 × 19 / 2) = 4 × 171 = **684** ANSWER: 684
Find the bugPassed
465 tokens: 107 read, 358 written · 15 s · 24.6 tok/s
The function largest should return the largest number in a non-empty list. The code below has one bug. Find the line with the bug, and write that line corrected, exactly as it should read in the code. Work it out, then end with a line "ANSWER: <corrected line>". def largest(numbers): best = numbers[0] for value in numbers: if value < best: best = value return bestLooking at the code, the function is meant to find the **largest** number, but the comparison on the `if` line uses `<` (less than), which causes `best` to be updated whenever a *smaller* value is found. This makes the function return the smallest element instead. The fix is to change `<` to `>` so that `best` is updated only when a *larger* value is found. ANSWER: if value > best:
Run a query in your headPassed
293 tokens: 143 read, 150 written · 7 s · 25.1 tok/s
What rows does this SQL query return? Output only the rows, one per line, as customer,total in the query's order. Table orders: id | customer | amount 1 | ana | 70 2 | ana | 10 3 | ben | 30 4 | ben | 100 5 | cal | 50 6 | cal | 45 Query: SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer HAVING SUM(amount) > 100 ORDER BY total DESC;
ben,130
Using tools 5 of 5
Call one toolPassed
847 tokens: 698 read, 149 written · 8 s · 24.4 tok/s
What's the weather in Oslo right now, in celsius?
- user
What's the weather in Oslo right now, in celsius?
- assistant
get_weather({"city":"Oslo","unit":"celsius"}) - tool
{"city":"Oslo","conditions":"snowing","temperature":10,"unit":"celsius"} - assistant
The current weather in Oslo is **snowing** at **10°C**. That's a fairly mild snowfall! 🌨️
- user
Don't call a tool when none is neededPassed
493 tokens: 417 read, 76 written · 5 s · 25.6 tok/s
What is 26 times 23?
- user
What is 26 times 23?
- assistant
26 × 23 = **598**
- user
Two calls for two answersPassed
1,031 tokens: 825 read, 206 written · 10 s · 25.4 tok/s
Convert 305 GBP to EUR and to JPY.
- user
Convert 305 GBP to EUR and to JPY.
- assistant
convert_currency({"amount":305,"from":"GBP","to":"EUR"})convert_currency({"amount":305,"from":"GBP","to":"JPY"}) - tool
{"amount":354.65,"currency":"EUR"} - tool
{"amount":56922,"currency":"JPY"} - assistant
Here's the conversion of **305 GBP** at today's rates: - **305 GBP = 354.65 EUR** - **305 GBP = 56,922 JPY**
- user
Chain two toolsPassed
1,479 tokens: 1,277 read, 202 written · 11 s · 24.8 tok/s
What is the status of each order for the customer with the email kim@example.com?
- user
What is the status of each order for the customer with the email kim@example.com?
- assistant
I'll start by looking up the customer with that email address.
find_customer({"email":"kim@example.com"}) - tool
{"customer_id":"C-1042","name":"Kim Park"} - assistant
Now let me fetch this customer's orders.
get_orders({"customer_id":"C-1042"}) - tool
{"orders":[{"order_id":"A-80","status":"cancelled"},{"order_id":"A-95","status":"delivered"}]} - assistant
Here are the order statuses for **Kim Park** (kim@example.com): - **Order A-80** — cancelled - **Order A-95** — delivered
- user
Handle a failed call honestlyPassed
1,073 tokens: 778 read, 295 written · 14 s · 24.3 tok/s
Book a table for 2 people at Taverna Sol tonight at 19:00. If that time is not free, do not book another time without asking me first.
- user
Book a table for 2 people at Taverna Sol tonight at 19:00. If that time is not free, do not book another time without asking me first.
- assistant
book_table({"restaurant":"Taverna Sol","people":2,"time":"19:00"}) - tool
{"available_times":["18:30","20:30"],"error":"fully booked at that time"} - assistant
Unfortunately, Taverna Sol is **fully booked at 19:00**. The system shows that the nearest available times are: - **18:30** - **20:30** As you requested, I haven't booked either of these. Would you like me to try one of these times, or is there anything else I can do for you?
- user
Building pages 5 of 5
A small websitePassed
2,370 tokens: 185 read, 2,185 written · 1 min 39 s · 22.3 tok/s
Build a one-page website for a bakery called "Rye Bakery". It must have a <header> containing an <h1> with the bakery's name; a <nav> with exactly 3 links; a <main> with a <section id="menu"> listing at least 4 items in a list, including Rosemary bread, Focaccia, Lemon tart and Brioche; and a <footer> with the opening hours. Output one complete HTML document and nothing else. Put all CSS and JavaScript inline. Do not load anything from another site: no external scripts, stylesheets, fonts or images. Do not link to a file by a relative path either: no src, href or url() that names a file next to the page. Do not hide anything with CSS: no display: none, visibility: hidden or opacity: 0.
Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Rye Bakery</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; } body { font-family: Georgia, "Times New Roman", serif; background-color: #fdf6ec; color: #4a3524; line-height: 1.6; min-height: 100vh; display: flex; flex-direction: column; } header { background-color: #7a4a2b; color: #fdf6ec; text-align: center; padding: 2rem 1rem 1rem; } h1 { font-size: 3rem; letter-spacing: 0.15em; text-transform: uppercase; margin-bottom: 0.5rem; } .tagline { font-style: italic; color: #e8c9a0; font-size: 1.1rem; } nav { background-color: #5c3a21; text-align: center; padding: 0.75rem; position: sticky; top: 0; z-index: 10; } nav a { color: #fdf6ec; text-decoration: none; margin: 0 1.25rem; font-size: 1.05rem; letter-spacing: 0.05em; padding: 0.25rem 0.5rem; border-bottom: 2px solid transparent; } nav a:hover, nav a:focus { border-bottom-color: #e8c9a0; color: #e8c9a0; } main { flex: 1; max-width: 760px; width: 100%; margin: 0 auto; padding: 2rem 1.5rem; } section { margin-bottom: 2.5rem; } h2 { color: #7a4a2b; font-size: 2rem; margin-bottom: 1rem; border-bottom: 3px double #c99a6a; display: inline-block; padding-bottom: 0.25rem; } #menu ul { list-style: none; } #menu li { background-color: #fffaf2; border: 1px solid #e6d3b8; border-radius: 8px; padding: 0.85rem 1.25rem; margin-bottom: 0.75rem; display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; box-shadow: 0 2px 4px rgba(74, 53, 36, 0.08); } #menu li:hover { background-color: #fff3df; } .item-name { font-weight: bold; font-size: 1.1rem; } .item-desc { font-size: 0.9rem; font-style: italic; color: #8a6a4a; } .item-price { color: #7a4a2b; font-weight: bold; white-space: nowrap; } button { background-color: #7a4a2b; color: #fdf6ec; border: none; border-radius: 6px; padding: 0.6rem 1.4rem; font-size: 1rem; font-family: inherit; cursor: pointer; } button:hover { background-color: #5c3a21; } #greeting { margin-top: 1rem; font-style: italic; color: #7a4a2b; min-height: 1.6em; } footer { background-color: #4a3524; color: #e8c9a0; text-align: center; padding: 1.5rem 1rem; } footer h3 { font-size: 1.2rem; letter-spacing: 0.1em; margin-bottom: 0.5rem; color: #fdf6ec; } footer ul { list-style: none; } footer li { font-size: 0.95rem; } </style> </head> <body> <header> <h1>Rye Bakery</h1> <p class="tagline">Baked fresh every morning since 1987</p> </header> <nav> <a href="#menu">Menu</a> <a href="#about">About</a> <a href="#hours">Hours</a> </nav> <main> <section id="menu"> <h2>Our Menu</h2> <ul> <li> <span> <span class="item-name">Rosemary bread</span><br> <span class="item-desc">Crusty sourdough loom with fresh rosemary and sea salt</span> </span> <span class="item-price">$8.50</span> </li> <li> <span> <span class="item-name">Focaccia</span><br> <span class="item-desc">Olive oil soaked, dimpled and topped with flaky salt</span> </span> <span class="item-price">$7.00</span> </li> <li> <span> <span class="item-name">Lemon tart</span><br> <span class="item-desc">Buttery shortcrust with tangy lemon curd and a dusting of sugar</span> </span> <span class="item-price">$5.50</span> </li> <li> <span> <span class="item-name">Brioche</span><br> <span class="item-desc">Rich, buttery and fluffy, perfect for toast or just tearing into</span> </span> <span class="item-price">$6.00</span> </li> <li> <span> <span class="item-name">Cinnamon knot</span><br> <span class="item-desc">Warm, swirled with cinnamon sugar and a drizzle of vanilla glaze</span> </span> <span class="item-price">$4.50</span> </li> </ul> </section> <section id="about"> <h2>About Us</h2> <p> Rye Bakery is a small, family-run bakery dedicated to slow fermentation, local flour and honest baking. Every loaf, roll and tart is made from scratch in our ovens before sunrise. </p> <button type="button" id="greetBtn">Say hello to the baker</button> <p id="greeting"></p> </section> </main> <footer id="hours"> <h3>Opening Hours</h3> <ul> <li>Monday – Friday: 7:00 AM – 6:00 PM</li> <li>Saturday: 8:00 AM – 5:00 PM</li> <li>Sunday: 8:00 AM – 2:00 PM</li> </ul> </footer> <script> document.getElementById("greetBtn").addEventListener("click", function () { var greetings = [ "Hello! Fresh bread is coming out of the oven in twenty minutes.", "Welcome to Rye Bakery! Try our lemon tart while it's still warm.", "Thanks for stopping by! The brioche was baked at five this morning." ]; document.getElementById("greeting").textContent = greetings[Math.floor(Math.random() * greetings.length)]; }); </script> </body> </html>A pricing table with a togglePassed
2,129 tokens: 194 read, 1,935 written · 1 min 19 s · 24.9 tok/s
Build a pricing page with three plans, in this order: Team at $5 a month or $50 a year, Studio at $21 a month or $210 a year and Basic at $54 a month or $540 a year. Each plan is an element with class "plan" containing an element with class "price". Show the monthly prices first. Add a <button id="billing-toggle"> that switches every price between monthly and yearly billing when clicked. Output one complete HTML document and nothing else. Put all CSS and JavaScript inline. Do not load anything from another site: no external scripts, stylesheets, fonts or images. Do not link to a file by a relative path either: no src, href or url() that names a file next to the page. Do not hide anything with CSS: no display: none, visibility: hidden or opacity: 0.
Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Pricing</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: Arial, Helvetica, sans-serif; background: linear-gradient(160deg, #f4f6fb 0%, #e8ecf5 100%); min-height: 100vh; color: #1f2430; padding: 48px 20px; } .page { max-width: 1040px; margin: 0 auto; text-align: center; } h1 { font-size: 2.4rem; margin-bottom: 12px; letter-spacing: -0.5px; } .subtitle { color: #5b6472; font-size: 1.05rem; margin-bottom: 36px; } #billing-toggle { font-size: 1rem; font-weight: 600; padding: 12px 28px; border: none; border-radius: 999px; background: #3b5bff; color: #ffffff; cursor: pointer; transition: background 0.2s ease, transform 0.1s ease; } #billing-toggle:hover { background: #2b46d6; } #billing-toggle:active { transform: scale(0.97); } .plans { display: flex; gap: 28px; justify-content: center; align-items: stretch; flex-wrap: wrap; margin-top: 44px; } .plan { background: #ffffff; border-radius: 16px; padding: 36px 30px; flex: 1 1 260px; max-width: 320px; box-shadow: 0 8px 24px rgba(31, 36, 48, 0.08); display: flex; flex-direction: column; transition: transform 0.2s ease, box-shadow 0.2s ease; } .plan:hover { transform: translateY(-6px); box-shadow: 0 16px 36px rgba(31, 36, 48, 0.14); } .plan h2 { font-size: 1.3rem; margin-bottom: 6px; } .plan .tagline { color: #7a8291; font-size: 0.9rem; margin-bottom: 22px; } .price { font-size: 2.6rem; font-weight: 700; color: #3b5bff; margin-bottom: 4px; } .price .period { font-size: 1rem; font-weight: 500; color: #7a8291; } .plan ul { list-style: none; margin: 22px 0 28px; text-align: left; flex: 1; } .plan ul li { font-size: 0.92rem; padding: 7px 0 7px 24px; position: relative; color: #414a58; } .plan ul li::before { content: "\2713"; position: absolute; left: 0; color: #3b5bff; font-weight: 700; } .plan .cta { display: block; width: 100%; padding: 12px; border: 2px solid #3b5bff; background: transparent; color: #3b5bff; border-radius: 10px; font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: background 0.2s ease, color 0.2s ease; } .plan .cta:hover { background: #3b5bff; color: #ffffff; } </style> </head> <body> <div class="page"> <h1>Simple, transparent pricing</h1> <p class="subtitle">Pick the plan that fits your workflow. Switch billing whenever you like.</p> <button id="billing-toggle" type="button">Switch to yearly billing</button> <div class="plans"> <div class="plan" data-monthly="5" data-yearly="50"> <h2>Team</h2> <p class="tagline">For small teams getting started.</p> <div class="price">$<span class="amount">5</span><span class="period">/mo</span></div> <ul> <li>Up to 5 members</li> <li>Unlimited projects</li> <li>Community support</li> </ul> <button class="cta" type="button">Choose Team</button> </div> <div class="plan" data-monthly="21" data-yearly="210"> <h2>Studio</h2> <p class="tagline">For growing studios that need more power.</p> <div class="price">$<span class="amount">21</span><span class="period">/mo</span></div> <ul> <li>Up to 25 members</li> <li>Advanced analytics</li> <li>Priority email support</li> </ul> <button class="cta" type="button">Choose Studio</button> </div> <div class="plan" data-monthly="54" data-yearly="540"> <h2>Basic</h2> <p class="tagline">For businesses that want the full package.</p> <div class="price">$<span class="amount">54</span><span class="period">/mo</span></div> <ul> <li>Unlimited members</li> <li>Custom integrations</li> <li>Dedicated account manager</li> </ul> <button class="cta" type="button">Choose Basic</button> </div> </div> </div> <script> (function () { var toggle = document.getElementById('billing-toggle'); var plans = document.querySelectorAll('.plan'); var isYearly = false; toggle.addEventListener('click', function () { isYearly = !isYearly; plans.forEach(function (plan) { var amount = plan.querySelector('.amount'); var period = plan.querySelector('.period'); var value = isYearly ? plan.dataset.yearly : plan.dataset.monthly; amount.textContent = value; period.textContent = isYearly ? '/yr' : '/mo'; }); toggle.textContent = isYearly ? 'Switch to monthly billing' : 'Switch to yearly billing'; }); })(); </script> </body> </html>An accessible sign-up formPassed
1,552 tokens: 246 read, 1,306 written · 53 s · 25.3 tok/s
Build a sign-up form for Velvet Studio. Put the brand name in a heading above the form. The form is <form id="signup"> with inputs id="name", id="email" (type email) and id="password" (type password, minlength at least 8), each with a <label for>, and a submit button. Give the form a novalidate attribute, and check the fields yourself when it is submitted. If the email is not a valid address, or the password is shorter than 8 characters, do not send the form; show a message in an element with id="status" and role="status" that says what is wrong. If the form is valid, prevent the real submission and leave the status element empty. Output one complete HTML document and nothing else. Put all CSS and JavaScript inline. Do not load anything from another site: no external scripts, stylesheets, fonts or images. Do not link to a file by a relative path either: no src, href or url() that names a file next to the page. Do not hide anything with CSS: no display: none, visibility: hidden or opacity: 0.
Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Sign Up — Velvet Studio</title> <style> body { font-family: Georgia, "Times New Roman", serif; background-color: #f7f2f5; color: #2b1e2e; display: flex; justify-content: center; padding: 2rem 1rem; margin: 0; } main { width: 100%; max-width: 30rem; background: #fffdfa; border: 1px solid #e6d9e2; border-radius: 12px; padding: 2rem; box-shadow: 0 4px 18px rgba(80, 40, 70, 0.12); } h1 { text-align: center; font-size: 1.8rem; letter-spacing: 0.05em; margin-top: 0; color: #5c2a4d; } fieldset { border: none; margin: 0; padding: 0; } .field { margin-bottom: 1.1rem; } label { display: block; font-weight: bold; margin-bottom: 0.35rem; } input[type="text"], input[type="email"], input[type="password"] { width: 100%; box-sizing: border-box; padding: 0.6rem 0.7rem; font-size: 1rem; font-family: inherit; border: 1px solid #c9b3c2; border-radius: 6px; background: #ffffff; } input:focus { outline: 2px solid #8e4a76; outline-offset: 1px; border-color: #8e4a76; } button[type="submit"] { display: block; width: 100%; padding: 0.7rem 1rem; font-size: 1.05rem; font-family: inherit; font-weight: bold; letter-spacing: 0.04em; color: #fffdfa; background: #6d3059; border: none; border-radius: 6px; cursor: pointer; } button[type="submit"]:hover { background: #58264a; } #status { margin-top: 1rem; min-height: 1.4em; padding: 0.6rem 0.8rem; border-radius: 6px; font-size: 0.95rem; color: #8a1f2d; background: #fdecee; border: 1px solid #f3c2c9; } </style> </head> <body> <main> <h1>Velvet Studio</h1> <form id="signup" novalidate> <fieldset> <div class="field"> <label for="name">Name</label> <input type="text" id="name" name="name" autocomplete="name" required> </div> <div class="field"> <label for="email">Email address</label> <input type="email" id="email" name="email" autocomplete="email" required> </div> <div class="field"> <label for="password">Password</label> <input type="password" id="password" name="password" minlength="8" autocomplete="new-password" required> </div> </fieldset> <button type="submit">Create account</button> <p id="status" role="status"></p> </form> </main> <script> (function () { var form = document.getElementById("signup"); var nameInput = document.getElementById("name"); var emailInput = document.getElementById("email"); var passwordInput = document.getElementById("password"); var status = document.getElementById("status"); var emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; form.addEventListener("submit", function (event) { var email = emailInput.value.trim(); var password = passwordInput.value; var problems = []; if (nameInput.value.trim() === "") { problems.push("Please enter your name."); } if (!emailPattern.test(email)) { problems.push("Please enter a valid email address."); } if (password.length < 8) { problems.push("Password must be at least 8 characters long."); } if (problems.length > 0) { event.preventDefault(); status.textContent = problems.join(" "); } else { event.preventDefault(); status.textContent = ""; } }); })(); </script> </body> </html>A to-do app that remembersPassed
1,663 tokens: 179 read, 1,484 written · 59 s · 25.3 tok/s
Build a to-do list app called "Garage checklist". Show its name in a heading. The app has an <input id="new-task">, a <button id="add"> and a <ul id="tasks">. Clicking add appends the text as an <li> with its own remove button. Save the list in localStorage under the key "todos" and load it again when the page opens. Output one complete HTML document and nothing else. Put all CSS and JavaScript inline. Do not load anything from another site: no external scripts, stylesheets, fonts or images. Do not link to a file by a relative path either: no src, href or url() that names a file next to the page. Do not hide anything with CSS: no display: none, visibility: hidden or opacity: 0.
Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Garage checklist</title> <style> body { font-family: Arial, Helvetica, sans-serif; background-color: #f4f4f4; margin: 0; padding: 20px; } .app { max-width: 480px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 6px rgba(0,0,0,0.15); padding: 20px; } h1 { text-align: center; color: #333333; margin-top: 0; } .input-row { display: flex; gap: 8px; margin-bottom: 16px; } #new-task { flex: 1; padding: 8px; font-size: 16px; border: 1px solid #cccccc; border-radius: 4px; } #add { padding: 8px 16px; font-size: 16px; background-color: #2c6e49; color: #ffffff; border: none; border-radius: 4px; cursor: pointer; } #add:hover { background-color: #23573b; } #tasks { list-style: none; padding: 0; margin: 0; } #tasks li { display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px; margin-bottom: 6px; background-color: #f9f9f9; border: 1px solid #e0e0e0; border-radius: 4px; word-break: break-word; } .task-text { flex: 1; } .remove-btn { background-color: #b23a3a; color: #ffffff; border: none; border-radius: 4px; padding: 4px 10px; cursor: pointer; font-size: 14px; } .remove-btn:hover { background-color: #8f2e2e; } .empty-message { text-align: center; color: #888888; padding: 12px 0; } </style> </head> <body> <div class="app"> <h1>Garage checklist</h1> <div class="input-row"> <input id="new-task" type="text" placeholder="Add a task..." autocomplete="off"> <button id="add">Add</button> </div> <ul id="tasks"></ul> <p id="empty" class="empty-message">No tasks yet.</p> </div> <script> (function () { var input = document.getElementById('new-task'); var addButton = document.getElementById('add'); var tasksList = document.getElementById('tasks'); var emptyMessage = document.getElementById('empty'); var STORAGE_KEY = 'todos'; function loadTodos() { try { var raw = localStorage.getItem(STORAGE_KEY); if (raw) { var parsed = JSON.parse(raw); if (Array.isArray(parsed)) { return parsed; } } } catch (e) { // Ignore corrupted storage } return []; } function saveTodos(todos) { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(todos)); } catch (e) { // Storage unavailable; continue in memory } } function getTodos() { var items = tasksList.querySelectorAll('li'); var todos = []; for (var i = 0; i < items.length; i++) { todos.push(items[i].getAttribute('data-text')); } return todos; } function updateEmptyMessage() { emptyMessage.textContent = tasksList.children.length === 0 ? 'No tasks yet.' : ''; } function addTask(text) { var li = document.createElement('li'); li.setAttribute('data-text', text); var span = document.createElement('span'); span.className = 'task-text'; span.textContent = text; var removeButton = document.createElement('button'); removeButton.className = 'remove-btn'; removeButton.textContent = 'Remove'; removeButton.setAttribute('aria-label', 'Remove task: ' + text); removeButton.addEventListener('click', function () { li.remove(); saveTodos(getTodos()); updateEmptyMessage(); }); li.appendChild(span); li.appendChild(removeButton); tasksList.appendChild(li); saveTodos(getTodos()); updateEmptyMessage(); } function handleAdd() { var text = input.value.trim(); if (text === '') { return; } addTask(text); input.value = ''; input.focus(); } addButton.addEventListener('click', handleAdd); input.addEventListener('keydown', function (event) { if (event.key === 'Enter') { handleAdd(); } }); // Load saved tasks on page open var saved = loadTodos(); for (var i = 0; i < saved.length; i++) { if (typeof saved[i] === 'string' && saved[i].trim() !== '') { addTask(saved[i].trim()); } } updateEmptyMessage(); })(); </script> </body> </html>A bar chart in SVGPassed
1,157 tokens: 230 read, 927 written · 39 s · 24.4 tok/s
Draw an inline SVG bar chart of lattes sold, in this order: Mon 35, Tue 30, Wed 34, Thu 8 and Fri 9. Give the <svg> a width and a height, and a <title> or an aria-label. Each bar is a <rect class="bar"> whose height attribute is proportional to its value, and every bar is inside the <svg>. Each bar is labelled with its day or month in a <text> element under the bar. Write the bars and labels directly in the SVG markup, not with JavaScript. Do not move, resize or hide them with a transform or with CSS. Output one complete HTML document and nothing else. Put all CSS and JavaScript inline. Do not load anything from another site: no external scripts, stylesheets, fonts or images. Do not link to a file by a relative path either: no src, href or url() that names a file next to the page. Do not hide anything with CSS: no display: none, visibility: hidden or opacity: 0.
Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Lattes Sold</title> <style> body { font-family: sans-serif; margin: 2rem; } .bar { fill: #b07a45; stroke: #6f4a24; stroke-width: 1; } .bar-label { font-size: 14px; text-anchor: middle; fill: #222; } </style> </head> <body> <svg width="400" height="360" xmlns="http://www.w3.org/2000/svg" aria-label="Bar chart of lattes sold: Mon 35, Tue 30, Wed 34, Thu 8, Fri 9"> <title>Lattes sold Monday to Friday</title> <rect class="bar" x="30" y="40" width="40" height="280"></rect> <text class="bar-label" x="50" y="345">Mon</text> <rect class="bar" x="100" y="80" width="40" height="240"></rect> <text class="bar-label" x="120" y="345">Tue</text> <rect class="bar" x="170" y="48" width="40" height="272"></rect> <text class="bar-label" x="190" y="345">Wed</text> <rect class="bar" x="240" y="256" width="40" height="64"></rect> <text class="bar-label" x="260" y="345">Thu</text> <rect class="bar" x="310" y="248" width="40" height="72"></rect> <text class="bar-label" x="330" y="345">Fri</text> </svg> </body> </html>
Building games 3 of 4
Build 2048Passed
4,391 tokens: 457 read, 3,934 written · 2 min 41 s · 24.8 tok/s
Build the game 2048 as one web page, playable with the arrow keys, with the board drawn on the page. In <script id="game">, define createGame() returning an object with move(dir) and state(). dir is "up", "down", "left" or "right". state() returns {board, score, over}: board is 4 rows of 4 numbers, top row first (0 is an empty cell), score is a number, over is a boolean. The rules, exactly: 1. The board starts as this one, then a 2 is put in each of the first two empty cells in reading order (row by row from the top, left to right). The score starts at 0. [0, 8, 0, 0] [2, 2, 0, 4] [0, 0, 0, 0] [0, 0, 0, 2] 2. A move slides every tile as far as it goes toward dir. Two tiles of the same value that meet merge into one tile of their sum, nearest the side they move toward first: moving left, [2,2,2,2] becomes [4,4,0,0] and [2,2,2,0] becomes [4,2,0,0]. A tile made by a merge does not merge again in the same move. 3. Each merge adds the new tile's value to the score. 4. If a move changed the board, a 2 is put in the first empty cell in reading order. A move that changes nothing does nothing. 5. over is true when no move would change the board; then moves do nothing. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and plays the game through createGame(). Wire the page in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>2048</title> <style> body { margin: 0; padding: 20px; background: #faf8ef; font-family: "Helvetica Neue", Arial, sans-serif; color: #776e65; display: flex; flex-direction: column; align-items: center; } h1 { margin: 0 0 10px; font-size: 42px; } .hud { margin-bottom: 12px; font-size: 18px; } .hud .box { background: #bbada0; color: #fff; border-radius: 6px; padding: 8px 18px; font-weight: bold; } canvas { background: #bbada0; border-radius: 8px; } #msg { margin-top: 12px; font-size: 18px; font-weight: bold; min-height: 22px; } #msg.gameover { color: #f65e3b; } </style> </head> <body> <h1>2048</h1> <div class="hud">Score: <span class="box" id="score">0</span></div> <canvas id="board" width="424" height="424"></canvas> <div id="msg"></div> <script id="game"> function createGame() { var N = 4; var board = [ [0, 8, 0, 0], [2, 2, 0, 4], [0, 0, 0, 0], [0, 0, 0, 2] ]; var score = 0; var over = false; function firstEmpty() { for (var r = 0; r < N; r++) { for (var c = 0; c < N; c++) { if (board[r][c] === 0) return [r, c]; } } return null; } function spawn() { var p = firstEmpty(); if (p) board[p[0]][p[1]] = 2; } // Put a 2 in each of the first two empty cells in reading order. spawn(); spawn(); // Slide a line toward index 0, merging equal neighbours once. function lineMove(arr) { var tiles = []; for (var i = 0; i < arr.length; i++) { if (arr[i] !== 0) tiles.push(arr[i]); } var out = []; var gained = 0; var j = 0; while (j < tiles.length) { if (j + 1 < tiles.length && tiles[j] === tiles[j + 1]) { var v = tiles[j] * 2; out.push(v); gained += v; j += 2; } else { out.push(tiles[j]); j++; } } while (out.length < N) out.push(0); return { line: out, gained: gained }; } function applyMove(dir) { var nb = board.map(function (row) { return row.slice(); }); var gained = 0; for (var i = 0; i < N; i++) { var line; if (dir === "left") { line = board[i].slice(); } else if (dir === "right") { line = [board[i][3], board[i][2], board[i][1], board[i][0]]; } else if (dir === "up") { line = [board[0][i], board[1][i], board[2][i], board[3][i]]; } else { line = [board[3][i], board[2][i], board[1][i], board[0][i]]; } var res = lineMove(line); gained += res.gained; for (var j = 0; j < N; j++) { var r, c; if (dir === "left") { r = i; c = j; } else if (dir === "right"){ r = i; c = N - 1 - j; } else if (dir === "up") { r = j; c = i; } else { r = N - 1 - j; c = i; } nb[r][c] = res.line[j]; } } var changed = false; for (var r2 = 0; r2 < N && !changed; r2++) { for (var c2 = 0; c2 < N && !changed; c2++) { if (nb[r2][c2] !== board[r2][c2]) changed = true; } } return { nb: nb, gained: gained, changed: changed }; } function anyMoveWorks() { var dirs = ["up", "down", "left", "right"]; for (var d = 0; d < dirs.length; d++) { if (applyMove(dirs[d]).changed) return true; } return false; } function move(dir) { if (over) return; var res = applyMove(dir); if (res.changed) { board = res.nb; score += res.gained; spawn(); if (!anyMoveWorks()) over = true; } } function state() { return { board: board.map(function (row) { return row.slice(); }), score: score, over: over }; } return { move: move, state: state }; } </script> <script> (function () { var game = createGame(); var canvas = document.getElementById("board"); var ctx = canvas.getContext("2d"); var CELL = 96, GAP = 8; var COLORS = { 2: "#eee4da", 4: "#ede0c8", 8: "#f2b179", 16: "#f59563", 32: "#f67c5f", 64: "#f65e3b", 128: "#edcf72", 256: "#edcc61", 512: "#edc850", 1024: "#edc53f", 2048: "#edc22e" }; function roundedRect(x, y, w, h, rad) { ctx.beginPath(); if (ctx.roundRect) { ctx.roundRect(x, y, w, h, rad); } else { ctx.rect(x, y, w, h); } ctx.fill(); } function draw() { var s = game.state(); ctx.fillStyle = "#bbada0"; ctx.fillRect(0, 0, canvas.width, canvas.height); for (var r = 0; r < 4; r++) { for (var c = 0; c < 4; c++) { var x = GAP + c * (CELL + GAP); var y = GAP + r * (CELL + GAP); var v = s.board[r][c]; ctx.fillStyle = v === 0 ? "#cdc1b4" : (COLORS[v] || "#3c3a32"); roundedRect(x, y, CELL, CELL, 6); if (v) { ctx.fillStyle = v <= 4 ? "#776e65" : "#f9f6f2"; ctx.font = "bold " + (v >= 1000 ? 32 : v >= 100 ? 40 : 52) + "px 'Helvetica Neue', Arial, sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText(String(v), x + CELL / 2, y + CELL / 2); } } } document.getElementById("score").textContent = s.score; var msg = document.getElementById("msg"); msg.textContent = s.over ? "Game over!" : "Use the arrow keys."; msg.className = s.over ? "gameover" : ""; } var KEY_DIRS = { ArrowUp: "up", ArrowDown: "down", ArrowLeft: "left", ArrowRight: "right" }; document.addEventListener("keydown", function (e) { var dir = KEY_DIRS[e.key]; if (dir) { e.preventDefault(); game.move(dir); draw(); } }); draw(); })(); </script> </body> </html>Build SnakeFailed
3,342 tokens: 455 read, 2,887 written · 2 min 1 s · 24.3 tok/s
Build Snake as one web page on a 10 by 10 grid, playable with the arrow keys (one key press, one step), with the grid drawn on the page. In <script id="game">, define createGame() returning an object with step(dir) and state(). dir is "up", "down", "left" or "right". state() returns {snake, food, score, over}: snake is a list of [x, y] cells, head first; food is [x, y]; score is a number; over is a boolean. x is the column (0 to 9, left to right), y the row (0 to 9, top to bottom); up is y - 1. The rules, exactly: 1. The game starts with snake [[6, 3], [7, 3], [8, 3]], moving left, food at [8, 1], score 0. 2. step(dir): if dir is the opposite of the current direction it is ignored and the snake keeps going; otherwise dir becomes the current direction. The head moves one cell that way. 3. If the new head cell holds the food, the snake grows: its tail stays. Otherwise the tail cell is freed first. 4. If the new head is off the grid or on a cell of the snake (after rule 3), the game is over: over becomes true and nothing else changes. Once over, step does nothing. 5. Eating adds 1 to the score, and the next food goes to the first empty cell in reading order (row by row from the top, left to right) after the new head's cell, wrapping from [9, 9] to [0, 0]. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and plays the game through createGame(). Wire the page in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Snake</title> <style> body { font-family: monospace; background: #1b1b2f; color: #e0e0e0; display: flex; flex-direction: column; align-items: center; padding-top: 24px; } h1 { font-size: 20px; margin: 0 0 8px; } #score { margin-bottom: 12px; font-size: 16px; } #board { display: grid; grid-template-columns: repeat(10, 32px); grid-template-rows: repeat(10, 32px); gap: 2px; background: #10101c; padding: 4px; border: 2px solid #444466; } .cell { background: #2a2a44; } .cell.snake { background: #4caf50; } .cell.head { background: #a5d6a7; } .cell.food { background: #ff5252; } #msg { margin-top: 12px; height: 20px; font-size: 16px; color: #ff8a80; } .hint { margin-top: 6px; font-size: 12px; color: #8888aa; } </style> </head> <body> <h1>Snake</h1> <div id="score">Score: 0</div> <div id="board"></div> <div id="msg"></div> <div class="hint">Arrow keys: one press, one step</div> <script id="game"> function createGame() { const DELTAS = { up: [0, -1], down: [0, 1], left: [-1, 0], right: [1, 0] }; const OPPOSITE = { up: 'down', down: 'up', left: 'right', right: 'left' }; const snake = [[6, 3], [7, 3], [8, 3]]; let dir = 'left'; let food = [8, 1]; let score = 0; let over = false; function step(d) { if (over) return; if (d !== OPPOSITE[dir]) dir = d; const head = snake[0]; const nx = head[0] + DELTAS[dir][0]; const ny = head[1] + DELTAS[dir][1]; if (nx < 0 || nx > 9 || ny < 0 || ny > 9) { over = true; return; } const eating = (nx === food[0] && ny === food[1]); const body = snake.slice(1); if (!eating) body.pop(); // tail freed first const bodyWithHead = [[nx, ny]].concat(body); if (bodyWithHead.slice(1).some(function (c) { return c[0] === nx && c[1] === ny; })) { over = true; return; } snake.length = 0; snake.push.apply(snake, bodyWithHead); if (eating) { score += 1; let i = (ny * 10 + nx + 1) % 100; for (let k = 0; k < 100; k++) { const fx = i % 10; const fy = Math.floor(i / 10); const occupied = snake.some(function (c) { return c[0] === fx && c[1] === fy; }); if (!occupied) { food = [fx, fy]; return; } i = (i + 1) % 100; } } } function state() { return { snake: snake.map(function (c) { return [c[0], c[1]]; }), food: [food[0], food[1]], score: score, over: over }; } return { step: step, state: state }; } </script> <script> (function () { const game = createGame(); const board = document.getElementById('board'); const scoreEl = document.getElementById('score'); const msgEl = document.getElementById('msg'); const cells = []; for (let i = 0; i < 100; i++) { const d = document.createElement('div'); d.className = 'cell'; board.appendChild(d); cells.push(d); } function render() { const s = game.state(); cells.forEach(function (c) { c.className = 'cell'; }); s.snake.forEach(function (cell, i) { cells[cell[1] * 10 + cell[0]].className = 'cell ' + (i === 0 ? 'head' : 'snake'); }); cells[s.food[1] * 10 + s.food[0]].classList.add('food'); scoreEl.textContent = 'Score: ' + s.score; msgEl.textContent = s.over ? 'Game over' : ''; } const KEYMAP = { ArrowUp: 'up', ArrowDown: 'down', ArrowLeft: 'left', ArrowRight: 'right' }; document.addEventListener('keydown', function (e) { if (KEYMAP[e.key]) { e.preventDefault(); game.step(KEYMAP[e.key]); render(); } }); render(); })(); </script> </body> </html> ```Box-pushing puzzlePassed
9,720 tokens: 1,130 read, 8,590 written · 6 min 17 s · 23.1 tok/s
Build a box-pushing puzzle as one web page on an 8 by 7 grid, playable with the arrow keys, with the level drawn on the page. Give the page and its heading the title Box-pushing puzzle. In <script id="game">, define createGame() returning an object with walk(dir) and state(). dir is "up", "down", "left" or "right". state() returns {player, boxes, pushes, steps, solved}: player is [x, y]; boxes is a list of [x, y] sorted by row, then column; pushes and steps are numbers; solved is a boolean. x is the column (0 to 7, left to right), y the row (0 to 6, top to bottom); up is y - 1. The level, row 0 first, 8 characters to a row (a space is empty floor; the outer ring is all wall): ``` ######## # #+# # * # # $ # # # # # # ######## ``` # wall, space floor, . goal, $ box, * box on a goal, @ player, + player on a goal. The rules, exactly: 1. The game starts with this level, steps 0, pushes 0 and solved false. Walls and goals never change. 2. walk(dir) moves the player one cell in dir. If that cell is a wall, nothing changes and nothing is counted. A goal is floor, so the player can stand on one. 3. If that cell holds a box, the box moves one cell further in dir and the player takes the box's old cell. This push happens only if the cell beyond the box is empty floor or a goal: not a wall and not another box. Otherwise nothing changes and nothing is counted. 4. A walk that moves the player adds 1 to steps. A push is a walk too, so it adds 1 to pushes as well. 5. solved is true when every box is on a goal. Once solved, walk does nothing. The page: the arrow keys do the same walks as walk(dir), one walk for each key press (a key that repeats while held walks once). Four buttons with data-dir="up", data-dir="down", data-dir="left" and data-dir="right" do the same walks. Label them Up, Down, Left and Right, laid out like the arrow keys: Up above Down, with Left, Down and Right in one row. A button with id="restart", labelled Restart, starts the level over, with steps and pushes back at 0. The board is an element with id="board". It holds one element per cell, 56 in all, row by row from the top, 8 to a row, and nothing else. Each cell has role="img" and an aria-label that names what it holds: wall, empty floor, empty goal, box, box on a goal, you or you on a goal. Every cell except empty floor also shows a visible character as its text, so that a wall, a goal, a box and you can each be seen (the character is yours to choose). Show the steps in an element with id="steps" and the pushes in one with id="pushes", each as a plain number. The status line is an element with id="status". Until the level is solved, it must not say that it is solved (a line such as Not solved yet is fine). Once it is, it says solved, with the number of steps next to the word steps and the number of pushes next to the word pushes, for example: Solved in 12 steps with 3 pushes. A tenth of a second after each key press, button press or Restart, the board, the steps, the pushes and the status line show what state() says. A page may draw on the next animation frame or after a timer. The page must not use eval or Function, must not give a timer a string of text (a timer takes a function), must not add a script element to the page, must not set an event attribute such as onclick from text, and must not make network requests or load anything from another site: no fetch, XMLHttpRequest, WebSocket, EventSource, sendBeacon or importScripts, and no image or file from another site. The whole page must be under 65,536 characters, and the script with id="game" under 20,000 characters. Light background; walls dark, goals ringed, boxes and the player easy to tell apart. Tell a box on a goal from one off a goal by a mark or shape, not by colour alone. The two scripts share one global scope, so give the page's copy of the map another name than the logic's (a const MAP in both stops the second script with an error), or wrap the page's script in a function. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and plays the game through createGame(). Wire the page in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Box-pushing puzzle</title> <style> body{ background:#f7f4ee; color:#222; font-family:system-ui,-apple-system,"Segoe UI",sans-serif; display:flex;flex-direction:column;align-items:center; padding:18px; } h1{font-size:1.4rem;margin:0 0 14px;} #board{ display:grid; grid-template-columns:repeat(8,46px); grid-auto-rows:46px; gap:3px; margin:10px 0 16px; } .cell{ display:flex;align-items:center;justify-content:center; font-size:24px;font-weight:bold;line-height:1; background:#efe8da;border-radius:8px; } .wall{background:#2e2e33;color:#f3f3f3;border-radius:5px;} .goal{box-shadow:inset 0 0 0 3px #c98a3d;} .box{color:#9a5a10;} .you{color:#1746b8;} .stats{display:flex;gap:28px;font-size:1.05rem;margin-bottom:8px;} .stats span{font-weight:bold;} #status{margin:6px 0 14px;font-size:1.05rem;min-height:1.3em;} #controls{ display:grid; grid-template-columns:repeat(3,68px); grid-auto-rows:44px; gap:6px; margin-bottom:12px; } #controls button{ font-size:1rem; border:1px solid #999; border-radius:8px; background:#fff; cursor:pointer; } #controls button:hover{background:#eee;} #controls [data-dir="up"]{grid-column:2;} #controls [data-dir="left"]{grid-row:2;} #controls [data-dir="down"]{grid-row:2;grid-column:2;} #controls [data-dir="right"]{grid-row:2;} #restart{ font-size:1rem;padding:8px 18px; border:1px solid #777;border-radius:8px; background:#fff;cursor:pointer; } #restart:hover{background:#eee;} </style> </head> <body> <h1>Box-pushing puzzle</h1> <div id="board"></div> <div class="stats"> <span>Steps: <span id="steps">0</span></span> <span>Pushes: <span id="pushes">0</span></span> </div> <p id="status">Not solved yet.</p> <div id="controls"> <button type="button" data-dir="up">Up</button> <button type="button" data-dir="left">Left</button> <button type="button" data-dir="down">Down</button> <button type="button" data-dir="right">Right</button> </div> <button type="button" id="restart">Restart</button> <script id="game"> "use strict"; const MAP = [ "########", "# #+#", "# * #", "# $ #", "# # #", "# #", "########" ]; const W = 8, H = 7; const DIRS = { up:[0,-1], down:[0,1], left:[-1,0], right:[1,0] }; function byRC(a, b){ return a[1] - b[1] || a[0] - b[0]; } function createGame(){ const walls = new Set(); const goals = new Set(); let player = null; const boxes = []; for (let y = 0; y < H; y++) for (let x = 0; x < W; x++){ const c = MAP[y][x]; if (c === "#") walls.add(y * W + x); if (c === "." || c === "*" || c === "+" || c === "@") goals.add(y * W + x); } for (let y = 0; y < H; y++) for (let x = 0; x < W; x++){ const c = MAP[y][x]; if (c === "$" || c === "*") boxes.push([x, y]); if (c === "@" || c === "+") player = [x, y]; } boxes.sort(byRC); let steps = 0; let pushes = 0; let solved = false; function walk(dir){ if (solved) return; const d = DIRS[dir]; if (!d) return; const nx = player[0] + d[0]; const ny = player[1] + d[1]; const k = ny * W + nx; if (walls.has(k)) return; let bi = -1; for (let i = 0; i < boxes.length; i++){ if (boxes[i][0] === nx && boxes[i][1] === ny){ bi = i; break; } } if (bi >= 0){ const bx = nx + d[0]; const by = ny + d[1]; const bk = by * W + bx; if (walls.has(bk)) return; for (let i = 0; i < boxes.length; i++){ if (i !== bi && boxes[i][0] === bx && boxes[i][1] === by) return; } boxes[bi] = [bx, by]; pushes++; } player = [nx, ny]; steps++; boxes.sort(byRC); solved = true; for (const b of boxes){ if (!goals.has(b[1] * W + b[0])){ solved = false; break; } } } function state(){ return { player: player.slice(), boxes: boxes.map(function(b){ return b.slice(); }), pushes: pushes, steps: steps, solved: solved }; } return { walk: walk, state: state }; } </script> <script> (function(){ "use strict"; const LEVEL = [ "########", "# #+#", "# * #", "# $ #", "# # #", "# #", "########" ]; const W = 8, H = 7; const goals = new Set(); for (let y = 0; y < H; y++) for (let x = 0; x < W; x++){ const c = LEVEL[y][x]; if (c === "." || c === "*" || c === "+" || c === "@") goals.add(y * W + x); } const board = document.getElementById("board"); const cells = []; for (let i = 0; i < W * H; i++){ const d = document.createElement("div"); d.className = "cell"; d.setAttribute("role", "img"); board.appendChild(d); cells.push(d); } let game = createGame(); let timer = null; function render(){ const s = game.state(); const boxIdx = new Set(); for (const b of s.boxes) boxIdx.add(b[1] * W + b[0]); const pk = s.player[1] * W + s.player[0]; for (let y = 0; y < H; y++) for (let x = 0; x < W; x++){ const i = y * W + x; const el = cells[i]; const c = LEVEL[y][x]; const isWall = (c === "#"); const isGoal = goals.has(i); const isBox = boxIdx.has(i); const isPlayer = (i === pk); let label, text = "", cls = "cell"; if (isWall){ label = "wall"; text = "#"; cls += " wall"; } else if (isPlayer){ label = isGoal ? "you on a goal" : "you"; text = "\u25CF"; cls += " you"; if (isGoal) cls += " goal"; } else if (isBox){ label = isGoal ? "box on a goal" : "box"; text = isGoal ? "\u25A0" : "\u25A1"; cls += " box"; if (isGoal) cls += " goal"; } else if (isGoal){ label = "empty goal"; text = "\u00B7"; cls += " goal"; } else { label = "empty floor"; } el.className = cls; el.textContent = text; el.setAttribute("aria-label", label); } document.getElementById("steps").textContent = s.steps; document.getElementById("pushes").textContent = s.pushes; document.getElementById("status").textContent = s.solved ? "Solved in " + s.steps + " steps with " + s.pushes + " pushes." : "Not solved yet."; } function scheduleRender(){ if (timer !== null) clearTimeout(timer); timer = setTimeout(render, 100); } function doWalk(dir){ game.walk(dir); scheduleRender(); } document.querySelectorAll("button[data-dir]").forEach(function(btn){ btn.addEventListener("click", function(){ doWalk(btn.getAttribute("data-dir")); }); }); document.getElementById("restart").addEventListener("click", function(){ game = createGame(); scheduleRender(); }); const KEYS = { ArrowUp:"up", ArrowDown:"down", ArrowLeft:"left", ArrowRight:"right" }; window.addEventListener("keydown", function(e){ if (e.repeat) return; const dir = KEYS[e.key]; if (dir){ e.preventDefault(); doWalk(dir); } }); render(); })(); </script> </body> </html>MinesweeperPassed
5,963 tokens: 1,429 read, 4,534 written · 3 min 53 s · 20 tok/s
Build Minesweeper as one web page: a 9 by 9 board with 10 mines, in the layout below, with the board drawn on the page. In <script id="game">, define createGame() returning an object with press(move) and state(). The site plays the game more than once, calling createGame() again each time, so every game starts from the layout. move is an array [kind, row, col]: kind is "open" or "flag", row is 0 (top) to 8 (bottom), col is 0 (left) to 8 (right). state() returns {cells, status, mines_left}: cells is 9 strings of 9 characters, one per row from the top. A character is "#" for a hidden cell, "F" for a flagged cell, "." for an opened cell with no mines around it, "1" to "8" for an opened cell with that many mines among the 8 cells around it, and "*" for a mine after a loss. status is "playing", "won" or "lost". mines_left is 10 minus the number of flagged cells, and can be negative. The mines, row by row from the top. In this layout * is a mine and . is a safe cell. row 0 ......... row 1 .*....... row 2 .*.*..... row 3 ......... row 4 ......... row 5 ...*...*. row 6 ........* row 7 ....***.. row 8 ......*.. The rules, exactly: 1. The game starts with every cell hidden, no flags, and status "playing". 2. press(["open", r, c]) on a hidden cell opens it. If it is a mine, status becomes "lost" and every mine shows "*", flagged or not. Otherwise the cell shows its number, or "." when no mine is among the cells around it. 3. An opened cell with no mines around it also opens each hidden, unflagged cell around it (8 directions). Each of those with no mines around it opens its own hidden, unflagged neighbours the same way, repeatedly, until nothing more opens. A flagged cell is never opened this way, and nothing spreads from it. A numbered cell opens, but nothing spreads from it. 4. press(["open", r, c]) on a flagged cell or an opened cell does nothing. 5. press(["flag", r, c]) on a hidden cell flags it. On a flagged cell it removes the flag, and the cell is hidden again. On an opened cell it does nothing. 6. status becomes "won" when every cell without a mine is opened, however the last cell is opened. A flag does not count: a flagged cell without a mine must be unflagged and opened. After a win every mine shows "F" and counts as flagged, whether or not the player flagged it, so mines_left is 0. 7. Once status is "won" or "lost", press does nothing. After a loss a flag still counts in mines_left, even on a mine that shows "*", and a flag on a safe cell still shows "F". The page: a title, a short paragraph of rules, then one white panel holding a status line, a Flag mode button and the board, on a warm off-white page. The type is the system sans-serif (font-family: system-ui, sans-serif); load no font. Give these parts these names, so the site can read them: - an element with role="status": it shows "Mines left" and mines_left as a number, with a minus sign when it is below zero, then the status word, "Playing", "Won" (green) or "Lost" (red); - a button with id="flag-mode": it starts with the text "Flag mode: off" and aria-pressed="false". When it is on, its text is "Flag mode: on", aria-pressed="true", and it is drawn in the pink accent; - the board, which is either 81 cell buttons, each with data-row (0 at the top to 8) and data-col (0 at the left to 8), or one canvas that draws all of it, with the id board: 324 pixels across and down (set its width and height attributes), nine squares of 36 pixels each way, row 0 at the top and column 0 at the left. On a canvas, a click or a right-click acts on the square under the pointer: find the square from the event's offsetX and offsetY, each scaled by the canvas's width over its clientWidth (or its height over its clientHeight), since a phone may draw the canvas smaller. A click on a cell calls press(["open", row, col]) for that cell, unless Flag mode is on: then it calls press(["flag", row, col]). A right-click on a cell (the contextmenu event) calls press(["flag", row, col]) and prevents the browser's own menu. Draw the board from state() after every press: a hidden or empty cell shows no text, a numbered cell shows its number, and a flag or a mine shows a mark with text in it (a symbol, or a word hidden from sight). On a canvas, clear the whole canvas and draw it again after every press, the cells in reading order (row 0 first, columns left to right): a numbered cell as its number in text, a flag or a mine as one short mark in text (F, *, or another plain symbol), and a hidden or empty cell as nothing; the canvas draws nothing else. Flags and mines are simple marks, not emoji. The page fits a phone with no sideways scrolling. A reload of the page starts a new game: every cell is hidden, no flag is set, Flag mode is off and the status reads "Playing", so nothing from the last load is kept. The keyboard is welcome but not checked: Tab moves between cells, Enter or Space opens one, and F flags it. The page runs its own code only: no eval, no Function(), no timer given as text, and no network request (fetch, XMLHttpRequest, WebSocket, EventSource, sendBeacon or importScripts). It loads nothing from another site. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and plays the game through createGame(). Wire the page in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Minesweeper</title> <style> html, body { margin: 0; padding: 0; } body { background: #f7f1e5; color: #2b2620; font-family: system-ui, sans-serif; padding: 16px; display: flex; flex-direction: column; align-items: center; } h1 { font-size: 28px; margin: 8px 0 12px; } p.rules { max-width: 420px; font-size: 14px; line-height: 1.45; margin: 0 0 16px; } #panel { background: #ffffff; border-radius: 10px; padding: 14px; box-shadow: 0 1px 4px rgba(0,0,0,0.12); width: fit-content; max-width: 100%; } #status { font-size: 15px; margin-bottom: 10px; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; } #status .word { font-weight: 600; } #status .word.won { color: #1a7f37; } #status .word.lost { color: #c0392b; } #flag-mode { font-family: system-ui, sans-serif; font-size: 14px; padding: 6px 12px; border-radius: 6px; border: 1px solid #b9ad99; background: #efeadf; color: #2b2620; cursor: pointer; margin-bottom: 12px; } #flag-mode.on { background: #ff5fa2; border-color: #ff5fa2; color: #ffffff; } #board { display: grid; grid-template-columns: repeat(9, 36px); grid-template-rows: repeat(9, 36px); width: 324px; height: 324px; } #board button { width: 36px; height: 36px; margin: 0; padding: 0; font-family: system-ui, sans-serif; font-size: 18px; font-weight: 600; display: flex; align-items: center; justify-content: center; border: 1px solid #cfc4b0; background: #e9e2d2; color: #2b2620; cursor: pointer; box-sizing: border-box; } #board button:hover { background: #f2ecdd; } #board button.open { background: #fbf8f1; cursor: default; } #board button.flag { background: #ffe1ee; color: #d6336c; } #board button.mine { background: #fbd5cd; color: #b03024; } </style> </head> <body> <h1>Minesweeper</h1> <p class="rules">A 9 by 9 field hides 10 mines. Click a cell to open it; if it is empty, its neighbours open too. Right-click a hidden cell (or use Flag mode) to plant a flag on a suspected mine. Open every safe cell to win; touch a mine and you lose.</p> <div id="panel"> <div role="status" id="status"></div> <button id="flag-mode" aria-pressed="false">Flag mode: off</button> <div id="board"></div> </div> <script id="game"> function createGame() { var LAYOUT = [ ".........", ".*.......", ".*.*.....", ".........", ".........", "...*...*.", "........*", "....***..", "......*.." ]; var N = 9; var TOTAL_MINES = 10; var mine = []; var opened = []; var flagged = []; var i, j; for (i = 0; i < N; i++) { mine.push([]); opened.push([]); flagged.push([]); for (j = 0; j < N; j++) { mine[i].push(LAYOUT[i].charAt(j) === "*"); opened[i].push(false); flagged[i].push(false); } } var status = "playing"; function inBoard(r, c) { return r >= 0 && r < N && c >= 0 && c < N; } function neighbourCount(r, c) { var count = 0; var dr, dc; for (dr = -1; dr <= 1; dr++) { for (dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; var rr = r + dr, cc = c + dc; if (inBoard(rr, cc) && mine[rr][cc]) count++; } } return count; } function allSafeOpened() { var r, c; for (r = 0; r < N; r++) { for (c = 0; c < N; c++) { if (!mine[r][c] && !opened[r][c]) return false; } } return true; } function press(move) { if (status !== "playing") return; var kind = move[0]; var r = move[1]; var c = move[2]; if (!inBoard(r, c)) return; if (kind === "flag") { if (!opened[r][c]) { flagged[r][c] = !flagged[r][c]; } return; } if (kind !== "open") return; if (opened[r][c] || flagged[r][c]) return; if (mine[r][c]) { status = "lost"; return; } var stack = [[r, c]]; opened[r][c] = true; while (stack.length > 0) { var cell = stack.pop(); var cr = cell[0], cc = cell[1]; if (neighbourCount(cr, cc) !== 0) continue; var dr, dc, nr, nc; for (dr = -1; dr <= 1; dr++) { for (dc = -1; dc <= 1; dc++) { if (dr === 0 && dc === 0) continue; nr = cr + dr; nc = cc + dc; if (!inBoard(nr, nc)) continue; if (opened[nr][nc] || flagged[nr][nc]) continue; if (mine[nr][nc]) continue; opened[nr][nc] = true; stack.push([nr, nc]); } } } if (allSafeOpened()) status = "won"; } function state() { var cells = []; var flags = 0; var r, c, ch, row; for (r = 0; r < N; r++) { row = ""; for (c = 0; c < N; c++) { if (flagged[r][c]) flags++; if (status === "lost" && mine[r][c]) { ch = "*"; } else if (status === "won" && mine[r][c]) { ch = "F"; } else if (flagged[r][c]) { ch = "F"; } else if (opened[r][c]) { ch = String(neighbourCount(r, c)); if (ch === "0") ch = "."; } else { ch = "#"; } row += ch; } cells.push(row); } var mines_left; if (status === "won") { mines_left = 0; } else { mines_left = TOTAL_MINES - flags; } return { cells: cells, status: status, mines_left: mines_left }; } return { press: press, state: state }; } </script> <script> (function () { "use strict"; var game = createGame(); var flagMode = false; var boardEl = document.getElementById("board"); var statusEl = document.getElementById("status"); var flagBtn = document.getElementById("flag-mode"); var cells = []; for (var r = 0; r < 9; r++) { for (var c = 0; c < 9; c++) { var btn = document.createElement("button"); btn.type = "button"; btn.dataset.row = String(r); btn.dataset.col = String(c); btn.setAttribute("aria-label", "cell row " + r + " column " + c); btn.addEventListener("click", function () { var row = Number(this.dataset.row); var col = Number(this.dataset.col); if (flagMode) { game.press(["flag", row, col]); } else { game.press(["open", row, col]); } render(); }); btn.addEventListener("contextmenu", function (e) { e.preventDefault(); var row = Number(this.dataset.row); var col = Number(this.dataset.col); game.press(["flag", row, col]); render(); }); btn.addEventListener("keydown", function (e) { if (e.key === "f" || e.key === "F") { e.preventDefault(); game.press(["flag", Number(this.dataset.row), Number(this.dataset.col)]); render(); } }); boardEl.appendChild(btn); cells.push(btn); } } flagBtn.addEventListener("click", function () { flagMode = !flagMode; flagBtn.textContent = flagMode ? "Flag mode: on" : "Flag mode: off"; flagBtn.setAttribute("aria-pressed", flagMode ? "true" : "false"); flagBtn.classList.toggle("on", flagMode); }); function render() { var s = game.state(); for (var r = 0; r < 9; r++) { for (var c = 0; c < 9; c++) { var ch = s.cells[r].charAt(c); var el = cells[r * 9 + c]; el.textContent = ""; el.className = ""; if (ch === "#") { /* hidden: no text */ } else if (ch === "F") { el.textContent = "F"; el.classList.add("flag"); } else if (ch === "*") { el.textContent = "*"; el.classList.add("mine"); } else if (ch === ".") { el.classList.add("open"); } else { el.textContent = ch; el.classList.add("open"); } } } var word = "Playing"; var cls = ""; if (s.status === "won") { word = "Won"; cls = "won"; } if (s.status === "lost") { word = "Lost"; cls = "lost"; } statusEl.textContent = ""; var mineSpan = document.createElement("span"); mineSpan.textContent = "Mines left " + s.mines_left; statusEl.appendChild(mineSpan); var wordSpan = document.createElement("span"); wordSpan.className = "word " + cls; wordSpan.textContent = word; statusEl.appendChild(wordSpan); } render(); })(); </script> </body> </html> ```
Building apps 4 of 4
Step sequencerPassed
10,412 tokens: 1,323 read, 9,089 written · 6 min 35 s · 23.3 tok/s
Build a web page called "Step sequencer": three rows labelled Kick, Snare and Hat, of 16 step buttons each, a Play button and a Stop button, and drums made with the Web Audio API, with no sound files. In <script id="game">, define createGame() returning an object with press(cmd) and state(). The page calls createGame() at load or on the first press. The logic keeps the pattern, whether it is playing, the playhead and the hits. The page makes the sound. Do not use eval or Function, and never run text as code: give a timer a function, not a string. The starting pattern, one row per track. Steps are numbered from 1 in the rows below: each row is 16 characters, 1 for on and 0 for off. The first character is step 1 on the page and step 0 for press(): kick 1001000010001000 snare 0000110100001000 hat 1010111110101010 The rules, exactly: 1. At the start, playing is false, playhead is 0 and hits is []. 2. press([track, step]) toggles one cell: track 0 is kick, 1 snare, 2 hat; step is 0 to 15, where 0 is the first step. Toggling changes the pattern and nothing else. 3. press('play') does nothing when playing is already true. Otherwise it sets playing to true, and hits becomes the list of track numbers (0 kick, 1 snare, 2 hat) whose cell at the playhead is 1, in ascending order ([] when there are none). So the step under the playhead sounds as play starts. 4. press('stop') sets playing to false, playhead to 0 and hits to []. 5. press('tick') does nothing unless playing is true. When it is, playhead goes on by one, and after 15 it goes back to 0. hits becomes the list of track numbers whose cell at the new playhead is 1, in ascending order ([] when there are none). 6. Any other cmd does nothing: a list that is not exactly two whole numbers (such as [0, 1, 2], [1], [] or [true, 0]), null, a number, true or false, a word other than play, stop or tick, and a track or step outside the ranges above. Track and step are whole numbers. state() returns {playing, playhead, hits, pattern}: playing is true or false; playhead is 0 to 15; hits lists the track numbers set by the last tick or by the play that started playback, in ascending order ([] at the start and after stop); pattern is three strings of 16 characters, kick first, each character 1 or 0. The page: - Each step button is a real button with the attributes data-track (0, 1 or 2) and data-step (0 to 15), and aria-pressed set to true or false to match its state. A click calls press([track, step]), and after every press, the page draws from state(). - A step that is on has the class on, and the stylesheet fills it dark; a step that is off has no class on. - Play has the id play and Stop the id stop. Play calls press('play') and starts one timer that calls press('tick') every 125 ms: 120 quarter-note beats a minute, four steps to a beat. Stop calls press('stop') and clears the timer. Each play and each tick sounds the hits that state() then reports, and nothing else sounds. - Play has the disabled attribute while playing, and Stop has it while stopped. - A status line with the id status reads "Stopped", or "Playing, step N of 16" with N the playhead plus 1. Give it a fixed height, so the grid does not move when its text changes. - A span with the id announce, set to aria-live polite, is empty until playback starts for the first time. From then on it says "Playing" when playback starts and "Stopped" when it stops, and changes at no other time. - The cells in the playhead column have the class playhead while playing, and no cell has it while stopped. - The numbers 1 to 16, as text, sit above the grid, and the playhead's number is pink. Under 720 px each step shows its number. - When the page becomes hidden, it presses Stop, so nothing sounds in a background tab. - Each track in hits plays its drum: kick is a falling sine tone, snare a short noise burst with a low body tone, hat a short high noise burst. Tones use oscillators; noise bursts use buffer sources playing a buffer of random samples: the kick is one oscillator, the snare one buffer source and one oscillator, the hat one buffer source. Hits that land together must not clip, so put a gain or a limiter before the output. Create the AudioContext inside the first click (browsers need a click before they make sound), and resume it if it is suspended. - Flat and plain: a light background, dark ink, no shadows or gradients, Play the one pink button (#b31f57), and the playhead cell outlined in pink where you are. At 1280 px the 16 steps sit in one row; under 720 px they form two bars of 8. The page never scrolls sideways. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and drives the sequencer through createGame(). Wire the page in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Step sequencer</title> <style> * { box-sizing: border-box; } html, body { margin: 0; } body { background: #f6f4ee; color: #1c1c1e; font: 15px/1.4 system-ui, -apple-system, "Segoe UI", sans-serif; overflow-x: hidden; } .wrap { max-width: 1280px; margin: 0 auto; padding: 16px 16px 48px; } h1 { font-size: 22px; margin: 0 0 14px; } .ctl { display: flex; gap: 8px; margin-bottom: 8px; } button { font: inherit; cursor: pointer; } #play { background: #b31f57; color: #fff; border: 1px solid #b31f57; padding: 8px 22px; font-weight: 600; } #stop { background: #fff; color: #1c1c1e; border: 1px solid #888; padding: 8px 22px; } button:disabled { opacity: .45; cursor: default; } #status { height: 24px; line-height: 24px; font-size: 14px; margin-bottom: 10px; } #announce { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } .head, .track { display: grid; grid-template-columns: 64px repeat(16, minmax(0, 1fr)); gap: 4px; margin-bottom: 4px; } .num { text-align: center; font-size: 12px; color: #555; padding: 2px 0; min-width: 0; } .num.now { color: #b31f57; font-weight: 700; } .lbl { font-size: 13px; display: flex; align-items: center; min-width: 0; overflow: hidden; } .step { aspect-ratio: 1 / 1; min-height: 26px; border: 1px solid #999; background: #fff; border-radius: 3px; padding: 0; display: flex; align-items: center; justify-content: center; min-width: 0; } .step .n { display: none; font-size: 10px; color: #999; } .step.on { background: #1c1c1e; color: #fff; } .step.playhead { outline: 2px solid #b31f57; outline-offset: -2px; } @media (max-width: 719px) { .head, .track { grid-template-columns: 48px repeat(8, minmax(0, 1fr)); } .lbl, .sp { grid-row: span 2; } .lbl { align-items: center; } .step .n { display: block; } } </style> </head> <body> <div class="wrap"> <h1>Step sequencer</h1> <div class="ctl"> <button id="play" disabled>Play</button> <button id="stop">Stop</button> </div> <div id="status">Stopped</div> <span id="announce" aria-live="polite"></span> <div id="head" class="head" aria-hidden="true"></div> <div id="grid"></div> </div> <script id="game"> function createGame() { var pattern = [ "1001000010001000", "0000110100001000", "1010111110101010" ]; var playing = false; var playhead = 0; var hits = []; function hitsAt(s) { var h = []; for (var t = 0; t < 3; t++) { if (pattern[t].charAt(s) === "1") h.push(t); } return h; } function isWhole(x) { return typeof x === "number" && isFinite(x) && Math.floor(x) === x; } function press(cmd) { if (cmd === "play") { if (playing) return; playing = true; hits = hitsAt(playhead); return; } if (cmd === "stop") { playing = false; playhead = 0; hits = []; return; } if (cmd === "tick") { if (!playing) return; playhead = (playhead + 1) % 16; hits = hitsAt(playhead); return; } if ( Object.prototype.toString.call(cmd) === "[object Array]" && cmd.length === 2 && isWhole(cmd[0]) && isWhole(cmd[1]) && cmd[0] >= 0 && cmd[0] <= 2 && cmd[1] >= 0 && cmd[1] <= 15 ) { var t = cmd[0], s = cmd[1]; var chars = pattern[t].split(""); chars[s] = chars[s] === "1" ? "0" : "1"; pattern[t] = chars.join(""); } } function state() { return { playing: playing, playhead: playhead, hits: hits.slice(), pattern: pattern.slice() }; } return { press: press, state: state }; } </script> <script> (function () { var game = createGame(); var trackNames = ["Kick", "Snare", "Hat"]; /* ---------- build the UI ---------- */ var head = document.getElementById("head"); var spacer = document.createElement("div"); spacer.className = "sp"; head.appendChild(spacer); var nums = []; for (var i = 0; i < 16; i++) { var c = document.createElement("div"); c.className = "num"; c.textContent = String(i + 1); head.appendChild(c); nums.push(c); } var grid = document.getElementById("grid"); var btns = []; for (var t = 0; t < 3; t++) { var row = document.createElement("div"); row.className = "track"; var lbl = document.createElement("div"); lbl.className = "lbl"; lbl.textContent = trackNames[t]; row.appendChild(lbl); for (var s = 0; s < 16; s++) { var b = document.createElement("button"); b.className = "step"; b.type = "button"; b.setAttribute("data-track", String(t)); b.setAttribute("data-step", String(s)); b.setAttribute("aria-pressed", "false"); b.setAttribute("aria-label", trackNames[t] + " step " + (s + 1)); var n = document.createElement("span"); n.className = "n"; n.textContent = String(s + 1); b.appendChild(n); b.addEventListener("click", (function (track, step) { return function () { game.press([track, step]); render(); }; })(t, s)); row.appendChild(b); btns.push(b); } grid.appendChild(row); } var playBtn = document.getElementById("play"); var stopBtn = document.getElementById("stop"); var statusEl = document.getElementById("status"); var announceEl = document.getElementById("announce"); /* ---------- audio (Web Audio API only, no files) ---------- */ var ctx = null, master = null, noiseBuf = null; function ensureAudio() { if (!ctx) { var AC = window.AudioContext || window.webkitAudioContext; ctx = new AC(); master = ctx.createGain(); master.gain.value = 0.8; var comp = ctx.createDynamicsCompressor(); comp.threshold.value = -12; comp.ratio.value = 6; master.connect(comp); comp.connect(ctx.destination); var len = Math.floor(ctx.sampleRate * 0.25); noiseBuf = ctx.createBuffer(1, len, ctx.sampleRate); var d = noiseBuf.getChannelData(0); for (var i = 0; i < len; i++) d[i] = Math.random() * 2 - 1; } if (ctx.state === "suspended") ctx.resume(); } function kick(t0) { var o = ctx.createOscillator(); var g = ctx.createGain(); o.type = "sine"; o.frequency.setValueAtTime(150, t0); o.frequency.exponentialRampToValueAtTime(40, t0 + 0.12); g.gain.setValueAtTime(1.0, t0); g.gain.exponentialRampToValueAtTime(0.001, t0 + 0.35); o.connect(g); g.connect(master); o.start(t0); o.stop(t0 + 0.4); } function snare(t0) { var n = ctx.createBufferSource(); n.buffer = noiseBuf; var ng = ctx.createGain(); ng.gain.setValueAtTime(0.5, t0); ng.gain.exponentialRampToValueAtTime(0.001, t0 + 0.15); n.connect(ng); ng.connect(master); var o = ctx.createOscillator(); o.type = "sine"; o.frequency.setValueAtTime(180, t0); var og = ctx.createGain(); og.gain.setValueAtTime(0.4, t0); og.gain.exponentialRampToValueAtTime(0.001, t0 + 0.12); o.connect(og); og.connect(master); n.start(t0); o.start(t0); o.stop(t0 + 0.15); } function hat(t0) { var n = ctx.createBufferSource(); n.buffer = noiseBuf; var hp = ctx.createBiquadFilter(); hp.type = "highpass"; hp.frequency.value = 6000; var g = ctx.createGain(); g.gain.setValueAtTime(0.35, t0); g.gain.exponentialRampToValueAtTime(0.001, t0 + 0.05); n.connect(hp); hp.connect(g); g.connect(master); n.start(t0, 0, 0.08); } function playHits(hits) { if (!hits || hits.length === 0) return; ensureAudio(); var t0 = ctx.currentTime; for (var i = 0; i < hits.length; i++) { if (hits[i] === 0) kick(t0); else if (hits[i] === 1) snare(t0); else if (hits[i] === 2) hat(t0); } } /* ---------- page state ---------- */ var timer = null; var wasPlaying = false; var everPlayed = false; function render() { var st = game.state(); for (var t = 0; t < 3; t++) { for (var s = 0; s < 16; s++) { var b = btns[t * 16 + s]; var on = st.pattern[t].charAt(s) === "1"; b.classList.toggle("on", on); b.setAttribute("aria-pressed", on ? "true" : "false"); b.classList.toggle("playhead", st.playing && s === st.playhead); } } for (var i = 0; i < 16; i++) { nums[i].classList.toggle("now", st.playing && i === st.playhead); } statusEl.textContent = st.playing ? "Playing, step " + (st.playhead + 1) + " of 16" : "Stopped"; playBtn.disabled = st.playing; stopBtn.disabled = !st.playing; if (st.playing && !wasPlaying) { everPlayed = true; announceEl.textContent = "Playing"; } else if (!st.playing && wasPlaying && everPlayed) { announceEl.textContent = "Stopped"; } wasPlaying = st.playing; } function startPlay() { if (timer !== null) return; game.press("play"); playHits(game.state().hits); render(); timer = setInterval(function () { game.press("tick"); playHits(game.state().hits); render(); }, 125); } function doStop() { game.press("stop"); if (timer !== null) { clearInterval(timer); timer = null; } render(); } playBtn.addEventListener("click", startPlay); stopBtn.addEventListener("click", doStop); document.addEventListener("visibilitychange", function () { if (document.hidden && game.state().playing) doStop(); }); render(); })(); </script> </body> </html> ```Grow a branching plantPassed
5,444 tokens: 1,240 read, 4,204 written · 3 min 29 s · 20.8 tok/s
Build a plant that grows by a rewrite rule (an L-system) as one web page: a heading, a canvas that draws the plant, a Grow button and a Reset button. In <script id="game">, define createGame() returning an object with grow() and state(). grow() takes no argument. state() returns {generation, text, segments}: generation is a number, text is a string, and segments is a list with one [x1, y1, x2, y2] entry for each F in text, in the order the Fs appear in text. [x1, y1] is the cell a segment starts from and [x2, y2] the cell it ends on. The rules, exactly: 1. A pen starts at [0, 0] facing north, which is heading 6. Headings are numbered 0 to 7 clockwise, each one a step [dx, dy] with y growing downward: 0 [1, 0] east, 1 [1, 1] south-east, 2 [0, 1] south, 3 [-1, 1] south-west, 4 [-1, 0] west, 5 [-1, -1] north-west, 6 [0, -1] north, 7 [1, -1] north-east. 2. The text starts as F, at generation 0. The pen reads the text from left to right. F moves the pen one step along its heading and adds the segment [x1, y1, x2, y2] for that step. + adds 1 to the heading and - subtracts 1, both modulo 8. [ saves the pen's position and heading. ] restores the last saved position and heading and forgets them. Any other symbol does nothing. 3. grow() rewrites the text in one pass: every F becomes F[[++F[--F]]F]F[-F]F, and every other symbol stays as it is. The Fs that the rule adds are not rewritten in that pass. Then generation goes up by 1. 4. segments is what the pen draws over the new text, starting again at [0, 0] facing north, as in rule 1. 5. At the start, generation is 0, text is "F" and segments is [[0, 0, 0, -1]]. 6. grow() at generation 4 changes nothing: generation, text and segments stay as they are. The site calls grow() five times in a row, and reads state() before the first call and after each call, so every state must match these rules. The fifth call is made at generation 4. Keep the rule in the game script as one string, written exactly as rule 3 gives it: the site also runs the script with another rule in its place, and its states must follow that rule. The page: a heading (an <h1>) reading exactly "Grow a branching plant". Below it, one canvas draws each segment as a line from its start point to its end point, with the context's own moveTo, lineTo and stroke (not Path2D). The canvas draws nothing else: no other shapes, no text and no images. The drawing has the shape the segments give, with north up on the canvas: one scale on both axes, fitted to the canvas and centred. Each drawing starts by clearing the whole canvas (clearRect over all of it, or setting the canvas's width), so only the new plant is on it. Each press of Grow draws the whole plant again, at once, with one lineTo for each segment: no animation frames and no delays. The plant is drawn when the page loads, and Reset draws the stem again within a tenth of a second. Grow is a <button id="grow"> reading exactly "Grow". A press calls grow(), then draws and shows the new state, and Grow is disabled at generation 4. Reset is a <button id="reset"> reading exactly "Reset". A press calls createGame() for a new plant, draws it, and enables Grow again. Wire both with addEventListener('click', ...). A status line, an element with role="status", reads "Generation g of 4, n segments", where g is the generation and n the number of segments (the word is "segment" when n is 1), and it changes after each press. Look: plain and tidy, like a small app. A light, warm off-white page, the canvas in a white card with a thin border, the plant in dark ink, Grow as the main button and Reset as an outlined button under the card. The page must work at 390 px and at 1280 px wide with no sideways scrolling. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not use document, window, localStorage, sessionStorage or any timer, because the site runs that script on its own and plays the game through createGame(). The script is at most 20,000 characters. Wire the page in another <script>. Neither script may use eval or Function, reach Function through a constructor, or give a timer text to run; and neither may read window, self, globalThis, top, parent, frames or this with square brackets. A constructor() method in a class is fine, and so is a constructor key in an object; reading a constructor property, as x.constructor or x['constructor'], is not. A timer is given a function: one written in the call, or one the page declares by name. Square brackets take a number or a name, never quoted text, and window is used only as window.name.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Grow a branching plant</title> <style> :root { --page: #faf5ec; --ink: #2a2118; --accent: #3d6b35; --card-border: #e2d9c8; } * { box-sizing: border-box; } html, body { margin: 0; padding: 0; } body { background: var(--page); color: var(--ink); font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; display: flex; flex-direction: column; align-items: center; min-height: 100vh; padding: 24px 16px 40px; } h1 { font-size: 1.5rem; font-weight: 600; margin: 0 0 20px; text-align: center; } .card { background: #ffffff; border: 1px solid var(--card-border); border-radius: 10px; padding: 12px; width: 100%; max-width: 560px; } canvas { display: block; width: 100%; height: auto; } .buttons { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; margin-top: 20px; } button { font: inherit; font-size: 0.95rem; padding: 10px 22px; border-radius: 8px; cursor: pointer; } button:disabled { opacity: 0.45; cursor: default; } .primary { background: var(--accent); color: #ffffff; border: 1px solid var(--accent); } .primary:not(:disabled):hover { background: #4a7d40; } .outline { background: transparent; color: var(--accent); border: 1px solid var(--accent); } .outline:hover { background: rgba(61, 107, 53, 0.08); } .status { margin-top: 16px; font-size: 0.9rem; color: #5a5145; min-height: 1.2em; text-align: center; } @media (max-width: 420px) { body { padding: 16px 10px 32px; } h1 { font-size: 1.25rem; } .card { padding: 8px; } } </style> </head> <body> <h1>Grow a branching plant</h1> <div class="card"> <canvas id="plant" width="600" height="600" aria-label="Plant drawing"></canvas> </div> <div class="buttons"> <button id="grow" class="primary" type="button">Grow</button> <button id="reset" class="outline" type="button">Reset</button> </div> <div id="status" class="status" role="status"></div> <script id="game"> function createGame() { var RULE = "F[[++F[--F]]F]F[-F]F"; var MAX_GEN = 4; var DIRS = [ [1, 0], [1, 1], [0, 1], [-1, 1], [-1, 0], [-1, -1], [0, -1], [1, -1] ]; var generation = 0; var text = "F"; var segments = [[0, 0, 0, -1]]; function drawSegments(str) { var segs = []; var x = 0, y = 0, heading = 6; var stack = []; var i, c, d, s; for (i = 0; i < str.length; i++) { c = str.charAt(i); if (c === "F") { d = DIRS[heading]; segs.push([x, y, x + d[0], y + d[1]]); x = x + d[0]; y = y + d[1]; } else if (c === "+") { heading = (heading + 1) % 8; } else if (c === "-") { heading = (heading + 7) % 8; } else if (c === "[") { stack.push([x, y, heading]); } else if (c === "]") { s = stack.pop(); x = s[0]; y = s[1]; heading = s[2]; } } return segs; } function grow() { if (generation >= MAX_GEN) return; var out = []; var i, c; for (i = 0; i < text.length; i++) { c = text.charAt(i); out.push(c === "F" ? RULE : c); } text = out.join(""); generation = generation + 1; segments = drawSegments(text); } function state() { var copy = []; var i, s; for (i = 0; i < segments.length; i++) { s = segments[i]; copy.push([s[0], s[1], s[2], s[3]]); } return { generation: generation, text: text, segments: copy }; } return { grow: grow, state: state }; } </script> <script> (function () { var game = createGame(); var canvas = document.getElementById("plant"); var ctx = canvas.getContext("2d"); var growBtn = document.getElementById("grow"); var resetBtn = document.getElementById("reset"); var statusEl = document.getElementById("status"); function render() { var st = game.state(); var segs = st.segments; var W = canvas.width; var H = canvas.height; ctx.clearRect(0, 0, W, H); if (segs.length > 0) { var minX = Infinity, maxX = -Infinity; var minY = Infinity, maxY = -Infinity; var i, s; for (i = 0; i < segs.length; i++) { s = segs[i]; if (s[0] < minX) minX = s[0]; if (s[2] < minX) minX = s[2]; if (s[0] > maxX) maxX = s[0]; if (s[2] > maxX) maxX = s[2]; if (s[1] < minY) minY = s[1]; if (s[3] < minY) minY = s[3]; if (s[1] > maxY) maxY = s[1]; if (s[3] > maxY) maxY = s[3]; } var spanX = maxX - minX; var spanY = maxY - minY; if (spanX === 0) spanX = 1; if (spanY === 0) spanY = 1; var pad = 24; var scale = Math.min((W - 2 * pad) / spanX, (H - 2 * pad) / spanY); var offX = W / 2 - (minX + maxX) / 2 * scale; var offY = H / 2 - (minY + maxY) / 2 * scale; ctx.strokeStyle = "#2a2118"; ctx.lineWidth = 2; ctx.lineCap = "round"; ctx.lineJoin = "round"; ctx.beginPath(); for (i = 0; i < segs.length; i++) { s = segs[i]; ctx.moveTo(s[0] * scale + offX, s[1] * scale + offY); ctx.lineTo(s[2] * scale + offX, s[3] * scale + offY); } ctx.stroke(); } var n = segs.length; statusEl.textContent = "Generation " + st.generation + " of 4, " + n + (n === 1 ? " segment" : " segments"); growBtn.disabled = st.generation >= 4; } growBtn.addEventListener("click", function () { game.grow(); render(); }); resetBtn.addEventListener("click", function () { game = createGame(); render(); }); render(); })(); </script> </body> </html>Falling sandPassed
7,151 tokens: 1,166 read, 5,985 written · 4 min 17 s · 23.8 tok/s
Build a page called Falling sand: a 40 by 30 board drawn on a canvas. Sand falls one frame at a time and slides off the edges of piles. Pressing or dragging on the board pours sand, Play runs the frames, and Step runs one. In <script id="game">, define createGame(). It returns an object with play(move) and state(). move is "step" (run one frame) or [x, y] (pour one grain of sand into column x, row y). state() returns {frame, cells}: frame is the number of frames run so far (a pour is not a frame), and cells is 30 rows of 40 numbers, top row first: 0 is empty, 1 is sand, 2 is wall. Column x runs 0 to 39, left to right; row y runs 0 to 29, top to bottom. The start, exactly (both ends of each run are included): 1. frame is 0. Row 29 is all wall. 2. Walls: row 17, columns 13 to 20; column 28, rows 21 to 26; row 14, columns 2 to 6. 3. Sand: column 16, row 2; row 3, columns 13 to 19; row 4, columns 12 to 20; row 5, columns 12 to 20; row 6, columns 11 to 21; row 7, columns 12 to 20; row 8, columns 12 to 20; row 9, columns 13 to 19; column 16, row 10. 4. Every other cell is empty. The rules, exactly: 1. A pour [x, y] puts one grain in that cell if it is empty; a cell holding sand or wall, or outside the grid, is not empty, so the pour does nothing. 2. A step runs one frame, using frame as it is before the step, then frame goes up by 1. A frame scans the rows from row 28 up to row 0. Within a row it scans the columns from left to right when frame is even, and from right to left when frame is odd. 3. Each sand cell the scan reaches moves at most once: to (x, y+1) if that cell is empty; otherwise to (x-1, y+1) if that is empty; otherwise to (x+1, y+1) if that is empty; otherwise it stays. Anything outside the grid counts as wall. 4. Each check reads the cells as they are at that moment: a grain that has moved leaves its cell empty, and a cell an earlier grain filled in this frame is not empty. The site plays a list of moves through play() and checks state() after each one. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the game logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and plays the game through createGame(). Wire the page in another <script>. Do not run a string as code: no eval, no Function (not even as a function's constructor property), no timer given a string, no javascript: address, and no script element made from text. Network requests are refused, and the game script is at most 20,000 characters. The page: a canvas with the id board and the width and height attributes 640 and 480. The board may be shown at any size and place on the page: a press or drag finds its cell from where the board is on screen not from its 640 by 480 pixels. A press on the board pours one grain into the cell under the pointer. A drag pours into every cell on the straight line from the cell the pointer left to the cell it reached, both ends included (Bresenham's line algorithm). Buttons with the ids play, step and reset. play runs one frame about every 50 ms, and its label reads Pause while it runs; pressing it again pauses, and the label reads Play. step runs one frame. reset calls createGame() again, back to the start, and stops Play if it is running. After each pour, after each frame that Play or Step runs, and after Reset, the board is cleared or filled once, then each grain of sand is drawn with fillRect in its own cell; empty cells are not drawn one by one. One line under the board, with the id status, reads "Frame N, M grains of sand" ("1 grain of sand" for one), N is the frame and M the grains. Not checked, but wanted: keyboard pouring (arrow keys move a pour cursor when the board has focus; Space or Enter pours at it); a live region with the id say that announces Play, Pause, Step and Reset; reduced motion (prefers-reduced-motion: reduce): a press of Play runs one frame; off screen, Play pauses for real (no frame runs, the label reads Play) and resumes on return only if it was playing, and a press of Play then does nothing, while Step still runs one frame.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Falling sand</title> <style> body { font-family: sans-serif; margin: 2rem; background: #f4f2ec; color: #222; } h1 { margin: 0 0 0.5rem; font-size: 1.4rem; } #board { display: block; width: 100%; max-width: 640px; background: #10131a; border: 1px solid #444; cursor: crosshair; touch-action: none; } #board:focus { outline: 3px solid #58a; outline-offset: 2px; } #status { margin-top: 0.4rem; } .btns { margin-top: 0.6rem; } button { font-size: 1rem; padding: 0.35rem 1rem; margin-right: 0.4rem; cursor: pointer; } #say { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; } </style> </head> <body> <h1>Falling sand</h1> <canvas id="board" width="640" height="480" tabindex="0"></canvas> <div id="status">Frame 0, 0 grains of sand</div> <div class="btns"> <button id="play" type="button">Play</button> <button id="step" type="button">Step</button> <button id="reset" type="button">Reset</button> </div> <div id="say" aria-live="polite"></div> <script id="game"> function createGame() { var W = 40, H = 30; var cells = []; for (var y = 0; y < H; y++) { var row = []; for (var x = 0; x < W; x++) row.push(0); cells.push(row); } function set(x, y, v) { if (x >= 0 && x < W && y >= 0 && y < H) cells[y][x] = v; } // Row 29 all wall for (var x = 0; x < W; x++) set(x, 29, 2); // Row 17, columns 13 to 20 for (x = 13; x <= 20; x++) set(x, 17, 2); // Column 28, rows 21 to 26 for (y = 21; y <= 26; y++) set(28, y, 2); // Row 14, columns 2 to 6 for (x = 2; x <= 6; x++) set(x, 14, 2); // Sand: column 16, row 2 set(16, 2, 1); // row 3, columns 13 to 19 for (x = 13; x <= 19; x++) set(x, 3, 1); // rows 4 and 5, columns 12 to 20 for (x = 12; x <= 20; x++) { set(x, 4, 1); set(x, 5, 1); } // row 6, columns 11 to 21 for (x = 11; x <= 21; x++) set(x, 6, 1); // rows 7 and 8, columns 12 to 20 for (x = 12; x <= 20; x++) { set(x, 7, 1); set(x, 8, 1); } // row 9, columns 13 to 19 for (x = 13; x <= 19; x++) set(x, 9, 1); // column 16, row 10 set(16, 10, 1); var frame = 0; function stepFrame() { var leftToRight = (frame % 2 === 0); for (var y = 28; y >= 0; y--) { for (var i = 0; i < W; i++) { var x = leftToRight ? i : (W - 1 - i); if (cells[y][x] !== 1) continue; var below = cells[y + 1][x]; if (below === 0) { cells[y + 1][x] = 1; cells[y][x] = 0; continue; } if (x - 1 >= 0 && cells[y + 1][x - 1] === 0) { cells[y + 1][x - 1] = 1; cells[y][x] = 0; continue; } if (x + 1 < W && cells[y + 1][x + 1] === 0) { cells[y + 1][x + 1] = 1; cells[y][x] = 0; } } } frame++; } return { play: function (move) { if (move === 'step') { stepFrame(); } else { var x = move[0], y = move[1]; if (x >= 0 && x < W && y >= 0 && y < H && cells[y][x] === 0) cells[y][x] = 1; } }, state: function () { var out = []; for (var y = 0; y < H; y++) out.push(cells[y].slice()); return { frame: frame, cells: out }; } }; } </script> <script> (function () { 'use strict'; var canvas = document.getElementById('board'); var ctx = canvas.getContext('2d'); var statusEl = document.getElementById('status'); var sayEl = document.getElementById('say'); var playBtn = document.getElementById('play'); var stepBtn = document.getElementById('step'); var resetBtn = document.getElementById('reset'); var reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)'); var W = 40, H = 30, CELL = 16; var game = createGame(); var timer = null; var playing = false; var offscreen = false; var pointerDown = false; var lastCell = null; var cursor = { x: 19, y: 1 }; var showCursor = false; function announce(text) { sayEl.textContent = text; } function render() { var s = game.state(); ctx.clearRect(0, 0, 640, 480); ctx.fillStyle = '#10131a'; ctx.fillRect(0, 0, 640, 480); var grains = 0; for (var y = 0; y < H; y++) { for (var x = 0; x < W; x++) { var c = s.cells[y][x]; if (c === 2) { ctx.fillStyle = '#8b8f99'; ctx.fillRect(x * CELL, y * CELL, CELL, CELL); } else if (c === 1) { ctx.fillStyle = '#e8c660'; ctx.fillRect(x * CELL, y * CELL, CELL, CELL); grains++; } } } if (showCursor) { ctx.strokeStyle = '#ffffff'; ctx.lineWidth = 2; ctx.strokeRect(cursor.x * CELL + 2, cursor.y * CELL + 2, CELL - 4, CELL - 4); } statusEl.textContent = 'Frame ' + s.frame + ', ' + grains + (grains === 1 ? ' grain of sand' : ' grains of sand'); } function runFrame() { game.play('step'); render(); } function cellFromEvent(e) { var r = canvas.getBoundingClientRect(); var x = Math.floor((e.clientX - r.left) / r.width * W); var y = Math.floor((e.clientY - r.top) / r.height * H); x = Math.max(0, Math.min(W - 1, x)); y = Math.max(0, Math.min(H - 1, y)); return { x: x, y: y }; } function bresenham(x0, y0, x1, y1, cb) { var dx = Math.abs(x1 - x0), dy = -Math.abs(y1 - y0); var sx = x0 < x1 ? 1 : -1, sy = y0 < y1 ? 1 : -1; var err = dx + dy; for (;;) { cb(x0, y0); if (x0 === x1 && y0 === y1) break; var e2 = 2 * err; if (e2 >= dy) { err += dy; x0 += sx; } if (e2 <= dx) { err += dx; y0 += sy; } } } function pourAt(x, y) { game.play([x, y]); render(); } canvas.addEventListener('pointerdown', function (e) { e.preventDefault(); canvas.setPointerCapture(e.pointerId); var c = cellFromEvent(e); pointerDown = true; lastCell = c; showCursor = false; pourAt(c.x, c.y); }); canvas.addEventListener('pointermove', function (e) { if (!pointerDown) return; var c = cellFromEvent(e); bresenham(lastCell.x, lastCell.y, c.x, c.y, function (x, y) { game.play([x, y]); }); lastCell = c; render(); }); function endPointer(e) { if (!pointerDown) return; pointerDown = false; lastCell = null; } canvas.addEventListener('pointerup', endPointer); canvas.addEventListener('pointercancel', endPointer); canvas.addEventListener('keydown', function (e) { var k = e.key; if (k === 'ArrowLeft') cursor.x = Math.max(0, cursor.x - 1); else if (k === 'ArrowRight') cursor.x = Math.min(W - 1, cursor.x + 1); else if (k === 'ArrowUp') cursor.y = Math.max(0, cursor.y - 1); else if (k === 'ArrowDown') cursor.y = Math.min(H - 1, cursor.y + 1); else if (k === ' ' || k === 'Enter') { pourAt(cursor.x, cursor.y); e.preventDefault(); return; } else return; e.preventDefault(); showCursor = true; render(); }); canvas.addEventListener('blur', function () { if (showCursor) { showCursor = false; render(); } }); function stopTimer() { if (timer !== null) { clearInterval(timer); timer = null; } playBtn.textContent = 'Play'; } function startPlay() { if (offscreen) return; // off-screen, a press of Play does nothing if (reducedMotion.matches) { announce('Play'); runFrame(); return; } playing = true; timer = setInterval(runFrame, 50); playBtn.textContent = 'Pause'; announce('Play'); } function stopPlay() { playing = false; stopTimer(); } playBtn.addEventListener('click', function () { if (playing) { stopPlay(); announce('Pause'); } else { startPlay(); } }); stepBtn.addEventListener('click', function () { runFrame(); announce('Step'); }); resetBtn.addEventListener('click', function () { stopPlay(); game = createGame(); render(); announce('Reset'); }); if ('IntersectionObserver' in window) { new IntersectionObserver(function (entries) { var entry = entries[0]; if (entry.isIntersecting) { offscreen = false; if (playing) startPlay(); // resume only if it was playing } else { offscreen = true; if (timer !== null) { stopTimer(); // pause for real, but keep playing === true } } }, { threshold: 0 }).observe(canvas); } render(); })(); </script> </body> </html> ```Focus timerPassed
4,482 tokens: 1,116 read, 3,366 written · 2 min 26 s · 23.9 tok/s
Build a focus timer as one web page. Work periods alternate with breaks, and after every few finished work periods the break is long. The page shows the name of the period, the time left, an SVG ring that empties as the time runs down, and how many work periods are done. In <script id="game">, define createGame(). It returns an object with two methods, tick(cmd) and state(). The page's own timer calls tick() once a second, and its buttons call tick('start'), tick('pause'), tick('skip') and tick('reset'). Those four exact lowercase words are commands: they change the timer and pass no time. Any other value passes one second, and only while the timer is running: no argument, null, undefined, a number, true, false, an empty text, any other text such as 'Start' or 'tick', or an object. state() returns {phase, left, running, done}: phase is 'work', 'short' or 'long'; left is the whole number of seconds left in this period; running is true or false; done is a number. The script in <script id="game"> is at most 20,000 characters. This run's lengths: work 1500 seconds (25 minutes), short break 300 seconds (5 minutes), long break 600 seconds (10 minutes). A long break follows every 4th finished work period. The rules, exactly: 1. The timer starts in work, with left 1500, running false and done 0. 2. 'start' sets running to true, and 'pause' sets it to false. Neither changes anything else. 3. While running, each passed second lowers left by 1. While paused, passed seconds change nothing. 4. When left reaches 0, the period is over at once, so state() never shows 0. The next period starts with its full length and paused (running false). Seconds passed after that change nothing until 'start'. 5. A work period that ends this way adds 1 to done. Then a long break comes when done is a multiple of 4, otherwise a short break. 6. 'skip' ends the current period at once, whatever left is, and the next period starts paused. A skipped work period does not add to done, and the break after it is a short break whatever done is. A skipped break is followed by work. 7. After any break comes work. A break never adds to done. 8. 'reset' sets left back to the full length of the current period and sets running to false. It does not change the phase or done. The page: - A heading, "Focus timer". - The name of the period, alone in an element with the id phase: Focus, Short break or Long break. - The time left, as mm:ss with two digits each, alone in an element with the id time. At the start of this run's work period it reads 25:00. - An SVG ring around the time: a circle with pathLength="100" and stroke-dasharray="100". Set its stroke-dashoffset attribute to 100 times (1 minus left divided by the full length of the current period) on every redraw. The arc is full, with an offset of 0, at the start of a period, and it is empty, with an offset of 100, when the time is up. A track circle without a stroke-dashoffset may sit under it. - Four buttons in one row, with the ids start, pause, skip and reset, labelled Start, Pause, Skip and Reset. Each calls tick() with its command. Start is disabled while the timer runs, and Pause is disabled while it is paused. Skip and Reset are always enabled. Below 390 px they may wrap into two rows of two. - The count in an element with the id count, in words: "Focus periods done: 3". - The page's own timer calls tick() once a second, with no argument. After every call, the page redraws from state(). When a period ends, the page may play a short chime with the Web Audio API. - Look: a light, warm off-white page with one white card, dark ink text and muted grey for the small labels. One accent colour, used for the Start button only. Flat fills, no gradients or shadows, no outside fonts or images: use the system font. It must look tidy at 390 px and at 1280 px wide, with no sideways scrolling. Output one complete HTML document and nothing else, with all CSS and JavaScript inline and nothing loaded from another site. Put the timer's logic, and only it, in <script id="game">: it must not touch document, window or timers, because the site runs that script on its own and drives the timer through createGame(). Do not use eval, Function or any other way of running text as code: no string given to a timer, and no script element or event-handler attribute made from text while the page runs. Put the wiring in another <script>.Open the page on its own. It runs in a sandbox: no network, no access to this site.
Page source
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Focus timer</title> <style> * { box-sizing: border-box; margin: 0; padding: 0; } html, body { min-width: 0; } body { font-family: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif; background: #faf5ec; color: #26221c; display: flex; justify-content: center; padding: 24px 16px 48px; } .card { background: #ffffff; border: 1px solid #e8e0d2; border-radius: 14px; width: 100%; max-width: 440px; padding: 28px 24px 32px; display: flex; flex-direction: column; align-items: center; } h1 { font-size: 1.4rem; font-weight: 650; margin-bottom: 20px; letter-spacing: 0.01em; } #phase { font-size: 1.15rem; font-weight: 600; margin-bottom: 18px; } .ring-wrap { position: relative; width: min(78vw, 260px); margin-bottom: 22px; } .ring-wrap svg { display: block; width: 100%; height: auto; } .track { fill: none; stroke: #efe8db; stroke-width: 10; } .progress { fill: none; stroke: #26221c; stroke-width: 10; stroke-linecap: round; transform: rotate(-90deg); transform-origin: 100px 100px; } #time { position: absolute; top: 0; left: 0; right: 0; bottom: 0; display: flex; align-items: center; justify-content: center; font-size: clamp(2rem, 12vw, 2.9rem); font-variant-numeric: tabular-nums; font-weight: 650; letter-spacing: 0.02em; } .buttons { display: flex; flex-wrap: wrap; justify-content: center; gap: 10px; width: 100%; margin-bottom: 22px; } .buttons button { font: inherit; font-weight: 600; font-size: 0.95rem; padding: 10px 0; width: calc(50% - 5px); border-radius: 9px; border: 1.5px solid #d8d0c0; background: #ffffff; color: #26221c; cursor: pointer; } .buttons button:hover:not(:disabled) { background: #f6f1e7; } .buttons button:disabled { opacity: 0.45; cursor: default; } #start { background: #d95b33; border-color: #d95b33; color: #ffffff; } #start:hover:not(:disabled) { background: #c44e28; } #count { font-size: 0.85rem; color: #8c8578; letter-spacing: 0.02em; } @media (max-width: 389px) { .card { padding: 22px 16px 26px; } .buttons { display: grid; grid-template-columns: 1fr 1fr; } .buttons button { width: auto; } } </style> </head> <body> <main class="card"> <h1>Focus timer</h1> <div id="phase">Focus</div> <div class="ring-wrap"> <svg viewBox="0 0 200 200" aria-hidden="true"> <circle class="track" cx="100" cy="100" r="88" pathLength="100"></circle> <circle id="ring" class="progress" cx="100" cy="100" r="88" pathLength="100" stroke-dasharray="100" stroke-dashoffset="0"></circle> </svg> <div id="time">25:00</div> </div> <div class="buttons"> <button id="start" type="button">Start</button> <button id="pause" type="button">Pause</button> <button id="skip" type="button">Skip</button> <button id="reset" type="button">Reset</button> </div> <div id="count">Focus periods done: 0</div> </main> <script id="game"> function createGame() { 'use strict'; var LEN = { work: 1500, short: 300, long: 600 }; var phase = 'work'; var left = LEN[phase]; var running = false; var done = 0; function nextAfterWork(skipped) { if (!skipped) { done += 1; } return (skipped || done % 4 !== 0) ? 'short' : 'long'; } function advance(skipped) { if (phase === 'work') { phase = nextAfterWork(skipped); } else { phase = 'work'; } left = LEN[phase]; running = false; } function tick(cmd) { if (cmd === 'start') { running = true; return; } if (cmd === 'pause') { running = false; return; } if (cmd === 'skip') { advance(true); return; } if (cmd === 'reset') { left = LEN[phase]; running = false; return; } if (running) { left -= 1; if (left <= 0) { advance(false); } } } function state() { return { phase: phase, left: left, running: running, done: done }; } return { tick: tick, state: state }; } </script> <script> (function () { 'use strict'; var game = createGame(); var LEN = { work: 1500, short: 300, long: 600 }; var NAMES = { work: 'Focus', short: 'Short break', long: 'Long break' }; var elPhase = document.getElementById('phase'); var elTime = document.getElementById('time'); var elRing = document.getElementById('ring'); var elCount = document.getElementById('count'); var btnStart = document.getElementById('start'); var btnPause = document.getElementById('pause'); var audioCtx = null; function chime() { try { if (!audioCtx) { audioCtx = new (window.AudioContext || window.webkitAudioContext)(); } var t = audioCtx.currentTime; var osc = audioCtx.createOscillator(); var gain = audioCtx.createGain(); osc.type = 'sine'; osc.frequency.setValueAtTime(660, t); osc.frequency.setValueAtTime(880, t + 0.12); gain.gain.setValueAtTime(0.0001, t); gain.gain.exponentialRampToValueAtTime(0.18, t + 0.02); gain.gain.exponentialRampToValueAtTime(0.0001, t + 0.5); osc.connect(gain); gain.connect(audioCtx.destination); osc.start(t); osc.stop(t + 0.55); } catch (e) { /* sound unavailable; ignore */ } } function pad(n) { return (n < 10 ? '0' : '') + n; } function fmt(sec) { return pad(Math.floor(sec / 60)) + ':' + pad(sec % 60); } var prev = game.state(); function redraw() { var s = game.state(); if (prev.running && prev.left === 1 && !s.running && s.left === LEN[s.phase]) { chime(); } prev = s; elPhase.textContent = NAMES[s.phase]; elTime.textContent = fmt(s.left); elRing.setAttribute('stroke-dashoffset', String(100 * (1 - s.left / LEN[s.phase]))); elCount.textContent = 'Focus periods done: ' + s.done; btnStart.disabled = s.running; btnPause.disabled = !s.running; } btnStart.addEventListener('click', function () { game.tick('start'); redraw(); }); btnPause.addEventListener('click', function () { game.tick('pause'); redraw(); }); document.getElementById('skip').addEventListener('click', function () { game.tick('skip'); redraw(); }); document.getElementById('reset').addEventListener('click', function () { game.tick('reset'); redraw(); }); setInterval(function () { game.tick(); redraw(); }, 1000); redraw(); })(); </script> </body> </html>
Writing code 3 of 3
Merge intervalsPassed
662 tokens: 158 read, 504 written · 21 s · 25 tok/s
Write a JavaScript function mergeIntervals(intervals). intervals is an array of [start, end] pairs of integers with start <= end, in any order, possibly empty. Return a new array of the merged intervals sorted by start: intervals that overlap or touch (one ends where the next starts) become one. Do not change the input array or its pairs. mergeIntervals([[8, 10], [1, 3], [2, 6], [6, 7]]) returns [[1, 7], [8, 10]]. Reply with one ```js code block holding plain JavaScript (no imports, no exports, no DOM, no timers). The site runs it with hidden tests.
```js function mergeIntervals(intervals) { if (!intervals || intervals.length === 0) return []; // Work on a deep copy of the pairs so the input stays untouched const sorted = intervals .map((pair) => [pair[0], pair[1]]) .sort((a, b) => (a[0] - b[0]) || (a[1] - b[1])); const merged = [sorted[0].slice()]; for (let i = 1; i < sorted.length; i++) { const current = sorted[i]; const last = merged[merged.length - 1]; // Overlap or touch (current.start <= last.end) if (current[0] <= last[1]) { if (current[1] > last[1]) { last[1] = current[1]; } } else { merged.push([current[0], current[1]]); } } return merged; } ```An LRU cachePassed
489 tokens: 168 read, 321 written · 14 s · 23.7 tok/s
Write a JavaScript class LRUCache: a least-recently-used cache of integer keys and values. - new LRUCache(capacity): capacity is an integer of at least 1. - get(key) returns the value stored for key, or -1 if there is none. A get that finds the key makes it the most recently used. - put(key, value) stores the value (replacing any value already there) and makes key the most recently used. If that leaves more than capacity keys, the least recently used key is removed. get and put should take constant time on average. Reply with one ```js code block holding plain JavaScript (no imports, no exports, no DOM, no timers). The site runs it with hidden tests.
```js class LRUCache { constructor(capacity) { this.capacity = capacity; this.map = new Map(); } get(key) { if (!this.map.has(key)) return -1; const value = this.map.get(key); // refresh recency: move key to the end (most recently used) this.map.delete(key); this.map.set(key, value); return value; } put(key, value) { if (this.map.has(key)) { // refresh recency this.map.delete(key); } else { if (this.map.size >= this.capacity) { // evict least recently used (first inserted key) const lruKey = this.map.keys().next().value; this.map.delete(lruKey); } } this.map.set(key, value); } } ```Evaluate arithmeticPassed
2,693 tokens: 194 read, 2,499 written · 1 min 43 s · 24.6 tok/s
Write a JavaScript function evaluate(expr) that returns the value of an arithmetic expression given as a string. The expression has non-negative integers, the operators + - * /, parentheses, unary minus (as in -3, - -3, 2 * -3 or -(1 + 2)) and spaces anywhere between tokens. * and / bind tighter than + and -, and operators of the same kind group from the left. / is integer division that truncates toward zero: 7 / 2 is 3 and -7 / 2 is -3. Dividing by zero must throw an Error. Do not use eval or Function. evaluate("2 + 3 * (4 - 6) / 4") returns 1. Reply with one ```js code block holding plain JavaScript (no imports, no exports, no DOM, no timers). The site runs it with hidden tests.```js function evaluate(expr) { let pos = 0; function skipSpaces() { while (pos < expr.length && expr[pos] === ' ') pos++; } function parseExpression() { let result = parseTerm(); for (;;) { skipSpaces(); if (pos < expr.length && (expr[pos] === '+' || expr[pos] === '-')) { let op = expr[pos]; pos++; let right = parseTerm(); if (op === '+') result += right; else result -= right; } else break; } return result; } function parseTerm() { let result = parseFactor(); for (;;) { skipSpaces(); if (pos < expr.length && (expr[pos] === '*' || expr[pos] === '/')) { let op = expr[pos]; pos++; let right = parseFactor(); if (op === '*') result *= right; else { if (right === 0) throw new Error("Division by zero"); result = Math.trunc(result / right); } } else break; } return result; } function parseFactor() { skipSpaces(); if (pos < expr.length && expr[pos] === '-') { pos++; return -parseFactor(); } return parsePrimary(); } function parsePrimary() { skipSpaces(); if (pos < expr.length && expr[pos] === '(') { pos++; let result = parseExpression(); skipSpaces(); if (pos >= expr.length || expr[pos] !== ')') throw new Error("Expected )"); pos++; return result; } let start = pos; while (pos < expr.length && expr[pos] >= '0' && expr[pos] <= '9') pos++; if (pos === start) throw new Error("Expected number"); return parseInt(expr.substring(start, pos), 10); } let result = parseExpression(); skipSpaces(); return result; } ```
Fixing code 2 of 2
Fix the bookings modulePassed
1,808 tokens: 669 read, 1,139 written · 48 s · 25.1 tok/s
This JavaScript module has one bug. The occupancy report sometimes counts one booked night more than there is in the range it was asked about. Find it and fix it without changing anything else. ```js // Bookings for one holiday flat. A booking is { guest, checkIn, checkOut } with dates as "YYYY-MM-DD". // A guest sleeps the nights from checkIn up to, but not including, checkOut: checkOut is the day they leave, // and another guest may check in that same day. function dayNumber(date) { const [y, m, d] = date.split('-').map(Number); return Date.UTC(y, m - 1, d) / 86400000; } function toDate(day) { return new Date(day * 86400000).toISOString().slice(0, 10); } function nights(booking) { return dayNumber(booking.checkOut) - dayNumber(booking.checkIn); } function overlaps(a, b) { return dayNumber(a.checkIn) < dayNumber(b.checkOut) && dayNumber(b.checkIn) < dayNumber(a.checkOut); } function canBook(bookings, request) { if (nights(request) < 1) return false; for (const booking of bookings) { if (overlaps(booking, request)) return false; } return true; } function isBooked(bookings, day) { return bookings.some((b) => dayNumber(b.checkIn) <= day && day < dayNumber(b.checkOut)); } // The nights from `from` up to, but not including, `to` that someone has booked. function bookedNights(bookings, from, to) { let count = 0; for (let day = dayNumber(from); day <= dayNumber(to); day++) { if (isBooked(bookings, day)) count++; } return count; } // The first night on or after `from` that nobody has booked, as "YYYY-MM-DD". function firstFreeNight(bookings, from) { let day = dayNumber(from); while (isBooked(bookings, day)) day++; return toDate(day); } // The price in cents: Friday and Saturday nights at rates.weekend, every other night at rates.weekday. function price(booking, rates) { let total = 0; for (let day = dayNumber(booking.checkIn); day < dayNumber(booking.checkOut); day++) { const weekday = new Date(day * 86400000).getUTCDay(); total += weekday === 5 || weekday === 6 ? rates.weekend : rates.weekday; } return total; } ``` Reply with the whole corrected module in one ```js code block, with the same function names.```js // Bookings for one holiday flat. A booking is { guest, checkIn, checkOut } with dates as "YYYY-MM-DD". // A guest sleeps the nights from checkIn up to, but not including, checkOut: checkOut is the day they leave, // and another guest may check in that same day. function dayNumber(date) { const [y, m, d] = date.split('-').map(Number); return Date.UTC(y, m - 1, d) / 86400000; } function toDate(day) { return new Date(day * 86400000).toISOString().slice(0, 10); } function nights(booking) { return dayNumber(booking.checkOut) - dayNumber(booking.checkIn); } function overlaps(a, b) { return dayNumber(a.checkIn) < dayNumber(b.checkOut) && dayNumber(b.checkIn) < dayNumber(a.checkOut); } function canBook(bookings, request) { if (nights(request) < 1) return false; for (const booking of bookings) { if (overlaps(booking, request)) return false; } return true; } function isBooked(bookings, day) { return bookings.some((b) => dayNumber(b.checkIn) <= day && day < dayNumber(b.checkOut)); } // The nights from `from` up to, but not including, `to` that someone has booked. function bookedNights(bookings, from, to) { let count = 0; for (let day = dayNumber(from); day < dayNumber(to); day++) { if (isBooked(bookings, day)) count++; } return count; } // The first night on or after `from` that nobody has booked, as "YYYY-MM-DD". function firstFreeNight(bookings, from) { let day = dayNumber(from); while (isBooked(bookings, day)) day++; return toDate(day); } // The price in cents: Friday and Saturday nights at rates.weekend, every other night at rates.weekday. function price(booking, rates) { let total = 0; for (let day = dayNumber(booking.checkIn); day < dayNumber(booking.checkOut); day++) { const weekday = new Date(day * 86400000).getUTCDay(); total += weekday === 5 || weekday === 6 ? rates.weekend : rates.weekday; } return total; } ``` The bug was in `bookedNights`: the loop condition used `day <= dayNumber(to)`, which included the `to` day. Since the function's contract is "nights from `from` up to, but **not including**, `to`", the upper bound must be exclusive. Changing `<=` to `<` fixes the off-by-one that caused an extra booked night to be counted when the `to` date itself happened to be an occupied night.Fix the CSV readerPassed
2,656 tokens: 526 read, 2,130 written · 1 min 29 s · 24.7 tok/s
This JavaScript module has one bug. A doubled quote inside a quoted field is read wrongly: the line "a""b",c comes back as one field, a"b,c, instead of two fields, a"b and c. Find it and fix it without changing anything else. ```js // Reads CSV the way spreadsheets write it: fields are separated by commas, a field may be wrapped in // double quotes so it can hold commas, and "" inside a quoted field stands for one double quote. // Fields are not trimmed. Empty lines are skipped. function parseLine(line) { const fields = []; let field = ''; let quoted = false; for (let i = 0; i < line.length; i++) { const ch = line[i]; if (quoted) { if (ch === '"') { if (line[i + 1] === '"') { field += '"'; } else { quoted = false; } } else { field += ch; } } else if (ch === '"') { quoted = true; } else if (ch === ',') { fields.push(field); field = ''; } else { field += ch; } } fields.push(field); return fields; } function parseCSV(text) { return text.split(/\r?\n/).filter((line) => line !== '').map(parseLine); } // Each row after the header as an object keyed by the header's names; a missing field is ''. function toObjects(text) { const [header, ...rows] = parseCSV(text); return rows.map((row) => { const record = {}; header.forEach((name, i) => { record[name] = i < row.length ? row[i] : ''; }); return record; }); } // The sum of a column's numbers; fields that are not numbers count as 0. function sumColumn(text, name) { return toObjects(text).reduce((total, record) => total + (Number(record[name]) || 0), 0); } ``` Reply with the whole corrected module in one ```js code block, with the same function names.The bug is in `parseLine`: when a doubled quote (`""`) is detected inside a quoted field, the code appends a literal `"` but never skips over the second quote character. The `for` loop then processes that second `"` on the next iteration, where it's mistaken for the *closing* quote of the field. This causes everything after it (including the comma) to be swallowed into the same field. The fix is a single `i++` to skip the second quote: ```js // Reads CSV the way spreadsheets write it: fields are separated by commas, a field may be wrapped in // double quotes so it can hold commas, and "" inside a quoted field stands for one double quote. // Fields are not trimmed. Empty lines are skipped. function parseLine(line) { const fields = []; let field = ''; let quoted = false; for (let i = 0; i < line.length; i++) { const ch = line[i]; if (quoted) { if (ch === '"') { if (line[i + 1] === '"') { field += '"'; i++; } else { quoted = false; } } else { field += ch; } } else if (ch === '"') { quoted = true; } else if (ch === ',') { fields.push(field); field = ''; } else { field += ch; } } fields.push(field); return fields; } function parseCSV(text) { return text.split(/\r?\n/).filter((line) => line !== '').map(parseLine); } // Each row after the header as an object keyed by the header's names; a missing field is ''. function toObjects(text) { const [header, ...rows] = parseCSV(text); return rows.map((row) => { const record = {}; header.forEach((name, i) => { record[name] = i < row.length ? row[i] : ''; }); return record; }); } // The sum of a column's numbers; fields that are not numbers count as 0. function sumColumn(text, name) { return toObjects(text).reduce((total, record) => total + (Number(record[name]) || 0), 0); } ```
Planning and data 3 of 3
A query over hidden dataPassed
581 tokens: 216 read, 365 written · 16 s · 24.2 tok/s
Write one SQLite query that answers the question below. The site runs it on its own copy of these tables, filled with rows you have not seen. ```sql CREATE TABLE customers (id INTEGER PRIMARY KEY, name TEXT NOT NULL, city TEXT NOT NULL); CREATE TABLE orders (id INTEGER PRIMARY KEY, customer_id INTEGER NOT NULL REFERENCES customers(id), placed TEXT NOT NULL, -- 'YYYY-MM-DD' status TEXT NOT NULL); -- 'delivered', 'cancelled' or 'pending' CREATE TABLE items (order_id INTEGER NOT NULL REFERENCES orders(id), product TEXT NOT NULL, quantity INTEGER NOT NULL, price_cents INTEGER NOT NULL); -- price_cents: for one unit ``` Question: The names of the customers with at least 3 delivered orders and no cancelled order. One column: name. In alphabetical order. Reply with only the query, in one ```sql code block: one SELECT statement (WITH is fine), nothing that changes the database.```sql SELECT c.name FROM customers c JOIN orders o ON o.customer_id = c.id GROUP BY c.id, c.name HAVING SUM(CASE WHEN o.status = 'delivered' THEN 1 ELSE 0 END) >= 3 AND SUM(CASE WHEN o.status = 'cancelled' THEN 1 ELSE 0 END) = 0 ORDER BY c.name; ```
Schedule five meetingsPassed
3,211 tokens: 335 read, 2,876 written · 1 min 59 s · 24.5 tok/s
Five people each have one meeting today: Ana, Ben, Hal, Ivy, Jon. The five meetings are at different times, 09:00, 10:00, 11:00, 13:00, 14:00 (in that order: 10:00 is right after 09:00, 13:00 right after 11:00), and in different rooms. The list of rooms, in order: Birch, Cedar, Elm, Oak, Willow. 1. Ivy is not in Oak. 2. Ana's and Hal's rooms are next to each other on the list of rooms. 3. Ana is not in Cedar. 4. Hal meets neither first nor last. 5. Ana's and Jon's rooms are not next to each other on the list of rooms. 6. Ivy is not in Willow. 7. Hal's and Ivy's rooms are not next to each other on the list of rooms. 8. Ana meets after lunch. 9. Ben is not in Elm. 10. Hal is not in Oak. 11. Ivy is not in Elm. 12. Ivy's meeting is in the slot right after Jon's. 13. Jon's meeting is in the slot right after Hal's. Exactly one schedule fits every clue. Work it out, then end with exactly five lines, one per person, in this form: Ana: 09:00, Oak
Looking at this puzzle, I'll work through the constraints systematically. **Step 1: Determine the time slots.** From clues 12 & 13: Ivy is right after Jon, and Jon is right after Hal → the sequence **Hal → Jon → Ivy** must occupy three consecutive slots. The five slots in order are: 09:00, 10:00, 11:00, 13:00, 14:00. Possible triplets: (09,10,11), (10,11,13), (11,13,14). - Clue 4 (Hal not first or last) eliminates (09,10,11). - Clue 8 (Ana after lunch, i.e. 13:00 or 14:00): in the (11,13,14) triplet, 13 and 14 are taken by Jon and Ivy, leaving only 09 and 10 for Ana — impossible. - Therefore: **Hal = 10:00, Jon = 11:00, Ivy = 13:00, Ana = 14:00, Ben = 09:00.** **Step 2: Assign rooms** (Birch, Cedar, Elm, Oak, Willow). - Clues 1, 6, 11: Ivy ≠ Oak, ≠ Willow, ≠ Elm → **Ivy ∈ {Birch, Cedar}**. - Clue 10: Hal ≠ Oak. Clue 9: Ben ≠ Elm. Clue 3: Ana ≠ Cedar. Trying **Ivy = Birch**: - Clue 7 (Hal & Ivy not adjacent): Hal ≠ Cedar. With Hal ≠ Oak too → Hal ∈ {Elm, Willow}. - *Hal = Elm*: Clue 2 (Ana & Hal adjacent) → Ana ∈ {Cedar, Oak}; Ana ≠ Cedar → **Ana = Oak**. Clue 5 (Ana & Jon not adjacent to Oak): Jon ≠ Elm, ≠ Willow → **Jon = Cedar**, leaving **Ben = Willow**. Ben = Willow ≠ Elm ✓. All clues check out. - *Hal = Willow*: Ana = Oak (only adjacent). Jon ≠ Elm, ≠ Willow → Jon = Birch or Cedar; Birch taken → Jon = Cedar, Ben = Elm → violates clue 9. ✗ Trying **Ivy = Cedar**: - Clue 7: Hal ≠ Birch, ≠ Elm; Clue 10: ≠ Oak → **Hal = Willow**. - Clue 2: Ana = Oak. Clue 5: Jon ≠ Elm, ≠ Willow → Jon = Birch, Ben = Elm → violates clue 9. ✗ **Unique solution:** Ana: 14:00, Oak Ben: 09:00, Willow Hal: 10:00, Elm Ivy: 13:00, Birch Jon: 11:00, CedarA replacement in ten calls or fewerPassed
11,369 tokens: 10,453 read, 916 written · 47 s · 24.1 tok/s
Hi, it's cal.reyes@example.com. My kettle arrived with a cracked lid. Can you sort it out?
- system
You are the support agent of Tidewell Home, working through its tools, and you may make at most 10 tool calls for one request. When an item arrives damaged: confirm which order it came in, send a replacement from the north warehouse if it has the item, else from south, else from east (check each in that order, and only as far as needed), and take the damaged item back with a return. If the return is refused, open a damage claim for the order with open_claim. Then reply to the customer with what you did, giving any reference numbers and the date the replacement ships.
- user
Hi, it's cal.reyes@example.com. My kettle arrived with a cracked lid. Can you sort it out?
- assistant
I'll help you sort that out. Let me look up your account and find the order with the kettle.
lookup_account({"email":"cal.reyes@example.com"}) - tool
{"account_id":"AC-457","name":"Cal Reyes"} - assistant
list_orders({"account_id":"AC-457"}) - tool
{"orders":[{"order_id":"R-5266","placed":"2026-10-03","status":"delivered"},{"order_id":"R-5292","placed":"2026-10-15","status":"delivered"},{"order_id":"R-5607","placed":"2026-10-19","status":"in transit"}]} - assistant
Let me check your delivered orders to find the kettle.
get_order({"order_id":"R-5292"})get_order({"order_id":"R-5266"}) - tool
{"items":[{"name":"Steel kettle","quantity":1,"sku":"kettle-steel"},{"name":"Grey mug","quantity":2,"sku":"mug-grey"}],"order_id":"R-5292"} - tool
{"items":[{"name":"Oak table lamp","quantity":1,"sku":"lamp-oak"}],"order_id":"R-5266"} - assistant
Found it — the Steel kettle (SKU kettle-steel) was in order R-5292, delivered. Let me check warehouse stock for the replacement, starting with the north warehouse.
check_stock({"sku":"kettle-steel","warehouse":"north"}) - tool
{"available":0,"sku":"kettle-steel","warehouse":"north"} - assistant
North doesn't have it. Checking south.
check_stock({"sku":"kettle-steel","warehouse":"south"}) - tool
{"available":4,"sku":"kettle-steel","warehouse":"south"} - assistant
South has it in stock. I'll reserve a replacement from there and set up a return for the damaged kettle.
reserve_item({"sku":"kettle-steel","warehouse":"south","order_id":"R-5292"})create_return({"order_id":"R-5292","reason":"Kettle arrived with a cracked lid"}) - tool
{"reservation_id":"RS-4011","ships_on":"2026-11-11"} - tool
{"error":"damaged items are not returned: open a damage claim with open_claim instead"} - assistant
The return wasn't accepted — for damaged items, the process is to open a damage claim instead. Let me do that.
open_claim({"order_id":"R-5292","reason":"Steel kettle arrived with a cracked lid"}) - tool
{"claim_id":"CL-6822","order_id":"R-5292","status":"open"} - assistant
All sorted, Cal! Here's what I did: - **Replacement sent** — I found your Steel kettle in order **R-5292**. The north warehouse had none, so I sent a replacement from the **south warehouse**. Reservation **RS-4011**, shipping **2026-11-11**. - **Damage claim opened** — Since a damaged item can't be sent back through a standard return, I opened a damage claim instead: **CL-6822** (status: open). You can just keep the cracked kettle — no need to mail it back. You should be all set by mid-November. Let me know if anything else comes up!
- system
Comments
Sign in or create an account to comment.