Recipes
Moving platforms, elevators, rotating hazards, and objects on a patrol path
A platform slides side to side, a lift rises and falls, or a blade spins. There is no
MotionComponent (stripped); self-driven motion is a tick handler that patches the TransformComponent every frame.engine v1.0.234since script-semantic-patch-ops.v1, action-catalog.v1.0.232, mutation.v1, hierarchy.v1, timer.v1Copy for LLM
Use this for
a platform that slides back and forth or up and down; elevators and lifts; rotating blades, gears, or swinging obstacles; any object that moves on its own path without player input
Not for
objects that move only when interacted with (see doors-buttons-and-interactions); projectiles that fly and hit (see projectiles-and-ranged-weapons); the player's own movement (see third-person-and-platformer-movement)
Pairs with: Doors buttons levers and press-to-interact, Physics colliders rigid bodies triggers and joints, Hazards lava damage zones and water, Timers countdowns cooldowns and enemy waves
The recipe
Author with project_apply_script_semantic_patch using the ai_safe op pack. The mover is an entity with a TransformComponent and usually a solid ColliderComponent so the player can stand on or be blocked by it.
- Add a tick handler:
addTickHandler{ "handlerKey":"onMove" }. - In the body (whole-body GessaScript via
replaceScriptFromGessaScript), read the current transform withctx.entity.readComponent(TransformComponent), compute the next position, and write it withctx.entity.patchComponent. Scale every delta byctx.delta(seconds since last tick) so speed does not depend on frame rate. - Oscillate back and forth: keep a phase in durable state, advance it each tick with
incrementNumericState{ "field":"phase", "by": <speed * delta> }, and map it to an offset (a triangle or sine of the phase). Or ping-pong: track agoingUpflag withsetBooleanState, move toward the current endpoint, and flip the flag when you pass it. - Rotate a blade or gear: patch
rotationinstead ofposition, adding a per-tick angle. Parent the visible mesh under a pivot entity withctx.entity.setParentwhen the spin axis is not the mesh center. - Timed lift (moves only on an interval): drive it from a
TimerComponentplusaddTimerHandlerinstead of every tick, patching to the next stop each fire.
Pitfalls
- Multiply every movement by
ctx.delta. A fixed per-tick step drifts when the tick rate changes and desyncs between clients. - Patch
position/rotationthroughctx.entity.patchComponent; do NOT writeVelocityComponent(it is engine-internal and hidden from AI/SDK authoring). - Transform patches are server-authoritative (
hierarchy.server_authority), so the platform moves identically for all players; ride-along works because the player stands on a solid collider. - Store oscillation phase or the ping-pong flag in durable state, not a local variable, so the platform keeps its cycle across a reload.
- Carry the rider by making the platform solid and letting the physics step resolve standing contact; do not teleport the player each tick.
Verify
simulation_run(qa.run.start) to watch the platform complete a full cycle and confirm a standing entity is carried and a solid mover blocks passage.project_get_graph_snapshotto confirm the tick or timer handler landed.