# 🏭 GooseFactory HITL Modals

> Interactive MCP App modals for Human-in-the-Loop feedback collection.

## What's Here

5 production-ready, self-contained HTML modals designed for sandboxed iframes inside AI chat interfaces:

| Modal | File | Use Case | Key Feature |
|---|---|---|---|
| 🚦 **Traffic Light** | `src/traffic-light.html` | Pass/Polish/Rework decisions | LED glow, tag pills, response time tracking |
| 📋 **Report Card** | `src/report-card.html` | Multi-dimension grading (A-F) | Bubble-fill animation, GPA auto-calc, grade change tracking |
| ⚡ **Speed Round** | `src/speed-round.html` | Batch pass/fail (timed) | 60s timer, streak counter, skip detection, full stats |
| ⚔️ **Side-by-Side Arena** | `src/side-by-side.html` | A/B comparison | Hover time tracking, per-dimension breakdown, winner celebration |
| 🌡️ **Thermometer** | `src/thermometer.html` | Subjective quality (0-100) | Draggable mercury, bg color transitions, particles, drag journey capture |

## Quick Start

```bash
# Serve the preview page
npx serve src/preview -p 3333

# Or serve all files for direct access
npx serve src -p 3334
```

Then open `http://localhost:3333` for the interactive preview environment.

## Architecture

### Self-Contained
Each modal is a **single HTML file** with inline CSS and JS. No external dependencies. This is intentional — modals are served as MCP App resources inside sandboxed iframes.

### Communication Protocol
Every modal follows the `CONTRACTS.md` §3 "Modal Data Contract":

```
Host → Modal:  window.__FACTORY_CONTEXT__  (injected before load)
Modal → Host:  window.parent.postMessage()
```

#### Message Types

| Type | Direction | When |
|---|---|---|
| `factory_modal_ready` | Modal → Host | Modal loaded and interactive |
| `factory_modal_response` | Modal → Host | User submitted feedback |
| `factory_modal_close` | Modal → Host | Modal wants to close |
| `factory_modal_resize` | Modal → Host | Modal wants to change size |
| `factory_modal_error` | Modal → Host | Modal hit an error |

### Hidden Behavioral Metrics
Every modal automatically captures:
- `timeToFirstInteractionMs` — How long before user engaged
- `timeToDecisionMs` — Total time from open to submit
- `totalInteractions` — Click/tap count
- `fieldsModified` — Which inputs were changed
- `deviceType` — Mobile vs desktop
- `viewportSize` — Screen dimensions

Plus modal-specific metrics:
- **Traffic Light**: `responseTimeMs` (fast = high confidence)
- **Report Card**: `gradeChanges` (mind-change tracking)
- **Speed Round**: Per-item `timeMs`, streaks, speed curve
- **Side-by-Side**: `hoverTimeA/B` (attention distribution)
- **Thermometer**: `dragJourney` (full temperature path during drag)

## File Structure

```
packages/modals/
├── package.json
├── README.md                    ← You are here
├── src/
│   ├── traffic-light.html       ← 🚦 Pass/Polish/Rework
│   ├── report-card.html         ← 📋 A-F grading
│   ├── speed-round.html         ← ⚡ Timed batch review
│   ├── side-by-side.html        ← ⚔️ A/B comparison
│   ├── thermometer.html         ← 🌡️ Quality temperature
│   ├── shared/
│   │   └── modal-utils.js       ← Canonical utility functions
│   └── preview/
│       └── index.html           ← Dev preview page with mock context & console
```

## Design Principles

1. **3-Second Rule** — Instantly obvious what to do
2. **Dopamine Design** — Every interaction feels satisfying
3. **Data Density** — Rich signal from every tap/drag/click
4. **Dark Mode First** — `#111` background, designed for chat panels
5. **Touch-Friendly** — 48px minimum tap targets
6. **400-600px Width** — Optimized for chat panel constraints

## Integrating with GooseFactory

### MCP App Host Usage

```typescript
// In your MCP tool response:
const response = {
  _meta: {
    goose: {
      toolUI: {
        displayType: "inline",
        name: "Traffic Light Review",
        renderer: "mcp-ui",
      },
    },
  },
  content: [{
    uri: "ui://factory-modal",
    mimeType: "text/html",
    text: trafficLightHtml, // The full HTML file content
  }],
};
```

### McpAppHost Component

The host component (React/Desktop) should:
1. Create a sandboxed iframe with `allow-scripts allow-forms`
2. Inject `window.__FACTORY_CONTEXT__` before the modal HTML
3. Listen for `postMessage` events
4. Forward `factory_modal_response` to `POST /v1/feedback`
5. Handle timeouts gracefully

See `CONTRACTS.md` §4.4 for the full `McpAppHost` component contract.

## Preview Page

The preview page at `src/preview/index.html` provides:
- Sidebar with all 5 modals
- 500px-wide iframe with simulated device chrome
- Mock context data (editable pipeline/item names)
- Real-time `postMessage` console showing all events
- Reload and new-window buttons for testing

## Next Modals (Planned)

The design doc (`design-hitl-modal-collection.md`) defines 25 total modals. Next batch:
- 🃏 Tinder Swipe — Batch card swiping
- 🎯 Spotlight — Code annotation with attention heatmap
- 🏆 Judge's Scorecard — Olympic-style weighted scoring
- 🎲 Priority Poker — Fibonacci estimation cards
- 🔫 Mission Briefing — High-stakes go/no-go with flight checks
