Transform your TV into a professional DJ lighting controller
A real-time lighting control application designed for DJ set recordings. Features beat-synced effects, MIDI clock integration, audio-reactive spectrum mode, and multiple shape modes.
Features · Quick Start · Usage · Clock System · Architecture
| Feature | Description |
|---|---|
| Beat Sync | Automatic beat detection from audio input with kick onset detection |
| MIDI Clock | Direct integration with Traktor, Ableton, or any DAW via Web MIDI API |
| Spectrum Mode | Audio-reactive colors that follow bass/mid/treble frequencies |
| Ring Light | Simulated ring light mode with adjustable size and thickness |
| 5 Effects | Static, Solid, Pulse, Breathe, and Strobe with clock synchronization |
| DJ Presets | 13 color presets accessible via keyboard (1-9 keys) |
| Persistent Settings | All preferences saved to localStorage automatically |
- Node.js 18+
- npm, yarn, or pnpm
- Chrome/Edge browser (required for MIDI support)
# Clone the repository
git clone https://github.com/yourusername/lightbox.git
cd lightbox
# Install dependencies
npm install
# Start development server
npm run devOpen http://localhost:3000 in your browser.
npm run build
npm run start| Key | Action |
|---|---|
F |
Toggle fullscreen |
Escape |
Hide control panel |
Space / Enter |
Toggle control panel |
1 |
White |
2 |
Warm White |
3 |
Hot Pink |
4 |
Electric Blue |
5 |
Deep Purple |
6 |
Neon Green |
7 |
Cyan |
8 |
Amber |
9 |
Red |
Click anywhere on the screen to toggle the control panel. The panel has four tabs:
- Hue: 0-360° color wheel
- Saturation: 0-100% color intensity
- Brightness: 0-100% overall light level
- Presets: Quick-select DJ color palette
- Spectrum Mode: Auto-color based on audio frequencies (requires Audio clock)
- Softbox: Full-screen solid color (default)
- Ring: Circular ring light simulation
- Size: 10-90% of screen
- Thickness: 5-50% of ring diameter
- Effect Selector: Choose from 5 effect types
- Speed: Animation speed multiplier (disabled when clock-synced)
- Intensity: Effect strength/amplitude
- Source: Off, Audio, Manual, Tap, or MIDI
- BPM Display: Current tempo
- Audio Settings: Sensitivity, smoothing, beat/volume mode
- MIDI Settings: Device selector
The clock system provides unified BPM control for synchronizing effects to music.
| Source | Description | Best For |
|---|---|---|
| Off | No synchronization, effects run freely | Ambient lighting |
| Audio | Beat detection from microphone input | Live DJ sets |
| Manual | Manual BPM entry (40-300) | Offline testing |
| Tap | Tap tempo (4-8 taps to set BPM) | Quick sync without audio |
| MIDI | MIDI clock from DAW/Traktor | Professional setups |
Download and install loopMIDI on Windows.
Create a new virtual port named Lightbox Clock.
Add Generic MIDI Device:
- Go to Preferences → Controller Manager
- Click Add... → Select Generic MIDI
- Set Out-Port to your loopMIDI port
- Set In-Port to None (prevents MIDI loops)
Enable MIDI Clock:
- Go to Preferences → MIDI Clock
- Enable Send MIDI Clock
- (Optional) Adjust MIDI Clock Sending Offset if timing feels off
Start Sending:
- Go to Preferences → Global Settings
- Enable Show Global Section
- In Traktor's top bar, click the SEND play button
- Set Clock Source to MIDI
- Click the refresh button to scan for devices
- Select your loopMIDI port from the dropdown
- Play music in Traktor - Lightbox will sync automatically
Reference: Native Instruments MIDI Clock Guide
The audio analyzer uses onset detection to identify kick drums:
| Parameter | Value |
|---|---|
| FFT Size | 512 bins |
| Bass Range | 0-8% of spectrum (~0-350Hz) |
| Detection | Onset threshold with adaptive sensitivity |
| Debounce | 100ms minimum between beats |
| BPM Range | 40-600 BPM supported |
Audio Modes:
| Mode | Behavior |
|---|---|
| Beat | Flash on kick detection, exponential decay between beats |
| Volume | Brightness follows overall audio level |
| Effect | Icon | Clock Off | Clock On |
|---|---|---|---|
| Static | ■ | Constant color | Constant color (ignores clock) |
| Solid | ● | Constant color | Flash + decay on beat |
| Pulse | ◐ | Sine wave oscillation | Synced to beat cycle |
| Breathe | ◯ | Slow eased oscillation | Synced with smoothstep easing |
| Strobe | ⚡ | Fast on/off flash | Flash on beat only |
When a clock source is active, the Speed slider is disabled for clock-synced effects (Solid, Pulse, Breathe, Strobe). The Static effect never syncs to clock.
Solid (Clock On)
On beat: 100% brightness
Decay: e^(-t/80ms) exponential falloff
Minimum: 15% brightness between beats
Pulse/Breathe
Clock Off: Speed slider controls frequency
Clock On: One full cycle per beat
Intensity: Controls oscillation amplitude
Strobe
Clock Off: Duty cycle from intensity
Clock On: 50ms flash on each beat
When clock source is set to Audio, enable Spectrum Mode to automatically color based on frequency content:
| Frequency Band | Hue Range | Colors |
|---|---|---|
| Bass (0-350Hz) | 0° - 40° | Red → Orange |
| Mids (350Hz-5kHz) | 70° - 170° | Yellow → Green → Cyan |
| Treble (5kHz+) | 220° - 260° | Blue → Purple |
The dominant frequency band determines the base hue, with smooth blending when bands overlap.
| Key | Name | HSL |
|---|---|---|
| 1 | White | (0, 0%, 100%) |
| 2 | Warm White | (40, 30%, 100%) |
| 3 | Hot Pink | (330, 100%, 50%) |
| 4 | Electric Blue | (220, 100%, 50%) |
| 5 | Deep Purple | (270, 100%, 50%) |
| 6 | Neon Green | (120, 100%, 50%) |
| 7 | Cyan | (180, 100%, 50%) |
| 8 | Amber | (35, 100%, 50%) |
| 9 | Red | (0, 100%, 50%) |
Full-screen solid color fill. Traditional background/fill lighting for video production.
Circular ring light simulation with configurable parameters:
| Parameter | Range | Description |
|---|---|---|
| Size | 10-90% | Ring diameter as percentage of screen |
| Thickness | 5-50% | Ring width as percentage of diameter |
Uses CSS radial gradient for smooth rendering. Black background with colored ring band.
src/
├── app/
│ ├── layout.tsx # Root layout, metadata
│ ├── page.tsx # Main page, keyboard handlers
│ └── globals.css # Global styles
├── components/
│ ├── LightingCanvas.tsx # Full-screen display
│ ├── ControlPanel.tsx # Floating control panel
│ ├── ColorControls.tsx # Color tab UI
│ ├── ShapeControls.tsx # Shape tab UI
│ ├── EffectControls.tsx # Effects tab UI
│ ├── ClockControls.tsx # Clock tab UI
│ └── ui/ # shadcn/ui components
├── hooks/
│ ├── useLightingStore.ts # Zustand state management
│ ├── useLightingEffect.ts # Animation loop
│ ├── useAudioAnalyzer.ts # Beat detection
│ └── useMidiClock.ts # MIDI integration
├── lib/
│ ├── colors.ts # Color utilities, presets
│ ├── effects.ts # Effect implementations
│ └── utils.ts # Helper functions
└── types/
└── index.ts # TypeScript definitions
graph TD
A[LightingCanvas] --> B[useLightingEffect]
B --> C[useLightingStore]
B --> D[useAudioAnalyzer]
B --> E[useMidiClock]
C --> |State| B
D --> |AudioData| B
E --> |MidiClockData| B
B --> |HSL Color| A
F[ControlPanel] --> C
subgraph "Clock Sources"
D
E
G[Manual BPM]
H[Tap Tempo]
end
Zustand store with localStorage persistence. Manages all application state:
interface LightingState {
// Color
hue: number;
saturation: number;
brightness: number;
colorMode: 'manual' | 'spectrum';
// Shape
shape: 'softbox' | 'ring';
ringSize: number;
ringThickness: number;
// Effect
effect: EffectId;
effectSpeed: number;
effectIntensity: number;
// Clock
clockSource: ClockSource;
manualBpm: number;
midiDeviceId: string | null;
// Audio
audioMode: 'beat' | 'volume';
audioSensitivity: number;
audioSmoothing: number;
}RAF-based animation loop running at 60 FPS. Computes final HSL color based on:
- Base color (hue, saturation)
- Active effect and its parameters
- Clock source and beat timing
- Brightness modifier
Web Audio API integration providing:
- Real-time FFT frequency analysis
- Onset detection for beat tracking
- BPM estimation from kick intervals
Web MIDI API integration providing:
- Device enumeration and selection
- MIDI clock pulse counting (24 PPQN)
- BPM calculation from pulse intervals
| Technology | Version | Purpose |
|---|---|---|
| Next.js | 16.1 | React framework with App Router |
| React | 19.2 | UI library |
| TypeScript | 5 | Type safety |
| Tailwind CSS | 4 | Utility-first styling |
| Zustand | 5.0 | State management |
| motion/react | 12.23 | Animations |
| shadcn/ui | - | UI components |
| Radix UI | - | Accessible primitives |
| Lucide | 0.562 | Icons |
| Browser | Audio | MIDI | Notes |
|---|---|---|---|
| Chrome 43+ | Yes | Yes | Full support |
| Edge 79+ | Yes | Yes | Full support |
| Firefox | Yes | No | No Web MIDI API |
| Safari | Yes | No | No Web MIDI API |
Requirements:
- HTTPS or localhost (required for Web MIDI)
- Microphone permission (for audio mode)
- Fork the repository
- Create a feature branch:
git checkout -b feature/my-feature - Make your changes
- Run type check:
npx tsc --noEmit - Commit:
git commit -m "Add my feature" - Push:
git push origin feature/my-feature - Open a Pull Request
- TypeScript strict mode enabled
- Functional components with hooks
- Zustand for global state
- Tailwind CSS for styling (prefer
stonepalette)
- Define the effect in
src/lib/effects.ts:
const myEffect: LightingEffect = {
id: 'myEffect',
name: 'My Effect',
icon: '★',
compute: (baseColor, time, settings) => {
// Return modified HSL
return { ...baseColor, l: 50 };
},
};-
Add the effect ID to
EffectIdtype insrc/types/index.ts -
Add to
EFFECTSobject insrc/lib/effects.ts -
If clock-synced, add to
CLOCK_SYNCED_EFFECTSinEffectControls.tsx -
Add clock-synced behavior in
useLightingEffect.ts
- Add source to
ClockSourcetype insrc/types/index.ts - Create hook if needed (e.g.,
useMidiClock.ts) - Update
ClockControls.tsxUI - Handle in
useLightingEffect.tsanimation loop
- Ensure you're using Chrome or Edge
- Check that the page is served over HTTPS or localhost
- Click the refresh button to re-scan devices
- Verify loopMIDI is running with active ports
- Grant microphone permission when prompted
- Increase Sensitivity in Clock settings
- Decrease Smoothing for faster response
- Ensure audio source has clear kick drums
This was fixed in the latest version. The spectrum now uses dominant frequency detection instead of weighted averaging.
Fixed in latest version. The MIDI hook now waits for device initialization before attempting connection.
MIT License - see LICENSE for details.
- Inspired by professional DJ lighting setups
- Built for the creator community
- shadcn/ui for beautiful components
- Radix UI for accessible primitives
Made with love for DJs and content creators