344 lines
11 KiB
Markdown
344 lines
11 KiB
Markdown
---
|
|
name: flutterflow-designer
|
|
description: Use when building Flutter UI screens in FlutterFlow. Triggers include "build UI in FlutterFlow", "create screens in FlutterFlow", "design app in FlutterFlow", "FlutterFlow automation", "orbit", or when the user wants to visually design and export Flutter screens. Uses the FlutterFlow AI Designer for rapid screen generation, FF Orbit MCP for programmatic refinement, and Chrome browser automation for interaction.
|
|
---
|
|
|
|
# FlutterFlow Designer — AI Designer + Orbit MCP + Browser Automation Skill
|
|
|
|
Build production Flutter screens in FlutterFlow using three complementary interfaces:
|
|
|
|
1. **FlutterFlow AI Designer** (primary) — Prompt-based AI tool at `https://designer.flutterflow.io/dashboard` that generates complete app screens from text descriptions. Fastest way to create multiple screens at once.
|
|
2. **FF Orbit MCP** (secondary) — Programmatic API with 70+ commands for pages, widgets, themes, routes, and changesets. Use for precise refinement after AI generation.
|
|
3. **Chrome Browser Automation** (tertiary) — Visual verification, previewing, and manual operations via `mcp__claude-in-chrome__*` tools.
|
|
|
|
## Prerequisites
|
|
|
|
### Required: Chrome Browser with Claude-in-Chrome Extension
|
|
|
|
The FlutterFlow AI Designer and Builder both require browser automation:
|
|
- Chrome browser with **Claude-in-Chrome extension**
|
|
- MCP tools: `mcp__claude-in-chrome__*`
|
|
- Verify: `tabs_context_mcp`
|
|
|
|
### Optional: FF Orbit MCP
|
|
|
|
For programmatic refinement after AI-generated screens. Check `.mcp.json` in the project root:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"ff_orbit_mcp": {
|
|
"command": "npm",
|
|
"args": ["start"],
|
|
"cwd": "/Users/alainbagmi/flutterflow-mcp",
|
|
"env": {
|
|
"FLUTTERFLOW_API_TOKEN": "<your-token>",
|
|
"FLUTTERFLOW_API_MIN_INTERVAL_MS": "1000",
|
|
"ORBIT_POLICY_SAFE_MODE": "guidedWrite"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
## Quick Start — Build Screens with AI Designer (Preferred)
|
|
|
|
### Step 1: Navigate to FlutterFlow AI Designer
|
|
|
|
```
|
|
1. tabs_context_mcp → check for existing tabs
|
|
2. tabs_create_mcp → create new tab
|
|
3. navigate → https://designer.flutterflow.io/dashboard
|
|
```
|
|
|
|
### Step 2: Enter Prompt
|
|
|
|
```
|
|
1. find → "text input field for prompt" → get ref for the textbox
|
|
2. click on textbox ref to focus it
|
|
3. type → comprehensive prompt describing all screens with:
|
|
- App name and theme (colors, background, accent)
|
|
- Each screen numbered with name and key UI elements
|
|
- Specific data examples (currencies, names, locations)
|
|
4. Press Enter OR click submit arrow to generate
|
|
```
|
|
|
|
### Step 3: AI Generates Screens
|
|
|
|
- The AI will navigate to a new design session URL
|
|
- Wait 10-15 seconds for generation to complete
|
|
- Screens appear as frames in the left sidebar
|
|
- Scroll through canvas to verify all screens
|
|
|
|
### Step 4: Add More Screens (Follow-up Prompts)
|
|
|
|
To add screens to an existing session, navigate back to the dashboard and submit a new prompt. Each submission creates a new design session.
|
|
|
|
### Key Tips for AI Designer
|
|
|
|
- **Be specific**: Include exact colors (#AAFF00), currency (XAF), data examples
|
|
- **Batch screens**: Submit up to ~10 screens per prompt for best results
|
|
- **Dark theme**: Specify background (#0D0F14), card surfaces (#1A1C24), text colors
|
|
- **Flutter Web quirks**: The text input is a Flutter web widget — use `find` to get ref, `type` for keyboard input, `Return` key to submit
|
|
- **Submit button**: If clicking the arrow doesn't work, focus the textbox and press Enter/Return
|
|
|
|
### Using Orbit MCP (For Refinement)
|
|
|
|
```
|
|
1. List projects: orbit({ cmd: "projects.list" })
|
|
2. Create snapshot: orbit({ cmd: "snapshots.create", args: { projectId: "..." } })
|
|
3. Create page: orbit({ cmd: "page.create", args: { name: "SplashScreen", apply: true } })
|
|
4. Add widgets: orbit({ cmd: "widget.create", args: { nameOrId: "SplashScreen", type: "Stack", apply: true } })
|
|
5. Configure widgets: orbit({ cmd: "widget.set", args: { nameOrId: "SplashScreen", nodeId: "...", ... } })
|
|
6. Preview via browser: Open FlutterFlow in Chrome to visually verify
|
|
```
|
|
|
|
### Using FlutterFlow Builder (Manual)
|
|
|
|
```
|
|
1. tabs_context_mcp → check for FlutterFlow tab
|
|
2. navigate → https://app.flutterflow.io
|
|
3. Open project → build widgets via UI interaction
|
|
4. See builder-reference.md for complete UI mapping
|
|
```
|
|
|
|
## Core Workflow: Orbit MCP
|
|
|
|
### Step 1: Resolve Project and Snapshot
|
|
|
|
Always start by establishing context:
|
|
|
|
```
|
|
orbit({ cmd: "projects.list" })
|
|
→ Find ZIVVO project ID
|
|
|
|
orbit({ cmd: "snapshots.create", args: { projectId: "<id>" } })
|
|
→ Creates local snapshot of project state
|
|
|
|
orbit({ cmd: "snapshots.info" })
|
|
→ Verify snapshot is fresh and complete
|
|
```
|
|
|
|
If snapshot exists but may be stale:
|
|
```
|
|
orbit({ cmd: "snapshots.ensureFresh" })
|
|
```
|
|
|
|
### Step 2: Create or Navigate to Page
|
|
|
|
```
|
|
# List existing pages
|
|
orbit({ cmd: "pages.list" })
|
|
|
|
# Create new page
|
|
orbit({ cmd: "page.create", args: { name: "SplashScreen", apply: true } })
|
|
|
|
# Get page details (full widget tree)
|
|
orbit({ cmd: "page.get", args: { nameOrId: "SplashScreen" } })
|
|
```
|
|
|
|
### Step 3: Build Widget Tree
|
|
|
|
Build top-down — add outermost layout first, then children:
|
|
|
|
```
|
|
# Add root Stack widget
|
|
orbit({ cmd: "widget.create", args: {
|
|
nameOrId: "SplashScreen",
|
|
type: "Stack",
|
|
apply: true
|
|
}})
|
|
|
|
# Add child Container inside Stack
|
|
orbit({ cmd: "widget.create", args: {
|
|
nameOrId: "SplashScreen",
|
|
type: "Container",
|
|
parentNodeId: "<stack-node-id>",
|
|
apply: true
|
|
}})
|
|
|
|
# Add Column inside Stack (for centered content)
|
|
orbit({ cmd: "widget.create", args: {
|
|
nameOrId: "SplashScreen",
|
|
type: "Column",
|
|
parentNodeId: "<stack-node-id>",
|
|
apply: true
|
|
}})
|
|
```
|
|
|
|
### Step 4: Configure Widget Properties
|
|
|
|
```
|
|
# Set widget properties
|
|
orbit({ cmd: "widget.set", args: {
|
|
nameOrId: "SplashScreen",
|
|
nodeId: "<widget-node-id>",
|
|
props: {
|
|
"width": "double.infinity",
|
|
"height": "double.infinity",
|
|
"color": "#FAFAF7"
|
|
},
|
|
apply: true
|
|
}})
|
|
|
|
# Update text content
|
|
orbit({ cmd: "widget.set", args: {
|
|
nameOrId: "SplashScreen",
|
|
nodeId: "<text-node-id>",
|
|
text: "ZIVVO",
|
|
apply: true
|
|
}})
|
|
```
|
|
|
|
### Step 5: Batch Operations
|
|
|
|
For efficiency, use batch commands:
|
|
|
|
```
|
|
# Update multiple widgets at once
|
|
orbit({ cmd: "widgets.updateMany", args: {
|
|
nameOrId: "SplashScreen",
|
|
filter: { type: "Text" },
|
|
updates: { ... },
|
|
apply: true
|
|
}})
|
|
|
|
# Find all text fields on a page
|
|
orbit({ cmd: "textfields.list", args: { nameOrId: "SplashScreen" } })
|
|
```
|
|
|
|
### Step 6: Safe Writes with Changesets
|
|
|
|
For complex multi-step edits, use the changeset pipeline:
|
|
|
|
```
|
|
# 1. Create changeset
|
|
orbit({ cmd: "changeset.new" })
|
|
|
|
# 2. Add patches
|
|
orbit({ cmd: "changeset.add", args: { changesetId: "chg_...", patches: [...] } })
|
|
|
|
# 3. Preview changes (diff)
|
|
orbit({ cmd: "changeset.preview", args: { changesetId: "chg_..." } })
|
|
|
|
# 4. Validate
|
|
orbit({ cmd: "changeset.validate", args: { changesetId: "chg_..." } })
|
|
|
|
# 5. Apply safely (handles rate limiting)
|
|
orbit({ cmd: "changeset.applySafe", args: { changesetId: "chg_...", confirm: true } })
|
|
```
|
|
|
|
**Only claim success when `applied === true`.**
|
|
|
|
### Step 7: Scaffold Pages from Templates
|
|
|
|
FlutterFlow MCP includes built-in page recipes:
|
|
|
|
```
|
|
orbit({ cmd: "page.scaffold", args: {
|
|
recipe: "auth.login",
|
|
name: "LoginPage",
|
|
apply: true
|
|
}})
|
|
```
|
|
|
|
Available recipes: `auth.login`, `auth.signup`, `settings.basic`, `list.cards.search`, `detail.basic`
|
|
|
|
## Command-First Policy
|
|
|
|
Always prefer deterministic first-class commands over exploratory probing:
|
|
|
|
| Intent | Command |
|
|
|--------|---------|
|
|
| List pages | `pages.list` |
|
|
| Page details | `page.get { nameOrId }` |
|
|
| Widget inventory | `widgets.list { nameOrId, type?, include? }` |
|
|
| Text fields | `textfields.list { nameOrId }` |
|
|
| Single widget | `widget.get { nameOrId, nodeId }` |
|
|
| Create widget | `widget.create { nameOrId, type, parentNodeId }` |
|
|
| Update widget | `widget.set { nameOrId, nodeId, ... }` |
|
|
| Update text | `widget.set { nameOrId, nodeId, text: "..." }` |
|
|
| Wrap widget | `widget.wrap { nameOrId, nodeId, wrapperType }` |
|
|
| Move widget | `widget.move { nameOrId, nodeId, newParentNodeId }` |
|
|
| Delete widget | `widget.delete { nameOrId, nodeId }` |
|
|
| Batch update | `widgets.updateMany { nameOrId, filter, updates }` |
|
|
| Create page | `page.create { name }` |
|
|
| Rename page | `page.update { nameOrId, key: "name", value: "..." }` |
|
|
| Delete page | `page.remove { nameOrId }` |
|
|
| Clone page | `page.clone { nameOrId, newName }` |
|
|
| Manage routes | `routes.upsert` / `routes.delete` / `routes.list` |
|
|
| Search project | `search { query }` |
|
|
| Natural language | `intent.run { text: "..." }` |
|
|
|
|
## Snapshot Freshness
|
|
|
|
- Default to the latest snapshot unless user pins one
|
|
- If data looks stale or incomplete: `snapshots.refresh`
|
|
- Conservative refresh: `{ mode: "incremental", fetchStrategy: "auto", maxFetch: 25, concurrency: 1, sleepMs: 250 }`
|
|
- Under heavy rate limiting: `snapshots.refreshSlow`
|
|
- Only treat snapshot as authoritative when `authoritative: true` and `pruneApplied: true`
|
|
- Never infer deletions from partial refreshes
|
|
|
|
## Policy Guardrails
|
|
|
|
The Orbit policy engine enforces write safety:
|
|
|
|
- **safeMode**: `readOnly` | `guidedWrite` | `fullWrite`
|
|
- Files matching `denyFileKeyPrefixes` are blocked from edits
|
|
- Custom code (`lib/custom_code/`, `lib/main.dart`) is denied by default
|
|
- If a write is blocked, report the exact `fileKey` and policy reason
|
|
- Never report success when apply is policy-blocked
|
|
|
|
Check policy: `orbit_policy_get()`
|
|
|
|
## Visual Verification via Browser
|
|
|
|
After building with Orbit, optionally verify visually:
|
|
|
|
```
|
|
1. tabs_context_mcp → check for FlutterFlow tab
|
|
2. navigate → open the project in FlutterFlow web UI
|
|
3. read_page / screenshot → verify the screen looks correct
|
|
4. Use gif_creator to record verification for documentation
|
|
```
|
|
|
|
See `builder-reference.md` for complete FlutterFlow UI mapping.
|
|
|
|
## Error Recovery
|
|
|
|
### Orbit Command Fails
|
|
1. Check error message — often contains the fix
|
|
2. Run `orbit({ cmd: "help", args: { cmd: "<command>" } })` to verify args
|
|
3. If stale data: `snapshots.refresh`
|
|
4. If rate limited (429): use `changeset.applySafe` with retry controls
|
|
|
|
### Widget/Page Not Found
|
|
1. Resolve via `pages.list` first
|
|
2. Use returned `pageId` / `nodeId` explicitly (don't guess from names)
|
|
3. Check `includeDeleted: true` if page may have been soft-deleted
|
|
|
|
### Rate Limiting (429)
|
|
- Use `changeset.applySafe` with bounded retries
|
|
- For refreshes: `snapshots.refreshSlow` with conservative pacing
|
|
- Report `rateLimited`, `retryAfterSeconds`, and `nextRetryAt` to user
|
|
|
|
## File Reference
|
|
|
|
| File | Contents |
|
|
|------|----------|
|
|
| `orbit-commands.md` | Complete Orbit command reference — all 70+ commands |
|
|
| `orbit-setup.md` | VSCode / Claude Code setup and configuration |
|
|
| `builder-reference.md` | FlutterFlow web UI map — panels, buttons, properties |
|
|
| `widget-catalog.md` | All widgets with properties and automation steps |
|
|
| `design-system-setup.md` | ZIVVO design system — colors, typography, theme widgets |
|
|
| `screen-blueprints.md` | Screen-by-screen widget trees for all 4 roles |
|
|
| `code-export.md` | Export workflows and Melos monorepo integration |
|
|
|
|
## Safety Notes
|
|
|
|
- Never delete pages without user confirmation
|
|
- Use `page.preflightDelete` before removing pages
|
|
- Use changeset preview/validate before applying complex edits
|
|
- For browser automation: stop and ask user if tools fail 2-3 times
|
|
- Respect policy guardrails — never force-write blocked files
|