WebSocket Protocol: cc-mcs ↔ EchelonCapture
Currently EchelonCapture **sends** sensor data to cc-mcs via HTTP POST. Now we need **bidirectional communication** so EchelonCapture can **receive** visualization data.
Full Public Reader
WebSocket Protocol: cc-mcs ↔ EchelonCapture
Overview
Currently EchelonCapture sends sensor data to cc-mcs via HTTP POST.
Now we need bidirectional communication so EchelonCapture can receive visualization data.
---
Architecture
EchelonCapture cc-mcs-headless
│ │
│─── POST /sensor_data ────────────→│ (existing)
│ (sensor frames) │
│ │
│ │ Compute:
│ │ • Sensor fusion
│ │ • LIM-RPS latent
│ │ • Trajectory prediction
│ │ • Section state
│ │
│←── WebSocket /visualization ──────│ (NEW)
│ (latent, trajectory, patterns) │
│ │---
WebSocket Endpoint
Connection
ws://[cc-mcs-url]/visualization?device_id=[left|right|watch]Query params:
- `device_id`: Which device this is (left, right, watch)
- Optional: `subscribe`: Comma-separated list of channels (latent,trajectory,pattern,audio)
### Authentication
None required for now (same network assumption as existing HTTP)
---
Message Format
All messages are JSON with a `type` field:
{
"type": "latent_state" | "trajectory" | "pattern" | "audio" | "section",
"timestamp": 1234567890.123,
"data": { ... }
}---
Message Types
1. `latent_state` - Real-time Latent Position
Sent at 50 Hz (matches sensor rate)
{
"type": "latent_state",
"timestamp": 1234567890.123,
"data": {
"position": [0.23, -0.45, 0.67], // 3D latent space position
"velocity": [0.01, -0.02, 0.03], // latent velocity vector
"equilibrium": 0.82, // LIM-RPS equilibrium metric (0-1)
"energy": 1.45, // motion energy
// Extracted embodied features
"tension": 0.34, // micro-tension (0-1)
"grounding": 0.78, // grounding metric (0-1)
"verticality": 0.65, // vertical vs horizontal motion
"rotation_drive": 0.23, // rotational acceleration
"micro_beat_drift": 0.12 // rhythmic micro-variation
}
}2. `trajectory` - Predicted Future States
Sent at 20 Hz (when trajectory updates)
{
"type": "trajectory",
"timestamp": 1234567890.123,
"data": {
"predicted_positions": [ // 46 frames @ 23fps = ~2 sec
[0.23, -0.45, 0.67],
[0.24, -0.44, 0.68],
// ... 44 more frames
],
"confidence": 0.87, // prediction confidence (0-1)
"curvature": 0.34, // trajectory curvature metric
"anticipated_inflection": true // whether an inflection point is predicted
}
}3. `pattern` - Pattern Coder Decisions
Sent when pattern changes (~1-4 times per second)
{
"type": "pattern",
"timestamp": 1234567890.123,
"data": {
"active_pattern": "buildup_023", // current active pattern ID
"pattern_phase": 0.34, // progress through pattern (0-1)
"pattern_energy": 0.67, // pattern energy level
// Next pattern candidates
"candidates": [
{
"pattern_id": "drop_012",
"probability": 0.45,
"reason": "high_energy_trajectory"
},
{
"pattern_id": "sustain_008",
"probability": 0.32,
"reason": "equilibrium_stable"
}
],
// Recent pattern edits
"recent_edits": [
{
"edit_type": "modulate_filter",
"target": "bass_synth",
"value": 0.78,
"reason": "tension_increase"
}
]
}
}4. `audio` - Audio State & Phrase Info
Sent at ~30 Hz during playback
{
"type": "audio",
"timestamp": 1234567890.123,
"data": {
"phrase_id": "phrase_gen_0234", // current phrase identifier
"phrase_type": "generative" | "sample", // generated vs. pre-made
"phrase_progress": 0.56, // progress through phrase (0-1)
// Musical properties
"harmonic_density": 0.67, // harmonic complexity (0-1)
"rhythmic_density": 0.45, // rhythmic complexity (0-1)
"spectral_centroid": 2340.5, // brightness (Hz)
// Form metrics (NOT amplitude)
"phrase_energy": 0.78, // musical energy
"tension_curve": 0.34, // musical tension (0-1)
"form_phase": "rising" | "peak" | "falling" | "trough"
}
}5. `section` - Section State Machine
Sent when section changes (~every 30-90 seconds)
{
"type": "section",
"timestamp": 1234567890.123,
"data": {
"section_id": "section_3",
"section_name": "exploration", // exploration, buildup, peak, release, etc.
"section_duration": 45.6, // how long we've been in this section (sec)
// Transition info
"in_transition": false,
"next_section_candidate": "buildup",
"transition_probability": 0.23
}
}6. `ambient_aura` - Global Performance State
Sent at ~5 Hz (slow updates for atmosphere)
{
"type": "ambient_aura",
"timestamp": 1234567890.123,
"data": {
"hue": 280, // 0-360 degrees (HSL)
"saturation": 0.65, // 0-1
"brightness": 0.45, // 0-1
"pulse_rate": 0.5, // breathing rate (Hz)
"global_energy_level": 0.67, // overall performance energy
"expressive_mode": "intense" | "exploratory" | "stable" | "transitioning"
}
}---
Client-Side Subscription
EchelonCapture can subscribe to specific channels:
// Subscribe to everything
ws://cc-mcs/visualization?device_id=left
// Subscribe only to latent and audio (lighter bandwidth)
ws://cc-mcs/visualization?device_id=left&subscribe=latent,audio---
Update Frequencies
| Message Type | Frequency | Bandwidth | Priority |
|---|---|---|---|
| `latent_state` | 50 Hz | ~2 KB/s | 🔴 Critical |
| `trajectory` | 20 Hz | ~3 KB/s | 🟡 High |
| `audio` | 30 Hz | ~1 KB/s | 🟡 High |
| `pattern` | 1-4 Hz | ~0.5 KB/s | 🟢 Medium |
| `section` | 0.01-0.05 Hz | ~0.01 KB/s | 🟢 Medium |
| `ambient_aura` | 5 Hz | ~0.2 KB/s | ⚪ Low |
Total bandwidth: ~7 KB/s (very light)
---
Error Handling
Connection Loss
{
"type": "error",
"timestamp": 1234567890.123,
"data": {
"code": "CONNECTION_LOST",
"message": "WebSocket connection closed",
"recoverable": true
}
}EchelonCapture should:
1. Show connection lost indicator
2. Attempt reconnect every 2 seconds
3. Continue sensor streaming (HTTP still works)
4. Resume visualization when reconnected
### Latency Warning
If round-trip latency > 100ms, cc-mcs can send:
{
"type": "warning",
"data": {
"code": "HIGH_LATENCY",
"latency_ms": 156,
"recommendation": "reduce_visualization_quality"
}
}---
Implementation Priority
### Phase 1 (Week 1):
- ✅ Implement WebSocket server in cc-mcs (Rust/Actix)
- ✅ Send `latent_state` messages only
- ✅ EchelonCapture connects and receives
### Phase 2 (Week 2):
- ✅ Add `trajectory` messages
- ✅ Add `audio` messages
- ✅ Basic visualization with these 3 types
### Phase 3 (Week 3):
- ✅ Add `pattern` messages
- ✅ Add `section` messages
- ✅ Add `ambient_aura` messages
- ✅ Full visualization dashboard
---
Swift Data Models
See `VisualizationModels.swift` for implementation:
struct LatentStateUpdate: Codable {
let position: SIMD3<Float>
let velocity: SIMD3<Float>
let equilibrium: Float
let energy: Float
let tension: Float
let grounding: Float
// ... etc
}
struct TrajectoryUpdate: Codable {
let predictedPositions: [SIMD3<Float>]
let confidence: Float
let curvature: Float
let anticipatedInflection: Bool
}
// ... etc---
Testing
### Mock WebSocket Server
For testing without full cc-mcs:
# test_ws_server.py
import asyncio
import websockets
import json
import time
async def mock_visualization(websocket):
while True:
# Send mock latent state
msg = {
"type": "latent_state",
"timestamp": time.time(),
"data": {
"position": [0.0, 0.0, 0.0],
"velocity": [0.01, 0.0, 0.0],
"equilibrium": 0.8,
"energy": 1.2,
"tension": 0.3,
"grounding": 0.7,
"verticality": 0.5,
"rotation_drive": 0.1,
"micro_beat_drift": 0.05
}
}
await websocket.send(json.dumps(msg))
await asyncio.sleep(0.02) # 50 Hz
asyncio.run(websockets.serve(mock_visualization, "localhost", 8765))# Run mock server
python3 test_ws_server.py
# Connect from EchelonCapture
ws://localhost:8765/visualization?device_id=test---
Next Steps
1. cc-mcs: Add WebSocket endpoint to existing Actix server
2. EchelonCapture: Implement WebSocket client service
3. Test: Mock server → EchelonCapture visualization
4. Integrate: Full cc-mcs → latent computation → WebSocket broadcast
Promotion Decision
Attach run IDs, datasets, metrics, and reproduction commands.
Source Anchor
Comp-Core/apps/ios/EchelonCapture/docs/legacy/WEBSOCKET_PROTOCOL.md
Detected Structure
Method · Evaluation · Code Anchors · Architecture