@clockworkdog/cogs-client 3.0.0-alpha.9 → 3.0.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 +20 -9
- package/dist/CogsConnection.d.ts +0 -4
- package/dist/CogsConnection.js +0 -10
- package/dist/browser/index.mjs +1901 -2707
- package/dist/browser/index.umd.js +13 -13
- package/dist/index.d.ts +1 -5
- package/dist/index.js +1 -3
- package/dist/state-based/MediaClipManager.d.ts +66 -0
- package/dist/state-based/MediaClipManager.js +420 -0
- package/dist/state-based/MediaPreloader.d.ts +14 -0
- package/dist/state-based/MediaPreloader.js +93 -0
- package/dist/state-based/SurfaceManager.d.ts +8 -1
- package/dist/state-based/SurfaceManager.js +36 -9
- package/dist/types/MediaSchema.d.ts +6 -0
- package/dist/types/MediaSchema.js +2 -0
- package/dist/utils/device.d.ts +2 -0
- package/dist/utils/device.js +4 -0
- package/dist/utils/getStateAtTime.d.ts +12 -2
- package/dist/utils/getStateAtTime.js +6 -1
- package/dist/utils/modulo.d.ts +6 -0
- package/dist/utils/modulo.js +17 -0
- package/package.json +3 -6
- package/dist/AudioPlayer.d.ts +0 -49
- package/dist/AudioPlayer.js +0 -474
- package/dist/VideoPlayer.d.ts +0 -49
- package/dist/VideoPlayer.js +0 -385
- package/dist/state-based/AudioManager.d.ts +0 -15
- package/dist/state-based/AudioManager.js +0 -116
- package/dist/state-based/ClipManager.d.ts +0 -22
- package/dist/state-based/ClipManager.js +0 -53
- package/dist/state-based/ImageManager.d.ts +0 -9
- package/dist/state-based/ImageManager.js +0 -53
- package/dist/state-based/VideoManager.d.ts +0 -15
- package/dist/state-based/VideoManager.js +0 -129
- package/dist/types/AllMediaClipStatesMessage.d.ts +0 -5
- package/dist/types/AllMediaClipStatesMessage.js +0 -1
- package/dist/types/AudioState.d.ts +0 -39
- package/dist/types/AudioState.js +0 -1
- package/dist/types/MediaClipStateMessage.d.ts +0 -7
- package/dist/types/MediaClipStateMessage.js +0 -1
- package/dist/types/VideoState.d.ts +0 -26
- package/dist/types/VideoState.js +0 -5
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import { ImageManager } from './
|
|
2
|
-
import {
|
|
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
|
-
|
|
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
|
-
|
|
71
|
-
|
|
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,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 {
|
|
2
|
-
export
|
|
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
|
|
6
|
+
"version": "3.0.0",
|
|
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
|
|
41
|
-
"howler": "clockwork-dog/howler.js#fix-looping-clips",
|
|
40
|
+
"@clockworkdog/timesync": "^3.0.0",
|
|
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
|
}
|
package/dist/AudioPlayer.d.ts
DELETED
|
@@ -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 {};
|