heartbeat¶
type: "heartbeat"
Plays a periodic heartbeat for the effect's lifetime. The sound is a
recording of one lub-dub that ships inside the mod (no resource pack, no
synthesised tone), played back at a speed the tempo drives. One voice per
effect instance: it opens when the instance starts, follows the animated
rate, volume and pitch every frame, and closes when the instance ends
(or is stopped, faded out, or rebuilt by a replay seek).
The duration decides when the sound stops, not a cut. When the instance ends, the thump stops repeating right there - and the beat that is sounding at that moment plays to its end instead of being cut in the middle. The same goes for a fade-out: the voice fades with the effect weight, and the last beat is not chopped.
Each beat restarts the recording, and the recording is time-scaled to the tempo: at 60 bpm it plays as recorded (0.85 s in a 1 s beat), at 140 bpm it is compressed to about 0.36 s in a 0.43 s beat, with the pause inside the lub-dub closing up in the same proportion. The scaling keeps the tone where it was - a fast heart is a fast recording on the same pitch, not a higher one. The pause between beats is whatever the recording leaves free; it is not re-timed separately.
Fields¶
Audio effects also accept the shared definition fields (
duration,easing,loop,persistent,fade_ticks,sound). They do not acceptscreen_layerororder, and they render no geometry.
| Field | Type | Default | Meaning |
|---|---|---|---|
rate |
float | 60.0 |
Beat rate in beats per minute. No upper cap; 0 or an unresolvable value is silence |
volume |
float | 0.0 |
Linear gain, 0..1. Fades with the effect weight, so fade_ticks fades the thump in and out |
pitch |
float | 1.0 |
Tone multiplier, 1 = the recorded pitch. 2 makes it an octave up (and twice as long) |
All are ordinary animatable params: start/end, keyframes, expr, graphs, setParam
and bind all work. volume's neutral is 0.0 (that is what the fade blends toward);
rate blends toward 60 and pitch toward 1. The beat phase integrates
per sample, so an animated rate glides instead of jumping.
The voice gain each frame is volume × weight × distance, where weight is the
effect's fade weight and distance is a linear falloff from the camera: full volume
within 8 blocks, silent past 48 blocks.
Positioning¶
Like a world overlay, the voice is heard from a world point (mono — there is no stereo panning, only distance). First source wins:
- a runtime move (
sendMove/ network MOVE), - the first static
positionsentry (block-centred), - the first entity anchor's live position (an untracked entity is silent that frame),
- the authored
pos_x/pos_y/pos_ztriple, - otherwise the local-player position (interpolated snapshot), so a plain
/vfx play vfxweaver:heartbeatfollows the viewer.
positions and region work as on Datapack format.
Example¶
{
"type": "heartbeat",
"duration": 100,
"fade_ticks": 20,
"params": {
"rate": 60.0,
"volume": 0.5,
"pitch": 1.0
}
}
Five seconds of a resting thump that fades in and out over one second each. Race it for a chase cue:
{
"type": "heartbeat",
"loop": true,
"persistent": true,
"fade_ticks": 20,
"params": {
"rate": { "keyframes": [{ "time": 0, "value": 60.0 }, { "time": 200, "value": 140.0 }] },
"volume": 0.4,
"pitch": 1.0
}
}
Honest limits¶
-
The frame rate does not reach the sound. The voices are synthesised on a dedicated audio thread, in fixed 5 ms blocks from that thread's own wall clock, and every line stays about 60 ms ahead of its playhead. A slow frame, a lost frame or an unfocused window therefore cannot starve the line or stretch a ramp - the sound is the same at 30 fps and at 200 fps. A paused game (or a paused replay) is the one thing that stops it: the shared effect clock freezes, the thread notices within a quarter of a second and renders silence until it moves again. A replay seek resyncs silently instead of bursting.
-
The vanilla mixer is bypassed. The recording is played into the OS mixer directly, so the game's volume sliders, mute and resource-pack sounds do not affect it — control loudness with the
volumeparam. A machine with no audio device (or a headless JVM) stays silent and logs once instead of failing. stopAllcuts immediately. Stopping one instance fades it out overfade_ticksand the last beat plays out; stopping everything (world exit,/vfx stopall, client shutdown) closes the voices at once, like the aux windows.