The speech API provides text-to-speech output via the browser TTS engine. Supports both global (2D) audio and 3D positional audio attached to ped entities or world coordinates.
Networked audio: When a 3D speak call is made for a networked entity (and network audio is enabled for the calling addon), the sound is broadcast to nearby players automatically via the server relay. Other players hear the speech spatially from the entity's position.
Synthesize and play TTS audio. Pass an entity or coords to produce 3D positioned audio; omit both for global audio.
Syntaxexports['onex-voiceInteraction']:speak(text, options)
| Name | Type | Description |
|---|---|---|
text | string | Text to speak. Required, non-empty. |
options.voice | string | table | Voice name string ("en-US-GuyNeural") or voice object — see below. |
options.entity | number | Ped entity handle for 3D positioned audio. Voice is auto-detected from NPC config if not specified. |
options.coords | vector3 | World coordinates for 3D audio without a ped entity. |
options.maxDistance | number | Hearing range in metres for 3D audio (default 30.0). |
options.animation | table | false | Animation options for ped entities. false disables all animation. |
options.showSubtitle | boolean | Display a subtitle synced to actual TTS duration. |
options.immediateSubtitle | boolean | Display subtitle immediately without waiting for TTS timing. |
options.npcName | string | Speaker name shown in the subtitle. |
options.networked | boolean | Broadcast 3D audio to nearby players via server relay. |
Returns: { success = true, data = { soundId = "sound_12345_6789", is3D = true } }
For global audio, soundId is nil and is3D is false. For 3D audio, soundId is a string you can pass to stopSpeech.
The voice field accepts either a plain string name or a full settings object:
-- String(name only) voice = "en-US-GuyNeural" -- Object(full settings) voice = { name = "en-US-GuyNeural", -- voice identifier rate = 1.0, -- speech rate(default 1.0) pitch = 1.0, -- pitch modifier(default 1.0) volume = 0.8 -- volume 0.0–1.0 (default 1.0) }
The legacy flat structure (options.rate, options.pitch, options.volume at the top level) is also supported for backward compatibility.
For entity-based 3D audio on peds, lip-sync and gesture animations are enabled by default:
animation = { lipSync = true, -- default: true gesture = true, -- default: true returnToIdle = true, -- return to idle after gesture(default: true) gestureDict = nil, -- custom gesture animation dict gestureAnim = nil, -- custom gesture animation name idleScenario = nil -- idle scenario to play after speech }
Pass animation = false to disable all animation entirely.
Your Script-- Simple global TTS exports['onex-voiceInteraction']:speak("Hello, this is a global announcement.", { voice = "en-US-GuyNeural" }) -- With full voice settings exports['onex-voiceInteraction']:speak("Attention all units.", { voice = { name = "en-US-EricNeural", rate = 0.95, pitch = 1.0, volume = 0.9 } })
Stop TTS playback. Stop a specific 3D sound by ID or stop all active sounds at once.
Syntaxexports['onex-voiceInteraction']:stopSpeech(soundId)
| Name | Type | Description |
|---|---|---|
soundId | string | Specific 3D sound ID returned from speak. Omit to stop all sounds. |
Returns: { success = true, data = { stopped = 1 } } — stopped is -1 when stopping all (count unknown).
Your Script-- Stop all TTS(global + all 3D) exports['onex-voiceInteraction']:stopSpeech() -- Stop a specific 3D sound exports['onex-voiceInteraction']:stopSpeech("sound_12345_6789")
Retrieve the list of available TTS voices from the browser engine. Async — the browser engine must be ready.
Syntaxexports['onex-voiceInteraction']:getVoices(callback, timeout)
| Name | Type | Description |
|---|---|---|
callback | function | function(result) — called with { success, data = { voices } } on completion or { success = false, code = "TIMEOUT" } on timeout. |
timeout | number | Milliseconds before callback fires with a timeout error (default 5000). |
Without a callback: returns immediately with { success = true, data = { pending = true, listenEvent = "onex-voiceInteraction:tts:voices" } }. Listen to the named event to receive the voice list asynchronously.
Your Scriptexports['onex-voiceInteraction']:getVoices(function(result) if not result.success then print("Failed to get voices:", result.code) return end for _, voice in ipairs(result.data.voices) do print(voice.name, voice.lang) end end, 5000)
Get the configured or auto-detected TTS voice for a ped entity. Uses NPC config if available, falls back to gender-based pool selection.
Syntaxexports['onex-voiceInteraction']:getVoiceForPed(entity)
| Name | Type | Description |
|---|---|---|
entity | number | Ped entity handle |
Returns: { success = true, data = { voice = "en-US-GuyNeural", gender = "male", cached = false } }
| Field | Type | Description |
|---|---|---|
voice | string | Voice name to use |
gender | string | "male" or "female" |
cached | boolean | true if result was served from cache |
Results are cached per entity using a stable key (network ID + model hash). The cache persists for 5 minutes; local entity cache entries are pruned automatically.
Your Scriptlocal r = exports['onex-voiceInteraction']:getVoiceForPed(pedHandle) if r.success then print("Voice:", r.data.voice) print("Gender:", r.data.gender) print("Cached:", r.data.cached) end
Clear the voice assignment cache for a specific ped or all peds. Forces re-detection on the next speak or getVoiceForPed call.
Syntaxexports['onex-voiceInteraction']:clearVoiceCache(entity)
| Name | Type | Description |
|---|---|---|
entity | number | Ped entity handle, or omit to clear all cached entries |
Returns: { success = true, data = { cleared = 1 } }
Your Script-- Clear for one ped(forces re-detection next speak) exports['onex-voiceInteraction']:clearVoiceCache(pedHandle) -- Clear all cached voice assignments exports['onex-voiceInteraction']:clearVoiceCache()
Last updated 14 days ago