npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

@rbxts/motion

v0.0.1-d

Published

## Introduction

Downloads

9

Readme

@rbxts/motion

Introduction

Simply animate UI from point A to B with motion, a simple yet powerful animation library for Roblox-TS & Roact, inspired by the popular framer-motion library for React.

The motion component

The core of motion is the motion object. Think of it as a plain Roblox GUI element, supercharged with animation capabilities.

import { motion } from "@rbxts/motion";

Animating a motion component is as straightforward as setting values on the animate prop.

<motion.textbutton animate={{ Position: new UDim2(0.5, 100, 0.5, 0) }} />

When these values change, motion will automatically generate an animation to the latest values. This animation will feel great by default, but it can be configured with the flexible transition prop.

Variants

Variants can be used to animate entire sub-trees of components with a single animate prop. They can be used to declaratively orchestrate these animations.

const [state, setState] = useState<"hover" | "default">("default");

const buttonVariants = {
  hover: {
    TextColor3: new Color3(0, 1, 0),
  },
  off: {
    TextColor3: new Color3(1, 1, 1),
  },
};

return (
  <motion.textbutton
    animate={state}
    Event={{
      MouseEnter: () => {
        setState("hover");
      },
      MouseLeave: () => {
        setState("off");
      },
    }}
    variants={buttonVariants}
  />
);

Transitions

A transition defines how values animate from one state to another. It defines the type of animation used when animating between two values.

<motion.textbutton
  animate={{ Position: new UDim2(0.5, 100, 0.5, 0) }}
  transition={{
    duration: 1,
    easingStyle: Enum.EasingStyle.Quad,
    easingDirection: Enum.EasingDirection.Out,
    delay: 0.5,
    repeatCount: 0, // -1 for infinity
    reverse: false,
  }}
/>

Transitions can also be used in variants. If used in variants and as a prop simultaneously, the transitions will merge into 1 transition. And in the case of a clash between transitions, the transition prop has priority over the variants.

const [state, setState] = useState<"hover" | "default">("default")

const buttonVariants = {
  hover: {
    TextColor3: new Color3(0, 1, 0),
    transition={{ 
        duration: 1,
        easingStyle: Enum.EasingStyle.Quad, 
        easingDirection: Enum.EasingDirection.Out, 
        delay: 0.5
    }}
  },
  default: {
    TextColor3: new Color3(1, 1, 1),
    transition={{ 
        duration: 1,
        easingStyle:
        Enum.EasingStyle.Quad, 
        easingDirection:
        Enum.EasingDirection.Out, 
        delay: 0.5
    }}
  },
};

return (
  <motion.textbutton
    animate={state}
    tansition={{
        duration: 20
    }}
    Event={{
      MouseEnter: () => {
        setState("hover");
      },
      MouseLeave: () => {
        setState("default");
      },
    }}
    variants={buttonVariants}
  />
);

Copy & Paste Example

import Roact from '@rbxts/roact'
import { useState, withHooks } from '@rbxts/roact-hooked'
import { motion } from '@rbxts/motion'

const variants = {
    off: {
        BackgroundColor3: Color3.fromRGB(255, 255, 255),
        TextColor3: Color3.fromRGB(0, 0, 0),
        Size: new UDim2(0, 300, 0, 100)
    },
    on: {
        BackgroundColor3: Color3.fromRGB(0, 0, 0),
        TextColor3: Color3.fromRGB(255, 255, 255),
        Size: new UDim2(0, 300, 0, 90)
    }
}

const Button = withHooks(() => {
    const [state, setState] = useState<'on' | 'off'>('off')

    return (
        <motion.textbutton
            Text="Hello"
            Event={{
                MouseEnter: () => {
                    setState('on')
                },
                MouseLeave: () => {
                    setState('off')
                }
            }}
            transition={{
                duration: 0.3
            }}
            TextSize={20}
            Size={new UDim2(0, 300, 0, 100)}
            variants={variants}
            AnchorPoint={new Vector2(0.5, 0.5)}
            Position={new UDim2(0.5, 0, 0.5, 0)}
            animate={state}
        >
            <motion.uicorner
                animate={{
                    CornerRadius: state === 'on' ? new UDim(0, 20) : new UDim(0, 0)
                }}
                transition={{
                    duration: 0.3
                }}
            />
        </motion.textbutton>
    )
})

export = (target: Instance) => {
    let tree = Roact.mount(
        <Button />,
        target,
        'UI'
    )

    return () => {
        Roact.unmount(tree)
    }
}