@responsivevoice/features
Dashboard feature plugins for ResponsiveVoice. Provides the FeatureManager
lifecycle manager plus nine speech features: welcome message, speak-
selected-text, speak-links, paragraph and tab navigation, inactivity
message, end-of-page message, exit intent, and web player.
Consumed primarily by @responsivevoice/core, which re-exports the full
surface.
Classes
Section titled “Classes”EndOfPageMessageFeature
Section titled “EndOfPageMessageFeature”Defined in: src/features/end-of-page-message.ts:9
Speaks a configured message when the user scrolls to (or near) the bottom of the page. Extends SpeakOnceFeature.
Extends
Section titled “Extends”SpeakOnceFeature
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new EndOfPageMessageFeature(): EndOfPageMessageFeature;Returns
Section titled “Returns”Inherited from
Section titled “Inherited from”SpeakOnceFeature.constructorProperties
Section titled “Properties”readonly name: "speakEndPage" = 'speakEndPage';Defined in: src/features/end-of-page-message.ts:11
Unique feature name matching the WebsiteFeatures key
Overrides
Section titled “Overrides”SpeakOnceFeature.nameAccessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/base-speak-once.ts:20
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”SpeakOnceFeature.activeMethods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/end-of-page-message.ts:39
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”SpeakOnceFeature.cleanupinit()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/end-of-page-message.ts:15
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”SpeakOnceFeature.initExitIntentFeature
Section titled “ExitIntentFeature”Defined in: src/features/exit-intent.ts:8
Speaks a configured message when the pointer moves toward the top of the viewport — a signal the user may be about to leave the page.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new ExitIntentFeature(): ExitIntentFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "exitIntent" = 'exitIntent';Defined in: src/features/exit-intent.ts:10
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/exit-intent.ts:16
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/exit-intent.ts:41
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/exit-intent.ts:21
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”FeatureManager
Section titled “FeatureManager”Defined in: src/manager.ts:10
Registers and orchestrates dashboard Feature plugins. Features are
registered once, then activated together with a resolved website config +
speak function; calling activate() again cleans up the previous batch
before starting the new one, so re-config is idempotent.
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new FeatureManager(): FeatureManager;Returns
Section titled “Returns”Methods
Section titled “Methods”activate()
Section titled “activate()”activate( config, speak, voice, apiKey?): void;Defined in: src/manager.ts:23
Initialize every registered feature with the given website config. If a previous activation is still live, cleans it up first.
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled? | boolean | - |
config.exitIntent.text? | string | null | - |
config.paragraphNavigation? | { enabled: boolean; } | - |
config.paragraphNavigation.enabled? | boolean | - |
config.speakEndPage? | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled? | boolean | - |
config.speakEndPage.text? | string | null | - |
config.speakInactivity? | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled? | boolean | - |
config.speakInactivity.text? | string | null | - |
config.speakLinks? | { enabled: boolean; } | - |
config.speakLinks.enabled? | boolean | - |
config.speakSelectedText? | { enabled: boolean; } | - |
config.speakSelectedText.enabled? | boolean | - |
config.webPlayer? | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls? | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand? | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress? | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip? | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed? | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time? | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled? | boolean | Turn the player on. |
config.webPlayer.layout? | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display? | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode? | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer? | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation? | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled? | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position? | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation? | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick? | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight? | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector? | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position? | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize? | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled? | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude? | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector? | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme? | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage? | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled? | boolean | - |
config.welcomeMessage.text? | string | null | - |
config.welcomeMessageOnce? | boolean | - |
speak? | SpeakFn | - |
voice? | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name? | string | - |
voice.pitch? | number | - |
voice.rate? | number | - |
voice.volume? | number | - |
apiKey? | string | - |
Returns
Section titled “Returns”void
cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/manager.ts:36
Tear down every currently-active feature (event listeners, timers, etc.).
Returns
Section titled “Returns”void
get<T>(name): T | undefined;Defined in: src/manager.ts:55
Returns the registered feature with the given name, or undefined if
none is registered. Useful for callers that need to invoke feature-
specific public methods (e.g. webPlayer.mount(...)).
Type Parameters
Section titled “Type Parameters”| Type Parameter | Default type |
|---|---|
T extends Feature | Feature |
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
name | string |
Returns
Section titled “Returns”T | undefined
getActiveFeatures()
Section titled “getActiveFeatures()”getActiveFeatures(): string[];Defined in: src/manager.ts:46
Names of features currently reporting active === true.
Returns
Section titled “Returns”string[]
isActivated()
Section titled “isActivated()”isActivated(): boolean;Defined in: src/manager.ts:60
Whether activate() has been called (and not yet cleaned up).
Returns
Section titled “Returns”boolean
register()
Section titled “register()”register(feature): void;Defined in: src/manager.ts:15
Register a feature plugin. Safe to call before or after activate().
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
feature | Feature |
Returns
Section titled “Returns”void
InactivityMessageFeature
Section titled “InactivityMessageFeature”Defined in: src/features/inactivity-message.ts:11
Speaks a configured message after a period of user inactivity on the page. Extends SpeakOnceFeature for per-page-load idempotency.
Extends
Section titled “Extends”SpeakOnceFeature
Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new InactivityMessageFeature(): InactivityMessageFeature;Returns
Section titled “Returns”Inherited from
Section titled “Inherited from”SpeakOnceFeature.constructorProperties
Section titled “Properties”readonly name: "speakInactivity" = 'speakInactivity';Defined in: src/features/inactivity-message.ts:13
Unique feature name matching the WebsiteFeatures key
Overrides
Section titled “Overrides”SpeakOnceFeature.nameAccessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/base-speak-once.ts:20
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Inherited from
Section titled “Inherited from”SpeakOnceFeature.activeMethods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/inactivity-message.ts:49
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”SpeakOnceFeature.cleanupinit()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/inactivity-message.ts:18
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Overrides
Section titled “Overrides”SpeakOnceFeature.initParagraphNavigationFeature
Section titled “ParagraphNavigationFeature”Defined in: src/features/paragraph-navigation.ts:8
Provides keyboard navigation across paragraphs with speech feedback on the focused block.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new ParagraphNavigationFeature(): ParagraphNavigationFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "paragraphNavigation" = 'paragraphNavigation';Defined in: src/features/paragraph-navigation.ts:10
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/paragraph-navigation.ts:16
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/paragraph-navigation.ts:52
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/paragraph-navigation.ts:21
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”SpeakLinksFeature
Section titled “SpeakLinksFeature”Defined in: src/features/speak-links.ts:9
Speaks link text when the pointer hovers long enough to register hover intent. Uses a short dwell timer to avoid firing on incidental cursor movement.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new SpeakLinksFeature(): SpeakLinksFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "speakLinks" = 'speakLinks';Defined in: src/features/speak-links.ts:11
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/speak-links.ts:17
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/speak-links.ts:61
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/speak-links.ts:22
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”SpeakSelectedTextFeature
Section titled “SpeakSelectedTextFeature”Defined in: src/features/speak-selected-text.ts:7
Listens for text selection on the page and speaks the highlighted text. Activates on mouseup selection events.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new SpeakSelectedTextFeature(): SpeakSelectedTextFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "speakSelectedText" = 'speakSelectedText';Defined in: src/features/speak-selected-text.ts:9
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/speak-selected-text.ts:14
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/speak-selected-text.ts:35
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/speak-selected-text.ts:19
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”TabNavigationFeature
Section titled “TabNavigationFeature”Defined in: src/features/tab-navigation.ts:7
Provides keyboard tab navigation with speech feedback on focused elements — the accessibility navigation mode.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new TabNavigationFeature(): TabNavigationFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "accessibilityNavigation" = 'accessibilityNavigation';Defined in: src/features/tab-navigation.ts:9
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/tab-navigation.ts:14
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/tab-navigation.ts:62
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/tab-navigation.ts:19
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”WebPlayerFeature
Section titled “WebPlayerFeature”Defined in: src/features/web-player.ts:49
Web player orchestrator. Discovers articles matching selector at init
time and binds an independent WebPlayerInstance to each one.
Exposes mount for runtime mounts on dynamically-added elements
(SPAs, lazy-loaded sections).
Coordinates single-active-narrator behaviour: when one instance starts
speaking, it calls back via the constructor-injected onActivate so the
orchestrator can preempt every other live instance.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new WebPlayerFeature(): WebPlayerFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "webPlayer" = 'webPlayer';Defined in: src/features/web-player.ts:51
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/web-player.ts:60
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/web-player.ts:91
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice): void;Defined in: src/features/web-player.ts:65
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled | boolean | - |
config.exitIntent.text | string | null | - |
config.paragraphNavigation | { enabled: boolean; } | - |
config.paragraphNavigation.enabled | boolean | - |
config.speakEndPage | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled | boolean | - |
config.speakEndPage.text | string | null | - |
config.speakInactivity | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled | boolean | - |
config.speakInactivity.text | string | null | - |
config.speakLinks | { enabled: boolean; } | - |
config.speakLinks.enabled | boolean | - |
config.speakSelectedText | { enabled: boolean; } | - |
config.speakSelectedText.enabled | boolean | - |
config.webPlayer | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled | boolean | Turn the player on. |
config.webPlayer.layout | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled | boolean | - |
config.welcomeMessage.text | string | null | - |
config.welcomeMessageOnce | boolean | - |
speak | SpeakFn | - |
voice | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name | string | - |
voice.pitch | number | - |
voice.rate | number | - |
voice.volume | number | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”mount()
Section titled “mount()”mount(selectorOrElement, overrides?): | WebPlayerMountHandle | null;Defined in: src/features/web-player.ts:112
Imperatively mount a player on a dynamically-added element. Used by
SPAs and any case where the target element wasn't in the DOM at
rv.init() time.
overrides accepts the same shape as the init webPlayer config;
leaf-merged over the init config (missing fields fall through to init
defaults). Returns a handle whose unmount() tears this instance down.
No-op when the feature isn't active (init not called or enabled: false)
or when the target element can't be resolved.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
selectorOrElement | string | HTMLElement |
overrides? | WebPlayerMountOverrides |
Returns
Section titled “Returns”| WebPlayerMountHandle
| null
WelcomeMessageFeature
Section titled “WelcomeMessageFeature”Defined in: src/features/welcome-message.ts:12
Speaks a configured welcome message shortly after page load. Respects the welcomeMessageOnce flag via sessionStorage (keyed by API key hash) so repeat visits stay silent for the same text.
Implements
Section titled “Implements”Constructors
Section titled “Constructors”Constructor
Section titled “Constructor”new WelcomeMessageFeature(): WelcomeMessageFeature;Returns
Section titled “Returns”Properties
Section titled “Properties”readonly name: "welcomeMessage" = 'welcomeMessage';Defined in: src/features/welcome-message.ts:14
Unique feature name matching the WebsiteFeatures key
Implementation of
Section titled “Implementation of”Accessors
Section titled “Accessors”active
Section titled “active”Get Signature
Section titled “Get Signature”get active(): boolean;Defined in: src/features/welcome-message.ts:19
Whether this feature is currently active
Returns
Section titled “Returns”boolean
Whether this feature is currently active
Implementation of
Section titled “Implementation of”Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/features/welcome-message.ts:66
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”init()
Section titled “init()”init( config, speak, voice, apiKey?): void;Defined in: src/features/welcome-message.ts:24
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled? | boolean | - |
config.exitIntent.text? | string | null | - |
config.paragraphNavigation? | { enabled: boolean; } | - |
config.paragraphNavigation.enabled? | boolean | - |
config.speakEndPage? | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled? | boolean | - |
config.speakEndPage.text? | string | null | - |
config.speakInactivity? | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled? | boolean | - |
config.speakInactivity.text? | string | null | - |
config.speakLinks? | { enabled: boolean; } | - |
config.speakLinks.enabled? | boolean | - |
config.speakSelectedText? | { enabled: boolean; } | - |
config.speakSelectedText.enabled? | boolean | - |
config.webPlayer? | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls? | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand? | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress? | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip? | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed? | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time? | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled? | boolean | Turn the player on. |
config.webPlayer.layout? | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display? | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode? | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer? | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation? | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled? | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position? | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation? | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick? | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight? | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector? | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position? | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize? | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled? | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude? | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector? | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme? | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage? | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled? | boolean | - |
config.welcomeMessage.text? | string | null | - |
config.welcomeMessageOnce? | boolean | - |
speak? | SpeakFn | - |
voice? | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name? | string | - |
voice.pitch? | number | - |
voice.rate? | number | - |
voice.volume? | number | - |
apiKey? | string | - |
Returns
Section titled “Returns”void
Implementation of
Section titled “Implementation of”Interfaces
Section titled “Interfaces”Feature
Section titled “Feature”Defined in: src/types.ts:64
Feature plugin interface. Each dashboard feature implements this.
Properties
Section titled “Properties”active
Section titled “active”readonly active: boolean;Defined in: src/types.ts:68
Whether this feature is currently active
readonly name: string;Defined in: src/types.ts:66
Unique feature name matching the WebsiteFeatures key
Methods
Section titled “Methods”cleanup()
Section titled “cleanup()”cleanup(): void;Defined in: src/types.ts:72
Tear down the feature (remove event listeners, timers, etc.)
Returns
Section titled “Returns”void
init()
Section titled “init()”init( config, speak, voice, apiKey?): void;Defined in: src/types.ts:70
Initialize and activate the feature
Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
config | { accessibilityNavigation: { enabled: boolean; }; exitIntent: { enabled: boolean; text: string | null; }; paragraphNavigation: { enabled: boolean; }; speakEndPage: { enabled: boolean; text: string | null; }; speakInactivity: { enabled: boolean; text: string | null; }; speakLinks: { enabled: boolean; }; speakSelectedText: { enabled: boolean; }; webPlayer: { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; }; welcomeMessage: { enabled: boolean; text: string | null; }; welcomeMessageOnce: boolean; } | - |
config.accessibilityNavigation | { enabled: boolean; } | - |
config.accessibilityNavigation.enabled | boolean | - |
config.exitIntent | { enabled: boolean; text: string | null; } | - |
config.exitIntent.enabled? | boolean | - |
config.exitIntent.text? | string | null | - |
config.paragraphNavigation? | { enabled: boolean; } | - |
config.paragraphNavigation.enabled? | boolean | - |
config.speakEndPage? | { enabled: boolean; text: string | null; } | - |
config.speakEndPage.enabled? | boolean | - |
config.speakEndPage.text? | string | null | - |
config.speakInactivity? | { enabled: boolean; text: string | null; } | - |
config.speakInactivity.enabled? | boolean | - |
config.speakInactivity.text? | string | null | - |
config.speakLinks? | { enabled: boolean; } | - |
config.speakLinks.enabled? | boolean | - |
config.speakSelectedText? | { enabled: boolean; } | - |
config.speakSelectedText.enabled? | boolean | - |
config.webPlayer? | { controls: { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; }; enabled: boolean; layout: { display: "inline" | "block"; mode: "fill" | "shrink"; }; miniPlayer: { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; }; navigation: { paragraphClick: boolean; paragraphHighlight: boolean; }; paragraphSelector: string; pitch?: number; position: | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; }; rate?: number; sanitize: { enabled: boolean; exclude: string[]; }; selector: string; theme: | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; }; voice?: | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; }; volume?: number; } | - |
config.webPlayer.controls? | { brand: boolean; progress: boolean; skip: boolean; speed: boolean; time: boolean; } | Show or hide individual controls (progress bar, time, skip, speed, brand). |
config.webPlayer.controls.brand? | boolean | ResponsiveVoice brand icon (links to responsivevoice.org). |
config.webPlayer.controls.progress? | boolean | Progress bar showing how much of the article has been narrated. |
config.webPlayer.controls.skip? | boolean | Skip-back and skip-forward buttons (jump one paragraph at a time). |
config.webPlayer.controls.speed? | boolean | Playback speed button — click to cycle 0.5× through 3×. |
config.webPlayer.controls.time? | boolean | Elapsed / total time label (e.g. 0:42 / 3:15). |
config.webPlayer.enabled? | boolean | Turn the player on. |
config.webPlayer.layout? | { display: "inline" | "block"; mode: "fill" | "shrink"; } | Main-pill width and page flow. |
config.webPlayer.layout.display? | "inline" | "block" | How the player sits on the page: block takes its own line, inline flows with surrounding text. |
config.webPlayer.layout.mode? | "fill" | "shrink" | Player width: shrink sizes to its content, fill stretches to fill its container. |
config.webPlayer.miniPlayer? | { animation: "none" | "fade" | "slide" | "pop"; enabled: boolean; position: | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; }; } | Floating mini-player. Boolean shorthand maps to { enabled, position } with the default 'bottom-left' corner. |
config.webPlayer.miniPlayer.animation? | "none" | "fade" | "slide" | "pop" | Entrance/exit animation. none is instant; fade opacity-only; slide fades and slides from the docked corner; pop scales in with a bounce. Forced instant under prefers-reduced-motion: reduce. |
config.webPlayer.miniPlayer.enabled? | boolean | Show the floating mini-player when the main player scrolls out of view. |
config.webPlayer.miniPlayer.position? | | "top-left" | "top-right" | "bottom-left" | "bottom-right" | { bottom?: string; left?: string; right?: string; top?: string; } | Viewport placement — a corner keyword or a CSS-offset object. |
config.webPlayer.navigation? | { paragraphClick: boolean; paragraphHighlight: boolean; } | Toggle paragraph highlighting and click-to-jump navigation. |
config.webPlayer.navigation.paragraphClick? | boolean | Click-to-jump: clicking any paragraph starts narration from that point. |
config.webPlayer.navigation.paragraphHighlight? | boolean | Visual "currently playing" indicator on each narrated paragraph. |
config.webPlayer.paragraphSelector? | string | CSS selector for the elements inside the article to narrate (paragraphs, headings, list items). |
config.webPlayer.pitch? | number | Voice pitch (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.position? | | "inline" | "before" | "after" | { at: "before" | "after" | "inside"; target: string; } | Where the player is placed. Either a keyword (relative to selector) or an object specifying a custom mount target. - `'before' |
config.webPlayer.rate? | number | Speech rate (0–2, default 1 = normal). Providers may normalize to their own scale. |
config.webPlayer.sanitize? | { enabled: boolean; exclude: string[]; } | Exclude non-narratable content (scripts, styles, controls, media) from narration. |
config.webPlayer.sanitize.enabled? | boolean | Strip non-narratable nodes from narrated text. |
config.webPlayer.sanitize.exclude? | string[] | Extra CSS selectors to exclude, composed with the built-in list. |
config.webPlayer.selector? | string | CSS selector for the article element to attach the player to (default: the first <article> on the page). |
config.webPlayer.theme? | | "neutral" | "responsivevoice" | { accent?: string; accentSoft?: string; bg?: string; border?: string; fg?: string; fill?: string; hover?: string; muted?: string; track?: string; } | Colour theme — a preset name or a partial set of overrides merged over the 'neutral' defaults. |
config.webPlayer.voice? | | string | { flags?: string; regex: string; } | { gender?: "m" | "male" | "f" | "female"; isByok?: boolean; lang?: string; name?: string; provider?: string; } | Voice to narrate this player. Same VoiceSelector grammar as core.speak()'s second argument — name string, regex literal, or structured query. Inherits the website default voice when omitted. |
config.webPlayer.volume? | number | Volume (0–1, default 1 = full). |
config.welcomeMessage? | { enabled: boolean; text: string | null; } | - |
config.welcomeMessage.enabled? | boolean | - |
config.welcomeMessage.text? | string | null | - |
config.welcomeMessageOnce? | boolean | - |
speak? | SpeakFn | - |
voice? | { name: string; pitch: number; rate: number; volume: number; } | - |
voice.name? | string | - |
voice.pitch? | number | - |
voice.rate? | number | - |
voice.volume? | number | - |
apiKey? | string | - |
Returns
Section titled “Returns”void
SpeakHandle
Section titled “SpeakHandle”Defined in: src/types.ts:15
Handle returned by SpeakFn. Lets features control the active utterance (pause / resume / cancel) without needing a direct reference to the core client.
Use pause / resume for "stop and continue from this exact point" —
implemented via speechSynthesis.pause() / resume(), which reliably
suspend the engine mid-word. Use cancel when abandoning the current
utterance entirely (e.g. to jump to a different paragraph); that routes
through speechSynthesis.cancel(), which is more aggressive but is the
right move when followed immediately by a fresh speak() call.
Methods
Section titled “Methods”cancel()
Section titled “cancel()”cancel(): void;Defined in: src/types.ts:17
Abort the active utterance and clear the queue. Does NOT fire onend.
Returns
Section titled “Returns”void
pause()
Section titled “pause()”pause(): void;Defined in: src/types.ts:22
Suspend the active utterance in place. The engine keeps the utterance alive; SpeakHandle.resume will continue from the same word.
Returns
Section titled “Returns”void
resume()
Section titled “resume()”resume(): void;Defined in: src/types.ts:24
Resume a paused utterance from the word it was suspended on.
Returns
Section titled “Returns”void
SpeakParams
Section titled “SpeakParams”Defined in: src/types.ts:46
Minimal parameter shape accepted by the injected SpeakFn. Matches
the subset of SpeakParams from @responsivevoice/types that feature
plugins actually need — keeping this local avoids a circular dependency
on the full core type.
Properties
Section titled “Properties”onend?
Section titled “onend?”optional onend?: () => void;Defined in: src/types.ts:56
Called when playback finishes naturally.
Returns
Section titled “Returns”void
onerror?
Section titled “onerror?”optional onerror?: (error) => void;Defined in: src/types.ts:58
Called on engine errors.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
error | Error |
Returns
Section titled “Returns”void
onstart?
Section titled “onstart?”optional onstart?: () => void;Defined in: src/types.ts:54
Called when playback starts.
Returns
Section titled “Returns”void
pitch?
Section titled “pitch?”optional pitch?: number;Defined in: src/types.ts:48
Speech pitch (0–2 scale, 1 = normal).
optional rate?: number;Defined in: src/types.ts:50
Speech rate (0.1–1.5 scale, 1 = normal).
volume?
Section titled “volume?”optional volume?: number;Defined in: src/types.ts:52
Speech volume (0–1 scale).
WebPlayerMountHandle
Section titled “WebPlayerMountHandle”Defined in: src/features/web-player.ts:19
Handle returned by WebPlayerFeature.mount. Caller invokes
unmount() when the mounted element is removed from the DOM, or to
tear the player down imperatively.
Methods
Section titled “Methods”unmount()
Section titled “unmount()”unmount(): void;Defined in: src/features/web-player.ts:21
Tear down this mounted instance. Idempotent.
Returns
Section titled “Returns”void
Type Aliases
Section titled “Type Aliases”SpeakFn
Section titled “SpeakFn”type SpeakFn = (text, voice?, params?) => SpeakHandle;Defined in: src/types.ts:34
A speak function injected by core — features don't depend on core directly.
This avoids the circular dependency core → features → core.
Returns a SpeakHandle the caller can use to cancel mid-utterance. Features that only need "fire and forget" playback may ignore the return.
Parameters
Section titled “Parameters”| Parameter | Type |
|---|---|
text | string |
voice? | VoiceSelectorInput |
params? | SpeakParams |
Returns
Section titled “Returns”WebPlayerMountOverrides
Section titled “WebPlayerMountOverrides”type WebPlayerMountOverrides = Omit<Partial<WebPlayerFeature>, "controls" | "navigation" | "layout"> & { controls?: Partial<WebPlayerFeature["controls"]>; layout?: Partial<WebPlayerFeature["layout"]>; navigation?: Partial<WebPlayerFeature["navigation"]>;};Defined in: src/features/web-player.ts:30
Partial-override shape for WebPlayerFeature.mount. Top-level
fields are optional and the three grouped sets (controls, navigation,
layout) accept partial leaves so { controls: { brand: false } } keeps
the rest of controls from the init config.
Type Declaration
Section titled “Type Declaration”controls?
Section titled “controls?”optional controls?: Partial<WebPlayerFeature["controls"]>;layout?
Section titled “layout?”optional layout?: Partial<WebPlayerFeature["layout"]>;navigation?
Section titled “navigation?”optional navigation?: Partial<WebPlayerFeature["navigation"]>;Functions
Section titled “Functions”createFeatureManager()
Section titled “createFeatureManager()”function createFeatureManager(): FeatureManager;Defined in: src/factory.ts:15
Creates a FeatureManager with all 9 built-in dashboard features registered.