@flighthq/timeline 0.1.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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/movieClip.d.ts +24 -0
- package/dist/movieClip.d.ts.map +1 -0
- package/dist/movieClip.js +123 -0
- package/dist/movieClip.js.map +1 -0
- package/dist/timeline.d.ts +23 -0
- package/dist/timeline.d.ts.map +1 -0
- package/dist/timeline.js +211 -0
- package/dist/timeline.js.map +1 -0
- package/package.json +39 -0
- package/src/movieClip.test.ts +430 -0
- package/src/timeline.test.ts +505 -0
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
import type { MovieClip, Timeline } from '@flighthq/types';
|
|
2
|
+
import { MovieClipKind } from '@flighthq/types';
|
|
3
|
+
|
|
4
|
+
import {
|
|
5
|
+
addMovieClipFrameScript,
|
|
6
|
+
createMovieClip,
|
|
7
|
+
createMovieClipData,
|
|
8
|
+
createMovieClipRuntime,
|
|
9
|
+
disposeMovieClipSignals,
|
|
10
|
+
enableMovieClipSignals,
|
|
11
|
+
getMovieClipCurrentFrame,
|
|
12
|
+
getMovieClipCurrentLabel,
|
|
13
|
+
getMovieClipFrameScript,
|
|
14
|
+
getMovieClipRuntime,
|
|
15
|
+
getMovieClipSignals,
|
|
16
|
+
getMovieClipTotalFrames,
|
|
17
|
+
gotoAndPlayMovieClip,
|
|
18
|
+
gotoAndStopMovieClip,
|
|
19
|
+
isMovieClipPlaying,
|
|
20
|
+
nextFrameMovieClip,
|
|
21
|
+
playMovieClip,
|
|
22
|
+
prevFrameMovieClip,
|
|
23
|
+
removeMovieClipFrameScript,
|
|
24
|
+
setMovieClipSource,
|
|
25
|
+
stopMovieClip,
|
|
26
|
+
updateMovieClip,
|
|
27
|
+
} from './movieClip';
|
|
28
|
+
import { createTimeline, createTimelineSource, playTimeline } from './timeline';
|
|
29
|
+
|
|
30
|
+
describe('addMovieClipFrameScript', () => {
|
|
31
|
+
it('does nothing when timeline is null', () => {
|
|
32
|
+
const clip = createMovieClip();
|
|
33
|
+
expect(() => addMovieClipFrameScript(clip, 1, () => {})).not.toThrow();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
it('attaches a script that fires on frame entry', () => {
|
|
37
|
+
const fired: number[] = [];
|
|
38
|
+
const clip = createMovieClip();
|
|
39
|
+
clip.data.timeline = createTimeline({
|
|
40
|
+
source: createTimelineSource({ totalFrames: 3, frameRate: null }),
|
|
41
|
+
target: clip,
|
|
42
|
+
});
|
|
43
|
+
addMovieClipFrameScript(clip, 2, (_t, f) => fired.push(f));
|
|
44
|
+
playMovieClip(clip);
|
|
45
|
+
updateMovieClip(clip, 0); // frame 1
|
|
46
|
+
updateMovieClip(clip, 0); // frame 2 — script fires
|
|
47
|
+
expect(fired).toEqual([2]);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
describe('createMovieClip', () => {
|
|
52
|
+
let movieClip: MovieClip;
|
|
53
|
+
|
|
54
|
+
beforeEach(() => {
|
|
55
|
+
movieClip = createMovieClip();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('initializes default values', () => {
|
|
59
|
+
expect(movieClip.data.timeline).toBeNull();
|
|
60
|
+
expect(movieClip.kind).toStrictEqual(MovieClipKind);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it('allows pre-defined values', () => {
|
|
64
|
+
const base = { data: { timeline: {} as Timeline } };
|
|
65
|
+
const obj = createMovieClip(base);
|
|
66
|
+
expect(obj.data.timeline).toStrictEqual(base.data.timeline);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it('returns a new object for better hidden-class performance', () => {
|
|
70
|
+
const base = {};
|
|
71
|
+
const obj = createMovieClip(base);
|
|
72
|
+
expect(obj).not.toStrictEqual(base);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe('createMovieClipData', () => {
|
|
77
|
+
it('returns default values', () => {
|
|
78
|
+
expect(createMovieClipData().timeline).toBeNull();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('allows pre-defined values', () => {
|
|
82
|
+
const timeline = {} as Timeline;
|
|
83
|
+
expect(createMovieClipData({ timeline }).timeline).toBe(timeline);
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('createMovieClipRuntime', () => {
|
|
88
|
+
it('returns a non-null runtime with movieClipSignals null', () => {
|
|
89
|
+
const runtime = createMovieClipRuntime();
|
|
90
|
+
expect(runtime).not.toBeNull();
|
|
91
|
+
expect(runtime.movieClipSignals).toBeNull();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
describe('disposeMovieClipSignals', () => {
|
|
96
|
+
it('clears movieClipSignals to null on the runtime', () => {
|
|
97
|
+
const clip = createMovieClip();
|
|
98
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3 }));
|
|
99
|
+
enableMovieClipSignals(clip);
|
|
100
|
+
expect(getMovieClipSignals(clip)).not.toBeNull();
|
|
101
|
+
disposeMovieClipSignals(clip);
|
|
102
|
+
expect(getMovieClipSignals(clip)).toBeNull();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('clears the underlying timeline signals', () => {
|
|
106
|
+
const clip = createMovieClip();
|
|
107
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3 }));
|
|
108
|
+
enableMovieClipSignals(clip);
|
|
109
|
+
expect(clip.data.timeline!.signals).not.toBeNull();
|
|
110
|
+
disposeMovieClipSignals(clip);
|
|
111
|
+
expect(clip.data.timeline!.signals).toBeNull();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('is idempotent — no-op when signals are already null', () => {
|
|
115
|
+
const clip = createMovieClip();
|
|
116
|
+
expect(() => disposeMovieClipSignals(clip)).not.toThrow();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('allows enableMovieClipSignals to re-arm after dispose', () => {
|
|
120
|
+
const clip = createMovieClip();
|
|
121
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3 }));
|
|
122
|
+
const first = enableMovieClipSignals(clip);
|
|
123
|
+
disposeMovieClipSignals(clip);
|
|
124
|
+
const second = enableMovieClipSignals(clip);
|
|
125
|
+
expect(second).not.toBe(first);
|
|
126
|
+
expect(getMovieClipSignals(clip)).toBe(second);
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
describe('enableMovieClipSignals', () => {
|
|
131
|
+
it('returns a signals group with all lifecycle signals defined', () => {
|
|
132
|
+
const clip = createMovieClip();
|
|
133
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3 }));
|
|
134
|
+
const signals = enableMovieClipSignals(clip);
|
|
135
|
+
expect(signals.onEnterFrame).toBeDefined();
|
|
136
|
+
expect(signals.onExitFrame).toBeDefined();
|
|
137
|
+
expect(signals.onFrameConstructed).toBeDefined();
|
|
138
|
+
expect(signals.onComplete).toBeDefined();
|
|
139
|
+
expect(signals.onLoop).toBeDefined();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('is idempotent — returns the same object on subsequent calls', () => {
|
|
143
|
+
const clip = createMovieClip();
|
|
144
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3 }));
|
|
145
|
+
expect(enableMovieClipSignals(clip)).toBe(enableMovieClipSignals(clip));
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
it('works before setMovieClipSource is called', () => {
|
|
149
|
+
const clip = createMovieClip();
|
|
150
|
+
expect(() => enableMovieClipSignals(clip)).not.toThrow();
|
|
151
|
+
expect(enableMovieClipSignals(clip)).not.toBeNull();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('emits onEnterFrame when the frame changes', () => {
|
|
155
|
+
const frames: number[] = [];
|
|
156
|
+
const clip = createMovieClip();
|
|
157
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3, frameRate: null }));
|
|
158
|
+
const signals = enableMovieClipSignals(clip);
|
|
159
|
+
signals.onEnterFrame.emit = (event) => frames.push(event.frame);
|
|
160
|
+
playMovieClip(clip);
|
|
161
|
+
updateMovieClip(clip, 0); // frame 1
|
|
162
|
+
updateMovieClip(clip, 0); // frame 2
|
|
163
|
+
expect(frames).toContain(2);
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
describe('getMovieClipCurrentFrame', () => {
|
|
168
|
+
it('returns 1 when timeline is null', () => {
|
|
169
|
+
const clip = createMovieClip();
|
|
170
|
+
expect(getMovieClipCurrentFrame(clip)).toBe(1);
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
it('returns the timeline currentFrame', () => {
|
|
174
|
+
const clip = createMovieClip();
|
|
175
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 5 }), currentFrame: 3 });
|
|
176
|
+
expect(getMovieClipCurrentFrame(clip)).toBe(3);
|
|
177
|
+
});
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
describe('getMovieClipCurrentLabel', () => {
|
|
181
|
+
it('returns null when timeline is null', () => {
|
|
182
|
+
const clip = createMovieClip();
|
|
183
|
+
expect(getMovieClipCurrentLabel(clip)).toBeNull();
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
it('returns the label at the current frame', () => {
|
|
187
|
+
const clip = createMovieClip();
|
|
188
|
+
setMovieClipSource(
|
|
189
|
+
clip,
|
|
190
|
+
createTimelineSource({
|
|
191
|
+
totalFrames: 5,
|
|
192
|
+
labels: [
|
|
193
|
+
{ name: 'idle', frame: 1 },
|
|
194
|
+
{ name: 'run', frame: 3 },
|
|
195
|
+
],
|
|
196
|
+
}),
|
|
197
|
+
);
|
|
198
|
+
gotoAndStopMovieClip(clip, 3);
|
|
199
|
+
expect(getMovieClipCurrentLabel(clip)?.name).toBe('run');
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
describe('getMovieClipFrameScript', () => {
|
|
204
|
+
it('returns null when timeline is null', () => {
|
|
205
|
+
const clip = createMovieClip();
|
|
206
|
+
expect(getMovieClipFrameScript(clip, 1)).toBeNull();
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it('returns null when no script is attached', () => {
|
|
210
|
+
const clip = createMovieClip();
|
|
211
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 3 }) });
|
|
212
|
+
expect(getMovieClipFrameScript(clip, 1)).toBeNull();
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('returns the script after addMovieClipFrameScript', () => {
|
|
216
|
+
const clip = createMovieClip();
|
|
217
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 3 }) });
|
|
218
|
+
const fn = () => {};
|
|
219
|
+
addMovieClipFrameScript(clip, 2, fn);
|
|
220
|
+
expect(getMovieClipFrameScript(clip, 2)).toBe(fn);
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
|
|
224
|
+
describe('getMovieClipRuntime', () => {
|
|
225
|
+
it('returns the runtime for a MovieClip', () => {
|
|
226
|
+
expect(getMovieClipRuntime(createMovieClip())).not.toBeNull();
|
|
227
|
+
});
|
|
228
|
+
});
|
|
229
|
+
|
|
230
|
+
describe('getMovieClipSignals', () => {
|
|
231
|
+
it('returns null before enableMovieClipSignals is called', () => {
|
|
232
|
+
const clip = createMovieClip();
|
|
233
|
+
expect(getMovieClipSignals(clip)).toBeNull();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('returns the signals group after enableMovieClipSignals', () => {
|
|
237
|
+
const clip = createMovieClip();
|
|
238
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 3 }));
|
|
239
|
+
const signals = enableMovieClipSignals(clip);
|
|
240
|
+
expect(getMovieClipSignals(clip)).toBe(signals);
|
|
241
|
+
});
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
describe('getMovieClipTotalFrames', () => {
|
|
245
|
+
it('returns 1 when timeline is null', () => {
|
|
246
|
+
const clip = createMovieClip();
|
|
247
|
+
expect(getMovieClipTotalFrames(clip)).toBe(1);
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it('returns the timeline totalFrames', () => {
|
|
251
|
+
const clip = createMovieClip();
|
|
252
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 10 }) });
|
|
253
|
+
expect(getMovieClipTotalFrames(clip)).toBe(10);
|
|
254
|
+
});
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
describe('gotoAndPlayMovieClip', () => {
|
|
258
|
+
it('does nothing when timeline is null', () => {
|
|
259
|
+
const clip = createMovieClip();
|
|
260
|
+
expect(() => gotoAndPlayMovieClip(clip, 2)).not.toThrow();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('seeks to the given frame and starts playing', () => {
|
|
264
|
+
const clip = createMovieClip();
|
|
265
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 5 }) });
|
|
266
|
+
gotoAndPlayMovieClip(clip, 3);
|
|
267
|
+
expect(clip.data.timeline.currentFrame).toBe(3);
|
|
268
|
+
expect(clip.data.timeline.isPlaying).toBe(true);
|
|
269
|
+
});
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
describe('gotoAndStopMovieClip', () => {
|
|
273
|
+
it('does nothing when timeline is null', () => {
|
|
274
|
+
const clip = createMovieClip();
|
|
275
|
+
expect(() => gotoAndStopMovieClip(clip, 2)).not.toThrow();
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
it('seeks to the given frame and stops', () => {
|
|
279
|
+
const clip = createMovieClip();
|
|
280
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 5 }) });
|
|
281
|
+
playMovieClip(clip);
|
|
282
|
+
gotoAndStopMovieClip(clip, 2);
|
|
283
|
+
expect(clip.data.timeline.currentFrame).toBe(2);
|
|
284
|
+
expect(clip.data.timeline.isPlaying).toBe(false);
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
describe('isMovieClipPlaying', () => {
|
|
289
|
+
it('returns false when timeline is null', () => {
|
|
290
|
+
const clip = createMovieClip();
|
|
291
|
+
expect(isMovieClipPlaying(clip)).toBe(false);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
it('returns true when the timeline is playing', () => {
|
|
295
|
+
const clip = createMovieClip();
|
|
296
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 3 }) });
|
|
297
|
+
playTimeline(clip.data.timeline);
|
|
298
|
+
expect(isMovieClipPlaying(clip)).toBe(true);
|
|
299
|
+
});
|
|
300
|
+
});
|
|
301
|
+
|
|
302
|
+
describe('nextFrameMovieClip', () => {
|
|
303
|
+
it('does nothing when timeline is null', () => {
|
|
304
|
+
const clip = createMovieClip();
|
|
305
|
+
expect(() => nextFrameMovieClip(clip)).not.toThrow();
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it('advances currentFrame by one', () => {
|
|
309
|
+
const clip = createMovieClip();
|
|
310
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 5 }), currentFrame: 2 });
|
|
311
|
+
nextFrameMovieClip(clip);
|
|
312
|
+
expect(clip.data.timeline.currentFrame).toBe(3);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
describe('playMovieClip', () => {
|
|
317
|
+
it('does nothing when timeline is null', () => {
|
|
318
|
+
const clip = createMovieClip();
|
|
319
|
+
expect(() => playMovieClip(clip)).not.toThrow();
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('starts the timeline playing', () => {
|
|
323
|
+
const clip = createMovieClip();
|
|
324
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 3 }) });
|
|
325
|
+
playMovieClip(clip);
|
|
326
|
+
expect(clip.data.timeline.isPlaying).toBe(true);
|
|
327
|
+
});
|
|
328
|
+
});
|
|
329
|
+
|
|
330
|
+
describe('prevFrameMovieClip', () => {
|
|
331
|
+
it('does nothing when timeline is null', () => {
|
|
332
|
+
const clip = createMovieClip();
|
|
333
|
+
expect(() => prevFrameMovieClip(clip)).not.toThrow();
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
it('moves currentFrame back by one', () => {
|
|
337
|
+
const clip = createMovieClip();
|
|
338
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 5 }), currentFrame: 3 });
|
|
339
|
+
prevFrameMovieClip(clip);
|
|
340
|
+
expect(clip.data.timeline.currentFrame).toBe(2);
|
|
341
|
+
});
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
describe('removeMovieClipFrameScript', () => {
|
|
345
|
+
it('does nothing when timeline is null', () => {
|
|
346
|
+
const clip = createMovieClip();
|
|
347
|
+
expect(() => removeMovieClipFrameScript(clip, 1)).not.toThrow();
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
it('removes the script so it no longer fires', () => {
|
|
351
|
+
const fired: number[] = [];
|
|
352
|
+
const clip = createMovieClip();
|
|
353
|
+
clip.data.timeline = createTimeline({
|
|
354
|
+
source: createTimelineSource({ totalFrames: 3, frameRate: null }),
|
|
355
|
+
target: clip,
|
|
356
|
+
});
|
|
357
|
+
addMovieClipFrameScript(clip, 2, (_t, f) => fired.push(f));
|
|
358
|
+
removeMovieClipFrameScript(clip, 2);
|
|
359
|
+
playMovieClip(clip);
|
|
360
|
+
updateMovieClip(clip, 0); // frame 1
|
|
361
|
+
updateMovieClip(clip, 0); // frame 2 — script should not fire
|
|
362
|
+
expect(fired).toEqual([]);
|
|
363
|
+
});
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
describe('setMovieClipSource', () => {
|
|
367
|
+
it('binds a source, targets the clip, and realizes the initial frame', () => {
|
|
368
|
+
const frames: number[] = [];
|
|
369
|
+
const clip = createMovieClip();
|
|
370
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 4, constructFrame: (_t, f) => frames.push(f) }));
|
|
371
|
+
expect(getMovieClipTotalFrames(clip)).toBe(4);
|
|
372
|
+
expect(clip.data.timeline?.target).toBe(clip);
|
|
373
|
+
expect(frames).toEqual([1]);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('reuses an existing timeline on the clip', () => {
|
|
377
|
+
const clip = createMovieClip();
|
|
378
|
+
clip.data.timeline = createTimeline({ currentFrame: 2 });
|
|
379
|
+
const existing = clip.data.timeline;
|
|
380
|
+
setMovieClipSource(clip, createTimelineSource({ totalFrames: 5 }));
|
|
381
|
+
expect(clip.data.timeline).toBe(existing);
|
|
382
|
+
expect(clip.data.timeline?.source?.totalFrames).toBe(5);
|
|
383
|
+
});
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
describe('stopMovieClip', () => {
|
|
387
|
+
it('does nothing when timeline is null', () => {
|
|
388
|
+
const clip = createMovieClip();
|
|
389
|
+
expect(() => stopMovieClip(clip)).not.toThrow();
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
it('stops a playing timeline', () => {
|
|
393
|
+
const clip = createMovieClip();
|
|
394
|
+
clip.data.timeline = createTimeline({ source: createTimelineSource({ totalFrames: 3 }) });
|
|
395
|
+
playMovieClip(clip);
|
|
396
|
+
stopMovieClip(clip);
|
|
397
|
+
expect(clip.data.timeline.isPlaying).toBe(false);
|
|
398
|
+
});
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
describe('updateMovieClip', () => {
|
|
402
|
+
it('does nothing when timeline is null', () => {
|
|
403
|
+
const clip = createMovieClip();
|
|
404
|
+
expect(() => updateMovieClip(clip, 16)).not.toThrow();
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('advances the timeline when playing', () => {
|
|
408
|
+
const frames: number[] = [];
|
|
409
|
+
const clip = createMovieClip();
|
|
410
|
+
clip.data.timeline = createTimeline({
|
|
411
|
+
source: createTimelineSource({ totalFrames: 3, frameRate: null, constructFrame: (_t, f) => frames.push(f) }),
|
|
412
|
+
target: clip,
|
|
413
|
+
});
|
|
414
|
+
playTimeline(clip.data.timeline);
|
|
415
|
+
updateMovieClip(clip, 16);
|
|
416
|
+
updateMovieClip(clip, 16);
|
|
417
|
+
expect(frames).toEqual([1, 2]);
|
|
418
|
+
});
|
|
419
|
+
|
|
420
|
+
it('fires constructFrame for frame 1 on first update even when stopped', () => {
|
|
421
|
+
const frames: number[] = [];
|
|
422
|
+
const clip = createMovieClip();
|
|
423
|
+
clip.data.timeline = createTimeline({
|
|
424
|
+
source: createTimelineSource({ totalFrames: 3, constructFrame: (_t, f) => frames.push(f) }),
|
|
425
|
+
target: clip,
|
|
426
|
+
});
|
|
427
|
+
updateMovieClip(clip, 0);
|
|
428
|
+
expect(frames).toEqual([1]);
|
|
429
|
+
});
|
|
430
|
+
});
|