or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

audio-processing.mdaudio-recording.mdcore-waveform-control.mdevent-system.mdindex.mdplugin-system.mdregions-plugin.mdtimeline-navigation.mdvisual-customization.md

regions-plugin.mddocs/

0

# Regions Plugin

1

2

Visual overlays and markers for audio segments with interactive drag, resize, content support, and comprehensive event handling for creating time-based annotations and selections.

3

4

## Capabilities

5

6

### Regions Plugin Class

7

8

Create and manage a regions plugin instance for visual audio segment marking.

9

10

```typescript { .api }

11

/**

12

* Regions plugin for creating visual overlays on the waveform

13

*/

14

class RegionsPlugin extends BasePlugin<RegionsPluginEvents, RegionsPluginOptions> {

15

/**

16

* Create a regions plugin instance

17

* @param options - Plugin configuration (currently undefined/no options)

18

* @returns New RegionsPlugin instance

19

*/

20

static create(options?: RegionsPluginOptions): RegionsPlugin;

21

22

/**

23

* Add a new region to the waveform

24

* @param params - Region configuration parameters

25

* @returns Created region instance

26

*/

27

addRegion(params: RegionParams): Region;

28

29

/**

30

* Remove all regions from the waveform

31

*/

32

clearRegions(): void;

33

34

/**

35

* Get all current regions

36

* @returns Array of all region instances

37

*/

38

getRegions(): Region[];

39

40

/**

41

* Enable drag selection to create regions by dragging on waveform

42

* @param options - Drag selection configuration

43

* @returns Function to disable drag selection

44

*/

45

enableDragSelection(options?: DragSelectionOptions): () => void;

46

}

47

48

type RegionsPluginOptions = undefined;

49

50

interface DragSelectionOptions {

51

color?: string;

52

[key: string]: any;

53

}

54

```

55

56

**Usage Examples:**

57

58

```typescript

59

import Regions from "wavesurfer.js/dist/plugins/regions.esm.js";

60

61

// Create and register regions plugin

62

const regions = Regions.create();

63

wavesurfer.registerPlugin(regions);

64

65

// Add basic region

66

const region1 = regions.addRegion({

67

start: 10,

68

end: 25,

69

color: "rgba(255, 0, 0, 0.3)",

70

content: "Verse 1",

71

});

72

73

// Add complex region with full options

74

const region2 = regions.addRegion({

75

id: "chorus-1",

76

start: 30,

77

end: 60,

78

drag: true,

79

resize: true,

80

color: "rgba(0, 255, 0, 0.3)",

81

content: "Chorus",

82

minLength: 5,

83

maxLength: 120,

84

});

85

86

// Enable drag to create regions

87

const disableDragSelect = regions.enableDragSelection({

88

color: "rgba(0, 0, 255, 0.2)",

89

});

90

91

// Get all regions

92

const allRegions = regions.getRegions();

93

console.log(`${allRegions.length} regions created`);

94

95

// Clear all regions

96

regions.clearRegions();

97

```

98

99

### Region Instance

100

101

Individual region objects with playback, modification, and content management capabilities.

102

103

```typescript { .api }

104

interface Region {

105

/** Unique region identifier */

106

id: string;

107

108

/** Start time in seconds */

109

start: number;

110

111

/** End time in seconds */

112

end: number;

113

114

/** Whether region can be dragged */

115

drag: boolean;

116

117

/** Whether region can be resized */

118

resize: boolean;

119

120

/** Region background color */

121

color: string;

122

123

/** Region content element */

124

content?: HTMLElement;

125

126

/** Minimum region length in seconds */

127

minLength: number;

128

129

/** Maximum region length in seconds */

130

maxLength: number;

131

132

/** Audio channel index */

133

channelIdx: number;

134

135

/**

136

* Play the region audio, optionally stopping at a specific time

137

* @param end - Optional end time, defaults to region end

138

* @returns Promise that resolves when playback starts

139

*/

140

play(end?: number): Promise<void>;

141

142

/**

143

* Update region parameters

144

* @param params - Partial region parameters to update

145

*/

146

setOptions(params: Partial<RegionParams>): void;

147

148

/**

149

* Remove the region from the waveform

150

*/

151

remove(): void;

152

153

/**

154

* Set or update region content (text or HTML element)

155

* @param content - Text string or HTML element

156

*/

157

setContent(content: string | HTMLElement): void;

158

}

159

```

160

161

**Usage Examples:**

162

163

```typescript

164

// Create region with all properties

165

const region = regions.addRegion({

166

id: "intro",

167

start: 0,

168

end: 15,

169

drag: true,

170

resize: true,

171

resizeStart: true,

172

resizeEnd: true,

173

color: "rgba(255, 255, 0, 0.4)",

174

content: "Introduction",

175

minLength: 2,

176

maxLength: 30,

177

channelIdx: 0,

178

contentEditable: true,

179

});

180

181

// Play region

182

await region.play(); // Play from region start to end

183

await region.play(12); // Play from region start to 12 seconds

184

185

// Update region properties

186

region.setOptions({

187

color: "rgba(255, 0, 255, 0.4)",

188

content: "Updated Introduction",

189

end: 18,

190

});

191

192

// Modify region content

193

region.setContent("New Title");

194

region.setContent(document.createElement("div")); // HTML element

195

196

// Remove region

197

region.remove();

198

199

// Access region properties

200

console.log(`Region "${region.id}" from ${region.start}s to ${region.end}s`);

201

console.log(`Duration: ${region.end - region.start}s`);

202

```

203

204

### Region Parameters

205

206

Configuration options for creating and updating regions.

207

208

```typescript { .api }

209

interface RegionParams {

210

/** The id of the region, defaults to random string */

211

id?: string;

212

213

/** The start position of the region (in seconds) - required */

214

start: number;

215

216

/** The end position of the region (in seconds), defaults to start + small duration */

217

end?: number;

218

219

/** Allow/disallow dragging the region, defaults to true */

220

drag?: boolean;

221

222

/** Allow/disallow resizing the region, defaults to true */

223

resize?: boolean;

224

225

/** Allow/disallow resizing the start of the region, defaults to resize value */

226

resizeStart?: boolean;

227

228

/** Allow/disallow resizing the end of the region, defaults to resize value */

229

resizeEnd?: boolean;

230

231

/** The color of the region (CSS color), defaults to random color */

232

color?: string;

233

234

/** Content string or HTML element */

235

content?: string | HTMLElement;

236

237

/** Min length when resizing (in seconds), defaults to 0 */

238

minLength?: number;

239

240

/** Max length when resizing (in seconds), defaults to Infinity */

241

maxLength?: number;

242

243

/** The index of the channel, defaults to 0 */

244

channelIdx?: number;

245

246

/** Allow/Disallow contenteditable property for content, defaults to false */

247

contentEditable?: boolean;

248

}

249

```

250

251

**Usage Examples:**

252

253

```typescript

254

// Minimal region (only start required)

255

const quickRegion = regions.addRegion({

256

start: 45,

257

// end defaults to start + small duration

258

// other properties use defaults

259

});

260

261

// Comprehensive region configuration

262

const detailedRegion = regions.addRegion({

263

id: "bridge-section",

264

start: 120,

265

end: 150,

266

drag: true,

267

resize: true,

268

resizeStart: false, // Can't resize start

269

resizeEnd: true, // Can resize end

270

color: "#ff6b6b",

271

content: "Bridge",

272

minLength: 10,

273

maxLength: 60,

274

channelIdx: 0,

275

contentEditable: true,

276

});

277

278

// Read-only region

279

const staticRegion = regions.addRegion({

280

id: "marker",

281

start: 75,

282

end: 75.1, // Very short duration for marker

283

drag: false,

284

resize: false,

285

color: "red",

286

content: "Important Moment",

287

});

288

289

// Multi-channel region

290

const stereoRegion = regions.addRegion({

291

start: 30,

292

end: 40,

293

channelIdx: 1, // Second channel

294

color: "rgba(0, 255, 255, 0.3)",

295

});

296

```

297

298

### Region Events

299

300

Events emitted by individual regions and the regions plugin for interaction tracking.

301

302

```typescript { .api }

303

interface RegionEvents {

304

/** Before the region is removed */

305

remove: [];

306

307

/** When the region's parameters are being updated */

308

update: [side?: 'start' | 'end'];

309

310

/** When dragging or resizing is finished */

311

'update-end': [];

312

313

/** On region play */

314

play: [end?: number];

315

316

/** On mouse click */

317

click: [event: MouseEvent];

318

319

/** Double click */

320

dblclick: [event: MouseEvent];

321

322

/** Mouse over */

323

over: [event: MouseEvent];

324

325

/** Mouse leave */

326

leave: [event: MouseEvent];

327

328

/** Content changed */

329

'content-changed': [];

330

}

331

332

interface RegionsPluginEvents extends BasePluginEvents {

333

/** When a new region is initialized but not rendered yet */

334

'region-initialized': [region: Region];

335

336

/** When a region is created and rendered */

337

'region-created': [region: Region];

338

339

/** When a region is being updated */

340

'region-update': [region: Region, side?: 'start' | 'end'];

341

342

/** When a region is done updating */

343

'region-updated': [region: Region];

344

345

/** When a region is removed */

346

'region-removed': [region: Region];

347

348

/** When a region is clicked */

349

'region-clicked': [region: Region, e: MouseEvent];

350

351

/** When a region is double-clicked */

352

'region-double-clicked': [region: Region, e: MouseEvent];

353

354

/** When playback enters a region */

355

'region-in': [region: Region];

356

357

/** When playback leaves a region */

358

'region-out': [region: Region];

359

360

/** When region content is changed */

361

'region-content-changed': [region: Region];

362

}

363

```

364

365

**Usage Examples:**

366

367

```typescript

368

// Listen to plugin-level events

369

regions.on("region-created", (region) => {

370

console.log(`New region created: ${region.id}`);

371

setupRegionControls(region);

372

});

373

374

regions.on("region-clicked", (region, event) => {

375

console.log(`Clicked region: ${region.id}`);

376

showRegionDetails(region);

377

});

378

379

regions.on("region-updated", (region) => {

380

console.log(`Region ${region.id} updated: ${region.start}s - ${region.end}s`);

381

saveRegionData(region);

382

});

383

384

regions.on("region-in", (region) => {

385

console.log(`Entered region: ${region.id}`);

386

highlightRegion(region);

387

});

388

389

regions.on("region-out", (region) => {

390

console.log(`Left region: ${region.id}`);

391

unhighlightRegion(region);

392

});

393

394

// Listen to individual region events

395

const region = regions.addRegion({ start: 10, end: 20, content: "Test" });

396

397

region.on("click", (event) => {

398

event.stopPropagation();

399

toggleRegionSelection(region);

400

});

401

402

region.on("dblclick", (event) => {

403

region.play();

404

});

405

406

region.on("update", (side) => {

407

console.log(`Updating region ${side || 'position'}`);

408

showUpdateIndicator();

409

});

410

411

region.on("update-end", () => {

412

console.log("Region update complete");

413

hideUpdateIndicator();

414

validateRegion(region);

415

});

416

417

region.on("content-changed", () => {

418

console.log("Region content changed");

419

autosaveContent(region);

420

});

421

```

422

423

### Advanced Region Features

424

425

Additional region functionality for complex use cases and applications.

426

427

**Usage Examples:**

428

429

```typescript

430

// Region templates for consistent styling

431

const regionTemplates = {

432

verse: {

433

color: "rgba(255, 0, 0, 0.3)",

434

drag: true,

435

resize: true,

436

minLength: 15,

437

maxLength: 45,

438

},

439

chorus: {

440

color: "rgba(0, 255, 0, 0.3)",

441

drag: true,

442

resize: true,

443

minLength: 20,

444

maxLength: 40,

445

},

446

bridge: {

447

color: "rgba(0, 0, 255, 0.3)",

448

drag: true,

449

resize: true,

450

minLength: 10,

451

maxLength: 30,

452

},

453

};

454

455

// Create templated regions

456

function createTemplatedRegion(type, start, end, content) {

457

return regions.addRegion({

458

...regionTemplates[type],

459

start,

460

end,

461

content,

462

id: `${type}-${Date.now()}`,

463

});

464

}

465

466

// Batch region operations

467

const songStructure = [

468

{ type: "verse", start: 0, end: 30, content: "Verse 1" },

469

{ type: "chorus", start: 30, end: 60, content: "Chorus 1" },

470

{ type: "verse", start: 60, end: 90, content: "Verse 2" },

471

{ type: "chorus", start: 90, end: 120, content: "Chorus 2" },

472

];

473

474

songStructure.forEach(section => {

475

createTemplatedRegion(section.type, section.start, section.end, section.content);

476

});

477

478

// Region export/import for persistence

479

function exportRegions() {

480

return regions.getRegions().map(region => ({

481

id: region.id,

482

start: region.start,

483

end: region.end,

484

color: region.color,

485

content: region.content?.textContent || "",

486

drag: region.drag,

487

resize: region.resize,

488

}));

489

}

490

491

function importRegions(regionData) {

492

regions.clearRegions();

493

regionData.forEach(data => {

494

regions.addRegion(data);

495

});

496

}

497

498

// Save/load regions

499

localStorage.setItem("savedRegions", JSON.stringify(exportRegions()));

500

const savedRegions = JSON.parse(localStorage.getItem("savedRegions") || "[]");

501

importRegions(savedRegions);

502

503

// Region validation and constraints

504

function validateRegionOverlap(newRegion) {

505

const existingRegions = regions.getRegions();

506

507

for (const region of existingRegions) {

508

if (region === newRegion) continue;

509

510

const hasOverlap =

511

(newRegion.start < region.end && newRegion.end > region.start);

512

513

if (hasOverlap) {

514

console.warn(`Region ${newRegion.id} overlaps with ${region.id}`);

515

return false;

516

}

517

}

518

return true;

519

}

520

521

// Auto-adjust regions to prevent overlap

522

regions.on("region-update", (region) => {

523

if (!validateRegionOverlap(region)) {

524

// Auto-adjust to prevent overlap

525

const conflicts = regions.getRegions().filter(r =>

526

r !== region && r.start < region.end && r.end > region.start

527

);

528

529

if (conflicts.length > 0) {

530

const nearestEnd = Math.min(...conflicts.map(r => r.end));

531

region.setOptions({ start: nearestEnd });

532

}

533

}

534

});

535

```