Audio plugins
Audio plugins add narration providers as separate packages. SuiteCut loads the selected package in its narration worker. Built-in Kokoro remains the default.
Install one model family
npm install --save-dev https://github.com/skyaara/suitecut/releases/download/v2.0.0/suitecut-audio-sherpa-core-2.0.0.tgz https://github.com/skyaara/suitecut/releases/download/v2.0.0/suitecut-audio-vits-2.0.0.tgzInstall the matching 2.0 shared runtime and family package from the GitHub release assets. Use @suitecut/audio-vits for VITS and Piper. Other packages are@suitecut/audio-matcha, @suitecut/audio-kokoro-sherpa,@suitecut/audio-kitten, @suitecut/audio-zipvoice,@suitecut/audio-pocket, and @suitecut/audio-supertonic.
import { defineSuiteCut } from 'suitecut/playwright'
const record = defineSuiteCut({
audioPlugins: [
{
provider: 'piper-amy',
module: '@suitecut/audio-vits',
options: {
model: './models/piper/en_US-amy-low/en_US-amy-low.onnx',
tokens: './models/piper/en_US-amy-low/tokens.txt',
dataDir: './models/piper/en_US-amy-low/espeak-ng-data',
},
},
],
})
await record('Piper narration', async ({ page, suitecut }) => {
await page.goto('https://example.com')
await suitecut.narrate('The report is ready.', {
provider: 'piper-amy',
voice: 'default',
speed: 1.1,
})
})Each package validates only its model family's options. The packages share one Sherpa runtime, which npm deduplicates when a project installs more than one family. The adapters never download models. Download the selected model separately and pass its local file paths in the plugin options. Sherpa publishes compatible files in its TTS model releases.
Listen and set the voice
Piper Amy
Package @suitecut/audio-vits. Model en_US-amy-low. Voicedefault. Speed 1. Sample text: "This is the Piper Amy voice, running through the VITS audio plugin."
Piper Amy has one speaker, so set voice: 'default'. For a multi-speaker model, use its numeric speaker ID as the voice, such as voice: '2', or give the ID a name inspeakerIds.
const record = defineSuiteCut({
audioPlugins: [
{
provider: 'vits-cast',
module: '@suitecut/audio-vits',
options: {
model: './models/cast/model.onnx',
tokens: './models/cast/tokens.txt',
speakerIds: { narrator: 2 },
},
},
],
})
await record('Named speaker', async ({ suitecut }) => {
await suitecut.narrate('Welcome to the tour.', {
provider: 'vits-cast',
voice: 'narrator',
})
})Playwright Test
The secondary test integration accepts the same references assuitecutAudioPlugins through test.use(). Import test fromsuitecut/test. The provider in narrate() must match the configured provider ID.
Write a plugin
Export one ESM plugin object from the package default entry. Its synthesize() method receives text, voice, speed, output path, and JSON options. It must write mono PCM WAV before it resolves. An optional dispose() method can release models, workers, files, and subprocesses when the narration worker closes normally.
import { writeFile } from 'node:fs/promises'
import {
defineSuiteCutAudioPlugin,
encodePcm16Wav,
} from 'suitecut/audio-plugin'
export default defineSuiteCutAudioPlugin({
async synthesize({ text, voice, speed, outputPath, options }) {
const { samples, sampleRate } = await runModel({ text, voice, speed, options })
await writeFile(outputPath, encodePcm16Wav(samples, sampleRate))
},
async dispose() {
await releaseModelResources()
},
})Provider IDs use lowercase letters, numbers, dots, underscores, and hyphens. Plugins cannot replace kokoro or macos-say.