@yassine-bouassida/scenecap
v1.1.0
Published
Scriptable screen recording with annotations, zoom effects, and highlights for Next.js — powered by natural language scenarios.
Maintainers
Readme
Scenecap
Record scripted screen scenarios as MP4/WebM videos directly from your React app — entirely in the browser, zero backend.
Describe what should happen in plain English, and Scenecap parses it, executes the actions on-screen (virtual cursor, animations, zoom, annotations), and captures everything into a downloadable video file.
Think of it as "Playwright meets screen recorder meets annotation tool" — but running entirely in the browser.
Installation
npm install @yassine-bouassida/scenecapQuick Start
React Hook (recommended for Next.js)
'use client';
import { useScenecap } from '@yassine-bouassida/scenecap';
export default function MyPage() {
const { containerRef, record, download, isRecording, progress } = useScenecap();
const handleRecord = async () => {
await record(`
Click the "Login" button
Type "[email protected]" in the email input
Zoom in on the password field
Circle the submit button in red
`);
download('my-demo.webm');
};
return (
<>
<button onClick={handleRecord} disabled={isRecording}>
{isRecording ? `${Math.round(progress)}%` : 'Record'}
</button>
<div ref={containerRef}>
{/* your UI */}
</div>
</>
);
}Vanilla JS / Imperative
import { createScenecap } from '@yassine-bouassida/scenecap';
const sc = createScenecap({ recording: { fps: 30 } });
const blob = await sc.record(`
Click the signup button
Type "hello" in the name field
`, document.getElementById('app')!);
const a = document.createElement('a');
a.href = URL.createObjectURL(blob);
a.download = 'recording.webm';
a.click();Structured Scenario (skip NLP)
import { ScenarioRunner } from '@yassine-bouassida/scenecap';
const runner = new ScenarioRunner();
const blob = await runner.recordScenario({
name: 'Login Flow',
actions: [
{ type: 'click', target: '#login-btn' },
{ type: 'type', target: 'input[name="email"]', value: '[email protected]' },
{ type: 'zoom', target: '#submit', zoomLevel: 2.0 },
{ type: 'circle', target: '#submit', color: '#ff0000' },
],
}, containerEl);Supported Actions
| What you write | What it does |
|---|---|
| Click the "Submit" button | Clicks element by text content |
| Type "hello" in the email field | Keystroke-by-keystroke typing |
| Zoom in on the navbar to 200% | Smooth CSS transform zoom |
| Zoom out | Resets zoom to 100% |
| Circle the logo in red | Animated ellipse with glow effect |
| Highlight the error message in yellow | Semi-transparent overlay |
| Draw an arrow to the submit button | Animated arrow pointing to element |
| Add text "Click here!" near the button | Pill-shaped label |
| Scroll down 500px | Smooth scroll by pixel amount |
| Scroll to the footer | Scrolls element into view |
| Hover over the menu | Dispatches mouseenter/mouseover |
| Wait 2 seconds | Pauses execution |
| Navigate to /dashboard | Changes window location |
| Take a screenshot | White flash effect |
Configuration
createScenecap({
recording: {
format: 'webm', // 'webm' | 'mp4' (mp4 depends on browser support)
fps: 30,
videoBitrate: 5_000_000,
width: 1280,
height: 720,
audio: false,
backgroundColor: '#ffffff',
devicePixelRatio: 1,
},
annotations: {
circleColor: '#ff3b30',
highlightColor: '#ffcc02',
arrowColor: '#ff3b30',
textColor: '#1a1a1a',
thickness: 3,
},
animation: {
defaultDuration: 800, // ms per action
defaultEasing: 'ease-in-out',
zoomDuration: 600,
},
callbacks: {
onActionStart: (action, index) => {},
onActionComplete: (action, index) => {},
onProgress: (percent) => {},
onError: (error) => {},
onComplete: (blob) => {},
},
});Browser Requirements
| API | Minimum versions | |---|---| | MediaRecorder | Chrome 49+, Firefox 25+, Edge 79+, Safari 14.1+ | | Canvas captureStream | Chrome 51+, Firefox 43+, Edge 79+, Safari 14.1+ |
Does not work in Node.js / SSR — all recording logic is browser-only.
Known Limitations
- DOM fidelity: The SVG foreignObject approach doesn't capture cross-origin images, iframes, or some CSS effects (backdrop-filter, complex shadows).
- MP4 output: MediaRecorder natively outputs WebM. True MP4 requires ffmpeg.wasm (not yet integrated).
- NLP parser: Regex-based — handles common phrasings well but won't understand arbitrary sentences.
- No iframe support: Can only record elements within the same document.
- Single-tab only: Cross-page navigations will break the recording session.
Development
npm install
npm run build # compile to dist/ (CJS + ESM + types)
npm run dev # watch mode
npm run lint
npm run testLicense
MIT — free for personal and commercial use.
