@revideo/2d 0.5.7-alpha.1076 → 0.5.7-alpha.1084

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.
@@ -14,32 +14,46 @@ export class ImageCommunication {
14
14
  }
15
15
  }
16
16
  async getFrame(id, src, time, duration, fps) {
17
- return new Promise((resolve, reject) => {
18
- if (!import.meta.hot) {
19
- reject('FfmpegVideoFrame can only be used with HMR.');
20
- return;
21
- }
22
- function handler(event) {
23
- const image = new Image();
24
- const uint8Array = new Uint8Array(event.data.frame.data);
25
- const blob = new Blob([uint8Array], { type: 'image/png' });
26
- const url = URL.createObjectURL(blob);
27
- image.src = url;
28
- image.onload = () => {
29
- resolve(image);
30
- };
31
- }
32
- this.nextFrameHandlers.push(handler);
33
- import.meta.hot.send('revideo:ffmpeg-decoder:video-frame', {
34
- data: {
35
- id: id,
36
- filePath: src,
37
- startTime: time,
38
- duration,
39
- fps,
40
- },
41
- });
17
+ const response = await fetch('/revideo-ffmpeg-decoder/video-frame', {
18
+ method: 'POST',
19
+ headers: {
20
+ // eslint-disable-next-line @typescript-eslint/naming-convention
21
+ 'Content-Type': 'application/json',
22
+ },
23
+ body: JSON.stringify({
24
+ id,
25
+ filePath: src,
26
+ startTime: time,
27
+ duration,
28
+ fps,
29
+ }),
42
30
  });
31
+ if (!response.ok) {
32
+ throw new Error(`HTTP error! status: ${response.status}`);
33
+ }
34
+ const arrayBuffer = await response.arrayBuffer();
35
+ // Assuming fixed dimensions for now
36
+ const width = 1080; // or whatever your fixed width is
37
+ const height = 1920; // or whatever your fixed height is
38
+ let imageData;
39
+ try {
40
+ imageData = new ImageData(new Uint8ClampedArray(arrayBuffer), width, height);
41
+ }
42
+ catch {
43
+ const width = 1080; // your desired width
44
+ const height = 1920; // your desired height
45
+ // Create a black frame
46
+ const blackFrame = new Uint8ClampedArray(width * height * 4); // 4 channels: R, G, B, A
47
+ for (let i = 0; i < blackFrame.length; i += 4) {
48
+ blackFrame[i] = 0; // R
49
+ blackFrame[i + 1] = 0; // G
50
+ blackFrame[i + 2] = 0; // B
51
+ blackFrame[i + 3] = 255; // A (fully opaque)
52
+ }
53
+ imageData = new ImageData(blackFrame, width, height);
54
+ }
55
+ const imageBitmap = await createImageBitmap(imageData);
56
+ return imageBitmap;
43
57
  }
44
58
  }
45
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmZtcGVnLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvdXRpbHMvdmlkZW8vZmZtcGVnLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCO1FBV1Esc0JBQWlCLEdBQXNDLEVBQUUsQ0FBQztRQVZoRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FDaEIsd0NBQXdDLEVBQ3hDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUN4QixDQUFDO0lBQ0osQ0FBQztJQUlPLE9BQU8sQ0FBQyxLQUFtQjtRQUNqQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUM7UUFDeEMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEVBQUUsQ0FBQztRQUU1QixLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVNLEtBQUssQ0FBQyxRQUFRLENBQ25CLEVBQVUsRUFDVixHQUFXLEVBQ1gsSUFBWSxFQUNaLFFBQWdCLEVBQ2hCLEdBQVc7UUFFWCxPQUFPLElBQUksT0FBTyxDQUFtQixDQUFDLE9BQU8sRUFBRSxNQUFNLEVBQUUsRUFBRTtZQUN2RCxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztnQkFDckIsTUFBTSxDQUFDLDZDQUE2QyxDQUFDLENBQUM7Z0JBQ3RELE9BQU87WUFDVCxDQUFDO1lBRUQsU0FBUyxPQUFPLENBQUMsS0FBbUI7Z0JBQ2xDLE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxFQUFFLENBQUM7Z0JBRTFCLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUN6RCxNQUFNLElBQUksR0FBRyxJQUFJLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxFQUFFLEVBQUMsSUFBSSxFQUFFLFdBQVcsRUFBQyxDQUFDLENBQUM7Z0JBQ3pELE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBRXRDLEtBQUssQ0FBQyxHQUFHLEdBQUcsR0FBRyxDQUFDO2dCQUVoQixLQUFLLENBQUMsTUFBTSxHQUFHLEdBQUcsRUFBRTtvQkFDbEIsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO2dCQUNqQixDQUFDLENBQUM7WUFDSixDQUFDO1lBRUQsSUFBSSxDQUFDLGlCQUFpQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztZQUVyQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsb0NBQW9DLEVBQUU7Z0JBQ3pELElBQUksRUFBRTtvQkFDSixFQUFFLEVBQUUsRUFBRTtvQkFDTixRQUFRLEVBQUUsR0FBRztvQkFDYixTQUFTLEVBQUUsSUFBSTtvQkFDZixRQUFRO29CQUNSLEdBQUc7aUJBQ0o7YUFDRixDQUFDLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7Q0FDRiJ9
59
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmZtcGVnLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9saWIvdXRpbHMvdmlkZW8vZmZtcGVnLWNsaWVudC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCO1FBV1Esc0JBQWlCLEdBQXNDLEVBQUUsQ0FBQztRQVZoRSxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQztZQUNyQixNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7UUFDakUsQ0FBQztRQUVELE1BQU0sQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FDaEIsd0NBQXdDLEVBQ3hDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUN4QixDQUFDO0lBQ0osQ0FBQztJQUlPLE9BQU8sQ0FBQyxLQUFtQjtRQUNqQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsaUJBQWlCLENBQUM7UUFDeEMsSUFBSSxDQUFDLGlCQUFpQixHQUFHLEVBQUUsQ0FBQztRQUU1QixLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVNLEtBQUssQ0FBQyxRQUFRLENBQ25CLEVBQVUsRUFDVixHQUFXLEVBQ1gsSUFBWSxFQUNaLFFBQWdCLEVBQ2hCLEdBQVc7UUFFWCxNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxxQ0FBcUMsRUFBRTtZQUNsRSxNQUFNLEVBQUUsTUFBTTtZQUNkLE9BQU8sRUFBRTtnQkFDUCxnRUFBZ0U7Z0JBQ2hFLGNBQWMsRUFBRSxrQkFBa0I7YUFDbkM7WUFDRCxJQUFJLEVBQUUsSUFBSSxDQUFDLFNBQVMsQ0FBQztnQkFDbkIsRUFBRTtnQkFDRixRQUFRLEVBQUUsR0FBRztnQkFDYixTQUFTLEVBQUUsSUFBSTtnQkFDZixRQUFRO2dCQUNSLEdBQUc7YUFDSixDQUFDO1NBQ0gsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLFFBQVEsQ0FBQyxFQUFFLEVBQUUsQ0FBQztZQUNqQixNQUFNLElBQUksS0FBSyxDQUFDLHVCQUF1QixRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztRQUM1RCxDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsTUFBTSxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUM7UUFFakQsb0NBQW9DO1FBQ3BDLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLGtDQUFrQztRQUN0RCxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsQ0FBQyxtQ0FBbUM7UUFFeEQsSUFBSSxTQUFvQixDQUFDO1FBRXpCLElBQUksQ0FBQztZQUNILFNBQVMsR0FBRyxJQUFJLFNBQVMsQ0FDdkIsSUFBSSxpQkFBaUIsQ0FBQyxXQUFXLENBQUMsRUFDbEMsS0FBSyxFQUNMLE1BQU0sQ0FDUCxDQUFDO1FBQ0osQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLE1BQU0sS0FBSyxHQUFHLElBQUksQ0FBQyxDQUFDLHFCQUFxQjtZQUN6QyxNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsQ0FBQyxzQkFBc0I7WUFFM0MsdUJBQXVCO1lBQ3ZCLE1BQU0sVUFBVSxHQUFHLElBQUksaUJBQWlCLENBQUMsS0FBSyxHQUFHLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLHlCQUF5QjtZQUN2RixLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQzlDLFVBQVUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJO2dCQUN2QixVQUFVLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLElBQUk7Z0JBQzNCLFVBQVUsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsSUFBSTtnQkFDM0IsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsR0FBRyxHQUFHLENBQUMsQ0FBQyxtQkFBbUI7WUFDOUMsQ0FBQztZQUVELFNBQVMsR0FBRyxJQUFJLFNBQVMsQ0FBQyxVQUFVLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBQ3ZELENBQUM7UUFDRCxNQUFNLFdBQVcsR0FBRyxNQUFNLGlCQUFpQixDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQ3ZELE9BQU8sV0FBVyxDQUFDO0lBQ3JCLENBQUM7Q0FDRiJ9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revideo/2d",
3
- "version": "0.5.7-alpha.1076+c0acda35",
3
+ "version": "0.5.7-alpha.1084+4580e7ac",
4
4
  "description": "A 2D renderer for revideo",
5
5
  "author": "revideo",
6
6
  "homepage": "https://re.video/",
@@ -30,7 +30,7 @@
30
30
  "devDependencies": {
31
31
  "@preact/signals": "^1.2.1",
32
32
  "@revideo/internal": "^0.0.0",
33
- "@revideo/ui": "^0.5.7-alpha.1076+c0acda35",
33
+ "@revideo/ui": "^0.5.7-alpha.1084+4580e7ac",
34
34
  "clsx": "^2.0.0",
35
35
  "jsdom": "^22.1.0",
36
36
  "preact": "^10.19.2",
@@ -40,7 +40,7 @@
40
40
  "@codemirror/language": "^6.10.1",
41
41
  "@lezer/common": "^1.2.1",
42
42
  "@lezer/highlight": "^1.2.0",
43
- "@revideo/core": "^0.5.7-alpha.1076+c0acda35",
43
+ "@revideo/core": "^0.5.7-alpha.1084+4580e7ac",
44
44
  "@rive-app/canvas-advanced": "2.7.3",
45
45
  "code-fns": "^0.8.2",
46
46
  "hls.js": "^1.5.11",
@@ -48,5 +48,5 @@
48
48
  "mp4box": "^0.5.2",
49
49
  "parse-svg-path": "^0.1.2"
50
50
  },
51
- "gitHead": "c0acda35b79eb998c2deb66e4a95f67680865942"
51
+ "gitHead": "4580e7ac3430f58ef720a31e7e46a99c22c9f261"
52
52
  }
@@ -284,8 +284,6 @@ export class Layout extends Node {
284
284
  @signal()
285
285
  public declare readonly textAlign: SimpleSignal<CanvasTextAlign, this>;
286
286
 
287
- protected fontLoaded: boolean = false;
288
-
289
287
  protected getX(): number {
290
288
  if (this.isLayoutRoot()) {
291
289
  return this.x.context.getter();
@@ -964,11 +962,13 @@ export class Layout extends Node {
964
962
 
965
963
  @computed()
966
964
  protected applyFont() {
967
- if (!this.fontLoaded) {
965
+ const loadingFonts = Array.from(document.fonts).filter(
966
+ font => font.status === 'loading',
967
+ );
968
+ if (loadingFonts.length > 0) {
968
969
  DependencyContext.collectPromise(
969
970
  (async () => {
970
971
  await document.fonts?.ready;
971
- this.fontLoaded = true;
972
972
  })(),
973
973
  );
974
974
  }
@@ -10,7 +10,6 @@ describe('Txt', () => {
10
10
 
11
11
  it('Handle plain text', () => {
12
12
  const node = (<Txt lineWidth={8}>test</Txt>) as Txt;
13
- node.toPromise();
14
13
 
15
14
  const parseSpy = vi.spyOn(node as any, 'parseChildren');
16
15
  const leaf = node.childAs<TxtLeaf>(0);
@@ -39,7 +38,6 @@ describe('Txt', () => {
39
38
  Apple <Txt>Banana</Txt> Cherry
40
39
  </Txt>
41
40
  ) as Txt;
42
- node.toPromise();
43
41
 
44
42
  const first = node.childAs<TxtLeaf>(0);
45
43
  const second = node.childAs<Txt>(1);
@@ -197,7 +197,7 @@ export class Video extends Media {
197
197
  return video;
198
198
  }
199
199
 
200
- protected lastFrame: HTMLImageElement | null = null;
200
+ protected lastFrame: any | null = null;
201
201
 
202
202
  protected async webcodecSeekedVideo(): Promise<CanvasImageSource> {
203
203
  const video = this.video();
@@ -213,7 +213,7 @@ export class Video extends Media {
213
213
  return getFrame(this.key, video.src, time, fps);
214
214
  }
215
215
 
216
- protected async ffmpegSeekedVideo(): Promise<HTMLImageElement> {
216
+ protected async ffmpegSeekedVideo(): Promise<ImageBitmap> {
217
217
  const video = this.video();
218
218
  const time = this.clampTime(this.time());
219
219
  const duration = this.getDuration();
@@ -52,7 +52,6 @@ describe('clone', () => {
52
52
  const template = (
53
53
  <Circle lineWidth={8} startAngle={signal} end={0.5} />
54
54
  ) as Circle;
55
- template.toPromise();
56
55
  const clone = template.snapshotClone({end: 0});
57
56
 
58
57
  expect(clone.lineWidth()).toBe(8);
@@ -12,7 +12,6 @@ describe('state', () => {
12
12
  const circle = (
13
13
  <Circle lineWidth={8} startAngle={signal} end={0.5} />
14
14
  ) as Circle;
15
- circle.toPromise();
16
15
  circle.save();
17
16
 
18
17
  circle.lineWidth(16);
@@ -28,37 +28,55 @@ export class ImageCommunication {
28
28
  duration: number,
29
29
  fps: number,
30
30
  ) {
31
- return new Promise<HTMLImageElement>((resolve, reject) => {
32
- if (!import.meta.hot) {
33
- reject('FfmpegVideoFrame can only be used with HMR.');
34
- return;
35
- }
31
+ const response = await fetch('/revideo-ffmpeg-decoder/video-frame', {
32
+ method: 'POST',
33
+ headers: {
34
+ // eslint-disable-next-line @typescript-eslint/naming-convention
35
+ 'Content-Type': 'application/json',
36
+ },
37
+ body: JSON.stringify({
38
+ id,
39
+ filePath: src,
40
+ startTime: time,
41
+ duration,
42
+ fps,
43
+ }),
44
+ });
36
45
 
37
- function handler(event: MessageEvent) {
38
- const image = new Image();
46
+ if (!response.ok) {
47
+ throw new Error(`HTTP error! status: ${response.status}`);
48
+ }
39
49
 
40
- const uint8Array = new Uint8Array(event.data.frame.data);
41
- const blob = new Blob([uint8Array], {type: 'image/png'});
42
- const url = URL.createObjectURL(blob);
50
+ const arrayBuffer = await response.arrayBuffer();
43
51
 
44
- image.src = url;
52
+ // Assuming fixed dimensions for now
53
+ const width = 1080; // or whatever your fixed width is
54
+ const height = 1920; // or whatever your fixed height is
45
55
 
46
- image.onload = () => {
47
- resolve(image);
48
- };
49
- }
56
+ let imageData: ImageData;
50
57
 
51
- this.nextFrameHandlers.push(handler);
58
+ try {
59
+ imageData = new ImageData(
60
+ new Uint8ClampedArray(arrayBuffer),
61
+ width,
62
+ height,
63
+ );
64
+ } catch {
65
+ const width = 1080; // your desired width
66
+ const height = 1920; // your desired height
52
67
 
53
- import.meta.hot.send('revideo:ffmpeg-decoder:video-frame', {
54
- data: {
55
- id: id,
56
- filePath: src,
57
- startTime: time,
58
- duration,
59
- fps,
60
- },
61
- });
62
- });
68
+ // Create a black frame
69
+ const blackFrame = new Uint8ClampedArray(width * height * 4); // 4 channels: R, G, B, A
70
+ for (let i = 0; i < blackFrame.length; i += 4) {
71
+ blackFrame[i] = 0; // R
72
+ blackFrame[i + 1] = 0; // G
73
+ blackFrame[i + 2] = 0; // B
74
+ blackFrame[i + 3] = 255; // A (fully opaque)
75
+ }
76
+
77
+ imageData = new ImageData(blackFrame, width, height);
78
+ }
79
+ const imageBitmap = await createImageBitmap(imageData);
80
+ return imageBitmap;
63
81
  }
64
82
  }