The Eighth Ketyl
README.md
Score
The sound of The Eighth Ketyl: the music bed, the still's ambience, every
noise the game makes, the mix, and both spoken voices. One component on the
Score host entity; everything it plays hangs underneath as children.
It never runs the game. It listens to the shared event bus in Still and
answers with sound, so a slice that emits growthBurned gets a growth bursting
without knowing this file exists.
What it plays
| Child | Channel | What |
|---|---|---|
score_bed | music | bed_music — four bars of eight, looping |
score_ambience | ambient | amb_still — the computed hum, boiling and brass |
score_room | ambient | amb_room — the recorded room, under the computed one |
score_voice | voice | whichever spoken line is up |
clip_voice_1..14 | sfx / ui | the one-shot pool audio.Clips cycles |
Public fields
master: number— the whole mix at the master fader (0..1).music: number— the bed, under everything.ambient: number— the still itself.sfx: number— the game's own noises.ui: number— the interface, quieter than the game because it is furniture.voice: number— the two speakers, the loudest thing in the mix on purpose.captions: boolean— this component's own caption band. Off: the presentation slice draws the game's caption from the samelineevent, and two bands would print every line twice. The words live inaudio.Scripteither way, so turning this on is the fallback if that band ever stops.
Methods
:say(id)— speak a line by id, the same path thelineevent takes. For driving one by hand from a test; staging cues lines through the bus.:report()— what the mix is doing right now: levels, mixer, live voice count, the duck, the bed's gain and pitch, how many clips are registered, and which line is up. Check the mix with this rather than assuming it.
The mix
Foreground is a voice and whatever the player just did; background is the bed and the still. A spoken line pulls the background down to 30% over about an eighth of a second and lets it back up over a second and a half — that is the whole difference between a mix and a pile. Measured at the busiest moment the game can produce (a line, a discharge, a growth bursting, a splash and a sodium node together) the master mix peaks at 0.74, so nothing clips.
The bed also follows the ascent: it comes forward and runs a shade faster as the plate number rises, so plate eight does not sound like plate one.
Lifecycle
awake()— registers theScoreanchor and the caption screen, builds the four sources as children (reusing them if a hot reload left them standing), seeds the clip library, subscribes to the bus, applies the mix.start()/ firstupdate— starts the bed and both ambiences. The still is never silent, even on the title.update(dt)— the duck envelope, the bed's arc, the wetness alarm's quickening pulse, and the mix.onDestroy()— unsubscribes everything and stops every source.
Usage
local score = Still.anchor("Score").component.get("Score")
score:say("v_seal_1")
score.music = 0.2
print(score:report().levels.rms)