@a-company/atelier 0.17.3 → 0.18.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/{chunk-LL2EJ6YE.js → chunk-H4A6HRMY.js} +501 -16
- package/dist/chunk-H4A6HRMY.js.map +1 -0
- package/dist/cli.cjs +500 -15
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +500 -15
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/mcp.cjs +336 -8
- package/dist/mcp.cjs.map +1 -1
- package/dist/mcp.js +336 -8
- package/dist/mcp.js.map +1 -1
- package/package.json +14 -13
- package/dist/chunk-LL2EJ6YE.js.map +0 -1
|
@@ -153,6 +153,30 @@ var ShadowSchema = z6.object({
|
|
|
153
153
|
offsetX: z6.number().optional(),
|
|
154
154
|
offsetY: z6.number().optional()
|
|
155
155
|
});
|
|
156
|
+
var BlendModeSchema = z7.enum([
|
|
157
|
+
"normal",
|
|
158
|
+
"multiply",
|
|
159
|
+
"screen",
|
|
160
|
+
"overlay",
|
|
161
|
+
"darken",
|
|
162
|
+
"lighten",
|
|
163
|
+
"color-dodge",
|
|
164
|
+
"color-burn",
|
|
165
|
+
"hard-light",
|
|
166
|
+
"soft-light",
|
|
167
|
+
"difference",
|
|
168
|
+
"exclusion",
|
|
169
|
+
"hue",
|
|
170
|
+
"saturation",
|
|
171
|
+
"color",
|
|
172
|
+
"luminosity"
|
|
173
|
+
]);
|
|
174
|
+
var MotionPathSchema = z7.object({
|
|
175
|
+
points: z7.array(PathPointSchema).min(2, "Motion path must have at least 2 points"),
|
|
176
|
+
closed: z7.boolean().optional(),
|
|
177
|
+
autoRotate: z7.boolean().optional(),
|
|
178
|
+
autoRotateOffset: z7.number().optional()
|
|
179
|
+
});
|
|
156
180
|
var ShapeVisualSchema = z7.object({
|
|
157
181
|
type: z7.literal("shape"),
|
|
158
182
|
shape: ShapeSchema,
|
|
@@ -196,7 +220,10 @@ var LayerSchema = z7.object({
|
|
|
196
220
|
rotation: z7.number().optional(),
|
|
197
221
|
scale: z7.object({ x: z7.number(), y: z7.number() }).optional(),
|
|
198
222
|
visible: z7.boolean().optional(),
|
|
199
|
-
shadow: ShadowSchema.optional()
|
|
223
|
+
shadow: ShadowSchema.optional(),
|
|
224
|
+
blendMode: BlendModeSchema.optional(),
|
|
225
|
+
motionPath: MotionPathSchema.optional(),
|
|
226
|
+
clipPath: ShapeSchema.optional()
|
|
200
227
|
});
|
|
201
228
|
var AnimatablePropertySchema = z8.enum([
|
|
202
229
|
"frame.x",
|
|
@@ -220,7 +247,12 @@ var AnimatablePropertySchema = z8.enum([
|
|
|
220
247
|
"shadow.color",
|
|
221
248
|
"shadow.blur",
|
|
222
249
|
"shadow.offsetX",
|
|
223
|
-
"shadow.offsetY"
|
|
250
|
+
"shadow.offsetY",
|
|
251
|
+
"motionPath.progress",
|
|
252
|
+
"visual.fill.angle",
|
|
253
|
+
"visual.fill.center.x",
|
|
254
|
+
"visual.fill.center.y",
|
|
255
|
+
"visual.fill.radius"
|
|
224
256
|
]);
|
|
225
257
|
var FrameRangeSchema = z8.tuple([
|
|
226
258
|
z8.number().int().min(0, "Frame start must be >= 0"),
|
|
@@ -240,11 +272,19 @@ var DeltaSchema = z8.object({
|
|
|
240
272
|
description: z8.string().optional(),
|
|
241
273
|
tags: z8.array(z8.string()).optional()
|
|
242
274
|
});
|
|
275
|
+
var AudioSchema = z9.object({
|
|
276
|
+
src: z9.string().min(1, "Audio src is required"),
|
|
277
|
+
offset: z9.number().min(0, "Audio offset must be non-negative").optional(),
|
|
278
|
+
volume: z9.number().min(0).max(1, "Audio volume must be 0\u20131").optional(),
|
|
279
|
+
loop: z9.boolean().optional(),
|
|
280
|
+
startFrame: z9.number().int().min(0, "Audio startFrame must be a non-negative integer").optional()
|
|
281
|
+
});
|
|
243
282
|
var StateSchema = z9.object({
|
|
244
283
|
description: z9.string().optional(),
|
|
245
284
|
tags: z9.array(z9.string()).optional(),
|
|
246
285
|
duration: z9.number().int().positive("State duration must be a positive integer (frames)"),
|
|
247
|
-
deltas: z9.array(DeltaSchema)
|
|
286
|
+
deltas: z9.array(DeltaSchema),
|
|
287
|
+
audio: AudioSchema.optional()
|
|
248
288
|
});
|
|
249
289
|
var PresetDeltaSchema = z10.object({
|
|
250
290
|
property: AnimatablePropertySchema,
|
|
@@ -264,7 +304,7 @@ var VariableSchema = z11.object({
|
|
|
264
304
|
default: z11.unknown().optional(),
|
|
265
305
|
description: z11.string().optional()
|
|
266
306
|
});
|
|
267
|
-
var AssetTypeSchema = z12.enum(["image", "svg", "font", "animation"]);
|
|
307
|
+
var AssetTypeSchema = z12.enum(["image", "svg", "font", "animation", "audio"]);
|
|
268
308
|
var AssetSchema = z12.object({
|
|
269
309
|
type: AssetTypeSchema,
|
|
270
310
|
src: z12.string().min(1, "Asset src is required"),
|
|
@@ -426,6 +466,75 @@ function lerpRgba(a, b, t) {
|
|
|
426
466
|
a: lerp(a.a, b.a, t)
|
|
427
467
|
};
|
|
428
468
|
}
|
|
469
|
+
function bezierSegmentLength(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, steps = 32) {
|
|
470
|
+
let length = 0;
|
|
471
|
+
let prevX = p0x;
|
|
472
|
+
let prevY = p0y;
|
|
473
|
+
for (let i = 1; i <= steps; i++) {
|
|
474
|
+
const t = i / steps;
|
|
475
|
+
const mt = 1 - t;
|
|
476
|
+
const x = mt * mt * mt * p0x + 3 * mt * mt * t * c0x + 3 * mt * t * t * c1x + t * t * t * p1x;
|
|
477
|
+
const y = mt * mt * mt * p0y + 3 * mt * mt * t * c0y + 3 * mt * t * t * c1y + t * t * t * p1y;
|
|
478
|
+
const dx = x - prevX;
|
|
479
|
+
const dy = y - prevY;
|
|
480
|
+
length += Math.sqrt(dx * dx + dy * dy);
|
|
481
|
+
prevX = x;
|
|
482
|
+
prevY = y;
|
|
483
|
+
}
|
|
484
|
+
return length;
|
|
485
|
+
}
|
|
486
|
+
function evalBezier(p0x, p0y, c0x, c0y, c1x, c1y, p1x, p1y, t) {
|
|
487
|
+
const mt = 1 - t;
|
|
488
|
+
const x = mt * mt * mt * p0x + 3 * mt * mt * t * c0x + 3 * mt * t * t * c1x + t * t * t * p1x;
|
|
489
|
+
const y = mt * mt * mt * p0y + 3 * mt * mt * t * c0y + 3 * mt * t * t * c1y + t * t * t * p1y;
|
|
490
|
+
const tx = 3 * mt * mt * (c0x - p0x) + 6 * mt * t * (c1x - c0x) + 3 * t * t * (p1x - c1x);
|
|
491
|
+
const ty = 3 * mt * mt * (c0y - p0y) + 6 * mt * t * (c1y - c0y) + 3 * t * t * (p1y - c1y);
|
|
492
|
+
const angle = Math.atan2(ty, tx) * (180 / Math.PI);
|
|
493
|
+
return { x, y, angle };
|
|
494
|
+
}
|
|
495
|
+
function buildSegmentLengths(points, closed) {
|
|
496
|
+
const segCount = closed ? points.length : points.length - 1;
|
|
497
|
+
const lengths = [];
|
|
498
|
+
for (let i = 0; i < segCount; i++) {
|
|
499
|
+
const p0 = points[i];
|
|
500
|
+
const p1 = points[(i + 1) % points.length];
|
|
501
|
+
const c0x = p0.x + (p0.out?.x ?? 0);
|
|
502
|
+
const c0y = p0.y + (p0.out?.y ?? 0);
|
|
503
|
+
const c1x = p1.x + (p1.in?.x ?? 0);
|
|
504
|
+
const c1y = p1.y + (p1.in?.y ?? 0);
|
|
505
|
+
lengths.push(bezierSegmentLength(p0.x, p0.y, c0x, c0y, c1x, c1y, p1.x, p1.y));
|
|
506
|
+
}
|
|
507
|
+
return lengths;
|
|
508
|
+
}
|
|
509
|
+
function evaluatePathAtProgress(points, progress, closed = false) {
|
|
510
|
+
if (points.length < 2) {
|
|
511
|
+
return { x: points[0]?.x ?? 0, y: points[0]?.y ?? 0, angle: 0 };
|
|
512
|
+
}
|
|
513
|
+
const t = Math.max(0, Math.min(1, progress));
|
|
514
|
+
const segLengths = buildSegmentLengths(points, closed);
|
|
515
|
+
const totalLength = segLengths.reduce((a, b) => a + b, 0);
|
|
516
|
+
if (totalLength === 0) {
|
|
517
|
+
return { x: points[0].x, y: points[0].y, angle: 0 };
|
|
518
|
+
}
|
|
519
|
+
const targetLength = t * totalLength;
|
|
520
|
+
let accumulated = 0;
|
|
521
|
+
for (let i = 0; i < segLengths.length; i++) {
|
|
522
|
+
const segLen = segLengths[i];
|
|
523
|
+
if (accumulated + segLen >= targetLength || i === segLengths.length - 1) {
|
|
524
|
+
const segProgress = segLen === 0 ? 0 : (targetLength - accumulated) / segLen;
|
|
525
|
+
const p0 = points[i];
|
|
526
|
+
const p1 = points[(i + 1) % points.length];
|
|
527
|
+
const c0x = p0.x + (p0.out?.x ?? 0);
|
|
528
|
+
const c0y = p0.y + (p0.out?.y ?? 0);
|
|
529
|
+
const c1x = p1.x + (p1.in?.x ?? 0);
|
|
530
|
+
const c1y = p1.y + (p1.in?.y ?? 0);
|
|
531
|
+
return evalBezier(p0.x, p0.y, c0x, c0y, c1x, c1y, p1.x, p1.y, segProgress);
|
|
532
|
+
}
|
|
533
|
+
accumulated += segLen;
|
|
534
|
+
}
|
|
535
|
+
const last = points[points.length - 1];
|
|
536
|
+
return { x: last.x, y: last.y, angle: 0 };
|
|
537
|
+
}
|
|
429
538
|
|
|
430
539
|
// ../core/dist/index.js
|
|
431
540
|
function resolveEasing(easing) {
|
|
@@ -460,6 +569,261 @@ function resolveEasing(easing) {
|
|
|
460
569
|
return linear;
|
|
461
570
|
}
|
|
462
571
|
}
|
|
572
|
+
function tokenize(expr) {
|
|
573
|
+
const tokens = [];
|
|
574
|
+
let i = 0;
|
|
575
|
+
while (i < expr.length) {
|
|
576
|
+
const ch = expr[i];
|
|
577
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r") {
|
|
578
|
+
i++;
|
|
579
|
+
continue;
|
|
580
|
+
}
|
|
581
|
+
if (ch >= "0" && ch <= "9" || ch === ".") {
|
|
582
|
+
let num = "";
|
|
583
|
+
while (i < expr.length && (expr[i] >= "0" && expr[i] <= "9" || expr[i] === ".")) {
|
|
584
|
+
num += expr[i++];
|
|
585
|
+
}
|
|
586
|
+
tokens.push({ type: "number", value: num });
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
if (ch >= "a" && ch <= "z" || ch >= "A" && ch <= "Z" || ch === "_") {
|
|
590
|
+
let id = "";
|
|
591
|
+
while (i < expr.length && (expr[i] >= "a" && expr[i] <= "z" || expr[i] >= "A" && expr[i] <= "Z" || expr[i] >= "0" && expr[i] <= "9" || expr[i] === "_")) {
|
|
592
|
+
id += expr[i++];
|
|
593
|
+
}
|
|
594
|
+
tokens.push({ type: "ident", value: id });
|
|
595
|
+
continue;
|
|
596
|
+
}
|
|
597
|
+
if (ch === "<" || ch === ">" || ch === "!" || ch === "=") {
|
|
598
|
+
if (i + 1 < expr.length && expr[i + 1] === "=") {
|
|
599
|
+
tokens.push({ type: "compare", value: ch + "=" });
|
|
600
|
+
i += 2;
|
|
601
|
+
continue;
|
|
602
|
+
}
|
|
603
|
+
if (ch === "<" || ch === ">") {
|
|
604
|
+
tokens.push({ type: "compare", value: ch });
|
|
605
|
+
i++;
|
|
606
|
+
continue;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
if (ch === "*" && i + 1 < expr.length && expr[i + 1] === "*") {
|
|
610
|
+
tokens.push({ type: "op", value: "**" });
|
|
611
|
+
i += 2;
|
|
612
|
+
continue;
|
|
613
|
+
}
|
|
614
|
+
if (ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%") {
|
|
615
|
+
tokens.push({ type: "op", value: ch });
|
|
616
|
+
i++;
|
|
617
|
+
continue;
|
|
618
|
+
}
|
|
619
|
+
if (ch === "(") {
|
|
620
|
+
tokens.push({ type: "lparen", value: "(" });
|
|
621
|
+
i++;
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
if (ch === ")") {
|
|
625
|
+
tokens.push({ type: "rparen", value: ")" });
|
|
626
|
+
i++;
|
|
627
|
+
continue;
|
|
628
|
+
}
|
|
629
|
+
if (ch === ",") {
|
|
630
|
+
tokens.push({ type: "comma", value: "," });
|
|
631
|
+
i++;
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
if (ch === "?") {
|
|
635
|
+
tokens.push({ type: "question", value: "?" });
|
|
636
|
+
i++;
|
|
637
|
+
continue;
|
|
638
|
+
}
|
|
639
|
+
if (ch === ":") {
|
|
640
|
+
tokens.push({ type: "colon", value: ":" });
|
|
641
|
+
i++;
|
|
642
|
+
continue;
|
|
643
|
+
}
|
|
644
|
+
throw new Error(`Expression: unexpected character '${ch}' at position ${i}`);
|
|
645
|
+
}
|
|
646
|
+
tokens.push({ type: "eof", value: "" });
|
|
647
|
+
return tokens;
|
|
648
|
+
}
|
|
649
|
+
var CONSTANTS = {
|
|
650
|
+
pi: Math.PI,
|
|
651
|
+
PI: Math.PI,
|
|
652
|
+
tau: Math.PI * 2,
|
|
653
|
+
TAU: Math.PI * 2,
|
|
654
|
+
e: Math.E,
|
|
655
|
+
E: Math.E
|
|
656
|
+
};
|
|
657
|
+
var FUNCTIONS = {
|
|
658
|
+
sin: Math.sin,
|
|
659
|
+
cos: Math.cos,
|
|
660
|
+
tan: Math.tan,
|
|
661
|
+
abs: Math.abs,
|
|
662
|
+
floor: Math.floor,
|
|
663
|
+
ceil: Math.ceil,
|
|
664
|
+
round: Math.round,
|
|
665
|
+
sqrt: Math.sqrt,
|
|
666
|
+
sign: Math.sign,
|
|
667
|
+
log: Math.log,
|
|
668
|
+
min: (...args) => Math.min(...args),
|
|
669
|
+
max: (...args) => Math.max(...args),
|
|
670
|
+
pow: (a, b) => Math.pow(a, b),
|
|
671
|
+
clamp: (v, lo, hi) => Math.min(Math.max(v, lo), hi)
|
|
672
|
+
};
|
|
673
|
+
var Parser = class {
|
|
674
|
+
tokens;
|
|
675
|
+
pos = 0;
|
|
676
|
+
ctx;
|
|
677
|
+
constructor(tokens, ctx) {
|
|
678
|
+
this.tokens = tokens;
|
|
679
|
+
this.ctx = ctx;
|
|
680
|
+
}
|
|
681
|
+
peek() {
|
|
682
|
+
return this.tokens[this.pos];
|
|
683
|
+
}
|
|
684
|
+
consume(expectedType) {
|
|
685
|
+
const tok = this.tokens[this.pos++];
|
|
686
|
+
if (expectedType && tok.type !== expectedType) {
|
|
687
|
+
throw new Error(`Expression: expected ${expectedType} but got ${tok.type} '${tok.value}'`);
|
|
688
|
+
}
|
|
689
|
+
return tok;
|
|
690
|
+
}
|
|
691
|
+
/** Entry: ternary (lowest precedence) */
|
|
692
|
+
parse() {
|
|
693
|
+
const result = this.parseTernary();
|
|
694
|
+
if (this.peek().type !== "eof") {
|
|
695
|
+
throw new Error(`Expression: unexpected token '${this.peek().value}'`);
|
|
696
|
+
}
|
|
697
|
+
return result;
|
|
698
|
+
}
|
|
699
|
+
/** ternary: comparison ? expr : expr */
|
|
700
|
+
parseTernary() {
|
|
701
|
+
const condition = this.parseComparison();
|
|
702
|
+
if (this.peek().type === "question") {
|
|
703
|
+
this.consume();
|
|
704
|
+
const trueVal = this.parseTernary();
|
|
705
|
+
this.consume("colon");
|
|
706
|
+
const falseVal = this.parseTernary();
|
|
707
|
+
return condition ? trueVal : falseVal;
|
|
708
|
+
}
|
|
709
|
+
return condition;
|
|
710
|
+
}
|
|
711
|
+
/** comparison: additive (< | > | <= | >= | == | !=) additive */
|
|
712
|
+
parseComparison() {
|
|
713
|
+
let left = this.parseAdditive();
|
|
714
|
+
while (this.peek().type === "compare") {
|
|
715
|
+
const op = this.consume().value;
|
|
716
|
+
const right = this.parseAdditive();
|
|
717
|
+
switch (op) {
|
|
718
|
+
case "<":
|
|
719
|
+
left = left < right ? 1 : 0;
|
|
720
|
+
break;
|
|
721
|
+
case ">":
|
|
722
|
+
left = left > right ? 1 : 0;
|
|
723
|
+
break;
|
|
724
|
+
case "<=":
|
|
725
|
+
left = left <= right ? 1 : 0;
|
|
726
|
+
break;
|
|
727
|
+
case ">=":
|
|
728
|
+
left = left >= right ? 1 : 0;
|
|
729
|
+
break;
|
|
730
|
+
case "==":
|
|
731
|
+
left = left === right ? 1 : 0;
|
|
732
|
+
break;
|
|
733
|
+
case "!=":
|
|
734
|
+
left = left !== right ? 1 : 0;
|
|
735
|
+
break;
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
return left;
|
|
739
|
+
}
|
|
740
|
+
/** additive: multiplicative (('+' | '-') multiplicative)* */
|
|
741
|
+
parseAdditive() {
|
|
742
|
+
let left = this.parseMultiplicative();
|
|
743
|
+
while (this.peek().type === "op" && (this.peek().value === "+" || this.peek().value === "-")) {
|
|
744
|
+
const op = this.consume().value;
|
|
745
|
+
const right = this.parseMultiplicative();
|
|
746
|
+
left = op === "+" ? left + right : left - right;
|
|
747
|
+
}
|
|
748
|
+
return left;
|
|
749
|
+
}
|
|
750
|
+
/** multiplicative: power (('*' | '/' | '%') power)* */
|
|
751
|
+
parseMultiplicative() {
|
|
752
|
+
let left = this.parsePower();
|
|
753
|
+
while (this.peek().type === "op" && (this.peek().value === "*" || this.peek().value === "/" || this.peek().value === "%")) {
|
|
754
|
+
const op = this.consume().value;
|
|
755
|
+
const right = this.parsePower();
|
|
756
|
+
if (op === "*") left = left * right;
|
|
757
|
+
else if (op === "/") left = right !== 0 ? left / right : 0;
|
|
758
|
+
else left = left % right;
|
|
759
|
+
}
|
|
760
|
+
return left;
|
|
761
|
+
}
|
|
762
|
+
/** power: unary ('**' unary)* (right-associative) */
|
|
763
|
+
parsePower() {
|
|
764
|
+
const base = this.parseUnary();
|
|
765
|
+
if (this.peek().type === "op" && this.peek().value === "**") {
|
|
766
|
+
this.consume();
|
|
767
|
+
const exp = this.parsePower();
|
|
768
|
+
return Math.pow(base, exp);
|
|
769
|
+
}
|
|
770
|
+
return base;
|
|
771
|
+
}
|
|
772
|
+
/** unary: ('-' | '+') unary | primary */
|
|
773
|
+
parseUnary() {
|
|
774
|
+
if (this.peek().type === "op" && (this.peek().value === "-" || this.peek().value === "+")) {
|
|
775
|
+
const op = this.consume().value;
|
|
776
|
+
const val = this.parseUnary();
|
|
777
|
+
return op === "-" ? -val : val;
|
|
778
|
+
}
|
|
779
|
+
return this.parsePrimary();
|
|
780
|
+
}
|
|
781
|
+
/** primary: number | ident | function(args) | '(' expr ')' */
|
|
782
|
+
parsePrimary() {
|
|
783
|
+
const tok = this.peek();
|
|
784
|
+
if (tok.type === "number") {
|
|
785
|
+
this.consume();
|
|
786
|
+
return parseFloat(tok.value);
|
|
787
|
+
}
|
|
788
|
+
if (tok.type === "ident") {
|
|
789
|
+
this.consume();
|
|
790
|
+
const name = tok.value;
|
|
791
|
+
if (this.peek().type === "lparen") {
|
|
792
|
+
this.consume();
|
|
793
|
+
const args = [];
|
|
794
|
+
if (this.peek().type !== "rparen") {
|
|
795
|
+
args.push(this.parseTernary());
|
|
796
|
+
while (this.peek().type === "comma") {
|
|
797
|
+
this.consume();
|
|
798
|
+
args.push(this.parseTernary());
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
this.consume("rparen");
|
|
802
|
+
const fn = FUNCTIONS[name];
|
|
803
|
+
if (!fn) throw new Error(`Expression: unknown function '${name}'`);
|
|
804
|
+
return fn(...args);
|
|
805
|
+
}
|
|
806
|
+
if (name in CONSTANTS) return CONSTANTS[name];
|
|
807
|
+
if (name in this.ctx) return this.ctx[name];
|
|
808
|
+
throw new Error(`Expression: unknown variable '${name}'`);
|
|
809
|
+
}
|
|
810
|
+
if (tok.type === "lparen") {
|
|
811
|
+
this.consume();
|
|
812
|
+
const val = this.parseTernary();
|
|
813
|
+
this.consume("rparen");
|
|
814
|
+
return val;
|
|
815
|
+
}
|
|
816
|
+
throw new Error(`Expression: unexpected token '${tok.value}'`);
|
|
817
|
+
}
|
|
818
|
+
};
|
|
819
|
+
function isExpression(value) {
|
|
820
|
+
return typeof value === "object" && value !== null && "expr" in value && typeof value.expr === "string";
|
|
821
|
+
}
|
|
822
|
+
function evaluateExpression(expr, ctx) {
|
|
823
|
+
const tokens = tokenize(expr);
|
|
824
|
+
const parser = new Parser(tokens, ctx);
|
|
825
|
+
return parser.parse();
|
|
826
|
+
}
|
|
463
827
|
function isFrameInRange(frame, range) {
|
|
464
828
|
return frame >= range[0] && frame <= range[1];
|
|
465
829
|
}
|
|
@@ -475,7 +839,15 @@ function resolveDeltaValue(delta, frame) {
|
|
|
475
839
|
const progress = computeProgress(frame, delta.range);
|
|
476
840
|
const easingFn = resolveEasing(delta.easing);
|
|
477
841
|
const easedProgress = easingFn(progress);
|
|
478
|
-
|
|
842
|
+
const exprCtx = {
|
|
843
|
+
t: easedProgress,
|
|
844
|
+
progress,
|
|
845
|
+
frame,
|
|
846
|
+
duration: delta.range[1] - delta.range[0]
|
|
847
|
+
};
|
|
848
|
+
const from = isExpression(delta.from) ? evaluateExpression(delta.from.expr, exprCtx) : delta.from;
|
|
849
|
+
const to = isExpression(delta.to) ? evaluateExpression(delta.to.expr, exprCtx) : delta.to;
|
|
850
|
+
return interpolateValue(from, to, easedProgress);
|
|
479
851
|
}
|
|
480
852
|
function interpolateValue(from, to, t) {
|
|
481
853
|
if (typeof from === "number" && typeof to === "number") {
|
|
@@ -503,7 +875,16 @@ function resolvePropertyAtFrame(deltas, frame) {
|
|
|
503
875
|
}
|
|
504
876
|
}
|
|
505
877
|
}
|
|
506
|
-
return
|
|
878
|
+
if (!lastCompleted) return void 0;
|
|
879
|
+
if (isExpression(lastCompleted.to)) {
|
|
880
|
+
return evaluateExpression(lastCompleted.to.expr, {
|
|
881
|
+
t: 1,
|
|
882
|
+
progress: 1,
|
|
883
|
+
frame,
|
|
884
|
+
duration: lastCompleted.range[1] - lastCompleted.range[0]
|
|
885
|
+
});
|
|
886
|
+
}
|
|
887
|
+
return lastCompleted.to;
|
|
507
888
|
}
|
|
508
889
|
function resolveFrame(doc, stateName, frame) {
|
|
509
890
|
const state = doc.states[stateName];
|
|
@@ -844,11 +1225,23 @@ function buildEffectiveLayer(resolved, parentWidth, parentHeight) {
|
|
|
844
1225
|
const { layer, computedProperties } = resolved;
|
|
845
1226
|
const cp = computedProperties;
|
|
846
1227
|
const hasShadow = layer.shadow || cp["shadow.blur"] !== void 0 || cp["shadow.color"] !== void 0;
|
|
1228
|
+
let x = resolveUnit(cp["frame.x"] ?? layer.frame.x, parentWidth);
|
|
1229
|
+
let y = resolveUnit(cp["frame.y"] ?? layer.frame.y, parentHeight);
|
|
1230
|
+
let motionPathAngle = 0;
|
|
1231
|
+
const motionProgress = cp["motionPath.progress"];
|
|
1232
|
+
if (motionProgress !== void 0 && layer.motionPath && layer.motionPath.points.length >= 2) {
|
|
1233
|
+
const pos = evaluatePathAtProgress(layer.motionPath.points, motionProgress, layer.motionPath.closed);
|
|
1234
|
+
x = pos.x;
|
|
1235
|
+
y = pos.y;
|
|
1236
|
+
if (layer.motionPath.autoRotate) {
|
|
1237
|
+
motionPathAngle = pos.angle + (layer.motionPath.autoRotateOffset ?? 0);
|
|
1238
|
+
}
|
|
1239
|
+
}
|
|
847
1240
|
return {
|
|
848
1241
|
layer,
|
|
849
1242
|
visual: buildEffectiveVisual(layer.visual, cp),
|
|
850
|
-
x
|
|
851
|
-
y
|
|
1243
|
+
x,
|
|
1244
|
+
y,
|
|
852
1245
|
width: resolveUnit(cp["bounds.width"] ?? layer.bounds.width, parentWidth),
|
|
853
1246
|
height: resolveUnit(cp["bounds.height"] ?? layer.bounds.height, parentHeight),
|
|
854
1247
|
opacity: cp["opacity"] ?? layer.opacity ?? 1,
|
|
@@ -862,19 +1255,42 @@ function buildEffectiveLayer(resolved, parentWidth, parentHeight) {
|
|
|
862
1255
|
blur: cp["shadow.blur"] ?? layer.shadow?.blur ?? 0,
|
|
863
1256
|
offsetX: cp["shadow.offsetX"] ?? layer.shadow?.offsetX ?? 0,
|
|
864
1257
|
offsetY: cp["shadow.offsetY"] ?? layer.shadow?.offsetY ?? 0
|
|
865
|
-
} : void 0
|
|
1258
|
+
} : void 0,
|
|
1259
|
+
blendMode: layer.blendMode ?? "normal",
|
|
1260
|
+
motionPathAngle
|
|
866
1261
|
};
|
|
867
1262
|
}
|
|
868
1263
|
function buildEffectiveVisual(visual, cp) {
|
|
869
|
-
const hasVisualOverride = cp["visual.fill.color"] !== void 0 || cp["visual.stroke.color"] !== void 0 || cp["visual.stroke.width"] !== void 0 || cp["visual.stroke.start"] !== void 0 || cp["visual.stroke.end"] !== void 0 || cp["visual.shape.cornerRadius"] !== void 0 || cp["visual.style.fontSize"] !== void 0 || cp["visual.style.color"] !== void 0;
|
|
1264
|
+
const hasVisualOverride = cp["visual.fill.color"] !== void 0 || cp["visual.fill.angle"] !== void 0 || cp["visual.fill.center.x"] !== void 0 || cp["visual.fill.center.y"] !== void 0 || cp["visual.fill.radius"] !== void 0 || cp["visual.stroke.color"] !== void 0 || cp["visual.stroke.width"] !== void 0 || cp["visual.stroke.start"] !== void 0 || cp["visual.stroke.end"] !== void 0 || cp["visual.shape.cornerRadius"] !== void 0 || cp["visual.style.fontSize"] !== void 0 || cp["visual.style.color"] !== void 0;
|
|
870
1265
|
if (!hasVisualOverride) return visual;
|
|
871
1266
|
if (visual.type === "shape") {
|
|
872
1267
|
const v = { ...visual };
|
|
873
1268
|
if (cp["visual.shape.cornerRadius"] !== void 0 && v.shape.type === "rect") {
|
|
874
1269
|
v.shape = { ...v.shape, cornerRadius: cp["visual.shape.cornerRadius"] };
|
|
875
1270
|
}
|
|
876
|
-
if (v.fill
|
|
877
|
-
|
|
1271
|
+
if (v.fill) {
|
|
1272
|
+
if (cp["visual.fill.color"] !== void 0 && v.fill.type === "solid") {
|
|
1273
|
+
v.fill = { ...v.fill, color: cp["visual.fill.color"] };
|
|
1274
|
+
}
|
|
1275
|
+
if (cp["visual.fill.angle"] !== void 0 && v.fill.type === "linear-gradient") {
|
|
1276
|
+
v.fill = { ...v.fill, angle: cp["visual.fill.angle"] };
|
|
1277
|
+
}
|
|
1278
|
+
if (v.fill.type === "radial-gradient") {
|
|
1279
|
+
const cx = cp["visual.fill.center.x"];
|
|
1280
|
+
const cy = cp["visual.fill.center.y"];
|
|
1281
|
+
const r = cp["visual.fill.radius"];
|
|
1282
|
+
if (cx !== void 0 || cy !== void 0 || r !== void 0) {
|
|
1283
|
+
const f = v.fill;
|
|
1284
|
+
v.fill = {
|
|
1285
|
+
...f,
|
|
1286
|
+
center: {
|
|
1287
|
+
x: cx !== void 0 ? cx : f.center.x,
|
|
1288
|
+
y: cy !== void 0 ? cy : f.center.y
|
|
1289
|
+
},
|
|
1290
|
+
radius: r !== void 0 ? r : f.radius
|
|
1291
|
+
};
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
878
1294
|
}
|
|
879
1295
|
if (v.stroke) {
|
|
880
1296
|
const strokeColor = cp["visual.stroke.color"] ?? v.stroke.color;
|
|
@@ -1088,13 +1504,17 @@ function renderFrame(ctx, resolvedFrame, doc, imageCache) {
|
|
|
1088
1504
|
ctx.save();
|
|
1089
1505
|
applyAncestorTransforms(ctx, layer.id, effMap, doc);
|
|
1090
1506
|
ctx.globalAlpha = eff.opacity;
|
|
1507
|
+
if (eff.blendMode !== "normal") {
|
|
1508
|
+
ctx.globalCompositeOperation = blendModeToComposite(eff.blendMode);
|
|
1509
|
+
}
|
|
1091
1510
|
ctx.translate(eff.x, eff.y);
|
|
1092
1511
|
const anchorPixelX = eff.anchorX * eff.width;
|
|
1093
1512
|
const anchorPixelY = eff.anchorY * eff.height;
|
|
1094
|
-
|
|
1513
|
+
const totalRotation = eff.rotation + eff.motionPathAngle;
|
|
1514
|
+
if (totalRotation !== 0 || eff.scaleX !== 1 || eff.scaleY !== 1) {
|
|
1095
1515
|
ctx.translate(anchorPixelX, anchorPixelY);
|
|
1096
|
-
if (
|
|
1097
|
-
ctx.rotate(
|
|
1516
|
+
if (totalRotation !== 0) {
|
|
1517
|
+
ctx.rotate(totalRotation * Math.PI / 180);
|
|
1098
1518
|
}
|
|
1099
1519
|
if (eff.scaleX !== 1 || eff.scaleY !== 1) {
|
|
1100
1520
|
ctx.scale(eff.scaleX, eff.scaleY);
|
|
@@ -1107,6 +1527,9 @@ function renderFrame(ctx, resolvedFrame, doc, imageCache) {
|
|
|
1107
1527
|
ctx.shadowOffsetX = eff.shadow.offsetX;
|
|
1108
1528
|
ctx.shadowOffsetY = eff.shadow.offsetY;
|
|
1109
1529
|
}
|
|
1530
|
+
if (layer.clipPath) {
|
|
1531
|
+
applyClipPath(ctx, layer.clipPath, eff.width, eff.height);
|
|
1532
|
+
}
|
|
1110
1533
|
switch (layer.visual.type) {
|
|
1111
1534
|
case "shape":
|
|
1112
1535
|
renderShape(ctx, eff);
|
|
@@ -1126,6 +1549,68 @@ function renderFrame(ctx, resolvedFrame, doc, imageCache) {
|
|
|
1126
1549
|
ctx.restore();
|
|
1127
1550
|
}
|
|
1128
1551
|
}
|
|
1552
|
+
function applyClipPath(ctx, shape, width, height) {
|
|
1553
|
+
ctx.beginPath();
|
|
1554
|
+
switch (shape.type) {
|
|
1555
|
+
case "rect":
|
|
1556
|
+
if (shape.cornerRadius && ctx.roundRect) {
|
|
1557
|
+
ctx.roundRect(0, 0, width, height, shape.cornerRadius);
|
|
1558
|
+
} else {
|
|
1559
|
+
ctx.moveTo(0, 0);
|
|
1560
|
+
ctx.lineTo(width, 0);
|
|
1561
|
+
ctx.lineTo(width, height);
|
|
1562
|
+
ctx.lineTo(0, height);
|
|
1563
|
+
ctx.closePath();
|
|
1564
|
+
}
|
|
1565
|
+
break;
|
|
1566
|
+
case "ellipse":
|
|
1567
|
+
ctx.ellipse(width / 2, height / 2, width / 2, height / 2, 0, 0, Math.PI * 2);
|
|
1568
|
+
break;
|
|
1569
|
+
case "path":
|
|
1570
|
+
if (shape.points.length >= 2) {
|
|
1571
|
+
ctx.moveTo(shape.points[0].x, shape.points[0].y);
|
|
1572
|
+
for (let i = 1; i < shape.points.length; i++) {
|
|
1573
|
+
const prev = shape.points[i - 1];
|
|
1574
|
+
const curr = shape.points[i];
|
|
1575
|
+
if (prev.out && curr.in) {
|
|
1576
|
+
ctx.bezierCurveTo(
|
|
1577
|
+
prev.x + prev.out.x,
|
|
1578
|
+
prev.y + prev.out.y,
|
|
1579
|
+
curr.x + curr.in.x,
|
|
1580
|
+
curr.y + curr.in.y,
|
|
1581
|
+
curr.x,
|
|
1582
|
+
curr.y
|
|
1583
|
+
);
|
|
1584
|
+
} else {
|
|
1585
|
+
ctx.lineTo(curr.x, curr.y);
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
if (shape.closed) ctx.closePath();
|
|
1589
|
+
}
|
|
1590
|
+
break;
|
|
1591
|
+
}
|
|
1592
|
+
ctx.clip();
|
|
1593
|
+
}
|
|
1594
|
+
function blendModeToComposite(mode) {
|
|
1595
|
+
const map = {
|
|
1596
|
+
"multiply": "multiply",
|
|
1597
|
+
"screen": "screen",
|
|
1598
|
+
"overlay": "overlay",
|
|
1599
|
+
"darken": "darken",
|
|
1600
|
+
"lighten": "lighten",
|
|
1601
|
+
"color-dodge": "color-dodge",
|
|
1602
|
+
"color-burn": "color-burn",
|
|
1603
|
+
"hard-light": "hard-light",
|
|
1604
|
+
"soft-light": "soft-light",
|
|
1605
|
+
"difference": "difference",
|
|
1606
|
+
"exclusion": "exclusion",
|
|
1607
|
+
"hue": "hue",
|
|
1608
|
+
"saturation": "saturation",
|
|
1609
|
+
"color": "color",
|
|
1610
|
+
"luminosity": "luminosity"
|
|
1611
|
+
};
|
|
1612
|
+
return map[mode] ?? "source-over";
|
|
1613
|
+
}
|
|
1129
1614
|
function applyAncestorTransforms(ctx, layerId, effMap, doc) {
|
|
1130
1615
|
const chain = [];
|
|
1131
1616
|
const layer = doc.layers.find((l) => l.id === layerId);
|
|
@@ -1462,4 +1947,4 @@ export {
|
|
|
1462
1947
|
renderDocument,
|
|
1463
1948
|
renderCommand
|
|
1464
1949
|
};
|
|
1465
|
-
//# sourceMappingURL=chunk-
|
|
1950
|
+
//# sourceMappingURL=chunk-H4A6HRMY.js.map
|