Quieres que una puerta se abra despacio, que una plataforma suba y baje, o que una moneda gire. Lo intentas con un bucle y wait(), y te queda un movimiento a tirones que además va distinto en cada ordenador.
La solución está integrada en Roblox y se llama TweenService. Le dices dónde está el objeto, dónde quieres que acabe y cuánto debe tardar, y él calcula todos los pasos intermedios. En la demo de más abajo puedes trastear con las curvas y ver el código que sale.
Respuesta rápida
local TweenService = game:GetService("TweenService")
local info = TweenInfo.new(2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
local tween = TweenService:Create(parte, info, {Position = Vector3.new(0, 20, 0)})
tween:Play()
Tres líneas: la configuración del movimiento, el tween con el destino, y darle al play.
Lo que necesitas antes de empezar
- Un Part en el Workspace, Anchored marcado.
- Un
ScriptenServerScriptService. - Unos 20 minutos.
Por qué no vale hacerlo con un bucle
Esto es lo que hace todo el mundo la primera vez:
-- MAL: a tirones y con velocidad distinta en cada máquina
for i = 1, 100 do
parte.Position = parte.Position + Vector3.new(0, 0.2, 0)
task.wait(0.03)
end
Dos problemas. El primero es que task.wait(0.03) no espera 0,03 segundos exactos: espera al menos eso, y luego hasta el siguiente fotograma. En un ordenador lento el movimiento tarda el doble.
El segundo es que va a velocidad constante, y eso se ve artificial. En la vida real las cosas arrancan despacio y frenan al llegar. Eso es lo que hacen las curvas de aceleración.

Paso 1: TweenInfo, la configuración
TweenInfo.new() acepta seis parámetros y todos menos el primero son opcionales:
local info = TweenInfo.new(
2, -- duración en segundos
Enum.EasingStyle.Quad, -- la curva
Enum.EasingDirection.Out, -- dónde se aplica la curva
0, -- repeticiones (-1 = infinito)
false, -- ¿vuelve al punto de partida?
0 -- retraso antes de empezar
)
Los dos que de verdad cambian cómo se siente el movimiento son la curva y la dirección:
| Curva | Cómo se siente |
|---|---|
Linear | Velocidad constante. Robótico, útil para cosas mecánicas |
Sine | Suave y discreto. El más seguro si dudas |
Quad, Cubic, Quart | Cada vez más pronunciado |
Back | Se pasa un poco y vuelve. Bueno para interfaces |
Bounce | Rebota al llegar, como una pelota |
Elastic | Oscila como un muelle |
| Dirección | Qué hace |
|---|---|
In | Arranca lento y acelera |
Out | Arranca rápido y frena al final. El más natural para casi todo |
InOut | Lento al principio y al final |
Trastea con la demo hasta que entiendas la diferencia: se explica sola mucho mejor que cualquier tabla.

Paso 2: crear y reproducir
-- Script en ServerScriptService
local TweenService = game:GetService("TweenService")
local parte = workspace:WaitForChild("Plataforma")
local info = TweenInfo.new(2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out)
-- El tercer parámetro es una tabla de propiedades DESTINO
local tween = TweenService:Create(parte, info, {
Position = parte.Position + Vector3.new(0, 15, 0)
})
tween:Play()
La tabla del final es la clave: pones el valor final, no el desplazamiento. TweenService se encarga de todo lo que hay en medio.
Paso 3: varias propiedades a la vez
Puedes animar todo lo que sea un número, un Vector3, un Color3 o un UDim2, y varias cosas a la vez:
local tween = TweenService:Create(parte, info, {
Position = Vector3.new(0, 20, 0),
Transparency = 0.5,
Color = Color3.fromRGB(255, 100, 100),
Size = Vector3.new(10, 1, 10)
})
tween:Play()
Todas empiezan y acaban a la vez, con la misma curva.
No se puede animar CFrame y Position en el mismo tween. Si necesitas mover y girar a la vez, usa solo CFrame:
local destino = CFrame.new(0, 20, 0) * CFrame.Angles(0, math.rad(90), 0)
local tween = TweenService:Create(parte, info, {CFrame = destino})
Paso 4: ida y vuelta, y en bucle
Con los parámetros 4 y 5 tienes movimientos que se repiten sin escribir un bucle:
-- Plataforma que sube y baja para siempre
local info = TweenInfo.new(
3, -- 3 segundos cada trayecto
Enum.EasingStyle.Sine,
Enum.EasingDirection.InOut,
-1, -- infinito
true, -- vuelve al origen
0
)
local tween = TweenService:Create(parte, info, {
Position = parte.Position + Vector3.new(0, 10, 0)
})
tween:Play()
Con true en «vuelve al origen», un ciclo son 6 segundos: 3 de subida y 3 de bajada.
Paso 5: esperar a que acabe
tween:Play() no bloquea: el código sigue a la línea siguiente mientras el objeto se mueve. Si necesitas encadenar cosas:
tween:Play()
tween.Completed:Wait() -- ahora sí espera
print("ya ha llegado")
O sin bloquear:
tween.Completed:Connect(function()
print("ya ha llegado")
end)
Pruébalo aquí
El mismo tween, distinta curva
Cambia los ajustes, dale a reproducir y mira el TweenInfo que sale.
Errores habituales
El objeto no se mueve
Casi siempre es que no está Anchored. Un Part sin anclar lo controla la física, y la física gana: el tween tira de él y la gravedad lo devuelve. Marca Anchored.
Unable to cast value to Vector3
Le estás pasando un número donde va un Vector3. {Position = 10} está mal; es {Position = Vector3.new(0, 10, 0)}.
El tween va bien la primera vez y luego se rompe
Estás creando el tween una vez y llamando a :Play() muchas. Un tween guarda el punto de partida de cuando lo creaste. Si el objeto se ha movido, hay que crear uno nuevo cada vez.
Tween:Play() is not a valid member
Te has saltado el TweenService:Create(...) y estás llamando a :Play() sobre el TweenInfo. El TweenInfo es solo la configuración; el tween es lo que devuelve Create.
Se mueve en el cliente pero los demás no lo ven
El tween lo lanzaste desde un LocalScript. Si el movimiento tiene que verlo todo el mundo, va en el servidor. Si es solo un efecto visual para ese jugador, déjalo en el cliente y ahorras red.
Preguntas frecuentes
¿Puedo parar un tween a medias?
Sí: tween:Cancel() lo para y deja el objeto donde esté, y tween:Pause() lo congela para poder reanudarlo con :Play().
¿Cuántos tweens puedo tener a la vez?
Muchos, pero cada uno cuesta. Para decenas de objetos moviéndose igual, sale más barato mover un Model entero por su PrimaryPart.
¿Sirve para la interfaz?
Sí, y es donde mejor queda. Anima Position y Size de tipo UDim2 en los elementos de GUI. Ahí Back y Elastic lucen mucho.
¿Y si quiero un recorrido con curvas, no en línea recta?
TweenService va siempre en línea recta entre dos puntos. Para trayectorias curvas necesitas encadenar varios tweens o calcular puntos intermedios tú.
Última revisión: 1 de septiembre de 2026




Deja una respuesta