A web-based VFX image and sequence viewer inspired by OpenRV. View images, videos, and image sequences with professional color tools, annotations, and RV session file compatibility.
- Single images (PNG, JPEG, WebP, GIF, BMP, TIFF, AVIF, JPEG XL, HEIC/HEIF, EXR/SXR, DPX/Cineon, Radiance HDR, RAW preview formats)
- EXR Format Support - full HDR image loading via WebAssembly decoder
- Float32 texture support for HDR precision
- Multi-layer EXR with AOV (Arbitrary Output Variable) selection
- Channel remapping (custom channel-to-RGBA mapping)
- Layer selection UI for multi-layer files (diffuse, specular, normals, depth, etc.)
- PIZ wavelet compression support (most common VFX compression)
- Radiance HDR (.hdr/.pic) - environment maps and light probes
- RGBE shared-exponent encoding with adaptive RLE decompression
- Header metadata (exposure, gamma, primaries)
- Automatic format detection via
#?RADIANCE/#?RGBEmagic bytes
- JPEG XL (.jxl) - modern HDR-capable image format
- SDR decode via
@jsquash/jxlWebAssembly decoder - HDR path via browser-native
createImageBitmap→VideoFrame(same pattern as AVIF HDR) - ISOBMFF container parsing for
colr(nclx)HDR transfer detection (HLG/PQ) - Bare codestream (
0xFF 0x0A) and container format support
- SDR decode via
- HEIC/HEIF (.heic/.heif) - Apple iPhone photos with HDR gainmap support
- Native decoding via
createImageBitmapon Safari - Cross-browser WASM fallback via
libheif-jsfor Chrome/Firefox/Edge - HDR Gainmap decoding (Apple
urn:com:apple:photo:2020:aux:hdrgainmapand ISO 21496-1 standard) - ISOBMFF container parsing for gainmap extraction and
colr(nclx)HDR transfer detection (HLG/PQ) - HDR reconstruction: sRGB-to-linear base + gain map with configurable headroom
- Standalone HEIC builder for gainmap item decoding (wraps raw HEVC data with hvcC config)
- Native decoding via
- Video files (Mediabunny containers: MP4/M4V/3GP/3G2, MOV/QuickTime, MKV/WebM, OGG/OGV/OGX; plus AVI browser fallback)
- ProRes/DNxHD Codec Detection - identifies unsupported professional codecs and provides FFmpeg transcoding guidance
- Image sequences (numbered files like
frame_001.png,file.0001.exr)- Missing frame detection - automatically detect and indicate gaps in sequences
- Visual overlay for missing frames during playback
- Pattern notation support -
%04d(printf),####(hash), and@notation parsing - Single-file sequence inference - drop one frame, automatically detect full sequence from directory
- Directory scanning - discover all sequences in a folder, select best match
- RV/GTO session files with full graph reconstruction
- Enhanced marker support - notes and colors preserved through GTO round-trip
- Exposure, gamma, saturation, contrast, brightness
- Color temperature and tint
- Hue Rotation - global hue shift control
- Vibrance with skin tone protection (hue 20-50° protected)
- Clarity/Local Contrast - enhance midtone detail without affecting highlights/shadows
- Highlight/Shadow recovery - recover detail in blown highlights and crushed shadows
- Whites/Blacks controls for clipping adjustment
- Lift/Gamma/Gain Color Wheels - three-way color correction for shadows, midtones, and highlights
- 120px wheels with color preview ring
- Master wheel for overall adjustments
- Undo/redo support
- Link option for gang adjustments
- HSL Qualifier - secondary color correction with hue/saturation/luminance selection
- Isolate specific colors by HSL range
- Apply corrections only to selected regions
- Matte preview and invert selection
- Eyedropper for color picking
- ASC CDL (slope, offset, power, saturation) with .cdl file support
- LUT support (.cube files) with GPU-accelerated processing
- 3D LUTs for complex color transforms
- 1D LUTs for simple curve-based corrections
- Single-pass float LUT pipeline - 3D LUT sampling in main fragment shader (no 8-bit bottleneck)
- Film emulation presets - 10 built-in looks (Warm Film, Cool Chrome, Bleach Bypass, Cross Process, Monochrome, Cinematic Teal & Orange, Vintage Fade, High/Low Contrast)
- Color curves (Master/R/G/B channels) with presets and import/export
- Log Curve Presets - camera-specific log-to-linear conversion
- Cineon Film Log (10-bit)
- ARRI LogC3 (EI 800) and LogC4
- Sony S-Log3
- RED Log3G10
- GLSL shader generation for GPU processing
- OCIO Color Management - OpenColorIO-style color pipeline
- Built-in config presets (ACES 1.2, sRGB)
- Custom .ocio config file loading - upload studio configs with drag-and-drop and validation feedback
- Input color space selection with auto-detection from metadata
- Working color space (ACEScg, Rec.709, Linear sRGB)
- Display and view transforms (sRGB, Rec.709, DCI-P3)
- Look transforms with forward/inverse direction
- Reverse transforms - bidirectional camera space conversions (sRGB ↔ ARRI LogC3/LogC4, Sony S-Log3, RED Log3G10, ACEScg)
- Integration with existing LUT and log curve infrastructure
- Toggle via Shift+O keyboard shortcut
- Tone Mapping for HDR - operators for mapping HDR content to SDR displays
- Reinhard operator with adjustable white point (0.5–10.0)
- Filmic operator with configurable exposure bias (0.5–8.0) and white point (2.0–20.0)
- ACES filmic tone mapping
- Per-operator parameter sliders with real-time preview
- Toggle via Shift+Alt+J keyboard shortcut
- Display Color Management - monitor-accurate output transforms
- Transfer functions: Linear, sRGB, Rec.709, Gamma 2.2, Gamma 2.4, Custom Gamma
- Display gamma and brightness adjustments
- GPU-accelerated via fragment shader (no CPU round-trip)
- LocalStorage persistence for display profile settings
- Cycle profiles via Shift+D keyboard shortcut
- HDR & Wide Color Gamut Output - progressive enhancement for HDR-capable displays
- Display P3 gamut - automatic Wide Color Gamut output on supported displays (Chrome 104+, Safari 15.1+)
- HDR extended range - HLG and PQ output modes for HDR displays (experimental, Chrome)
- Display capabilities detection - centralized runtime detection of P3, HDR, and WebGPU support
- User gamut preference - force sRGB or Display P3 output via Display Profile settings
- HDR-aware scopes - waveform, histogram, and vectorscope extend beyond 1.0 for HDR content
- WebGPU backend - renderer abstraction with WebGPU migration path (rgba16float, extended tone mapping)
- Canvas2D HDR fallback - last-resort HDR display path when WebGL2 native HDR and WebGPU are unavailable
- Uses Canvas 2D API with
srgb-linearorrec2100-hlgcolor spaces and float16 pixel storage - Automatic fallback chain: srgb-linear + colorType → pixelFormat → rec2100-hlg + colorType → pixelFormat
- Float32 ImageData with browser-handled float32→float16 conversion
- Row-flipped readback from WebGL2 FBO for correct display
- Uses Canvas 2D API with
- Full backward compatibility - all features are opt-in, fallback to sRGB on unsupported browsers
- Rotation (90°/180°/270°) and flip (H/V)
- Crop tool with aspect ratio presets and rule-of-thirds guides
- Uncrop / Canvas Extension - add padding around image for composition reference
- Uniform padding mode (equal on all sides)
- Per-side padding controls (top, right, bottom, left)
- Customizable fill color
- Pixel Aspect Ratio (PAR) Support - correct anamorphic squeeze for proper display
- Auto-detection from image/video metadata
- Presets for common PARs (DV NTSC, DV PAL, HD Anamorphic, 2:1 Anamorphic, etc.)
- Manual PAR value entry
- Toggle via Shift+P keyboard shortcut
- Lens distortion correction (barrel/pincushion)
- Blur and sharpen filters
- Noise Reduction - edge-preserving bilateral filter
- GPU-accelerated with WebGL2
- Automatic CPU fallback
- Adjustable strength and radius (1-5)
- Wipe comparison (horizontal/vertical split view)
- Split Screen Compare - side-by-side A/B source comparison
- Horizontal and vertical split modes
- Draggable divider for adjustable split position
- A/B labels for source identification
- Difference Matte - show pixel differences between A/B with gain and heatmap modes
- Blend Modes for A/B comparison
- Onion skin - overlay B over A with adjustable opacity
- Flicker - rapidly alternate between A/B at configurable rate (1-30 Hz)
- Blend - mix A and B with adjustable ratio
- Multi-layer stack with blend modes
- A/B source switching with auto-assignment when loading multiple files
- Quick toggle between sources with backtick key
- Side-by-side and over/under stereo modes
- Mirror mode (side-by-side with flipped right eye)
- Anaglyph mode (red/cyan 3D glasses)
- Luminance anaglyph for reduced color fringing
- Checkerboard mode (for DLP projectors with shutter glasses)
- Scanline interleaved mode (for line-blanking displays)
- Eye swap control (swap left/right eyes)
- Convergence offset adjustment
- Histogram (RGB/Luminance/Separate channels, log scale option)
- Clipping Indicators - show percentage of clipped highlights/shadows
- Clipping Overlay - visual overlay showing clipped areas (red for highlights, blue for shadows)
- Waveform monitor (Luma/RGB/Parade/YCbCr modes)
- YCbCr Parade - visualize Y (luma), Cb (blue difference), Cr (red difference) using BT.709 coefficients
- Vectorscope with zoom levels
- Pixel Probe / Color Sampler - click to sample RGB/HSL/IRE values at any pixel
- Area averaging - configurable sample size (1x1, 3x3, 5x5, 9x9)
- Source vs Rendered toggle - view pre- or post-color-pipeline values
- Alpha channel display - shows alpha in both 0-255 and 0.0-1.0 formats
- HDR out-of-range indicators - color-coded values for >1.0 (red) and <0.0 (blue)
- Nits readout - HDR luminance in cd/m² (luminance × 203)
- Color space info - displays active color space from image metadata
- Float precision toggle - switch between 3 and 6 decimal places
- False Color Display - exposure visualization with ARRI, RED, and custom presets
- Zebra Stripes - animated diagonal stripes for exposure warnings
- High zebras (>95% IRE) - right-leaning red stripes
- Low zebras (<5% IRE) - left-leaning blue stripes
- Adjustable thresholds
- Safe Areas / Guides Overlay - broadcast safe zones and composition guides
- Title Safe and Action Safe zones
- Rule of Thirds grid
- Center crosshair
- Aspect ratio overlays (16:9, 2.39:1, etc.)
- Timecode Overlay - on-screen SMPTE timecode display (HH:MM:SS:FF format)
- Pen tool with pressure sensitivity
- Text annotations with formatting (bold, italic, underline, background color, callouts)
- Shape Tools - Rectangle, ellipse, line, arrow, and polygon with fill/stroke options
- Spotlight Tool - Dim everything except highlighted region (circle or rectangle)
- Eraser and brush types
- Ghost mode (show nearby frame annotations)
- Hold mode (persist annotations across frames)
- Per-frame annotation storage
- Ghost Frames / Onion Skin - semi-transparent previous/next frames for animation review
- Configurable frames before and after (0-5 each)
- Adjustable base opacity and falloff
- Optional color tinting (red for before, green for after)
- Frame-accurate timeline with scrubbing
- Timeline Thumbnails - frame preview thumbnails along the timeline track
- LRU cache for efficient memory usage (max 150 thumbnails)
- Progressive loading without blocking UI
- Automatic recalculation on resize
- In/out points and markers with notes (color-coded, with text annotations)
- Duration Markers - markers spanning frame ranges for segment annotation
- Loop modes (once, loop, ping-pong)
- Playback speed control (0.1x to 8x) with J/K/L shortcuts
- Audio pitch correction - preserves pitch at non-1x playback speeds
- Sub-frame Interpolation - alpha blending between frames for smooth slow motion
- Smooth Zoom Animation - requestAnimationFrame-based zoom with ease-out cubic easing
- Cache indicator showing cached frames and memory usage
- Prerender Buffer - background processing of effects for smooth playback
- Double-buffered cache for glitch-free effects parameter changes
- SIMD-like TypedArray optimizations for color inversion and channel isolation
- Half-resolution convolution for clarity and sharpen (4x fewer pixels)
- Async chunked processing with main-thread yielding (<16ms blocking)
- Multi-Clip Playlist - manage and play multiple clips in sequence
- Add clips from any loaded source with in/out points
- Drag-and-drop reordering
- Loop modes: none, single clip, or all clips
- EDL (Edit Decision List) export
- OTIO (OpenTimelineIO) import - parse editorial timelines with clips, gaps, and transitions
- Total duration display
- Web Worker-based parallel effect processing
- Smart cache management with LRU eviction
- Direction-aware preloading (forward/backward)
- Audio Playback System - robust audio handling with multiple fallbacks
- Web Audio API for independent audio control and waveform generation
- HTMLVideoElement fallback for cross-origin or codec issues
- Mediabunny-based audio extraction for CORS-blocked content
- Graceful autoplay policy handling with user-friendly error messages
- Audio sync during frame-accurate playback with drift correction
- Automatic muting during reverse playback (audio cannot be reversed)
- Audio waveform display with multi-channel support
- Volume control with mute (volume preserved across mute/unmute cycles)
- Page Visibility Handling - smart resource management
- Automatically pauses playback when tab is hidden
- Resumes playback when tab becomes visible
- Reduces scope processing while hidden
- Dark/Light Theme with auto (system) mode and Shift+T shortcut
- Fullscreen Mode - native browser fullscreen via F11 or toolbar button
- Presentation Mode - clean display with all UI hidden and cursor auto-hide on inactivity (Ctrl+Shift+P)
- Background Pattern Selector - configurable viewer background for alpha transparency visualization
- Checkerboard (classic alpha pattern)
- Grey 18%, Grey 50%, White, Black
- Crosshatch pattern
- Custom color picker
- Toggle via Shift+B (cycle) or Shift+Alt+B (quick checkerboard toggle)
- History Panel - visual undo/redo with jump to any state
- Floating Info Panel - filename, resolution, frame, FPS, and cursor color readout
- Hi-DPI/Retina Display Support - crisp rendering on high-density displays (2x, 3x DPR)
- Session Snapshots - named version history with preview and restore
- Manual snapshots with custom names and descriptions
- Auto-checkpoints before major operations (project load, restore)
- IndexedDB persistence across browser sessions
- Preview showing frame count, annotations, and color grade status
- Export/import snapshots as JSON
- LRU eviction (max 50 manual snapshots, 10 auto-checkpoints)
- Auto-Save - automatic session persistence to IndexedDB with crash recovery
- Configurable save interval (1-30 minutes, default 5)
- Debounced saves to prevent excessive writes during rapid changes
- Crash recovery detection with prompt to restore previous session
- Visual indicator showing save status (saving, saved, unsaved, error)
- Click-to-retry on save failures
- Storage quota monitoring with low-space warnings
- Theme-consistent styling with CSS variables
- Session Recovery - intelligent handling of temporary file references
- Detects blob URLs that become invalid after browser restart
- Prompts user to re-select files with original filename validation
- Skip option to load session without unavailable media
- Watermark Overlay - add logos and watermarks to exports
- 9 preset positions (3x3 grid) plus custom positioning
- Adjustable scale (10-200%), opacity, and margin
- Supports PNG, JPEG, WebP, and SVG images
- Frame export (PNG/JPEG/WebP)
- Sequence export with progress
- Copy to clipboard
- Session save/load (.orvproject format)
- Annotation JSON Export/Import - standalone annotation metadata exchange
- Frame range filtering and statistics (pen strokes, text, shapes)
- Full round-trip: export → parse → import with validation
- Import modes: replace (clear existing) or merge (add to existing)
- Frame offset support for timeline alignment
- Automatic ID collision avoidance in merge mode
- Paint effects preservation (hold, ghost settings)
- Annotation PDF Export - printable annotation reports
- Frame thumbnails with timecodes
- Annotation summary tables
- Uses browser native print (no external libraries)
- Visual EDL/Cut Editing for sequence nodes
- Colored cut blocks representing source clips
- Drag handles for trimming in/out points
- Drag cuts to reorder
- Zoom control for timeline detail
- Context menu for delete operations
- Real-time event emission for cut changes
- Public JavaScript API (
window.openrv) for programmatic control from browser console or external scripts- Playback control:
play(),pause(),toggle(),stop(),seek(frame),step(direction),setSpeed(),getSpeed(),isPlaying(),getCurrentFrame() - Media info:
getCurrentSource(),getDuration(),getFPS(),getResolution() - Audio control:
setVolume(),getVolume(),mute(),unmute(),isMuted() - Loop control:
setMode(),getMode(),setInPoint(),setOutPoint(),clearInOut() - View control:
setZoom(),getZoom(),fitToWindow(),setPan(),setChannel() - Color control:
setAdjustments(),getAdjustments(),reset(),setCDL(),loadLUT() - Markers:
add(),remove(),getAll(),clear(),goToNext(),goToPrevious() - Events:
on(),off(),once()for frameChange, play, pause, sourceLoaded, error, etc. - Version and readiness:
openrv.version,openrv.isReady() - Input validation and error handling on all methods
- Playback control:
- WebSocket-based sync client for real-time collaboration between viewers
- Room creation and joining with unique room codes
- User presence indicators (connected users list)
- Configurable sync elements: playback, view (pan/zoom), color adjustments, annotations
- Host/participant role distinction
- Reconnection handling with exponential backoff
- Supports signaling server failover via
VITE_NETWORK_SIGNALING_SERVERS(comma-separatedwss:///ws://URLs) - WebRTC peer connections include public STUN/TURN defaults (Google, Cloudflare, OpenRelay) for cross-network/NAT traversal
- Keyboard shortcut: Shift+N to toggle network panel
# Clone the repository
git clone https://github.com/lifeart/openrv-web.git
cd openrv-web
# Install dependencies
pnpm install
# Start development server
pnpm dev- Drag and drop files onto the viewer
- Click the folder icon to open file picker
- Load RV session files (.rv) directly
- Load multiple files for A/B comparison (second file auto-assigns as source B)
| Key | Action |
|---|---|
Space |
Play/Pause |
Left/Right |
Step frame backward/forward |
Up |
Toggle play direction |
Home/End |
Go to start/end |
I or [ |
Set in point |
O or ] |
Set out point |
R |
Reset in/out points |
M |
Toggle mark at current frame |
L |
Cycle loop mode (once/loop/ping-pong) |
J |
Decrease playback speed |
K |
Pause playback |
L |
Increase playback speed |
| Key | Action |
|---|---|
F |
Fit to window |
= / - |
Zoom in/out |
Shift+= / Shift+- |
Fine zoom in/out |
1-5 |
Switch tabs (View, Color, Effects, Transform, Annotate) |
0 |
Set zoom to 50% |
F11 |
Toggle fullscreen mode |
Ctrl+Shift+P |
Toggle presentation mode (clean display, cursor auto-hide) |
Shift+B |
Cycle background pattern (checker, grey, white, etc.) |
Shift+Alt+B |
Toggle checkerboard background |
Shift+P |
Toggle pixel aspect ratio correction |
| Key | Action |
|---|---|
` (backtick) |
Toggle between A/B sources |
~ (tilde) |
Toggle between A/B sources |
Shift+D |
Toggle difference matte |
Shift+Alt+S |
Toggle split screen A/B comparison |
| Key | Action |
|---|---|
Shift+W |
Cycle wipe modes (off/horizontal/vertical) |
w |
Toggle waveform monitor |
h |
Toggle histogram |
y |
Toggle vectorscope |
| Key | Action |
|---|---|
Shift+I |
Toggle pixel probe |
Shift+Alt+F |
Toggle false color display |
Shift+Alt+Z |
Toggle zebra stripes |
; |
Toggle safe areas overlay |
Shift+Alt+T |
Toggle timecode overlay |
Shift+Alt+W |
Toggle color wheels panel |
| Key | Action |
|---|---|
Shift+3 |
Cycle stereo modes (off/side-by-side/over-under/mirror/anaglyph/etc.) |
| Key | Action |
|---|---|
Shift+R |
Red channel |
Shift+G |
Green channel |
Shift+B |
Blue channel |
Shift+A |
Alpha channel |
Shift+L |
Luminance/Grayscale |
Shift+Y |
Grayscale (alias for Shift+L) |
Shift+N |
Normal (RGB) |
| Key | Action |
|---|---|
C |
Toggle color panel |
U |
Toggle curves panel |
Shift+O |
Toggle OCIO color management panel |
Shift+Alt+J |
Toggle tone mapping |
Shift+D |
Cycle display color profile |
Shift+Alt+E |
Toggle effects/filter panel |
Shift+K |
Toggle crop mode |
Shift+H |
Toggle HSL Qualifier |
| Key | Action |
|---|---|
Shift+R |
Rotate left 90° |
Alt+R |
Rotate right 90° |
Alt+H |
Flip horizontal |
Shift+V |
Flip vertical |
| Key | Action |
|---|---|
V |
Pan tool |
P |
Pen tool |
E |
Eraser tool |
T |
Text tool |
R |
Rectangle tool |
O |
Ellipse tool |
L |
Line tool |
A |
Arrow tool |
B |
Toggle brush type (soft/hard) |
G |
Toggle ghost mode |
Shift+G |
Toggle ghost frames (onion skin) |
X |
Toggle hold mode (persist annotations across frames) |
Shift+Q |
Toggle spotlight |
Ctrl+Z |
Undo |
Ctrl+Y |
Redo |
, / . |
Jump to prev/next annotation |
| Key | Action |
|---|---|
Shift+T |
Cycle theme (auto/dark/light) |
Shift+Alt+H |
Toggle history panel |
Shift+Alt+I |
Toggle info panel |
Shift+Alt+M |
Toggle markers panel |
Shift+N |
Toggle network sync panel |
Ctrl+Shift+S |
Create quick snapshot |
Ctrl+Shift+Alt+S |
Toggle snapshots panel |
Shift+Alt+P |
Toggle playlist panel |
| Key | Action |
|---|---|
Ctrl+S |
Export frame |
Ctrl+C |
Copy frame to clipboard |
- Scroll: Zoom in/out
- Drag: Pan image
- Click timeline: Seek to frame
- Drag timeline: Scrub
src/
├── api/ # Public scripting API (window.openrv)
│ ├── OpenRVAPI.ts # Main API class and initialization
│ ├── PlaybackAPI.ts # Playback control methods
│ ├── MediaAPI.ts # Media/source information
│ ├── AudioAPI.ts # Volume and audio control
│ ├── LoopAPI.ts # Loop mode and in/out points
│ ├── ViewAPI.ts # Zoom, pan, channel control
│ ├── ColorAPI.ts # Color adjustment methods
│ ├── MarkersAPI.ts # Marker management
│ ├── EventsAPI.ts # Event subscription system
│ └── index.ts # API export and registration
├── core/
│ ├── graph/ # Node graph system (Graph, Property, Signal)
│ ├── image/ # IPImage data structure (with PAR metadata)
│ └── session/ # Session management, GTO loading, serialization, auto-save
│ ├── SnapshotManager.ts # IndexedDB-based session snapshots
│ └── PlaylistManager.ts # Multi-clip playlist with EDL export & OTIO import
├── formats/
│ ├── EXRDecoder.ts # WebAssembly EXR decoder with multi-layer support
│ ├── EXRPIZCodec.ts # PIZ wavelet compression codec (Huffman + Haar + LUT)
│ ├── HDRDecoder.ts # Radiance HDR (.hdr/.pic) decoder with RLE support
│ ├── JXLDecoder.ts # JPEG XL decoder (WASM SDR + browser-native HDR)
│ ├── HEICGainmapDecoder.ts # HEIC HDR gainmap decoder (ISOBMFF parsing, HDR reconstruction)
│ └── HEICWasmDecoder.ts # HEIC WASM fallback via libheif-js (Chrome/Firefox/Edge)
├── nodes/
│ ├── base/ # IPNode, NodeFactory with @RegisterNode decorator
│ ├── sources/ # FileSourceNode, VideoSourceNode, SequenceSourceNode
│ └── groups/ # SequenceGroup, StackGroup, SwitchGroup, etc.
├── render/ # WebGL2 renderer and shaders (incl. tone mapping)
│ ├── RendererBackend.ts # Renderer abstraction (WebGL2/WebGPU backends)
│ ├── WebGPUBackend.ts # WebGPU HDR renderer (rgba16float, extended tone mapping)
│ ├── Canvas2DHDRBlit.ts # Canvas 2D API HDR fallback (float16, srgb-linear/rec2100-hlg)
│ └── TextureCacheManager.ts # LRU texture cache for GPU performance
├── ui/
│ ├── components/ # Viewer, Timeline, Toolbar, Controls, TimelineEditor
│ │ ├── ViewerSplitScreen.ts # Split screen A/B comparison
│ │ ├── ThumbnailManager.ts # Timeline thumbnail generation and caching
│ │ ├── GhostFrameControl.ts # Ghost frames / onion skin control
│ │ ├── SnapshotPanel.ts # Session snapshot management UI
│ │ ├── PlaylistPanel.ts # Multi-clip playlist UI
│ │ ├── ChannelSelect.ts # Channel isolation with EXR layer selection
│ │ ├── BackgroundPatternControl.ts # Viewer background patterns (checker, grey, etc.)
│ │ ├── DisplayProfileControl.ts # Display color management profile selector
│ │ ├── PARControl.ts # Pixel aspect ratio controls
│ │ ├── CropControl.ts # Crop and uncrop/canvas extension
│ │ └── OCIOControl.ts # OCIO color management UI (incl. custom config upload)
│ └── shared/ # Button, Modal, Panel utilities
├── paint/ # Annotation engine
├── audio/ # Audio playback and waveform rendering
│ ├── AudioPlaybackManager.ts # Web Audio API playback with fallbacks
│ └── WaveformRenderer.ts # Waveform extraction and rendering
├── color/ # CDL, LUT loader (1D & 3D), WebGL LUT processor
│ ├── LogCurves.ts # Camera log curve presets (Cineon, LogC, S-Log3, etc.)
│ ├── DisplayCapabilities.ts # HDR/P3/WebGPU display capability detection
│ ├── DisplayTransfer.ts # Display transfer functions (sRGB, Rec.709, gamma)
│ ├── HDRPixelData.ts # HDR-aware pixel value access wrapper
│ ├── LUTPresets.ts # Film emulation preset library (10 built-in looks)
│ ├── SafeCanvasContext.ts # Safe canvas context creation with P3/HDR fallback
│ └── ocio/ # OCIO color management (config, transforms, processor)
├── filters/ # Image processing filters
│ ├── NoiseReduction.ts # Bilateral filter (CPU implementation)
│ └── WebGLNoiseReduction.ts # GPU-accelerated bilateral filter
├── network/ # Network sync infrastructure (WebSocket client, rooms)
├── stereo/ # Stereoscopic 3D viewing modes
├── transform/ # Lens distortion
├── composite/ # Blend modes
├── scopes/ # GPU-accelerated scopes (Histogram, Waveform, Vectorscope)
├── utils/ # EventEmitter, FrameExporter, SequenceLoader, HiDPICanvas
│ ├── CodecUtils.ts # Codec detection (ProRes, DNxHD, etc.)
│ ├── PixelAspectRatio.ts # PAR detection and correction
│ ├── FullscreenManager.ts # Fullscreen API wrapper
│ ├── PresentationMode.ts # Presentation mode (UI hide, cursor auto-hide)
│ ├── FrameInterpolator.ts # Sub-frame interpolation for slow motion
│ ├── EffectProcessor.ts # CPU effect processing (highlights, vibrance, clarity, etc.)
│ ├── PrerenderBufferManager.ts # Prerender cache for smooth playback with effects
│ ├── WorkerPool.ts # Generic worker pool for parallel processing
│ ├── AnnotationJSONExporter.ts # Export/import annotations as JSON (round-trip)
│ ├── AnnotationPDFExporter.ts # Export annotations as PDF via browser print
│ └── OTIOParser.ts # OpenTimelineIO import parser
└── workers/ # Web Workers for background processing
└── effectProcessor.worker.ts # Background effect processing
The application uses a centralized KeyboardManager for all keyboard shortcuts, providing:
- Flexible Registration: Register shortcuts with key combinations, handlers, and descriptions
- Cross-Platform Support: Automatically treats Meta (Cmd) as Ctrl for compatibility
- Input Field Awareness: Skips shortcuts when typing in text inputs (except global keys like Escape)
- Configurable Bindings: All shortcuts defined in
KeyBindings.tsfor easy customization
Modal Exceptions: Modal dialogs (showAlert, showConfirm, showPrompt) have their own local keyboard handling for Escape/Enter keys. This is intentional as modals are focused, temporary UI elements that require immediate keyboard response and proper cleanup.
// Register a shortcut
keyboardManager.register('Ctrl+S', () => exportFrame(), 'Export frame');
// Register with object notation (uses KeyboardEvent.code)
keyboardManager.register({
code: 'KeyS',
ctrl: true
}, () => exportFrame(), 'Export frame');
// Check if a shortcut is registered
if (keyboardManager.isRegistered('Ctrl+S')) { ... }
// Get all bindings for UI display
const bindings = keyboardManager.getBindings();The application uses a directed acyclic graph (DAG) for media processing:
[Source Nodes] → [Group Nodes] → [Effect Nodes] → [Output]
↓ ↓ ↓
FileSource SequenceGroup RVColor (future)
VideoSource StackGroup RVTransform2D (future)
SequenceSource SwitchGroup
LayoutGroup
Nodes are registered via decorators:
@RegisterNode('RVFileSource')
export class FileSourceNode extends BaseSourceNode { ... }RV session files are parsed using gto-js and reconstructed into the node graph, restoring key session settings such as playback ranges, channel selection, scopes, and paint effects. Exporting .rv/.gto sessions currently preserves playback and annotation data (not the full media graph), and re-exports loaded sessions with UI changes applied.
// Session loads GTO and builds graph
await session.loadFromGTO(fileData);
// Access the reconstructed graph
const graph = session.graph;
const rootNode = session.graphParseResult?.rootNode;# Type check
pnpm typecheck
# Run unit tests (12200+ tests)
pnpm test
# Run e2e tests (requires dev server running)
pnpm dev # in one terminal
npx playwright test # in another terminal
# Build for production
pnpm build
# Preview production build
pnpm previewThe codebase includes comprehensive test coverage with 12200+ unit tests across 294 test files and 103 e2e test suites:
- Color Tools: ColorWheels (46 tests), FalseColor (30 tests), HSLQualifier (57 tests), Curves, CDL, LogCurves (27 tests), DisplayTransfer, DisplayProfileControl
- OCIO: OCIOConfig, OCIOTransform, OCIOProcessor (color space transforms, config parsing, reverse transforms)
- Tone Mapping: Reinhard (white point), Filmic (exposure bias, white point), ACES operator tests
- LUT Presets: Preset generation, identity verification, value ranges, category grouping (16 tests)
- EXR PIZ Codec: Huffman decode, wavelet reconstruction, LUT inverse (39 tests)
- Analysis: ZebraStripes (49 tests), PixelProbe (45+ tests), ClippingOverlay (48 tests), Waveform (50 tests), Histogram (45 tests), Vectorscope (49 tests)
- Overlays: TimecodeOverlay (50 tests), SafeAreasOverlay (46 tests), SpotlightOverlay (62 tests)
- UI Components: ThemeControl, HistoryPanel, InfoPanel, Modal, Button, CurveEditor (33 tests), AutoSaveIndicator (35 tests), TimelineEditor (25 tests), ThumbnailManager (12 tests), BackgroundPatternControl (32 tests), PARControl (13 tests)
- Core: Session, Graph, GTO loading/export, SequenceLoader (88 tests), AutoSaveManager (28 tests), SessionSerializer (35 tests), SnapshotManager (16 tests), PlaylistManager (34 tests)
- Formats: EXRDecoder (multi-layer, channel remapping), HDRDecoder (34 tests), JXLDecoder, HEICGainmapDecoder, HEICWasmDecoder, DecoderRegistry, ChannelSelect (EXR layer UI)
- Render: TextureCacheManager (22 tests), Canvas2DHDRBlit (23 tests)
- Export/Import: AnnotationJSONExporter (33 tests incl. import), AnnotationPDFExporter (21 tests), OTIOParser (42 tests)
- Audio: AudioPlaybackManager (36 tests), WaveformRenderer (35 tests)
- Filters: NoiseReduction (18 tests), WebGLNoiseReduction
- Overlays: MissingFrameOverlay (16 tests), WatermarkOverlay, WatermarkControl
- Utilities: HiDPICanvas (32 tests), EffectProcessor (51 tests), WorkerPool (28 tests), PrerenderBufferManager (36 tests), PixelAspectRatio (28 tests), FullscreenManager (13 tests), PresentationMode (20 tests), FrameInterpolator, CodecUtils, ViewerInteraction
- API: OpenRVAPI (80+ tests covering all sub-modules: Playback, Media, Audio, Loop, View, Color, Markers, Events)
E2E Tests (103 test suites):
- Core: App initialization, tab navigation, media loading, playback controls, session recovery, page visibility handling
- Audio: Volume control, mute/unmute, audio sync, error recovery, keyboard shortcuts (21 tests)
- View: Grayscale toggle (Shift+L/Y), channel isolation, EXR layers, background patterns (14 tests), fullscreen/presentation
- GTO: Round-trip verification (markers, frame ranges, matte, paint effects, metadata, custom nodes)
- Scopes: Histogram, Waveform, Vectorscope, Parade scope
- Color: Color controls, Curves, Vibrance, Highlight/Shadow recovery, Log curves, OCIO
- View: Pixel probe (incl. HDR nits/precision), False color, Zebra stripes, Safe areas, Spotlight, Info panel, Pixel aspect ratio (11 tests)
- Comparison: A/B compare, Wipe modes, Difference matte
- Compositing: Stack Control - layer management, blend modes, opacity, visibility, reordering (44 tests)
- Transform: Rotation, Flip, Crop, Uncrop (9 tests)
- Annotations: Paint tools, Paint coordinates, Text formatting, JSON/PDF export, annotation import (18 tests)
- Export: Frame export, Sequence export, Annotation export
- Timeline: EDL editing, cut manipulation
- Auto-Save: Indicator display, status changes, styling, animations (14 tests)
- Sequences: Image sequence loading, pattern detection (11 tests)
- Codecs: Unsupported codec detection and transcoding guidance
- Scripting API: window.openrv API testing
- Tone Mapping: Per-operator parameter controls, persistence, visual impact (30 tests)
- OTIO Import: Parser validation, playlist integration, UI workflow (20 tests)
- LUT Presets & OCIO Config: Preset browser, custom config loading (12 tests)
- HDR Pixel Probe: Float precision, nits display, out-of-range detection (24 tests)
- Display & Float LUT: GPU display profiles, float LUT shader, compound effects (21 tests)
All canvas-based components support hi-DPI/Retina displays using the HiDPICanvas utility:
import { setupHiDPICanvas, clientToCanvasCoordinates } from '../../utils/HiDPICanvas';
// Setup canvas for hi-DPI rendering
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d')!;
const result = setupHiDPICanvas({
canvas,
ctx,
width: 256, // Logical width (CSS pixels)
height: 100, // Logical height (CSS pixels)
});
// Result contains: { dpr, physicalWidth, physicalHeight, logicalWidth, logicalHeight }
// At 2x DPR: canvas.width = 512, canvas.style.width = '256px'
// Draw using logical coordinates - context is automatically scaled
ctx.fillRect(0, 0, 256, 100); // Fills the entire canvas
// For mouse events, convert client coords to logical canvas coords
canvas.addEventListener('click', (e) => {
const { x, y } = clientToCanvasCoordinates(canvas, e.clientX, e.clientY, 256, 100);
// x, y are in logical coordinates (0-256, 0-100 range)
});Key functions:
setupHiDPICanvas()- Configure canvas for hi-DPI with physical/CSS dimensions and scaled contextresizeHiDPICanvas()- Resize an existing hi-DPI canvas (alias for setup)createHiDPICanvas()- Create a new canvas with hi-DPI supportclientToCanvasCoordinates()- Convert mouse event coords to logical canvas coordslogicalToPhysical()/physicalToLogical()- Coordinate conversion helpers
Important notes for pixel buffer operations:
When using getImageData/putImageData, work in physical pixel coordinates (these bypass the context transform):
// For direct pixel manipulation, use physical dimensions
const physicalWidth = canvas.width; // Not logical width
const physicalHeight = canvas.height;
const imageData = ctx.getImageData(0, 0, physicalWidth, physicalHeight);The rendering pipeline adapts resolution across four layers to balance quality and performance:
Phase 1 — DPI-Aware Canvas: The WebGL canvas renders at physical resolution (logical × devicePixelRatio) while the 2D canvas stays at logical resolution to avoid CPU effect regressions. CSS width/height on the GL canvas maps physical pixels back to logical layout. A matchMedia('(resolution:…)') listener detects DPR changes when windows move between displays. Physical dimensions are capped at MAX_TEXTURE_SIZE proportionally to prevent GL failures.
Phase 2 — Interaction Quality Tiering: During zoom/scrub, InteractionQualityManager drops the GL viewport to 50% of physical resolution via gl.viewport() subrect, restoring full quality 200ms after the last interaction ends. Reference-counted beginInteraction()/endInteraction() handles overlapping interactions (e.g. simultaneous wheel zoom + timeline scrub).
Phase 3 — GL Mipmaps: generateMipmap() is called for RGBA float textures (including 3-channel EXR padded to RGBA) and static SDR images. Guards skip mipmaps for RGB32F (not color-renderable), VideoFrame sources (too expensive per frame), and when OES_texture_float_linear/EXT_color_buffer_float are unavailable.
Phase 4 — Cache-Level Resize: createImageBitmap() resize options downscale frames at extraction time to match display resolution. The frame cache stores a single entry per frame with lazy upgrade: proxy-resolution frames display immediately, then re-extract at full resolution in the background when interaction ends.
Key files: Viewer.ts (dimension state), ViewerGLRenderer.ts (GL canvas sizing), Renderer.ts (mipmaps, viewport), InteractionQualityManager.ts (quality tiering), MediabunnyFrameExtractor.ts (cache-level resize).
- Create node class extending
IPNodeorBaseGroupNode - Add
@RegisterNode('NodeType')decorator - Implement
process()method - Import in
src/nodes/<category>/index.ts
Example:
import { RegisterNode } from '../base/NodeFactory';
import { BaseGroupNode } from './BaseGroupNode';
@RegisterNode('RVMyGroup')
export class MyGroupNode extends BaseGroupNode {
constructor(name?: string) {
super('RVMyGroup', name ?? 'My Group');
this.properties.add({ name: 'myProp', defaultValue: 0 });
}
getActiveInputIndex(context: EvalContext): number {
return 0;
}
}- TypeScript - Type-safe development
- Vite - Fast bundler with HMR
- Vitest - Unit testing framework
- Playwright - End-to-end testing
- WebGL2 - GPU-accelerated rendering (tone mapping, LUT processing, color transforms)
- WebAssembly - High-performance EXR and JPEG XL decoding
- WebCodecs API - Frame-accurate video decoding via mediabunny
- Web Audio API - Audio playback, waveform generation, volume control, and pitch correction
- Fullscreen API - Native fullscreen and presentation modes
- Mediabunny - Also used for audio extraction fallback when native fetch is blocked by CORS
- @jsquash/jxl - JPEG XL WebAssembly decoder (libjxl)
- libheif-js - HEIC/HEIF WebAssembly decoder (libheif) for cross-browser support
- gto-js - RV/GTO file parsing
- gl-matrix - Matrix/vector math
Requires WebGL2 support:
- Chrome 56+
- Firefox 51+
- Safari 15+
- Edge 79+
Hi-DPI/Retina displays are fully supported with automatic detection of devicePixelRatio. All canvas-based UI components (scopes, color wheels, curve editor, overlays) render at native resolution for crisp display on 2x, 3x, and fractional DPR screens.
MIT