feat: Create BroadcastStudio component as the main UI container for broadcasting feat: Develop ControlPanel component for managing broadcast controls and layouts feat: Add LiveKitBroadcastWrapper to encapsulate LiveKitRoom and manage broadcasting feat: Implement StreamView component for rendering video output with overlays and layouts feat: Create SceneContext for managing scene configurations and layouts chore: Update index exports for broadcast components
6.3 KiB
LiveKit Broadcast Studio UI - Documentación
📋 Descripción General
Sistema de interfaz de usuario para un estudio de producción de video en vivo estilo StreamYard, construido con React, TypeScript y LiveKit Components.
🏗️ Arquitectura
Estructura de Componentes
BroadcastStudio (Contenedor Principal)
├── SceneProvider (Context)
│ ├── StreamView (Visualización - CONSUMIDOR)
│ │ ├── Layouts dinámicos basados en sceneConfig
│ │ ├── Renderizado de participantes (LiveKit)
│ │ └── Overlays (logos, lower thirds)
│ │
│ └── ControlPanel (Controles - MODIFICADOR)
│ ├── LocalControls (Izquierda - Vista local + Presentar)
│ ├── ScrollableLayoutsContainer (Centro - Botones de layouts)
│ └── ActionControls (Derecha - Config y recursos)
Sistema de Estado (SceneContext)
Ubicación: src/context/SceneContext.tsx
El contexto centralizado gestiona toda la configuración de escenas:
interface SceneConfig {
participantLayout: ParticipantLayoutType // Tipo de layout activo
mediaSource: MediaSourceType | null // Contenido adicional (screen, file, etc)
overlays: OverlayConfig // Logos, lower thirds, etc
}
Regla de oro:
- ControlPanel: Único componente que MODIFICA
sceneConfig - StreamView: Único componente que CONSUME
sceneConfigpara renderizar
🎨 Componentes Principales
1. StreamView
Archivo: src/components/broadcast/StreamView.tsx
Renderiza la salida final de video en formato 16:9.
Características:
- Aspecto ratio fijo 16:9 (
aspect-ratio: 16 / 9) - 6 layouts predefinidos:
grid_4: Grid 2×2grid_6: Grid 3×2focus_side: Foco principal + sidebarside_by_side: Dos participantes lado a ladopresentation: Pantalla compartida + speaker pequeñosingle_speaker: Un solo participante
- Sistema de overlays configurable
- Integración con hooks de LiveKit (
useParticipants,useTracks)
2. ControlPanel
Archivo: src/components/broadcast/ControlPanel.tsx
Panel de control interactivo dividido en 3 secciones.
Estructura CSS:
.control-panel-wrapper {
display: flex;
justify-content: space-between;
align-items: flex-end;
}
2.1 LocalControls (Izquierda)
- Vista previa del usuario local
- Botón "Presentar"
flex-shrink: 0(ancho fijo)
2.2 ScrollableLayoutsContainer (Centro)
- Scroll horizontal de botones de layouts
flex-grow: 1; overflow-x: auto; overflow-y: hidden- Botones con
flex-shrink: 0en fila única
2.3 ActionControls (Derecha)
- Botones de acción (Editor, Config, Añadir)
flex-shrink: 0(ancho fijo)
3. BroadcastStudio
Archivo: src/components/broadcast/BroadcastStudio.tsx
Contenedor principal que alinea todo.
CSS clave:
.main-app-container {
display: flex;
flex-direction: column;
align-items: center;
}
.stream-view-container,
.control-panel-wrapper {
width: 100%;
max-width: 1200px; /* Mismo ancho máximo para ambos */
}
4. LiveKitBroadcastWrapper
Archivo: src/components/broadcast/LiveKitBroadcastWrapper.tsx
Wrapper que conecta el BroadcastStudio con LiveKit.
🔧 Uso
Integración Básica
import { LiveKitBroadcastWrapper } from './components/broadcast'
function App() {
return (
<LiveKitBroadcastWrapper
token="your-livekit-token"
serverUrl="wss://your-server.com"
userName="Usuario"
roomName="sala-demo"
onDisconnect={() => console.log('Desconectado')}
/>
)
}
Uso Standalone (sin LiveKit)
import { BroadcastStudio } from './components/broadcast'
import { LiveKitRoom } from '@livekit/components-react'
function App() {
return (
<LiveKitRoom token={token} serverUrl={serverUrl}>
<BroadcastStudio />
</LiveKitRoom>
)
}
Acceso al Contexto de Escenas
import { useScene } from './context/SceneContext'
function MiComponente() {
const { sceneConfig, applyPreset, updateOverlays } = useScene()
// Aplicar un preset
const handleChangeLayout = () => {
applyPreset('FOCUS_SIDE')
}
// Actualizar overlays
const handleToggleLogo = () => {
updateOverlays({ showLogo: !sceneConfig.overlays.showLogo })
}
return (...)
}
📦 Presets de Layouts
Definidos en SceneContext.tsx:
PRESET_LAYOUTS = {
GRID_4: { participantLayout: 'grid_4', ... },
GRID_6: { participantLayout: 'grid_6', ... },
FOCUS_SIDE: { participantLayout: 'focus_side', ... },
SIDE_BY_SIDE: { participantLayout: 'side_by_side', ... },
PRESENTATION: { participantLayout: 'presentation', ... },
SINGLE_SPEAKER: { participantLayout: 'single_speaker', ... },
}
🎯 Próximos Pasos
Features Pendientes
- Integración con LiveKit Egress para grabación/streaming
- Editor visual de escenas (modal con drag & drop)
- Gestión de overlays personalizado
- Soporte para múltiples cámaras por participante
- Transiciones animadas entre layouts
- Guardado/carga de escenas personalizadas
Mejoras de UX
- Tooltips informativos en botones de layout
- Preview en miniatura de cada layout
- Keyboard shortcuts para cambio rápido
- Indicador visual del layout activo más prominente
- Confirmación antes de cambios críticos
🐛 Debugging
Verificar estado de escenas
// En DevTools Console:
window.__SCENE_DEBUG__ = true
// O agregar en tu componente:
console.log('[SceneDebug]', sceneConfig)
Logs de LiveKit
Los hooks de LiveKit (useParticipants, useTracks) ya incluyen logs internos.
Para más detalle, habilitar en LiveKitRoom:
<LiveKitRoom logLevel="debug" ... />
📝 Notas de Implementación
- Aspecto Ratio: StreamView usa
aspect-ratio: 16/9nativo de CSS (compatibilidad moderna) - Scroll Horizontal: El scroll en LayoutsContainer es solo horizontal para mejor UX
- Flexibilidad: Todos los componentes son modulares y pueden usarse independientemente
- Performance: Los layouts se renderizan condicionalmente para evitar re-renders innecesarios
- TypeScript: Todo el código está fuertemente tipado para mejor DX
Creado el: 7 de noviembre de 2025
Versión: 1.0.0
Stack: React + TypeScript + LiveKit + Tailwind CSS