Skip to article

Motion Studio

Edit Motion animations directly on your website with a visual editor and fast animation editor AI. Then apply changes to source with your existing code agent.

Motion Studio puts a timeline directly on your website. Select an animation, edit visually with AI, apply direct to source code.

Edit and preview animations without leaving your website. A visual animation editor combined with a fast animation editing agent.

0.00.51.01.5
h1
.description
buttons
0.00 / 1.52s

Motion Studio is free to install and edit animations visually. The Ultramotion editor agent and Apply to code features require a Motion Studio subscription.

Supported environments

Studio runs in your local development environment. The bundler integration and the animation code that reaches the browser determine what Studio can edit.

EnvironmentSupport
Next.js with TurbopackSupported with withMotionStudio and the companion Studio server.
Next.js with WebpackSupported with the same Next.js wrapper and companion server.
ViteSupported with the motionStudio() plugin.
WebpackSupported with the development-only Studio loader and companion server.
Nuxt with ViteSupported with motionStudio({ serverUrl }) and the companion Studio server. Use explicit Motion imports in Vue components.
AstroSupported with the same Vite plugin and companion server for imported client scripts and hydrated React or Vue components.

Nuxt and Astro were verified with Nuxt 4.5.2, Astro 7.3.3 and Node.js 22.19.0. Checks cover animation discovery, preview, Apply, hot reload and production builds without Studio code. Your framework may need a newer Node.js version than Studio's minimum.

React Server Component boundaries

In the Next.js App Router, keep animations you want to edit in client modules. Studio preserves the "use client" directive and does not add it to Server Components. The panel starts only in the browser.

A Server Component can render an animated Client Component. Put "use client" at the top of the client entry file, before its imports:

"use client"

import { motion } from "motion/react"

export function AnimatedCard() {
  return <motion.div animate={{ opacity: 1 }} initial={{ opacity: 0 }} />
}

Keep server data fetching in the Server Component and pass serialisable props to the Client Component. Studio discovers animation code that runs in the browser. Animation definitions that run only on the server are outside that discovery path. See the Next.js guide to Server and Client Components for boundary rules.

Nuxt and Astro

Nuxt and Astro control their own HTML output. Set serverUrl on the Vite plugin so instrumented client modules can load the panel from the companion server. This setup does not depend on Vite's HTML hook.

In Nuxt, import the Motion APIs you use from motion-v in each Vue file. Studio needs these imports to discover the animation source. Nuxt auto-imports alone are not enough.

In Astro, put JavaScript animations in a .js or .ts file imported by a client script. React and Vue components need a client:* directive. Studio waits for an island to hydrate before starting a component preview. Server-only components, Astro frontmatter and animation definitions written directly inside .astro script blocks are not supported.

Install

Motion Studio requires Motion 13.3.0 or later and Node.js 22.13 or later, or the newer Node.js version your framework requires. Studio runs in your local Vite, Next.js, Nuxt, Astro or Webpack development environment.

Copy this prompt into your agent to install Motion Studio.

Show manual setup

Install the package

Run this command from your app's directory:

npm install -D motion-studio

Use your project's package manager if it uses Yarn, pnpm or Bun. Then follow the steps for your framework. Keep your existing configuration and add the Studio integration to it.

Vite

Add motionStudio() before your React or Vue plugin in vite.config.ts:

import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { motionStudio } from "motion-studio"

export default defineConfig({
  plugins: [motionStudio(), react()],
})

For Vue, keep your existing vue() plugin in place of react(). For plain JavaScript, use plugins: [motionStudio()].

Run your normal development command. Vite starts the Studio server for you. The plugin only runs in development.

Next.js

Wrap your existing config with withMotionStudio in next.config.mjs or next.config.ts:

import { withMotionStudio } from "motion-studio/next"

const nextConfig = {
  // Keep your existing Next.js options here.
}

export default withMotionStudio(nextConfig)

The wrapper supports both Turbopack and Webpack. It enables Studio during next dev and leaves production builds unchanged.

Run your normal development command. In a second terminal, start the Studio server from the same app directory:

npx motion-studio serve

Keep both commands running. Studio uses http://localhost:5200 by default. If you change the server port, pass the matching serverUrl as the second argument to withMotionStudio.

Nuxt

Add the plugin to vite.plugins in nuxt.config.ts. Keep your existing Nuxt options and plugins:

import { motionStudio } from "motion-studio"

export default defineNuxtConfig({
  vite: {
    plugins: [motionStudio({ serverUrl: "http://localhost:5200" })],
  },
})

Run your normal Nuxt development command. In a second terminal, run npx motion-studio serve from the same app directory. Keep both commands running. This integration supports Nuxt's Vite builder.

Use explicit imports in your Vue components:

<script setup>
import { motion } from "motion-v"
</script>

<template>
  <motion.div :animate="{ opacity: 1 }" />
</template>

Astro

Add the plugin to vite.plugins in astro.config.mjs or astro.config.ts. Keep your existing integrations, including any React or Vue integration:

import { defineConfig } from "astro/config"
import { motionStudio } from "motion-studio"

export default defineConfig({
  vite: {
    plugins: [motionStudio({ serverUrl: "http://localhost:5200" })],
  },
})

Run your normal Astro development command. In a second terminal, run npx motion-studio serve from the same app directory. Keep both commands running.

For JavaScript animations, create a client module such as src/scripts/animate.ts:

import { animate } from "motion"

animate(".card", { opacity: [0, 1] }, { duration: 0.4 })

Import it from the page's client script. For a page in src/pages/, this can be:

<div class="card">Hello</div>
<script>
  import "../scripts/animate"
</script>

Keep the animation definition in the imported file so Studio can edit it. For React or Vue animations, hydrate the component, for example with <AnimatedCard client:load />. A component rendered only on the server cannot appear in the timeline.

For Nuxt and Astro, the plugin runs only during development. Production builds exclude Studio. If you change the companion server port, set the same port in serverUrl.

Webpack

Add a development-only pre-loader to your existing module.rules in webpack.config.cjs. Keep your other rules and options:

module.exports = (_env, argv) => ({
  module: {
    rules: [
      ...(argv.mode === "development" ? [{
        test: /\.(?:[cm]?[jt]s|[jt]sx)$/,
        exclude: /node_modules/,
        enforce: "pre",
        use: [{
          loader: require.resolve("motion-studio/loader"),
          options: { boot: { serverUrl: "http://localhost:5200" } },
        }],
      }] : []),
      // Keep your existing rules here.
    ],
  },
})

Run your development server with --mode development. In a second terminal, run npx motion-studio serve from the app directory. Keep both commands running. The Studio loader must be excluded from production builds.

Open Studio

Open your local app and press the timeline button. Play an animation if the timeline is empty, then preview a timing change. Log in from the Studio panel to use your subscription.

Connect external agent

Choose a provider in your project's .env.local:

MOTION_STUDIO_AGENT_PROVIDER=cursor

The supported values are cursor, codex and claude. Cursor is the default. Studio reads .env.local on each request, so changes take effect without a restart. Restart the dev server if you change its process environment or install an SDK.

Cursor SDK is included. Use Connect Cursor in the panel to sign in. An existing Cursor SDK sign-in is reused.

Codex needs its SDK installed separately:

npm install -D @openai/codex-sdk
npx codex login

Claude needs its SDK and Claude Code sign-in:

npm install -D @anthropic-ai/claude-agent-sdk
claude auth login

If the Claude command is missing, install Claude Code. The editor reuses its sign-in.

Set MOTION_STUDIO_AGENT_MODEL to override the provider's default model. The selected model must be available to your account.

ProviderModel when no override is set
Cursorcomposer-latest, which follows Cursor's current Composer model
CodexThe model selected by Codex configuration, or its built-in default
ClaudeThe Claude Code SDK default model

For example, to use the Composer alias explicitly:

MOTION_STUDIO_AGENT_PROVIDER=cursor
MOTION_STUDIO_AGENT_MODEL=composer-latest

Cursor's local SDK needs a model, so Studio supplies the alias. Studio omits the model option for Codex and Claude unless you set an override. This avoids a Studio release for each new model. Your installed SDK must still support the selected model. Codex runs with low reasoning effort.

Studio checks the process environment first, then .env.local and .env in the app directory, then those files in its parent directory. The first non-empty value wins. Leave MOTION_STUDIO_AGENT_MODEL unset to use the defaults above.

You can preview and apply literal edits without an agent. With a Studio subscription, chat works without an agent too: Ultramotion edits the timeline with your Studio login. Ultramotion has a monthly allowance for each account. When it is used up, the chat asks you to connect a coding agent until the allowance resets. Writing a new animation or an agent edit to source needs a connected agent. Without one, Apply copies the prompt to your clipboard so you can paste it into any coding agent, and the chat explains how to connect one.

Editing

Animations will appear in the timeline editor when detected. For JS, animations are detected when they run whereas many React and Vue animations will be parsed from props.

Select an animation from the dropdown to start editing.

Each group of elements within an animation are represented by a track.

A track can be dragged to move an animation (by setting its delay). It has resize handles at each end which can be used to rescale the animation and the duration of all its keyframes.

Double-click a track to add a keyframe, or select a keyframe to edit its values or easing.

Transition

Double click a keyframe to snap it to the nearest keyframe.

0.00.51.01.52.0
opacity
y
opacity
y

Changes stay in the preview until Apply. Use the discard control to remove pending changes.

Use Cmd+Z or Ctrl+Z to undo. Add Shift to redo. Draft edits and applied source edits have undo history. Source history belongs to the current dev server session.

Add a new animation

By pressing the Add animation button, you can select an element (or multiple elements) to apply a new animation to.

Choose Animation, Hover, Press, or In view.

Keyboard controls

Use Cmd on macOS or Ctrl on Windows and Linux. Option on macOS is the same as Alt below.

Panel and timeline

These shortcuts work while Studio is open, except when you're typing in a field. Alt+T also works when the panel is closed.

ShortcutAction
Alt+TOpen or close Studio.
SpacePlay or pause the selected animation.
Space+dragPan the timeline. Release Space without dragging to play or pause.
Left arrow / Right arrowMove the playhead to the previous or next keyframe.
HomeMove the playhead to the start.
Cmd/Ctrl+ASelect all tracks in the current animation.
Cmd/Ctrl+ZUndo an edit.
Cmd/Ctrl+Shift+ZRedo an edit.
Shift+ACycle the Studio accent colour.

Press Cmd/Ctrl+S to apply pending changes for the selected animation. This also works while typing in a field. Other animations keep their pending changes. Apply requires an active Studio subscription.

Editing and chat

ShortcutAction
Enter in the agent inputSend your message.
Shift+Enter in the agent inputAdd a new line.
Arrow keys with a Bézier control point focusedMove the control point by 0.1. Hold Shift for smaller steps of 0.01.
Escape while picking an elementCancel element selection.

Text fields keep their normal text-editing shortcuts, including undo and redo.

Ultramotion

Ultramotion is Motion Studio's animation editing agent.

It can edit animations based on natural language up to 15x faster than even a cheap and fast coding agent. Currently, it's built on Jev, falling back to Luna for more complicated edits.

Prompt it with terms like "increase duration" or "stagger these by 0.2s" and it'll perform those edits on the same preview that you're working on. You can undo its changes the same way you'd undo your own.

Selected tracks will appear in the chat as context, or you can refer to them by name.

Limitations

Ultramotion achieves its speed by being narrow in scope. It only performs edits on the current animation. It isn't chatty, although it can ask for clarification.

Because of this, prompts like "add the header to this animation" won't (currently) work. This action must be performed manually via the "Add element" button.

Apply to code

Pressing Apply will write your new animation to your codebase. Simple edits are written straight to code by the Motion Studio server.

With a connected agent, pressing Apply will automatically write the animation to your codebase.

Without one, a prompt will be copied to your clipboard to paste into the agent of your choice.

Supported animation APIs

Motion Studio currently supports animate(), <motion.*>, useAnimate() and v-motion.

It works with all React, JS, Vue, Three.js and vgpu flavours of Motion.

Troubleshooting

The panel does not appear. Confirm the app runs in development. Press the timeline button on the page. For Next.js, Nuxt, Astro and Webpack, check that the editor server is running and that its port matches serverUrl. In Nuxt and Astro, load a component or client module with a supported animation so it can start the panel.

A Nuxt or Astro animation is missing. In Nuxt, add explicit motion-v imports to the Vue file. In Astro, move inline animation code to an imported .js or .ts file, or use a hydrated React or Vue component. An island appears after it hydrates.

No animations appear. Trigger the interaction first. Check that the file imports from "motion" rather than "framer-motion".

Why is my value read-only? Values set as expressions in your code currently appear as read-only in the timeline.

Apply reports a stale file. The source changed since the preview was made. Reload the page and make the edit again. Studio rejects stale edits to protect changes made in your code editor.

Apply asks me to sign up. Apply and the agent need an active Motion Studio subscription. Press Log in if you already have one. If you were logged in before, your subscription may have ended or the login was revoked; log in again after you renew.

The agent is unavailable. Check MOTION_STUDIO_AGENT_PROVIDER, install that provider's SDK, and complete its sign-in. Restart the dev server after you install an SDK.

A custom local hostname cannot save. Allow the app's origin when you start the companion server:

npx motion-studio serve --origin https://app.local:3000

The page must be able to reach the companion server. Use a local HTTPS proxy if your browser blocks an HTTP server from an HTTPS page.