@framefields/node-compositor 0.0.0-stage → 2.0.3

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 (40) hide show
  1. package/.turbo/turbo-build.log +22 -0
  2. package/.turbo/turbo-test.log +21 -0
  3. package/CHANGELOG.md +34 -0
  4. package/LICENCE +202 -0
  5. package/SKILL.md +370 -0
  6. package/dist/index-B0ir9Z7o.d.mts +139 -0
  7. package/dist/index-B0ir9Z7o.d.mts.map +1 -0
  8. package/dist/index.d.mts +230 -0
  9. package/dist/index.d.mts.map +1 -0
  10. package/dist/index.mjs +674 -0
  11. package/dist/index.mjs.map +1 -0
  12. package/dist/renderer.d.mts +2 -0
  13. package/dist/renderer.mjs +3 -0
  14. package/dist/renderers-DoYYCzgA.mjs +3326 -0
  15. package/dist/renderers-DoYYCzgA.mjs.map +1 -0
  16. package/package.json +51 -3
  17. package/src/index.ts +2 -0
  18. package/src/renderers/audio-processor.ts +123 -0
  19. package/src/renderers/container-bg.test.ts +22 -0
  20. package/src/renderers/container-bg.ts +15 -0
  21. package/src/renderers/index.ts +9 -0
  22. package/src/renderers/transform.test.ts +120 -0
  23. package/src/renderers/transform.ts +101 -0
  24. package/src/renderers/transform3d.test.ts +290 -0
  25. package/src/renderers/transform3d.ts +428 -0
  26. package/src/renderers/webgpu-renderer.ts +4038 -0
  27. package/src/shared/audio-reactive.test.ts +224 -0
  28. package/src/shared/bezier-solver.test.ts +92 -0
  29. package/src/shared/bezier-solver.ts +257 -0
  30. package/src/shared/compiler.test.ts +1309 -0
  31. package/src/shared/compiler.ts +996 -0
  32. package/src/shared/config.ts +44 -0
  33. package/src/shared/index.ts +3 -0
  34. package/src/shared/kinetic-typography.test.ts +138 -0
  35. package/src/shared/presets.test.ts +217 -0
  36. package/src/shared/presets.ts +644 -0
  37. package/src/shared/processor.ts +105 -0
  38. package/tsconfig.json +13 -0
  39. package/tsdown.config.ts +13 -0
  40. package/README.md +0 -3
package/dist/index.mjs ADDED
@@ -0,0 +1,674 @@
1
+ import { a as compileLayerTimeline, c as mappedEase, i as solveHomography, l as setCachedTimeline, n as Transform3DMath, o as compileTimeline, r as has3DTransform, s as getCachedTimeline } from "./renderers-DoYYCzgA.mjs";
2
+ import { CompositorProgramSchema } from "@framefields/compositions/program";
3
+ import { MediaMetadataSchema } from "@framefields/core";
4
+ import { ImageResultSchema, VideoResultSchema } from "@framefields/node-sdk";
5
+ import { z } from "zod";
6
+
7
+ //#region src/shared/config.ts
8
+ /**
9
+ * v2 config — THE document (spec: SKILL.md).
10
+ * No `layers`, no `layerUpdates`, no aliases. The node config IS the
11
+ * composition program: strict zod, validated by the E-code pre-parse scan
12
+ * in `@framefields/compositions/program/validate`.
13
+ */
14
+ const CompositorNodeConfigSchema = CompositorProgramSchema;
15
+ /** Data types accepted by the variable composer inputs. */
16
+ const VariableInputDataTypes = [
17
+ "Text",
18
+ "Image",
19
+ "Video",
20
+ "Audio",
21
+ "Caption",
22
+ "SVG",
23
+ "GIF",
24
+ "Lottie",
25
+ "Signal"
26
+ ];
27
+ /** The Compositor op framing (used in the render tree, per processCompositor). */
28
+ const CompositorOperationSchema = CompositorNodeConfigSchema.extend({
29
+ op: z.literal("Compositor"),
30
+ dataType: z.enum(["Video", "Image"]).optional(),
31
+ metadata: MediaMetadataSchema.optional()
32
+ }).strict();
33
+ const CompositorResultSchema = z.union([VideoResultSchema, ImageResultSchema]);
34
+
35
+ //#endregion
36
+ //#region src/shared/presets.ts
37
+ function generateId() {
38
+ return Math.random().toString(36).substring(2, 11);
39
+ }
40
+ function getPresetDetails(presetType) {
41
+ switch (presetType) {
42
+ case "fade-in": return {
43
+ kind: "entrance",
44
+ label: "Fade In"
45
+ };
46
+ case "fade-out": return {
47
+ kind: "exit",
48
+ label: "Fade Out"
49
+ };
50
+ case "typewriter": return {
51
+ kind: "entrance",
52
+ label: "Typewriter"
53
+ };
54
+ case "word-reveal": return {
55
+ kind: "entrance",
56
+ label: "Word Reveal"
57
+ };
58
+ case "line-reveal": return {
59
+ kind: "entrance",
60
+ label: "Line Reveal"
61
+ };
62
+ case "karaoke": return {
63
+ kind: "entrance",
64
+ label: "Karaoke"
65
+ };
66
+ case "slide-in-left": return {
67
+ kind: "entrance",
68
+ label: "Slide In Left"
69
+ };
70
+ case "slide-in-right": return {
71
+ kind: "entrance",
72
+ label: "Slide In Right"
73
+ };
74
+ case "slide-in-top": return {
75
+ kind: "entrance",
76
+ label: "Slide In Top"
77
+ };
78
+ case "slide-in-bottom": return {
79
+ kind: "entrance",
80
+ label: "Slide In Bottom"
81
+ };
82
+ case "slide-out-left": return {
83
+ kind: "exit",
84
+ label: "Slide Out Left"
85
+ };
86
+ case "slide-out-right": return {
87
+ kind: "exit",
88
+ label: "Slide Out Right"
89
+ };
90
+ case "slide-out-top": return {
91
+ kind: "exit",
92
+ label: "Slide Out Top"
93
+ };
94
+ case "slide-out-bottom": return {
95
+ kind: "exit",
96
+ label: "Slide Out Bottom"
97
+ };
98
+ case "zoom-in": return {
99
+ kind: "entrance",
100
+ label: "Zoom In"
101
+ };
102
+ case "zoom-out": return {
103
+ kind: "exit",
104
+ label: "Zoom Out"
105
+ };
106
+ case "bounce-in": return {
107
+ kind: "entrance",
108
+ label: "Bounce In"
109
+ };
110
+ case "rotate-cw": return {
111
+ kind: "emphasis",
112
+ label: "Rotate Clockwise"
113
+ };
114
+ case "rotate-ccw": return {
115
+ kind: "emphasis",
116
+ label: "Rotate Counter-Clockwise"
117
+ };
118
+ case "pulse": return {
119
+ kind: "emphasis",
120
+ label: "Pulse"
121
+ };
122
+ case "shake": return {
123
+ kind: "emphasis",
124
+ label: "Shake"
125
+ };
126
+ case "wobble": return {
127
+ kind: "emphasis",
128
+ label: "Wobble"
129
+ };
130
+ case "bounce": return {
131
+ kind: "emphasis",
132
+ label: "Bounce"
133
+ };
134
+ case "tracking-expand": return {
135
+ kind: "entrance",
136
+ label: "Tracking Expand"
137
+ };
138
+ case "blur-reveal": return {
139
+ kind: "entrance",
140
+ label: "Blur Reveal"
141
+ };
142
+ case "kinetic-wave": return {
143
+ kind: "emphasis",
144
+ label: "Kinetic Wave"
145
+ };
146
+ case "slice-wipe": return {
147
+ kind: "entrance",
148
+ label: "Slice Wipe"
149
+ };
150
+ default: return {
151
+ kind: "emphasis",
152
+ label: presetType
153
+ };
154
+ }
155
+ }
156
+ function chipsForLayer(layer) {
157
+ const groups = {};
158
+ const tracks = layer?.animation?.tracks ?? [];
159
+ for (const track of tracks) for (const kf of track.keyframes) if (kf.presetGroupId) if (!groups[kf.presetGroupId]) groups[kf.presetGroupId] = {
160
+ minFrame: kf.frame,
161
+ maxFrame: kf.frame,
162
+ ease: kf.ease,
163
+ presetType: kf.presetType
164
+ };
165
+ else {
166
+ const g = groups[kf.presetGroupId];
167
+ if (kf.frame < g.minFrame) g.minFrame = kf.frame;
168
+ if (kf.frame > g.maxFrame) {
169
+ g.maxFrame = kf.frame;
170
+ if (kf.ease) g.ease = kf.ease;
171
+ }
172
+ if (kf.presetType && !g.presetType) g.presetType = kf.presetType;
173
+ }
174
+ const chips = [];
175
+ for (const [groupId, data] of Object.entries(groups)) {
176
+ const presetType = data.presetType || (groupId.includes("_") ? groupId.slice(0, groupId.lastIndexOf("_")) : groupId) || "";
177
+ const { kind, label } = getPresetDetails(presetType);
178
+ chips.push({
179
+ groupId,
180
+ presetType,
181
+ kind,
182
+ label,
183
+ durationFrames: data.maxFrame - data.minFrame,
184
+ ease: data.ease
185
+ });
186
+ }
187
+ return chips;
188
+ }
189
+ function materializePreset(layerBase, presetType, options) {
190
+ const groupId = options.presetGroupId ?? `${presetType}_${generateId()}`;
191
+ const width = options.width;
192
+ const height = options.height;
193
+ const layerDuration = layerBase.durationFrames;
194
+ const defaultDuration = options.durationFrames ?? options.fps;
195
+ let prop;
196
+ let keyframes = [];
197
+ let repeat;
198
+ let yoyo;
199
+ switch (presetType) {
200
+ case "fade-in":
201
+ prop = "opacity";
202
+ keyframes = [{
203
+ id: generateId(),
204
+ frame: 0,
205
+ value: 0,
206
+ presetGroupId: groupId
207
+ }, {
208
+ id: generateId(),
209
+ frame: defaultDuration,
210
+ value: layerBase.opacity,
211
+ ease: {
212
+ name: "none",
213
+ dir: "out"
214
+ },
215
+ presetGroupId: groupId
216
+ }];
217
+ break;
218
+ case "fade-out":
219
+ prop = "opacity";
220
+ keyframes = [{
221
+ id: generateId(),
222
+ frame: Math.max(0, layerDuration - defaultDuration),
223
+ value: layerBase.opacity,
224
+ presetGroupId: groupId
225
+ }, {
226
+ id: generateId(),
227
+ frame: layerDuration,
228
+ value: 0,
229
+ ease: {
230
+ name: "none",
231
+ dir: "out"
232
+ },
233
+ presetGroupId: groupId
234
+ }];
235
+ break;
236
+ case "slide-in-left":
237
+ prop = "x";
238
+ keyframes = [{
239
+ id: generateId(),
240
+ frame: 0,
241
+ value: layerBase.x - width,
242
+ presetGroupId: groupId
243
+ }, {
244
+ id: generateId(),
245
+ frame: defaultDuration,
246
+ value: layerBase.x,
247
+ ease: {
248
+ name: "none",
249
+ dir: "out"
250
+ },
251
+ presetGroupId: groupId
252
+ }];
253
+ break;
254
+ case "slide-in-right":
255
+ prop = "x";
256
+ keyframes = [{
257
+ id: generateId(),
258
+ frame: 0,
259
+ value: layerBase.x + width,
260
+ presetGroupId: groupId
261
+ }, {
262
+ id: generateId(),
263
+ frame: defaultDuration,
264
+ value: layerBase.x,
265
+ ease: {
266
+ name: "none",
267
+ dir: "out"
268
+ },
269
+ presetGroupId: groupId
270
+ }];
271
+ break;
272
+ case "slide-in-top":
273
+ prop = "y";
274
+ keyframes = [{
275
+ id: generateId(),
276
+ frame: 0,
277
+ value: layerBase.y - height,
278
+ presetGroupId: groupId
279
+ }, {
280
+ id: generateId(),
281
+ frame: defaultDuration,
282
+ value: layerBase.y,
283
+ ease: {
284
+ name: "none",
285
+ dir: "out"
286
+ },
287
+ presetGroupId: groupId
288
+ }];
289
+ break;
290
+ case "slide-in-bottom":
291
+ prop = "y";
292
+ keyframes = [{
293
+ id: generateId(),
294
+ frame: 0,
295
+ value: layerBase.y + height,
296
+ presetGroupId: groupId
297
+ }, {
298
+ id: generateId(),
299
+ frame: defaultDuration,
300
+ value: layerBase.y,
301
+ ease: {
302
+ name: "none",
303
+ dir: "out"
304
+ },
305
+ presetGroupId: groupId
306
+ }];
307
+ break;
308
+ case "slide-out-left":
309
+ prop = "x";
310
+ keyframes = [{
311
+ id: generateId(),
312
+ frame: Math.max(0, layerDuration - defaultDuration),
313
+ value: layerBase.x,
314
+ presetGroupId: groupId
315
+ }, {
316
+ id: generateId(),
317
+ frame: layerDuration,
318
+ value: layerBase.x - width,
319
+ ease: {
320
+ name: "none",
321
+ dir: "out"
322
+ },
323
+ presetGroupId: groupId
324
+ }];
325
+ break;
326
+ case "slide-out-right":
327
+ prop = "x";
328
+ keyframes = [{
329
+ id: generateId(),
330
+ frame: Math.max(0, layerDuration - defaultDuration),
331
+ value: layerBase.x,
332
+ presetGroupId: groupId
333
+ }, {
334
+ id: generateId(),
335
+ frame: layerDuration,
336
+ value: layerBase.x + width,
337
+ ease: {
338
+ name: "none",
339
+ dir: "out"
340
+ },
341
+ presetGroupId: groupId
342
+ }];
343
+ break;
344
+ case "slide-out-top":
345
+ prop = "y";
346
+ keyframes = [{
347
+ id: generateId(),
348
+ frame: Math.max(0, layerDuration - defaultDuration),
349
+ value: layerBase.y,
350
+ presetGroupId: groupId
351
+ }, {
352
+ id: generateId(),
353
+ frame: layerDuration,
354
+ value: layerBase.y - height,
355
+ ease: {
356
+ name: "none",
357
+ dir: "out"
358
+ },
359
+ presetGroupId: groupId
360
+ }];
361
+ break;
362
+ case "slide-out-bottom":
363
+ prop = "y";
364
+ keyframes = [{
365
+ id: generateId(),
366
+ frame: Math.max(0, layerDuration - defaultDuration),
367
+ value: layerBase.y,
368
+ presetGroupId: groupId
369
+ }, {
370
+ id: generateId(),
371
+ frame: layerDuration,
372
+ value: layerBase.y + height,
373
+ ease: {
374
+ name: "none",
375
+ dir: "out"
376
+ },
377
+ presetGroupId: groupId
378
+ }];
379
+ break;
380
+ case "zoom-in":
381
+ prop = "scale";
382
+ keyframes = [{
383
+ id: generateId(),
384
+ frame: 0,
385
+ value: 0,
386
+ presetGroupId: groupId
387
+ }, {
388
+ id: generateId(),
389
+ frame: defaultDuration,
390
+ value: layerBase.scale,
391
+ ease: {
392
+ name: "none",
393
+ dir: "out"
394
+ },
395
+ presetGroupId: groupId
396
+ }];
397
+ break;
398
+ case "zoom-out":
399
+ prop = "scale";
400
+ keyframes = [{
401
+ id: generateId(),
402
+ frame: Math.max(0, layerDuration - defaultDuration),
403
+ value: layerBase.scale,
404
+ presetGroupId: groupId
405
+ }, {
406
+ id: generateId(),
407
+ frame: layerDuration,
408
+ value: 0,
409
+ ease: {
410
+ name: "none",
411
+ dir: "out"
412
+ },
413
+ presetGroupId: groupId
414
+ }];
415
+ break;
416
+ case "bounce-in":
417
+ prop = "scale";
418
+ keyframes = [{
419
+ id: generateId(),
420
+ frame: 0,
421
+ value: 0,
422
+ presetGroupId: groupId
423
+ }, {
424
+ id: generateId(),
425
+ frame: defaultDuration,
426
+ value: layerBase.scale,
427
+ ease: {
428
+ name: "back",
429
+ dir: "out",
430
+ params: [1.7]
431
+ },
432
+ presetGroupId: groupId
433
+ }];
434
+ break;
435
+ case "rotate-cw":
436
+ prop = "rotation";
437
+ keyframes = [{
438
+ id: generateId(),
439
+ frame: 0,
440
+ value: layerBase.rotation,
441
+ presetGroupId: groupId
442
+ }, {
443
+ id: generateId(),
444
+ frame: defaultDuration,
445
+ value: layerBase.rotation + 360,
446
+ ease: {
447
+ name: "none",
448
+ dir: "out"
449
+ },
450
+ presetGroupId: groupId
451
+ }];
452
+ repeat = 1;
453
+ break;
454
+ case "rotate-ccw":
455
+ prop = "rotation";
456
+ keyframes = [{
457
+ id: generateId(),
458
+ frame: 0,
459
+ value: layerBase.rotation,
460
+ presetGroupId: groupId
461
+ }, {
462
+ id: generateId(),
463
+ frame: defaultDuration,
464
+ value: layerBase.rotation - 360,
465
+ ease: {
466
+ name: "none",
467
+ dir: "out"
468
+ },
469
+ presetGroupId: groupId
470
+ }];
471
+ repeat = 1;
472
+ break;
473
+ case "pulse": {
474
+ prop = "scale";
475
+ const halfDur = Math.max(1, Math.round(defaultDuration / 2));
476
+ keyframes = [{
477
+ id: generateId(),
478
+ frame: 0,
479
+ value: layerBase.scale,
480
+ presetGroupId: groupId
481
+ }, {
482
+ id: generateId(),
483
+ frame: halfDur,
484
+ value: layerBase.scale * 1.1,
485
+ ease: {
486
+ name: "none",
487
+ dir: "out"
488
+ },
489
+ presetGroupId: groupId
490
+ }];
491
+ repeat = -1;
492
+ yoyo = true;
493
+ break;
494
+ }
495
+ case "shake": {
496
+ prop = "x";
497
+ const segmentDur = Math.max(1, Math.round(defaultDuration / 10));
498
+ keyframes = [{
499
+ id: generateId(),
500
+ frame: 0,
501
+ value: layerBase.x,
502
+ presetGroupId: groupId
503
+ }, {
504
+ id: generateId(),
505
+ frame: segmentDur,
506
+ value: layerBase.x + 20,
507
+ ease: {
508
+ name: "sine",
509
+ dir: "inOut"
510
+ },
511
+ presetGroupId: groupId
512
+ }];
513
+ repeat = 9;
514
+ yoyo = true;
515
+ break;
516
+ }
517
+ case "wobble": {
518
+ prop = "rotation";
519
+ const segmentDur = Math.max(1, Math.round(defaultDuration / 6));
520
+ keyframes = [{
521
+ id: generateId(),
522
+ frame: 0,
523
+ value: layerBase.rotation,
524
+ presetGroupId: groupId
525
+ }, {
526
+ id: generateId(),
527
+ frame: segmentDur,
528
+ value: layerBase.rotation + 15,
529
+ ease: {
530
+ name: "sine",
531
+ dir: "inOut"
532
+ },
533
+ presetGroupId: groupId
534
+ }];
535
+ repeat = 9;
536
+ yoyo = true;
537
+ break;
538
+ }
539
+ case "bounce":
540
+ prop = "y";
541
+ keyframes = [{
542
+ id: generateId(),
543
+ frame: 0,
544
+ value: layerBase.y - 100,
545
+ presetGroupId: groupId
546
+ }, {
547
+ id: generateId(),
548
+ frame: defaultDuration,
549
+ value: layerBase.y,
550
+ ease: {
551
+ name: "bounce",
552
+ dir: "out"
553
+ },
554
+ presetGroupId: groupId
555
+ }];
556
+ break;
557
+ case "typewriter":
558
+ case "word-reveal":
559
+ case "line-reveal":
560
+ case "karaoke":
561
+ prop = "text";
562
+ keyframes = [{
563
+ id: generateId(),
564
+ frame: 0,
565
+ value: 0,
566
+ presetGroupId: groupId,
567
+ presetType
568
+ }, {
569
+ id: generateId(),
570
+ frame: defaultDuration,
571
+ value: 1,
572
+ ease: {
573
+ name: "none",
574
+ dir: "out"
575
+ },
576
+ presetGroupId: groupId,
577
+ presetType
578
+ }];
579
+ break;
580
+ case "tracking-expand":
581
+ prop = "letterSpacing";
582
+ keyframes = [{
583
+ id: generateId(),
584
+ frame: 0,
585
+ value: 0,
586
+ presetGroupId: groupId
587
+ }, {
588
+ id: generateId(),
589
+ frame: defaultDuration,
590
+ value: 24,
591
+ ease: {
592
+ name: "sine",
593
+ dir: "out"
594
+ },
595
+ presetGroupId: groupId
596
+ }];
597
+ break;
598
+ case "blur-reveal":
599
+ prop = "opacity";
600
+ keyframes = [{
601
+ id: generateId(),
602
+ frame: 0,
603
+ value: 0,
604
+ presetGroupId: groupId
605
+ }, {
606
+ id: generateId(),
607
+ frame: defaultDuration,
608
+ value: layerBase.opacity,
609
+ ease: {
610
+ name: "power1",
611
+ dir: "out"
612
+ },
613
+ presetGroupId: groupId
614
+ }];
615
+ break;
616
+ case "kinetic-wave": {
617
+ prop = "y";
618
+ const halfDur = Math.max(1, Math.round(defaultDuration / 2));
619
+ keyframes = [{
620
+ id: generateId(),
621
+ frame: 0,
622
+ value: layerBase.y,
623
+ presetGroupId: groupId
624
+ }, {
625
+ id: generateId(),
626
+ frame: halfDur,
627
+ value: layerBase.y - 24,
628
+ ease: {
629
+ name: "sine",
630
+ dir: "inOut"
631
+ },
632
+ presetGroupId: groupId
633
+ }];
634
+ repeat = 3;
635
+ yoyo = true;
636
+ break;
637
+ }
638
+ case "slice-wipe": {
639
+ prop = "x";
640
+ const offset = layerBase.width ?? 300;
641
+ keyframes = [{
642
+ id: generateId(),
643
+ frame: 0,
644
+ value: layerBase.x - offset,
645
+ presetGroupId: groupId
646
+ }, {
647
+ id: generateId(),
648
+ frame: defaultDuration,
649
+ value: layerBase.x,
650
+ ease: {
651
+ name: "expo",
652
+ dir: "out"
653
+ },
654
+ presetGroupId: groupId
655
+ }];
656
+ break;
657
+ }
658
+ default: throw new Error(`Unsupported preset type: ${presetType}`);
659
+ }
660
+ return [{
661
+ id: generateId(),
662
+ prop,
663
+ keyframes: keyframes.map((kf) => ({
664
+ ...kf,
665
+ presetType
666
+ })),
667
+ ...repeat !== void 0 && { repeat },
668
+ ...yoyo !== void 0 && { yoyo }
669
+ }];
670
+ }
671
+
672
+ //#endregion
673
+ export { CompositorNodeConfigSchema, CompositorOperationSchema, CompositorResultSchema, Transform3DMath, VariableInputDataTypes, chipsForLayer, compileLayerTimeline, compileTimeline, getCachedTimeline, getPresetDetails, has3DTransform, mappedEase, materializePreset, setCachedTimeline, solveHomography };
674
+ //# sourceMappingURL=index.mjs.map