skills/player-physics/SKILL.md
Apply physics forces to the player in Decentraland scenes. Impulses (one-shot pushes), knockback (push away from a point with falloff), continuous forces (wind tunnels, anti-gravity, lift, levitation, hover), timed forces, and repulsion fields. Use when the user wants launch pads, knockback on hit, wind zones, gravity fields, jumps, lifting/floating the player, pushing the player up/sideways/back, hover effects, or any scene-applied force on the player. THIS is also the right skill when an agent's first instinct is to mutate `Transform` on `engine.PlayerEntity` to move/lift/push the player — that does NOT work (the player Transform is engine-controlled and read-only); use the Physics API instead. Do NOT use for player movement speed (see player-avatar AvatarLocomotionSettings) or platform movement (see animations-tweens).
npx skillsauth add dcl-regenesislabs/opendcl player-physicsInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Apply forces to the player's avatar using the Physics API from @dcl/sdk/ecs. All physics operations affect the local player only.
Force calls are runtime — they live in src/index.ts. The trigger entities that cause forces (the launch pad, the wind tunnel volume, the repulsion field marker) are static placements and belong in main-entities.ts with a Transform (and optional MeshRenderer / GltfContainer). Wire pointer/proximity events or trigger systems in src/index.ts to call the Physics.* methods.
The player's Transform (on engine.PlayerEntity) is engine-controlled and read-only from scene code. Writing to it via Transform.getMutable, Transform.createOrReplace, or direct .position / .rotation mutation silently does nothing — the code compiles, the system ticks, no error is thrown, and the avatar never moves.
If your goal is to lift, float, push, knock back, or apply any sustained force to the player, use this skill's Physics API. For instant teleports / smooth slides to a specific position, use movePlayerTo from ~system/RestrictedActions (skill: player-avatar).
// WRONG — has no effect in-world
const t = Transform.getMutable(engine.PlayerEntity)
t.position.y += 0.1 // ignored every frame
// CORRECT — lift the player upward
import { Physics } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'
Physics.applyImpulseToPlayer(Vector3.create(0, 50, 0)) // one-shot upward launch
// or, sustained lift / hover:
const lifter = engine.getEntityOrNullByName('hover_zone') // named entity from main-entities.ts
if (lifter) Physics.applyForceToPlayer(lifter, Vector3.create(0, 1, 0), 12)
// stop with: Physics.removeForceFromPlayer(lifter)
Apply a single instantaneous force with Physics.applyImpulseToPlayer(direction, magnitude?). Direction is auto-normalized when magnitude is passed separately. Multiple calls within the same frame are accumulated. Use for launch pads, jumps, and explosions.
Push the player away from a source position with Physics.applyKnockbackToPlayer(sourcePos, magnitude, radius?, falloff?). Direction is computed automatically from source to player.
| Falloff | Behavior |
|---|---|
| KnockbackFalloff.CONSTANT | Same magnitude at any distance within radius (default) |
| KnockbackFalloff.LINEAR | Smooth linear decrease to 0 at the radius edge |
| KnockbackFalloff.INVERSE_SQUARE | Sharp, physically-realistic drop-off |
If the player is exactly at the source, they are pushed straight up. A negative magnitude pulls the player toward the point (gravity well). The same falloff values apply to applyRepulsionForceToPlayer().
Apply a persistent directional force identified by an entity (the force "owner"). Multiple forces from different entities stack.
Physics.applyForceToPlayer(entity, direction, magnitude?)Physics.removeForceFromPlayer(entity)Use with trigger zones for wind tunnels, conveyor belts, and gravity fields. The owner entity is just an ID handle for later removal — typically the named main-entities.ts entity representing the trigger zone.
Apply a force for a fixed duration: Physics.applyForceToPlayerForDuration(entity, seconds, direction, magnitude?). Expires automatically.
Continuous push away from a fixed point with distance-based falloff, recalculated each frame: Physics.applyRepulsionForceToPlayer(entity, position, magnitude, radius). The position must be passed explicitly — not read from the entity's Transform automatically. Remove with Physics.removeForceFromPlayer(entity).
Convert local direction to world space with Transform.localToWorldDirection(entity, localDir). Use when pushing relative to an entity's orientation (e.g. "forward from this cannon").
| Method | Type | Description |
|---|---|---|
| Physics.applyImpulseToPlayer(dir, mag?) | One-shot | Instant directional push |
| Physics.applyKnockbackToPlayer(pos, mag, radius?, falloff?) | One-shot | Push away from point |
| Physics.applyForceToPlayer(entity, dir, mag?) | Continuous | Persistent push while active |
| Physics.removeForceFromPlayer(entity) | Control | Stop a continuous force |
| Physics.applyForceToPlayerForDuration(entity, secs, dir, mag?) | Timed | Force that expires automatically |
| Physics.applyRepulsionForceToPlayer(entity, pos, mag, radius) | Continuous | Distance-based push from point |
| Transform.localToWorldDirection(entity, dir) | Utility | Convert local direction to world space |
applyImpulseToPlayer for one-off events (jump pads, explosions, hits).applyForceToPlayer + removeForceFromPlayer with trigger zones for areas (wind tunnels, conveyor belts).KnockbackFalloff.LINEAR for most area effects — it feels natural and predictable.result.trigger?.entity !== engine.PlayerEntity in trigger callbacks to only affect the local player.development
Capture screenshots of the running Decentraland preview to verify scene changes visually. Covers camera movement, interaction actions, and visual debugging. Use when the preview is running and you need to check what the scene looks like, debug visual issues, or verify layout. Do NOT use for code changes (make changes first, then screenshot).
development
Cross-cutting runtime APIs for Decentraland SDK7 scenes. Use when the user needs async operations (executeTask), HTTP requests (fetch, signedFetch), WebSocket connections, timers, realm/scene detection, restricted actions (movePlayerTo, teleportTo, triggerEmote, openExternalUrl), portable experiences, or the testing framework. Do NOT use for UI (see build-ui), multiplayer sync (see multiplayer-sync), or avatar/player data (see player-avatar).
data-ai
Player and avatar system in Decentraland. Read player position/profile, customize appearance (AvatarBase), trigger emotes (triggerEmote/triggerSceneEmote), read equipped wearables (AvatarEquippedData), attach objects to players (AvatarAttach), create NPC avatars (AvatarShape), avatar modifier areas, and locomotion settings. Use when the user wants player data, emotes, wearables, NPC avatars, avatar attachments, or movement speed changes. Do NOT use for wallet/blockchain interactions (see nft-blockchain).
development
Emit particles (fire, smoke, sparks, snow, magic, fireworks) from an entity in a Decentraland SDK7 scene with the ParticleSystem component. Covers emitter shapes (Point, Sphere, Cone, Box), continuous rate vs Burst emission, lifetime/size/color/velocity ranges, gravity and additionalForce, blend modes (ALPHA/ADD/MULTIPLY), billboard and faceTravelDirection, sprite-sheet texture animation, simulation space (local vs world), playback state, and per-scene particle budget. Use when the user asks for particles, sparks, fire, smoke, dust, fog, fireworks, magic effects, snowfall, rain, embers, trails, or atmospheric effects. Do NOT use for procedural entity motion (see animations-tweens), GLTF model effects (see add-3d-models), or 2D UI effects (see build-ui).