Skip to content

Cloud-based remote control for Resolume Arena/Avenue - React + TypeScript + FastAPI

Notifications You must be signed in to change notification settings

yuan-cloud/resofleur

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

2 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

🌸 Resofleur

The VJ remote control that actually works.

Control Resolume Arena from your phone, tablet, or anywhere in the venue. No cables. No limitations. Just beautiful, responsive control.

Live Demo TypeScript React FastAPI Mobile Ready


🎯 The Problem

Resolume's REST API is notoriously difficult. Most developers give up after:

  • ❌ Getting stuck on basic composition queries
  • ❌ Failing to control anything beyond layer 1
  • ❌ Realizing PUT/POST endpoints return 404s
  • ❌ Not understanding the undocumented parameter-by-ID pattern

The result? VJs are still chained to their laptops during performances.


βœ… The Solution

I reverse-engineered the Resolume API and built the remote control that should have shipped with the software.

Feature Description
4-Layer Control Full access to layers 1-4, not just the first one
9 Clips Per Layer Trigger any clip with live thumbnail preview
Video Scrubbing Drag the timeline, see it update instantly
BPM Sync Match your visuals to the DJ's tempo
Opacity Control Blend layers smoothly in real-time
Mobile-First Responsive UI tested on iOS, Android, iPad
Multi-User Each user connects to their own Resolume instance

πŸ† Technical Highlights

Cracking the Resolume API

After extensive reverse-engineering, I discovered that Resolume's REST API requires a two-step pattern:

1. GET /composition β†’ fetch parameter IDs
2. PUT /parameter/by-id/{id} β†’ change values

This is undocumented. The official Swagger docs show endpoints that return 404. I discovered the real pattern through packet inspection and systematic testing.

Type-Safe Architecture

One of the only TypeScript implementations of a Resolume controller:

// Fully typed clip model
interface ClipViewModel {
  readonly id: number;
  readonly name: string;
  readonly isConnected: boolean;
  readonly thumbnailUrl: string;
}

// Type-safe API client
class ResolumeApiClient {
  async triggerClip(layer: LayerIndex, clip: ClipIndex): Promise<void>
  async setLayerOpacity(layer: LayerIndex, opacity: number): Promise<void>
  async setBpm(value: number): Promise<void>
}

Mobile-First Design

Device Experience
iPhone Touch-optimized with 44px tap targets, no accidental triggers
iPad Landscape mode transforms into a full control surface
Desktop Hover states with keyboard shortcuts (roadmap)

πŸ›  Tech Stack

Layer Technology Rationale
Frontend React 18 + TypeScript Type safety, modern hooks, excellent DX
Styling Tailwind CSS Rapid iteration, consistent design system
Backend FastAPI (Python) Async-first, auto-generated OpenAPI docs
Database MongoDB Flexible schemas for user configurations
Auth JWT + bcrypt Industry standard, stateless authentication
Payments Stripe Subscription billing infrastructure
Tunnel ngrok Secure localhost-to-cloud bridging

πŸ“ Architecture

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                        USER DEVICES                          β”‚
β”‚   πŸ“± iPhone    πŸ“± Android    πŸ“± iPad    πŸ’» Desktop           β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚ HTTPS
                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                    RESOFLEUR CLOUD                           β”‚
β”‚  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”  β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”          β”‚
β”‚  β”‚   React     │──│   FastAPI   │──│   MongoDB   β”‚          β”‚
β”‚  β”‚  Frontend   β”‚  β”‚   Backend   β”‚  β”‚   Atlas     β”‚          β”‚
β”‚  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”˜  β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”Όβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                           β”‚ Authenticated Proxy
                           β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                      NGROK TUNNEL                            β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
                          β”‚
                          β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                   RESOLUME ARENA/AVENUE                      β”‚
β”‚                   (Running locally on VJ's machine)          β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Key insight: Each user's Resolume stays on their machine. Resofleur provides secure remote access without exposing local networks.


πŸš€ Quick Start

Prerequisites

  • Resolume Arena/Avenue 7+ (REST API enabled)
  • ngrok account (free tier)
  • Node.js 18+, Python 3.11+

Setup

# Clone the repository
git clone https://github.com/yuan-cloud/resofleur.git
cd resofleur

# Backend
cd backend
pip install -r requirements.txt
uvicorn server:app --port 8001

# Frontend (new terminal)
cd frontend
yarn install
yarn start

# Enable Resolume REST API: Preferences β†’ Webserver β†’ Enable
# Start ngrok: ngrok http 8080
# Open http://localhost:3000 and add your ngrok URL

πŸ“ Project Structure

resofleur/
β”œβ”€β”€ backend/
β”‚   β”œβ”€β”€ server.py              # FastAPI application (~550 LOC)
β”‚   β”œβ”€β”€ models/                # Pydantic schemas
β”‚   β”‚   β”œβ”€β”€ user_models.py
β”‚   β”‚   β”œβ”€β”€ resolume_models.py
β”‚   β”‚   └── payment_models.py
β”‚   └── tests/                 # pytest test suite
β”‚
β”œβ”€β”€ frontend/
β”‚   └── src/
β”‚       β”œβ”€β”€ components/        # React components
β”‚       β”œβ”€β”€ hooks/             # Custom hooks (connection, clips, controls)
β”‚       β”œβ”€β”€ context/           # Authentication context
β”‚       β”œβ”€β”€ services/          # Type-safe API client
β”‚       β”œβ”€β”€ pages/             # Route pages
β”‚       └── types/             # TypeScript definitions
β”‚
└── README.md

πŸ” Security

  • βœ… JWT authentication with 24-hour token expiration
  • βœ… bcrypt password hashing (work factor 12)
  • βœ… User-scoped configurations (complete data isolation)
  • βœ… HTTPS enforced in production
  • βœ… Input validation via Pydantic models
  • βœ… CORS configured for production origins

πŸ—Ί Roadmap

  • Keyboard shortcuts for clip triggering
  • OSC protocol bridge
  • Effect parameter controls
  • Cue list / show programming
  • Multi-composition switching

πŸ’‘ Key Learnings

  1. Read the packets, not the docs β€” Resolume's Swagger documentation is incomplete
  2. Parameter IDs are everything β€” The undocumented key to actual control
  3. Mobile-first is mandatory β€” VJs need to move; the app should move with them
  4. Proxy architecture enables scale β€” User isolation becomes natural

πŸ™‹ FAQ

Q: Why not use OSC?
A: OSC requires static IPs and network configuration. Resofleur works over the internet from anywhere.

Q: What's the latency?
A: ~50-100ms via ngrokβ€”imperceptible for manual control.

Q: Can multiple people control one Resolume?
A: Yes. Share the same configuration for collaborative VJing.

Q: Which Resolume versions are supported?
A: Arena 7+ and Avenue 7+ with REST API enabled.


πŸ“„ License

Proprietary software. All rights reserved.


Built by a full-stack engineer who actually VJs.

Because performers deserve better tools. 🌸