studio-dev

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Studio development

Studio 开发

Apply these principles when implementing or reviewing Studio itself. They cover the regular Studio and Browser Studio at
remotion.new
.
实施或审查 Studio 本身时,应遵循以下原则。这些原则适用于常规 Studio 和位于
remotion.new
的 Browser Studio。

Optimistic operations

乐观操作

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.
每项操作都必须具有乐观更新。立即反映用户的意图,而不是等待服务器请求、文件系统写入、codemod 或 hot reload。对于结果尚不明确的工作,应立即显示待处理状态,但不得宣称操作已完成。
将乐观状态与持久化结果进行协调。在更新后的源码或配置通过 HMR 到达之前,应保留乐观状态;发生失败时,应执行回滚并显示可见错误。延迟到达的响应或回滚不得覆盖较新的编辑或撤销操作。使用现有的 mutation queue 和 history 机制;请参阅 enqueueStudioSourceMutation和乐观 composition metadata。

Agent, interactive, and code parity

Agent、交互与代码对等

  • Every state and action must be available to an agent through project code or WebMCP. Anything already editable in project source satisfies this requirement. Moving or trimming a sequence, for example, does not need a WebMCP tool. Do not add redundant tools solely to mirror source-backed editing actions.
  • Expose transient Studio state and actions through WebMCP when project source cannot represent them, such as playback, selection, pending render jobs, and render cancellation. Follow the existing registrations in WebMcp.tsx and the relevant feature's tools.
  • Document every new WebMCP tool and changes to its inputs or outputs in the WebMCP documentation, including pending state, results, and mode availability.
  • Every source-backed edit must work interactively and by editing project code, which also provides agentic access. Direct code changes must appear correctly after hot reload. Where a WebMCP editing tool exists, it must use the same source mutation/history path as the UI. Avoid separate sources of truth.
  • Keep validation, optimistic behavior, undo/redo, errors, and mode restrictions consistent across interactive and WebMCP entry points. Read current state when a tool executes instead of capturing a stale snapshot at registration time.
  • 每项状态和操作都必须能够通过项目代码或 WebMCP 供 Agent 使用。任何已经可以在项目源码中编辑的内容都满足此要求。例如,移动或裁剪 sequence 不需要 WebMCP 工具。不要仅为镜像基于源码的编辑操作而添加冗余工具。
  • 当项目源码无法表示临时的 Studio 状态和操作时,应通过 WebMCP 暴露这些状态和操作,例如播放、选中、待处理的渲染任务以及取消渲染。请遵循 WebMcp.tsx中的现有注册方式以及相关功能的工具。
  • 必须在 WebMCP 文档中记录每个新增的 WebMCP 工具及其输入或输出的变更,包括待处理状态、结果和模式可用性。
  • 每项基于源码的编辑都必须能够通过交互方式及直接编辑项目代码完成,这也为 Agent 提供访问能力。直接修改代码后,必须在 hot reload 后正确显示。如果存在 WebMCP 编辑工具,它必须与 UI 使用相同的源码 mutation 和 history 路径。避免出现相互独立的事实来源。
  • 在交互入口和 WebMCP 入口之间,应保持验证、乐观行为、undo/redo、错误处理和模式限制的一致。工具执行时应读取当前状态,而不是在注册时捕获过期快照。

Consider all four Studio modes

考虑全部四种 Studio 模式

Read studio-mode when deciding availability. Check each new action and its WebMCP entry point against all four modes:
ModeCapabilities to consider
Regular interactive StudioAttached 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 StudioNo attached server; hide or disable server-dependent actions. GitHub is the only supported “Open in” action.
Browser Studio (
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: Browser Studio has its own mutation capabilities. Hide or disable unsupported UI actions and enforce the same restrictions when invoked agentically.
决定功能的可用性时,请阅读 studio-mode。应根据全部四种模式检查每项新操作及其 WebMCP 入口:
模式需要考虑的能力
常规交互式 Studio已连接的 Studio 服务器;源码编辑、codemods、依赖安装、服务器渲染以及受支持的 “Open in” 操作。
预览服务器已分离的常规 Studio
previewServerConnected
为
false
;实际上处于只读状态,但仍可使用客户端渲染。
只读部署版 Studio没有连接的服务器;隐藏或禁用依赖服务器的操作。GitHub 是唯一支持的 “Open in” 操作。
Browser Studio(
remotion.new
)
在 iframe 中运行,虚拟文件系统对用户隐藏;支持 codemods 和依赖安装,但不支持 “Open in” 操作。
使用现有的能力检查机制。部署版 Studio 不一定是只读的:Browser Studio 拥有自己的 mutation 能力。隐藏或禁用不受支持的 UI 操作,并在 Agent 调用时强制执行相同限制。

Prevent the iframe hover bug

防止 iframe 悬停 Bug

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.
  • Drive purely visual hover styling with CSS
    :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.
  • When JavaScript behavior depends on hover, such as a delayed menu or tooltip, use observeHover(). It handles recovery from missed leave events, window blur, visibility changes, and Browser Studio's forwarded
    remotion-browser-studio-pointerleave
    event. Dispose the observer and cancel pending timers during cleanup and dismissal.
  • Preserve intentional selected, keyboard-focused, and open-menu states. Nested actions must not appear hovered just because their parent row is hovered. Keep actions usable with keyboard and touch.
  • Verify in an iframe as well as regular Studio: hover, leave the frame, re-enter, and switch window focus. Highlights and pending/visible tooltips must clear correctly. The existing regression in browser-studio.test.ts,
    clears hover backgrounds even if pointer leave events are lost
    , deliberately suppresses leave events to exercise this failure.
悬停 Bug 是指指针离开 Studio 的 iframe 后仍保留过期的悬停状态。浏览器可能会遗漏
pointerleave
/鼠标离开事件,导致由事件驱动的 React 悬停状态卡住:按钮和菜单行持续高亮,或者指针已经离开后 tooltip 仍然可见。请参阅 issue #9886及 tooltip 与 hover 修复。
  • 纯视觉悬停样式应完全由 CSS
    :hover
    驱动,并使用 hoverable.ts中的
    HOVERABLE_CLASS_NAME
    和
    hoverableStyle()
    。使用现有的 hover-group 类显示行操作。不要仅为了改变颜色、背景或可见性而引入 React 悬停状态。
  • 当 JavaScript 行为依赖悬停状态时,例如延迟显示的菜单或 tooltip,应使用 observeHover()。它可以处理遗漏离开事件、窗口失去焦点、可见性变化,以及 Browser Studio 转发的
    remotion-browser-studio-pointerleave
    事件。在清理和关闭过程中,应释放 observer 并取消待执行的计时器。
  • 保留有意设置的选中、键盘聚焦和菜单打开状态。嵌套操作不得仅因父行处于悬停状态就显示为悬停。确保操作仍可通过键盘和触摸设备使用。
  • 应在 iframe 和常规 Studio 中进行验证:悬停、离开框架、重新进入并切换窗口焦点。高亮效果以及处于等待显示或已经可见的 tooltip 必须正确清除。browser-studio.test.ts中的现有回归测试
    clears hover backgrounds even if pointer leave events are lost
    会故意抑制离开事件,以验证对此故障的处理。

Follow the Studio design and CSS reset

遵循 Studio 设计和 CSS reset

Read studio-css-reset and no-pointer when adding or changing UI.
  • Reuse the closest existing Studio controls, layouts, and interaction patterns. Match their colors, fonts, font sizes, control sizes, spacing, borders, icons, and hover, focus, selected, and disabled traits. Use shared tokens from colors.ts and existing component styles instead of introducing a separate visual language.
  • The
    .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.
  • Never add a DOM
    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.
  • Never use
    cursor: 'pointer'
    for Studio controls or links. Use
    cursor: 'default'
    . Follow the shared hover and
    :focus-visible
    conventions; keep a visible keyboard focus indicator.
添加或修改 UI 时,请阅读 studio-css-reset和 no-pointer。
  • 复用最接近的现有 Studio 控件、布局和交互模式。匹配其颜色、字体、字体大小、控件尺寸、间距、边框、图标,以及 hover、focus、selected 和 disabled 状态特征。使用 colors.ts中的共享 token 和现有组件样式,不要引入独立的视觉语言。
  • .css-reset, .css-reset *
    规则会应用于 reset 容器中的每个后代元素,而不仅仅是父元素。它会重置字体大小、行高、颜色、字体系列、背景和 box sizing。仅设置父元素的文本样式无法覆盖每个子元素上的 reset。应对实际绘制文本或 SVG 的元素设置样式,或使用适当的后代选择器。检查计算后的样式,包括嵌套的 label 和 icon。
  • 绝不要为 tooltip 添加 DOM
    title
    属性,包括
    title=""
    。应使用 tooltip 组件:现有 Studio 实现通过 ActionTooltip.tsx提供
    ActionTooltip
    和
    ClippedTextTooltip
    。保留无障碍标签和键盘聚焦行为。
  • 绝不要对 Studio 控件或链接使用
    cursor: 'pointer'
    。应使用
    cursor: 'default'
    。遵循共享的 hover 和
    :focus-visible
    约定;保留清晰可见的键盘焦点指示器。

Performance must not regress

性能不得退化

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.
请阅读 studio-perf。如果某个值仅在执行操作时需要,应优先通过现有的稳定 ref 或命令式 getter 读取 context。订阅后将响应式 context 值复制到 ref 中,并不能避免订阅引起的重新渲染。
例如,应在事件处理器和 WebMCP 工具内部调用 imperative-state.ts中的
getCurrentFrame()
,而不是将
Internals.Timeline.useTimelinePosition()
导入其所属组件。仅在最小的叶子组件中订阅帧数据,且该组件的可见输出必须随每一帧发生变化。确保 props 和 context 值在 memoized 边界之间保持稳定。
添加功能时应测试性能;仅检查源码并不足够。应先捕获基线,然后在修改后重复执行相同的代表性交互。如果功能参与帧更新,还应包括 playback/scrubbing。使用 react-scan进行 render/commit 测量,并使用浏览器性能分析工具检查非 React 工作。确保 composition、viewport 和重复次数具有可比性。根据实际情况检查不必要的渲染、commit 耗时、交互延迟和播放流畅度,并在完成前解决性能退化问题。
报告测量结果以及任何验证限制。

Verify the feature

验证功能

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.
For Studio code changes, run the package build and relevant existing checks:
sh
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.
通过 UI 和直接修改代码两种方式测试基于源码的编辑。如果提供了相应工具,或临时 Studio 状态和操作需要通过 WebMCP 访问,则应测试 WebMCP。检查即时反馈、HMR 后的状态保留、失败恢复,以及参与 history 的编辑的 undo/redo。检查每种模式下的可用性,以及上述相关的 hover、focus、cursor 和 CSS-reset 行为。
对于 Studio 代码修改,应运行包构建和相关现有检查:
sh
bunx turbo run make --filter='@remotion/studio'
bunx turbo run lint test --filter='@remotion/studio'
当修改跨越相关边界时,应同时涵盖受影响的包和现有浏览器回归测试。添加或修改测试时,请遵循 writing-tests。