Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docs/slides/*.pdf
113 changes: 113 additions & 0 deletions docs/challenges/challenge_one.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Challenge 1 — The Impossible Invitation to Refuse

**Level:** beginner
**Estimated time:** 20–30 min
**Objective:** practice your first prompt in OpenCode, see the Plan → Build cycle, and learn to iterate with short feedback.

## Context

We're going to build a single-page mini web app: a fun invitation to hang out with a friend. The page has two buttons, **Yes** and **No**. The **No** button flees from the cursor so no one can click it. The **Yes** button leads to a second screen with a calendar of the current month where the invitee chooses a day and time.

The challenge covers:

- Project generation from scratch (HTML + CSS + JS, no dependencies).
- JavaScript interaction logic (button movement, view navigation).
- Rendering a dynamic calendar based on system date.
- Light persistence of final choice in `localStorage`.

## Setup

```bash
mkdir invitation
cd invitation
opencode
```

Connect your favorite model (`/connect` and `/models`). For this challenge, a free model like **MiniMax M** or **Big Pickle** is more than enough.

## Prompt

Copy and paste this prompt into OpenCode. It's designed to start in **Build mode**, but you can start in **Plan** if you want to see the proposal first:

````text
Create a single-page mini web application titled "Want to hang out one day?".

Required stack:
- HTML, CSS, and vanilla JavaScript
- No external dependencies, no build step, no frameworks
- Three files maximum: index.html, styles.css, app.js
- Compatible with current Chrome, Safari, and Firefox

Views:

VIEW 1 — Invitation
- Centered title: "Do you want to hang out one day?"
- Optional subtitle with a friendly and fun touch
- Two buttons below the title: "Yes" and "No"
- "Yes" button: main style (accent color, smooth hover, accessible visible focus)
- "No" button: secondary style, but with special behavior:
- When the user's cursor gets close to the "No" button within ~80px, the button
must jump to a random position within the visible viewport
- Must never be clickable
- On touch devices, as soon as the user touches the screen near the
button, the button moves to another corner (no overflow or broken scroll)
- Clicking "Yes" navigates to VIEW 2 with a smooth transition (fade or slide)

VIEW 2 — Calendar and time
- Calendar of the CURRENT MONTH from the system, generated dynamically in JavaScript
- Header with the month name and year
- 7x6 grid with days, marking "today" with a different style
- Days before today appear disabled (no click)
- When selecting a day, a time selector appears below in 30-minute intervals
between 09:00 and 22:00
- "Confirm" button that saves the choice to localStorage and displays a
final message: "Great! See you on {day} at {time}."

Visual design:
- Soft palette: cream background (#F5F1E8), sage accents (#84B59F), and slate (#50808E)
- Sans-serif system typography (system-ui)
- Centered, responsive layout, mobile-first
- Smooth animations (transition: 200ms ease)
- Visible focus state for keyboard accessibility

Deliverables:
1. The three project files
2. A SPEC.md with the final specification (objective, stack, views, acceptance criteria)
3. A one-page README.md with how to start the project (npx serve .)

When you finish, do NOT install anything extra. Only run `npx serve .` and tell me what URL I can open it at.
````

## Suggested steps during the exercise

1. **Plan first (optional):** press `Tab` to enter Plan mode and paste the previous prompt with "Don't modify anything yet, give me the plan." Review the plan proposed by the agent.
2. **Build:** go back to Build (`Tab`) and let it execute.
3. **Start:**
```text
!npx serve .
```
4. **Iterate with short feedback.** Examples you can paste one after another while the agent keeps working (task queue):
- "The No button goes off viewport, keep it always 16px within the borders."
- "When the No button exit animation finishes, add a short confetti if the user clicks Yes."
- "In view 2, disable weekends."
- "Change the palette to something darker and more elegant while keeping sage as accent."
5. **Save tokens:** if you want to check a specific file, use `@app.js` in the input.
6. **Close the loop:** create an `AGENTS.md` with `/init` and commit with `/supercommit` (if you have it) or:
```text
!git init && git add . && git commit -m "feat: invitation challenge"
```

## Acceptance criteria

- [ ] The page looks correct on mobile and desktop.
- [ ] The "No" button can never be clicked.
- [ ] The calendar reflects the actual current month and year.
- [ ] The choice is saved in `localStorage` and appears again when reloading.
- [ ] There are no errors in the console.
- [ ] The project includes `SPEC.md` and `README.md`.

## Extensions (if you have time left)

- Add a `mailto:` endpoint that opens the email client with the proposed date/time already filled in.
- Internationalize the calendar (es / en) by detecting browser language.
- Replace local persistence with a `share link` that encodes the choice in the query string.
148 changes: 148 additions & 0 deletions docs/challenges/challenge_three.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Challenge 3 — Todo List Pro with backend and SQLite

**Level:** advanced
**Estimated time:** 60–90 min
**Objective:** build a real fullstack web application with SQLite persistence, practice the complete OpenSpec workflow (SPEC.md → AGENTS.md → sub-agents), and learn to work with multiple layers at once (frontend, API, database).

## Context

The classic Todo List, but built the way a professional team would: REST API backend, SQLite database, decoupled frontend, and a minimum of care for security and tests. It's the perfect challenge to show how OpenCode shines in multi-layer projects.

The challenge covers:

- Client-server architecture in a simple monorepo.
- REST endpoints with input validation.
- Persistence in SQLite (a single `data.db` file).
- Live AGENTS.md: rules that the agent respects between iterations.
- Division of work into sub-agents (explore, security, reviewer).
- Basic automated tests.

## Setup

```bash
mkdir todolist-pro
cd todolist-pro
opencode
```

Recommended: **Mimo 2.5 Pro** or **Qwen 3.6** for execution via OpenCode Zen, planning with **GPT-5.5 high** if you have ChatGPT Plus connected. The challenge benefits greatly from a good planner.

## Prompt

Copy and paste this prompt into OpenCode, ideally starting in **Plan mode**:

````text
Build a fullstack Todo List application with SQLite persistence.

Folder structure:
- /server → Node.js backend + SQLite (no Express if possible, use native http or minimal dependency like Hono)
- /web → vanilla frontend (HTML + CSS + JS, no frameworks)
- /db → data.db file and SQL migrations
- AGENTS.md → project rules
- SPEC.md → live specification
- README.md → how to start and test

Backend:
- Runtime: Node.js 24 or Bun (agent chooses and documents in AGENTS.md)
- REST API at /api with the following endpoints:
- GET /api/notes → paginated list (?page=1&limit=20)
- POST /api/notes → creates a note
- GET /api/notes/:id → detail
- PATCH /api/notes/:id → updates title, content, or status (done)
- DELETE /api/notes/:id → logical delete (soft delete, deleted_at column)
- Input validation: required title 1-120 chars; optional content max 5000 chars
- Consistent JSON responses: { ok: true, data } or { ok: false, error: { code, message } }
- Error handling with correct status codes (400, 404, 409, 500)
- CORS open to localhost in development

Database:
- SQLite (better-sqlite3 or bun:sqlite driver)
- File at /db/data.db
- Initial migration at /db/migrations/001_init.sql with the notes table:
id INTEGER PRIMARY KEY AUTOINCREMENT
title TEXT NOT NULL
content TEXT
done INTEGER NOT NULL DEFAULT 0
created_at DATETIME DEFAULT CURRENT_TIMESTAMP
updated_at DATETIME DEFAULT CURRENT_TIMESTAMP
deleted_at DATETIME
- Migrations apply automatically when starting the server

Frontend:
- index.html with:
- List of notes, filterable by status (all / pending / completed)
- Inline form to create new note (title + content)
- Inline editing when clicking title or content
- Button to mark as done (accessible checkbox)
- Delete button with discreet confirmation
- Friendly empty state when there are no notes
- styles.css with the soft sage palette from the workshop:
cream background #F5F1E8, sage accents #84B59F, slate #50808E, text #2E3A42
- app.js with fetch to /api, error handling, and visual feedback
- No frameworks or libraries; one template helper allowed (template literals)

Tests (minimal):
- API tests with node:test or bun:test
- Coverage: create, list paginated, update, delete, error validations
- Single command: `bun test` or `npm test`

Quality:
- Consistent code style (Prettier defaults)
- README with: requirements, start (single command), endpoints, curl examples
- AGENTS.md with all decisions (runtime, SQLite driver, no framework, no frontend framework)
- SPEC.md with objectives, entities, endpoints, and acceptance criteria

Steps before starting to program:
1. Give me a numbered plan of 7 to 10 steps without touching files.
2. List the decisions I need to confirm (runtime, driver, single startup command).
3. Wait for me to say "go" before starting to write code.
````

## Suggested steps during the exercise

1. **Plan and decisions.** Review the plan and confirm key decisions (runtime, driver). This avoids rewrites.
2. **Build with sub-agents.** When implementation starts, divide the work:
```text
In parallel:
@explore map what files you'll create and in what order
@general assess API security risks (SQL injection, CORS, validation)
```
3. **Build by layers.** Explicitly suggest to the agent to go layer by layer:
- Migration and data access module.
- Endpoints one by one with their tests.
- Minimal frontend connected to backend.
- Visual polish and empty states.
4. **Iterate with curl examples.** When the backend is ready, test in Shell Mode:
```text
!curl -s http://localhost:3000/api/notes | jq
!curl -s -X POST http://localhost:3000/api/notes -H 'Content-Type: application/json' -d '{"title":"First note","content":"hello"}'
```
5. **Save tokens.** For spot fixes, use `@server/routes/notes.js` or other specific files in the input.
6. **Close with a clean commit:**
```text
/supercommit feat: todo list MVP fullstack
```
Or manually:
```text
!git init && git add . && git commit -m "feat: todo list MVP fullstack"
```

## Acceptance criteria

- [ ] `bun dev` (or `npm run dev`) starts backend and frontend with a single command.
- [ ] All 5 REST endpoints work with consistent JSON responses.
- [ ] Database persists after restarting the server.
- [ ] Delete is logical (note isn't lost from database).
- [ ] Frontend shows empty states and errors in a friendly way.
- [ ] Tests pass (`bun test` or `npm test`).
- [ ] Repository includes `SPEC.md`, `AGENTS.md`, and `README.md`.
- [ ] No obvious vulnerabilities (SQL injection, XSS when rendering content).

## Extensions (if you have time left)

- **Tags:** add a tag system per note and a tag filter in the frontend.
- **Search:** `GET /api/notes?q=text` endpoint with full-text search using SQLite's FTS5 extension.
- **Basic auth:** middleware with Bearer token and single user configurable by `.env`.
- **Export / Import:** endpoints to download and upload JSON backups.
- **PWA:** convert the frontend into an installable PWA with manifest and offline-first service worker.
- **DESIGN.md:** document the design system used and ask the AI to respect those tokens in future iterations.
121 changes: 121 additions & 0 deletions docs/challenges/challenge_two.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
# Challenge 2 — Space Invaders: an arcade in an afternoon

**Level:** intermediate
**Estimated time:** 40–60 min
**Objective:** build a classic arcade game like *Space Invaders* from scratch, practice the iteration cycle, and learn to use `SPEC.md`, sub-agents, and the `frontend-design` skill to level up visually.

## Context

You're going to recreate the typical 80s arcade: a ship at the bottom of the screen, waves of aliens descending from above, bullets going up, and score. Only HTML, CSS, and a `<canvas>` with vanilla JavaScript. The goal is not just that it "works," but that it feels good to play: rhythm, impact effects, and increasing difficulty.

The challenge covers:

- Architecture of a game loop with `requestAnimationFrame`.
- Rendering on `<canvas>` (no external sprites, only shapes).
- Simple collision detection (AABB).
- Game states (intro → playing → game over).
- Iteration guided by feedback (game-feel, not just logic).

## Setup

```bash
mkdir invaders
cd invaders
opencode
```

Recommended for this challenge: a medium to high reasoning model (for example **Mimo 2.5 Pro** via OpenCode Zen, or **GPT-5.5 medium** if you have ChatGPT Plus connected). Smaller models tend to struggle with collision logic.

## Prompt

Copy and paste this prompt into OpenCode. It's designed to start in **Plan mode** first, validate the design, and then switch to Build:

````text
Build an arcade game on a single web page inspired by Space Invaders.

Required stack:
- HTML, CSS, and vanilla JavaScript
- Render on a single <canvas>
- No external dependencies, no image sprites (shapes drawn by code)
- Three files maximum: index.html, styles.css, game.js

Mechanics:
- Player ship at the bottom, moves with LEFT and RIGHT arrow keys
- Shooting with SPACEBAR (limited firing rate: max one bullet every 220 ms)
- Initial grid of 5 rows x 8 columns of aliens at the top
- Aliens move as a block left/right and drop one row when touching edge
- Every so often a random alien shoots downward (adjustable firing rate)
- AABB collision detection between bullets and aliens, and between enemy bullets and ship
- Each destroyed alien scores points based on its row (higher up = more points)
- 3 lives. Lose a life on impact, with brief invulnerability (~1 s)
- When all aliens are eliminated, a new wave begins that's faster

Game states:
- INTRO: screen with title "INVADERS", high score display, and "Press SPACE to start"
- PLAYING: HUD with score, lives, and current wave in the upper corner
- GAME OVER: screen with "GAME OVER", final score, and "Press SPACE to retry"
- High score persists in localStorage

Game feel (important):
- Small screen shake when destroying an alien
- Brief white flash on ship impact
- Simple particles (4-8 pixels) when destroying aliens
- Sounds generated with WebAudio (no files): pew on shooting, hit on impact, explosion on death
- Difficulty curve: each wave speeds up movement by 10%

Visual design:
- Retro CRT aesthetic, but with soft and modern colors
- Almost black background (#0E1116), ship in sage (#84B59F), aliens in eucalyptus (#69A297), and slate (#50808E)
- Monospaced typography (system-ui mono)
- No gradients; sharp pixel-perfect edges
- Canvas 800x600 logical, scaled responsively while maintaining aspect ratio

Deliverables:
1. index.html, styles.css, game.js
2. SPEC.md with the final specification (mechanics, states, game feel, acceptance criteria)
3. AGENTS.md with project rules (vanilla, no dependencies, single canvas, no external sprites)

First, give me a plan in five steps without touching any files.
When you say "go", we move to Build.
````

## Suggested steps during the exercise

1. **Plan:** read the plan the agent proposes, adjust if you want (for example, "I don't care about screen shake in the first version, prioritize collisions").
2. **Build:** respond `go` and let it execute. Meanwhile, in another tab, open the file explorer to watch how it creates `game.js`.
3. **Start the game:**
```text
!npx serve .
```
4. **Iterate with short prompts.** Queue up several without waiting between them:
- "The firing rate feels slow, lower it to 180 ms."
- "When the player holds spacebar, it should fire continuously respecting the firing rate."
- "Add a power-up that appears at random and grants double cannon for 6 seconds."
- "Improve the retro look using the frontend-design skill."
5. **Use sub-agents for review.** In a single prompt:
```text
In parallel:
@reviewer review game.js and tell me the logic bugs you see
@general evaluate game loop performance on mobile
When both finish, consolidate an improvement plan.
```
6. **Commit:**
```text
!git init && git add . && git commit -m "feat: invaders mvp"
```

## Acceptance criteria

- [ ] The game starts, is playable with keyboard, and ends when you lose 3 lives.
- [ ] Score and high score appear on screen and persist when reloading.
- [ ] Collisions work in both directions (bullet→alien and bullet→ship).
- [ ] Difficulty increases when changing waves.
- [ ] No external sprites: everything is drawn with code.
- [ ] The project includes `SPEC.md` and `AGENTS.md`.

## Extensions (if you have time left)

- Add a boss alien that appears every N waves, with multiple lives and different movement pattern.
- Gamepad support: read the Gamepad API and map d-pad + A button.
- Create a simple *replay* that records player inputs and allows playback.
- Convert the HUD into a reusable component and document the design in `DESIGN.md`.