# Pen → Flutter workflow

One workflow for every Kasy project. The client **almost never keeps the default
Kasy brand**. They rebrand first (colours, font, radius), then build screens.
Your job as the AI is to keep **Pen, the design system, and Flutter code in
sync**, and to ship screens that are **faithful and functional**.

**Pen is the same product formerly called "Pencil".** The company rebranded; the
domain is now `pen.dev`. You may still see `pencil` in package names, MCP server
identifiers, or config files — that is the same tool, not a different one.
Talk to the user about "Pen", not "Pencil".

This is the **alternative** design tool to Figma. Both deliver the exact same
design system (same tokens: colour, spacing, radius, typography) and both ship
their own MCP server usable from any IDE (Cursor, Claude Code, Claude Desktop,
Windsurf, …). Pick whichever the project already uses — check which MCP tools
are available (`get_variables`/`batch_design` → Pen; `get_variable_defs`/`use_figma`
→ Figma) or ask the client. Figma's equivalent workflow: `docs/figma-workflow.md`.

Human-friendly guides (step by step, localized): **`docs/pen-guia.md`** in the
user's project language. Public docs: **kasy.dev/docs** → Personalização → Pen.

## Get the design system file

There is **no local design file** in the generated project, and unlike Figma,
Pen has no cloud "Community" page to duplicate from inside the tool. The master
file is hosted as a **zip** download, not a bare `.pen`: Pen stores images as
separate files next to the `.pen`, so a `.pen` alone (without its images
folder) breaks the image references — the zip keeps both together.

| Resource | URL |
| -------- | --- |
| Design system file (zip download) | https://xkefozfsrmqjtesiitvk.supabase.co/storage/v1/object/public/design-downloads/Kasy-Design-System.zip |
| This workflow (AI) | `docs/pen-workflow.md` |
| Beginner guide (human) | `docs/pen-guia.md` |

**How the client gets their own copy:**

1. Download the zip from the URL above and unzip it — you get a folder with
   the `.pen` file and its images side by side.
2. Open the `.pen` file **from inside that extracted folder** in the **Pen
   desktop app** (pen.dev) — this is a local file, not a web session, so
   there's nothing to "duplicate" or "save to drafts". It's already theirs
   once downloaded. Don't move the `.pen` file out of the folder on its own;
   the images have to stay alongside it.
3. Keep the Pen desktop app **running with that file open** — the Pen MCP
   connects to the currently open file in the running app, not to a file path
   or URL. If a Pen MCP tool call fails with a connection error, the fix is
   opening (or re-opening) the file in the desktop app, not retrying the tool.
4. Edit **Variables** in that copy, then hand the AI the running session (no
   file key / URL to pass — the MCP already knows what's open).

Because there's no cloud master, freshness works differently than Figma: if
Kasy updates the design system later, the client needs a fresh copy of the same
URL (re-download), not a "get latest" action inside Pen.

## The one Pen file (for now)

Unlike Figma (separate **Kasy Design System** + **App Design** files), a single
`.pen` file is the norm for the design system today. Product screens can live
in new pages of the same file, or in a second `.pen` file the client creates —
either way, they must use the **same variables** as the design system pages.

## Pen MCP tools (read + write design)

Use these on the file **currently open in the Pen desktop app**:

| Tool | Use |
| ---- | --- |
| `get_editor_state` | Call this **first** if you don't have the current file's schema — required before any other Pen tool call |
| `get_variables` | Read colour/spacing/radius tokens defined in the file |
| `get_guidelines` | Read the file's own design guidelines, if the client wrote any |
| `snapshot_layout` | Structure of frames/pages, similar to Figma's metadata |
| `get_screenshot` | Visual verification vs the running app |
| `batch_get` | Batch-read multiple nodes at once |
| `batch_design` | **Generate or edit nodes directly in the file.** Unlike Figma MCP (mostly read + "edit assist"), Pen's AI can draw the screens itself — use this to build frames, not just read them |
| `export_nodes` / `export_html` | Export assets (icon, splash, logos) or markup for handoff |

## Step 1 — Rebrand (always before screens)

### 1a. Read tokens from Pen

Call `get_editor_state` once, then `get_variables` to see the real token names
in **this** file — Pen files built from the Kasy token set typically mirror the
same categories as Figma (just double-check naming, it may use dotted paths
like `brand.primary.base` instead of Figma's `primary/base`):

| Category | Maps to |
| -------- | ------- |
| Brand / primary colours (light + dark) | `KasyColors.light()` / `.dark()` |
| Spacing scale | `KasySpacing.*` |
| Radius scale | `KasyRadius.*` |

**Rebrand shortcut:** change the primary/accent colour per mode (light stays
the darker brand tone; dark needs a lighter tone for contrast on near-black),
then update derived tokens and run the full sync below. Do **not** stop at
primary only — same rule as Figma.

Premium paywall tokens (`premiumOverlay*`, `premiumBannerText`) are **not** in
the design file (Figma or Pen). They stay internal in `colors.dart`.

### 1b. Sync colours → `lib/core/theme/colors.dart`

Edit **`KasyColors.light()`** and **`KasyColors.dark()`** factories. Map every
token `get_variables` returned — accent/primary, default/neutral, success,
warning, danger, foreground, background, surface, form field, separator,
other. Do **not** change only primary / accent.

**Derived tokens** (`primarySoft`, `dangerSoft`, …): keep the existing alpha
pattern in `colors.dart` unless the user provides explicit soft values.

**Typography:** single family (Poppins in the kit default) — Pen and the
Flutter app should use the same one.

### 1c. Sync radius and spacing

Map Pen's radius/spacing scale into `KasyRadius.*` (`radius.dart`) and
`KasySpacing.*` (`spacing.dart`) the same way as the Figma workflow (Step 1c).

### 1d. Verify rebrand

1. `kasy run --web` (or the `run_app` MCP tool, platform web).
2. Open **Home → Design System**. Compare light + dark to the Pen file
   (`get_screenshot` for a side-by-side).
3. `flutter analyze` — zero issues.

Do not implement product screens until this step passes.

## Step 2 — Implement a screen (faithful + functional)

### 2a. Inputs

- Frame/page name in the client's Pen file, open in the desktop app.
- Rebrand already applied (Step 1).

### 2b. Design system guard (run first)

Same guard as Figma (`docs/figma-workflow.md` Step 2b): every colour and font
size in the frame must resolve to a token already in `colors.dart` /
`KasyTypeScale`. Hex **not** in the design system → stop, report it, fix the
design file + `colors.dart` first, don't hardcode.

### 2c. Build the screen

| Requirement | How |
| ----------- | --- |
| Layout faithful to the Pen frame | Spacing, hierarchy, light + dark (`get_screenshot` / `snapshot_layout` for reference) |
| Tokens only | `context.colors.*`, `context.kasyTextTheme.*`, `KasySpacing.*`, `KasyRadius.*` |
| Kit components | `KasyButton`, `KasyTextField`, `KasySwitch`, `KasyCard`, `KasyScreen`, … (cross-check with the `list_components` tool) |
| Functional | Real `onPressed`, controllers, providers, navigation |
| i18n | `context.t.*` + keys in slang JSON (pt, en, es) |
| No raw Material | `showKasyConfirmDialog`, `showKasyToast`, not `AlertDialog` / `SnackBar` |

### 2d. Verify screen

- [ ] Matches the Pen frame (light + dark)
- [ ] Interactions work
- [ ] `flutter analyze` clean
- [ ] Optional: `dart run tool/design_check.dart`

## Copy-paste prompts (user → AI)

**Rebrand:**

```
Read AGENTS.md and docs/pen-workflow.md.
My design system is open in the Pen desktop app (pen.dev).
Call get_editor_state, then get_variables to read the tokens.
Sync ALL colour tokens into KasyColors.light() and .dark() in
lib/core/theme/colors.dart (not accent only).
Update splash colour in pubspec.yaml if background changed.
Verify on Design System screen. flutter analyze clean.
```

**New screen:**

```
Read docs/pen-workflow.md. My screen is on page/frame [FRAME NAME] in the
Pen file that's open right now.
Run design system guard on that frame.
Use get_screenshot + snapshot_layout for reference.
Implement faithful + functional screen: feature folder, route, i18n (pt/en/es),
Kasy components + tokens only. flutter analyze clean.
```

## Common mistakes

| Mistake | Fix |
| ------- | --- |
| Rebrand accent only | Update the full mapping table (Step 1b) |
| `Color(0x…)` on screens | Token in `colors.dart` first |
| Screen before rebrand | Step 1 first |
| Static mockup | Wire state and callbacks |
| Raw Material widgets | Kasy components |
| Pen MCP tool errors with a connection message | The desktop app isn't running or the file isn't open — open it, don't just retry |
| Calling any Pen tool before `get_editor_state` | Always call it first when you don't already have the file's schema |

## AI checklist

- [ ] Read `docs/pen-workflow.md` and `docs/pen-guia.md` if user is non-technical
- [ ] Client downloaded and unzipped the folder, and has the `.pen` file (images alongside it) open in the Pen desktop app
- [ ] Rebrand complete (all mapped colours, light + dark)
- [ ] Design system guard passed for screen frames
- [ ] Feature + route + i18n
- [ ] Faithful + functional
- [ ] `flutter analyze` clean

## Related docs

- **`docs/pen-guia.md`** — beginner guide (project language)
- **`docs/figma-workflow.md`** — the Figma equivalent, same result, different tool
- **`AGENTS.md`** — golden rules
- **`DESIGN_SYSTEM.md`** — full token reference
- **kasy.dev/docs** → Personalização → Pen
