@clockworkdog/cogs-client 3.0.0-alpha.0 → 3.0.0-alpha.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.
- package/dist/browser/index.mjs +682 -604
- package/dist/browser/index.umd.js +5 -5
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/utils/getStateAtTime.d.ts +28 -0
- package/dist/utils/getStateAtTime.js +141 -0
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ export { default as CogsAudioPlayer } from './AudioPlayer';
|
|
|
9
9
|
export { default as CogsVideoPlayer } from './VideoPlayer';
|
|
10
10
|
export * from './types/AudioState';
|
|
11
11
|
export { assetUrl, preloadUrl } from './utils/urls';
|
|
12
|
+
export { getStateAtTime } from './utils/getStateAtTime';
|
|
12
13
|
export * from './types/CogsPluginManifest';
|
|
13
14
|
export * as ManifestTypes from './types/ManifestTypes';
|
|
14
15
|
export * from './DataStore';
|
package/dist/index.js
CHANGED
|
@@ -5,6 +5,7 @@ export { default as CogsAudioPlayer } from './AudioPlayer';
|
|
|
5
5
|
export { default as CogsVideoPlayer } from './VideoPlayer';
|
|
6
6
|
export * from './types/AudioState';
|
|
7
7
|
export { assetUrl, preloadUrl } from './utils/urls';
|
|
8
|
+
export { getStateAtTime } from './utils/getStateAtTime';
|
|
8
9
|
export * from './types/CogsPluginManifest';
|
|
9
10
|
export * as ManifestTypes from './types/ManifestTypes';
|
|
10
11
|
export * from './DataStore';
|
|
@@ -0,0 +1,28 @@
|
|
|
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;
|
|
3
|
+
/**
|
|
4
|
+
* Goes through all keyframes to lerp between many different properties
|
|
5
|
+
* Note: This has no specific logic regarding types of properties
|
|
6
|
+
* Do not use this for setting time / rate.
|
|
7
|
+
* They behave differently in the schema. ( @see getTemporalPropertiesAtTime )
|
|
8
|
+
*
|
|
9
|
+
* @param keyframes keyframes from a given MediaClipState
|
|
10
|
+
* @param time the time (on or between keyframes) to calculate
|
|
11
|
+
* @returns a grouped object of all properties
|
|
12
|
+
*/
|
|
13
|
+
export declare function getPropertiesAtTime<P extends Record<string, unknown>>(keyframes: [number, {
|
|
14
|
+
set?: Partial<P>;
|
|
15
|
+
lerp?: Partial<P>;
|
|
16
|
+
}][], time: number): P;
|
|
17
|
+
/**
|
|
18
|
+
* Keep track of time whilst going through the keyframes at respective rate.
|
|
19
|
+
* Temporal properties cannot be interpolated in the media schema.
|
|
20
|
+
*
|
|
21
|
+
* @param keyframes temporal keyframes from an AudioClipState or VideoClipState
|
|
22
|
+
* @param time the time (on or between keyframes) to calculate
|
|
23
|
+
* @returns the temporal properties of the media at the given time
|
|
24
|
+
*/
|
|
25
|
+
export declare function getTemporalPropertiesAtTime<P extends TemporalProperties>(keyframes: [number, {
|
|
26
|
+
set?: Partial<P>;
|
|
27
|
+
lerp?: Partial<P>;
|
|
28
|
+
}][], time: number): TemporalProperties | undefined;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { defaultAudioOptions, defaultImageOptions, defaultVideoOptions } from '../types/MediaSchema';
|
|
2
|
+
export function getStateAtTime(state, time) {
|
|
3
|
+
switch (state.type) {
|
|
4
|
+
case 'image': {
|
|
5
|
+
const firstTimestamp = state.keyframes[0][0];
|
|
6
|
+
if (firstTimestamp > time) {
|
|
7
|
+
return undefined;
|
|
8
|
+
}
|
|
9
|
+
const nonNullKeyframes = state.keyframes.filter((k) => k[1] !== null);
|
|
10
|
+
const properties = getPropertiesAtTime(nonNullKeyframes, time);
|
|
11
|
+
return { ...defaultImageOptions, ...properties };
|
|
12
|
+
}
|
|
13
|
+
case 'audio': {
|
|
14
|
+
const nonNullKeyframes = state.keyframes.filter((k) => k[1] !== null);
|
|
15
|
+
const temporalProperties = getTemporalPropertiesAtTime(nonNullKeyframes, time);
|
|
16
|
+
if (!temporalProperties) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const properties = getPropertiesAtTime(nonNullKeyframes, time);
|
|
20
|
+
return { ...defaultAudioOptions, ...properties, ...temporalProperties };
|
|
21
|
+
}
|
|
22
|
+
case 'video': {
|
|
23
|
+
const nonNullKeyframes = state.keyframes.filter((k) => k[1] !== null);
|
|
24
|
+
const temporalProperties = getTemporalPropertiesAtTime(nonNullKeyframes, time);
|
|
25
|
+
if (!temporalProperties) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const properties = getPropertiesAtTime(nonNullKeyframes, time);
|
|
29
|
+
return { ...defaultVideoOptions, ...properties, ...temporalProperties };
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Goes through all keyframes to lerp between many different properties
|
|
35
|
+
* Note: This has no specific logic regarding types of properties
|
|
36
|
+
* Do not use this for setting time / rate.
|
|
37
|
+
* They behave differently in the schema. ( @see getTemporalPropertiesAtTime )
|
|
38
|
+
*
|
|
39
|
+
* @param keyframes keyframes from a given MediaClipState
|
|
40
|
+
* @param time the time (on or between keyframes) to calculate
|
|
41
|
+
* @returns a grouped object of all properties
|
|
42
|
+
*/
|
|
43
|
+
export function getPropertiesAtTime(keyframes, time) {
|
|
44
|
+
const propertyKeyframes = {};
|
|
45
|
+
for (const [timestamp, properties] of keyframes) {
|
|
46
|
+
if (timestamp <= time) {
|
|
47
|
+
// If lerp and set are both present, we assume we lerp up until the timestamp,
|
|
48
|
+
// then set to a new value
|
|
49
|
+
Object.entries(properties.lerp ?? {}).forEach(([property, value]) => {
|
|
50
|
+
propertyKeyframes[property] ?? (propertyKeyframes[property] = {});
|
|
51
|
+
propertyKeyframes[property].before = [timestamp, value];
|
|
52
|
+
});
|
|
53
|
+
Object.entries(properties.set ?? {}).forEach(([property, value]) => {
|
|
54
|
+
propertyKeyframes[property] ?? (propertyKeyframes[property] = {});
|
|
55
|
+
propertyKeyframes[property].before = [timestamp, value];
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
// We're trying to find the closest timestamp afterwards for lerping
|
|
60
|
+
// So only set if not yet set
|
|
61
|
+
Object.entries(properties.lerp ?? {}).forEach(([property, value]) => {
|
|
62
|
+
propertyKeyframes[property] ?? (propertyKeyframes[property] = {});
|
|
63
|
+
if (propertyKeyframes[property].after === undefined) {
|
|
64
|
+
propertyKeyframes[property].after = [timestamp, value];
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
const properties = {};
|
|
70
|
+
Object.entries(propertyKeyframes).forEach(([property, { before, after }]) => {
|
|
71
|
+
// There is no lerping, and it has been set before
|
|
72
|
+
// It's a constant!
|
|
73
|
+
if (after === undefined && before) {
|
|
74
|
+
properties[property] = before[1];
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
// Multiple timestamps on the same, we return after
|
|
78
|
+
if (before && after && before[0] === after[0]) {
|
|
79
|
+
properties[property] = after[1];
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
// Property has been set, and there's a lerp timestamp afterwards
|
|
83
|
+
// We've got numbers, so lets try to linearly inerpolate
|
|
84
|
+
if (before && typeof before[1] === 'number' && after && typeof after[1] === 'number') {
|
|
85
|
+
properties[property] = (before[1] + ((time - before[0]) * (after[1] - before[1])) / (after[0] - before[0]));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
return properties;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Keep track of time whilst going through the keyframes at respective rate.
|
|
93
|
+
* Temporal properties cannot be interpolated in the media schema.
|
|
94
|
+
*
|
|
95
|
+
* @param keyframes temporal keyframes from an AudioClipState or VideoClipState
|
|
96
|
+
* @param time the time (on or between keyframes) to calculate
|
|
97
|
+
* @returns the temporal properties of the media at the given time
|
|
98
|
+
*/
|
|
99
|
+
export function getTemporalPropertiesAtTime(keyframes, time) {
|
|
100
|
+
// Not defined if the media starts in the future
|
|
101
|
+
const firstKeyframe = keyframes[0];
|
|
102
|
+
if (!firstKeyframe || firstKeyframe[0] > time) {
|
|
103
|
+
return undefined;
|
|
104
|
+
}
|
|
105
|
+
let timeAtLastKeyframe = 0;
|
|
106
|
+
let { t: mediaTimeAtLastKeyframe, rate: mediaRateAtLastKeyframe } = defaultAudioOptions;
|
|
107
|
+
for (const [timestamp, properties] of keyframes) {
|
|
108
|
+
// Only calculate up to the keyframe on or before
|
|
109
|
+
if (timestamp > time)
|
|
110
|
+
break;
|
|
111
|
+
const { set } = properties;
|
|
112
|
+
if (!set)
|
|
113
|
+
continue;
|
|
114
|
+
const { t, rate } = set;
|
|
115
|
+
// time is set - no calculations needed
|
|
116
|
+
if (t !== undefined) {
|
|
117
|
+
timeAtLastKeyframe = timestamp;
|
|
118
|
+
mediaTimeAtLastKeyframe = t;
|
|
119
|
+
if (rate !== undefined) {
|
|
120
|
+
mediaRateAtLastKeyframe = rate;
|
|
121
|
+
}
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
// rate is set on it's own, calculate how much time has passed
|
|
125
|
+
if (rate !== undefined) {
|
|
126
|
+
const duration = timestamp - timeAtLastKeyframe;
|
|
127
|
+
const mediaDuration = duration * mediaRateAtLastKeyframe;
|
|
128
|
+
timeAtLastKeyframe = timestamp;
|
|
129
|
+
mediaTimeAtLastKeyframe += mediaDuration;
|
|
130
|
+
mediaRateAtLastKeyframe = rate;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
// Calculate time after last keyframe
|
|
134
|
+
const finalDuration = time - timeAtLastKeyframe;
|
|
135
|
+
const finalMediaDuration = finalDuration * mediaRateAtLastKeyframe;
|
|
136
|
+
const finalMediaTime = mediaTimeAtLastKeyframe + finalMediaDuration;
|
|
137
|
+
return {
|
|
138
|
+
rate: mediaRateAtLastKeyframe,
|
|
139
|
+
t: finalMediaTime,
|
|
140
|
+
};
|
|
141
|
+
}
|
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.
|
|
6
|
+
"version": "3.0.0-alpha.1",
|
|
7
7
|
"keywords": [],
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"repository": {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"prerelease": "yarn npm publish --access public --tag=next"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@clockworkdog/timesync": "^3.0.0-alpha.
|
|
37
|
+
"@clockworkdog/timesync": "^3.0.0-alpha.1",
|
|
38
38
|
"howler": "clockwork-dog/howler.js#fix-looping-clips",
|
|
39
39
|
"reconnecting-websocket": "^4.4.0",
|
|
40
40
|
"zod": "^4.1.13"
|