superfly-timeline
Advanced tools
Comparing version 6.0.3 to 7.0.0
@@ -5,2 +5,28 @@ # Change Log | ||
<a name="7.0.0"></a> | ||
# [7.0.0](https://github.com/SuperFlyTV/supertimeline/compare/6.0.3...7.0.0) (2019-04-06) | ||
### Bug Fixes | ||
* minor bugs in expressions ([bcfe44f](https://github.com/SuperFlyTV/supertimeline/commit/bcfe44f)) | ||
* tests and ts3 lint issues ([01a537e](https://github.com/SuperFlyTV/supertimeline/commit/01a537e)) | ||
* use ts 3 and update deps ([0731cba](https://github.com/SuperFlyTV/supertimeline/commit/0731cba)) | ||
### Features | ||
* add reference breadcrumbs, continued work on capping-in-parent etc.. ([af4380d](https://github.com/SuperFlyTV/supertimeline/commit/af4380d)) | ||
* continued implementation ([296729c](https://github.com/SuperFlyTV/supertimeline/commit/296729c)) | ||
* continued implementation, all (non-deprecated) tests are now ok ([3f90008](https://github.com/SuperFlyTV/supertimeline/commit/3f90008)) | ||
* continued implementation, validation, ([f95b4ce](https://github.com/SuperFlyTV/supertimeline/commit/f95b4ce)) | ||
* implement cap-in-parent, refactoring, rename trigger => enable ([ce656a9](https://github.com/SuperFlyTV/supertimeline/commit/ce656a9)) | ||
* implement classes ([6d1b2e0](https://github.com/SuperFlyTV/supertimeline/commit/6d1b2e0)) | ||
* implement getState & getNextEvents ([c04a269](https://github.com/SuperFlyTV/supertimeline/commit/c04a269)) | ||
* implement getState, groups & repeating trigger ([f1753e1](https://github.com/SuperFlyTV/supertimeline/commit/f1753e1)) | ||
* implement keyframes ([80513ea](https://github.com/SuperFlyTV/supertimeline/commit/80513ea)) | ||
* mixed expressions, initial implementation. Complete rehaul (WIP) ([923b2e2](https://github.com/SuperFlyTV/supertimeline/commit/923b2e2)) | ||
<a name="6.0.3"></a> | ||
@@ -7,0 +33,0 @@ ## [6.0.3](https://github.com/SuperFlyTV/supertimeline/compare/6.0.2...6.0.3) (2018-11-07) |
@@ -1,2 +0,4 @@ | ||
export * from './enums/enums'; | ||
export * from './resolver/resolver'; | ||
export * from './api/enums'; | ||
export * from './api/api'; | ||
export { Resolver } from './resolver/resolver'; | ||
export { validateTimeline, validateObject, validateKeyframe } from './resolver/validate'; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
tslib_1.__exportStar(require("./enums/enums"), exports); | ||
tslib_1.__exportStar(require("./resolver/resolver"), exports); | ||
tslib_1.__exportStar(require("./api/enums"), exports); | ||
var resolver_1 = require("./resolver/resolver"); | ||
exports.Resolver = resolver_1.Resolver; | ||
var validate_1 = require("./resolver/validate"); | ||
exports.validateTimeline = validate_1.validateTimeline; | ||
exports.validateObject = validate_1.validateObject; | ||
exports.validateKeyframe = validate_1.validateKeyframe; | ||
//# sourceMappingURL=index.js.map |
@@ -1,133 +0,21 @@ | ||
import { TriggerType, TraceLevel, EventType } from '../enums/enums'; | ||
export interface TimelineTrigger { | ||
type: TriggerType; | ||
value: number | string; | ||
import { TimelineObject, ResolvedTimeline, ResolveOptions, Expression, ResolvedTimelineObject, TimelineObjectInstance, Time, TimelineState, Reference } from '../api/api'; | ||
export declare class Resolver { | ||
/** | ||
* Go through all objects on the timeline and calculate all the timings. | ||
* Returns a ResolvedTimeline which can be piped into Resolver.getState() | ||
* @param timeline Array of timeline objects | ||
* @param options Resolve options | ||
*/ | ||
static resolveTimeline(timeline: Array<TimelineObject>, options: ResolveOptions): ResolvedTimeline; | ||
/** | ||
* Calculate the state at a given point in time. Using a ResolvedTimeline calculated by Resolver.resolveTimeline. | ||
* @param resolved ResolvedTimeline calculated by Resolver.resolveTimeline. | ||
* @param time The point in time where to calculate the state | ||
* @param eventLimit (Optional) Limits the number of returned upcoming events. | ||
*/ | ||
static getState(resolved: ResolvedTimeline, time: Time, eventLimit?: number): TimelineState; | ||
} | ||
export interface TimelineObject { | ||
id: ObjectId; | ||
trigger: TimelineTrigger; | ||
duration?: number | string; | ||
LLayer: string | number; | ||
content: { | ||
objects?: Array<TimelineObject>; | ||
keyframes?: Array<TimelineKeyframe>; | ||
[key: string]: any; | ||
}; | ||
classes?: Array<string>; | ||
disabled?: boolean; | ||
isGroup?: boolean; | ||
repeating?: boolean; | ||
priority?: number; | ||
externalFunction?: string; | ||
} | ||
export interface TimelineGroup extends TimelineObject { | ||
resolved: ResolvedDetails; | ||
parent?: TimelineGroup; | ||
} | ||
export declare type TimeMaybe = number | null; | ||
export declare type StartTime = number | null; | ||
export declare type EndTime = number | null; | ||
export declare type Duration = number | null; | ||
export declare type SomeTime = number; | ||
export declare type ObjectId = string; | ||
export interface TimelineEvent { | ||
type: EventType; | ||
time: SomeTime; | ||
obj: TimelineObject; | ||
kf?: TimelineResolvedKeyframe; | ||
} | ||
export interface TimelineKeyframe { | ||
id: string; | ||
trigger: { | ||
type: TriggerType; | ||
value: number | string; | ||
}; | ||
duration?: number | string; | ||
content?: { | ||
[key: string]: any; | ||
}; | ||
classes?: Array<string>; | ||
} | ||
export interface TimelineResolvedObject extends TimelineObject { | ||
resolved: ResolvedDetails; | ||
parent?: TimelineGroup; | ||
} | ||
export interface TimelineResolvedKeyframe extends TimelineKeyframe { | ||
resolved: ResolvedDetails; | ||
parent?: TimelineResolvedObject; | ||
} | ||
export interface ResolvedDetails { | ||
startTime?: StartTime; | ||
endTime?: EndTime; | ||
innerStartTime?: StartTime; | ||
innerEndTime?: EndTime; | ||
innerDuration?: Duration; | ||
outerDuration?: Duration; | ||
parentStart?: StartTime; | ||
parentId?: ObjectId; | ||
disabled?: boolean; | ||
referredObjectIds?: Array<ResolvedObjectId> | null; | ||
repeatingStartTime?: StartTime; | ||
templateData?: any; | ||
developed?: boolean; | ||
[key: string]: any; | ||
} | ||
export interface ResolvedObjectId { | ||
id: string; | ||
hook: string; | ||
} | ||
export interface ResolvedTimeline { | ||
resolved: Array<TimelineResolvedObject>; | ||
unresolved: Array<TimelineObject>; | ||
} | ||
export interface DevelopedTimeline { | ||
resolved: Array<TimelineResolvedObject>; | ||
unresolved: Array<TimelineObject>; | ||
groups: Array<TimelineGroup>; | ||
} | ||
export interface TimelineState { | ||
time: SomeTime; | ||
GLayers: { | ||
[GLayer: string]: TimelineResolvedObject; | ||
}; | ||
LLayers: { | ||
[LLayer: string]: TimelineResolvedObject; | ||
}; | ||
} | ||
export interface ExternalFunctions { | ||
[fcnName: string]: (obj: TimelineResolvedObject, state: TimelineState, tld: DevelopedTimeline) => boolean; | ||
} | ||
export interface UnresolvedTimeline extends Array<TimelineObject> { | ||
} | ||
export interface ResolvedObjectsStore { | ||
[id: string]: TimelineResolvedObject | TimelineResolvedKeyframe; | ||
} | ||
export interface ResolvedObjectTouches { | ||
[key: string]: number; | ||
} | ||
export declare type Expression = number | string | ExpressionObj; | ||
export interface ExpressionObj { | ||
l: Expression; | ||
o: string; | ||
r: Expression; | ||
} | ||
export interface Filter { | ||
startTime?: StartTime; | ||
endTime?: EndTime; | ||
} | ||
export declare type WhosAskingTrace = Array<string>; | ||
export declare type objAttributeFunction = (objId: string, hook: 'start' | 'end' | 'duration' | 'parentStart', whosAsking: WhosAskingTrace, supressAlreadyAskedWarning?: boolean) => number | null; | ||
declare class Resolver { | ||
static setTraceLevel(levelName: string | TraceLevel): void; | ||
static getTraceLevel(): TraceLevel; | ||
static getState(data: UnresolvedTimeline | ResolvedTimeline, time: SomeTime, externalFunctions?: ExternalFunctions): TimelineState; | ||
static getNextEvents(data: ResolvedTimeline, time: SomeTime, count?: number): TimelineEvent[]; | ||
static getTimelineInWindow(data: UnresolvedTimeline, startTime?: StartTime, endTime?: EndTime): ResolvedTimeline; | ||
static getObjectsInWindow(data: UnresolvedTimeline, startTime: SomeTime, endTime?: SomeTime): DevelopedTimeline; | ||
static interpretExpression(strOrExpr: string | number | Expression, isLogical?: boolean): string | number | ExpressionObj | null; | ||
static resolveExpression(strOrExpr: string | number | Expression, getObjectAttribute?: objAttributeFunction): StartTime; | ||
static resolveLogicalExpression(expressionOrString: Expression | null, obj?: TimelineResolvedObject, returnExpl?: boolean, currentState?: TimelineState): boolean; | ||
static developTimelineAroundTime(tl: ResolvedTimeline, time: SomeTime): DevelopedTimeline; | ||
static decipherLogicalValue(str: string | number, obj: TimelineObject | TimelineKeyframe, currentState: TimelineState, returnExpl?: boolean): boolean | string; | ||
} | ||
export { Resolver }; | ||
export declare function resolveTimelineObj(resolvedTimeline: ResolvedTimeline, obj: ResolvedTimelineObject): void; | ||
declare type ObjectRefType = 'start' | 'end' | 'duration'; | ||
export declare function lookupExpression(resolvedTimeline: ResolvedTimeline, obj: TimelineObject, expr: Expression | null, context: ObjectRefType): Array<TimelineObjectInstance> | Reference | null; | ||
export {}; |
{ | ||
"name": "superfly-timeline", | ||
"version": "6.0.3", | ||
"version": "7.0.0", | ||
"description": "A collection of rules as well as a resolver for placing objects on a virtual timeline.", | ||
@@ -30,2 +30,4 @@ "license": "MIT", | ||
"build:main": "tsc -p tsconfig.json", | ||
"build-examples": "yarn build && yarn build:examples", | ||
"build:examples": "tsc -p tsconfig-examples.json", | ||
"lint": "tslint --project tsconfig.jest.json --config tslint.json", | ||
@@ -48,3 +50,3 @@ "unit": "jest --forceExit --detectOpenHandles", | ||
"ci": "yarn test && yarn docs:test", | ||
"validate:dependencies": "nsp check && yarn license-validate", | ||
"validate:dependencies": "yarn audit && yarn license-validate", | ||
"license-validate": "node-license-validator -p -d --allow-licenses MIT BSD BSD-3-Clause ISC Apache" | ||
@@ -82,21 +84,19 @@ }, | ||
"@types/node": "^8.0.4", | ||
"codecov": "^3.0.2", | ||
"cpx": "^1.5.0", | ||
"codecov": "^3.1.0", | ||
"fast-clone": "^1.5.3", | ||
"gh-pages": "^1.2.0", | ||
"jest": "^23.1.0", | ||
"jest": "^24.1.0", | ||
"mkdirp": "^0.5.1", | ||
"node-license-validator": "^1.3.0", | ||
"npm-scripts-info": "^0.3.7", | ||
"nsp": "^3.2.1", | ||
"nyc": "^12.0.2", | ||
"opn-cli": "^3.1.0", | ||
"npm-scripts-info": "^0.3.9", | ||
"nyc": "^13.3.0", | ||
"opn-cli": "^4.0.0", | ||
"sleep-ms": "^2.0.1", | ||
"standard-version": "^4.4.0", | ||
"trash-cli": "^1.4.0", | ||
"ts-jest": "^22.4.6", | ||
"tslint": "^5.10.0", | ||
"tslint-config-standard": "^7.0.0", | ||
"typedoc": "^0.11.1", | ||
"typescript": "^2.9.1" | ||
"ts-jest": "^24.0.0", | ||
"tslint": "^5.12.1", | ||
"tslint-config-standard": "^8.0.1", | ||
"typedoc": "^0.14.2", | ||
"typescript": "^3.3.3333" | ||
}, | ||
@@ -111,3 +111,3 @@ "keywords": [ | ||
"dependencies": { | ||
"@types/underscore": "^1.8.8", | ||
"@types/underscore": "^1.8.9", | ||
"underscore": "^1.9.1" | ||
@@ -114,0 +114,0 @@ }, |
425
README.md
@@ -0,1 +1,2 @@ | ||
# SuperFly-Timeline | ||
@@ -22,248 +23,252 @@ [![CircleCI](https://circleci.com/gh/SuperFlyTV/supertimeline.svg?style=svg)](https://circleci.com/gh/SuperFlyTV/supertimeline) | ||
// The input to the timeline is an array of objects | ||
var myObjects = []; | ||
// The input to the timeline is an array of objects: | ||
const myTimeline = [ | ||
{ | ||
id: 'video0', | ||
layer: 'L1', | ||
enable: { | ||
start: 10, | ||
end: 100 | ||
}, | ||
content: {} | ||
}, | ||
{ // This object defines a graphic, to be overlaid on the video | ||
id: 'graphic0', | ||
layer: 'L2', | ||
enable: { | ||
start: '#video0.start + 10', // 10 after video0 starts | ||
duration: 10 | ||
}, | ||
content: {}, | ||
classes: ['graphics'] | ||
}, | ||
{ | ||
id: 'graphic1', | ||
layer: 'L2', | ||
enable: { | ||
start: '#graphic0.end + 10', // 10 after graphic0 ends | ||
duration: 15 | ||
}, | ||
content: {}, | ||
classes: ['graphics'] | ||
}, | ||
{ | ||
id: 'graphicBackground', | ||
layer: 'L3', | ||
enable: { | ||
while: '!.graphics' // When no graphics are playing | ||
}, | ||
content: {} | ||
} | ||
]; | ||
// Lets add an object to the timeline: | ||
myObjects.push({ | ||
id: 'obj0', // the id must be unique | ||
// When we have a new timeline, the first thing to do is to "Resolve" it. | ||
// This calculates all timings of the objects in the timeline. | ||
const options = { | ||
time: 0 | ||
}; | ||
const resolvedTimeline = Timeline.Resolver.resolveTimeline(myTimeline, options); | ||
trigger: { | ||
type: Timeline.Enums.TriggerType.TIME_ABSOLUTE, | ||
value: Date.now()/1000 - 10 // 10 seconds ago | ||
}, | ||
duration: 60, // 1 minute long | ||
LLayer: 1 // Logical layer | ||
}); | ||
// Lets add another object to the timeline, set to start right after the previous one: | ||
myObjects.push({ | ||
id: 'obj1', // the id must be unique | ||
// Fetch the state at time 10: | ||
const state0 = Timeline.Resolver.getState(resolvedTimeline, 10); | ||
console.log(`At the time ${state0.time}, the active objects are "${ | ||
_.map(state0.layers, (o, l) => `${o.id} at layer ${l}`).join(', ') | ||
}"`); | ||
trigger: { | ||
type: Timeline.Enums.TriggerType.TIME_RELATIVE, | ||
value: '#obj0.end' | ||
}, | ||
duration: 60, // 1 minute long | ||
LLayer: 1 // Logical layer | ||
}); | ||
// Fetch the state at time 25: | ||
const state1 = Timeline.Resolver.getState(resolvedTimeline, 25); | ||
console.log(`At the time ${state1.time}, the active objects are "${ | ||
_.map(state1.layers, (o, l) => `${o.id} at layer ${l}`).join(', ') | ||
}"`); | ||
// By resolving the timeline, the times of the objects are calculated: | ||
var tl = Timeline.Resolver.getTimelineInWindow(myObjects); | ||
// To see whats on right now, we fetch the State: | ||
var stateNow = Timeline.Resolver.getState(tl, Date.now()/1000); | ||
// | ||
/* | ||
stateNow = { | ||
time: 1511009749, | ||
GLayers: { | ||
'1': { | ||
id: 'obj0', | ||
trigger: {}, | ||
duration: 60, | ||
LLayer: 1, | ||
content: {}, | ||
resolved: {} | ||
} | ||
}, | ||
LLayers: { | ||
'1': { | ||
id: 'obj0', | ||
trigger: {}, | ||
duration: 60, | ||
LLayer: 1, | ||
content: {}, | ||
resolved: {} | ||
} | ||
} | ||
console.log(`The object "graphicBackground" will play at [${ | ||
_.map(resolvedTimeline.objects['graphicBackground'].resolved.instances, (instance) => `${instance.start} to ${instance.end}`).join(', ') | ||
}]`); | ||
const nextEvent = state1.nextEvents[0]; | ||
console.log(`After the time ${state1.time}, the next event to happen will be at time ${nextEvent.time}. The event is related to the object "${nextEvent.objId}"`); | ||
// Output: | ||
// At the time 10, the active objects are "video0 at layer L1, graphicBackground at layer L3" | ||
// At the time 25, the active objects are "video0 at layer L1, graphic0 at layer L2" | ||
// The object "graphicBackground" will play at "0 to 20, 30 to 40, 55 to null" | ||
// After the time 25, the next event to happen will be at time 30. The event is related to the object "graphic0" | ||
``` | ||
# API | ||
The logic is set by setting properties in the `.enable` property. | ||
| Property | Description | | ||
|--|--| | ||
| `.start` | The start time of the object. (cannot be combined with `.while`) | | ||
| `.end` | The end time of the object (cannot be combined with `.while` or `.duration`). | | ||
| `.while` | Enables the object WHILE expression is true (ie sets both the start and end). (cannot be combined with `.start`, `.end` or `.duration` ) | | ||
| `.duration` | The duration of an object | | ||
| `.repeating` | Makes the object repeat with given interval | | ||
If `.end`, `.duration` or `.while` is not set, the object will run indefinitely. | ||
**Examples** | ||
```javascript | ||
{ | ||
enable: { | ||
start: '#abc.end + 5', // Start 5 seconds after #abc ends | ||
duration: '#abc.duration' // Have the same duration as #abc | ||
} | ||
} | ||
*/ | ||
// To see what will be on in a minute, we fetch the state for that time: | ||
var stateInAMinute = Timeline.Resolver.getState(tl, Date.now()/1000 + 60); | ||
/* | ||
stateNow = { | ||
time: 1511009749, | ||
GLayers: { | ||
'1': { | ||
id: 'obj1', | ||
trigger: {}, | ||
duration: 60, | ||
LLayer: 1, | ||
content: {}, | ||
resolved: {} | ||
} | ||
}, | ||
LLayers: { | ||
'1': { | ||
id: 'obj1', | ||
trigger: {}, | ||
duration: 60, | ||
LLayer: 1, | ||
content: {}, | ||
resolved: {} | ||
} | ||
} | ||
``` | ||
```javascript | ||
{ | ||
enable: { | ||
while: '#abc', // Enable while #abc is enabled | ||
} | ||
} | ||
*/ | ||
``` | ||
## Features | ||
## State & Layers | ||
All objects will be resolved to a **layer** in the calculated **state**. There are a few rules: | ||
* Only **one** object can exist on a layer at the same time. | ||
* If two (or more) objects fight for the place on a layer: | ||
* The one with highest `.priority` will win. | ||
* If tied, the one with *latest start time* will win. | ||
### Trigger types | ||
* **Absolute time** (TIME_ABSOLUTE) | ||
The start time of the object is defined as a float number (unix time). | ||
**Example** | ||
* **Relative time** (TIME_RELATIVE) | ||
The start time of the object is defined by an expression, relative to another object. | ||
Examples: | ||
**"#obj0.end"** The end time of another object | ||
**"#obj0.start"** The start time of another object | ||
**"#obj0.duration"** The duration of another object | ||
It is also possible to use basic math, using +, -, *, /, () | ||
Examples: | ||
**"#obj0.end - 2"** 2 seconds before the end of another object | ||
**"(#obj0.start + #obj0.end) / 2 "** Half-way in | ||
```javascript | ||
{ | ||
id: 'A', | ||
layer: 'L1', | ||
enable: { | ||
start: 10, | ||
end: 100 | ||
}, | ||
content: {}, | ||
}, | ||
{ | ||
id: 'B', | ||
layer: 'L1', | ||
enable: { | ||
start: 50, | ||
end: 10 | ||
}, | ||
content: {}, | ||
} | ||
// This will cause the timeline to be: | ||
// A on layer L1 for 10 - 50 | ||
// B on layer L1 for 50 - 60 | ||
// A on layer L1 for 60 - 100 (since B has stopped) | ||
* **Duraion** | ||
The duration of an object can either be an absolute number, or an expresstion (like the Relative time) | ||
``` | ||
* **Logical expression** (LOGICAL) | ||
Use a logical expression to place an object on the timeline (unlike a time-based expression). | ||
When the expression is evaluated to True, the object will be present. | ||
## References | ||
Examples: | ||
**"#obj0"** Id of another object (if the other object is playing, this object will be played as well) | ||
**"$L1"** Anything on LLayer 1 | ||
**"$G1"** Anything on GLayer 1 | ||
**".main"** If any other object with this class is present (read more on classes below) | ||
**"#obj0 & .main"** Logical AND | ||
**"#obj0 | .main"** Logical OR | ||
**"!#obj0"** Logical NOT | ||
### Reference types | ||
| Example | Description | | ||
|--|--| | ||
| `#objId` | Reference to the object that has the specified **.id** | | ||
| `.className` | Reference to any object that has the class-name in its **.classes** | | ||
| `$layerName` | Reference to any object that is on the specified layer (**.layer**) | | ||
#### Expressions as objects | ||
It is also possible to define expressions as objects, as opposed to the strings explained above. | ||
The object has a left-hand-side operand, a right-hand-side operand and an operator. The operand can be a number, a reference or another expression. | ||
#### Reference modifiers | ||
The references listed above can be modified: | ||
| Example | Description | | ||
|--|--| | ||
| #objId.start | Refer to the start of the object | | ||
| #objId.end| Refer to the end of the object | | ||
| #objId.duration | Refer to the duration of the object | | ||
Example: | ||
### Reference combinations | ||
The references can be combined using basic math expressions ( + - * / % ) and logical operators ( & | ! ) | ||
**"#obj0.end - 2"** is equivalent to | ||
**Examples** | ||
```javascript | ||
{ | ||
r: "#obj0.end" | ||
o: "-" | ||
l: "2" | ||
enable: { | ||
start: '#abc.start + #abc.duration / 2', // Start halfway in | ||
} | ||
} | ||
``` | ||
```javascript | ||
{ | ||
enable: { | ||
while: '#sun & !(#moon | #jupiter ) ', // Enable while #sun (but not #moon or #jupiter) are enabled. | ||
} | ||
} | ||
``` | ||
### Layers | ||
* **Logical layer** (LLayer): | ||
If two objects are on the same LLayer, the latest (or the one with highest priority) will take precedence. | ||
-------- | ||
* **Graphical layer** (GLayer): | ||
The difference between GLayers & LLayers are that while LLayers are used first to find out WHAT to play, WHERE to play it is defined by GLayers. **(For most applications, these two will always be the same.)** | ||
## Object reference | ||
| Attribute | Description | Examples | | ||
| ------------- |:-------------:| -----:| | ||
| id | The id must be unique | 'obj0' | | ||
| trigger.type | See "Trigger types" above | Enums.TriggerType.TIME_ABSOLUTE, TIME_RELATIVE, LOGICAL | | ||
| trigger.value | See "Trigger types" above | For TIME_ABSOLUTE: Date.now()/1000, TIME_RELATIVE: "#obj1.end", LOGICAL: "#obj1" | | ||
| duration | The duration of the object (0 is infinite) | 60 | | ||
| LLayer | See "Layers" above | 1 | | ||
| priority | Objects with higher priority will take precedence | 0 | | ||
| classes | An array of class-names, that can be referenced from other LOGICAL objects | ['main', 'bug'] | | ||
| disabled | Disables this object for resolving | true/false | | ||
| content | This is where you put your specific attributes, to use later in your application | {} | | ||
| content.keyframes | See keyframes below | [{Keyframe}] | | ||
## Keyframes | ||
It is possible to add keyframes to an object, which works the same way as normal objects, and their content is added to the object's. | ||
It is also possible to add keyframes to an object. A keyframe can have the same logics as normal timeline objects, and when "enabled", it applies it's `.content` on its parent object's `.content`. | ||
**Example** | ||
```javascript | ||
// example of an object with keyframes | ||
{ | ||
id: 'obj0', | ||
duration: 50, | ||
trigger: { | ||
type: Timeline.Enums.TriggerType.TIME_ABSOLUTE, | ||
value: 1000, | ||
id: 'myObj', | ||
layer: 'L1', | ||
enable: { | ||
start: 10, | ||
end: 100 | ||
}, | ||
LLayer: 1, | ||
content: { | ||
media: 'AMB', | ||
attributes: { | ||
positionY: 0, | ||
positionX: 0, | ||
scale: 1 | ||
opacity: 100 | ||
}, | ||
keyframes: [{ | ||
id: 'kf0', | ||
enable: { | ||
start: 5, // relative to parent, so will start at 15 | ||
duration: 10 | ||
}, | ||
keyframes: [ | ||
{ | ||
id: 'K0', // id must be unique | ||
duration: 5, // duration of keyframe | ||
trigger: { | ||
type: Timeline.Enums.TriggerType.TIME_ABSOLUTE, | ||
value: 5 // Abslute time means "relative to parent start time" for a keyframe | ||
}, | ||
content: { | ||
attributes: { | ||
scale: 0.5 | ||
} | ||
} | ||
}, | ||
] | ||
} | ||
content: { | ||
opacity: 0 | ||
} | ||
}] | ||
} | ||
// At the time 1000 the content will be: | ||
/* | ||
// This will cause the object to be | ||
// * Enabled between 10 - 100 | ||
// * Have opacity = 100 between 10 - 15, and 25 - 100 | ||
// * Have opacity = 0 between 15 - 25 | ||
``` | ||
## Groups | ||
It is also possible to add groups that contain other objects as children. The children will always be capped within their parent. | ||
Groups can work in 2 ways: | ||
* A *"Transparent group"* **does not** have a `.layer` assigned to it (or it's set to ''). A transparent group does not "collide" with other objects, nor be visible in the calculated state. But its children objects will always be put on the timeline. | ||
* A *"Normal group"* **does** have a `.layer` assigned to it. This means that the group works the same way as normal objects, and can collide with them. The children of the group will only be enabled while the parent is enabled. | ||
**Example** | ||
```javascript | ||
{ | ||
media: 'AMB', | ||
attributes: { | ||
positionY: 0, | ||
positionX: 0, | ||
scale: 1 | ||
} | ||
id: 'myGroup', | ||
layer: '', | ||
enable: { | ||
start: 10, | ||
duration: 10 | ||
repeat: 20 // Repeat every 20 seconds, so will start at 10, 30, 50 etc... | ||
}, | ||
content: {}, | ||
children: [{ | ||
id: 'child0', | ||
layer: 'L1', | ||
enable: { | ||
start: 2, // will repeat with parent, so will start at 12, 32, 52 etc... | ||
duration: null // Duration not set, but will be capped in parent, so will end at 20, 40, 60 etc... | ||
}, | ||
content: {}, | ||
}] | ||
} | ||
// At the time 1005 (when the keyframes has started) the content will be: | ||
/* | ||
{ | ||
media: 'AMB', | ||
attributes: { | ||
positionY: 0, | ||
positionX: 0, | ||
scale: 1, | ||
opacity: 0.5 | ||
} | ||
} | ||
// At the time 1010 (when the keyframe has ended) the content will be: | ||
/* | ||
{ | ||
media: 'AMB', | ||
attributes: { | ||
positionY: 0, | ||
positionX: 0, | ||
scale: 1 | ||
} | ||
} | ||
*/ | ||
``` | ||
## Todo | ||
* Add documentation for how to use *groups* | ||
--- | ||
Please note that in the examples above the times have been defined in seconds. | ||
This is for readability only, you may use whatever time-base you like (like milliseconds) in your implementation. |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is not supported yet
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
188824
19
29
273
1818
1
Updated@types/underscore@^1.8.9