Initial commit - Phase 3/4

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
michael
2026-01-06 13:45:29 -08:00
parent 1da6730735
commit 4f35df1781
323 changed files with 98287 additions and 1195 deletions

701
VISUALIZATION_PLAN.md Normal file
View File

@@ -0,0 +1,701 @@
# 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.