@elah/editor 0.3.1 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -16,7 +16,9 @@ Ships `EditorProvider`, `Preview` (WebGL2 canvas + interactive transform overlay
16
16
  npm install @elah/editor
17
17
  ```
18
18
 
19
- Peer dependencies: `react`, `react-dom` >= 18.
19
+ Peer dependencies: `react`, `react-dom` >= 18, `lucide-react` >= 0.400.0 (used by the
20
+ bundled `@elah/timeline` UI for clip icons — install it alongside `react`/`react-dom`
21
+ even though nothing in your own code imports it).
20
22
 
21
23
  **Bundle size:** ~10 KiB gzipped for the editor layer (51 KiB raw); ~63 KiB gzipped for the full SDK graph (`core` + `timeline` + `editor`, 330 KiB raw). `mediabunny` is injected, never bundled — see [BUNDLE_STRATEGY.md](../../BUNDLE_STRATEGY.md).
22
24
 
@@ -142,12 +144,26 @@ Runs in a web worker. Reuses `resolveTimeline` + the GPU renderer's placement ma
142
144
  ## Package layers
143
145
 
144
146
  ```
145
- @elah/core — engine, playback, resolver, stores, media, export (framework-agnostic)
146
- @elah/timeline — React timeline UI components and hooks
147
- @elah/editor — EditorProvider, Preview, AssetPanel + re-exports everything above
147
+ @elah/core — engine, playback, resolver, vanilla stores, media, export (framework-agnostic)
148
+ @elah/react — React bindings: EditorContext, store hooks, audio hooks
149
+ @elah/timeline — React timeline UI components and hooks (consumes @elah/core + @elah/react)
150
+ @elah/editor — EditorProvider, Preview, AssetPanel + re-exports @elah/core, @elah/react, @elah/timeline
151
+ @elah/cli — headless split/trim/build/export/serve on top of @elah/core
148
152
  ```
149
153
 
150
- Use `@elah/editor` for the full experience. Use `@elah/core` directly for headless or custom rendering pipelines.
154
+ Use `@elah/editor` for the full in-browser experience. Use `@elah/core` directly
155
+ for headless or custom rendering pipelines, or pair it with `@elah/react` if you
156
+ want the hooks without the timeline UI. Use `@elah/cli` for automation,
157
+ AI-generation pipelines, and server-side rendering.
158
+
159
+ **One active project per page.** `@elah/core`'s stores (`tracksStore`,
160
+ `playbackStore`, `selectionStore`, `transitionsStore`, `mediaLibraryStore`) are
161
+ module-level singletons, and `<EditorProvider>` wires the `TimelineEngine` /
162
+ `PlaybackEngine` it creates into those same shared stores. Mounting a second
163
+ `<EditorProvider>` on the same page (two independent projects at once) will have
164
+ both instances overwrite each other's state — there is currently no per-instance
165
+ scoping. If you need multiple concurrent editors, isolate each in its own
166
+ tab/window/iframe.
151
167
 
152
168
  ---
153
169
 
@@ -156,5 +172,6 @@ Use `@elah/editor` for the full experience. Use `@elah/core` directly for headle
156
172
  - [Website](https://www.elah.dev)
157
173
  - [GitHub](https://github.com/elahlabs/elah)
158
174
  - [Discord](https://discord.gg/8CeZ2XbPy)
175
+ - [Headless CLI — @elah/cli](https://www.npmjs.com/package/@elah/cli)
159
176
  - [License](https://github.com/elahlabs/elah/blob/main/LICENSE)
160
177
  - [Commercial licensing](mailto:paul@elah.dev)
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState, } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { importFiles, importUrl, MEDIA_DRAG_MIME, mediaDragKindMime, useMediaLibrary, useMediaLibraryStore, } from '@elah/core';
4
+ import { importFiles, importUrl, MEDIA_DRAG_MIME, mediaDragKindMime, } from '@elah/core';
5
+ import { useMediaLibrary, useMediaLibraryStore } from '@elah/react';
5
6
  import { cn } from '@elah/timeline';
6
7
  import { isActivationKey, useAssetActivation, } from '../activation';
7
8
  const KIND_ICONS = {
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useEffect, useMemo } from 'react';
3
- import { TimelineEngine, PlaybackEngine, useTracksStore, usePlaybackStore, useTransitionsStore, EditorContext, installTraceGlobal, trace, } from '@elah/core';
3
+ import { TimelineEngine, PlaybackEngine, installTraceGlobal, trace, } from '@elah/core';
4
+ import { useTracksStore, usePlaybackStore, useTransitionsStore, EditorContext, } from '@elah/react';
4
5
  export function EditorProvider({ fps, stage, defaultTrackHeight, maxHistorySize, initialTracks, children, }) {
5
6
  const engine = useMemo(() => new TimelineEngine({
6
7
  fps,
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useLayoutEffect, useMemo, useRef, useState, } from 'react';
3
- import { useTimelineEngine, useSelectionStore, usePlaybackStore, useMediaLibraryStore, resolveDrawRect, transformFromContainRect, computeContainViewport, } from '@elah/core';
3
+ import { resolveDrawRect, transformFromContainRect, computeContainViewport, } from '@elah/core';
4
+ import { useTimelineEngine, useSelectionStore, usePlaybackStore, useMediaLibraryStore, } from '@elah/react';
4
5
  import { useResolvedScene } from '../useResolvedScene';
5
6
  const MIN_BOX_PX = 28;
6
7
  const BOX_PAD = 0;
@@ -2,8 +2,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { forwardRef, useEffect, useImperativeHandle, useRef, } from 'react';
3
3
  import { GpuRenderer } from '@elah/core';
4
4
  import { resolveTimeline } from '@elah/core';
5
- import { useTimelineEngine, usePlaybackEngine } from '@elah/core';
6
- import { AudioPlaybackController, useMediaLibraryStore, preloadProjectImages, warmImageSrc } from '@elah/core';
5
+ import { useTimelineEngine, usePlaybackEngine, useMediaLibraryStore } from '@elah/react';
6
+ import { AudioPlaybackController, preloadProjectImages, warmImageSrc } from '@elah/core';
7
7
  import { cn } from '@elah/timeline';
8
8
  import { TextOverlay } from './TextOverlay';
9
9
  import { ShapeOverlay } from './ShapeOverlay';
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useLayoutEffect, useMemo, useRef, useState, } from 'react';
3
- import { useTimelineEngine, useSelectionStore, usePlaybackStore, computeContainViewport, } from '@elah/core';
3
+ import { computeContainViewport } from '@elah/core';
4
+ import { useTimelineEngine, useSelectionStore, usePlaybackStore, } from '@elah/react';
4
5
  import { useResolvedScene } from '../useResolvedScene';
5
6
  const DEFAULT_SCALE = 0.5;
6
7
  const DEFAULT_CENTER = 0.5;
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { useLayoutEffect, useMemo, useRef, useState } from 'react';
3
- import { computeContainViewport, useTracksStore } from '@elah/core';
3
+ import { computeContainViewport } from '@elah/core';
4
+ import { useTracksStore } from '@elah/react';
4
5
  export function StageBorder() {
5
6
  const rootRef = useRef(null);
6
7
  const [size, setSize] = useState({ width: 0, height: 0 });
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, } from 'react';
3
- import { computeTextLayout, computeContainViewport, useTimelineEngine, useSelectionStore, usePlaybackStore, SIDE_MARGIN, } from '@elah/core';
3
+ import { computeTextLayout, computeContainViewport, SIDE_MARGIN, } from '@elah/core';
4
+ import { useTimelineEngine, useSelectionStore, usePlaybackStore, } from '@elah/react';
4
5
  import { useResolvedScene } from '../useResolvedScene';
5
6
  const MIN_FONT_SIZE = 6;
6
7
  const MAX_FONT_SIZE = 4000;
@@ -1,7 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useCallback, useEffect, useRef, useState, } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { importFiles, importUrl, MEDIA_DRAG_MIME, mediaDragKindMime, useMediaLibrary, useMediaLibraryStore, } from '@elah/core';
4
+ import { importFiles, importUrl, MEDIA_DRAG_MIME, mediaDragKindMime, } from '@elah/core';
5
+ import { useMediaLibrary, useMediaLibraryStore } from '@elah/react';
5
6
  import { ELEMENT_DRAG_MIME, cn } from '@elah/timeline';
6
7
  import { isActivationKey, useAssetActivation, } from '../activation';
7
8
  const KIND_ICONS = { video: '▶', audio: '♪', image: '◻' };
@@ -1,4 +1,4 @@
1
- import { type MediaAsset } from '@elah/core';
1
+ import type { MediaAsset } from '@elah/core';
2
2
  import { type ElementKind, type ShapeVariant } from '@elah/timeline';
3
3
  export interface ActivationToast {
4
4
  message: string;
@@ -1,5 +1,5 @@
1
1
  import { useCallback, useContext } from 'react';
2
- import { EditorContext } from '@elah/core';
2
+ import { EditorContext } from '@elah/react';
3
3
  import { insertElement, insertMediaAsset, } from '@elah/timeline';
4
4
  export function isActivationKey(key) {
5
5
  return key === 'Enter' || key === ' ';
@@ -1,5 +1,6 @@
1
1
  import { useMemo, useRef } from 'react';
2
- import { useTimelineEngine, useTracksStore, usePlaybackStore, resolveTimeline, } from '@elah/core';
2
+ import { resolveTimeline } from '@elah/core';
3
+ import { useTimelineEngine, useTracksStore, usePlaybackStore, } from '@elah/react';
3
4
  export function useResolvedScene(frameOverride) {
4
5
  const engine = useTimelineEngine();
5
6
  const playbackFrame = usePlaybackStore((s) => (s.isPlaying ? null : s.currentFrame));
package/dist/index.d.ts CHANGED
@@ -18,11 +18,12 @@ export { AudioPlaybackController } from '@elah/core';
18
18
  export type { AudioPlaybackControllerOptions } from '@elah/core';
19
19
  export { defaultAudioResolver } from '@elah/core';
20
20
  export type { AudioResolver } from '@elah/core';
21
- export { useMediaLibrary, useMediaLibraryStore, MEDIA_DRAG_MIME, mediaDragKindMime, importFiles, importUrl } from '@elah/core';
21
+ export { MEDIA_DRAG_MIME, mediaDragKindMime, importFiles, importUrl } from '@elah/core';
22
+ export { useMediaLibrary, useMediaLibraryStore } from '@elah/react';
22
23
  export type { MediaAsset, MediaKind, DragMediaPayload, ImportFilesOptions, ImportFilesResult, SkippedImport } from '@elah/core';
23
- export { useTracksStore } from '@elah/core';
24
- export { usePlaybackStore } from '@elah/core';
25
- export { useSelectionStore } from '@elah/core';
24
+ export { useTracksStore } from '@elah/react';
25
+ export { usePlaybackStore } from '@elah/react';
26
+ export { useSelectionStore } from '@elah/react';
26
27
  export { createVideoClip } from '@elah/core';
27
28
  export { createAudioClip } from '@elah/core';
28
29
  export { createTextClip } from '@elah/core';
@@ -48,7 +49,9 @@ export { ELEMENT_DRAG_MIME } from '@elah/timeline';
48
49
  export type { DragElementPayload, ElementKind, ShapeVariant, InsertAssetOptions, InsertAssetResult, InsertAssetFailureReason, InsertedKind, } from '@elah/timeline';
49
50
  export { EditorProvider } from './editor/EditorProvider';
50
51
  export type { EditorProviderProps } from './editor/EditorProvider';
51
- export { useEditor, useTimelineEngine, usePlaybackEngine } from '@elah/core';
52
+ export { useEditor, useTimelineEngine, usePlaybackEngine } from '@elah/react';
53
+ export { useAudioMixer, useMasterVolume, useTrackLevels } from '@elah/react';
54
+ export type { AudioMixerApi, MasterVolumeApi, TrackLevel } from '@elah/react';
52
55
  export { useResolvedScene } from './editor/useResolvedScene';
53
56
  export { AssetPanel } from './editor/AssetPanel';
54
57
  export type { AssetPanelProps } from './editor/AssetPanel';
package/dist/index.js CHANGED
@@ -7,10 +7,11 @@ export { createDefaultDemuxerFactory, createMediabunnyBackend, isMediabunnyCompa
7
7
  export { createVideoFrameProvider, MockVideoFrameProvider, SyntheticVideoFrameProvider } from '@elah/core';
8
8
  export { AudioPlaybackController } from '@elah/core';
9
9
  export { defaultAudioResolver } from '@elah/core';
10
- export { useMediaLibrary, useMediaLibraryStore, MEDIA_DRAG_MIME, mediaDragKindMime, importFiles, importUrl } from '@elah/core';
11
- export { useTracksStore } from '@elah/core';
12
- export { usePlaybackStore } from '@elah/core';
13
- export { useSelectionStore } from '@elah/core';
10
+ export { MEDIA_DRAG_MIME, mediaDragKindMime, importFiles, importUrl } from '@elah/core';
11
+ export { useMediaLibrary, useMediaLibraryStore } from '@elah/react';
12
+ export { useTracksStore } from '@elah/react';
13
+ export { usePlaybackStore } from '@elah/react';
14
+ export { useSelectionStore } from '@elah/react';
14
15
  export { createVideoClip } from '@elah/core';
15
16
  export { createAudioClip } from '@elah/core';
16
17
  export { createTextClip } from '@elah/core';
@@ -30,7 +31,8 @@ export { useTimelineDrop } from '@elah/timeline';
30
31
  export { insertMediaAsset, insertElement } from '@elah/timeline';
31
32
  export { ELEMENT_DRAG_MIME } from '@elah/timeline';
32
33
  export { EditorProvider } from './editor/EditorProvider';
33
- export { useEditor, useTimelineEngine, usePlaybackEngine } from '@elah/core';
34
+ export { useEditor, useTimelineEngine, usePlaybackEngine } from '@elah/react';
35
+ export { useAudioMixer, useMasterVolume, useTrackLevels } from '@elah/react';
34
36
  export { useResolvedScene } from './editor/useResolvedScene';
35
37
  export { AssetPanel } from './editor/AssetPanel';
36
38
  export { ElementsPanel } from './editor/ElementsPanel';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elah/editor",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "description": "Full React video editor SDK — timeline UI, WebGL2 preview, media library, drag and drop, and MP4 export",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -55,11 +55,13 @@
55
55
  "license": "Apache-2.0",
56
56
  "peerDependencies": {
57
57
  "react": ">=18.0.0",
58
- "react-dom": ">=18.0.0"
58
+ "react-dom": ">=18.0.0",
59
+ "lucide-react": ">=0.400.0"
59
60
  },
60
61
  "dependencies": {
61
- "@elah/core": "^0.3.0",
62
- "@elah/timeline": "^0.3.0",
62
+ "@elah/core": "^0.4.0",
63
+ "@elah/react": "^0.4.0",
64
+ "@elah/timeline": "^0.4.0",
63
65
  "immer": "^10.1.1",
64
66
  "zustand": "^5.0.3"
65
67
  },
@@ -67,6 +69,7 @@
67
69
  "@types/react": "^18.3.18",
68
70
  "@types/react-dom": "^18.3.5",
69
71
  "autoprefixer": "^10.4.21",
72
+ "lucide-react": "^0.511.0",
70
73
  "postcss": "^8.5.3",
71
74
  "tailwindcss": "^3.4.17",
72
75
  "typescript": "^5.7.3",