Characters
Usage guide of the character kits: choosing third-person, first-person, top-down or platformer, roster and forms, settings and defaults, character.control and camera services, events, hooks (character.jump, character.respawn, character.action), engines.
The player character (character.* kits) #
The body the player controls: walking, running, jumping, the camera that follows it, and the contract other kits use to borrow it (vehicles, climbing, attacks, dashes). Readable offline: gripforge docs character, or the MCP tool gripforge_docs (topic character).
What it is for #
A game installs ONE controlled-character kit for its view, and optionally the add-ons. Every controlled-character kit owns the entity tagged player and provides character.control, so interaction, vehicles, scenes, saves and combat work whichever one is installed.
| Kit | What it adds |
|---|---|
character.third_person | a kinematic capsule that walks, runs and jumps from input actions, a spring-arm chase camera, optional free look, shoulder aim for shooters, double jump |
character.first_person | the same capsule seen through its eyes: pointer and right stick turn the head, the body faces where the eyes look |
character.top_down | the view from above: isometric follow camera, world-relative movement, aim from the pointer, click to move, and a motor other kits use to lock, push or turn the body |
character.platformer | camera-relative platforming: accelerated movement, variable jump height, coyote time, jump buffering, checkpoint respawn |
character.roster | game-defined characters and roles, team selection and locking, ability slots and bounded resources (reuses combat.abilities) |
character.forms | transformations (small, large, robot...) with a capability profile, collision size, duration and a bounded stack of previous forms; a Rust core |
Install what the game needs; gripforge kit api <id> lists every setting of a kit.
Turn it on #
gripforge_gamekit_install { project_id: "gkp_…", id: "character.third_person" }
gripforge_gamekit_configure { project_id: "gkp_…", id: "character.third_person",
config: { "walkSpeed": 4, "runSpeed": 7, "airJumps": 1, "cameraDistance": 6 } }
The controlled-character kits require input.actions, world.ground (the platformer: world.platforms), the host physics (physics.character, physics.port) and game.engine. Controls come from the input kits (see the Controls guide): the actions are move_x / move_y, sprint, jump, and look_x / look_y when free look is on.
Settings and defaults #
character.third_person #
| Key | Default | Meaning |
|---|---|---|
walkSpeed / runSpeed | 4 / 7 | m/s |
jumpImpulse | 5 | take-off speed |
airJumps / airJumpImpulse | 0 / 5 | extra jumps before landing (1: double jump); also usable after walking off an edge |
cameraDistance / cameraHeight | 5 / 2 | metres |
turnSmoothing | 0.15 | 0 snaps, 1 turns very slowly |
freeLook | false | the pointer and the right stick turn the camera; it no longer recentres behind the heading |
shoulder | 0 | camera offset to the right of the character, metres (0 to 1.5) |
aimDistance | 0 | with freeLook: camera distance while aim is held (0: cameraDistance) |
combatDistance / combatSeconds | 0 / 4 | camera distance while the player fights (0: off), and how long after the last blow it holds |
lookSensitivity / stickLookSpeed / pitchLimit | 0.0024 / 2.4 / 85 | free look comfort (radians per pixel, radians per second, degrees) |
lockStrafe / lockCameraSpeed | true / 6 | movement and camera blend while a combat.ranged target is locked |
actionLayers | {} | animation layers by action family (attack, shoot, reload, block, hit...): mask, weight, fade and how much the movement slows |
A shooter turns the shoulder aim on together: { "freeLook": true, "shoulder": 0.6, "aimDistance": 3 }, with combat.ranged aimFromView: true.
<!-- test: kits/character_third_person/tests/character_third_person.rs::the_combat_camera_pulls_back_while_the_player_fights_then_returns --> A melee game pulls the camera back while the player fights, so wind-ups and threats on the sides stay in view: { "cameraDistance": 4.5, "combatDistance": 6.5, "combatSeconds": 4 }. The player fights while a blow it dealt, took or swung is less than combatSeconds old, or while a lock-on of combat.lockon holds; camera.distance follows, and aimDistance still wins while aim is held. Without combatDistance nothing changes.
character.first_person #
walkSpeed 4, runSpeed 7, jumpImpulse 5, eyeHeight 1.62 m, fov 72 degrees, lookSensitivity, stickLookSpeed, pitchLimit 85. The player's own model is not drawn through its eyes; it comes back in a vehicle.
character.top_down #
| Key | Default | Meaning |
|---|---|---|
moveSpeed / acceleration / turnSpeed | 7 / 60 / 18 | m/s, m/s squared, rad/s |
aim | auto | the pointer when the host publishes aim.point, else the nearest enemy in front, else the heading |
aimAssistRange / aimAssistCone | 7 / 100 | metres / degrees |
cameraYaw / cameraPitch / cameraDistance | 45 / 55 / 22 | degrees, degrees, metres |
cameraProjection | perspective | or orthographic (then cameraViewHeight is the visible world height) |
cameraFov, cameraTargetOffset, cameraSmoothing | 0, [0,0,0], 0.125 | lens, framed point, follow softness (seconds) |
clickArrive / clickReach | 0.3 / 1.6 | click to move: stop distance, and reach before attacking or using the clicked entity |
clickPath / clickBlocked / clickRepath | navigation / straight / 0.5 | route with ai.navigation when the game has it, what to do when the point is unreachable, replan delay |
character.platformer #
moveSpeed 6.8, acceleration 42, jumpImpulse 9.5, gravity 23, coyoteTime 0.12 s, jumpBuffer 0.14 s, airControl 0.68, jumpCut 0.48 (upward speed kept when the jump key is released early), fallGravity 1.25, cameraDistance 9, cameraHeight 5, capsule radius 0.35 and height 1.8. With world.platforms the kit also keeps the course records and settings of the campaign.
character.roster and character.forms #
character.roster: unique (a character is taken once per game), autoPlayer, maxMembers, title, and the collection roster_characters ({ id, name, slots: [{ id, ability, label, action }] }, up to 12 slots). character.forms: baseForm (default base), changeCooldown 0.5 s, maxDepth 4 (1 to 8) and 1 to 16 forms, each { id, duration, radius, height, speedScale, damageScale, capabilities[] } (duration 0 is permanent; the default set is a base form and a ten-second small form).
Services other kits use #
character.control:player(),position(),yaw(),lookYaw()/pitch()(where the camera looks: the aim of a shooter),speed(),detach/attach,teleport,hold(owner). In the Rust player alsoclaim(owner, priority),release(owner, velocity),beginMove(owner),setVelocity(owner, velocity),velocity()so grapples, grinds and boosts can borrow the capsule by priority.camera.third_person,camera.first_person,camera.top_down(the pose the renderer reads) andcamera.look(free look:add(dx, dy),yaw(),pitch()).character.motor(top down): lock, push or turn the body for attacks, dashes and staggers.character.platformer:grounded(),velocity(),launch(vy)(a spring),push(dx, dz)(a conveyor).
Events: player.moved (10 Hz while moving: { id, x, y, z, yaw, speed }), player.jumped (aerial is true for an extra jump), player.action (an action started and how it slows the movement), player.pushed. Variables: player.speed, camera.yaw, camera.pitch, camera.shoulder. The character listens to vehicle.entered / vehicle.exited: the capsule is detached while driving and returns beside the door.
Hooks and modding #
The names and payloads are the same in every character kit, so one tap works whichever character a game plays.
| Hook | Payload | What a tap may do |
|---|---|---|
character.jump | { entity, speed, aerial } | change speed (0 to 30), cancel the jump |
character.respawn | { entity, x, y, z, reason } | change the position, cancel; asked at a scene entry (scene) or on the scene's player instance (instance), not on a load or while driving |
character.action | { entity, anim, movement, moveScale } | change how an action slows the movement (free, slow, lock, root) |
character.push | top down | accept or change a push |
roster.select, roster.lock, roster.close, roster.use, roster.grant | roster | pick another character, refuse a lock, cancel the end of selection, swap the ability of a slot, change a granted amount |
{ "id": "no_jump_indoors", "hook": "character.jump", "if": [{ "in_zone": "z_house" }], "cancel": true, "reason": "low_ceiling" }
Moddable keys: the speeds, jump values, camera keys and actionLayers. The comfort of the person playing (lookSensitivity, stickLookSpeed) is not moddable. In game.engine content a scene entry places the player (position and heading), and an instance of kind player is the player.
Engines #
The movement rules are the same Rust implementation on the web and in the native player. character.third_person, character.top_down and character.platformer are also delivered to Godot and Unity as files (a character body with a seed scene and a generated options file) and to Unreal through the shared kit library; character.first_person, character.roster and character.forms run on the web and in the native player. On the engines that do not run the hooks yet, the behaviour is the one without any tap.
When it does not do what you expect #
| Symptom | Cause and fix |
|---|---|
| The player does not move | no input.actions, or the action is not mapped to the device: check the Controls guide |
| No double jump | airJumps is 0 (the default); set it to 1 |
| The camera keeps recentring behind the character | freeLook is off; turn it on for pointer-driven views |
| A second shooter-style setting does nothing | aimDistance only works with freeLook; shoulder works without |
| A form change is refused | the cooldown is running, the stack is full (maxDepth) or the engine reported the destination blocked |