@editframe/elements 0.12.0-beta.2 → 0.12.0-beta.20

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.
Files changed (92) hide show
  1. package/dist/elements/EFAudio.d.ts +1 -1
  2. package/dist/elements/EFCaptions.d.ts +5 -5
  3. package/dist/elements/EFImage.d.ts +1 -1
  4. package/dist/elements/EFMedia.browsertest.d.ts +1 -1
  5. package/dist/elements/EFMedia.d.ts +1 -2
  6. package/dist/elements/{src/elements/EFMedia.js → EFMedia.js} +72 -15
  7. package/dist/elements/EFTemporal.browsertest.d.ts +1 -1
  8. package/dist/elements/EFTemporal.d.ts +4 -1
  9. package/dist/elements/{src/elements/EFTemporal.js → EFTemporal.js} +3 -0
  10. package/dist/elements/EFTimegroup.browsertest.d.ts +2 -2
  11. package/dist/elements/EFTimegroup.d.ts +3 -3
  12. package/dist/elements/EFVideo.d.ts +1 -1
  13. package/dist/elements/{src/elements/EFVideo.js → EFVideo.js} +10 -2
  14. package/dist/elements/EFWaveform.d.ts +7 -4
  15. package/dist/elements/{src/elements/EFWaveform.js → EFWaveform.js} +48 -56
  16. package/dist/elements/TimegroupController.d.ts +2 -2
  17. package/dist/elements/util.d.ts +1 -1
  18. package/dist/gui/ContextMixin.browsertest.d.ts +1 -1
  19. package/dist/gui/ContextMixin.d.ts +1 -1
  20. package/dist/{elements/src/gui → gui}/ContextMixin.js +8 -4
  21. package/dist/gui/EFFilmstrip.d.ts +7 -7
  22. package/dist/gui/EFPreview.d.ts +1 -1
  23. package/dist/{elements/src/gui → gui}/EFPreview.js +3 -1
  24. package/dist/gui/EFScrubber.d.ts +1 -1
  25. package/dist/gui/EFTimeDisplay.d.ts +1 -1
  26. package/dist/gui/EFToggleLoop.d.ts +1 -1
  27. package/dist/gui/EFTogglePlay.d.ts +1 -3
  28. package/dist/{elements/src/gui → gui}/EFTogglePlay.js +1 -9
  29. package/dist/gui/EFWorkbench.d.ts +1 -1
  30. package/dist/{elements/src/gui → gui}/TWMixin.css.js +1 -1
  31. package/dist/gui/efContext.d.ts +1 -1
  32. package/dist/index.d.ts +14 -14
  33. package/package.json +5 -4
  34. package/src/elements/EFAudio.ts +3 -3
  35. package/src/elements/EFCaptions.browsertest.ts +3 -3
  36. package/src/elements/EFCaptions.ts +9 -9
  37. package/src/elements/EFImage.browsertest.ts +2 -2
  38. package/src/elements/EFImage.ts +4 -4
  39. package/src/elements/EFMedia.browsertest.ts +7 -5
  40. package/src/elements/EFMedia.ts +91 -19
  41. package/src/elements/EFSourceMixin.ts +3 -3
  42. package/src/elements/EFTemporal.browsertest.ts +1 -1
  43. package/src/elements/EFTemporal.ts +9 -3
  44. package/src/elements/EFTimegroup.browsertest.ts +5 -5
  45. package/src/elements/EFTimegroup.ts +6 -6
  46. package/src/elements/EFVideo.ts +15 -4
  47. package/src/elements/EFWaveform.ts +82 -98
  48. package/src/elements/FetchMixin.ts +2 -2
  49. package/src/elements/TimegroupController.ts +2 -2
  50. package/src/elements/durationConverter.ts +1 -1
  51. package/src/elements/util.ts +1 -1
  52. package/src/gui/ContextMixin.browsertest.ts +3 -3
  53. package/src/gui/ContextMixin.ts +18 -12
  54. package/src/gui/EFFilmstrip.ts +15 -15
  55. package/src/gui/EFPreview.ts +5 -3
  56. package/src/gui/EFScrubber.ts +3 -3
  57. package/src/gui/EFTimeDisplay.ts +2 -2
  58. package/src/gui/EFToggleLoop.ts +4 -4
  59. package/src/gui/EFTogglePlay.ts +4 -10
  60. package/src/gui/EFWorkbench.ts +2 -2
  61. package/src/gui/efContext.ts +1 -1
  62. package/dist/assets/src/EncodedAsset.js +0 -560
  63. package/dist/assets/src/MP4File.js +0 -172
  64. package/dist/assets/src/memoize.js +0 -14
  65. package/dist/elements/src/elements/util.js +0 -11
  66. package/dist/{elements/src/EF_FRAMEGEN.js → EF_FRAMEGEN.js} +0 -0
  67. package/dist/{elements/src/EF_INTERACTIVE.js → EF_INTERACTIVE.js} +0 -0
  68. package/dist/{elements/src/EF_RENDERING.js → EF_RENDERING.js} +0 -0
  69. package/dist/elements/{src/elements/CrossUpdateController.js → CrossUpdateController.js} +0 -0
  70. package/dist/elements/{src/elements/EFAudio.js → EFAudio.js} +2 -2
  71. package/dist/elements/{src/elements/EFCaptions.js → EFCaptions.js} +0 -0
  72. package/dist/elements/{src/elements/EFImage.js → EFImage.js} +0 -0
  73. package/dist/elements/{src/elements/EFSourceMixin.js → EFSourceMixin.js} +1 -1
  74. package/dist/elements/{src/elements/EFTimegroup.js → EFTimegroup.js} +0 -0
  75. package/dist/elements/{src/elements/FetchMixin.js → FetchMixin.js} +0 -0
  76. package/dist/elements/{src/elements/TimegroupController.js → TimegroupController.js} +0 -0
  77. package/dist/elements/{src/elements/durationConverter.js → durationConverter.js} +0 -0
  78. package/dist/elements/{src/elements/parseTimeToMs.js → parseTimeToMs.js} +0 -0
  79. package/dist/{elements/src/gui → gui}/EFFilmstrip.js +0 -0
  80. package/dist/{elements/src/gui → gui}/EFScrubber.js +0 -0
  81. package/dist/{elements/src/gui → gui}/EFTimeDisplay.js +0 -0
  82. package/dist/{elements/src/gui → gui}/EFToggleLoop.js +1 -1
  83. /package/dist/{elements/src/gui → gui}/EFWorkbench.js +0 -0
  84. /package/dist/{elements/src/gui → gui}/TWMixin.js +0 -0
  85. /package/dist/{elements/src/gui → gui}/apiHostContext.js +0 -0
  86. /package/dist/{elements/src/gui → gui}/efContext.js +0 -0
  87. /package/dist/{elements/src/gui → gui}/fetchContext.js +0 -0
  88. /package/dist/{elements/src/gui → gui}/focusContext.js +0 -0
  89. /package/dist/{elements/src/gui → gui}/focusedElementContext.js +0 -0
  90. /package/dist/{elements/src/gui → gui}/playingContext.js +0 -0
  91. /package/dist/{elements/src/index.js → index.js} +0 -0
  92. /package/dist/{elements/src/msToTimeCode.js → msToTimeCode.js} +0 -0
@@ -1,5 +1,5 @@
1
- import { EFMedia } from './EFMedia.ts';
2
1
  import { Task } from '@lit/task';
2
+ import { EFMedia } from './EFMedia.js';
3
3
  export declare class EFAudio extends EFMedia {
4
4
  audioElementRef: import('lit-html/directives/ref.js').Ref<HTMLAudioElement>;
5
5
  src: string;
@@ -1,8 +1,8 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement, PropertyValueMap } from 'lit';
3
- import { EFAudio } from './EFAudio.ts';
4
- import { EFVideo } from './EFVideo.ts';
5
- declare const EFCaptionsActiveWord_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
3
+ import { EFAudio } from './EFAudio.js';
4
+ import { EFVideo } from './EFVideo.js';
5
+ declare const EFCaptionsActiveWord_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
6
6
  export declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
7
7
  static styles: import('lit').CSSResult[];
8
8
  render(): import('lit-html').TemplateResult<1> | undefined;
@@ -13,7 +13,7 @@ export declare class EFCaptionsActiveWord extends EFCaptionsActiveWord_base {
13
13
  get startTimeMs(): number;
14
14
  get durationMs(): number;
15
15
  }
16
- declare const EFCaptionsSegment_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
16
+ declare const EFCaptionsSegment_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
17
17
  export declare class EFCaptionsSegment extends EFCaptionsSegment_base {
18
18
  static styles: import('lit').CSSResult[];
19
19
  render(): import('lit-html').TemplateResult<1> | undefined;
@@ -44,7 +44,7 @@ export declare class EFCaptionsAfterActiveWord extends EFCaptionsSegment {
44
44
  get startTimeMs(): number;
45
45
  get durationMs(): number;
46
46
  }
47
- declare const EFCaptions_base: (new (...args: any[]) => import('./EFSourceMixin.ts').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.ts').FetchMixinInterface) & typeof LitElement;
47
+ declare const EFCaptions_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
48
48
  export declare class EFCaptions extends EFCaptions_base {
49
49
  static styles: import('lit').CSSResult[];
50
50
  displayMode: "word" | "segment" | "context";
@@ -1,6 +1,6 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement } from 'lit';
3
- declare const EFImage_base: (new (...args: any[]) => import('./EFSourceMixin.ts').EFSourceMixinInterface) & (new (...args: any[]) => import('./FetchMixin.ts').FetchMixinInterface) & typeof LitElement;
3
+ declare const EFImage_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
4
4
  export declare class EFImage extends EFImage_base {
5
5
  #private;
6
6
  static styles: import('lit').CSSResult[];
@@ -1,4 +1,4 @@
1
- import { EFMedia } from './EFMedia.ts';
1
+ import { EFMedia } from './EFMedia.js';
2
2
  declare class TestMedia extends EFMedia {
3
3
  }
4
4
  declare global {
@@ -5,7 +5,7 @@ import { VideoAsset } from '../../../assets/src/EncodedAsset.ts';
5
5
  import { MP4File } from '../../../assets/src/MP4File.ts';
6
6
  import type * as MP4Box from "mp4box";
7
7
  export declare const deepGetMediaElements: (element: Element, medias?: EFMedia[]) => EFMedia[];
8
- declare const EFMedia_base: (new (...args: any[]) => import('./EFSourceMixin.ts').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.ts').FetchMixinInterface) & typeof LitElement;
8
+ declare const EFMedia_base: (new (...args: any[]) => import('./EFSourceMixin.js').EFSourceMixinInterface) & (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & (new (...args: any[]) => import('./FetchMixin.js').FetchMixinInterface) & typeof LitElement;
9
9
  export declare class EFMedia extends EFMedia_base {
10
10
  #private;
11
11
  static styles: import('lit').CSSResult[];
@@ -47,7 +47,6 @@ export declare class EFMedia extends EFMedia_base {
47
47
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
48
48
  get hasOwnDuration(): boolean;
49
49
  get durationMs(): number;
50
- get startTimeMs(): number;
51
50
  audioBufferTask: Task<readonly [Record<string, File> | undefined, Record<string, {
52
51
  segment: TrackSegment;
53
52
  track: MP4Box.TrackInfo;
@@ -4,15 +4,14 @@ import { deepArrayEquals } from "@lit/task/deep-equals.js";
4
4
  import debug from "debug";
5
5
  import { css, LitElement } from "lit";
6
6
  import { property, state } from "lit/decorators.js";
7
- import { VideoAsset } from "../../../assets/src/EncodedAsset.js";
8
- import { MP4File } from "../../../assets/src/MP4File.js";
7
+ import { VideoAsset } from "@editframe/assets/EncodedAsset.js";
8
+ import { MP4File } from "@editframe/assets/MP4File.js";
9
9
  import { EF_INTERACTIVE } from "../EF_INTERACTIVE.js";
10
10
  import { EF_RENDERING } from "../EF_RENDERING.js";
11
11
  import { apiHostContext } from "../gui/apiHostContext.js";
12
12
  import { EFSourceMixin } from "./EFSourceMixin.js";
13
- import { EFTemporal } from "./EFTemporal.js";
13
+ import { EFTemporal, isEFTemporal } from "./EFTemporal.js";
14
14
  import { FetchMixin } from "./FetchMixin.js";
15
- import { getStartTimeMs } from "./util.js";
16
15
  var __defProp = Object.defineProperty;
17
16
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
18
17
  var __decorateClass = (decorators, target, key, kind) => {
@@ -62,10 +61,10 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
62
61
  return await Promise.all(
63
62
  Object.entries(fragmentIndex).map(async ([trackId, track]) => {
64
63
  const start = track.initSegment.offset;
65
- const end = track.initSegment.offset + track.initSegment.size - 1;
64
+ const end = track.initSegment.offset + track.initSegment.size;
66
65
  const response = await fetch(this.fragmentTrackPath(trackId), {
67
66
  signal,
68
- headers: { Range: `bytes=${start}-${end}` }
67
+ headers: { Range: `bytes=${start}-${end - 1}` }
69
68
  });
70
69
  const buffer = await response.arrayBuffer();
71
70
  buffer.fileStart = 0;
@@ -131,14 +130,14 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
131
130
  const end = segment.offset + segment.size;
132
131
  const response = await fetch(this.fragmentTrackPath(trackId), {
133
132
  signal,
134
- headers: { Range: `bytes=${start}-${end}` }
133
+ headers: { Range: `bytes=${start}-${end - 1}` }
135
134
  });
136
135
  if (nextSegment) {
137
136
  const nextStart = nextSegment.offset;
138
137
  const nextEnd = nextSegment.offset + nextSegment.size;
139
138
  fetch(this.fragmentTrackPath(trackId), {
140
139
  signal,
141
- headers: { Range: `bytes=${nextStart}-${nextEnd}` }
140
+ headers: { Range: `bytes=${nextStart}-${nextEnd - 1}` }
142
141
  }).then(() => {
143
142
  log("Prefetched next segment");
144
143
  }).catch((error) => {
@@ -270,6 +269,67 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
270
269
  if (changedProperties.has("ownCurrentTimeMs")) {
271
270
  this.executeSeek(this.trimAdjustedOwnCurrentTimeMs);
272
271
  }
272
+ if (changedProperties.has("currentTime") || changedProperties.has("ownCurrentTimeMs")) {
273
+ const timelineTimeMs = (this.rootTimegroup ?? this).currentTimeMs;
274
+ if (this.startTimeMs > timelineTimeMs || this.endTimeMs < timelineTimeMs) {
275
+ this.style.display = "none";
276
+ return;
277
+ }
278
+ this.style.display = "";
279
+ const animations = this.getAnimations({ subtree: true });
280
+ this.style.setProperty("--ef-duration", `${this.durationMs}ms`);
281
+ this.style.setProperty(
282
+ "--ef-transition--duration",
283
+ `${this.parentTimegroup?.overlapMs ?? 0}ms`
284
+ );
285
+ this.style.setProperty(
286
+ "--ef-transition-out-start",
287
+ `${this.durationMs - (this.parentTimegroup?.overlapMs ?? 0)}ms`
288
+ );
289
+ for (const animation of animations) {
290
+ if (animation.playState === "running") {
291
+ animation.pause();
292
+ }
293
+ const effect = animation.effect;
294
+ if (!(effect && effect instanceof KeyframeEffect)) {
295
+ return;
296
+ }
297
+ const target = effect.target;
298
+ if (!target) {
299
+ return;
300
+ }
301
+ if (target.closest("ef-video, ef-audio") !== this) {
302
+ return;
303
+ }
304
+ if (isEFTemporal(target)) {
305
+ const timing = effect.getTiming();
306
+ const duration = Number(timing.duration) ?? 0;
307
+ const delay = Number(timing.delay);
308
+ const newTime = Math.floor(
309
+ Math.min(target.ownCurrentTimeMs, duration - 1 + delay)
310
+ );
311
+ if (Number.isNaN(newTime)) {
312
+ return;
313
+ }
314
+ animation.currentTime = newTime;
315
+ } else if (target) {
316
+ const nearestTimegroup = target.closest("ef-timegroup");
317
+ if (!nearestTimegroup) {
318
+ return;
319
+ }
320
+ const timing = effect.getTiming();
321
+ const duration = Number(timing.duration) ?? 0;
322
+ const delay = Number(timing.delay);
323
+ const newTime = Math.floor(
324
+ Math.min(nearestTimegroup.ownCurrentTimeMs, duration - 1 + delay)
325
+ );
326
+ if (Number.isNaN(newTime)) {
327
+ return;
328
+ }
329
+ animation.currentTime = newTime;
330
+ }
331
+ }
332
+ }
273
333
  }
274
334
  get hasOwnDuration() {
275
335
  return true;
@@ -300,9 +360,6 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
300
360
  }
301
361
  return Math.max(...durations) - this.trimStartMs - this.trimEndMs;
302
362
  }
303
- get startTimeMs() {
304
- return getStartTimeMs(this);
305
- }
306
363
  #audioContext;
307
364
  async fetchAudioSpanningTime(fromMs, toMs) {
308
365
  if (this.sourceInMs) {
@@ -325,11 +382,11 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
325
382
  return;
326
383
  }
327
384
  const start = audioTrackIndex.initSegment.offset;
328
- const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size - 1;
385
+ const end = audioTrackIndex.initSegment.offset + audioTrackIndex.initSegment.size;
329
386
  const audioInitFragmentRequest = this.fetch(
330
387
  this.fragmentTrackPath(String(audioTrackId)),
331
388
  {
332
- headers: { Range: `bytes=${start}-${end}` }
389
+ headers: { Range: `bytes=${start}-${end - 1}` }
333
390
  }
334
391
  );
335
392
  const fragments = Object.values(audioTrackIndex.segments).filter(
@@ -350,11 +407,11 @@ class EFMedia extends EFSourceMixin(EFTemporal(FetchMixin(LitElement)), {
350
407
  return;
351
408
  }
352
409
  const fragmentStart = firstFragment.offset;
353
- const fragmentEnd = lastFragment.offset + lastFragment.size - 1;
410
+ const fragmentEnd = lastFragment.offset + lastFragment.size;
354
411
  const audioFragmentRequest = this.fetch(
355
412
  this.fragmentTrackPath(String(audioTrackId)),
356
413
  {
357
- headers: { Range: `bytes=${fragmentStart}-${fragmentEnd}` }
414
+ headers: { Range: `bytes=${fragmentStart}-${fragmentEnd - 1}` }
358
415
  }
359
416
  );
360
417
  const initResponse = await audioInitFragmentRequest;
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
2
+ declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
3
3
  declare class TestTemporal extends TestTemporal_base {
4
4
  }
5
5
  declare global {
@@ -1,5 +1,5 @@
1
1
  import { LitElement, ReactiveController } from 'lit';
2
- import { EFTimegroup } from './EFTimegroup.ts';
2
+ import { EFTimegroup } from './EFTimegroup.js';
3
3
  import { Task } from '@lit/task';
4
4
  export declare const timegroupContext: {
5
5
  __context__: EFTimegroup;
@@ -20,6 +20,9 @@ export declare class TemporalMixinInterface {
20
20
  set sourceout(value: string);
21
21
  get durationMs(): number;
22
22
  get startTimeMs(): number;
23
+ /**
24
+ * The start time of the element within its parent timegroup.
25
+ */
23
26
  get startTimeWithinParentMs(): number;
24
27
  get endTimeMs(): number;
25
28
  get ownCurrentTimeMs(): number;
@@ -218,6 +218,9 @@ const EFTemporal = (superClass) => {
218
218
  }
219
219
  return parent;
220
220
  }
221
+ /**
222
+ * The start time of the element within its parent timegroup.
223
+ */
221
224
  get startTimeWithinParentMs() {
222
225
  if (!this.parentTemporal) {
223
226
  return 0;
@@ -1,8 +1,8 @@
1
1
  import { LitElement } from 'lit';
2
- declare const TestContext_base: (new (...args: any[]) => import('../gui/ContextMixin.ts').ContextMixinInterface) & typeof LitElement;
2
+ declare const TestContext_base: (new (...args: any[]) => import('../gui/ContextMixin.js').ContextMixinInterface) & typeof LitElement;
3
3
  declare class TestContext extends TestContext_base {
4
4
  }
5
- declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
5
+ declare const TestTemporal_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
6
6
  declare class TestTemporal extends TestTemporal_base {
7
7
  get hasOwnDuration(): boolean;
8
8
  }
@@ -1,7 +1,7 @@
1
1
  import { Task } from '@lit/task';
2
2
  import { LitElement, PropertyValueMap } from 'lit';
3
3
  export declare const shallowGetTimegroups: (element: Element, groups?: EFTimegroup[]) => EFTimegroup[];
4
- declare const EFTimegroup_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
4
+ declare const EFTimegroup_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
5
5
  export declare class EFTimegroup extends EFTimegroup_base {
6
6
  #private;
7
7
  static styles: import('lit').CSSResult;
@@ -28,9 +28,9 @@ export declare class EFTimegroup extends EFTimegroup_base {
28
28
  buffer: import('mp4box').MP4ArrayBuffer;
29
29
  mp4File: import('../../../assets/src/MP4File.ts').MP4File;
30
30
  }[] | undefined)[]>;
31
- get childTemporals(): import('./EFTemporal.ts').TemporalMixinInterface[];
31
+ get childTemporals(): import('./EFTemporal.js').TemporalMixinInterface[];
32
32
  protected updated(changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void;
33
- get contextProvider(): import('../gui/ContextMixin.ts').ContextMixinInterface | null;
33
+ get contextProvider(): import('../gui/ContextMixin.js').ContextMixinInterface | null;
34
34
  /**
35
35
  * Returns true if the timegroup should be wrapped with a workbench.
36
36
  *
@@ -1,5 +1,5 @@
1
1
  import { Task } from '@lit/task';
2
- import { EFMedia } from './EFMedia.ts';
2
+ import { EFMedia } from './EFMedia.js';
3
3
  declare const EFVideo_base: typeof EFMedia;
4
4
  export declare class EFVideo extends EFVideo_base {
5
5
  #private;
@@ -66,8 +66,16 @@ let EFVideo = class extends TWMixin(EFMedia) {
66
66
  if (!(frame && ctx)) {
67
67
  return;
68
68
  }
69
- this.canvasElement.width = frame?.codedWidth;
70
- this.canvasElement.height = frame?.codedHeight;
69
+ if (frame?.codedWidth && frame?.codedHeight) {
70
+ if (this.canvasElement.width !== frame.codedWidth || this.canvasElement.height !== frame.codedHeight) {
71
+ this.canvasElement.width = frame.codedWidth;
72
+ this.canvasElement.height = frame.codedHeight;
73
+ }
74
+ }
75
+ if (frame.format === null) {
76
+ console.warn("Frame format is null", frame);
77
+ return seekToMs;
78
+ }
71
79
  ctx.drawImage(
72
80
  frame,
73
81
  0,
@@ -1,13 +1,15 @@
1
- import { EFAudio } from './EFAudio.ts';
1
+ import { EFAudio } from './EFAudio.js';
2
2
  import { Task } from '@lit/task';
3
3
  import { LitElement, PropertyValueMap } from 'lit';
4
4
  import { Ref } from 'lit/directives/ref.js';
5
- import { EFVideo } from './EFVideo.ts';
6
- declare const EFWaveform_base: (new (...args: any[]) => import('./EFTemporal.ts').TemporalMixinInterface) & typeof LitElement;
5
+ import { EFVideo } from './EFVideo.js';
6
+ declare const EFWaveform_base: (new (...args: any[]) => import('./EFTemporal.js').TemporalMixinInterface) & typeof LitElement;
7
7
  export declare class EFWaveform extends EFWaveform_base {
8
8
  static styles: import('lit').CSSResult[];
9
9
  canvasRef: Ref<HTMLCanvasElement>;
10
10
  private ctx;
11
+ private resizeObserver?;
12
+ private mutationObserver?;
11
13
  createRenderRoot(): this;
12
14
  render(): import('lit-html').TemplateResult<1>;
13
15
  mode: "roundBars" | "bars" | "bricks" | "equalizer" | "curve" | "line" | "pixel" | "wave";
@@ -15,6 +17,8 @@ export declare class EFWaveform extends EFWaveform_base {
15
17
  targetSelector: string;
16
18
  set target(value: string);
17
19
  connectedCallback(): void;
20
+ disconnectedCallback(): void;
21
+ private resizeCanvas;
18
22
  protected initCanvas(): CanvasRenderingContext2D | null;
19
23
  protected drawBars(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
20
24
  protected drawBricks(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
@@ -24,7 +28,6 @@ export declare class EFWaveform extends EFWaveform_base {
24
28
  protected drawCurve(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
25
29
  protected drawPixel(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
26
30
  protected drawWave(ctx: CanvasRenderingContext2D, frequencyData: Uint8Array): void;
27
- private lastFrameTime;
28
31
  frameTask: Task<readonly [import('@lit/task').TaskStatus], void>;
29
32
  get durationMs(): number;
30
33
  get targetElement(): EFAudio | EFVideo;
@@ -26,53 +26,39 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
26
26
  this.mode = "bars";
27
27
  this.color = "currentColor";
28
28
  this.targetSelector = "";
29
- this.lastFrameTime = 0;
30
29
  this.frameTask = new Task(this, {
31
30
  autoRun: EF_INTERACTIVE,
32
31
  args: () => [this.targetElement.audioBufferTask.status],
33
32
  task: async () => {
34
- const currentTime = performance.now();
35
- const timeSinceLastFrame = this.lastFrameTime ? currentTime - this.lastFrameTime : 0;
36
- console.log(`Time since last frame: ${timeSinceLastFrame.toFixed(2)}ms`);
37
- this.lastFrameTime = currentTime;
38
33
  await this.targetElement.audioBufferTask.taskComplete;
39
34
  this.ctx ||= this.initCanvas();
40
35
  const ctx = this.ctx;
41
36
  if (!ctx) return;
42
37
  if (!this.targetElement.audioBufferTask.value) return;
43
38
  if (this.targetElement.trimAdjustedOwnCurrentTimeMs > 0) {
44
- const FRAMES_TO_ANALYZE = 4;
45
- const FRAME_DURATION_MS = 48e3 / 100;
46
- const multiFrameData = [];
47
- for (let i = 0; i < FRAMES_TO_ANALYZE; i++) {
48
- const frameOffset = i - Math.floor(FRAMES_TO_ANALYZE / 2);
49
- const audioContext = new OfflineAudioContext(2, 48e3 / 25, 48e3);
50
- const audioBufferSource = audioContext.createBufferSource();
51
- audioBufferSource.buffer = this.targetElement.audioBufferTask.value.buffer;
52
- const analyser = audioContext.createAnalyser();
53
- analyser.fftSize = 128 / 2;
54
- analyser.smoothingTimeConstant = 0.1;
55
- audioBufferSource.connect(analyser);
56
- const startTime = Math.max(
57
- 0,
58
- (this.targetElement.trimAdjustedOwnCurrentTimeMs - this.targetElement.audioBufferTask.value.startOffsetMs) / 1e3 + frameOffset * FRAME_DURATION_MS / 1e3
59
- );
60
- audioBufferSource.start(0, startTime, FRAME_DURATION_MS / 1e3);
61
- await audioContext.startRendering();
62
- const frameData = new Uint8Array(analyser.frequencyBinCount);
63
- analyser.getByteFrequencyData(frameData);
64
- multiFrameData.push(frameData);
65
- }
66
- const dataLength = multiFrameData[0]?.length ?? 0;
67
- const smoothedData = new Uint8Array(dataLength);
68
- for (let i = 0; i < smoothedData.length; i++) {
69
- let sum = 0;
70
- for (const frameData of multiFrameData) {
71
- sum += frameData[i] ?? 0;
72
- }
73
- let avg = sum / FRAMES_TO_ANALYZE;
74
- avg = (avg / 255) ** 1.2 * 255;
75
- smoothedData[i] = Math.round(avg);
39
+ const FRAME_DURATION_MS = 48e3 / 1e3;
40
+ const FRAME_SMEAR_MS = FRAME_DURATION_MS * 1;
41
+ const FRAME_SMEAR_S = FRAME_SMEAR_MS / 1e3;
42
+ const audioContext = new OfflineAudioContext(2, 48e3 / 25, 48e3);
43
+ const audioBufferSource = audioContext.createBufferSource();
44
+ audioBufferSource.buffer = this.targetElement.audioBufferTask.value.buffer;
45
+ const analyser = audioContext.createAnalyser();
46
+ analyser.fftSize = 128 * 8;
47
+ audioBufferSource.connect(analyser);
48
+ const startTime = Math.max(
49
+ 0,
50
+ (this.targetElement.trimAdjustedOwnCurrentTimeMs - this.targetElement.audioBufferTask.value.startOffsetMs) / 1e3
51
+ );
52
+ audioBufferSource.start(0, startTime, FRAME_SMEAR_S);
53
+ await audioContext.startRendering();
54
+ const frameData = new Uint8Array(analyser.frequencyBinCount);
55
+ analyser.getByteFrequencyData(frameData);
56
+ const smoothedData = frameData.slice(0, frameData.length / 2);
57
+ if (this.color === "currentColor") {
58
+ const computedStyle = getComputedStyle(this);
59
+ const currentColor = computedStyle.color;
60
+ ctx.strokeStyle = currentColor;
61
+ ctx.fillStyle = currentColor;
76
62
  }
77
63
  switch (this.mode) {
78
64
  case "bars":
@@ -118,9 +104,31 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
118
104
  if (this.targetElement) {
119
105
  new CrossUpdateController(this.targetElement, this);
120
106
  }
107
+ this.resizeObserver = new ResizeObserver(() => {
108
+ this.resizeCanvas();
109
+ });
110
+ this.resizeObserver.observe(this);
111
+ this.mutationObserver = new MutationObserver((mutationsList) => {
112
+ for (const mutation of mutationsList) {
113
+ if (mutation.type === "attributes") {
114
+ this.frameTask.run();
115
+ }
116
+ }
117
+ });
118
+ this.mutationObserver.observe(this, { attributes: true });
119
+ }
120
+ disconnectedCallback() {
121
+ super.disconnectedCallback();
122
+ this.resizeObserver?.disconnect();
123
+ this.mutationObserver?.disconnect();
124
+ }
125
+ resizeCanvas() {
126
+ this.ctx = this.initCanvas();
127
+ if (this.ctx) {
128
+ this.frameTask.run();
129
+ }
121
130
  }
122
131
  initCanvas() {
123
- console.count("initCanvas");
124
132
  const canvas = this.canvasRef.value;
125
133
  if (!canvas) return null;
126
134
  const rect = this.getBoundingClientRect();
@@ -135,8 +143,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
135
143
  return ctx;
136
144
  }
137
145
  drawBars(ctx, frequencyData) {
138
- ctx.strokeStyle = this.color;
139
- ctx.fillStyle = this.color;
140
146
  const canvas = ctx.canvas;
141
147
  const waveWidth = canvas.width / devicePixelRatio;
142
148
  const waveHeight = canvas.height / devicePixelRatio;
@@ -151,8 +157,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
151
157
  });
152
158
  }
153
159
  drawBricks(ctx, frequencyData) {
154
- ctx.strokeStyle = this.color;
155
- ctx.fillStyle = this.color;
156
160
  const canvas = ctx.canvas;
157
161
  const waveWidth = canvas.width / devicePixelRatio;
158
162
  const waveHeight = canvas.height / devicePixelRatio;
@@ -176,8 +180,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
176
180
  });
177
181
  }
178
182
  drawLine(ctx, frequencyData) {
179
- ctx.strokeStyle = this.color;
180
- ctx.fillStyle = this.color;
181
183
  const canvas = ctx.canvas;
182
184
  const waveWidth = canvas.width / devicePixelRatio;
183
185
  const waveHeight = canvas.height / devicePixelRatio;
@@ -196,8 +198,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
196
198
  ctx.stroke();
197
199
  }
198
200
  drawRoundBars(ctx, frequencyData) {
199
- ctx.strokeStyle = this.color;
200
- ctx.fillStyle = this.color;
201
201
  const canvas = ctx.canvas;
202
202
  const waveWidth = canvas.width / devicePixelRatio;
203
203
  const waveHeight = canvas.height / devicePixelRatio;
@@ -216,8 +216,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
216
216
  });
217
217
  }
218
218
  drawEqualizer(ctx, frequencyData) {
219
- ctx.strokeStyle = this.color;
220
- ctx.fillStyle = this.color;
221
219
  const canvas = ctx.canvas;
222
220
  const waveWidth = canvas.width / devicePixelRatio;
223
221
  const waveHeight = canvas.height / devicePixelRatio;
@@ -237,8 +235,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
237
235
  });
238
236
  }
239
237
  drawCurve(ctx, frequencyData) {
240
- ctx.strokeStyle = this.color;
241
- ctx.fillStyle = this.color;
242
238
  const canvas = ctx.canvas;
243
239
  const waveWidth = canvas.width / devicePixelRatio;
244
240
  const waveHeight = canvas.height / devicePixelRatio;
@@ -257,8 +253,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
257
253
  ctx.stroke();
258
254
  }
259
255
  drawPixel(ctx, frequencyData) {
260
- ctx.strokeStyle = this.color;
261
- ctx.fillStyle = this.color;
262
256
  const canvas = ctx.canvas;
263
257
  const waveWidth = canvas.width / devicePixelRatio;
264
258
  const waveHeight = canvas.height / devicePixelRatio;
@@ -273,8 +267,6 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
273
267
  });
274
268
  }
275
269
  drawWave(ctx, frequencyData) {
276
- ctx.strokeStyle = this.color;
277
- ctx.fillStyle = this.color;
278
270
  const canvas = ctx.canvas;
279
271
  const waveWidth = canvas.width / devicePixelRatio;
280
272
  const waveHeight = canvas.height / devicePixelRatio;
@@ -285,7 +277,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
285
277
  ctx.moveTo(0, baseline);
286
278
  ctx.lineTo(waveWidth, baseline);
287
279
  ctx.strokeStyle = this.color;
288
- ctx.lineWidth = 2;
280
+ ctx.lineWidth = 1;
289
281
  ctx.stroke();
290
282
  frequencyData.forEach((value, i) => {
291
283
  const x = i * (waveWidth / frequencyData.length);
@@ -306,7 +298,7 @@ let EFWaveform = class extends EFTemporal(TWMixin(LitElement)) {
306
298
  }
307
299
  updated(changedProperties) {
308
300
  super.updated(changedProperties);
309
- if (changedProperties.has("color") || changedProperties.has("mode")) {
301
+ if (changedProperties.size > 0) {
310
302
  this.frameTask.run();
311
303
  }
312
304
  }
@@ -1,5 +1,5 @@
1
- import { ReactiveController, LitElement } from 'lit';
2
- import { EFTimegroup } from './EFTimegroup.ts';
1
+ import { LitElement, ReactiveController } from 'lit';
2
+ import { EFTimegroup } from './EFTimegroup.js';
3
3
  export declare class TimegroupController implements ReactiveController {
4
4
  private host;
5
5
  private child;
@@ -1,3 +1,3 @@
1
- import { EFTimegroup } from './EFTimegroup.ts';
1
+ import { EFTimegroup } from './EFTimegroup.js';
2
2
  export declare const getRootTimeGroup: (element: Element) => EFTimegroup | null;
3
3
  export declare const getStartTimeMs: (element: Element) => number;
@@ -1,5 +1,5 @@
1
1
  import { LitElement } from 'lit';
2
- declare const TestContext_base: (new (...args: any[]) => import('./ContextMixin.ts').ContextMixinInterface) & typeof LitElement;
2
+ declare const TestContext_base: (new (...args: any[]) => import('./ContextMixin.js').ContextMixinInterface) & typeof LitElement;
3
3
  declare class TestContext extends TestContext_base {
4
4
  }
5
5
  declare global {
@@ -1,6 +1,6 @@
1
1
  import { LitElement } from 'lit';
2
2
  import { createRef } from 'lit/directives/ref.js';
3
- import { EFTimegroup } from '../elements/EFTimegroup.ts';
3
+ import { EFTimegroup } from '../elements/EFTimegroup.js';
4
4
  export declare class ContextMixinInterface extends LitElement {
5
5
  signingURL?: string;
6
6
  apiHost?: string;
@@ -83,14 +83,14 @@ function ContextMixin(superClass) {
83
83
  const scale = stageHeight / canvasHeight;
84
84
  if (this.stageScale !== scale) {
85
85
  canvasElement.style.transform = `scale(${scale})`;
86
- canvasElement.style.transformOrigin = "top";
86
+ canvasElement.style.transformOrigin = "center left";
87
87
  }
88
88
  this.stageScale = scale;
89
89
  } else {
90
90
  const scale = stageWidth / canvasWidth;
91
91
  if (this.stageScale !== scale) {
92
92
  canvasElement.style.transform = `scale(${scale})`;
93
- canvasElement.style.transformOrigin = "top";
93
+ canvasElement.style.transformOrigin = "center left";
94
94
  }
95
95
  this.stageScale = scale;
96
96
  }
@@ -187,6 +187,12 @@ function ContextMixin(superClass) {
187
187
  }
188
188
  await timegroup.waitForMediaDurations();
189
189
  let currentMs = timegroup.currentTimeMs;
190
+ const fromMs = currentMs;
191
+ const toMs = timegroup.endTimeMs;
192
+ if (fromMs >= toMs) {
193
+ this.pause();
194
+ return;
195
+ }
190
196
  let bufferCount = 0;
191
197
  this.#playbackAudioContext = new AudioContext({
192
198
  latencyHint: "playback"
@@ -213,8 +219,6 @@ function ContextMixin(superClass) {
213
219
  fillBuffer();
214
220
  }
215
221
  };
216
- const fromMs = currentMs;
217
- const toMs = timegroup.endTimeMs;
218
222
  const queueBufferSource = async () => {
219
223
  if (currentMs >= toMs) {
220
224
  return false;
@@ -1,11 +1,11 @@
1
1
  import { LitElement, PropertyValueMap, ReactiveController, TemplateResult, nothing } from 'lit';
2
- import { EFAudio } from '../elements/EFAudio.ts';
3
- import { EFImage } from '../elements/EFImage.ts';
4
- import { TemporalMixinInterface } from '../elements/EFTemporal.ts';
5
- import { EFTimegroup } from '../elements/EFTimegroup.ts';
6
- import { EFVideo } from '../elements/EFVideo.ts';
7
- import { TimegroupController } from '../elements/TimegroupController.ts';
8
- import { FocusContext } from './focusContext.ts';
2
+ import { EFAudio } from '../elements/EFAudio.js';
3
+ import { EFImage } from '../elements/EFImage.js';
4
+ import { TemporalMixinInterface } from '../elements/EFTemporal.js';
5
+ import { EFTimegroup } from '../elements/EFTimegroup.js';
6
+ import { EFVideo } from '../elements/EFVideo.js';
7
+ import { TimegroupController } from '../elements/TimegroupController.js';
8
+ import { FocusContext } from './focusContext.js';
9
9
  declare class ElementFilmstripController implements ReactiveController {
10
10
  private host;
11
11
  private filmstrip;