voice
The one call the rest of the game makes to be heard.
sound.voice
The one call the rest of the game makes to be heard.
local Voice = require("sound.voice")
Voice.line("tongue.reedgate.call") -- a written line, spoken
Voice.say("Walk on, then.", "The Lingster") -- free text, spoken if it was baked
Voice.sfx("answer_right") -- a one-shot, flat
Voice.sfx("sfx_splash", { x = 0, y = 0, z = 84 }) -- a one-shot, out there
Voice.ui("click") -- the interface answering
A spoken line always has its text on screen
Every call that speaks also raises hernsew:say with the text, the speaker's
name, and the clip's real length, read off the payload's own header. The
screens slice's caption queue listens on that signal, so the words are up for
exactly as long as the voice is — and a line whose clip was never baked still
goes up, unvoiced. The return value says only whether it was heard.
Everything here is guarded
A clip that was never baked, an anchor that has not spawned yet, a slice that loaded before the mix did — each of them makes this quiet, never an error. A game taken down by a missing noise is a worse failure than a game missing a noise.
Surface
| Call | Does |
|---|---|
line(id, opts?) | speak a line of the written script by id |
say(text, who?) | speak free text; matches it against the script |
sfx(name, at?, opts?) | a one-shot from sound.clips, flat or placed |
ui(kind) | "click" / "hover" / "back" / "page" |
lines() | the whole spoken script, for anybody baking or listing it |
clipFor(id) / lengthOf(id) | the clip and its true length |
isSpeaking() / lastLine() / stop() | what is being said right now |
ready() | whether the mix is up and holding emitters |
__attach / __detach are the mix component's own; nothing else calls them.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2sound.voice — the one call the rest of the game makes to be heard. local Voice = require("sound.voice") Voice.line("tongue.reedgate.call") -- a written line, spoken Voice.say("Walk on, then.", "The Lingster") -- free text, spoken if baked Voice.sfx("answer_right") -- a one-shot, 2D Voice.sfx("sfx_splash", { x = 0, y = 0, z = 84 }) -- a one-shot, out there Everything here is guarded. A clip that was never baked, an anchor that does not exist yet, a slice that loaded before the mix did — each of them makes this quiet, never an error. A game taken down by a missing noise is a worse failure than a game that is missing a noise. A spoken line ALWAYS puts its text on screen, whether or not the audio exists. That goes out on `hernsew:say`, the signal the screens slice's caption queue listens on, carrying the clip's REAL length so the words are up for exactly as long as the voice is.
__attach(rig: { voice: any?, ui: any?, world: any?, spatial: { any }? }) → void
The mix component publishes its emitter entities here as it builds them. Nothing else writes it. Before it does, every call below is a no-op that still puts the caption up.
| arg | type | description |
|---|---|---|
| rig | { voice: any?, ui: any?, world: any?, spatial: { any }? } |
__detach( ) → void
rig( ) → any
lines( ) → void
Every line in the game meant to be said aloud, with its text and speaker.
textIndex( ) → void
reindex( ) → void
Drop the text index. Called when the script changes underneath us.
voiceBank( ) → any
The generated bank of clip references, or nil while it does not exist yet. The bake writes the bank, and this module is loaded before the bake runs — so "not there" is the NORMAL first answer, not a permanent one. `exists` is asked first because it records no dependency and raises nothing, where a `require` of a module that is not there logs an error every time it is asked; and the miss is never cached, because caching it once made the whole game silent for the rest of a session in which the bank landed a minute later.
clipFor(lineId: string) → any
The clip for a line id, or nil when that line was never voiced.
| arg | type | description |
|---|---|---|
| lineId | string |
lengthOf(lineId: string) → number
How long a line's clip runs, in seconds, or nil if it has none. Read off the payload's own header rather than guessed, which is what lets a caption hold for exactly as long as the voice does.
| arg | type | description |
|---|---|---|
| lineId | string |
caption(text: string, who: string?, seconds: number?) → void
| arg | type | description |
|---|---|---|
| text | string | |
| who | string? | |
| seconds | number? |
playOn(source: any, clip: any, volume: number, pitch: number?) → boolean
| arg | type | description |
|---|---|---|
| source | any | |
| clip | any | |
| volume | number | |
| pitch | number? |
line(lineId: string, opts: { volume: number?, silent: boolean? }?) → boolean
Speak a line of the written script by its id. The text goes up on screen whether or not the clip exists; the return says only whether it was HEARD.
| arg | type | description |
|---|---|---|
| lineId | string | |
| opts | { volume: number?, silent: boolean? }? |
say(text: string, who: string?) → boolean
Speak free text. If the words match a line of the written script, that line's clip is used; otherwise the text still goes on screen unvoiced. This is the shape the other slices call — `Voice.say(text, who)`.
| arg | type | description |
|---|---|---|
| text | string | |
| who | string? |
isSpeaking( ) → boolean
Whether a line is being spoken right now.
lastLine( ) → string
The line id last spoken aloud, or nil.
stop( ) → void
Stop the voice mid-line — a cut, a skip, an ending.
sfx(name: string, at: any?, opts: { volume: number?, pitch: number? }?) → boolean
The shared one-shot library. `name` is a key in `sound.clips`; `at` is an optional world position, which plays it out there through a spatial emitter instead of flat across the mix. Returns true if a sound was actually started, so a caller that cares can tell "played" from "there is no such clip".
| arg | type | description |
|---|---|---|
| name | string | |
| at | any? | |
| opts | { volume: number?, pitch: number? }? |
ui(kind: string) → boolean
A UI answer: the click, the hover, the page. Separated from `sfx` only so the screens slice reads as asking for an interface sound rather than for a noise in the world.
| arg | type | description |
|---|---|---|
| kind | string |
ready( ) → boolean
Is the sound slice up and holding emitters? A caller does not need this — every call above is safe without it — but a diagnostic wants it.
The one call the rest of the game makes to be heard: a spoken line with its text on screen, a one-shot flat or placed in the world, and the interface answering.Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
Showing up to 3 levels deep. Open a part to see what it holds further down.
Problems
Everything affecting this asset right now: its own problems, anything wrong inside it, and problems on its direct dependencies.
agent_score is exposed.+ quality × 0.35
+ performance × 0.25
± compat factor
Usability ratings
Did the part work as advertised when consumers tried to drop it in. Separate from upvotes: those are taste; this is "did it function".
Scoped to this part · feeds back into the world's score.