add experimental keyframe functions
This commit is contained in:
parent
7874d3c291
commit
78a67ee665
3 changed files with 488 additions and 4 deletions
|
@ -1,13 +1,26 @@
|
||||||
|
import get from 'lodash-es/get'
|
||||||
import type {IProject, IRafDriver, ISheet, ISheetObject} from '@theatre/core'
|
import type {IProject, IRafDriver, ISheet, ISheetObject} from '@theatre/core'
|
||||||
import type {Prism, Pointer} from '@theatre/dataverse'
|
import type {Prism, Pointer} from '@theatre/dataverse'
|
||||||
import {prism} from '@theatre/dataverse'
|
import {getPointerParts, prism, val} from '@theatre/dataverse'
|
||||||
import SimpleCache from '@theatre/shared/utils/SimpleCache'
|
import SimpleCache from '@theatre/shared/utils/SimpleCache'
|
||||||
import type {$IntentionalAny, VoidFn} from '@theatre/shared/utils/types'
|
import {
|
||||||
|
getPropConfigByPath,
|
||||||
|
isPropConfigComposite,
|
||||||
|
iteratePropType,
|
||||||
|
} from '@theatre/shared/propTypes/utils'
|
||||||
|
import type {PropTypeConfig} from '@theatre/core/propTypes'
|
||||||
|
import type {PathToProp} from '@theatre/shared/src/utils/addresses'
|
||||||
|
import type {KeyframeId, SequenceTrackId} from '@theatre/shared/utils/ids'
|
||||||
|
import pointerDeep from '@theatre/shared/utils/pointerDeep'
|
||||||
|
import forEachPropDeep from '@theatre/shared/utils/forEachDeep'
|
||||||
|
import getDeep from '@theatre/shared/utils/getDeep'
|
||||||
|
import type {$FixMe, $IntentionalAny, VoidFn} from '@theatre/shared/utils/types'
|
||||||
import type {IScrub} from '@theatre/studio/Scrub'
|
import type {IScrub} from '@theatre/studio/Scrub'
|
||||||
import type {Studio} from '@theatre/studio/Studio'
|
import type {Studio} from '@theatre/studio/Studio'
|
||||||
import {
|
import {
|
||||||
isSheetObjectPublicAPI,
|
isSheetObjectPublicAPI,
|
||||||
isSheetPublicAPI,
|
isSheetPublicAPI,
|
||||||
|
isSheetObject,
|
||||||
} from '@theatre/shared/instanceTypes'
|
} from '@theatre/shared/instanceTypes'
|
||||||
import {getOutlineSelection} from './selectors'
|
import {getOutlineSelection} from './selectors'
|
||||||
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
import type SheetObject from '@theatre/core/sheetObjects/SheetObject'
|
||||||
|
@ -78,6 +91,18 @@ export interface ITransactionAPI {
|
||||||
* Makes Theatre forget about this sheet.
|
* Makes Theatre forget about this sheet.
|
||||||
*/
|
*/
|
||||||
__experimental_forgetSheet(sheet: TheatreSheet): void
|
__experimental_forgetSheet(sheet: TheatreSheet): void
|
||||||
|
|
||||||
|
__experimental_sequenceProp<V>(pointer: Pointer<V>): void
|
||||||
|
__experimental_staticProp<V>(pointer: Pointer<V>): void
|
||||||
|
__experimental_deleteKeyframes<V>(
|
||||||
|
pointer: Pointer<V>,
|
||||||
|
from: number,
|
||||||
|
to: number,
|
||||||
|
): void
|
||||||
|
__experimental_addKeyframes<V>(pointer: Pointer<V>, keyframes: []): void
|
||||||
|
// transaction
|
||||||
|
//
|
||||||
|
//__experimental_setSequenceDuration<V>(pointer: Pointer<V>, duration: number): void
|
||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
|
@ -462,6 +487,14 @@ export interface IStudio {
|
||||||
__experimental_createContentOfSaveFileTyped(
|
__experimental_createContentOfSaveFileTyped(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
): __UNSTABLE_Project_OnDiskState
|
): __UNSTABLE_Project_OnDiskState
|
||||||
|
|
||||||
|
__experimental_setPropAsSequenced<V>(prop: Pointer<V>): void
|
||||||
|
__experimental_setPropAsStatic<V>(prop: Pointer<V>): void
|
||||||
|
__experimental_isPropSequenced<V>(prop: Pointer<V>): boolean
|
||||||
|
|
||||||
|
// __experimental
|
||||||
|
//
|
||||||
|
//__experimental_setSequenceDuration<V>(prop: Pointer<V>, duration: number): boolean
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,6 +540,97 @@ export default class TheatreStudio implements IStudio {
|
||||||
): __UNSTABLE_Project_OnDiskState {
|
): __UNSTABLE_Project_OnDiskState {
|
||||||
return getStudio().createContentOfSaveFile(projectId) as $IntentionalAny
|
return getStudio().createContentOfSaveFile(projectId) as $IntentionalAny
|
||||||
},
|
},
|
||||||
|
// WARNING: for some reason this is not immediately applied
|
||||||
|
// but needs a timeout.. urgh
|
||||||
|
__experimental_setPropAsSequenced<V>(prop: Pointer<V>): void {
|
||||||
|
const {path, root} = getPointerParts(prop)
|
||||||
|
if (!isSheetObject(root)) {
|
||||||
|
throw new Error(
|
||||||
|
'Argument prop must be a pointer to a SheetObject property',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
const propConfig = getPropConfigByPath(root.template.staticConfig, path)
|
||||||
|
if (typeof propConfig !== 'undefined')
|
||||||
|
getStudio()!.transaction(({stateEditors}) => {
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsSequenced(
|
||||||
|
propAddress,
|
||||||
|
propConfig,
|
||||||
|
)
|
||||||
|
console.log('inner setPropAsSequenced', performance.now())
|
||||||
|
})
|
||||||
|
},
|
||||||
|
__experimental_setPropAsStatic<V>(prop: Pointer<V>): void {
|
||||||
|
const {path, root} = getPointerParts(prop)
|
||||||
|
if (!isSheetObject(root)) {
|
||||||
|
throw new Error(
|
||||||
|
'Argument prop must be a pointer to a SheetObject property',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
const propConfig = getPropConfigByPath(root.template.staticConfig, path)
|
||||||
|
if (typeof propConfig !== 'undefined') {
|
||||||
|
for (const {path: subPath, conf} of iteratePropType(propConfig, [])) {
|
||||||
|
if (isPropConfigComposite(conf)) continue
|
||||||
|
getStudio()!.transaction(({stateEditors}) => {
|
||||||
|
const pointerToSub = pointerDeep(prop, subPath)
|
||||||
|
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsStatic(
|
||||||
|
{
|
||||||
|
...propAddress,
|
||||||
|
value: root.getValueByPointer(pointerToSub as $IntentionalAny),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
__experimental_isPropSequenced<V>(prop: Pointer<V>): boolean {
|
||||||
|
const {path, root} = getPointerParts(prop)
|
||||||
|
if (!isSheetObject(root)) {
|
||||||
|
throw new Error(
|
||||||
|
'Argument prop must be a pointer to a SheetObject property',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
const propConfig = getPropConfigByPath(root.template.staticConfig, path)
|
||||||
|
const validTracks = root.template
|
||||||
|
.getArrayOfValidSequenceTracks()
|
||||||
|
.getValue()
|
||||||
|
tf: for (let t = 0; t < validTracks.length; t++) {
|
||||||
|
const otherPath = validTracks[t].pathToProp
|
||||||
|
if (otherPath.length === path.length) {
|
||||||
|
for (let p = 0; p < path.length; p++) {
|
||||||
|
if (path[p] !== otherPath[p]) {
|
||||||
|
continue tf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
},
|
||||||
|
// __experimental
|
||||||
|
//
|
||||||
|
//__experimental_setSequenceDuration<V>(prop: Pointer<V>, duration: number): boolean {
|
||||||
|
//const {path, root} = getPointerParts(prop)
|
||||||
|
//if (!isSheet(root)) {
|
||||||
|
//throw new Error(
|
||||||
|
//'Argument prop must be a pointer to a Sheet property',
|
||||||
|
//)
|
||||||
|
//}
|
||||||
|
|
||||||
|
//getStudio()!.transaction(({stateEditors}) => {
|
||||||
|
//stateEditors.coreByProject.historic.sheetsById.sequence.setLength({
|
||||||
|
//...root.address,
|
||||||
|
//length: duration,
|
||||||
|
//})
|
||||||
|
//})
|
||||||
|
//return false
|
||||||
|
//},
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -552,11 +676,250 @@ export default class TheatreStudio implements IStudio {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const __experimental_sequenceProp = <V>(prop: Pointer<V>) => {
|
||||||
|
const {path, root} = getPointerParts(prop)
|
||||||
|
|
||||||
|
// NOT IMPLEMENTED FULLY
|
||||||
|
// only works for simple props. not something like color
|
||||||
|
if (!isSheetObject(root)) {
|
||||||
|
throw new Error(
|
||||||
|
'Argument prop must be a pointer to a SheetObject property',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
const propConfig = getPropConfigByPath(root.template.staticConfig, path)
|
||||||
|
|
||||||
|
if (propConfig === undefined) {
|
||||||
|
throw new Error('propConfig is undefined. so, yeah.')
|
||||||
|
}
|
||||||
|
console.log({propConfig, propAddress})
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsSequenced(
|
||||||
|
propAddress,
|
||||||
|
propConfig,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
const __experimental_staticProp = <V>(prop: Pointer<V>) => {
|
||||||
|
const {path, root} = getPointerParts(prop)
|
||||||
|
|
||||||
|
// NOT IMPLEMENTED FULLY
|
||||||
|
// only works for simple props. not something like color
|
||||||
|
if (!isSheetObject(root)) {
|
||||||
|
throw new Error(
|
||||||
|
'Argument prop must be a pointer to a SheetObject property',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
const propConfig = getPropConfigByPath(root.template.staticConfig, path)
|
||||||
|
|
||||||
|
if (propConfig === undefined) {
|
||||||
|
throw new Error('propConfig is undefined. so, yeah.')
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const {path: subPath, conf} of iteratePropType(propConfig, [])) {
|
||||||
|
if (isPropConfigComposite(conf)) continue
|
||||||
|
const pointerToSub = pointerDeep(prop, subPath)
|
||||||
|
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsStatic(
|
||||||
|
{
|
||||||
|
...propAddress,
|
||||||
|
value: root.getValueByPointer(pointerToSub as $IntentionalAny),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const __experimental_deleteKeyframes = <V>(
|
||||||
|
prop: Pointer<V>,
|
||||||
|
from: number = 0,
|
||||||
|
to: number = 0,
|
||||||
|
) => {
|
||||||
|
const {root, path} = getPointerParts(prop as Pointer<$FixMe>)
|
||||||
|
if (isSheetObject(root)) {
|
||||||
|
const sequenceTracksTree = root.template
|
||||||
|
.getMapOfValidSequenceTracks_forStudio()
|
||||||
|
.getValue()
|
||||||
|
|
||||||
|
const defaultValue = getDeep(
|
||||||
|
root.template.getDefaultValues().getValue(),
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
|
||||||
|
const propConfig = getPropConfigByPath(
|
||||||
|
root.template.staticConfig,
|
||||||
|
path,
|
||||||
|
) as PropTypeConfig
|
||||||
|
|
||||||
|
const unsetStaticOrKeyframeProp = <T>(value: T, path: PathToProp) => {
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
|
||||||
|
const trackId = get(sequenceTracksTree, path) as $FixMe as
|
||||||
|
| SequenceTrackId
|
||||||
|
| undefined
|
||||||
|
|
||||||
|
const sequence = root.sheet.getSequence()
|
||||||
|
const trackP = val(
|
||||||
|
sequence._project.pointers.historic.sheetsById[
|
||||||
|
sequence._sheet.address.sheetId
|
||||||
|
].sequence.tracksByObject[root.address.objectKey],
|
||||||
|
)
|
||||||
|
if (!trackP) {
|
||||||
|
throw new Error('whatever, man')
|
||||||
|
}
|
||||||
|
const {trackData, trackIdByPropPath} = trackP
|
||||||
|
//const objectAddress = encodePathToProp(path)
|
||||||
|
//const id = trackIdByPropPath[objectAddress]
|
||||||
|
|
||||||
|
if (
|
||||||
|
typeof trackId === 'string' &&
|
||||||
|
typeof trackData !== 'undefined'
|
||||||
|
) {
|
||||||
|
const track = trackData[trackId]
|
||||||
|
if (!track) {
|
||||||
|
throw new Error('whatever, man')
|
||||||
|
}
|
||||||
|
|
||||||
|
const keyframeIds: KeyframeId[] = []
|
||||||
|
if (to > from) {
|
||||||
|
track.keyframes.forEach((kf) => {
|
||||||
|
if (kf.position >= from && kf.position <= to) {
|
||||||
|
} else {
|
||||||
|
keyframeIds.push(kf.id)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
const objectKey = propAddress.objectKey
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.sequence.keepKeyframes(
|
||||||
|
{
|
||||||
|
...root.address,
|
||||||
|
objectKey,
|
||||||
|
trackId,
|
||||||
|
keyframeIds,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
} else if (propConfig !== undefined) {
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.staticOverrides.byObject.unsetValueOfPrimitiveProp(
|
||||||
|
propAddress,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propConfig.type === 'compound') {
|
||||||
|
forEachPropDeep(
|
||||||
|
defaultValue,
|
||||||
|
(v, pathToProp) => {
|
||||||
|
unsetStaticOrKeyframeProp(v, pathToProp)
|
||||||
|
},
|
||||||
|
getPointerParts(prop).path,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
unsetStaticOrKeyframeProp(defaultValue, path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'Only setting props of SheetObject-s is supported in a transaction so far',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const __experimental_addKeyframes = <V>(
|
||||||
|
prop: Pointer<V>,
|
||||||
|
keyframes: [],
|
||||||
|
) => {
|
||||||
|
const {root, path} = getPointerParts(prop as Pointer<$FixMe>)
|
||||||
|
if (isSheetObject(root)) {
|
||||||
|
let sequenceTracksTree = root.template
|
||||||
|
.getMapOfValidSequenceTracks_forStudio()
|
||||||
|
.getValue()
|
||||||
|
|
||||||
|
const defaultValue = getDeep(
|
||||||
|
root.template.getDefaultValues().getValue(),
|
||||||
|
path,
|
||||||
|
)
|
||||||
|
|
||||||
|
const propConfig = getPropConfigByPath(
|
||||||
|
root.template.staticConfig,
|
||||||
|
path,
|
||||||
|
) as PropTypeConfig
|
||||||
|
console.log(path, propConfig)
|
||||||
|
|
||||||
|
const addStaticOrKeyframeProp = <T>(value: T, path: PathToProp) => {
|
||||||
|
const propAddress = {...root.address, pathToProp: path}
|
||||||
|
|
||||||
|
let trackId = get(sequenceTracksTree, path) as $FixMe as
|
||||||
|
| SequenceTrackId
|
||||||
|
| undefined
|
||||||
|
|
||||||
|
if (typeof trackId !== 'string' && propConfig !== undefined) {
|
||||||
|
throw Error('can only add keyframes to sequenced prop')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof trackId === 'string') {
|
||||||
|
const objectKey = propAddress.objectKey
|
||||||
|
stateEditors.coreByProject.historic.sheetsById.sequence.addKeyframes(
|
||||||
|
{
|
||||||
|
...root.address,
|
||||||
|
objectKey,
|
||||||
|
trackId,
|
||||||
|
keyframes,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
console.log({
|
||||||
|
a: {...root.address},
|
||||||
|
objectKey,
|
||||||
|
trackId,
|
||||||
|
keyframes,
|
||||||
|
})
|
||||||
|
} else if (propConfig !== undefined) {
|
||||||
|
throw Error('hmmm')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (propConfig.type === 'compound') {
|
||||||
|
forEachPropDeep(
|
||||||
|
defaultValue,
|
||||||
|
(v, pathToProp) => {
|
||||||
|
console.log('comp compoumnD')
|
||||||
|
addStaticOrKeyframeProp(v, pathToProp)
|
||||||
|
},
|
||||||
|
getPointerParts(prop).path,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
console.log('singlerer', {defaultValue, path})
|
||||||
|
addStaticOrKeyframeProp(defaultValue, path)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error(
|
||||||
|
'Only setting props of SheetObject-s is supported in a transaction so far',
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transaction
|
||||||
|
//
|
||||||
|
//const __experimental_setSequenceDuration = <V>(prop: Pointer<V>, duration: number) => {
|
||||||
|
//const {root, path} = getPointerParts(prop as Pointer<$FixMe>)
|
||||||
|
//if (isSheet(root)) {
|
||||||
|
//stateEditors.coreByProject.historic.sheetsById.sequence.setLength({
|
||||||
|
//...root.address,
|
||||||
|
//length: duration,
|
||||||
|
//})
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
return fn({
|
return fn({
|
||||||
set,
|
set,
|
||||||
unset,
|
unset,
|
||||||
__experimental_forgetObject,
|
__experimental_forgetObject,
|
||||||
__experimental_forgetSheet,
|
__experimental_forgetSheet,
|
||||||
|
__experimental_sequenceProp,
|
||||||
|
__experimental_staticProp,
|
||||||
|
__experimental_deleteKeyframes,
|
||||||
|
__experimental_addKeyframes,
|
||||||
|
// transaction
|
||||||
|
//
|
||||||
|
//__experimental_setSequenceDuration,
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -293,7 +293,6 @@ function createPrism<T extends SerializablePrimitive>(
|
||||||
callback: () => {
|
callback: () => {
|
||||||
getStudio()!.transaction(({stateEditors}) => {
|
getStudio()!.transaction(({stateEditors}) => {
|
||||||
const propAddress = {...obj.address, pathToProp}
|
const propAddress = {...obj.address, pathToProp}
|
||||||
|
|
||||||
stateEditors.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsSequenced(
|
stateEditors.coreByProject.historic.sheetsById.sequence.setPrimitivePropAsSequenced(
|
||||||
propAddress,
|
propAddress,
|
||||||
propConfig,
|
propConfig,
|
||||||
|
|
|
@ -772,6 +772,63 @@ namespace stateEditors {
|
||||||
stateEditors.coreByProject.historic.sheetsById.staticOverrides.byObject.setValueOfCompoundProp(
|
stateEditors.coreByProject.historic.sheetsById.staticOverrides.byObject.setValueOfCompoundProp(
|
||||||
p,
|
p,
|
||||||
)
|
)
|
||||||
|
const toVT = {
|
||||||
|
sequenced: false,
|
||||||
|
panelID: p.objectKey,
|
||||||
|
prop: p.pathToProp,
|
||||||
|
origin: 'stateEditors.ts',
|
||||||
|
}
|
||||||
|
const event = new CustomEvent('sequenceEvent', {
|
||||||
|
bubbles: false,
|
||||||
|
detail: toVT,
|
||||||
|
})
|
||||||
|
window.dispatchEvent(event)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setCompoundPropAsSequenced(
|
||||||
|
p: WithoutSheetInstance<PropAddress>,
|
||||||
|
) {
|
||||||
|
const tracks = _ensureTracksOfObject(p)
|
||||||
|
|
||||||
|
for (const encodedPropPath of Object.keys(
|
||||||
|
tracks.trackIdByPropPath,
|
||||||
|
)) {
|
||||||
|
const propPath = JSON.parse(encodedPropPath)
|
||||||
|
const isSubOfTargetPath = p.pathToProp.every(
|
||||||
|
(key, i) => propPath[i] === key,
|
||||||
|
)
|
||||||
|
if (isSubOfTargetPath) {
|
||||||
|
const possibleTrackId =
|
||||||
|
tracks.trackIdByPropPath[encodedPropPath]
|
||||||
|
if (typeof possibleTrackId === 'string') return
|
||||||
|
|
||||||
|
const trackId = generateSequenceTrackId()
|
||||||
|
|
||||||
|
const track: BasicKeyframedTrack = {
|
||||||
|
type: 'BasicKeyframedTrack',
|
||||||
|
__debugName: `${p.objectKey}:${encodedPropPath}`,
|
||||||
|
keyframes: [],
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks.trackData[trackId] = track
|
||||||
|
tracks.trackIdByPropPath[encodedPropPath] = trackId
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//stateEditors.coreByProject.historic.sheetsById.staticOverrides.byObject.setValueOfCompoundProp(
|
||||||
|
//p,
|
||||||
|
//)
|
||||||
|
const toVT = {
|
||||||
|
sequenced: false,
|
||||||
|
panelID: p.objectKey,
|
||||||
|
prop: p.pathToProp,
|
||||||
|
origin: 'stateEditors.ts',
|
||||||
|
}
|
||||||
|
const event = new CustomEvent('sequenceEvent', {
|
||||||
|
bubbles: false,
|
||||||
|
detail: toVT,
|
||||||
|
})
|
||||||
|
window.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
function _getTrack(
|
function _getTrack(
|
||||||
|
@ -979,7 +1036,54 @@ namespace stateEditors {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deleteKeyframes(
|
export function addKeyframes<T extends SerializableValue>(
|
||||||
|
p: WithoutSheetInstance<SheetObjectAddress> & {
|
||||||
|
trackId: SequenceTrackId
|
||||||
|
keyframes: {
|
||||||
|
position: number
|
||||||
|
handles?: [number, number, number, number]
|
||||||
|
value: T
|
||||||
|
type?: KeyframeType
|
||||||
|
}[]
|
||||||
|
},
|
||||||
|
override: boolean = true,
|
||||||
|
) {
|
||||||
|
const track = _getTrack(p)
|
||||||
|
if (!track) return
|
||||||
|
if (p.keyframes.length < 1)
|
||||||
|
throw new Error(
|
||||||
|
'holy shit, you are trying to add non-existing keyframes',
|
||||||
|
)
|
||||||
|
//const {keyframes} = track
|
||||||
|
if (!override)
|
||||||
|
throw new Error('whoopsie, not overriding is not implemented')
|
||||||
|
|
||||||
|
// is it necessary to be so stupid here?
|
||||||
|
const oldKeyframes = track.keyframes
|
||||||
|
track.keyframes = []
|
||||||
|
oldKeyframes.forEach((kf) => {
|
||||||
|
if (p.keyframes[0].position > kf.position) {
|
||||||
|
track.keyframes.push(kf)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
p.keyframes.forEach((pkf) => {
|
||||||
|
track.keyframes.push({
|
||||||
|
id: generateKeyframeId(),
|
||||||
|
position: pkf.position,
|
||||||
|
connectedRight: true,
|
||||||
|
handles: pkf.handles || [0.5, 1, 0.5, 0],
|
||||||
|
type: pkf.type || 'bezier',
|
||||||
|
value: pkf.value,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
oldKeyframes.forEach((kf) => {
|
||||||
|
if (p.keyframes[p.keyframes.length - 1].position < kf.position) {
|
||||||
|
track.keyframes.push(kf)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function keepKeyframes(
|
||||||
p: WithoutSheetInstance<SheetObjectAddress> & {
|
p: WithoutSheetInstance<SheetObjectAddress> & {
|
||||||
trackId: SequenceTrackId
|
trackId: SequenceTrackId
|
||||||
keyframeIds: KeyframeId[]
|
keyframeIds: KeyframeId[]
|
||||||
|
@ -988,6 +1092,24 @@ namespace stateEditors {
|
||||||
const track = _getTrack(p)
|
const track = _getTrack(p)
|
||||||
if (!track) return
|
if (!track) return
|
||||||
|
|
||||||
|
// is it necessary to be so stupid here?
|
||||||
|
const keyframes = track.keyframes
|
||||||
|
track.keyframes = []
|
||||||
|
keyframes.forEach((kf) => {
|
||||||
|
if (p.keyframeIds.indexOf(kf.id) >= 0) {
|
||||||
|
track.keyframes.push(kf)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function deleteKeyframes(
|
||||||
|
p: WithoutSheetInstance<SheetObjectAddress> & {
|
||||||
|
trackId: SequenceTrackId
|
||||||
|
keyframeIds: KeyframeId[]
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const track = _getTrack(p)
|
||||||
|
if (!track) return
|
||||||
track.keyframes = track.keyframes.filter(
|
track.keyframes = track.keyframes.filter(
|
||||||
(kf) => p.keyframeIds.indexOf(kf.id) === -1,
|
(kf) => p.keyframeIds.indexOf(kf.id) === -1,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in a new issue