@clockworkdog/cogs-client 3.0.0-alpha.9 → 3.0.1

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 (42) hide show
  1. package/README.md +20 -9
  2. package/dist/CogsConnection.d.ts +0 -4
  3. package/dist/CogsConnection.js +0 -10
  4. package/dist/browser/index.mjs +1901 -2707
  5. package/dist/browser/index.umd.js +13 -13
  6. package/dist/index.d.ts +1 -5
  7. package/dist/index.js +1 -3
  8. package/dist/state-based/MediaClipManager.d.ts +66 -0
  9. package/dist/state-based/MediaClipManager.js +420 -0
  10. package/dist/state-based/MediaPreloader.d.ts +14 -0
  11. package/dist/state-based/MediaPreloader.js +93 -0
  12. package/dist/state-based/SurfaceManager.d.ts +8 -1
  13. package/dist/state-based/SurfaceManager.js +36 -9
  14. package/dist/types/MediaSchema.d.ts +6 -0
  15. package/dist/types/MediaSchema.js +2 -0
  16. package/dist/utils/device.d.ts +2 -0
  17. package/dist/utils/device.js +4 -0
  18. package/dist/utils/getStateAtTime.d.ts +12 -2
  19. package/dist/utils/getStateAtTime.js +6 -1
  20. package/dist/utils/modulo.d.ts +6 -0
  21. package/dist/utils/modulo.js +17 -0
  22. package/package.json +3 -6
  23. package/dist/AudioPlayer.d.ts +0 -49
  24. package/dist/AudioPlayer.js +0 -474
  25. package/dist/VideoPlayer.d.ts +0 -49
  26. package/dist/VideoPlayer.js +0 -385
  27. package/dist/state-based/AudioManager.d.ts +0 -15
  28. package/dist/state-based/AudioManager.js +0 -116
  29. package/dist/state-based/ClipManager.d.ts +0 -22
  30. package/dist/state-based/ClipManager.js +0 -53
  31. package/dist/state-based/ImageManager.d.ts +0 -9
  32. package/dist/state-based/ImageManager.js +0 -53
  33. package/dist/state-based/VideoManager.d.ts +0 -15
  34. package/dist/state-based/VideoManager.js +0 -129
  35. package/dist/types/AllMediaClipStatesMessage.d.ts +0 -5
  36. package/dist/types/AllMediaClipStatesMessage.js +0 -1
  37. package/dist/types/AudioState.d.ts +0 -39
  38. package/dist/types/AudioState.js +0 -1
  39. package/dist/types/MediaClipStateMessage.d.ts +0 -7
  40. package/dist/types/MediaClipStateMessage.js +0 -1
  41. package/dist/types/VideoState.d.ts +0 -26
  42. package/dist/types/VideoState.js +0 -5
@@ -1,6 +1,5 @@
1
- import { ImageManager } from './ImageManager';
2
- import { VideoManager } from './VideoManager';
3
- import { AudioManager } from './AudioManager';
1
+ import { AudioManager, ImageManager, VideoManager } from './MediaClipManager';
2
+ import { MediaPreloader } from './MediaPreloader';
4
3
  export const DATA_CLIP_ID = 'data-clip-id';
5
4
  /**
6
5
  * The SurfaceManager will receive state updates and:
@@ -8,18 +7,37 @@ export const DATA_CLIP_ID = 'data-clip-id';
8
7
  * - Instantiate a ClipManager attached to each respective element
9
8
  */
10
9
  export class SurfaceManager {
10
+ constructAssetUrl;
11
+ getAudioOutput;
12
+ mediaPreloader;
11
13
  _state = {};
12
14
  setState(newState) {
13
15
  this._state = newState;
14
16
  this.update();
15
17
  }
18
+ _volume = 1;
19
+ get volume() {
20
+ return this._volume;
21
+ }
22
+ set volume(newVolume) {
23
+ this._volume = newVolume;
24
+ Object.values(this.resources).forEach(({ manager }) => {
25
+ if (manager instanceof AudioManager || manager instanceof VideoManager) {
26
+ manager.volume = newVolume;
27
+ }
28
+ });
29
+ }
16
30
  _element;
17
31
  get element() {
18
32
  return this._element;
19
33
  }
20
34
  resources = {};
21
- constructor(testState) {
35
+ constructor(constructAssetUrl, getAudioOutput, testState, mediaPreloader = new MediaPreloader(constructAssetUrl)) {
36
+ this.constructAssetUrl = constructAssetUrl;
37
+ this.getAudioOutput = getAudioOutput;
38
+ this.mediaPreloader = mediaPreloader;
22
39
  this._element = document.createElement('div');
40
+ this._element.className = 'surface-manager';
23
41
  this._element.style.width = '100%';
24
42
  this._element.style.height = '100%';
25
43
  this._state = testState || {};
@@ -62,14 +80,23 @@ export class SurfaceManager {
62
80
  if (!resource.manager) {
63
81
  switch (clip.type) {
64
82
  case 'image':
65
- resource.manager = new ImageManager(this._element, resource.element, clip);
83
+ resource.manager = new ImageManager(this._element, resource.element, clip, this.constructAssetUrl, this.getAudioOutput, this.mediaPreloader);
84
+ resource.manager.loop();
66
85
  break;
67
- case 'audio':
68
- resource.manager = new AudioManager(this._element, resource.element, clip);
86
+ case 'audio': {
87
+ const audioManager = new AudioManager(this._element, resource.element, clip, this.constructAssetUrl, this.getAudioOutput, this.mediaPreloader);
88
+ resource.manager = audioManager;
89
+ audioManager.volume = this._volume;
90
+ audioManager.loop();
69
91
  break;
70
- case 'video':
71
- resource.manager = new VideoManager(this._element, resource.element, clip);
92
+ }
93
+ case 'video': {
94
+ const videoManager = new VideoManager(this._element, resource.element, clip, this.constructAssetUrl, this.getAudioOutput, this.mediaPreloader);
95
+ resource.manager = videoManager;
96
+ videoManager.volume = this._volume;
97
+ videoManager.loop();
72
98
  break;
99
+ }
73
100
  }
74
101
  }
75
102
  else {
@@ -24,12 +24,14 @@ declare const AudioMetadata: z.ZodObject<{
24
24
  type: z.ZodLiteral<"audio">;
25
25
  file: z.ZodString;
26
26
  audioOutput: z.ZodString;
27
+ enablePlaybackRateAdjustment: z.ZodBoolean;
27
28
  }, z.core.$strip>;
28
29
  export type VideoMetadata = z.infer<typeof VideoMetadata>;
29
30
  declare const VideoMetadata: z.ZodObject<{
30
31
  type: z.ZodLiteral<"video">;
31
32
  file: z.ZodString;
32
33
  audioOutput: z.ZodString;
34
+ enablePlaybackRateAdjustment: z.ZodBoolean;
33
35
  fit: z.ZodUnion<readonly [z.ZodLiteral<"contain">, z.ZodLiteral<"cover">, z.ZodLiteral<"none">]>;
34
36
  }, z.core.$strip>;
35
37
  export type NullKeyframe = z.infer<typeof NullKeyframe>;
@@ -153,6 +155,7 @@ export declare const MediaSurfaceStateSchema: z.ZodRecord<z.ZodString, z.ZodUnio
153
155
  type: z.ZodLiteral<"audio">;
154
156
  file: z.ZodString;
155
157
  audioOutput: z.ZodString;
158
+ enablePlaybackRateAdjustment: z.ZodBoolean;
156
159
  }, z.core.$strip>, z.ZodObject<{
157
160
  keyframes: z.ZodTuple<[z.ZodTuple<[z.ZodNumber, z.ZodObject<{
158
161
  set: z.ZodOptional<z.ZodObject<{
@@ -179,6 +182,7 @@ export declare const MediaSurfaceStateSchema: z.ZodRecord<z.ZodString, z.ZodUnio
179
182
  type: z.ZodLiteral<"video">;
180
183
  file: z.ZodString;
181
184
  audioOutput: z.ZodString;
185
+ enablePlaybackRateAdjustment: z.ZodBoolean;
182
186
  fit: z.ZodUnion<readonly [z.ZodLiteral<"contain">, z.ZodLiteral<"cover">, z.ZodLiteral<"none">]>;
183
187
  }, z.core.$strip>]>>;
184
188
  export type ImageOptions = VisualProperties;
@@ -194,6 +198,7 @@ export type AudioState = {
194
198
  type: 'audio';
195
199
  file: string;
196
200
  audioOutput: string;
201
+ enablePlaybackRateAdjustment: boolean;
197
202
  keyframes: [InitialAudioKeyframe, ...Array<AudioKeyframe | NullKeyframe>];
198
203
  };
199
204
  export type VideoState = {
@@ -201,6 +206,7 @@ export type VideoState = {
201
206
  file: string;
202
207
  fit: 'cover' | 'contain' | 'none';
203
208
  audioOutput: string;
209
+ enablePlaybackRateAdjustment: boolean;
204
210
  keyframes: [InitialVideoKeyframe, ...Array<VideoKeyframe | NullKeyframe>];
205
211
  };
206
212
  export type MediaClipState = ImageState | AudioState | VideoState;
@@ -19,11 +19,13 @@ const AudioMetadata = z.object({
19
19
  type: z.literal('audio'),
20
20
  file: z.string(),
21
21
  audioOutput: z.string(),
22
+ enablePlaybackRateAdjustment: z.boolean(),
22
23
  });
23
24
  const VideoMetadata = z.object({
24
25
  type: z.literal('video'),
25
26
  file: z.string(),
26
27
  audioOutput: z.string(),
28
+ enablePlaybackRateAdjustment: z.boolean(),
27
29
  fit: z.union([z.literal('contain'), z.literal('cover'), z.literal('none')]),
28
30
  });
29
31
  const NullKeyframe = z.tuple([z.number(), z.null()]);
@@ -0,0 +1,2 @@
1
+ export declare const IS_IOS: boolean;
2
+ export declare const IS_WEBKIT: boolean;
@@ -0,0 +1,4 @@
1
+ // Check an iOS-only property (See https://developer.mozilla.org/en-US/docs/Web/API/Navigator#non-standard_properties)
2
+ export const IS_IOS = typeof navigator !== 'undefined' && typeof navigator.standalone !== 'undefined';
3
+ // https://evilmartians.com/chronicles/how-to-detect-safari-and-ios-versions-with-ease
4
+ export const IS_WEBKIT = 'GestureEvent' in window;
@@ -1,5 +1,15 @@
1
- import { MediaClipState, TemporalProperties } from '../types/MediaSchema';
2
- export declare function getStateAtTime<State extends MediaClipState>(state: State, time: number): State['keyframes'][0][1]['set'] | undefined;
1
+ import { AudioState, ImageState, TemporalProperties, VideoState } from '../types/MediaSchema';
2
+ export type MinimalClipState = {
3
+ type: 'image';
4
+ keyframes: ImageState['keyframes'];
5
+ } | {
6
+ type: 'audio';
7
+ keyframes: AudioState['keyframes'];
8
+ } | {
9
+ type: 'video';
10
+ keyframes: VideoState['keyframes'];
11
+ };
12
+ export declare function getStateAtTime<State extends MinimalClipState>(state: State, time: number): State['keyframes'][0][1]['set'] | undefined;
3
13
  /**
4
14
  * Goes through all keyframes to lerp between many different properties
5
15
  * Note: This has no specific logic regarding types of properties
@@ -1,5 +1,10 @@
1
- import { defaultAudioOptions, defaultImageOptions, defaultVideoOptions } from '../types/MediaSchema';
1
+ import { defaultAudioOptions, defaultImageOptions, defaultVideoOptions, } from '../types/MediaSchema';
2
2
  export function getStateAtTime(state, time) {
3
+ //If there are any null keyframes the clip has been terminated
4
+ const nullKeyframes = state.keyframes.filter((kf) => kf[1] === null);
5
+ if (nullKeyframes.some((kf) => kf[0] <= time)) {
6
+ return undefined;
7
+ }
3
8
  switch (state.type) {
4
9
  case 'image': {
5
10
  const firstTimestamp = state.keyframes[0][0];
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Correct modulo operator
3
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder#description
4
+ */
5
+ export declare function modulo(n: number, divisor: number): number;
6
+ export declare function moduloDiff(n: number, m: number, divisor: number): number;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Correct modulo operator
3
+ * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Remainder#description
4
+ */
5
+ export function modulo(n, divisor) {
6
+ return ((n % divisor) + divisor) % divisor;
7
+ }
8
+ export function moduloDiff(n, m, divisor) {
9
+ n = modulo(n, divisor);
10
+ m = modulo(m, divisor);
11
+ if (Math.abs(n - m) < divisor / 2) {
12
+ return n - m;
13
+ }
14
+ else {
15
+ return n < m ? n + divisor - m : n - (m + divisor);
16
+ }
17
+ }
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "description": "Connect to COGS to build a custom Media Master",
4
4
  "author": "Clockwork Dog <info@clockwork.dog>",
5
5
  "homepage": "https://github.com/clockwork-dog/cogs-sdk/tree/main/packages/javascript",
6
- "version": "3.0.0-alpha.9",
6
+ "version": "3.0.1",
7
7
  "keywords": [],
8
8
  "license": "MIT",
9
9
  "repository": {
@@ -37,15 +37,13 @@
37
37
  "cy:generate": "cypress run --e2e"
38
38
  },
39
39
  "dependencies": {
40
- "@clockworkdog/timesync": "^3.0.0-alpha.9",
41
- "howler": "clockwork-dog/howler.js#fix-looping-clips",
40
+ "@clockworkdog/timesync": "^3.0.1",
42
41
  "reconnecting-websocket": "^4.4.0",
43
42
  "zod": "^4.1.13"
44
43
  },
45
44
  "devDependencies": {
46
45
  "@cypress/mount-utils": "^4.1.2",
47
46
  "@eslint/js": "^9.17.0",
48
- "@types/howler": "2.2.12",
49
47
  "@types/jsdom": "^27",
50
48
  "@types/node": "^22.10.2",
51
49
  "cypress": "^14.5.4",
@@ -62,6 +60,5 @@
62
60
  "typescript-eslint": "^8.18.1",
63
61
  "vite": "^7.1.12",
64
62
  "vitest": "^4.0.6"
65
- },
66
- "stableVersion": "0.0.0"
63
+ }
67
64
  }
@@ -1,49 +0,0 @@
1
- import CogsConnection from './CogsConnection';
2
- import { AudioState } from './types/AudioState';
3
- import MediaClipStateMessage from './types/MediaClipStateMessage';
4
- type EventTypes = {
5
- state: AudioState;
6
- audioClipState: MediaClipStateMessage;
7
- };
8
- export default class AudioPlayer {
9
- private cogsConnection;
10
- private eventTarget;
11
- private globalVolume;
12
- private audioClipPlayers;
13
- private sinkId;
14
- constructor(cogsConnection: CogsConnection<any>);
15
- setGlobalVolume(volume: number): void;
16
- playAudioClip(path: string, { playId, volume, fade, loop }: {
17
- playId: string;
18
- volume: number;
19
- fade?: number;
20
- loop: boolean;
21
- }): void;
22
- pauseAudioClip(path: string, { fade }: {
23
- fade?: number;
24
- }, onlySoundId?: number, allowIfPauseRequested?: boolean): void;
25
- stopAudioClip(path: string, { fade }: {
26
- fade?: number;
27
- }, onlySoundId?: number, allowIfStopRequested?: boolean): void;
28
- stopAllAudioClips(options: {
29
- fade?: number;
30
- }): void;
31
- setAudioClipVolume(path: string, { volume, fade }: {
32
- volume: number;
33
- fade?: number;
34
- }): void;
35
- private handleStoppedClip;
36
- private updateActiveAudioClip;
37
- private updateAudioClipPlayer;
38
- setAudioSink(sinkId: string): void;
39
- private updateConfig;
40
- private notifyStateListeners;
41
- private notifyClipStateListeners;
42
- addEventListener<EventName extends keyof EventTypes>(type: EventName, listener: (ev: CustomEvent<EventTypes[EventName]>) => void, options?: boolean | AddEventListenerOptions): void;
43
- removeEventListener<EventName extends keyof EventTypes>(type: EventName, listener: (ev: CustomEvent<EventTypes[EventName]>) => void, options?: boolean | EventListenerOptions): void;
44
- private dispatchEvent;
45
- private createPlayer;
46
- private createClip;
47
- private updatedClip;
48
- }
49
- export {};