diff --git a/docs/src/SUMMARY.md b/docs/src/SUMMARY.md
index 9015755e6..3423ac5e5 100644
--- a/docs/src/SUMMARY.md
+++ b/docs/src/SUMMARY.md
@@ -37,12 +37,14 @@
# Part IV - User Interface
- [Chapter 04: .gbui Interface Reference](./chapter-04-gbui/README.md)
+ - [Suite User Manual](./chapter-04-gbui/suite-manual.md)
- [UI Structure](./chapter-04-gbui/ui-structure.md)
- [default.gbui - Full Desktop](./chapter-04-gbui/default-gbui.md)
- [single.gbui - Simple Chat](./chapter-04-gbui/single-gbui.md)
- [Console Mode](./chapter-04-gbui/console-mode.md)
- [Player - Media Viewer](./chapter-04-gbui/player.md)
- [Monitoring Dashboard](./chapter-04-gbui/monitoring.md)
+ - [HTMX Architecture](./chapter-04-gbui/htmx-architecture.md)
# Part V - Themes and Styling
diff --git a/docs/src/chapter-04-gbui/htmx-architecture.md b/docs/src/chapter-04-gbui/htmx-architecture.md
index 8c4526e72..00ffc3d84 100644
--- a/docs/src/chapter-04-gbui/htmx-architecture.md
+++ b/docs/src/chapter-04-gbui/htmx-architecture.md
@@ -1 +1,535 @@
# HTMX Architecture
+
+## Overview
+
+General Bots Suite uses **HTMX** for its user interface - a modern approach that delivers the interactivity of a single-page application without the complexity of JavaScript frameworks like React, Vue, or Angular.
+
+> **Why HTMX?**
+> - Simpler code, easier maintenance
+> - Server-rendered HTML (fast, SEO-friendly)
+> - Progressive enhancement
+> - No build step required
+> - Smaller payload than SPA frameworks
+
+---
+
+## How HTMX Works
+
+### Traditional Web vs HTMX
+
+**Traditional (Full Page Reload):**
+```
+User clicks → Browser requests full page → Server returns entire HTML → Browser replaces everything
+```
+
+**HTMX (Partial Update):**
+```
+User clicks → HTMX requests fragment → Server returns HTML snippet → HTMX updates only that part
+```
+
+### Core Concept
+
+HTMX extends HTML with attributes that define:
+1. **What triggers the request** (`hx-trigger`)
+2. **Where to send it** (`hx-get`, `hx-post`)
+3. **What to update** (`hx-target`)
+4. **How to update it** (`hx-swap`)
+
+---
+
+## HTMX Attributes Reference
+
+### Request Attributes
+
+| Attribute | Purpose | Example |
+|-----------|---------|---------|
+| `hx-get` | GET request to URL | `hx-get="/api/tasks"` |
+| `hx-post` | POST request | `hx-post="/api/tasks"` |
+| `hx-put` | PUT request | `hx-put="/api/tasks/1"` |
+| `hx-patch` | PATCH request | `hx-patch="/api/tasks/1"` |
+| `hx-delete` | DELETE request | `hx-delete="/api/tasks/1"` |
+
+### Trigger Attributes
+
+| Attribute | Purpose | Example |
+|-----------|---------|---------|
+| `hx-trigger` | Event that triggers request | `hx-trigger="click"` |
+| | Load on page | `hx-trigger="load"` |
+| | Periodic polling | `hx-trigger="every 5s"` |
+| | Keyboard event | `hx-trigger="keyup changed delay:300ms"` |
+
+### Target & Swap Attributes
+
+| Attribute | Purpose | Example |
+|-----------|---------|---------|
+| `hx-target` | Element to update | `hx-target="#results"` |
+| `hx-swap` | How to insert content | `hx-swap="innerHTML"` |
+| | | `hx-swap="outerHTML"` |
+| | | `hx-swap="beforeend"` |
+| | | `hx-swap="afterbegin"` |
+
+---
+
+## Suite Architecture
+
+### File Structure
+
+```
+ui/suite/
+├── index.html # Main entry point with navigation
+├── default.gbui # Full desktop layout
+├── single.gbui # Simple chat layout
+├── designer.html # Visual dialog designer
+├── editor.html # Code editor
+├── settings.html # User settings
+├── css/
+│ └── app.css # Global styles
+├── js/
+│ ├── layout.js # Layout management
+│ └── theme-manager.js # Theme switching
+├── chat/
+│ ├── chat.html # Chat component
+│ └── chat.css # Chat styles
+├── drive/
+│ └── index.html # File manager
+├── tasks/
+│ ├── tasks.html # Task manager
+│ └── tasks.css # Task styles
+├── mail/
+│ ├── mail.html # Email client
+│ └── mail.css # Email styles
+├── calendar/
+│ └── calendar.html # Calendar view
+├── meet/
+│ ├── meet.html # Video meetings
+│ └── meet.css # Meeting styles
+├── paper/
+│ └── paper.html # Document editor
+├── research/
+│ └── research.html # AI search
+├── analytics/
+│ └── analytics.html # Dashboards
+├── sources/
+│ └── index.html # Prompts & templates
+├── tools/
+│ └── compliance.html # Security scanner
+└── monitoring/
+ └── ... # System monitoring
+```
+
+### Loading Pattern
+
+The Suite uses **lazy loading** - components load only when needed:
+
+```html
+
+
+ Chat
+
+```
+
+When user clicks "Chat":
+1. HTMX requests `/ui/suite/chat/chat.html`
+2. Server returns the Chat HTML fragment
+3. HTMX inserts it into `#main-content`
+4. Only Chat code loads, not entire app
+
+---
+
+## Component Patterns
+
+### 1. Load on Page View
+
+```html
+
+
+```
+
+### 2. Form Submission
+
+```html
+
+
+```
+
+**Flow:**
+1. User types task, clicks Add
+2. HTMX POSTs form data to `/api/tasks`
+3. Server creates task, returns HTML for new task item
+4. HTMX inserts at beginning of `#task-list`
+5. Form resets automatically
+
+### 3. Click Actions
+
+```html
+
+
+
+ Review quarterly report
+
+ 🗑
+
+
+```
+
+### 4. Search with Debounce
+
+```html
+
+
+
+🔄
+
+```
+
+**Flow:**
+1. User types in search box
+2. After 300ms of no typing, HTMX sends request
+3. Spinner shows during request
+4. Results replace `#search-results` content
+
+### 5. Real-time Updates (WebSocket)
+
+```html
+
+
+```
+
+**Flow:**
+1. WebSocket connects on load
+2. History loads via HTMX GET
+3. New messages sent via WebSocket (`ws-send`)
+4. Server pushes updates to all connected clients
+
+### 6. Polling for Updates
+
+```html
+
+
+
+
+```
+
+### 7. Infinite Scroll
+
+```html
+
+
+
+
+
+ Loading more...
+
+
+```
+
+---
+
+## API Response Patterns
+
+### Server Returns HTML Fragments
+
+The server doesn't return JSON - it returns ready-to-display HTML:
+
+**Request:**
+```
+GET /api/tasks
+```
+
+**Response:**
+```html
+
+
+ Review quarterly report
+
+
+
+ Update documentation
+
+```
+
+### Swap Strategies
+
+| Strategy | Effect |
+|----------|--------|
+| `innerHTML` | Replace contents of target |
+| `outerHTML` | Replace entire target element |
+| `beforeend` | Append inside target (at end) |
+| `afterbegin` | Prepend inside target (at start) |
+| `beforebegin` | Insert before target |
+| `afterend` | Insert after target |
+| `delete` | Delete target element |
+| `none` | Don't swap (for side effects) |
+
+---
+
+## CSS Integration
+
+### Loading Indicators
+
+```css
+/* Hidden by default */
+.htmx-indicator {
+ display: none;
+}
+
+/* Shown during request */
+.htmx-request .htmx-indicator {
+ display: inline-block;
+}
+
+/* Or when indicator IS the requesting element */
+.htmx-request.htmx-indicator {
+ display: inline-block;
+}
+```
+
+### Transition Effects
+
+```css
+/* Fade in new content */
+.htmx-settling {
+ opacity: 0;
+}
+
+.htmx-swapping {
+ opacity: 0;
+ transition: opacity 0.2s ease-out;
+}
+```
+
+---
+
+## JavaScript Integration
+
+### HTMX Events
+
+```javascript
+// After any HTMX swap
+document.body.addEventListener('htmx:afterSwap', (e) => {
+ console.log('Content updated:', e.detail.target);
+});
+
+// Before request
+document.body.addEventListener('htmx:beforeRequest', (e) => {
+ console.log('Sending request to:', e.detail.pathInfo.path);
+});
+
+// After request completes
+document.body.addEventListener('htmx:afterRequest', (e) => {
+ if (e.detail.successful) {
+ console.log('Request succeeded');
+ } else {
+ console.error('Request failed');
+ }
+});
+
+// On WebSocket message
+document.body.addEventListener('htmx:wsAfterMessage', (e) => {
+ console.log('Received:', e.detail.message);
+});
+```
+
+### Triggering HTMX from JavaScript
+
+```javascript
+// Trigger an HTMX request programmatically
+htmx.trigger('#task-list', 'load');
+
+// Make an AJAX request
+htmx.ajax('GET', '/api/tasks', {
+ target: '#task-list',
+ swap: 'innerHTML'
+});
+
+// Process new HTMX content
+htmx.process(document.getElementById('new-content'));
+```
+
+---
+
+## Designer Page Architecture
+
+The visual dialog designer uses a hybrid approach:
+
+### Canvas Management (JavaScript)
+```javascript
+// State managed in JavaScript
+const state = {
+ nodes: new Map(), // Node data
+ connections: [], // Connections between nodes
+ zoom: 1, // Canvas zoom level
+ pan: { x: 0, y: 0 } // Canvas position
+};
+```
+
+### File Operations (HTMX)
+```html
+
+
+ Open File
+
+
+
+
+ Save
+
+```
+
+### Drag-and-Drop (JavaScript)
+```javascript
+// Toolbox items are draggable
+toolboxItems.forEach(item => {
+ item.addEventListener('dragstart', (e) => {
+ e.dataTransfer.setData('nodeType', item.dataset.nodeType);
+ });
+});
+
+// Canvas handles drop
+canvas.addEventListener('drop', (e) => {
+ const nodeType = e.dataTransfer.getData('nodeType');
+ createNode(nodeType, e.clientX, e.clientY);
+});
+```
+
+---
+
+## Performance Considerations
+
+### 1. Minimize Request Size
+
+Return only what's needed:
+```html
+
+...
+
+
+
+```
+
+### 2. Use Appropriate Triggers
+
+```html
+
+hx-trigger="every 30s"
+hx-trigger="every 1s"
+
+
+hx-trigger="keyup changed delay:300ms"
+hx-trigger="keyup"
+```
+
+### 3. Lazy Load Heavy Content
+
+```html
+
+
+
+```
+
+### 4. Use `hx-boost` for Navigation
+
+```html
+
+
+ Page 1
+ Page 2
+
+```
+
+---
+
+## Security
+
+### CSRF Protection
+
+HTMX automatically includes CSRF tokens:
+
+```html
+
+```
+
+```javascript
+// Configure HTMX to send CSRF token
+document.body.addEventListener('htmx:configRequest', (e) => {
+ e.detail.headers['X-CSRF-Token'] = document.querySelector('meta[name="csrf-token"]').content;
+});
+```
+
+### Content Security
+
+- Server validates all inputs
+- HTML is sanitized before rendering
+- Authentication checked on every request
+
+---
+
+## Comparison: HTMX vs React
+
+| Aspect | HTMX | React |
+|--------|------|-------|
+| **Learning Curve** | Low (HTML attributes) | High (JSX, hooks, state) |
+| **Bundle Size** | ~14KB | ~40KB + app code |
+| **Build Step** | None | Required |
+| **Server Load** | More (renders HTML) | Less (returns JSON) |
+| **Client Load** | Less | More |
+| **SEO** | Excellent | Requires SSR |
+| **Complexity** | Simple | Complex |
+| **Best For** | Content sites, dashboards | Complex SPAs, offline apps |
+
+---
+
+## Further Reading
+
+- [HTMX Official Documentation](https://htmx.org/docs/)
+- [HTMX Examples](https://htmx.org/examples/)
+- [Hypermedia Systems (Book)](https://hypermedia.systems/)
+- [Chapter 04: UI Reference](./README.md)
\ No newline at end of file
diff --git a/docs/src/chapter-04-gbui/suite-manual.md b/docs/src/chapter-04-gbui/suite-manual.md
new file mode 100644
index 000000000..e04d0c883
--- /dev/null
+++ b/docs/src/chapter-04-gbui/suite-manual.md
@@ -0,0 +1,1138 @@
+# General Bots Suite - User Manual
+
+> **The Complete Productivity Workspace**
+>
+> *Like Microsoft Office, but with AI built-in*
+
+---
+
+## Welcome to General Bots Suite
+
+General Bots Suite is your all-in-one workspace that combines communication, productivity, and AI assistance. Think of it like having Word, Outlook, Teams, and an AI assistant all in one place - but simpler and more powerful.
+
+**What makes it special:**
+- Everything works together seamlessly
+- AI helps you with every task
+- No complex setup required
+- Works in your browser
+
+---
+
+## Part I: Getting Started
+
+### Opening the Suite
+
+1. **Open your web browser** (Chrome, Firefox, Safari, or Edge)
+2. **Go to your General Bots address** (example: `http://your-company.bot:8080`)
+3. **The Suite loads automatically** - you'll see the workspace in seconds
+
+### Your First Look
+
+When the Suite opens, you see:
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ 🤖 General Bots [Apps Menu ⋮⋮⋮] [Theme 🌙] [U] │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ │
+│ 💬 Chat (Main Area) │
+│ │
+│ Type your message here... │
+│ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### The Apps Menu
+
+Click the **nine-dot grid** (⋮⋮⋮) in the top right to see all applications:
+
+| Icon | App | What It Does |
+|------|-----|--------------|
+| 💬 | **Chat** | Talk with your AI assistant |
+| 📁 | **Drive** | Store and manage your files |
+| ✓ | **Tasks** | Manage your to-do lists |
+| ✉ | **Mail** | Send and receive emails |
+| 📅 | **Calendar** | Schedule meetings and events |
+| 🎥 | **Meet** | Video calls and meetings |
+| 📝 | **Paper** | Write documents with AI help |
+| 🔍 | **Research** | AI-powered search |
+| 📊 | **Analytics** | View reports and statistics |
+
+---
+
+## Part II: Chat - Your AI Assistant
+
+### What Chat Does
+
+Chat is your personal AI assistant. Ask questions, get help with tasks, or have a conversation - just like talking to a helpful colleague.
+
+### How to Use Chat
+
+**Sending a Message:**
+1. Click in the message box at the bottom
+2. Type your question or request
+3. Press **Enter** or click the **↑** button
+
+**Example Conversations:**
+
+```
+You: What meetings do I have today?
+Bot: You have 2 meetings scheduled:
+ • 10:00 AM - Team Standup
+ • 2:00 PM - Project Review
+
+You: Remind me to call John tomorrow at 3pm
+Bot: Done! I've created a reminder for tomorrow at 3:00 PM
+ to call John.
+
+You: Write a professional email to decline a meeting
+Bot: Here's a draft:
+
+ Subject: Unable to Attend Meeting
+
+ Dear [Name],
+
+ Thank you for the invitation. Unfortunately, I have
+ a scheduling conflict and won't be able to attend.
+
+ Would it be possible to reschedule or receive a
+ summary of the discussion?
+
+ Best regards
+```
+
+### Voice Input
+
+1. Click the **🎤 microphone** button
+2. Speak your message
+3. Click again to stop
+4. Your words appear as text automatically
+
+### Quick Suggestions
+
+Below the message box, you'll see **suggestion chips** - common actions you can click:
+
+```
+[📊 Show my tasks] [📧 Check email] [📅 Today's schedule] [❓ Help]
+```
+
+### Keyboard Shortcuts for Chat
+
+| Shortcut | Action |
+|----------|--------|
+| `Enter` | Send message |
+| `Shift+Enter` | New line (without sending) |
+| `↑` Arrow | Edit last message |
+| `/` | Show command menu |
+
+---
+
+## Part III: Drive - File Management
+
+### What Drive Does
+
+Drive is your file storage - like Google Drive or OneDrive. Store documents, images, spreadsheets, and any file you need.
+
+### The Drive Interface
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ [+ New ▼] 🔍 Search files... [⊞] [≡] │
+├──────────────┬──────────────────────────────────────────────────┤
+│ │ 📁 My Drive > Projects > 2024 │
+│ My Drive │ ─────────────────────────────────────────────────│
+│ ⭐ Starred │ [☐] Name Size Modified │
+│ 🕐 Recent │ ─────────────────────────────────────────────── │
+│ 🗑 Trash │ 📁 Reports - Today │
+│ │ 📁 Presentations - Yesterday │
+│ ───────────│ 📄 Budget.xlsx 245 KB Mar 15 │
+│ Labels │ 📄 Notes.docx 12 KB Mar 14 │
+│ 🔵 Work │ 🖼 Logo.png 89 KB Mar 10 │
+│ 🟢 Personal│ │
+└──────────────┴──────────────────────────────────────────────────┘
+```
+
+### Creating and Uploading
+
+**Upload Files:**
+1. Click **+ New** button
+2. Select **Upload Files**
+3. Choose files from your computer
+4. *Or:* Drag files directly into Drive
+
+**Create New Folder:**
+1. Click **+ New**
+2. Select **New Folder**
+3. Type the folder name
+4. Press Enter
+
+### Working with Files
+
+**Open a file:** Double-click it
+
+**Select files:** Click the checkbox beside the file name
+
+**Multiple selection:** Hold `Ctrl` (or `Cmd` on Mac) and click files
+
+**Right-click menu options:**
+- 📂 Open
+- ⬇️ Download
+- ✏️ Rename
+- 📋 Copy
+- 📁 Move to...
+- ⭐ Add to Starred
+- 🔗 Share
+- 🗑 Delete
+
+### View Options
+
+| Button | View | Best For |
+|--------|------|----------|
+| ⊞ | Grid view | Images and visual files |
+| ≡ | List view | Documents and details |
+
+### Keyboard Shortcuts for Drive
+
+| Shortcut | Action |
+|----------|--------|
+| `Ctrl+U` | Upload files |
+| `Ctrl+N` | New folder |
+| `Delete` | Move to trash |
+| `Ctrl+C` | Copy |
+| `Ctrl+V` | Paste |
+| `Enter` | Open selected |
+
+---
+
+## Part IV: Tasks - To-Do Management
+
+### What Tasks Does
+
+Tasks helps you track what needs to be done. Create to-do lists, set due dates, and mark items complete.
+
+### The Tasks Interface
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ ✓ Tasks Total: 12 Active: 5 Done: 7│
+├─────────────────────────────────────────────────────────────────┤
+│ ┌─────────────────────────────────────────────────────────┐ │
+│ │ What needs to be done? [Category ▼] [+ Add]│ │
+│ └─────────────────────────────────────────────────────────┘ │
+├─────────────────────────────────────────────────────────────────┤
+│ [📋 All (12)] [⏳ Active (5)] [✓ Completed (7)] [⚡ Priority] │
+├─────────────────────────────────────────────────────────────────┤
+│ ☐ Review quarterly report 📅 Today 🔴 │
+│ ☐ Call client about proposal 📅 Today 🟡 │
+│ ☐ Update project documentation 📅 Tomorrow 🟢 │
+│ ☑ Send meeting notes ✓ Done │
+│ ☑ Complete expense report ✓ Done │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Adding a Task
+
+1. Type your task in the input box
+2. *(Optional)* Select a category: Work, Personal, Shopping, Health
+3. *(Optional)* Set a due date
+4. Click **+ Add** or press Enter
+
+**Pro tip:** Be specific! Instead of "Work on project", write "Draft introduction section for project proposal"
+
+### Task Priorities
+
+| Color | Priority | When to Use |
+|-------|----------|-------------|
+| 🔴 Red | High | Must do today |
+| 🟡 Yellow | Medium | Important but not urgent |
+| 🟢 Green | Low | Can wait |
+
+### Completing Tasks
+
+- **Click the checkbox** to mark a task done
+- Completed tasks move to the "Completed" tab
+- Feel the satisfaction! ✓
+
+### Filter Tabs
+
+| Tab | Shows |
+|-----|-------|
+| **All** | Everything |
+| **Active** | Tasks not yet done |
+| **Completed** | Finished tasks |
+| **Priority** | High-priority tasks only |
+
+### Creating Tasks from Chat
+
+In Chat, just say:
+```
+You: Create a task to review the budget by Friday
+Bot: Task created: "Review the budget" - Due: Friday
+```
+
+---
+
+## Part V: Mail - Email Management
+
+### What Mail Does
+
+Mail connects to your email accounts so you can read, write, and organize emails without leaving the Suite.
+
+### The Mail Interface
+
+```
+┌────────────────┬───────────────────┬────────────────────────────┐
+│ │ │ │
+│ [✏ Compose] │ Inbox │ From: john@company.com │
+│ │ │ Subject: Project Update │
+│ 📥 Inbox (3) │ ● Project Update │ ──────────────────────── │
+│ 📤 Sent │ from John │ │
+│ 📝 Drafts │ 10:30 AM │ Hi, │
+│ 🗑 Trash │ │ │
+│ │ ○ Meeting Notes │ Here's the latest update │
+│ │ from Sarah │ on our project... │
+│ │ Yesterday │ │
+│ │ │ Best, │
+│ │ ○ Invoice #1234 │ John │
+│ │ from Vendor │ │
+│ │ Mar 15 │ [Reply] [Forward] [Delete]│
+└────────────────┴───────────────────┴────────────────────────────┘
+```
+
+### Reading Email
+
+1. Click on **Mail** in the Apps menu
+2. Click any email in the list to read it
+3. The full email appears on the right
+
+### Composing Email
+
+1. Click **✏ Compose**
+2. Fill in the fields:
+ - **To:** recipient's email
+ - **Subject:** what it's about
+ - **Body:** your message
+3. Click **Send**
+
+**AI-Assisted Writing:**
+```
+You: Help me write an email to reschedule tomorrow's meeting
+Bot: Here's a draft:
+
+ To: [recipient]
+ Subject: Request to Reschedule Meeting
+
+ Hi [Name],
+
+ I hope this message finds you well. Would it be
+ possible to reschedule our meeting tomorrow?
+ I have an unexpected conflict.
+
+ Please let me know what times work for you
+ later this week.
+
+ Thank you for understanding.
+```
+
+### Email Folders
+
+| Folder | Purpose |
+|--------|---------|
+| **Inbox** | New and unread messages |
+| **Sent** | Emails you've sent |
+| **Drafts** | Unfinished emails |
+| **Trash** | Deleted emails (emptied after 30 days) |
+
+### Email Actions
+
+| Button | Action |
+|--------|--------|
+| **Reply** | Respond to sender |
+| **Reply All** | Respond to everyone |
+| **Forward** | Send to someone else |
+| **Delete** | Move to Trash |
+| **Archive** | Remove from Inbox but keep |
+
+---
+
+## Part VI: Calendar - Scheduling
+
+### What Calendar Does
+
+Calendar shows your schedule, meetings, and events. Plan your day, week, or month at a glance.
+
+### The Calendar Interface
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ ◄ March 2024 ► [Day] [Week] [Month] │
+├─────────────────────────────────────────────────────────────────┤
+│ Mon Tue Wed Thu Fri Sat Sun │
+│ ────────────────────────────────────────────────────────────── │
+│ 1 2 3 │
+│ │
+│ 4 5 6 7 8 9 10 │
+│ ████ │
+│ Team │
+│ Meeting │
+│ │
+│ 11 12 13 14 15 16 17 │
+│ ████ ████ │
+│ Project Review │
+│ Demo 1:1 │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Creating an Event
+
+**Method 1: Click and Create**
+1. Click on a day/time slot
+2. Enter event details
+3. Click Save
+
+**Method 2: Ask the AI**
+```
+You: Schedule a team meeting for next Tuesday at 2pm
+Bot: Event created:
+ 📅 Team Meeting
+ 🕐 Tuesday, March 19 at 2:00 PM
+ ⏱ Duration: 1 hour
+```
+
+### Event Details
+
+When creating an event, you can set:
+- **Title** - What the event is
+- **Date & Time** - When it happens
+- **Duration** - How long it lasts
+- **Location** - Where (room or video link)
+- **Attendees** - Who to invite
+- **Reminder** - When to notify you
+- **Repeat** - Daily, weekly, monthly
+
+### Calendar Views
+
+| View | Shows | Best For |
+|------|-------|----------|
+| **Day** | Hour by hour | Detailed daily planning |
+| **Week** | 7 days | Seeing your week ahead |
+| **Month** | Full month | Long-term planning |
+
+### Keyboard Navigation
+
+| Key | Action |
+|-----|--------|
+| `←` `→` | Previous/Next period |
+| `T` | Jump to Today |
+| `D` | Day view |
+| `W` | Week view |
+| `M` | Month view |
+
+---
+
+## Part VII: Meet - Video Calls
+
+### What Meet Does
+
+Meet lets you have video calls with one person or many. Share your screen, record meetings, and get AI transcriptions.
+
+### Starting a Meeting
+
+**Start Instant Meeting:**
+1. Click **Meet** in Apps menu
+2. Click **Start Meeting**
+3. Share the link with others
+
+**Schedule for Later:**
+```
+You: Schedule a video call with the team for tomorrow at 10am
+Bot: Meeting scheduled:
+ 🎥 Team Video Call
+ 📅 Tomorrow at 10:00 AM
+ 🔗 Link: meet.bot/abc-defg-hij
+
+ Shall I send invites to the team?
+```
+
+### The Meeting Interface
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Meeting Room 00:15:32 [👥 3] [💬] │
+├─────────────────────────────────────────────────────────────────┤
+│ ┌─────────────────────┐ ┌─────────────────────┐ │
+│ │ │ │ │ │
+│ │ 👤 You │ │ 👤 John │ │
+│ │ │ │ │ │
+│ │ (Camera) │ │ (Camera) │ │
+│ └─────────────────────┘ └─────────────────────┘ │
+│ │
+│ ┌─────────────────────┐ │
+│ │ 👤 Sarah │ │
+│ └─────────────────────┘ │
+├─────────────────────────────────────────────────────────────────┤
+│ [🎤 Mute] [📹 Video] [🖥 Share] [🔴 Record] [📞 End] │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Meeting Controls
+
+| Button | Function |
+|--------|----------|
+| 🎤 **Mute** | Turn microphone on/off |
+| 📹 **Video** | Turn camera on/off |
+| 🖥 **Share** | Share your screen |
+| 🔴 **Record** | Record the meeting |
+| 📝 **Transcribe** | Get live captions |
+| 💬 **Chat** | Open meeting chat |
+| 👥 **Participants** | See who's in the call |
+| 📞 **End** | Leave the meeting |
+
+### Screen Sharing
+
+1. Click **🖥 Share**
+2. Choose what to share:
+ - **Entire Screen** - Everything you see
+ - **Window** - One application
+ - **Tab** - One browser tab
+3. Click **Share**
+4. Click **Stop Sharing** when done
+
+### AI Features in Meetings
+
+**Live Transcription:**
+- Enable with the **📝 Transcribe** button
+- Words appear as people speak
+- Great for accessibility and note-taking
+
+**Meeting Summary:**
+After the meeting, ask:
+```
+You: Summarize today's project meeting
+Bot: Meeting Summary:
+
+ Duration: 45 minutes
+ Participants: You, John, Sarah
+
+ Key Points:
+ • Project deadline moved to April 15
+ • John will handle client communication
+ • Sarah completing design by Friday
+
+ Action Items:
+ • [You] Review budget proposal
+ • [John] Send client update
+ • [Sarah] Share design mockups
+```
+
+---
+
+## Part VIII: Paper - AI Writing
+
+### What Paper Does
+
+Paper is your writing space with AI assistance. Write documents, notes, reports - and let AI help you write better.
+
+### The Paper Interface
+
+```
+┌────────────────┬────────────────────────────────────────────────┐
+│ │ [B] [I] [U] H1 H2 • ― 🔗 📷 [AI ✨] │
+│ 📄 Notes ├────────────────────────────────────────────────┤
+│ ──────────── │ │
+│ Meeting Notes │ Project Proposal │
+│ Project Plan │ ════════════════ │
+│ Ideas │ │
+│ │ Introduction │
+│ ──────────── │ ──────────── │
+│ Quick Start │ │
+│ [📄 Blank] │ This document outlines our proposal for │
+│ [📋 Meeting] │ the upcoming project. We aim to... │
+│ [✓ To-Do] │ │
+│ [🔬 Research] │ | │
+│ │ │
+└────────────────┴────────────────────────────────────────────────┘
+```
+
+### Creating a Document
+
+1. Click **+ New** in the sidebar
+2. Choose a template:
+ - **Blank** - Start fresh
+ - **Meeting Notes** - Pre-formatted for meetings
+ - **To-Do List** - Checkbox format
+ - **Research** - Sections for sources
+
+### Formatting Toolbar
+
+| Button | Function | Shortcut |
+|--------|----------|----------|
+| **B** | Bold | `Ctrl+B` |
+| **I** | Italic | `Ctrl+I` |
+| **U** | Underline | `Ctrl+U` |
+| **H1** | Heading 1 | `Ctrl+1` |
+| **H2** | Heading 2 | `Ctrl+2` |
+| **•** | Bullet list | `Ctrl+Shift+8` |
+| **―** | Numbered list | `Ctrl+Shift+7` |
+| **🔗** | Insert link | `Ctrl+K` |
+| **📷** | Insert image | - |
+
+### AI Writing Assistant ✨
+
+Click the **AI ✨** button or type `/ai` for AI help:
+
+**Commands:**
+```
+/ai improve → Make the text better
+/ai shorter → Make it more concise
+/ai longer → Expand with more detail
+/ai formal → Make it professional
+/ai friendly → Make it casual
+/ai translate → Translate to another language
+/ai summarize → Create a summary
+```
+
+**Example:**
+```
+You wrote: "The thing we need to do is make the stuff better"
+
+/ai formal
+
+AI suggests: "Our objective is to enhance the quality of
+ our deliverables to meet higher standards."
+```
+
+### Auto-Save
+
+Paper saves automatically as you type. Look for:
+- **"Saving..."** - Currently saving
+- **"Saved"** - All changes saved
+- **"Offline"** - Will save when connected
+
+---
+
+## Part IX: Research - AI Search
+
+### What Research Does
+
+Research is like having a research assistant. Search the web, your documents, and knowledge bases - then get AI-synthesized answers.
+
+### The Research Interface
+
+```
+┌────────────────┬────────────────────────────────────────────────┐
+│ │ │
+│ 🔍 Research │ ┌────────────────────────────────────────┐ │
+│ │ │ What are the best practices for... │ │
+│ ──────────── │ └────────────────────────────────────────┘ │
+│ Focus: │ │
+│ [🌐 All] │ AI Answer: │
+│ [📚 Academic] │ ══════════ │
+│ [💻 Code] │ Based on multiple sources, here are the │
+│ [🏠 Internal] │ key best practices: │
+│ │ │
+│ Collections: │ 1. Start with clear requirements │
+│ 📁 Project A │ 2. Use iterative development │
+│ 📁 References │ 3. Test early and often │
+│ │ │
+│ Recent: │ Sources: │
+│ • market size │ [1] industry-guide.com │
+│ • competitors │ [2] techblog.dev │
+│ │ [3] your-docs/guidelines.pdf │
+└────────────────┴────────────────────────────────────────────────┘
+```
+
+### Search Modes
+
+| Mode | Icon | Searches |
+|------|------|----------|
+| **All** | 🌐 | Everything |
+| **Academic** | 📚 | Research papers, journals |
+| **Code** | 💻 | Documentation, code examples |
+| **Internal** | 🏠 | Your company's knowledge base |
+
+### Using Research
+
+1. Type your question in the search box
+2. Select a focus mode (optional)
+3. Press Enter
+4. Read the AI-synthesized answer
+5. Click sources to see original content
+
+### Collections
+
+Save important searches and sources:
+
+1. Click **+ New Collection**
+2. Name it (e.g., "Q1 Project Research")
+3. Add sources by clicking **Save to Collection**
+4. Access anytime from the sidebar
+
+### Pro Tips
+
+**Be specific:**
+- ❌ "marketing"
+- ✅ "B2B SaaS marketing strategies for startups under 50 employees"
+
+**Use follow-up questions:**
+```
+Search: What is machine learning?
+Follow-up: How is it different from deep learning?
+Follow-up: What are practical business applications?
+```
+
+---
+
+## Part X: Analytics - Reports & Insights
+
+### What Analytics Does
+
+Analytics shows you reports about usage, conversations, and performance. Understand how the bot is being used and what's working.
+
+### The Analytics Interface
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ 📊 Analytics Dashboard [Last 24h ▼] [⟳ Refresh] │
+├─────────────────────────────────────────────────────────────────┤
+│ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
+│ │ 1,234 │ │ 89% │ │ 2.3s │ │ 45 │ │
+│ │ Messages │ │ Success │ │ Avg Time │ │ Users │ │
+│ │ +12% │ │ Rate │ │ Response │ │ Today │ │
+│ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │
+├─────────────────────────────────────────────────────────────────┤
+│ │
+│ Messages Over Time Top Questions │
+│ ┌─────────────────────────┐ ┌─────────────────────────┐ │
+│ │ ╭─╮ │ │ 1. How do I reset... │ │
+│ │ ╭╯ ╰╮ ╭─╮ │ │ 2. What is the status...│ │
+│ │ ╭╯ ╰────╯ ╰╮ │ │ 3. Where can I find... │ │
+│ │ ─╯ ╰── │ │ 4. Help with login │ │
+│ └─────────────────────────┘ └─────────────────────────┘ │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+### Key Metrics
+
+| Metric | What It Means |
+|--------|---------------|
+| **Messages** | Total conversations |
+| **Success Rate** | % of questions answered well |
+| **Avg Response Time** | How fast the bot replies |
+| **Users** | Number of people using the bot |
+| **Popular Topics** | What people ask about most |
+
+### Time Ranges
+
+Select different periods to analyze:
+- Last Hour
+- Last 6 Hours
+- Last 24 Hours
+- Last 7 Days
+- Last 30 Days
+- Custom Range
+
+### Exporting Data
+
+Click **Export** to download reports as:
+- **CSV** - For spreadsheets
+- **PDF** - For sharing
+- **JSON** - For developers
+
+---
+
+## Part XI: Designer - Visual Dialog Builder
+
+### What Designer Does
+
+Designer lets you create bot conversations visually - like VB6 form designer, but for conversations. Drag and drop blocks to build dialogs without coding.
+
+### The Designer Interface
+
+```
+┌──────────────┬──────────────────────────────────────┬──────────┐
+│ Toolbox │ Canvas │Properties│
+├──────────────┼──────────────────────────────────────┼──────────┤
+│ │ │ │
+│ 💬 TALK │ ┌─────────┐ │ Node: │
+│ 👂 HEAR │ │💬 TALK │ │ TALK │
+│ 📝 SET │ │"Hello!" │───┐ │ │
+│ │ └─────────┘ │ │ Message: │
+│ ───────── │ ▼ │ [Hello!] │
+│ │ ┌─────────┐ ┌─────────┐ │ │
+│ 🔀 IF │ │👂 HEAR │──▶│🔀 IF │ │ │
+│ 🔄 FOR │ │ name │ │name="Jo"│ │ │
+│ 🔃 SWITCH │ └─────────┘ └────┬────┘ │ │
+│ │ ┌───┴───┐ │ │
+│ ───────── │ Yes No │ │
+│ │ │ │ │ │
+│ 📞 CALL │ ┌────┴──┐ ┌──┴────┐ │ │
+│ 📧 SEND │ │💬TALK │ │💬TALK │ │ │
+│ 💾 SAVE │ │"Hi Jo"│ │"Hello"│ │ │
+│ │ └───────┘ └───────┘ │ │
+└──────────────┴──────────────────────────────────────┴──────────┘
+```
+
+### Building a Dialog
+
+**Step 1: Drag Blocks**
+- Drag from Toolbox to Canvas
+- Blocks snap to grid
+
+**Step 2: Connect Blocks**
+- Drag from output port (●) to input port
+- Lines show conversation flow
+
+**Step 3: Configure Properties**
+- Click a block
+- Edit settings in Properties panel
+
+**Step 4: Export**
+- Click **Export to .bas**
+- Save your dialog file
+
+### Block Types
+
+| Block | Icon | Purpose | Example |
+|-------|------|---------|---------|
+| **TALK** | 💬 | Bot speaks | "Welcome! How can I help?" |
+| **HEAR** | 👂 | Wait for user input | Store response in `name` |
+| **SET** | 📝 | Set a variable | `total = price * quantity` |
+| **IF** | 🔀 | Make decisions | If age > 18 then... |
+| **FOR** | 🔄 | Repeat for items | For each item in cart... |
+| **SWITCH** | 🔃 | Multiple choices | Switch on category... |
+| **CALL** | 📞 | Call another dialog | Call "checkout" |
+| **SEND MAIL** | 📧 | Send email | Send confirmation |
+| **SAVE** | 💾 | Save data | Save to database |
+| **WAIT** | ⏱ | Pause | Wait 5 seconds |
+
+### Example: Simple Greeting Dialog
+
+```
+ ┌─────────────────┐
+ │ 💬 TALK │
+ │ "What's your │
+ │ name?" │
+ └────────┬────────┘
+ │
+ ▼
+ ┌─────────────────┐
+ │ 👂 HEAR │
+ │ as: name │
+ │ type: STRING │
+ └────────┬────────┘
+ │
+ ▼
+ ┌─────────────────┐
+ │ 💬 TALK │
+ │ "Nice to meet │
+ │ you, {name}!" │
+ └─────────────────┘
+```
+
+**Generated Code:**
+```basic
+TALK "What's your name?"
+HEAR name AS STRING
+TALK "Nice to meet you, " + name + "!"
+```
+
+### Keyboard Shortcuts in Designer
+
+| Shortcut | Action |
+|----------|--------|
+| `Ctrl+S` | Save |
+| `Ctrl+O` | Open file |
+| `Ctrl+Z` | Undo |
+| `Ctrl+Y` | Redo |
+| `Ctrl+C` | Copy block |
+| `Ctrl+V` | Paste block |
+| `Delete` | Delete selected |
+| `Escape` | Deselect |
+
+---
+
+## Part XII: Sources - Prompts & Templates
+
+### What Sources Does
+
+Sources is your library of prompts, templates, tools, and AI models. Find and use pre-built components to extend your bot.
+
+### The Sources Interface
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ Sources 🔍 Search... │
+├─────────────────────────────────────────────────────────────────┤
+│ [Prompts] [Templates] [MCP Servers] [LLM Tools] [Models] │
+├──────────────┬──────────────────────────────────────────────────┤
+│ │ │
+│ Categories │ ⭐ Featured │
+│ ─────────── │ ┌────────────┐ ┌────────────┐ │
+│ 📝 Writing │ │ Customer │ │ Sales │ │
+│ 📊 Analysis │ │ Service │ │ Assistant │ │
+│ 💼 Business │ │ ──────────│ │ ──────────│ │
+│ 💻 Code │ │ Handle │ │ Qualify │ │
+│ 🎨 Creative │ │ support │ │ leads and │ │
+│ │ │ inquiries │ │ schedule │ │
+│ │ │ [Use] │ │ [Use] │ │
+│ │ └────────────┘ └────────────┘ │
+└──────────────┴──────────────────────────────────────────────────┘
+```
+
+### Tabs Explained
+
+| Tab | Contains | Use For |
+|-----|----------|---------|
+| **Prompts** | Pre-written AI instructions | Starting conversations |
+| **Templates** | Complete bot packages | Full solutions |
+| **MCP Servers** | External tool connections | Integrations |
+| **LLM Tools** | AI functions | Extending capabilities |
+| **Models** | AI model options | Choosing AI provider |
+
+### Using a Prompt
+
+1. Browse or search prompts
+2. Click on a prompt card
+3. Click **Use** to apply it
+4. Customize if needed
+
+### Installing a Template
+
+1. Go to **Templates** tab
+2. Find a template (e.g., "CRM Contacts")
+3. Click **Install**
+4. Configure settings
+5. Template is now active
+
+### Available Models
+
+| Model | Provider | Best For |
+|-------|----------|----------|
+| GPT-4o | OpenAI | General tasks, vision |
+| Claude 3.5 | Anthropic | Analysis, coding |
+| Gemini 1.5 | Google | Long documents |
+| Llama 3.1 | Meta | Open source, privacy |
+
+---
+
+## Part XIII: Tools - System Utilities
+
+### Compliance Scanner
+
+Check your bot dialogs for security issues:
+
+```
+┌─────────────────────────────────────────────────────────────────┐
+│ 🛡 Compliance Scanner [Scan] [Export] │
+├─────────────────────────────────────────────────────────────────┤
+│ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ │
+│ │ 2 │ │ 5 │ │ 3 │ │ 1 │ │ 0 │ │
+│ │🔴Crit│ │🟠High│ │🟡Med │ │🟢Low │ │ℹInfo│ │
+│ └──────┘ └──────┘ └──────┘ └──────┘ └──────┘ │
+├─────────────────────────────────────────────────────────────────┤
+│ Severity │ Issue │ File │ Action │
+│ ───────────────────────────────────────────────────────────── │
+│ 🔴 Critical│ Hardcoded password │ start.bas:15 │ [Fix] │
+│ 🔴 Critical│ API key exposed │ api.bas:42 │ [Fix] │
+│ 🟠 High │ SQL injection risk │ data.bas:28 │ [Review] │
+└─────────────────────────────────────────────────────────────────┘
+```
+
+**What It Checks:**
+- Hardcoded passwords
+- Exposed API keys
+- SQL injection risks
+- Deprecated keywords
+- Security best practices
+
+---
+
+## Part XIV: Settings
+
+### Accessing Settings
+
+1. Click your **avatar** (top right)
+2. Select **Settings**
+
+### Setting Categories
+
+**Profile:**
+- Display name
+- Avatar image
+- Email address
+- Language preference
+
+**Notifications:**
+- Email notifications
+- Desktop alerts
+- Sound preferences
+
+**Appearance:**
+- Theme (Light/Dark/Auto)
+- Accent color
+- Font size
+
+**Privacy:**
+- Data retention
+- Conversation history
+- Usage analytics
+
+**Connections:**
+- Email accounts
+- Calendar sync
+- Cloud storage
+
+---
+
+## Part XV: Keyboard Shortcuts Reference
+
+### Global Shortcuts
+
+| Shortcut | Action |
+|----------|--------|
+| `Alt+1` | Open Chat |
+| `Alt+2` | Open Drive |
+| `Alt+3` | Open Tasks |
+| `Alt+4` | Open Mail |
+| `Alt+5` | Open Calendar |
+| `Escape` | Close dialog/menu |
+| `/` | Focus search |
+| `Ctrl+K` | Command palette |
+
+### Common Shortcuts
+
+| Shortcut | Action |
+|----------|--------|
+| `Ctrl+S` | Save |
+| `Ctrl+Z` | Undo |
+| `Ctrl+Y` | Redo |
+| `Ctrl+C` | Copy |
+| `Ctrl+V` | Paste |
+| `Ctrl+A` | Select all |
+| `Ctrl+F` | Find |
+
+---
+
+## Part XVI: Tips & Best Practices
+
+### Daily Workflow
+
+**Morning:**
+1. Open Suite
+2. Check Chat for overnight messages
+3. Review Tasks for the day
+4. Check Calendar for meetings
+
+**During Work:**
+- Use Chat for quick questions
+- Upload files to Drive
+- Update Tasks as you complete them
+- Take notes in Paper
+
+**End of Day:**
+- Mark completed tasks done
+- Archive old emails
+- Review tomorrow's calendar
+
+### Productivity Tips
+
+**In Chat:**
+- Be specific in your questions
+- Use follow-up questions
+- Say "summarize" for long responses
+
+**In Drive:**
+- Use folders to organize
+- Star important files
+- Use search instead of browsing
+
+**In Tasks:**
+- Break big tasks into smaller ones
+- Set realistic due dates
+- Use categories to organize
+
+**In Mail:**
+- Process emails once
+- Archive instead of delete
+- Use AI for drafting
+
+### Getting Help
+
+**Ask the Bot:**
+```
+You: How do I upload a file?
+You: What keyboard shortcuts are there?
+You: Help me with tasks
+```
+
+**Resources:**
+- This manual
+- In-app help (click ?)
+- Support team
+
+---
+
+## Appendix A: Troubleshooting
+
+### Common Issues
+
+**Suite won't load:**
+- Refresh the page (`F5` or `Ctrl+R`)
+- Clear browser cache
+- Try a different browser
+
+**Files won't upload:**
+- Check file size (max 100MB)
+- Check internet connection
+- Try a smaller file first
+
+**Bot not responding:**
+- Wait a few seconds
+- Refresh the page
+- Check internet connection
+
+**Video/audio not working:**
+- Allow camera/microphone in browser
+- Check device permissions
+- Try different browser
+
+### Error Messages
+
+| Message | Solution |
+|---------|----------|
+| "Connection lost" | Check internet, refresh page |
+| "File too large" | Reduce file size |
+| "Permission denied" | Contact administrator |
+| "Session expired" | Log in again |
+
+---
+
+## Appendix B: Glossary
+
+| Term | Definition |
+|------|------------|
+| **Bot** | AI assistant that responds to your messages |
+| **Dialog** | A conversation flow or script |
+| **HTMX** | Technology that makes pages interactive |
+| **KB** | Knowledge Base - stored information |
+| **MCP** | Model Context Protocol - tool connections |
+| **Suite** | The complete workspace application |
+| **Template** | Pre-built bot configuration |
+
+---
+
+## Appendix C: Version History
+
+| Version | Date | Changes |
+|---------|------|---------|
+| 1.0 | March 2024 | Initial release with Chat, Drive, Tasks, Mail |
+| 1.1 | April 2024 | Added Meet, Paper, Research |
+| 1.2 | May 2024 | Added Designer, Sources, Compliance |
+
+---
+
+*© General Bots - Built with ❤️ and AI*
+
+*For the latest documentation, visit the [online manual](../chapter-04-gbui/README.md)*
\ No newline at end of file
diff --git a/ui/suite/designer.html b/ui/suite/designer.html
index fccb7a9c5..90ec4212c 100644
--- a/ui/suite/designer.html
+++ b/ui/suite/designer.html
@@ -1462,4 +1462,670 @@
// Zoom with scroll
container.addEventListener('wheel', (e) => {
e.preventDefault();
- const delta = e.deltaY >
+ const delta = e.deltaY > 0 ? -0.1 : 0.1;
+ const newZoom = Math.min(Math.max(state.zoom + delta, 0.25), 2);
+ state.zoom = newZoom;
+ updateCanvasTransform();
+ updateZoomDisplay();
+ });
+ }
+
+ function updateCanvasTransform() {
+ const inner = document.getElementById('canvas-inner');
+ inner.style.transform = `translate(${state.pan.x}px, ${state.pan.y}px) scale(${state.zoom})`;
+ }
+
+ function updateZoomDisplay() {
+ document.getElementById('zoom-value').textContent = Math.round(state.zoom * 100) + '%';
+ }
+
+ // Grid snapping
+ function snapToGrid(value, gridSize = 20) {
+ return Math.round(value / gridSize) * gridSize;
+ }
+
+ // Create Node
+ function createNode(type, x, y) {
+ const template = nodeTemplates[type];
+ if (!template) return;
+
+ const id = 'node-' + state.nextNodeId++;
+ const node = {
+ id,
+ type,
+ x,
+ y,
+ fields: {}
+ };
+
+ // Initialize field values
+ template.fields.forEach(field => {
+ node.fields[field.name] = field.default;
+ });
+
+ state.nodes.set(id, node);
+ renderNode(node);
+ saveToHistory();
+ updateStatusBar();
+ }
+
+ // Render Node
+ function renderNode(node) {
+ const template = nodeTemplates[node.type];
+ const typeClass = node.type.toLowerCase().replace(/\s+/g, '-');
+
+ let fieldsHtml = '';
+ template.fields.forEach(field => {
+ const value = node.fields[field.name] || '';
+ if (field.type === 'textarea') {
+ fieldsHtml += `
+
+ ${field.label}
+
+
+ `;
+ } else if (field.type === 'select') {
+ const options = field.options.map(opt =>
+ `${opt} `
+ ).join('');
+ fieldsHtml += `
+
+ ${field.label}
+ ${options}
+
+ `;
+ } else {
+ fieldsHtml += `
+
+ ${field.label}
+
+
+ `;
+ }
+ });
+
+ let portsHtml = '';
+ if (template.hasInput) {
+ portsHtml += `
`;
+ }
+ if (template.hasOutput) {
+ portsHtml += `
`;
+ }
+ if (template.hasOutputTrue) {
+ portsHtml += `
`;
+ }
+ if (template.hasOutputFalse) {
+ portsHtml += `
`;
+ }
+
+ const nodeEl = document.createElement('div');
+ nodeEl.className = 'node';
+ nodeEl.id = node.id;
+ nodeEl.style.left = node.x + 'px';
+ nodeEl.style.top = node.y + 'px';
+ nodeEl.innerHTML = `
+
+
+ ${fieldsHtml}
+
+ ${portsHtml}
+ `;
+
+ // Make draggable
+ nodeEl.addEventListener('mousedown', (e) => {
+ if (e.target.classList.contains('node-port')) return;
+ selectNode(node.id);
+ startNodeDrag(e, node);
+ });
+
+ // Field change handlers
+ nodeEl.querySelectorAll('.node-field-input, .node-field-select').forEach(input => {
+ input.addEventListener('change', (e) => {
+ node.fields[e.target.dataset.field] = e.target.value;
+ saveToHistory();
+ });
+ });
+
+ // Port handlers for connections
+ nodeEl.querySelectorAll('.node-port').forEach(port => {
+ port.addEventListener('mousedown', (e) => {
+ e.stopPropagation();
+ startConnection(node.id, port.dataset.port);
+ });
+ port.addEventListener('mouseup', (e) => {
+ e.stopPropagation();
+ endConnection(node.id, port.dataset.port);
+ });
+ });
+
+ document.getElementById('canvas-inner').appendChild(nodeEl);
+ }
+
+ function getNodeIcon(type) {
+ const icons = {
+ 'TALK': ' ',
+ 'HEAR': ' ',
+ 'SET': ' ',
+ 'IF': ' ',
+ 'FOR': ' ',
+ 'SWITCH': ' ',
+ 'CALL': ' ',
+ 'SEND MAIL': ' ',
+ 'GET': ' ',
+ 'POST': ' ',
+ 'SAVE': ' ',
+ 'WAIT': ' ',
+ 'SET BOT MEMORY': ' ',
+ 'GET BOT MEMORY': ' ',
+ 'SET USER MEMORY': ' ',
+ 'GET USER MEMORY': ' '
+ };
+ return icons[type] || ' ';
+ }
+
+ // Node dragging
+ function startNodeDrag(e, node) {
+ state.isDragging = true;
+ const nodeEl = document.getElementById(node.id);
+ const startX = e.clientX;
+ const startY = e.clientY;
+ const origX = node.x;
+ const origY = node.y;
+
+ function onMove(e) {
+ const dx = (e.clientX - startX) / state.zoom;
+ const dy = (e.clientY - startY) / state.zoom;
+ node.x = snapToGrid(origX + dx);
+ node.y = snapToGrid(origY + dy);
+ nodeEl.style.left = node.x + 'px';
+ nodeEl.style.top = node.y + 'px';
+ updateConnections();
+ }
+
+ function onUp() {
+ state.isDragging = false;
+ document.removeEventListener('mousemove', onMove);
+ document.removeEventListener('mouseup', onUp);
+ saveToHistory();
+ }
+
+ document.addEventListener('mousemove', onMove);
+ document.addEventListener('mouseup', onUp);
+ }
+
+ // Node selection
+ function selectNode(id) {
+ if (state.selectedNode) {
+ const prevEl = document.getElementById(state.selectedNode);
+ if (prevEl) prevEl.classList.remove('selected');
+ }
+ state.selectedNode = id;
+ const nodeEl = document.getElementById(id);
+ if (nodeEl) nodeEl.classList.add('selected');
+ updatePropertiesPanel();
+ }
+
+ function deselectAll() {
+ if (state.selectedNode) {
+ const el = document.getElementById(state.selectedNode);
+ if (el) el.classList.remove('selected');
+ }
+ state.selectedNode = null;
+ state.selectedConnection = null;
+ updatePropertiesPanel();
+ }
+
+ // Connections
+ function startConnection(nodeId, portType) {
+ state.isConnecting = true;
+ state.connectionStart = { nodeId, portType };
+ }
+
+ function endConnection(nodeId, portType) {
+ if (!state.isConnecting || !state.connectionStart) return;
+ if (state.connectionStart.nodeId === nodeId) {
+ state.isConnecting = false;
+ state.connectionStart = null;
+ return;
+ }
+
+ // Only allow output to input connections
+ if (state.connectionStart.portType === 'input' || portType !== 'input') {
+ state.isConnecting = false;
+ state.connectionStart = null;
+ return;
+ }
+
+ const connection = {
+ from: state.connectionStart.nodeId,
+ fromPort: state.connectionStart.portType,
+ to: nodeId,
+ toPort: portType
+ };
+
+ state.connections.push(connection);
+ state.isConnecting = false;
+ state.connectionStart = null;
+ updateConnections();
+ saveToHistory();
+ }
+
+ function updateConnections() {
+ const svg = document.getElementById('connections-svg');
+ let paths = '';
+
+ state.connections.forEach((conn, index) => {
+ const fromEl = document.getElementById(conn.from);
+ const toEl = document.getElementById(conn.to);
+ if (!fromEl || !toEl) return;
+
+ const fromPort = fromEl.querySelector(`[data-port="${conn.fromPort}"]`);
+ const toPort = toEl.querySelector(`[data-port="${conn.toPort}"]`);
+ if (!fromPort || !toPort) return;
+
+ const fromRect = fromPort.getBoundingClientRect();
+ const toRect = toPort.getBoundingClientRect();
+ const canvasRect = document.getElementById('canvas-inner').getBoundingClientRect();
+
+ const x1 = (fromRect.left + fromRect.width / 2 - canvasRect.left) / state.zoom;
+ const y1 = (fromRect.top + fromRect.height / 2 - canvasRect.top) / state.zoom;
+ const x2 = (toRect.left + toRect.width / 2 - canvasRect.left) / state.zoom;
+ const y2 = (toRect.top + toRect.height / 2 - canvasRect.top) / state.zoom;
+
+ const midX = (x1 + x2) / 2;
+ const d = `M ${x1} ${y1} C ${midX} ${y1}, ${midX} ${y2}, ${x2} ${y2}`;
+
+ paths += ` `;
+ });
+
+ svg.innerHTML = `
+
+
+
+
+
+ ${paths}
+ `;
+ }
+
+ // Properties Panel
+ function updatePropertiesPanel() {
+ const content = document.getElementById('properties-content');
+ const empty = document.getElementById('properties-empty');
+
+ if (!state.selectedNode) {
+ content.style.display = 'none';
+ empty.style.display = 'block';
+ return;
+ }
+
+ const node = state.nodes.get(state.selectedNode);
+ if (!node) return;
+
+ const template = nodeTemplates[node.type];
+ empty.style.display = 'none';
+ content.style.display = 'block';
+
+ let html = `
+
+
Node Info
+
+ Type
+
+
+
+ ID
+
+
+
+
+
Properties
+ `;
+
+ template.fields.forEach(field => {
+ const value = node.fields[field.name] || '';
+ if (field.type === 'textarea') {
+ html += `
+
+ ${field.label}
+
+
+ `;
+ } else {
+ html += `
+
+ ${field.label}
+
+
+ `;
+ }
+ });
+
+ html += '
';
+ content.innerHTML = html;
+
+ // Add change handlers
+ content.querySelectorAll('.property-input:not([readonly]), .property-textarea').forEach(input => {
+ input.addEventListener('change', (e) => {
+ const n = state.nodes.get(e.target.dataset.node);
+ if (n) {
+ n.fields[e.target.dataset.field] = e.target.value;
+ // Update node view
+ const nodeInput = document.querySelector(`#${n.id} [data-field="${e.target.dataset.field}"]`);
+ if (nodeInput) nodeInput.value = e.target.value;
+ saveToHistory();
+ }
+ });
+ });
+ }
+
+ // History (Undo/Redo)
+ function saveToHistory() {
+ const snapshot = {
+ nodes: Array.from(state.nodes.entries()).map(([id, node]) => ({...node})),
+ connections: [...state.connections]
+ };
+ state.history = state.history.slice(0, state.historyIndex + 1);
+ state.history.push(snapshot);
+ state.historyIndex = state.history.length - 1;
+ }
+
+ function undo() {
+ if (state.historyIndex > 0) {
+ state.historyIndex--;
+ restoreSnapshot(state.history[state.historyIndex]);
+ }
+ }
+
+ function redo() {
+ if (state.historyIndex < state.history.length - 1) {
+ state.historyIndex++;
+ restoreSnapshot(state.history[state.historyIndex]);
+ }
+ }
+
+ function restoreSnapshot(snapshot) {
+ // Clear canvas
+ document.getElementById('canvas-inner').innerHTML = '';
+ state.nodes.clear();
+ state.connections = [];
+
+ // Restore nodes
+ snapshot.nodes.forEach(node => {
+ state.nodes.set(node.id, {...node});
+ renderNode(node);
+ });
+
+ // Restore connections
+ state.connections = [...snapshot.connections];
+ updateConnections();
+ updateStatusBar();
+ }
+
+ // Keyboard Shortcuts
+ function initKeyboardShortcuts() {
+ document.addEventListener('keydown', (e) => {
+ if (e.ctrlKey || e.metaKey) {
+ switch (e.key) {
+ case 's':
+ e.preventDefault();
+ saveDesign();
+ break;
+ case 'o':
+ e.preventDefault();
+ showModal('open-modal');
+ break;
+ case 'z':
+ e.preventDefault();
+ if (e.shiftKey) redo();
+ else undo();
+ break;
+ case 'y':
+ e.preventDefault();
+ redo();
+ break;
+ case 'c':
+ if (state.selectedNode) {
+ e.preventDefault();
+ state.clipboard = {...state.nodes.get(state.selectedNode)};
+ }
+ break;
+ case 'v':
+ if (state.clipboard) {
+ e.preventDefault();
+ const newNode = {...state.clipboard};
+ newNode.id = 'node-' + state.nextNodeId++;
+ newNode.x += 40;
+ newNode.y += 40;
+ state.nodes.set(newNode.id, newNode);
+ renderNode(newNode);
+ selectNode(newNode.id);
+ saveToHistory();
+ }
+ break;
+ }
+ }
+
+ if (e.key === 'Delete' && state.selectedNode) {
+ deleteSelectedNode();
+ }
+
+ if (e.key === 'Escape') {
+ deselectAll();
+ hideContextMenu();
+ }
+ });
+ }
+
+ function deleteSelectedNode() {
+ if (!state.selectedNode) return;
+ const nodeEl = document.getElementById(state.selectedNode);
+ if (nodeEl) nodeEl.remove();
+
+ // Remove connections
+ state.connections = state.connections.filter(
+ conn => conn.from !== state.selectedNode && conn.to !== state.selectedNode
+ );
+
+ state.nodes.delete(state.selectedNode);
+ state.selectedNode = null;
+ updateConnections();
+ updatePropertiesPanel();
+ updateStatusBar();
+ saveToHistory();
+ }
+
+ // Context Menu
+ function initContextMenu() {
+ const canvas = document.getElementById('canvas');
+ const contextMenu = document.getElementById('context-menu');
+
+ canvas.addEventListener('contextmenu', (e) => {
+ e.preventDefault();
+ const nodeEl = e.target.closest('.node');
+ if (nodeEl) {
+ selectNode(nodeEl.id);
+ }
+ contextMenu.style.left = e.clientX + 'px';
+ contextMenu.style.top = e.clientY + 'px';
+ contextMenu.classList.add('visible');
+ });
+
+ document.addEventListener('click', () => {
+ hideContextMenu();
+ });
+ }
+
+ function hideContextMenu() {
+ document.getElementById('context-menu').classList.remove('visible');
+ }
+
+ // Context Menu Actions
+ function duplicateNode() {
+ if (!state.selectedNode) return;
+ const node = state.nodes.get(state.selectedNode);
+ if (!node) return;
+
+ const newNode = {...node, fields: {...node.fields}};
+ newNode.id = 'node-' + state.nextNodeId++;
+ newNode.x += 40;
+ newNode.y += 40;
+ state.nodes.set(newNode.id, newNode);
+ renderNode(newNode);
+ selectNode(newNode.id);
+ saveToHistory();
+ hideContextMenu();
+ }
+
+ // Status Bar
+ function updateStatusBar() {
+ document.getElementById('node-count').textContent = state.nodes.size + ' nodes';
+ document.getElementById('connection-count').textContent = state.connections.length + ' connections';
+ }
+
+ // Zoom Controls
+ function zoomIn() {
+ state.zoom = Math.min(state.zoom + 0.1, 2);
+ updateCanvasTransform();
+ updateZoomDisplay();
+ }
+
+ function zoomOut() {
+ state.zoom = Math.max(state.zoom - 0.1, 0.25);
+ updateCanvasTransform();
+ updateZoomDisplay();
+ }
+
+ // Modal Management
+ function showModal(id) {
+ document.getElementById(id).classList.add('visible');
+ if (id === 'open-modal') {
+ htmx.trigger('#file-list-content', 'load');
+ }
+ }
+
+ function hideModal(id) {
+ document.getElementById(id).classList.remove('visible');
+ }
+
+ // Save Design
+ function saveDesign() {
+ const nodesData = Array.from(state.nodes.values());
+ document.getElementById('nodes-data').value = JSON.stringify(nodesData);
+ document.getElementById('connections-data').value = JSON.stringify(state.connections);
+
+ // Trigger HTMX save
+ htmx.ajax('POST', '/api/v1/designer/save', {
+ source: document.getElementById('designer-data'),
+ target: '#status-message'
+ });
+ }
+
+ // Export to .bas
+ function exportToBas() {
+ let basCode = "' Generated by General Bots Designer\n";
+ basCode += "' " + new Date().toISOString() + "\n\n";
+
+ // Sort nodes by position (top to bottom, left to right)
+ const sortedNodes = Array.from(state.nodes.values()).sort((a, b) => {
+ if (Math.abs(a.y - b.y) < 30) return a.x - b.x;
+ return a.y - b.y;
+ });
+
+ sortedNodes.forEach(node => {
+ const template = nodeTemplates[node.type];
+ switch (node.type) {
+ case 'TALK':
+ basCode += `TALK "${node.fields.message}"\n`;
+ break;
+ case 'HEAR':
+ basCode += `HEAR ${node.fields.variable} AS ${node.fields.type}\n`;
+ break;
+ case 'SET':
+ basCode += `SET ${node.fields.variable} = ${node.fields.expression}\n`;
+ break;
+ case 'IF':
+ basCode += `IF ${node.fields.condition} THEN\n`;
+ break;
+ case 'FOR':
+ basCode += `FOR EACH ${node.fields.variable} IN ${node.fields.collection}\n`;
+ break;
+ case 'CALL':
+ basCode += `CALL ${node.fields.procedure}(${node.fields.arguments})\n`;
+ break;
+ case 'SEND MAIL':
+ basCode += `SEND MAIL TO "${node.fields.to}" SUBJECT "${node.fields.subject}" BODY "${node.fields.body}"\n`;
+ break;
+ case 'GET':
+ basCode += `GET ${node.fields.url} TO ${node.fields.variable}\n`;
+ break;
+ case 'POST':
+ basCode += `POST ${node.fields.url} WITH ${node.fields.body} TO ${node.fields.variable}\n`;
+ break;
+ case 'SAVE':
+ basCode += `SAVE ${node.fields.data} TO "${node.fields.filename}"\n`;
+ break;
+ case 'WAIT':
+ basCode += `WAIT ${node.fields.duration}\n`;
+ break;
+ case 'SET BOT MEMORY':
+ basCode += `SET BOT MEMORY "${node.fields.key}", ${node.fields.value}\n`;
+ break;
+ case 'GET BOT MEMORY':
+ basCode += `GET BOT MEMORY "${node.fields.key}" AS ${node.fields.variable}\n`;
+ break;
+ case 'SET USER MEMORY':
+ basCode += `SET USER MEMORY "${node.fields.key}", ${node.fields.value}\n`;
+ break;
+ case 'GET USER MEMORY':
+ basCode += `GET USER MEMORY "${node.fields.key}" AS ${node.fields.variable}\n`;
+ break;
+ }
+ });
+
+ // Download as file
+ const blob = new Blob([basCode], { type: 'text/plain' });
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = (document.getElementById('current-filename').value || 'dialog') + '.bas';
+ a.click();
+ URL.revokeObjectURL(url);
+ }
+
+ // New Design
+ function newDesign() {
+ if (state.nodes.size > 0) {
+ if (!confirm('Clear current design? Unsaved changes will be lost.')) return;
+ }
+ document.getElementById('canvas-inner').innerHTML = '';
+ state.nodes.clear();
+ state.connections = [];
+ state.selectedNode = null;
+ state.history = [];
+ state.historyIndex = -1;
+ state.nextNodeId = 1;
+ document.getElementById('current-filename').value = '';
+ document.getElementById('file-name').textContent = 'Untitled';
+ updateConnections();
+ updatePropertiesPanel();
+ updateStatusBar();
+ }
+
+ // File selection in open modal
+ document.addEventListener('click', (e) => {
+ const fileItem = e.target.closest('.file-item');
+ if (fileItem) {
+ document.querySelectorAll('.file-item').forEach(f => f.classList.remove('selected'));
+ fileItem.classList.add('selected');
+ document.getElementById('selected-file').value = fileItem.dataset.path;
+ }
+ });
+
+