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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gedatou/editor

v0.5.3

Published

Embeddable Remotion video editor React components — timeline, canvas, inspector; shadcn-authored, theme-able

Readme

@gedatou/editor

一个可嵌入的 headless 视频编辑器引擎(Remotion)——核心是状态 + 命令 + 钩子 + 画布/时间线/检查器等交互面,由你在其上自建 UI;不锁定文案、配色、布局。也自带一套可选的 batteries-included 外壳(EditorRoot / Editor.*),要开箱即用直接放进去即可。组件按 shadcn 官方写法编写(base-ui + cva + data-slot + CSS 变量 token),主题可换肤。

要求:React 19 · Tailwind CSS v4 · Remotion 4.0.491。

安装

npm install @gedatou/editor @gedatou/shared
# peer 依赖(宿主提供,版本需对齐;Remotion 全家必须单版本)
npm install react react-dom @base-ui/react lucide-react zustand mediabunny \
  [email protected] @remotion/[email protected] @remotion/[email protected] \
  @remotion/[email protected] @remotion/[email protected] @remotion/[email protected]

CSS(Tailwind v4,策略:发源码)

组件是 Tailwind class 字符串——由你自己的 Tailwind 编译器扫描本包生成工具类。在你的入口 CSS 里:

@import "tailwindcss";
/* 让 Tailwind 扫描本包,生成组件用到的工具类 */
@source "../node_modules/@gedatou/editor/dist";
/* 本包的 oklch 主题 token(换肤只需重定义下面变量,无需碰组件) */
@import "@gedatou/editor/styles.css";

换肤:在你的 :root / .dark 里覆盖 --primary--background--card--border 等 token 即可。

核心(headless)—— 自建 UI

主用法:EditorProvider 提供每实例的 store/refs/deps;useEditor(selector) 读响应式状态、 useEditorCommands() 取一套绑好的命令、再配合 Canvas / Timeline / Inspector / PlaybackBar 这些交互面,自建任意工具栏 / 菜单 / 快捷键 / 布局(文案、配色、语言全归你):

import {
  Canvas,
  EditorProvider,
  Inspector,
  PlaybackBar,
  Timeline,
  useEditor,
  useEditorChrome,
  useEditorCommands,
} from '@gedatou/editor'

// 你自己的工具栏:命令来自 useEditorCommands,状态来自 useEditor —— 文案/样式都归你
function Toolbar() {
  const cmd = useEditorCommands()
  const canUndo = useEditor(s => s.past.length > 0)
  const dirty = useEditor(s => s.undoable !== s.lastSavedState)
  return (
    <header className="flex items-center gap-2">
      <button disabled={!canUndo} onClick={cmd.undo}>Undo</button>
      <button onClick={cmd.togglePlay}>Play/Pause</button>
      <button onClick={() => cmd.setTool('text')}>Text</button>
      <input type="file" multiple onChange={e => cmd.importAssets([...(e.target.files ?? [])])} />
      <button onClick={cmd.save}>
        Save
        {dirty ? ' •' : ''}
      </button>
      <button onClick={() => cmd.render('mp4')}>Render</button>
    </header>
  )
}

function Shell() {
  useEditorChrome() // 快捷键 + Esc 退画布工具 + 上传/渲染未完成拦刷新(自绘外壳时手动接回)
  return (
    <div className="flex flex-col block-screen">
      <Toolbar />
      <div className="flex flex-1 min-block-0">
        <Canvas />
        <aside className="overflow-y-auto border-s inline-[349px]"><Inspector /></aside>
      </div>
      <PlaybackBar />
      <Timeline />
    </div>
  )
}

export function MyEditor({ deps }: { deps: EditorDeps }) {
  return (
    <EditorProvider deps={deps}>
      <Shell />
    </EditorProvider>
  )
}
  • useEditorCommands()EditorCommands):undo/redotogglePlay/play/pause/seekToaddText/addSolid/importAssetscopy/cut/paste/duplicate/deleteSelected/selectAllbringToFront/sendToBack/splitAtPlayhead/toggleSnappingsetToolsetZoom/zoomIn/zoomOut/fitZoomsave/downloadState/loadState/cleanupAssets/render。命令在调用时读最新状态,返回对象引用稳定。
  • useEditor(selector):读响应式状态(s.past.length/s.future.lengths.undoable !== s.lastSavedStates.selectedItemIdss.canvasZooms.snappingEnableds.renderingTaskss.assetStatus …)。
  • 交互面组件Canvas / Timeline / Inspector / PlaybackBar —— 这些是库的重头(画布拖拽/缩放/裁剪、 时间线 trim/吸附/框选、检查器字段),通常直接用;想自绘也可基于 useEditorApi().updateUndoable(...) 自建。
  • useEditorApi() / useEditorRefs():拿裸 store 句柄与 player/pan 等 refs(性能敏感/命令未覆盖的场景)。

注入后端 / 存储 / 提示 / 文本(deps)

编辑器不写死任何后端、也不做 i18n。这些 app 关注点全部注入(有默认适配器):

interface EditorDeps {
  transport: EditorTransport // 服务端 I/O(默认 createHttpTransport 打同源 /api)
  storage: EditorStorage // 持久化 + 素材缓存(默认 createBrowserStorage)
  notify: NotifyFn // 用户提示(默认 sonner;(msg, level) => void)
  t?: EditorT // 文本解析器(可选):不传用库内置 en 默认,见下
  exportFileName?: (codec: 'mp4' | 'webm') => string | undefined // 导出下载名(策略在宿主;不传则渲染服务用默认名)
  customItemPanels?: Record<string, ComponentType<{ item: CustomItem }>> // custom item 的检查器面板,按 kind,见「扩展点」
}

后端契约见默认适配器实现(@gedatou/editor/adapters 源码):/api/upload(签名+PUT)、/api/render/api/progress/api/captions/api/delete-asset

i18n:库不做 i18n,只留注入缝

库本身不切语言、不带多语言、不引 i18n 依赖——把「文本」当作又一个 app 关注点外包:库文案写成 t('key'),内置一套 en 默认字典enMessages,对齐官方英文 UI,也是完整 key 目录)。消费方注入 自己的 deps.t(如接了 react-i18next 的宿主)即可让编辑器跟随宿主语言,库一行不用改

import type { EditorT } from '@gedatou/editor'
import { enMessages } from '@gedatou/editor'
// enMessages 是完整 key 清单 + en 源文案,拿它当翻译基线。
const t: EditorT = (key, params) => myI18n.exists(`editor.${key}`)
  ? myI18n.t(`editor.${key}`, params) // 命中你的翻译
  : key // 未命中 → 返回 key → 库回落内置 en 默认

不注入 t 时全部走内置 en 默认(standalone / demo 即英文,与官方一致)。

扩展点(机制,不用即无感)

功能面严格对齐官方 editor-starter;宿主定制走以下机制,全部「不用时零 UI 零行为」:

  • 自定义素材类型@gedatou/shared):CustomItem = { type:'custom', kind, label, data } + registerCustomItem(kind, Renderer) 渲染器注册表。注册是副作用:预览端(app 入口)和 服务端渲染 bundle 入口都要 import 注册模块——渲染入口自建: registerRoot(CompositionRoot)CompositionRoot/FontGate@gedatou/shared/composition 导出)。
  • custom item 检查器面板deps.customItemPanels[kind]——选中该 kind 的条目时渲染在通用分区之前。 与渲染器分开注入是刻意的:面板是纯编辑器 UI,不应进服务端渲染 bundle。
  • 检查器画布区槽<Inspector canvasExtra={...} />,渲染在「画布」区宽高输入行之后。
  • 检查器积木InspectorSections.*(Composition/Item/Source/Layout/Fill/Crop/Fade/Captions/Export)
    • useItemPatch(itemId) + 字段原语(Section/Row/ColorField/SliderField/FadeSliders/NumberField), 宿主可绕开成品 Inspector 自拼面板;成品 Inspector = 官方默认拼法。

可选:batteries-included 外壳(EditorRoot / Editor.*)

不想自建 chrome 时,用现成的一站式外壳(它本身就是用下面的 Editor.* 零件拼出来的 preset):

import { EditorRoot } from '@gedatou/editor'

export default function App() {
  return <EditorRoot deps={deps} />
}

想改工具栏/布局但又不想全headless,用 Editor.* compound 零件(context-connected,摆放即用)自拼:

import { Canvas, Editor, EditorContainer, EditorProvider, Inspector, PlaybackBar, Timeline } from '@gedatou/editor'

<EditorProvider deps={deps}>
  <EditorContainer>
    <Editor.Toolbar>
      <Editor.Title>我的剪辑器</Editor.Title>
      <Editor.UndoButton />
      <Editor.RedoButton />
      <Editor.ImportAssetButton />
      <div className="ms-auto flex gap-2">
        <MyButton />
        <Editor.SaveButton />
      </div>
    </Editor.Toolbar>
    <div className="flex flex-1 min-block-0">
      <Canvas />
      <Inspector className="inline-80" />
    </div>
    <PlaybackBar />
    <Timeline />
  </EditorContainer>
</EditorProvider>

Editor.* 只含 chrome(工具栏容器/标题/按钮/徽章);交互面用扁平的 Canvas/Timeline/Inspector/PlaybackBar (均接受 className),外壳用 EditorContainer(内含 TooltipProvider + 快捷键/拦刷新)。 这些具体 chrome 有内置文案(走 deps.t / 内置 zh)与默认样式;要完全掌控就走上面的 headless 核心。

导出一览

  • headless 核心EditorProvideruseEditoruseEditorApiuseEditorRefsuseEditorDepsuseEditorCommandsuseEditorChromeuseShortcutscreateEditorStorecreateInstanceRefs
  • 交互面组件CanvasTimelineInspectorPlaybackBar(均接受 className
  • 外壳 / 可选 chromeEditorContainerTooltipProviderEditorRoot(preset)、 Editor.* 命名空间(Toolbar/Title + 各工具栏按钮 + 徽章,仅 chrome)
  • 命令式操作importFilesstartRendergenerateCaptionscleanupDeletedAssetssaveStateloadStateFromFiledownloadStateFilerestoreLocalUrlsserializeStatedeserializeState
  • 检查器积木InspectorSectionsuseItemPatchSectionRowColorFieldSliderFieldFadeSlidersNumberField
  • i18nenMessages(en 默认 + key 目录)
  • 类型EditorCommandsEditorTransportEditorStorageNotifyFnEditorDepsEditorTEditorStoreEditorStoreApiEditorInitialStateEditorInstanceRefsRenderProgressEditorRootPropsCanvasToolPatchFn

已知限制

  • RSC:产物暂未逐文件保留 "use client";在 Next.js App Router 里请于你的 import 边界处标注 client(编辑器全为交互组件)。
  • 仅 ESM。