Create consistent, branded Plug & Play videos for MCP extension demos using Remotion + Goose.
This repo is the official Plug & Play video template.
It gives you:
- π Locked branding (colors, fonts, layout, animation)
- π§± Reusable scene structure
- π§ Goose-powered video generation with audio syncing
- π Automatic captions via Whisper
- π Template vs Current preview toggle
You never edit the template.
You only create configs.
- Goose with Skills and Developer extensions enabled
- ffmpeg (for audio processing):
# macOS brew install ffmpeg # Linux sudo apt-get install ffmpeg
- Whisper (for captions):
pip3 install openai-whisper
- Install Remotion skill in Goose:
npx skills add remotion-dev/skills
- Clone this repo:
git clone https://github.com/block/plug-and-play-template cd plug-and-play-template npm install
npm startThis launches the Remotion desktop preview.
You will see two videos:
- PlugAndPlay-Template β example reference
- PlugAndPlay-Current β your active video
Goose automatically updates the Current video.
Open Goose and use the Plug & Play recipe.
Say something like:
Create a Plug & Play video
Goose will collect:
- Extension slug (e.g.,
councilOfMine) - MCP server name (e.g.,
Council of Mine) - Badge line (e.g.,
multi-perspective reasoning) - Hook text (2 lines)
- Setup type (built-in, STDIO, STDIO + env vars, HTTP, HTTP + headers)
- Explainer lines (optional)
- Prompt text
- Results type (bullets, screen recording, or custom visuals)
- Summary type (none, bullets, or custom visuals)
- Voiceover audio file (optional, can add later)
Then Goose generates your config, creates any custom visuals, and activates it as Current.
No manual editing required.
plug-and-play-template/
βββ src/
β βββ template/ π LOCKED β never edit
β β βββ components/ # Shared UI (MovingDots, GradientBorder, PlugAndPlayBar, Captions)
β β βββ sequences/ # Scene components + routers
β β βββ styles.ts # Colors, dimensions, timing
β β βββ config.ts # TypeScript types + example config
β β
β βββ videos/ π Your generated videos
β β βββ current.ts β Active pointer
β β βββ <your-video>/
β β βββ config.ts # Video configuration
β β βββ captions.ts # Auto-generated captions
β β βββ sequences/ # Custom visual components
β β
β βββ Root.tsx
β
βββ public/
β βββ template/ # Template assets
β βββ <your-video>/ # Your video assets (audio, recordings)
β
βββ package.json
Each Plug & Play video follows this sequence:
| Scene | Purpose |
|---|---|
| Hook | Attention-grabbing opener (2 lines) |
| Plug & Play | Brand transition with badge line |
| Setup | Extension installation (5 types supported) |
| Explainer | Optional teaching points (1-4 lines) |
| Let's Play | Transition to demo |
| Prompt | Typewriter effect showing the prompt |
| Results | Bullets, screen recording, or custom visuals |
| Summary | Optional wrap-up (bullets or custom visuals) |
| End | Call to action with docs URL |
- Record your voiceover
- Enhance it at Adobe Podcast
- Provide the audio file to Goose
- Runs Whisper to generate word-level timestamps
- Trims trailing silence from audio
- Auto-generates karaoke-style captions
- Syncs video scenes to audio cues
Goose looks for these phrases to align scenes:
- "Let's play" / "Now let's play" β LetsPlayScene
- Your prompt text β PromptScene
- "To get started" / "visit block.github.io/goose" β EndScene
If auto-sync can't find all cues, Goose will:
- Show you a timestamped transcript
- Ask you to identify scene boundaries
- Let you correct any misheard words
- Iterate until timing is perfect
npm start # Launch Remotion studio
npm install # Install dependencies
npx remotion render # Render video (or let Goose handle it)interface VideoConfig {
hookText: string;
mcpServerName: string;
badgeLine: string;
setup: SetupConfig; // Union type: builtin | stdio | stdio_with_env | http | http_with_headers
explainerLines?: string[];
promptText: string;
results: ResultConfig; // Union type: bullets | recording | visuals
summary?: SummaryConfig; // Union type: none | bullets | visuals
captionsData?: Caption[];
audioSrc?: string;
docsUrl: string;
tutorialTitle: string;
}type SetupConfig =
| { type: "builtin"; extensionName: string; extensionDescription: string }
| { type: "stdio"; extensionName: string; extensionCommand: string }
| { type: "stdio_with_env"; extensionName: string; extensionCommand: string; envVars: NameValuePair[] }
| { type: "http"; extensionName: string; endpoint: string }
| { type: "http_with_headers"; extensionName: string; endpoint: string; requestHeaders: NameValuePair[] };type ResultConfig =
| { type: "bullets"; bullets: string[] }
| { type: "recording"; recordingPath: string; durationInSeconds?: number }
| { type: "visuals"; description?: string; componentName?: string };type SummaryConfig =
| { type: "none" }
| { type: "bullets"; lines: string[]; title?: string }
| { type: "visuals"; description?: string; componentName?: string };You don't edit this manually β Goose writes it.
When Goose creates custom visuals for Results or Summary, they follow this structure:
- Wrapped in
<GradientBorder>(animated teal/orange border) - Include
<VisibleMovingDots />background - Include
<PlugAndPlayBar />at bottom - Use colors from
template/styles.ts
Custom visuals are placed in:
src/videos/<your-video>/sequences/<ComponentName>.tsx
And registered in the appropriate router (ResultsRouter.tsx or SummaryRouter.tsx).
Never modify:
src/template/
Only create/edit:
src/videos/<your-video>/
public/<your-video>/
Template styling is locked to preserve brand consistency.
Created a custom visual that could benefit the whole team?
- Open a PR moving your sequence from
src/videos/<your-video>/sequences/tosrc/template/sequences/ - Update the relevant router (
ResultsRouter.tsxorSummaryRouter.tsx) to include it as a template option
Template sequences should be generic and reusable across multiple videos.