# @elah/timeline 中文文档

规范地址：https://npmcn.com/package/%40elah/timeline/

版本：1\.0\.0
npm 元数据更新时间：2026-10-28T07:06:22.745Z
中文译文更新时间：2026-11-13T13:44:13.137Z
软件包许可：Apache-2\.0

本文由上游 README 翻译，可能存在偏差，请结合原文核对 API、命令与配置。版权与许可归原作者所有。

原始 npm 页面：https://www.npmjs.com/package/%40elah/timeline
原文对照：https://npmcn.com/package/%40elah/timeline/?lang=original
项目主页：https://www.elah.dev/
源码仓库：https://github.com/elahlabs/elah

## 关键信息（来自 npm 元数据）

- 包体积（解压后）：184 kB，62 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：4 个
- peer 依赖：react \>=18\.0\.0，react-dom \>=18\.0\.0，lucide-react \>=0\.400\.0
- 首次发布：2026-06-09T14:14:50.759Z
- 最新版本发布：2026-10-28T07:06:22.567Z
- 近 30 天下载量：3448（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：11（近 12 个月 11 个）

## 中文简介

Elah 视频引擎的反应时间线 UI — 轨迹、剪辑、标尺、播放头、拖放和修剪手势

## 安装

```sh
npm install @elah/timeline
```

也可以使用：`pnpm add @elah/timeline`、`yarn add @elah/timeline`、`bun add @elah/timeline`

## README

# @elah/ 时间线

Elah视频引擎的反应时间轴 UI. 轨迹、剪辑、尺子和弹头——并用电线将拖放、修剪、擦除、放大和手势投入 `@elah/core` 发动机呼叫.

消费者 `@elah/core`没有项目状态——所有州都住在核心商店.

[![npm](https://img.shields.io/npm/v/@elah/timeline)](https://www.npmjs.com/package/@elah/timeline) [![license](https://img.shields.io/badge/license-Apache--2.0-blue)](https://github.com/elahlabs/elah/blob/main/LICENSE)

* * *

## 安装

```bash
npm install @elah/timeline @elah/core @elah/react lucide-react
```

同伴依赖性 : `react`, (中文(简体) ), `react-dom` 18岁, `lucide-react` 0.400.0 (直接使用于 `TrackRow`编号 :`ClipBlock` 用于剪辑图标 — 即使应用程序中没有其它内容, 也要安装它 需要它吗? 引擎/回放上下文( E)`EditorContext`, (中文(简体) ), `useTimelineEngine`)来自 `@elah/react`,自动拖入的运行时间依赖(`@elah/timeline` 取决于 `@elah/core@^1.0.0` 财务报告和审定财务报表 `@elah/react@^1.0.0`) (中文(简体) ).

**版本和稳定性:** 1.0.0. 出口的API跟随铸币局 `@elah/timeline` 实值 锁定后释放 `@elah/core`, (中文(简体) ), `@elah/react` 财务报告和审定财务报表 `@elah/editor` (所有1.0),所以请保持 四个在同一个版本。 AI - Faccing (英语) `@elah/core` 条目(`@elah/core/spec`, (中文(简体) ), `/html`, (中文(简体) ), `/ops`, (中文(简体) ), `/icons`活在1.0中,并跟随铸币局 `@elah/core` 只有根这样 根会保持小。 此软件包不导入它们 。 参见《稳定》部分 [变动情况](https://npmcn.com/package/CHANGELOG.md)。 。 。 .

**套装大小 :** 仅UI 层( 项目状态存在于 `@elah/core`页:1 `clsx` 财务报告和审定财务报表 `tailwind-merge`。在 1.0.0 与 `node scripts/measure-bundle.mjs` (建造、改良、, g; `react`, (中文(简体) ), `react-dom`, (中文(简体) ), `lucide-react` 财务报告和审定财务报表 `mediabunny` 外部 :

| 应用程序导入 | gz 时速 |
| --- | --- |
| 编辑器应用程序 : `EditorProvider`, (中文(简体) ), `Preview`, (中文(简体) ), `Timeline` 从 `@elah/editor` | 112.0 基贝 |
| `@elah/core` 仅限引擎( e)`TimelineEngine`, (中文(简体) ), `resolveTimeline`(中文(简体) ) | 44.7 基贝 |
| `@elah/core` 发动机 + `GpuRenderer` + 键 `exportVideo` | 75.0基贝 |
| `@elah/timeline` 枪管,每个出口都保留,加 `clsx` 财务报告和审定财务报表 `tailwind-merge` | 21.6 KiB(14.9 KiB自有代码) |

前三起是真正的应用程序在启动时支付的费用;后一起是无法接触到应用程序的最坏情况. 可选的渲染器特性(效果、发电机、序列夹、旋转口罩、音频增强) 并不属于这些数字. [Bundle 战略.md](https://npmcn.com/package/BUNDLE_STRATEGY.md) 解释方法和每行包括什么.

**剪切类型( 1. 0.0) :** 时间线绘制每个剪辑类型 `@elah/core` ——视频,音频,文本,图像,形状,自由手,以及更新的调整,生成器,化合物和序列剪接等,以被标记的块来显示. 您可以移动、 修剪、 拆分、 复制并粘贴( 打印用途) `engine.cloneClip`) (中文(简体) ). 任意类型的选中剪辑显示其密钥框 [键框道](https://npmcn.com/package/%40elah/timeline/#readme-keyframe-lane)。 。 。 . `@elah/editor` 仍然没有编辑新剪辑类型的UI(没有检查器,曲线编辑器,效果堆栈或复合编辑器):通过引擎,操作或VideoSpec驱动. 见 [现值 升起.md](https://npmcn.com/package/CURRENT_LIMITATIONS.md)。 。 。 .

* * *

## 构成部分

| 构成部分 | 说明 |
| --- | --- |
| `Timeline` | 主要组成部分——道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道道 拖曳来移动、 边缘拖曳来修剪、 单击或拖曳标尺来擦除 |
| `KeyframeLane` | 沿着所选剪辑的下边缘键框方块 . `Timeline` 为你挂起它,你看 [键框道](https://npmcn.com/package/%40elah/timeline/#readme-keyframe-lane) |

尺子、轨迹、剪接块和弹头是 `Timeline`: 它们没有被导出。 把它们换成 `classNames` 螺旋桨和 `--elah-*` 变量(下文).

* * *

## 快开始

`Timeline` 从 React 上下文读取引擎和播放时钟——它没有 `engine` 道具 (英语). 把它包起来 `EditorContext.Provider` 从 `@elah/react` (或使用) `EditorProvider` 从 `@elah/editor`为你做这个:

```tsx
import { Timeline } from '@elah/timeline'
import { TimelineEngine, PlaybackEngine } from '@elah/core'
import { EditorContext } from '@elah/react'

const engine = new TimelineEngine({ fps: 30, stage: { width: 1920, height: 1080 } })
const playback = new PlaybackEngine({ fps: 30, getTotalFrames: () => engine.getTotalFrames() })

function App() {
  return (
    <EditorContext.Provider value={{ engine, playback }}>
      <Timeline fps={30} style={{ height: 300 }} />
    </EditorContext.Provider>
  )
}
```

`EditorContext` 只供应引擎配对——确实如此 **没有** 有线 `engine` 在Zustand中的事件 照亮了道路 `<EditorProvider>` 是的,所以一个赤裸的 `EditorContext.Provider` 像这样需要自己的 `engine.on('change', ...)` → `tracksStore.sync(...)` 接线( 见 `@elah/editor`是因为 `EditorProvider` 来源)或 uI不会更新。 偏爱 `EditorProvider` 除非您特别需要一个 自定义存储同步策略 .

仓库 `Timeline` 改为:`tracksStore`, (中文(简体) ), `playbackStore`, (中文(简体) ), `selectionStore`, (...) (中文(简体) ) 是模块级单数 `@elah/core` - 只有一个引擎状态可以 一次照在他们身上 二号 `<Timeline>` 由两棵树支撑 同一页的不同引擎会让它们为同一商店而战 [`@elah/core`读取](https://www.npmjs.com/package/@elah/core) 详细情况.

* * *

## 样式

一次导入已编译的样式表( 平面 CSS — Tailwind 是) **没有** 所需数量 您的应用程序, 并且没有用户类 泄露到您的全球范围 :

```ts
import '@elah/timeline/styles.css'
import '@elah/editor/styles/tokens.css' // --elah-* defaults (standalone use)
```

`tokens.css` 船舶在 `@elah/editor`,该软件包不依赖于: `npm install @elah/editor` 或定义 `--elah-*` 变量本身 内部 `.elah-root` (见 `THEMING.md` 在此包中).

颜色由 `--elah-*` CSS变量. 重温主题,在你的 拥有 `.elah-root` 范围——见 [设计 -- -- md](https://github.com/elahlabs/elah/blob/main/docs/design-tokens.md)。 。 。 .

### 行为超越—— `classNames`

对特定时间段的一次性造型,通过 `classNames` ——每秒地图 尾风课. 无论你通过什么 胜过内置课程(`tailwind-merge`) (中文(简体) ).

```tsx
<Timeline
  classNames={{
    root:       'rounded-xl',
    ruler:      'bg-zinc-900',
    rulerTick:  'bg-zinc-700',
    rulerLabel: 'text-zinc-500',
    trackLabel: 'bg-zinc-900',
    lane:       'bg-zinc-950',
    clip:       'rounded-lg shadow-lg',   // shape/shadow (all clip types)
    // per-type clip color — body + accent are separate slots:
    clipVideo:       'from-sky-400 to-sky-600',  // body (gradient or solid bg-*)
    clipVideoAccent: 'text-sky-300',              // stripe + selection + track bar
    playhead:   'text-rose-500',
  }}
/>
```

公约:

-   **背景情况** (尺子、车道、标签、剪接体) `bg-*` 或渐变 停车( e)`from-… to-…`;为您添加了梯度方向).
-   **分数** (玩家头,剪条纹/选取,音轨标签栏) `currentColor`,所以重新涂上他们 **`text-*`** 课.

槽数 : `root`, (中文(简体) ), `ruler`, (中文(简体) ), `rulerTick`, (中文(简体) ), `rulerLabel`, (中文(简体) ), `track`, (中文(简体) ), `trackLabel`, (中文(简体) ), `lane`, (中文(简体) ), `clip`, (中文(简体) ), `clip{Video,Audio,Text,Image}`, (中文(简体) ), `clip{Video,Audio,Text,Image}Accent`, (中文(简体) ), `playhead`见 `TimelineClassNames` 类型.

* * *

## 键框道

选中的剪贴板显示其下边缘的密钥框为钻石 。 这是开源 编辑器的视觉密钥框编辑; `Timeline` 使其在选中范围内 `ClipBlock`这样 没有什么可以监听的.

-   **点击** 一个钻石来选择它 并寻找它的玩家.
-   **拖动** 重排时间 抓到的钥匙扣到其他钥匙 剪辑是第一个也是最后一个 边框和播放头 `playbackStore.snapEnabled` 开始 整个拖累是一体的 撤销步骤( e)`Move keyframes`(三); **英格兰** 取消这个.
-   **Shift+ 单击** 将钻石添加到选取中或取出. 拖动选定的钻石 将每个选定的密钥以相同数量移动。 未选中的密钥, 只需单击即可 单独选择它.
-   握取键框画作正方形; 键盘被左向修剪推到剪辑外 剪辑边并无法被拖动; 在远缩放时, 键比几个像素折叠成 一个集群标记(单击求取其第一个密钥,在您放大前不能拖动) .
-   在锁定的音轨上,您仍然可以选择和寻找,但不能移动 .

`KeyframeLane` 用于显示自己剪辑UI的主机。 这需要 `EditorContext` 提供者和一个绝对位置的父公司( 它填补了父公司的底部) `KEYFRAME_LANE_HEIGHT` 像素, 14 个.

```ts
import { KeyframeLane, KEYFRAME_LANE_HEIGHT, type KeyframeLaneProps } from '@elah/timeline'
```

| Prop | 类型 | 含义 |
| --- | --- | --- |
| `clip` | `Clip` | 要画出钥匙的夹子. `Keyframe.frame` 是剪接相对的,所以 `left = frame * zoom` |
| `zoom` | `number` | 每帧像素 |
| `locked` | `boolean` (可选) | 导航但不编辑 |
| `channels` | `ReadonlyArray<AnyKeyframeChannel>` (可选) | 只显示这些频道的密钥 。 显示每个频道的结合 |

选择的密钥在 `useKeySelectionStore`和剪辑分开的一栋露天店 选择( e)`useSelectionStore`) (中文(简体) ). 它每次持有一个剪辑的密钥: 从另一个键中选择一个密钥 剪辑取代选择,并取消剪辑的选择.

```ts
import { useKeySelectionStore, keysOf } from '@elah/timeline'

const clipId = useKeySelectionStore(s => s.clipId)       // clip the selected keys belong to, or null
const frames = useKeySelectionStore(s => s.frames)       // ReadonlySet<number> of clip-relative frames
useKeySelectionStore.getState().select(clipId, [12, 30]) // also: toggle, shift(delta), clear
keysOf(clipId)                                           // non-reactive read: the set for that clip, else empty
```

* * *

## 钩子

```ts
import { useTracks, usePlayback, useSelection } from '@elah/timeline'

const tracks = useTracks(s => s.tracks)
const isPlaying = usePlayback(s => s.isPlaying)
const selectedClipIds = useSelection(s => s.selectedClipIds)
```

这些别名是: `useTracksStore`, (中文(简体) ), `usePlaybackStore` 财务报告和审定财务报表 `useSelectionStore` 从 `@elah/react`· ; 保持选择器的窄度( e)`usePlayback(s => s)` 重新对每段回放框进行回复). `useTimeline()` 返回时 `TimelineEngine` 从上下文. `useKeySelectionStore` (见 [键框道](https://npmcn.com/package/%40elah/timeline/#readme-keyframe-lane))是这个软件包拥有的一家商店.

* * *

## 拖放( D)

将媒体投放处理器附加到任何轨道道元素中. `useTimelineDrop(trackId, lane)` 将轨道ID和车道DOM节点定位,并读取引擎 页:1 `EditorContext` (所以它必须运行在提供者内部). 接线员说 副作用并返回车道的拖动状态, `TimelineDropState`数字 : `'valid'` (相容的拖曳徘徊), `'invalid'` (不兼容类型或锁定的音轨) 或者说 `null` (不拖放),用于突出显示投放目标 :

```tsx
import { useState } from 'react'
import { useTimelineDrop } from '@elah/timeline'

function Lane({ trackId }: { trackId: string }) {
  // State, not useRef: the hook needs the node on a render after it mounts.
  const [lane, setLane] = useState<HTMLDivElement | null>(null)
  const dropState = useTimelineDrop(trackId, lane)
  return <div ref={setLane} data-drop={dropState ?? undefined} />
}
```

将一个媒体资产从库拖入道中解析位置 `startFrame` (尊重缩放和snap).

### 在探测介质前插入

`insertMediaAsset(engine, assetId, opts?)` 财务报告和审定财务报表 `insertElement(engine, payload, opts?)` 放置不拖动的片段。 对于远程资产 从核心开始 `beginImportUrl` 插入(立即返回待决资产) 后退长度的剪辑,然后调用 `growClipToAssetDuration` 一次真实 期限是已知的。 他的同伴 `beginImportUrl` 用于插入剪辑的主机 在探测其介质之前:

```ts
import { growClipToAssetDuration } from '@elah/timeline'

// growClipToAssetDuration(engine, clipId, expectedFallbackFrames, newDurationSec)
growClipToAssetDuration(engine, clipId, fallbackFrames, durationSec)
```

它只在下个片段(从不产生重叠)之前就发展到空白,并留下一个 如果用户已经将其从倒数长度中剪切出来,则单独剪切.

* * *

## 缩放和多条视频轨道

这个 `Timeline` 裁判曝光 `{ engine, playback, fitToWindow, zoomAtAnchor }`。 。 。 . `zoomAtAnchor(nextZoom)` 瞄准目标时 瞄准目标 取景器中心,所以工具栏缩放按钮或滑动器从不将播放头卷走. 用这个 而不是生下来 `setZoom`。 。 。 .

时间线使任何视频音轨都成为了最上方的道道道复合材料. 仅 滚动的取景口内部的剪辑被挂起(外加一个边距),所以较长的时长仍然很便宜.

* * *

## 链接

-   [网站](https://www.elah.dev/)
-   [GitHub 图像](https://github.com/elahlabs/elah)
-   [完整 SDK — @ elah/编辑器](https://www.npmjs.com/package/@elah/editor)
-   [无头CLI — @elah/cli](https://www.npmjs.com/package/@elah/cli)
-   [许可证](https://github.com/elahlabs/elah/blob/main/LICENSE)
-   [商业许可证发放](mailto:paul@elah.dev)

## 常见问题

### @elah/timeline 是什么？

Elah 视频引擎的反应时间线 UI — 轨迹、剪辑、标尺、播放头、拖放和修剪手势

### 如何安装 @elah/timeline？

在项目目录运行 npm install @elah/timeline，或使用 pnpm add / yarn add / bun add。它还需要宿主项目提供 peer 依赖：react（\>=18\.0\.0）、react-dom（\>=18\.0\.0）、lucide-react（\>=0\.400\.0）。npm 7 及以上与 pnpm 8 及以上默认会自动安装必需的 peer 依赖，Yarn 需要手动安装。

### @elah/timeline 支持 TypeScript 吗？

支持。包内自带 TypeScript 类型声明（package\.json 声明了 types 入口），安装后即可获得类型提示，无需再安装 @types 包。

### @elah/timeline 支持 ESM 还是 CommonJS？

以 ES Module 形式发布，推荐使用 import 引入。在 CommonJS 项目中，Node\.js 20\.19\+ / 22\.12\+ 可以直接 require\(\) 不含顶层 await 的 ES Module，更早的版本需要改用动态 import\(\)。

### @elah/timeline 可以商用吗？

@elah/timeline 使用 Apache-2\.0 许可。宽松许可：允许商业使用、修改和再分发，并附带明确的专利授权；分发时需保留许可与 NOTICE 文件，修改过的文件要注明改动。以上为概括，不构成法律意见，请以许可原文为准。

### @elah/timeline 的下载量有多少？

根据 npm 官方下载统计，@elah/timeline 在 2026/10/13 – 2026/11/11 这 30 天内被下载 3,448 次，日均约 115 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入，适合横向比较热度，不能直接等同于使用人数。

### @elah/timeline 还在维护吗？

最新版本 1\.0\.0 发布于 2026/10/28（16 天前）；至今共发布 11 个版本，其中过去 12 个月发布了 11 个；首次发布于 2026/06/09。发布频率只是参考信号：功能稳定的工具可能很少需要更新，建议结合源码仓库的 issue 和提交记录判断。

