hzengine-core 0.1.2-dev

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.
Files changed (103) hide show
  1. package/dist/async/index.js +162 -0
  2. package/dist/async/zeppos_timer.js +58 -0
  3. package/dist/audio/index.js +260 -0
  4. package/dist/config/index.js +57 -0
  5. package/dist/debug/index.js +8 -0
  6. package/dist/index.js +103 -0
  7. package/dist/platform/index.js +1 -0
  8. package/dist/plugins/basic_command/$.js +8 -0
  9. package/dist/plugins/basic_command/audio.js +40 -0
  10. package/dist/plugins/basic_command/basic.js +124 -0
  11. package/dist/plugins/basic_command/character.js +112 -0
  12. package/dist/plugins/basic_command/conditional.js +260 -0
  13. package/dist/plugins/basic_command/config.js +22 -0
  14. package/dist/plugins/basic_command/decorator.js +24 -0
  15. package/dist/plugins/basic_command/eval.js +67 -0
  16. package/dist/plugins/basic_command/img.js +249 -0
  17. package/dist/plugins/basic_command/index.js +22 -0
  18. package/dist/plugins/basic_command/menu.js +140 -0
  19. package/dist/plugins/global_gesture/index.js +25 -0
  20. package/dist/plugins/transform/animation.js +440 -0
  21. package/dist/plugins/transform/commands.js +38 -0
  22. package/dist/plugins/transform/example_profiles.js +32 -0
  23. package/dist/plugins/transform/hz_anime.js +211 -0
  24. package/dist/plugins/transform/index.js +93 -0
  25. package/dist/script/index.js +537 -0
  26. package/dist/script/readscript.js +15 -0
  27. package/dist/script/strtools.js +157 -0
  28. package/dist/storage/decorator.js +260 -0
  29. package/dist/storage/fs.js +96 -0
  30. package/dist/storage/index.js +442 -0
  31. package/dist/system/index.js +144 -0
  32. package/dist/ui/index.js +535 -0
  33. package/dist/utils/path.js +289 -0
  34. package/license.txt +202 -0
  35. package/package.json +26 -0
  36. package/src/async/index.ts +124 -0
  37. package/src/async/zeppos_timer.js +65 -0
  38. package/src/audio/index.ts +224 -0
  39. package/src/config/index.ts +80 -0
  40. package/src/debug/index.ts +11 -0
  41. package/src/index.ts +122 -0
  42. package/src/platform/index.ts +158 -0
  43. package/src/plugins/basic_command/$.ts +11 -0
  44. package/src/plugins/basic_command/audio.ts +53 -0
  45. package/src/plugins/basic_command/basic.ts +145 -0
  46. package/src/plugins/basic_command/character.ts +144 -0
  47. package/src/plugins/basic_command/conditional.ts +349 -0
  48. package/src/plugins/basic_command/config.ts +29 -0
  49. package/src/plugins/basic_command/decorator.ts +29 -0
  50. package/src/plugins/basic_command/eval.ts +88 -0
  51. package/src/plugins/basic_command/img.ts +317 -0
  52. package/src/plugins/basic_command/index.ts +24 -0
  53. package/src/plugins/basic_command/menu.ts +178 -0
  54. package/src/plugins/global_gesture/index.ts +29 -0
  55. package/src/plugins/transform/animation.ts +542 -0
  56. package/src/plugins/transform/commands.ts +53 -0
  57. package/src/plugins/transform/example_profiles.ts +36 -0
  58. package/src/plugins/transform/hz_anime.ts +214 -0
  59. package/src/plugins/transform/index.ts +141 -0
  60. package/src/plugins/transform/readme.md +1 -0
  61. package/src/script/index.ts +623 -0
  62. package/src/script/readscript.ts +17 -0
  63. package/src/script/strtools.ts +159 -0
  64. package/src/storage/decorator.ts +473 -0
  65. package/src/storage/fs.ts +104 -0
  66. package/src/storage/index.ts +541 -0
  67. package/src/system/index.ts +95 -0
  68. package/src/ui/index.ts +699 -0
  69. package/src/utils/path.js +338 -0
  70. package/tsconfig.json +111 -0
  71. package/types/async/index.d.ts +24 -0
  72. package/types/async/zeppos_timer.d.ts +14 -0
  73. package/types/audio/index.d.ts +64 -0
  74. package/types/config/index.d.ts +9 -0
  75. package/types/debug/index.d.ts +6 -0
  76. package/types/index.d.ts +41 -0
  77. package/types/platform/index.d.ts +134 -0
  78. package/types/plugins/basic_command/$.d.ts +2 -0
  79. package/types/plugins/basic_command/audio.d.ts +2 -0
  80. package/types/plugins/basic_command/basic.d.ts +3 -0
  81. package/types/plugins/basic_command/character.d.ts +2 -0
  82. package/types/plugins/basic_command/conditional.d.ts +2 -0
  83. package/types/plugins/basic_command/config.d.ts +2 -0
  84. package/types/plugins/basic_command/decorator.d.ts +2 -0
  85. package/types/plugins/basic_command/eval.d.ts +2 -0
  86. package/types/plugins/basic_command/img.d.ts +2 -0
  87. package/types/plugins/basic_command/index.d.ts +2 -0
  88. package/types/plugins/basic_command/menu.d.ts +2 -0
  89. package/types/plugins/global_gesture/index.d.ts +2 -0
  90. package/types/plugins/transform/animation.d.ts +131 -0
  91. package/types/plugins/transform/commands.d.ts +7 -0
  92. package/types/plugins/transform/example_profiles.d.ts +2 -0
  93. package/types/plugins/transform/hz_anime.d.ts +51 -0
  94. package/types/plugins/transform/index.d.ts +13 -0
  95. package/types/script/index.d.ts +123 -0
  96. package/types/script/readscript.d.ts +2 -0
  97. package/types/script/strtools.d.ts +31 -0
  98. package/types/storage/decorator.d.ts +41 -0
  99. package/types/storage/fs.d.ts +1 -0
  100. package/types/storage/index.d.ts +86 -0
  101. package/types/system/index.d.ts +35 -0
  102. package/types/ui/index.d.ts +167 -0
  103. package/types/utils/path.d.ts +84 -0
@@ -0,0 +1,542 @@
1
+ /**
2
+ * animation.js
3
+ * @description A library for providing multi-track animations for HZEngine. 一个用于在HZEngine中提供简单动画的库
4
+ * @date 2024/10/2
5
+ * @author CuberQAQ
6
+ */
7
+
8
+ export class Animation<P extends Profile.PropsType = unknown> {
9
+ normalizedProfile: Profile.Track<P>;
10
+ initProps: Partial<P> = {};
11
+ activeRootTrack: ActiveTrackNode<P> | null = null;
12
+ lastTime: number = 0;
13
+ public onFrame: ((props: Partial<P>) => void) | null = null;
14
+ public onEnd: (() => void) | null = null;
15
+ customWrappers: Record<string, Wrapper> = {};
16
+
17
+ constructor(profile: Profile<P>, options?: Animation.Options<P>) {
18
+ this.normalizedProfile = Profile.normalize(profile);
19
+ console.log(`Animation: ${JSON.stringify(profile)}`);
20
+
21
+ if (options) {
22
+ options.initProps && (this.initProps = options.initProps);
23
+ options.wrappers && (this.customWrappers = options.wrappers);
24
+ }
25
+ }
26
+
27
+ public onStop: ((animation: Animation<P>) => void) | null = null;
28
+
29
+ serialize(): Animation.Serialized {
30
+ return {
31
+ normalizedProfile: this.normalizedProfile,
32
+ initProps: this.initProps,
33
+ activeRootTrack: this.activeRootTrack?.serialize(),
34
+ lastTime: this.lastTime,
35
+ };
36
+ }
37
+ static unserialize(
38
+ serialized: Animation.Serialized,
39
+ wrappers?: Record<string, Wrapper>
40
+ ): Animation<unknown> {
41
+ let profile = serialized.normalizedProfile;
42
+ let animation = new Animation(profile, {
43
+ initProps: serialized.initProps,
44
+ wrappers,
45
+ });
46
+ animation.lastTime = serialized.lastTime;
47
+ serialized.activeRootTrack &&
48
+ (animation.activeRootTrack = ActiveTrackNode.unserialize(
49
+ animation,
50
+ serialized.activeRootTrack
51
+ ));
52
+ return animation;
53
+ }
54
+
55
+ timerCb(): void {}
56
+
57
+ init(): void {
58
+ this.activeRootTrack = new ActiveTrackNode(this, {
59
+ accessKeys: [],
60
+ index: 0,
61
+ initProps: this.initProps,
62
+ });
63
+ }
64
+
65
+ goto(time: number) {
66
+ if (!this.activeRootTrack) {
67
+ this.init();
68
+ }
69
+ if (time < 0) time = 0;
70
+ if (time < this.lastTime) {
71
+ this.init(); // reset the tracknode
72
+ try {
73
+ this.activeRootTrack!.step(time);
74
+ } catch (e) {
75
+ console.log(e);
76
+ this.activeRootTrack!.status = ActiveTrackNode.Status.Pause;
77
+ }
78
+ if (this.activeRootTrack!.status === ActiveTrackNode.Status.Pause) {
79
+ if (this.onEnd) this.onEnd();
80
+ }
81
+ } else {
82
+ if (this.activeRootTrack!.status !== ActiveTrackNode.Status.Pause) {
83
+ try {
84
+ this.activeRootTrack!.step(time - this.lastTime);
85
+ } catch (e) {
86
+ console.log(e);
87
+ this.activeRootTrack!.status = ActiveTrackNode.Status.Pause;
88
+ }
89
+ }
90
+ }
91
+ this.lastTime = time;
92
+
93
+ if (this.onFrame) {
94
+ // console.log("on frame", JSON.stringify(this.calcProps()));
95
+ this.onFrame(this.calcProps());
96
+ }
97
+
98
+ if (this.activeRootTrack!.status === ActiveTrackNode.Status.Pause) {
99
+ if (this.onEnd) this.onEnd();
100
+ }
101
+ }
102
+
103
+ step(delta_time: number) {
104
+ this.goto(this.lastTime + delta_time);
105
+ }
106
+
107
+ calcProps(): Partial<P> {
108
+ return this.activeRootTrack!.calcProps();
109
+ }
110
+
111
+ reverse(): void {}
112
+
113
+ stop(): void {}
114
+
115
+ _accessProfile(accessKeys: string[]): unknown {
116
+ let section: any = this.normalizedProfile;
117
+ for (let i = 0; i < accessKeys.length; i++) {
118
+ section = section[accessKeys[i]];
119
+ }
120
+ return section;
121
+ }
122
+
123
+ _getWrapper(wrapper: string | Wrapper | undefined): Wrapper {
124
+ if (typeof wrapper === "string") {
125
+ return (
126
+ this.customWrappers[wrapper] ??
127
+ buildInWrappers[wrapper as keyof typeof buildInWrappers] ??
128
+ buildInWrappers.none
129
+ );
130
+ } else if (wrapper === undefined) {
131
+ return buildInWrappers.none;
132
+ } else return wrapper;
133
+ }
134
+
135
+ _calcWrappedProps<P extends Profile.PropsType>(
136
+ former_props: Partial<P>,
137
+ props: Partial<P>,
138
+ wrapper: Wrapper | string | undefined,
139
+ progress: number
140
+ ): Partial<P> {
141
+ let _former_props: any = { ...former_props };
142
+ let wrapper_func = this._getWrapper(wrapper);
143
+ let wraped_prog = wrapper_func(progress);
144
+ let res = { ..._former_props };
145
+ for (let key in props) {
146
+ if (typeof props[key] === "number") {
147
+ if (_former_props[key] == undefined) _former_props[key] = 0;
148
+ res[key] =
149
+ _former_props[key] + wraped_prog * (props[key] - _former_props[key]);
150
+ } else if (typeof props[key] === "boolean") {
151
+ if (_former_props[key] == undefined) _former_props[key] = false;
152
+ res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
153
+ } else if (typeof props[key] === "string") {
154
+ if (_former_props[key] == undefined) _former_props[key] = "";
155
+ res[key] = wraped_prog === 1 ? props[key] : _former_props[key];
156
+ } else {
157
+ res[key] = props[key];
158
+ }
159
+ }
160
+ return res;
161
+ }
162
+ }
163
+
164
+ export namespace Animation {
165
+ export interface Options<P extends Profile.PropsType> {
166
+ // @ts-ignore
167
+ initProps?: Partial<P>;
168
+ wrappers?: Record<string, Wrapper>;
169
+ }
170
+ export interface Serialized {
171
+ normalizedProfile: Profile.Serialized;
172
+ initProps?: Partial<unknown>;
173
+ activeRootTrack?: ActiveTrackNode.Serialized;
174
+ lastTime: number;
175
+ }
176
+ }
177
+
178
+ export type Profile<P extends Profile.PropsType = unknown> =
179
+ | Profile.Section<P>
180
+ | Profile.Track<P>
181
+ | Profile.TrackList<P>;
182
+
183
+ export namespace Profile {
184
+ export type Serialized = Profile;
185
+
186
+ export type TrackList<P extends PropsType> = Track<P>[];
187
+ export type Track<P extends PropsType> = Section<P>[];
188
+ export type Section<P extends PropsType> = {
189
+ time?: number;
190
+ repeat?: number;
191
+ wrapper?: keyof typeof buildInWrappers | string | Wrapper;
192
+ frame?: Partial<P>;
193
+ syncs?: Profile<P>[];
194
+ asyncs?: Profile<P>[];
195
+ };
196
+ export type FrameItem = number | boolean | string;
197
+ export type PropsType = Record<string, FrameItem> | unknown;
198
+ export function normalize<P extends PropsType>(
199
+ profile: Profile<P>
200
+ ): Track<P> {
201
+ if (!Array.isArray(profile)) {
202
+ // section
203
+ return [profile];
204
+ } else if (profile.length === 0) {
205
+ // empty track/tracklist
206
+ return [];
207
+ } else if (!Array.isArray(profile[0])) {
208
+ // track
209
+ return profile as Track<P>;
210
+ } else {
211
+ // tracklist
212
+ return [
213
+ {
214
+ syncs: profile,
215
+ },
216
+ ];
217
+ }
218
+ }
219
+ }
220
+
221
+ export interface Timer<TimerIdType> {
222
+ init(animation: Animation): void;
223
+ // 回調時調用animation.timerCallback
224
+ setTimeout(timeout?: number): TimerIdType;
225
+ clearTimeout(timerId: TimerIdType): void;
226
+ setInterval(interval?: number): TimerIdType;
227
+ clearInterval(timerId: TimerIdType): void;
228
+ getTime(): number; // in ms
229
+ setOption?(option: Timer.Options): void;
230
+ }
231
+
232
+ export namespace Timer {
233
+ export interface Options {
234
+ fps?: number;
235
+ }
236
+ }
237
+
238
+ export class ActiveTrackNode<P extends Profile.PropsType> {
239
+ accessKeys: string[];
240
+ currentIndex: number | null;
241
+ repeated: number = 0;
242
+ status: ActiveTrackNode.Status = ActiveTrackNode.Status.Playing;
243
+ now_time: number = 0;
244
+ #currentSection: Profile.Section<P> | null = null;
245
+ #currentIndex: number | null = null;
246
+ get currentSection() {
247
+ if (this.#currentSection === null) {
248
+ if (this.currentIndex === null) {
249
+ this.#currentSection = this.animation._accessProfile(
250
+ this.accessKeys
251
+ ) as Profile.Section<P>;
252
+ } else {
253
+ this.#currentSection = this.currentTrack![this.currentIndex!];
254
+ }
255
+ this.#currentIndex = this.currentIndex;
256
+ } else if (this.currentIndex !== this.#currentIndex) {
257
+ this.#currentSection = this.currentTrack![this.currentIndex!];
258
+ this.#currentIndex = this.currentIndex;
259
+ }
260
+ return this.#currentSection;
261
+ }
262
+ #currentTrack: Profile.Track<P> | null = null;
263
+ get currentTrack() {
264
+ if (this.#currentTrack === null && this.currentIndex !== null) {
265
+ this.#currentTrack = this.animation._accessProfile(
266
+ this.accessKeys
267
+ ) as Profile.Track<P>;
268
+ }
269
+ return this.#currentTrack;
270
+ }
271
+ lastProps: Partial<P> = {};
272
+ nowProps: Partial<P> = {};
273
+ constructor(
274
+ public animation: Animation,
275
+ {
276
+ accessKeys,
277
+ index,
278
+ initProps,
279
+ }: {
280
+ accessKeys: string[];
281
+ index: number | null;
282
+ initProps: Partial<P>;
283
+ }
284
+ ) {
285
+ this.accessKeys = accessKeys;
286
+ this.currentIndex = index;
287
+
288
+ this.lastProps = { ...initProps };
289
+ this.nowProps = { ...initProps };
290
+ }
291
+
292
+ serialize(): ActiveTrackNode.Serialized {
293
+ return {
294
+ accessKeys: this.accessKeys,
295
+ currentIndex: this.currentIndex,
296
+ repeated: this.repeated,
297
+ status: this.status,
298
+ now_time: this.now_time,
299
+ lastProps: this.lastProps,
300
+ nowProps: this.nowProps,
301
+ activeSyncs: this.activeSyncs.map((sync) => sync.serialize()),
302
+ };
303
+ }
304
+ static unserialize<P>(
305
+ animation: Animation,
306
+ serialized: ActiveTrackNode.Serialized
307
+ ): ActiveTrackNode<P> {
308
+ let node = new ActiveTrackNode(animation, {
309
+ accessKeys: serialized.accessKeys,
310
+ index: serialized.currentIndex,
311
+ initProps: serialized.lastProps,
312
+ });
313
+ node.lastProps = serialized.lastProps;
314
+ node.nowProps = serialized.nowProps;
315
+ node.status = serialized.status;
316
+ node.repeated = serialized.repeated;
317
+ node.now_time = serialized.now_time;
318
+
319
+ node.activeSyncs = serialized.activeSyncs.map((sync) =>
320
+ ActiveTrackNode.unserialize<P>(animation, sync)
321
+ );
322
+ return node;
323
+ }
324
+ /**
325
+ *
326
+ * @param delta_time
327
+ * @returns 剩餘的時間
328
+ */
329
+ step(delta_time: number): number {
330
+ // console.log(`node step: ${delta_time}`);
331
+
332
+ // if (this.status === ActiveTrackNode.Status.Pause) return delta_time;
333
+ // because we should proceed async list
334
+ // normal
335
+ if(!this.currentSection) {
336
+ this.status = ActiveTrackNode.Status.Pause;
337
+ return delta_time;
338
+ }
339
+ while (true) {
340
+ // constant field: time, wrapper, frame
341
+ // instant filed: syncs, asyncs
342
+ if (this.status === ActiveTrackNode.Status.Playing) {
343
+ if (
344
+ this.currentSection.time === undefined ||
345
+ this.currentSection.time <= 0
346
+ ) {
347
+ this.nowProps = { ...this.nowProps, ...this.currentSection.frame };
348
+ } else {
349
+ if (this.now_time + delta_time >= this.currentSection.time) {
350
+ // this.now_time = this.currentSection.time
351
+ delta_time -= this.currentSection.time - this.now_time;
352
+ this.nowProps = { ...this.nowProps, ...this.currentSection.frame };
353
+ } else {
354
+ this.now_time += delta_time;
355
+ delta_time = 0;
356
+ // calc
357
+ let progress = this.now_time / this.currentSection.time;
358
+ // console.log(`progress: ${progress}`);
359
+ this.nowProps = this.animation._calcWrappedProps(
360
+ this.lastProps,
361
+ this.currentSection.frame ?? {},
362
+ this.currentSection.wrapper,
363
+ progress
364
+ );
365
+ break;
366
+ }
367
+ }
368
+
369
+ // sync async
370
+ if (this.currentSection.syncs && this.currentSection.syncs.length > 0) {
371
+ this.initSyncs();
372
+ this.status = ActiveTrackNode.Status.WaitingSyncs;
373
+ }
374
+ }
375
+
376
+ // step and check sync
377
+ if (this.status === ActiveTrackNode.Status.WaitingSyncs) {
378
+ delta_time = this.stepSyncs(delta_time); // returns lefted time
379
+ this.nowProps = Object.assign(this.nowProps, this.getSyncsProps());
380
+ if (this.checkSyncsFinished()) {
381
+ this.status = ActiveTrackNode.Status.Playing;
382
+ this.activeSyncs = [];
383
+ } else {
384
+ // debug
385
+ if (delta_time !== 0)
386
+ throw "syncs not finished while lefted time != 0. may be bugs";
387
+ break;
388
+ }
389
+ }
390
+
391
+ // check repeat , finish
392
+ if (this.currentSection.repeat !== undefined) {
393
+ this.repeated++;
394
+ if (this.repeated >= this.currentSection.repeat) {
395
+ // finish and proceed next section
396
+ // TODO
397
+ if (this._switchNextSection()) continue;
398
+ else break;
399
+ } else {
400
+ // continue this section
401
+ this.now_time = 0;
402
+ this.nowProps = { ...this.lastProps };
403
+ continue;
404
+ }
405
+ } else {
406
+ if (this._switchNextSection()) continue;
407
+ else break;
408
+ }
409
+ }
410
+
411
+ // waiting syncs
412
+
413
+ return delta_time;
414
+ }
415
+
416
+ calcProps(): Partial<P> {
417
+ return this.nowProps;
418
+ }
419
+
420
+ _switchNextSection(): boolean {
421
+ if (
422
+ this.currentIndex === null ||
423
+ this.currentTrack!.length === this.currentIndex + 1
424
+ ) {
425
+ // already reach the end
426
+ this.status = ActiveTrackNode.Status.Pause;
427
+ return false;
428
+ } else {
429
+ this.lastProps = { ...this.nowProps };
430
+ this.repeated = 0;
431
+ this.now_time = 0;
432
+ this.currentIndex++;
433
+ return true;
434
+ }
435
+ }
436
+
437
+ activeSyncs: ActiveTrackNode<P>[] = [];
438
+
439
+ initSyncs() {
440
+ // console.log("init syncs");
441
+
442
+ let activeSyncs: ActiveTrackNode<P>[] = [];
443
+ // if (this.currentSection.syncs == null) return;
444
+ let subprofile = this.currentSection.syncs!;
445
+ let activeTrackNode;
446
+ if (Array.isArray(subprofile)) {
447
+ if (subprofile.length > 0 && Array.isArray(subprofile[0])) {
448
+ // tracklist
449
+ for (let j = 0; j < subprofile.length; ++j) {
450
+ activeTrackNode = new ActiveTrackNode(this.animation, {
451
+ accessKeys: [
452
+ ...this.accessKeys,
453
+ "" + this.currentIndex,
454
+ "syncs",
455
+ "" + j,
456
+ ],
457
+ index: 0,
458
+ initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
459
+ });
460
+ activeSyncs.push(activeTrackNode);
461
+ }
462
+ } else {
463
+ // Track
464
+ activeTrackNode = new ActiveTrackNode(this.animation, {
465
+ accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
466
+ index: 0,
467
+ initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
468
+ });
469
+ activeSyncs.push(activeTrackNode);
470
+ console
471
+ .log
472
+ // "create subtrack=" + JSON.stringify(activeTrackNode.serialize())
473
+ ();
474
+ }
475
+ } else {
476
+ // section
477
+ activeTrackNode = new ActiveTrackNode(this.animation, {
478
+ accessKeys: [...this.accessKeys, "" + this.currentIndex, "syncs"],
479
+ index: null,
480
+ initProps: this.nowProps, // TODO 因为 lastProps在切换的时候才会更新,所以用nowProps
481
+ });
482
+ activeSyncs.push(activeTrackNode);
483
+ }
484
+ // activeTrackNode?.step(0); // TODO
485
+
486
+ this.activeSyncs = activeSyncs;
487
+ }
488
+
489
+ stepSyncs(delta_time: number): number {
490
+ let lefted_time = delta_time;
491
+ for (let i = 0; i < this.activeSyncs.length; ++i) {
492
+ lefted_time = Math.min(this.activeSyncs[i].step(delta_time), lefted_time);
493
+ }
494
+ return lefted_time;
495
+ }
496
+
497
+ checkSyncsFinished(): boolean {
498
+ for (let i = 0; i < this.activeSyncs.length; ++i) {
499
+ if (this.activeSyncs[i].status !== ActiveTrackNode.Status.Pause)
500
+ return false;
501
+ }
502
+ return true;
503
+ }
504
+
505
+ getSyncsProps() {
506
+ let res: Partial<P> = {};
507
+ for (let i = 0; i < this.activeSyncs.length; ++i) {
508
+ Object.assign(res, this.activeSyncs[i].calcProps());
509
+ }
510
+ return res;
511
+ }
512
+ }
513
+
514
+ export namespace ActiveTrackNode {
515
+ export enum Status {
516
+ Playing,
517
+ WaitingSyncs,
518
+ Pause,
519
+ }
520
+ export interface Serialized {
521
+ accessKeys: string[];
522
+ currentIndex: number | null;
523
+ repeated: number;
524
+ status: ActiveTrackNode.Status;
525
+ now_time: number;
526
+ lastProps: Partial<unknown>;
527
+ nowProps: Partial<unknown>;
528
+ activeSyncs: ActiveTrackNode.Serialized[];
529
+ }
530
+ }
531
+
532
+ // Map a number from [0, 1] (progress time percentage) to [0, 1] (animation parameter value percentage).
533
+ export type Wrapper = (x: number) => number;
534
+
535
+ const buildInWrappers = {
536
+ none: (x: number) => (x < 1 ? 0 : 1),
537
+ linear: (x: number) => x,
538
+ easeout: (x: number) => Math.pow(x, 3),
539
+ easein: (x: number) => 1 - Math.pow(1 - x, 3),
540
+ easeinout: (x: number) =>
541
+ x < 0.5 ? 0.5 * Math.pow(x, 3) : 1 - 0.5 * Math.pow(1 - x, 3),
542
+ };
@@ -0,0 +1,53 @@
1
+ import { HZEngineCore, Script } from "../../index.js";
2
+
3
+ export function registerHzscriptCommands(core: HZEngineCore) {
4
+ core.script.use((ctx, next) => {
5
+ if (ctx.rawtext.trim().split(" ")[0] !== "transition") return next();
6
+ if (ctx.rawtext.includes(`"`))
7
+ throw `Transition Command: cannot have quotes in transition command`;
8
+ if (ctx.slicedArgs.length !== 4)
9
+ throw `Transition Command: incorrect amount of args`;
10
+ if (ctx.slicedArgs[1].isQuoted || ctx.slicedArgs[1].isSquared)
11
+ throw `Transition Command: invalid transition name type`;
12
+ let transitionName = ctx.slicedArgs[1].str;
13
+ if (
14
+ ctx.slicedArgs[2].isQuoted ||
15
+ ctx.slicedArgs[2].isSquared ||
16
+ ctx.slicedArgs[2].str !== "="
17
+ ) {
18
+ throw `the third arg of transition command should be "="`;
19
+ }
20
+ let tuple_str = Script.Utils.joinSlicedArgs(ctx.slicedArgs.slice(3));
21
+ let tuple = Script.Utils.parseTuple(tuple_str);
22
+ if (tuple.length !== 2) {
23
+ throw `thransition tuple must have 2 args`;
24
+ }
25
+
26
+ let inTransforms: string[] = (tuple[0] as string).startsWith("[")
27
+ ? Script.Utils.parseArray((tuple[0] as string)) as string[]
28
+ : [(tuple[0] as string)];
29
+ let outTransforms: string[] = (tuple[1] as string).startsWith("[")
30
+ ? Script.Utils.parseArray((tuple[1] as string)) as string[]
31
+ : [(tuple[1] as string)];
32
+
33
+ let transitionMap = getTransitionMap(core);
34
+ transitionMap[transitionName] = {
35
+ inTransforms,
36
+ outTransforms,
37
+ };
38
+ });
39
+ }
40
+
41
+ export function getTransitionMap(core: HZEngineCore) {
42
+ return core.storage.getSaveableData(
43
+ core.storage.archiveData,
44
+ true,
45
+ "script",
46
+ "transitionMap"
47
+ ) as unknown as Record<string, TransitionData>;
48
+ }
49
+
50
+ export type TransitionData = {
51
+ inTransforms: string[];
52
+ outTransforms: string[];
53
+ };
@@ -0,0 +1,36 @@
1
+ import { Profile } from "./animation.js";
2
+
3
+ export const ExampleProfile1: Profile = [
4
+ [ // alpha
5
+ {
6
+ frame: {
7
+ alpha: 0,
8
+ }
9
+ },
10
+ {
11
+ time: 0.5,
12
+ wrapper: "easein",
13
+ frame: {
14
+ alpha: 1,
15
+ }
16
+ }
17
+ ],
18
+ [ // x
19
+ {
20
+ frame: {
21
+ xalign: -1,
22
+ xanchor: -1,
23
+ }
24
+ },
25
+ {
26
+ time: 1.0,
27
+ wrapper: "easein",
28
+ frame: {
29
+ xalign: 1,
30
+ xanchor: 1,
31
+ }
32
+ }
33
+
34
+ ]
35
+ ]
36
+