# From Sketch to Spec to Ship: Spec-Driven Development with Spec-Kit and GitHub Copilot

I wanted to build a Flappy Ghost game — a browser-based, zero-dependency HTML5 canvas game — but instead of just vibe-coding it with an AI, I challenged myself to do it properly using **Specification-Driven Development (SDD)** with **Spec-Kit** and **GitHub Copilot** inside VS Code. This post walks through exactly what I did, why SDD matters, and how the whole thing came together.

* * *

## The Problem with "Just Prompt It"

When most developers use AI coding assistants, the workflow looks like this:

> Describe what you want → get code → tweak it → ship it

It works, kind of. But you end up with code that has no traceable spec, no acceptance criteria, and no plan. You can't answer "does this code actually match what was intended?" because there was never a written intention to begin with. That's vibe-coding — and it gets messy fast.

* * *

## What Is Specification-Driven Development (SDD)?

SDD flips the order. You write the **specification first**, then derive the implementation from it — with AI doing the heavy lifting at every step, but always anchored to a written artifact you've reviewed and approved.

The SDD cycle looks like this:

```plaintext
Visual Mockup / Idea
        │
        ▼
  spec.md      ← BDD acceptance criteria (Given/When/Then)
        │
        ▼
  plan.md      ← Architecture, technical decisions, file structure
        │
        ▼
  tasks.md     ← Checkbox task list, ordered and granular
        │
        ▼
  Code         ← Generated against the tasks, traceable to spec
        │
        ▼
  Validate     ← Does the code satisfy spec.md acceptance criteria?
```

At each phase, a **human reviews and approves** the artifact before the next phase begins. Copilot doesn't proceed until you say so. This enforces spec-first discipline and gives you traceability from every line of code back to a user story.

* * *

## What Is Spec-Kit?

[Spec-Kit](https://github.github.com/spec-kit) is an open-source CLI tool from GitHub that scaffolds the SDD workflow directly into your project. It installs a set of **Copilot agent files** (`.github/agents/`) that extend GitHub Copilot Chat with slash commands like `/speckit.specify`, `/speckit.plan`, `/speckit.tasks`, and `/speckit.implement`.

Once initialised, your project has a structured `.specify/` folder with templates, scripts, memory (a project constitution), and integration configs. Copilot reads the agent files automatically — no extra configuration needed.

* * *

## My Scenario: Flappy Ghost 👻

I had a hand-drawn mockup image of a Flappy Bird-style game with a ghost as the player. The design showed:

*   Light blue sketchy/pencil-textured background
    
*   Green pipes extending from top and bottom edges
    
*   Rounded cloud platforms as mid-field obstacles
    
*   A dark floor strip with a score HUD: `Score: X | High: X`
    
*   A ghost emoji (`👻`) as the player character
    

The goal: a single self-contained `index.html` — no frameworks, no build tools, no CDN links. Just vanilla HTML5 Canvas and JavaScript.

* * *

## Step-by-Step: How I Built It

### Step 1 — Install the Tooling

Spec-Kit's CLI (`specify`) is installed from GitHub, not PyPI. Use `uv` (a fast Python package manager):

```powershell
# Install uv (Windows)
winget install --id=astral-sh.uv -e

# Install specify CLI (check releases for latest tag)
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@v0.11.5

# Verify
specify version
```

> ⚠️ `pip install speckit` installs a completely unrelated spectral analysis library. Always use the `uv tool install` command above.

* * *

### Step 2 — Initialise the Project

```powershell
mkdir flappy-ghost
cd flappy-ghost
git init
specify init flappy-ghost --integration copilot
code .
```

This scaffolds everything into `.github/agents/`, `.github/prompts/`, and `.specify/`. Open `.github/agents/` — you'll see agent files like `speckit.specify.agent.md`, `speckit.plan.agent.md`, etc. These extend Copilot Chat with the `/speckit.*` slash commands.

* * *

### Step 3 — Generate the Spec from the Mockup Image

This is where SDD gets interesting. I opened **GitHub Copilot Chat** in Agent mode (`Ctrl+Alt+I`), selected the `speckit.specify` agent, attached my mockup image, and described the feature:

```plaintext
Use the attached sketch as the visual specification for a browser-based 
HTML5 canvas game called "Flappy Ghost".

The game must match everything visible in the image:
- Hand-drawn / sketchy art style for all visuals
- Small ghost emoji as the player character
- Green pipe obstacles from top and bottom
- Rounded cloud platforms as mid-field obstacles
- Light blue pencil-stroke textured background
- Dark grey floor strip at the bottom
- Score HUD: "Score: X | High: X"
- Spacebar or click to flap; gravity pulls down
- Collision with pipes, clouds, floor, or ceiling ends the game
```

Copilot generated `features/001-flappy-ghost-game/spec.md` — a full BDD spec with user stories and acceptance scenarios. For example:

> **Given** the game is running and the player does nothing, **When** each frame advances, **Then** the ghost's vertical velocity increases by the gravity constant until it reaches terminal velocity.

Seven user stories covered: flight loop, pipe obstacles, cloud platforms, floor/ceiling boundaries, score tracking, game over/restart, and the hand-drawn art style.

```powershell
git add .
git commit -m "feat(spec): flappy-ghost-game specification"
```

* * *

### Step 4 — Generate the Implementation Plan

Back in Copilot Chat:

```plaintext
/speckit.plan The game is a single self-contained index.html file.
Use vanilla HTML5 Canvas and JavaScript — no frameworks or build tools.
```

Copilot read `spec.md` and wrote `plan.md` covering canvas setup, the `requestAnimationFrame` game loop, physics model (gravity constant + flap impulse), pipe and cloud spawning, collision detection (AABB), score tracking with `localStorage`, and the sketchy rendering approach.

```powershell
git add .
git commit -m "feat(plan): flappy-ghost-game implementation plan"
```

* * *

### Step 5 — Break It into Tasks

```plaintext
/speckit.tasks
```

Copilot produced `tasks.md` — a numbered checkbox list:

*   \[ \] T1: Create `index.html` with canvas element and score HUD
    
*   \[ \] T2: Implement game loop with `requestAnimationFrame`
    
*   \[ \] T3: Render ghost as 👻 emoji on canvas (34px, velocity-rotated)
    
*   \[ \] T4: Implement gravity and flap physics
    
*   \[ \] T5: Pipe spawning at random heights with fixed gap
    
*   \[ \] T6: Cloud platform spawning (white rounded rects, mid-screen)
    
*   \[ \] T7: Collision detection (ghost vs pipes, clouds, floor, ceiling)
    
*   \[ \] T8: Score increment on pipe pass; high score via `localStorage`
    
*   \[ \] T9: Game-over overlay with restart prompt
    
*   \[ \] T10: Sketchy background — pencil-line pattern pre-rendered to off-screen canvas
    

```powershell
git add .
git commit -m "feat(tasks): flappy-ghost-game task breakdown"
```

* * *

### Step 6 — Implement

```plaintext
/speckit.implement
```

Copilot worked through `tasks.md` top-to-bottom and generated `index.html`. When the first pass looked too clean, I followed up with a targeted style prompt:

```plaintext
The art style must look hand-drawn:
- strokeRect with ±3px random jitter on pipes and floor
- Ghost as 👻 at 34px, rotated proportionally to vertical velocity
- Background: #a8d5e8 fill, overlaid with diagonal pencil strokes (off-screen canvas)
- Clouds: white rounded rectangles with canvas shadow blur glow
- Floor: #2d2d2d strip, 40px tall
- HUD: monospace, white, centred in the floor strip
```

Result: a working `index.html` that opens directly in the browser, no server needed.

* * *

### Step 7 — Validate Against the Spec

I opened `index.html` in the browser and manually tested against each acceptance scenario in `spec.md`:

*   ✅ Press Space → ghost flaps upward, gravity pulls it back down
    
*   ✅ Fly into a pipe → Game Over triggers
    
*   ✅ Pass through a gap → score increments
    
*   ✅ Reload the page → high score persists via `localStorage`
    
*   ✅ Background has visible pencil-stroke texture
    
*   ✅ Ghost rotates with velocity direction
    

Every test traced back to a specific Given/When/Then in the spec.

* * *

## The Key Insight: Traceability

Without SDD, you have code. With SDD, you have:

*   **spec.md** → what the software must do (acceptance criteria)
    
*   **plan.md** → how it will be built (architecture decisions)
    
*   **tasks.md** → what was built and in what order
    
*   **code** → the implementation, traceable to every task above
    

If a bug appears, you don't just fix it — you check which acceptance scenario it violates and trace it back. That's the discipline SDD enforces.

* * *

## Spec-Kit Slash Commands Reference

| Command | Purpose |
| --- | --- |
| `/speckit.constitution` | Establish project coding standards |
| `/speckit.specify` | Create feature spec from description or image |
| `/speckit.clarify` | Surface ambiguities before planning |
| `/speckit.plan` | Generate technical implementation plan |
| `/speckit.analyze` | Cross-check spec, plan, and tasks for consistency |
| `/speckit.tasks` | Break plan into actionable task checklist |
| `/speckit.implement` | Execute tasks and generate code |
| `/speckit.checklist` | Generate quality checklist for the feature |
| `/speckit.converge` | Assess codebase against spec and append remaining work |

* * *

## Final Thoughts

SDD with Spec-Kit didn't slow me down — it made every AI-generated output useful because it was grounded in something I had reviewed. The mockup image became a living specification. The spec became the plan. The plan became tasks. The tasks became working code.

If you're using GitHub Copilot and finding that "just prompt it" leaves you with code you can't justify, this workflow is worth trying. The spec is the contract — everything else follows from it.

* * *

*Try it yourself:* [*github.github.com/spec-kit*](https://github.github.com/spec-kit)
