framewebworker 0.1.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.
@@ -0,0 +1,120 @@
1
+ 'use strict';
2
+
3
+ var react = require('react');
4
+
5
+ // src/react/useRender.ts
6
+ function useRender(frameWorker) {
7
+ const [state, setState] = react.useState({
8
+ progress: 0,
9
+ isRendering: false,
10
+ error: null,
11
+ blob: null,
12
+ url: null
13
+ });
14
+ const abortRef = react.useRef(null);
15
+ const urlRef = react.useRef(null);
16
+ const cancel = react.useCallback(() => {
17
+ abortRef.current?.abort();
18
+ }, []);
19
+ const reset = react.useCallback(() => {
20
+ if (urlRef.current) {
21
+ URL.revokeObjectURL(urlRef.current);
22
+ urlRef.current = null;
23
+ }
24
+ setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });
25
+ }, []);
26
+ const render = react.useCallback(
27
+ async (clip, options) => {
28
+ if (urlRef.current) {
29
+ URL.revokeObjectURL(urlRef.current);
30
+ urlRef.current = null;
31
+ }
32
+ const controller = new AbortController();
33
+ abortRef.current = controller;
34
+ setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });
35
+ try {
36
+ const blob = await frameWorker.render(clip, {
37
+ ...options,
38
+ signal: controller.signal,
39
+ onProgress: (p) => {
40
+ setState((prev) => ({ ...prev, progress: p }));
41
+ }
42
+ });
43
+ const url = URL.createObjectURL(blob);
44
+ urlRef.current = url;
45
+ setState({ progress: 1, isRendering: false, error: null, blob, url });
46
+ return blob;
47
+ } catch (err) {
48
+ if (err instanceof DOMException && err.name === "AbortError") {
49
+ setState((prev) => ({ ...prev, isRendering: false, error: null }));
50
+ return null;
51
+ }
52
+ const error = err instanceof Error ? err : new Error(String(err));
53
+ setState((prev) => ({ ...prev, isRendering: false, error }));
54
+ return null;
55
+ }
56
+ },
57
+ [frameWorker]
58
+ );
59
+ return { ...state, render, cancel, reset };
60
+ }
61
+ function useStitch(frameWorker) {
62
+ const [state, setState] = react.useState({
63
+ progress: 0,
64
+ isRendering: false,
65
+ error: null,
66
+ blob: null,
67
+ url: null
68
+ });
69
+ const abortRef = react.useRef(null);
70
+ const urlRef = react.useRef(null);
71
+ const cancel = react.useCallback(() => {
72
+ abortRef.current?.abort();
73
+ }, []);
74
+ const reset = react.useCallback(() => {
75
+ if (urlRef.current) {
76
+ URL.revokeObjectURL(urlRef.current);
77
+ urlRef.current = null;
78
+ }
79
+ setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });
80
+ }, []);
81
+ const stitch = react.useCallback(
82
+ async (clips, options) => {
83
+ if (urlRef.current) {
84
+ URL.revokeObjectURL(urlRef.current);
85
+ urlRef.current = null;
86
+ }
87
+ const controller = new AbortController();
88
+ abortRef.current = controller;
89
+ setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });
90
+ try {
91
+ const blob = await frameWorker.stitch(clips, {
92
+ ...options,
93
+ signal: controller.signal,
94
+ onProgress: (p) => {
95
+ setState((prev) => ({ ...prev, progress: p }));
96
+ }
97
+ });
98
+ const url = URL.createObjectURL(blob);
99
+ urlRef.current = url;
100
+ setState({ progress: 1, isRendering: false, error: null, blob, url });
101
+ return blob;
102
+ } catch (err) {
103
+ if (err instanceof DOMException && err.name === "AbortError") {
104
+ setState((prev) => ({ ...prev, isRendering: false, error: null }));
105
+ return null;
106
+ }
107
+ const error = err instanceof Error ? err : new Error(String(err));
108
+ setState((prev) => ({ ...prev, isRendering: false, error }));
109
+ return null;
110
+ }
111
+ },
112
+ [frameWorker]
113
+ );
114
+ return { ...state, stitch, cancel, reset };
115
+ }
116
+
117
+ exports.useRender = useRender;
118
+ exports.useStitch = useStitch;
119
+ //# sourceMappingURL=index.cjs.map
120
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/useRender.ts","../../src/react/useStitch.ts"],"names":["useState","useRef","useCallback"],"mappings":"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","file":"index.cjs","sourcesContent":["'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipInput, RenderOptions, FrameWorker } from '../types.js';\n\nexport interface UseRenderState {\n progress: number;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n}\n\nexport interface UseRenderActions {\n render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseRenderResult = UseRenderState & UseRenderActions;\n\nexport function useRender(frameWorker: FrameWorker): UseRenderResult {\n const [state, setState] = useState<UseRenderState>({\n progress: 0,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });\n }, []);\n\n const render = useCallback(\n async (\n clip: ClipInput,\n options?: Omit<RenderOptions, 'onProgress' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });\n\n try {\n const blob = await frameWorker.render(clip, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => {\n setState((prev) => ({ ...prev, progress: p }));\n },\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n setState({ progress: 1, isRendering: false, error: null, blob, url });\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, render, cancel, reset };\n}\n","'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipInput, RenderOptions, FrameWorker } from '../types.js';\n\nexport interface UseStitchState {\n progress: number;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n}\n\nexport interface UseStitchActions {\n stitch: (clips: ClipInput[], options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseStitchResult = UseStitchState & UseStitchActions;\n\nexport function useStitch(frameWorker: FrameWorker): UseStitchResult {\n const [state, setState] = useState<UseStitchState>({\n progress: 0,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });\n }, []);\n\n const stitch = useCallback(\n async (\n clips: ClipInput[],\n options?: Omit<RenderOptions, 'onProgress' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });\n\n try {\n const blob = await frameWorker.stitch(clips, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => {\n setState((prev) => ({ ...prev, progress: p }));\n },\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n setState({ progress: 1, isRendering: false, error: null, blob, url });\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, stitch, cancel, reset };\n}\n"]}
@@ -0,0 +1,119 @@
1
+ interface CaptionSegment {
2
+ text: string;
3
+ startTime: number;
4
+ endTime: number;
5
+ style?: Partial<CaptionStyle>;
6
+ }
7
+ type CaptionStylePreset = 'hormozi' | 'modern' | 'minimal' | 'bold';
8
+ interface CaptionStyle {
9
+ preset: CaptionStylePreset;
10
+ fontFamily: string;
11
+ fontSize: number;
12
+ fontWeight: string | number;
13
+ color: string;
14
+ strokeColor: string;
15
+ strokeWidth: number;
16
+ backgroundColor: string;
17
+ backgroundPadding: number;
18
+ backgroundRadius: number;
19
+ position: 'top' | 'center' | 'bottom';
20
+ textAlign: CanvasTextAlign;
21
+ lineHeight: number;
22
+ maxWidth: number;
23
+ shadow: boolean;
24
+ shadowColor: string;
25
+ shadowBlur: number;
26
+ shadowOffsetX: number;
27
+ shadowOffsetY: number;
28
+ uppercase: boolean;
29
+ wordHighlight: boolean;
30
+ wordHighlightColor: string;
31
+ wordHighlightTextColor: string;
32
+ }
33
+ type AspectRatio = '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | 'original';
34
+ interface CropOptions {
35
+ x: number;
36
+ y: number;
37
+ width: number;
38
+ height: number;
39
+ }
40
+ interface CaptionOptions {
41
+ segments: CaptionSegment[];
42
+ style?: Partial<CaptionStyle>;
43
+ }
44
+ interface ClipInput {
45
+ /** Video source: URL string, File, Blob, or HTMLVideoElement */
46
+ source: string | File | Blob | HTMLVideoElement;
47
+ /** Trim start in seconds (default: 0) */
48
+ startTime?: number;
49
+ /** Trim end in seconds (default: video duration) */
50
+ endTime?: number;
51
+ /** Captions to overlay */
52
+ captions?: CaptionOptions;
53
+ /** Crop settings */
54
+ crop?: CropOptions;
55
+ /** Output aspect ratio */
56
+ aspectRatio?: AspectRatio;
57
+ /** Volume multiplier 0-2 (default: 1) */
58
+ volume?: number;
59
+ }
60
+ interface RenderOptions {
61
+ /** Output width in pixels (default: 1280) */
62
+ width?: number;
63
+ /** Output height in pixels (default: 720) */
64
+ height?: number;
65
+ /** Frames per second (default: 30) */
66
+ fps?: number;
67
+ /** Output MIME type (default: 'video/mp4') */
68
+ mimeType?: string;
69
+ /** Quality 0-1 for non-ffmpeg backends (default: 0.92) */
70
+ quality?: number;
71
+ /** Additional codec/format options passed to the backend */
72
+ encoderOptions?: Record<string, unknown>;
73
+ /** Progress callback (0-1) */
74
+ onProgress?: (progress: number) => void;
75
+ /** AbortSignal to cancel rendering */
76
+ signal?: AbortSignal;
77
+ }
78
+ interface FrameWorker {
79
+ /** Render a single clip to a Blob */
80
+ render(clip: ClipInput, options?: RenderOptions): Promise<Blob>;
81
+ /** Render a single clip and return an object URL */
82
+ renderToUrl(clip: ClipInput, options?: RenderOptions): Promise<string>;
83
+ /** Stitch multiple clips into one Blob */
84
+ stitch(clips: ClipInput[], options?: RenderOptions): Promise<Blob>;
85
+ /** Stitch multiple clips and return an object URL */
86
+ stitchToUrl(clips: ClipInput[], options?: RenderOptions): Promise<string>;
87
+ }
88
+
89
+ interface UseRenderState {
90
+ progress: number;
91
+ isRendering: boolean;
92
+ error: Error | null;
93
+ blob: Blob | null;
94
+ url: string | null;
95
+ }
96
+ interface UseRenderActions {
97
+ render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
98
+ cancel: () => void;
99
+ reset: () => void;
100
+ }
101
+ type UseRenderResult = UseRenderState & UseRenderActions;
102
+ declare function useRender(frameWorker: FrameWorker): UseRenderResult;
103
+
104
+ interface UseStitchState {
105
+ progress: number;
106
+ isRendering: boolean;
107
+ error: Error | null;
108
+ blob: Blob | null;
109
+ url: string | null;
110
+ }
111
+ interface UseStitchActions {
112
+ stitch: (clips: ClipInput[], options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
113
+ cancel: () => void;
114
+ reset: () => void;
115
+ }
116
+ type UseStitchResult = UseStitchState & UseStitchActions;
117
+ declare function useStitch(frameWorker: FrameWorker): UseStitchResult;
118
+
119
+ export { type UseRenderActions, type UseRenderResult, type UseRenderState, type UseStitchActions, type UseStitchResult, type UseStitchState, useRender, useStitch };
@@ -0,0 +1,119 @@
1
+ interface CaptionSegment {
2
+ text: string;
3
+ startTime: number;
4
+ endTime: number;
5
+ style?: Partial<CaptionStyle>;
6
+ }
7
+ type CaptionStylePreset = 'hormozi' | 'modern' | 'minimal' | 'bold';
8
+ interface CaptionStyle {
9
+ preset: CaptionStylePreset;
10
+ fontFamily: string;
11
+ fontSize: number;
12
+ fontWeight: string | number;
13
+ color: string;
14
+ strokeColor: string;
15
+ strokeWidth: number;
16
+ backgroundColor: string;
17
+ backgroundPadding: number;
18
+ backgroundRadius: number;
19
+ position: 'top' | 'center' | 'bottom';
20
+ textAlign: CanvasTextAlign;
21
+ lineHeight: number;
22
+ maxWidth: number;
23
+ shadow: boolean;
24
+ shadowColor: string;
25
+ shadowBlur: number;
26
+ shadowOffsetX: number;
27
+ shadowOffsetY: number;
28
+ uppercase: boolean;
29
+ wordHighlight: boolean;
30
+ wordHighlightColor: string;
31
+ wordHighlightTextColor: string;
32
+ }
33
+ type AspectRatio = '16:9' | '9:16' | '1:1' | '4:3' | '3:4' | 'original';
34
+ interface CropOptions {
35
+ x: number;
36
+ y: number;
37
+ width: number;
38
+ height: number;
39
+ }
40
+ interface CaptionOptions {
41
+ segments: CaptionSegment[];
42
+ style?: Partial<CaptionStyle>;
43
+ }
44
+ interface ClipInput {
45
+ /** Video source: URL string, File, Blob, or HTMLVideoElement */
46
+ source: string | File | Blob | HTMLVideoElement;
47
+ /** Trim start in seconds (default: 0) */
48
+ startTime?: number;
49
+ /** Trim end in seconds (default: video duration) */
50
+ endTime?: number;
51
+ /** Captions to overlay */
52
+ captions?: CaptionOptions;
53
+ /** Crop settings */
54
+ crop?: CropOptions;
55
+ /** Output aspect ratio */
56
+ aspectRatio?: AspectRatio;
57
+ /** Volume multiplier 0-2 (default: 1) */
58
+ volume?: number;
59
+ }
60
+ interface RenderOptions {
61
+ /** Output width in pixels (default: 1280) */
62
+ width?: number;
63
+ /** Output height in pixels (default: 720) */
64
+ height?: number;
65
+ /** Frames per second (default: 30) */
66
+ fps?: number;
67
+ /** Output MIME type (default: 'video/mp4') */
68
+ mimeType?: string;
69
+ /** Quality 0-1 for non-ffmpeg backends (default: 0.92) */
70
+ quality?: number;
71
+ /** Additional codec/format options passed to the backend */
72
+ encoderOptions?: Record<string, unknown>;
73
+ /** Progress callback (0-1) */
74
+ onProgress?: (progress: number) => void;
75
+ /** AbortSignal to cancel rendering */
76
+ signal?: AbortSignal;
77
+ }
78
+ interface FrameWorker {
79
+ /** Render a single clip to a Blob */
80
+ render(clip: ClipInput, options?: RenderOptions): Promise<Blob>;
81
+ /** Render a single clip and return an object URL */
82
+ renderToUrl(clip: ClipInput, options?: RenderOptions): Promise<string>;
83
+ /** Stitch multiple clips into one Blob */
84
+ stitch(clips: ClipInput[], options?: RenderOptions): Promise<Blob>;
85
+ /** Stitch multiple clips and return an object URL */
86
+ stitchToUrl(clips: ClipInput[], options?: RenderOptions): Promise<string>;
87
+ }
88
+
89
+ interface UseRenderState {
90
+ progress: number;
91
+ isRendering: boolean;
92
+ error: Error | null;
93
+ blob: Blob | null;
94
+ url: string | null;
95
+ }
96
+ interface UseRenderActions {
97
+ render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
98
+ cancel: () => void;
99
+ reset: () => void;
100
+ }
101
+ type UseRenderResult = UseRenderState & UseRenderActions;
102
+ declare function useRender(frameWorker: FrameWorker): UseRenderResult;
103
+
104
+ interface UseStitchState {
105
+ progress: number;
106
+ isRendering: boolean;
107
+ error: Error | null;
108
+ blob: Blob | null;
109
+ url: string | null;
110
+ }
111
+ interface UseStitchActions {
112
+ stitch: (clips: ClipInput[], options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;
113
+ cancel: () => void;
114
+ reset: () => void;
115
+ }
116
+ type UseStitchResult = UseStitchState & UseStitchActions;
117
+ declare function useStitch(frameWorker: FrameWorker): UseStitchResult;
118
+
119
+ export { type UseRenderActions, type UseRenderResult, type UseRenderState, type UseStitchActions, type UseStitchResult, type UseStitchState, useRender, useStitch };
@@ -0,0 +1,117 @@
1
+ import { useState, useRef, useCallback } from 'react';
2
+
3
+ // src/react/useRender.ts
4
+ function useRender(frameWorker) {
5
+ const [state, setState] = useState({
6
+ progress: 0,
7
+ isRendering: false,
8
+ error: null,
9
+ blob: null,
10
+ url: null
11
+ });
12
+ const abortRef = useRef(null);
13
+ const urlRef = useRef(null);
14
+ const cancel = useCallback(() => {
15
+ abortRef.current?.abort();
16
+ }, []);
17
+ const reset = useCallback(() => {
18
+ if (urlRef.current) {
19
+ URL.revokeObjectURL(urlRef.current);
20
+ urlRef.current = null;
21
+ }
22
+ setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });
23
+ }, []);
24
+ const render = useCallback(
25
+ async (clip, options) => {
26
+ if (urlRef.current) {
27
+ URL.revokeObjectURL(urlRef.current);
28
+ urlRef.current = null;
29
+ }
30
+ const controller = new AbortController();
31
+ abortRef.current = controller;
32
+ setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });
33
+ try {
34
+ const blob = await frameWorker.render(clip, {
35
+ ...options,
36
+ signal: controller.signal,
37
+ onProgress: (p) => {
38
+ setState((prev) => ({ ...prev, progress: p }));
39
+ }
40
+ });
41
+ const url = URL.createObjectURL(blob);
42
+ urlRef.current = url;
43
+ setState({ progress: 1, isRendering: false, error: null, blob, url });
44
+ return blob;
45
+ } catch (err) {
46
+ if (err instanceof DOMException && err.name === "AbortError") {
47
+ setState((prev) => ({ ...prev, isRendering: false, error: null }));
48
+ return null;
49
+ }
50
+ const error = err instanceof Error ? err : new Error(String(err));
51
+ setState((prev) => ({ ...prev, isRendering: false, error }));
52
+ return null;
53
+ }
54
+ },
55
+ [frameWorker]
56
+ );
57
+ return { ...state, render, cancel, reset };
58
+ }
59
+ function useStitch(frameWorker) {
60
+ const [state, setState] = useState({
61
+ progress: 0,
62
+ isRendering: false,
63
+ error: null,
64
+ blob: null,
65
+ url: null
66
+ });
67
+ const abortRef = useRef(null);
68
+ const urlRef = useRef(null);
69
+ const cancel = useCallback(() => {
70
+ abortRef.current?.abort();
71
+ }, []);
72
+ const reset = useCallback(() => {
73
+ if (urlRef.current) {
74
+ URL.revokeObjectURL(urlRef.current);
75
+ urlRef.current = null;
76
+ }
77
+ setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });
78
+ }, []);
79
+ const stitch = useCallback(
80
+ async (clips, options) => {
81
+ if (urlRef.current) {
82
+ URL.revokeObjectURL(urlRef.current);
83
+ urlRef.current = null;
84
+ }
85
+ const controller = new AbortController();
86
+ abortRef.current = controller;
87
+ setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });
88
+ try {
89
+ const blob = await frameWorker.stitch(clips, {
90
+ ...options,
91
+ signal: controller.signal,
92
+ onProgress: (p) => {
93
+ setState((prev) => ({ ...prev, progress: p }));
94
+ }
95
+ });
96
+ const url = URL.createObjectURL(blob);
97
+ urlRef.current = url;
98
+ setState({ progress: 1, isRendering: false, error: null, blob, url });
99
+ return blob;
100
+ } catch (err) {
101
+ if (err instanceof DOMException && err.name === "AbortError") {
102
+ setState((prev) => ({ ...prev, isRendering: false, error: null }));
103
+ return null;
104
+ }
105
+ const error = err instanceof Error ? err : new Error(String(err));
106
+ setState((prev) => ({ ...prev, isRendering: false, error }));
107
+ return null;
108
+ }
109
+ },
110
+ [frameWorker]
111
+ );
112
+ return { ...state, stitch, cancel, reset };
113
+ }
114
+
115
+ export { useRender, useStitch };
116
+ //# sourceMappingURL=index.js.map
117
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/react/useRender.ts","../../src/react/useStitch.ts"],"names":["useState","useRef","useCallback"],"mappings":"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","file":"index.js","sourcesContent":["'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipInput, RenderOptions, FrameWorker } from '../types.js';\n\nexport interface UseRenderState {\n progress: number;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n}\n\nexport interface UseRenderActions {\n render: (clip: ClipInput, options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseRenderResult = UseRenderState & UseRenderActions;\n\nexport function useRender(frameWorker: FrameWorker): UseRenderResult {\n const [state, setState] = useState<UseRenderState>({\n progress: 0,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });\n }, []);\n\n const render = useCallback(\n async (\n clip: ClipInput,\n options?: Omit<RenderOptions, 'onProgress' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });\n\n try {\n const blob = await frameWorker.render(clip, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => {\n setState((prev) => ({ ...prev, progress: p }));\n },\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n setState({ progress: 1, isRendering: false, error: null, blob, url });\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, render, cancel, reset };\n}\n","'use client';\n\nimport { useState, useCallback, useRef } from 'react';\nimport type { ClipInput, RenderOptions, FrameWorker } from '../types.js';\n\nexport interface UseStitchState {\n progress: number;\n isRendering: boolean;\n error: Error | null;\n blob: Blob | null;\n url: string | null;\n}\n\nexport interface UseStitchActions {\n stitch: (clips: ClipInput[], options?: Omit<RenderOptions, 'onProgress' | 'signal'>) => Promise<Blob | null>;\n cancel: () => void;\n reset: () => void;\n}\n\nexport type UseStitchResult = UseStitchState & UseStitchActions;\n\nexport function useStitch(frameWorker: FrameWorker): UseStitchResult {\n const [state, setState] = useState<UseStitchState>({\n progress: 0,\n isRendering: false,\n error: null,\n blob: null,\n url: null,\n });\n\n const abortRef = useRef<AbortController | null>(null);\n const urlRef = useRef<string | null>(null);\n\n const cancel = useCallback(() => {\n abortRef.current?.abort();\n }, []);\n\n const reset = useCallback(() => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n setState({ progress: 0, isRendering: false, error: null, blob: null, url: null });\n }, []);\n\n const stitch = useCallback(\n async (\n clips: ClipInput[],\n options?: Omit<RenderOptions, 'onProgress' | 'signal'>\n ): Promise<Blob | null> => {\n if (urlRef.current) {\n URL.revokeObjectURL(urlRef.current);\n urlRef.current = null;\n }\n\n const controller = new AbortController();\n abortRef.current = controller;\n\n setState({ progress: 0, isRendering: true, error: null, blob: null, url: null });\n\n try {\n const blob = await frameWorker.stitch(clips, {\n ...options,\n signal: controller.signal,\n onProgress: (p) => {\n setState((prev) => ({ ...prev, progress: p }));\n },\n });\n\n const url = URL.createObjectURL(blob);\n urlRef.current = url;\n setState({ progress: 1, isRendering: false, error: null, blob, url });\n return blob;\n } catch (err) {\n if (err instanceof DOMException && err.name === 'AbortError') {\n setState((prev) => ({ ...prev, isRendering: false, error: null }));\n return null;\n }\n const error = err instanceof Error ? err : new Error(String(err));\n setState((prev) => ({ ...prev, isRendering: false, error }));\n return null;\n }\n },\n [frameWorker]\n );\n\n return { ...state, stitch, cancel, reset };\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,83 @@
1
+ {
2
+ "name": "framewebworker",
3
+ "version": "0.1.0",
4
+ "description": "Browser-native video rendering and clip export library. Trim, caption, and export MP4 Blobs in the browser — no server needed.",
5
+ "keywords": [
6
+ "video",
7
+ "browser",
8
+ "mp4",
9
+ "ffmpeg",
10
+ "wasm",
11
+ "captions",
12
+ "subtitles",
13
+ "video-editing",
14
+ "clip",
15
+ "export",
16
+ "canvas",
17
+ "typescript"
18
+ ],
19
+ "homepage": "https://github.com/nareshipme/frameworker#readme",
20
+ "bugs": {
21
+ "url": "https://github.com/nareshipme/frameworker/issues"
22
+ },
23
+ "repository": {
24
+ "type": "git",
25
+ "url": "git+https://github.com/nareshipme/frameworker.git"
26
+ },
27
+ "license": "MIT",
28
+ "author": "nareshipme",
29
+ "sideEffects": false,
30
+ "type": "module",
31
+ "exports": {
32
+ ".": {
33
+ "import": "./dist/index.js",
34
+ "require": "./dist/index.cjs",
35
+ "types": "./dist/index.d.ts"
36
+ },
37
+ "./react": {
38
+ "import": "./dist/react/index.js",
39
+ "require": "./dist/react/index.cjs",
40
+ "types": "./dist/react/index.d.ts"
41
+ }
42
+ },
43
+ "main": "./dist/index.cjs",
44
+ "module": "./dist/index.js",
45
+ "types": "./dist/index.d.ts",
46
+ "files": [
47
+ "dist",
48
+ "LICENSE",
49
+ "README.md"
50
+ ],
51
+ "scripts": {
52
+ "build": "tsup",
53
+ "dev": "tsup --watch",
54
+ "test": "vitest run",
55
+ "test:watch": "vitest",
56
+ "lint": "tsc --noEmit",
57
+ "prepublishOnly": "npm run build"
58
+ },
59
+ "peerDependencies": {
60
+ "react": ">=18.0.0",
61
+ "react-dom": ">=18.0.0"
62
+ },
63
+ "peerDependenciesMeta": {
64
+ "react": {
65
+ "optional": true
66
+ },
67
+ "react-dom": {
68
+ "optional": true
69
+ }
70
+ },
71
+ "optionalDependencies": {
72
+ "@ffmpeg/ffmpeg": "^0.12.10",
73
+ "@ffmpeg/util": "^0.12.1"
74
+ },
75
+ "devDependencies": {
76
+ "@types/node": "^20.0.0",
77
+ "@types/react": "^18.0.0",
78
+ "happy-dom": "^20.8.9",
79
+ "tsup": "^8.0.0",
80
+ "typescript": "^5.4.0",
81
+ "vitest": "^1.6.0"
82
+ }
83
+ }