# @elah/core 中文文档

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

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

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

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

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

- 包体积（解压后）：3.1 MB，749 个文件
- 模块格式：ES Module
- TypeScript 类型：包内自带
- 运行依赖：3 个
- 首次发布：2026-06-09T14:12:12.196Z
- 最新版本发布：2026-10-28T07:06:19.699Z
- 近 30 天下载量：4062（2026-10-13 至 2026-11-11，npm 官方下载统计）
- 已发布版本数：11（近 12 个月 11 个）

## 中文简介

框架不可知视频时间表引擎——回放,帧分辨率,WebGL2渲染器以及媒体管理

## 安装

```sh
npm install @elah/core
```

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

## README

# @elah/ 核心

框架不可知视频时序引擎. 没有反应。 无出使相. 只是纯逻辑层——项目状态,回放,帧分辨率,以及媒体管理.

内部使用 `@elah/react`, (中文(简体) ), `@elah/timeline`,以及 `@elah/editor`,但可直接为自定义渲染管道或无头环境所消耗.

反应钩是 **没有** 在这个包裹中,他们生活在 [`@elah/react`](https://www.npmjs.com/package/@elah/react),将下面的存储包成组件使用.

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

* * *

## 安装

```bash
npm install @elah/core
```

**软件包大小 :** 大约1.2 MB作为npm tarball(3.0 MB已打包),其中大约一半是捆绑的字体,只有选择加入时才加载(参见 [字体](https://npmcn.com/package/%40elah/core/#readme-fonts-and-loading-from-a-cdn)) (中文(简体) ). 代码为可树动( :`sideEffects: false`; 导入 `@elah/core/engine` 如果您不需要渲染器或解码器。 运行时间道克 : `immer`, (中文(简体) ), `zustand` 财务报告和审定财务报表 `mediabunny` (单位:千美元)`^1.50.8`)),除通过外,解码器和出口工人在首先解码或出口时懒散地装入 `createDefaultDemuxerFactory`,它静态导入。 真正的应用程序下载( 构建、 精密化、 gziped; 反应、 清晰反应和 媒体bunny 外部): 编辑器应用程序( )`EditorProvider`, (中文(简体) ), `Preview`, (中文(简体) ), `Timeline` 从 `@elah/editor`大约 **112基B克兹**,从0.6.0中的68个KiB(在效应、发电机、序列夹、转子口罩和音频增强之前是133个KiB)起起,它成为首次投入使用的块; `prepareFeatures(project)` 将工程的特性加载到前面). 单发动机( :`TimelineEngine`, (中文(简体) ), `resolveTimeline`)是大约45个基B克兹,发动机加 `GpuRenderer` 财务报告和审定财务报表 `exportVideo` 大约75克比克兹。 下方的AI-facing层花费了一个没有导入的应用程序. [Bundle 战略.md](https://npmcn.com/package/BUNDLE_STRATEGY.md) 解释如何测量捆绑大小(`node scripts/measure-bundle.mjs`和尚存的启动.

**稳定性(1.0):** 根入和根入的导出 `@elah/core/engine` 跟着赛姆 三层人工智能 **现场直播** 在1.0,并跟随铸币局。 不从根导出; 从自己的条目导入 : `@elah/core/spec` (视频Spec,组件,系统, `specVocabulary`, (中文(简体) ), `@elah/core/html` (HTML/CSS场景转换), `@elah/core/ops` (业务词汇表和 `describe*` 帮助者)和 `@elah/core/icons` (卖家图标集). 每一个都标在下面。 一个项目作为文件版本1至5编写(见 [保存并恢复](https://npmcn.com/package/%40elah/core/#readme-save-and-restore); 6.6.x 无法打开使用更新型剪辑类型的文档.

* * *

## 里面的东西

| 模块 | 说明 |
| --- | --- |
| `TimelineEngine` | 管理工程状态——轨道、剪辑、撤销/重写 |
| `PlaybackEngine` | 帧精确回放时钟 |
| `resolveTimeline` | 纯函数- 项目- 在特定框架的活场景 |
| `GpuRenderer` | WebGL2 用于视频、图像、文本、形状和自由手层的渲染器 |
| `AudioPlaybackController` | 播放时钟上的多轨音频混音器 |
| `tracksStore` | Vanilla Zustand 商店镜像项目状态 — 用它绑定 `useTracksStore` 从 `@elah/react` |
| `playbackStore` | Vanilla Zustand 商店镜像回放状态 — 用它绑定 `usePlaybackStore` 从 `@elah/react` |
| `selectionStore` | 用于剪辑选择的香草Zustand商店——将其与 `useSelectionStore` 从 `@elah/react` |
| `transitionsStore` | 香草Zustand 存储镜像过渡——用它绑住 `useTransitionsStore` 从 `@elah/react` |
| `textStylePresetsStore` | 可重复使用的文本外观( 内置加用户预设) —— 用 `useTextStylePresetsStore` 从 `@elah/react` |
| `clipLoadStore` | 预览无法绘制的剪辑( W)`'loading'` 编号 : `'error'`) (中文(简体) ). 永不保存或无法撤销的渲染器状态——用 `useClipLoadStore` 从 `@elah/react` |
| `mediaLibraryStore` | 媒体资产登记(香草店)——与 `useMediaLibrary` 从 `@elah/react` |
| `importFiles` 编号 : `importUrl` 编号 : `importBlob` | 将本地文件、 远程 URL 或 blobs 导入媒体库 |
| `beginImportUrl` | 喜欢 `importUrl` 返回一个 `status: 'pending'` 资产,所以可以在媒体探测前放置剪辑 |
| `determineAssetHasAudio` 编号 : `probeHasAudio` | 视频是否带有音频音轨 |
| `serializeProject` 编号 : `deserializeProject` | 将引擎项目保存为 JSON 并装入返回( 外观) `readProjectDocument`(中文(简体) ) |
| `readProjectDocument` 编号 : `relinkProjectMedia` | 验证存储的文档为 `Project`; 在媒体库重新点回剪辑 |
| `BUILT_IN_TEXT_TEMPLATES` 编号 : `applyTextTemplate` | 14个文本带有分层出入口运动; `applyTextTemplate(template, clip)` 返回可撤销的 `Partial<Clip>` 补丁 |
| `sampleTextAnimation` | 文字/形状出入境动画纯采样器(`TextAnimation`, (中文(简体) ), `MotionSpec`(中文(简体) ) |
| `createFrameSequence` 编号 : `FrameSequenceController` | 有序的图像集(360°轨道,故事板),并有洗涤、回转和预装; `frameSequenceToProject` 使一个可编辑 |
| `snapshotMediaLibrary` 编号 : `hydrateMediaLibrary` | 将媒体库变成可存储的条目, 并在页面装入后放回( 身份保存); 存储为您的 |
| `sourceBlobCache` | 共享缓存, 该缓存可以在调试器和预览之间复制视频下载 |
| `PerfSummary` | 一次一秒渲染成本汇总; 沉默, 除非 `PERF` 追踪通道已打开 |
| `exportVideo` | 通过网络工作者导出时间表: MP4( 默认), WebM, GIF 或 PNG 序列 |
| `Clip.keyframes`, (中文(简体) ), `TEXT_ANIMATION_EASINGS`, (中文(简体) ), `SPRING_PRESETS`, (中文(简体) ), `MOTION_PRESETS` | 运动层:每个变换通道上的键框,31个被命名的易行加立方位贝,步和弹簧相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相接相 [动议](https://npmcn.com/package/%40elah/core/#readme-motion-keyframes-springs-stagger-paths)(中文(简体) ) |
| `createGenerator`, (中文(简体) ), `GENERATOR_REGISTRY` | 发电机剪辑:粒子、能量线、光泄漏、镜头照明、梯度背景、计数器、条形图、进度栏 |
| `EFFECT_REGISTRY`, (中文(简体) ), `EFFECT_BUNDLES` | 23 GPU效应、捆绑和外观; `adjustment` 剪辑应用到下面的每件事 |
| `TRANSITION_REGISTRY` | 九次过渡,按摘取顺序 |
| `createCompoundClip`, (中文(简体) ), `nestClips`, (中文(简体) ), `createSequenceClip` | 复合剪辑(嵌入式项目为一剪辑)和序列剪辑(动画图像或编号帧) |
| `Clip.audio`, (中文(简体) ), `clipAudioGain`, (中文(简体) ), `enhancePlan` | 静音、振动、淡出和增强;一个用于预览和导出的信封 |
| `svgToProject`, (中文(简体) ), `lottieToClip` | 导入 SVG 和 Lottie 作为可编辑剪辑和密钥 |
| `validateScene`, (中文(简体) ), `sceneToClip` (从) `@elah/core/html`(中文(简体) ) | **活着.** HTML/CSS 场景子集:验证,然后将一个测量的场景转换为一个复合剪辑 |
| `compileVideoSpec`, (中文(简体) ), `buildVideo`, (中文(简体) ), `layProject`, (中文(简体) ), `specVocabulary` (从) `@elah/core/spec`(中文(简体) ) | **活着.** VideoSpec: 一个基于秒的 JSON 文档, 一个模型写, 编译到一个 `Project` |
| `applyOps`, (中文(简体) ), `sanitizeOps`, (中文(简体) ), `EDITOR_OP_NAMES`, (中文(简体) ), `describeProject` (从) `@elah/core/ops`(中文(简体) ) | **活着.** 57 键入编辑器对编辑工程的模型的操作 |
| `packageFontsBaseUrl` | 包内12个捆绑字体的自有拷贝所住之处( opt- in) |

这些商店 **香草** (单位:千美元)`zustand/vanilla`)——无反应,可从任何地方分出(`store.getState()`, (中文(简体) ), `store.subscribe()`) (中文(简体) ). 他们也是 **模块级单数**页:1 `tracksStore`,一个 `playbackStore`等,根据JS领域. `@elah/editor`是因为 `<EditorProvider>` 每个线 `TimelineEngine`编号 :`PlaybackEngine` 因此只允许 **每页一个活动项目** 今天得到支持的有: `<EditorProvider>` (或两台手动接线发动机)一并会让它们覆盖商店中彼此的状态. 一个页面上的多个独立编辑器需要单独的标签/框架/窗口,直到范围商店登陆.

* * *

## 快开始

```ts
import { TimelineEngine, PlaybackEngine, resolveTimeline } from '@elah/core'

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

// Add a track, then a clip onto it. addClip takes a single typed
// options object (a discriminated union keyed on `type`) and returns the Clip.
const track = engine.addTrack('video')
engine.addClip({ trackId: track.id, type: 'video', src: 'video.mp4', startFrame: 0, durationFrames: 90 })

// Resolve the scene at frame 15 — pure (frame, project) → Scene.
const scene = resolveTimeline(15, engine.getProject())
```

* * *

## 使用没有浏览器的引擎

`@elah/core/engine` 是无浏览器子集:引擎,解析器, `PlaybackEngine`,则 商店、剪接厂、项目文件 以及纯粹的放置和时间表数学 它离开 退出 WebGL2 渲染器、 WebCodecs 解码器、媒体导入器和 MP4 导出器,即 使用一个模块 `import.meta`。使用来自 React 本地(Metro 和 Hermes 拒绝) `import.meta`, (中文(简体) ), 工人,或节点:

```ts
import { TimelineEngine, resolveTimeline } from '@elah/core/engine'
```

两个条目共享模块实例,所以 `tracksStore` 从任意一个对象都是一样的。 测试, `src/engine.no-browser.test.ts`,如果浏览器所绑定的任何东西从中可以到达,则失败.

* * *

## 保存并恢复

`serializeProject` 编号 : `deserializeProject` 是简单的一对。 在他们下面, `readProjectDocument` 是总读取器: 它返回 a `Project` 或掷出 `ProjectDocumentError` (单位:千美元)`code: 'unreadable' | 'unsupported-version'`从不半 项目。 无文件 `version` 印花读取为 第 1 版; 1 从更新的 建筑(`PROJECT_VERSION`,现在5)被拒绝. 项目印有 _最低_ 版本可以 持有它用的东西: 2 `adjustment` 剪贴板; 3 个用于生成器、形状绘图和6个更新的 过渡; 4 为复合夹; 5 为序列夹. 一个没有使用它们的项目仍然 1版并开通于0.6.x.

```ts
import {
  serializeProject, deserializeProject,
  readProjectDocument, relinkProjectMedia, missingMediaSummary,
} from '@elah/core'

const json = serializeProject(engine)
deserializeProject(engine, json) // throws, leaving the engine untouched, if unreadable

// Or in two steps, so a refusal can be shown before the editor is cleared:
const project = readProjectDocument(JSON.parse(json))
engine.loadProject(project) // options: { transport?: 'rewind' | 'keep', history?: 'reset' | 'keep' }

// Media imported from disk is a blob: URL and does not survive a reload.
// After the library is rebuilt, repair the clips' assetIds and report what is gone:
const { project: repaired, relinked, missing } = relinkProjectMedia(engine.getProject(), assets)
engine.loadProject(repaired, { transport: 'keep', history: 'keep' })
const note = missingMediaSummary(missing) // e.g. "a.mp4, b.mp4 and 3 more"
```

引擎发射 `project:loaded` (单位:千美元)`ProjectLoadedEvent`每次载货后 新项目和要求 `transport`。 。 。 .

* * *

## 文本模板和动画

```ts
import { BUILT_IN_TEXT_TEMPLATES, findTextTemplate, applyTextTemplate } from '@elah/core'

const template = findTextTemplate(BUILT_IN_TEXT_TEMPLATES[0].id)!
engine.updateClip(clip.id, trackId, applyTextTemplate(template, clip)) // one undo entry
```

应用模板是干净的,不是累积的:模板不使用的字段是 清除. `TextAnimation` 保持单类型 `in`编号 :`out` enum并添加 `inMotion` 编号 : `outMotion` 联合国 `MotionSpec`数字 : `opacity`, (中文(简体) ), `offsetX`, (中文(简体) ), `offsetY`, (中文(简体) ), `scale`, (中文(简体) ), `rotation`, (中文(简体) ), `ease`, (中文(简体) ), `opacityEase`)),在出现时替换了enum.

模板携带的两样东西 **只有数据**数字 : `stagger` (将一行打入剪辑中) 和 `tracking` (假字母间距. `applyTextTemplate` 忽略 并且这些包里没有任何东西能运行它们 模板本身.

* * *

## 过渡

```ts
engine.addTransition({ fromClipId, toClipId, trackId, kind: 'slide', durationFrames: 12, direction: 'left' })
```

`kind` 是九项之一: `'fade' | 'slide' | 'wipe' | 'zoom' | 'spin' | 'whip' | 'glitchCut' | 'warpDissolve' | 'lumaWipe'` (单位:千美元)`TRANSITION_REGISTRY` 以标签和提示列出它们. `slide` 财务报告和审定财务报表 `whip` 带一个 `direction` (单位:千美元)`'left' | 'right' | 'up' | 'down'`,默认正确);其他人则忽略它。 解脱者保留两者 在现场的片断和列表中的过渡 `scene.transitions` 进展减缓 WebGL2 渲染器将配对用一个阴影来合成,所以两个片段都继续播放效果,在 预览和导出中。 仅使用的项目 `fade`, (中文(简体) ), `wipe` 财务报告和审定财务报表 `slide` 仍然在运行中出口工人 没有WebGL2(一个2D快照路径,只有左/右幻灯片);一个使用任何其他类型需要WebGL2的工程 没有它,它的出口会很快失败 除了前三张邮票之外,任何种类的项目都是 文档版本3.

* * *

## 运动:键框、弹簧、交错、路径

动画是剪辑上的数据. 键框为整数 **相对于片段的开始**,这样移动 一个剪辑会移动它的键; 修剪, 速度和拆分重映射它们.

```ts
engine.updateClip(title.id, trackId, {
  keyframes: {
    channels: {
      x: {
        source: { kind: 'keyframes' },
        keys: [
          { id: 'k0', frame: 0, value: 0.2, easing: 'linear' },
          { id: 'k1', frame: 30, value: 0.8, easing: 'back-out' }, // the curve INTO this key
        ],
      },
    },
  },
})
```

钥匙 `easing` 这是其中之一 `TEXT_ANIMATION_EASINGS` (正、正、正、正、正、正、正、正、正、正、正), 反,弹性和回弹, 每一个在/出/出,和 `linear`) (中文(简体) ). 钥匙可以带生 `easingBezier`, (中文(简体) ), `steps` (楼梯), `hold`,或封闭式 `spring` (单位:千美元)`SPRING_PRESETS`温柔地, 发作 发作 发作 发作 写密钥的纯助手( E)`setKeysEasingAtFrame`, (中文(简体) ), `moveKeysAtFrame`, (中文(简体) ), `repeatKeysPatch` 重复和优雅, `staggerOffsets` 开始交错, 端口、中心、边缘或随机和横跨网格, `scrambleText`)和36项 `MOTION_PRESETS` 是公开的. 颜色和路径通道也可以键入,以及 `setChannelExpression` 从一个频道驱动一个频道 表达式 (`wiggle`, (中文(简体) ), `loop`, (中文(简体) ), `sin`,等等).

扭曲( S)`skewX`, (中文(简体) ), `skewY`)是一个可键入的信道。 3D 倾斜`rotateX`, (中文(简体) ), `rotateY`视频、图像、, 在文字、形状和自由手上拒绝。 剪辑也可以走路径 (单位:千美元) `motion.progress` (原始内容存档于2018-10-25). Channel. 单行 `data-motion` hTML 场景层读取的语法 由同一键构建.

* * *

## 新的剪辑类型、效果和发电机

```ts
import { createGenerator } from '@elah/core'

const confetti = engine.addClip({
  trackId, type: 'generator', name: 'Confetti', startFrame: 0, durationFrames: 90,
  generator: createGenerator('particles', { count: 80 }),
})
const grade = engine.addClip({ trackId: overlayTrackId, type: 'adjustment', name: 'Grade', startFrame: 0, durationFrames: 90 })
```

-   **`adjustment`**:没有自己的相片;其效果,遮盖和混合适用于其下的所有复合体.
-   **`generator`**: 8个`GENERATOR_REGISTRY`) (中文(简体) ).
-   **`compound`**:一个嵌入式项目作为一段播放(`createCompoundClip`· ; `engine.nestClips` 编号 : `unnestClip` 将一个选择变成一个并返回; 巢穴封顶于 `MAX_COMPOUND_DEPTH`) (中文(简体) ).
-   **`sequence`**: 动画相片或编号相框集,由相框索引选择,所以预览并导出显示相同的相框.

效果是23个GPU通行证(`EFFECT_REGISTRY`:颜色分级,加乌西模糊,花纹,谷物,RGB分出, 开花、发光、镜头和波浪扭曲、VHS、CRT、故障、像素、运动模糊等) `EFFECT_BUNDLES` 如一击外观,加上口罩,跟踪垫和混合模式. 使用这些提升 文档版本(见 [保存并恢复](https://npmcn.com/package/%40elah/core/#readme-save-and-restore)) (中文(简体) ). `@elah/editor` 播放、保存和导出 这些剪辑;它还没有编辑它们的UI.

* * *

## 模型的场景和视频Spec(活于1.0)

一个模型写出一个视频的两种方式,该视频作为普通,可编辑的片段登陆. 两者都是 **现场直播** 在1.0中,在他们自己的条目上,所以根保持小.

-   **HTML/CSS 场景** (单位:千美元)`import { validateScene, sceneToClip } from '@elah/core/html'`:模型在一个白列子集中写出一个HTML片段和一个样式表. `validateScene({ html, css })` 返回指定所支持的替换符的违反. `sceneToClip(measuredScene, { fps })` 转换浏览器..**测量** 场景(框,换行符) 和已解析的样式)收成一个由本地剪辑和密钥组成的复合剪辑. 衡量是东道方的工作; 这个包裹没有DOM测量器.
-   **视频Spec** (单位:千美元)`from '@elah/core/spec'`: 一个基于秒的JSON文档. `compileVideoSpec(spec)` 返回时 `{ project, issues }` 永不抛掷; `buildVideo(authoredSpec)` 还可扩大组件和抛光; `layProject(engine, project)` 将结果放入活的发动机上,作为倒转的一步; `specVocabulary()` 使词汇块迅速.

工作、测试过的例子 [`docs/ai/ELAH_FOR_AI_AGENTS.md`](https://github.com/elahlabs/elah/blob/main/docs/ai/ELAH_FOR_AI_AGENTS.md#11-writing-videos-and-scenes-with-a-model)。 。 。 . 编辑会通过输入的操作( E)`from '@elah/core/ops'`: `sanitizeOps(raw, project)` 修复模型的操作列表和 `applyOps(engine, ops)` 应用它作为倒数一步.

* * *

## 从 CDN 装入字体

文本片段命名了12个捆绑家庭(`FONT_REGISTRY`: Inter、蒙特塞拉特、波平斯、克罗特斯克航天公司、, Playfair Display、DM Serif Display、Bebas Neue、Anton、Oswald、Archivo Black、Roboto Mono、Caveat; 拉丁语 只有子集,SIL OFL 1.1。 默认是从 `/fonts/` 打开 **** 主持人。 Woff2文件飞船 此套件下 `fonts/<id>/`,所以,无论复制文件夹到您的公众 `fonts/` 目录,或 未捆绑的导入( CDN, 本地- ESM dev 服务器) , 将装载器指向包本身 :

```ts
import { exportVideo, packageFontsBaseUrl } from '@elah/core'

await exportVideo(project, { fonts: { baseUrl: packageFontsBaseUrl() } })
```

导出、音频分析和能力测试工作者从一个跨源模块URL开始,通过一个 blob 模块工人(jsDelivr) `/+esm` 包含构建; 捆绑的主机为普通 `new Worker(new URL(...))` 路径。 使用 `packageFontsBaseUrl()` 只用于未捆绑的导入: 捆绑器重写 `import.meta.url`。 。 。 .

* * *

## 框架序列

```ts
import { createFrameSequence, frameSequenceToProject } from '@elah/core'

const seq = createFrameSequence({ frames: urls.map((src) => ({ src })), fps: 12, loop: 'wrap' })
engine.loadProject(frameSequenceToProject(seq, { holdFrames: 6 })) // edit/export as image clips
```

`FrameSequenceController` 从时钟或拖动驱动序列; `createFramePreloader` 温度比指数高; `pickFrameSource` 选择 合适的候选人.

* * *

## 剪贴和跟踪字段

| 外地 | 适用于 | 含义 |
| --- | --- | --- |
| `Clip.speed` | 视频 | 回放乘数,被夹到0.25-4(`engine.setClipSpeed`; 时间长度随之而来 |
| `Clip.crop` | 视频,图像 | 规范化源窗口 `{ x, y, width, height }`; 见 `normalizeCrop`, (中文(简体) ), `FULL_CROP` |
| `Clip.cornerRadius` | 视频,图像 | 圆角口罩,0-0.5分短边 |
| `Track.protected` | 任意 | 用户无法删除音轨 |
| `Track.pinned` | 任意 | `'bottom'` 将车道保持在每道没有固定的轨道下方; `addTrack` 很荣幸 |

允许任何数量的视频音轨;它们按照音轨顺序复合,最上行道位于上方.

* * *

## 将媒体库保存在页面上

```ts
import {
  mediaLibraryStore, snapshotMediaLibrary, hydrateMediaLibrary, refreshMissingThumbnails,
} from '@elah/core'

// Save: plain entries (assets still being probed are skipped). Where they go is up to you.
const entries = snapshotMediaLibrary(mediaLibraryStore.getState())

// Restore: ids are kept, so restored clips resolve their `assetId` directly.
const { hydrated, needsThumbnail } = hydrateMediaLibrary(entries, {
  referencedSrcs: new Set(/* every media clip's src in the project being opened */),
})
refreshMissingThumbnails(needsThumbnail) // cosmetic, fire-and-forget
```

这只包含资产元数据和缩略图 。 从磁盘导入的文件是 `blob:` 網址 随会话而死亡;其字节没有被存储,以及 `relinkProjectMedia` 报告 剪辑为 `missing`。 。 。 .

* * *

## 诊断

```ts
import { PerfSummary } from '@elah/core'
// In the browser console: __trace.on('PERF') turns the once-a-second summary on.
```

`PerfSummary` 计算整个数据勾选(阶段时间、预算超支),而不是 只是GPU上传。 它没有分配,而 `PERF` 频道关闭了.

* * *

## 剪接厂

返回完全正常状态的独立建设者 `Clip` 对象( 四舍五入的框架、 默认音量/ opacity, 生成 id) 没有引擎—— 可用于输入的无头管 `resolveTimeline` 直接说 当你有了引擎,更喜欢 `engine.addClip(options)` 相反,它构建了剪辑并记录了一个倒数的条目.

```ts
import {
  createVideoClip,
  createAudioClip,
  createTextClip,
  createImageClip,
  createShapeClip,
  createFreehandClip,
} from '@elah/core'

const clip = createVideoClip({ trackId: 'v1', src: 'video.mp4', startFrame: 0, durationFrames: 90 })
const rect = createShapeClip({
  trackId: 'el1',
  startFrame: 0,
  durationFrames: 90,
  shape: { shapeKind: 'rect', shapeFill: '#22d3ee' }, // 'rect' | 'circle' | 'triangle'
})
```

* * *

## 导出

```ts
import { exportVideo } from '@elah/core'

const blob = await exportVideo(engine.getProject(), {
  videoBitrate: 8_000_000,
  outputHeight: 1080, // short edge — optional, defaults to the stage's own
  onProgress: ({ frame, totalFrames }) => console.log(frame, '/', totalFrames),
})
```

`outputHeight` 这是舞台的 _简称_ 边 (`1080` =1920×1080或1080×1920;另一条 边沿宽度比,并按解码器的要求四舍五入到平数.

`container` 选择输出 : `'mp4'` (违约), `'webm'` (编) `transparent: true` 对于一个α通道,只有在 浏览器自己的编码和解码检查通过, `'gif'` (单位:千美元)`gifFps`,默认为 15,没有音频)或 `'png-sequence'` (a ZIP,或你自己的) `frameSink`) (中文(简体) ). `videoCodec` 实值 `'avc' | 'hevc' | 'av1' | 'vp9' | 'vp8'` 其中浏览器可以编码它,以及 `range: 'inOut'` 只导出已标记的入出范围。 导出需要 WebCodes 和 `OffscreenCanvas`:在实际操作中为Chrome或Edge.

* * *

## 链接

-   [网站](https://www.elah.dev/)
-   [GitHub 图像](https://github.com/elahlabs/elah)
-   [反应绑定 — @ elah/ react](https://www.npmjs.com/package/@elah/react)
-   [完整 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/core 是什么？

框架不可知视频时间表引擎——回放,帧分辨率,WebGL2渲染器以及媒体管理

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

在项目目录运行 npm install @elah/core，或使用 pnpm add / yarn add / bun add。

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

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

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

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

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

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

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

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

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

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

