API and CLI
SuiteCut's fixture, capture, output, reporter, and render option objects reject unknown keys and invalid values. Playwright launch and browser-context options pass through to Playwright.
Native API in 2.0
The root record and defineSuiteCut now use CEF. Configure dimensions, device scale, FPS, and executable path in native. Native capture accepts size, narrationTailMs, and booleanaudio. The callback receives source, page,suitecut, signal, and addSource. Locators are strict main-document CSS selectors. See native setup and migration.
import { record, launchBrowser, createBroadcast } from 'suitecut'
await record('Native tour', async ({ page, suitecut }) => {
await page.goto('https://example.com')
await suitecut.highlight(page.locator('h1'))
}, {
native: { width: 1920, height: 1080, framesPerSecond: 60 },
capture: { audio: true },
})launchBrowser(options) returns a caller-owned native source.createBroadcast({ source, stream }) publishes it; stop the broadcast and close the source separately. createNativePage(source) exposes page controls outside a recording. Root recording types describe native callbacks and results. Import Playwright recording types fromsuitecut/playwright. The detailed Playwright capture and setup options below apply to that explicit backend and the test integration.
Public exports
These are the main package entry points and public exports. Files belowsuitecut/src are internal and are not public imports.
suitecut
The native CEF recorder, browser launcher, broadcaster, renderer, and their public types.
import {
DEFAULT_BACKEND,
launchBrowser,
createBroadcast,
createNativePage,
type SuiteCutBrowserOptions,
type SuiteCutNativeRecordOptions,
type SuiteCutPlaywrightRecordOptions,
type SuiteCutRecordingResult,
type NativePage,
type NativeLocator,
type NativeRecordingContext,
defineSuiteCut,
record,
decodeWordTimingArtifact,
renderSuiteCut,
type LiveStreamDiagnostic,
type SuiteCutBrowserName,
type SuiteCutDefinitionOptions,
type SuiteCutWordTiming,
type SuiteCutWordTimingArtifact,
type Milliseconds,
type SuiteCutAnimationOptions,
type SuiteCutAudioPlugin,
type SuiteCutAudioPluginReference,
type SuiteCutAudioSynthesisRequest,
type SuiteCutBorderStyle,
type SuiteCutStreamOptions,
type SuiteCutReconnectOptions,
type SuiteCutCaptureOptions,
type SuiteCutCaptureSize,
type SuiteCutCaptureViewport,
type SuiteCutCheckpointOptions,
type SuiteCutCleanup,
type SuiteCutColorRange,
type SuiteCutEasing,
type SuiteCutFixture,
type SuiteCutHighlightMode,
type SuiteCutHighlightOptions,
type SuiteCutJsonValue,
type SuiteCutNarrationOptions,
type SuiteCutNarrationProvider,
type SuiteCutNarrationVoice,
type SuiteCutOutputOptions,
type SuiteCutOutputContainer,
type SuiteCutOutputFormat,
type SuiteCutPointerActionOptions,
type SuiteCutRecordOptions,
type SuiteCutRecordResult,
type SuiteCutRecorder,
type SuiteCutRecordingCallback,
type SuiteCutRecordingContext,
type SuiteCutRenderConfig,
type SuiteCutRenderFailureMode,
type SuiteCutRenderOutputConfig,
type SuiteCutRenderQuality,
type SuiteCutRenderReport,
type SuiteCutRenderRequest,
type SuiteCutScrollAlignment,
type SuiteCutScrollBehavior,
type SuiteCutScrollOptions,
type SuiteCutSetupContext,
type SuiteCutTypeOptions,
type SuiteCutVisualAnimation,
type SuiteCutZoomOptions,
} from 'suitecut'suitecut/test
The optional Playwright Test fixture and assertion API.
import { expect, test } from 'suitecut/test'suitecut/playwright
The explicit Playwright recorder, preserving the 1.x launch, context, and setup APIs.
import {
defineSuiteCut,
record,
type Milliseconds,
type SuiteCutAudioPluginReference,
type SuiteCutBrowserName,
type SuiteCutCaptureOptions,
type SuiteCutCheckpointOptions,
type SuiteCutCleanup,
type SuiteCutDefinitionOptions,
type SuiteCutFixture,
type SuiteCutHighlightOptions,
type SuiteCutNarrationOptions,
type SuiteCutOutputOptions,
type SuiteCutPointerActionOptions,
type SuiteCutRecordOptions,
type SuiteCutRecordResult,
type SuiteCutRecorder,
type SuiteCutRecordingCallback,
type SuiteCutRecordingContext,
type SuiteCutScrollOptions,
type SuiteCutTypeOptions,
type SuiteCutSetupContext,
type SuiteCutZoomOptions,
} from 'suitecut/playwright'suitecut/audio-plugin
The contract and helpers for external narration packages.
import {
audioPluginReference,
defineSuiteCutAudioPlugin,
encodePcm16Wav,
type SuiteCutAudioPlugin,
type SuiteCutAudioPluginReference,
type SuiteCutAudioSynthesisRequest,
type SuiteCutJsonValue,
} from 'suitecut/audio-plugin'suitecut/render
The programmatic renderer and its complete request, output, edit, and report types.
import {
renderSuiteCut,
type SuiteCutColorRange,
type SuiteCutEditSegment,
type SuiteCutOutputContainer,
type SuiteCutOutputFormat,
type SuiteCutRenderConfig,
type SuiteCutRenderFailureMode,
type SuiteCutRenderOutputConfig,
type SuiteCutRenderQuality,
type SuiteCutRenderReport,
type SuiteCutRenderRequest,
} from 'suitecut/render'suitecut/reporter
The Playwright reporter class and reporter configuration type.
import SuiteCutReporter, {
type SuiteCutReporterOptions,
} from 'suitecut/reporter'suitecut/types
The complete manifest, event, artifact, media, geometry, diagnostic, and identity model.
import {
SUITECUT_EVENT_ATTACHMENT,
SUITECUT_MANIFEST_SCHEMA_VERSION,
type EpochMilliseconds,
type FilePath,
type ISODateTime,
type Milliseconds,
type MimeType,
type SuiteCutActiveScreencast,
type SuiteCutAnimationOptions,
type SuiteCutArtifact,
type SuiteCutArtifactId,
type SuiteCutArtifactRole,
type SuiteCutAttempt,
type SuiteCutAttemptClock,
type SuiteCutAttemptId,
type SuiteCutAudioStream,
type SuiteCutBorderStyle,
type SuiteCutCapturedArtifact,
type SuiteCutCapturedCheckpointArtifact,
type SuiteCutCapturedNarrationArtifact,
type SuiteCutCapturedVideo,
type SuiteCutCheckpointEvent,
type SuiteCutCheckpointOptions,
type SuiteCutDiagnostic,
type SuiteCutDiagnosticCode,
type SuiteCutDiagnosticLevel,
type SuiteCutEasing,
type SuiteCutError,
type SuiteCutEvent,
type SuiteCutEventAttachment,
type SuiteCutEventBase,
type SuiteCutEventId,
type SuiteCutExecutionStep,
type SuiteCutFixture,
type SuiteCutHighlightEvent,
type SuiteCutHighlightMode,
type SuiteCutHighlightOptions,
type SuiteCutHoldEvent,
type SuiteCutHoldReason,
type SuiteCutManifest,
type SuiteCutMedia,
type SuiteCutMediaId,
type SuiteCutMediaStream,
type SuiteCutNarrationEvent,
type SuiteCutNarrationOptions,
type SuiteCutNarrationProvider,
type SuiteCutNarrationVoice,
type SuiteCutPage,
type SuiteCutPageEventBase,
type SuiteCutPageSelectionEvent,
type SuiteCutPageSelectionReason,
type SuiteCutPageId,
type SuiteCutPageKind,
type SuiteCutPathKind,
type SuiteCutPoint,
type SuiteCutPointerButton,
type SuiteCutPointerButtonEvent,
type SuiteCutPointerMoveEvent,
type SuiteCutPointerType,
type SuiteCutRecordingSession,
type SuiteCutRect,
type SuiteCutRunStatus,
type SuiteCutScrollAlignment,
type SuiteCutScrollBehavior,
type SuiteCutScrollOptions,
type SuiteCutSize,
type SuiteCutSourceLocation,
type SuiteCutStepCategory,
type SuiteCutStepId,
type SuiteCutStepOutcome,
type SuiteCutTest,
type SuiteCutTestId,
type SuiteCutTestStatus,
type SuiteCutTypeOptions,
type SuiteCutVideoStream,
type SuiteCutVideoTiming,
type SuiteCutViewport,
type SuiteCutVisualAnimation,
type SuiteCutZoomEvent,
type SuiteCutZoomOptions,
} from 'suitecut/types'Playwright Test
Import from suitecut/test. test extends Playwright Test with thesuitecut fixture and two options. expect is Playwright's normal assertion API.
suitecut: the recording controls documented below.suitecutCapture: viewport, device scale, source size, frame rate, quality, narration tail, and streaming options.suitecutAudioPlugins: external provider references loaded in the narration worker.
Fixture methods
interface SuiteCutFixture {
selectPage(page: Page): void
narrate(text: string, options?: SuiteCutNarrationOptions): Promise<void>
checkpoint(label: string, options?: SuiteCutCheckpointOptions): Promise<void>
hold(durationMs: number): Promise<void>
highlight(locator: Locator, options?: SuiteCutHighlightOptions): Promise<void>
zoom(locator: Locator, options?: SuiteCutZoomOptions): Promise<void>
hover(locator: Locator, options?: SuiteCutPointerActionOptions): Promise<void>
click(locator: Locator, options?: SuiteCutPointerActionOptions): Promise<void>
type(locator: Locator, text: string, options?: SuiteCutTypeOptions): Promise<void>
scrollTo(locator: Locator, options?: SuiteCutScrollOptions): Promise<void>
scrollTop(options?: SuiteCutScrollOptions): Promise<void>
}selectPage(page): void
Selects the main page, popup, or secondary page used by later narration, checkpoints, holds, andscrollTop(). Locator methods select their locator's page automatically. Closing a selected popup returns selection to its opener when possible.
narrate(text, options?): Promise<void>
Synthesizes speech locally, records its audio, displays a caption, and waits for the measured clip plus the configured narration tail. Synthesis time is excluded from the recording clock. Thetext must not be empty.
provider:kokoroby default,macos-say, or a configured audio plugin ID.voice:af_heartfor Kokoro; the native provider uses its system default when omitted.speed:0.5through2; default1.caption: override the spoken text shown on screen. Use an empty string to hide the caption without removing audio.
checkpoint(label, options?): Promise<void>
Marks the current page state and attaches a WebM clip cut from the same page screencast used by the final render. The label must not be empty. durationMs sets the recording window; the default is 500 milliseconds and the maximum is 10000.
hold(durationMs): Promise<void>
Keeps the selected browser page recording its current state. The duration is in milliseconds and must be greater than zero.
highlight(locator, options?): Promise<void>
Measures a visible locator and records the complete highlight animation in the selected browser. Hidden or geometry-less locators fail clearly.
durationMs: total duration; default1200.mode:outlineby default,fill, orspotlight.geometry:elementby default, orcontentto tightly wrap rendered text and controls inside a block.paddingPx:8;borderWidthPx:4.borderStyle:solidby default, ordashed.borderColor:#7C3AED;borderRadiusPx:10.fillColor:#7C3AED;fillOpacity:0.08.backdropColor:#000000;backdropOpacity:0.45.label: optional text displayed above the target.enter: default{ type: 'fade', durationMs: 180, easing: 'ease-out' }.exit: default{ type: 'fade', durationMs: 140, easing: 'ease-in' }.
Animation type accepts none, fade, scale, orfade-scale. Easing accepts linear, ease-in,ease-out, or ease-in-out. A none phase is instantaneous. Scale emphasis never transforms the highlight box, so its border stays aligned throughout the phase.
Action zoom
highlight(), hover(), and click() accept zoom: trueor a zoom options object. Zoom is off by default. The camera enters before the action, stays close until it completes, and exits afterward. holdMs adds dwell time after the action. Action zooms share the camera queue with zoom() and work in renders and live streams.
await suitecut.highlight(details, { zoom: true })
await suitecut.click(publishButton, { zoom: { scale: 1.25, paddingPx: 32 } })The recorded cursor changes between arrow, pointer, and text shapes based on the element under it. Disabled controls use the arrow. Zoom crops the captured image, so capture at a higher resolution when you need more detail. Upscaling a low-resolution source cannot restore missing detail.
zoom(locator, options?): Promise<void>
Scrolls the locator into view and records a continuously evaluated camera move. SuiteCut centers edge targets, pads beyond the captured browser frame when needed, and limits the requested scale when necessary to retain available target padding. Concurrent zoom calls run in call order.
scale:1through1.25; default1.15.geometry:elementby default, orcontentto center rendered text and controls inside a block.paddingPx: minimum retained target padding; default24.holdMs: time at the closest scale; default900.enter: default{ type: 'scale', durationMs: 260, easing: 'ease-out' }.exit: default{ type: 'scale', durationMs: 220, easing: 'ease-in-out' }.
Zoom accepts the same animation values as highlight. none disables a phase;fade, scale, and fade-scale use eased camera interpolation.
hover(locator, options?): Promise<void>
Scrolls the locator into view, moves the recorded cursor to its center, performs a real Playwright hover, waits for resulting application animations by default, and settles.
moveDurationMs:450.settleMs:120.waitForAnimations:true.animationTimeoutMs:2000.
click(locator, options?): Promise<void>
Uses the same options as hover(), performs a real click, and records a 280 ms ripple. The ripple and optional application-animation wait run together. Click-driven navigation is supported.
type(locator, text, options?): Promise<void>
Scrolls the field into view and enters text one character at a time through Playwright's keyboard events. The source recording shows each character as it appears. The text must contain at least one character.
delayMs: time between characters; default70.settleMs: wait after the last character; default250.clearExisting: replace the current value before typing; defaulttrue. Set it tofalseto type at the current caret.
scrollTo(locator, options?): Promise<void>
Calls native scrollIntoView() and waits for the target to remain stable for three animation frames.
behavior:smoothby default, orauto.block:centerby default; alsostart,end, ornearest.inline:nearestby default; alsostart,center, orend.timeoutMs:2000;settleMs:120.
scrollTop(options?): Promise<void>
Scrolls the selected window to the origin. It uses behavior, timeoutMs, andsettleMs with the defaults above. block and inline are accepted for the shared options type but do not affect a window-to-origin scroll.
Capture options
Set suitecutCapture through test.use() or Playwright Test configuration. Plain Playwright scripts pass the same object as capture to record() ordefineSuiteCut().
viewport: default1600x900; maximum7680x4320.deviceScaleFactor: physical pixels per CSS pixel from1through4. A1920x1080viewport at2renders3840x2160pixels while keeping CSS layout and responsive breakpoints at1920x1080.size: encoded source size, defaulting to the viewport. WithdeviceScaleFactor, SuiteCut downsamples the physical render to this size with Lanczos filtering. Without a device scale, the existing larger proportional size behavior remains available for compatibility. Both size dimensions must be even and no larger than7680x4320.framesPerSecond:30or60; default30.quality: capture JPEG quality1through100; default100.narrationTailMs: non-negative post-narration pause; default350.
Set capture.stream to publish H.264 video with silent AAC audio over RTMP or RTMPS. This selects streaming-only mode, with no source recordings or checkpoint clips. See live streaming for options, including the boolean audio flag, reconnect behavior, cancellation, and supported effects. Streaming JPEG quality defaults to 90.
Reporter options
outputFile: default.suitecut/latest-run.json. TheSUITECUT_MANIFEST_PATHenvironment variable takes precedence.pathKind:absoluteby default, ormanifest-relative.includeStepCategories: optional allowlist ofhook,fixture,pw:api,expect,test.step,test.attach, orunknown. Retained descendants reconnect to the nearest retained ancestor.
Recording options
Import record or defineSuiteCut from suitecut/playwright. Each call owns one browser, context, main page, and recording. It writes one manifest attempt with no test steps.
record(
name: string,
callback: SuiteCutRecordingCallback,
options?: SuiteCutRecordOptions,
): Promise<SuiteCutRecordResult>
defineSuiteCut<Extensions extends object = object>(
defaults?: SuiteCutDefinitionOptions<Extensions>,
): SuiteCutRecorder<Extensions>browserName:chromium,firefox, orwebkit.launch: Playwright launch options.context: Playwright browser context options. Do not setrecordVideo; SuiteCut owns the page screencasts.capture: the capture options listed above.output.directory: artifact directory. The default is a unique directory under.suitecut/recordings.output.manifestPath: default.suitecut/latest-run.json.output.pathKind:absoluteby default, ormanifest-relative.signal: anAbortSignalthat cancels setup, capture, narration, and owned browser resources. Setup and recording callbacks receive the same signal.
SuiteCutRecordResult
A successful recording returns attemptId, testId, the decodedmanifest, its manifestPath, and the outputDirectory.defineSuiteCut() can add typed setup values and reverse-order cleanup callbacks.
Renderer
renderSuiteCut(request) selects one recorded attempt, invokes FFmpeg, writes the requested video, and writes <output>.suitecut.json. It returns the same render report.
const report = await renderSuiteCut({
manifestPath: '.suitecut/latest-run.json',
outputPath: '.suitecut/videos/tour.mp4',
selection: { testId, retry: 0 },
config: {
narrationEnabled: true,
resultHoldMs: 500,
failureMode: 'strict',
output: {
container: 'mp4',
width: 3840,
height: 2160,
framesPerSecond: 60,
quality: 'high',
},
},
})The request accepts manifestPath, outputPath, optional test and retry selection, optional render configuration, and an optional signal. Aborting stops the owned FFmpeg process and rejects with the signal reason. The report includes timing edits, diagnostics, selected IDs, output status, and the FFmpeg command result.
Audio plugin helpers
defineSuiteCutAudioPlugin(plugin)preserves the plugin type without wrapping the runtime object.audioPluginReference(reference)validates a provider ID, module name, and optional JSON settings before the worker loads them.encodePcm16Wav(samples, sampleRate)converts a monoFloat32Arrayinto a 16-bit PCM WAV byte array.SuiteCutAudioPlugin.synthesize(request)receives text, voice, speed, output path, and plugin settings. It resolves after writing the WAV file.- Optional
SuiteCutAudioPlugin.dispose()releases plugin-owned models, workers, files, or subprocesses when the narration worker closes normally.
The audio plugin guide shows package installation and provider setup.
Streaming API
SuiteCutStreamOptions configures capture.stream. Supply an RTMP or RTMPSurl, optional size, and bitrateKbps from 100 to 50,000. Audio defaults to false; true requires the standalone Chromium recorder.adaptiveBitrate defaults to enabled. reconnect accepts falseor SuiteCutReconnectOptions with initialDelayMs, maxDelayMs, and maxAttempts. onDiagnostic receives LiveStreamDiagnostic. See the streaming guide for limits and recovery behavior.
Word timing artifacts
decodeWordTimingArtifact(value) validates a saved word-timing artifact.SuiteCutWordTimingArtifact uses schemaVersion: 1 andtype: 'word-timings'. Entries include character offsets and relativestartMs/endMs; sourceEventId links to the narration event. Use timings only when spoken words map to the displayed text.
Command-line flags
suitecut install installs pinned FFmpeg and FFprobe into the OS cache.suitecut doctor verifies media tools and required codecs and protocols offline. Explicit media-tool environment paths take priority over the managed cache and system PATH.
suitecut test [--manifest path] -- [Playwright options] forwards Playwright arguments and installs the SuiteCut reporter. suitecut render requires--manifest <path> and --output <path>.
--test-id <id>: select a test; default is the first.--retry <number>: select an attempt; default is the latest.--container <mp4|webm|mov|mkv>: default comes from the output extension.--format: deprecated alias for--container.--video-codec: defaultlibvpx-vp9for WebM,libx264otherwise.--audio-codec: defaultlibopusfor WebM,aacotherwise.--pixel-format: defaultyuv422p10lefor ProRes,yuv420potherwise.--color-range <auto|full|limited>: defaultauto.--widthand--height: default1920x1080; supply both, even, maximum7680x4320.--fps <30|60>: default30.--quality <standard|high|master>: defaultstandard.--result-hold-ms: non-negative final-frame hold; default0.--background-color: default#0B1020; three- or six-digit hex or the basic names black, white, red, green, blue, and yellow.--failure-mode <strict|best-effort>: defaultstrict. Best-effort can omit unavailable narration and records anOPTIONAL_TRACK_OMITTEDwarning; required video failures remain fatal.--ffmpeg-path: explicit FFmpeg executable path.--no-narration: omit narration audio; recorded captions remain.
A recorded test
import { expect, test } from 'suitecut/test'
test('opens the account', async ({ page, suitecut }) => {
await page.goto('/account')
await suitecut.narrate('The account page is open.')
const billing = page.getByRole('link', { name: 'Billing' })
await suitecut.highlight(billing, { label: 'Open billing' })
await suitecut.click(billing)
await suitecut.hold(500)
await suitecut.checkpoint('Billing page')
})