Log inGet started
World

Builtin Library

Branchmain
Branchesmainpublish
Commit8d45df8664

README.md

shake_engine

Procedural camera shake engine used by the built-in first-person controller. Layered sine waves synchronized to step cycle for head bob, decaying sinusoid for landing impact, and multi-sine pseudo-noise for trauma shake. All shake is additive — it never fights player input.

Pure math — no engine calls, no module state. Consumers (the fps_controller module) accumulate step time and trauma, then pass them in alongside the active shake profile each frame.

Exports

  • M.headBob(t, profile, speed, isRunning) -> (x, y, roll) — locomotion bob.
  • M.breathing(t, profile) -> (x, y, pitch, roll) — subtle idle micro-movement.
  • M.landingImpact(elapsed, fallSpeed, profile) -> number — decaying-sinusoid vertical offset.
  • M.traumaShake(t, trauma, profile) -> (x, y, roll) — multi-sine pseudo-noise scaled by trauma^power.

Types:

  • ShakeProfile = { walkFrequency?, walkVerticalAmplitude?, ..., traumaDecayRate? } — see the module body for the full field list.

Usage

local ShakeEngine = require("@builtin::modules.fps_controller.shake_engine")

local x, y, roll      = ShakeEngine.headBob(stepTime, profile, 1.0, false)
local bx, by, bp, br  = ShakeEngine.breathing(now, profile)
local landY           = ShakeEngine.landingImpact(elapsed, fallSpeed, profile)
local tx, ty, tr      = ShakeEngine.traumaShake(now, trauma, profile)

Notes

  • Output amplitudes are in metres, rotation outputs in radians. The consumer is expected to add them to the base camera pose.
  • headBob returns zeros when speed < 0.01. traumaShake returns zeros when trauma < 0.001. landingImpact returns 0 when the computed offset's magnitude drops below 0.0005m so the consumer can stop sampling after a few hundred ms.
  • Frequencies, amplitudes, and decay rates all come from the profile — fall back to the realistic defaults when a field is missing. See modules/presets for the built-in profiles.
  • No state, no time-source dependency — pass in whatever clock you're driving the controller with so the shake stays frame-coherent with the rest of the controller.