> ## Documentation Index
> Fetch the complete documentation index at: https://docs.daydream.live/llms.txt
> Use this file to discover all available pages before exploring further.

# Integration API

> Python scripting and automation for TouchDesigner

# Integration API

The Daydream TouchDesigner plugin exposes a Python API for scripting, automation, and building custom interfaces.

## Accessing the Extension

```python theme={null}
# Get the extension from your Daydream component
ext = op('/daydream').ext.Daydream
```

## Public Contract

The extension exposes `PUBLIC_CONTRACT` with introspectable metadata:

```python theme={null}
PUBLIC_CONTRACT = {
    'extension_name': 'Daydream',
    'lifecycle_methods': ['Login', 'Start', 'Stop', 'ResetParameters'],
    'state_properties': ['state', 'Active', 'IsLoggedIn', 'ApiToken', 'stream_id', 'whip_url', 'whep_url'],
    'states': ['IDLE', 'CREATING', 'STREAMING', 'ERROR'],
    'listener_api': ['register_listener', 'unregister_listener'],
    'events': [
        'initialized',
        'login_started', 'login_success', 'login_failed',
        'stream_create_started', 'stream_created', 'stream_create_failed',
        'streaming_started', 'streaming_stopped',
        'params_update_sent', 'params_update_result',
        'state_changed', 'error',
    ],
}
```

## GetCapabilities

Query runtime capabilities for the current model:

```python theme={null}
ext = op('/daydream').ext.Daydream
caps = ext.GetCapabilities()

# Returns:
# {
#     'backend': 'daydream',
#     'version': 'x.y.z',
#     'model': 'stabilityai/sdxl-turbo',
#     'supported_models': ['stabilityai/sdxl-turbo', 'stabilityai/sd-turbo', ...],
#     'controlnets': ['depth', 'canny', 'tile'],
#     'ip_adapter_types': ['regular', 'faceid'],
# }
```

Use this to build adaptive interfaces that show only available options.

## State Properties

Read the current state:

```python theme={null}
ext = op('/daydream').ext.Daydream

# Current state
print(ext.state)  # 'IDLE', 'CREATING', 'STREAMING', or 'ERROR'

# Stream info
print(ext.stream_id)
print(ext.whip_url)
print(ext.whep_url)

# Auth status
print(ext.IsLoggedIn)
print(ext.Active)
```

## Lifecycle Methods

Control the component programmatically:

```python theme={null}
ext = op('/daydream').ext.Daydream

# Start authentication flow
ext.Login()

# Start streaming (requires login)
ext.Start()

# Stop streaming
ext.Stop()

# Reset all parameters to defaults
ext.ResetParameters()
```

## Event Listeners

Register a callback to receive lifecycle events without polling:

```python theme={null}
def on_daydream_event(event, payload):
    # payload always includes: owner_path, state, stream_id
    print(f"Event: {event}")
    print(f"Payload: {payload}")

ext = op('/daydream').ext.Daydream
ext.register_listener(on_daydream_event)

# Later, to stop listening:
# ext.unregister_listener(on_daydream_event)
```

### Event Reference

| Event                   | Payload                            | Description            |
| ----------------------- | ---------------------------------- | ---------------------- |
| `initialized`           | `logged_in`                        | Extension ready        |
| `login_started`         | `auth_port`                        | Auth flow began        |
| `login_success`         | —                                  | Successfully logged in |
| `login_failed`          | `error`                            | Login error            |
| `stream_create_started` | `model`                            | Creating stream        |
| `stream_created`        | `whip_url`, `model_id`             | Stream ready           |
| `stream_create_failed`  | `error`                            | Creation error         |
| `streaming_started`     | `whip_url`, `whep_url`, `model_id` | Streaming active       |
| `streaming_stopped`     | `prev_stream_id`                   | Streaming ended        |
| `params_update_sent`    | `changed`, `params`                | Parameters sent        |
| `params_update_result`  | `success`, `error`                 | Update response        |
| `state_changed`         | `from`, `to`, `reason`, `error`    | State transition       |
| `error`                 | `error`, `context`, `will_retry`   | Error occurred         |

## Example: State Machine Monitor

```python theme={null}
def on_event(event, payload):
    if event == 'state_changed':
        from_state = payload.get('from', 'unknown')
        to_state = payload.get('to', 'unknown')
        reason = payload.get('reason', '')
        print(f"State: {from_state} → {to_state} ({reason})")

        # Update UI based on state
        if to_state == 'STREAMING':
            op('status_text').par.text = 'Live!'
            op('status_text').par.fontcolorr = 0
            op('status_text').par.fontcolorg = 1
            op('status_text').par.fontcolorb = 0
        elif to_state == 'ERROR':
            op('status_text').par.text = f'Error: {payload.get("error", "unknown")}'
            op('status_text').par.fontcolorr = 1
            op('status_text').par.fontcolorg = 0
            op('status_text').par.fontcolorb = 0

    elif event == 'streaming_started':
        whep_url = payload.get('whep_url')
        print(f"Watch at: {whep_url}")

    elif event == 'error':
        context = payload.get('context', 'unknown')
        error = payload.get('error', 'unknown error')
        will_retry = payload.get('will_retry', False)
        print(f"Error in {context}: {error}")
        if will_retry:
            print("Will retry automatically...")

ext = op('/daydream').ext.Daydream
ext.register_listener(on_event)
```

## Example: Dynamic Parameter Control

Control parameters from CHOPs for audio-reactive visuals:

```python theme={null}
# In an Execute DAT triggered by a CHOP

def onValueChange(channel, sampleIndex, val, prev):
    daydream = op('/daydream')

    if channel.name == 'audio_bass':
        # Map bass to guidance scale
        guidance = tdu.remap(val, 0, 1, 1.0, 2.5)
        daydream.par.Guidance = guidance

    elif channel.name == 'audio_mid':
        # Map mids to delta
        delta = tdu.remap(val, 0, 1, 0.3, 0.8)
        daydream.par.Delta = delta

    elif channel.name == 'beat':
        # On beat, randomize seeds
        if val > 0.5:
            daydream.ext.Daydream.RandomizeSeeds()
```

## Example: Custom Control Panel

Build a custom UI that shows only relevant controls:

```python theme={null}
# In a Panel Execute DAT

def onReady():
    ext = op('/daydream').ext.Daydream
    caps = ext.GetCapabilities()

    # Show/hide ControlNet sliders based on model
    available_controlnets = caps.get('controlnets', [])

    for cn in ['depth', 'canny', 'tile', 'openpose', 'hed', 'color']:
        slider = op(f'slider_{cn}')
        if slider:
            slider.par.display = cn in available_controlnets

    # Show/hide IP Adapter based on model
    ip_types = caps.get('ip_adapter_types', [])
    op('ip_adapter_panel').par.display = len(ip_types) > 0
```

## Next Steps

* [Features](/sdks/touchdesigner/features) - ControlNets, IP Adapter, prompt scheduling
* [Installation](/sdks/touchdesigner/installation) - Setup guide
* [GitHub Repository](https://github.com/daydreamlive/daydream-touchdesigner) - Source code and issues
