# AI-TV Page Architecture Plan

## Concept

**AI-TV** transforms the standard AI chat interface into a "generative web browser" — every AI response is a **full HTML page** rendered in an iframe "TV screen". The user sends prompts, and instead of receiving markdown chat bubbles, they see a fully rendered web page appear in the main viewport.

## Layout

```
┌─────────────────────────────────────────────────────────────┐
│  Header Bar: [Provider ▼] [Model ▼]              Balance    │
├──────────────┬──────────────────────────────────────────────┤
│              │                                              │
│  Past Pages  │           iframe "TV Screen"                 │
│  Strip       │                                              │
│              │   (sandboxed iframe rendering the             │
│  ┌────────┐  │    AI-generated HTML page)                   │
│  │ Page 3 │  │                                              │
│  │ active  │  │                                              │
│  └────────┘  │                                              │
│  ┌────────┐  │                                              │
│  │ Page 2 │  │                                              │
│  └────────┘  │                                              │
│  ┌────────┐  │                                              │
│  │ Page 1 │  │                                              │
│  └────────┘  │                                              │
│              │                                              │
│  [+ New]     │                                              │
├──────────────┴──────────────────────────────────────────────┤
│  ▶ System Prompt (collapsible)                              │
│  ┌──────────────────────────────────────────────────────┐   │
│  │ You are a web page generator. Respond only in HTML...│   │
│  └──────────────────────────────────────────────────────┘   │
├─────────────────────────────────────────────────────────────┤
│  [Prompt textarea                              ] [Send]     │
├─────────────────────────────────────────────────────────────┤
│  Status bar                                                 │
└─────────────────────────────────────────────────────────────┘
```

## Architecture Diagram

```mermaid
graph TD
    A[AI-TV Page] --> B[Header Bar]
    A --> C[Main Content Area]
    A --> D[Input Section]
    A --> E[Footer]

    B --> B1[Provider Select]
    B --> B2[Model Dropdown]
    B --> B3[Balance Display]

    C --> C1[Past Pages Strip - left sidebar]
    C --> C2[iframe TV Screen - main area]

    C1 --> C1a[Page cards with title + timestamp]
    C1 --> C1b[Click to load page into viewer]
    C1 --> C1c[Delete page button]
    C1 --> C1d[New Session button]

    C2 --> C2a[sandbox=allow-scripts]
    C2 --> C2b[srcdoc set from AI response]

    D --> D1[Collapsible system prompt section]
    D --> D2[Prompt textarea]
    D --> D3[Send button]

    D1 --> D1a[Default: HTML-only response instruction]
    D1 --> D1b[Editable per session]

    subgraph Response Pipeline
        R1[User sends prompt] --> R2[System prompt prepended to messages]
        R2 --> R3[API call via callOpenAICompatibleChat]
        R3 --> R4[Extract content from response]
        R4 --> R5[extractHtmlFromResponse - strip code fences]
        R5 --> R6[Store raw HTML in conversation messages array]
        R6 --> R7[Set iframe.srcdoc = cleanHtml]
        R7 --> R8[Add page card to Past Pages strip]
    end
```

## Detailed Changes from ai.html

### 1. HTML Structure Changes

**Remove:**
- `#divAiMessages` — the chat bubbles container
- Chat bubble CSS classes (`.aiMessageRow`, `.aiMessageBubble`, `.aiMessageContent`, `.aiMessageMeta`, `.aiTyping`, `.aiTypingDot`)
- Image attachment UI in messages (keep pending attachments for sending)

**Transform `#divAiConversationsPane` into Past Pages Strip:**
- Rename to `#divAiPagesPane`
- Each item shows: page title (auto-generated from prompt), timestamp, delete button
- Active page highlighted
- `+ New Session` button at bottom (clears conversation, starts fresh)

**Add:**
- `<iframe id="iframeAiTv">` inside `#divAiChatPane` where `#divAiMessages` was
- Collapsible `#divAiSystemPromptSection` above the input area
- Loading overlay on the iframe while waiting for response

### 2. iframe Configuration

```html
<iframe
  id="iframeAiTv"
  sandbox="allow-scripts allow-same-origin"
  style="width: 100%; flex: 1; border: none; border-radius: 8px; background: white;"
  srcdoc="<html><body style='display:flex;align-items:center;justify-content:center;height:100vh;font-family:sans-serif;color:#888;'><p>Send a prompt to generate a page...</p></body></html>"
></iframe>
```

**Sandbox notes:**
- `allow-scripts` — lets the generated page run JS for interactivity
- `allow-same-origin` — needed if the generated page wants to use localStorage or similar (optional, could be removed for stricter isolation)
- No `allow-top-navigation` — prevents the generated page from navigating the parent
- No `allow-popups` — prevents unwanted popups

### 3. System Prompt Default

```
You are a web page generator. You MUST respond to ALL user requests with a complete, valid HTML page. Your entire response must be ONLY the HTML document — no markdown, no explanations, no code fences, no commentary before or after the HTML.

Rules:
- Start with <!DOCTYPE html> and include <html>, <head>, and <body> tags
- All CSS must be inline in a <style> tag in the <head>
- All JavaScript must be inline in <script> tags
- Do not reference external resources (CDNs are acceptable)
- Make the page visually appealing with good typography and layout
- The page should be responsive and work at any viewport size
- Use modern CSS features (flexbox, grid, custom properties)
```

### 4. Response Processing

New function `extractHtmlFromResponse(rawContent)`:

```javascript
function extractHtmlFromResponse(rawContent) {
  let html = String(rawContent || '').trim();
  
  // Strip markdown code fences: ```html ... ``` or ``` ... ```
  const fencePattern = /^```(?:html)?\s*\n?([\s\S]*?)\n?\s*```$/;
  const match = html.match(fencePattern);
  if (match) {
    html = match[1].trim();
  }
  
  // Validate it looks like HTML
  if (!html.toLowerCase().includes('<html') && !html.toLowerCase().includes('<!doctype')) {
    // Wrap bare content in a basic HTML page
    html = `<!DOCTYPE html><html><head><meta charset="utf-8"></head><body>${html}</body></html>`;
  }
  
  return html;
}
```

### 5. Conversation Storage Changes

The existing conversation storage structure works well. Each message in `convo.messages[]` already has:
- `role` — 'user' or 'assistant'
- `content` — the raw text (for assistant, this will be the full HTML)
- `createdAt` — timestamp

For the Past Pages strip, we derive page cards from assistant messages:
```javascript
function getPageCards(convo) {
  return convo.messages
    .filter(m => m.role === 'assistant' && !m.typing)
    .map((m, index) => ({
      messageId: m.id,
      title: getPageTitle(m, index),
      timestamp: m.createdAt,
      html: m.content
    }));
}

function getPageTitle(msg, index) {
  // Try to extract <title> from the HTML
  const titleMatch = String(msg.content || '').match(/<title[^>]*>(.*?)<\/title>/i);
  if (titleMatch && titleMatch[1].trim()) return titleMatch[1].trim();
  return `Page ${index + 1}`;
}
```

### 6. Past Pages Strip UI

Each page card in the strip:
```html
<div class="aiPageItem active" data-message-id="...">
  <div class="aiPageHeader">
    <div class="aiPageTitle">My Generated Page</div>
    <button class="aiDeletePageBtn" title="Delete">×</button>
  </div>
  <div class="aiPagePreview">3:42 PM</div>
</div>
```

Clicking a card sets `iframeAiTv.srcdoc` to that message's HTML content.

### 7. Collapsible System Prompt Section

```html
<div id="divAiSystemPromptSection">
  <button id="btnToggleSystemPrompt" class="aiSystemPromptToggle">
    ▶ System Prompt
  </button>
  <div id="divAiSystemPromptBody" style="display: none;">
    <textarea id="taAiSystemPrompt" class="aiTextarea">...</textarea>
  </div>
</div>
```

Toggle shows/hides the textarea. The default value is the HTML-only instruction from section 3.

### 8. Send Flow Changes

The `sendPrompt()` function changes:
1. User message is added to conversation (same as before)
2. Instead of adding a typing bubble, show a loading overlay on the iframe
3. Call `callOpenAICompatibleChat()` (same API call)
4. On response: `extractHtmlFromResponse(result.content)`
5. Store the raw HTML as the assistant message content
6. Set `iframeAiTv.srcdoc = extractedHtml`
7. Add a new page card to the Past Pages strip
8. Remove loading overlay

### 9. CSS Changes

**New styles needed:**
- `#iframeAiTv` — full flex area, no border, white background default
- `.aiPageItem` — page card in the strip (similar to `.aiConversationItem` but adapted)
- `.aiPageItem.active` — highlighted state
- `#divAiSystemPromptSection` — collapsible section styling
- `.aiLoadingOverlay` — semi-transparent overlay with spinner on the iframe area

**Remove:**
- `.aiMessageRow`, `.aiMessageBubble`, `.aiMessageContent`, `.aiMessageMeta`
- `.aiTyping`, `.aiTypingDot`, `@keyframes aiPulse`
- `.aiMessageAttachments`, `.aiMessageAttachmentImg`

### 10. What Stays the Same

- Header bar with provider/model selection
- Sidebar config (provider settings, API keys, payment methods)
- All Routstr/ppq.ai payment and balance logic
- Conversation persistence in localStorage
- Image attachment sending (vision models can still receive images)
- Footer with relay status
- Hamburger menu and sidebar navigation
- Theme toggle, logout

## Files to Modify

| File | Change |
|------|--------|
| `www/ai-tv.html` | Full restructure: layout, CSS, JavaScript |

No other files need modification — this is a self-contained page.

## Risk Considerations

- **Large HTML in localStorage** — Generated pages could be large. Consider truncating stored HTML or adding a max page count.
- **Malicious generated content** — The iframe sandbox mitigates this, but `allow-scripts` means generated JS will run. This is intentional for interactivity but worth noting.
- **Models wrapping in code fences** — The `extractHtmlFromResponse` function handles this, but edge cases may exist (multiple code blocks, partial fences).
- **Models adding commentary** — Some models may add text before/after the HTML despite instructions. The extraction function should handle this by finding the HTML document boundaries.
