livestream-engineer
Expert in live streaming, WebRTC, and real-time video/audio
What this skill does
# Livestream Engineer Skill
I help you build live streaming features, implement WebRTC, and create real-time broadcasting experiences.
## What I Do
**Live Streaming:**
- WebRTC peer-to-peer video
- Live broadcasting
- Screen sharing
- Real-time chat
**Streaming Platforms:**
- Twitch-style streaming
- Video conferencing
- Live events
- Webinars
## WebRTC Basics
### Peer-to-Peer Video Call
```typescript
// lib/webrtc.ts
export class WebRTCConnection {
private peerConnection: RTCPeerConnection
private localStream: MediaStream | null = null
constructor() {
this.peerConnection = new RTCPeerConnection({
iceServers: [{ urls: 'stun:stun.l.google.com:19302' }]
})
}
async startLocalStream() {
try {
this.localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true
})
this.localStream.getTracks().forEach(track => {
this.peerConnection.addTrack(track, this.localStream!)
})
return this.localStream
} catch (error) {
console.error('Failed to get local stream:', error)
throw error
}
}
async createOffer() {
const offer = await this.peerConnection.createOffer()
await this.peerConnection.setLocalDescription(offer)
return offer
}
async handleAnswer(answer: RTCSessionDescriptionInit) {
await this.peerConnection.setRemoteDescription(answer)
}
async handleOffer(offer: RTCSessionDescriptionInit) {
await this.peerConnection.setRemoteDescription(offer)
const answer = await this.peerConnection.createAnswer()
await this.peerConnection.setLocalDescription(answer)
return answer
}
addIceCandidate(candidate: RTCIceCandidateInit) {
return this.peerConnection.addIceCandidate(candidate)
}
onTrack(callback: (stream: MediaStream) => void) {
this.peerConnection.ontrack = event => {
callback(event.streams[0])
}
}
onIceCandidate(callback: (candidate: RTCIceCandidate) => void) {
this.peerConnection.onicecandidate = event => {
if (event.candidate) {
callback(event.candidate)
}
}
}
close() {
this.localStream?.getTracks().forEach(track => track.stop())
this.peerConnection.close()
}
}
```
**Usage:**
```typescript
'use client'
import { useEffect, useRef, useState } from 'react'
import { WebRTCConnection } from '@/lib/webrtc'
export function VideoCall() {
const localVideoRef = useRef<HTMLVideoElement>(null)
const remoteVideoRef = useRef<HTMLVideoElement>(null)
const [connection] = useState(() => new WebRTCConnection())
useEffect(() => {
const init = async () => {
// Start local stream
const stream = await connection.startLocalStream()
if (localVideoRef.current) {
localVideoRef.current.srcObject = stream
}
// Handle remote stream
connection.onTrack((remoteStream) => {
if (remoteVideoRef.current) {
remoteVideoRef.current.srcObject = remoteStream
}
})
// Handle ICE candidates
connection.onIceCandidate((candidate) => {
// Send candidate to other peer via signaling server
socket.emit('ice-candidate', candidate)
})
}
init()
return () => {
connection.close()
}
}, [connection])
return (
<div className="grid grid-cols-2 gap-4">
<div>
<h3>You</h3>
<video ref={localVideoRef} autoPlay muted className="w-full" />
</div>
<div>
<h3>Remote</h3>
<video ref={remoteVideoRef} autoPlay className="w-full" />
</div>
</div>
)
}
```
---
## Screen Sharing
```typescript
'use client'
import { useRef, useState } from 'react'
export function ScreenShare() {
const videoRef = useRef<HTMLVideoElement>(null)
const [sharing, setSharing] = useState(false)
const [stream, setStream] = useState<MediaStream | null>(null)
const startSharing = async () => {
try {
const mediaStream = await navigator.mediaDevices.getDisplayMedia({
video: {
cursor: 'always'
},
audio: false
})
setStream(mediaStream)
if (videoRef.current) {
videoRef.current.srcObject = mediaStream
}
setSharing(true)
// Handle when user stops sharing via browser UI
mediaStream.getVideoTracks()[0].onended = () => {
stopSharing()
}
} catch (error) {
console.error('Failed to start screen sharing:', error)
}
}
const stopSharing = () => {
stream?.getTracks().forEach(track => track.stop())
setStream(null)
setSharing(false)
}
return (
<div>
<video ref={videoRef} autoPlay className="w-full bg-black rounded" />
<button
onClick={sharing ? stopSharing : startSharing}
className={`mt-4 px-6 py-3 rounded ${
sharing ? 'bg-red-600' : 'bg-blue-600'
} text-white`}
>
{sharing ? 'โน๏ธ Stop Sharing' : '๐ฅ๏ธ Share Screen'}
</button>
</div>
)
}
```
---
## Live Streaming with Chat
```typescript
// components/LiveStream.tsx
'use client'
import { useState, useEffect, useRef } from 'react'
import { io, Socket } from 'socket.io-client'
interface ChatMessage {
user: string
message: string
timestamp: Date
}
export function LiveStream({ streamId }: { streamId: string }) {
const videoRef = useRef<HTMLVideoElement>(null)
const [socket, setSocket] = useState<Socket | null>(null)
const [messages, setMessages] = useState<ChatMessage[]>([])
const [messageInput, setMessageInput] = useState('')
const [viewers, setViewers] = useState(0)
useEffect(() => {
// Connect to streaming server
const newSocket = io('wss://streaming-server.com')
setSocket(newSocket)
// Join stream room
newSocket.emit('join-stream', streamId)
// Receive viewer count
newSocket.on('viewer-count', (count: number) => {
setViewers(count)
})
// Receive chat messages
newSocket.on('chat-message', (msg: ChatMessage) => {
setMessages(prev => [...prev, msg])
})
// Receive video stream chunks (simplified)
newSocket.on('stream-data', (data: ArrayBuffer) => {
// Handle stream data
})
return () => {
newSocket.disconnect()
}
}, [streamId])
const sendMessage = () => {
if (!socket || !messageInput.trim()) return
socket.emit('chat-message', {
user: 'Anonymous',
message: messageInput,
timestamp: new Date()
})
setMessageInput('')
}
return (
<div className="grid md:grid-cols-3 gap-4">
{/* Video Player */}
<div className="md:col-span-2">
<div className="bg-black rounded-lg overflow-hidden">
<video
ref={videoRef}
autoPlay
controls
className="w-full aspect-video"
/>
<div className="p-4 bg-gray-900 text-white">
<h2 className="text-xl font-bold">Live Stream Title</h2>
<p className="text-sm text-gray-400">
๐ด {viewers} watching now
</p>
</div>
</div>
</div>
{/* Chat */}
<div className="flex flex-col h-[600px]">
<div className="bg-gray-100 p-4 rounded-t-lg font-semibold">
Live Chat
</div>
<div className="flex-1 overflow-y-auto p-4 bg-white border-x">
{messages.map((msg, i) => (
<div key={i} className="mb-3">
<span className="font-semibold text-blue-600">{msg.user}:</span>
<span className="ml-2">{msg.message}</span>
</div>
))}
</div>
<div className="p-4 bg-gray-100 rounded-b-lg">
<input
type="text"
value={messageInput}
onChange={(e) => setMessageInput(e.target.value)}
onKeyPress={(e) => e.key === 'Enter' && sendMessage()}
placeholder="Say something..."
className="w-full px-4 py-2 border rounded"
/>
</divRelated in Image & Video
watch
IncludedWatch a video (URL or local path). Downloads with yt-dlp, extracts auto-scaled frames with ffmpeg, pulls the transcript from captions (or Whisper API fallback), and hands the result to Claude so it can answer questions about what's in the video.
physical-ai-defect-image-generation
IncludedUse when the user wants to orchestrate defect image generation, run associated setup, or handle outputs on OSMO. The Day 0 path handles cold-start with USD-to-ROI, image-edit augmentation, and AnomalyGen to create initial PCBA datasets. The Day 1 path performs inference and labeling on real images. This skill helps with first-time asset setup, creation of finetuning checkpoints, and configuring deployment. Trigger keywords: defect image generation, dig workflow, dig pipeline, defect image detection workflow, aoi pipeline, aoi anomalygen, usd2roi anomalygen, day 0 pcba, day 1 pcba, day 1 real-photo alignment, day 1 manual roi, metal surface anomaly, glass defect, anomalygen finetune, setup_pcb, setup_metal, setup_glass, setup_pretrained, dig setup, dig datasets, dig pretrained checkpoint, dig image-edit endpoint.
accelint-react-best-practices
IncludedReact performance optimization and best practices. ALWAYS use this skill when working with any React code - writing components, hooks, JSX; refactoring; optimizing re-renders, memoization, state management; reviewing for performance; fixing hydration mismatches; debugging infinite re-renders, stale closures, input focus loss, animations restarting; preventing remounting; implementing transitions, lazy initialization, effect dependencies. Even simple React tasks benefit from these patterns. Covers React 19+ (useEffectEvent, Activity, ref props). Triggers - useEffect, useState, useMemo, useCallback, memo, inline components, nested components, components inside components, re-render, performance, hydration, SSR, Next.js, useDeferredValue, combined hooks.
elevenlabs-agents
IncludedBuild conversational AI voice agents with ElevenLabs Platform using React, JavaScript, React Native, or Swift SDKs. Configure agents, tools (client/server/MCP), RAG knowledge bases, multi-voice, and Scribe real-time STT. Use when: building voice chat interfaces, implementing AI phone agents with Twilio, configuring agent workflows or tools, adding RAG knowledge bases, testing with CLI "agents as code", or troubleshooting deprecated @11labs packages, Android audio cutoff, CSP violations, dynamic variables, or WebRTC config. Keywords: ElevenLabs Agents, ElevenLabs voice agents, AI voice agents, conversational AI, @elevenlabs/react, @elevenlabs/client, @elevenlabs/react-native, @elevenlabs/elevenlabs-js, @elevenlabs/agents-cli, elevenlabs SDK, voice AI, TTS, text-to-speech, ASR, speech recognition, turn-taking model, WebRTC voice, WebSocket voice, ElevenLabs conversation, agent system prompt, agent tools, agent knowledge base, RAG voice agents, multi-voice agents, pronunciation dictionary, voice speed control, elevenlabs scribe, @11labs deprecated, Android audio cutoff, CSP violation elevenlabs, dynamic variables elevenlabs, case-sensitive tool names, webhook authentication
humanizer
IncludedHumanize AI-generated text by detecting and removing patterns typical of LLM output. Rewrites text to sound natural, specific, and human. Uses 28 pattern detectors, 560+ AI vocabulary terms across 3 tiers, and statistical analysis (burstiness, type-token ratio, readability) for comprehensive detection. Use when asked to humanize text, de-AI writing, make content sound more natural/human, review writing for AI patterns, score text for AI detection, or improve AI-generated drafts. Covers content, language, style, communication, and filler categories.
generating-mermaid-diagrams
IncludedSalesforce architecture diagrams using Mermaid with ASCII fallback. Use this skill when generating text-based diagrams for Salesforce architecture, OAuth flows, ERDs, integration sequences, or Agentforce structure. TRIGGER when: user says "diagram", "visualize", "ERD", or asks for sequence diagrams, flowcharts, class diagrams, or architecture visualizations in Mermaid. DO NOT TRIGGER when: user wants PNG/SVG image output (use generating-visual-diagrams), or asks about non-Salesforce systems.