Rhythm
Patapon's beat clock, drum input, command parser, combo/FEVER and the whole game's audio. Attach it to the scene's `Game` entity, beside `Battle` and `Hud`. It talks to them only through `game.Rules`: it writes the rhythm fields of `R.state` and emits `beat`, `drum`, `command`, `…
Rhythm
Patapon's beat clock, drum input, command parser, combo/FEVER and the whole game's audio. Attach it to the scene's Game entity, beside Battle and Hud. It talks to them only through game.Rules: it writes the rhythm fields of R.state and emits beat, drum, command, perform, comboBreak and fever on the bus. It listens for start, phase, hit, unitDied and fortressDown to reset the clock and play their sound effects.
The beat runs at 120 BPM while the phase is playing, with a soft metronome on the title screen. Drum keys (F/Left PATA, J/Right PON, I/Up CHAKA, K/Down DON) are judged against the nearest beat as perfect, good or miss. Four accepted drums that match a command fire command, and perform follows on the next measure's first beat. Each command adds one to the combo. FEVER turns on at R.FEVER_COMBO or after 3 perfect commands in a row.
Every sound is synthesised in Luau by game/rhythm/tools/bake_sounds.luau into game/rhythm/sounds/*.soundClip. Sounds play through non-spatial Audio components on three temporary child hosts: RhythmMusic, RhythmDrums and RhythmSfx.
Interface
What this asset declares: the schema it conforms to, what it exposes, and the rendered structured payload.
conforms to
zero/source-extract/v2Rhythm Component — Patapon's beat clock, drum input, command parser, combo / FEVER, and the whole game's audio. Lives on the scene's "Game" entity beside Battle and Hud. Talks to them only through game/Rules.module (R.state rhythm fields + the bus): emits beat { beat, measure, inMeasure } every 0.5 s (120 BPM) drum { drum, quality, offset } each drum struck (perfect|good|miss) command { name, measure, perfect } a 4-drum command was entered perform { name, measure } first beat of the measure the army performs it comboBreak { reason } offbeat | wrong | silence fever { on } hears start, phase (clock reset / stings), hit, unitDied, fortressDown (sfx) Timing model (spec rules 2-4). Beat k sounds at beatTime = k * BEAT. A drum is judged against the NEAREST beat: |offset| <= PERFECT perfect, <= GOOD good, wider is a miss that breaks the combo. Out of a combo chain the four drums may start on any beat but must fall on consecutive beats. When the 4th drum lands on beat B the command fires, the measure grid re-aligns so beat B+1 is beat 1 of a measure, and the army performs during beats B+1..B+4 (drums there break the combo). Within a chain the next command must be drummed on beats B+5..B+8, starting on B+5; a window that passes without one is a "silence" break (or "wrong" when it was left half-drummed). Sound: every clip under game/rhythm/sounds/ is synthesised in Luau by game/rhythm/tools/bake_sounds.luau and played through non-spatial Audio components on three child hosts ("RhythmMusic", "RhythmDrums", "RhythmSfx"). The groove is a one-measure clip retriggered on every downbeat, so it stays locked to the beat clock instead of drifting against it.
loadClips( ) → void
spawnHost(name: string, channel: string, clip: any) → void
| arg | type | description |
|---|---|---|
| name | string | |
| channel | string | |
| clip | any |
ensureHosts( ) → void
play(channel: string, clipKey: string, volume: number, pitch: number?) → void
| arg | type | description |
|---|---|---|
| channel | string | |
| clipKey | string | |
| volume | number | |
| pitch | number? |
syncState( ) → void
resetClock( ) → void
clearDrums( ) → void
breakCombo(reason: string) → void
| arg | type | description |
|---|---|---|
| reason | string |
after(sec: number, fn: () → void
| arg | type | description |
|---|---|---|
| sec | number | |
| fn | ( |
fireBeat(k: number, quiet: boolean) → void
| arg | type | description |
|---|---|---|
| k | number | |
| quiet | boolean |
strike(drum: string) → void
| arg | type | description |
|---|---|---|
| drum | string |
readKeys( ) → void
onStart(_p: any) → void
| arg | type | description |
|---|---|---|
| _p | any |
onPhase(p: any) → void
| arg | type | description |
|---|---|---|
| p | any |
onHit(p: any) → void
| arg | type | description |
|---|---|---|
| p | any |
onUnitDied(p: any) → void
| arg | type | description |
|---|---|---|
| p | any |
onFortressDown(_p: any) → void
| arg | type | description |
|---|---|---|
| _p | any |
subscribe( ) → void
start( ) → void
update(dt: ?) → void
| arg | type | description |
|---|---|---|
| dt | ? |
onDestroy( ) → void
debugState( ) →
Snapshot of the rhythm engine's internal state, for tests and debugging.
examples
entity.find("Game").component.get("Rhythm"):debugState()Sub-parts
Everything contained inside this part. Assets are composite children (clickable cards). Files are leaf payloads. Expand any row to view its source.
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.