# API Helpers Reference

Python helper functions for building CE deck slides via Google Slides API.

## Authentication

```bash
gws-auth slides presentations create --json '{"title": "Deck Title"}'
gws-auth slides presentations batchUpdate --params '{"presentationId":"PRES_ID"}' --json '{"requests":[...]}'
```

## Constants

```python
RED = {"red": 0.80, "green": 0.0, "blue": 0.0}
DARK = {"red": 0.10, "green": 0.10, "blue": 0.10}
GRAY = {"red": 0.40, "green": 0.40, "blue": 0.40}
LIGHT_GRAY = {"red": 0.60, "green": 0.60, "blue": 0.60}
WHITE = {"red": 1.0, "green": 1.0, "blue": 1.0}
BLACK = {"red": 0.0, "green": 0.0, "blue": 0.0}
LINE_GRAY = {"red": 0.93, "green": 0.93, "blue": 0.93}

MONO = "JetBrains Mono"
SERIF = "Playfair Display"
SANS = "DM Sans"

LABEL_X = 457245
LABEL_Y = 302064
HEAD_X = 457250
HEAD_Y = 579136
MARGIN = 457200
PAGE_W = 9144000
PAGE_H = 5143500
RULE_Y = 1150000
CONTENT_Y = 1300000
FOOTER_Y = 4200000

COL_W = 2610000
COL_GAP = 142500
```

## Core Functions

```python
def create_slide(slide_id):
    return {"createSlide": {"objectId": slide_id,
        "slideLayoutReference": {"predefinedLayout": "BLANK"}}}

def set_slide_bg(slide_id, color):
    return {"updatePageProperties": {"objectId": slide_id,
        "pageProperties": {"pageBackgroundFill": {
            "solidFill": {"color": {"rgbColor": color}, "alpha": 1.0}}},
        "fields": "pageBackgroundFill"}}

def text_box(obj_id, page_id, x, y, w, h):
    return {"createShape": {"objectId": obj_id, "shapeType": "TEXT_BOX",
        "elementProperties": {"pageObjectId": page_id,
            "size": {"width": {"magnitude": w, "unit": "EMU"},
                     "height": {"magnitude": h, "unit": "EMU"}},
            "transform": {"scaleX": 1, "scaleY": 1,
                "translateX": x, "translateY": y, "unit": "EMU"}}}}

def rect(obj_id, page_id, x, y, w, h):
    return {"createShape": {"objectId": obj_id, "shapeType": "RECTANGLE",
        "elementProperties": {"pageObjectId": page_id,
            "size": {"width": {"magnitude": w, "unit": "EMU"},
                     "height": {"magnitude": h, "unit": "EMU"}},
            "transform": {"scaleX": 1, "scaleY": 1,
                "translateX": x, "translateY": y, "unit": "EMU"}}}}

def circle(obj_id, page_id, x, y, size):
    return {"createShape": {"objectId": obj_id, "shapeType": "ELLIPSE",
        "elementProperties": {"pageObjectId": page_id,
            "size": {"width": {"magnitude": size, "unit": "EMU"},
                     "height": {"magnitude": size, "unit": "EMU"}},
            "transform": {"scaleX": 1, "scaleY": 1,
                "translateX": x, "translateY": y, "unit": "EMU"}}}}

def image(obj_id, page_id, url, x, y, w, h):
    return {"createImage": {"objectId": obj_id, "url": url,
        "elementProperties": {"pageObjectId": page_id,
            "size": {"width": {"magnitude": w, "unit": "EMU"},
                     "height": {"magnitude": h, "unit": "EMU"}},
            "transform": {"scaleX": 1, "scaleY": 1,
                "translateX": x, "translateY": y, "unit": "EMU"}}}}

def insert_text(obj_id, text, index=0):
    return {"insertText": {"objectId": obj_id, "text": text,
        "insertionIndex": index}}

def style_text(obj_id, start, end, font, size, bold, color):
    return {"updateTextStyle": {"objectId": obj_id,
        "textRange": {"type": "FIXED_RANGE",
            "startIndex": start, "endIndex": end},
        "style": {
            "foregroundColor": {"opaqueColor": {"rgbColor": color}},
            "fontFamily": font,
            "fontSize": {"magnitude": size, "unit": "PT"},
            "bold": bold},
        "fields": "foregroundColor,fontFamily,fontSize,bold"}}

def shape_bg(obj_id, color, alpha=1.0):
    return {"updateShapeProperties": {"objectId": obj_id,
        "shapeProperties": {
            "shapeBackgroundFill": {"solidFill": {
                "color": {"rgbColor": color}, "alpha": alpha}},
            "outline": {"propertyState": "NOT_RENDERED"}},
        "fields": "shapeBackgroundFill,outline"}}

def h_rule(obj_id, page_id, y=RULE_Y):
    """Horizontal rule spanning margin to margin."""
    return {"createLine": {"objectId": obj_id,
        "lineCategory": "STRAIGHT",
        "elementProperties": {"pageObjectId": page_id,
            "size": {"width": {"magnitude": PAGE_W - 2 * MARGIN, "unit": "EMU"},
                     "height": {"magnitude": 0, "unit": "EMU"}},
            "transform": {"scaleX": 1, "scaleY": 1,
                "translateX": MARGIN, "translateY": y, "unit": "EMU"}}}}

def h_rule_style(obj_id):
    return {"updateLineProperties": {"objectId": obj_id,
        "lineProperties": {
            "lineFill": {"solidFill": {"color": {"rgbColor": LINE_GRAY}}},
            "weight": {"magnitude": 9525, "unit": "EMU"}},
        "fields": "lineFill,weight"}}

def center_text(obj_id):
    return {"updateParagraphStyle": {"objectId": obj_id,
        "textRange": {"type": "ALL"},
        "style": {"alignment": "CENTER"}, "fields": "alignment"}}
```

## Composite Helpers

### Standard Header (use on every content slide)

```python
def add_header(requests, slide_id, prefix, label_text, headline_text):
    """Add the standard CE header pattern to a slide."""
    lid = f"{prefix}_label"
    hid = f"{prefix}_head"
    rid = f"{prefix}_rule"
    
    requests.append(text_box(lid, slide_id, LABEL_X, LABEL_Y, 5490000, 300000))
    requests.append(insert_text(lid, label_text))
    requests.append(style_text(lid, 0, len(label_text), MONO, 10, True, RED))
    requests.append(shape_bg(lid, WHITE))
    
    requests.append(text_box(hid, slide_id, HEAD_X, HEAD_Y, 5490000, 480000))
    requests.append(insert_text(hid, headline_text))
    requests.append(style_text(hid, 0, len(headline_text), SERIF, 24, False, DARK))
    requests.append(shape_bg(hid, WHITE))
    
    requests.append(h_rule(rid, slide_id))
    requests.append(h_rule_style(rid))
```

### Three-Column

```python
def add_three_columns(requests, slide_id, prefix, items):
    """items: list of (number, title, description)"""
    for idx, (num, title, desc) in enumerate(items):
        col_x = MARGIN + (idx * (COL_W + COL_GAP))
        
        nid = f"{prefix}_num_{idx}"
        requests.append(text_box(nid, slide_id, col_x, 1350000, COL_W, 250000))
        requests.append(insert_text(nid, num))
        requests.append(style_text(nid, 0, len(num), MONO, 10, False, RED))
        requests.append(shape_bg(nid, WHITE))
        
        tid = f"{prefix}_title_{idx}"
        requests.append(text_box(tid, slide_id, col_x, 1650000, COL_W, 500000))
        requests.append(insert_text(tid, title))
        requests.append(style_text(tid, 0, len(title), SERIF, 15, False, RED))
        requests.append(shape_bg(tid, WHITE))
        
        did = f"{prefix}_desc_{idx}"
        requests.append(text_box(did, slide_id, col_x, 2250000, COL_W, 1200000))
        requests.append(insert_text(did, desc))
        requests.append(style_text(did, 0, len(desc), SANS, 12, False, GRAY))
        requests.append(shape_bg(did, WHITE))
```

### Full-Bleed Image Slide

```python
def add_fullbleed(requests, slide_id, prefix, img_url, scrim_alpha=0.55):
    """Full-bleed image with dark scrim."""
    requests.append(image(f"{prefix}_img", slide_id, img_url, 0, 0, PAGE_W, PAGE_H))
    requests.append(rect(f"{prefix}_scrim", slide_id, 0, 0, PAGE_W, PAGE_H))
    requests.append(shape_bg(f"{prefix}_scrim", BLACK, scrim_alpha))
```

### Execution

```python
import json, subprocess

def execute_batch(pres_id, requests):
    body = {"requests": requests}
    result = subprocess.run(
        ["gws-auth", "slides", "presentations", "batchUpdate",
         "--params", json.dumps({"presentationId": pres_id}),
         "--json", json.dumps(body)],
        capture_output=True, text=True, timeout=60)
    if result.returncode != 0:
        raise RuntimeError(result.stderr or result.stdout)
    return json.loads(result.stdout)
```

## Common Patterns

### Delete default slide after creating presentation
```python
requests.append({"deleteObject": {"objectId": "p"}})
```

### Text on scrim (transparent background)
```python
requests.append(shape_bg(obj_id, BLACK, 0))  # alpha=0 = transparent
```

### Paragraph spacing
```python
requests.append({"updateParagraphStyle": {"objectId": obj_id,
    "textRange": {"type": "ALL"},
    "style": {"lineSpacing": 150}, "fields": "lineSpacing"}})
```
