mirror of
https://github.com/bmadcode/BMAD-METHOD.git
synced 2025-12-29 16:14:59 +00:00
* feat: add frame-expert agent definition - Add frame-expert.agent.yaml with persona and workflow menu - Agent specializes in Excalidraw visual representations - Supports flowcharts, diagrams, dataflows, and wireframes Closes #890 * feat: add frame-expert workflows and shared resources - Add 4 workflows: create-flowchart, create-diagram, create-dataflow, create-wireframe - Include shared Excalidraw helpers, library, templates, and validation - Each workflow has instructions, checklist, and workflow.yaml Related to #890 * feat: register frame-expert workflows in manifest - Add create-flowchart workflow entry - Add create-diagram workflow entry - Add create-dataflow workflow entry - Add create-wireframe workflow entry Related to #890 * feat: integrate frame-expert into team configurations - Add frame-expert to default-party.csv with full agent details - Add frame-expert to team-fullstack.yaml agent list - Frame-expert now available in fullstack team workflows Related to #890
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
# Excalidraw Element Creation Guidelines
|
||||
|
||||
## Text Width Calculation
|
||||
|
||||
For text elements inside shapes (labels):
|
||||
|
||||
```
|
||||
text_width = (text.length × fontSize × 0.6) + 20
|
||||
```
|
||||
|
||||
Round to nearest 10 for grid alignment.
|
||||
|
||||
## Element Grouping Rules
|
||||
|
||||
**CRITICAL:** When creating shapes with labels:
|
||||
|
||||
1. Generate unique IDs:
|
||||
- `shape-id` for the shape
|
||||
- `text-id` for the text
|
||||
- `group-id` for the group
|
||||
|
||||
2. Shape element must have:
|
||||
- `groupIds: [group-id]`
|
||||
- `boundElements: [{type: "text", id: text-id}]`
|
||||
|
||||
3. Text element must have:
|
||||
- `containerId: shape-id`
|
||||
- `groupIds: [group-id]` (SAME as shape)
|
||||
- `textAlign: "center"`
|
||||
- `verticalAlign: "middle"`
|
||||
- `width: calculated_width`
|
||||
|
||||
## Grid Alignment
|
||||
|
||||
- Snap all `x`, `y` coordinates to 20px grid
|
||||
- Formula: `Math.round(value / 20) * 20`
|
||||
- Spacing between elements: 60px minimum
|
||||
|
||||
## Arrow Creation
|
||||
|
||||
### Straight Arrows
|
||||
|
||||
Use for forward flow (left-to-right, top-to-bottom):
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "arrow",
|
||||
"startBinding": {
|
||||
"elementId": "source-shape-id",
|
||||
"focus": 0,
|
||||
"gap": 10
|
||||
},
|
||||
"endBinding": {
|
||||
"elementId": "target-shape-id",
|
||||
"focus": 0,
|
||||
"gap": 10
|
||||
},
|
||||
"points": [[0, 0], [distance_x, distance_y]]
|
||||
}
|
||||
```
|
||||
|
||||
### Elbow Arrows
|
||||
|
||||
Use for upward flow, backward flow, or complex routing:
|
||||
|
||||
```json
|
||||
{
|
||||
"type": "arrow",
|
||||
"startBinding": {...},
|
||||
"endBinding": {...},
|
||||
"points": [
|
||||
[0, 0],
|
||||
[intermediate_x, 0],
|
||||
[intermediate_x, intermediate_y],
|
||||
[final_x, final_y]
|
||||
],
|
||||
"elbowed": true
|
||||
}
|
||||
```
|
||||
|
||||
### Update Connected Shapes
|
||||
|
||||
After creating arrow, update `boundElements` on both connected shapes:
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "shape-id",
|
||||
"boundElements": [
|
||||
{ "type": "text", "id": "text-id" },
|
||||
{ "type": "arrow", "id": "arrow-id" }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## Theme Application
|
||||
|
||||
Theme colors should be applied consistently:
|
||||
|
||||
- **Shapes**: `backgroundColor` from theme primary fill
|
||||
- **Borders**: `strokeColor` from theme accent
|
||||
- **Text**: `strokeColor` = "#1e1e1e" (dark text)
|
||||
- **Arrows**: `strokeColor` from theme accent
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Before saving, verify:
|
||||
|
||||
- [ ] All shapes with labels have matching `groupIds`
|
||||
- [ ] All text elements have `containerId` pointing to parent shape
|
||||
- [ ] Text width calculated properly (no cutoff)
|
||||
- [ ] Text alignment set (`textAlign` + `verticalAlign`)
|
||||
- [ ] All elements snapped to 20px grid
|
||||
- [ ] All arrows have `startBinding` and `endBinding`
|
||||
- [ ] `boundElements` array updated on connected shapes
|
||||
- [ ] Theme colors applied consistently
|
||||
- [ ] No metadata or history in final output
|
||||
- [ ] All IDs are unique
|
||||
|
||||
## Optimization
|
||||
|
||||
Remove from final output:
|
||||
|
||||
- `appState` object
|
||||
- `files` object (unless images used)
|
||||
- All elements with `isDeleted: true`
|
||||
- Unused library items
|
||||
- Version history
|
||||
@@ -0,0 +1,90 @@
|
||||
{
|
||||
"type": "excalidrawlib",
|
||||
"version": 2,
|
||||
"library": [
|
||||
{
|
||||
"id": "start-end-circle",
|
||||
"status": "published",
|
||||
"elements": [
|
||||
{
|
||||
"type": "ellipse",
|
||||
"width": 120,
|
||||
"height": 60,
|
||||
"strokeColor": "#1976d2",
|
||||
"backgroundColor": "#e3f2fd",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"roughness": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "process-rectangle",
|
||||
"status": "published",
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"width": 160,
|
||||
"height": 80,
|
||||
"strokeColor": "#1976d2",
|
||||
"backgroundColor": "#e3f2fd",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"roughness": 0,
|
||||
"roundness": {
|
||||
"type": 3,
|
||||
"value": 8
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "decision-diamond",
|
||||
"status": "published",
|
||||
"elements": [
|
||||
{
|
||||
"type": "diamond",
|
||||
"width": 140,
|
||||
"height": 100,
|
||||
"strokeColor": "#f57c00",
|
||||
"backgroundColor": "#fff3e0",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"roughness": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "data-store",
|
||||
"status": "published",
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"width": 140,
|
||||
"height": 80,
|
||||
"strokeColor": "#388e3c",
|
||||
"backgroundColor": "#e8f5e9",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 2,
|
||||
"roughness": 0
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "external-entity",
|
||||
"status": "published",
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"width": 120,
|
||||
"height": 80,
|
||||
"strokeColor": "#7b1fa2",
|
||||
"backgroundColor": "#f3e5f5",
|
||||
"fillStyle": "solid",
|
||||
"strokeWidth": 3,
|
||||
"roughness": 0
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
flowchart:
|
||||
viewport:
|
||||
x: 0
|
||||
y: 0
|
||||
zoom: 1
|
||||
grid:
|
||||
size: 20
|
||||
spacing:
|
||||
vertical: 100
|
||||
horizontal: 180
|
||||
elements:
|
||||
start:
|
||||
type: ellipse
|
||||
width: 120
|
||||
height: 60
|
||||
label: "Start"
|
||||
process:
|
||||
type: rectangle
|
||||
width: 160
|
||||
height: 80
|
||||
roundness: 8
|
||||
decision:
|
||||
type: diamond
|
||||
width: 140
|
||||
height: 100
|
||||
end:
|
||||
type: ellipse
|
||||
width: 120
|
||||
height: 60
|
||||
label: "End"
|
||||
|
||||
diagram:
|
||||
viewport:
|
||||
x: 0
|
||||
y: 0
|
||||
zoom: 1
|
||||
grid:
|
||||
size: 20
|
||||
spacing:
|
||||
vertical: 120
|
||||
horizontal: 200
|
||||
elements:
|
||||
component:
|
||||
type: rectangle
|
||||
width: 180
|
||||
height: 100
|
||||
roundness: 8
|
||||
database:
|
||||
type: rectangle
|
||||
width: 140
|
||||
height: 80
|
||||
service:
|
||||
type: rectangle
|
||||
width: 160
|
||||
height: 90
|
||||
roundness: 12
|
||||
external:
|
||||
type: rectangle
|
||||
width: 140
|
||||
height: 80
|
||||
|
||||
wireframe:
|
||||
viewport:
|
||||
x: 0
|
||||
y: 0
|
||||
zoom: 0.8
|
||||
grid:
|
||||
size: 20
|
||||
spacing:
|
||||
vertical: 40
|
||||
horizontal: 40
|
||||
elements:
|
||||
container:
|
||||
type: rectangle
|
||||
width: 800
|
||||
height: 600
|
||||
strokeStyle: solid
|
||||
strokeWidth: 2
|
||||
header:
|
||||
type: rectangle
|
||||
width: 800
|
||||
height: 80
|
||||
button:
|
||||
type: rectangle
|
||||
width: 120
|
||||
height: 40
|
||||
roundness: 4
|
||||
input:
|
||||
type: rectangle
|
||||
width: 300
|
||||
height: 40
|
||||
roundness: 4
|
||||
text:
|
||||
type: text
|
||||
fontSize: 16
|
||||
|
||||
dataflow:
|
||||
viewport:
|
||||
x: 0
|
||||
y: 0
|
||||
zoom: 1
|
||||
grid:
|
||||
size: 20
|
||||
spacing:
|
||||
vertical: 120
|
||||
horizontal: 200
|
||||
elements:
|
||||
process:
|
||||
type: ellipse
|
||||
width: 140
|
||||
height: 80
|
||||
label: "Process"
|
||||
datastore:
|
||||
type: rectangle
|
||||
width: 140
|
||||
height: 80
|
||||
label: "Data Store"
|
||||
external:
|
||||
type: rectangle
|
||||
width: 120
|
||||
height: 80
|
||||
strokeWidth: 3
|
||||
label: "External Entity"
|
||||
dataflow:
|
||||
type: arrow
|
||||
strokeWidth: 2
|
||||
label: "Data Flow"
|
||||
@@ -0,0 +1,79 @@
|
||||
# JSON Validation Instructions
|
||||
|
||||
## Purpose
|
||||
|
||||
Validate Excalidraw JSON files after saving to catch syntax errors (missing commas, brackets, quotes).
|
||||
|
||||
## How to Validate
|
||||
|
||||
Use Node.js built-in JSON parsing to validate the file:
|
||||
|
||||
```bash
|
||||
node -e "JSON.parse(require('fs').readFileSync('FILE_PATH', 'utf8')); console.log('✓ Valid JSON')"
|
||||
```
|
||||
|
||||
Replace `FILE_PATH` with the actual file path.
|
||||
|
||||
## Exit Codes
|
||||
|
||||
- Exit code 0 = Valid JSON
|
||||
- Exit code 1 = Invalid JSON (syntax error)
|
||||
|
||||
## Error Output
|
||||
|
||||
If invalid, Node.js will output:
|
||||
|
||||
- Error message with description
|
||||
- Position in file where error occurred
|
||||
- Line and column information (if available)
|
||||
|
||||
## Common Errors and Fixes
|
||||
|
||||
### Missing Comma
|
||||
|
||||
```
|
||||
SyntaxError: Expected ',' or '}' after property value
|
||||
```
|
||||
|
||||
**Fix:** Add comma after the property value
|
||||
|
||||
### Missing Bracket/Brace
|
||||
|
||||
```
|
||||
SyntaxError: Unexpected end of JSON input
|
||||
```
|
||||
|
||||
**Fix:** Add missing closing bracket `]` or brace `}`
|
||||
|
||||
### Extra Comma (Trailing)
|
||||
|
||||
```
|
||||
SyntaxError: Unexpected token ,
|
||||
```
|
||||
|
||||
**Fix:** Remove the trailing comma before `]` or `}`
|
||||
|
||||
### Missing Quote
|
||||
|
||||
```
|
||||
SyntaxError: Unexpected token
|
||||
```
|
||||
|
||||
**Fix:** Add missing quote around string value
|
||||
|
||||
## Workflow Integration
|
||||
|
||||
After saving an Excalidraw file, run validation:
|
||||
|
||||
1. Save the file
|
||||
2. Run: `node -e "JSON.parse(require('fs').readFileSync('{{save_location}}', 'utf8')); console.log('✓ Valid JSON')"`
|
||||
3. If validation fails:
|
||||
- Read the error message for line/position
|
||||
- Open the file at that location
|
||||
- Fix the syntax error
|
||||
- Save and re-validate
|
||||
4. Repeat until validation passes
|
||||
|
||||
## Critical Rule
|
||||
|
||||
**NEVER delete the file due to validation errors - always fix the syntax error at the reported location.**
|
||||
Reference in New Issue
Block a user