---
name: omnigraffle
description: >
  Generate native OmniGraffle .graffle files programmatically. Use this skill whenever the user
  asks to create, build, or generate an OmniGraffle diagram, network diagram, architecture diagram,
  flowchart, or any visual diagram that should be saved as a .graffle file. Also trigger when the
  user mentions "OmniGraffle", ".graffle", "graffle file", or asks for diagrams specifically for
  macOS/iOS diagramming. This skill generates zipped binary plist packages that open natively in
  OmniGraffle 7+ without any conversion or import steps. Supports: rectangles with colored fills,
  text labels (RTF), named layers, line connections between shapes, arrows, groups, rotation,
  dashed lines, multi-point paths, and magnets for connection snapping.
---

# OmniGraffle File Generator

Generate native `.graffle` files that open directly in OmniGraffle 7+ on macOS and iOS.

## How It Works

OmniGraffle files are ZIP archives containing a binary Apple plist (`data.plist`) and a preview
JPEG. This skill uses Python's `plistlib` to assemble the document structure and `zipfile` to
package it. The output matches OmniGraffle 7's native format (GraphDocumentVersion 16, zipped).

## Step 1: Copy Scripts

Before generating any file, copy the builder scripts to your working directory:

```bash
cp -r /path/to/this/skill/src/ /home/claude/omnigraffle-src/
```

Then import:
```python
import sys
sys.path.insert(0, '/home/claude/omnigraffle-scripts')
from src.graffle_builder import GraffleBuilder, create_network_diagram, COLORS
```

## Step 2: Understand the User's Diagram

Ask or infer:
1. **What type of diagram?** Network architecture, flowchart, org chart, system diagram
2. **What are the nodes/shapes?** Names, positions, colors, groupings
3. **What are the connections?** Which nodes connect, line colors, arrows
4. **What layers are needed?** Logical groupings (e.g., "hardware", "network", "labels")

## Step 3: Build the Diagram

### Option A: Low-Level Builder API

For full control over every element:

```python
from src.graffle_builder import GraffleBuilder

b = GraffleBuilder(title="My Diagram", creator="User Name")

# Clear default layer and add custom ones
b._layers = []
l_hw = b.add_layer("hardware")
l_net = b.add_layer("network")

# Add shapes (returns shape ID for connections)
srv = b.add_shape(x=100, y=100, w=120, h=40,
                  text="Server1", fill_color="blue",
                  layer=l_hw, name="Server1")

sw = b.add_shape(x=300, y=100, w=120, h=40,
                 text="Switch", fill_color="green",
                 layer=l_net, name="Switch")

# Connect shapes
b.add_line(from_id=srv, to_id=sw, color="blue", width=2.0,
           layer=l_net, head_arrow="FilledArrow")

# Add floating text labels
b.add_text_label(100, 60, "Rack 1", font_size=14,
                 text_color=(0,0,0), bold=True)

# Group shapes together
group_id = b.add_group([srv, sw], layer=l_hw)

# Save
b.save("/mnt/user-data/outputs/diagram.graffle")
```

### Option B: High-Level Network Diagram

For quick network/architecture diagrams from structured data:

```python
from src.graffle_builder import create_network_diagram

builder = create_network_diagram(
    title="Data Center Network",
    layers=["servers", "switches", "storage"],
    nodes=[
        {"name": "Web-1", "x": 100, "y": 50, "color": "blue"},
        {"name": "Web-2", "x": 250, "y": 50, "color": "blue"},
        {"name": "LB",    "x": 175, "y": 150, "w": 140, "color": "green"},
        {"name": "DB",    "x": 175, "y": 250, "color": "red", "layer": 2},
    ],
    connections=[
        {"from_name": "Web-1", "to_name": "LB", "color": "yellow", "width": 2},
        {"from_name": "Web-2", "to_name": "LB", "color": "yellow", "width": 2},
        {"from_name": "LB", "to_name": "DB", "arrow": True, "width": 2},
    ],
)
builder.save("/mnt/user-data/outputs/network.graffle")
```

## API Reference

### GraffleBuilder(title, creator, orientation, paper_size)

| Param | Default | Values |
|-------|---------|--------|
| title | "Canvas 1" | Canvas name |
| creator | "Claude" | Author metadata |
| orientation | "landscape" | "landscape" or "portrait" |
| paper_size | "A4" | "A4", "letter", "A3" |

### add_layer(name, locked, visible, printable) → layer_index

### add_shape(x, y, w, h, ...) → shape_id

| Param | Default | Notes |
|-------|---------|-------|
| text | "" | Label inside shape |
| fill_color | None | RGB (0-1) tuple or color name string |
| text_color | (255,255,255) | RGB (0-255) |
| font_size | 10 | Points |
| font | "HelveticaNeue" | Font name |
| layer | 0 | Layer index |
| name | None | Shape identifier |
| rotation | None | Degrees (e.g., 90.0) |
| magnets | True | Connection snap points |
| stroke | False | Draw border |
| stroke_color | None | Border RGB (0-1) |
| stroke_width | 1.0 | Border width |
| bold | False | Bold text |
| fit_text | False | Auto-resize to fit text |

### add_text_label(x, y, text, ...) → shape_id

Convenience for borderless/fillless text. Same params as add_shape minus fill/stroke.

### add_line(from_id, to_id, ...) → line_id

| Param | Default | Notes |
|-------|---------|-------|
| from_id/to_id | None | Shape IDs for connected lines |
| from_point/to_point | None | (x,y) for unconnected endpoints |
| color | None | RGB (0-1) or color name |
| width | 1.0 | Line width |
| layer | 0 | Layer index |
| head_arrow | None | "FilledArrow" for arrowhead |
| dashed | False | Dashed line style |

### add_line_multi_point(points, ...) → line_id

For multi-segment paths. `points` is a list of (x,y) tuples.

### add_group(shape_ids, layer) → group_id

Groups existing shapes. Removes them from main list and nests under group.

### save(filepath)

Writes the .graffle ZIP file.

## Available Named Colors

Use these strings for `fill_color` or `color` parameters:

blue, red, green, yellow, orange, purple, cyan, pink, brown, white,
lightgray, darkgray, black, lightblue, lightgreen, lightcyan, lightpink,
lightyellow, darkblue, darkgreen, darkred

Or pass any RGB tuple like `(0.5, 0.8, 0.2)` in the 0-1 range.

## Layout Tips

- OmniGraffle coordinate system: origin is top-left, units are points (1/72 inch)
- Typical node sizes: 100-150w × 30-50h for labels, 40-60w × 14-20h for small tags
- Vertical spacing: 80-120 points between rows
- Horizontal spacing: 40-80 points between columns
- Use layers to separate logical diagram elements (hardware, networks, labels)
- Name important shapes so they can be found in OmniGraffle's sidebar

## Limitations

- All shapes are rectangles (no circles, ovals, or custom paths yet)
- No image fills or embedded images
- No stencil references
- Auto-layout must be done in OmniGraffle after opening
- Preview JPEG is a blank placeholder (OmniGraffle regenerates it on first save)
