Skip to content

Commit e444fe4

Browse files
committed
feat: add support for kairos layer effects
1 parent 8af7787 commit e444fe4

10 files changed

Lines changed: 415 additions & 3 deletions

File tree

packages/timeline-state-resolver-types/src/generated/kairos.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,31 @@ export interface MappingKairosSceneLayer {
3535
mappingType: MappingKairosType.SceneLayer
3636
}
3737

38+
export interface MappingKairosSceneLayerEffect {
39+
effectType:
40+
| 'crop'
41+
| 'transform2D'
42+
| 'luminanceKey'
43+
| 'chromaKey'
44+
| 'yUVCorrection'
45+
| 'rGBCorrection'
46+
| 'lUTCorrection'
47+
| 'virtualPTZ'
48+
| 'toneCurveCorrection'
49+
| 'matrixCorrection'
50+
| 'temperatureCorrection'
51+
| 'linearKey'
52+
| 'position'
53+
| 'pCrop'
54+
| 'filmLook'
55+
| 'glowEffect'
56+
sceneName: string[]
57+
layerName: string[]
58+
effectName?: string[]
59+
temporalPriority?: number
60+
mappingType: MappingKairosType.SceneLayerEffect
61+
}
62+
3863
export interface MappingKairosAux {
3964
auxName: string
4065
temporalPriority?: number
@@ -75,6 +100,7 @@ export interface MappingKairosSoundPlayer {
75100
export enum MappingKairosType {
76101
Scene = 'scene',
77102
SceneLayer = 'scene-layer',
103+
SceneLayerEffect = 'scene-layer-effect',
78104
Aux = 'aux',
79105
Macro = 'macro',
80106
ClipPlayer = 'clip-player',
@@ -83,7 +109,7 @@ export enum MappingKairosType {
83109
SoundPlayer = 'sound-player',
84110
}
85111

86-
export type SomeMappingKairos = MappingKairosScene | MappingKairosSceneLayer | MappingKairosAux | MappingKairosMacro | MappingKairosClipPlayer | MappingKairosRamRecPlayer | MappingKairosImageStore | MappingKairosSoundPlayer
112+
export type SomeMappingKairos = MappingKairosScene | MappingKairosSceneLayer | MappingKairosSceneLayerEffect | MappingKairosAux | MappingKairosMacro | MappingKairosClipPlayer | MappingKairosRamRecPlayer | MappingKairosImageStore | MappingKairosSoundPlayer
87113

88114
export interface ListScenesPayload {
89115
scenePath: string[]

packages/timeline-state-resolver-types/src/integrations/kairos/timeline.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,28 @@ import type {
1313
MediaImageRef,
1414
DissolveMode,
1515
UpdateImageStoreObject,
16+
UpdateEffectChromaKeyObject,
17+
UpdateEffectCropObject,
18+
UpdateEffectFilmLookObject,
19+
UpdateEffectGlowEffectObject,
20+
UpdateEffectLinearKeyObject,
21+
UpdateEffectLuminanceKeyObject,
22+
UpdateEffectLUTCorrectionObject,
23+
UpdateEffectMatrixCorrectionObject,
24+
UpdateEffectPCropObject,
25+
UpdateEffectPositionObject,
26+
UpdateEffectRGBCorrectionObject,
27+
UpdateEffectTemperatureCorrectionObject,
28+
UpdateEffectToneCurveCorrectionObject,
29+
UpdateEffectTransform2DObject,
30+
UpdateEffectVirtualPTZObject,
31+
UpdateEffectYUVCorrectionObject,
1632
} from 'kairos-lib'
1733

1834
export enum TimelineContentTypeKairos {
1935
SCENE = 'scene',
2036
SCENE_LAYER = 'scene-layer',
37+
SCENE_LAYER_EFFECT = 'scene-layer-effect',
2138

2239
// MVs? - no
2340
// gfx / painter - yes, to be implemented
@@ -41,6 +58,7 @@ type PartialOrNull<T> = {
4158
export type TimelineContentKairosAny =
4259
| TimelineContentKairosScene
4360
| TimelineContentKairosSceneLayer
61+
| TimelineContentKairosSceneLayerEffect
4462
| TimelineContentKairosAux
4563
| TimelineContentKairosMacros
4664
| TimelineContentKairosClipPlayer
@@ -81,6 +99,30 @@ export interface TimelineContentKairosSceneLayer {
8199
}
82100
>
83101
}
102+
export interface TimelineContentKairosSceneLayerEffect {
103+
deviceType: DeviceType.KAIROS
104+
type: TimelineContentTypeKairos.SCENE_LAYER_EFFECT
105+
106+
effect: TimelineContentKairosSceneAnySceneLayerEffect
107+
}
108+
109+
export type TimelineContentKairosSceneAnySceneLayerEffect =
110+
| { type: 'crop'; values: Partial<UpdateEffectCropObject> }
111+
| { type: 'transform2D'; values: Partial<UpdateEffectTransform2DObject> }
112+
| { type: 'luminanceKey'; values: Partial<UpdateEffectLuminanceKeyObject> }
113+
| { type: 'chromaKey'; values: Partial<UpdateEffectChromaKeyObject> }
114+
| { type: 'yUVCorrection'; values: Partial<UpdateEffectYUVCorrectionObject> }
115+
| { type: 'rGBCorrection'; values: Partial<UpdateEffectRGBCorrectionObject> }
116+
| { type: 'lUTCorrection'; values: Partial<UpdateEffectLUTCorrectionObject> }
117+
| { type: 'virtualPTZ'; values: Partial<UpdateEffectVirtualPTZObject> }
118+
| { type: 'toneCurveCorrection'; values: Partial<UpdateEffectToneCurveCorrectionObject> }
119+
| { type: 'matrixCorrection'; values: Partial<UpdateEffectMatrixCorrectionObject> }
120+
| { type: 'temperatureCorrection'; values: Partial<UpdateEffectTemperatureCorrectionObject> }
121+
| { type: 'linearKey'; values: Partial<UpdateEffectLinearKeyObject> }
122+
| { type: 'position'; values: Partial<UpdateEffectPositionObject> }
123+
| { type: 'pCrop'; values: Partial<UpdateEffectPCropObject> }
124+
| { type: 'filmLook'; values: Partial<UpdateEffectFilmLookObject> }
125+
| { type: 'glowEffect'; values: Partial<UpdateEffectGlowEffectObject> }
84126

85127
export interface TimelineContentKairosAux {
86128
deviceType: DeviceType.KAIROS

packages/timeline-state-resolver/src/integrations/kairos/$schemas/mappings.json

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,87 @@
7474
],
7575
"additionalProperties": false
7676
},
77+
"scene-layer-effect": {
78+
"type": "object",
79+
"properties": {
80+
"effectType": {
81+
"type": "string",
82+
"enum": [
83+
"crop",
84+
"transform2D",
85+
"luminanceKey",
86+
"chromaKey",
87+
"yUVCorrection",
88+
"rGBCorrection",
89+
"lUTCorrection",
90+
"virtualPTZ",
91+
"toneCurveCorrection",
92+
"matrixCorrection",
93+
"temperatureCorrection",
94+
"linearKey",
95+
"position",
96+
"pCrop",
97+
"filmLook",
98+
"glowEffect"
99+
],
100+
"ui:title": "Effect Type",
101+
"ui:description": "Type of Layer Effect",
102+
"ui:summaryTitle": "Effect Type",
103+
"ui:displayType": "breadcrumbs",
104+
"default": []
105+
},
106+
"sceneName": {
107+
"type": "array",
108+
"items": {
109+
"type": "string"
110+
},
111+
"ui:title": "Scene",
112+
"ui:description": "The Scene to use",
113+
"ui:summaryTitle": "Scene",
114+
"ui:displayType": "breadcrumbs",
115+
"default": [
116+
"Main"
117+
]
118+
},
119+
"layerName": {
120+
"type": "array",
121+
"items": {
122+
"type": "string"
123+
},
124+
"ui:title": "Layer",
125+
"ui:description": "The layer in a scene to use",
126+
"ui:summaryTitle": "Layer",
127+
"ui:displayType": "breadcrumbs",
128+
"default": [
129+
"Background"
130+
]
131+
},
132+
"effectName": {
133+
"type": "array",
134+
"items": {
135+
"type": "string"
136+
},
137+
"ui:title": "Effect",
138+
"ui:description": "Name of the effect (optional)",
139+
"ui:summaryTitle": "Effect Name",
140+
"ui:displayType": "breadcrumbs",
141+
"default": []
142+
},
143+
"temporalPriority": {
144+
"type": "integer",
145+
"ui:title": "Temporal Priority",
146+
"ui:description": "Set this to a higher value to make commands that affects this Scene be sent first. Set this to a negative value to ensure that other untracked things are done first. Defaults to 0.",
147+
"ui:summaryTitle": "Temporal Priority",
148+
"default": 0
149+
}
150+
},
151+
"required": [
152+
"effectType",
153+
"sceneName",
154+
"layerName"
155+
],
156+
"additionalProperties": false
157+
},
77158
"aux": {
78159
"type": "object",
79160
"properties": {

packages/timeline-state-resolver/src/integrations/kairos/__tests__/diffState.spec.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,16 @@ describe('diffState', () => {
3030
layerName: ['Background'],
3131
},
3232
},
33+
mainSceneBackgroundLayerLuminance: {
34+
device: DeviceType.KAIROS,
35+
deviceId: 'kairos0',
36+
options: {
37+
mappingType: MappingKairosType.SceneLayerEffect,
38+
effectType: 'luminanceKey',
39+
sceneName: ['Main'],
40+
layerName: ['Background'],
41+
},
42+
},
3343
clipPlayer1: {
3444
device: DeviceType.KAIROS,
3545
deviceId: 'kairos0',
@@ -491,6 +501,63 @@ describe('diffState', () => {
491501
compareStates(DEFAULT_MAPPINGS, oldState, newState, [])
492502
})
493503
})
504+
test('Set LuminanceKey of SceneLayer', () => {
505+
compareStates(
506+
DEFAULT_MAPPINGS,
507+
{ ...EMPTY_STATE, stateTime: now },
508+
KairosStateBuilder.fromTimeline(
509+
{
510+
objects: [
511+
makeDeviceTimelineStateObject({
512+
enable: { start: now },
513+
id: 'obj0',
514+
layer: 'mainSceneBackgroundLayerLuminance',
515+
content: {
516+
deviceType: DeviceType.KAIROS,
517+
type: TimelineContentTypeKairos.SCENE_LAYER_EFFECT,
518+
effect: {
519+
type: 'luminanceKey',
520+
values: {
521+
sourceKey: {
522+
realm: 'ip-input',
523+
ipInput: 23,
524+
},
525+
},
526+
},
527+
},
528+
}),
529+
],
530+
time: now,
531+
},
532+
DEFAULT_MAPPINGS
533+
),
534+
[
535+
{
536+
context: expect.any(String),
537+
timelineObjId: expect.any(String),
538+
command: {
539+
type: 'scene-layer-effect',
540+
// sceneLayerId: 'SCENES.Main.Layers.Background',
541+
ref: {
542+
realm: 'scene-layer-effect',
543+
scenePath: ['Main'],
544+
layerPath: ['Background'],
545+
effectPath: ['LuminanceKey'],
546+
},
547+
effect: {
548+
type: 'luminanceKey',
549+
values: {
550+
sourceKey: {
551+
realm: 'ip-input',
552+
ipInput: 23,
553+
},
554+
},
555+
},
556+
},
557+
},
558+
]
559+
)
560+
})
494561
// test('temporal order when cutting to/from a clip player before it has started/stopped playing', () => {
495562

496563
// })
@@ -513,6 +580,7 @@ const EMPTY_STATE: Omit<KairosDeviceState, 'stateTime'> = {
513580
macros: {},
514581
ramRecPlayers: {},
515582
sceneLayers: {},
583+
sceneLayerEffects: {},
516584
sceneSnapshots: {},
517585
scenes: {},
518586
soundPlayers: {},

packages/timeline-state-resolver/src/integrations/kairos/__tests__/lib.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const EMPTY_STATE: Omit<KairosDeviceState, 'stateTime'> = {
66
macros: {},
77
ramRecPlayers: {},
88
sceneLayers: {},
9+
sceneLayerEffects: {},
910
sceneSnapshots: {},
1011
scenes: {},
1112
soundPlayers: {},

packages/timeline-state-resolver/src/integrations/kairos/commands.ts

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@ import type { CommandWithContext } from 'timeline-state-resolver-api'
1818
import { isEqual } from 'underscore'
1919
import { assertNever } from '../../lib.js'
2020
import type { KairosRamLoader } from './lib/kairosRamLoader.js'
21+
import { SceneLayerEffectRef, TimelineContentKairosSceneAnySceneLayerEffect } from 'timeline-state-resolver-types'
2122

2223
export type KairosCommandWithContext = CommandWithContext<KairosCommandAny, string>
2324

2425
export type KairosCommandAny =
2526
| KairosSceneCommand
2627
| KairosSceneRecallSnapshotCommand
2728
| KairosSceneLayerCommand
29+
| KairosSceneLayerEffectCommand
2830
| KairosAuxCommand
2931
| KairosMacroCommand
3032
| KairosClipPlayerCommand
@@ -58,6 +60,13 @@ export interface KairosSceneLayerCommand {
5860

5961
values: Partial<UpdateSceneLayerObject>
6062
}
63+
export interface KairosSceneLayerEffectCommand {
64+
type: 'scene-layer-effect'
65+
66+
ref: SceneLayerEffectRef
67+
68+
effect: TimelineContentKairosSceneAnySceneLayerEffect
69+
}
6170

6271
export interface KairosAuxCommand {
6372
type: 'aux'
@@ -223,6 +232,47 @@ export async function sendCommand(
223232
await kairos.updateSceneLayer(command.ref, values)
224233
break
225234
}
235+
case 'scene-layer-effect': {
236+
const effect = command.effect
237+
const ref = command.ref
238+
239+
if (effect.type === 'crop') {
240+
await kairos.updateSceneLayerEffectCrop(ref, effect.values)
241+
} else if (effect.type === 'transform2D') {
242+
await kairos.updateSceneLayerEffectTransform2D(ref, effect.values)
243+
} else if (effect.type === 'luminanceKey') {
244+
await kairos.updateSceneLayerEffectLuminanceKey(ref, effect.values)
245+
} else if (effect.type === 'chromaKey') {
246+
await kairos.updateSceneLayerEffectChromaKey(ref, effect.values)
247+
} else if (effect.type === 'yUVCorrection') {
248+
await kairos.updateSceneLayerEffectYUVCorrection(ref, effect.values)
249+
} else if (effect.type === 'rGBCorrection') {
250+
await kairos.updateSceneLayerEffectRGBCorrection(ref, effect.values)
251+
} else if (effect.type === 'lUTCorrection') {
252+
await kairos.updateSceneLayerEffectLUTCorrection(ref, effect.values)
253+
} else if (effect.type === 'virtualPTZ') {
254+
await kairos.updateSceneLayerEffectVirtualPTZ(ref, effect.values)
255+
} else if (effect.type === 'toneCurveCorrection') {
256+
await kairos.updateSceneLayerEffectToneCurveCorrection(ref, effect.values)
257+
} else if (effect.type === 'matrixCorrection') {
258+
await kairos.updateSceneLayerEffectMatrixCorrection(ref, effect.values)
259+
} else if (effect.type === 'temperatureCorrection') {
260+
await kairos.updateSceneLayerEffectTemperatureCorrection(ref, effect.values)
261+
} else if (effect.type === 'linearKey') {
262+
await kairos.updateSceneLayerEffectLinearKey(ref, effect.values)
263+
} else if (effect.type === 'position') {
264+
await kairos.updateSceneLayerEffectPosition(ref, effect.values)
265+
} else if (effect.type === 'pCrop') {
266+
await kairos.updateSceneLayerEffectPCrop(ref, effect.values)
267+
} else if (effect.type === 'filmLook') {
268+
await kairos.updateSceneLayerEffectFilmLook(ref, effect.values)
269+
} else if (effect.type === 'glowEffect') {
270+
await kairos.updateSceneLayerEffectGlowEffect(ref, effect.values)
271+
} else {
272+
assertNever(effect)
273+
}
274+
break
275+
}
226276
case 'aux':
227277
await kairos.updateAux(command.ref, command.values)
228278
break

0 commit comments

Comments
 (0)