# Dangerous Pi - Visualization & Guided Workflows Plan

**Status**: 🎯 In Planning
**Priority**: High (Post-MVP Phase 1)
**Target Timeline**: 4-6 weeks implementation
**Last Updated**: 2025-11-26

---

## Executive Summary

Dangerous Pi will implement data visualization and guided workflows using **Victory Charts**, a cross-platform charting library that works seamlessly across Web (Remix), React Native (mobile), and Electron (desktop) applications.

### Key Decisions

- **Charting Library**: Victory (cross-platform, mobile-first)
- **Bundle Impact**: ~50KB (acceptable via code splitting)
- **Primary Target**: Mobile/smartphone users (📱 80% of usage)
- **Architecture**: Shared components across all platforms

---

## 1. Why Victory Charts?

### Cross-Platform Requirements

| Platform | Framework | Victory Package | Rendering |
|----------|-----------|-----------------|-----------|
| **Web** | Remix.js + React | `victory` | SVG/Canvas |
| **Mobile** | React Native | `victory-native` | Native |
| **Desktop** | Electron + React | `victory` | SVG/Canvas |

**Code Reuse**: ~90% of chart components shared across platforms

### Comparison with Alternatives

| Feature | Victory | Chart.js | Recharts | Nivo |
|---------|---------|----------|----------|------|
| React Native Support | ✅ Native | ❌ None | ⚠️ Wrapper | ❌ None |
| Touch Gestures | ✅ Built-in | ⚠️ Limited | ⚠️ Limited | ✅ Good |
| Bundle Size | 50KB | 30KB | 45KB | 120KB |
| Mobile-First | ✅ Yes | ❌ No | ❌ No | ✅ Yes |
| **Score** | **9/10** | 5/10 | 6/10 | 6/10 |

**Winner**: Victory (only library with true cross-platform support)

---

## 2. Architecture Overview

### Data Flow

```
Proxmark3 Hardware
    ↓ USB
Pi Zero 2 W Backend (Python)
    ↓ Execute PM3 command
PM3 Python Module (SWIG)
    ↓ Text output
Parser Layer (NEW)
    ↓ Structured JSON
FastAPI Endpoint (Enhanced)
    ↓ REST/SSE
Frontend (Remix/React)
    ↓ Victory Charts
User (Mobile/Desktop)
```

### New Backend Components

#### Parser Module (`app/backend/parsers/pm3_output.py`)

```python
"""
Convert PM3 text output into structured data for visualization.
"""

def parse_antenna_tuning(output: str) -> dict:
    """
    Parse hw tune / hf tune / lf tune output.

    Input: "# LF antenna: 50.00 V @ 125.00 kHz"
    Output: {
        "frequency": 125.0,
        "voltage": 50.0,
        "type": "lf",
        "optimal": voltage > 45.0
    }
    """

def parse_waveform_data(output: str) -> dict:
    """
    Parse data samples command output.

    Output: {
        "samples": [1, 2, 3, ...],
        "sample_rate": 48000,
        "total_samples": 10000
    }
    """

def parse_protocol_trace(output: str) -> dict:
    """
    Parse hf list / lf list output into timeline.

    Output: {
        "frames": [
            {
                "timestamp": 1234,
                "direction": "tag_to_reader",
                "data": "0x01 0x02",
                "crc": "ok"
            },
            ...
        ]
    }
    """

def parse_tag_detection(output: str) -> dict:
    """
    Parse hf search / lf search results.

    Output: {
        "found": true,
        "tag_type": "MIFARE Classic 1K",
        "uid": "01234567",
        "signal_strength": "good"
    }
    """
```

#### Enhanced API Response

```python
# app/backend/api/pm3.py

class CommandWithDataResponse(BaseModel):
    """Enhanced response with visualization data."""
    success: bool
    output: str  # Original text (backwards compatible)
    data: Optional[Dict] = None  # Structured data for charts
    visualization_type: Optional[str] = None  # Chart type hint
    # visualization_type values: "waveform", "tune", "trace", "summary"

@router.post("/command-with-data", response_model=CommandWithDataResponse)
async def execute_command_with_visualization(request: CommandRequest):
    """Execute PM3 command and return structured data."""

    # Execute command
    result = await pm3_worker.execute_command(request.command)

    # Parse output based on command type
    data = None
    viz_type = None

    if request.command.startswith(('hw tune', 'hf tune', 'lf tune')):
        data = parse_antenna_tuning(result.output)
        viz_type = "tune"

    elif request.command.startswith('data'):
        data = parse_waveform_data(result.output)
        viz_type = "waveform"

    elif request.command.startswith(('hf list', 'lf list')):
        data = parse_protocol_trace(result.output)
        viz_type = "trace"

    elif request.command.startswith(('hf search', 'lf search')):
        data = parse_tag_detection(result.output)
        viz_type = "summary"

    return CommandWithDataResponse(
        success=result.success,
        output=result.output,
        data=data,
        visualization_type=viz_type
    )
```

### Frontend Components

#### Shared Chart Library (`app/shared/components/charts/`)

**Cross-platform components used by Web + React Native + Electron**

```typescript
// TuneChart.tsx
import { VictoryLine, VictoryChart, VictoryAxis, VictoryTheme } from 'victory'

interface TuneData {
  frequency: number
  voltage: number
  optimal?: boolean
}

export function TuneChart({
  data,
  title,
  thresholdVoltage = 40
}: {
  data: TuneData[],
  title: string,
  thresholdVoltage?: number
}) {
  return (
    <VictoryChart
      theme={VictoryTheme.material}
      height={300}
      padding={{ top: 40, bottom: 40, left: 60, right: 40 }}
    >
      <VictoryAxis
        label="Frequency (kHz)"
        style={{
          axisLabel: { fontSize: 14, padding: 30, fill: '#9ca3af' }
        }}
      />
      <VictoryAxis
        dependentAxis
        label="Voltage (V)"
        style={{
          axisLabel: { fontSize: 14, padding: 40, fill: '#9ca3af' }
        }}
      />

      {/* Threshold line */}
      <VictoryLine
        data={[
          { x: Math.min(...data.map(d => d.frequency)), y: thresholdVoltage },
          { x: Math.max(...data.map(d => d.frequency)), y: thresholdVoltage }
        ]}
        style={{
          data: { stroke: "#ffaa00", strokeWidth: 1, strokeDasharray: "4,4" }
        }}
      />

      {/* Actual data */}
      <VictoryLine
        data={data}
        x="frequency"
        y="voltage"
        style={{
          data: { stroke: "#00ffff", strokeWidth: 3 }
        }}
        animate={{
          duration: 500,
          onLoad: { duration: 500 }
        }}
      />
    </VictoryChart>
  )
}
```

```typescript
// WaveformChart.tsx
import { VictoryLine, VictoryChart, VictoryZoomContainer } from 'victory'

export function WaveformChart({ samples }: { samples: number[] }) {
  // Downsample if > 1000 points for performance
  const displaySamples = samples.length > 1000
    ? downsample(samples, 1000)
    : samples

  const data = displaySamples.map((value, index) => ({ x: index, y: value }))

  return (
    <VictoryChart
      height={400}
      containerComponent={
        <VictoryZoomContainer
          zoomDimension="x"
          allowPan={true}
          allowZoom={true}
          minimumZoom={{ x: 1 }}
        />
      }
    >
      <VictoryLine
        data={data}
        style={{
          data: { stroke: "#00ffff", strokeWidth: 2 }
        }}
      />
    </VictoryChart>
  )
}

function downsample(data: number[], targetSize: number): number[] {
  const step = Math.floor(data.length / targetSize)
  return data.filter((_, i) => i % step === 0)
}
```

---

## 3. Guided Workflows

### Framework Architecture

```typescript
// app/frontend/app/components/GuidedWorkflow.tsx

interface WorkflowStep {
  id: string
  title: string
  description: string
  component: React.ComponentType<StepProps>
  validation?: (data: any) => boolean
  helpText?: string
}

interface StepProps {
  data: Record<string, any>
  onUpdate: (data: Record<string, any>) => void
  onComplete: () => void
}

export function GuidedWorkflow({
  steps,
  onComplete
}: {
  steps: WorkflowStep[],
  onComplete: (data: any) => void
}) {
  const [currentStep, setCurrentStep] = useState(0)
  const [stepData, setStepData] = useState<Record<string, any>>({})

  const canProceed = () => {
    const step = steps[currentStep]
    return !step.validation || step.validation(stepData)
  }

  const CurrentStepComponent = steps[currentStep].component

  return (
    <div className="workflow-container">
      {/* Progress bar */}
      <div className="progress-steps">
        {steps.map((step, i) => (
          <div
            key={step.id}
            className={`step ${i === currentStep ? 'active' : ''} ${i < currentStep ? 'completed' : ''}`}
          >
            {i < currentStep ? '✓' : i + 1} {step.title}
          </div>
        ))}
      </div>

      {/* Current step */}
      <div className="step-content">
        <h2>{steps[currentStep].title}</h2>
        <p>{steps[currentStep].description}</p>

        <CurrentStepComponent
          data={stepData}
          onUpdate={(data) => setStepData({ ...stepData, ...data })}
          onComplete={() => {
            if (currentStep < steps.length - 1) {
              setCurrentStep(currentStep + 1)
            } else {
              onComplete(stepData)
            }
          }}
        />

        {steps[currentStep].helpText && (
          <div className="help-text">{steps[currentStep].helpText}</div>
        )}
      </div>

      {/* Navigation */}
      <div className="step-navigation">
        {currentStep > 0 && (
          <button onClick={() => setCurrentStep(currentStep - 1)}>
            ← Back
          </button>
        )}
        <button
          onClick={() => {
            if (currentStep < steps.length - 1) {
              setCurrentStep(currentStep + 1)
            } else {
              onComplete(stepData)
            }
          }}
          disabled={!canProceed()}
        >
          {currentStep < steps.length - 1 ? 'Next →' : 'Finish'}
        </button>
      </div>
    </div>
  )
}
```

### Priority Workflows to Implement

#### 1. HF/LF/HW Tune (Week 1-2)

**Steps**:
1. Select frequency type (HF/LF/HW)
2. Run tuning command
3. Display real-time chart
4. Show optimal/warning indicators

**Files**:
- `app/frontend/app/routes/workflows/tune.tsx`
- `app/shared/components/charts/TuneChart.tsx`

#### 2. ID Transponder (Week 2-3)

**Steps**:
1. Select frequency (HF/LF)
2. Place tag on antenna
3. Run detection command
4. Display tag information card

**Files**:
- `app/frontend/app/routes/workflows/id-tag.tsx`
- Component: Tag info card with icon

#### 3. Clone MIFARE Classic 1K (Week 3-4)

**Steps**:
1. Tune HF antenna
2. Read source card (64 blocks)
3. Verify read success
4. Write to target card
5. Verify write success

**Files**:
- `app/frontend/app/routes/workflows/clone-mifare.tsx`
- Progress tracking component

#### 4. Clone to T5577 (Week 4-5)

**Steps**:
1. Tune LF antenna
2. Read source tag
3. Configure T5577 settings
4. Write to T5577
5. Verify clone

**Files**:
- `app/frontend/app/routes/workflows/clone-t5577.tsx`

#### 5. Sniffing Utility (Week 5-6)

**Steps**:
1. Configure sniffing parameters
2. Start capture
3. Real-time frame display
4. Stop capture
5. Analyze captured data

**Files**:
- `app/frontend/app/routes/workflows/sniff.tsx`
- `app/shared/components/charts/ProtocolTimeline.tsx`

---

## 4. Implementation Roadmap

### Phase 1: Foundation (Week 1)

**Backend**:
- [ ] Create `app/backend/parsers/pm3_output.py`
- [ ] Implement antenna tuning parser
- [ ] Add `/api/pm3/command-with-data` endpoint
- [ ] Write parser unit tests

**Frontend**:
- [ ] Install Victory: `npm install victory`
- [ ] Create `app/shared/components/charts/` directory
- [ ] Implement `TuneChart.tsx`
- [ ] Test with mock data

**Deliverable**: Working HF/LF tune visualization

### Phase 2: Guided Workflows (Week 2-3)

**Frontend**:
- [ ] Create `GuidedWorkflow.tsx` framework
- [ ] Implement HF/LF Tune workflow
- [ ] Implement ID Transponder workflow
- [ ] Add progress indicators
- [ ] Mobile touch optimization

**Deliverable**: Two working guided workflows

### Phase 3: Advanced Workflows (Week 3-4)

**Backend**:
- [ ] Implement waveform parser
- [ ] Implement trace parser
- [ ] Add streaming support for sniffing

**Frontend**:
- [ ] Clone MIFARE Classic workflow
- [ ] Clone T5577 workflow
- [ ] `WaveformChart.tsx` with pan/zoom
- [ ] Progress tracking components

**Deliverable**: Complete cloning workflows

### Phase 4: Sniffing & Polish (Week 5-6)

**Frontend**:
- [ ] Sniffing utility implementation
- [ ] `ProtocolTimeline.tsx` chart
- [ ] Real-time data streaming
- [ ] Export capabilities (CSV/JSON)

**Polish**:
- [ ] Performance optimization
- [ ] Code splitting setup
- [ ] Mobile gesture improvements
- [ ] Accessibility improvements

**Deliverable**: Production-ready visualization system

---

## 5. Bundle Size Management

### Code Splitting Strategy

```typescript
// Lazy load charts only when needed
import { lazy, Suspense } from 'react'

const TuneChart = lazy(() => import('~/shared/components/charts/TuneChart'))

function TunePage() {
  return (
    <Suspense fallback={<div>Loading chart...</div>}>
      <TuneChart data={data} />
    </Suspense>
  )
}
```

### Bundle Impact Analysis

| Component | Size (gzipped) | When Loaded |
|-----------|----------------|-------------|
| Base App | ~120KB | Initial |
| Victory Core | +35KB | On-demand |
| TuneChart | +5KB | Workflow page |
| WaveformChart | +8KB | Workflow page |
| **Total (worst case)** | **~170KB** | ✅ Acceptable |

**Optimization**: Most users won't load all charts in one session.

---

## 6. Cross-Platform Strategy

### React Native App (Future)

```typescript
// Same component, different import!
// Web version (Remix)
import { VictoryLine } from 'victory'

// React Native version
import { VictoryLine } from 'victory-native'

// Component code is IDENTICAL
export function TuneChart({ data }) {
  return (
    <VictoryChart>
      <VictoryLine data={data} />
    </VictoryChart>
  )
}
```

### BLE Integration for Mobile

Enhanced BLE Manager will support:
- Command execution via BLE (offline PM3 operations)
- Status queries via BLE
- Guided workflow triggers via BLE
- Real-time data streaming via BLE

**Use Case**: User operates PM3 with phone via BLE, no WiFi needed.

---

## 7. Testing Strategy

### Backend Parser Tests

```python
# test_pm3_parsers.py

def test_parse_antenna_tuning():
    output = "# LF antenna: 50.00 V @ 125.00 kHz"
    result = parse_antenna_tuning(output)
    assert result["voltage"] == 50.0
    assert result["frequency"] == 125.0
    assert result["optimal"] == True  # > 45V threshold
```

### Frontend Chart Tests

```typescript
// Mock data testing (no hardware needed)
const mockTuneData = [
  { frequency: 120, voltage: 45 },
  { frequency: 125, voltage: 50 },
  { frequency: 130, voltage: 48 }
]

test('TuneChart renders with mock data', () => {
  render(<TuneChart data={mockTuneData} />)
  expect(screen.getByText(/Voltage/)).toBeInTheDocument()
})
```

### Mobile Touch Testing

- Test on actual smartphone (iPhone/Android)
- Verify pinch-zoom works smoothly
- Check 44px touch target compliance
- Test landscape orientation

---

## 8. Dependencies

### NPM Packages

```json
{
  "dependencies": {
    "victory": "^37.0.0",           // ~35KB gzipped
    "victory-native": "^37.0.0"     // For React Native (later)
  }
}
```

### Python Packages

No new dependencies - use standard library for parsing.

---

## 9. Success Metrics

### Technical
- [ ] Bundle size stays under 200KB (gzipped)
- [ ] Charts render in < 200ms on mobile
- [ ] Touch gestures work smoothly (60fps)
- [ ] Parser accuracy > 95% for all PM3 commands

### UX
- [ ] Users complete workflows 80% faster than manual commands
- [ ] Mobile users can operate PM3 with one hand
- [ ] Reduce support requests by 50% (guided workflows)

---

## 10. Future Enhancements

### After Initial Implementation

1. **Waveform Annotations**
   - Mark interesting signal features
   - Save/load annotated captures

2. **Chart Exports**
   - Export as PNG/SVG
   - Export data as CSV/JSON
   - Share via mobile apps

3. **Advanced Analytics**
   - Signal quality metrics
   - Antenna tuning history tracking
   - Success rate statistics

4. **Offline Support**
   - Cache chart data locally
   - Service worker for offline workflows
   - Sync when reconnected

---

## Summary

**Victory Charts** provides the perfect foundation for Dangerous Pi's visualization needs:
- ✅ True cross-platform support (Web, Mobile, Desktop)
- ✅ Mobile-first with touch gestures built-in
- ✅ Shared components = faster development
- ✅ Acceptable bundle size with code splitting
- ✅ Perfect for guided workflow UX

**Next Step**: Begin Phase 1 implementation (Backend parsers + Victory setup)

**Questions?** See [UI_GUIDELINES.md](UI_GUIDELINES.md) for styling and [claude.md](claude.md) for architecture details.
