# How to Use the Code Playground in Trevor-UI for Live Coding

> Master the Trevor-UI code playground for live Python coding. Execute and save code instantly using keyboard shortcuts with Nallely via WebSocket.

- Repository: [dr-schlange/nallely-midi](https://github.com/dr-schlange/nallely-midi)
- Tags: how-to-guide
- Published: 2026-02-28

---

**The Trevor-UI code playground is a CodeMirror 6-based modal that connects to the Nallely Python session via WebSocket, allowing you to write, execute, and save Python code in real time using keyboard shortcuts like Mod-d to run and Mod-s to persist.**

The dr-schlange/nallely-midi repository ships Trevor-UI, a React-based web interface for controlling Nallely MIDI sessions. Its integrated code playground lets you live-code Python against connected hardware without leaving the browser, with full persistence across UI reloads.

## Opening the Trevor-UI Code Playground

Press **Alt-Space** (or click the **"Playground"** button in the device-patching toolbar) to open the modal. The component is lazily loaded from [`trevor/src/components/modals/Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/trevor/src/components/modals/Playground.tsx) (see the dynamic import pattern in [`DevicePatching.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/DevicePatching.tsx) lines 48-51) to keep the initial bundle size small.

When opened, the playground renders a **CodeMirror 6** editor pane and a terminal view. The editor comes pre-loaded with any previously saved code from the Redux store ([`trevorSlice.ts`](https://github.com/dr-schlange/nallely-midi/blob/main/trevorSlice.ts)), ensuring you never lose your work between sessions.

## Executing Python Code in Real Time

The playground communicates with the Nallely process through the **TrevorWebSocket** protocol defined in [`trevor/src/websockets/websocket.ts`](https://github.com/dr-schlange/nallely-midi/blob/main/trevor/src/websockets/websocket.ts).

### Running Code with Keyboard Shortcuts

- **Mod-d** (⌘-d on macOS, Ctrl-d on Windows/Linux): Executes the current line or selected text. The `execute` function (lines 60-88 in [`Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/Playground.tsx)) forwards the selection to `trevorSocket?.executeCode(code)` (line 106).
- **Mod-p**: Wraps the selected code in `print(...)` before execution, useful for quick inspection.
- **Mod-l**: Clears the terminal pane by resetting the internal `stdout` state.

### Data Flow from Editor to Python Interpreter

When you press **Mod-d**, the following sequence occurs:

1. [`Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/Playground.tsx) extracts the selected line(s) and calls `executeCode`.
2. `TrevorWebSocket.executeCode` serializes the request as JSON and sends it over the WebSocket.
3. The Trevor server (running inside the Nallely process) receives the command, runs the code in the active Python interpreter, and streams back `stdout` or `error` events.
4. The Playground’s `onMessageHandler` (registered in the `useEffect` at line 44) updates the terminal view via `setStdout` or displays diagnostics via `displayError`.

## Saving Work and Auto-Completion

### Persisting Code Across Sessions

Press **Mod-s** to persist the current buffer. This triggers `trevorSocket?.saveCode(code)` (line 80 in [`Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/Playground.tsx)), which stores the content in the Nallely session state. The Redux slice ([`trevorSlice.ts`](https://github.com/dr-schlange/nallely-midi/blob/main/trevorSlice.ts)) holds the `playground_code` field; when the server broadcasts a full-state update, the UI synchronizes the editor content, ensuring your code survives page reloads.

### Intelligent Auto-Completion

Invoke completion with **Mod-Space** or by typing a dot. The `askCompletion` function (lines 35-38) extracts the last expression and queries the server via `websocket.requestCompletion(lastExpression)` (line 51). The server returns a JSON array of suggestions that CodeMirror renders as an autocomplete dropdown.

## Working with Connected Devices

Use the device drop-downs in the modal header to inject references to MIDI or virtual devices. Selecting a device calls `insertAssignmentAtCursor` (lines 18-45), injecting a line such as:

```python
mydevice = connected_devices[0]

```

This lets you immediately script against hardware without manually typing device identifiers.

## Programmatic Integration Examples

### Opening the Playground from Custom Components

Mirror the lazy-loading pattern used in [`DevicePatching.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/DevicePatching.tsx):

```tsx
import { lazy, useState } from "react";

const Playground = lazy(() =>
  import("./modals/Playground").then(m => ({ default: m.Playground }))
);

function CustomToolbar() {
  const [showPlayground, setShowPlayground] = useState(false);
  return (
    <>
      <button onClick={() => setShowPlayground(true)}>Open Playground</button>
      {showPlayground && (
        <Playground onClose={() => setShowPlayground(false)} />
      )}
    </>
  );
}

```

### Executing Code Without the UI

For automated testing or headless operation, use the `TrevorWebSocket` class directly:

```typescript
import { TrevorWebSocket } from "./websockets/websocket";

async function runHeadless(wsUrl: string, code: string) {
  const socket = new TrevorWebSocket(wsUrl);
  await socket.waitForReady();
  socket.executeCode(code);  // Same method the Playground uses
}

runHeadless(
  "ws://localhost:6788/trevor", 
  "print('Hello from automated script')"
);

```

### Adding Server-Side Completion Handlers

Extend the Python side in [`nallely/session.py`](https://github.com/dr-schlange/nallely-midi/blob/main/nallely/session.py) to handle the `completion` command. The Playground already sends requests via `requestCompletion`; you only need to implement the handler that returns:

```json
{
  "command": "completion",
  "options": [
    { "label": "my_device", "type": "variable" },
    { "label": "send_note", "type": "function" }
  ]
}

```

## Summary

- **Alt-Space** opens the CodeMirror 6-based playground modal, lazily loaded from [`Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/Playground.tsx).
- **Mod-d** executes selected Python code via `TrevorWebSocket.executeCode`, streaming results back through the WebSocket.
- **Mod-s** persists code to the Nallely session state via `saveCode`, with Redux ensuring content survives reloads.
- **Mod-Space** triggers auto-completion through `requestCompletion`, querying the server for contextual suggestions.
- Device drop-downs inject ready-to-use device references via `insertAssignmentAtCursor`.

## Frequently Asked Questions

### How do I open the code playground in Trevor-UI?

Press **Alt-Space** on your keyboard, or click the **"Playground"** button in the device-patching toolbar. The modal is lazily imported from [`trevor/src/components/modals/Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/trevor/src/components/modals/Playground.tsx) to optimize performance.

### What keyboard shortcuts are available for live coding?

**Mod-d** executes the current line or selection, **Mod-p** executes with automatic printing, **Mod-s** saves the buffer to session state, **Mod-l** clears the terminal, and **Mod-?** displays a help cheat-sheet in the terminal pane.

### How does code execution work behind the scenes?

When you press **Mod-d**, the `execute` function in [`Playground.tsx`](https://github.com/dr-schlange/nallely-midi/blob/main/Playground.tsx) (lines 60-88) sends the code to `TrevorWebSocket.executeCode`, which transmits it over the WebSocket to the Trevor server inside Nallely. The server runs the code in the active Python interpreter and pushes `stdout` or `error` events back to the UI.

### Can I use the playground functionality without the browser UI?

Yes. Import `TrevorWebSocket` from [`trevor/src/websockets/websocket.ts`](https://github.com/dr-schlange/nallely-midi/blob/main/trevor/src/websockets/websocket.ts) and call `executeCode` directly after waiting for the connection to be ready. This is useful for automated testing or scripting against a headless Nallely session.