Develop or review Remotion Studio features and UI. Apply Studio principles for optimistic updates, agent access through code or WebMCP, iframe-safe hover behavior, design consistency, mode availability, and performance verification.
84%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Apply these principles when implementing or reviewing Studio itself. They cover the regular Studio and remotion.new.
Every operation must have an optimistic update. Reflect the user's intent immediately instead of waiting for a server request, filesystem write, codemod, or hot reload. For work whose result is not yet known, show its pending state immediately without claiming completion.
Reconcile the optimistic state with the persisted result. Preserve it until the updated source/configuration arrives through HMR, and handle failures with a rollback and visible error. A late response or rollback must not overwrite a newer edit or undo. Use the existing mutation queue and history mechanisms; see enqueueStudioSourceMutation and optimistic composition metadata.
Read studio-mode when deciding availability. Check each new action and its WebMCP entry point against all four modes:
| Mode | Capabilities to consider |
|---|---|
| Regular interactive Studio | Attached Studio server; source edits, codemods, dependency installation, server rendering, and supported “Open in” actions. |
| Regular Studio with preview server detached | previewServerConnected is false; effectively read-only, with client-side rendering still available. |
| Read-only deployed Studio | No attached server; hide or disable server-dependent actions. GitHub is the only supported “Open in” action. |
| remotion.new | Runs in an iframe with a virtual filesystem hidden from the user; supports codemods and dependency installation, but no “Open in” actions. |
Use existing capability checks. A deployed Studio is not necessarily read-only: remotion.new has its own mutation capabilities. Hide or disable unsupported UI actions and enforce the same restrictions when invoked agentically.
The hover bug is stale hover state after the pointer leaves Studio's iframe.
Browsers can miss pointerleave/mouse leave events, leaving event-driven React
hover state stuck: buttons and menu rows stay highlighted, or tooltips remain
visible after the pointer has gone. See issue #9886
and the tooltip and hover fix.
:hover, using
HOVERABLE_CLASS_NAME and hoverableStyle() from
hoverable.ts. Use the
existing hover-group classes to reveal row actions. Do not introduce React
hover state just to change colors, backgrounds, or visibility.remotion-browser-studio-pointerleave event.
Dispose the observer and cancel pending timers during cleanup and dismissal.clears hover backgrounds even if pointer leave events are lost, deliberately
suppresses leave events to exercise this failure.Read studio-css-reset and no-pointer when adding or changing UI.
.css-reset, .css-reset * rule applies to every descendant in a reset
container, not just the parent. It resets font size, line height, color, font
family, background, and box sizing. Parent text styles alone do not override
each child's reset. Style the element that paints the text or SVG, or use an
appropriate descendant selector. Check computed styles, including nested
labels and icons.title attribute for a tooltip, including title="". Use a
tooltip component: the existing Studio implementation exposes ActionTooltip
and ClippedTextTooltip in
ActionTooltip.tsx.
Preserve accessible labels and keyboard focus behavior.cursor: 'pointer' for Studio controls or links. Use
cursor: 'default'. Follow the shared hover and :focus-visible conventions;
keep a visible keyboard focus indicator.Do not conditionally add or remove a context provider around children that must stay mounted. Keep the provider at the same position and change its value or an explicit enabled/disabled prop instead. Preserve any inherited context value when the local override is inactive.
Adding or removing a provider changes the React tree and remounts its descendants, resetting state, focus, effects, and media decoders. Check ternaries, early returns, and conditional wrapper components, especially when toggling playback features, sample counts, selection, or optional callbacks. For example, changing motion blur from one sample to four and back must preserve the surviving sample's subtree.
Verify descendant identity and state across the toggle and compare buffering or effect cleanup where relevant. Conditional mounting remains appropriate when the whole subtree is intentionally created or removed, such as opening a modal.
Read studio-perf. Prefer consuming context through an existing stable ref or imperative getter when the value is needed only during an action. Copying a reactive context value into a ref after subscribing does not avoid the subscription's re-renders.
For example, read getCurrentFrame() from
imperative-state.ts
inside event handlers and WebMCP tools instead of importing
Internals.Timeline.useTimelinePosition() into their owning component. Subscribe
to the frame only in the smallest leaf whose visible output must change on
every frame. Keep props and context values stable across memoized boundaries.
Test performance when adding features; source inspection is not enough. Capture a baseline and repeat the same representative interaction after the change, including playback/scrubbing when the feature participates in frame updates. Use react-scan for render/commit measurements and browser profiling for non-React work. Keep the composition, viewport, and repetitions comparable. Check unnecessary renders, commit duration, interaction latency, and playback smoothness as relevant, and resolve regressions before finishing. Report the measured result and any verification limits.
Exercise source-backed edits through the UI and direct code changes. Exercise WebMCP where a tool is provided or needed for transient Studio state and actions. Check immediate feedback, persistence after HMR, failure recovery, and undo/redo for edits that participate in history. Check availability in each mode and the relevant hover, focus, cursor, and CSS-reset behavior above.
Apply nullable-new-params when adding or reviewing TypeScript parameters, React props, and type/interface members. Use required nullable inputs for internal APIs, update callers explicitly, and preserve public API compatibility. Run the skill's scanner against the PR diff before finishing.
For Studio code changes, run the package build and relevant existing checks:
bunx turbo run make --filter='@remotion/studio'
bunx turbo run lint test --filter='@remotion/studio'Include affected packages and existing browser regression tests when the change crosses those boundaries. Follow writing-tests when adding or changing tests.
remotion-dev/remotion
cc7879e
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.