agentsclimarketplace

Tutorial video

Skill tinh2/skills-hub-registry/build/tutorial-video

Create Fireship-quality developer tutorial videos from annotated markdown and terminal recordings. Animated code transitions (Code Hike + Shiki Magic Move), terminal replay (Asciinema), auto-zoom effects, AI voiceover (Qwen3-TTS or ElevenLabs), progress bar with chapters, webcam/avatar PiP, step annotations, and social format export. Full pipeline from markdown to rendered MP4 via Remotion.From its SKILL.md

Install
npx -y skills add tinh2/skills-hub-registry --skill tutorial-video

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 12 stars12 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

20.4 KB, ~5.6k tokens by cl100k_base, as published. Nobody here has run it

Tutorial Video

Create polished developer tutorial videos from markdown and terminal recordings. Write your tutorial as annotated markdown, record your terminal with Asciinema, and get a Fireship-quality MP4.

Prerequisites

Requires the video-toolkit skill to be installed (for voiceover, image generation, talking head, cloud GPU endpoints). Also requires the remotion skill for composition patterns.

Setup

Step 1: Check State

TOOLKIT=~/.openclaw/workspace/claude-code-video-toolkit
cd $TOOLKIT
python3 tools/verify_setup.py

Step 2: Install Dependencies

cd $TOOLKIT
pip3 install --break-system-packages -r tools/requirements-tutorial.txt
npm install -g asciinema  # Or: brew install asciinema

Step 3: Verify Cloud GPU Endpoints

Confirm .env in $TOOLKIT has Modal endpoint URLs configured (see video-toolkit skill for full setup). At minimum you need MODAL_QWEN3_TTS_ENDPOINT_URL. If using AI avatar, also MODAL_FLUX2_ENDPOINT_URL and MODAL_SADTALKER_ENDPOINT_URL.

Step 4: Verify Code Hike + Shiki

cd $TOOLKIT/templates/tutorial
npm install
npx remotion studio  # Should open with sample tutorial

Creating a Tutorial Video

Step 1: Write Annotated Markdown

Create tutorial.md using Code Hike format:

!!steps

## Setting Up the Project

Create a new Hono project with the Cloudflare Workers template.

\`\`\`ts ! src/index.ts
import { Hono } from 'hono'

const app = new Hono()

export default app
\`\`\`

## Adding Your First Route

Add a GET route that returns JSON.

\`\`\`ts ! src/index.ts
import { Hono } from 'hono'

const app = new Hono()

// !mark(1:3)
app.get('/', (c) => {
  return c.json({ message: 'Hello Hono!' })
})

export default app
\`\`\`

Each ## Heading becomes a video step. Text below the heading becomes voiceover narration. Code blocks animate between states with Shiki Magic Move.

Step 2: Record Terminal Demos

# Record a terminal session
asciinema rec recordings/01-setup.cast

# Replay to verify
asciinema play recordings/01-setup.cast

Step 3: Create Project

cd $TOOLKIT
cp -r templates/tutorial projects/MY_TUTORIAL
cd projects/MY_TUTORIAL
npm install

Step 4: Write Config

Edit src/config/tutorial-config.ts:

export const tutorialConfig: TutorialConfig = {
  meta: {
    title: 'Build a REST API with Hono',
    fps: 30, width: 1920, height: 1080,
  },
  steps: [
    {
      id: 'intro',
      type: 'title',
      title: 'Build a REST API with Hono',
      narration: 'In this tutorial, you will build a REST API with Hono.',
      durationSeconds: 6,
      transition: 'fade',
    },
    {
      id: 'setup',
      type: 'terminal',
      title: 'Project Setup',
      narration: 'Start by scaffolding a new Hono project.',
      terminal: {
        castFile: 'recordings/01-setup.cast',
        theme: 'dracula',
        speed: 1.5,
      },
      transition: 'slide-left',
    },
    {
      id: 'first-route',
      type: 'code',
      title: 'Your First Route',
      narration: 'Add a GET route that returns JSON.',
      code: {
        markdownFile: 'tutorial.md',
        language: 'typescript',
        theme: 'github-dark',
        transitionFrames: 25,
      },
      transition: 'slide-left',
    },
  ],
  layout: {
    defaultLayout: 'code-only',
    padding: 40,
    cornerRadius: 12,
    showProgressBar: true,
    progressBarPosition: 'bottom',
    showChapterTitles: true,
    webcam: {
      enabled: true,
      source: 'avatar',
      file: 'webcam/avatar.mp4',
      position: 'bottom-right',
      sizePercent: 15,
      borderRadius: 50,
    },
  },
  audio: {
    voiceover: {
      provider: 'qwen3-tts',
      speaker: 'Ryan',
      tone: 'tutorial',
      stepGap: 0.5,
    },
    backgroundMusic: {
      file: 'audio/bg-music.mp3',
      volume: 0.08,
    },
  },
  theme: {
    codeTheme: 'github-dark',
    terminalTheme: 'dracula',
    backgroundColor: '#0a0a0a',
    accentColor: '#3b82f6',
    textColor: '#ffffff',
    fontFamily: 'Inter',
    codeFontFamily: 'JetBrains Mono',
  },
  export: {
    formats: [
      { name: 'youtube', width: 1920, height: 1080, fps: 30 },
      { name: 'shorts', width: 1080, height: 1920, fps: 30, maxDuration: 60 },
    ],
    outputDir: 'out/',
  },
};

Step types: title, code, terminal, browser, chapter, outro.

Transition types: fade, slide-left, slide-right, slide-up, wipe, zoom-in, none.

Duration rule for narration: ceil(word_count / 2.5) + 2 seconds. Terminal and code steps auto-calculate duration from content + voiceover length.

Asset Manifest

Each asset gets a manifest entry telling the skill what it contains, how important it is, and where it should appear in the tutorial.

interface TutorialAsset {
  path: string;                    // relative path to file
  type: 'code' | 'terminal' | 'screenshot' | 'diagram' | 'video' | 'photo';
  description: string;             // what this asset shows — Claude uses this for placement
  tags: string[];                  // searchable: ['setup', 'api', 'database', 'demo']
  step?: number | string;          // which tutorial step this belongs to
  weight: 1 | 2 | 3 | 4 | 5;     // 1=brief flash, 3=standard, 5=key concept (linger)
  zoomRegion?: {                   // auto-zoom to this region when showing
    x: number; y: number;
    width: number; height: number;
  };
  annotations?: string[];          // callouts: ['highlight line 12', 'arrow to submit button']
  duration?: number;               // suggested screen time in seconds
  notes?: string;                  // special instructions
}

interface TutorialManifest {
  assets: TutorialAsset[];
  defaults: {
    weight: number;
    durationByWeight: {
      1: number; // 2s — quick flash
      2: number; // 4s — brief show
      3: number; // 6s — standard explanation
      4: number; // 8s — important concept
      5: number; // 12s — key concept, linger for comprehension
    };
  };
}

How Weights Work for Tutorials

WeightRoleScreen TimeVoiceoverEffects
5 — Key ConceptCore lesson, aha moment10-15sDetailed explanationSlow zoom, highlight, pause
4 — ImportantSignificant step6-10sClear walkthroughZoom to region, annotations
3 — StandardNormal tutorial step4-6sBrief narrationStandard code transition
2 — ContextSupporting visual2-4sQuick mentionQuick show, no zoom
1 — ReferenceBrief flash1-2sNone or "as you can see"Flash on screen

Smart Placement Rules

  • Assets tagged setup or install → early in tutorial (Chapter 1)
  • Assets tagged demo or result → after the code that produces them
  • type: 'terminal' → played back with typing animation, paused at key outputs
  • type: 'code' with step numbers → ordered by step, animated transitions between steps
  • type: 'screenshot' with zoomRegion → auto-zoom + highlight
  • type: 'diagram' → shown during concept explanation, held longer
  • weight: 5 assets get the voiceover's most detailed explanation
  • weight: 1-2 assets appear in rapid montage sections or are skipped if runtime is tight

Example

const manifest: TutorialManifest = {
  assets: [
    {
      path: 'recordings/npm-install.cast',
      type: 'terminal',
      description: 'Running npm install and seeing the dependency tree',
      tags: ['setup', 'install'],
      step: 1,
      weight: 2,
      duration: 4,
    },
    {
      path: 'code/api-handler.ts',
      type: 'code',
      description: 'The main API route handler showing the GET endpoint',
      tags: ['api', 'core'],
      step: 3,
      weight: 5,
      annotations: ['highlight lines 8-15: this is where the magic happens'],
      notes: 'This is THE key code. Linger here, explain each line.',
    },
    {
      path: 'screenshots/browser-result.png',
      type: 'screenshot',
      description: 'Browser showing the JSON response from our API',
      tags: ['demo', 'result'],
      step: 4,
      weight: 3,
      zoomRegion: { x: 100, y: 200, width: 600, height: 300 },
    },
  ],
  defaults: {
    weight: 3,
    durationByWeight: { 1: 2, 2: 4, 3: 6, 4: 8, 5: 12 },
  },
};

Step 5: Parse Markdown

cd $TOOLKIT
python3 tools/parse_tutorial.py \
  --input projects/MY_TUTORIAL/tutorial.md \
  --output projects/MY_TUTORIAL/src/config/parsed-steps.json

Step 6: Generate Voiceover

cd $TOOLKIT
python3 tools/generate_voiceover.py \
  --config projects/MY_TUTORIAL/src/config/tutorial-config.ts \
  --output-dir projects/MY_TUTORIAL/public/audio/voiceover/ \
  --provider qwen3-tts --speaker Ryan --tone tutorial \
  --cloud modal

Step 7: Generate Focus Regions (optional)

Auto-detect zoom regions from code diffs:

cd $TOOLKIT
python3 tools/detect_focus.py \
  --config projects/MY_TUTORIAL/src/config/tutorial-config.ts \
  --output projects/MY_TUTORIAL/src/config/focus-regions.json

Step 8: Extract Terminal Timing (optional)

Extract timing keyframes from .cast files for auto-generated pause points:

cd $TOOLKIT
python3 tools/cast_to_keyframes.py \
  --input projects/MY_TUTORIAL/recordings/01-setup.cast \
  --speed 1.5 \
  --max-idle 2.0 \
  --output projects/MY_TUTORIAL/src/config/cast-timing.json

Step 9: Generate Background Music (optional)

cd $TOOLKIT
python3 tools/music_gen.py \
  --preset lofi \
  --duration 300 \
  --output projects/MY_TUTORIAL/public/audio/bg-music.mp3 \
  --cloud modal

Presets: corporate-bg, upbeat-tech, ambient, dramatic, tension, hopeful, cta, lofi.

Step 10: Preview and Render

cd $TOOLKIT/projects/MY_TUTORIAL

# Real-time preview
npx remotion studio

# Render YouTube format
npx remotion render TutorialVideo out/tutorial-youtube.mp4

# Render TikTok/Shorts format
npx remotion render TutorialVideoVertical out/tutorial-shorts.mp4

# Instagram Square (1:1)
npx remotion render TutorialVideoSquare out/tutorial-square.mp4

Step 11: Post-Process (optional)

# Add intro/outro bumper
ffmpeg -f concat -safe 0 -i concat-list.txt -c copy out/final.mp4

# Optimize for web streaming
ffmpeg -i out/tutorial-youtube.mp4 -movflags +faststart out/tutorial-youtube-web.mp4

Output: out/tutorial-youtube.mp4

Layout Modes

ModeDescriptionUse when
code-onlyFull-screen animated codeShowing code changes
terminal-onlyFull-screen terminal replayRunning CLI commands
code-terminalSide-by-side code + terminalShowing code and its output
code-browserSide-by-side code + browserWeb development tutorials
fullscreenFull-screen screenshot/imageArchitecture diagrams, UI demos
split-view50/50 configurable splitComparing before/after
picture-in-pictureMain content + PiP overlayWebcam or avatar talking head

Animated Code Transitions

Code transitions use Shiki Magic Move (token-level FLIP animations):

  • Move: Tokens that exist in both states animate to their new position
  • Enter: New tokens fade in and slide from the right
  • Leave: Removed tokens fade out and slide to the left

Supported annotations in Code Hike markdown:

  • // !mark(1:3) -- Highlight lines 1-3
  • // !fold(5:10) -- Collapse lines 5-10
  • // !callout[This is important] -- Callout annotation

150+ languages supported via Shiki. Themes: github-dark, github-light, dracula, monokai, one-dark-pro, vitesse-dark, etc.

Terminal Replay

Asciinema recordings play back inside the video with frame-perfect sync:

  • Speed control: speed: 1.5 plays back at 1.5x
  • Idle compression: maxIdleTime: 2.0 caps gaps between keystrokes at 2 seconds
  • Pause points: pauseAt: [{ time: 3.2, duration: 2, annotation: 'Note this output' }]
  • Themes: dracula, monokai, solarized-dark, solarized-light, tango

Auto-Zoom Effects

Define focus regions per step to zoom into specific code or terminal areas:

focusRegions: [
  { startFrame: 0, x: 10, y: 40, width: 80, height: 30, zoom: 1.8 },
  { startFrame: 90, x: 10, y: 55, width: 80, height: 35, zoom: 1.6 },
]

Zoom transitions use Remotion spring() with high damping for smooth, non-bouncy motion. Auto-zoom regions can also be auto-generated from code diffs using tools/detect_focus.py.

Focus Highlight

Dims everything outside a focus region (spotlight effect):

focusHighlight: {
  enabled: true,
  opacity: 0.6,           // Dim overlay opacity
  borderRadius: 8,
  featheredEdges: true,    // Soft edges via box-shadow blur
}

The spotlight window animates with spring() when the focus region changes. Used automatically when focusRegions are defined on a step.

Smooth Cursor

Animated cursor overlay with Bezier interpolation between keyframe positions:

cursor: {
  enabled: true,
  keyframes: [
    { frame: 0, x: 50, y: 50 },
    { frame: 30, x: 200, y: 100, click: true },
    { frame: 60, x: 400, y: 300 },
  ],
  showTrail: true,
  trailLength: 4,
}
  • Bezier interpolation: Smooth curves between positions (no jerky linear movement)
  • Click ripple: Expanding ring animation on click events
  • Motion trail: 3-5 ghost cursors at decreasing opacity following the main cursor

Webcam / Avatar PiP

Add a talking head overlay:

Option A: Real webcam recording Record separately, reference in config:

webcam: {
  enabled: true,
  source: 'file',
  file: 'webcam/recording.mp4',
  position: 'bottom-right',
  sizePercent: 15,
  borderRadius: 50,
}

Option B: AI avatar (SadTalker) Generate from a portrait image + voiceover audio:

cd $TOOLKIT
python3 tools/flux2.py --prompt "Professional developer, dark background" \
  --width 1024 --height 576 --output projects/MY_TUTORIAL/public/webcam/presenter.png --cloud modal

python3 tools/sadtalker.py \
  --image projects/MY_TUTORIAL/public/webcam/presenter.png \
  --audio projects/MY_TUTORIAL/public/audio/voiceover/01-intro.mp3 \
  --preprocess full --still --expression-scale 0.8 \
  --output projects/MY_TUTORIAL/public/webcam/avatar-01.mp4 --cloud modal

SadTalker rules: ALWAYS use --preprocess full and --still. Generate per-step clips, NEVER one long video.

Step Annotations

Overlay arrows, callouts, and highlights on any step:

annotations: [
  {
    type: 'arrow',
    x: 45, y: 60,
    direction: 'down',
    text: 'This line is key',
    showAtFrame: 30,
    durationFrames: 90,
  },
  {
    type: 'highlight',
    x: 10, y: 55,
    width: 80, height: 8,
    color: '#3b82f680',
    showAtFrame: 0,
  },
]

Types: arrow, callout, highlight, circle, underline, box.

Progress Bar + Chapter Markers

The progress bar fills proportionally to the current frame and shows chapter markers as dots at step boundaries:

layout: {
  showProgressBar: true,
  progressBarPosition: 'bottom',  // 'top' or 'bottom'
  showChapterTitles: true,
}
  • Chapter markers appear as dots at each step boundary on the progress bar
  • Chapter title animates in with a staggered spring at step start, auto-dismisses after 1.5s
  • Both components respect theme accentColor and textColor

Social Format Export

Export from the same source to multiple formats:

FormatResolutionFPSMax Duration
YouTube1920x108030--
TikTok1080x192030180s
YouTube Shorts1080x19203060s
Square (Instagram)1080x108030--

Vertical formats auto-reflow: code gets larger font, terminal stacks above narration, PiP moves to top. See Step 10 for render commands.

Composition Patterns

Per-Step Audio (1s delay)

<Sequence from={30}>
  <Audio src={staticFile('audio/voiceover/01-intro.mp3')} volume={1} />
</Sequence>

Background Music (full duration)

<Audio src={staticFile('audio/bg-music.mp3')} volume={0.08} />

Narrator PiP

<Sequence from={30}>
  <OffthreadVideo
    src={staticFile('webcam/avatar-01.mp4')}
    style={{ width: 320, height: 180, objectFit: 'cover' }}
    muted
  />
</Sequence>

ALWAYS use <OffthreadVideo>, NEVER <video>.

Transitions

import { TransitionSeries, linearTiming } from '@remotion/transitions';
import { fade } from '@remotion/transitions/fade';

Import custom transitions from lib/transitions/presentations/ directly, never from barrel.

Cost Estimates

StepCostNotes
Voiceover (Qwen3-TTS)~$0.01/step~20s warm GPU via Modal
AI avatar (SadTalker)~$0.05-0.20/step~3-4 min per 10s audio
Background music (MusicGen)~$0.02-0.05Duration-dependent
Presenter portrait (FLUX.2)~$0.01One-time
Remotion renderFree (local)~2-5 min for 5-min video

Total 5-minute tutorial: ~$0.50-2.00 with AI avatar, ~$0.10-0.50 without.

Remotion Ecosystem Packages

Install the official Remotion skills for best results: npx skills i remotion-dev/skills/skills/remotion. This provides 35 production rules covering animations, audio, transitions, text, 3D, and more.

Core Packages

PackageWhat it does
@remotion/transitionsfade, slide, wipe, flip, clockWipe, iris
@remotion/captionsTikTok-style word-by-word captions
@remotion/media-utilsvisualizeAudio(), getAudioData(), getAudioDurationInSeconds()
@remotion/layout-utilsmeasureText(), fitText(), fillTextBox() — use for dynamic code block sizing
@remotion/noiseProcedural noise for film grain
@remotion/google-fontsGoogle Fonts loading
@remotion/shapesGeometric shape components — use for overlays in explanations
@remotion/pathsSVG path animation — use for animated diagrams and flowcharts
remotion-animatedDeclarative <Animated> with Move(), Scale(), Fade()

Community Packages

PackageWhat it does
Remotion Bits (npx remotion-bits find/fetch)ParticleSystem, AnimatedText (char/word/line stagger), StaggeredMotion — use AnimatedText for step titles
GL Transitions (remotion-gl-transitions)Hundreds of GLSL shader transitions from gl-transitions.com
remotion-confettiCanvas-based confetti with physics

AI Services

ServiceWhat it doesCost
fal.aiSingle API for video gen (Veo 3.1, Kling 3, Wan 2.2). One key, all models$0.05-0.50/sec
whisper.cppLOCAL speech-to-text, zero cost. Use for caption generation instead of cloud APIsFree
Suno (via KIE)AI music with vocals. Better than MusicGen for songs with lyrics$0.03/song

Producer Intelligence

Audio ducking: Auto-lower music volume when voiceover speaks. Use Remotion's interpolate() on volume based on voiceover audio presence.

Loudness normalization: Target LUFS per platform: YouTube -14, TikTok -14, Instagram -14, Podcast -16. Post-process:

ffmpeg -i input.mp4 -af loudnorm=I=-14:TP=-1.5:LRA=11 output.mp4

Film grain via @remotion/noise: Use noise2D() or noise3D() for procedural film grain instead of CSS overlay.

Light leaks via @remotion/light-leaks: WebGL overlays for transitions between acts/scenes.

Key Rules

  1. All animation via useCurrentFrame() + interpolate()/spring(). No CSS transitions or Tailwind animation classes.
  2. Always staticFile() for assets. Never require().
  3. Always <OffthreadVideo> for webcam/avatar. Never <video>.
  4. Always --preprocess full --still for SadTalker.
  5. Generate voiceover per step, never as one long audio file.
  6. Duration = ceil(word_count / 2.5) + 2 for narration-driven steps.
  7. Run all tools from $TOOLKIT root, not from the project directory.

Source: Built on remotion.dev/templates/code-hike, codehike.org, shikijs/shiki-magic-move, asciinema.org

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.