Token导航 LogoToken导航TokenDH.com
研究检索操作浏览器github未标认证来源可访问clear审计通过

video-producer视频制作人

Agent Skill

用于辅助视频生成、动画合成、脚本化剪辑或 Remotion 等视频项目开发。它适合让 Agent 组织镜头、生成素材说明、维护合成代码或排查渲染问题。使用时需要确认分辨率、时长、素材路径和导出格式;涉及外部素材、人物肖像或商业发布时,应先核对版权授权和内容审核要求。

总安装

9,211

周安装

380

GitHub Stars

25

下载量

3,010
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

3

许可证

MIT

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:video-producer(视频制作人)
来源仓库:https://github.com/daffy0208/ai-dev-standards
仓库路径:skills/video-producer
安装命令:
npx skills add https://github.com/daffy0208/ai-dev-standards --skill video-producer
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。不同来源提供的安装方式可能略有差异;本站展示可直接复制的安装命令,安装前请核对来源页面。

skills.shnpx skills
npx skills add https://github.com/daffy0208/ai-dev-standards --skill video-producer

简介

具有自适应流媒体、质量选择和播放控制的自定义视频播放器。

  • 支持 HLS 自适应比特率流媒体,具有自动质量切换和错误恢复功能,以及本机 Safari 回退功能
  • 包括全屏、画中画、音量控制、播放速度调节和字幕/字幕轨道
  • 提供质量选择 UI、悬停缩略图预览以及带进度跟踪的视频上传
  • 使用 React hooks 和 hls.js 库构建,以实现跨浏览器兼容性

SKILL.md

Video Producer Skill

I help you build video players, handle video streaming, and create engaging video experiences.

What I Do

Video Playback:

  • Custom video players with controls
  • Adaptive bitrate streaming (HLS, DASH)
  • Picture-in-picture mode
  • Fullscreen support

Video Features:

  • Subtitles and captions
  • Quality selection
  • Playback speed control
  • Thumbnail previews

Streaming:

  • Live video streaming
  • Video on demand (VOD)
  • Progressive download
  • Adaptive streaming

Custom Video Player

// components/VideoPlayer.tsx
'use client'
import { useRef, useState, useEffect } from 'react'

interface VideoPlayerProps {
  src: string
  poster?: string
  title?: string
}

export function VideoPlayer({ src, poster, title }: VideoPlayerProps) {
  const videoRef = useRef<HTMLVideoElement>(null)
  const [playing, setPlaying] = useState(false)
  const [currentTime, setCurrentTime] = useState(0)
  const [duration, setDuration] = useState(0)
  const [volume, setVolume] = useState(1)
  const [fullscreen, setFullscreen] = useState(false)
  const [showControls, setShowControls] = useState(true)

  useEffect(() => {
    const video = videoRef.current
    if (!video) return

    const updateTime = () => setCurrentTime(video.currentTime)
    const updateDuration = () => setDuration(video.duration)
    const handleEnded = () => setPlaying(false)

    video.addEventListener('timeupdate', updateTime)
    video.addEventListener('loadedmetadata', updateDuration)
    video.addEventListener('ended', handleEnded)

    return () => {
      video.removeEventListener('timeupdate', updateTime)
      video.removeEventListener('loadedmetadata', updateDuration)
      video.removeEventListener('ended', handleEnded)
    }
  }, [])

  const togglePlay = () => {
    if (!videoRef.current) return

    if (playing) {
      videoRef.current.pause()
    } else {
      videoRef.current.play()
    }
    setPlaying(!playing)
  }

  const handleSeek = (e: React.ChangeEvent<HTMLInputElement>) => {
    const time = parseFloat(e.target.value)
    setCurrentTime(time)
    if (videoRef.current) {
      videoRef.current.currentTime = time
    }
  }

  const handleVolumeChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    const vol = parseFloat(e.target.value)
    setVolume(vol)
    if (videoRef.current) {
      videoRef.current.volume = vol
    }
  }

  const toggleFullscreen = () => {
    if (!videoRef.current) return

    if (!fullscreen) {
      videoRef.current.requestFullscreen()
    } else {
      document.exitFullscreen()
    }
    setFullscreen(!fullscreen)
  }

  const formatTime = (seconds: number) => {
    const mins = Math.floor(seconds / 60)
    const secs = Math.floor(seconds % 60)
    return `${mins}:${secs.toString().padStart(2, '0')}`
  }

  return (
    <div
      className="relative bg-black rounded-lg overflow-hidden"
      onMouseEnter={() => setShowControls(true)}
      onMouseLeave={() => setShowControls(playing ? false : true)}
    >
      {title && (
        <div className="absolute top-0 left-0 right-0 p-4 bg-gradient-to-b from-black/70 to-transparent z-10">
          <h3 className="text-white font-semibold">{title}</h3>
        </div>
      )}

      <video
        ref={videoRef}
        src={src}
        poster={poster}
        onClick={togglePlay}
        className="w-full"
      />

      {showControls && (
        <div className="absolute bottom-0 left-0 right-0 p-4 bg-gradient-to-t from-black/70 to-transparent">
          {/* Progress Bar */}
          <input
            type="range"
            min="0"
            max={duration || 0}
            value={currentTime}
            onChange={handleSeek}
            className="w-full mb-2"
          />

          <div className="flex items-center gap-4">
            {/* Play/Pause */}
            <button
              onClick={togglePlay}
              className="text-white text-2xl hover:scale-110 transition"
            >
              {playing ? '⏸️' : '▶️'}
            </button>

            {/* Time */}
            <span className="text-white text-sm">
              {formatTime(currentTime)} / {formatTime(duration)}
            </span>

            {/* Volume */}
            <div className="flex items-center gap-2">
              <span className="text-white">🔊</span>
              <input
                type="range"
                min="0"
                max="1"
                step="0.1"
                value={volume}
                onChange={handleVolumeChange}
                className="w-20"
              />
            </div>

            <div className="flex-1" />

            {/* Fullscreen */}
            <button
              onClick={toggleFullscreen}
              className="text-white hover:scale-110 transition"
            >
              {fullscreen ? '⬛' : '⬜'}
            </button>
          </div>
        </div>
      )}
    </div>
  )
}

HLS Streaming (Adaptive Bitrate)

npm install hls.js
// components/HLSPlayer.tsx
'use client'
import { useEffect, useRef } from 'react'
import Hls from 'hls.js'

export function HLSPlayer({ src }: { src: string }) {
  const videoRef = useRef<HTMLVideoElement>(null)

  useEffect(() => {
    const video = videoRef.current
    if (!video) return

    if (Hls.isSupported()) {
      const hls = new Hls({
        enableWorker: true,
        lowLatencyMode: true
      })

      hls.loadSource(src)
      hls.attachMedia(video)

      hls.on(Hls.Events.MANIFEST_PARSED, () => {
        console.log('HLS manifest loaded, quality levels:', hls.levels)
      })

      hls.on(Hls.Events.ERROR, (event, data) => {
        console.error('HLS error:', data)
        if (data.fatal) {
          switch (data.type) {
            case Hls.ErrorTypes.NETWORK_ERROR:
              hls.startLoad()
              break
            case Hls.ErrorTypes.MEDIA_ERROR:
              hls.recoverMediaError()
              break
            default:
              hls.destroy()
              break
          }
        }
      })

      return () => {
        hls.destroy()
      }
    } else if (video.canPlayType('application/vnd.apple.mpegurl')) {
      // Native HLS support (Safari)
      video.src = src
    }
  }, [src])

  return <video ref={videoRef} controls className="w-full" />
}

Picture-in-Picture

// components/PIPVideoPlayer.tsx
'use client'
import { useRef, useState } from 'react'

export function PIPVideoPlayer({ src }: { src: string }) {
  const videoRef = useRef<HTMLVideoElement>(null)
  const [pipActive, setPipActive] = useState(false)

  const togglePIP = async () => {
    if (!videoRef.current) return

    try {
      if (!pipActive) {
        await videoRef.current.requestPictureInPicture()
        setPipActive(true)
      } else {
        await document.exitPictureInPicture()
        setPipActive(false)
      }
    } catch (error) {
      console.error('PIP error:', error)
    }
  }

  return (
    <div>
      <video ref={videoRef} src={src} controls className="w-full" />

      <button
        onClick={togglePIP}
        className="mt-4 px-4 py-2 bg-blue-600 text-white rounded"
      >
        {pipActive ? 'Exit PIP' : 'Enter PIP'}
      </button>
    </div>
  )
}

Subtitles/Captions

// components/VideoWithSubtitles.tsx
'use client'
export function VideoWithSubtitles() {
  return (
    <video controls className="w-full">
      <source src="/video.mp4" type="video/mp4" />

      <track
        kind="subtitles"
        src="/subtitles/en.vtt"
        srcLang="en"
        label="English"
        default
      />
      <track
        kind="subtitles"
        src="/subtitles/es.vtt"
        srcLang="es"
        label="Español"
      />
      <track
        kind="subtitles"
        src="/subtitles/fr.vtt"
        srcLang="fr"
        label="Français"
      />
    </video>
  )
}

VTT Subtitle File:

WEBVTT

00:00:00.000 --> 00:00:02.000
Hello, welcome to our video.

00:00:02.500 --> 00:00:05.000
Today we'll learn about web development.

00:00:05.500 --> 00:00:08.000
Let's get started!

Quality Selection

// components/QualitySelector.tsx
'use client'
import { useState } from 'react'

const qualities = [
  { label: '1080p', src: '/video-1080p.mp4' },
  { label: '720p', src: '/video-720p.mp4' },
  { label: '480p', src: '/video-480p.mp4' },
  { label: '360p', src: '/video-360p.mp4' }
]

export function QualitySelector() {
  const [currentQuality, setCurrentQuality] = useState(qualities[1])

  return (
    <div>
      <video src={currentQuality.src} controls className="w-full" />

      <div className="mt-4">
        <label className="mr-2">Quality:</label>
        <select
          value={currentQuality.label}
          onChange={(e) => {
            const quality = qualities.find(q => q.label === e.target.value)
            if (quality) setCurrentQuality(quality)
          }}
          className="px-4 py-2 border rounded"
        >
          {qualities.map((q) => (
            <option key={q.label} value={q.label}>
              {q.label}
            </option>
          ))}
        </select>
      </div>
    </div>
  )
}

Playback Speed Control

// components/PlaybackSpeed.tsx
'use client'
import { useRef, useState } from 'react'

const speeds = [0.5, 0.75, 1, 1.25, 1.5, 2]

export function PlaybackSpeed({ src }: { src: string }) {
  const videoRef = useRef<HTMLVideoElement>(null)
  const [speed, setSpeed] = useState(1)

  const handleSpeedChange = (newSpeed: number) => {
    setSpeed(newSpeed)
    if (videoRef.current) {
      videoRef.current.playbackRate = newSpeed
    }
  }

  return (
    <div>
      <video ref={videoRef} src={src} controls className="w-full" />

      <div className="mt-4 flex gap-2">
        <span>Speed:</span>
        {speeds.map((s) => (
          <button
            key={s}
            onClick={() => handleSpeedChange(s)}
            className={`px-3 py-1 rounded ${
              speed === s ? 'bg-blue-600 text-white' : 'bg-gray-200'
            }`}
          >
            {s}x
          </button>
        ))}
      </div>
    </div>
  )
}

Video Thumbnail on Hover

// components/VideoThumbnailPreview.tsx
'use client'
import { useState } from 'react'

export function VideoThumbnailPreview({ videoSrc }: { videoSrc: string }) {
  const [thumbnailTime, setThumbnailTime] = useState(0)

  const handleProgressHover = (e: React.MouseEvent<HTMLDivElement>) => {
    const rect = e.currentTarget.getBoundingClientRect()
    const percent = (e.clientX - rect.left) / rect.width
    // Assuming 60 second video
    setThumbnailTime(percent * 60)
  }

  return (
    <div className="relative">
      <div
        onMouseMove={handleProgressHover}
        className="h-2 bg-gray-300 rounded cursor-pointer relative"
      >
        {/* Thumbnail preview */}
        <div
          className="absolute bottom-4 -translate-x-1/2 pointer-events-none"
          style={{ left: `${(thumbnailTime / 60) * 100}%` }}
        >
          <video
            src={videoSrc}
            className="w-40 h-24 object-cover rounded shadow-lg"
            muted
            currentTime={thumbnailTime}
          />
          <span className="block text-center text-sm mt-1">
            {Math.floor(thumbnailTime)}s
          </span>
        </div>
      </div>

      <video src={videoSrc} controls className="w-full mt-4" />
    </div>
  )
}

Video Upload with Progress

// components/VideoUpload.tsx
'use client'
import { useState } from 'react'

export function VideoUpload() {
  const [uploading, setUploading] = useState(false)
  const [progress, setProgress] = useState(0)
  const [videoURL, setVideoURL] = useState<string | null>(null)

  const handleUpload = async (e: React.ChangeEvent<HTMLInputElement>) => {
    const file = e.target.files?.[0]
    if (!file) return

    setUploading(true)
    setProgress(0)

    const formData = new FormData()
    formData.append('video', file)

    const xhr = new XMLHttpRequest()

    xhr.upload.addEventListener('progress', (e) => {
      if (e.lengthComputable) {
        const percentComplete = (e.loaded / e.total) * 100
        setProgress(percentComplete)
      }
    })

    xhr.addEventListener('load', () => {
      if (xhr.status === 200) {
        const response = JSON.parse(xhr.responseText)
        setVideoURL(response.url)
      }
      setUploading(false)
    })

    xhr.open('POST', '/api/upload/video')
    xhr.send(formData)
  }

  return (
    <div>
      <input
        type="file"
        accept="video/*"
        onChange={handleUpload}
        disabled={uploading}
        className="mb-4"
      />

      {uploading && (
        <div className="mb-4">
          <div className="h-2 bg-gray-200 rounded overflow-hidden">
            <div
              className="h-full bg-blue-600 transition-all"
              style={{ width: `${progress}%` }}
            />
          </div>
          <p className="text-sm text-gray-600 mt-1">
            Uploading: {Math.round(progress)}%
          </p>
        </div>
      )}

      {videoURL && (
        <video src={videoURL} controls className="w-full" />
      )}
    </div>
  )
}

When to Use Me

Perfect for:

  • Building video platforms
  • Adding video content
  • Implementing video streaming
  • Creating video courses
  • Building video players

I'll help you:

  • Build custom video players
  • Implement HLS streaming
  • Add subtitles/captions
  • Support multiple qualities
  • Handle video uploads

What I'll Create

🎥 Custom Video Players
📺 HLS/Adaptive Streaming
📝 Subtitles & Captions
⚙️ Quality Selection
⏩ Playback Speed Control
🖼️ Picture-in-Picture

Let's create amazing video experiences!

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

04

需要参考平台分布和安装热度时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

补充不同宿主或平台的使用分布数据

能力 5

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Claude Code

31.51%
按下载量换算948

OpenCode

22.95%
按下载量换算691

Gemini CLI

18.97%
按下载量换算571

Antigravity

12.84%
按下载量换算386

Codex

7.96%
按下载量换算240

Cursor

3.68%
按下载量换算111

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

操作浏览器

该 Skill 可能涉及浏览器控制能力,使用时可能读取或操作网页内容,需要在受控环境中确认权限边界。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。

来源信息

继续浏览同类 Skills