Skip to content

feat: add Natural Head Movement effect - #5

Merged
aefly merged 3 commits into
mainfrom
feat/natural-head-movement
Oct 6, 2026
Merged

aefly merged 3 commits into
mainfrom
feat/natural-head-movement

Conversation

@aefly

@aefly aefly commented Oct 6, 2026

Copy link
Copy Markdown
Owner

Summary

Adds Natural Head Movement, a new Cabin effect that gives the head a TrackIR-like movement without a tracker: the head never holds perfectly still, mimicking the subtle movements of a player wearing a head tracker. Off by default.

All layers are summed:

  • Tremor: a faint, continuous noise on every axis.
  • Micro-adjustments: the head holds still, then every few seconds makes a small move to a new spot and holds it.
  • Resting postures: every ~15 s, the head settles into a new posture drawn from body shapes (leaning on the door, leaning forward toward the road, slouching, tilting the head, etc.), so the axes move together as they would for a real body.
  • Idle (stopped for 5 s): relaxed postures, wider and slower (slouching, leaning on the door, stretching the neck, looking out of the window, or looking down).
  • Driving: focused postures, smaller in amplitude (sitting up, leaning toward the road).
  • Mode switching: switching modes immediately draws a posture from the new mode (for example, sitting up when pulling away).
  • Steering tilt: the head tilts into the turn as the steering wheel turns.
  • Neck pivot: every rotation pivots around a neck point below and behind the eyes, so turning or tilting the head also moves the eyes, as with a 6DOF tracker.
  • Movement profile: every move follows a minimum-jerk profile (math::SmootherStep): it starts gently, stops gently, and has no tail. The farther it moves, the longer it takes.
  • Right-hand drive: right-hand-drive trucks are handled; their camera mirrors X and roll, not yaw, as observed in-game.

Settings are available under Quick Settings > Cabin. Everything else is a constant tuned in-game.

Setting Default Range
tremor_intensity 5.0 0–8
micro_intensity 2.5 0–5
posture_intensity 1.3 0–2
posture_interval 15 s 5–60 s
steering_tilt 1.5 0–3

Effects Pausing Other Effects

Natural Head Movement moves the head on its own, so the background motion of a still head would otherwise be layered on top of it. While it plays, it pauses Idle Breathing and Speed Shake; their settings remain untouched.

  • Added a new conflicts::kPauses table (src/core/Conflicts.hpp) that declares which effect pauses which. Effects are declared once by settings prefix and checked at compile time against settings::kAll.
  • EffectManager fades a paused effect out over 0.5 s, with a separate fade per effect, and calls Reset() once it has faded out.
  • A pausing effect only pauses other effects while it is actually playing. For example, an effect that requires the driver's seat lets the others resume while Cabin Walk is away.
  • Each effect's toggle fade now continues progressing while the seat or a pause holds it back, so it never resumes from a stale value.
  • This also fixes an existing case where an effect turned off while Cabin Walk temporarily moved the player away from the seat could briefly play again when returning to the seat.
  • Quick Settings reads the same table:
    • A pausing effect lists what it pauses: "When enabled, this pauses the following effect(s):"
    • A paused effect displays "Paused by ..." and disables its sliders.
  • Adding a new conflict later requires only one line in kPauses.

Other Commits

  • build: disable C++ module scanning
    With Ninja and C++23, CMake added GCC's -fmodules-ts / -fdeps-format flags to compile_commands.json, which clangd rejects. The project does not use C++20 modules.

  • refactor: share SmootherStep, Lerp and IsRightHandDrive
    Moved these helpers from Cabin Walk to src/math/Units.hpp and src/effects/Telemetry.hpp so both effects can use them. No behavior change.

Related Issue

N/A

Type of Change

  • New effect
  • Bug fix (stale toggle fade while an effect is held back)
  • Refactor / Cleanup
  • Build / CI
  • Localization
  • Docs
  • Other

Affected Effects

  • Natural Head Movement (new)
  • Idle Breathing, Speed Shake (paused while Natural Head Movement plays)
  • Cabin Walk (helpers moved; no behavior change)
  • All effects (EffectManager toggle fade fix)

Checklist

  • Effect is toggleable via its own enabled setting.
  • Effect is active in cabin view only.
  • Effect doesn't conflict with existing effects (Idle Breathing and Speed Shake are paused through conflicts::kPauses).
  • Effect overrides NeedsDriverSeat(), if it only makes sense in the driver's seat.
  • Setting declared in settings::kAll (src/core/Settings.hpp).
  • New effect listed in kEffects (src/ui/EffectTabs.cpp).
  • Keybind declared in src/core/Keybinds.hpp (kAllActions), if any: no keybind.
  • Effects that shouldn't run together are declared in conflicts::kPauses (src/core/Conflicts.hpp), if any.
  • Text added to every localization/*.json file.
  • README.md's settings table updated, if a setting changed.
  • Checked the ./SPF_API docs before implementing or modifying an SDK interaction.

Test Plan

  • Built successfully via cmake --workflow --preset user-mingw-release.
  • Tested in-game:
    • Tremor, micro-adjustments, postures, idle mode, and driving mode.
    • Steering tilt goes into the turn for both left-hand-drive and right-hand-drive vehicles.
    • Idle Breathing and Speed Shake fade out when enabling Natural Head Movement.
    • Idle Breathing comes back while standing with Cabin Walk.
  • Quick Settings window checked in-game, if a setting changed.
  • python3 .github/scripts/check-localization.py passes, if a localization/*.json file changed.
  • Changed text checked in-game in every language

Commit Style

Markdown

  • Markdown rules follow .markdownlint-cli2.jsonc.

@aefly aefly self-assigned this Oct 6, 2026
@aefly aefly added enhancement New feature or request new effect Implement a new effect labels Oct 6, 2026
@aefly
aefly merged commit 63c7179 into main Oct 6, 2026
3 checks passed
@aefly
aefly deleted the feat/natural-head-movement branch October 6, 2026 05:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request new effect Implement a new effect

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant