Part of the
character-movement skill. The skill links here when your agent needs the detail.First-person node layout (non-negotiable)
Crouch
Keep two collision shapes (standing + crouching), toggledisabled, and a
RayCast3D pointing up (CeilingCheck) so you cannot stand up under a ceiling.
Lerp the Head y from 1.5 to ~0.9 for a smooth crouch, not a snap.
Headbob (optional polish)
Drive the Camera’s local y withsin(time * bob_freq) * bob_amp scaled by
horizontal speed, only while is_on_floor(). Keep amp under 0.08 or it nauseates.
Third-person node layout
SpringArm3D is the whole trick: it raycasts from the pivot to the camera
and shortens when a wall is in the way, so the camera never clips into geometry.
Set its collision_mask to your Level layer only (not the player).
Third-person differences from FPS:
- Mouse motion rotates the
CameraController(orbit), not the body. - The visual wrapper rotates to face the MOVEMENT direction, decoupled from the camera.
Because imported characters face the engine forward
-Z, lerpCharacterRotationRoot.rotation.ytowardatan2(-direction.x, -direction.z). - Rotate only
CharacterRotationRoot.rotation.y. Do not yaw the CharacterBody3D or add a compensating 180-degree model rotation. The package already normalizes forward to-Z. - Keep the third-person camera behind the character on the camera rig’s local
+Zside. - Camera direction drives movement basis: build
directionfrom the spring-arm’s global basis, flattened to the XZ plane, so “forward” means “where the camera looks”.
Canonical humanoid animation states
Keep translation in the controller and use package animations only as in-place visuals. For a standard playable third-person character, read and copydefault-third-person-controller.gd. It already loads exact semantic roles
from character.json, selects state after move_and_slide(), gives airborne
Jump highest priority, changes clips only when state changes, uses camera-relative
movement, and turns only the normalized -Z visual root. Do not reassemble the
controller from partial examples.
Do not advance the CharacterBody3D from animation root translation. Rotate only the
visual child when movement is non-zero, and keep the last facing direction while idle.
Legacy clip-name compatibility only
Use substring discovery only for old, non-package GLBs that have no manifest. Resolve Jump before Run and claim each real clip at most once. Never use this for a canonical package:Shared traps
- Capture/release the mouse as a pair or you trap the player (see SKILL.md).
- Sprint reads an unbound
sprintaction = silent no-op; bind it first. - Spring arm with the wrong mask collides with the player and jams at length 0.
Source:
library/skills/character-movement/references/movement-3d.md, rendered from summer-engine@4.3.0 on npm.
